From f3d7afc376247592f9fcc88b392cac84392edbc1 Mon Sep 17 00:00:00 2001 From: dankito Date: Mon, 24 Aug 2020 13:43:51 +0200 Subject: [PATCH] Implemented displaying auto retrieved BIC and bank name in an info label; extracted InfoLabel from ValidationLabel --- .../ui/android/dialogs/TransferMoneyDialog.kt | 55 +++++++------------ .../main/res/layout/dialog_transfer_money.xml | 35 ++---------- .../src/main/res/values-de/strings.xml | 6 +- .../src/main/res/values/strings.xml | 6 +- .../dankito/banking/util/InputValidator.kt | 2 + .../Base.lproj/Localizable.strings | 2 + .../de.lproj/Localizable.strings | 2 + .../BankingiOSApp/ui/InfoLabel.swift | 47 ++++++++++++++++ .../BankingiOSApp/ui/SwiftExtensions.swift | 19 +++++++ .../BankingiOSApp/ui/ValidationLabel.swift | 18 +----- .../ui/views/TransferMoneyDialog.swift | 15 +++++ 11 files changed, 117 insertions(+), 90 deletions(-) create mode 100644 ui/BankingiOSApp/BankingiOSApp/ui/InfoLabel.swift diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt index 0864b19e..301035a7 100644 --- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt +++ b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt @@ -59,6 +59,9 @@ open class TransferMoneyDialog : DialogFragment() { protected val inputValidator = InputValidator() // TODO: move to presenter + protected var remitteeBic: String? = null + + protected var validRemitteeNameEntered = false protected var validRemitteeIbanEntered = false @@ -133,7 +136,6 @@ open class TransferMoneyDialog : DialogFragment() { tryToGetBicFromIban(it) }) - rootView.edtxtRemitteeBic.addTextChangedListener(checkRequiredDataWatcher()) rootView.edtxtAmount.addTextChangedListener(checkRequiredDataWatcher()) rootView.edtxtUsage.addTextChangedListener(checkRequiredDataWatcher { checkIfEnteredUsageTextIsValid() @@ -141,13 +143,11 @@ open class TransferMoneyDialog : DialogFragment() { rootView.edtxtRemitteeName.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredRemitteeNameIsValidAfterFocusLost() } rootView.edtxtRemitteeIban.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredRemitteeIbanIsValidAfterFocusLost() } - rootView.edtxtRemitteeBic.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredRemitteeBicIsValid() } rootView.edtxtAmount.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredAmountIsValid() } rootView.edtxtUsage.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredUsageTextIsValid() } transferMoneyIfEnterPressed(rootView.edtxtRemitteeName) transferMoneyIfEnterPressed(rootView.edtxtRemitteeIban) - transferMoneyIfEnterPressed(rootView.edtxtRemitteeBic) transferMoneyIfEnterPressed(rootView.edtxtAmount) transferMoneyIfEnterPressed(rootView.edtxtUsage) @@ -218,7 +218,7 @@ open class TransferMoneyDialog : DialogFragment() { } // a little bit inconsistent as if IBAN is not set bank's name won't be displayed even though it can be retrieved by BIC - rootView.edtxtRemitteeBic.setText(data.creditorBic) + remitteeBic = data.creditorBic if (data.amount > BigDecimal.ZERO) { rootView.edtxtAmount.setText(AmountFormat.format(data.amount)) @@ -231,12 +231,7 @@ open class TransferMoneyDialog : DialogFragment() { protected open fun focusEditTextAccordingToPreselectedValues(rootView: View, data: TransferMoneyData) { if (data.creditorName.trim().isNotEmpty()) { if (data.creditorIban.trim().isNotEmpty()) { - if (data.creditorBic.trim().isNotEmpty()) { - rootView.edtxtAmount.requestFocus() - } - else { - rootView.edtxtRemitteeBic.requestFocus() - } + rootView.edtxtAmount.requestFocus() } else { rootView.edtxtRemitteeIban.requestFocus() @@ -247,8 +242,8 @@ open class TransferMoneyDialog : DialogFragment() { protected open fun remitteeSelected(item: Remittee) { edtxtRemitteeName.setText(item.name) - edtxtRemitteeBic.setText(item.bic) edtxtRemitteeIban.setText(item.iban) + remitteeBic = item.bic } protected open fun transferMoney() { @@ -256,7 +251,7 @@ open class TransferMoneyDialog : DialogFragment() { val data = TransferMoneyData( inputValidator.convertToAllowedSepaCharacters(edtxtRemitteeName.text.toString()), edtxtRemitteeIban.text.toString().replace(" ", ""), - edtxtRemitteeBic.text.toString().replace(" ", ""), + remitteeBic?.replace(" ", "") ?: "", // should always be != null at this point amount.toBigDecimal(), inputValidator.convertToAllowedSepaCharacters(edtxtUsage.text.toString()), chkbxInstantPayment.isChecked @@ -308,18 +303,26 @@ open class TransferMoneyDialog : DialogFragment() { protected open fun tryToGetBicFromIban(enteredIban: CharSequence) { presenter.findUniqueBankForIbanAsync(enteredIban.toString()) { foundBank -> context?.asActivity()?.runOnUiThread { - showValuesForFoundBankOnUiThread(foundBank) + showValuesForFoundBankOnUiThread(enteredIban, foundBank) } } } - private fun showValuesForFoundBankOnUiThread(foundBank: BankInfo?) { + private fun showValuesForFoundBankOnUiThread(enteredIban: CharSequence, foundBank: BankInfo?) { validRemitteeBicEntered = foundBank != null + remitteeBic = foundBank?.bic - edtxtRemitteeBank.setText(if (foundBank != null) (foundBank.name + " " + foundBank.city) else "") - - edtxtRemitteeBic.setText(foundBank?.bic ?: "") // TODO: check if user entered BIC to not overwrite self entered BIC - lytRemitteeBic.error = null // TODO: show information here if BIC hasn't been found + if (foundBank != null) { + txtRemitteeBankInfo.text = getString(R.string.dialog_transfer_money_bic_detected_from_iban, foundBank.bic, foundBank.name) + txtRemitteeBankInfo.visibility = View.VISIBLE + } + else if (enteredIban.length >= InputValidator.MinimumLengthToDetermineBicFromIban) { + txtRemitteeBankInfo.text = getString(R.string.dialog_transfer_money_could_not_determine_bic_from_iban, enteredIban.substring(4, InputValidator.MinimumLengthToDetermineBicFromIban)) + txtRemitteeBankInfo.visibility = View.VISIBLE + } + else { + txtRemitteeBankInfo.visibility = View.GONE + } checkIfRequiredDataEnteredOnUiThread() } @@ -357,13 +360,6 @@ open class TransferMoneyDialog : DialogFragment() { this.validRemitteeIbanEntered = validationResult.validationSuccessfulOrCouldCorrectString showValidationResult(lytRemitteeIban, validationResult) - - if (validRemitteeBicEntered || enteredIban.isBlank()) { - lytRemitteeBic.error = null - } - else { - lytRemitteeBic.error = context?.getString(R.string.error_no_bank_found_for_entered_iban) - } } protected open fun checkIfEnteredRemitteeIbanIsValidAfterFocusLost() { @@ -376,15 +372,6 @@ open class TransferMoneyDialog : DialogFragment() { } } - protected open fun checkIfEnteredRemitteeBicIsValid() { - val enteredBic = edtxtRemitteeBic.text.toString() - val validationResult = inputValidator.validateBic(enteredBic) - - this.validRemitteeBicEntered = validationResult.validationSuccessfulOrCouldCorrectString - - showValidationResult(lytRemitteeBic, validationResult) - } - protected open fun checkIfEnteredAmountIsValid() { val validationResult = inputValidator.validateAmount(edtxtAmount.text.toString()) diff --git a/ui/BankingAndroidApp/src/main/res/layout/dialog_transfer_money.xml b/ui/BankingAndroidApp/src/main/res/layout/dialog_transfer_money.xml index 0e219d42..1d693e55 100644 --- a/ui/BankingAndroidApp/src/main/res/layout/dialog_transfer_money.xml +++ b/ui/BankingAndroidApp/src/main/res/layout/dialog_transfer_money.xml @@ -79,41 +79,14 @@ - - - - - - - - - - - - - Konto: Name: IBAN: - Bank (wird automatisch eingetragen): - BIC (wird automatisch eingetragen): + BIC: %1$s, %2$s + Keine BIC gefunden für BLZ %1$s Betrag: Verwendungszweck: Echtzeitüberweisung @@ -103,8 +103,6 @@ Bitte geben Sie die IBAN des Empfängers ein Unzulässige(s) Zeichen eingegeben: %s IBANs bestehen aus folgendem Muster: DE12 1234 5678 9012 3456 78 - Es wurde keine Bank zur eingegebenen IBAN gefunden. - Bitte geben Sie die BIC des Empfängers ein Unzulässige(s) Zeichen eingegeben: %s Eine BIC besteht aus 8 oder 11 Zeichen und folgt dem Muster: ABCDED12(XYZ) Bitte geben Sie den zu überweisenden Betrag ein diff --git a/ui/BankingAndroidApp/src/main/res/values/strings.xml b/ui/BankingAndroidApp/src/main/res/values/strings.xml index 098d6303..6913ae7b 100644 --- a/ui/BankingAndroidApp/src/main/res/values/strings.xml +++ b/ui/BankingAndroidApp/src/main/res/values/strings.xml @@ -52,8 +52,8 @@ Account: Name: IBAN: - Bank (will be entered automatically): - BIC (will be entered automatically): + BIC: %1$s, %2$s + No BIC found for bank code %1$s Amount: Usage: Instant payment @@ -103,8 +103,6 @@ Please enter remittee\'s IBAN Invalid character(s) entered: %s IBAN has to have pattern: EN12 1234 5678 9012 3456 78 - No bank found for entered IBAN. - Please enter remittee\'s BIC Invalid character(s) entered: %s A BIC consists of 8 or 11 characters and has the pattern: ABCDED12(XYZ) Please enter the amount to be transferred diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/util/InputValidator.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/util/InputValidator.kt index 8b0fdb36..73ccc486 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/util/InputValidator.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/util/InputValidator.kt @@ -17,6 +17,8 @@ open class InputValidator { const val UsageMaxLength = 140 + const val MinimumLengthToDetermineBicFromIban = 12 // TODO: this is only true for German (and may some other) IBANs + /** * The IBAN consists of up to 34 alphanumeric characters, as follows: diff --git a/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings b/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings index f32809a1..0b54fdee 100644 --- a/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings +++ b/ui/BankingiOSApp/BankingiOSApp/Base.lproj/Localizable.strings @@ -72,6 +72,8 @@ "Transfer Money Dialog Title" = "Bank transfer"; "Remittee Name" = "Name"; "Remittee IBAN" = "IBAN"; +"BIC: %@, %@" = "BIC: %@, %@"; +"No BIC found for bank code %@" = "No BIC found for bank code %@"; "Amount" = "Amount"; "Usage" = "Usage"; "Instant Payment" = "Instant Payment"; diff --git a/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings b/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings index 12acb34b..7e33f7b4 100644 --- a/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings +++ b/ui/BankingiOSApp/BankingiOSApp/de.lproj/Localizable.strings @@ -72,6 +72,8 @@ "Transfer Money Dialog Title" = "Überweisung"; "Remittee Name" = "Name"; "Remittee IBAN" = "IBAN"; +"BIC: %@, %@" = "BIC: %@, %@"; +"No BIC found for bank code %@" = "Keine BIC gefunden für BLZ %@"; "Amount" = "Betrag"; "Usage" = "Verwendungszweck"; "Instant Payment" = "Echtzeitüberweisung"; diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/InfoLabel.swift b/ui/BankingiOSApp/BankingiOSApp/ui/InfoLabel.swift new file mode 100644 index 00000000..91976d8d --- /dev/null +++ b/ui/BankingiOSApp/BankingiOSApp/ui/InfoLabel.swift @@ -0,0 +1,47 @@ +import SwiftUI + + +struct InfoLabel: View { + + private let information: LocalizedStringKey + + + init(_ information: String) { + self.init(LocalizedStringKey(information)) + } + + init(_ information: LocalizedStringKey) { + self.information = information + } + + + var body: some View { + VStack { + Spacer() + .frame(height: 6) + + HStack { + Text(information) + .padding(.leading, 16) + + Spacer() + } + + Spacer() + .frame(height: 18) + } + .font(.callout) + .systemGroupedBackground() + .listRowInsets(EdgeInsets()) + } + +} + + +struct InfoLabel_Previews: PreviewProvider { + + static var previews: some View { + InfoLabel("A nice info") + } + +} diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift b/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift index 374cff98..7cb114a5 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/SwiftExtensions.swift @@ -20,6 +20,25 @@ extension String { return NSLocalizedString(self, comment: "") } + + subscript(_ i: Int) -> String { + let idx1 = index(startIndex, offsetBy: i) + let idx2 = index(idx1, offsetBy: 1) + return String(self[idx1..) -> String { + let start = index(startIndex, offsetBy: r.lowerBound) + let end = index(startIndex, offsetBy: r.upperBound) + return String(self[start ..< end]) + } + + subscript (r: CountableClosedRange) -> String { + let startIndex = self.index(self.startIndex, offsetBy: r.lowerBound) + let endIndex = self.index(startIndex, offsetBy: r.upperBound - r.lowerBound) + return String(self[startIndex...endIndex]) + } + } extension Optional where Wrapped == String { diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/ValidationLabel.swift b/ui/BankingiOSApp/BankingiOSApp/ui/ValidationLabel.swift index db184332..08a34407 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/ValidationLabel.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/ValidationLabel.swift @@ -25,24 +25,8 @@ struct ValidationLabel: View { var body: some View { - VStack { - Spacer() - .frame(height: 6) - - HStack { - Text(validationErrorOrHint) - .padding(.leading, 16) - - Spacer() - } - - Spacer() - .frame(height: 18) - } - .font(.callout) + InfoLabel(validationErrorOrHint) .foregroundColor(isHint ? Color.yellow : Color.red) - .systemGroupedBackground() - .listRowInsets(EdgeInsets()) } } diff --git a/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift b/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift index 7c64356d..b597b7f5 100644 --- a/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift +++ b/ui/BankingiOSApp/BankingiOSApp/ui/views/TransferMoneyDialog.swift @@ -29,6 +29,8 @@ struct TransferMoneyDialog: View { @State private var isValidRemitteeBicEntered = false @State private var remitteeBicValidationResult: ValidationResult? = nil + @State private var remitteeBankInfo: String? = nil + @State private var amount = "" @State private var isValidAmountEntered = false @State private var amountValidationResult: ValidationResult? = nil @@ -127,6 +129,11 @@ struct TransferMoneyDialog: View { remitteeIbanValidationResult.map { validationError in ValidationLabel(validationError) } + + remitteeBankInfo.map { + InfoLabel($0) + .font(.caption) + } } Section { @@ -215,9 +222,17 @@ struct TransferMoneyDialog: View { if let foundBank = foundBank { self.remitteeBic = foundBank.bic + self.remitteeBankInfo = "BIC: \(foundBank.bic), \(foundBank.name)" } else { self.remitteeBic = "" + + if enteredIban.count >= InputValidator.Companion().MinimumLengthToDetermineBicFromIban { + self.remitteeBankInfo = "No BIC found for bank code \(enteredIban[4..