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..