From b74b1659743d4fe1d3810b2e1ae1649a9c1558e8 Mon Sep 17 00:00:00 2001 From: dankito Date: Sat, 19 Feb 2022 15:15:23 +0100 Subject: [PATCH] Implemented that entered tan now can directly be set on TanChallenge, therefore no need of callback anymore --- .../banking/fints4k/android/FirstFragment.kt | 15 +- .../banking/fints4k/android/Presenter.kt | 13 +- .../fints4k/android/dialogs/EnterTanDialog.kt | 140 ++++++++++++++++++ .../src/main/res/layout/dialog_enter_tan.xml | 96 ++++++++++++ .../AndroidApp/src/main/res/values/dimens.xml | 8 + .../src/main/res/values/strings.xml | 6 + .../main/kotlin/AccountTransactionsView.kt | 28 ++-- .../WebApp/src/main/kotlin/EnterTanView.kt | 69 +++++++++ .../WebApp/src/main/kotlin/Presenter.kt | 45 ++++++ .../WebApp/src/main/kotlin/main.kt | 4 +- .../fints4k iOS.xcodeproj/project.pbxproj | 4 + .../fints4k iOS/fints4k iOS/ContentView.swift | 2 +- .../fints4k iOS/fints4k iOS/Presenter.swift | 14 +- .../fints4k iOS/fints4k_iOSApp.swift | 32 +++- .../service/UrlSessionWebClient.swift | 4 +- .../fints4k iOS/ui/EnterTanDialog.swift | 118 +++++++++++++++ .../dankito/banking/fints/FinTsJobExecutor.kt | 32 ++-- .../fints/callback/FinTsClientCallback.kt | 2 +- .../fints/callback/NoOpFinTsClientCallback.kt | 4 +- .../callback/SimpleFinTsClientCallback.kt | 8 +- .../banking/fints/model/EnterTanResult.kt | 22 +-- .../banking/fints/model/TanChallenge.kt | 27 ++++ .../dankito/banking/fints/model/TanMethod.kt | 4 + .../banking/fints/webclient/IWebClient.kt | 4 - .../fints/extensions/TanImageExtensions.kt | 11 ++ .../dankito/banking/fints/iOSFinTsClient.kt | 30 ++++ fints4k/src/nativeMain/kotlin/Application.kt | 20 ++- .../extensions/ByteArrayExtensions.kt | 12 ++ 28 files changed, 701 insertions(+), 73 deletions(-) create mode 100644 SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/dialogs/EnterTanDialog.kt create mode 100644 SampleApplications/AndroidApp/src/main/res/layout/dialog_enter_tan.xml create mode 100644 SampleApplications/WebApp/src/main/kotlin/EnterTanView.kt create mode 100644 SampleApplications/WebApp/src/main/kotlin/Presenter.kt create mode 100644 SampleApplications/iOSApp/fints4k iOS/fints4k iOS/ui/EnterTanDialog.swift create mode 100644 fints4k/src/iosMain/kotlin/net/dankito/banking/fints/extensions/TanImageExtensions.kt create mode 100644 fints4k/src/iosMain/kotlin/net/dankito/banking/fints/iOSFinTsClient.kt create mode 100644 multiplatform-utils/src/iosMain/kotlin/net/dankito/utils/multiplatform/extensions/ByteArrayExtensions.kt diff --git a/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/FirstFragment.kt b/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/FirstFragment.kt index fe69e139..c8232c2e 100644 --- a/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/FirstFragment.kt +++ b/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/FirstFragment.kt @@ -10,6 +10,7 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import net.codinux.banking.fints4k.android.adapter.AccountTransactionsListRecyclerAdapter import net.codinux.banking.fints4k.android.databinding.FragmentFirstBinding +import net.codinux.banking.fints4k.android.dialogs.EnterTanDialog /** * A simple [Fragment] subclass as the default destination in the navigation. @@ -24,14 +25,10 @@ class FirstFragment : Fragment() { // onDestroyView. private val binding get() = _binding!! - override fun onCreateView( - inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? - ): View? { + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = FragmentFirstBinding.inflate(inflater, container, false) return binding.root - } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -43,8 +40,14 @@ class FirstFragment : Fragment() { adapter = accountTransactionsAdapter } + val presenter = Presenter() // TODO: inject + + presenter.enterTanCallback = { tanChallenge -> + EnterTanDialog().show(tanChallenge, activity!!) + } + // TODO: set your credentials here - Presenter().retrieveAccountData("", "", "", "") { response -> + presenter.retrieveAccountData("", "", "", "") { response -> if (response.successful) { accountTransactionsAdapter.items = response.retrievedData.flatMap { it.bookedTransactions } } diff --git a/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/Presenter.kt b/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/Presenter.kt index 6b70dc43..3b39b8fa 100644 --- a/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/Presenter.kt +++ b/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/Presenter.kt @@ -8,6 +8,7 @@ import kotlinx.datetime.LocalDate import net.dankito.banking.fints.FinTsClientDeprecated import net.dankito.banking.fints.callback.SimpleFinTsClientCallback import net.dankito.banking.fints.model.AddAccountParameter +import net.dankito.banking.fints.model.TanChallenge import net.dankito.banking.fints.response.client.AddAccountResponse import net.dankito.utils.multiplatform.extensions.millisSinceEpochAtSystemDefaultTimeZone import org.slf4j.LoggerFactory @@ -15,7 +16,7 @@ import java.math.BigDecimal import java.text.DateFormat import java.util.* -class Presenter { +open class Presenter { companion object { val ValueDateFormat = DateFormat.getDateInstance(DateFormat.SHORT) @@ -23,11 +24,17 @@ class Presenter { private val log = LoggerFactory.getLogger(Presenter::class.java) } - private val fintsClient = FinTsClientDeprecated(SimpleFinTsClientCallback()) + private val fintsClient = FinTsClientDeprecated(SimpleFinTsClientCallback { challenge -> enterTan(challenge) }) + + open var enterTanCallback: ((TanChallenge) -> Unit)? = null + + open protected fun enterTan(tanChallenge: TanChallenge) { + enterTanCallback?.invoke(tanChallenge) ?: run { tanChallenge.userDidNotEnterTan() } + } - fun retrieveAccountData(bankCode: String, customerId: String, pin: String, finTs3ServerAddress: String, retrievedResult: (AddAccountResponse) -> Unit) { + open fun retrieveAccountData(bankCode: String, customerId: String, pin: String, finTs3ServerAddress: String, retrievedResult: (AddAccountResponse) -> Unit) { GlobalScope.launch(Dispatchers.IO) { val response = fintsClient.addAccountAsync(AddAccountParameter(bankCode, customerId, pin, finTs3ServerAddress)) log.info("Retrieved response from ${response.bank.bankName} for ${response.bank.customerName}") diff --git a/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/dialogs/EnterTanDialog.kt b/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/dialogs/EnterTanDialog.kt new file mode 100644 index 00000000..4140c342 --- /dev/null +++ b/SampleApplications/AndroidApp/src/main/java/net/codinux/banking/fints4k/android/dialogs/EnterTanDialog.kt @@ -0,0 +1,140 @@ +package net.codinux.banking.fints4k.android.dialogs + +import android.graphics.BitmapFactory +import android.os.Bundle +import android.os.Handler +import android.text.InputFilter +import android.text.InputType +import android.view.KeyEvent +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.* +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import androidx.fragment.app.FragmentActivity +import net.codinux.banking.fints4k.android.Presenter +import net.codinux.banking.fints4k.android.R +import net.dankito.banking.fints.model.FlickerCodeTanChallenge +import net.dankito.banking.fints.model.ImageTanChallenge +import net.dankito.banking.fints.model.TanChallenge +import net.dankito.utils.android.extensions.getSpannedFromHtml +import net.dankito.utils.android.extensions.show + + +open class EnterTanDialog : DialogFragment() { + + companion object { + const val DialogTag = "EnterTanDialog" + } + + + protected lateinit var tanChallenge: TanChallenge + + + open fun show(tanChallenge: TanChallenge, activity: FragmentActivity) { + this.tanChallenge = tanChallenge + + setStyle(STYLE_NORMAL, R.style.FullscreenDialogWithStatusBar) + + show(activity.supportFragmentManager, DialogTag) + } + + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val rootView = inflater.inflate(R.layout.dialog_enter_tan, container, false) + + setupUI(rootView) + + return rootView + } + + protected open fun setupUI(rootView: View) { + setupTanView(rootView) + + setupEnteringTan(rootView) + + rootView.findViewById(R.id.txtvwMessageToShowToUser).text = tanChallenge.messageToShowToUser.getSpannedFromHtml() + + rootView.findViewById