From a3a44a90b061b5154d9dbcb307409051a39d397d Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Fri, 2 Dec 2022 18:16:51 +0100 Subject: [PATCH] Implemented focus and handling of the return key presses in the LoginForm view apart from overall UI improvements. --- BeReal/Login/Components/LoginForm.swift | 91 +++++++++++++++++++------ 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/BeReal/Login/Components/LoginForm.swift b/BeReal/Login/Components/LoginForm.swift index 024f080..bce0dfe 100644 --- a/BeReal/Login/Components/LoginForm.swift +++ b/BeReal/Login/Components/LoginForm.swift @@ -10,12 +10,20 @@ import SwiftUI struct LoginForm: View { + // MARK: States + + @FocusState private var focusedField: Field? + // MARK: Bindings @Binding var username: String @Binding var password: String @Binding var errorMessage: String? + // MARK: Properties + + let onReturn: () -> Void + // MARK: Body var body: some View { @@ -23,25 +31,33 @@ struct LoginForm: View { alignment: .leading, spacing: 16 ) { - TextField( - "Username", - text: $username - ) - .textContentType(.username) - .autocapitalization(.none) - .disableAutocorrection(true) - .keyboardType(.default) + TextField("Username", text: $username) { isBeginEditing in + guard isBeginEditing, errorMessage != nil else { return } + + errorMessage = nil + } + .textContentType(.username) + .lineLimit(1) + .autocapitalization(.none) + .disableAutocorrection(true) + .keyboardType(.default) + .focused($focusedField, equals: .username) + .onSubmit { + onUsernameReturnPressed() + } Divider() - SecureField( - "Password", - text: $password - ) - .textContentType(.password) - .autocapitalization(.none) - .disableAutocorrection(true) - .keyboardType(.default) + SecureField("Password", text: $password) + .textContentType(.password) + .lineLimit(1) + .autocapitalization(.none) + .disableAutocorrection(true) + .keyboardType(.default) + .focused($focusedField, equals: .password) + .onSubmit { + onPasswordReturnPressed() + } if let errorMessage { Divider() @@ -53,7 +69,7 @@ struct LoginForm: View { } .frame(maxWidth: .infinity, alignment: .leading) .padding(16) - .background(Color.white) + .background(Color.primary.colorInvert()) .cornerRadius(8) .onAppear { setClearButtonIfNeeded() @@ -69,6 +85,41 @@ private extension LoginForm { UITextField.appearance().clearButtonMode = .whileEditing } + + func onUsernameReturnPressed() { + guard !username.isEmpty else { + focusedField = .username + return + } + + if password.isEmpty { + focusedField = .password + } else { + onReturn() + } + } + + func onPasswordReturnPressed() { + guard !password.isEmpty else { + focusedField = .password + return + } + + if username.isEmpty { + focusedField = .username + } else { + onReturn() + } + } +} + +// MARK: - Enumerations + +private extension LoginForm { + enum Field: Hashable { + case username + case password + } } // MARK: - Previews @@ -78,14 +129,16 @@ struct LoginForm_Previews: PreviewProvider { LoginForm( username: .constant("Some username"), password: .constant("Some Password"), - errorMessage: .constant(nil) + errorMessage: .constant(nil), + onReturn: {} ) .previewDisplayName("Login form with no error message") LoginForm( username: .constant("Some username"), password: .constant("Some Password"), - errorMessage: .constant("Some error goes in here...") + errorMessage: .constant("Some error goes in here..."), + onReturn: {} ) .previewDisplayName("Login form with some error message") }