Made BankingUiCommon a multi platform project
This commit is contained in:
parent
588877cb20
commit
52d3b49baa
|
@ -1,16 +1,17 @@
|
||||||
package net.dankito.banking.persistence
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.Customer
|
||||||
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
|
||||||
import net.dankito.banking.util.ISerializer
|
import net.dankito.banking.util.ISerializer
|
||||||
import net.dankito.banking.util.JacksonJsonSerializer
|
import java.io.FileOutputStream
|
||||||
import java.io.File
|
import java.net.URL
|
||||||
|
|
||||||
|
|
||||||
open class BankingPersistenceJson(
|
open class BankingPersistenceJson(
|
||||||
protected val jsonFile: File,
|
protected val jsonFile: File,
|
||||||
protected val serializer: ISerializer = JacksonJsonSerializer()
|
protected val serializer: ISerializer
|
||||||
) : IBankingPersistence {
|
) : IBankingPersistence {
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,7 +29,7 @@ open class BankingPersistenceJson(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun readPersistedAccounts(): List<Customer> {
|
override fun readPersistedAccounts(): List<Customer> {
|
||||||
return serializer.deserializeListOr(jsonFile, Customer::class.java, listOf())
|
return serializer.deserializeListOr(jsonFile, Customer::class, listOf())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,4 +37,13 @@ open class BankingPersistenceJson(
|
||||||
// done when called saveOrUpdateAccount()
|
// done when called saveOrUpdateAccount()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun saveUrlToFile(url: String, file: File) {
|
||||||
|
URL(url).openConnection().getInputStream().buffered().use { iconInputStream ->
|
||||||
|
FileOutputStream(file).use { fileOutputStream ->
|
||||||
|
iconInputStream.copyTo(fileOutputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -78,9 +78,7 @@ android {
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation project(":fints4k"), {
|
implementation project(":fints4k")
|
||||||
exclude group: "com.soywiz.korlibs.klock", module: "klock-android" // klock-jvm already adds required extensions, to avoid duplicates
|
|
||||||
}
|
|
||||||
|
|
||||||
implementation project(':BankingUiCommon')
|
implementation project(':BankingUiCommon')
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ import android.content.Context
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import dagger.Module
|
import dagger.Module
|
||||||
import dagger.Provides
|
import dagger.Provides
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.ui.android.RouterAndroid
|
import net.dankito.banking.ui.android.RouterAndroid
|
||||||
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
import net.dankito.banking.ui.android.util.CurrentActivityTracker
|
||||||
import net.dankito.banking.ui.android.util.Base64ServiceAndroid
|
|
||||||
import net.dankito.banking.fints4kBankingClientCreator
|
import net.dankito.banking.fints4kBankingClientCreator
|
||||||
import net.dankito.banking.persistence.IBankingPersistence
|
import net.dankito.banking.persistence.IBankingPersistence
|
||||||
import net.dankito.banking.persistence.LuceneBankingPersistence
|
import net.dankito.banking.persistence.LuceneBankingPersistence
|
||||||
|
@ -17,6 +17,7 @@ import net.dankito.banking.ui.IRouter
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.bankfinder.IBankFinder
|
import net.dankito.banking.bankfinder.IBankFinder
|
||||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||||
|
import net.dankito.utils.multiplatform.toFile
|
||||||
import net.dankito.banking.util.*
|
import net.dankito.banking.util.*
|
||||||
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
|
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
|
||||||
import net.dankito.banking.util.extraction.ITextExtractorRegistry
|
import net.dankito.banking.util.extraction.ITextExtractorRegistry
|
||||||
|
@ -28,7 +29,6 @@ import net.dankito.text.extraction.pdf.iText2PdfTextExtractor
|
||||||
import net.dankito.utils.ThreadPool
|
import net.dankito.utils.ThreadPool
|
||||||
import net.dankito.utils.web.client.IWebClient
|
import net.dankito.utils.web.client.IWebClient
|
||||||
import net.dankito.utils.web.client.OkHttpWebClient
|
import net.dankito.utils.web.client.OkHttpWebClient
|
||||||
import java.io.File
|
|
||||||
import javax.inject.Named
|
import javax.inject.Named
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
@Singleton
|
@Singleton
|
||||||
@Named(DataFolderKey)
|
@Named(DataFolderKey)
|
||||||
fun provideDataFolder(applicationContext: Context) : File {
|
fun provideDataFolder(applicationContext: Context) : File {
|
||||||
return ensureFolderExists(applicationContext.filesDir, "data")
|
return ensureFolderExists(applicationContext.filesDir.toFile(), "data")
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -93,7 +93,7 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
|
textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
|
||||||
serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
|
serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
|
||||||
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister,
|
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister,
|
||||||
remitteeSearcher, bankIconFinder, textExtractorRegistry, router, invoiceDataExtractor, serializer, asyncRunner)
|
router, remitteeSearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, serializer, asyncRunner)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@ -110,8 +110,8 @@ class BankingModule(private val applicationContext: Context) {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
fun provideBankingClientCreator() : IBankingClientCreator {
|
fun provideBankingClientCreator(serializer: ISerializer) : IBankingClientCreator {
|
||||||
return fints4kBankingClientCreator()
|
return fints4kBankingClientCreator(serializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
@ -24,7 +24,6 @@ import net.dankito.banking.ui.android.extensions.closePopupOnBackButtonPress
|
||||||
import net.dankito.banking.ui.android.listener.ListItemSelectedListener
|
import net.dankito.banking.ui.android.listener.ListItemSelectedListener
|
||||||
import net.dankito.banking.ui.android.util.StandardAutocompleteCallback
|
import net.dankito.banking.ui.android.util.StandardAutocompleteCallback
|
||||||
import net.dankito.banking.ui.android.util.StandardTextWatcher
|
import net.dankito.banking.ui.android.util.StandardTextWatcher
|
||||||
import net.dankito.banking.search.IRemitteeSearcher
|
|
||||||
import net.dankito.banking.search.Remittee
|
import net.dankito.banking.search.Remittee
|
||||||
import net.dankito.banking.ui.model.BankAccount
|
import net.dankito.banking.ui.model.BankAccount
|
||||||
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
import net.dankito.banking.ui.model.parameters.TransferMoneyData
|
||||||
|
@ -32,6 +31,7 @@ import net.dankito.banking.ui.model.responses.BankingClientResponse
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.util.InputValidator
|
import net.dankito.banking.util.InputValidator
|
||||||
import net.dankito.banking.bankfinder.BankInfo
|
import net.dankito.banking.bankfinder.BankInfo
|
||||||
|
import net.dankito.utils.multiplatform.toBigDecimal
|
||||||
import net.dankito.utils.android.extensions.asActivity
|
import net.dankito.utils.android.extensions.asActivity
|
||||||
import java.math.BigDecimal
|
import java.math.BigDecimal
|
||||||
import java.text.DecimalFormatSymbols
|
import java.text.DecimalFormatSymbols
|
||||||
|
@ -242,7 +242,7 @@ open class TransferMoneyDialog : DialogFragment() {
|
||||||
inputValidator.convertToAllowedSepaCharacters(edtxtRemitteeName.text.toString()),
|
inputValidator.convertToAllowedSepaCharacters(edtxtRemitteeName.text.toString()),
|
||||||
edtxtRemitteeIban.text.toString().replace(" ", ""),
|
edtxtRemitteeIban.text.toString().replace(" ", ""),
|
||||||
edtxtRemitteeBic.text.toString().replace(" ", ""),
|
edtxtRemitteeBic.text.toString().replace(" ", ""),
|
||||||
amount,
|
amount.toBigDecimal(),
|
||||||
inputValidator.convertToAllowedSepaCharacters(edtxtUsage.text.toString()),
|
inputValidator.convertToAllowedSepaCharacters(edtxtUsage.text.toString()),
|
||||||
chkbxInstantPayment.isChecked
|
chkbxInstantPayment.isChecked
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
package net.dankito.banking.ui.android.util
|
|
||||||
|
|
||||||
import android.util.Base64
|
|
||||||
import net.dankito.banking.util.IBase64Service
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
|
|
||||||
open class Base64ServiceAndroid : IBase64Service {
|
|
||||||
|
|
||||||
override fun encode(text: String, charset: Charset): String {
|
|
||||||
val bytes = text.toByteArray(charset)
|
|
||||||
|
|
||||||
return Base64.encodeToString(bytes, Base64.NO_WRAP)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun decode(base64: String, charset: Charset): String {
|
|
||||||
val decoded = Base64.decode(base64, Base64.NO_WRAP)
|
|
||||||
|
|
||||||
return String(decoded, charset)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -7,6 +7,7 @@ import androidx.fragment.app.FragmentActivity
|
||||||
import com.github.clans.fab.FloatingActionButton
|
import com.github.clans.fab.FloatingActionButton
|
||||||
import com.github.clans.fab.FloatingActionMenu
|
import com.github.clans.fab.FloatingActionMenu
|
||||||
import kotlinx.android.synthetic.main.view_floating_action_button_main.view.*
|
import kotlinx.android.synthetic.main.view_floating_action_button_main.view.*
|
||||||
|
import net.dankito.utils.multiplatform.toFile
|
||||||
import net.dankito.banking.ui.android.R
|
import net.dankito.banking.ui.android.R
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
||||||
|
@ -78,7 +79,7 @@ open class MainActivityFloatingActionMenuButton(
|
||||||
selectedFile?.let {
|
selectedFile?.let {
|
||||||
lastSelectedFolder = selectedFile.parentFile
|
lastSelectedFolder = selectedFile.parentFile
|
||||||
|
|
||||||
val result = presenter.transferMoneyWithDataFromPdf(selectedFile)
|
val result = presenter.transferMoneyWithDataFromPdf(selectedFile.toFile())
|
||||||
|
|
||||||
if (result.type != ExtractTransferMoneyDataFromPdfResultType.Success) {
|
if (result.type != ExtractTransferMoneyDataFromPdfResultType.Success) {
|
||||||
showTransferMoneyWithDataFromPdfError(activity, selectedFile, result)
|
showTransferMoneyWithDataFromPdfError(activity, selectedFile, result)
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
package net.dankito.banking.ui.javafx.dialogs.mainwindow
|
package net.dankito.banking.ui.javafx.dialogs.mainwindow
|
||||||
|
|
||||||
import javafx.scene.control.SplitPane
|
import javafx.scene.control.SplitPane
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.fints4kBankingClientCreator
|
import net.dankito.banking.fints4kBankingClientCreator
|
||||||
import net.dankito.banking.ui.javafx.RouterJavaFx
|
import net.dankito.banking.ui.javafx.RouterJavaFx
|
||||||
import net.dankito.banking.ui.javafx.controls.AccountTransactionsView
|
import net.dankito.banking.ui.javafx.controls.AccountTransactionsView
|
||||||
import net.dankito.banking.ui.javafx.controls.AccountsView
|
import net.dankito.banking.ui.javafx.controls.AccountsView
|
||||||
import net.dankito.banking.ui.javafx.dialogs.mainwindow.controls.MainMenuBar
|
import net.dankito.banking.ui.javafx.dialogs.mainwindow.controls.MainMenuBar
|
||||||
import net.dankito.banking.ui.javafx.util.Base64ServiceJava8
|
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.util.BankIconFinder
|
import net.dankito.banking.util.BankIconFinder
|
||||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||||
import net.dankito.banking.persistence.LuceneBankingPersistence
|
import net.dankito.banking.persistence.LuceneBankingPersistence
|
||||||
import net.dankito.banking.search.LuceneRemitteeSearcher
|
import net.dankito.banking.search.LuceneRemitteeSearcher
|
||||||
|
import net.dankito.banking.util.JacksonJsonSerializer
|
||||||
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
|
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
|
||||||
import net.dankito.text.extraction.TextExtractorRegistry
|
import net.dankito.text.extraction.TextExtractorRegistry
|
||||||
import net.dankito.text.extraction.TikaTextExtractor
|
import net.dankito.text.extraction.TikaTextExtractor
|
||||||
|
@ -19,10 +20,8 @@ import net.dankito.text.extraction.image.Tesseract4CommandlineImageTextExtractor
|
||||||
import net.dankito.text.extraction.image.model.OcrLanguage
|
import net.dankito.text.extraction.image.model.OcrLanguage
|
||||||
import net.dankito.text.extraction.image.model.TesseractConfig
|
import net.dankito.text.extraction.image.model.TesseractConfig
|
||||||
import net.dankito.text.extraction.pdf.*
|
import net.dankito.text.extraction.pdf.*
|
||||||
import net.dankito.utils.web.client.OkHttpWebClient
|
|
||||||
import tornadofx.*
|
import tornadofx.*
|
||||||
import tornadofx.FX.Companion.messages
|
import tornadofx.FX.Companion.messages
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
class MainWindow : View(messages["application.title"]) {
|
class MainWindow : View(messages["application.title"]) {
|
||||||
|
@ -33,6 +32,8 @@ class MainWindow : View(messages["application.title"]) {
|
||||||
|
|
||||||
private val indexFolder = ensureFolderExists(dataFolder, "index")
|
private val indexFolder = ensureFolderExists(dataFolder, "index")
|
||||||
|
|
||||||
|
private val serializer = JacksonJsonSerializer()
|
||||||
|
|
||||||
private val tesseractTextExtractor = Tesseract4CommandlineImageTextExtractor(TesseractConfig(listOf(OcrLanguage.English, OcrLanguage.German)))
|
private val tesseractTextExtractor = Tesseract4CommandlineImageTextExtractor(TesseractConfig(listOf(OcrLanguage.English, OcrLanguage.German)))
|
||||||
|
|
||||||
private val textExtractorRegistry = JavaTextExtractorRegistry(TextExtractorRegistry(pdffontsPdfTypeDetector(), listOf(
|
private val textExtractorRegistry = JavaTextExtractorRegistry(TextExtractorRegistry(pdffontsPdfTypeDetector(), listOf(
|
||||||
|
@ -41,12 +42,12 @@ class MainWindow : View(messages["application.title"]) {
|
||||||
tesseractTextExtractor, TikaTextExtractor()
|
tesseractTextExtractor, TikaTextExtractor()
|
||||||
)))
|
)))
|
||||||
|
|
||||||
private val presenter = BankingPresenter(fints4kBankingClientCreator(),
|
private val presenter = BankingPresenter(fints4kBankingClientCreator(serializer),
|
||||||
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
|
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
|
||||||
LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry, RouterJavaFx())
|
RouterJavaFx(), LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry)
|
||||||
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),
|
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),
|
||||||
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), LuceneRemitteeSearcher(indexFolder),
|
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), RouterJavaFx(), LuceneRemitteeSearcher(indexFolder),
|
||||||
// BankIconFinder(), textExtractorRegistry, RouterJavaFx())
|
// BankIconFinder(), textExtractorRegistry)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import javafx.scene.input.KeyCode
|
||||||
import javafx.scene.input.KeyCodeCombination
|
import javafx.scene.input.KeyCodeCombination
|
||||||
import javafx.scene.input.KeyCombination
|
import javafx.scene.input.KeyCombination
|
||||||
import javafx.stage.FileChooser
|
import javafx.stage.FileChooser
|
||||||
|
import net.dankito.utils.multiplatform.toFile
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
||||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
|
@ -79,7 +80,7 @@ open class MainMenuBar(protected val presenter: BankingPresenter) : View() {
|
||||||
fileChooser.showOpenDialog(currentStage)?.let { pdfFile ->
|
fileChooser.showOpenDialog(currentStage)?.let { pdfFile ->
|
||||||
lastSelectedFolder = pdfFile.parentFile
|
lastSelectedFolder = pdfFile.parentFile
|
||||||
|
|
||||||
val result = presenter.transferMoneyWithDataFromPdf(pdfFile)
|
val result = presenter.transferMoneyWithDataFromPdf(pdfFile.toFile())
|
||||||
|
|
||||||
if (result.type != ExtractTransferMoneyDataFromPdfResultType.Success) {
|
if (result.type != ExtractTransferMoneyDataFromPdfResultType.Success) {
|
||||||
showTransferMoneyWithDataFromPdfError(pdfFile, result)
|
showTransferMoneyWithDataFromPdfError(pdfFile, result)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import net.dankito.banking.ui.presenter.BankingPresenter
|
||||||
import net.dankito.banking.util.InputValidator
|
import net.dankito.banking.util.InputValidator
|
||||||
import net.dankito.banking.bankfinder.BankInfo
|
import net.dankito.banking.bankfinder.BankInfo
|
||||||
import net.dankito.banking.search.Remittee
|
import net.dankito.banking.search.Remittee
|
||||||
|
import net.dankito.utils.multiplatform.toBigDecimal
|
||||||
import net.dankito.banking.ui.javafx.extensions.focusNextControl
|
import net.dankito.banking.ui.javafx.extensions.focusNextControl
|
||||||
import net.dankito.utils.javafx.ui.controls.AutoCompletionSearchTextField
|
import net.dankito.utils.javafx.ui.controls.AutoCompletionSearchTextField
|
||||||
import net.dankito.utils.javafx.ui.controls.autocompletionsearchtextfield
|
import net.dankito.utils.javafx.ui.controls.autocompletionsearchtextfield
|
||||||
|
@ -352,7 +353,7 @@ open class TransferMoneyDialog @JvmOverloads constructor(
|
||||||
inputValidator.convertToAllowedSepaCharacters(remitteeName.value),
|
inputValidator.convertToAllowedSepaCharacters(remitteeName.value),
|
||||||
remitteeIban.value.replace(" ", ""),
|
remitteeIban.value.replace(" ", ""),
|
||||||
remitteeBic.value.replace(" ", ""),
|
remitteeBic.value.replace(" ", ""),
|
||||||
amount.value.toBigDecimal(),
|
amount.value.toBigDecimal().toBigDecimal(),
|
||||||
inputValidator.convertToAllowedSepaCharacters(usage.value),
|
inputValidator.convertToAllowedSepaCharacters(usage.value),
|
||||||
instantPayment.value
|
instantPayment.value
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,41 +1,165 @@
|
||||||
apply plugin: 'java-library'
|
plugins {
|
||||||
apply plugin: 'kotlin'
|
id "org.jetbrains.kotlin.multiplatform"
|
||||||
|
id "com.android.library"
|
||||||
|
id "maven-publish"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ext.artifactName = "banking-ui-common"
|
ext.artifactName = "banking-ui-common"
|
||||||
|
|
||||||
|
|
||||||
sourceCompatibility = "1.7"
|
kotlin {
|
||||||
targetCompatibility = "1.7"
|
jvm {
|
||||||
|
compilations.main.kotlinOptions {
|
||||||
|
jvmTarget = "1.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compileKotlin {
|
targets {
|
||||||
kotlinOptions.jvmTarget = "1.6"
|
// Select iOS target for real device or emulator.
|
||||||
}
|
final def iOSIsRealDevice = System.getenv('SDK_NAME')?.startsWith("iphoneos")
|
||||||
compileTestKotlin {
|
final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
|
||||||
kotlinOptions.jvmTarget = "1.6"
|
|
||||||
|
// iOS target.
|
||||||
|
fromPreset(iOSTarget, 'ios') {
|
||||||
|
binaries {
|
||||||
|
framework {
|
||||||
|
baseName = "BankingUiCommon"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
commonMain {
|
||||||
|
dependencies {
|
||||||
|
api kotlin("stdlib-common")
|
||||||
|
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinCoroutinesVersion"
|
||||||
|
|
||||||
|
// TODO: try to get rid of this import
|
||||||
|
api project(":fints4k")
|
||||||
|
|
||||||
|
api project(":BankFinder")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
commonTest {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("test-common")
|
||||||
|
implementation kotlin("test-annotations-common")
|
||||||
|
|
||||||
|
implementation "ch.tutteli.atrium:atrium-fluent-en_GB:$atriumVersion"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
jvmMain {
|
||||||
|
dependencies {
|
||||||
|
api "net.dankito.utils:java-utils:$javaUtilsVersion"
|
||||||
|
|
||||||
|
api "net.dankito.text.extraction:text-extractor-common:$textExtractorVersion"
|
||||||
|
api "net.dankito.text.extraction:text-info-extractor:$textInfoExtractorVersion"
|
||||||
|
|
||||||
|
implementation "net.dankito.utils:favicon-finder:1.0.0-SNAPSHOT"
|
||||||
|
|
||||||
|
implementation "org.jsoup:jsoup:1.13.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jvmTest {
|
||||||
|
dependencies {
|
||||||
|
implementation kotlin("test-junit")
|
||||||
|
|
||||||
|
implementation "junit:junit:$junitVersion"
|
||||||
|
// implementation "org.junit.jupiter:junit-jupiter:$junit5Version"
|
||||||
|
// runtimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit5Version"
|
||||||
|
|
||||||
|
implementation "org.assertj:assertj-core:$assertJVersion"
|
||||||
|
implementation "org.mockito:mockito-core:$mockitoVersion"
|
||||||
|
|
||||||
|
implementation "ch.tutteli.atrium:atrium-api-fluent-en_GB-jdk8:$atriumVersion"
|
||||||
|
|
||||||
|
implementation "org.slf4j:slf4j-simple:$slf4jVersion"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
iosMain {
|
||||||
|
dependencies {
|
||||||
|
api "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
||||||
|
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$kotlinCoroutinesVersion"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
// Task to generate iOS framework for xcode projects.
|
||||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
task packForXCode(type: Sync) {
|
||||||
|
|
||||||
api "net.dankito.utils:java-utils:$javaUtilsVersion"
|
final File frameworkDir = new File(buildDir, "xcode-frameworks")
|
||||||
|
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
|
||||||
|
|
||||||
api project(":BankFinder")
|
final def framework = kotlin.targets.ios.binaries.getFramework("", mode)
|
||||||
|
|
||||||
api "net.dankito.text.extraction:text-extractor-common:$textExtractorVersion"
|
inputs.property "mode", mode
|
||||||
api "net.dankito.text.extraction:text-info-extractor:$textInfoExtractorVersion"
|
dependsOn framework.linkTask
|
||||||
|
|
||||||
implementation "net.dankito.utils:favicon-finder:1.0.0-SNAPSHOT"
|
from { framework.outputFile.parentFile }
|
||||||
|
into frameworkDir
|
||||||
|
|
||||||
implementation "org.jsoup:jsoup:1.13.1"
|
doLast {
|
||||||
|
new File(frameworkDir, 'gradlew').with {
|
||||||
|
text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
|
||||||
|
setExecutable(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: try to get rid of this import
|
// Run packForXCode when building.
|
||||||
api project(':fints4k')
|
tasks.build.dependsOn packForXCode
|
||||||
|
|
||||||
|
|
||||||
testImplementation "junit:junit:$junitVersion"
|
android {
|
||||||
testImplementation "org.assertj:assertj-core:$assertJVersion"
|
compileSdkVersion androidCompileSdkVersion
|
||||||
|
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion androidMinSdkVersion
|
||||||
|
targetSdkVersion androidTargetSdkVersion
|
||||||
|
|
||||||
|
versionName version
|
||||||
|
versionCode appVersionCode
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
packagingOptions {
|
||||||
|
pickFirst 'META-INF/ktor-http.kotlin_module'
|
||||||
|
pickFirst 'META-INF/kotlinx-io.kotlin_module'
|
||||||
|
pickFirst 'META-INF/atomicfu.kotlin_module'
|
||||||
|
pickFirst 'META-INF/ktor-utils.kotlin_module'
|
||||||
|
pickFirst 'META-INF/kotlinx-coroutines-io.kotlin_module'
|
||||||
|
pickFirst 'META-INF/ktor-client-core.kotlin_module'
|
||||||
|
pickFirst 'META-INF/DEPENDENCIES'
|
||||||
|
pickFirst 'META-INF/NOTICE'
|
||||||
|
pickFirst 'META-INF/LICENSE'
|
||||||
|
pickFirst 'META-INF/LICENSE.txt'
|
||||||
|
pickFirst 'META-INF/NOTICE.txt'
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
|
||||||
testImplementation "org.slf4j:slf4j-simple:$slf4jVersion"
|
|
||||||
}
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package net.dankito.banking.persistence
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.Customer
|
||||||
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
|
||||||
|
@ -16,4 +17,6 @@ interface IBankingPersistence {
|
||||||
|
|
||||||
fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>)
|
fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>)
|
||||||
|
|
||||||
|
fun saveUrlToFile(url: String, file: File)
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package net.dankito.banking.persistence
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.AccountTransaction
|
||||||
|
import net.dankito.banking.ui.model.BankAccount
|
||||||
|
import net.dankito.banking.ui.model.Customer
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
|
||||||
|
|
||||||
|
open class NoOpBankingPersistence : IBankingPersistence {
|
||||||
|
|
||||||
|
override fun saveOrUpdateAccount(customer: Customer, allCustomers: List<Customer>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deleteAccount(customer: Customer, allCustomers: List<Customer>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun readPersistedAccounts(): List<Customer> {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun saveOrUpdateAccountTransactions(bankAccount: BankAccount, transactions: List<AccountTransaction>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun saveUrlToFile(url: String, file: File) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package net.dankito.banking.search
|
||||||
|
|
||||||
|
|
||||||
|
open class NoOpRemitteeSearcher : IRemitteeSearcher {
|
||||||
|
|
||||||
|
override fun findRemittees(query: String): List<Remittee> {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package net.dankito.banking.ui
|
package net.dankito.banking.ui
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.banking.bankfinder.BankInfo
|
import net.dankito.banking.bankfinder.BankInfo
|
||||||
import net.dankito.banking.util.IAsyncRunner
|
import net.dankito.banking.util.IAsyncRunner
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
interface IBankingClientCreator {
|
interface IBankingClientCreator {
|
|
@ -1,14 +1,14 @@
|
||||||
package net.dankito.banking.ui.model
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
//import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
//import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||||
import java.math.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import java.text.DateFormat
|
import net.dankito.utils.multiplatform.Date
|
||||||
import java.text.SimpleDateFormat
|
import net.dankito.utils.multiplatform.DateFormatStyle
|
||||||
import java.util.*
|
import net.dankito.utils.multiplatform.DateFormatter
|
||||||
|
|
||||||
|
|
||||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
//@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||||
open class AccountTransaction(
|
open class AccountTransaction(
|
||||||
open val bankAccount: BankAccount,
|
open val bankAccount: BankAccount,
|
||||||
open val amount: BigDecimal,
|
open val amount: BigDecimal,
|
||||||
|
@ -50,7 +50,7 @@ open class AccountTransaction(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val IdDateFormat = SimpleDateFormat("yyyy.MM.dd")
|
val IdDateFormat = DateFormatter("yyyy.MM.dd")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ open class AccountTransaction(
|
||||||
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
|
||||||
|
|
||||||
// for object deserializers
|
// for object deserializers
|
||||||
internal constructor() : this(BankAccount(), BigDecimal.ZERO, "","", Date(), null, null, null, null, Date(), 0, null, BigDecimal.ZERO, BigDecimal.ZERO,
|
internal constructor() : this(BankAccount(), BigDecimal.Zero, "","", Date(), null, null, null, null, Date(), 0, null, BigDecimal.Zero, BigDecimal.Zero,
|
||||||
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
null, null, null, null, null, null, null, null, null, null, null, null, null,
|
||||||
null, "", "", null, null, "", null)
|
null, "", "", null, null, "", null)
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ open class AccountTransaction(
|
||||||
if (other !is AccountTransaction) return false
|
if (other !is AccountTransaction) return false
|
||||||
|
|
||||||
if (bankAccount != other.bankAccount) return false
|
if (bankAccount != other.bankAccount) return false
|
||||||
if (amount.compareTo(other.amount) != 0) return false
|
if (amount != other) return false // TODO: does this work?
|
||||||
if (currency != other.currency) return false
|
if (currency != other.currency) return false
|
||||||
if (unparsedUsage != other.unparsedUsage) return false
|
if (unparsedUsage != other.unparsedUsage) return false
|
||||||
if (bookingDate != other.bookingDate) return false
|
if (bookingDate != other.bookingDate) return false
|
||||||
|
@ -108,7 +108,7 @@ open class AccountTransaction(
|
||||||
|
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "${DateFormat.getDateInstance(DateFormat.MEDIUM).format(valueDate)} $amount $otherPartyName: $usage"
|
return "${DateFormatter(DateFormatStyle.Medium).format(valueDate)} $amount $otherPartyName: $usage"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,12 +1,14 @@
|
||||||
package net.dankito.banking.ui.model
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
//import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
//import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||||
import java.math.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import java.util.*
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
import kotlin.jvm.JvmOverloads
|
||||||
|
|
||||||
|
|
||||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
//@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||||
open class BankAccount @JvmOverloads constructor(
|
open class BankAccount @JvmOverloads constructor(
|
||||||
open val customer: Customer,
|
open val customer: Customer,
|
||||||
open val identifier: String,
|
open val identifier: String,
|
||||||
|
@ -14,7 +16,7 @@ open class BankAccount @JvmOverloads constructor(
|
||||||
open var iban: String?,
|
open var iban: String?,
|
||||||
open var subAccountNumber: String?,
|
open var subAccountNumber: String?,
|
||||||
open val customerId: String,
|
open val customerId: String,
|
||||||
open var balance: BigDecimal = BigDecimal.ZERO,
|
open var balance: BigDecimal = BigDecimal.Zero,
|
||||||
open var currency: String = "EUR",
|
open var currency: String = "EUR",
|
||||||
open var type: BankAccountType = BankAccountType.Girokonto,
|
open var type: BankAccountType = BankAccountType.Girokonto,
|
||||||
open val productName: String? = null,
|
open val productName: String? = null,
|
||||||
|
@ -30,7 +32,7 @@ open class BankAccount @JvmOverloads constructor(
|
||||||
internal constructor() : this(Customer(), "", "", null, null, "") // for object deserializers
|
internal constructor() : this(Customer(), "", "", null, null, "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
open var id: String = UUID.randomUUID().toString()
|
open var id: String = UUID.random()
|
||||||
|
|
||||||
|
|
||||||
open val displayName: String
|
open val displayName: String
|
|
@ -1,15 +1,16 @@
|
||||||
package net.dankito.banking.ui.model
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
//import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
//import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
import net.dankito.utils.multiplatform.UUID
|
||||||
|
import net.dankito.utils.multiplatform.sum
|
||||||
import net.dankito.banking.ui.model.tan.TanMedium
|
import net.dankito.banking.ui.model.tan.TanMedium
|
||||||
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
import net.dankito.banking.ui.model.tan.TanMediumStatus
|
||||||
import net.dankito.banking.ui.model.tan.TanProcedure
|
import net.dankito.banking.ui.model.tan.TanProcedure
|
||||||
import java.math.BigDecimal
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
//@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
|
||||||
open class Customer(
|
open class Customer(
|
||||||
val bankCode: String,
|
val bankCode: String,
|
||||||
val customerId: String,
|
val customerId: String,
|
||||||
|
@ -27,7 +28,7 @@ open class Customer(
|
||||||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||||
|
|
||||||
|
|
||||||
var id: String = UUID.randomUUID().toString()
|
var id: String = UUID.random()
|
||||||
|
|
||||||
|
|
||||||
var supportedTanProcedures: List<TanProcedure> = listOf()
|
var supportedTanProcedures: List<TanProcedure> = listOf()
|
||||||
|
@ -44,7 +45,7 @@ open class Customer(
|
||||||
get() = bankName
|
get() = bankName
|
||||||
|
|
||||||
val balance: BigDecimal
|
val balance: BigDecimal
|
||||||
get() = accounts.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
get() = accounts.map { it.balance }.sum()
|
||||||
|
|
||||||
val transactions: List<AccountTransaction>
|
val transactions: List<AccountTransaction>
|
||||||
get() = accounts.flatMap { it.bookedTransactions }
|
get() = accounts.flatMap { it.bookedTransactions }
|
|
@ -1,6 +1,6 @@
|
||||||
package net.dankito.banking.ui.model
|
package net.dankito.banking.ui.model
|
||||||
|
|
||||||
import java.util.*
|
import net.dankito.utils.multiplatform.Date
|
||||||
|
|
||||||
|
|
||||||
open class MessageLogEntry(
|
open class MessageLogEntry(
|
|
@ -1,7 +1,7 @@
|
||||||
package net.dankito.banking.ui.model.parameters
|
package net.dankito.banking.ui.model.parameters
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.Date
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.AccountTransaction
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
|
|
||||||
open class GetTransactionsParameter(
|
open class GetTransactionsParameter(
|
|
@ -1,7 +1,7 @@
|
||||||
package net.dankito.banking.ui.model.parameters
|
package net.dankito.banking.ui.model.parameters
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.banking.ui.model.AccountTransaction
|
import net.dankito.banking.ui.model.AccountTransaction
|
||||||
import java.math.BigDecimal
|
|
||||||
|
|
||||||
|
|
||||||
open class TransferMoneyData(
|
open class TransferMoneyData(
|
||||||
|
@ -20,7 +20,7 @@ open class TransferMoneyData(
|
||||||
transaction.otherPartyName ?: "",
|
transaction.otherPartyName ?: "",
|
||||||
transaction.otherPartyAccountId ?: "",
|
transaction.otherPartyAccountId ?: "",
|
||||||
transaction.otherPartyBankCode ?: "",
|
transaction.otherPartyBankCode ?: "",
|
||||||
BigDecimal.ZERO,
|
BigDecimal.Zero,
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
package net.dankito.banking.ui.model.responses
|
package net.dankito.banking.ui.model.responses
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
import net.dankito.banking.ui.model.Customer
|
import net.dankito.banking.ui.model.Customer
|
||||||
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
|
||||||
import java.math.BigDecimal
|
|
||||||
|
|
||||||
|
|
||||||
open class AddAccountResponse(
|
open class AddAccountResponse(
|
|
@ -1,8 +1,8 @@
|
||||||
package net.dankito.banking.ui.model.responses
|
package net.dankito.banking.ui.model.responses
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
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
|
||||||
import java.math.BigDecimal
|
|
||||||
|
|
||||||
|
|
||||||
open class GetTransactionsResponse(
|
open class GetTransactionsResponse(
|
|
@ -17,6 +17,7 @@ import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
|
||||||
import net.dankito.banking.bankfinder.IBankFinder
|
import net.dankito.banking.bankfinder.IBankFinder
|
||||||
import net.dankito.banking.bankfinder.BankInfo
|
import net.dankito.banking.bankfinder.BankInfo
|
||||||
import net.dankito.banking.search.IRemitteeSearcher
|
import net.dankito.banking.search.IRemitteeSearcher
|
||||||
|
import net.dankito.banking.search.NoOpRemitteeSearcher
|
||||||
import net.dankito.banking.search.Remittee
|
import net.dankito.banking.search.Remittee
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
||||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
||||||
|
@ -25,14 +26,10 @@ import net.dankito.banking.ui.model.settings.AppSettings
|
||||||
import net.dankito.banking.util.*
|
import net.dankito.banking.util.*
|
||||||
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
|
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
|
||||||
import net.dankito.banking.util.extraction.ITextExtractorRegistry
|
import net.dankito.banking.util.extraction.ITextExtractorRegistry
|
||||||
import net.dankito.banking.util.extraction.JavaInvoiceDataExtractor
|
import net.dankito.banking.util.extraction.NoOpInvoiceDataExtractor
|
||||||
import org.slf4j.LoggerFactory
|
import net.dankito.banking.util.extraction.NoOpTextExtractorRegistry
|
||||||
import java.io.File
|
import net.dankito.utils.multiplatform.*
|
||||||
import java.io.FileOutputStream
|
import net.dankito.utils.multiplatform.log.LoggerFactory
|
||||||
import java.math.BigDecimal
|
|
||||||
import java.net.URL
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
import kotlin.collections.ArrayList
|
import kotlin.collections.ArrayList
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,21 +38,21 @@ open class BankingPresenter(
|
||||||
protected val bankFinder: IBankFinder,
|
protected val bankFinder: IBankFinder,
|
||||||
protected val dataFolder: File,
|
protected val dataFolder: File,
|
||||||
protected val persister: IBankingPersistence,
|
protected val persister: IBankingPersistence,
|
||||||
protected val remitteeSearcher: IRemitteeSearcher,
|
|
||||||
protected val bankIconFinder: IBankIconFinder,
|
|
||||||
protected val textExtractorRegistry: ITextExtractorRegistry,
|
|
||||||
protected val router: IRouter,
|
protected val router: IRouter,
|
||||||
protected val invoiceDataExtractor: IInvoiceDataExtractor = JavaInvoiceDataExtractor(),
|
protected val remitteeSearcher: IRemitteeSearcher = NoOpRemitteeSearcher(),
|
||||||
protected val serializer: ISerializer = JacksonJsonSerializer(),
|
protected val bankIconFinder: IBankIconFinder = NoOpBankIconFinder(),
|
||||||
|
protected val textExtractorRegistry: ITextExtractorRegistry = NoOpTextExtractorRegistry(),
|
||||||
|
protected val invoiceDataExtractor: IInvoiceDataExtractor = NoOpInvoiceDataExtractor(),
|
||||||
|
protected val serializer: ISerializer = NoOpSerializer(),
|
||||||
protected val asyncRunner: IAsyncRunner = CoroutinesAsyncRunner()
|
protected val asyncRunner: IAsyncRunner = CoroutinesAsyncRunner()
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
protected const val OneDayMillis = 24 * 60 * 60 * 1000
|
protected const val OneDayMillis = 24 * 60 * 60 * 1000
|
||||||
|
|
||||||
protected val MessageLogEntryDateFormat = SimpleDateFormat("yyyy.MM.dd HH:mm:ss.SSS")
|
protected val MessageLogEntryDateFormatter = DateFormatter("yyyy.MM.dd HH:mm:ss.SSS")
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(BankingPresenter::class.java)
|
private val log = LoggerFactory.getLogger(BankingPresenter::class)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -127,7 +124,7 @@ open class BankingPresenter(
|
||||||
try {
|
try {
|
||||||
newClient.restoreData()
|
newClient.restoreData()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Could not deserialize customer data of $customer", e)
|
log.error(e) { "Could not deserialize customer data of $customer" }
|
||||||
// TODO: show error message to user
|
// TODO: show error message to user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +135,7 @@ open class BankingPresenter(
|
||||||
|
|
||||||
selectedAllBankAccounts() // TODO: save last selected bank account(s)
|
selectedAllBankAccounts() // TODO: save last selected bank account(s)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Could not deserialize persisted accounts with persister $persister", e)
|
log.error(e) { "Could not deserialize persisted accounts with persister $persister" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,14 +191,14 @@ open class BankingPresenter(
|
||||||
bankIconFinder.findIconForBank(customer.bankName)?.let { bankIconUrl ->
|
bankIconFinder.findIconForBank(customer.bankName)?.let { bankIconUrl ->
|
||||||
val bankIconFile = saveBankIconToDisk(customer, bankIconUrl)
|
val bankIconFile = saveBankIconToDisk(customer, bankIconUrl)
|
||||||
|
|
||||||
customer.iconUrl = "file://" + bankIconFile.absolutePath // without 'file://' Android will not find it
|
customer.iconUrl = "file://" + bankIconFile.getAbsolutePath() // without 'file://' Android will not find it
|
||||||
|
|
||||||
persistAccount(customer)
|
persistAccount(customer)
|
||||||
|
|
||||||
callAccountsChangedListeners()
|
callAccountsChangedListeners()
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Could not get icon for bank ${customer.bankName}", e)
|
log.error(e) { "Could not get icon for bank ${customer.bankName}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,28 +209,24 @@ open class BankingPresenter(
|
||||||
val extension = getIconFileExtension(bankIconUrl)
|
val extension = getIconFileExtension(bankIconUrl)
|
||||||
val bankIconFile = File(bankIconsDir, customer.bankCode + if (extension != null) (".$extension") else "")
|
val bankIconFile = File(bankIconsDir, customer.bankCode + if (extension != null) (".$extension") else "")
|
||||||
|
|
||||||
URL(bankIconUrl).openConnection().getInputStream().buffered().use { iconInputStream ->
|
persister.saveUrlToFile(bankIconUrl, bankIconFile)
|
||||||
FileOutputStream(bankIconFile).use { fileOutputStream ->
|
|
||||||
iconInputStream.copyTo(fileOutputStream)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bankIconFile
|
return bankIconFile
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getIconFileExtension(bankIconUrl: String): String? {
|
protected open fun getIconFileExtension(bankIconUrl: String): String? {
|
||||||
try {
|
try {
|
||||||
var iconFilename = File(bankIconUrl).name
|
var iconFilename = File(bankIconUrl).filename
|
||||||
if (iconFilename.contains('?')) {
|
if (iconFilename.contains('?')) {
|
||||||
iconFilename = iconFilename.substring(0, iconFilename.indexOf('?'))
|
iconFilename = iconFilename.substring(0, iconFilename.indexOf('?'))
|
||||||
}
|
}
|
||||||
|
|
||||||
val extension = File(iconFilename).extension
|
val extension = File(iconFilename).fileExtension
|
||||||
if (extension.isNotBlank()) {
|
if (extension.isNotBlank()) {
|
||||||
return extension
|
return extension
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.info("Could not get icon file extension from url '$bankIconUrl'", e)
|
log.info(e) { "Could not get icon file extension from url '$bankIconUrl'" }
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
|
@ -308,7 +301,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun updateBankAccountTransactionsAsync(bankAccount: BankAccount, abortIfTanIsRequired: Boolean, callback: (GetTransactionsResponse) -> Unit) {
|
protected open fun updateBankAccountTransactionsAsync(bankAccount: BankAccount, abortIfTanIsRequired: Boolean, callback: (GetTransactionsResponse) -> Unit) {
|
||||||
val fromDate = bankAccount.lastRetrievedTransactionsTimestamp?.let { Date(it.time - OneDayMillis) } // one day before last received transactions
|
val fromDate = bankAccount.lastRetrievedTransactionsTimestamp?.let { Date(it.millisSinceEpoch - OneDayMillis) } // one day before last received transactions
|
||||||
|
|
||||||
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
|
fetchAccountTransactionsAsync(bankAccount, fromDate, abortIfTanIsRequired, callback)
|
||||||
}
|
}
|
||||||
|
@ -348,7 +341,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun formatAmount(amount: BigDecimal): String {
|
open fun formatAmount(amount: BigDecimal): String {
|
||||||
return String.format("%.02f", amount)
|
return amount.format("%.02f")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -391,7 +384,7 @@ open class BankingPresenter(
|
||||||
val transferMoneyData = TransferMoneyData("",
|
val transferMoneyData = TransferMoneyData("",
|
||||||
invoiceData.potentialIban ?: "",
|
invoiceData.potentialIban ?: "",
|
||||||
invoiceData.potentialBic ?: "",
|
invoiceData.potentialBic ?: "",
|
||||||
invoiceData.potentialTotalAmount ?: BigDecimal.ZERO, "")
|
invoiceData.potentialTotalAmount ?: BigDecimal.Zero, "")
|
||||||
showTransferMoneyDialog(null, transferMoneyData)
|
showTransferMoneyDialog(null, transferMoneyData)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -481,7 +474,7 @@ open class BankingPresenter(
|
||||||
}
|
}
|
||||||
|
|
||||||
return logEntries.map { entry ->
|
return logEntries.map { entry ->
|
||||||
MessageLogEntryDateFormat.format(entry.time) + " " + entry.customer.bankCode + " " + entry.message
|
MessageLogEntryDateFormatter.format(entry.time) + " " + entry.customer.bankCode + " " + entry.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -608,15 +601,15 @@ open class BankingPresenter(
|
||||||
|
|
||||||
|
|
||||||
protected open fun getAccountTransactionsForBankAccounts(bankAccounts: Collection<BankAccount>): List<AccountTransaction> {
|
protected open fun getAccountTransactionsForBankAccounts(bankAccounts: Collection<BankAccount>): List<AccountTransaction> {
|
||||||
return bankAccounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate } // TODO: someday add unbooked transactions
|
return bankAccounts.flatMap { it.bookedTransactions }.sortedByDescending { it.valueDate.millisSinceEpoch } // TODO: someday add unbooked transactions
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun getBalanceForAccounts(customers: Collection<Customer>): BigDecimal {
|
protected open fun getBalanceForAccounts(customers: Collection<Customer>): BigDecimal {
|
||||||
return customers.map { it.balance }.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
return customers.map { it.balance }.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun sumBalance(singleBalances: Collection<BigDecimal>): BigDecimal {
|
protected open fun sumBalance(singleBalances: Collection<BigDecimal>): BigDecimal {
|
||||||
return singleBalances.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
return singleBalances.sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -631,17 +624,17 @@ open class BankingPresenter(
|
||||||
try {
|
try {
|
||||||
serializer.serializeObject(appSettings, getAppSettingsFile())
|
serializer.serializeObject(appSettings, getAppSettingsFile())
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Could not persist AppSettings to file ${getAppSettingsFile()}", e)
|
log.error(e) { "Could not persist AppSettings to file ${getAppSettingsFile()}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun readAppSettings() {
|
protected open fun readAppSettings() {
|
||||||
try {
|
try {
|
||||||
serializer.deserializeObject(getAppSettingsFile(), AppSettings::class.java)?.let {
|
serializer.deserializeObject(getAppSettingsFile(), AppSettings::class)?.let {
|
||||||
appSettings = it
|
appSettings = it
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
log.error("Could not read AppSettings from file ${getAppSettingsFile()}", e)
|
log.error(e) { "Could not read AppSettings from file ${getAppSettingsFile()}" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package net.dankito.banking.ui.util
|
||||||
|
|
||||||
|
import net.dankito.banking.ui.model.tan.FlickerCode
|
||||||
|
import net.dankito.banking.fints.tan.Bit
|
||||||
|
import net.dankito.banking.fints.tan.FlickerCanvas
|
||||||
|
import net.dankito.utils.multiplatform.log.LoggerFactory
|
||||||
|
import kotlin.jvm.JvmOverloads
|
||||||
|
import kotlin.jvm.Volatile
|
||||||
|
|
||||||
|
|
||||||
|
open class FlickerCodeAnimator {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val MinFrequency = 2
|
||||||
|
const val MaxFrequency = 40
|
||||||
|
const val DefaultFrequency = 20
|
||||||
|
|
||||||
|
private val log = LoggerFactory.getLogger(FlickerCodeAnimator::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected var currentFrequency: Int = DefaultFrequency
|
||||||
|
|
||||||
|
protected var currentStepIndex = 0
|
||||||
|
|
||||||
|
@Volatile
|
||||||
|
protected var isPaused = false
|
||||||
|
|
||||||
|
// protected var calculateAnimationThread: Thread? = null
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@JvmOverloads
|
||||||
|
open fun animateFlickerCode(flickerCode: FlickerCode, frequency: Int = DefaultFrequency, showStep: (Array<Bit>) -> Unit) {
|
||||||
|
currentFrequency = frequency
|
||||||
|
currentStepIndex = 0
|
||||||
|
val steps = FlickerCanvas(flickerCode.parsedDataSet).steps
|
||||||
|
|
||||||
|
stop() // stop may still running previous animation
|
||||||
|
|
||||||
|
// calculateAnimationThread = Thread({ calculateAnimation(steps, showStep) }, "CalculateFlickerCodeAnimation")
|
||||||
|
//
|
||||||
|
// calculateAnimationThread?.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
// protected open fun calculateAnimation(steps: List<Array<Bit>>, showStep: (Array<Bit>) -> Unit) {
|
||||||
|
// while (Thread.currentThread().isInterrupted == false) {
|
||||||
|
// if (isPaused == false) {
|
||||||
|
// val nextStep = steps[currentStepIndex]
|
||||||
|
//
|
||||||
|
// showStep(nextStep)
|
||||||
|
//
|
||||||
|
// currentStepIndex++
|
||||||
|
// if (currentStepIndex >= steps.size) {
|
||||||
|
// currentStepIndex = 0 // all steps shown, start again from beginning
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// try {
|
||||||
|
// TimeUnit.MILLISECONDS.sleep(1000L / currentFrequency)
|
||||||
|
// } catch (ignored: Exception) {
|
||||||
|
// Thread.currentThread().interrupt()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
open fun pause() {
|
||||||
|
this.isPaused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun resume() {
|
||||||
|
this.isPaused = false
|
||||||
|
}
|
||||||
|
|
||||||
|
open fun stop() {
|
||||||
|
try {
|
||||||
|
// if (calculateAnimationThread?.isInterrupted == false) {
|
||||||
|
// calculateAnimationThread?.interrupt()
|
||||||
|
// calculateAnimationThread?.join(500)
|
||||||
|
//
|
||||||
|
// calculateAnimationThread = null
|
||||||
|
// }
|
||||||
|
} catch (e: Exception) {
|
||||||
|
log.warn(e) { "Could not stop calculateAnimationThread" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open fun setFrequency(frequency: Int) {
|
||||||
|
if (frequency in MinFrequency..MaxFrequency) {
|
||||||
|
currentFrequency = frequency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +1,13 @@
|
||||||
package net.dankito.banking.util
|
package net.dankito.banking.util
|
||||||
|
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
||||||
open class CoroutinesAsyncRunner : IAsyncRunner {
|
open class CoroutinesAsyncRunner : IAsyncRunner { // TODO: remove (coroutines in common)
|
||||||
|
|
||||||
override fun runAsync(runnable: () -> Unit) {
|
override fun runAsync(runnable: () -> Unit) {
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch {
|
||||||
runnable()
|
runnable()
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package net.dankito.banking.util
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
|
interface ISerializer {
|
||||||
|
|
||||||
|
fun serializeObject(obj: Any, outputFile: File)
|
||||||
|
|
||||||
|
fun <T : Any> deserializeObject(serializedObjectFile: File, objectClass: KClass<T>, vararg genericParameterTypes: KClass<*>): T?
|
||||||
|
|
||||||
|
fun <T : Any> deserializeListOr(serializedObjectFile: File, genericListParameterType: KClass<T>,
|
||||||
|
defaultValue: List<T> = listOf()) : List<T>
|
||||||
|
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package net.dankito.banking.util
|
||||||
|
|
||||||
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator
|
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.ISepaMessageCreator
|
||||||
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.SepaMessageCreator
|
import net.dankito.banking.fints.messages.segmente.implementierte.sepa.SepaMessageCreator
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
|
|
||||||
open class InputValidator {
|
open class InputValidator {
|
||||||
|
@ -22,7 +21,7 @@ open class InputValidator {
|
||||||
* (https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure)
|
* (https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure)
|
||||||
*/
|
*/
|
||||||
const val IbanPatternString = "[A-Z]{2}\\d{2}[A-Z0-9]{10,30}"
|
const val IbanPatternString = "[A-Z]{2}\\d{2}[A-Z0-9]{10,30}"
|
||||||
val IbanPattern = Pattern.compile("^" + IbanPatternString + "\$")
|
val IbanPattern = Regex("^" + IbanPatternString + "\$")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The IBAN should not contain spaces when transmitted electronically. When printed it is expressed in groups
|
* The IBAN should not contain spaces when transmitted electronically. When printed it is expressed in groups
|
||||||
|
@ -30,9 +29,9 @@ open class InputValidator {
|
||||||
* (https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure)
|
* (https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure)
|
||||||
*/
|
*/
|
||||||
const val IbanWithSpacesPatternString = "[A-Z]{2}\\d{2}\\s([A-Z0-9]{4}\\s){3}[A-Z0-9\\s]{1,18}"
|
const val IbanWithSpacesPatternString = "[A-Z]{2}\\d{2}\\s([A-Z0-9]{4}\\s){3}[A-Z0-9\\s]{1,18}"
|
||||||
val IbanWithSpacesPattern = Pattern.compile("^" + IbanWithSpacesPatternString + "\$")
|
val IbanWithSpacesPattern = Regex("^" + IbanWithSpacesPatternString + "\$")
|
||||||
|
|
||||||
val InvalidIbanCharactersPattern = Pattern.compile("[^A-Z0-9 ]")
|
val InvalidIbanCharactersPattern = Regex("[^A-Z0-9 ]")
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -47,12 +46,12 @@ open class InputValidator {
|
||||||
* Where an eight digit code is given, it may be assumed that it refers to the primary office.
|
* Where an eight digit code is given, it may be assumed that it refers to the primary office.
|
||||||
*/
|
*/
|
||||||
const val BicPatternString = "[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:\\b|[A-Z0-9]{03})"
|
const val BicPatternString = "[A-Z]{4}[A-Z]{2}[A-Z0-9]{2}(?:\\b|[A-Z0-9]{03})"
|
||||||
val BicPattern = Pattern.compile("^" + BicPatternString + "$")
|
val BicPattern = Regex("^" + BicPatternString + "$")
|
||||||
|
|
||||||
val InvalidBicCharactersPattern = Pattern.compile("[^A-Z0-9]")
|
val InvalidBicCharactersPattern = Regex("[^A-Z0-9]")
|
||||||
|
|
||||||
|
|
||||||
val InvalidSepaCharactersPattern = Pattern.compile("[^${SepaMessageCreator.AllowedSepaCharacters}]+")
|
val InvalidSepaCharactersPattern = Regex("[^${SepaMessageCreator.AllowedSepaCharacters}]+")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@ open class InputValidator {
|
||||||
|
|
||||||
|
|
||||||
open fun isValidIban(stringToTest: String): Boolean {
|
open fun isValidIban(stringToTest: String): Boolean {
|
||||||
return IbanPattern.matcher(stringToTest.replace(" ", "")).matches()
|
return IbanPattern.matches(stringToTest.replace(" ", ""))
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getInvalidIbanCharacters(string: String): String {
|
open fun getInvalidIbanCharacters(string: String): String {
|
||||||
|
@ -69,7 +68,7 @@ open class InputValidator {
|
||||||
|
|
||||||
|
|
||||||
open fun isValidBic(stringToTest: String): Boolean {
|
open fun isValidBic(stringToTest: String): Boolean {
|
||||||
return BicPattern.matcher(stringToTest).matches()
|
return BicPattern.matches(stringToTest)
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun getInvalidBicCharacters(string: String): String {
|
open fun getInvalidBicCharacters(string: String): String {
|
||||||
|
@ -114,16 +113,8 @@ open class InputValidator {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open fun getInvalidCharacters(string: String, pattern: Pattern): String {
|
open fun getInvalidCharacters(string: String, pattern: Regex): String {
|
||||||
val illegalCharacters = mutableSetOf<String>()
|
return pattern.findAll(string).joinToString("")
|
||||||
|
|
||||||
val matcher = pattern.matcher(string)
|
|
||||||
|
|
||||||
while (matcher.find()) {
|
|
||||||
illegalCharacters.add(matcher.group())
|
|
||||||
}
|
|
||||||
|
|
||||||
return illegalCharacters.joinToString("")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package net.dankito.banking.util
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
|
open class NoOpSerializer : ISerializer {
|
||||||
|
|
||||||
|
override fun serializeObject(obj: Any, outputFile: File) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> deserializeObject(serializedObjectFile: File, objectClass: KClass<T>, vararg genericParameterTypes: KClass<*>): T? {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> deserializeListOr(serializedObjectFile: File, genericListParameterType: KClass<T>, defaultValue: List<T>): List<T> {
|
||||||
|
return defaultValue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,5 @@
|
||||||
package net.dankito.banking.util.extraction
|
package net.dankito.banking.util.extraction
|
||||||
|
|
||||||
import java.lang.Exception
|
|
||||||
|
|
||||||
|
|
||||||
open class ExtractionResult(
|
open class ExtractionResult(
|
||||||
open val couldExtractText: Boolean,
|
open val couldExtractText: Boolean,
|
|
@ -1,6 +1,6 @@
|
||||||
package net.dankito.banking.util.extraction
|
package net.dankito.banking.util.extraction
|
||||||
|
|
||||||
import java.io.File
|
import net.dankito.utils.multiplatform.File
|
||||||
|
|
||||||
|
|
||||||
interface ITextExtractorRegistry {
|
interface ITextExtractorRegistry {
|
|
@ -1,6 +1,6 @@
|
||||||
package net.dankito.banking.util.extraction
|
package net.dankito.banking.util.extraction
|
||||||
|
|
||||||
import java.math.BigDecimal
|
import net.dankito.utils.multiplatform.BigDecimal
|
||||||
|
|
||||||
|
|
||||||
open class InvoiceData(
|
open class InvoiceData(
|
|
@ -1,6 +1,6 @@
|
||||||
package net.dankito.banking.util.extraction
|
package net.dankito.banking.util.extraction
|
||||||
|
|
||||||
import java.io.File
|
import net.dankito.utils.multiplatform.File
|
||||||
|
|
||||||
|
|
||||||
open class NoOpTextExtractorRegistry : ITextExtractorRegistry {
|
open class NoOpTextExtractorRegistry : ITextExtractorRegistry {
|
|
@ -0,0 +1,24 @@
|
||||||
|
package net.dankito.banking.util
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
|
||||||
|
open class JacksonJsonSerializer(
|
||||||
|
protected val serializer: net.dankito.utils.serialization.ISerializer = net.dankito.utils.serialization.JacksonJsonSerializer()
|
||||||
|
) : ISerializer {
|
||||||
|
|
||||||
|
override fun serializeObject(obj: Any, outputFile: File) {
|
||||||
|
return serializer.serializeObject(obj, outputFile)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> deserializeObject(serializedObjectFile: File, objectClass: KClass<T>,
|
||||||
|
vararg genericParameterTypes: KClass<*>): T? {
|
||||||
|
return serializer.deserializeObject(serializedObjectFile, objectClass.java, *genericParameterTypes.map { it.java }.toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun <T : Any> deserializeListOr(serializedObjectFile: File, genericListParameterType: KClass<T>, defaultValue: List<T>): List<T> {
|
||||||
|
return serializer.deserializeListOr(serializedObjectFile, genericListParameterType.java, defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
package net.dankito.banking.util.extraction
|
package net.dankito.banking.util.extraction
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.toBigDecimal
|
||||||
import net.dankito.text.extraction.info.invoice.InvoiceDataExtractor
|
import net.dankito.text.extraction.info.invoice.InvoiceDataExtractor
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package net.dankito.banking.util.extraction
|
package net.dankito.banking.util.extraction
|
||||||
|
|
||||||
|
import net.dankito.utils.multiplatform.File
|
||||||
import net.dankito.text.extraction.TextExtractorRegistry
|
import net.dankito.text.extraction.TextExtractorRegistry
|
||||||
import net.dankito.text.extraction.model.ErrorType
|
import net.dankito.text.extraction.model.ErrorType
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
open class JavaTextExtractorRegistry(
|
open class JavaTextExtractorRegistry(
|
|
@ -1,6 +1,5 @@
|
||||||
package net.dankito.banking.util
|
package net.dankito.banking.util
|
||||||
|
|
||||||
import net.dankito.banking.bankfinder.InMemoryBankFinder
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="net.dankito.banking.ui">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
|
</manifest>
|
|
@ -1,94 +0,0 @@
|
||||||
package net.dankito.banking.ui.util
|
|
||||||
|
|
||||||
import net.dankito.banking.ui.model.tan.FlickerCode
|
|
||||||
import net.dankito.banking.fints.tan.Bit
|
|
||||||
import net.dankito.banking.fints.tan.FlickerCanvas
|
|
||||||
import org.slf4j.LoggerFactory
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
|
|
||||||
open class FlickerCodeAnimator { // TODO: move to fints44
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val MinFrequency = 2
|
|
||||||
const val MaxFrequency = 40
|
|
||||||
const val DefaultFrequency = 20
|
|
||||||
|
|
||||||
private val log = LoggerFactory.getLogger(FlickerCodeAnimator::class.java)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected var currentFrequency: Int = DefaultFrequency
|
|
||||||
|
|
||||||
protected var currentStepIndex = 0
|
|
||||||
|
|
||||||
@Volatile
|
|
||||||
protected var isPaused = false
|
|
||||||
|
|
||||||
protected var calculateAnimationThread: Thread? = null
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@JvmOverloads
|
|
||||||
open fun animateFlickerCode(flickerCode: FlickerCode, frequency: Int = DefaultFrequency, showStep: (Array<Bit>) -> Unit) {
|
|
||||||
currentFrequency = frequency
|
|
||||||
currentStepIndex = 0
|
|
||||||
val steps = FlickerCanvas(flickerCode.parsedDataSet).steps
|
|
||||||
|
|
||||||
stop() // stop may still running previous animation
|
|
||||||
|
|
||||||
calculateAnimationThread = Thread({ calculateAnimation(steps, showStep) }, "CalculateFlickerCodeAnimation")
|
|
||||||
|
|
||||||
calculateAnimationThread?.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected open fun calculateAnimation(steps: List<Array<Bit>>, showStep: (Array<Bit>) -> Unit) {
|
|
||||||
while (Thread.currentThread().isInterrupted == false) {
|
|
||||||
if (isPaused == false) {
|
|
||||||
val nextStep = steps[currentStepIndex]
|
|
||||||
|
|
||||||
showStep(nextStep)
|
|
||||||
|
|
||||||
currentStepIndex++
|
|
||||||
if (currentStepIndex >= steps.size) {
|
|
||||||
currentStepIndex = 0 // all steps shown, start again from beginning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
TimeUnit.MILLISECONDS.sleep(1000L / currentFrequency)
|
|
||||||
} catch (ignored: Exception) {
|
|
||||||
Thread.currentThread().interrupt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun pause() {
|
|
||||||
this.isPaused = true
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun resume() {
|
|
||||||
this.isPaused = false
|
|
||||||
}
|
|
||||||
|
|
||||||
open fun stop() {
|
|
||||||
try {
|
|
||||||
if (calculateAnimationThread?.isInterrupted == false) {
|
|
||||||
calculateAnimationThread?.interrupt()
|
|
||||||
calculateAnimationThread?.join(500)
|
|
||||||
|
|
||||||
calculateAnimationThread = null
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
log.warn("Could not stop calculateAnimationThread", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
open fun setFrequency(frequency: Int) {
|
|
||||||
if (frequency in MinFrequency..MaxFrequency) {
|
|
||||||
currentFrequency = frequency
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package net.dankito.banking.util
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
interface ISerializer {
|
|
||||||
|
|
||||||
fun serializeObject(obj: Any, outputFile: File)
|
|
||||||
|
|
||||||
fun <T> deserializeObject(serializedObjectFile: File, objectClass: Class<T>, vararg genericParameterTypes: Class<*>): T?
|
|
||||||
|
|
||||||
fun <T> deserializeListOr(serializedObjectFile: File, genericListParameterType: Class<T>,
|
|
||||||
defaultValue: List<T> = listOf()) : List<T>
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
package net.dankito.banking.util
|
|
||||||
|
|
||||||
import net.dankito.utils.serialization.JacksonJsonSerializer
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
open class JacksonJsonSerializer(
|
|
||||||
protected val serializer: net.dankito.utils.serialization.ISerializer = JacksonJsonSerializer()
|
|
||||||
) : ISerializer {
|
|
||||||
|
|
||||||
override fun serializeObject(obj: Any, outputFile: File) {
|
|
||||||
return serializer.serializeObject(obj, outputFile)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T> deserializeObject(serializedObjectFile: File, objectClass: Class<T>,
|
|
||||||
vararg genericParameterTypes: Class<*>): T? {
|
|
||||||
return serializer.deserializeObject(serializedObjectFile, objectClass, *genericParameterTypes)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T> deserializeListOr(serializedObjectFile: File, genericListParameterType: Class<T>, defaultValue: List<T>): List<T> {
|
|
||||||
return serializer.deserializeListOr(serializedObjectFile, genericListParameterType, defaultValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package net.dankito.banking.util
|
|
||||||
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
open class NoOpSerializer : ISerializer {
|
|
||||||
|
|
||||||
override fun serializeObject(obj: Any, outputFile: File) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T> deserializeObject(serializedObjectFile: File, objectClass: Class<T>, vararg genericParameterTypes: Class<*>): T? {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <T> deserializeListOr(serializedObjectFile: File, genericListParameterType: Class<T>, defaultValue: List<T>): List<T> {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -34,24 +34,22 @@ kotlin {
|
||||||
sourceSets {
|
sourceSets {
|
||||||
commonMain {
|
commonMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation kotlin("stdlib-common")
|
api project(":BankingUiCommon")
|
||||||
|
api project(":fints4k")
|
||||||
implementation project(":BankingUiCommon")
|
|
||||||
implementation project(":fints4k")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
jvmMain {
|
jvmMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
api kotlin("stdlib-jdk7")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
iosMain {
|
iosMain {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue