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