diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/UIKitTextField.swift b/ui/BankingiOSApp/BankingiOSApp/ui/UIKitTextField.swift index 9c6e2fca..43f408e1 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/UIKitTextField.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/UIKitTextField.swift @@ -2,7 +2,10 @@ import SwiftUI struct UIKitTextField: UIViewRepresentable { + + static private var NextTagId = 234567 // start at a high, very unlikely number to not interfere with manually set tags + @Binding private var text: String private var placeHolder: String @@ -10,15 +13,21 @@ struct UIKitTextField: UIViewRepresentable { private var keyboardType: UIKeyboardType = .default private var isPasswordField: Bool = false - private var actionOnReturnKeyPress: (() -> Void)? = nil + private var focusNextTextFieldOnReturnKeyPress = false - init(_ titleKey: String, text: Binding, keyboardType: UIKeyboardType = .default, isPasswordField: Bool = false, actionOnReturnKeyPress: (() -> Void)? = nil) { + private var actionOnReturnKeyPress: (() -> Bool)? = nil + + + init(_ titleKey: String, text: Binding, keyboardType: UIKeyboardType = .default, isPasswordField: Bool = false, + focusNextTextFieldOnReturnKeyPress: Bool = false, actionOnReturnKeyPress: (() -> Bool)? = nil) { self.placeHolder = titleKey _text = text self.keyboardType = keyboardType self.isPasswordField = isPasswordField + self.focusNextTextFieldOnReturnKeyPress = focusNextTextFieldOnReturnKeyPress + self.actionOnReturnKeyPress = actionOnReturnKeyPress } @@ -33,11 +42,14 @@ struct UIKitTextField: UIViewRepresentable { textField.delegate = context.coordinator + Self.NextTagId = Self.NextTagId + 1 // unbelievable, there's no ++ operator + textField.tag = Self.NextTagId + return textField } func makeCoordinator() -> UIKitTextField.Coordinator { - return Coordinator(text: $text, actionOnReturnKeyPress: actionOnReturnKeyPress /*, nextResponder: $nextResponder, isResponder: $isResponder */) + return Coordinator(text: $text, focusNextTextFieldOnReturnKeyPress: focusNextTextFieldOnReturnKeyPress, actionOnReturnKeyPress: actionOnReturnKeyPress) } func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext) { @@ -49,12 +61,16 @@ struct UIKitTextField: UIViewRepresentable { @Binding private var text: String - private var actionOnReturnKeyPress: (() -> Void)? + private var focusNextTextFieldOnReturnKeyPress: Bool + + private var actionOnReturnKeyPress: (() -> Bool)? - init(text: Binding, actionOnReturnKeyPress: (() -> Void)? = nil) { + init(text: Binding, focusNextTextFieldOnReturnKeyPress: Bool, actionOnReturnKeyPress: (() -> Bool)? = nil) { _text = text + self.focusNextTextFieldOnReturnKeyPress = focusNextTextFieldOnReturnKeyPress + self.actionOnReturnKeyPress = actionOnReturnKeyPress } @@ -63,11 +79,18 @@ struct UIKitTextField: UIViewRepresentable { } func textFieldShouldReturn(_ textField: UITextField) -> Bool { - actionOnReturnKeyPress?() + var didHandleReturnKey = actionOnReturnKeyPress?() ?? false - textField.resignFirstResponder() + if didHandleReturnKey == false && focusNextTextFieldOnReturnKeyPress == true { + let nextViewTag = textField.tag + 1 + + let nextView = textField.superview?.superview?.superview?.viewWithTag(nextViewTag) + ?? textField.superview?.superview?.superview?.superview?.superview?.viewWithTag(nextViewTag) // for text fields in Lists (tables) + + didHandleReturnKey = nextView?.becomeFirstResponder() ?? false + } - return actionOnReturnKeyPress != nil + return didHandleReturnKey } } diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/views/AddAccountDialog.swift b/ui/BankingiOSApp/BankingiOSApp/ui/views/AddAccountDialog.swift index f817c2a0..168d4a24 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/views/AddAccountDialog.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/views/AddAccountDialog.swift @@ -37,17 +37,9 @@ struct AddAccountDialog: View { } Section { - UIKitTextField("Customer ID", text: $customerId) { - if self.isRequiredDataEntered() { - self.addAccount() - } - } + UIKitTextField("Customer ID", text: $customerId, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress) - UIKitTextField("Password", text: $password, isPasswordField: true) { - if self.isRequiredDataEntered() { - self.addAccount() - } - } + UIKitTextField("Password", text: $password, isPasswordField: true, actionOnReturnKeyPress: handleReturnKeyPress) } Section { @@ -68,6 +60,16 @@ struct AddAccountDialog: View { } + func handleReturnKeyPress() -> Bool { + if self.isRequiredDataEntered() { + self.addAccount() + + return true + } + + return false + } + func isRequiredDataEntered() -> Bool { return bank != nil && customerId.isNotBlank diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/views/EnterTanDialog.swift b/ui/BankingiOSApp/BankingiOSApp/ui/views/EnterTanDialog.swift index 6a438f87..a54cc378 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/views/EnterTanDialog.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/views/EnterTanDialog.swift @@ -129,9 +129,12 @@ struct EnterTanDialog: View { Section { UIKitTextField("Enter TAN:", text: $enteredTan) { - if self.enteredTan.isNotBlank { - self.enteringTanDone() - } + if self.isRequiredDataEntered() { + self.enteringTanDone() + return true + } + + return false } } @@ -140,7 +143,7 @@ struct EnterTanDialog: View { Spacer() Button(action: { self.enteringTanDone() }, label: { Text("OK") }) - .disabled(self.enteredTan.isBlank) + .disabled( !self.isRequiredDataEntered()) Spacer() } } @@ -155,6 +158,10 @@ struct EnterTanDialog: View { } + private func isRequiredDataEntered() -> Bool { + return self.enteredTan.isNotBlank + } + private func selectedTanProcedureChanged(_ changeTanProcedureTo: TanProcedure) { // do async as at this point Picker dialog gets dismissed -> this EnterTanDialog would never get dismissed (and dismiss has to be called before callback.changeTanProcedure()) DispatchQueue.main.async { diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift b/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift index 0cad63aa..7fb03b3a 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift @@ -90,11 +90,7 @@ struct TransferMoneyDialog: View { } Section { - UIKitTextField("Remittee Name", text: $remitteeName) { - if self.isRequiredDataEntered() { - self.transferMoney() - } - } + UIKitTextField("Remittee Name", text: $remitteeName, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress) .onReceive(Just(remitteeName)) { newValue in self.isValidRemitteeNameEntered = self.remitteeName.isNotBlank } @@ -109,11 +105,7 @@ struct TransferMoneyDialog: View { } } - UIKitTextField("Remittee IBAN", text: $remitteeIban) { - if self.isRequiredDataEntered() { - self.transferMoney() - } - } + UIKitTextField("Remittee IBAN", text: $remitteeIban, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress) .onReceive(Just(remitteeIban)) { newValue in self.isValidRemitteeIbanEntered = newValue.count > 14 // TODO: implement real check if IBAN is valid self.tryToGetBicFromIban(newValue) @@ -121,11 +113,7 @@ struct TransferMoneyDialog: View { } Section { - UIKitTextField("Amount", text: $amount, keyboardType: .decimalPad) { - if self.isRequiredDataEntered() { - self.transferMoney() - } - } + UIKitTextField("Amount", text: $amount, keyboardType: .decimalPad, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress) .onReceive(Just(amount)) { newValue in // TODO: implement DecimalTextField / NumericTextField let filtered = newValue.filter { "0123456789,".contains($0) } @@ -136,11 +124,7 @@ struct TransferMoneyDialog: View { self.isValidAmountEntered = self.amount.isNotBlank } - UIKitTextField("Usage", text: $usage) { - if self.isRequiredDataEntered() { - self.transferMoney() - } - } + UIKitTextField("Usage", text: $usage, actionOnReturnKeyPress: handleReturnKeyPress) .onReceive(Just($usage)) { newValue in self.isValidUsageEntered = true } @@ -174,6 +158,17 @@ struct TransferMoneyDialog: View { } + func handleReturnKeyPress() -> Bool { + if self.isRequiredDataEntered() { + self.transferMoney() + + return true + } + + return false + } + + func tryToGetBicFromIban(_ enteredIban: String) { let foundBank = presenter.findUniqueBankForIban(iban: enteredIban)