From 11f115936b72ca0ed49d5a594e298217d7a9489d Mon Sep 17 00:00:00 2001 From: dankl Date: Sun, 29 Dec 2019 17:55:41 +0100 Subject: [PATCH] Implemented showing user's tan media --- .../net/dankito/banking/ui/model/Account.kt | 2 ++ .../net/dankito/banking/ui/model/TanMedium.kt | 14 ++++++++++ .../banking/ui/model/TanMediumStatus.kt | 10 +++++++ .../fints4java/android/MainActivity.kt | 11 +++++--- .../android/mapper/fints4javaModelMapper.kt | 25 +++++++++++++++++ .../android/ui/MainWindowPresenter.kt | 4 +++ .../android/ui/adapter/TanMediumAdapter.kt | 25 +++++++++++++++++ .../android/ui/dialogs/EnterTanDialog.kt | 16 ++++++++++- .../src/main/res/layout/dialog_enter_tan.xml | 28 ++++++++++++++++++- .../main/res/layout/list_item_tan_medium.xml | 10 +++++++ .../src/main/res/values/dimens.xml | 2 ++ .../src/main/res/values/strings.xml | 3 +- .../kotlin/net/dankito/fints/FinTsClient.kt | 4 +-- .../net/dankito/fints/FinTsClientCallback.kt | 3 +- .../net/dankito/fints/java/JavaShowcase.java | 2 +- .../net/dankito/fints/FinTsClientTest.kt | 2 +- 16 files changed, 149 insertions(+), 12 deletions(-) create mode 100644 BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt create mode 100644 BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt create mode 100644 fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt create mode 100644 fints4javaAndroidApp/src/main/res/layout/list_item_tan_medium.xml diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt index 8c0e5fb0..29c92cd9 100644 --- a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/Account.kt @@ -19,6 +19,8 @@ open class Account( var selectedTanProcedure: TanProcedure? = null + var tanMedia: List = listOf() + val balance: BigDecimal get() = bankAccounts.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e } diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt new file mode 100644 index 00000000..a2135ef1 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMedium.kt @@ -0,0 +1,14 @@ +package net.dankito.banking.ui.model + + +open class TanMedium( + val displayName: String, + val status: TanMediumStatus, + val originalObject: Any +) { + + override fun toString(): String { + return "$displayName $status" + } + +} \ No newline at end of file diff --git a/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt new file mode 100644 index 00000000..4a385061 --- /dev/null +++ b/BankingUiCommon/src/main/java/net/dankito/banking/ui/model/TanMediumStatus.kt @@ -0,0 +1,10 @@ +package net.dankito.banking.ui.model + + +enum class TanMediumStatus { + + Used, + + Available + +} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt index db14eece..5d106ff5 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/MainActivity.kt @@ -12,6 +12,7 @@ import net.dankito.banking.fints4java.android.ui.MainWindowPresenter import net.dankito.banking.fints4java.android.ui.dialogs.AddAccountDialog import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog import net.dankito.fints.FinTsClientCallback +import net.dankito.fints.model.CustomerData import net.dankito.fints.model.TanChallenge import net.dankito.fints.model.TanProcedure import java.util.concurrent.CountDownLatch @@ -29,8 +30,8 @@ class MainActivity : AppCompatActivity() { return supportedTanProcedures.first() } - override fun enterTan(tanChallenge: TanChallenge): String? { - return getTanFromUserOffUiThread(tanChallenge) + override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String? { + return getTanFromUserOffUiThread(customer, tanChallenge) } }) @@ -82,12 +83,14 @@ class MainActivity : AppCompatActivity() { // return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() // } - private fun getTanFromUserOffUiThread(tanChallenge: TanChallenge): String? { + private fun getTanFromUserOffUiThread(customer: CustomerData, tanChallenge: TanChallenge): String? { val enteredTan = AtomicReference(null) val tanEnteredLatch = CountDownLatch(1) + val account = presenter.getAccountForCustomer(customer) + runOnUiThread { - EnterTanDialog().show(tanChallenge, this@MainActivity, false) { + EnterTanDialog().show(account, tanChallenge, this@MainActivity, false) { enteredTan.set(it) tanEnteredLatch.countDown() } diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/mapper/fints4javaModelMapper.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/mapper/fints4javaModelMapper.kt index 5a7d220f..a486c2d0 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/mapper/fints4javaModelMapper.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/mapper/fints4javaModelMapper.kt @@ -4,6 +4,7 @@ import net.dankito.banking.ui.model.* import net.dankito.banking.ui.model.responses.AddAccountResponse import net.dankito.banking.ui.model.responses.GetTransactionsResponse import net.dankito.fints.messages.datenelemente.implementierte.signatur.Sicherheitsfunktion +import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium import net.dankito.fints.model.AccountData import net.dankito.fints.model.BankData import net.dankito.fints.model.CustomerData @@ -21,6 +22,7 @@ open class fints4javaModelMapper { account.bankAccounts = mapBankAccounts(account, customer.accounts) account.supportedTanProcedures = mapTanProcedures(customer.supportedTanProcedures) + account.tanMedia = mapTanMediums(customer.tanMedia) return account } @@ -89,6 +91,29 @@ open class fints4javaModelMapper { } + open fun mapTanMediums(tanMediums: List): List { + return tanMediums.map { mapTanMedium(it) } + } + + open fun mapTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium { + val status = if (tanMedium.status.name.contains("Aktiv")) TanMediumStatus.Used else TanMediumStatus.Available + + return TanMedium(getDisplayNameForTanMedium(tanMedium), status, tanMedium) + } + + protected open fun getDisplayNameForTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): String { + if (tanMedium is TanGeneratorTanMedium) { + tanMedium.mediaName?.let { mediaName -> + return "$mediaName ${tanMedium.cardNumber}" + } + + return "Card ${tanMedium.cardNumber}" // TODO: translate + } + + return tanMedium.mediumClass.name + } + + fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse { var bookedTransactions = mapOf>() var balances = mapOf() diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt index a80057cb..c82f8d35 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/MainWindowPresenter.kt @@ -187,6 +187,10 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service, open val balanceOfAllAccounts: BigDecimal get() = accounts.keys.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e } + open fun getAccountForCustomer(customer: CustomerData): Account { // TODO: remove as presenter should not be aware of fints4java objects + return accounts.keys.first { it.customerId == customer.customerId } + } + open fun addAccountAddedListener(listener: (Account) -> Unit) { accountAddedListeners.add(listener) diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt new file mode 100644 index 00000000..164701ae --- /dev/null +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/adapter/TanMediumAdapter.kt @@ -0,0 +1,25 @@ +package net.dankito.banking.fints4java.android.ui.adapter + +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import net.dankito.banking.fints4java.android.R +import net.dankito.banking.ui.model.TanMedium +import net.dankito.utils.android.extensions.asActivity +import net.dankito.utils.android.ui.adapter.ListAdapter + + +open class TanMediumAdapter : ListAdapter() { + + override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? { + val procedure = getItem(position) + + val view = convertView ?: parent?.context?.asActivity()?.layoutInflater?.inflate( + R.layout.list_item_tan_medium, parent, false) + + view?.findViewById(R.id.txtTanMediumDisplayName)?.text = procedure.displayName + + return view + } + +} \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt index 431d2861..1ed29ac1 100644 --- a/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt +++ b/fints4javaAndroidApp/src/main/java/net/dankito/banking/fints4java/android/ui/dialogs/EnterTanDialog.kt @@ -9,6 +9,9 @@ import android.view.View import android.view.ViewGroup import kotlinx.android.synthetic.main.dialog_enter_tan.view.* import net.dankito.banking.fints4java.android.R +import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter +import net.dankito.banking.ui.model.Account +import net.dankito.banking.ui.model.TanMediumStatus import net.dankito.fints.model.TanChallenge import net.dankito.fints.model.TanProcedureType import net.dankito.fints.tan.FlickercodeDecoder @@ -21,14 +24,19 @@ open class EnterTanDialog : DialogFragment() { } + protected lateinit var account: Account + protected lateinit var tanChallenge: TanChallenge protected lateinit var tanEnteredCallback: (String?) -> Unit + protected val tanMediumAdapter = TanMediumAdapter() - open fun show(tanChallenge: TanChallenge, activity: AppCompatActivity, + + open fun show(account: Account, tanChallenge: TanChallenge, activity: AppCompatActivity, fullscreen: Boolean = false, tanEnteredCallback: (String?) -> Unit) { + this.account = account this.tanChallenge = tanChallenge this.tanEnteredCallback = tanEnteredCallback @@ -51,6 +59,12 @@ open class EnterTanDialog : DialogFragment() { val flickerCodeView = rootView.flickerCodeView if (tanChallenge.tanProcedure.type == TanProcedureType.ChipTanOptisch) { + if (account.tanMedia.isNotEmpty()) { + rootView.lytTanMedium.visibility = View.VISIBLE + tanMediumAdapter.setItems(account.tanMedia.sortedByDescending { it.status == TanMediumStatus.Used }) + rootView.spnTanMedium.adapter = tanMediumAdapter + } + flickerCodeView.visibility = View.VISIBLE flickerCodeView.setCode(FlickercodeDecoder().decodeChallenge(tanChallenge.tanChallenge)) diff --git a/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml b/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml index 172adf6e..864f87cc 100644 --- a/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml +++ b/fints4javaAndroidApp/src/main/res/layout/dialog_enter_tan.xml @@ -6,6 +6,32 @@ android:padding="@dimen/dialog_enter_tan_padding" > + + + + + + + + + \ No newline at end of file diff --git a/fints4javaAndroidApp/src/main/res/values/dimens.xml b/fints4javaAndroidApp/src/main/res/values/dimens.xml index 07db9497..96d67d2c 100644 --- a/fints4javaAndroidApp/src/main/res/values/dimens.xml +++ b/fints4javaAndroidApp/src/main/res/values/dimens.xml @@ -49,6 +49,8 @@ 6dp 4dp + 30dp + 8dp 175dp 20dp 50dp diff --git a/fints4javaAndroidApp/src/main/res/values/strings.xml b/fints4javaAndroidApp/src/main/res/values/strings.xml index bb1ec47f..33651eb2 100644 --- a/fints4javaAndroidApp/src/main/res/values/strings.xml +++ b/fints4javaAndroidApp/src/main/res/values/strings.xml @@ -58,6 +58,7 @@ + - - Enter TAN: + TAN medium + Enter TAN: diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt index 1176b066..01d1e995 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClient.kt @@ -582,8 +582,8 @@ open class FinTsClient @JvmOverloads constructor( if (response.isStrongAuthenticationRequired) { response.tanResponse?.let { tanResponse -> // TODO: is this true for all tan procedures? - val enteredTan = callback.enterTan(TanChallenge(tanResponse.challenge ?: "", - tanResponse.challengeHHD_UC ?: "", customer.selectedTanProcedure)) + val enteredTan = callback.enterTan(customer, TanChallenge(tanResponse.challenge ?: "", + tanResponse.challengeHHD_UC ?: "", customer.selectedTanProcedure)) if (enteredTan == null) { // i tried to send a HKTAN with cancelJob = true but then i saw there are no tan procedures that support cancellation (at least not at my bank) diff --git a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt index 67a4dbf9..d0e4d960 100644 --- a/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt +++ b/fints4javaLib/src/main/kotlin/net/dankito/fints/FinTsClientCallback.kt @@ -1,5 +1,6 @@ package net.dankito.fints +import net.dankito.fints.model.CustomerData import net.dankito.fints.model.TanChallenge import net.dankito.fints.model.TanProcedure @@ -8,6 +9,6 @@ interface FinTsClientCallback { fun askUserForTanProcedure(supportedTanProcedures: List): TanProcedure? - fun enterTan(tanChallenge: TanChallenge): String? + fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String? } \ No newline at end of file diff --git a/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java b/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java index a65c6d1c..3c7aac97 100644 --- a/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java +++ b/fints4javaLib/src/test/java/net/dankito/fints/java/JavaShowcase.java @@ -41,7 +41,7 @@ public class JavaShowcase { @Nullable @Override - public String enterTan(@NotNull TanChallenge tanChallenge) { + public String enterTan(@NotNull CustomerData customer, @NotNull TanChallenge tanChallenge) { return null; } diff --git a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt index 8f8519f4..04a904b3 100644 --- a/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt +++ b/fints4javaLib/src/test/kotlin/net/dankito/fints/FinTsClientTest.kt @@ -35,7 +35,7 @@ class FinTsClientTest { return supportedTanProcedures.first() } - override fun enterTan(tanChallenge: TanChallenge): String? { + override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String? { didAskUserToEnterTan.set(true) return null