Implement bank transfer app flows
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
import SwiftUI
|
||||
|
||||
struct OnboardingView: View {
|
||||
@Environment(AppViewModel.self) private var app
|
||||
@State private var page = 0
|
||||
@State private var pinDone = false
|
||||
|
||||
var body: some View {
|
||||
TabView(selection: $page) {
|
||||
WelcomePage(onNext: { page = 1 })
|
||||
.tag(0)
|
||||
|
||||
SecuritySetupView(onComplete: {
|
||||
pinDone = true
|
||||
withAnimation { page = 2 }
|
||||
})
|
||||
.tag(1)
|
||||
|
||||
FinishPage(onGetStarted: { app.completeOnboarding() })
|
||||
.tag(2)
|
||||
}
|
||||
.tabViewStyle(.page(indexDisplayMode: .never))
|
||||
// Prevent swiping forward past the PIN page until it's configured
|
||||
.gesture(
|
||||
DragGesture().onEnded { v in
|
||||
let forward = v.translation.width < -40
|
||||
if forward && page == 1 && !pinDone { return }
|
||||
}
|
||||
)
|
||||
.ignoresSafeArea()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Page 1: Welcome
|
||||
|
||||
private struct WelcomePage: View {
|
||||
let onNext: () -> Void
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(.systemBackground).ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
|
||||
VStack(spacing: 20) {
|
||||
Image(systemName: "building.columns.fill")
|
||||
.font(.system(size: 72))
|
||||
.foregroundStyle(.tint)
|
||||
|
||||
VStack(spacing: 8) {
|
||||
Text("Thijooree")
|
||||
.font(.largeTitle.bold())
|
||||
Text("MIB · BML · Fahipay — one app.")
|
||||
.font(.title3)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
FeatureRow(icon: "lock.shield.fill", text: "Your credentials stay on your device — no backend, no middleman.")
|
||||
FeatureRow(icon: "faceid", text: "Face ID & Touch ID unlock in an instant.")
|
||||
FeatureRow(icon: "arrow.triangle.2.circlepath", text: "Balances from all your banks in one tap.")
|
||||
}
|
||||
.padding(.horizontal, 32)
|
||||
.padding(.top, 8)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Get Started") { onNext() }
|
||||
.buttonStyle(.borderedProminent)
|
||||
.controlSize(.large)
|
||||
.padding(.horizontal, 40)
|
||||
.padding(.bottom, 48)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private struct FeatureRow: View {
|
||||
let icon: String
|
||||
let text: String
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top, spacing: 12) {
|
||||
Image(systemName: icon)
|
||||
.font(.system(size: 20))
|
||||
.foregroundStyle(.tint)
|
||||
.frame(width: 28)
|
||||
Text(text)
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Page 3: Finish
|
||||
|
||||
private struct FinishPage: View {
|
||||
let onGetStarted: () -> Void
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(.systemBackground).ignoresSafeArea()
|
||||
|
||||
VStack(spacing: 32) {
|
||||
Spacer()
|
||||
|
||||
VStack(spacing: 16) {
|
||||
Image(systemName: "checkmark.circle.fill")
|
||||
.font(.system(size: 72))
|
||||
.foregroundStyle(.green)
|
||||
|
||||
Text("You're all set!")
|
||||
.font(.title.bold())
|
||||
|
||||
Text("Add your first bank account to get started.")
|
||||
.font(.body)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
.padding(.horizontal, 40)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Continue to Thijooree") { onGetStarted() }
|
||||
.buttonStyle(.borderedProminent)
|
||||
.controlSize(.large)
|
||||
.padding(.horizontal, 40)
|
||||
.padding(.bottom, 48)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
OnboardingView()
|
||||
.environment(AppViewModel())
|
||||
}
|
||||
Reference in New Issue
Block a user