Implemented showing user's tan media
This commit is contained in:
parent
be3dba4765
commit
11f115936b
|
@ -19,6 +19,8 @@ open class Account(
|
|||
|
||||
var selectedTanProcedure: TanProcedure? = null
|
||||
|
||||
var tanMedia: List<TanMedium> = listOf()
|
||||
|
||||
|
||||
val balance: BigDecimal
|
||||
get() = bankAccounts.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
|
||||
enum class TanMediumStatus {
|
||||
|
||||
Used,
|
||||
|
||||
Available
|
||||
|
||||
}
|
|
@ -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<String>(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()
|
||||
}
|
||||
|
|
|
@ -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<net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium>): List<TanMedium> {
|
||||
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<BankAccount, List<AccountTransaction>>()
|
||||
var balances = mapOf<BankAccount, BigDecimal>()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<TanMedium>() {
|
||||
|
||||
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<TextView>(R.id.txtTanMediumDisplayName)?.text = procedure.displayName
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
}
|
|
@ -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))
|
||||
|
||||
|
|
|
@ -6,6 +6,32 @@
|
|||
android:padding="@dimen/dialog_enter_tan_padding"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/lytTanMedium"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dialog_enter_tan_tan_medium_height"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:visibility="gone"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:text="@string/dialog_enter_tan_select_tan_medium"
|
||||
android:layout_marginRight="@dimen/dialog_enter_tan_tan_medium_label_right_margin"
|
||||
android:layout_marginEnd="@dimen/dialog_enter_tan_tan_medium_label_right_margin"
|
||||
/>
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spnTanMedium"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<net.dankito.banking.fints4java.android.ui.views.ChipTanFlickerCodeView
|
||||
android:id="@+id/flickerCodeView"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -33,7 +59,7 @@
|
|||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/dialog_enter_tan_enter_tan_dialog"
|
||||
android:text="@string/dialog_enter_tan_enter_tan"
|
||||
/>
|
||||
|
||||
<EditText
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TextView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/txtTanMediumDisplayName"
|
||||
style="@style/TextAppearance.AppCompat.Small"
|
||||
android:singleLine="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:ellipsize="marquee"
|
||||
/>
|
|
@ -49,6 +49,8 @@
|
|||
<dimen name="view_tan_generator_marker_margin_bottom">6dp</dimen>
|
||||
|
||||
<dimen name="dialog_enter_tan_padding">4dp</dimen>
|
||||
<dimen name="dialog_enter_tan_tan_medium_height">30dp</dimen>
|
||||
<dimen name="dialog_enter_tan_tan_medium_label_right_margin">8dp</dimen>
|
||||
<dimen name="dialog_enter_tan_flicker_view_height">175dp</dimen>
|
||||
<dimen name="dialog_enter_tan_flicker_view_margin_top_bottom">20dp</dimen>
|
||||
<dimen name="dialog_enter_tan_enter_tan_height">50dp</dimen>
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
<string name="view_flicker_code_increase_frequency">+</string>
|
||||
<string name="view_flicker_code_decrease_frequency">-</string>
|
||||
|
||||
<string name="dialog_enter_tan_enter_tan_dialog">Enter TAN:</string>
|
||||
<string name="dialog_enter_tan_select_tan_medium">TAN medium</string>
|
||||
<string name="dialog_enter_tan_enter_tan">Enter TAN:</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -582,7 +582,7 @@ 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 ?: "",
|
||||
val enteredTan = callback.enterTan(customer, TanChallenge(tanResponse.challenge ?: "",
|
||||
tanResponse.challengeHHD_UC ?: "", customer.selectedTanProcedure))
|
||||
|
||||
if (enteredTan == null) {
|
||||
|
|
|
@ -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>): TanProcedure?
|
||||
|
||||
fun enterTan(tanChallenge: TanChallenge): String?
|
||||
fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): String?
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue