Implemented BankingClientCallback to abstract away FinTsClientCallback
This commit is contained in:
parent
b7e294bcbe
commit
6e712316ab
|
@ -0,0 +1,19 @@
|
|||
package net.dankito.banking.ui
|
||||
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||
import net.dankito.banking.ui.model.tan.TanChallenge
|
||||
import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||
|
||||
|
||||
interface BankingClientCallback {
|
||||
|
||||
fun enterTan(account: Account, tanChallenge: TanChallenge): EnterTanResult
|
||||
|
||||
/**
|
||||
* This method gets called for chipTan TAN generators when the bank asks the customer to synchronize her/his TAN generator.
|
||||
*/
|
||||
fun enterTanGeneratorAtc(tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult
|
||||
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import net.dankito.banking.ui.model.tan.TanMedium
|
||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class EnterTanGeneratorAtcResult protected constructor(
|
||||
val tan: String?,
|
||||
val atc: Int?
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
fun userEnteredAtc(enteredTan: String, enteredAtc: Int): EnterTanGeneratorAtcResult {
|
||||
return EnterTanGeneratorAtcResult(enteredTan, enteredAtc)
|
||||
}
|
||||
|
||||
fun userDidNotEnterTan(): EnterTanGeneratorAtcResult {
|
||||
return EnterTanGeneratorAtcResult(null, null)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
val hasAtcBeenEntered: Boolean
|
||||
get() = tan != null && atc != null
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
return "TAN: $tan, ATC: $atc"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
|
||||
|
||||
open class EnterTanResult protected constructor(
|
||||
val enteredTan: String?,
|
||||
val changeTanProcedureTo: TanProcedure? = null,
|
||||
val changeTanMediumTo: TanMedium? = null,
|
||||
val changeTanMediumResultCallback: ((BankingClientResponse) -> Unit)? = null
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
||||
fun userEnteredTan(enteredTan: String): EnterTanResult {
|
||||
return EnterTanResult(enteredTan)
|
||||
}
|
||||
|
||||
fun userDidNotEnterTan(): EnterTanResult {
|
||||
return EnterTanResult(null)
|
||||
}
|
||||
|
||||
fun userAsksToChangeTanProcedure(changeTanProcedureTo: TanProcedure): EnterTanResult {
|
||||
return EnterTanResult(null, changeTanProcedureTo)
|
||||
}
|
||||
|
||||
fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: ((BankingClientResponse) -> Unit)?): EnterTanResult {
|
||||
return EnterTanResult(null, null, changeTanMediumTo, changeTanMediumResultCallback)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
if (changeTanProcedureTo != null) {
|
||||
return "User asks to change TAN procedure to $changeTanProcedureTo"
|
||||
}
|
||||
|
||||
if (changeTanMediumTo != null) {
|
||||
return "User asks to change TAN medium to $changeTanMediumTo"
|
||||
}
|
||||
|
||||
return "enteredTan = $enteredTan"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class FlickerCode(
|
||||
val challengeHHD_UC: String,
|
||||
val parsedDataSet: String,
|
||||
val decodingError: Exception? = null
|
||||
) {
|
||||
|
||||
val decodingSuccessful: Boolean
|
||||
get() = decodingError == null
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
if (decodingSuccessful == false) {
|
||||
return "Decoding error: $decodingError"
|
||||
}
|
||||
|
||||
return "Parsed $challengeHHD_UC to $parsedDataSet"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class FlickerCodeTanChallenge(
|
||||
val flickerCode: FlickerCode,
|
||||
messageToShowToUser: String,
|
||||
tanProcedure: TanProcedure
|
||||
|
||||
) : TanChallenge(messageToShowToUser, tanProcedure) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$tanProcedure $flickerCode: $messageToShowToUser"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class ImageTanChallenge(
|
||||
val image: TanImage,
|
||||
messageToShowToUser: String,
|
||||
tanProcedure: TanProcedure
|
||||
|
||||
) : TanChallenge(messageToShowToUser, tanProcedure) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$tanProcedure $image: $messageToShowToUser"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class TanChallenge(
|
||||
val messageToShowToUser: String,
|
||||
val tanProcedure: TanProcedure
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$tanProcedure: $messageToShowToUser"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class TanGeneratorTanMedium(
|
||||
displayName: String,
|
||||
status: TanMediumStatus,
|
||||
val cardNumber: String
|
||||
|
||||
) : TanMedium(displayName, status) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$displayName $status"
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class TanImage(
|
||||
val mimeType: String,
|
||||
val imageBytes: ByteArray,
|
||||
val decodingError: Exception? = null
|
||||
) {
|
||||
|
||||
val decodingSuccessful: Boolean
|
||||
get() = decodingError == null
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
if (decodingSuccessful == false) {
|
||||
return "Decoding error: $decodingError"
|
||||
}
|
||||
|
||||
return "$mimeType ${imageBytes.size} bytes"
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,9 @@
|
|||
package net.dankito.banking.ui.model
|
||||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class TanMedium(
|
||||
val displayName: String,
|
||||
val status: TanMediumStatus,
|
||||
val originalObject: Any
|
||||
val status: TanMediumStatus
|
||||
) {
|
||||
|
||||
override fun toString(): String {
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.ui.model
|
||||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
enum class TanMediumStatus {
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.ui.model
|
||||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
open class TanProcedure(
|
|
@ -1,4 +1,4 @@
|
|||
package net.dankito.banking.ui.model
|
||||
package net.dankito.banking.ui.model.tan
|
||||
|
||||
|
||||
enum class TanProcedureType {
|
|
@ -8,17 +8,17 @@ import android.support.v7.app.AppCompatActivity
|
|||
import android.support.v7.widget.Toolbar
|
||||
import android.view.Menu
|
||||
import androidx.navigation.findNavController
|
||||
import net.dankito.banking.mapper.fints4javaModelMapper
|
||||
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.EnterAtcDialog
|
||||
import net.dankito.banking.fints4java.android.ui.dialogs.EnterTanDialog
|
||||
import net.dankito.fints.FinTsClientCallback
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.model.EnterTanGeneratorAtcResult
|
||||
import net.dankito.fints.model.EnterTanResult
|
||||
import net.dankito.fints.model.TanChallenge
|
||||
import net.dankito.banking.mapper.fints4javaModelMapper
|
||||
import net.dankito.banking.ui.BankingClientCallback
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanResult
|
||||
import net.dankito.banking.ui.model.tan.TanChallenge
|
||||
import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
|
@ -27,14 +27,14 @@ class MainActivity : AppCompatActivity() {
|
|||
|
||||
// private lateinit var appBarConfiguration: AppBarConfiguration
|
||||
|
||||
val presenter = MainWindowPresenter(Base64ServiceAndroid(), object : FinTsClientCallback {
|
||||
val presenter = MainWindowPresenter(Base64ServiceAndroid(), object : BankingClientCallback {
|
||||
|
||||
override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult {
|
||||
return getTanFromUserOffUiThread(customer, tanChallenge)
|
||||
override fun enterTan(account: Account, tanChallenge: TanChallenge): EnterTanResult {
|
||||
return getTanFromUserOffUiThread(account, tanChallenge)
|
||||
}
|
||||
|
||||
override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
return getAtcFromUserOffUiThread(customer, tanMedium)
|
||||
override fun enterTanGeneratorAtc(tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
return getAtcFromUserOffUiThread(tanMedium)
|
||||
}
|
||||
|
||||
})
|
||||
|
@ -86,12 +86,10 @@ class MainActivity : AppCompatActivity() {
|
|||
// return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
||||
// }
|
||||
|
||||
private fun getTanFromUserOffUiThread(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult {
|
||||
private fun getTanFromUserOffUiThread(account: Account, tanChallenge: TanChallenge): EnterTanResult {
|
||||
val enteredTan = AtomicReference<EnterTanResult>(null)
|
||||
val tanEnteredLatch = CountDownLatch(1)
|
||||
|
||||
val account = presenter.getAccountForCustomer(customer)
|
||||
|
||||
runOnUiThread {
|
||||
EnterTanDialog().show(account, tanChallenge, presenter, this@MainActivity, false) {
|
||||
enteredTan.set(it)
|
||||
|
@ -104,13 +102,13 @@ class MainActivity : AppCompatActivity() {
|
|||
return enteredTan.get()
|
||||
}
|
||||
|
||||
private fun getAtcFromUserOffUiThread(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
private fun getAtcFromUserOffUiThread(tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
val result = AtomicReference<EnterTanGeneratorAtcResult>(null)
|
||||
val tanEnteredLatch = CountDownLatch(1)
|
||||
|
||||
runOnUiThread {
|
||||
// TODO: don't create a fints4javaModelMapper instance here, let MainWindowPresenter do the job
|
||||
EnterAtcDialog().show(net.dankito.banking.mapper.fints4javaModelMapper().mapTanMedium(tanMedium), this@MainActivity, false) { enteredResult ->
|
||||
EnterAtcDialog().show(tanMedium, this@MainActivity, false) { enteredResult ->
|
||||
result.set(enteredResult)
|
||||
tanEnteredLatch.countDown()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package net.dankito.banking.fints4java.android.ui
|
||||
|
||||
import net.dankito.banking.ui.IBankingClient
|
||||
import net.dankito.banking.ui.BankingClientCallback
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
|
@ -8,11 +9,8 @@ import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
|||
import net.dankito.banking.ui.model.responses.AddAccountResponse
|
||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
|
||||
import net.dankito.fints.FinTsClientCallback
|
||||
import net.dankito.fints.banks.BankFinder
|
||||
import net.dankito.fints.model.BankInfo
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.fints.util.IBase64Service
|
||||
import net.dankito.utils.IThreadPool
|
||||
import net.dankito.utils.ThreadPool
|
||||
|
@ -23,7 +21,7 @@ import kotlin.collections.ArrayList
|
|||
|
||||
|
||||
open class MainWindowPresenter(protected val base64Service: IBase64Service,
|
||||
protected val callback: FinTsClientCallback
|
||||
protected val callback: BankingClientCallback
|
||||
) {
|
||||
|
||||
companion object {
|
||||
|
@ -35,10 +33,8 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
|
|||
|
||||
protected val threadPool: IThreadPool = ThreadPool()
|
||||
|
||||
protected val fints4javaModelMapper = net.dankito.banking.mapper.fints4javaModelMapper()
|
||||
|
||||
|
||||
protected val accounts = mutableMapOf<Account, IBankingClient>()
|
||||
protected val clientsForAccounts = mutableMapOf<Account, IBankingClient>()
|
||||
|
||||
protected val accountAddedListeners = mutableListOf<(Account) -> Unit>()
|
||||
|
||||
|
@ -54,7 +50,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
|
|||
val account = response.account
|
||||
|
||||
if (response.isSuccessful) {
|
||||
accounts.put(account, newClient)
|
||||
clientsForAccounts.put(account, newClient)
|
||||
|
||||
callAccountAddedListeners(account)
|
||||
|
||||
|
@ -98,7 +94,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
|
|||
}
|
||||
|
||||
open fun updateAccountsTransactionsAsync(callback: (GetTransactionsResponse) -> Unit) {
|
||||
accounts.keys.forEach { account ->
|
||||
clientsForAccounts.keys.forEach { account ->
|
||||
account.bankAccounts.forEach { bankAccount ->
|
||||
val today = Date() // TODO: still don't know where this bug is coming from that bank returns a transaction dated at end of year
|
||||
val lastRetrievedTransactionDate = bankAccount.bookedTransactions.firstOrNull { it.bookingDate <= today }?.bookingDate
|
||||
|
@ -179,7 +175,7 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
|
|||
|
||||
|
||||
protected open fun getClientForAccount(account: Account): IBankingClient? {
|
||||
accounts.get(account)?.let { client ->
|
||||
clientsForAccounts.get(account)?.let { client ->
|
||||
// TODO: is this code still needed after updating data model is implemented?
|
||||
// account.selectedTanProcedure?.let { selectedTanProcedure ->
|
||||
// client.customer.selectedTanProcedure = fints4javaModelMapper.mapTanProcedureBack(selectedTanProcedure)
|
||||
|
@ -192,20 +188,14 @@ open class MainWindowPresenter(protected val base64Service: IBase64Service,
|
|||
}
|
||||
|
||||
|
||||
open fun getErrorToShowToUser(response: FinTsClientResponse): String? {
|
||||
return fints4javaModelMapper.mapErrorToShowToUser(response)
|
||||
}
|
||||
|
||||
open val accounts: List<Account>
|
||||
get() = clientsForAccounts.keys.toList()
|
||||
|
||||
open val allTransactions: List<AccountTransaction>
|
||||
get() = accounts.keys.flatMap { it.transactions }.sortedByDescending { it.bookingDate } // TODO: someday add unbooked transactions
|
||||
get() = clientsForAccounts.keys.flatMap { it.transactions }.sortedByDescending { it.bookingDate } // TODO: someday add unbooked transactions
|
||||
|
||||
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 }
|
||||
}
|
||||
get() = clientsForAccounts.keys.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
||||
|
||||
|
||||
open fun addAccountAddedListener(listener: (Account) -> Unit) {
|
||||
|
|
|
@ -4,7 +4,7 @@ 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.banking.ui.model.tan.TanMedium
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
import net.dankito.utils.android.ui.adapter.ListAdapter
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ 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.TanProcedure
|
||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
import net.dankito.utils.android.ui.adapter.ListAdapter
|
||||
|
||||
|
|
|
@ -18,7 +18,6 @@ import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
|||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator
|
||||
import net.dankito.fints.messages.segmente.implementierte.sepa.SepaMessageCreator
|
||||
import net.dankito.fints.model.BankTransferData
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
@ -34,7 +33,7 @@ open class BankTransferDialog : DialogFragment() {
|
|||
|
||||
protected lateinit var bankAccount: BankAccount
|
||||
|
||||
protected var preselectedValues: BankTransferData? = null
|
||||
protected var preselectedValues: TransferMoneyData? = null
|
||||
|
||||
protected val sepaMessageCreator: ISepaMessageCreator = SepaMessageCreator()
|
||||
|
||||
|
@ -43,7 +42,7 @@ open class BankTransferDialog : DialogFragment() {
|
|||
show(activity, presenter, bankAccount, null, fullscreen)
|
||||
}
|
||||
|
||||
open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, bankAccount: BankAccount, preselectedValues: BankTransferData?, fullscreen: Boolean = false) {
|
||||
open fun show(activity: AppCompatActivity, presenter: MainWindowPresenter, bankAccount: BankAccount, preselectedValues: TransferMoneyData?, fullscreen: Boolean = false) {
|
||||
this.presenter = presenter
|
||||
this.bankAccount = bankAccount
|
||||
this.preselectedValues = preselectedValues
|
||||
|
@ -92,7 +91,7 @@ open class BankTransferDialog : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
protected open fun focusEditTextAccordingToPreselectedValues(rootView: View, data: BankTransferData) {
|
||||
protected open fun focusEditTextAccordingToPreselectedValues(rootView: View, data: TransferMoneyData) {
|
||||
if (data.creditorName.trim().isNotEmpty()) {
|
||||
if (data.creditorIban.trim().isNotEmpty()) {
|
||||
if (data.creditorBic.trim().isNotEmpty()) {
|
||||
|
|
|
@ -10,8 +10,8 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import kotlinx.android.synthetic.main.dialog_enter_atc.view.*
|
||||
import net.dankito.banking.fints4java.android.R
|
||||
import net.dankito.banking.ui.model.TanMedium
|
||||
import net.dankito.fints.model.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
|
||||
import net.dankito.banking.ui.model.tan.TanMedium
|
||||
|
||||
|
||||
open class EnterAtcDialog : DialogFragment() {
|
||||
|
|
|
@ -15,17 +15,13 @@ import android.widget.Spinner
|
|||
import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
|
||||
import kotlinx.android.synthetic.main.view_tan_image.view.*
|
||||
import net.dankito.banking.fints4java.android.R
|
||||
import net.dankito.banking.mapper.fints4javaModelMapper
|
||||
import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
|
||||
import net.dankito.banking.fints4java.android.ui.adapter.TanMediumAdapter
|
||||
import net.dankito.banking.fints4java.android.ui.adapter.TanProceduresAdapter
|
||||
import net.dankito.banking.fints4java.android.ui.listener.ListItemSelectedListener
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.banking.ui.model.TanMedium
|
||||
import net.dankito.banking.ui.model.TanMediumStatus
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.model.*
|
||||
import net.dankito.fints.response.client.FinTsClientResponse
|
||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.banking.ui.model.tan.*
|
||||
|
||||
|
||||
open class EnterTanDialog : DialogFragment() {
|
||||
|
@ -96,8 +92,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
|
||||
spinner.onItemSelectedListener = ListItemSelectedListener(adapter) { newSelectedTanProcedure ->
|
||||
if (newSelectedTanProcedure != selectedTanProcedure) {
|
||||
val mappedTanProcedure = net.dankito.banking.mapper.fints4javaModelMapper().mapTanProcedureBack(newSelectedTanProcedure) // TODO: move to MainWindowPresenter
|
||||
tanEnteredCallback(EnterTanResult.userAsksToChangeTanProcedure(mappedTanProcedure))
|
||||
tanEnteredCallback(EnterTanResult.userAsksToChangeTanProcedure(newSelectedTanProcedure))
|
||||
// TODO: find a way to update account.selectedTanProcedure afterwards
|
||||
|
||||
dismiss()
|
||||
|
@ -114,7 +109,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
rootView.spnTanMedium.adapter = tanMediumAdapter
|
||||
rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium ->
|
||||
if (selectedTanMedium.status != TanMediumStatus.Used) {
|
||||
(selectedTanMedium.originalObject as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium ->
|
||||
(selectedTanMedium as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium ->
|
||||
tanEnteredCallback(EnterTanResult.userAsksToChangeTanMedium(tanGeneratorTanMedium) { response ->
|
||||
handleChangeTanMediumResponse(selectedTanMedium, response)
|
||||
})
|
||||
|
@ -132,16 +127,16 @@ open class EnterTanDialog : DialogFragment() {
|
|||
setupSelectTanMediumView(rootView)
|
||||
}
|
||||
|
||||
if (tanChallenge is FlickercodeTanChallenge) {
|
||||
if (tanChallenge is FlickerCodeTanChallenge) {
|
||||
val flickerCodeView = rootView.flickerCodeView
|
||||
flickerCodeView.visibility = View.VISIBLE
|
||||
|
||||
val flickercode = (tanChallenge as FlickercodeTanChallenge).flickercode
|
||||
val flickercode = (tanChallenge as FlickerCodeTanChallenge).flickerCode
|
||||
if (flickercode.decodingSuccessful) {
|
||||
flickerCodeView.setCode(flickercode)
|
||||
}
|
||||
else {
|
||||
showDecodingTanChallengeFailedErrorDelayed(flickercode.error)
|
||||
showDecodingTanChallengeFailedErrorDelayed(flickercode.decodingError)
|
||||
}
|
||||
}
|
||||
else if (tanChallenge is ImageTanChallenge) {
|
||||
|
@ -153,7 +148,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
rootView.imgTanImageView.setImageBitmap(bitmap)
|
||||
}
|
||||
else {
|
||||
showDecodingTanChallengeFailedErrorDelayed(decodedImage.error)
|
||||
showDecodingTanChallengeFailedErrorDelayed(decodedImage.decodingError)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +177,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
|
||||
protected open fun handleChangeTanMediumResponse(newUsedTanMedium: TanMedium, response: FinTsClientResponse) {
|
||||
protected open fun handleChangeTanMediumResponse(newUsedTanMedium: TanMedium, response: BankingClientResponse) {
|
||||
activity?.let { activity ->
|
||||
activity.runOnUiThread {
|
||||
handleChangeTanMediumResponseOnUiThread(activity, newUsedTanMedium, response)
|
||||
|
@ -190,7 +185,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
protected open fun handleChangeTanMediumResponseOnUiThread(context: Context, newUsedTanMedium: TanMedium, response: FinTsClientResponse) {
|
||||
protected open fun handleChangeTanMediumResponseOnUiThread(context: Context, newUsedTanMedium: TanMedium, response: BankingClientResponse) {
|
||||
if (response.isSuccessful) {
|
||||
AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.dialog_enter_tan_tan_medium_successfully_changed, newUsedTanMedium.displayName))
|
||||
|
@ -202,7 +197,7 @@ open class EnterTanDialog : DialogFragment() {
|
|||
}
|
||||
else {
|
||||
AlertDialog.Builder(context)
|
||||
.setMessage(context.getString(R.string.dialog_enter_tan_error_changing_tan_medium, newUsedTanMedium.displayName, presenter.getErrorToShowToUser(response)))
|
||||
.setMessage(context.getString(R.string.dialog_enter_tan_error_changing_tan_medium, newUsedTanMedium.displayName, response.errorToShowToUser))
|
||||
.setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ import net.dankito.banking.fints4java.android.ui.MainWindowPresenter
|
|||
import net.dankito.banking.fints4java.android.ui.adapter.AccountTransactionAdapter
|
||||
import net.dankito.banking.fints4java.android.ui.dialogs.BankTransferDialog
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
|
||||
import net.dankito.fints.model.BankTransferData
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
@ -177,9 +177,9 @@ class HomeFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun mapPreselectedValues(selectedTransaction: AccountTransaction?): BankTransferData? {
|
||||
private fun mapPreselectedValues(selectedTransaction: AccountTransaction?): TransferMoneyData? {
|
||||
selectedTransaction?.let {
|
||||
return BankTransferData(
|
||||
return TransferMoneyData(
|
||||
selectedTransaction.otherPartyName ?: "",
|
||||
selectedTransaction.otherPartyAccountId ?: "",
|
||||
selectedTransaction.otherPartyBankCode ?: "",
|
||||
|
|
|
@ -8,9 +8,9 @@ import android.widget.LinearLayout
|
|||
import kotlinx.android.synthetic.main.view_flicker_code.view.*
|
||||
import kotlinx.android.synthetic.main.view_tan_image_size_controls.view.*
|
||||
import net.dankito.banking.fints4java.android.R
|
||||
import net.dankito.banking.fints4java.android.util.FlickercodeAnimator
|
||||
import net.dankito.banking.fints4java.android.util.FlickerCodeAnimator
|
||||
import net.dankito.banking.ui.model.tan.FlickerCode
|
||||
import net.dankito.fints.tan.Bit
|
||||
import net.dankito.fints.tan.Flickercode
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
|
||||
protected lateinit var allStripes: List<ChipTanFlickerCodeStripeView>
|
||||
|
||||
protected val animator = FlickercodeAnimator()
|
||||
protected val animator = FlickerCodeAnimator()
|
||||
|
||||
|
||||
protected var stripesHeight = 360
|
||||
|
@ -160,12 +160,12 @@ open class ChipTanFlickerCodeView @JvmOverloads constructor(
|
|||
}
|
||||
|
||||
|
||||
open fun setCode(flickercode: Flickercode) {
|
||||
open fun setCode(flickerCode: FlickerCode) {
|
||||
animator.stop()
|
||||
|
||||
setFrequency(currentFrequency)
|
||||
|
||||
animator.animateFlickercode(flickercode) { step ->
|
||||
animator.animateFlickerCode(flickerCode) { step ->
|
||||
context.asActivity()?.runOnUiThread {
|
||||
showStepOnUiThread(step)
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
package net.dankito.banking.fints4java.android.util
|
||||
|
||||
import net.dankito.banking.ui.model.tan.FlickerCode
|
||||
import net.dankito.fints.tan.Bit
|
||||
import net.dankito.fints.tan.FlickerCanvas
|
||||
import net.dankito.fints.tan.Flickercode
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
|
||||
open class FlickercodeAnimator { // TODO: move to fints4javaLib
|
||||
open class FlickerCodeAnimator { // TODO: move to fints4javaLib
|
||||
|
||||
companion object {
|
||||
const val MinFrequency = 2
|
||||
const val MaxFrequency = 40
|
||||
const val DefaultFrequency = 20
|
||||
|
||||
private val log = LoggerFactory.getLogger(FlickercodeAnimator::class.java)
|
||||
private val log = LoggerFactory.getLogger(FlickerCodeAnimator::class.java)
|
||||
}
|
||||
|
||||
|
||||
|
@ -27,14 +27,14 @@ open class FlickercodeAnimator { // TODO: move to fints4javaLib
|
|||
|
||||
|
||||
@JvmOverloads
|
||||
open fun animateFlickercode(flickercode: Flickercode, frequency: Int = DefaultFrequency, showStep: (Array<Bit>) -> Unit) {
|
||||
open fun animateFlickerCode(flickerCode: FlickerCode, frequency: Int = DefaultFrequency, showStep: (Array<Bit>) -> Unit) {
|
||||
currentFrequency = frequency
|
||||
currentStepIndex = 0
|
||||
val steps = FlickerCanvas(flickercode.parsedDataSet).steps
|
||||
val steps = FlickerCanvas(flickerCode.parsedDataSet).steps
|
||||
|
||||
stop() // stop may still running previous animation
|
||||
|
||||
calculateAnimationThread = Thread({ calculateAnimation(steps, showStep) }, "CalculateFlickercodeAnimation")
|
||||
calculateAnimationThread = Thread({ calculateAnimation(steps, showStep) }, "CalculateFlickerCodeAnimation")
|
||||
|
||||
calculateAnimationThread?.start()
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package net.dankito.banking
|
||||
|
||||
import net.dankito.banking.ui.BankingClientCallback
|
||||
import net.dankito.banking.ui.IBankingClient
|
||||
import net.dankito.banking.ui.model.Account
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import net.dankito.banking.ui.model.parameters.GetTransactionsParameter
|
||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||
|
@ -9,9 +11,8 @@ import net.dankito.banking.ui.model.responses.BankingClientResponse
|
|||
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
|
||||
import net.dankito.fints.FinTsClientCallback
|
||||
import net.dankito.fints.FinTsClientForCustomer
|
||||
import net.dankito.fints.model.BankInfo
|
||||
import net.dankito.fints.model.BankTransferData
|
||||
import net.dankito.fints.model.CustomerData
|
||||
import net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
|
||||
import net.dankito.fints.model.*
|
||||
import net.dankito.fints.model.mapper.BankDataMapper
|
||||
import net.dankito.fints.util.IBase64Service
|
||||
import net.dankito.utils.IThreadPool
|
||||
|
@ -27,7 +28,7 @@ open class fints4javaBankingClient(
|
|||
webClient: IWebClient = OkHttpWebClient(),
|
||||
base64Service: IBase64Service,
|
||||
threadPool: IThreadPool = ThreadPool(),
|
||||
callback: FinTsClientCallback
|
||||
callback: BankingClientCallback
|
||||
|
||||
) : IBankingClient {
|
||||
|
||||
|
@ -39,12 +40,28 @@ open class fints4javaBankingClient(
|
|||
|
||||
protected val customer = CustomerData(customerId, pin)
|
||||
|
||||
protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, callback)
|
||||
protected lateinit var account: Account
|
||||
|
||||
|
||||
protected val client = FinTsClientForCustomer(bank, customer, webClient, base64Service, threadPool, object : FinTsClientCallback {
|
||||
override fun enterTan(customer: CustomerData, tanChallenge: TanChallenge): EnterTanResult {
|
||||
val result = callback.enterTan(account, mapper.mapTanChallenge(tanChallenge))
|
||||
|
||||
return mapper.mapEnterTanResult(result, customer)
|
||||
}
|
||||
|
||||
override fun enterTanGeneratorAtc(customer: CustomerData, tanMedium: TanGeneratorTanMedium): EnterTanGeneratorAtcResult {
|
||||
val result = callback.enterTanGeneratorAtc(mapper.mapTanMedium(tanMedium))
|
||||
|
||||
return mapper.mapEnterTanGeneratorAtcResult(result)
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
|
||||
override fun addAccountAsync(callback: (AddAccountResponse) -> Unit) {
|
||||
client.addAccountAsync { response ->
|
||||
val account = mapper.mapAccount(customer, bank)
|
||||
this.account = mapper.mapAccount(customer, bank)
|
||||
val mappedResponse = mapper.mapResponse(account, response)
|
||||
|
||||
callback(mappedResponse)
|
||||
|
|
|
@ -4,8 +4,8 @@ import net.dankito.banking.ui.model.*
|
|||
import net.dankito.banking.ui.model.responses.AddAccountResponse
|
||||
import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||
import net.dankito.banking.ui.model.responses.GetTransactionsResponse
|
||||
import net.dankito.banking.ui.model.tan.*
|
||||
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
|
||||
|
@ -16,6 +16,40 @@ import java.math.BigDecimal
|
|||
|
||||
open class fints4javaModelMapper {
|
||||
|
||||
|
||||
open fun mapResponse(response: FinTsClientResponse): BankingClientResponse {
|
||||
return BankingClientResponse(response.isSuccessful, mapErrorToShowToUser(response))
|
||||
}
|
||||
|
||||
open fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse {
|
||||
var bookedTransactions = mapOf<BankAccount, List<AccountTransaction>>()
|
||||
var balances = mapOf<BankAccount, BigDecimal>()
|
||||
|
||||
account.bankAccounts.firstOrNull()?.let { bankAccount -> // TODO: set bank account also on net.dankito.fints.response.client.GetTransactionsResponse
|
||||
bookedTransactions = mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions))
|
||||
response.balance?.let { balances = mapOf(bankAccount to it) }
|
||||
}
|
||||
|
||||
return AddAccountResponse(response.isSuccessful, mapErrorToShowToUser(response),
|
||||
account, response.supportsRetrievingTransactionsOfLast90DaysWithoutTan,
|
||||
bookedTransactions,
|
||||
mapOf(), // TODO: map unbooked transactions
|
||||
balances)
|
||||
}
|
||||
|
||||
open fun mapResponse(bankAccount: BankAccount, response: net.dankito.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
|
||||
|
||||
return GetTransactionsResponse(response.isSuccessful, mapErrorToShowToUser(response),
|
||||
mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions)),
|
||||
mapOf(), // TODO: map unbooked transactions
|
||||
response.balance?.let { mapOf(bankAccount to it) } ?: mapOf())
|
||||
}
|
||||
|
||||
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
|
||||
return response.exception?.localizedMessage ?: response.errorsToShowToUser.joinToString("\n")
|
||||
}
|
||||
|
||||
|
||||
open fun mapAccount(customer: CustomerData, bank: BankData): Account {
|
||||
val mappedBank = mapBank(bank)
|
||||
|
||||
|
@ -73,6 +107,7 @@ open class fints4javaModelMapper {
|
|||
)
|
||||
}
|
||||
|
||||
|
||||
open fun mapTanProcedures(tanProcedures: List<net.dankito.fints.model.TanProcedure>): List<TanProcedure> {
|
||||
return tanProcedures.map { mapTanProcedure(it) }
|
||||
}
|
||||
|
@ -107,13 +142,22 @@ open class fints4javaModelMapper {
|
|||
}
|
||||
|
||||
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),
|
||||
mapTanMediumStatus(tanMedium)
|
||||
)
|
||||
}
|
||||
|
||||
return TanMedium(getDisplayNameForTanMedium(tanMedium), status, tanMedium)
|
||||
open fun mapTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium): TanGeneratorTanMedium {
|
||||
return TanGeneratorTanMedium(
|
||||
getDisplayNameForTanMedium(tanMedium),
|
||||
mapTanMediumStatus(tanMedium),
|
||||
tanMedium.cardNumber
|
||||
)
|
||||
}
|
||||
|
||||
protected open fun getDisplayNameForTanMedium(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): String {
|
||||
if (tanMedium is TanGeneratorTanMedium) {
|
||||
if (tanMedium is net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium) {
|
||||
var cardNumber = tanMedium.cardNumber
|
||||
tanMedium.cardSequenceNumber?.let {
|
||||
cardNumber += " (Kartenfolgenummer $it)" // TODO: translate
|
||||
|
@ -129,49 +173,37 @@ open class fints4javaModelMapper {
|
|||
return tanMedium.mediumClass.name
|
||||
}
|
||||
|
||||
|
||||
open fun mapResponse(response: FinTsClientResponse): BankingClientResponse {
|
||||
return BankingClientResponse(response.isSuccessful, mapErrorToShowToUser(response))
|
||||
open fun mapTanMediumStatus(tanMedium: net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMediumStatus {
|
||||
return if (tanMedium.status.name.contains("aktiv", true)) TanMediumStatus.Used else TanMediumStatus.Available
|
||||
}
|
||||
|
||||
open fun mapResponse(account: Account, response: net.dankito.fints.response.client.AddAccountResponse): AddAccountResponse {
|
||||
var bookedTransactions = mapOf<BankAccount, List<AccountTransaction>>()
|
||||
var balances = mapOf<BankAccount, BigDecimal>()
|
||||
|
||||
account.bankAccounts.firstOrNull()?.let { bankAccount -> // TODO: set bank account also on net.dankito.fints.response.client.GetTransactionsResponse
|
||||
bookedTransactions = mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions))
|
||||
response.balance?.let { balances = mapOf(bankAccount to it) }
|
||||
open fun mapTanMedium(tanMedium: TanMedium, customer: CustomerData): net.dankito.fints.messages.datenelemente.implementierte.tan.TanMedium {
|
||||
if (tanMedium is TanGeneratorTanMedium) {
|
||||
return mapTanMedium(tanMedium, customer)
|
||||
}
|
||||
|
||||
return AddAccountResponse(response.isSuccessful, mapErrorToShowToUser(response),
|
||||
account, response.supportsRetrievingTransactionsOfLast90DaysWithoutTan,
|
||||
bookedTransactions,
|
||||
mapOf(), // TODO: map unbooked transactions
|
||||
balances)
|
||||
val statusToHave = if (tanMedium.status == TanMediumStatus.Used) listOf(net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.Aktiv, net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.AktivFolgekarte)
|
||||
else listOf(net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.Verfuegbar, net.dankito.fints.messages.datenelemente.implementierte.tan.TanMediumStatus.VerfuegbarFolgekarte)
|
||||
|
||||
return customer.tanMedia.first { tanMedium.displayName == it.mediumClass.name && statusToHave.contains(it.status) }
|
||||
}
|
||||
|
||||
open fun mapResponse(bankAccount: BankAccount, response: net.dankito.fints.response.client.GetTransactionsResponse): GetTransactionsResponse {
|
||||
|
||||
return GetTransactionsResponse(response.isSuccessful, mapErrorToShowToUser(response),
|
||||
mapOf(bankAccount to mapTransactions(bankAccount, response.bookedTransactions)),
|
||||
mapOf(), // TODO: map unbooked transactions
|
||||
response.balance?.let { mapOf(bankAccount to it) } ?: mapOf())
|
||||
}
|
||||
|
||||
open fun mapErrorToShowToUser(response: FinTsClientResponse): String? {
|
||||
return response.exception?.localizedMessage ?: response.errorsToShowToUser.joinToString("\n")
|
||||
open fun mapTanMedium(tanMedium: TanGeneratorTanMedium, customer: CustomerData): net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium {
|
||||
return customer.tanMedia.mapNotNull { it as? net.dankito.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium }
|
||||
.first { it.cardNumber == tanMedium.cardNumber
|
||||
&& (it.cardSequenceNumber == null || tanMedium.displayName.contains(it.cardSequenceNumber!!)) }
|
||||
}
|
||||
|
||||
|
||||
open fun mapTanProcedureBack(tanProcedure: TanProcedure): net.dankito.fints.model.TanProcedure {
|
||||
open fun mapTanProcedure(tanProcedure: TanProcedure): net.dankito.fints.model.TanProcedure {
|
||||
return net.dankito.fints.model.TanProcedure(
|
||||
tanProcedure.displayName,
|
||||
Sicherheitsfunktion.values().first { it.code == tanProcedure.bankInternalProcedureCode },
|
||||
mapTanProcedureTypeBack(tanProcedure.type)
|
||||
mapTanProcedureType(tanProcedure.type)
|
||||
)
|
||||
}
|
||||
|
||||
open fun mapTanProcedureTypeBack(type: TanProcedureType): net.dankito.fints.model.TanProcedureType {
|
||||
open fun mapTanProcedureType(type: TanProcedureType): net.dankito.fints.model.TanProcedureType {
|
||||
return when (type) {
|
||||
TanProcedureType.EnterTan -> net.dankito.fints.model.TanProcedureType.EnterTan
|
||||
TanProcedureType.ChipTanManuell -> net.dankito.fints.model.TanProcedureType.ChipTanManuell
|
||||
|
@ -183,4 +215,64 @@ open class fints4javaModelMapper {
|
|||
}
|
||||
}
|
||||
|
||||
open fun mapEnterTanResult(result: EnterTanResult, customer: CustomerData): net.dankito.fints.model.EnterTanResult {
|
||||
result.changeTanProcedureTo?.let { changeTanProcedureTo ->
|
||||
return net.dankito.fints.model.EnterTanResult.userAsksToChangeTanProcedure(mapTanProcedure(changeTanProcedureTo))
|
||||
}
|
||||
|
||||
result.changeTanMediumTo?.let { changeTanMediumTo ->
|
||||
val callback: ((FinTsClientResponse) -> Unit)? = if (result.changeTanMediumResultCallback == null) null
|
||||
else { response -> result.changeTanMediumResultCallback?.invoke(mapResponse(response)) }
|
||||
return net.dankito.fints.model.EnterTanResult.userAsksToChangeTanMedium(mapTanMedium(changeTanMediumTo, customer), callback)
|
||||
}
|
||||
|
||||
result.enteredTan?.let { enteredTan ->
|
||||
return net.dankito.fints.model.EnterTanResult.userEnteredTan(enteredTan)
|
||||
}
|
||||
|
||||
return net.dankito.fints.model.EnterTanResult.userDidNotEnterTan()
|
||||
}
|
||||
|
||||
open fun mapEnterTanGeneratorAtcResult(result: EnterTanGeneratorAtcResult): net.dankito.fints.model.EnterTanGeneratorAtcResult {
|
||||
if (result.hasAtcBeenEntered) {
|
||||
return net.dankito.fints.model.EnterTanGeneratorAtcResult.userEnteredAtc(result.tan!!, result.atc!!)
|
||||
}
|
||||
|
||||
return net.dankito.fints.model.EnterTanGeneratorAtcResult.userDidNotEnterTan()
|
||||
}
|
||||
|
||||
open fun mapTanChallenge(tanChallenge: net.dankito.fints.model.TanChallenge): TanChallenge {
|
||||
if (tanChallenge is net.dankito.fints.model.FlickerCodeTanChallenge) {
|
||||
return mapTanChallenge(tanChallenge)
|
||||
}
|
||||
|
||||
if (tanChallenge is net.dankito.fints.model.ImageTanChallenge) {
|
||||
return mapTanChallenge(tanChallenge)
|
||||
}
|
||||
|
||||
return TanChallenge(tanChallenge.messageToShowToUser,
|
||||
mapTanProcedure(tanChallenge.tanProcedure)
|
||||
)
|
||||
}
|
||||
|
||||
open fun mapTanChallenge(tanChallenge: net.dankito.fints.model.FlickerCodeTanChallenge): FlickerCodeTanChallenge {
|
||||
return FlickerCodeTanChallenge(mapFlickerCode(tanChallenge.flickerCode), tanChallenge.messageToShowToUser,
|
||||
mapTanProcedure(tanChallenge.tanProcedure)
|
||||
)
|
||||
}
|
||||
|
||||
open fun mapFlickerCode(flickerCode: net.dankito.fints.tan.FlickerCode): FlickerCode {
|
||||
return FlickerCode(flickerCode.challengeHHD_UC, flickerCode.parsedDataSet, flickerCode.decodingError)
|
||||
}
|
||||
|
||||
open fun mapTanChallenge(tanChallenge: net.dankito.fints.model.ImageTanChallenge): ImageTanChallenge {
|
||||
return ImageTanChallenge(mapTanImage(tanChallenge.image), tanChallenge.messageToShowToUser,
|
||||
mapTanProcedure(tanChallenge.tanProcedure)
|
||||
)
|
||||
}
|
||||
|
||||
open fun mapTanImage(image: net.dankito.fints.tan.TanImage): TanImage {
|
||||
return TanImage(image.mimeType, image.imageBytes, image.decodingError)
|
||||
}
|
||||
|
||||
}
|
|
@ -18,7 +18,7 @@ import net.dankito.fints.response.client.FinTsClientResponse
|
|||
import net.dankito.fints.response.client.GetTanMediaListResponse
|
||||
import net.dankito.fints.response.client.GetTransactionsResponse
|
||||
import net.dankito.fints.response.segments.*
|
||||
import net.dankito.fints.tan.FlickercodeDecoder
|
||||
import net.dankito.fints.tan.FlickerCodeDecoder
|
||||
import net.dankito.fints.tan.TanImageDecoder
|
||||
import net.dankito.fints.transactions.IAccountTransactionsParser
|
||||
import net.dankito.fints.transactions.Mt940AccountTransactionsParser
|
||||
|
@ -648,7 +648,7 @@ open class FinTsClient @JvmOverloads constructor(
|
|||
|
||||
return when (tanProcedure.type) {
|
||||
TanProcedureType.ChipTanOptisch, TanProcedureType.ChipTanManuell ->
|
||||
FlickercodeTanChallenge(FlickercodeDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
|
||||
FlickerCodeTanChallenge(FlickerCodeDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
|
||||
|
||||
TanProcedureType.ChipTanQrCode, TanProcedureType.PhotoTan ->
|
||||
ImageTanChallenge(TanImageDecoder().decodeChallenge(challenge), messageToShowToUser, challenge, tanProcedure, tanResponse.tanMediaIdentifier)
|
||||
|
|
|
@ -3,7 +3,7 @@ package net.dankito.fints.messages.datenelemente.implementierte.tan
|
|||
import java.util.*
|
||||
|
||||
|
||||
class TanGeneratorTanMedium(
|
||||
open class TanGeneratorTanMedium(
|
||||
mediumClass: TanMediumKlasse,
|
||||
status: TanMediumStatus,
|
||||
val cardNumber: String,
|
||||
|
|
|
@ -25,7 +25,7 @@ open class EnterTanResult protected constructor(
|
|||
return EnterTanResult(null, changeTanProcedureTo)
|
||||
}
|
||||
|
||||
fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: (FinTsClientResponse) -> Unit): EnterTanResult {
|
||||
fun userAsksToChangeTanMedium(changeTanMediumTo: TanMedium, changeTanMediumResultCallback: ((FinTsClientResponse) -> Unit)?): EnterTanResult {
|
||||
return EnterTanResult(null, null, changeTanMediumTo, changeTanMediumResultCallback)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package net.dankito.fints.model
|
||||
|
||||
import net.dankito.fints.tan.Flickercode
|
||||
import net.dankito.fints.tan.FlickerCode
|
||||
|
||||
|
||||
open class FlickercodeTanChallenge(
|
||||
val flickercode: Flickercode,
|
||||
open class FlickerCodeTanChallenge(
|
||||
val flickerCode: FlickerCode,
|
||||
messageToShowToUser: String,
|
||||
challenge: String,
|
||||
tanProcedure: TanProcedure,
|
||||
|
@ -12,7 +12,7 @@ open class FlickercodeTanChallenge(
|
|||
) : TanChallenge(messageToShowToUser, challenge, tanProcedure, tanMediaIdentifier) {
|
||||
|
||||
override fun toString(): String {
|
||||
return "$tanProcedure (medium: $tanMediaIdentifier) $flickercode: $messageToShowToUser"
|
||||
return "$tanProcedure (medium: $tanMediaIdentifier) $flickerCode: $messageToShowToUser"
|
||||
}
|
||||
|
||||
}
|
|
@ -1,15 +1,8 @@
|
|||
package net.dankito.fints.tan
|
||||
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
||||
open class FlickerCanvas(var code: String) {
|
||||
|
||||
companion object {
|
||||
private val log = LoggerFactory.getLogger(FlickerCanvas::class.java)
|
||||
}
|
||||
|
||||
|
||||
var halfbyteid = 0
|
||||
var clock = Bit.High
|
||||
var bitarray = mutableListOf<MutableList<Bit>>()
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package net.dankito.fints.tan
|
||||
|
||||
|
||||
open class Flickercode(
|
||||
open class FlickerCode(
|
||||
val challengeHHD_UC: String,
|
||||
val parsedDataSet: String,
|
||||
val error: Exception? = null
|
||||
val decodingError: Exception? = null
|
||||
) {
|
||||
|
||||
val decodingSuccessful: Boolean
|
||||
get() = error == null
|
||||
get() = decodingError == null
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
if (decodingSuccessful == false) {
|
||||
return "Decoding error: $error"
|
||||
return "Decoding error: $decodingError"
|
||||
}
|
||||
|
||||
return "Parsed $challengeHHD_UC to $parsedDataSet"
|
|
@ -1,10 +1,10 @@
|
|||
package net.dankito.fints.tan
|
||||
|
||||
|
||||
open class FlickercodeDatenelement(
|
||||
open class FlickerCodeDatenelement(
|
||||
val lengthInByte: String,
|
||||
val data: String,
|
||||
val encoding: FlickercodeEncoding,
|
||||
val encoding: FlickerCodeEncoding,
|
||||
val endIndex: Int
|
||||
) {
|
||||
|
|
@ -4,16 +4,16 @@ import org.slf4j.LoggerFactory
|
|||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
open class FlickercodeDecoder {
|
||||
open class FlickerCodeDecoder {
|
||||
|
||||
companion object {
|
||||
val ContainsOtherSymbolsThanFiguresPattern: Pattern = Pattern.compile("\\D")
|
||||
|
||||
private val log = LoggerFactory.getLogger(FlickercodeDecoder::class.java)
|
||||
private val log = LoggerFactory.getLogger(FlickerCodeDecoder::class.java)
|
||||
}
|
||||
|
||||
|
||||
open fun decodeChallenge(challengeHHD_UC: String): Flickercode {
|
||||
open fun decodeChallenge(challengeHHD_UC: String): FlickerCode {
|
||||
try {
|
||||
val challengeLength = parseIntToHex(challengeHHD_UC.substring(0, 2))
|
||||
|
||||
|
@ -40,28 +40,28 @@ open class FlickercodeDecoder {
|
|||
|
||||
val parsedDataSet = dataWithoutChecksum + luhnChecksum + xorChecksumString
|
||||
|
||||
return Flickercode(challengeHHD_UC, parsedDataSet)
|
||||
return FlickerCode(challengeHHD_UC, parsedDataSet)
|
||||
} catch (e: Exception) {
|
||||
log.error("Could not decode challenge $challengeHHD_UC")
|
||||
|
||||
return Flickercode(challengeHHD_UC, "", e)
|
||||
return FlickerCode(challengeHHD_UC, "", e)
|
||||
}
|
||||
}
|
||||
|
||||
protected fun parseStartCode(challengeHHD_UC: String, startIndex: Int): FlickercodeDatenelement {
|
||||
protected open fun parseStartCode(challengeHHD_UC: String, startIndex: Int): FlickerCodeDatenelement {
|
||||
return parseDatenelement(challengeHHD_UC, startIndex) { lengthByteString -> parseIntToHex(lengthByteString) }
|
||||
}
|
||||
|
||||
protected open fun parseDatenelement(code: String, startIndex: Int): FlickercodeDatenelement {
|
||||
protected open fun parseDatenelement(code: String, startIndex: Int): FlickerCodeDatenelement {
|
||||
return parseDatenelement(code, startIndex) { lengthByteString -> lengthByteString.toInt() }
|
||||
}
|
||||
|
||||
protected open fun parseDatenelement(code: String, startIndex: Int, lengthParser: (lengthByteString: String) -> Int): FlickercodeDatenelement {
|
||||
protected open fun parseDatenelement(code: String, startIndex: Int, lengthParser: (lengthByteString: String) -> Int): FlickerCodeDatenelement {
|
||||
val lengthByteLength = 2
|
||||
val dataElementAndRest = code.substring(startIndex)
|
||||
|
||||
if (dataElementAndRest.isEmpty() || dataElementAndRest.length < lengthByteLength) { // data element not set
|
||||
return FlickercodeDatenelement("", "", FlickercodeEncoding.BCD, startIndex)
|
||||
return FlickerCodeDatenelement("", "", FlickerCodeEncoding.BCD, startIndex)
|
||||
}
|
||||
|
||||
val lengthByteString = dataElementAndRest.substring(0, lengthByteLength)
|
||||
|
@ -76,14 +76,14 @@ open class FlickercodeDecoder {
|
|||
// Sollte ein Datenelement eine Zahl mit Komma-Trennung oder Vorzeichen beinhalten (z. B. Betrag oder Anzahl),
|
||||
// so muss als Format ASCII gewählt werden, da ggf. auch ein Sonderzeichen mit übertragen werden muss.
|
||||
if (ContainsOtherSymbolsThanFiguresPattern.matcher(data).find()) {
|
||||
encoding = FlickercodeEncoding.ASCII
|
||||
encoding = FlickerCodeEncoding.ASCII
|
||||
}
|
||||
|
||||
if (encoding == FlickercodeEncoding.ASCII) {
|
||||
if (encoding == FlickerCodeEncoding.ASCII) {
|
||||
data = data.map { toHex(it.toInt(), 2) }.joinToString("")
|
||||
}
|
||||
|
||||
if (encoding == FlickercodeEncoding.BCD && data.length % 2 != 0) {
|
||||
if (encoding == FlickerCodeEncoding.BCD && data.length % 2 != 0) {
|
||||
data += "F" // Im Format BCD ggf. mit „F“ auf Bytegrenze ergänzt
|
||||
}
|
||||
|
||||
|
@ -91,7 +91,7 @@ open class FlickercodeDecoder {
|
|||
|
||||
var lengthInByte = dataLength / 2
|
||||
|
||||
if (encoding == FlickercodeEncoding.ASCII) {
|
||||
if (encoding == FlickerCodeEncoding.ASCII) {
|
||||
if (lengthInByte < 16) {
|
||||
lengthInByte += 16 // set left half byte to '1' for ASCII
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ open class FlickercodeDecoder {
|
|||
|
||||
val lengthInByteString = toHex(lengthInByte, 2)
|
||||
|
||||
return FlickercodeDatenelement(
|
||||
return FlickerCodeDatenelement(
|
||||
lengthInByteString,
|
||||
data,
|
||||
encoding,
|
||||
|
@ -107,8 +107,8 @@ open class FlickercodeDecoder {
|
|||
)
|
||||
}
|
||||
|
||||
protected open fun getEncodingFromLengthByte(engthByte: Int): FlickercodeEncoding {
|
||||
return if (isBitSet(engthByte, 6)) FlickercodeEncoding.ASCII else FlickercodeEncoding.BCD
|
||||
protected open fun getEncodingFromLengthByte(engthByte: Int): FlickerCodeEncoding {
|
||||
return if (isBitSet(engthByte, 6)) FlickerCodeEncoding.ASCII else FlickerCodeEncoding.BCD
|
||||
}
|
||||
|
||||
protected open fun getLengthFromLengthByte(lengthByte: Int): Int {
|
||||
|
@ -116,8 +116,8 @@ open class FlickercodeDecoder {
|
|||
}
|
||||
|
||||
|
||||
protected open fun calculateLuhnChecksum(startCode: FlickercodeDatenelement, controlByte: String,
|
||||
de1: FlickercodeDatenelement, de2: FlickercodeDatenelement, de3: FlickercodeDatenelement): Int {
|
||||
protected open fun calculateLuhnChecksum(startCode: FlickerCodeDatenelement, controlByte: String,
|
||||
de1: FlickerCodeDatenelement, de2: FlickerCodeDatenelement, de3: FlickerCodeDatenelement): Int {
|
||||
|
||||
val luhnData = controlByte + startCode.data + de1.data + de2.data + de3.data
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.fints.tan
|
||||
|
||||
|
||||
enum class FlickercodeEncoding {
|
||||
enum class FlickerCodeEncoding {
|
||||
|
||||
BCD,
|
||||
|
|
@ -4,16 +4,16 @@ package net.dankito.fints.tan
|
|||
open class TanImage(
|
||||
val mimeType: String,
|
||||
val imageBytes: ByteArray,
|
||||
val error: Exception? = null
|
||||
val decodingError: Exception? = null
|
||||
) {
|
||||
|
||||
val decodingSuccessful: Boolean
|
||||
get() = error == null
|
||||
get() = decodingError == null
|
||||
|
||||
|
||||
override fun toString(): String {
|
||||
if (decodingSuccessful == false) {
|
||||
return "Decoding error: $error"
|
||||
return "Decoding error: $decodingError"
|
||||
}
|
||||
|
||||
return "$mimeType ${imageBytes.size} bytes"
|
||||
|
|
|
@ -4,9 +4,9 @@ import org.assertj.core.api.Assertions.assertThat
|
|||
import org.junit.Test
|
||||
|
||||
|
||||
class FlickercodeDecoderTest {
|
||||
class FlickerCodeDecoderTest {
|
||||
|
||||
private val underTest = FlickercodeDecoder()
|
||||
private val underTest = FlickerCodeDecoder()
|
||||
|
||||
|
||||
@Test
|
|
@ -6,4 +6,6 @@ include ':BankListCreator'
|
|||
|
||||
include ':BankingUiCommon'
|
||||
|
||||
include ':fints4javaBankingClient'
|
||||
|
||||
include ':fints4javaAndroidApp'
|
Loading…
Reference in New Issue