import SwiftUI struct LoginView: View { @Environment(AuthManager.self) private var authManager @State private var username = "" @State private var password = "" @State private var isLoading = false @FocusState private var focusedField: Field? private enum Field: Hashable { case username, password } var body: some View { ZStack { Color.canvas .ignoresSafeArea() ScrollView { VStack(spacing: 32) { Spacer() .frame(height: 60) // Logo / Branding VStack(spacing: 8) { Image(systemName: "square.grid.2x2.fill") .font(.system(size: 48)) .foregroundStyle(Color.accentWarm) Text("Platform") .font(.largeTitle.weight(.bold)) .foregroundStyle(Color.text1) Text("Sign in to your dashboard") .font(.subheadline) .foregroundStyle(Color.text3) } // Form VStack(spacing: 16) { VStack(alignment: .leading, spacing: 6) { Text("Username") .font(.caption.weight(.semibold)) .foregroundStyle(Color.text3) .textCase(.uppercase) TextField("Enter username", text: $username) .textFieldStyle(.plain) .textContentType(.username) .textInputAutocapitalization(.never) .autocorrectionDisabled() .focused($focusedField, equals: .username) .padding(14) .background(Color.surface) .clipShape(RoundedRectangle(cornerRadius: 12)) .overlay( RoundedRectangle(cornerRadius: 12) .stroke( focusedField == .username ? Color.accentWarm : Color.black.opacity(0.06), lineWidth: focusedField == .username ? 2 : 1 ) ) } VStack(alignment: .leading, spacing: 6) { Text("Password") .font(.caption.weight(.semibold)) .foregroundStyle(Color.text3) .textCase(.uppercase) SecureField("Enter password", text: $password) .textFieldStyle(.plain) .textContentType(.password) .focused($focusedField, equals: .password) .padding(14) .background(Color.surface) .clipShape(RoundedRectangle(cornerRadius: 12)) .overlay( RoundedRectangle(cornerRadius: 12) .stroke( focusedField == .password ? Color.accentWarm : Color.black.opacity(0.06), lineWidth: focusedField == .password ? 2 : 1 ) ) } if let error = authManager.loginError { HStack(spacing: 8) { Image(systemName: "exclamationmark.circle.fill") .foregroundStyle(Color.error) Text(error) .font(.subheadline) .foregroundStyle(Color.error) } .frame(maxWidth: .infinity, alignment: .leading) .padding(.top, 4) } } .padding(.horizontal, 4) // Sign In Button Button { performLogin() } label: { HStack(spacing: 8) { if isLoading { ProgressView() .controlSize(.small) .tint(.white) } Text("Sign In") .font(.body.weight(.semibold)) } .frame(maxWidth: .infinity) .padding(.vertical, 16) .background(canSubmit ? Color.accentWarm : Color.text4) .foregroundStyle(.white) .clipShape(RoundedRectangle(cornerRadius: 14)) } .disabled(!canSubmit) Spacer() } .padding(.horizontal, 28) } } .onSubmit { switch focusedField { case .username: focusedField = .password case .password: performLogin() case .none: break } } } private var canSubmit: Bool { !username.trimmingCharacters(in: .whitespaces).isEmpty && !password.isEmpty && !isLoading } private func performLogin() { guard canSubmit else { return } isLoading = true focusedField = nil Task { await authManager.login( username: username.trimmingCharacters(in: .whitespaces), password: password ) isLoading = false } } }