import SwiftUI struct AppLockView: View { @Binding var isUnlocked: Bool @AppStorage("faceIdEnabled") private var faceIdEnabled = false @AppStorage("pinEnabled") private var pinEnabled = false @State private var pin = "" @State private var errorMessage: String? @State private var didAttemptBiometrics = false @FocusState private var pinFocused: Bool var body: some View { ZStack { Color(.systemBackground) .ignoresSafeArea() VStack(spacing: 20) { Spacer() Image("BrandMark") .resizable() .scaledToFit() .frame(width: 64, height: 64) Text("Locked") .font(.title.weight(.bold)) Text("Unlock Portfolio Journal to view your data.") .font(.subheadline) .foregroundColor(.secondary) .multilineTextAlignment(.center) .padding(.horizontal, 30) if faceIdEnabled { Button { authenticateWithBiometrics() } label: { Label("Unlock with Face ID", systemImage: "faceid") .font(.headline) .frame(maxWidth: .infinity) .padding() .background(Color.appPrimary) .foregroundColor(.white) .cornerRadius(AppConstants.UI.cornerRadius) } .padding(.horizontal, 24) } if pinEnabled { VStack(spacing: 10) { SecureField("4-digit PIN", text: $pin) .keyboardType(.numberPad) .textContentType(.oneTimeCode) .multilineTextAlignment(.center) .font(.title3.weight(.semibold)) .padding() .background(Color.gray.opacity(0.1)) .cornerRadius(12) .focused($pinFocused) .onChange(of: pin) { _, newValue in pin = String(newValue.filter(\.isNumber).prefix(4)) errorMessage = nil if pin.count == 4 { validatePin() } } Button("Unlock") { validatePin() } .font(.subheadline.weight(.semibold)) .disabled(pin.count < 4) } .padding(.horizontal, 24) } if let errorMessage { Text(errorMessage) .font(.caption) .foregroundColor(.negativeRed) } Spacer() } } .onAppear { if faceIdEnabled && !didAttemptBiometrics { didAttemptBiometrics = true authenticateWithBiometrics() } else if pinEnabled { pinFocused = true } } } private func authenticateWithBiometrics() { AppLockService.authenticate(reason: "Unlock your portfolio") { success in if success { isUnlocked = true } else if pinEnabled { pinFocused = true } else { errorMessage = "Face ID failed. Please try again." } } } private func validatePin() { guard let storedPin = KeychainService.readPin() else { errorMessage = "PIN not set." pin = "" return } if pin == storedPin { isUnlocked = true pin = "" errorMessage = nil } else { errorMessage = "Incorrect PIN." pin = "" } } }