Implemented focusing the next text field on return key press

This commit is contained in:
dankito 2020-07-29 13:18:45 +02:00
parent e7127aa88b
commit 15939d5862
4 changed files with 69 additions and 42 deletions

View File

@ -3,6 +3,9 @@ import SwiftUI
struct UIKitTextField: UIViewRepresentable { 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 @Binding private var text: String
private var placeHolder: String private var placeHolder: String
@ -10,15 +13,21 @@ struct UIKitTextField: UIViewRepresentable {
private var keyboardType: UIKeyboardType = .default private var keyboardType: UIKeyboardType = .default
private var isPasswordField: Bool = false private var isPasswordField: Bool = false
private var actionOnReturnKeyPress: (() -> Void)? = nil private var focusNextTextFieldOnReturnKeyPress = false
init(_ titleKey: String, text: Binding<String>, keyboardType: UIKeyboardType = .default, isPasswordField: Bool = false, actionOnReturnKeyPress: (() -> Void)? = nil) { private var actionOnReturnKeyPress: (() -> Bool)? = nil
init(_ titleKey: String, text: Binding<String>, keyboardType: UIKeyboardType = .default, isPasswordField: Bool = false,
focusNextTextFieldOnReturnKeyPress: Bool = false, actionOnReturnKeyPress: (() -> Bool)? = nil) {
self.placeHolder = titleKey self.placeHolder = titleKey
_text = text _text = text
self.keyboardType = keyboardType self.keyboardType = keyboardType
self.isPasswordField = isPasswordField self.isPasswordField = isPasswordField
self.focusNextTextFieldOnReturnKeyPress = focusNextTextFieldOnReturnKeyPress
self.actionOnReturnKeyPress = actionOnReturnKeyPress self.actionOnReturnKeyPress = actionOnReturnKeyPress
} }
@ -33,11 +42,14 @@ struct UIKitTextField: UIViewRepresentable {
textField.delegate = context.coordinator textField.delegate = context.coordinator
Self.NextTagId = Self.NextTagId + 1 // unbelievable, there's no ++ operator
textField.tag = Self.NextTagId
return textField return textField
} }
func makeCoordinator() -> UIKitTextField.Coordinator { 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<UIKitTextField>) { func updateUIView(_ uiView: UITextField, context: UIViewRepresentableContext<UIKitTextField>) {
@ -49,12 +61,16 @@ struct UIKitTextField: UIViewRepresentable {
@Binding private var text: String @Binding private var text: String
private var actionOnReturnKeyPress: (() -> Void)? private var focusNextTextFieldOnReturnKeyPress: Bool
private var actionOnReturnKeyPress: (() -> Bool)?
init(text: Binding<String>, actionOnReturnKeyPress: (() -> Void)? = nil) { init(text: Binding<String>, focusNextTextFieldOnReturnKeyPress: Bool, actionOnReturnKeyPress: (() -> Bool)? = nil) {
_text = text _text = text
self.focusNextTextFieldOnReturnKeyPress = focusNextTextFieldOnReturnKeyPress
self.actionOnReturnKeyPress = actionOnReturnKeyPress self.actionOnReturnKeyPress = actionOnReturnKeyPress
} }
@ -63,11 +79,18 @@ struct UIKitTextField: UIViewRepresentable {
} }
func textFieldShouldReturn(_ textField: UITextField) -> Bool { func textFieldShouldReturn(_ textField: UITextField) -> Bool {
actionOnReturnKeyPress?() var didHandleReturnKey = actionOnReturnKeyPress?() ?? false
textField.resignFirstResponder() if didHandleReturnKey == false && focusNextTextFieldOnReturnKeyPress == true {
let nextViewTag = textField.tag + 1
return actionOnReturnKeyPress != nil 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 didHandleReturnKey
} }
} }

View File

@ -37,17 +37,9 @@ struct AddAccountDialog: View {
} }
Section { Section {
UIKitTextField("Customer ID", text: $customerId) { UIKitTextField("Customer ID", text: $customerId, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress)
if self.isRequiredDataEntered() {
self.addAccount()
}
}
UIKitTextField("Password", text: $password, isPasswordField: true) { UIKitTextField("Password", text: $password, isPasswordField: true, actionOnReturnKeyPress: handleReturnKeyPress)
if self.isRequiredDataEntered() {
self.addAccount()
}
}
} }
Section { Section {
@ -68,6 +60,16 @@ struct AddAccountDialog: View {
} }
func handleReturnKeyPress() -> Bool {
if self.isRequiredDataEntered() {
self.addAccount()
return true
}
return false
}
func isRequiredDataEntered() -> Bool { func isRequiredDataEntered() -> Bool {
return bank != nil return bank != nil
&& customerId.isNotBlank && customerId.isNotBlank

View File

@ -129,9 +129,12 @@ struct EnterTanDialog: View {
Section { Section {
UIKitTextField("Enter TAN:", text: $enteredTan) { UIKitTextField("Enter TAN:", text: $enteredTan) {
if self.enteredTan.isNotBlank { if self.isRequiredDataEntered() {
self.enteringTanDone() self.enteringTanDone()
return true
} }
return false
} }
} }
@ -140,7 +143,7 @@ struct EnterTanDialog: View {
Spacer() Spacer()
Button(action: { self.enteringTanDone() }, Button(action: { self.enteringTanDone() },
label: { Text("OK") }) label: { Text("OK") })
.disabled(self.enteredTan.isBlank) .disabled( !self.isRequiredDataEntered())
Spacer() Spacer()
} }
} }
@ -155,6 +158,10 @@ struct EnterTanDialog: View {
} }
private func isRequiredDataEntered() -> Bool {
return self.enteredTan.isNotBlank
}
private func selectedTanProcedureChanged(_ changeTanProcedureTo: TanProcedure) { 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()) // 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 { DispatchQueue.main.async {

View File

@ -90,11 +90,7 @@ struct TransferMoneyDialog: View {
} }
Section { Section {
UIKitTextField("Remittee Name", text: $remitteeName) { UIKitTextField("Remittee Name", text: $remitteeName, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress)
if self.isRequiredDataEntered() {
self.transferMoney()
}
}
.onReceive(Just(remitteeName)) { newValue in .onReceive(Just(remitteeName)) { newValue in
self.isValidRemitteeNameEntered = self.remitteeName.isNotBlank self.isValidRemitteeNameEntered = self.remitteeName.isNotBlank
} }
@ -109,11 +105,7 @@ struct TransferMoneyDialog: View {
} }
} }
UIKitTextField("Remittee IBAN", text: $remitteeIban) { UIKitTextField("Remittee IBAN", text: $remitteeIban, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress)
if self.isRequiredDataEntered() {
self.transferMoney()
}
}
.onReceive(Just(remitteeIban)) { newValue in .onReceive(Just(remitteeIban)) { newValue in
self.isValidRemitteeIbanEntered = newValue.count > 14 // TODO: implement real check if IBAN is valid self.isValidRemitteeIbanEntered = newValue.count > 14 // TODO: implement real check if IBAN is valid
self.tryToGetBicFromIban(newValue) self.tryToGetBicFromIban(newValue)
@ -121,11 +113,7 @@ struct TransferMoneyDialog: View {
} }
Section { Section {
UIKitTextField("Amount", text: $amount, keyboardType: .decimalPad) { UIKitTextField("Amount", text: $amount, keyboardType: .decimalPad, focusNextTextFieldOnReturnKeyPress: true, actionOnReturnKeyPress: handleReturnKeyPress)
if self.isRequiredDataEntered() {
self.transferMoney()
}
}
.onReceive(Just(amount)) { newValue in .onReceive(Just(amount)) { newValue in
// TODO: implement DecimalTextField / NumericTextField // TODO: implement DecimalTextField / NumericTextField
let filtered = newValue.filter { "0123456789,".contains($0) } let filtered = newValue.filter { "0123456789,".contains($0) }
@ -136,11 +124,7 @@ struct TransferMoneyDialog: View {
self.isValidAmountEntered = self.amount.isNotBlank self.isValidAmountEntered = self.amount.isNotBlank
} }
UIKitTextField("Usage", text: $usage) { UIKitTextField("Usage", text: $usage, actionOnReturnKeyPress: handleReturnKeyPress)
if self.isRequiredDataEntered() {
self.transferMoney()
}
}
.onReceive(Just($usage)) { newValue in .onReceive(Just($usage)) { newValue in
self.isValidUsageEntered = true 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) { func tryToGetBicFromIban(_ enteredIban: String) {
let foundBank = presenter.findUniqueBankForIban(iban: enteredIban) let foundBank = presenter.findUniqueBankForIban(iban: enteredIban)