From 0c87d99d77a6d108dac359c1ca42cb82dd519ee7 Mon Sep 17 00:00:00 2001 From: dankito Date: Fri, 18 Oct 2024 06:48:47 +0200 Subject: [PATCH] Using now BankFinder library --- composeApp/build.gradle.kts | 1 + .../banking/ui/composables/BankIcon.kt | 4 +- .../banking/ui/dialogs/AddAccountDialog.kt | 5 +- .../net/codinux/banking/ui/model/BankInfo.kt | 27 ---- .../banking/ui/model/RecipientSuggestion.kt | 2 + .../codinux/banking/ui/service/BankFinder.kt | 117 ++---------------- .../banking/ui/service/BankingService.kt | 6 +- gradle/libs.versions.toml | 2 + 8 files changed, 19 insertions(+), 145 deletions(-) delete mode 100644 composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/BankInfo.kt diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index 7d5ee7c..afedb8c 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -78,6 +78,7 @@ kotlin { implementation(libs.banking.client.model) implementation(libs.fints4k.banking.client) + implementation(libs.bank.finder) implementation(libs.epcqrcode) implementation(libs.kcsv) diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt index a7b5861..1bf9b1a 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/composables/BankIcon.kt @@ -13,7 +13,7 @@ import androidx.compose.ui.unit.dp import net.codinux.banking.client.model.BankAccess import net.codinux.banking.client.model.BankViewInfo import net.codinux.banking.ui.config.DI -import net.codinux.banking.ui.model.BankInfo +import net.dankito.banking.bankfinder.BankInfo import net.dankito.banking.banklistcreator.prettifier.BankingGroupMapper private val bankIconService = DI.bankIconService @@ -31,7 +31,7 @@ private val bankingGroupMapper = BankingGroupMapper() @Composable fun BankIcon(bank: BankInfo, modifier: Modifier = Modifier, iconModifier: Modifier = DefaultIconModifier, fallbackIcon: ImageVector? = null) { - val iconUrl by remember(bank.bic) { mutableStateOf(bankIconService.findIconForBank(bank.name, bank.bic, bankingGroupMapper.getBankingGroup(bank.name, bank.bic))) } + val iconUrl by remember(bank.bic) { mutableStateOf(bankIconService.findIconForBank(bank.name, bank.bic, bankingGroupMapper.getBankingGroup(bank.name, bank.bic ?: ""))) } BankIcon(iconUrl, modifier, iconModifier, fallbackIcon = fallbackIcon) } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt index 9b84102..81f4101 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/dialogs/AddAccountDialog.kt @@ -12,7 +12,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color -import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import kotlinx.coroutines.* @@ -23,7 +22,7 @@ import net.codinux.banking.ui.config.DI import net.codinux.banking.ui.extensions.ImeNext import net.codinux.banking.ui.forms.* import net.codinux.banking.ui.forms.OutlinedTextField -import net.codinux.banking.ui.model.BankInfo +import net.dankito.banking.bankfinder.BankInfo import net.codinux.log.Log @@ -143,7 +142,7 @@ fun AddAccountDialog( } Row(Modifier.fillMaxWidth().padding(top = 6.dp)) { - Text(bank.domesticBankCode, color = textColor) + Text(bank.bankCode, color = textColor) Text("${bank.postalCode} ${bank.city}", Modifier.weight(1f).padding(start = 8.dp), color = if (supportsFinTs) Color.Gray else textColor) } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/BankInfo.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/BankInfo.kt deleted file mode 100644 index 872abf3..0000000 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/BankInfo.kt +++ /dev/null @@ -1,27 +0,0 @@ -package net.codinux.banking.ui.model - -import net.codinux.banking.client.model.BankingGroup -import kotlinx.serialization.Serializable - -@Serializable -class BankInfo( - val name: String, - val domesticBankCode: String, - val bic: String = "", - val postalCode: String, - val city: String, - val pinTanAddress: String? = null, - val pinTanVersion: String? = null, - val bankingGroup: BankingGroup? = null, - val branchesInOtherCities: List = listOf() // to have only one entry per bank its branches' cities are now stored in branchesInOtherCities so that branches' cities are still searchable -) { - - val supportsPinTan: Boolean - get() = pinTanAddress.isNullOrEmpty() == false - - val supportsFinTs3_0: Boolean - get() = pinTanVersion == "FinTS V3.0" - - - override fun toString() = "$domesticBankCode $name $city" -} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/RecipientSuggestion.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/RecipientSuggestion.kt index 4724d0b..00cf9f6 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/RecipientSuggestion.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/model/RecipientSuggestion.kt @@ -1,5 +1,7 @@ package net.codinux.banking.ui.model +import net.dankito.banking.bankfinder.BankInfo + data class RecipientSuggestion( val name: String, val bankIdentifier: String?, diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankFinder.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankFinder.kt index 31fb621..c2f3e2e 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankFinder.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankFinder.kt @@ -1,119 +1,16 @@ package net.codinux.banking.ui.service -import bankmeister.composeapp.generated.resources.Res -import kotlinx.serialization.json.Json -import net.codinux.banking.ui.model.BankInfo -import org.jetbrains.compose.resources.ExperimentalResourceApi +import net.dankito.banking.bankfinder.BankInfo +import net.dankito.banking.bankfinder.InMemoryBankFinder class BankFinder { - private lateinit var bankList: List + private val bankFinder by lazy { InMemoryBankFinder() } - suspend fun getBankList(maxItems: Int? = null): List { - if (this::bankList.isInitialized == false) { - bankList = loadBankList() - } + fun findBankByNameBicBankCodeOrCity(query: String?, maxItems: Int? = null): List = + bankFinder.findBankByNameBicBankCodeOrCity(query, maxItems) - return bankList.take(maxItems ?: Int.MAX_VALUE) - } - - suspend fun findBankByNameBicBankCodeOrCity(query: String?, maxItems: Int? = null): List { - if (query.isNullOrBlank()) { - return getBankList(maxItems) - } - - query.toIntOrNull()?.let { // if query is an integer, then it can only be an bank code, but not a bank name or city - return findBankByBankCode(query, maxItems) - } - - // we already checked for BankCode above, so there's no need to do this again in method below - return findBankByNameBicOrCityForNonEmptyQuery(query, maxItems) - } - - - suspend fun findBankByBankCode(query: String, maxItems: Int?): List { - if (query.isEmpty()) { - return getBankList(maxItems) - } - - return getBankList().asSequence().filter { it.domesticBankCode.startsWith(query) } - .max(maxItems) - } - - suspend fun findBankByBicOrIban(bic: String?, iban: String): BankInfo? { - if (bic == null || iban.length < 9) { - return null - } - - return findBankByBic(bic) ?: findBankByIban(iban) - } - - suspend fun findBankByBic(bic: String): BankInfo? { - if (bic.length != 8 && bic.length != 11) { - return null - } - - val result = getBankList().asSequence().filter { it.bic == bic || (bic.length == 8 && it.bic.startsWith(bic)) }.max(2) - - return if (result.size > 1) { // non unique result, but should actually never happen for BICs - null - } else { - result.firstOrNull() - } - } - - suspend fun findBankByIban(iban: String): BankInfo? { - if (iban.length < 9) { - return null - } - - val bankCode = iban.substring(4) // first two letters are the country code, third and fourth char are the checksum, bank code starts at 5th char - - val result = getBankList().asSequence().filter { it.domesticBankCode.startsWith(bankCode) }.max(2) - - return if (result.size > 1) { // non unique result, but should actually never happen for BICs - null - } else { - result.firstOrNull() - } - } - - private suspend fun findBankByNameBicOrCityForNonEmptyQuery(query: String, maxItems: Int?): List { - val queryPartsLowerCase = query.lowercase().split(" ", "-") - - return getBankList().asSequence().filter { bankInfo -> - checkIfAllQueryPartsMatchBankNameBicOrCity(queryPartsLowerCase, bankInfo) - } - .max(maxItems) - } - - private fun checkIfAllQueryPartsMatchBankNameBicOrCity(queryPartsLowerCase: List, bankInfo: BankInfo): Boolean { - for (queryPartLowerCase in queryPartsLowerCase) { - if (checkIfQueryMatchesBankNameBicOrCity(bankInfo, queryPartLowerCase) == false) { - return false - } - } - - return true - } - - private fun checkIfQueryMatchesBankNameBicOrCity(bankInfo: BankInfo, queryLowerCase: String): Boolean { - return bankInfo.name.contains(queryLowerCase, true) - || bankInfo.bic.startsWith(queryLowerCase, true) - || bankInfo.city.startsWith(queryLowerCase, true) - || bankInfo.branchesInOtherCities.any { it.startsWith(queryLowerCase, true) } - } - - fun Sequence.max(maxItems: Int? = null): List = - this.take(maxItems ?: Int.MAX_VALUE) - .toList() - - - @OptIn(ExperimentalResourceApi::class) - private suspend fun loadBankList(): List { - val json = Res.readBytes("files/BankList.json").decodeToString() - - return Json.decodeFromString(json) - } + fun findBankByBicOrIban(bic: String?, iban: String): BankInfo? = + bankFinder.findBankByBicOrIban(bic, iban) } \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt index b14b5e8..cc89b56 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt @@ -25,7 +25,7 @@ import net.codinux.banking.persistence.entities.HoldingEntity import net.codinux.banking.persistence.entities.UiSettingsEntity import net.codinux.banking.ui.IOorDefault import net.codinux.banking.ui.model.AccountTransactionViewModel -import net.codinux.banking.ui.model.BankInfo +import net.dankito.banking.bankfinder.BankInfo import net.codinux.banking.ui.model.error.* import net.codinux.banking.ui.model.events.AccountTransactionsRetrievedEvent import net.codinux.banking.ui.model.events.TransferredMoneyEvent @@ -190,7 +190,7 @@ class BankingService( val retrieveTransactions = if (retrieveAllTransactions) RetrieveTransactions.All else RetrieveTransactions.OfLast90Days val options = GetAccountDataOptions(retrieveTransactions, preferredTanMethods = preferredTanMethods) - val response = client.getAccountDataAsync(GetAccountDataRequest(bank.domesticBankCode, loginName, password, options, mapBankInfo(bank))) + val response = client.getAccountDataAsync(GetAccountDataRequest(bank.bankCode, loginName, password, options, mapBankInfo(bank))) if (response.type == ResponseType.Success && response.data != null) { handleSuccessfulGetAccountDataResponse(response.data!!) @@ -211,7 +211,7 @@ class BankingService( private fun mapBankInfo(bank: BankInfo): net.codinux.banking.client.model.BankInfo? = if (bank.pinTanAddress != null) { net.codinux.banking.client.model.BankInfo( - bank.name, bank.bic, bank.pinTanAddress, bank.bankingGroup + bank.name, bank.bic ?: "", bank.pinTanAddress!!, bank.bankingGroup?.let { BankingGroup.valueOf(it.name) } ) } else { null diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 3dd2a4f..269b4df 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -3,6 +3,7 @@ kotlin = "2.0.10" kotlinx-coroutines = "1.8.1" banking-client = "0.7.1" +bank-finder = "0.5.0-SNAPSHOT" epcqrcode = "0.5.0" kcsv = "2.2.0" @@ -35,6 +36,7 @@ camerax = "1.3.4" [libraries] banking-client-model = { group = "net.codinux.banking.client", name = "banking-client-model", version.ref = "banking-client" } fints4k-banking-client = { group = "net.codinux.banking.client", name = "fints4k-banking-client", version.ref = "banking-client" } +bank-finder = { group = "net.codinux.banking", name = "bank-finder", version.ref = "bank-finder" } epcqrcode = { group = "net.codinux.banking.epcqrcode", name = "epc-qr-code", version.ref = "epcqrcode" } kcsv = { group = "net.codinux.csv", name = "kcsv", version.ref = "kcsv" }