Made BankingUiCommon a multi platform project
This commit is contained in:
parent
588877cb20
commit
52d3b49baa
|
@ -1,16 +1,17 @@
|
|||
package net.dankito.banking.persistence
|
||||
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.ui.model.Customer
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import net.dankito.banking.util.ISerializer
|
||||
import net.dankito.banking.util.JacksonJsonSerializer
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.net.URL
|
||||
|
||||
|
||||
open class BankingPersistenceJson(
|
||||
protected val jsonFile: File,
|
||||
protected val serializer: ISerializer = JacksonJsonSerializer()
|
||||
protected val serializer: ISerializer
|
||||
) : IBankingPersistence {
|
||||
|
||||
|
||||
|
@ -28,7 +29,7 @@ open class BankingPersistenceJson(
|
|||
}
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
implementation project(":fints4k"), {
|
||||
exclude group: "com.soywiz.korlibs.klock", module: "klock-android" // klock-jvm already adds required extensions, to avoid duplicates
|
||||
}
|
||||
implementation project(":fints4k")
|
||||
|
||||
implementation project(':BankingUiCommon')
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ import android.content.Context
|
|||
import androidx.appcompat.app.AppCompatActivity
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.ui.android.RouterAndroid
|
||||
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.persistence.IBankingPersistence
|
||||
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.bankfinder.IBankFinder
|
||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||
import net.dankito.utils.multiplatform.toFile
|
||||
import net.dankito.banking.util.*
|
||||
import net.dankito.banking.util.extraction.IInvoiceDataExtractor
|
||||
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.web.client.IWebClient
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import java.io.File
|
||||
import javax.inject.Named
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -59,7 +59,7 @@ class BankingModule(private val applicationContext: Context) {
|
|||
@Singleton
|
||||
@Named(DataFolderKey)
|
||||
fun provideDataFolder(applicationContext: Context) : File {
|
||||
return ensureFolderExists(applicationContext.filesDir, "data")
|
||||
return ensureFolderExists(applicationContext.filesDir.toFile(), "data")
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -93,7 +93,7 @@ class BankingModule(private val applicationContext: Context) {
|
|||
textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
|
||||
serializer: ISerializer, asyncRunner: IAsyncRunner) : BankingPresenter {
|
||||
return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister,
|
||||
remitteeSearcher, bankIconFinder, textExtractorRegistry, router, invoiceDataExtractor, serializer, asyncRunner)
|
||||
router, remitteeSearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, serializer, asyncRunner)
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
@ -110,8 +110,8 @@ class BankingModule(private val applicationContext: Context) {
|
|||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBankingClientCreator() : IBankingClientCreator {
|
||||
return fints4kBankingClientCreator()
|
||||
fun provideBankingClientCreator(serializer: ISerializer) : IBankingClientCreator {
|
||||
return fints4kBankingClientCreator(serializer)
|
||||
}
|
||||
|
||||
@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.util.StandardAutocompleteCallback
|
||||
import net.dankito.banking.ui.android.util.StandardTextWatcher
|
||||
import net.dankito.banking.search.IRemitteeSearcher
|
||||
import net.dankito.banking.search.Remittee
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
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.util.InputValidator
|
||||
import net.dankito.banking.bankfinder.BankInfo
|
||||
import net.dankito.utils.multiplatform.toBigDecimal
|
||||
import net.dankito.utils.android.extensions.asActivity
|
||||
import java.math.BigDecimal
|
||||
import java.text.DecimalFormatSymbols
|
||||
|
@ -242,7 +242,7 @@ open class TransferMoneyDialog : DialogFragment() {
|
|||
inputValidator.convertToAllowedSepaCharacters(edtxtRemitteeName.text.toString()),
|
||||
edtxtRemitteeIban.text.toString().replace(" ", ""),
|
||||
edtxtRemitteeBic.text.toString().replace(" ", ""),
|
||||
amount,
|
||||
amount.toBigDecimal(),
|
||||
inputValidator.convertToAllowedSepaCharacters(edtxtUsage.text.toString()),
|
||||
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.FloatingActionMenu
|
||||
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.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResultType
|
||||
|
@ -78,7 +79,7 @@ open class MainActivityFloatingActionMenuButton(
|
|||
selectedFile?.let {
|
||||
lastSelectedFolder = selectedFile.parentFile
|
||||
|
||||
val result = presenter.transferMoneyWithDataFromPdf(selectedFile)
|
||||
val result = presenter.transferMoneyWithDataFromPdf(selectedFile.toFile())
|
||||
|
||||
if (result.type != ExtractTransferMoneyDataFromPdfResultType.Success) {
|
||||
showTransferMoneyWithDataFromPdfError(activity, selectedFile, result)
|
||||
|
|
|
@ -1,17 +1,18 @@
|
|||
package net.dankito.banking.ui.javafx.dialogs.mainwindow
|
||||
|
||||
import javafx.scene.control.SplitPane
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.fints4kBankingClientCreator
|
||||
import net.dankito.banking.ui.javafx.RouterJavaFx
|
||||
import net.dankito.banking.ui.javafx.controls.AccountTransactionsView
|
||||
import net.dankito.banking.ui.javafx.controls.AccountsView
|
||||
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.util.BankIconFinder
|
||||
import net.dankito.banking.bankfinder.LuceneBankFinder
|
||||
import net.dankito.banking.persistence.LuceneBankingPersistence
|
||||
import net.dankito.banking.search.LuceneRemitteeSearcher
|
||||
import net.dankito.banking.util.JacksonJsonSerializer
|
||||
import net.dankito.banking.util.extraction.JavaTextExtractorRegistry
|
||||
import net.dankito.text.extraction.TextExtractorRegistry
|
||||
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.TesseractConfig
|
||||
import net.dankito.text.extraction.pdf.*
|
||||
import net.dankito.utils.web.client.OkHttpWebClient
|
||||
import tornadofx.*
|
||||
import tornadofx.FX.Companion.messages
|
||||
import java.io.File
|
||||
|
||||
|
||||
class MainWindow : View(messages["application.title"]) {
|
||||
|
@ -33,6 +32,8 @@ class MainWindow : View(messages["application.title"]) {
|
|||
|
||||
private val indexFolder = ensureFolderExists(dataFolder, "index")
|
||||
|
||||
private val serializer = JacksonJsonSerializer()
|
||||
|
||||
private val tesseractTextExtractor = Tesseract4CommandlineImageTextExtractor(TesseractConfig(listOf(OcrLanguage.English, OcrLanguage.German)))
|
||||
|
||||
private val textExtractorRegistry = JavaTextExtractorRegistry(TextExtractorRegistry(pdffontsPdfTypeDetector(), listOf(
|
||||
|
@ -41,12 +42,12 @@ class MainWindow : View(messages["application.title"]) {
|
|||
tesseractTextExtractor, TikaTextExtractor()
|
||||
)))
|
||||
|
||||
private val presenter = BankingPresenter(fints4kBankingClientCreator(),
|
||||
private val presenter = BankingPresenter(fints4kBankingClientCreator(serializer),
|
||||
LuceneBankFinder(indexFolder), dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder),
|
||||
LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry, RouterJavaFx())
|
||||
RouterJavaFx(), LuceneRemitteeSearcher(indexFolder), BankIconFinder(), textExtractorRegistry)
|
||||
// private val presenter = BankingPresenter(hbci4jBankingClientCreator(), LuceneBankFinder(indexFolder),
|
||||
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), LuceneRemitteeSearcher(indexFolder),
|
||||
// BankIconFinder(), textExtractorRegistry, RouterJavaFx())
|
||||
// dataFolder, LuceneBankingPersistence(indexFolder, databaseFolder), RouterJavaFx(), LuceneRemitteeSearcher(indexFolder),
|
||||
// BankIconFinder(), textExtractorRegistry)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import javafx.scene.input.KeyCode
|
|||
import javafx.scene.input.KeyCodeCombination
|
||||
import javafx.scene.input.KeyCombination
|
||||
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.ExtractTransferMoneyDataFromPdfResultType
|
||||
import net.dankito.banking.ui.presenter.BankingPresenter
|
||||
|
@ -79,7 +80,7 @@ open class MainMenuBar(protected val presenter: BankingPresenter) : View() {
|
|||
fileChooser.showOpenDialog(currentStage)?.let { pdfFile ->
|
||||
lastSelectedFolder = pdfFile.parentFile
|
||||
|
||||
val result = presenter.transferMoneyWithDataFromPdf(pdfFile)
|
||||
val result = presenter.transferMoneyWithDataFromPdf(pdfFile.toFile())
|
||||
|
||||
if (result.type != ExtractTransferMoneyDataFromPdfResultType.Success) {
|
||||
showTransferMoneyWithDataFromPdfError(pdfFile, result)
|
||||
|
|
|
@ -19,6 +19,7 @@ import net.dankito.banking.ui.presenter.BankingPresenter
|
|||
import net.dankito.banking.util.InputValidator
|
||||
import net.dankito.banking.bankfinder.BankInfo
|
||||
import net.dankito.banking.search.Remittee
|
||||
import net.dankito.utils.multiplatform.toBigDecimal
|
||||
import net.dankito.banking.ui.javafx.extensions.focusNextControl
|
||||
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),
|
||||
remitteeIban.value.replace(" ", ""),
|
||||
remitteeBic.value.replace(" ", ""),
|
||||
amount.value.toBigDecimal(),
|
||||
amount.value.toBigDecimal().toBigDecimal(),
|
||||
inputValidator.convertToAllowedSepaCharacters(usage.value),
|
||||
instantPayment.value
|
||||
)
|
||||
|
|
|
@ -1,27 +1,62 @@
|
|||
apply plugin: 'java-library'
|
||||
apply plugin: 'kotlin'
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.multiplatform"
|
||||
id "com.android.library"
|
||||
id "maven-publish"
|
||||
}
|
||||
|
||||
|
||||
ext.artifactName = "banking-ui-common"
|
||||
|
||||
|
||||
sourceCompatibility = "1.7"
|
||||
targetCompatibility = "1.7"
|
||||
kotlin {
|
||||
jvm {
|
||||
compilations.main.kotlinOptions {
|
||||
jvmTarget = "1.6"
|
||||
}
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.6"
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.6"
|
||||
}
|
||||
targets {
|
||||
// Select iOS target for real device or emulator.
|
||||
final def iOSIsRealDevice = System.getenv('SDK_NAME')?.startsWith("iphoneos")
|
||||
final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
|
||||
|
||||
// iOS target.
|
||||
fromPreset(iOSTarget, 'ios') {
|
||||
binaries {
|
||||
framework {
|
||||
baseName = "BankingUiCommon"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
|
||||
sourceSets {
|
||||
commonMain {
|
||||
dependencies {
|
||||
api kotlin("stdlib-common")
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinCoroutinesVersion"
|
||||
|
||||
api "net.dankito.utils:java-utils:$javaUtilsVersion"
|
||||
// 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"
|
||||
|
@ -29,13 +64,102 @@ dependencies {
|
|||
implementation "net.dankito.utils:favicon-finder:1.0.0-SNAPSHOT"
|
||||
|
||||
implementation "org.jsoup:jsoup:1.13.1"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: try to get rid of this import
|
||||
api project(':fints4k')
|
||||
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"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
testImplementation "org.assertj:assertj-core:$assertJVersion"
|
||||
iosMain {
|
||||
dependencies {
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$kotlinCoroutinesVersion"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Task to generate iOS framework for xcode projects.
|
||||
task packForXCode(type: Sync) {
|
||||
|
||||
final File frameworkDir = new File(buildDir, "xcode-frameworks")
|
||||
final String mode = project.findProperty("XCODE_CONFIGURATION")?.toUpperCase() ?: 'DEBUG'
|
||||
|
||||
final def framework = kotlin.targets.ios.binaries.getFramework("", mode)
|
||||
|
||||
inputs.property "mode", mode
|
||||
dependsOn framework.linkTask
|
||||
|
||||
from { framework.outputFile.parentFile }
|
||||
into frameworkDir
|
||||
|
||||
doLast {
|
||||
new File(frameworkDir, 'gradlew').with {
|
||||
text = "#!/bin/bash\nexport 'JAVA_HOME=${System.getProperty("java.home")}'\ncd '${rootProject.rootDir}'\n./gradlew \$@\n"
|
||||
setExecutable(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run packForXCode when building.
|
||||
tasks.build.dependsOn packForXCode
|
||||
|
||||
|
||||
android {
|
||||
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
|
||||
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.ui.model.Customer
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
|
@ -16,4 +17,6 @@ interface IBankingPersistence {
|
|||
|
||||
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
|
||||
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.banking.bankfinder.BankInfo
|
||||
import net.dankito.banking.util.IAsyncRunner
|
||||
import java.io.File
|
||||
|
||||
|
||||
interface IBankingClientCreator {
|
|
@ -1,14 +1,14 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import java.math.BigDecimal
|
||||
import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
//import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
//import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
import net.dankito.utils.multiplatform.DateFormatStyle
|
||||
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 val bankAccount: BankAccount,
|
||||
open val amount: BigDecimal,
|
||||
|
@ -50,7 +50,7 @@ open class AccountTransaction(
|
|||
) {
|
||||
|
||||
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)
|
||||
|
||||
// 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)
|
||||
|
||||
|
@ -79,7 +79,7 @@ open class AccountTransaction(
|
|||
if (other !is AccountTransaction) 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 (unparsedUsage != other.unparsedUsage) return false
|
||||
if (bookingDate != other.bookingDate) return false
|
||||
|
@ -108,7 +108,7 @@ open class AccountTransaction(
|
|||
|
||||
|
||||
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
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
//import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
//import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
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 val customer: Customer,
|
||||
open val identifier: String,
|
||||
|
@ -14,7 +16,7 @@ open class BankAccount @JvmOverloads constructor(
|
|||
open var iban: String?,
|
||||
open var subAccountNumber: String?,
|
||||
open val customerId: String,
|
||||
open var balance: BigDecimal = BigDecimal.ZERO,
|
||||
open var balance: BigDecimal = BigDecimal.Zero,
|
||||
open var currency: String = "EUR",
|
||||
open var type: BankAccountType = BankAccountType.Girokonto,
|
||||
open val productName: String? = null,
|
||||
|
@ -30,7 +32,7 @@ open class BankAccount @JvmOverloads constructor(
|
|||
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
|
|
@ -1,15 +1,16 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
import com.fasterxml.jackson.annotation.ObjectIdGenerators
|
||||
//import com.fasterxml.jackson.annotation.JsonIdentityInfo
|
||||
//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.TanMediumStatus
|
||||
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(
|
||||
val bankCode: String,
|
||||
val customerId: String,
|
||||
|
@ -27,7 +28,7 @@ open class Customer(
|
|||
internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
|
||||
|
||||
|
||||
var id: String = UUID.randomUUID().toString()
|
||||
var id: String = UUID.random()
|
||||
|
||||
|
||||
var supportedTanProcedures: List<TanProcedure> = listOf()
|
||||
|
@ -44,7 +45,7 @@ open class Customer(
|
|||
get() = bankName
|
||||
|
||||
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>
|
||||
get() = accounts.flatMap { it.bookedTransactions }
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.ui.model
|
||||
|
||||
import java.util.*
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
|
||||
|
||||
open class MessageLogEntry(
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.ui.model.parameters
|
||||
|
||||
import net.dankito.utils.multiplatform.Date
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import java.util.*
|
||||
|
||||
|
||||
open class GetTransactionsParameter(
|
|
@ -1,7 +1,7 @@
|
|||
package net.dankito.banking.ui.model.parameters
|
||||
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
import net.dankito.banking.ui.model.AccountTransaction
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
open class TransferMoneyData(
|
||||
|
@ -20,7 +20,7 @@ open class TransferMoneyData(
|
|||
transaction.otherPartyName ?: "",
|
||||
transaction.otherPartyAccountId ?: "",
|
||||
transaction.otherPartyBankCode ?: "",
|
||||
BigDecimal.ZERO,
|
||||
BigDecimal.Zero,
|
||||
""
|
||||
)
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
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.AccountTransaction
|
||||
import net.dankito.banking.ui.model.BankAccount
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
open class AddAccountResponse(
|
|
@ -1,8 +1,8 @@
|
|||
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.BankAccount
|
||||
import java.math.BigDecimal
|
||||
|
||||
|
||||
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.BankInfo
|
||||
import net.dankito.banking.search.IRemitteeSearcher
|
||||
import net.dankito.banking.search.NoOpRemitteeSearcher
|
||||
import net.dankito.banking.search.Remittee
|
||||
import net.dankito.banking.ui.model.moneytransfer.ExtractTransferMoneyDataFromPdfResult
|
||||
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.extraction.IInvoiceDataExtractor
|
||||
import net.dankito.banking.util.extraction.ITextExtractorRegistry
|
||||
import net.dankito.banking.util.extraction.JavaInvoiceDataExtractor
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.math.BigDecimal
|
||||
import java.net.URL
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import net.dankito.banking.util.extraction.NoOpInvoiceDataExtractor
|
||||
import net.dankito.banking.util.extraction.NoOpTextExtractorRegistry
|
||||
import net.dankito.utils.multiplatform.*
|
||||
import net.dankito.utils.multiplatform.log.LoggerFactory
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
|
||||
|
@ -41,21 +38,21 @@ open class BankingPresenter(
|
|||
protected val bankFinder: IBankFinder,
|
||||
protected val dataFolder: File,
|
||||
protected val persister: IBankingPersistence,
|
||||
protected val remitteeSearcher: IRemitteeSearcher,
|
||||
protected val bankIconFinder: IBankIconFinder,
|
||||
protected val textExtractorRegistry: ITextExtractorRegistry,
|
||||
protected val router: IRouter,
|
||||
protected val invoiceDataExtractor: IInvoiceDataExtractor = JavaInvoiceDataExtractor(),
|
||||
protected val serializer: ISerializer = JacksonJsonSerializer(),
|
||||
protected val remitteeSearcher: IRemitteeSearcher = NoOpRemitteeSearcher(),
|
||||
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()
|
||||
) {
|
||||
|
||||
companion object {
|
||||
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 {
|
||||
newClient.restoreData()
|
||||
} 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
|
||||
}
|
||||
|
||||
|
@ -138,7 +135,7 @@ open class BankingPresenter(
|
|||
|
||||
selectedAllBankAccounts() // TODO: save last selected bank account(s)
|
||||
} 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 ->
|
||||
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)
|
||||
|
||||
callAccountsChangedListeners()
|
||||
}
|
||||
} 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 bankIconFile = File(bankIconsDir, customer.bankCode + if (extension != null) (".$extension") else "")
|
||||
|
||||
URL(bankIconUrl).openConnection().getInputStream().buffered().use { iconInputStream ->
|
||||
FileOutputStream(bankIconFile).use { fileOutputStream ->
|
||||
iconInputStream.copyTo(fileOutputStream)
|
||||
}
|
||||
}
|
||||
persister.saveUrlToFile(bankIconUrl, bankIconFile)
|
||||
|
||||
return bankIconFile
|
||||
}
|
||||
|
||||
protected open fun getIconFileExtension(bankIconUrl: String): String? {
|
||||
try {
|
||||
var iconFilename = File(bankIconUrl).name
|
||||
var iconFilename = File(bankIconUrl).filename
|
||||
if (iconFilename.contains('?')) {
|
||||
iconFilename = iconFilename.substring(0, iconFilename.indexOf('?'))
|
||||
}
|
||||
|
||||
val extension = File(iconFilename).extension
|
||||
val extension = File(iconFilename).fileExtension
|
||||
if (extension.isNotBlank()) {
|
||||
return extension
|
||||
}
|
||||
} 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
|
||||
|
@ -308,7 +301,7 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
@ -348,7 +341,7 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
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("",
|
||||
invoiceData.potentialIban ?: "",
|
||||
invoiceData.potentialBic ?: "",
|
||||
invoiceData.potentialTotalAmount ?: BigDecimal.ZERO, "")
|
||||
invoiceData.potentialTotalAmount ?: BigDecimal.Zero, "")
|
||||
showTransferMoneyDialog(null, transferMoneyData)
|
||||
}
|
||||
else {
|
||||
|
@ -481,7 +474,7 @@ open class BankingPresenter(
|
|||
}
|
||||
|
||||
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> {
|
||||
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 {
|
||||
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 {
|
||||
return singleBalances.fold(BigDecimal.ZERO) { acc, e -> acc + e }
|
||||
return singleBalances.sum()
|
||||
}
|
||||
|
||||
|
||||
|
@ -631,17 +624,17 @@ open class BankingPresenter(
|
|||
try {
|
||||
serializer.serializeObject(appSettings, getAppSettingsFile())
|
||||
} 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() {
|
||||
try {
|
||||
serializer.deserializeObject(getAppSettingsFile(), AppSettings::class.java)?.let {
|
||||
serializer.deserializeObject(getAppSettingsFile(), AppSettings::class)?.let {
|
||||
appSettings = it
|
||||
}
|
||||
} 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
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
|
||||
open class CoroutinesAsyncRunner : IAsyncRunner {
|
||||
open class CoroutinesAsyncRunner : IAsyncRunner { // TODO: remove (coroutines in common)
|
||||
|
||||
override fun runAsync(runnable: () -> Unit) {
|
||||
GlobalScope.launch(Dispatchers.IO) {
|
||||
GlobalScope.launch {
|
||||
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.SepaMessageCreator
|
||||
import java.util.regex.Pattern
|
||||
|
||||
|
||||
open class InputValidator {
|
||||
|
@ -22,7 +21,7 @@ open class InputValidator {
|
|||
* (https://en.wikipedia.org/wiki/International_Bank_Account_Number#Structure)
|
||||
*/
|
||||
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
|
||||
|
@ -30,9 +29,9 @@ open class InputValidator {
|
|||
* (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}"
|
||||
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.
|
||||
*/
|
||||
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 {
|
||||
return IbanPattern.matcher(stringToTest.replace(" ", "")).matches()
|
||||
return IbanPattern.matches(stringToTest.replace(" ", ""))
|
||||
}
|
||||
|
||||
open fun getInvalidIbanCharacters(string: String): String {
|
||||
|
@ -69,7 +68,7 @@ open class InputValidator {
|
|||
|
||||
|
||||
open fun isValidBic(stringToTest: String): Boolean {
|
||||
return BicPattern.matcher(stringToTest).matches()
|
||||
return BicPattern.matches(stringToTest)
|
||||
}
|
||||
|
||||
open fun getInvalidBicCharacters(string: String): String {
|
||||
|
@ -114,16 +113,8 @@ open class InputValidator {
|
|||
}
|
||||
|
||||
|
||||
open fun getInvalidCharacters(string: String, pattern: Pattern): String {
|
||||
val illegalCharacters = mutableSetOf<String>()
|
||||
|
||||
val matcher = pattern.matcher(string)
|
||||
|
||||
while (matcher.find()) {
|
||||
illegalCharacters.add(matcher.group())
|
||||
}
|
||||
|
||||
return illegalCharacters.joinToString("")
|
||||
open fun getInvalidCharacters(string: String, pattern: Regex): String {
|
||||
return pattern.findAll(string).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
|
||||
|
||||
import java.lang.Exception
|
||||
|
||||
|
||||
open class ExtractionResult(
|
||||
open val couldExtractText: Boolean,
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.util.extraction
|
||||
|
||||
import java.io.File
|
||||
import net.dankito.utils.multiplatform.File
|
||||
|
||||
|
||||
interface ITextExtractorRegistry {
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.util.extraction
|
||||
|
||||
import java.math.BigDecimal
|
||||
import net.dankito.utils.multiplatform.BigDecimal
|
||||
|
||||
|
||||
open class InvoiceData(
|
|
@ -1,6 +1,6 @@
|
|||
package net.dankito.banking.util.extraction
|
||||
|
||||
import java.io.File
|
||||
import net.dankito.utils.multiplatform.File
|
||||
|
||||
|
||||
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
|
||||
|
||||
import net.dankito.utils.multiplatform.toBigDecimal
|
||||
import net.dankito.text.extraction.info.invoice.InvoiceDataExtractor
|
||||
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
package net.dankito.banking.util.extraction
|
||||
|
||||
import net.dankito.utils.multiplatform.File
|
||||
import net.dankito.text.extraction.TextExtractorRegistry
|
||||
import net.dankito.text.extraction.model.ErrorType
|
||||
import java.io.File
|
||||
|
||||
|
||||
open class JavaTextExtractorRegistry(
|
|
@ -1,6 +1,5 @@
|
|||
package net.dankito.banking.util
|
||||
|
||||
import net.dankito.banking.bankfinder.InMemoryBankFinder
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
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 {
|
||||
commonMain {
|
||||
dependencies {
|
||||
implementation kotlin("stdlib-common")
|
||||
|
||||
implementation project(":BankingUiCommon")
|
||||
implementation project(":fints4k")
|
||||
api project(":BankingUiCommon")
|
||||
api project(":fints4k")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
jvmMain {
|
||||
dependencies {
|
||||
api kotlin("stdlib-jdk7")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
iosMain {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue