diff --git a/build.gradle b/build.gradle
index 0a418aa8..3892b7e0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2,99 +2,12 @@
ext {
appVersionName = '1.0.0-Alpha-10'
- appVersionCode = 10
-
/* MPP / basic dependencies */
- kotlinVersion = '1.4.21'
- kotlinCoroutinesVersion = "1.3.7"
-
-
- ktorVersion = "1.4.2"
-
javaUtilsVersion = '1.0.18'
- luceneUtilsVersion = "0.6.0"
-
-
- textExtractorVersion = "0.6.0"
-
- textInfoExtractorVersion = "1.0.1"
-
- commonsCsvVersion = "1.8"
-
-
- hbci4jVersion = '3.1.37'
-
-
- /* iOS */
-
- iOSIsRealDevice = false
- embedBitcodeValue = "marker" // Use "marker" to embed the bitcode marker (for debug builds)
-// embedBitcodeValue = "bitcode" // for release binaries
-
-
- /* Java */
-
- faviconFinderVersion = "1.0.0"
-
-
- /* Android */
-
- androidCompileSdkVersion = 30
-
- androidBuildToolsVersion = "30.0.3"
-
- androidMinSdkVersion = 21 // TODO: fix SSLv3 / TLS and set back to 16
-
- androidTargetSdkVersion = 30
-
-
- fileChooserDialogVersion = "1.3.1-androidx"
-
- androidUtilsVersion = '1.1.2'
-
- fastAdapterVersion = "5.2.4"
-
- materialDrawerVersion = "8.1.6"
-
- clansFloatingActionButtonVersion = '1.6.4'
-
- autocompleteVersion = "1.1.0"
-
- zxingVersion = "3.3.0"
-
- scytaleVersion = "1.0.1"
-
- multiDexVersion = "2.0.1"
-
- appCompatVersion = "1.1.0"
-
- androidXCoreVersion = "1.3.1"
-
- androidXNavigationVersion = "2.3.0"
-
- androidXBiometricVersion = "1.0.1"
-
- constraintLayoutVersion = "1.1.3"
-
- materialComponentsVersion = "1.1.0"
-
- daggerVersion = "2.27"
-
- roomVersion = "2.2.5"
-
- sqlCipherVersion = "4.4.0"
-
- bcryptVersion = "0.9.0"
-
-
- /* JavaFX */
-
- javaFxUtilsVersion = '1.0.9'
-
/* Test */
@@ -113,17 +26,13 @@ ext {
}
buildscript {
- ext.kotlin_version = '1.3.72'
-// ext.kotlin_version = '1.4.10'
-
repositories {
+ mavenCentral()
google()
- jcenter()
}
+
dependencies {
- classpath 'com.android.tools.build:gradle:4.0.1'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
-// classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
// Nexus staging plugin has to be downgraded to 0.10.0 to be applicable to sub projects, see https://github.com/UweTrottmann/SeriesGuide/commit/ca33e8ad2fa6cc5c426450c8aef3417ba073ca7f
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.10.0"
@@ -142,10 +51,9 @@ allprojects {
mavenLocal()
mavenCentral()
google()
- jcenter()
}
- group 'net.dankito.banking'
+ group 'net.codinux.banking'
version appVersionName
}
@@ -154,26 +62,6 @@ allprojects {
task jarAll {
dependsOn = [
"common:jvmJar",
- "fints4k:jvm6Jar",
- "fints4k-jvm:jar",
- "BankFinder:jvmJar",
- "EpcQrCodeParser:jvmJar",
- "BankingUiCommon:jvmJar",
- "fints4kBankingClient:jvmJar",
- "BankingUiCommon:jvmJar",
- "BankingJavaFxControls:jar",
- "BankingJavaFxApp:jar"
- ]
-}
-
-task packAllForXcode {
- dependsOn = [
- "common:packForXcode",
- "fints4k:packForXcode",
- "BankFinder:packForXcode",
- "EpcQrCodeParser:packForXcode",
- "BankingUiCommon:packForXcode",
- "fints4kBankingClient:packForXcode",
- "BankingUiNativeIntegration:packForXcode"
+ "fints4k:jvmJar",
]
}
\ No newline at end of file
diff --git a/common/build.gradle b/common/build.gradle
index 6b146195..66bb7f9a 100644
--- a/common/build.gradle
+++ b/common/build.gradle
@@ -1,41 +1,52 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
- id "com.android.library"
id "maven-publish"
}
ext.artifactName = "multiplatform-utils"
-def frameworkName = "MultiplatformUtils"
-
kotlin {
jvm {
- compilations.main.kotlinOptions {
- jvmTarget = "1.6"
+ compilations.all {
+ kotlinOptions.jvmTarget = '1.8'
+ }
+ withJava()
+ testRuns["test"].executionTask.configure {
+ useJUnitPlatform()
}
}
- targets {
- final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
+// js(BOTH) {
+// browser {
+// commonWebpackConfig {
+// cssSupport.enabled = true
+// }
+// }
+// }
- fromPreset(iOSTarget, 'ios') {
- binaries {
- framework {
- baseName = frameworkName
-
- embedBitcode(embedBitcodeValue)
- }
+ ios {
+ binaries {
+ framework {
+ baseName = "MultiplatformUtils"
}
}
}
+// def hostOs = System.getProperty("os.name")
+// def isMingwX64 = hostOs.startsWith("Windows")
+// def nativeTarget
+// if (hostOs == "Mac OS X") nativeTarget = macosX64('native') { binaries.executable() }
+// else if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries.executable() }
+// else if (isMingwX64) nativeTarget = mingwX64("native") { binaries.executable() }
+// else throw new GradleException("Host OS is not supported in Kotlin/Native.")
+
sourceSets {
commonMain {
dependencies {
- implementation kotlin("stdlib-common")
+
}
}
@@ -51,7 +62,6 @@ kotlin {
jvmMain {
dependencies {
- api kotlin("stdlib-jdk7")
compileOnly "org.slf4j:slf4j-api:$slf4jVersion"
@@ -79,97 +89,9 @@ kotlin {
iosMain {
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
+
}
}
}
-}
-
-
-task copyFramework {
- def buildType = project.findProperty('kotlin.build.type') ?: 'DEBUG'
- def target = project.findProperty('kotlin.target') ?: 'ios'
- def framework = kotlin.targets."$target".binaries.getFramework(buildType)
-
- dependsOn framework.linkTask
-
- doLast {
- def srcFile = framework.outputFile
- def targetDir = getProperty('configuration.build.dir')
-
- copy {
- from srcFile.parent
- into targetDir
- include "${frameworkName}.framework/**"
- include "${frameworkName}.framework.dSYM"
- }
- }
-}
-
-// 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
- }
-
}
\ No newline at end of file
diff --git a/common/src/main/AndroidManifest.xml b/common/src/main/AndroidManifest.xml
deleted file mode 100644
index d7b5d1bf..00000000
--- a/common/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
\ No newline at end of file
diff --git a/fints4k-jvm/build.gradle b/fints4k-jvm/build.gradle
deleted file mode 100644
index 377323fc..00000000
--- a/fints4k-jvm/build.gradle
+++ /dev/null
@@ -1,10 +0,0 @@
-apply plugin: 'java-library'
-apply plugin: 'kotlin'
-
-sourceCompatibility = "1.7"
-targetCompatibility = "1.7"
-
-
-dependencies {
- api project(":fints4k")
-}
\ No newline at end of file
diff --git a/fints4k/build.gradle b/fints4k/build.gradle
index f10bf355..ac9b8aaa 100644
--- a/fints4k/build.gradle
+++ b/fints4k/build.gradle
@@ -1,96 +1,75 @@
-
-buildscript {
- repositories {
- jcenter()
- }
-}
-
plugins {
id "org.jetbrains.kotlin.multiplatform"
- id "com.android.library"
id "maven-publish"
}
kotlin {
- jvm("jvm6") {
- compilations.main.kotlinOptions {
- jvmTarget = "1.6"
+ jvm {
+ compilations.all {
+ kotlinOptions.jvmTarget = '1.8'
+ }
+ withJava()
+ testRuns["test"].executionTask.configure {
+ useJUnitPlatform()
}
}
- android()
+// js(BOTH) {
+// browser {
+// commonWebpackConfig {
+// cssSupport.enabled = true
+// }
+// }
+// }
- targets {
- final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
-
- fromPreset(iOSTarget, 'ios') {
- binaries {
- framework {
- baseName = "fints4k"
-
- embedBitcode(embedBitcodeValue)
-
- export(project(":common"))
- }
+ ios {
+ binaries {
+ framework {
+ baseName = "fints4k"
}
}
}
- js() {
-
- nodejs {
- testTask {
- enabled = false
- }
- }
-
- browser {
- testTask {
- enabled = false
- }
-
- }
- }
+// def hostOs = System.getProperty("os.name")
+// def isMingwX64 = hostOs.startsWith("Windows")
+// def nativeTarget
+// if (hostOs == "Mac OS X") nativeTarget = macosX64('native') { binaries.executable() }
+// else if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries.executable() }
+// else if (isMingwX64) nativeTarget = mingwX64("native") { binaries.executable() }
+// else throw new GradleException("Host OS is not supported in Kotlin/Native.")
sourceSets {
commonMain {
dependencies {
- implementation kotlin("stdlib-common")
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlinCoroutinesVersion"
-
api project(":common")
+ implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion"
+
implementation "io.ktor:ktor-client-core:$ktorVersion"
}
}
commonTest {
dependencies {
- implementation kotlin("test-common")
- implementation kotlin("test-annotations-common")
+ implementation kotlin("test")
implementation "ch.tutteli.atrium:atrium-fluent-en_GB-common:$atriumVersion"
}
}
- jvm6Main {
+ jvmMain {
dependencies {
-// implementation "io.ktor:ktor-client-cio:$ktorVersion"
implementation "io.ktor:ktor-client-okhttp:$ktorVersion"
implementation "org.slf4j:slf4j-api:$slf4jVersion"
}
}
- jvm6Test {
+ jvmTest {
dependencies {
- implementation kotlin("test-junit")
-
- 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"
@@ -98,9 +77,9 @@ kotlin {
implementation "ch.tutteli.atrium:atrium-fluent-en_GB:$atriumVersion"
- implementation project(":BankingUiCommon")
- implementation project(":BankFinder")
- implementation project(":fints4kBankingClient")
+// implementation project(":BankingUiCommon")
+// implementation project(":BankFinder")
+// implementation project(":fints4kBankingClient")
implementation "org.apache.commons:commons-csv:1.8"
@@ -111,111 +90,36 @@ kotlin {
}
- androidMain {
- dependsOn jvm6Main
+// jsMain {
+// dependencies {
+// implementation "io.ktor:ktor-client-js:$ktorVersion"
+// }
+// }
+//
+// jsTest {
+//
+// }
- dependencies {
- implementation "io.ktor:ktor-client-android:$ktorVersion"
- }
- }
iosMain {
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
+ // ktor Native needs "-native-mt" coroutines version. Export it so that referencing applications don't need to import it on their own
+ api("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion-native-mt")
implementation "io.ktor:ktor-client-ios:$ktorVersion"
- implementation "io.ktor:ktor-client-core-native:$ktorVersion"
}
}
- jsMain {
- dependsOn commonMain
-
+ nativeMain {
dependencies {
- api kotlin("stdlib-js")
+ // ktor Native needs "-native-mt" coroutines version. Export it so that referencing applications don't need to import it on their own
+ api"org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion-native-mt"
- implementation "io.ktor:ktor-client-js:$ktorVersion"
- implementation "io.ktor:ktor-client-encoding-js:$ktorVersion"
- implementation "io.ktor:ktor-client-js-kotlinMultiplatform:$ktorVersion"
- }
- }
-
- jsTest {
- dependencies {
- implementation kotlin("test-js")
-
- implementation "ch.tutteli.atrium:atrium-fluent-en_GB-js:$atriumVersion"
+ // requires cURL to be installed on your system
+ implementation "io.ktor:ktor-client-curl:$ktorVersion"
}
}
}
-}
-
-
-// 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
- }
-
}
\ No newline at end of file
diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilderResult.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilderResult.kt
index a6497ce6..278c71c4 100644
--- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilderResult.kt
+++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/messages/MessageBuilderResult.kt
@@ -24,7 +24,7 @@ open class MessageBuilderResult(
}
open val getHighestAllowedVersion: Int?
- get() = allowedVersions.max()
+ get() = allowedVersions.maxOrNull()
open fun isSendEnteredTanMessage(): Boolean {
// contains only a ZweiSchrittTanEinreichung segment
diff --git a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt
index e4e911b6..4137579c 100644
--- a/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt
+++ b/fints4k/src/commonMain/kotlin/net/dankito/banking/fints/webclient/KtorWebClient.kt
@@ -2,10 +2,10 @@ package net.dankito.banking.fints.webclient
import io.ktor.client.HttpClient
import io.ktor.client.request.post
-import io.ktor.client.statement.HttpResponse
-import io.ktor.client.statement.readText
-import io.ktor.content.TextContent
+import io.ktor.client.request.setBody
+import io.ktor.client.statement.bodyAsText
import io.ktor.http.ContentType
+import io.ktor.http.contentType
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.cancel
@@ -38,11 +38,12 @@ open class KtorWebClient : IWebClient {
override fun post(url: String, body: String, contentType: String, userAgent: String, callback: (WebClientResponse) -> Unit) {
GlobalScope.async {
try {
- val clientResponse = client.post(url) {
- this.body = TextContent(body, contentType = ContentType.Application.OctetStream)
+ val clientResponse = client.post(url) {
+ contentType(ContentType.Application.OctetStream)
+ setBody(body)
}
- val responseBody = clientResponse.readText()
+ val responseBody = clientResponse.bodyAsText()
callback(WebClientResponse(clientResponse.status.value == 200, clientResponse.status.value, body = responseBody))
} catch (e: Exception) {
diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt
index fb5708ea..b8413ad5 100644
--- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt
+++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/messages/MessageBuilderTest.kt
@@ -15,6 +15,7 @@ import net.dankito.banking.fints.util.FinTsUtils
import net.dankito.utils.multiplatform.Date
import net.dankito.utils.multiplatform.Month
import kotlin.test.AfterTest
+import kotlin.test.Ignore
import kotlin.test.Test
@@ -191,6 +192,7 @@ class MessageBuilderTest : FinTsTestBase() {
))
}
+ @Ignore
@Test
fun createGetTransactionsMessage_WithContinuationIdSet() {
diff --git a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt
index 6c69c463..79a9e288 100644
--- a/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt
+++ b/fints4k/src/commonTest/kotlin/net/dankito/banking/fints/response/ResponseParserTest.kt
@@ -17,6 +17,7 @@ import net.dankito.banking.fints.extensions.isFalse
import net.dankito.banking.fints.extensions.isTrue
import net.dankito.banking.fints.model.Amount
import net.dankito.utils.multiplatform.Date
+import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.fail
@@ -460,6 +461,7 @@ class ResponseParserTest : FinTsTestBase() {
?: run { fail("No segment of type UserParameters found in ${result.receivedSegments}") }
}
+ @Ignore
@Test
fun parseAccountInfo() {
@@ -1315,9 +1317,9 @@ class ResponseParserTest : FinTsTestBase() {
assertCouldParseSegment(segment, segmentId, segmentNumber, segmentVersion, referenceSegmentNumber)
}
- private fun assertCouldParseSegment(segment: ReceivedSegment?, segmentId: ISegmentId, segmentNumber: Int,
+ private fun assertCouldParseSegment(segment: ReceivedSegment?, segmentId: ISegmentId, segmentNumber: Int,
segmentVersion: Int, referenceSegmentNumber: Int?) {
-
+
expect(segment).notToBeNull()
segment?.let {
@@ -1328,10 +1330,10 @@ class ResponseParserTest : FinTsTestBase() {
}
}
- private fun assertCouldParseJobParametersSegment(segment: JobParameters?, segmentId: ISegmentId, segmentNumber: Int,
+ private fun assertCouldParseJobParametersSegment(segment: JobParameters?, segmentId: ISegmentId, segmentNumber: Int,
segmentVersion: Int, referenceSegmentNumber: Int?, jobName: String,
maxCountJobs: Int, minimumCountSignatures: Int, securityClass: Int?) {
-
+
assertCouldParseSegment(segment, segmentId, segmentNumber, segmentVersion, referenceSegmentNumber)
segment?.let {
diff --git a/fints4k/src/jvm6Test/java/net/dankito/banking/fints/JavaShowcase.java b/fints4k/src/jvm6Test/java/net/dankito/banking/fints/JavaShowcase.java
deleted file mode 100644
index 6803de47..00000000
--- a/fints4k/src/jvm6Test/java/net/dankito/banking/fints/JavaShowcase.java
+++ /dev/null
@@ -1,184 +0,0 @@
-package net.dankito.banking.fints;
-
-import net.dankito.banking.fints.banks.IBankFinder;
-import net.dankito.banking.fints.banks.InMemoryBankFinder;
-import net.dankito.banking.fints.callback.FinTsClientCallback;
-import net.dankito.banking.fints.callback.SimpleFinTsClientCallback;
-import net.dankito.banking.fints.model.AccountData;
-import net.dankito.banking.fints.model.AccountFeature;
-import net.dankito.banking.fints.model.AccountTransaction;
-import net.dankito.banking.fints.model.BankData;
-import net.dankito.banking.bankfinder.BankInfo;
-import net.dankito.banking.fints.model.BankTransferData;
-import net.dankito.banking.fints.model.CustomerData;
-import net.dankito.banking.fints.model.EnterTanGeneratorAtcResult;
-import net.dankito.banking.fints.model.EnterTanResult;
-import net.dankito.banking.fints.model.TanChallenge;
-import net.dankito.banking.fints.model.TanMethod;
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium;
-import net.dankito.banking.fints.model.mapper.BankDataMapper;
-import net.dankito.banking.fints.response.client.AddAccountResponse;
-import net.dankito.banking.fints.response.client.FinTsClientResponse;
-import net.dankito.banking.fints.response.client.GetTransactionsResponse;
-import net.dankito.banking.fints.util.Java8Base64Service;
-
-import java.math.BigDecimal;
-import java.util.List;
-
-
-public class JavaShowcase {
-
- public static void main(String[] args) {
- JavaShowcase showcase = new JavaShowcase();
-
- showcase.basicShowcase();
-
- showcase.advancedShowcase();
- }
-
- private void basicShowcase() {
- // Set your bank code (Bankleitzahl) here.
- // BankInfo contains e.g. a bank's FinTS server address, country code and BIC (needed for money transfer)
- List foundBanks = new InMemoryBankFinder().findBankByNameBankCodeOrCity("");
-
- if (foundBanks.isEmpty() == false) { // please also check if bank supports FinTS 3.0
- BankData bank = new BankDataMapper().mapFromBankInfo(foundBanks.get(0));
-
- // set your customer data (customerId = username you use to log in; pin = online banking pin / password)
- CustomerData customer = new CustomerData("", "");
-
- FinTsClientCallback callback = new SimpleFinTsClientCallback(); // see advanced showcase for configuring callback
-
- FinTsClient finTsClient = new FinTsClient(callback, new Java8Base64Service());
-
- AddAccountResponse addAccountResponse = finTsClient.addAccount(bank, customer);
-
- if (addAccountResponse.isSuccessful()) {
- System.out.println("Successfully added account for " + bank.getBankCode() + " " + customer.getCustomerId());
-
- if (addAccountResponse.getBookedTransactions().isEmpty() == false) {
- System.out.println("Account transactions of last 90 days:");
- showGetTransactionsResponse(addAccountResponse);
- }
- }
- else {
- System.out.println("Could not add account for " + bank.getBankCode() + " " + customer.getCustomerId() + ":");
- showResponseError(addAccountResponse);
- }
-
- // see advanced show case what else you can do with this library, e.g. retrieving all account transactions and transferring money
- }
- }
-
- private void advancedShowcase() {
- IBankFinder bankFinder = new InMemoryBankFinder();
-
- // Set your bank code (Bankleitzahl) here. Or create BankData manually. Required fields are:
- // bankCode, bankCountryCode (Germany = 280), finTs3ServerAddress and for bank transfers bic
- List foundBanks = bankFinder.findBankByBankCode("");
-
- if (foundBanks.isEmpty() == false) { // please also check if bank supports FinTS 3.0
- BankData bank = new BankDataMapper().mapFromBankInfo(foundBanks.get(0));
-
- // set your customer data (customerId = Kontonummer in most cases, pin = online banking pin)
- CustomerData customer = new CustomerData("", "");
-
- FinTsClientCallback callback = new FinTsClientCallback() {
-
- @Override
- public TanMethod askUserForTanMethod(List extends TanMethod> supportedTanMethods, TanMethod suggestedTanMethod) {
- // E.g. show a dialog to ask for user's TAN method.
- // In most cases it's senseful to simply return suggestedTanMethod and to let
- // user select TAN method when entering TAN is required (see enterTan() below)
- return suggestedTanMethod;
- }
-
- @Override
- public EnterTanResult enterTan(CustomerData customer, TanChallenge tanChallenge) {
- // e.g. show
- // - Android: net.dankito.banking.ui.android.dialogs.EnterTanDialog
- // - JavaFX: net.dankito.banking.ui.javafx.dialogs.tan.EnterTanDialog
- return EnterTanResult.Companion.userDidNotEnterTan(); // user did not enter TAN. aborts operation
- }
-
- @Override
- public EnterTanGeneratorAtcResult enterTanGeneratorAtc(CustomerData customer, TanGeneratorTanMedium tanMedium) {
- // needed only in rare cases to synchronize TAN generator for chipTAN methods. E.g. show
- // - Android: net.dankito.banking.ui.android.dialogs.EnterAtcDialog
- return EnterTanGeneratorAtcResult.Companion.userDidNotEnterAtc(); // user did not enter TAN and ATC. aborts operation
- }
- };
-
-
- // may also check if FinTsClientForCustomer fits your needs, avoids passing bank and customer to each method
- FinTsClient finTsClient = new FinTsClient(callback, new Java8Base64Service());
-
- AddAccountResponse addAccountResponse = finTsClient.addAccount(bank, customer);
- if (addAccountResponse.isSuccessful() == false) {
- System.out.println("Could not add account for " + bank.getBankCode() + " " + customer.getCustomerId() + ":");
- showResponseError(addAccountResponse);
- return;
- }
-
- System.out.println("Successfully added account for " + bank.getBankCode() + " " + customer.getCustomerId());
-
-
- for (AccountData account : customer.getAccounts()) { // accounts are now retrieved
- if (account.supportsFeature(AccountFeature.RetrieveAccountTransactions)) {
- // Most banks support retrieving account transactions of last 90 without TAN, may also your bank.
- // Alternatively call getTransactions() to retrieve all account transactions. But then entering a TAN is required.
- GetTransactionsResponse response = finTsClient.tryGetTransactionsOfLast90DaysWithoutTan(bank, customer, account);
-
- showGetTransactionsResponse(response);
- }
-
- if (account.supportsFeature(AccountFeature.TransferMoney)) {
- // Transfer 0.01 € to yourself. Transferring money to one self doesn't require a TAN.
- BankTransferData data = new BankTransferData(customer.getName(), account.getIban(), bank.getBic(),
- new BigDecimal("0.01"), "Give me some money", false);
- FinTsClientResponse transferMoneyResponse = finTsClient.doBankTransfer(data, bank, customer, account);
-
- if (transferMoneyResponse.isSuccessful()) {
- System.out.println("Successfully transferred " + data.getAmount() + " to " + data.getCreditorIban());
- }
- else {
- showResponseError(transferMoneyResponse);
- }
- }
- }
- }
- }
-
- private static void showGetTransactionsResponse(GetTransactionsResponse response) {
- if (response.isSuccessful()) {
- System.out.println("Balance (Saldo) = " + response.getBalance());
-
- System.out.println("Account transactions (Umsätze):");
- for (AccountTransaction transaction : response.getBookedTransactions()) {
- System.out.println(transaction.toString());
- }
- }
- else {
- if (response.isStrongAuthenticationRequired()) {
- System.out.println("Sorry, your bank doesn't support retrieving account " +
- "transactions of last 90 days without TAN");
- }
- else {
- System.out.println("An error occurred:");
- showResponseError(response);
- }
- }
- }
-
- private static void showResponseError(FinTsClientResponse response) {
- if (response.getException() != null) { // something severe occurred
- System.out.println(response.getException().getMessage());
- }
-
- // error messages retrieved from bank (e.g. PIN is wrong, message contains errors, ...)
- for (String retrievedErrorMessage : response.getErrorsToShowToUser()) {
- System.out.println(retrievedErrorMessage);
- }
- }
-
-}
diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt b/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt
deleted file mode 100644
index a47a82d4..00000000
--- a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt
+++ /dev/null
@@ -1,269 +0,0 @@
-package net.dankito.banking.fints
-
-import ch.tutteli.atrium.api.fluent.en_GB.*
-import ch.tutteli.atrium.api.verbs.expect
-import net.dankito.banking.bankfinder.InMemoryBankFinder
-import net.dankito.banking.fints.callback.FinTsClientCallback
-import net.dankito.banking.fints.extensions.isTrue
-import net.dankito.banking.fints.extensions.isFalse
-import net.dankito.banking.fints.messages.datenelemente.implementierte.Dialogsprache
-import net.dankito.banking.fints.messages.datenelemente.implementierte.KundensystemStatus
-import net.dankito.banking.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanEinsatzOption
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
-import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
-import net.dankito.banking.fints.model.*
-import net.dankito.banking.fints.response.client.*
-import net.dankito.utils.multiplatform.Date
-import net.dankito.utils.multiplatform.DateFormatter
-import net.dankito.utils.multiplatform.UUID
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.atomic.AtomicReference
-import kotlin.test.DefaultAsserter.fail
-import kotlin.test.Ignore
-import kotlin.test.Test
-
-
-@Ignore // not an automatic test, supply your settings below
-open class FinTsClientTestBase {
-
- companion object {
-
- // TODO: add your settings here:
- val BankCode = ""
-
- val CustomerId = ""
-
- val Password = ""
-
-
- val DateTimeFormatForUniqueBankTransferReference = DateFormatter("yyyy-MM-dd'T'HH:mm:ss.SSS")
- }
-
-
- private var didAskUserForTanMethod = false
-
- private var didAskUserToEnterTan = false
-
-
- private val callback = object : FinTsClientCallback {
-
- override fun askUserForTanMethod(supportedTanMethods: List, suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
- didAskUserForTanMethod = true
- callback(suggestedTanMethod) // simply return suggestedTanMethod as in most cases it's the best fitting one
- }
-
- override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
- didAskUserToEnterTan = true
-
- callback(EnterTanResult.userDidNotEnterTan())
- }
-
- override fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanGeneratorTanMedium, callback: (EnterTanGeneratorAtcResult) -> Unit) {
- fail("Bank asks you to synchronize your TAN generator for card ${tanMedium.cardNumber} " +
- "(card sequence number ${tanMedium.cardSequenceNumber}). Please do this via your online banking portal or Banking UI.")
- }
-
- }
-
-
- private val underTest = FinTsClient(callback)
-
-
- private val BankDataAnonymous = BankData.anonymous("10070000", "https://fints.deutsche-bank.de/", "DEUTDEBBXXX")
-
- private val bankInfo = InMemoryBankFinder().findBankByBankCode(BankCode).first()
- private val Bank = BankData(bankInfo.bankCode, CustomerId, Password, bankInfo.pinTanAddress ?: "", bankInfo.bic, bankInfo.name)
-
-
-
- @Test
- fun getAnonymousBankInfo() {
-
- // when
- underTest.getAnonymousBankInfo(BankDataAnonymous) { result ->
-
- // then
- expect(result.successful).isTrue()
- expect(BankDataAnonymous.supportedHbciVersions).isNotEmpty()
- expect(BankDataAnonymous.tanMethodsSupportedByBank).isNotEmpty()
- expect(BankDataAnonymous.supportedJobs).isNotEmpty()
- expect(BankDataAnonymous.supportedLanguages).isNotEmpty()
- expect(BankDataAnonymous.bankName).isNotEmpty()
- }
- }
-
-
- @Test
- fun addAccount() {
-
- // given
- val response = AtomicReference()
- val countDownLatch = CountDownLatch(1)
-
-
- // when
- underTest.addAccountAsync(Bank.toAddAccountParameter()) {
- response.set(it)
- countDownLatch.countDown()
- }
-
-
- // then
- countDownLatch.await(30, TimeUnit.SECONDS)
- val result = response.get()
-
- expect(result.successful).isTrue()
-
- expect(didAskUserForTanMethod).isFalse()
-
- expect(Bank.bankName).isNotEmpty()
- expect(Bank.supportedJobs).isNotEmpty() // supported jobs are now known
- expect(Bank.tanMethodsSupportedByBank).isNotEmpty() // supported tan methods are now known
- expect(Bank.supportedHbciVersions).isNotEmpty() // supported HBIC versions are now known
- expect(Bank.supportedLanguages).isNotEmpty() // supported languages are now known
-
- expect(Bank.customerName).isNotEmpty()
- expect(Bank.tanMethodsAvailableForUser).isNotEmpty()
- expect(Bank.selectedLanguage).notToBe(Dialogsprache.Default) // language is set now
- expect(Bank.customerSystemId).notToBe(KundensystemStatus.SynchronizingCustomerSystemId.code) // customer system id is now set
- expect(Bank.customerSystemStatus).toBe(KundensystemStatusWerte.Benoetigt) // customerSystemStatus is set now
- expect(Bank.accounts).isNotEmpty() // accounts are now known
- expect(Bank.accounts.first().allowedJobs).isNotEmpty() // allowed jobs are now known
- }
-
-
- @ExperimentalWithOptions
- @Test
- fun getTransactions() {
-
- // given
- val response = AtomicReference()
- val countDownLatch = CountDownLatch(1)
-
- underTest.addAccountAsync(Bank.toAddAccountParameter(false)) { // retrieve basic data, e.g. accounts
- val account = Bank.accounts.firstOrNull { it.supportsFeature(AccountFeature.RetrieveAccountTransactions) }
- expect(account).withRepresentation("We need at least one account that supports retrieving account transactions (${CustomerSegmentId.AccountTransactionsMt940.id})").notToBeNull()
-
- // when
-
- // some banks support retrieving account transactions of last 90 days without TAN
- underTest.tryGetAccountTransactionsOfLast90DaysWithoutTan(Bank, account!!) {
- response.set(it)
- countDownLatch.countDown()
- }
- }
-
-
- // then
- countDownLatch.await(30, TimeUnit.SECONDS)
- val result = response.get()
-
- expect(result.successful).isTrue()
- expect(result.retrievedData.map { it.bookedTransactions }).isNotEmpty()
- }
-
-
- @Test
- fun getTanMediaList() {
-
- // this test is only senseful for accounts using chipTAN / TAN generator as TAN method
-
- // given
- val response = AtomicReference()
- val countDownLatch = CountDownLatch(1)
- val anonymousBankInfoCountDownLatch = CountDownLatch(1)
-
-
- underTest.getAnonymousBankInfo(Bank) {
- anonymousBankInfoCountDownLatch.countDown()
- }
- anonymousBankInfoCountDownLatch.await(30, TimeUnit.SECONDS)
-
-
- val supportsRetrievingTanMedia = Bank.supportedJobs.firstOrNull { it.jobName == "HKTAB" } != null
-
- if (supportsRetrievingTanMedia == false) { // accounts with appTAN, pushTAN, smsTAN, ... would fail here -> simply return
- println("Bank ${Bank.bankName} does not support retrieving TAN media. Therefore cannot execute test getTanMediaList()")
- return
- }
-
- expect(Bank.tanMedia).isEmpty()
-
-
- // when
- underTest.getTanMediaList(Bank, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien) { result ->
- response.set(result)
- countDownLatch.countDown()
- }
-
- // then
- countDownLatch.await(30, TimeUnit.SECONDS)
- val result = response.get()
-
- expect(result.successful).isTrue()
-
- expect(result.tanMediaList).notToBeNull()
- expect(result.tanMediaList!!.usageOption).toBe(TanEinsatzOption.KundeKannGenauEinMediumZuEinerZeitNutzen) // TODO: may adjust to your value
- expect(result.tanMediaList!!.tanMedia).isNotEmpty()
-
- expect(Bank.tanMedia).isNotEmpty()
- }
-
- @Ignore // only works with banks that don't support HKTAB version 5
- @Test
- fun getTanMediaList_UnsupportedTanMediumClass() {
-
- // when
- expect {
- underTest.getTanMediaList(Bank, TanMedienArtVersion.Alle, TanMediumKlasse.BilateralVereinbart) { }
- }.toThrow()
-
-
- // then
- // exception gets thrown
- }
-
-
- @ExperimentalWithOptions
- @Test
- fun testBankTransfer() {
-
- // given
- val response = AtomicReference()
- val countDownLatch = CountDownLatch(1)
-
- underTest.addAccountAsync(Bank.toAddAccountParameter(false)) { // retrieve basic data, e.g. accounts
- // we need at least one account that supports cash transfer
- val account = Bank.accounts.firstOrNull { it.supportsFeature(AccountFeature.TransferMoney) }
- expect(account).withRepresentation("We need at least one account that supports cash transfer (${CustomerSegmentId.SepaBankTransfer.id})").notToBeNull()
-
- // IBAN should be set
- expect(account?.iban).withRepresentation("Account IBAN must be set").notToBeNull()
-
- // transfer 1 cent to yourself. Transferring money to oneself also doesn't require to enter a TAN according to PSD2
- val BankTransferData = BankTransferData(Bank.customerName, account?.iban!!, Bank.bic, Money(Amount("0,01"), "EUR"),
- "${DateTimeFormatForUniqueBankTransferReference.format(Date())} Test transaction ${UUID.random()}")
-
-
- // when
- underTest.doBankTransferAsync(BankTransferData, Bank, account) { result ->
- response.set(result)
- countDownLatch.countDown()
- }
-
- }
-
-
- // then
- countDownLatch.await(30, TimeUnit.SECONDS)
- val result = response.get()
-
- expect(result.successful).isTrue()
-
- }
-
-}
\ No newline at end of file
diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/bankdetails/BanksFinTsDetailsRetriever.kt b/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/bankdetails/BanksFinTsDetailsRetriever.kt
deleted file mode 100644
index 8cb41eb7..00000000
--- a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/bankdetails/BanksFinTsDetailsRetriever.kt
+++ /dev/null
@@ -1,317 +0,0 @@
-package net.dankito.banking.fints.bankdetails
-
-import kotlinx.coroutines.runBlocking
-import net.dankito.banking.bankfinder.InMemoryBankFinder
-import net.dankito.banking.fints.callback.NoOpFinTsClientCallback
-import net.dankito.banking.fints.messages.MessageBuilder
-import net.dankito.banking.fints.messages.MessageBuilderResult
-import net.dankito.banking.fints.messages.Separators
-import net.dankito.banking.fints.messages.datenelemente.implementierte.Dialogsprache
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.AuftraggeberkontoErforderlich
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.BezeichnungDesTanMediumsErforderlich
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.SmsAbbuchungskontoErforderlich
-import net.dankito.banking.fints.model.*
-import net.dankito.banking.bankfinder.BankInfo
-import net.dankito.banking.fints.FinTsJobExecutor
-import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
-import net.dankito.banking.fints.model.mapper.ModelMapper
-import net.dankito.banking.fints.response.BankResponse
-import net.dankito.banking.fints.response.segments.SepaAccountInfoParameters
-import net.dankito.banking.fints.response.segments.TanInfo
-import net.dankito.banking.fints.response.segments.TanMethodParameters
-import net.dankito.banking.fints.util.*
-import org.apache.commons.csv.CSVFormat
-import org.apache.commons.csv.CSVPrinter
-import org.junit.Ignore
-import kotlin.test.Test
-import org.slf4j.LoggerFactory
-import java.io.File
-import java.io.FileWriter
-import java.text.SimpleDateFormat
-import java.util.*
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
-import java.util.concurrent.atomic.AtomicReference
-
-
-@Ignore // not a real test, run manually to retrieve FinTS information from all banks
-class BanksFinTsDetailsRetriever {
-
- companion object {
- private val OutputFolderDateFormat = SimpleDateFormat("yyyy_MM_dd_HH_mm_ss")
-
- private val log = LoggerFactory.getLogger(BanksFinTsDetailsRetriever::class.java)
- }
-
-
- private val bankFinder = InMemoryBankFinder()
-
- private val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
-
- private val messageBuilder = MessageBuilder()
-
- private val modelMapper = object : ModelMapper(messageBuilder) {
-
- fun mapToTanMethodTypePublic(parameters: TanMethodParameters): TanMethodType? {
- return super.mapToTanMethodType(parameters)
- }
-
- }
-
- private val jobExecutor = object : FinTsJobExecutor(modelMapper = modelMapper) {
-
- fun getAndHandleResponseForMessagePublic(context: JobContext, message: MessageBuilderResult, callback: (BankResponse) -> Unit) {
- getAndHandleResponseForMessage(context, message, callback)
- }
- }
-
-
- private val requestNotSuccessful = mutableListOf()
-
- private val tanMethodParameter = mutableMapOf>()
- private val tanMethodTypes = mutableMapOf>()
-
- private val tanMethodParameterTechnicalIdentification = mutableSetOf()
- private val tanMethodParameterVersionDkTanMethod = mutableSetOf()
-
- private val requiresSmsAbbuchungskonto = mutableListOf()
- private val requiresAuftraggeberkonto = mutableListOf()
- private val requiresChallengeClass = mutableListOf()
- private val signatureStructured = mutableListOf()
- private val requiresNameOfTanMedia = mutableListOf()
- private val requiresHhdUcResponse = mutableListOf()
-
- private val doesNotSupportHKTAN6 = mutableListOf()
- private val doesNotSupportHKSAL5or7 = mutableListOf()
- private val doesNotSupportHKKAZ5to7 = mutableListOf()
- private val doesNotSupportHKCCS1 = mutableListOf()
-
- private val supportsHhd13 = mutableListOf()
- private val supportsHhd14 = mutableListOf()
-
- private val doesNotSupportPain_001_001_or_003_03 = mutableListOf()
-
-
- @Test
- fun retrieveAllBanksFinTsDetails() {
-
- val allBanks = bankFinder.getBankList()
- val banksSupportingFinTs = allBanks.filter { it.supportsFinTs3_0 }
-
- val outputFolder = File("bankData", OutputFolderDateFormat.format(Date()))
- val responsesFolder = File(outputFolder, "responses")
- responsesFolder.mkdirs()
-
- val csvFile = FileWriter(File(outputFolder, "bank_details.csv"))
- val csvPrinter = CSVPrinter(csvFile, CSVFormat.DEFAULT.withHeader(
- "BLZ", "Name", "Ort", "BPD", "Tanverfahren", "Technische Tanverfahrennamen", "HHD 1.3?", "HHD 1.4?",
- "HKTAN 6?", "HKTAN", "HKSAL 5?", "HKSAL", "HKKAZ 5-7?", "HKKAZ", "HKCAZ", "HKCCS 1?", "HKCCS",
- "pain.001.001.03?", "SEPA Formate", "Sprachen", "Untersstützte Geschäftsvorfälle"
- ))
-
-
- val uniqueBanks = banksSupportingFinTs.associateBy { "${it.bankCode}_${it.name}" }
- var bankIndex = 0
-
- uniqueBanks.forEach { bankName, bankInfo ->
- log.info("[${++bankIndex}] Getting details for $bankName ...")
-
- getAndSaveBankDetails(bankInfo, responsesFolder, csvPrinter)
- }
-
- printStatistics()
-
- csvPrinter.close()
- csvFile.close()
- }
-
-
- private fun getAnonymousBankInfo(bank: BankData): BankResponse {
- val context = JobContext(JobContextType.AnonymousBankInfo, SimpleFinTsClientCallback(), product, bank)
- context.startNewDialog()
-
- val requestBody = messageBuilder.createAnonymousDialogInitMessage(context)
-
- val anonymousBankInfoResponse = AtomicReference()
- val countDownLatch = CountDownLatch(1)
-
- jobExecutor.getAndHandleResponseForMessagePublic(context, requestBody) {
- anonymousBankInfoResponse.set(it)
- countDownLatch.countDown()
- }
-
- countDownLatch.await(30, TimeUnit.SECONDS)
-
- modelMapper.updateBankData(bank, anonymousBankInfoResponse.get())
-
- return anonymousBankInfoResponse.get()
- }
-
- private fun getAndSaveBankDetails(bankInfo: BankInfo, responsesFolder: File, csvPrinter: CSVPrinter) = runBlocking {
- val bank = BankData.anonymous(bankInfo.bankCode, bankInfo.pinTanAddress ?: "", bankInfo.bic)
- bank.bankName = bankInfo.name
-
- val anonymousBankInfoResponse = getAnonymousBankInfo(bank)
-
- File(responsesFolder, "${bankInfo.bankCode}_${bankInfo.name.replace('/', '-')}").writeText(
- anonymousBankInfoResponse.receivedSegments.joinToString(System.lineSeparator()) { it.segmentString + Separators.SegmentSeparator })
-
- if (anonymousBankInfoResponse.successful == false) {
- requestNotSuccessful.add(bankInfo)
- log.warn("Did not receive response from bank $bankInfo: ${anonymousBankInfoResponse.receivedSegments.joinToString(System.lineSeparator()) { it.segmentString + Separators.SegmentSeparator }}")
-
- return@runBlocking
- }
-
-
- val supportsHKTAN6 = supportsJobInVersion(bank, "HKTAN", 6)
- val supportsHKSAL5or7 = supportsJobInVersion(bank, "HKSAL", listOf(5, 7))
- val supportsHKKAZ5to7 = supportsJobInVersion(bank, "HKKAZ", listOf(5, 6, 7))
- val supportsHKCCS1 = supportsJobInVersion(bank, "HKCCS", 1)
-
- val tanInfo = anonymousBankInfoResponse.receivedSegments.filterIsInstance(TanInfo::class.java)
- val tanMethodParameters = tanInfo.flatMap { it.tanProcedureParameters.methodParameters }
- val supportedTanMethods = tanMethodParameters.map { it.technicalTanMethodIdentification }
- val hhd13Supported = supportedTanMethods.firstOrNull { it.startsWith("hhd1.3", true) } != null
- val hhd14Supported = supportedTanMethods.firstOrNull { it.startsWith("hhd1.4", true) } != null
-
- val supportedHKTANVersions = tanInfo.map { it.segmentVersion }
- val supportedHKSALVersions = getSupportedVersions(bank, "HKSAL")
- val supportedHKKAZVersions = getSupportedVersions(bank, "HKKAZ")
- val supportedHKCAZVersions = getSupportedVersions(bank, "HKCAZ")
- val supportedHKCCSVersions = getSupportedVersions(bank, "HKCCS")
-
- val sepaAccountInfoParameters = anonymousBankInfoResponse.receivedSegments.filterIsInstance()
- val supportedSepaFormats = sepaAccountInfoParameters.flatMap { it.supportedSepaFormats }.map { it.substring(it.indexOf(":xsd:") + ":xsd:".length) }
- val supportsPain_001_001_or_003_03 = supportedSepaFormats.firstOrNull { it.contains("pain.001.001.03") or it.contains("pain.001.003.03") } != null
-
- csvPrinter.printRecord(bankInfo.bankCode, bankInfo.name, bankInfo.city,
- bank.bpdVersion,
- bank.tanMethodsSupportedByBank.joinToString(", ") { it.securityFunction.code + ": " + it.displayName + " (" + it.type + ")" },
- supportedTanMethods.joinToString(", "),
- hhd13Supported,
- hhd14Supported,
- supportsHKTAN6,
- supportedHKTANVersions.joinToString(", "),
- supportsHKSAL5or7,
- supportedHKSALVersions.joinToString(", "),
- supportsHKKAZ5to7,
- supportedHKKAZVersions.joinToString(", "),
- supportedHKCAZVersions.joinToString(", "),
- supportsHKCCS1,
- supportedHKCCSVersions.joinToString(", "),
- supportsPain_001_001_or_003_03,
- supportedSepaFormats.joinToString(", "),
- bank.supportedLanguages.filter { it != Dialogsprache.German }.joinToString(", ") { it.name },
- bank.supportedJobs.joinToString(", ") { it.jobName + " " + it.segmentVersion }
- )
-
- tanMethodParameters.forEach { methodParameter ->
- if (tanMethodParameter.containsKey(methodParameter.methodName) == false) {
- tanMethodParameter.put(methodParameter.methodName, mutableSetOf(methodParameter))
- }
- else {
- tanMethodParameter[methodParameter.methodName]?.add(methodParameter)
- }
-
- val tanMethodType = modelMapper.mapToTanMethodTypePublic(methodParameter)
- if (tanMethodTypes.containsKey(tanMethodType) == false) {
- tanMethodTypes.put(tanMethodType, mutableSetOf(methodParameter))
- }
- else {
- tanMethodTypes[tanMethodType]?.add(methodParameter)
- }
-
- tanMethodParameterTechnicalIdentification.add(methodParameter.technicalTanMethodIdentification)
- tanMethodParameterVersionDkTanMethod.add(methodParameter.versionDkTanMethod)
-
- if (methodParameter.smsDebitAccountRequired == SmsAbbuchungskontoErforderlich.SmsAbbuchungskontoMussAngegebenWerden) {
- requiresSmsAbbuchungskonto.add(bankInfo)
- }
- if (methodParameter.initiatorAccountRequired == AuftraggeberkontoErforderlich.AuftraggeberkontoMussAngegebenWerdenWennImGeschaeftsvorfallEnthalten) {
- requiresAuftraggeberkonto.add(bankInfo)
- }
- if (methodParameter.challengeClassRequired) {
- requiresChallengeClass.add(bankInfo)
- }
- if (methodParameter.signatureStructured) {
- signatureStructured.add(bankInfo)
- }
- if (methodParameter.nameOfTanMediumRequired == BezeichnungDesTanMediumsErforderlich.BezeichnungDesTanMediumsMussAngegebenWerden) {
- requiresNameOfTanMedia.add(bankInfo)
- }
- if (methodParameter.hhdUcResponseRequired) {
- requiresHhdUcResponse.add(bankInfo)
- }
- }
-
- if (supportsHKTAN6 == false) {
- doesNotSupportHKTAN6.add(bankInfo)
- }
- if (supportsHKSAL5or7 == false) {
- doesNotSupportHKSAL5or7.add(bankInfo)
- }
- if (supportsHKKAZ5to7 == false) {
- doesNotSupportHKKAZ5to7.add(bankInfo)
- }
- if (supportsHKCCS1 == false) {
- doesNotSupportHKCCS1.add(bankInfo)
- }
-
- if (hhd13Supported) {
- supportsHhd13.add(bankInfo)
- }
- if (hhd14Supported) {
- supportsHhd14.add(bankInfo)
- }
-
- if (supportsPain_001_001_or_003_03 == false) {
- doesNotSupportPain_001_001_or_003_03.add(bankInfo)
- }
- }
-
- private fun getSupportedVersions(bank: BankData, jobName: String): List {
- return bank.supportedJobs.filter { it.jobName == jobName }.map { it.segmentVersion }
- }
-
- private fun supportsJobInVersion(bank: BankData, jobName: String, version: Int): Boolean {
- return supportsJobInVersion(bank, jobName, listOf(version))
- }
-
- private fun supportsJobInVersion(bank: BankData, jobName: String, versions: List): Boolean {
- return bank.supportedJobs.firstOrNull { it.jobName == jobName && versions.contains(it.segmentVersion) } != null
- }
-
-
- private fun printStatistics() {
- log.info("Did not receive response from Banks ${printBanks(requestNotSuccessful)}")
-
- log.info("Mapped tanMethodTypes: ${tanMethodTypes.map { System.lineSeparator() + it.key + ": " + it.value.map { it.methodName + " " + it.dkTanMethod + " " + it.technicalTanMethodIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") }}\n\n")
- log.info("TanMethodParameters:${tanMethodParameter.map { System.lineSeparator() + it.key + ": " + it.value.map { it.securityFunction.code + " " + it.dkTanMethod + " " + it.technicalTanMethodIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") } }\n\n")
-
- log.info("TanMethodParameters TechnicalIdentification:${tanMethodParameterTechnicalIdentification.joinToString(", ") } \n\n")
- log.info("TanMethodParameters VersionDkTanMethod:${tanMethodParameterVersionDkTanMethod.joinToString(", ") } \n\n")
-
- log.info("Requires SmsAbbuchungskonto ${printBanks(requiresSmsAbbuchungskonto)}") // no (only 2)
- log.info("Requires Auftraggeberkonto ${printBanks(requiresAuftraggeberkonto)}") // yes, a lot of (12631)
- log.info("Requires ChallengeClass ${printBanks(requiresChallengeClass)}") // no
- log.info("Has structured signature ${printBanks(signatureStructured)}") // yes, a lot of (12651)
- log.info("Requires NameOfTanMedia ${printBanks(requiresNameOfTanMedia)}") // yes, a lot of (912)
- log.info("Requires HhdUcResponse ${printBanks(requiresHhdUcResponse)}") // no (only 2)
-
- log.info("Banks supporting HHD 1.3 (${supportsHhd13.size}):${printBanks(supportsHhd13)}")
- log.info("Banks supporting HHD 1.4 (${supportsHhd14.size}):${printBanks(supportsHhd14)}")
-
- log.info("Banks not supporting HKTAN 6 ${printBanks(doesNotSupportHKTAN6)}")
- log.info("Banks not supporting HKSAL 5 or 7 ${printBanks(doesNotSupportHKSAL5or7)}")
- log.info("Banks not supporting HKKAZ 5-7 ${printBanks(doesNotSupportHKKAZ5to7)}")
- log.info("Banks not supporting HKCCS 1 ${printBanks(doesNotSupportHKCCS1)}")
-
- log.info("Banks not supporting pain.001.001.03 or pain.001.003.03 ${printBanks(doesNotSupportPain_001_001_or_003_03)}")
- }
-
- private fun printBanks(banks: List): String {
- return "(${banks.size}):${ banks.joinToString { System.lineSeparator() + it } }\n\n\n"
- }
-
-}
\ No newline at end of file
diff --git a/fints4k/src/jvm6Main/kotlin/net/dankito/banking/fints/util/JavaThreadPool.kt b/fints4k/src/jvmMain/kotlin/net/dankito/banking/fints/util/JavaThreadPool.kt
similarity index 100%
rename from fints4k/src/jvm6Main/kotlin/net/dankito/banking/fints/util/JavaThreadPool.kt
rename to fints4k/src/jvmMain/kotlin/net/dankito/banking/fints/util/JavaThreadPool.kt
diff --git a/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt
new file mode 100644
index 00000000..90b08afd
--- /dev/null
+++ b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/FinTsClientTestBase.kt
@@ -0,0 +1,270 @@
+//package net.dankito.banking.fints
+//
+//import ch.tutteli.atrium.api.fluent.en_GB.*
+//import ch.tutteli.atrium.api.verbs.expect
+//import jdk.nashorn.internal.ir.annotations.Ignore
+//import net.dankito.banking.bankfinder.InMemoryBankFinder
+//import net.dankito.banking.fints.callback.FinTsClientCallback
+//import net.dankito.banking.fints.extensions.isTrue
+//import net.dankito.banking.fints.extensions.isFalse
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.Dialogsprache
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.KundensystemStatus
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.KundensystemStatusWerte
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanEinsatzOption
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedienArtVersion
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMediumKlasse
+//import net.dankito.banking.fints.messages.segmente.id.CustomerSegmentId
+//import net.dankito.banking.fints.model.*
+//import net.dankito.banking.fints.response.client.*
+//import net.dankito.utils.multiplatform.Date
+//import net.dankito.utils.multiplatform.DateFormatter
+//import net.dankito.utils.multiplatform.UUID
+//import org.assertj.core.api.Assertions.assertThat
+//import org.junit.jupiter.api.Test
+//import org.junit.jupiter.api.fail
+//import java.util.concurrent.CountDownLatch
+//import java.util.concurrent.TimeUnit
+//import java.util.concurrent.atomic.AtomicReference
+//
+//
+//@Ignore // not an automatic test, supply your settings below
+//open class FinTsClientTestBase {
+//
+// companion object {
+//
+// // TODO: add your settings here:
+// val BankCode = ""
+//
+// val CustomerId = ""
+//
+// val Password = ""
+//
+//
+// val DateTimeFormatForUniqueBankTransferReference = DateFormatter("yyyy-MM-dd'T'HH:mm:ss.SSS")
+// }
+//
+//
+// private var didAskUserForTanMethod = false
+//
+// private var didAskUserToEnterTan = false
+//
+//
+// private val callback = object : FinTsClientCallback {
+//
+// override fun askUserForTanMethod(supportedTanMethods: List, suggestedTanMethod: TanMethod?, callback: (TanMethod?) -> Unit) {
+// didAskUserForTanMethod = true
+// callback(suggestedTanMethod) // simply return suggestedTanMethod as in most cases it's the best fitting one
+// }
+//
+// override fun enterTan(bank: BankData, tanChallenge: TanChallenge, callback: (EnterTanResult) -> Unit) {
+// didAskUserToEnterTan = true
+//
+// callback(EnterTanResult.userDidNotEnterTan())
+// }
+//
+// override fun enterTanGeneratorAtc(bank: BankData, tanMedium: TanGeneratorTanMedium, callback: (EnterTanGeneratorAtcResult) -> Unit) {
+// fail("Bank asks you to synchronize your TAN generator for card ${tanMedium.cardNumber} " +
+// "(card sequence number ${tanMedium.cardSequenceNumber}). Please do this via your online banking portal or Banking UI.")
+// }
+//
+// }
+//
+//
+// private val underTest = FinTsClient(callback)
+//
+//
+// private val BankDataAnonymous = BankData.anonymous("10070000", "https://fints.deutsche-bank.de/", "DEUTDEBBXXX")
+//
+// private val bankInfo = InMemoryBankFinder().findBankByBankCode(BankCode).first()
+// private val Bank = BankData(bankInfo.bankCode, CustomerId, Password, bankInfo.pinTanAddress ?: "", bankInfo.bic, bankInfo.name)
+//
+//
+//
+// @Test
+// fun getAnonymousBankInfo() {
+//
+// // when
+// underTest.getAnonymousBankInfo(BankDataAnonymous) { result ->
+//
+// // then
+// expect(result.successful).isTrue()
+// expect(BankDataAnonymous.supportedHbciVersions).isNotEmpty()
+// expect(BankDataAnonymous.tanMethodsSupportedByBank).isNotEmpty()
+// expect(BankDataAnonymous.supportedJobs).isNotEmpty()
+// expect(BankDataAnonymous.supportedLanguages).isNotEmpty()
+// expect(BankDataAnonymous.bankName).isNotEmpty()
+// }
+// }
+//
+//
+// @Test
+// fun addAccount() {
+//
+// // given
+// val response = AtomicReference()
+// val countDownLatch = CountDownLatch(1)
+//
+//
+// // when
+// underTest.addAccountAsync(Bank.toAddAccountParameter()) {
+// response.set(it)
+// countDownLatch.countDown()
+// }
+//
+//
+// // then
+// countDownLatch.await(30, TimeUnit.SECONDS)
+// val result = response.get()
+//
+// expect(result.successful).isTrue()
+//
+// expect(didAskUserForTanMethod).isFalse()
+//
+// expect(Bank.bankName).isNotEmpty()
+// expect(Bank.supportedJobs).isNotEmpty() // supported jobs are now known
+// expect(Bank.tanMethodsSupportedByBank).isNotEmpty() // supported tan methods are now known
+// expect(Bank.supportedHbciVersions).isNotEmpty() // supported HBIC versions are now known
+// expect(Bank.supportedLanguages).isNotEmpty() // supported languages are now known
+//
+// expect(Bank.customerName).isNotEmpty()
+// expect(Bank.tanMethodsAvailableForUser).isNotEmpty()
+// expect(Bank.selectedLanguage).notToBe(Dialogsprache.Default) // language is set now
+// expect(Bank.customerSystemId).notToBe(KundensystemStatus.SynchronizingCustomerSystemId.code) // customer system id is now set
+// expect(Bank.customerSystemStatus).toBe(KundensystemStatusWerte.Benoetigt) // customerSystemStatus is set now
+// expect(Bank.accounts).isNotEmpty() // accounts are now known
+// expect(Bank.accounts.first().allowedJobs).isNotEmpty() // allowed jobs are now known
+// }
+//
+//
+// @ExperimentalWithOptions
+// @Test
+// fun getTransactions() {
+//
+// // given
+// val response = AtomicReference()
+// val countDownLatch = CountDownLatch(1)
+//
+// underTest.addAccountAsync(Bank.toAddAccountParameter(false)) { // retrieve basic data, e.g. accounts
+// val account = Bank.accounts.firstOrNull { it.supportsFeature(AccountFeature.RetrieveAccountTransactions) }
+// expect(account).withRepresentation("We need at least one account that supports retrieving account transactions (${CustomerSegmentId.AccountTransactionsMt940.id})").notToBeNull()
+//
+// // when
+//
+// // some banks support retrieving account transactions of last 90 days without TAN
+// underTest.tryGetAccountTransactionsOfLast90DaysWithoutTan(Bank, account!!) {
+// response.set(it)
+// countDownLatch.countDown()
+// }
+// }
+//
+//
+// // then
+// countDownLatch.await(30, TimeUnit.SECONDS)
+// val result = response.get()
+//
+// assertThat(result.successful).isTrue()
+// assertThat(result.retrievedData).isNotNull()
+// }
+//
+//
+// @Test
+// fun getTanMediaList() {
+//
+// // this test is only senseful for accounts using chipTAN / TAN generator as TAN method
+//
+// // given
+// val response = AtomicReference()
+// val countDownLatch = CountDownLatch(1)
+// val anonymousBankInfoCountDownLatch = CountDownLatch(1)
+//
+//
+// underTest.getAnonymousBankInfo(Bank) {
+// anonymousBankInfoCountDownLatch.countDown()
+// }
+// anonymousBankInfoCountDownLatch.await(30, TimeUnit.SECONDS)
+//
+//
+// val supportsRetrievingTanMedia = Bank.supportedJobs.firstOrNull { it.jobName == "HKTAB" } != null
+//
+// if (supportsRetrievingTanMedia == false) { // accounts with appTAN, pushTAN, smsTAN, ... would fail here -> simply return
+// println("Bank ${Bank.bankName} does not support retrieving TAN media. Therefore cannot execute test getTanMediaList()")
+// return
+// }
+//
+// expect(Bank.tanMedia).isEmpty()
+//
+//
+// // when
+// underTest.getTanMediaList(Bank, TanMedienArtVersion.Alle, TanMediumKlasse.AlleMedien) { result ->
+// response.set(result)
+// countDownLatch.countDown()
+// }
+//
+// // then
+// countDownLatch.await(30, TimeUnit.SECONDS)
+// val result = response.get()
+//
+// expect(result.successful).isTrue()
+//
+// expect(result.tanMediaList).notToBeNull()
+// expect(result.tanMediaList!!.usageOption).toBe(TanEinsatzOption.KundeKannGenauEinMediumZuEinerZeitNutzen) // TODO: may adjust to your value
+// expect(result.tanMediaList!!.tanMedia).isNotEmpty()
+//
+// expect(Bank.tanMedia).isNotEmpty()
+// }
+//
+// @Ignore // only works with banks that don't support HKTAB version 5
+// @Test
+// fun getTanMediaList_UnsupportedTanMediumClass() {
+//
+// // when
+// expect {
+// underTest.getTanMediaList(Bank, TanMedienArtVersion.Alle, TanMediumKlasse.BilateralVereinbart) { }
+// }.toThrow()
+//
+//
+// // then
+// // exception gets thrown
+// }
+//
+//
+// @ExperimentalWithOptions
+// @Test
+// fun testBankTransfer() {
+//
+// // given
+// val response = AtomicReference()
+// val countDownLatch = CountDownLatch(1)
+//
+// underTest.addAccountAsync(Bank.toAddAccountParameter(false)) { // retrieve basic data, e.g. accounts
+// // we need at least one account that supports cash transfer
+// val account = Bank.accounts.firstOrNull { it.supportsFeature(AccountFeature.TransferMoney) }
+// expect(account).withRepresentation("We need at least one account that supports cash transfer (${CustomerSegmentId.SepaBankTransfer.id})").notToBeNull()
+//
+// // IBAN should be set
+// expect(account?.iban).withRepresentation("Account IBAN must be set").notToBeNull()
+//
+// // transfer 1 cent to yourself. Transferring money to oneself also doesn't require to enter a TAN according to PSD2
+// val BankTransferData = BankTransferData(Bank.customerName, account?.iban!!, Bank.bic, Money(Amount("0,01"), "EUR"),
+// "${DateTimeFormatForUniqueBankTransferReference.format(Date())} Test transaction ${UUID.random()}")
+//
+//
+// // when
+// underTest.doBankTransferAsync(BankTransferData, Bank, account) { result ->
+// response.set(result)
+// countDownLatch.countDown()
+// }
+//
+// }
+//
+//
+// // then
+// countDownLatch.await(30, TimeUnit.SECONDS)
+// val result = response.get()
+//
+// expect(result.successful).isTrue()
+//
+// }
+//
+//}
\ No newline at end of file
diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsTestBaseJvm.kt b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/FinTsTestBaseJvm.kt
similarity index 100%
rename from fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/FinTsTestBaseJvm.kt
rename to fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/FinTsTestBaseJvm.kt
diff --git a/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/bankdetails/BanksFinTsDetailsRetriever.kt b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/bankdetails/BanksFinTsDetailsRetriever.kt
new file mode 100644
index 00000000..3f226962
--- /dev/null
+++ b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/bankdetails/BanksFinTsDetailsRetriever.kt
@@ -0,0 +1,317 @@
+//package net.dankito.banking.fints.bankdetails
+//
+//import kotlinx.coroutines.runBlocking
+//import net.dankito.banking.bankfinder.InMemoryBankFinder
+//import net.dankito.banking.fints.callback.NoOpFinTsClientCallback
+//import net.dankito.banking.fints.messages.MessageBuilder
+//import net.dankito.banking.fints.messages.MessageBuilderResult
+//import net.dankito.banking.fints.messages.Separators
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.Dialogsprache
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.AuftraggeberkontoErforderlich
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.BezeichnungDesTanMediumsErforderlich
+//import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.SmsAbbuchungskontoErforderlich
+//import net.dankito.banking.fints.model.*
+//import net.dankito.banking.bankfinder.BankInfo
+//import net.dankito.banking.fints.FinTsJobExecutor
+//import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
+//import net.dankito.banking.fints.model.mapper.ModelMapper
+//import net.dankito.banking.fints.response.BankResponse
+//import net.dankito.banking.fints.response.segments.SepaAccountInfoParameters
+//import net.dankito.banking.fints.response.segments.TanInfo
+//import net.dankito.banking.fints.response.segments.TanMethodParameters
+//import net.dankito.banking.fints.util.*
+//import org.apache.commons.csv.CSVFormat
+//import org.apache.commons.csv.CSVPrinter
+//import org.junit.Ignore
+//import kotlin.test.Test
+//import org.slf4j.LoggerFactory
+//import java.io.File
+//import java.io.FileWriter
+//import java.text.SimpleDateFormat
+//import java.util.*
+//import java.util.concurrent.CountDownLatch
+//import java.util.concurrent.TimeUnit
+//import java.util.concurrent.atomic.AtomicReference
+//
+//
+//@Ignore // not a real test, run manually to retrieve FinTS information from all banks
+//class BanksFinTsDetailsRetriever {
+//
+// companion object {
+// private val OutputFolderDateFormat = SimpleDateFormat("yyyy_MM_dd_HH_mm_ss")
+//
+// private val log = LoggerFactory.getLogger(BanksFinTsDetailsRetriever::class.java)
+// }
+//
+//
+// private val bankFinder = InMemoryBankFinder()
+//
+// private val product: ProductData = ProductData("15E53C26816138699C7B6A3E8", "1.0.0") // TODO: get version dynamically
+//
+// private val messageBuilder = MessageBuilder()
+//
+// private val modelMapper = object : ModelMapper(messageBuilder) {
+//
+// fun mapToTanMethodTypePublic(parameters: TanMethodParameters): TanMethodType? {
+// return super.mapToTanMethodType(parameters)
+// }
+//
+// }
+//
+// private val jobExecutor = object : FinTsJobExecutor(modelMapper = modelMapper) {
+//
+// fun getAndHandleResponseForMessagePublic(context: JobContext, message: MessageBuilderResult, callback: (BankResponse) -> Unit) {
+// getAndHandleResponseForMessage(context, message, callback)
+// }
+// }
+//
+//
+// private val requestNotSuccessful = mutableListOf()
+//
+// private val tanMethodParameter = mutableMapOf>()
+// private val tanMethodTypes = mutableMapOf>()
+//
+// private val tanMethodParameterTechnicalIdentification = mutableSetOf()
+// private val tanMethodParameterVersionDkTanMethod = mutableSetOf()
+//
+// private val requiresSmsAbbuchungskonto = mutableListOf()
+// private val requiresAuftraggeberkonto = mutableListOf()
+// private val requiresChallengeClass = mutableListOf()
+// private val signatureStructured = mutableListOf()
+// private val requiresNameOfTanMedia = mutableListOf()
+// private val requiresHhdUcResponse = mutableListOf()
+//
+// private val doesNotSupportHKTAN6 = mutableListOf()
+// private val doesNotSupportHKSAL5or7 = mutableListOf()
+// private val doesNotSupportHKKAZ5to7 = mutableListOf()
+// private val doesNotSupportHKCCS1 = mutableListOf()
+//
+// private val supportsHhd13 = mutableListOf()
+// private val supportsHhd14 = mutableListOf()
+//
+// private val doesNotSupportPain_001_001_or_003_03 = mutableListOf()
+//
+//
+// @Test
+// fun retrieveAllBanksFinTsDetails() {
+//
+// val allBanks = bankFinder.getBankList()
+// val banksSupportingFinTs = allBanks.filter { it.supportsFinTs3_0 }
+//
+// val outputFolder = File("bankData", OutputFolderDateFormat.format(Date()))
+// val responsesFolder = File(outputFolder, "responses")
+// responsesFolder.mkdirs()
+//
+// val csvFile = FileWriter(File(outputFolder, "bank_details.csv"))
+// val csvPrinter = CSVPrinter(csvFile, CSVFormat.DEFAULT.withHeader(
+// "BLZ", "Name", "Ort", "BPD", "Tanverfahren", "Technische Tanverfahrennamen", "HHD 1.3?", "HHD 1.4?",
+// "HKTAN 6?", "HKTAN", "HKSAL 5?", "HKSAL", "HKKAZ 5-7?", "HKKAZ", "HKCAZ", "HKCCS 1?", "HKCCS",
+// "pain.001.001.03?", "SEPA Formate", "Sprachen", "Untersstützte Geschäftsvorfälle"
+// ))
+//
+//
+// val uniqueBanks = banksSupportingFinTs.associateBy { "${it.bankCode}_${it.name}" }
+// var bankIndex = 0
+//
+// uniqueBanks.forEach { bankName, bankInfo ->
+// log.info("[${++bankIndex}] Getting details for $bankName ...")
+//
+// getAndSaveBankDetails(bankInfo, responsesFolder, csvPrinter)
+// }
+//
+// printStatistics()
+//
+// csvPrinter.close()
+// csvFile.close()
+// }
+//
+//
+// private fun getAnonymousBankInfo(bank: BankData): BankResponse {
+// val context = JobContext(JobContextType.AnonymousBankInfo, SimpleFinTsClientCallback(), product, bank)
+// context.startNewDialog()
+//
+// val requestBody = messageBuilder.createAnonymousDialogInitMessage(context)
+//
+// val anonymousBankInfoResponse = AtomicReference()
+// val countDownLatch = CountDownLatch(1)
+//
+// jobExecutor.getAndHandleResponseForMessagePublic(context, requestBody) {
+// anonymousBankInfoResponse.set(it)
+// countDownLatch.countDown()
+// }
+//
+// countDownLatch.await(30, TimeUnit.SECONDS)
+//
+// modelMapper.updateBankData(bank, anonymousBankInfoResponse.get())
+//
+// return anonymousBankInfoResponse.get()
+// }
+//
+// private fun getAndSaveBankDetails(bankInfo: BankInfo, responsesFolder: File, csvPrinter: CSVPrinter) = runBlocking {
+// val bank = BankData.anonymous(bankInfo.bankCode, bankInfo.pinTanAddress ?: "", bankInfo.bic)
+// bank.bankName = bankInfo.name
+//
+// val anonymousBankInfoResponse = getAnonymousBankInfo(bank)
+//
+// File(responsesFolder, "${bankInfo.bankCode}_${bankInfo.name.replace('/', '-')}").writeText(
+// anonymousBankInfoResponse.receivedSegments.joinToString(System.lineSeparator()) { it.segmentString + Separators.SegmentSeparator })
+//
+// if (anonymousBankInfoResponse.successful == false) {
+// requestNotSuccessful.add(bankInfo)
+// log.warn("Did not receive response from bank $bankInfo: ${anonymousBankInfoResponse.receivedSegments.joinToString(System.lineSeparator()) { it.segmentString + Separators.SegmentSeparator }}")
+//
+// return@runBlocking
+// }
+//
+//
+// val supportsHKTAN6 = supportsJobInVersion(bank, "HKTAN", 6)
+// val supportsHKSAL5or7 = supportsJobInVersion(bank, "HKSAL", listOf(5, 7))
+// val supportsHKKAZ5to7 = supportsJobInVersion(bank, "HKKAZ", listOf(5, 6, 7))
+// val supportsHKCCS1 = supportsJobInVersion(bank, "HKCCS", 1)
+//
+// val tanInfo = anonymousBankInfoResponse.receivedSegments.filterIsInstance(TanInfo::class.java)
+// val tanMethodParameters = tanInfo.flatMap { it.tanProcedureParameters.methodParameters }
+// val supportedTanMethods = tanMethodParameters.map { it.technicalTanMethodIdentification }
+// val hhd13Supported = supportedTanMethods.firstOrNull { it.startsWith("hhd1.3", true) } != null
+// val hhd14Supported = supportedTanMethods.firstOrNull { it.startsWith("hhd1.4", true) } != null
+//
+// val supportedHKTANVersions = tanInfo.map { it.segmentVersion }
+// val supportedHKSALVersions = getSupportedVersions(bank, "HKSAL")
+// val supportedHKKAZVersions = getSupportedVersions(bank, "HKKAZ")
+// val supportedHKCAZVersions = getSupportedVersions(bank, "HKCAZ")
+// val supportedHKCCSVersions = getSupportedVersions(bank, "HKCCS")
+//
+// val sepaAccountInfoParameters = anonymousBankInfoResponse.receivedSegments.filterIsInstance()
+// val supportedSepaFormats = sepaAccountInfoParameters.flatMap { it.supportedSepaFormats }.map { it.substring(it.indexOf(":xsd:") + ":xsd:".length) }
+// val supportsPain_001_001_or_003_03 = supportedSepaFormats.firstOrNull { it.contains("pain.001.001.03") or it.contains("pain.001.003.03") } != null
+//
+// csvPrinter.printRecord(bankInfo.bankCode, bankInfo.name, bankInfo.city,
+// bank.bpdVersion,
+// bank.tanMethodsSupportedByBank.joinToString(", ") { it.securityFunction.code + ": " + it.displayName + " (" + it.type + ")" },
+// supportedTanMethods.joinToString(", "),
+// hhd13Supported,
+// hhd14Supported,
+// supportsHKTAN6,
+// supportedHKTANVersions.joinToString(", "),
+// supportsHKSAL5or7,
+// supportedHKSALVersions.joinToString(", "),
+// supportsHKKAZ5to7,
+// supportedHKKAZVersions.joinToString(", "),
+// supportedHKCAZVersions.joinToString(", "),
+// supportsHKCCS1,
+// supportedHKCCSVersions.joinToString(", "),
+// supportsPain_001_001_or_003_03,
+// supportedSepaFormats.joinToString(", "),
+// bank.supportedLanguages.filter { it != Dialogsprache.German }.joinToString(", ") { it.name },
+// bank.supportedJobs.joinToString(", ") { it.jobName + " " + it.segmentVersion }
+// )
+//
+// tanMethodParameters.forEach { methodParameter ->
+// if (tanMethodParameter.containsKey(methodParameter.methodName) == false) {
+// tanMethodParameter.put(methodParameter.methodName, mutableSetOf(methodParameter))
+// }
+// else {
+// tanMethodParameter[methodParameter.methodName]?.add(methodParameter)
+// }
+//
+// val tanMethodType = modelMapper.mapToTanMethodTypePublic(methodParameter)
+// if (tanMethodTypes.containsKey(tanMethodType) == false) {
+// tanMethodTypes.put(tanMethodType, mutableSetOf(methodParameter))
+// }
+// else {
+// tanMethodTypes[tanMethodType]?.add(methodParameter)
+// }
+//
+// tanMethodParameterTechnicalIdentification.add(methodParameter.technicalTanMethodIdentification)
+// tanMethodParameterVersionDkTanMethod.add(methodParameter.versionDkTanMethod)
+//
+// if (methodParameter.smsDebitAccountRequired == SmsAbbuchungskontoErforderlich.SmsAbbuchungskontoMussAngegebenWerden) {
+// requiresSmsAbbuchungskonto.add(bankInfo)
+// }
+// if (methodParameter.initiatorAccountRequired == AuftraggeberkontoErforderlich.AuftraggeberkontoMussAngegebenWerdenWennImGeschaeftsvorfallEnthalten) {
+// requiresAuftraggeberkonto.add(bankInfo)
+// }
+// if (methodParameter.challengeClassRequired) {
+// requiresChallengeClass.add(bankInfo)
+// }
+// if (methodParameter.signatureStructured) {
+// signatureStructured.add(bankInfo)
+// }
+// if (methodParameter.nameOfTanMediumRequired == BezeichnungDesTanMediumsErforderlich.BezeichnungDesTanMediumsMussAngegebenWerden) {
+// requiresNameOfTanMedia.add(bankInfo)
+// }
+// if (methodParameter.hhdUcResponseRequired) {
+// requiresHhdUcResponse.add(bankInfo)
+// }
+// }
+//
+// if (supportsHKTAN6 == false) {
+// doesNotSupportHKTAN6.add(bankInfo)
+// }
+// if (supportsHKSAL5or7 == false) {
+// doesNotSupportHKSAL5or7.add(bankInfo)
+// }
+// if (supportsHKKAZ5to7 == false) {
+// doesNotSupportHKKAZ5to7.add(bankInfo)
+// }
+// if (supportsHKCCS1 == false) {
+// doesNotSupportHKCCS1.add(bankInfo)
+// }
+//
+// if (hhd13Supported) {
+// supportsHhd13.add(bankInfo)
+// }
+// if (hhd14Supported) {
+// supportsHhd14.add(bankInfo)
+// }
+//
+// if (supportsPain_001_001_or_003_03 == false) {
+// doesNotSupportPain_001_001_or_003_03.add(bankInfo)
+// }
+// }
+//
+// private fun getSupportedVersions(bank: BankData, jobName: String): List {
+// return bank.supportedJobs.filter { it.jobName == jobName }.map { it.segmentVersion }
+// }
+//
+// private fun supportsJobInVersion(bank: BankData, jobName: String, version: Int): Boolean {
+// return supportsJobInVersion(bank, jobName, listOf(version))
+// }
+//
+// private fun supportsJobInVersion(bank: BankData, jobName: String, versions: List): Boolean {
+// return bank.supportedJobs.firstOrNull { it.jobName == jobName && versions.contains(it.segmentVersion) } != null
+// }
+//
+//
+// private fun printStatistics() {
+// log.info("Did not receive response from Banks ${printBanks(requestNotSuccessful)}")
+//
+// log.info("Mapped tanMethodTypes: ${tanMethodTypes.map { System.lineSeparator() + it.key + ": " + it.value.map { it.methodName + " " + it.dkTanMethod + " " + it.technicalTanMethodIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") }}\n\n")
+// log.info("TanMethodParameters:${tanMethodParameter.map { System.lineSeparator() + it.key + ": " + it.value.map { it.securityFunction.code + " " + it.dkTanMethod + " " + it.technicalTanMethodIdentification + " (" + it.descriptionToShowToUser + ")" }.toSet().joinToString(", ") } }\n\n")
+//
+// log.info("TanMethodParameters TechnicalIdentification:${tanMethodParameterTechnicalIdentification.joinToString(", ") } \n\n")
+// log.info("TanMethodParameters VersionDkTanMethod:${tanMethodParameterVersionDkTanMethod.joinToString(", ") } \n\n")
+//
+// log.info("Requires SmsAbbuchungskonto ${printBanks(requiresSmsAbbuchungskonto)}") // no (only 2)
+// log.info("Requires Auftraggeberkonto ${printBanks(requiresAuftraggeberkonto)}") // yes, a lot of (12631)
+// log.info("Requires ChallengeClass ${printBanks(requiresChallengeClass)}") // no
+// log.info("Has structured signature ${printBanks(signatureStructured)}") // yes, a lot of (12651)
+// log.info("Requires NameOfTanMedia ${printBanks(requiresNameOfTanMedia)}") // yes, a lot of (912)
+// log.info("Requires HhdUcResponse ${printBanks(requiresHhdUcResponse)}") // no (only 2)
+//
+// log.info("Banks supporting HHD 1.3 (${supportsHhd13.size}):${printBanks(supportsHhd13)}")
+// log.info("Banks supporting HHD 1.4 (${supportsHhd14.size}):${printBanks(supportsHhd14)}")
+//
+// log.info("Banks not supporting HKTAN 6 ${printBanks(doesNotSupportHKTAN6)}")
+// log.info("Banks not supporting HKSAL 5 or 7 ${printBanks(doesNotSupportHKSAL5or7)}")
+// log.info("Banks not supporting HKKAZ 5-7 ${printBanks(doesNotSupportHKKAZ5to7)}")
+// log.info("Banks not supporting HKCCS 1 ${printBanks(doesNotSupportHKCCS1)}")
+//
+// log.info("Banks not supporting pain.001.001.03 or pain.001.003.03 ${printBanks(doesNotSupportPain_001_001_or_003_03)}")
+// }
+//
+// private fun printBanks(banks: List): String {
+// return "(${banks.size}):${ banks.joinToString { System.lineSeparator() + it } }\n\n\n"
+// }
+//
+//}
\ No newline at end of file
diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/response/ResponseParserTestJvm.kt b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/response/ResponseParserTestJvm.kt
similarity index 96%
rename from fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/response/ResponseParserTestJvm.kt
rename to fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/response/ResponseParserTestJvm.kt
index e4a191be..0eaeb0bd 100644
--- a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/response/ResponseParserTestJvm.kt
+++ b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/response/ResponseParserTestJvm.kt
@@ -4,7 +4,7 @@ import net.dankito.banking.fints.FinTsTestBaseJvm
import net.dankito.banking.fints.messages.HbciCharset
import net.dankito.banking.fints.tan.TanImageDecoder
import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
+import org.junit.jupiter.api.Test
import java.nio.charset.Charset
diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParserTest.kt b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParserTest.kt
similarity index 95%
rename from fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParserTest.kt
rename to fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParserTest.kt
index 5586cbe0..22cd68c1 100644
--- a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParserTest.kt
+++ b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/transactions/Mt940AccountTransactionsParserTest.kt
@@ -4,7 +4,7 @@ import net.dankito.banking.fints.FinTsTestBaseJvm
import net.dankito.banking.fints.model.AccountData
import net.dankito.banking.fints.model.BankData
import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
+import org.junit.jupiter.api.Test
class Mt940AccountTransactionsParserTest : FinTsTestBaseJvm() {
diff --git a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTestJvm.kt b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTestJvm.kt
similarity index 94%
rename from fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTestJvm.kt
rename to fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTestJvm.kt
index 38b1b399..dbec106f 100644
--- a/fints4k/src/jvm6Test/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTestJvm.kt
+++ b/fints4k/src/jvmTest/kotlin/net/dankito/banking/fints/transactions/Mt940ParserTestJvm.kt
@@ -3,7 +3,7 @@ package net.dankito.banking.fints.transactions
import net.dankito.banking.fints.FinTsTestBaseJvm
import net.dankito.banking.fints.transactions.mt940.Mt940Parser
import org.assertj.core.api.Assertions.assertThat
-import org.junit.Test
+import org.junit.jupiter.api.Test
class Mt940ParserTestJvm : FinTsTestBaseJvm() {
diff --git a/fints4k/src/jvm6Test/resources/logback-test.xml b/fints4k/src/jvmTest/resources/logback-test.xml
similarity index 100%
rename from fints4k/src/jvm6Test/resources/logback-test.xml
rename to fints4k/src/jvmTest/resources/logback-test.xml
diff --git a/fints4k/src/jvm6Test/resources/test_files/Decode_TanChallengeHhdUc_WithMaskedCharacter.txt b/fints4k/src/jvmTest/resources/test_files/Decode_TanChallengeHhdUc_WithMaskedCharacter.txt
similarity index 100%
rename from fints4k/src/jvm6Test/resources/test_files/Decode_TanChallengeHhdUc_WithMaskedCharacter.txt
rename to fints4k/src/jvmTest/resources/test_files/Decode_TanChallengeHhdUc_WithMaskedCharacter.txt
diff --git a/fints4k/src/jvm6Test/resources/test_files/TransactionsMt940.txt b/fints4k/src/jvmTest/resources/test_files/TransactionsMt940.txt
similarity index 100%
rename from fints4k/src/jvm6Test/resources/test_files/TransactionsMt940.txt
rename to fints4k/src/jvmTest/resources/test_files/TransactionsMt940.txt
diff --git a/fints4k/src/jvm6Test/resources/test_files/TransactionsMt940_2.txt b/fints4k/src/jvmTest/resources/test_files/TransactionsMt940_2.txt
similarity index 100%
rename from fints4k/src/jvm6Test/resources/test_files/TransactionsMt940_2.txt
rename to fints4k/src/jvmTest/resources/test_files/TransactionsMt940_2.txt
diff --git a/fints4k/src/main/AndroidManifest.xml b/fints4k/src/main/AndroidManifest.xml
deleted file mode 100644
index aa7335e3..00000000
--- a/fints4k/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 763395f0..155302ba 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,5 +1,3 @@
-android.enableJetifier=true
-android.useAndroidX=true
kotlin.code.style=official
# Specifies the JVM arguments used for the daemon process.
@@ -7,6 +5,7 @@ kotlin.code.style=official
org.gradle.jvmargs=-Xmx3072m
-quarkusVersion=1.11.0.Final
+kotlinVersion=1.6.0
-#kotlin.js.compiler=ir
\ No newline at end of file
+coroutinesVersion=1.6.0
+ktorVersion=2.0.0-beta-1
\ No newline at end of file
diff --git a/persistence/LuceneBankingPersistence/build.gradle b/persistence/LuceneBankingPersistence/build.gradle
deleted file mode 100644
index fe208776..00000000
--- a/persistence/LuceneBankingPersistence/build.gradle
+++ /dev/null
@@ -1,30 +0,0 @@
-apply plugin: 'java-library'
-apply plugin: 'kotlin'
-
-
-sourceCompatibility = "1.7"
-targetCompatibility = "1.7"
-
-compileKotlin {
- kotlinOptions.jvmTarget = "1.6"
-}
-compileTestKotlin {
- kotlinOptions.jvmTarget = "1.6"
-}
-
-
-dependencies {
- implementation project(":BankingUiCommon")
-
- api project(":BankingPersistenceJson")
-
- implementation "net.dankito.search:lucene-4-utils:$luceneUtilsVersion"
-
-
- testImplementation "junit:junit:$junitVersion"
- testImplementation "org.assertj:assertj-core:$assertJVersion"
-
- testImplementation "org.mockito:mockito-core:$mockitoVersion"
-
- testImplementation "org.slf4j:slf4j-simple:$slf4jVersion"
-}
\ No newline at end of file
diff --git a/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/LuceneConfig.kt b/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/LuceneConfig.kt
deleted file mode 100644
index d97f0f8f..00000000
--- a/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/LuceneConfig.kt
+++ /dev/null
@@ -1,39 +0,0 @@
-package net.dankito.banking
-
-import java.io.File
-
-
-class LuceneConfig {
-
- companion object {
- const val BankAccountIdFieldName = "bank_account_id"
-
- const val IdFieldName = "id"
-
- const val OtherPartyNameFieldName = "other_party_name"
-
- const val OtherPartyBankCodeFieldName = "other_party_bank_code"
-
- const val OtherPartyAccountIdFieldName = "other_party_account_id"
-
- const val BookingDateFieldName = "booking_date"
- const val DateSortFieldName = "value_date_sort"
-
- const val ReferenceFieldName = "reference"
-
- const val BookingTextFieldName = "booking_text"
-
- const val AmountFieldName = "amount"
-
- const val CurrencyFieldName = "currency"
-
- const val BalanceFieldName = "balance"
-
-
- fun getAccountTransactionsIndexFolder(indexFolder: File): File {
- return File(indexFolder, "account_transactions")
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/persistence/LuceneBankingPersistence.kt b/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/persistence/LuceneBankingPersistence.kt
deleted file mode 100644
index 3063331b..00000000
--- a/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/persistence/LuceneBankingPersistence.kt
+++ /dev/null
@@ -1,109 +0,0 @@
-package net.dankito.banking.persistence
-
-import net.dankito.utils.multiplatform.File
-import net.dankito.banking.LuceneConfig
-import net.dankito.banking.LuceneConfig.Companion.AmountFieldName
-import net.dankito.banking.LuceneConfig.Companion.BalanceFieldName
-import net.dankito.banking.LuceneConfig.Companion.BankAccountIdFieldName
-import net.dankito.banking.LuceneConfig.Companion.BookingDateFieldName
-import net.dankito.banking.LuceneConfig.Companion.DateSortFieldName
-import net.dankito.banking.LuceneConfig.Companion.BookingTextFieldName
-import net.dankito.banking.LuceneConfig.Companion.CurrencyFieldName
-import net.dankito.banking.LuceneConfig.Companion.IdFieldName
-import net.dankito.banking.LuceneConfig.Companion.OtherPartyAccountIdFieldName
-import net.dankito.banking.LuceneConfig.Companion.OtherPartyBankCodeFieldName
-import net.dankito.banking.LuceneConfig.Companion.OtherPartyNameFieldName
-import net.dankito.banking.LuceneConfig.Companion.ReferenceFieldName
-import net.dankito.banking.ui.model.*
-import net.dankito.banking.util.ISerializer
-import net.dankito.banking.util.JacksonJsonSerializer
-import net.dankito.utils.lucene.index.DocumentsWriter
-import net.dankito.utils.lucene.index.FieldBuilder
-import org.apache.lucene.index.IndexableField
-import org.slf4j.LoggerFactory
-
-
-open class LuceneBankingPersistence(
- protected val indexFolder: File,
- databaseFolder: File,
- serializer: ISerializer = JacksonJsonSerializer()
-) : BankingPersistenceJson(databaseFolder, serializer), IBankingPersistence {
-
- companion object {
-
- // i really hate this solution, but could find no other way to avoid app crashes when
- // Android app gets restored as previous IndexWriter is not not destroyed yet and holds
- // write lock and a new IndexWriter instance in DocumentsWriter gets instantiated
- protected var documentsWriter: DocumentsWriter? = null
-
-
- private val log = LoggerFactory.getLogger(LuceneBankingPersistence::class.java)
-
- }
-
-
- protected val fields = FieldBuilder()
-
-
- override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List) {
- val writer = getWriter()
-
- transactions.forEach { transaction ->
- writer.updateDocumentForNonNullFields(
- IdFieldName, transaction.technicalId,
- *createFieldsForAccountTransaction(account, transaction).toTypedArray()
- )
- }
-
- writer.flushChangesToDisk()
- }
-
- protected open fun createFieldsForAccountTransaction(account: TypedBankAccount, transaction: IAccountTransaction): List {
- return listOf(
- fields.keywordField(BankAccountIdFieldName, account.technicalId),
- fields.nullableFullTextSearchField(OtherPartyNameFieldName, transaction.otherPartyName, true),
- fields.fullTextSearchField(ReferenceFieldName, transaction.reference, true),
- fields.nullableFullTextSearchField(BookingTextFieldName, transaction.bookingText, true),
-
- fields.nullableStoredField(OtherPartyBankCodeFieldName, transaction.otherPartyBankCode),
- fields.nullableStoredField(OtherPartyAccountIdFieldName, transaction.otherPartyAccountId),
- fields.storedField(BookingDateFieldName, transaction.bookingDate),
- fields.storedField(AmountFieldName, transaction.amount),
- fields.storedField(CurrencyFieldName, transaction.currency),
- fields.nullableStoredField(BalanceFieldName, transaction.closingBalance), // TODO: remove
-
- fields.sortField(DateSortFieldName, transaction.valueDate)
- )
- }
-
-
- override fun deleteBank(bank: TypedBankData, allBanks: List) {
- try {
- deleteAccountTransactions(bank.accounts)
- } catch (e: Exception) {
- log.error("Could not delete account transactions of account $bank", e)
- }
-
- super.deleteBank(bank, allBanks)
- }
-
- protected open fun deleteAccountTransactions(accounts: List) {
- val writer = getWriter()
-
- val accountIds = accounts.map { it.technicalId }
- writer.deleteDocumentsAndFlushChangesToDisk(BankAccountIdFieldName, *accountIds.toTypedArray())
- }
-
-
- @Synchronized
- protected open fun getWriter(): DocumentsWriter {
- documentsWriter?.let { return it }
-
- val writer = DocumentsWriter(LuceneConfig.getAccountTransactionsIndexFolder(indexFolder))
-
- documentsWriter = writer
-
- return writer
- }
-
-}
\ No newline at end of file
diff --git a/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/search/LuceneTransactionPartySearcher.kt b/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/search/LuceneTransactionPartySearcher.kt
deleted file mode 100644
index 6b5105a1..00000000
--- a/persistence/LuceneBankingPersistence/src/main/kotlin/net/dankito/banking/search/LuceneTransactionPartySearcher.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package net.dankito.banking.search
-
-import net.dankito.banking.LuceneConfig
-import net.dankito.banking.LuceneConfig.Companion.OtherPartyAccountIdFieldName
-import net.dankito.banking.LuceneConfig.Companion.OtherPartyBankCodeFieldName
-import net.dankito.banking.LuceneConfig.Companion.OtherPartyNameFieldName
-import net.dankito.utils.lucene.mapper.PropertyDescription
-import net.dankito.utils.lucene.mapper.PropertyType
-import net.dankito.utils.lucene.search.MappedSearchConfig
-import net.dankito.utils.lucene.search.QueryBuilder
-import net.dankito.utils.lucene.search.Searcher
-import java.io.File
-
-
-open class LuceneTransactionPartySearcher(indexFolder: File) : ITransactionPartySearcher {
-
- companion object {
-
- private val properties = listOf(
- PropertyDescription(PropertyType.NullableString, OtherPartyNameFieldName, TransactionParty::name),
- PropertyDescription(PropertyType.NullableString, OtherPartyBankCodeFieldName, TransactionParty::bic),
- PropertyDescription(PropertyType.NullableString, OtherPartyAccountIdFieldName, TransactionParty::iban)
- )
-
- }
-
-
- protected val queries = QueryBuilder()
-
- protected val searcher = Searcher(LuceneConfig.getAccountTransactionsIndexFolder(indexFolder))
-
-
- override fun findTransactionParty(query: String): List {
- val luceneQuery = queries.createQueriesForSingleTerms(query.toLowerCase()) { singleTerm ->
- listOf(
- queries.fulltextQuery(OtherPartyNameFieldName, singleTerm)
- )
- }
-
- return searcher.searchAndMap(MappedSearchConfig(luceneQuery, TransactionParty::class.java, properties))
- .toSet() // don't display same transaction party multiple times
- .filterNot { it.iban.isNullOrBlank() || it.bic.isNullOrBlank() } // e.g. comdirect doesn't supply other party's IBAN and BIC -> filter these as they have no value for auto-entering a transaction party's IBAN and BIC
- }
-
-}
\ No newline at end of file
diff --git a/persistence/LuceneBankingPersistence/src/test/kotlin/net/dankito/banking/search/LuceneTransactionPartySearcherTest.kt b/persistence/LuceneBankingPersistence/src/test/kotlin/net/dankito/banking/search/LuceneTransactionPartySearcherTest.kt
deleted file mode 100644
index 1c714b98..00000000
--- a/persistence/LuceneBankingPersistence/src/test/kotlin/net/dankito/banking/search/LuceneTransactionPartySearcherTest.kt
+++ /dev/null
@@ -1,235 +0,0 @@
-package net.dankito.banking.search
-
-import net.dankito.banking.persistence.LuceneBankingPersistence
-import net.dankito.banking.ui.model.BankData
-import net.dankito.banking.ui.model.AccountTransaction
-import net.dankito.banking.ui.model.BankAccount
-import net.dankito.utils.io.FileUtils
-import net.dankito.utils.multiplatform.File
-import net.dankito.utils.multiplatform.toBigDecimal
-import net.dankito.utils.multiplatform.toDate
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.mockito.Mockito.mock
-import java.math.BigDecimal
-import java.text.SimpleDateFormat
-import java.util.*
-import java.util.concurrent.ThreadLocalRandom
-
-
-class LuceneTransactionPartySearcherTest {
-
- companion object {
-
- private val dataFolder = File("testData")
-
- private val databaseFolder = File(dataFolder, "db")
-
- private val indexFolder = File(dataFolder, "index")
-
-
- private val BookingDate = "27.03.2020"
- private val OtherPartyName = "Mahatma Gandhi"
- private val OtherPartyBankCode = "12345678"
- private val OtherPartyAccountId = "0987654321"
- private val Amount = BigDecimal.valueOf(123.45)
-
-
- private val bankAccountMock = BankAccount(mock(BankData::class.java), "", "", null, null, "")
-
-
- private val dateFormat = SimpleDateFormat("dd.MM.yyyy")
-
- }
-
-
- private val fileUtils = FileUtils()
-
- private val bankingPersistence = LuceneBankingPersistence(indexFolder, databaseFolder)
-
- private val underTest = LuceneTransactionPartySearcher(indexFolder)
-
-
- @Before
- fun setUp() {
- clearDataFolder()
- }
-
- @After
- fun tearDown() {
- clearDataFolder()
- }
-
- private fun clearDataFolder() {
- fileUtils.deleteFolderRecursively(dataFolder)
- }
-
-
- @Test
- fun findTransactionParty_ByFullName() {
-
- // given
- val query = OtherPartyName
-
- val before = underTest.findTransactionParty(query)
- assertThat(before).isEmpty()
-
- bankingPersistence.saveOrUpdateAccountTransactions(bankAccountMock, listOf(
- createTransaction(bankAccountMock, BookingDate, Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(),
- createTransaction()
- ))
-
-
- // when
- val result = underTest.findTransactionParty(query)
-
-
- // then
- assertThat(result).hasSize(1)
- assertThat(result.first().name).isEqualTo(OtherPartyName)
- assertThat(result.first().bic).isEqualTo(OtherPartyBankCode)
- assertThat(result.first().iban).isEqualTo(OtherPartyAccountId)
- }
-
- @Test
- fun findTransactionParty_ByPartialName() {
-
- // given
- val query = "gand"
-
- val before = underTest.findTransactionParty(query)
- assertThat(before).isEmpty()
-
- bankingPersistence.saveOrUpdateAccountTransactions(bankAccountMock, listOf(
- createTransaction(bankAccountMock, BookingDate, Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(),
- createTransaction()
- ))
-
-
- // when
- val result = underTest.findTransactionParty(query)
-
-
- // then
- assertThat(result).hasSize(1)
- assertThat(result.first().name).isEqualTo(OtherPartyName)
- assertThat(result.first().bic).isEqualTo(OtherPartyBankCode)
- assertThat(result.first().iban).isEqualTo(OtherPartyAccountId)
- }
-
- @Test
- fun findTransactionParty_SimilarNames() {
-
- // given
- val query = "gand"
- val secondOtherPartyName = "Gandalf"
-
- val before = underTest.findTransactionParty(query)
- assertThat(before).isEmpty()
-
- bankingPersistence.saveOrUpdateAccountTransactions(bankAccountMock, listOf(
- createTransaction(bankAccountMock, BookingDate, Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(otherPartyName = secondOtherPartyName),
- createTransaction()
- ))
-
-
- // when
- val result = underTest.findTransactionParty(query)
-
-
- // then
- assertThat(result).hasSize(2)
- assertThat(result.map { it.name }).containsExactlyInAnyOrder(OtherPartyName, secondOtherPartyName)
- }
-
- @Test
- fun findTransactionParty_DuplicateEntries() {
-
- // given
- val query = OtherPartyName
-
- val before = underTest.findTransactionParty(query)
- assertThat(before).isEmpty()
-
- bankingPersistence.saveOrUpdateAccountTransactions(bankAccountMock, listOf(
- createTransaction(bankAccountMock, BookingDate, Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(bankAccountMock, "01.02.2020", Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(bankAccountMock, "03.04.2020", Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(),
- createTransaction()
- ))
-
-
- // when
- val result = underTest.findTransactionParty(query)
-
-
- // then
- assertThat(result).hasSize(1)
- assertThat(result.first().name).isEqualTo(OtherPartyName)
- assertThat(result.first().bic).isEqualTo(OtherPartyBankCode)
- assertThat(result.first().iban).isEqualTo(OtherPartyAccountId)
- }
-
- @Test
- fun findTransactionParty_OtherName() {
-
- // given
- val query = "Mandela"
-
- val before = underTest.findTransactionParty(query)
- assertThat(before).isEmpty()
-
- bankingPersistence.saveOrUpdateAccountTransactions(bankAccountMock, listOf(
- createTransaction(bankAccountMock, BookingDate, Amount, OtherPartyName, OtherPartyBankCode, OtherPartyAccountId),
- createTransaction(),
- createTransaction()
- ))
-
-
- // when
- val result = underTest.findTransactionParty(query)
-
-
- // then
- assertThat(result).isEmpty()
- }
-
-
- private fun createTransaction(bankAccount: BankAccount = bankAccountMock, bookingDate: String, amount: BigDecimal = randomBigDecimal(),
- otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(),
- otherPartyAccountId: String = randomString(), reference: String = randomString()): AccountTransaction {
-
- return createTransaction(bankAccount, dateFormat.parse(bookingDate), amount, otherPartyName,
- otherPartyBankCode, otherPartyAccountId, reference)
- }
-
- private fun createTransaction(bankAccount: BankAccount = bankAccountMock, bookingDate: Date = randomDate(), amount: BigDecimal = randomBigDecimal(),
- otherPartyName: String = randomString(), otherPartyBankCode: String = randomString(),
- otherPartyAccountId: String = randomString(), reference: String = randomString()): AccountTransaction {
-
- return AccountTransaction(bankAccount, amount.toBigDecimal(), "EUR", reference, bookingDate.toDate(), otherPartyName, otherPartyBankCode, otherPartyAccountId, null, bookingDate.toDate())
- }
-
- private fun randomString(): String {
- return UUID.randomUUID().toString()
- }
-
- private fun randomDate(): Date {
- val pseudoRandomLong = ThreadLocalRandom.current().nextLong(0, Date().time)
-
- return Date(pseudoRandomLong)
- }
-
- private fun randomBigDecimal(): BigDecimal {
- val pseudoRandomDouble = ThreadLocalRandom.current().nextDouble(-5-000.0, 12_000.0)
-
- return BigDecimal.valueOf(pseudoRandomDouble)
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/build.gradle b/persistence/database/RoomBankingPersistence/build.gradle
deleted file mode 100644
index a4c9db2b..00000000
--- a/persistence/database/RoomBankingPersistence/build.gradle
+++ /dev/null
@@ -1,39 +0,0 @@
-apply plugin: 'com.android.library'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
-apply plugin: 'kotlin-kapt'
-
-android {
- compileSdkVersion androidCompileSdkVersion
- buildToolsVersion androidBuildToolsVersion
-
- defaultConfig {
-
- minSdkVersion androidMinSdkVersion
- targetSdkVersion androidTargetSdkVersion
-
- versionName version
- versionCode appVersionCode
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- consumerProguardFiles "consumer-rules.pro"
- }
-
- buildTypes {
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
-}
-
-dependencies {
- implementation project(':BankingUiCommon')
-
- implementation "androidx.room:room-runtime:$roomVersion"
- kapt "androidx.room:room-compiler:$roomVersion"
- implementation "androidx.room:room-ktx:$roomVersion"
-
- implementation "net.zetetic:android-database-sqlcipher:$sqlCipherVersion"
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/consumer-rules.pro b/persistence/database/RoomBankingPersistence/consumer-rules.pro
deleted file mode 100644
index e69de29b..00000000
diff --git a/persistence/database/RoomBankingPersistence/proguard-rules.pro b/persistence/database/RoomBankingPersistence/proguard-rules.pro
deleted file mode 100644
index 481bb434..00000000
--- a/persistence/database/RoomBankingPersistence/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/AndroidManifest.xml b/persistence/database/RoomBankingPersistence/src/main/AndroidManifest.xml
deleted file mode 100644
index 622eda74..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- /
-
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt
deleted file mode 100644
index 6045d5f5..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package net.dankito.banking.persistence
-
-import androidx.room.Database
-import androidx.room.RoomDatabase
-import androidx.room.TypeConverters
-import net.dankito.banking.persistence.dao.*
-import net.dankito.banking.persistence.model.*
-
-
-@Database(entities = [
- Bank::class, BankAccount::class, AccountTransaction::class,
- TanMethod::class, TanMedium::class,
- AppSettings::class, TanMethodSettings::class
-], version = 1, exportSchema = false)
-@TypeConverters(net.dankito.banking.persistence.TypeConverters::class)
-abstract class BankingDatabase : RoomDatabase() {
-
- abstract fun bankDao(): BankDao
-
- abstract fun bankAccountDao(): BankAccountDao
-
- abstract fun accountTransactionDao(): AccountTransactionDao
-
- abstract fun tanMethodDao(): TanMethodDao
-
- abstract fun tanMediumDao(): TanMediumDao
-
-
- abstract fun appSettingsDao(): AppSettingsDao
-
- abstract fun tanMethodSettingsDao(): TanMethodSettingsDao
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt
deleted file mode 100644
index e061c6e1..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt
+++ /dev/null
@@ -1,286 +0,0 @@
-package net.dankito.banking.persistence
-
-import android.content.Context
-import androidx.room.Room
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.persistence.dao.saveOrUpdate
-import net.dankito.banking.persistence.model.*
-import net.dankito.banking.search.ITransactionPartySearcher
-import net.dankito.banking.search.TransactionParty
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.settings.AppSettings
-import net.dankito.banking.ui.model.tan.MobilePhoneTanMedium
-import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
-import net.dankito.banking.util.persistence.downloadIcon
-import net.dankito.utils.multiplatform.asString
-import net.sqlcipher.database.SQLiteDatabase
-import net.sqlcipher.database.SupportFactory
-import org.slf4j.LoggerFactory
-import java.util.concurrent.CopyOnWriteArraySet
-
-
-open class RoomBankingPersistence(protected open val applicationContext: Context) : IBankingPersistence, ITransactionPartySearcher {
-
- companion object {
- const val DatabaseName = "banking-database"
-
- const val AppSettingsId = 1
-
- const val FlickerCodeTanMethodSettingsId = 1
- const val QrCodeTanMethodSettingsId = 2
- const val PhotoTanTanMethodSettingsId = 3
-
- private val log = LoggerFactory.getLogger(RoomBankingPersistence::class.java)
- }
-
-
- protected lateinit var database: BankingDatabase
-
- protected open var isInitialized = false
-
- protected open val initializedListeners = CopyOnWriteArraySet<() -> Unit>()
-
-
- override fun decryptData(password: CharArray): Boolean {
- val result = openDatabase(password)
-
- if (result) {
- callInitializedListeners()
- }
-
- return result
- }
-
- override fun changePassword(newPassword: CharArray): Boolean {
- if (this::database.isInitialized) {
- val cursor = database.query("PRAGMA rekey = '${newPassword.asString()}';", emptyArray())
-
- return cursor.count == 1 // TODO: also check if first column content is 'ok' ?
- }
- else { // database hasn't been opened yet, that means we're on the first app run
- return openDatabase(newPassword)
- }
- }
-
- protected open fun openDatabase(password: CharArray): Boolean {
- try {
- val passphrase = SQLiteDatabase.getBytes(password)
- val factory = SupportFactory(passphrase)
-
- database = Room.databaseBuilder(applicationContext, BankingDatabase::class.java, DatabaseName)
- .openHelperFactory(factory)
- .build()
-
- return true
- } catch (e: Exception) {
- log.error("Could not open database", e)
- }
-
- return false
- }
-
-
- override fun saveOrUpdateBank(bank: TypedBankData, allBanks: List) {
- (bank as? Bank)?.let { bank ->
- bank.selectedTanMethodId = bank.selectedTanMethod?.technicalId
-
- database.bankDao().saveOrUpdate(bank)
-
- // TODO: in this way removed accounts won't be deleted from DB and therefore still be visible to user
- val accounts = bank.accounts.filterIsInstance()
- accounts.forEach { it.bankId = bank.id }
- database.bankAccountDao().saveOrUpdate(accounts)
-
- // TODO: in this way removed TAN methods won't be deleted from DB and therefore still be visible to user
- val tanMethods = bank.supportedTanMethods.filterIsInstance()
- tanMethods.forEach { tantanMethod ->
- if (tantanMethod.bankId == BaseDao.ObjectNotInsertedId) {
- tantanMethod.bankId = bank.id
- database.tanMethodDao().insert(tantanMethod)
- }
- else {
- database.tanMethodDao().update(tantanMethod)
- }
- }
-
- // TODO: in this way removed TAN media won't be deleted from DB and therefore still be visible to user
- val tanMedia = bank.tanMedia.map { tanMedium ->
- bank.tanMediumEntities.firstOrNull { it.id == tanMedium.technicalId } ?: map(bank, tanMedium)
- }
- database.tanMediumDao().saveOrUpdate(tanMedia)
- bank.tanMediumEntities = tanMedia
- }
- }
-
- override fun deleteBank(bank: TypedBankData, allBanks: List) {
- (bank as? Bank)?.let { bank ->
- database.accountTransactionDao().delete(bank.accounts.flatMap { it.bookedTransactions }.filterIsInstance())
-
- database.bankAccountDao().delete(bank.accounts.filterIsInstance())
-
- database.tanMethodDao().delete(bank.supportedTanMethods.filterIsInstance())
- database.tanMediumDao().delete(bank.tanMedia.filterIsInstance())
-
- database.bankDao().delete(bank)
- }
- }
-
- override fun readPersistedBanks(): List {
- val banks = database.bankDao().getAll()
-
- val accounts = database.bankAccountDao().getAll()
-
- val transactions = database.accountTransactionDao().getAll()
-
- val tanMethods = database.tanMethodDao().getAll()
-
- val tanMedia = database.tanMediumDao().getAll()
-
- banks.forEach { bank ->
- bank.accounts = accounts.filter { it.bankId == bank.id }
-
- bank.accounts.filterIsInstance().forEach { account ->
- account.bank = bank
-
- account.bookedTransactions = transactions.filter { it.accountId == account.id }
-
- account.bookedTransactions.filterIsInstance().forEach { transaction ->
- transaction.account = account
- }
- }
-
- bank.supportedTanMethods = tanMethods.filter { it.bankId == bank.id }
- bank.selectedTanMethod = bank.supportedTanMethods.firstOrNull { it.technicalId == bank.selectedTanMethodId }
-
- bank.tanMediumEntities = tanMedia.filter { it.bankId == bank.id }
- bank.tanMedia = bank.tanMediumEntities.map { map(it) }
- }
-
- return banks
- }
-
- override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List) {
- val accountId = (account as? BankAccount)?.id ?: account.technicalId.toLong()
-
- val mappedTransactions = transactions.filterIsInstance()
-
- mappedTransactions.forEach { it.accountId = accountId }
-
- database.accountTransactionDao().saveOrUpdate(mappedTransactions)
- }
-
-
- protected open fun map(bank: Bank, tanMedium: net.dankito.banking.ui.model.tan.TanMedium): TanMedium {
- val type = when (tanMedium) {
- is TanGeneratorTanMedium -> TanMediumType.TanGeneratorTanMedium
- is MobilePhoneTanMedium -> TanMediumType.MobilePhoneTanMedium
- else -> TanMediumType.OtherTanMedium
- }
-
- return TanMedium(tanMedium.technicalId, bank.id, type, tanMedium.displayName, tanMedium.status,
- (tanMedium as? TanGeneratorTanMedium)?.cardNumber, (tanMedium as? MobilePhoneTanMedium)?.phoneNumber)
- }
-
- protected open fun map(tanMedium: TanMedium): net.dankito.banking.ui.model.tan.TanMedium {
- val displayName = tanMedium.displayName
- val status = tanMedium.status
-
- val mapped = when (tanMedium.type) {
- TanMediumType.TanGeneratorTanMedium -> TanGeneratorTanMedium(displayName, status, tanMedium.cardNumber ?: "")
- TanMediumType.MobilePhoneTanMedium -> MobilePhoneTanMedium(displayName, status, tanMedium.phoneNumber)
- else -> net.dankito.banking.ui.model.tan.TanMedium(displayName, status)
- }
-
- mapped.technicalId = tanMedium.id
-
- return mapped
- }
-
-
- override fun saveOrUpdateAppSettings(appSettings: AppSettings) {
- val mapped = net.dankito.banking.persistence.model.AppSettings(appSettings.automaticallyUpdateAccountsAfterMinutes,
- appSettings.lockAppAfterMinutes, appSettings.screenshotsAllowed, appSettings.lastSelectedOpenPdfFolder, appSettings.lastSelectedImportFolder, appSettings.lastSelectedExportFolder)
- database.appSettingsDao().saveOrUpdate(mapped)
-
- saveOrUpdateTanMethodSettings(appSettings.flickerCodeSettings, FlickerCodeTanMethodSettingsId)
- saveOrUpdateTanMethodSettings(appSettings.qrCodeSettings, QrCodeTanMethodSettingsId)
- saveOrUpdateTanMethodSettings(appSettings.photoTanSettings, PhotoTanTanMethodSettingsId)
- }
-
- protected open fun saveOrUpdateTanMethodSettings(settings: net.dankito.banking.ui.model.settings.TanMethodSettings?, id: Int) {
- settings?.let {
- val settingsEntity = TanMethodSettings(id, it.width, it.height, it.space, it.frequency)
-
- database.tanMethodSettingsDao().saveOrUpdate(settingsEntity)
- }
- }
-
- override fun readPersistedAppSettings(): AppSettings? {
- val tanMethodSettings = database.tanMethodSettingsDao().getAll()
-
- val settings = AppSettings()
-
- database.appSettingsDao().getAll().firstOrNull { it.id == AppSettingsId }?.let { persistedSettings ->
- settings.automaticallyUpdateAccountsAfterMinutes = persistedSettings.automaticallyUpdateAccountsAfterMinutes
- settings.lockAppAfterMinutes = persistedSettings.lockAppAfterMinutes
- settings.screenshotsAllowed = persistedSettings.screenshotsAllowed
- settings.lastSelectedOpenPdfFolder = persistedSettings.lastSelectedOpenPdfFolder
- settings.lastSelectedImportFolder = persistedSettings.lastSelectedImportFolder
- settings.lastSelectedExportFolder = persistedSettings.lastSelectedExportFolder
- }
-
- settings.flickerCodeSettings = findTanMethodSettings(FlickerCodeTanMethodSettingsId, tanMethodSettings)
- settings.qrCodeSettings = findTanMethodSettings(QrCodeTanMethodSettingsId, tanMethodSettings)
- settings.photoTanSettings = findTanMethodSettings(PhotoTanTanMethodSettingsId, tanMethodSettings)
-
- return settings
- }
-
- protected open fun findTanMethodSettings(id: Int, settings: List): TanMethodSettings? {
- return settings.firstOrNull { it.id == id }
- }
-
-
- override fun saveBankIcon(bank: TypedBankData, iconUrl: String, fileExtension: String?) {
- val iconData = downloadIcon(iconUrl)
- bank.iconData = iconData
-
- (bank as? Bank)?.let {
- database.bankDao().saveOrUpdate(it)
- }
- }
-
-
- override fun findTransactionParty(query: String): List {
- return database.accountTransactionDao().findTransactionParty(query)
- .toSet() // don't display same transaction party multiple times
- .filterNot { it.bankCode.isNullOrBlank() || it.accountId.isNullOrBlank() }
- .map { TransactionParty(it.name, it.accountId, it.bankCode) }
- }
-
-
- override fun addInitializedListener(listener: () -> Unit) {
- if (isInitialized) {
- listener()
- } else {
- initializedListeners.add(listener)
- }
- }
-
- protected open fun callInitializedListeners() {
- isInitialized = true
- val copy = ArrayList(initializedListeners)
- initializedListeners.clear()
-
- copy.forEach { listener -> {
- try {
- listener()
- } catch (e: Exception) {
- log.error("Could not call listener $listener", e)
- }
- } }
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt
deleted file mode 100644
index b067a05c..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package net.dankito.banking.persistence
-
-import androidx.room.TypeConverter
-import net.dankito.banking.persistence.model.TanMediumType
-import net.dankito.banking.ui.model.BankAccountType
-import net.dankito.banking.ui.model.tan.AllowedTanFormat
-import net.dankito.banking.ui.model.tan.TanMediumStatus
-import net.dankito.banking.ui.model.tan.TanMethodType
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-
-
-open class TypeConverters {
-
- @TypeConverter
- fun fromMultiplatformBigDecimal(value: BigDecimal?): String? {
- return value?.toPlainString()
- }
-
- @TypeConverter
- fun toMultiplatformBigDecimal(value: String?): BigDecimal? {
- return value?.let { BigDecimal(value) }
- }
-
-
- @TypeConverter
- fun fromMultiplatformDate(value: Date?): Long? {
- return value?.millisSinceEpoch
- }
-
- @TypeConverter
- fun toMultiplatformDate(value: Long?): Date? {
- return value?.let { Date(value) }
- }
-
-
- @TypeConverter
- fun fromBankAccountType(value: BankAccountType): Int {
- return value.ordinal
- }
-
- @TypeConverter
- fun toBankAccountType(value: Int): BankAccountType {
- return BankAccountType.values().first { it.ordinal == value }
- }
-
-
- @TypeConverter
- fun fromTanMethodType(value: TanMethodType): Int {
- return value.ordinal
- }
-
- @TypeConverter
- fun toTanMethodType(value: Int): TanMethodType {
- return TanMethodType.values().first { it.ordinal == value }
- }
-
-
- @TypeConverter
- fun fromAllowedTanFormat(value: AllowedTanFormat): Int {
- return value.ordinal
- }
-
- @TypeConverter
- fun toAllowedTanFormat(value: Int): AllowedTanFormat {
- return AllowedTanFormat.values().first { it.ordinal == value }
- }
-
-
- @TypeConverter
- fun fromTanMediumStatus(value: TanMediumStatus): Int {
- return value.ordinal
- }
-
- @TypeConverter
- fun toTanMediumStatus(value: Int): TanMediumStatus {
- return TanMediumStatus.values().first { it.ordinal == value }
- }
-
-
- @TypeConverter
- fun fromTanMediumTypes(value: TanMediumType): Int {
- return value.ordinal
- }
-
- @TypeConverter
- fun toTanMediumType(value: Int): TanMediumType {
- return TanMediumType.values().first { it.ordinal == value }
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AccountTransactionDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AccountTransactionDao.kt
deleted file mode 100644
index bbb39265..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AccountTransactionDao.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.Dao
-import androidx.room.Query
-import net.dankito.banking.persistence.model.AccountTransaction
-import net.dankito.banking.persistence.model.TransactionParty
-
-
-@Dao
-interface AccountTransactionDao : BaseDao {
-
- @Query("SELECT * FROM AccountTransaction")
- fun getAll(): List
-
- @Query("SELECT otherPartyName, otherPartyBankCode, otherPartyAccountId FROM AccountTransaction WHERE otherPartyName LIKE '%' || :query || '%'")
- fun findTransactionParty(query: String): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AppSettingsDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AppSettingsDao.kt
deleted file mode 100644
index 200db798..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AppSettingsDao.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.*
-import net.dankito.banking.persistence.model.AppSettings
-
-
-@Dao
-interface AppSettingsDao : BaseDao {
-
- @Query("SELECT * FROM AppSettings")
- fun getAll(): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankAccountDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankAccountDao.kt
deleted file mode 100644
index 3a4e2af6..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankAccountDao.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.Dao
-import androidx.room.Query
-import net.dankito.banking.persistence.model.BankAccount
-
-
-@Dao
-interface BankAccountDao : BaseDao {
-
- @Query("SELECT * FROM BankAccount")
- fun getAll(): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankDao.kt
deleted file mode 100644
index ed23ede9..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankDao.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.*
-import net.dankito.banking.persistence.model.Bank
-
-
-@Dao
-interface BankDao : BaseDao {
-
- @Query("SELECT * FROM Bank")
- fun getAll(): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDao.kt
deleted file mode 100644
index 794362cb..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDao.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.*
-
-
-interface BaseDao {
-
- companion object {
- const val ObjectNotInsertedId = -1L
-
- const val IdNotSet = 0L
- }
-
-
- @Insert(onConflict = OnConflictStrategy.IGNORE)
- fun insert(obj: T): Long
-
- @Insert(onConflict = OnConflictStrategy.IGNORE)
- fun insert(obj: List): List
-
-
- @Update(onConflict = OnConflictStrategy.IGNORE)
- fun update(obj: T)
-
- @Update(onConflict = OnConflictStrategy.IGNORE)
- fun update(obj: List)
-
-
- @Delete
- fun delete(obj: T)
-
- @Delete
- fun delete(obj: List)
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDaoExtensions.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDaoExtensions.kt
deleted file mode 100644
index 28dc3c97..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDaoExtensions.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.Transaction
-import net.dankito.banking.persistence.model.*
-
-
-/* Room didn't allow me to add these methods to BaseDao directly (Kapt error), so i defined them as extension methods */
-
-@Transaction
-fun BaseDao.saveOrUpdate(obj: T) {
- val id = insert(obj)
-
- if (wasNotInserted(id)) {
- update(obj)
- }
- else {
- setId(obj, id)
- }
-}
-
-@Transaction
-fun BaseDao.saveOrUpdate(objList: List) {
- val ids = insert(objList)
-
- // i was not allowed to use mapIndexedNotNull()
- val notInsertedObjects = mutableListOf()
- ids.forEachIndexed { index, id ->
- val obj = objList[index]
-
- if (wasNotInserted(id)) {
- notInsertedObjects.add(obj)
- }
- else {
- setId(obj, id)
- }
- }
-
- update(notInsertedObjects)
-}
-
-private fun wasNotInserted(id: Long): Boolean {
- return id == BaseDao.ObjectNotInsertedId
-}
-
-private fun setId(obj: T, id: Long) {
- if (obj is Bank) {
- obj.id = id // why doesn't Room set this on itself?
- obj.technicalId = obj.id.toString()
- }
- else if (obj is BankAccount) {
- obj.id = id // why doesn't Room set this on itself?
- obj.technicalId = obj.id.toString()
- }
- else if (obj is AccountTransaction) {
- obj.id = id // why doesn't Room set this on itself?
- obj.technicalId = obj.id.toString()
- }
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMediumDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMediumDao.kt
deleted file mode 100644
index 676c48b0..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMediumDao.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.Dao
-import androidx.room.Query
-import net.dankito.banking.persistence.model.TanMedium
-
-
-@Dao
-interface TanMediumDao : BaseDao {
-
- @Query("SELECT * FROM TanMedium")
- fun getAll(): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt
deleted file mode 100644
index cae83b1a..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodDao.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.Dao
-import androidx.room.Query
-import net.dankito.banking.persistence.model.TanMethod
-
-
-@Dao
-interface TanMethodDao : BaseDao {
-
- @Query("SELECT * FROM TanMethod")
- fun getAll(): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodSettingsDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodSettingsDao.kt
deleted file mode 100644
index 1aaca077..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMethodSettingsDao.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.dankito.banking.persistence.dao
-
-import androidx.room.*
-import net.dankito.banking.persistence.model.TanMethodSettings
-
-
-@Dao
-interface TanMethodSettingsDao : BaseDao {
-
- @Query("SELECT * FROM TanMethodSettings")
- fun getAll(): List
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AccountTransaction.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AccountTransaction.kt
deleted file mode 100644
index 261df062..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AccountTransaction.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.Ignore
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.utils.multiplatform.*
-
-
-@Entity
-open class AccountTransaction(
- @Ignore
- override var account: BankAccount,
-
- override var amount: BigDecimal,
- override var currency: String,
- override var unparsedReference: String,
- override var bookingDate: Date,
- override var otherPartyName: String?,
- override var otherPartyBankCode: String?,
- override var otherPartyAccountId: String?,
- override var bookingText: String?,
- override var valueDate: Date,
- override var statementNumber: Int,
- override var sequenceNumber: Int?,
- override var openingBalance: BigDecimal?,
- override var closingBalance: BigDecimal?,
-
- override var endToEndReference: String?,
- override var customerReference: String?,
- override var mandateReference: String?,
- override var creditorIdentifier: String?,
- override var originatorsIdentificationCode: String?,
- override var compensationAmount: String?,
- override var originalAmount: String?,
- override var sepaReference: String?,
- override var deviantOriginator: String?,
- override var deviantRecipient: String?,
- override var referenceWithNoSpecialType: String?,
- override var primaNotaNumber: String?,
- override var textKeySupplement: String?,
-
- override var currencyType: String?,
- override var bookingKey: String,
- override var referenceForTheAccountOwner: String,
- override var referenceOfTheAccountServicingInstitution: String?,
- override var supplementaryDetails: String?,
-
- override var transactionReferenceNumber: String,
- override var relatedReferenceNumber: String?
-) : IAccountTransaction {
-
- // for object deserializers
- internal constructor() : this(BankAccount(), null, "", BigDecimal.Zero, Date(), null)
-
- /* convenience constructors for languages not supporting default values */
-
- constructor(account: BankAccount, otherPartyName: String?, unparsedReference: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
- : this(account, amount, "EUR", unparsedReference, valueDate,
- otherPartyName, null, null, bookingText, valueDate)
-
-
- constructor(account: BankAccount, amount: BigDecimal, currency: String, unparsedReference: String, bookingDate: Date,
- otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?,
- bookingText: String?, valueDate: Date)
- : this(account, amount, currency, unparsedReference, bookingDate,
- otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate,
- 0, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null, null, "", null)
-
-
- @PrimaryKey(autoGenerate = true)
- open var id: Long = BaseDao.IdNotSet
-
- override var technicalId: String = buildTransactionIdentifier()
-
- // Room doesn't allow me to add getters and setters -> have to map it manually
- open var accountId: Long = BaseDao.ObjectNotInsertedId
-
-
- override fun equals(other: Any?): Boolean {
- return doesEqual(other)
- }
-
- override fun hashCode(): Int {
- return calculateHashCode()
- }
-
-
- override fun toString(): String {
- return stringRepresentation
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AppSettings.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AppSettings.kt
deleted file mode 100644
index 64fd8d0c..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AppSettings.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.RoomBankingPersistence
-import net.dankito.banking.ui.model.settings.AppSettings
-
-
-@Entity
-open class AppSettings(
- open var automaticallyUpdateAccountsAfterMinutes: Int? = AppSettings.DefaultAutomaticallyUpdateAccountsAfterMinutes,
- open var lockAppAfterMinutes: Int? = null,
- open var screenshotsAllowed: Boolean = false,
- open var lastSelectedOpenPdfFolder: String? = null,
- open var lastSelectedImportFolder: String? = null,
- open var lastSelectedExportFolder: String? = null
-) {
-
- internal constructor() : this(AppSettings.DefaultAutomaticallyUpdateAccountsAfterMinutes, null, false)
-
- @PrimaryKey
- open var id: Int = RoomBankingPersistence.AppSettingsId
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt
deleted file mode 100644
index 468ce9e3..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.Ignore
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.tan.TanMedium
-import net.dankito.banking.ui.model.tan.TanMethod
-
-
-@Entity
-open class Bank(
- override var bankCode: String,
- override var userName: String,
- override var password: String,
- override var finTsServerAddress: String,
- override var bankName: String,
- override var bic: String,
- override var customerName: String,
-
- override var userId: String = userName,
- override var iconData: ByteArray? = null,
-
- @Ignore
- override var accounts: List = listOf(),
-
- @Ignore
- override var supportedTanMethods: List = listOf(),
- @Ignore
- override var selectedTanMethod: TanMethod? = null,
- @Ignore
- override var tanMedia: List = listOf(),
-
-
- @PrimaryKey(autoGenerate = true)
- open var id: Long = BaseDao.IdNotSet,
-
- override var technicalId: String = id.toString(),
-
- override var wrongCredentialsEntered: Boolean = false,
-
- override var savePassword: Boolean = true,
-
- override var userSetDisplayName: String? = null,
- override var displayIndex: Int = 0
-) : TypedBankData {
-
- internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
-
-
- open var selectedTanMethodId: String? = null
-
- @Ignore
- open var tanMediumEntities = listOf()
-
-
- override fun toString(): String {
- return stringRepresentation
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt
deleted file mode 100644
index fadc019c..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.Ignore
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.ui.model.*
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-import net.dankito.utils.multiplatform.UUID
-
-
-@Entity
-open class BankAccount(
- @Ignore
- override var bank: TypedBankData,
- override var identifier: String,
- override var accountHolderName: String,
- override var iban: String?,
- override var subAccountNumber: String?,
- override var balance: BigDecimal = BigDecimal.Zero,
- override var currency: String = "EUR",
- override var type: BankAccountType = BankAccountType.CheckingAccount,
- override var productName: String? = null,
- override var accountLimit: String? = null,
- override var retrievedTransactionsFromOn: Date? = null,
- override var retrievedTransactionsUpTo: Date? = null,
-
- override var supportsRetrievingAccountTransactions: Boolean = false,
- override var supportsRetrievingBalance: Boolean = false,
- override var supportsTransferringMoney: Boolean = false,
- override var supportsRealTimeTransfer: Boolean = false,
-
- @Ignore
- override var bookedTransactions: List = listOf(),
- @Ignore
- override var unbookedTransactions: List = listOf()
-) : TypedBankAccount {
-
- internal constructor() : this(Bank(), null, "") // for object deserializers
-
- /* convenience constructors for languages not supporting default values */
-
- constructor(bank: TypedBankData, productName: String?, identifier: String) : this(bank, productName, identifier, BankAccountType.CheckingAccount)
-
- constructor(bank: TypedBankData, productName: String?, identifier: String, type: BankAccountType = BankAccountType.CheckingAccount, balance: BigDecimal = BigDecimal.Zero)
- : this(bank, identifier, "", null, null, balance, "EUR", type, productName)
-
-
- @PrimaryKey(autoGenerate = true)
- open var id: Long = BaseDao.IdNotSet
-
- override var technicalId: String = UUID.random()
-
- // Room doesn't allow me to add getters and setters -> have to map it manually
- open var bankId: Long = BaseDao.ObjectNotInsertedId
-
-
- override var haveAllTransactionsBeenRetrieved: Boolean = false
-
- override var isAccountTypeSupportedByApplication: Boolean = true
-
- override var countDaysForWhichTransactionsAreKept: Int? = null
-
-
- override var userSetDisplayName: String? = null
-
- override var displayIndex: Int = 0
-
-
- override var hideAccount = false
-
- override var includeInAutomaticAccountsUpdate = true
-
- override var doNotShowStrikingFetchAllTransactionsView = false
-
-
- override fun toString(): String {
- return stringRepresentation
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt
deleted file mode 100644
index d61eba78..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt
+++ /dev/null
@@ -1,75 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.mapper.IModelCreator
-import net.dankito.banking.ui.model.tan.AllowedTanFormat
-import net.dankito.banking.ui.model.tan.TanMethodType
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-
-
-open class RoomModelCreator : IModelCreator {
-
- override fun createBank(
- bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String,
- bic: String, customerName: String, userId: String, iconData: ByteArray?
- ): TypedBankData {
-
- return Bank(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconData)
- }
-
- override fun createAccount(bank: TypedBankData, productName: String?, identifier: String): TypedBankAccount {
- return BankAccount(bank, productName, identifier)
- }
-
- override fun createTransaction(
- account: TypedBankAccount,
- amount: BigDecimal,
- currency: String,
- unparsedReference: String,
- bookingDate: Date,
- otherPartyName: String?,
- otherPartyBankCode: String?,
- otherPartyAccountId: String?,
- bookingText: String?,
- valueDate: Date,
- statementNumber: Int,
- sequenceNumber: Int?,
- openingBalance: BigDecimal?,
- closingBalance: BigDecimal?,
- endToEndReference: String?,
- customerReference: String?,
- mandateReference: String?,
- creditorIdentifier: String?,
- originatorsIdentificationCode: String?,
- compensationAmount: String?,
- originalAmount: String?,
- sepaReference: String?,
- deviantOriginator: String?,
- deviantRecipient: String?,
- referenceWithNoSpecialType: String?,
- primaNotaNumber: String?,
- textKeySupplement: String?,
- currencyType: String?,
- bookingKey: String,
- referenceForTheAccountOwner: String,
- referenceOfTheAccountServicingInstitution: String?,
- supplementaryDetails: String?,
- transactionReferenceNumber: String,
- relatedReferenceNumber: String?
- ): IAccountTransaction {
- return AccountTransaction(account as BankAccount, amount, currency, unparsedReference, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId,
- bookingText, valueDate, statementNumber, sequenceNumber, openingBalance, closingBalance, endToEndReference, customerReference, mandateReference,
- creditorIdentifier, originatorsIdentificationCode, compensationAmount, originalAmount, sepaReference, deviantOriginator, deviantRecipient,
- referenceWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner,
- referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber)
- }
-
-
- override fun createTanMethod(displayName: String, type: TanMethodType, bankInternalMethodCode: String, maxTanInputLength: Int?, allowedTanFormat: AllowedTanFormat): net.dankito.banking.ui.model.tan.TanMethod {
- return TanMethod(displayName, type, bankInternalMethodCode, maxTanInputLength, allowedTanFormat)
- }
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMedium.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMedium.kt
deleted file mode 100644
index 9be6843b..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMedium.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.ui.model.tan.TanMediumStatus
-
-
-@Entity
-open class TanMedium(
- @PrimaryKey
- open var id: String,
- open var bankId: Long,
-
- open var type: TanMediumType,
- open var displayName: String,
- open var status: TanMediumStatus,
- open var cardNumber: String? = null,
- open var phoneNumber: String? = null
-) {
-
- internal constructor() : this("", BaseDao.ObjectNotInsertedId, TanMediumType.OtherTanMedium, "", TanMediumStatus.Available) // for object deserializers
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMediumType.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMediumType.kt
deleted file mode 100644
index 719273a4..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMediumType.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.dankito.banking.persistence.model
-
-
-enum class TanMediumType {
-
- TanGeneratorTanMedium,
-
- MobilePhoneTanMedium,
-
- OtherTanMedium
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt
deleted file mode 100644
index a8edd57f..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethod.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.ui.model.tan.AllowedTanFormat
-import net.dankito.banking.ui.model.tan.TanMethod
-import net.dankito.banking.ui.model.tan.TanMethodType
-
-
-@Entity
-open class TanMethod(
- override var displayName: String,
- override var type: TanMethodType,
- override var bankInternalMethodCode: String,
- override var maxTanInputLength: Int? = null,
- override var allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric
-) : TanMethod(displayName, type, bankInternalMethodCode, maxTanInputLength, allowedTanFormat) {
-
- internal constructor() : this("", TanMethodType.EnterTan, "") // for object deserializers
-
-
- @PrimaryKey
- open var id: String = technicalId
-
- // Room doesn't allow me to add getters and setters -> have to map it manually
- open var bankId: Long = BaseDao.ObjectNotInsertedId
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethodSettings.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethodSettings.kt
deleted file mode 100644
index 40188863..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMethodSettings.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.Entity
-import androidx.room.PrimaryKey
-import net.dankito.banking.persistence.dao.BaseDao
-import net.dankito.banking.ui.model.settings.TanMethodSettings
-
-
-@Entity
-open class TanMethodSettings(
- @PrimaryKey
- open var id: Int,
- width: Int,
- height: Int,
- space: Int = -1,
- frequency: Int = -1
-) : TanMethodSettings(width, height, space, frequency) {
-
- internal constructor() : this(BaseDao.IdNotSet.toInt(), 0, 0) // for object deserializers
-
-}
\ No newline at end of file
diff --git a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TransactionParty.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TransactionParty.kt
deleted file mode 100644
index 7d346bbc..00000000
--- a/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TransactionParty.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import androidx.room.ColumnInfo
-
-
-data class TransactionParty(
- @ColumnInfo(name = "otherPartyName") val name: String,
-
- @ColumnInfo(name = "otherPartyBankCode") val bankCode: String?,
-
- @ColumnInfo(name = "otherPartyAccountId") val accountId: String?
-)
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/README.md b/persistence/json/BankingPersistenceJson/README.md
deleted file mode 100644
index 2e62b22f..00000000
--- a/persistence/json/BankingPersistenceJson/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# BankingPersistenceJson
-
-A simple IBankingPersistence implementation based on Json.
-
-Not meant to be a real or useful implementation. Just there to get you up and running fast.
-
-Preferably use another IBankingPersistence implementation, e.g. a JPA based one.
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/build.gradle b/persistence/json/BankingPersistenceJson/build.gradle
deleted file mode 100644
index 5177cf94..00000000
--- a/persistence/json/BankingPersistenceJson/build.gradle
+++ /dev/null
@@ -1,27 +0,0 @@
-apply plugin: 'java-library'
-apply plugin: 'kotlin'
-apply plugin: 'kotlin-kapt'
-
-
-sourceCompatibility = "1.7"
-targetCompatibility = "1.7"
-
-compileKotlin {
- kotlinOptions.jvmTarget = "1.6"
-}
-compileTestKotlin {
- kotlinOptions.jvmTarget = "1.6"
-}
-
-
-dependencies {
- implementation project(':BankingUiCommon')
-
-
- testImplementation "junit:junit:$junitVersion"
-
- testImplementation "org.assertj:assertj-core:$assertJVersion"
- testImplementation "org.mockito:mockito-core:$mockitoVersion"
-
- testImplementation "org.slf4j:slf4j-simple:$slf4jVersion"
-}
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/BankingPersistenceJson.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/BankingPersistenceJson.kt
deleted file mode 100644
index eea7e825..00000000
--- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/BankingPersistenceJson.kt
+++ /dev/null
@@ -1,101 +0,0 @@
-package net.dankito.banking.persistence
-
-import net.dankito.banking.persistence.model.BankDataEntity
-import net.dankito.banking.ui.model.*
-import net.dankito.banking.ui.model.settings.AppSettings
-import net.dankito.utils.multiplatform.File
-import net.dankito.banking.util.ISerializer
-import net.dankito.banking.util.persistence.downloadIcon
-
-
-open class BankingPersistenceJson(
- protected val databaseFolder: File,
- protected val serializer: ISerializer
-) : IBankingPersistence {
-
- companion object {
- const val BanksJsonFileName = "accounts.json"
-
- const val AppSettingsJsonFileName = "app_settings.json"
- }
-
-
- protected val banksJsonFile: File
-
- protected val appSettingsJsonFile: File
-
- protected var allBanks: List? = null
-
-
- init {
- databaseFolder.mkdirs()
-
- banksJsonFile = File(databaseFolder, BanksJsonFileName)
- appSettingsJsonFile = File(databaseFolder, AppSettingsJsonFileName)
- }
-
-
- override fun decryptData(password: CharArray): Boolean {
- // TODO: may implement data decryption. But then we have to store password to be able to encrypt data
- return true
- }
-
- override fun changePassword(newPassword: CharArray): Boolean {
- // TODO: may implement data decryption. But then we have to store newPassword to be able to encrypt data
- return true
- }
-
-
- override fun saveOrUpdateBank(bank: TypedBankData, allBanks: List) {
- saveAllBanks(allBanks)
- }
-
- override fun deleteBank(bank: TypedBankData, allBanks: List) {
- saveAllBanks(allBanks)
- }
-
- override fun readPersistedBanks(): List {
- val banks = serializer.deserializeListOr(banksJsonFile, BankDataEntity::class).map { it as TypedBankData }
-
- this.allBanks = banks
-
- return banks
- }
-
-
- override fun saveOrUpdateAccountTransactions(account: TypedBankAccount, transactions: List) {
- // done when called saveOrUpdateAccount()
- // TODO: or also call saveAllBanks()?
- }
-
-
- protected open fun saveAllBanks(allBanks: List) {
- this.allBanks = allBanks
-
- serializer.serializeObject(allBanks, banksJsonFile)
- }
-
-
- override fun saveOrUpdateAppSettings(appSettings: AppSettings) {
- serializer.serializeObject(appSettings, appSettingsJsonFile)
- }
-
- override fun readPersistedAppSettings(): AppSettings? {
- return serializer.deserializeObject(appSettingsJsonFile, AppSettings::class)
- }
-
-
- override fun saveBankIcon(bank: TypedBankData, iconUrl: String, fileExtension: String?) {
- bank.iconData = downloadIcon(iconUrl)
-
- allBanks?.let {
- saveOrUpdateBank(bank, it)
- }
- }
-
-
- override fun addInitializedListener(listener: () -> Unit) {
- listener()
- }
-
-}
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/mapper/EntitiesModelCreator.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/mapper/EntitiesModelCreator.kt
deleted file mode 100644
index cc010de6..00000000
--- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/mapper/EntitiesModelCreator.kt
+++ /dev/null
@@ -1,74 +0,0 @@
-package net.dankito.banking.persistence.mapper
-
-import net.dankito.banking.persistence.model.AccountTransactionEntity
-import net.dankito.banking.persistence.model.BankAccountEntity
-import net.dankito.banking.persistence.model.BankDataEntity
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.mapper.IModelCreator
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-
-
-open class EntitiesModelCreator : IModelCreator {
-
- override fun createBank(
- bankCode: String, userName: String, password: String, finTsServerAddress: String, bankName: String, bic: String,
- customerName: String, userId: String, iconData: ByteArray?
- ): TypedBankData {
-
- return BankDataEntity(bankCode, userName, password, finTsServerAddress, bankName, bic, customerName, userId, iconData) as TypedBankData
- }
-
-
- override fun createAccount(bank: TypedBankData, productName: String?, identifier: String): TypedBankAccount {
- return BankAccountEntity(bank as BankDataEntity, identifier, "", null, null, productName = productName) as TypedBankAccount
- }
-
- override fun createTransaction(
- account: TypedBankAccount,
- amount: BigDecimal,
- currency: String,
- unparsedReference: String,
- bookingDate: Date,
- otherPartyName: String?,
- otherPartyBankCode: String?,
- otherPartyAccountId: String?,
- bookingText: String?,
- valueDate: Date,
- statementNumber: Int,
- sequenceNumber: Int?,
- openingBalance: BigDecimal?,
- closingBalance: BigDecimal?,
- endToEndReference: String?,
- customerReference: String?,
- mandateReference: String?,
- creditorIdentifier: String?,
- originatorsIdentificationCode: String?,
- compensationAmount: String?,
- originalAmount: String?,
- sepaReference: String?,
- deviantOriginator: String?,
- deviantRecipient: String?,
- referenceWithNoSpecialType: String?,
- primaNotaNumber: String?,
- textKeySupplement: String?,
- currencyType: String?,
- bookingKey: String,
- referenceForTheAccountOwner: String,
- referenceOfTheAccountServicingInstitution: String?,
- supplementaryDetails: String?,
- transactionReferenceNumber: String,
- relatedReferenceNumber: String?
- ) : IAccountTransaction {
-
- return AccountTransactionEntity(account as BankAccountEntity, amount, currency, unparsedReference, bookingDate,
- otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, valueDate, statementNumber, sequenceNumber,
- openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, creditorIdentifier,
- originatorsIdentificationCode, compensationAmount, originalAmount, sepaReference, deviantOriginator, deviantRecipient,
- referenceWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner,
- referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber)
- }
-
-}
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/AccountTransactionEntity.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/AccountTransactionEntity.kt
deleted file mode 100644
index f51ca477..00000000
--- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/AccountTransactionEntity.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import com.fasterxml.jackson.annotation.JsonIdentityInfo
-import com.fasterxml.jackson.annotation.ObjectIdGenerators
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-import net.dankito.utils.multiplatform.UUID
-
-
-@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
-// had to define all properties as 'var' 'cause MapStruct cannot handle vals
-open class AccountTransactionEntity(
- override var account: BankAccountEntity,
- override var amount: BigDecimal,
- override var currency: String,
- override var unparsedReference: String,
- override var bookingDate: Date,
- override var otherPartyName: String?,
- override var otherPartyBankCode: String?,
- override var otherPartyAccountId: String?,
- override var bookingText: String?,
- override var valueDate: Date,
- override var statementNumber: Int,
- override var sequenceNumber: Int?,
- override var openingBalance: BigDecimal?,
- override var closingBalance: BigDecimal?,
-
- override var endToEndReference: String?,
- override var customerReference: String?,
- override var mandateReference: String?,
- override var creditorIdentifier: String?,
- override var originatorsIdentificationCode: String?,
- override var compensationAmount: String?,
- override var originalAmount: String?,
- override var sepaReference: String?,
- override var deviantOriginator: String?,
- override var deviantRecipient: String?,
- override var referenceWithNoSpecialType: String?,
- override var primaNotaNumber: String?,
- override var textKeySupplement: String?,
-
- override var currencyType: String?,
- override var bookingKey: String,
- override var referenceForTheAccountOwner: String,
- override var referenceOfTheAccountServicingInstitution: String?,
- override var supplementaryDetails: String?,
-
- override var transactionReferenceNumber: String,
- override var relatedReferenceNumber: String?,
- override var technicalId: String = UUID.random()
-) : IAccountTransaction {
-
- // for object deserializers
- internal constructor() : this(BankAccountEntity(), BigDecimal.Zero, "", "", Date(), null, null, null, null, Date(),
- -1, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, "", "", null,
- null, "", null)
-
- constructor(account: BankAccountEntity, otherPartyName: String?, unparsedReference: String, amount: BigDecimal, valueDate: Date, bookingText: String?)
- : this(account, amount, "EUR", unparsedReference, valueDate, otherPartyName, null, null, bookingText, valueDate, 0, null, null, null,
- null, null, null, null, null, null, null, null, null, null, null, null, null,
- null, "", "", null, null, "", null)
-
-
- override fun equals(other: Any?): Boolean {
- return doesEqual(other)
- }
-
- override fun hashCode(): Int {
- return calculateHashCode()
- }
-
- override fun toString(): String {
- return stringRepresentation
- }
-
-}
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt
deleted file mode 100644
index 582bf17c..00000000
--- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankAccountEntity.kt
+++ /dev/null
@@ -1,51 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import com.fasterxml.jackson.annotation.JsonIdentityInfo
-import com.fasterxml.jackson.annotation.ObjectIdGenerators
-import net.dankito.banking.ui.model.*
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-import net.dankito.utils.multiplatform.UUID
-
-
-@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
-// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableBankAccountBuilder would fail with @Context)
-open class BankAccountEntity(
- override var bank: BankDataEntity,
- override var identifier: String,
- override var accountHolderName: String,
- override var iban: String?,
- override var subAccountNumber: String?,
- override var balance: BigDecimal = BigDecimal.Zero,
- override var currency: String = "EUR",
- override var type: BankAccountType = BankAccountType.CheckingAccount,
- override var productName: String? = null,
- override var accountLimit: String? = null,
- override var retrievedTransactionsFromOn: Date? = null,
- override var retrievedTransactionsUpTo: Date? = null,
- override var supportsRetrievingAccountTransactions: Boolean = false,
- override var supportsRetrievingBalance: Boolean = false,
- override var supportsTransferringMoney: Boolean = false,
- override var supportsRealTimeTransfer: Boolean = false,
- override var bookedTransactions: List = listOf(),
- override var unbookedTransactions: List = listOf(),
- override var technicalId: String = UUID.random(),
- override var userSetDisplayName: String? = null,
- override var haveAllTransactionsBeenRetrieved: Boolean = false,
- override var isAccountTypeSupportedByApplication: Boolean = true,
- override var countDaysForWhichTransactionsAreKept: Int? = null,
- override var displayIndex: Int = 0,
- override var hideAccount: Boolean = false,
- override var includeInAutomaticAccountsUpdate: Boolean = true,
- override var doNotShowStrikingFetchAllTransactionsView: Boolean = false
-
-) : IBankAccount {
-
- internal constructor() : this(BankDataEntity(), "", "", null, null) // for object deserializers
-
-
- override fun toString(): String {
- return stringRepresentation
- }
-
-}
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankDataEntity.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankDataEntity.kt
deleted file mode 100644
index 224add0b..00000000
--- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/BankDataEntity.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-package net.dankito.banking.persistence.model
-
-import com.fasterxml.jackson.annotation.*
-import net.dankito.banking.ui.model.IBankData
-import net.dankito.banking.ui.model.tan.TanMedium
-import net.dankito.banking.ui.model.tan.TanMethod
-import java.util.*
-
-
-@JsonIdentityInfo(property = "technicalId", generator = ObjectIdGenerators.PropertyGenerator::class) // to avoid stack overflow due to circular references
-// had to define all properties as 'var' 'cause MapStruct cannot handle vals (and cannot use Pozo's mapstruct-kotlin as SerializableCustomerBuilder would fail with @Context)
-open class BankDataEntity(
- override var bankCode: String,
- override var userName: String,
- override var password: String,
- override var finTsServerAddress: String,
- override var bankName: String,
- override var bic: String,
- override var customerName: String,
- override var userId: String = userName,
- override var iconData: ByteArray? = null,
- override var accounts: List = listOf(),
- override var supportedTanMethods: List = listOf(),
- override var selectedTanMethod: TanMethod? = null,
- override var tanMedia: List = listOf(),
- override var technicalId: String = UUID.randomUUID().toString(),
- override var wrongCredentialsEntered: Boolean = false,
- override var savePassword: Boolean = true,
- override var userSetDisplayName: String? = null,
- override var displayIndex: Int = 0
-) : IBankData {
-
- internal constructor() : this("", "", "", "", "", "", "") // for object deserializers
-
-
- override fun toString(): String {
- return stringRepresentation
- }
-
-}
\ No newline at end of file
diff --git a/persistence/json/BankingPersistenceJson/src/test/kotlin/net/dankito/banking/persistence/BankingPersistenceJsonTest.kt b/persistence/json/BankingPersistenceJson/src/test/kotlin/net/dankito/banking/persistence/BankingPersistenceJsonTest.kt
deleted file mode 100644
index dcb92631..00000000
--- a/persistence/json/BankingPersistenceJson/src/test/kotlin/net/dankito/banking/persistence/BankingPersistenceJsonTest.kt
+++ /dev/null
@@ -1,238 +0,0 @@
-package net.dankito.banking.persistence
-
-import net.dankito.banking.persistence.model.AccountTransactionEntity
-import net.dankito.banking.persistence.model.BankAccountEntity
-import net.dankito.banking.persistence.model.BankDataEntity
-import net.dankito.banking.ui.model.*
-import net.dankito.banking.util.JacksonJsonSerializer
-import net.dankito.utils.multiplatform.BigDecimal
-import net.dankito.utils.multiplatform.Date
-import net.dankito.utils.multiplatform.File
-import org.assertj.core.api.Assertions.assertThat
-import org.junit.Assert
-import org.junit.Test
-import kotlin.random.Random
-
-
-class BankingPersistenceJsonTest {
-
- companion object {
-
- const val BankCode = "12345678"
-
- const val CustomerId = "0987654321"
-
- const val Password = "12345"
-
- const val FinTsServerAddress = "http://i-do-not-exist.fail/givemeyourmoney"
-
- const val BankName = "Abzock GmbH"
-
- const val Bic = "ABCDDEBB123"
-
- const val CustomerName = "Hans Dampf"
-
- const val UserId = CustomerId
-
- val NowMillis = System.currentTimeMillis()
-
- val TwoYearsAgoMillis = NowMillis - (2 * 365 * 24 * 60 * 60 * 1000L)
-
-
- val TestDataFolder = File("testData")
-
- init {
- TestDataFolder.mkdirs()
- }
- }
-
-
- private val file = File(TestDataFolder, BankingPersistenceJson.BanksJsonFileName)
-
- private val serializer = JacksonJsonSerializer()
-
- private val underTest = BankingPersistenceJson(TestDataFolder, serializer)
-
-
- @Test
- fun saveOrUpdateBank() {
-
- // given
- val banks = listOf(
- createBank(2),
- createBank(3)
- )
-
-
- // when
- underTest.saveOrUpdateBank(banks.first() as TypedBankData, banks.map { it as TypedBankData })
-
-
- // then
- val result = serializer.deserializeListOr(file, BankDataEntity::class)
-
- assertBanksEqual(result, banks)
- }
-
- @Test
- fun saveOrUpdateBankWithAccountsAndTransactions() {
-
- // given
- val bank = createBank(2)
-
-
- // when
- underTest.saveOrUpdateBank(bank as TypedBankData, listOf(bank).map { it as TypedBankData })
-
-
- // then
- val result = serializer.deserializeListOr(file, BankDataEntity::class)
-
- assertBanksEqual(result, listOf(bank) as List)
- }
-
-
- @Test
- fun readPersistedBanks() {
-
- // given
- val banks = listOf(
- createBank(2),
- createBank(3)
- )
-
- serializer.serializeObject(banks, file)
-
-
- // when
- val result = underTest.readPersistedBanks()
-
-
- // then
- assertBanksEqual(banks, result as List)
- }
-
-
- private fun createBank(countAccounts: Int = 0, customerId: String = CustomerId): BankDataEntity {
- val result = BankDataEntity(BankCode, customerId, Password, FinTsServerAddress, BankName, Bic, CustomerName, UserId, null)
-
- result.accounts = createAccounts(countAccounts, result)
-
- return result
- }
-
- private fun createAccounts(count: Int, customer: BankDataEntity): List {
- val random = Random(System.nanoTime())
-
- return IntRange(1, count).map { accountIndex ->
- createAccount("Account_$accountIndex", customer, random.nextInt(2, 50))
- }
- }
-
- private fun createAccount(productName: String, customer: BankDataEntity, countTransactions: Int = 0): BankAccountEntity {
- val result = BankAccountEntity(customer, customer.userName, "AccountHolder", "DE00" + customer.bankCode + customer.userName, null,
- BigDecimal(84.25), productName = productName)
-
- result.bookedTransactions = createTransactions(countTransactions, result)
-
- return result
- }
-
- private fun createTransactions(countTransactions: Int, account: BankAccountEntity): List {
- return IntRange(1, countTransactions).map { transactionIndex ->
- createTransaction(transactionIndex, account)
- }
- }
-
- private fun createTransaction(transactionIndex: Int, account: BankAccountEntity): AccountTransactionEntity {
- return AccountTransactionEntity(account, "OtherParty_$transactionIndex", "Reference_$transactionIndex", BigDecimal(transactionIndex.toDouble()), createDate(), null)
- }
-
- private fun createDate(): Date {
- return Date(Random(System.nanoTime()).nextLong(TwoYearsAgoMillis, NowMillis))
- }
-
-
- private fun assertBanksEqual(deserializedBanks: List, banks: List) {
- assertThat(deserializedBanks.size).isEqualTo(banks.size)
-
- deserializedBanks.forEach { deserializedBanks ->
- val bank = banks.firstOrNull { it.technicalId == deserializedBanks.technicalId }
-
- if (bank == null) {
- Assert.fail("Could not find matching bank for deserialized bank $deserializedBanks. banks = $banks")
- }
- else {
- assertBanksEqual(deserializedBanks, bank)
- }
- }
- }
-
- private fun assertBanksEqual(deserializedBank: BankDataEntity, bank: BankDataEntity) {
- assertThat(deserializedBank.bankCode).isEqualTo(bank.bankCode)
- assertThat(deserializedBank.userName).isEqualTo(bank.userName)
- assertThat(deserializedBank.password).isEqualTo(bank.password)
- assertThat(deserializedBank.finTsServerAddress).isEqualTo(bank.finTsServerAddress)
-
- assertThat(deserializedBank.bankName).isEqualTo(bank.bankName)
- assertThat(deserializedBank.bic).isEqualTo(bank.bic)
- assertThat(deserializedBank.customerName).isEqualTo(bank.customerName)
- assertThat(deserializedBank.userId).isEqualTo(bank.userId)
- assertThat(deserializedBank.iconData).isEqualTo(bank.iconData)
-
- assertAccountsEqual(deserializedBank.accounts, bank.accounts)
- }
-
- private fun assertAccountsEqual(deserializedAccounts: List, accounts: List) {
- assertThat(deserializedAccounts.size).isEqualTo(accounts.size)
-
- deserializedAccounts.forEach { deserializedAccount ->
- val account = accounts.firstOrNull { it.technicalId == deserializedAccount.technicalId }
-
- if (account == null) {
- Assert.fail("Could not find matching account for deserialized account $deserializedAccount. accounts = $accounts")
- }
- else {
- assertAccountsEqual(deserializedAccount, account)
- }
- }
- }
-
- private fun assertAccountsEqual(deserializedAccount: BankAccountEntity, account: BankAccountEntity) {
- // to check if MapStruct created reference correctly
- assertThat(deserializedAccount.bank.technicalId).isEqualTo(account.bank.technicalId)
-
- assertThat(deserializedAccount.identifier).isEqualTo(account.identifier)
- assertThat(deserializedAccount.iban).isEqualTo(account.iban)
- assertThat(deserializedAccount.balance).isEqualTo(account.balance)
- assertThat(deserializedAccount.productName).isEqualTo(account.productName)
-
- assertTransactionsEqual(deserializedAccount.bookedTransactions, account.bookedTransactions)
- }
-
- private fun assertTransactionsEqual(deserializedTransactions: List, transactions: List) {
- assertThat(deserializedTransactions.size).isEqualTo(transactions.size)
-
- deserializedTransactions.forEach { deserializedTransaction ->
- val transaction = transactions.firstOrNull { it.technicalId == deserializedTransaction.technicalId }
-
- if (transaction == null) {
- Assert.fail("Could not find matching transaction for deserialized transaction $deserializedTransaction. transactions = $transactions")
- }
- else {
- assertTransactionsEqual(deserializedTransaction, transaction)
- }
- }
- }
-
- private fun assertTransactionsEqual(deserializedTransaction: AccountTransactionEntity, transaction: AccountTransactionEntity) {
- // to check if MapStruct created reference correctly
- assertThat(deserializedTransaction.account.technicalId).isEqualTo(transaction.account.technicalId)
-
- assertThat(deserializedTransaction.otherPartyName).isEqualTo(transaction.otherPartyName)
- assertThat(deserializedTransaction.unparsedReference).isEqualTo(transaction.unparsedReference)
- assertThat(deserializedTransaction.amount).isEqualTo(transaction.amount)
- assertThat(deserializedTransaction.valueDate).isEqualTo(transaction.valueDate)
- }
-
-}
\ No newline at end of file
diff --git a/rest/BankFinderRest/.dockerignore b/rest/BankFinderRest/.dockerignore
deleted file mode 100644
index 4361d2fb..00000000
--- a/rest/BankFinderRest/.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*
-!build/*-runner
-!build/*-runner.jar
-!build/lib/*
-!build/quarkus-app/*
\ No newline at end of file
diff --git a/rest/BankFinderRest/build.gradle b/rest/BankFinderRest/build.gradle
deleted file mode 100644
index 6c9b04fc..00000000
--- a/rest/BankFinderRest/build.gradle
+++ /dev/null
@@ -1,66 +0,0 @@
-plugins {
- id 'org.jetbrains.kotlin.jvm'
- id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72"
- id 'io.quarkus'
-}
-
-apply plugin: 'java-library'
-apply plugin: 'kotlin'
-
-
-
-dependencies {
- implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
-
- // TODO: why can't Gradle find BankFinder project? .jars have temporarily to be copied to libs folder - which are not committed to repo of course - till this issue is fixed
-// implementation project(path: ":common", configuration: 'jvmDefault')
-// implementation project(path: ":BankFinder", configuration: 'jvmDefault')
-// implementation "net.dankito.banking:BankFinder-jvm:$version"
-
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- implementation "net.dankito.utils:java-utils:$javaUtilsVersion"
-
- implementation enforcedPlatform("io.quarkus:quarkus-bom:$quarkusVersion")
- implementation 'io.quarkus:quarkus-kotlin'
- implementation 'io.quarkus:quarkus-resteasy'
- implementation 'io.quarkus:quarkus-resteasy-jackson'
-
- testImplementation 'io.quarkus:quarkus-junit5'
- testImplementation 'io.rest-assured:kotlin-extensions'
-}
-
-
-quarkus {
- setOutputDirectory("$projectDir/build/classes/kotlin/main")
-}
-
-quarkusDev {
- setSourceDir("$projectDir/src/main/kotlin")
-}
-
-allOpen {
- annotation("javax.ws.rs.Path")
- annotation("javax.enterprise.context.ApplicationScoped")
- annotation("io.quarkus.test.junit.QuarkusTest")
-}
-
-
-def javaVersion = JavaVersion.VERSION_11
-
-java {
- sourceCompatibility = javaVersion
- targetCompatibility = javaVersion
-}
-
-compileKotlin {
- kotlinOptions.jvmTarget = javaVersion
- kotlinOptions.javaParameters = true
-}
-
-compileTestKotlin {
- kotlinOptions.jvmTarget = javaVersion
-}
-test {
- systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
-}
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/main/docker/Dockerfile.fast-jar b/rest/BankFinderRest/src/main/docker/Dockerfile.fast-jar
deleted file mode 100644
index 2793e081..00000000
--- a/rest/BankFinderRest/src/main/docker/Dockerfile.fast-jar
+++ /dev/null
@@ -1,57 +0,0 @@
-####
-# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
-#
-# Before building the container image run:
-#
-# mvn package -Dquarkus.package.type=fast-jar
-#
-# Then, build the image with:
-#
-# docker build -f src/main/docker/Dockerfile.fast-jar -t codinux/bank-finder-fast-jar .
-#
-# Then run the container using:
-#
-# docker run -i --rm -p 8080:8080 codinux/bank-finder-fast-jar
-#
-# If you want to include the debug port into your docker image
-# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050
-#
-# Then run the container using :
-#
-# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" codinux/bank-finder-fast-jar
-#
-###
-FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
-
-ARG JAVA_PACKAGE=java-11-openjdk-headless
-ARG RUN_JAVA_VERSION=1.3.8
-
-ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
-
-# Install java and the run-java script
-# Also set up permissions for user `1001`
-RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
- && microdnf update \
- && microdnf clean all \
- && mkdir /deployments \
- && chown 1001 /deployments \
- && chmod "g+rwX" /deployments \
- && chown 1001:root /deployments \
- && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
- && chown 1001 /deployments/run-java.sh \
- && chmod 540 /deployments/run-java.sh \
- && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
-
-# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
-ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
-
-# We make four distinct layers so if there are application changes the library layers can be re-used
-COPY --chown=1001 build/quarkus-app/lib/ /deployments/lib/
-COPY --chown=1001 build/quarkus-app/*.jar /deployments/
-COPY --chown=1001 build/quarkus-app/app/ /deployments/app/
-COPY --chown=1001 build/quarkus-app/quarkus/ /deployments/quarkus/
-
-EXPOSE 8080
-USER 1001
-
-ENTRYPOINT [ "/deployments/run-java.sh" ]
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/main/docker/Dockerfile.jvm b/rest/BankFinderRest/src/main/docker/Dockerfile.jvm
deleted file mode 100644
index 771a9ae2..00000000
--- a/rest/BankFinderRest/src/main/docker/Dockerfile.jvm
+++ /dev/null
@@ -1,54 +0,0 @@
-####
-# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
-#
-# Before building the container image run:
-#
-# mvn package
-#
-# Then, build the image with:
-#
-# docker build -f src/main/docker/Dockerfile.jvm -t codinux/bank-finder-jvm .
-#
-# Then run the container using:
-#
-# docker run -i --rm -p 8080:8080 codinux/bank-finder-jvm
-#
-# If you want to include the debug port into your docker image
-# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050
-#
-# Then run the container using :
-#
-# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" codinux/bank-finder-jvm
-#
-###
-FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
-
-ARG JAVA_PACKAGE=java-11-openjdk-headless
-ARG RUN_JAVA_VERSION=1.3.8
-
-ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
-
-# Install java and the run-java script
-# Also set up permissions for user `1001`
-RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
- && microdnf update \
- && microdnf clean all \
- && mkdir /deployments \
- && chown 1001 /deployments \
- && chmod "g+rwX" /deployments \
- && chown 1001:root /deployments \
- && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
- && chown 1001 /deployments/run-java.sh \
- && chmod 540 /deployments/run-java.sh \
- && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
-
-# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
-ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
-
-COPY build/lib/* /deployments/lib/
-COPY build/*-runner.jar /deployments/app.jar
-
-EXPOSE 8080
-USER 1001
-
-ENTRYPOINT [ "/deployments/run-java.sh" ]
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/main/docker/Dockerfile.native b/rest/BankFinderRest/src/main/docker/Dockerfile.native
deleted file mode 100644
index 39ba04c6..00000000
--- a/rest/BankFinderRest/src/main/docker/Dockerfile.native
+++ /dev/null
@@ -1,27 +0,0 @@
-####
-# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode
-#
-# Before building the container image run:
-#
-# mvn package -Pnative -Dquarkus.native.container-build=true
-#
-# Then, build the image with:
-#
-# docker build -f src/main/docker/Dockerfile.native -t codinux/bank-finder .
-#
-# Then run the container using:
-#
-# docker run -i --rm -p 8080:8080 codinux/bank-finder
-#
-###
-FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
-WORKDIR /work/
-RUN chown 1001 /work \
- && chmod "g+rwX" /work \
- && chown 1001:root /work
-COPY --chown=1001:root build/*-runner /work/application
-
-EXPOSE 8080
-USER 1001
-
-CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/main/kotlin/net/dankito/banking/bankfinder/rest/BankFinderResource.kt b/rest/BankFinderRest/src/main/kotlin/net/dankito/banking/bankfinder/rest/BankFinderResource.kt
deleted file mode 100644
index 36df7493..00000000
--- a/rest/BankFinderRest/src/main/kotlin/net/dankito/banking/bankfinder/rest/BankFinderResource.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.bankfinder.rest
-
-import net.dankito.banking.bankfinder.BankInfo
-import net.dankito.banking.bankfinder.InMemoryBankFinder
-import org.jboss.resteasy.annotations.jaxrs.PathParam
-import javax.ws.rs.GET
-import javax.ws.rs.Path
-import javax.ws.rs.Produces
-import javax.ws.rs.core.MediaType
-
-
-@Path("/bankfinder")
-class BankFinderResource {
-
- protected var bankFinder = InMemoryBankFinder()
-
-
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("{query}")
- fun findBank(@PathParam query: String): List {
- return bankFinder.findBankByNameBankCodeOrCity(query)
- }
-
-}
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/main/resources/application.properties b/rest/BankFinderRest/src/main/resources/application.properties
deleted file mode 100644
index 4c6d1e55..00000000
--- a/rest/BankFinderRest/src/main/resources/application.properties
+++ /dev/null
@@ -1 +0,0 @@
-quarkus.http.port=5666
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/native-test/kotlin/net/dankito/banking/bankfinder/rest/NativeBankFinderResourceIT.kt b/rest/BankFinderRest/src/native-test/kotlin/net/dankito/banking/bankfinder/rest/NativeBankFinderResourceIT.kt
deleted file mode 100644
index c3437278..00000000
--- a/rest/BankFinderRest/src/native-test/kotlin/net/dankito/banking/bankfinder/rest/NativeBankFinderResourceIT.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.dankito.banking.bankfinder.rest
-
-import io.quarkus.test.junit.NativeImageTest
-
-@NativeImageTest
-class NativeBankFinderResourceIT : ExampleResourceTest()
\ No newline at end of file
diff --git a/rest/BankFinderRest/src/test/kotlin/net/dankito/banking/bankfinder/rest/BankFinderResourceTest.kt b/rest/BankFinderRest/src/test/kotlin/net/dankito/banking/bankfinder/rest/BankFinderResourceTest.kt
deleted file mode 100644
index 4bb0ce8a..00000000
--- a/rest/BankFinderRest/src/test/kotlin/net/dankito/banking/bankfinder/rest/BankFinderResourceTest.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.dankito.banking.bankfinder.rest
-
-import io.quarkus.test.junit.QuarkusTest
-import io.restassured.RestAssured.given
-import org.hamcrest.CoreMatchers.containsString
-import org.junit.jupiter.api.Test
-
-
-@QuarkusTest
-class BankFinderResourceTest {
-
- @Test
- fun testSparkasse() {
- given()
- .`when`().get("/bankfinder/Sparkasse")
- .then()
- .statusCode(200)
- .body(containsString("Berliner Sparkasse"))
- .body(containsString("\"bankCode\":\"10050000\""))
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/.dockerignore b/rest/fints4kRest/.dockerignore
deleted file mode 100644
index 4361d2fb..00000000
--- a/rest/fints4kRest/.dockerignore
+++ /dev/null
@@ -1,5 +0,0 @@
-*
-!build/*-runner
-!build/*-runner.jar
-!build/lib/*
-!build/quarkus-app/*
\ No newline at end of file
diff --git a/rest/fints4kRest/build.gradle b/rest/fints4kRest/build.gradle
deleted file mode 100644
index bbdd6852..00000000
--- a/rest/fints4kRest/build.gradle
+++ /dev/null
@@ -1,65 +0,0 @@
-plugins {
- id 'org.jetbrains.kotlin.jvm'
- id "org.jetbrains.kotlin.plugin.allopen" version "1.3.72"
- id 'io.quarkus'
-}
-
-
-dependencies {
- implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
-
- // TODO: why can't Gradle find fints4k project? .jars have temporarily to be copied to libs folder - which are not committed to repo of course - till this issue is fixed
- implementation fileTree(dir: 'libs', include: ['*.jar'])
-
- implementation "net.dankito.utils:java-utils:$javaUtilsVersion"
-
- implementation "io.ktor:ktor-client-okhttp:$ktorVersion"
-
- implementation "org.slf4j:slf4j-api:$slf4jVersion"
-
- implementation enforcedPlatform("io.quarkus:quarkus-bom:$quarkusVersion")
- implementation 'io.quarkus:quarkus-kotlin'
- implementation 'io.quarkus:quarkus-resteasy'
- implementation 'io.quarkus:quarkus-resteasy-jackson'
-
- implementation "ch.qos.logback:logback-classic:$logbackVersion"
-
-
- testImplementation 'io.quarkus:quarkus-junit5'
- testImplementation 'io.rest-assured:kotlin-extensions'
-}
-
-
-quarkus {
- setOutputDirectory("$projectDir/build/classes/kotlin/main")
-}
-
-quarkusDev {
- setSourceDir("$projectDir/src/main/kotlin")
-}
-
-allOpen {
- annotation("javax.ws.rs.Path")
- annotation("javax.enterprise.context.ApplicationScoped")
- annotation("io.quarkus.test.junit.QuarkusTest")
-}
-
-
-def javaVersion = JavaVersion.VERSION_11
-
-java {
- sourceCompatibility = javaVersion
- targetCompatibility = javaVersion
-}
-
-compileKotlin {
- kotlinOptions.jvmTarget = javaVersion
- kotlinOptions.javaParameters = true
-}
-
-compileTestKotlin {
- kotlinOptions.jvmTarget = javaVersion
-}
-test {
- systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/docker/Dockerfile.fast-jar b/rest/fints4kRest/src/main/docker/Dockerfile.fast-jar
deleted file mode 100644
index ed4e2dd9..00000000
--- a/rest/fints4kRest/src/main/docker/Dockerfile.fast-jar
+++ /dev/null
@@ -1,57 +0,0 @@
-####
-# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
-#
-# Before building the container image run:
-#
-# mvn package -Dquarkus.package.type=fast-jar
-#
-# Then, build the image with:
-#
-# docker build -f src/main/docker/Dockerfile.fast-jar -t codinux/fints4k-fast-jar .
-#
-# Then run the container using:
-#
-# docker run -i --rm -p 8080:8080 codinux/fints4k-fast-jar
-#
-# If you want to include the debug port into your docker image
-# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050
-#
-# Then run the container using :
-#
-# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" codinux/fints4k-fast-jar
-#
-###
-FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
-
-ARG JAVA_PACKAGE=java-11-openjdk-headless
-ARG RUN_JAVA_VERSION=1.3.8
-
-ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
-
-# Install java and the run-java script
-# Also set up permissions for user `1001`
-RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
- && microdnf update \
- && microdnf clean all \
- && mkdir /deployments \
- && chown 1001 /deployments \
- && chmod "g+rwX" /deployments \
- && chown 1001:root /deployments \
- && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
- && chown 1001 /deployments/run-java.sh \
- && chmod 540 /deployments/run-java.sh \
- && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
-
-# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
-ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
-
-# We make four distinct layers so if there are application changes the library layers can be re-used
-COPY --chown=1001 build/quarkus-app/lib/ /deployments/lib/
-COPY --chown=1001 build/quarkus-app/*.jar /deployments/
-COPY --chown=1001 build/quarkus-app/app/ /deployments/app/
-COPY --chown=1001 build/quarkus-app/quarkus/ /deployments/quarkus/
-
-EXPOSE 8080
-USER 1001
-
-ENTRYPOINT [ "/deployments/run-java.sh" ]
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/docker/Dockerfile.jvm b/rest/fints4kRest/src/main/docker/Dockerfile.jvm
deleted file mode 100644
index 0e76ac92..00000000
--- a/rest/fints4kRest/src/main/docker/Dockerfile.jvm
+++ /dev/null
@@ -1,54 +0,0 @@
-####
-# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
-#
-# Before building the container image run:
-#
-# mvn package
-#
-# Then, build the image with:
-#
-# docker build -f src/main/docker/Dockerfile.jvm -t codinux/fints4k-jvm .
-#
-# Then run the container using:
-#
-# docker run -i --rm -p 8080:8080 codinux/fints4k-jvm
-#
-# If you want to include the debug port into your docker image
-# you will have to expose the debug port (default 5005) like this : EXPOSE 8080 5050
-#
-# Then run the container using :
-#
-# docker run -i --rm -p 8080:8080 -p 5005:5005 -e JAVA_ENABLE_DEBUG="true" codinux/fints4k-jvm
-#
-###
-FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
-
-ARG JAVA_PACKAGE=java-11-openjdk-headless
-ARG RUN_JAVA_VERSION=1.3.8
-
-ENV LANG='en_US.UTF-8' LANGUAGE='en_US:en'
-
-# Install java and the run-java script
-# Also set up permissions for user `1001`
-RUN microdnf install curl ca-certificates ${JAVA_PACKAGE} \
- && microdnf update \
- && microdnf clean all \
- && mkdir /deployments \
- && chown 1001 /deployments \
- && chmod "g+rwX" /deployments \
- && chown 1001:root /deployments \
- && curl https://repo1.maven.org/maven2/io/fabric8/run-java-sh/${RUN_JAVA_VERSION}/run-java-sh-${RUN_JAVA_VERSION}-sh.sh -o /deployments/run-java.sh \
- && chown 1001 /deployments/run-java.sh \
- && chmod 540 /deployments/run-java.sh \
- && echo "securerandom.source=file:/dev/urandom" >> /etc/alternatives/jre/lib/security/java.security
-
-# Configure the JAVA_OPTIONS, you can add -XshowSettings:vm to also display the heap size.
-ENV JAVA_OPTIONS="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
-
-COPY build/lib/* /deployments/lib/
-COPY build/*-runner.jar /deployments/app.jar
-
-EXPOSE 8080
-USER 1001
-
-ENTRYPOINT [ "/deployments/run-java.sh" ]
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/docker/Dockerfile.native b/rest/fints4kRest/src/main/docker/Dockerfile.native
deleted file mode 100644
index c1522ea4..00000000
--- a/rest/fints4kRest/src/main/docker/Dockerfile.native
+++ /dev/null
@@ -1,27 +0,0 @@
-####
-# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode
-#
-# Before building the container image run:
-#
-# mvn package -Pnative -Dquarkus.native.container-build=true
-#
-# Then, build the image with:
-#
-# docker build -f src/main/docker/Dockerfile.native -t codinux/fints4k .
-#
-# Then run the container using:
-#
-# docker run -i --rm -p 8080:8080 codinux/fints4k
-#
-###
-FROM registry.access.redhat.com/ubi8/ubi-minimal:8.1
-WORKDIR /work/
-RUN chown 1001 /work \
- && chmod "g+rwX" /work \
- && chown 1001:root /work
-COPY --chown=1001:root build/*-runner /work/application
-
-EXPOSE 8080
-USER 1001
-
-CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/AccessControlResponseFilter.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/AccessControlResponseFilter.kt
deleted file mode 100644
index 0a450ffd..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/AccessControlResponseFilter.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.dankito.banking.fints.rest
-
-import javax.annotation.Priority
-import javax.ws.rs.Priorities
-import javax.ws.rs.container.ContainerRequestContext
-import javax.ws.rs.container.ContainerResponseContext
-import javax.ws.rs.container.ContainerResponseFilter
-import javax.ws.rs.core.MultivaluedMap
-import javax.ws.rs.ext.Provider
-
-
-@Provider
-@Priority(Priorities.HEADER_DECORATOR)
-open class AccessControlResponseFilter : ContainerResponseFilter {
-
-
- override fun filter(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
- val headers: MultivaluedMap = responseContext.headers
-
- headers.add("Access-Control-Allow-Origin", "*")
- headers.add("Access-Control-Allow-Headers", "Authorization, Origin, X-Requested-With, Content-Type")
- headers.add("Access-Control-Expose-Headers", "Location, Content-Disposition")
- headers.add("Access-Control-Allow-Methods", "POST, PUT, GET, DELETE, HEAD, OPTIONS")
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/LoggingFilter.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/LoggingFilter.kt
deleted file mode 100644
index 7e84f18f..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/LoggingFilter.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package net.dankito.banking.fints.rest
-
-import com.fasterxml.jackson.databind.ObjectMapper
-import org.slf4j.LoggerFactory
-import javax.inject.Inject
-import javax.ws.rs.container.ContainerRequestContext
-import javax.ws.rs.container.ContainerResponseContext
-import javax.ws.rs.container.ContainerResponseFilter
-import javax.ws.rs.core.Response
-import javax.ws.rs.ext.Provider
-
-
-@Provider
-class LoggingFilter : ContainerResponseFilter {
-
- companion object {
- private val log = LoggerFactory.getLogger(LoggingFilter::class.java)
- }
-
-
- @Inject
- internal lateinit var mapper: ObjectMapper
-
-
- override fun filter(requestContext: ContainerRequestContext, responseContext: ContainerResponseContext) {
- if (responseContext.statusInfo.family != Response.Status.Family.SUCCESSFUL) {
- log.warn("Request ${geRequestUrl(requestContext)} failed: ${getResponseStatus(responseContext)}"
- + System.lineSeparator() + getHeadersAsString(responseContext)
- + System.lineSeparator() + getBodyAsString(responseContext))
- }
- else if (log.isInfoEnabled) {
- log.info("Result of request ${geRequestUrl(requestContext)}: ${getResponseStatus(responseContext)}"
- + System.lineSeparator() + getHeadersAsString(responseContext)
- + System.lineSeparator() + getBodyAsString(responseContext))
- }
- }
-
- private fun geRequestUrl(requestContext: ContainerRequestContext): String {
- return "${requestContext.request.method} ${requestContext.uriInfo.requestUri}"
- }
-
- private fun getResponseStatus(responseContext: ContainerResponseContext): String {
- return "${responseContext.status} ${responseContext.statusInfo.reasonPhrase}"
- }
-
- private fun getHeadersAsString(responseContext: ContainerResponseContext): String {
- return responseContext.stringHeaders.map { header -> "${header.key}: ${header.value}" }.joinToString("\n", "Headers:\n")
- }
-
- private fun getBodyAsString(responseContext: ContainerResponseContext): String {
- if (responseContext.hasEntity()) {
- return "Body ${responseContext.entityClass.name}:\n" + mapper.writeValueAsString(responseContext.entity)
- }
-
- return ""
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/fints4kResource.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/fints4kResource.kt
deleted file mode 100644
index 05bd958e..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/fints4kResource.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-package net.dankito.banking.fints.rest
-
-import net.dankito.banking.fints.response.client.AddAccountResponse
-import net.dankito.banking.fints.response.client.GetTransactionsResponse
-import net.dankito.banking.fints.rest.model.dto.request.AddAccountRequestDto
-import net.dankito.banking.fints.rest.mapper.DtoMapper
-import net.dankito.banking.fints.rest.model.dto.request.GetAccountsTransactionsRequestDto
-import net.dankito.banking.fints.rest.model.dto.request.TanResponseDto
-import net.dankito.banking.fints.rest.model.dto.response.AddAccountResponseDto
-import net.dankito.banking.fints.rest.model.dto.response.GetAccountsTransactionsResponseDto
-import net.dankito.banking.fints.rest.model.dto.response.RestResponse
-import net.dankito.banking.fints.rest.service.fints4kService
-import net.dankito.banking.fints.rest.service.model.GetAccountsTransactionsResponse
-import org.slf4j.LoggerFactory
-import javax.inject.Inject
-import javax.ws.rs.*
-import javax.ws.rs.core.MediaType
-
-
-@Path("/fints/v1")
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-class fints4kResource {
-
- @Inject
- protected val service = fints4kService()
-
- protected val mapper = DtoMapper()
-
-
- @POST
- @Path("addaccount")
- fun addAccount(request: AddAccountRequestDto): RestResponse {
- val response = service.getAddAccountResponse(request)
-
- return mapper.createRestResponse(response) { successResponse -> mapper.map(successResponse) }
- }
-
-
- @POST
- @Path("transactions")
- fun getAccountTransactions(request: GetAccountsTransactionsRequestDto): GetAccountsTransactionsResponseDto {
- val response = service.getAccountTransactions(request)
-
- return mapper.map(response)
- }
-
-
- @POST
- @Path("tanresponse")
- fun tanResponse(dto: TanResponseDto): RestResponse {
- val response = service.handleTanResponse(dto)
-
- // couldn't make it that compiler access ResponseHolder<*> for mapper.createRestResponse(), resulted in very cryptic "{"arity":0}" response -> handle it manually
- response.response?.let { successResponse ->
- return RestResponse.success(mapSuccessResponse(successResponse))
- }
-
- // all other cases map here, the responseMapper callback has no function
- return mapper.createRestResponse(response) { it!! }
- }
-
- private fun mapSuccessResponse(successResponse: Any): Any {
- return when (successResponse) {
- is AddAccountResponse -> mapper.map(successResponse)
- is GetAccountsTransactionsResponse -> mapper.map(successResponse)
- is GetTransactionsResponse -> mapper.mapTransactions(successResponse)
- else -> successResponse // add others / new ones here
- }
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/mapper/DtoMapper.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/mapper/DtoMapper.kt
deleted file mode 100644
index 50187a4c..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/mapper/DtoMapper.kt
+++ /dev/null
@@ -1,166 +0,0 @@
-package net.dankito.banking.fints.rest.mapper
-
-import net.dankito.banking.fints.model.*
-import net.dankito.banking.fints.response.client.AddAccountResponse
-import net.dankito.banking.fints.response.client.FinTsClientResponse
-import net.dankito.banking.fints.response.client.GetTransactionsResponse
-import net.dankito.banking.fints.rest.model.ResponseHolder
-import net.dankito.banking.fints.rest.model.dto.response.*
-import net.dankito.banking.fints.rest.service.model.GetAccountsTransactionsResponse
-import java.math.BigDecimal
-import javax.ws.rs.InternalServerErrorException
-
-
-open class DtoMapper {
-
- fun createRestResponse(responseHolder: ResponseHolder, responseMapper: (DomainType) -> DtoType): RestResponse {
- responseHolder.response?.let { response ->
- return RestResponse.success(responseMapper(response))
- }
-
- responseHolder.enterTanRequest?.let { enterTanRequest ->
- return RestResponse.requiresTan(enterTanRequest)
- }
-
- return RestResponse.error(responseHolder.error ?: "Unknown error")
- }
-
-
- open fun map(response: AddAccountResponse): AddAccountResponseDto {
- return AddAccountResponseDto(
- response.successful,
- mapErrorMessage(response),
- map(response.bank),
- map(response.retrievedData)
- )
- }
-
-
- protected open fun map(bank: BankData): BankResponseDto {
- return BankResponseDto(
- bank.bankCode,
- bank.customerId,
- bank.finTs3ServerAddress,
- bank.bic,
- bank.bankName,
- bank.userId,
- bank.customerName,
- mapTanMethods(bank.tanMethodsAvailableForUser),
- if (bank.isTanMethodSelected) map(bank.selectedTanMethod) else null,
- bank.tanMedia,
- bank.supportedHbciVersions.map { it.name.replace("Hbci_", "HBCI ").replace("FinTs_", "FinTS ").replace('_', '.') }
- )
- }
-
-
- open fun map(response: GetAccountsTransactionsResponse?): GetAccountsTransactionsResponseDto {
- // TODO: is this still the case?
- // TODO: if a TAN is required then accountsTransactions contains null value(s) (but why?) -> application crashes
- if (response == null) {
- throw InternalServerErrorException("Could not fetch account transactions. Either TAN hasn't been entered or developers made a mistake.")
- }
-
- return GetAccountsTransactionsResponseDto(
- // TODO: is this correct removing accounts from result for which no transactions have been retrieved?
- response.transactionsPerAccount.filter { it.response?.retrievedData?.isNotEmpty() != false }
- .map { createRestResponse(it) { transactionsResponse -> mapTransactions(transactionsResponse) } }
- )
- }
-
- open fun mapTransactions(accountTransactions: GetTransactionsResponse): GetAccountTransactionsResponseDto {
- val retrievedData = accountTransactions.retrievedData.first()
- val balance = mapNullable(retrievedData.balance)
- val bookedTransactions = map(retrievedData.bookedTransactions)
-
- return GetAccountTransactionsResponseDto(
- retrievedData.account.accountIdentifier,
- retrievedData.account.productName,
- accountTransactions.successful,
- mapErrorMessage(accountTransactions),
- balance,
- bookedTransactions,
- listOf()
- )
- }
-
-
- protected open fun map(accountData: List): List {
- return accountData.map { map(it) }
- }
-
- protected open fun map(accountData: RetrievedAccountData): BankAccountResponseDto {
- val account = accountData.account
-
- return BankAccountResponseDto(
- account.accountIdentifier,
- account.subAccountAttribute,
- account.iban,
- account.accountType,
- account.currency,
- account.accountHolderName,
- account.productName,
- account.supportsRetrievingBalance,
- account.supportsRetrievingAccountTransactions,
- account.supportsTransferringMoney,
- account.supportsRealTimeTransfer,
- accountData.successfullyRetrievedData,
- mapNullable(accountData.balance),
- accountData.retrievedTransactionsFrom,
- accountData.retrievedTransactionsTo,
- map(accountData.bookedTransactions),
- listOf()
- )
- }
-
-
- protected open fun map(transactions: Collection): Collection {
- return transactions.map { map(it) }
- }
-
- protected open fun map(transaction: AccountTransaction): AccountTransactionResponseDto {
- return AccountTransactionResponseDto(
- map(transaction.amount),
- transaction.amount.currency.code,
- transaction.reference,
- transaction.bookingDate,
- transaction.otherPartyName,
- transaction.otherPartyBankCode,
- transaction.otherPartyAccountId,
- transaction.bookingText,
- transaction.valueDate
- )
- }
-
-
- protected open fun mapTanMethods(tanMethods: List): List {
- return tanMethods.map { map(it) }
- }
-
- protected open fun map(tanMethod: TanMethod): TanMethodResponseDto {
- return TanMethodResponseDto(
- tanMethod.displayName,
- tanMethod.securityFunction.code,
- tanMethod.type,
- tanMethod.hhdVersion?.name?.replace("HHD_", "")?.replace('_', '.'),
- tanMethod.maxTanInputLength,
- tanMethod.allowedTanFormat
- )
- }
-
-
- protected open fun map(money: Money): BigDecimal {
- return money.bigDecimal
- }
-
- protected open fun mapNullable(money: Money?): BigDecimal? {
- return money?.let { map(it) }
- }
-
-
- protected open fun mapErrorMessage(response: FinTsClientResponse): String? {
- // TODO: evaluate fields like isJobAllowed or tanRequiredButWeWereToldToAbortIfSo and set error message accordingly
- return response.errorMessage
- ?: if (response.errorsToShowToUser.isNotEmpty()) response.errorsToShowToUser.joinToString("\n") else null
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/BankAccessData.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/BankAccessData.kt
deleted file mode 100644
index c0506723..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/BankAccessData.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.dankito.banking.fints.rest.model
-
-
-open class BankAccessData(
- open val bankCode: String,
- open val loginName: String,
- open val password: String,
- open val finTsServerAddress: String? = null
-) {
-
- internal constructor() : this("", "", "") // for object deserializers
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/EnterTanContext.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/EnterTanContext.kt
deleted file mode 100644
index 2fe11498..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/EnterTanContext.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.fints.rest.model
-
-import net.dankito.banking.fints.model.EnterTanResult
-import java.util.*
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.atomic.AtomicReference
-
-
-class EnterTanContext(
- val enterTanResult: AtomicReference,
- val responseHolder: ResponseHolder<*>,
- val countDownLatch: CountDownLatch,
- val tanRequestedTimeStamp: Date = Date()
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/EnteringTanRequested.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/EnteringTanRequested.kt
deleted file mode 100644
index 7adcfdd2..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/EnteringTanRequested.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.dankito.banking.fints.rest.model
-
-import net.dankito.banking.fints.model.TanChallenge
-
-
-class EnteringTanRequested(
- val tanRequestId: String,
- val tanChallenge: TanChallenge
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/ResponseHolder.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/ResponseHolder.kt
deleted file mode 100644
index 02264988..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/ResponseHolder.kt
+++ /dev/null
@@ -1,63 +0,0 @@
-package net.dankito.banking.fints.rest.model
-
-import java.util.concurrent.CountDownLatch
-
-
-class ResponseHolder() {
-
- private var responseReceivedLatch = CountDownLatch(1)
-
- constructor(error: String) : this() {
- setError(error)
- }
-
-
- var response: T? = null
- private set
-
- var error: String? = null
- private set
-
- var enterTanRequest: EnteringTanRequested? = null
- private set
-
-
- fun setResponse(response: T) {
- this.response = response
-
- signalResponseReceived()
- }
-
- fun setError(error: String) {
- this.error = error
-
- signalResponseReceived()
- }
-
- fun setEnterTanRequest(enterTanRequest: EnteringTanRequested) {
- this.enterTanRequest = enterTanRequest
-
- signalResponseReceived()
- }
-
-
- fun waitForResponse() {
- responseReceivedLatch.await()
- }
-
- fun resetAfterEnteringTan() {
- this.enterTanRequest = null
-
- responseReceivedLatch = CountDownLatch(1)
- }
-
- private fun signalResponseReceived() {
- responseReceivedLatch.countDown()
- }
-
-
- override fun toString(): String {
- return "Error: $error, TAN requested: $enterTanRequest, success: $response"
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/AccountRequestDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/AccountRequestDto.kt
deleted file mode 100644
index 413695a3..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/AccountRequestDto.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.request
-
-
-open class AccountRequestDto(
- open val identifier: String
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/AddAccountRequestDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/AddAccountRequestDto.kt
deleted file mode 100644
index 0eeb34d7..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/AddAccountRequestDto.kt
+++ /dev/null
@@ -1,4 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.request
-
-
-open class AddAccountRequestDto : BankAccessDataRequestDto()
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/BankAccessDataRequestDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/BankAccessDataRequestDto.kt
deleted file mode 100644
index 1533e2dc..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/BankAccessDataRequestDto.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.request
-
-import net.dankito.banking.fints.rest.model.BankAccessData
-
-
-open class BankAccessDataRequestDto : BankAccessData()
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/GetAccountsTransactionsRequestDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/GetAccountsTransactionsRequestDto.kt
deleted file mode 100644
index fdad36af..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/GetAccountsTransactionsRequestDto.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.request
-
-import net.dankito.banking.fints.rest.model.BankAccessData
-import net.dankito.utils.multiplatform.Date
-
-
-open class GetAccountsTransactionsRequestDto(
- open val credentials: BankAccessData,
- open val accounts: List,
- open val alsoRetrieveBalance: Boolean = true,
- open val fromDate: Date? = null,
- open val toDate: Date? = null,
- open val abortIfTanIsRequired: Boolean = false
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/TanResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/TanResponseDto.kt
deleted file mode 100644
index d41f383a..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/request/TanResponseDto.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.request
-
-import net.dankito.banking.fints.model.EnterTanResult
-
-
-class TanResponseDto(
- val tanRequestId: String,
- val enterTanResult: EnterTanResult
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/AccountTransactionResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/AccountTransactionResponseDto.kt
deleted file mode 100644
index 867b923b..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/AccountTransactionResponseDto.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-import net.dankito.utils.multiplatform.Date
-import java.math.BigDecimal
-
-
-open class AccountTransactionResponseDto(
- open val amount: BigDecimal,
- open val currency: String,
- open val reference: String,
- open val bookingDate: Date,
- open val otherPartyName: String?,
- open val otherPartyBankCode: String?,
- open val otherPartyAccountId: String?,
- open val bookingText: String?,
- open val valueDate: Date
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/AddAccountResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/AddAccountResponseDto.kt
deleted file mode 100644
index fab0a71c..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/AddAccountResponseDto.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-
-open class AddAccountResponseDto(
- successful: Boolean,
- errorMessage: String?,
- open val bank: BankResponseDto,
- open val accounts: List
-) : ResponseDtoBase(successful, errorMessage)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/BankAccountResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/BankAccountResponseDto.kt
deleted file mode 100644
index d49b216e..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/BankAccountResponseDto.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-import net.dankito.banking.fints.response.segments.AccountType
-import net.dankito.utils.multiplatform.Date
-import java.math.BigDecimal
-
-
-open class BankAccountResponseDto(
- open val accountIdentifier: String,
- open val subAccountAttribute: String?,
- open val iban: String?,
- open val accountType: AccountType?,
- open val currency: String?,
- open val accountHolderName: String,
- open val productName: String?,
- open val supportsRetrievingBalance: Boolean,
- open val supportsRetrievingAccountTransactions: Boolean,
- open val supportsTransferringMoney: Boolean,
- open val supportsInstantPaymentMoneyTransfer: Boolean,
- open val successfullyRetrievedData: Boolean,
- open val balance: BigDecimal?,
- open val retrievedTransactionsFrom: Date?,
- open val retrievedTransactionsTo: Date?,
- open var bookedTransactions: Collection,
- open var unbookedTransactions: Collection
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/BankResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/BankResponseDto.kt
deleted file mode 100644
index 2d1b5492..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/BankResponseDto.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium
-
-
-open class BankResponseDto(
- open val bankCode: String,
- open val userName: String,
- open val finTs3ServerAddress: String,
- open val bic: String,
-
- open val bankName: String,
-
- open val userId: String,
- open val customerName: String,
-
- open val usersTanMethods: List,
- open val selectedTanMethod: TanMethodResponseDto?,
- open val tanMedia: List,
-
- open val supportedHbciVersions: List
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/GetAccountTransactionsResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/GetAccountTransactionsResponseDto.kt
deleted file mode 100644
index fa4005d9..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/GetAccountTransactionsResponseDto.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-import java.math.BigDecimal
-
-
-open class GetAccountTransactionsResponseDto(
- open val identifier: String,
- open val productName: String?,
- successful: Boolean,
- errorMessage: String?,
- open val balance: BigDecimal?,
- open var bookedTransactions: Collection,
- open var unbookedTransactions: Collection
-) : ResponseDtoBase(successful, errorMessage)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/GetAccountsTransactionsResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/GetAccountsTransactionsResponseDto.kt
deleted file mode 100644
index dbda2749..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/GetAccountsTransactionsResponseDto.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-
-open class GetAccountsTransactionsResponseDto(
- open val transactionsPerAccount: List>
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/ResponseDtoBase.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/ResponseDtoBase.kt
deleted file mode 100644
index e0747d1a..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/ResponseDtoBase.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-
-open class ResponseDtoBase(
- open val successful: Boolean,
- open val errorMessage: String?
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/ResponseType.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/ResponseType.kt
deleted file mode 100644
index bed09865..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/ResponseType.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-
-enum class ResponseType {
-
- Success,
-
- Error,
-
- TanRequired
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/RestResponse.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/RestResponse.kt
deleted file mode 100644
index 291b5b5c..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/RestResponse.kt
+++ /dev/null
@@ -1,29 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-import net.dankito.banking.fints.rest.model.EnteringTanRequested
-
-
-class RestResponse(
- val status: ResponseType,
- val errorMessage: String?,
- val successResponse: T?,
- val enteringTanRequested: EnteringTanRequested? = null
-) {
-
- companion object {
-
- fun success(result: T): RestResponse {
- return RestResponse(ResponseType.Success, null, result, null)
- }
-
- fun error(errorMessage: String): RestResponse {
- return RestResponse(ResponseType.Error, errorMessage, null, null)
- }
-
- fun requiresTan(enteringTanRequested: EnteringTanRequested): RestResponse {
- return RestResponse(ResponseType.TanRequired, null, null, enteringTanRequested)
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/TanMethodResponseDto.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/TanMethodResponseDto.kt
deleted file mode 100644
index c08f110b..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/model/dto/response/TanMethodResponseDto.kt
+++ /dev/null
@@ -1,15 +0,0 @@
-package net.dankito.banking.fints.rest.model.dto.response
-
-import net.dankito.banking.fints.messages.datenelemente.implementierte.tan.AllowedTanFormat
-import net.dankito.banking.fints.model.TanMethodType
-
-
-open class TanMethodResponseDto(
- open val displayName: String,
- open val bankInternalMethodCode: String,
- open val type: TanMethodType,
- open val hhdVersion: String? = null,
- open val maxTanInputLength: Int? = null,
- open val allowedTanFormat: AllowedTanFormat? = null,
- open val nameOfTanMediumRequired: Boolean = false
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/service/fints4kService.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/service/fints4kService.kt
deleted file mode 100644
index db759449..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/service/fints4kService.kt
+++ /dev/null
@@ -1,202 +0,0 @@
-package net.dankito.banking.fints.rest.service
-
-import net.dankito.banking.bankfinder.InMemoryBankFinder
-import net.dankito.banking.fints.FinTsClientForCustomer
-import net.dankito.banking.fints.callback.FinTsClientCallback
-import net.dankito.banking.fints.callback.SimpleFinTsClientCallback
-import net.dankito.banking.fints.model.*
-import net.dankito.banking.fints.response.client.AddAccountResponse
-import net.dankito.banking.fints.response.client.GetTransactionsResponse
-import net.dankito.banking.fints.rest.model.BankAccessData
-import net.dankito.banking.fints.rest.model.EnterTanContext
-import net.dankito.banking.fints.rest.model.EnteringTanRequested
-import net.dankito.banking.fints.rest.model.ResponseHolder
-import net.dankito.banking.fints.rest.model.dto.request.GetAccountsTransactionsRequestDto
-import net.dankito.banking.fints.rest.model.dto.request.TanResponseDto
-import net.dankito.banking.fints.rest.service.model.GetAccountsTransactionsResponse
-import java.util.*
-import java.util.concurrent.ConcurrentHashMap
-import java.util.concurrent.CountDownLatch
-import java.util.concurrent.atomic.AtomicReference
-import javax.enterprise.context.ApplicationScoped
-
-
-@ApplicationScoped
-class fints4kService {
-
- protected val bankFinder = InMemoryBankFinder()
-
- protected val clientCache = ConcurrentHashMap()
-
- // TODO: create clean up job for timed out TAN requests
- protected val tanRequests = ConcurrentHashMap()
-
-
- fun getAddAccountResponse(accessData: BankAccessData): ResponseHolder {
- val (bank, errorMessage) = mapToBankData(accessData)
-
- if (errorMessage != null) {
- return ResponseHolder(errorMessage)
- }
-
- return getAccountData(bank)
- }
-
- protected fun getAccountData(bank: BankData): ResponseHolder {
- return getAsyncResponse(bank) { client, responseRetrieved ->
- client.addAccountAsync(AddAccountParameter(bank)) { response ->
- responseRetrieved(response)
- }
- }
- }
-
-
- fun getAccountTransactions(dto: GetAccountsTransactionsRequestDto): GetAccountsTransactionsResponse {
- val (bank, errorMessage) = mapToBankData(dto.credentials)
-
- if (errorMessage != null) {
- return GetAccountsTransactionsResponse(listOf(ResponseHolder(errorMessage)))
- }
-
- val retrievedAccounts = getAccounts(bank)
-
- val transactionsPerAccount = dto.accounts.map { accountDto ->
- val account = retrievedAccounts?.firstOrNull { it.accountIdentifier == accountDto.identifier }
-
- return@map if (account != null) {
- val parameter = GetTransactionsParameter(account, dto.alsoRetrieveBalance, dto.fromDate, dto.toDate, abortIfTanIsRequired = dto.abortIfTanIsRequired)
- getAccountTransactions(bank, parameter)
- }
- else {
- ResponseHolder("Account with identifier '${accountDto.identifier}' not found. Available accounts: " +
- "${retrievedAccounts?.joinToString(", ") { it.accountIdentifier }}")
- }
- }
-
- return GetAccountsTransactionsResponse(transactionsPerAccount)
- }
-
- fun getAccountTransactions(bank: BankData, parameter: GetTransactionsParameter): ResponseHolder {
- return getAsyncResponse(bank) { client, responseRetrieved ->
- client.getTransactionsAsync(parameter) { response ->
- responseRetrieved(response)
- }
- }
- }
-
-
- fun handleTanResponse(dto: TanResponseDto): ResponseHolder<*> {
- tanRequests.remove(dto.tanRequestId)?.let { enterTanContext ->
- val responseHolder = enterTanContext.responseHolder
- responseHolder.resetAfterEnteringTan()
-
- enterTanContext.enterTanResult.set(dto.enterTanResult)
- enterTanContext.countDownLatch.countDown()
-
- responseHolder.waitForResponse()
-
- return responseHolder
- }
-
- return ResponseHolder("No TAN request found for TAN Request ID '${dto.tanRequestId}'")
- }
-
-
- protected fun getAsyncResponse(bank: BankData, executeRequest: (FinTsClientForCustomer, ((T) -> Unit)) -> Unit): ResponseHolder {
- val responseHolder = ResponseHolder()
-
- val client = getClient(bank, responseHolder)
-
- executeRequest(client) { response ->
- responseHolder.setResponse(response)
- }
-
- responseHolder.waitForResponse()
-
- return responseHolder
- }
-
- private fun getClient(bank: BankData, responseHolder: ResponseHolder): FinTsClientForCustomer {
- val cacheKey = getCacheKey(bank.bankCode, bank.customerId)
-
- clientCache[cacheKey]?.let {
- // TODO: this will not work for two parallel calls for the same account if both calls require entering a TAN as second one overwrites callback and ResponseHolder of first one -> first one blocks forever
- it.setCallback(createFinTsClientCallback(responseHolder)) // we have to newly create callback otherwise ResponseHolder instance of when client was created is used -> its CountDownLatch would never signal
- return it
- }
-
- val client = FinTsClientForCustomer(bank, createFinTsClientCallback(responseHolder))
-
- clientCache[cacheKey] = client
-
- return client
- }
-
- private fun createFinTsClientCallback(responseHolder: ResponseHolder): FinTsClientCallback {
- return SimpleFinTsClientCallback({ bank, tanChallenge -> handleEnterTan(bank, tanChallenge, responseHolder) }) { supportedTanMethods, suggestedTanMethod ->
- suggestedTanMethod
- }
- }
-
- protected fun handleEnterTan(bank: BankData, tanChallenge: TanChallenge, responseHolder: ResponseHolder): EnterTanResult {
- val enterTanResult = AtomicReference()
- val enterTanLatch = CountDownLatch(1)
-
- val tanRequestId = UUID.randomUUID().toString()
-
- tanRequests.put(tanRequestId, EnterTanContext(enterTanResult, responseHolder, enterTanLatch))
-
- responseHolder.setEnterTanRequest(EnteringTanRequested(tanRequestId, tanChallenge))
-
- enterTanLatch.await()
-
- return enterTanResult.get()
- }
-
-
- protected fun mapToBankData(accessData: BankAccessData): Pair {
- val bankSearchResult = bankFinder.findBankByBankCode(accessData.bankCode)
- val fintsServerAddress = accessData.finTsServerAddress ?: bankSearchResult.firstOrNull { it.pinTanAddress != null }?.pinTanAddress
- val potentialBankInfo = bankSearchResult.firstOrNull()
-
- val bank = BankData(accessData.bankCode, accessData.loginName, accessData.password, fintsServerAddress ?: "",
- potentialBankInfo?.bic ?: "", potentialBankInfo?.name ?: "")
-
- if (fintsServerAddress == null) {
- val errorMessage = if (bankSearchResult.isEmpty()) "No bank found for bank code '${accessData.bankCode}'" else "Bank '${bankSearchResult.firstOrNull()?.name} does not support FinTS 3.0"
-
- return Pair(bank, errorMessage)
- }
-
- return Pair(bank, null)
- }
-
-
- protected fun getAccounts(bank: BankData): List? {
- getCachedClient(bank)?.bank?.accounts?.let {
- return it
- }
-
- val addAccountResponse = getAccountData(bank)
-
- return addAccountResponse.response?.bank?.accounts
- }
-
-
- private fun getCachedClient(bank: BankData): FinTsClientForCustomer? {
- val cacheKey = getCacheKey(bank.bankCode, bank.customerId)
-
- return clientCache[cacheKey]
- }
-
- private fun getCachedClient(credentials: BankAccessData): FinTsClientForCustomer? {
- val cacheKey = getCacheKey(credentials.bankCode, credentials.loginName)
-
- return clientCache[cacheKey]
- }
-
- private fun getCacheKey(bankCode: String, loginName: String): String {
- return bankCode + "_" + loginName
- }
-
-}
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/service/model/GetAccountsTransactionsResponse.kt b/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/service/model/GetAccountsTransactionsResponse.kt
deleted file mode 100644
index c686e3e1..00000000
--- a/rest/fints4kRest/src/main/kotlin/net/dankito/banking/fints/rest/service/model/GetAccountsTransactionsResponse.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.dankito.banking.fints.rest.service.model
-
-import net.dankito.banking.fints.response.client.GetTransactionsResponse
-import net.dankito.banking.fints.rest.model.ResponseHolder
-
-
-class GetAccountsTransactionsResponse(
- val transactionsPerAccount: List>
-)
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/resources/application.properties b/rest/fints4kRest/src/main/resources/application.properties
deleted file mode 100644
index 0793aed7..00000000
--- a/rest/fints4kRest/src/main/resources/application.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-quarkus.http.port=5555
-
-# enable https support in native builds
-quarkus.native.enable-https-url-handler=true
-quarkus.native.enable-all-security-services=true
-
-quarkus.log.level=WARN
-# FinTS messages are logged on DEBUG
-quarkus.log.category."net.dankito.banking.fints.log.MessageLogCollector".level=INFO
-# REST responses are logged on INFO
-quarkus.log.category."net.dankito.banking.fints.rest.LoggingFilter".level=WARN
\ No newline at end of file
diff --git a/rest/fints4kRest/src/main/resources/logback.xml b/rest/fints4kRest/src/main/resources/logback.xml
deleted file mode 100755
index 828c47b6..00000000
--- a/rest/fints4kRest/src/main/resources/logback.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
- %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
-
-
-
- DEBUG
-
-
-
-
-
-
-
-
- data/logs/fints4kRest-${bySecond}.log
-
-
- %-4relative [%thread] %-5level %logger{35} - %msg%n
-
-
-
- DEBUG
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/rest/fints4kRest/src/native-test/kotlin/net/dankito/banking/fints/rest/NativeFints4kIT.kt b/rest/fints4kRest/src/native-test/kotlin/net/dankito/banking/fints/rest/NativeFints4kIT.kt
deleted file mode 100644
index 8f497ac9..00000000
--- a/rest/fints4kRest/src/native-test/kotlin/net/dankito/banking/fints/rest/NativeFints4kIT.kt
+++ /dev/null
@@ -1,6 +0,0 @@
-package net.dankito.banking.fints.rest
-
-import io.quarkus.test.junit.NativeImageTest
-
-@NativeImageTest
-class NativeFints4kIT : ExampleResourceTest()
\ No newline at end of file
diff --git a/rest/fints4kRest/src/test/kotlin/net/dankito/banking/fints/rest/fints4kResourceTest.kt b/rest/fints4kRest/src/test/kotlin/net/dankito/banking/fints/rest/fints4kResourceTest.kt
deleted file mode 100644
index 338e8f8a..00000000
--- a/rest/fints4kRest/src/test/kotlin/net/dankito/banking/fints/rest/fints4kResourceTest.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.dankito.banking.fints.rest
-
-import io.quarkus.test.junit.QuarkusTest
-import io.restassured.RestAssured.given
-import org.hamcrest.CoreMatchers.`is`
-import org.junit.jupiter.api.Test
-
-@QuarkusTest
-class fints4kResourceTest {
-
- @Test
- fun testHelloEndpoint() {
- given()
- .`when`().get("/hello")
- .then()
- .statusCode(200)
- .body(`is`("hello"))
- }
-
-}
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 540066df..1f0c14cc 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,82 +1,13 @@
pluginManagement {
repositories {
- mavenLocal()
mavenCentral()
gradlePluginPortal()
}
- plugins {
- id 'io.quarkus' version "$quarkusVersion"
- }
}
rootProject.name = 'fints4kProject'
-enableFeaturePreview('GRADLE_METADATA')
-
include ':fints4k'
-include ':fints4k-jvm'
include ':common'
-
-
-/* UI */
-
-include ':BankingUiCommon'
-
-include ':fints4kBankingClient'
-include ':hbci4jBankingClient'
-
-include ':BankingPersistenceJson'
-include ':LuceneBankingPersistence'
-include ':RoomBankingPersistence'
-
-include ':BankingAndroidApp'
-
-include ':BankingJavaFxControls'
-include ':BankingJavaFxApp'
-
-include ':BankingUiNativeIntegration'
-
-
-project(':BankingUiCommon').projectDir = "$rootDir/ui/BankingUiCommon/" as File
-
-project(':fints4kBankingClient').projectDir = "$rootDir/ui/fints4kBankingClient/" as File
-project(':hbci4jBankingClient').projectDir = "$rootDir/ui/hbci4jBankingClient/" as File
-
-project(':BankingAndroidApp').projectDir = "$rootDir/ui/BankingAndroidApp/" as File
-
-project(':BankingJavaFxControls').projectDir = "$rootDir/ui/BankingJavaFxControls/" as File
-project(':BankingJavaFxApp').projectDir = "$rootDir/ui/BankingJavaFxApp/" as File
-
-project(':BankingUiNativeIntegration').projectDir = "$rootDir/ui/BankingUiNativeIntegration/" as File
-
-project(':BankingPersistenceJson').projectDir = "$rootDir/persistence/json/BankingPersistenceJson/" as File
-project(':LuceneBankingPersistence').projectDir = "$rootDir/persistence/LuceneBankingPersistence/" as File
-project(':RoomBankingPersistence').projectDir = "$rootDir/persistence/database/RoomBankingPersistence/" as File
-
-
-/* REST APIs */
-
-include ':BankFinderRest'
-include ':fints4kRest'
-
-project(':BankFinderRest').projectDir = "$rootDir/rest/BankFinderRest/" as File
-project(':fints4kRest').projectDir = "$rootDir/rest/fints4kRest/" as File
-
-
-
-/* Tools */
-
-include ':BankFinder'
-include ':LuceneBankFinder'
-include ':BankListCreator'
-include ':CsvAccountTransactionsImporterAndExporter'
-include ':EpcQrCodeParser'
-
-
-project(':BankFinder').projectDir = "$rootDir/tools/BankFinder/" as File
-project(':LuceneBankFinder').projectDir = "$rootDir/tools/LuceneBankFinder/" as File
-project(':BankListCreator').projectDir = "$rootDir/tools/BankListCreator/" as File
-project(':CsvAccountTransactionsImporterAndExporter').projectDir = "$rootDir/tools/CsvAccountTransactionsImporterAndExporter/" as File
-project(':EpcQrCodeParser').projectDir = "$rootDir/tools/EpcQrCodeParser/" as File
diff --git a/tools/BankFinder/build.gradle b/tools/BankFinder/build.gradle
index 1dcdba63..1795e4dd 100644
--- a/tools/BankFinder/build.gradle
+++ b/tools/BankFinder/build.gradle
@@ -1,6 +1,5 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
- id "com.android.library"
id "maven-publish"
}
@@ -10,31 +9,43 @@ ext.artifactName = "bank-finder"
kotlin {
jvm {
- compilations.main.kotlinOptions {
- jvmTarget = "1.6"
+ compilations.all {
+ kotlinOptions.jvmTarget = '1.8'
+ }
+ withJava()
+ testRuns["test"].executionTask.configure {
+ useJUnitPlatform()
}
}
- targets {
- final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
+// js(BOTH) {
+// browser {
+// commonWebpackConfig {
+// cssSupport.enabled = true
+// }
+// }
+// }
- fromPreset(iOSTarget, 'ios') {
- binaries {
- framework {
- baseName = "BankFinder"
-
- embedBitcode(embedBitcodeValue)
- }
+ ios {
+ binaries {
+ framework {
+ baseName = "BankFinder"
}
}
}
+// def hostOs = System.getProperty("os.name")
+// def isMingwX64 = hostOs.startsWith("Windows")
+// def nativeTarget
+// if (hostOs == "Mac OS X") nativeTarget = macosX64('native') { binaries.executable() }
+// else if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries.executable() }
+// else if (isMingwX64) nativeTarget = mingwX64("native") { binaries.executable() }
+// else throw new GradleException("Host OS is not supported in Kotlin/Native.")
+
sourceSets {
commonMain {
dependencies {
- api kotlin("stdlib-common")
-
api project(":common")
}
}
@@ -55,10 +66,7 @@ kotlin {
jvmTest {
dependencies {
- implementation kotlin("test-junit")
- implementation "org.junit.jupiter:junit-jupiter:$junit5Version"
- runtimeOnly "org.junit.jupiter:junit-jupiter-engine:$junit5Version"
}
}
@@ -66,97 +74,14 @@ kotlin {
iosMain {
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion"
+
}
}
iosTest {
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation "org.jetbrains.kotlin:kotlin-test"
+
}
}
}
-}
-
-
-// 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
- }
-
-}
-
-
-//task jarTest (type: Jar) {
-// from sourceSets.jvmTest.output
-// classifier = 'test'
-//}
-//
-//configurations {
-// testOutput
-//}
-//
-//artifacts {
-// testOutput jarTest
-//}
\ No newline at end of file
+}
\ No newline at end of file
diff --git a/tools/EpcQrCodeParser/build.gradle b/tools/EpcQrCodeParser/build.gradle
index c9b48918..25899cfb 100644
--- a/tools/EpcQrCodeParser/build.gradle
+++ b/tools/EpcQrCodeParser/build.gradle
@@ -1,55 +1,52 @@
plugins {
id 'org.jetbrains.kotlin.multiplatform'
-// id 'java-library'
- id "com.android.library" // TODO: get rid off, use java-library instead
id "maven-publish"
}
ext.artifactName = "epc-qr-code-parser"
-def frameworkName = "EpcQrCodeParser"
-
kotlin {
+ jvm {
+ compilations.all {
+ kotlinOptions.jvmTarget = '1.8'
+ }
+ withJava()
+ testRuns["test"].executionTask.configure {
+ useJUnitPlatform()
+ }
+ }
- targets {
- final def iOSTarget = iOSIsRealDevice ? presets.iosArm64 : presets.iosX64
+// js(BOTH) {
+// browser {
+// commonWebpackConfig {
+// cssSupport.enabled = true
+// }
+// }
+// }
- fromPreset(iOSTarget, 'ios') {
- binaries {
- framework {
- baseName = frameworkName
-
- embedBitcode(embedBitcodeValue)
- }
+ ios {
+ binaries {
+ framework {
+ baseName = "EpcQrCodeParser"
}
}
}
- jvm()
+// def hostOs = System.getProperty("os.name")
+// def isMingwX64 = hostOs.startsWith("Windows")
+// def nativeTarget
+// if (hostOs == "Mac OS X") nativeTarget = macosX64('native') { binaries.executable() }
+// else if (hostOs == "Linux") nativeTarget = linuxX64("native") { binaries.executable() }
+// else if (isMingwX64) nativeTarget = mingwX64("native") { binaries.executable() }
+// else throw new GradleException("Host OS is not supported in Kotlin/Native.")
- js {
-
- nodejs {
- testTask {
- enabled = false
- }
- }
-
- browser {
- testTask {
- enabled = false
- }
-
- }
-
- }
sourceSets {
commonMain {
dependencies {
- implementation kotlin('stdlib-common')
+
}
}
commonTest {
@@ -61,25 +58,24 @@ kotlin {
jvmMain {
dependencies {
- implementation kotlin('stdlib-jdk8')
+
}
}
jvmTest {
dependencies {
- implementation kotlin('test')
- implementation kotlin('test-junit')
+
}
}
jsMain {
dependencies {
- implementation kotlin('stdlib-js')
+
}
}
jsTest {
dependencies {
- implementation kotlin('test-js')
+
}
}
@@ -89,73 +85,4 @@ kotlin {
}
}
-}
-
-
-// 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
-
-
-// TODO: get rid of this
-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
- }
-
}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/build.gradle b/ui/BankingAndroidApp/build.gradle
deleted file mode 100644
index 73771dde..00000000
--- a/ui/BankingAndroidApp/build.gradle
+++ /dev/null
@@ -1,184 +0,0 @@
-apply plugin: 'com.android.application'
-apply plugin: 'kotlin-android'
-apply plugin: 'kotlin-android-extensions'
-apply plugin: 'kotlin-kapt'
-
-
-repositories {
- // for security issues fixed version of iText 2 from JasperReports
- maven {
- url "https://jaspersoft.jfrog.io/jaspersoft/third-party-ce-artifacts"
- }
-}
-
-
-android {
- compileSdkVersion androidCompileSdkVersion
- buildToolsVersion androidBuildToolsVersion
-
-
- defaultConfig {
- applicationId "net.codinux.banking.android"
-
- minSdkVersion androidMinSdkVersion
- targetSdkVersion androidTargetSdkVersion
-
- versionName version.replace("-", " ")
- versionCode appVersionCode
-
- multiDexEnabled true
-
- // enable using vector drawables on pre Lollipop devices
- vectorDrawables.useSupportLibrary = true
-
- testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
- }
-
- kotlinOptions {
- jvmTarget = '1.8'
- }
-
- compileOptions {
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- }
-
- buildTypes {
- debug {
- applicationIdSuffix = ".develop"
- }
- release {
- minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
- }
- }
-
- signingConfigs {
- debug {
- // so that all machines have the same signing key, no matter if app is installed from developer's machine or from Jenkins
- storeFile file('debug-keystore.jks')
- storePassword 'find_my_bugs_before_releasing_me'
- keyAlias 'DebugKey'
- keyPassword 'find_my_bugs_before_releasing_me'
- }
- }
-
- packagingOptions {
- pickFirst 'META-INF/kotlinx-coroutines-io.kotlin_module'
- pickFirst 'META-INF/kotlinx-io.kotlin_module'
- pickFirst 'META-INF/kotlinx-serialization-runtime.kotlin_module'
- pickFirst 'META-INF/ktor-utils.kotlin_module'
- pickFirst 'META-INF/ktor-client-core.kotlin_module'
- pickFirst 'META-INF/ktor-http.kotlin_module'
- pickFirst 'META-INF/ktor-io.kotlin_module'
- pickFirst 'META-INF/ktor-http-cio.kotlin_module'
- pickFirst 'META-INF/atomicfu.kotlin_module'
-
- pickFirst 'META-INF/common.kotlin_module'
- pickFirst 'META-INF/fints4k.kotlin_module'
- pickFirst 'META-INF/BankFinder.kotlin_module'
- pickFirst 'META-INF/BankFinder.kotlin_module'
-
- pickFirst 'META-INF/DEPENDENCIES'
- pickFirst 'META-INF/NOTICE'
- pickFirst 'META-INF/LICENSE'
- pickFirst 'META-INF/LICENSE.txt'
- pickFirst 'META-INF/NOTICE.txt'
-
- pickFirst 'BankList.json'
- exclude 'DetailedBankList.json'
- }
-
- lintOptions {
- abortOnError false
- }
-
-}
-
-dependencies {
- implementation project(":fints4k")
-
- implementation project(':BankingUiCommon')
-
- implementation project(':fints4kBankingClient')
-
- implementation project(':LuceneBankFinder')
-
- implementation project(':BankingPersistenceJson')
- implementation project(':LuceneBankingPersistence')
- implementation project(':RoomBankingPersistence')
-
- implementation project(':CsvAccountTransactionsImporterAndExporter')
-
-
- implementation "net.dankito.text.extraction:itext2-text-extractor:$textExtractorVersion"
- implementation "net.dankito.text.extraction:pdfbox-android-text-extractor:$textExtractorVersion" + "a" // TODO: version 0.6.0a become only necessary due to a misconfigured Maven upload task. Remove 'a' again on next version
-
- implementation "com.github.clans:fab:$clansFloatingActionButtonVersion"
- implementation 'info.hoang8f:android-segmented:1.0.6'
-
- implementation "com.otaliastudios:autocomplete:$autocompleteVersion"
-
- implementation("com.journeyapps:zxing-android-embedded:4.1.0") { transitive = false } // transitive to use older ZXing version as ZXing 3.4.0 requires Android > 23
- implementation "com.google.zxing:core:$zxingVersion"
-
- implementation "com.yakivmospan:scytale:$scytaleVersion"
-
- implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
- implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutinesVersion"
-
- implementation "net.dankito.filechooserdialog:filechooserdialog-android:$fileChooserDialogVersion", {
- exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib'
- exclude group: 'com.android.support', module: 'appcompat-v7'
- exclude group: 'com.android.support', module: 'design'
- exclude group: 'com.android.support.constraint', module: 'constraint-layout'
- exclude module: 'recyclerview-v7'
- }
-
- implementation "net.dankito.utils:android-utils:$androidUtilsVersion", {
- exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
- exclude group: 'com.android.support', module: 'appcompat-v7'
- exclude group: 'com.android.support', module: 'design'
- }
-
- // Android 4 support has been dropped with version 3.13.0
- implementation('com.squareup.okhttp3:okhttp') {
- version { strictly '3.12.12' }
- }
-
- implementation "org.slf4j:slf4j-android:$slf4jVersion"
-
-
- implementation "androidx.multidex:multidex:$multiDexVersion"
-
- implementation "androidx.appcompat:appcompat:$appCompatVersion"
- implementation "androidx.recyclerview:recyclerview:$appCompatVersion"
- implementation "androidx.annotation:annotation:$appCompatVersion"
- implementation "com.google.android.material:material:$materialComponentsVersion"
- implementation "androidx.constraintlayout:constraintlayout:$constraintLayoutVersion"
-
- implementation "androidx.biometric:biometric:$androidXBiometricVersion"
- implementation "at.favre.lib:bcrypt:$bcryptVersion"
-
- implementation "com.mikepenz:fastadapter:$fastAdapterVersion"
- implementation "com.mikepenz:fastadapter-extensions-binding:$fastAdapterVersion"
- implementation "com.mikepenz:fastadapter-extensions-drag:$fastAdapterVersion"
- implementation "com.mikepenz:fastadapter-extensions-swipe:$fastAdapterVersion"
- implementation "com.mikepenz:fastadapter-extensions-utils:$fastAdapterVersion"
-
- // for MaterialDrawer
- implementation "com.mikepenz:materialdrawer:$materialDrawerVersion"
- implementation "com.mikepenz:materialdrawer-nav:$materialDrawerVersion"
-
- implementation "com.mikepenz:materialdrawer-iconics:$materialDrawerVersion"
-
-
- kapt "com.google.dagger:dagger-compiler:$daggerVersion"
- implementation "com.google.dagger:dagger:$daggerVersion"
-
-
- implementation "androidx.navigation:navigation-fragment:$androidXNavigationVersion"
- implementation "androidx.navigation:navigation-ui:$androidXNavigationVersion"
- implementation "androidx.navigation:navigation-fragment-ktx:$androidXNavigationVersion"
- implementation "androidx.navigation:navigation-ui-ktx:$androidXNavigationVersion"
-}
diff --git a/ui/BankingAndroidApp/debug-keystore.jks b/ui/BankingAndroidApp/debug-keystore.jks
deleted file mode 100644
index 0809a56d..00000000
Binary files a/ui/BankingAndroidApp/debug-keystore.jks and /dev/null differ
diff --git a/ui/BankingAndroidApp/proguard-rules.pro b/ui/BankingAndroidApp/proguard-rules.pro
deleted file mode 100644
index f1b42451..00000000
--- a/ui/BankingAndroidApp/proguard-rules.pro
+++ /dev/null
@@ -1,21 +0,0 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
-
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
-
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
diff --git a/ui/BankingAndroidApp/src/main/AndroidManifest.xml b/ui/BankingAndroidApp/src/main/AndroidManifest.xml
deleted file mode 100644
index 0a13382e..00000000
--- a/ui/BankingAndroidApp/src/main/AndroidManifest.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/ic_launcher-playstore.png b/ui/BankingAndroidApp/src/main/ic_launcher-playstore.png
deleted file mode 100644
index 8e3d8299..00000000
Binary files a/ui/BankingAndroidApp/src/main/ic_launcher-playstore.png and /dev/null differ
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/BankingApp.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/BankingApp.kt
deleted file mode 100644
index 5da1fc3e..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/BankingApp.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.ui.android
-
-import androidx.multidex.MultiDexApplication
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.di.BankingModule
-import net.dankito.banking.ui.android.di.DaggerBankingComponent
-
-
-class BankingApp : MultiDexApplication() {
-
- override fun onCreate() {
- super.onCreate()
-
- setupDependencyInjection()
- }
-
- private fun setupDependencyInjection() {
- val component = DaggerBankingComponent.builder()
- .bankingModule(BankingModule(this))
- .build()
-
- BankingComponent.component = component
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/MainActivity.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/MainActivity.kt
deleted file mode 100644
index 6f61767c..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/MainActivity.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-package net.dankito.banking.ui.android
-
-import android.content.ClipData
-import android.content.ClipboardManager
-import android.content.Context
-import android.content.Intent
-import android.os.Bundle
-import android.os.Handler
-import android.os.Looper
-import android.view.Menu
-import android.view.MotionEvent
-import androidx.appcompat.app.ActionBarDrawerToggle
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.widget.Toolbar
-import androidx.core.os.postDelayed
-import androidx.drawerlayout.widget.DrawerLayout
-import com.github.clans.fab.FloatingActionMenu
-import com.google.zxing.integration.android.IntentIntegrator
-import com.google.zxing.integration.android.IntentResult
-import kotlinx.android.synthetic.main.activity_main.*
-import net.codinux.banking.tools.epcqrcode.ParseEpcQrCodeResult
-import net.dankito.banking.ui.android.activities.BaseActivity
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.di.BankingModule
-import net.dankito.banking.ui.android.views.DrawerView
-import net.dankito.banking.ui.android.views.MainActivityFloatingActionMenuButton
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.utils.android.permissions.IPermissionsService
-import net.dankito.utils.android.permissions.PermissionsService
-import javax.inject.Inject
-
-
-class MainActivity : BaseActivity() {
-
-// private lateinit var appBarConfiguration: AppBarConfiguration
-
- private lateinit var drawerToggle: ActionBarDrawerToggle
-
- private lateinit var drawerView: DrawerView
-
- private lateinit var floatingActionMenuButton: MainActivityFloatingActionMenuButton
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
- @Inject
- protected lateinit var permissionsService: IPermissionsService
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- BankingModule.mainActivity = this
-
- BankingComponent.component.inject(this)
-
- initUi()
- }
-
- private fun initUi() {
- setContentView(R.layout.activity_main)
-
- val toolbar: Toolbar = findViewById(R.id.toolbar)
- setSupportActionBar(toolbar)
-
- val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
-// val navController = findNavController(R.id.nav_host_fragment)
-
-// // Passing each menu ID as a set of Ids because each
-// // menu should be considered as top level destinations.
-// appBarConfiguration = AppBarConfiguration(
-// setOf(
-// R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow,
-// R.id.nav_tools, R.id.nav_share, R.id.nav_send
-// ), drawerLayout
-// )
-//
-// setupActionBarWithNavController(navController, appBarConfiguration)
-// navigationView.setupWithNavController(navController)
-
- drawerToggle = ActionBarDrawerToggle(
- this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
- drawerLayout.addDrawerListener(drawerToggle)
- drawerToggle.syncState()
-
- slider?.let { slider ->
- drawerView = DrawerView(this, slider, presenter)
- }
-
- val floatingActionMenu = findViewById(R.id.floatingActionMenu)
- floatingActionMenuButton = MainActivityFloatingActionMenuButton(floatingActionMenu, permissionsService, presenter)
- }
-
- override fun onCreateOptionsMenu(menu: Menu): Boolean {
- menuInflater.inflate(R.menu.menu_main, menu)
-
- return true
- }
-
-
-
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) {
- permissionsService.onRequestPermissionsResult(requestCode, permissions, grantResults)
-
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- }
-
- override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
- val scanQrCodeResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
-
- if (scanQrCodeResult != null) {
- // at this point camera activity is still displayed and not returned yet to MainActivity -> app would crash if we don't wait
- Handler(Looper.getMainLooper()).postDelayed(250) {
- handleQrCodeScanResult(scanQrCodeResult)
- }
- }
- else {
- super.onActivityResult(requestCode, resultCode, data)
- }
- }
-
- private fun handleQrCodeScanResult(scanQrCodeResult: IntentResult) {
- scanQrCodeResult.contents?.let { decodedQrCode ->
- val result = presenter.showTransferMoneyDialogWithDataFromQrCode(decodedQrCode)
-
- if (result.successful == false) {
- showParseQrCodeError(result)
- }
- }
- }
-
- protected fun showParseQrCodeError(result: ParseEpcQrCodeResult) {
- // TODO: show localized error message that matches ParseEpcQrCodeResultCode
- val errorMessage = getString(R.string.money_transfer_from_scanning_qr_code_error, result.error, result.decodedQrCode)
-
- AlertDialog.Builder(this)
- .setMessage(errorMessage)
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
-
-
- override fun dispatchTouchEvent(event: MotionEvent): Boolean {
- if(floatingActionMenuButton.handlesTouch(event)) { // close menu when menu is opened and touch is outside floatingActionMenuButton
- return true
- }
-
- return super.dispatchTouchEvent(event)
- }
-
- override fun onBackPressed() {
- if (floatingActionMenuButton.handlesBackButtonPress()) { // close menu when menu is opened and back button gets pressed
- return
- }
-
- super.onBackPressed()
- }
-
-}
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/RouterAndroid.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/RouterAndroid.kt
deleted file mode 100644
index 342084d2..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/RouterAndroid.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package net.dankito.banking.ui.android
-
-import net.dankito.banking.ui.android.util.CurrentActivityTracker
-import net.dankito.banking.ui.IRouter
-import net.dankito.banking.ui.android.dialogs.*
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.parameters.TransferMoneyData
-import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
-import net.dankito.banking.ui.model.tan.EnterTanResult
-import net.dankito.banking.ui.model.tan.TanChallenge
-import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium
-import net.dankito.banking.ui.presenter.BankingPresenter
-
-
-open class RouterAndroid(protected val activityTracker: CurrentActivityTracker) : IRouter {
-
- override fun showAddAccountDialog(presenter: BankingPresenter) {
- activityTracker.currentOrNextActivity { activity ->
- AddAccountDialog().show(activity)
- }
- }
-
- override fun getTanFromUserFromNonUiThread(bank: TypedBankData, tanChallenge: TanChallenge, presenter: BankingPresenter, callback: (EnterTanResult) -> Unit) {
- activityTracker.currentOrNextActivity { activity ->
- activity.runOnUiThread {
- EnterTanDialog().show(bank, tanChallenge, activity, false) { result ->
- callback(result)
- }
- }
- }
- }
-
- override fun getAtcFromUserFromNonUiThread(tanMedium: TanGeneratorTanMedium, callback: (EnterTanGeneratorAtcResult) -> Unit) {
- activityTracker.currentOrNextActivity { activity ->
- activity.runOnUiThread {
- EnterAtcDialog().show(tanMedium, activity, false) { enteredResult ->
- callback(enteredResult)
- }
- }
- }
- }
-
- override fun showTransferMoneyDialog(presenter: BankingPresenter, preselectedValues: TransferMoneyData?) {
- activityTracker.currentOrNextActivity { activity ->
- TransferMoneyDialog().show(activity, preselectedValues)
- }
- }
-
- override fun showSendMessageLogDialog(presenter: BankingPresenter) {
- activityTracker.currentOrNextActivity { activity ->
- activity.runOnUiThread {
- SendMessageLogDialog().show(activity)
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/ActivityExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/ActivityExtensions.kt
deleted file mode 100644
index ded62c06..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/ActivityExtensions.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.dankito.banking.ui.android.activities
-
-import android.app.Activity
-import android.content.Intent
-import android.util.DisplayMetrics
-
-
-fun Activity.navigateToActivity(activityClass: Class) {
- val intent = Intent(applicationContext, activityClass)
-
- startActivity(intent)
-}
-
-val Activity.screenWidth: Int
- get() {
- val displayMetrics = DisplayMetrics()
- windowManager.defaultDisplay.getMetrics(displayMetrics)
-
- return displayMetrics.widthPixels
- }
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/BaseActivity.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/BaseActivity.kt
deleted file mode 100644
index 45dae8df..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/BaseActivity.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-package net.dankito.banking.ui.android.activities
-
-import android.content.pm.ActivityInfo
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.util.CurrentActivityTracker
-import org.slf4j.LoggerFactory
-import javax.inject.Inject
-
-
-abstract class BaseActivity : AppCompatActivity() {
-
- companion object {
- private val log = LoggerFactory.getLogger(BaseActivity::class.java)
- }
-
-
- @Inject
- protected lateinit var currentActivityTracker: CurrentActivityTracker
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- open val isRunningOnTablet: Boolean
- get() = resources.getBoolean(R.bool.isTablet)
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- log.info("Creating Activity $this")
-
- // a bit bad as it not clearly visible that orientation lock is done here
- if (isRunningOnTablet == false) { // lock screen to portrait mode on phones as there app really looks bad and some EditTexts are almost unusable
- requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
- }
-
- super.onCreate(savedInstanceState)
- }
-
- override fun onStart() {
- super.onStart()
-
- currentActivityTracker.currentActivity = this
-
- log.info("Started Activity $this")
- }
-
- override fun onResume() {
- super.onResume()
-
- currentActivityTracker.currentActivity = this
-
- log.info("Resumed Activity $this")
- }
-
- override fun onPause() {
- log.info("Paused Activity $this")
-
- super.onPause()
- }
-
- override fun onStop() {
- log.info("Stopped Activity $this")
-
- super.onStop()
- }
-
- override fun onDestroy() {
- log.info("Destroyed Activity $this")
-
- super.onDestroy()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/LandingActivity.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/LandingActivity.kt
deleted file mode 100644
index c72b9aa9..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/LandingActivity.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-package net.dankito.banking.ui.android.activities
-
-import android.app.Activity
-import android.os.Bundle
-import androidx.appcompat.app.AppCompatActivity
-import net.dankito.banking.ui.android.MainActivity
-import net.dankito.banking.ui.android.authentication.AuthenticationService
-import net.dankito.banking.ui.android.authentication.AuthenticationType
-import net.dankito.banking.ui.android.di.BankingComponent
-import javax.inject.Inject
-
-
-open class LandingActivity : AppCompatActivity() {
-
- @Inject
- protected lateinit var authenticationService: AuthenticationService
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- if (authenticationService.authenticationType == AuthenticationType.None) {
- launchActivity(MainActivity::class.java)
- }
- else {
- launchActivity(LoginActivity::class.java)
- }
- }
-
-
- protected open fun launchActivity(activityClass: Class) {
- navigateToActivity(activityClass)
-
- finish()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/LoginActivity.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/LoginActivity.kt
deleted file mode 100644
index 2a67a43a..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/activities/LoginActivity.kt
+++ /dev/null
@@ -1,89 +0,0 @@
-package net.dankito.banking.ui.android.activities
-
-import android.os.Bundle
-import android.view.View
-import android.widget.Toast
-import kotlinx.android.synthetic.main.activity_login.*
-import kotlinx.android.synthetic.main.activity_login.btnBiometricAuthentication
-import kotlinx.android.synthetic.main.view_biometric_authentication_button.*
-import net.dankito.banking.ui.android.MainActivity
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.authentication.AuthenticationService
-import net.dankito.banking.ui.android.authentication.AuthenticationType
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.extensions.addEnterPressedListener
-import net.dankito.utils.android.extensions.hide
-import javax.inject.Inject
-
-
-open class LoginActivity : BaseActivity() {
-
- @Inject
- protected lateinit var authenticationService: AuthenticationService
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- initUi()
- }
-
-
- protected open fun initUi() {
- setContentView(R.layout.activity_login)
-
- if (authenticationService.authenticationType == AuthenticationType.Password) {
- lytBiometricAuthentication.hide()
-
- edtxtLoginPassword.actualEditText.addEnterPressedListener {
- checkEnteredPasswordAndLogIn()
- true
- }
-
- btnLogin.setOnClickListener { checkEnteredPasswordAndLogIn() }
- }
- else {
- lytPasswordAuthentication.hide()
-
- btnBiometricAuthentication.customButtonClickHandler = {
- authenticationService.loginUserWithBiometric { result ->
- if (result) {
- btnStartBiometricAuthentication.isEnabled = false
-
- biometricAuthenticationSuccessful()
- }
- }
- }
-
- btnBiometricAuthentication.showBiometricPrompt()
- }
- }
-
-
- protected open fun checkEnteredPasswordAndLogIn() {
- btnLogin.isEnabled = false
-
- if (authenticationService.loginUserWithPassword(edtxtLoginPassword.chars)) {
- navigateToMainActivity()
- }
- else {
- btnLogin.isEnabled = true
-
- Toast.makeText(this, R.string.activity_login_incorrect_password_entered, Toast.LENGTH_SHORT).show()
- }
- }
-
- protected open fun biometricAuthenticationSuccessful() {
- navigateToMainActivity()
- }
-
- protected open fun navigateToMainActivity() {
- navigateToActivity(MainActivity::class.java)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/AccountTransactionAdapter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/AccountTransactionAdapter.kt
deleted file mode 100644
index fcf92c2c..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/AccountTransactionAdapter.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.ContextMenu
-import android.view.View
-import androidx.appcompat.app.AppCompatActivity
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.viewholder.AccountTransactionViewHolder
-import net.dankito.banking.ui.android.dialogs.AccountTransactionDetailsDialog
-import net.dankito.banking.ui.android.extensions.setIcon
-import net.dankito.banking.ui.android.extensions.showAmount
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.utils.android.extensions.asActivity
-import net.dankito.utils.android.extensions.hide
-import net.dankito.utils.android.extensions.show
-import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
-
-
-open class AccountTransactionAdapter(protected val presenter: BankingPresenter)
- : ListRecyclerAdapter() {
-
-
- var selectedTransaction: IAccountTransaction? = null
-
-
- override fun getListItemLayoutId() = R.layout.list_item_account_transaction
-
- override fun createViewHolder(itemView: View): AccountTransactionViewHolder {
- val viewHolder = AccountTransactionViewHolder(itemView)
-
- itemView.setOnCreateContextMenuListener { menu, view, menuInfo -> createContextMenu(menu, view, menuInfo, viewHolder) }
-
- return viewHolder
- }
-
- override fun bindItemToView(viewHolder: AccountTransactionViewHolder, item: IAccountTransaction) {
- viewHolder.txtvwDate.text = presenter.formatToShortDate(item.valueDate)
-
- val label = if (item.showOtherPartyName) item.otherPartyName else item.bookingText
- viewHolder.txtvwTransactionLabel.text = label ?: item.bookingText ?: ""
-
- viewHolder.txtvwReference.text = item.reference
-
- viewHolder.txtvwAmount.showAmount(presenter, item.amount, item.currency)
-
- if (presenter.areAllAccountSelected) {
- viewHolder.imgvwBankIcon.setIcon(item.account.bank)
- viewHolder.imgvwBankIcon.show()
- }
- else {
- // TODO: if bank icon isn't set: Show default icon? show at least an empty space to that amount and date don't shift up causing an inconsistent view?
- viewHolder.imgvwBankIcon.hide()
- }
-
- viewHolder.itemView.setOnClickListener {
- AccountTransactionDetailsDialog().show(item, viewHolder.itemView.context as AppCompatActivity)
- }
- }
-
-
- protected open fun createContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenu.ContextMenuInfo?,
- viewHolder: AccountTransactionViewHolder) {
-
- view.context.asActivity()?.menuInflater?.inflate(R.menu.context_menu_account_transactions, menu)
-
- selectedTransaction = getItem(viewHolder.adapterPosition)
-
- val canCreateMoneyTransferFrom = selectedTransaction?.canCreateMoneyTransferFrom ?: false
-
- menu.findItem(R.id.mnitmNewTransferWithSameData)?.isVisible = canCreateMoneyTransferFrom
-
- menu.findItem(R.id.mnitmNewTransferToSameTransactionParty)?.let { mnitmShowTransferMoneyDialog ->
- mnitmShowTransferMoneyDialog.isVisible = canCreateMoneyTransferFrom
-
- val recipientName = selectedTransaction?.otherPartyName ?: ""
-
- mnitmShowTransferMoneyDialog.title = view.context.getString(R.string.fragment_home_transfer_money_to, recipientName)
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/BankDataAdapterItem.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/BankDataAdapterItem.kt
deleted file mode 100644
index 84afc7ed..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/BankDataAdapterItem.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.View
-import com.mikepenz.fastadapter.drag.IDraggable
-import com.mikepenz.fastadapter.items.AbstractItem
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.viewholder.BankDataViewHolder
-import net.dankito.banking.ui.model.TypedBankData
-
-
-open class BankDataAdapterItem(open val bank: TypedBankData) : AbstractItem(), IDraggable {
-
- override var isDraggable = true
-
- override val type: Int
- get() = R.id.bank_data_item_id
-
- override val layoutRes: Int
- get() = R.layout.list_item_bank_data
-
- override fun getViewHolder(v: View): BankDataViewHolder {
- return BankDataViewHolder(v)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/BankListAdapter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/BankListAdapter.kt
deleted file mode 100644
index 90ca7fc8..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/BankListAdapter.kt
+++ /dev/null
@@ -1,43 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.View
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.viewholder.BankInfoViewHolder
-import net.dankito.banking.bankfinder.BankInfo
-import net.dankito.utils.android.extensions.setTintColor
-import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
-
-
-open class BankListAdapter(protected val itemClicked: ((BankInfo) -> Unit)? = null) : ListRecyclerAdapter() {
-
- override fun getListItemLayoutId() = R.layout.list_item_bank_info
-
- override fun createViewHolder(itemView: View): BankInfoViewHolder {
- return BankInfoViewHolder(itemView)
- }
-
- override fun bindItemToView(viewHolder: BankInfoViewHolder, item: BankInfo) {
- if (item.supportsFinTs3_0) {
- viewHolder.imgSupportsFints30.setImageResource(R.drawable.ic_check_circle_white_48dp)
- viewHolder.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_supported)
- }
- else {
- viewHolder.imgSupportsFints30.setImageResource(R.drawable.ic_clear_white_48dp)
- viewHolder.imgSupportsFints30.setTintColor(R.color.list_item_bank_info_bank_not_supported)
- }
-
- viewHolder.txtvwBankName.text = item.name
- viewHolder.txtvwBankName.isEnabled = item.supportsFinTs3_0
-
- viewHolder.txtvwBankCode.text = item.bankCode
- viewHolder.txtvwBankCode.isEnabled = item.supportsFinTs3_0
-
- viewHolder.txtvwBankAddress.text = item.postalCode + " " + item.city
- viewHolder.txtvwBankAddress.isEnabled = item.supportsFinTs3_0
-
- viewHolder.itemView.setOnClickListener {
- itemClicked?.invoke(item)
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/CheckableValueAdapterItem.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/CheckableValueAdapterItem.kt
deleted file mode 100644
index 0d18d1d0..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/CheckableValueAdapterItem.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.content.Context
-import android.view.View
-import androidx.annotation.StringRes
-import com.mikepenz.fastadapter.items.AbstractItem
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.viewholder.CheckableValueViewHolder
-
-
-open class CheckableValueAdapterItem(open val isChecked: Boolean, open val text: String) : AbstractItem() {
-
- constructor(isChecked: Boolean, context: Context, @StringRes textStringResourceId: Int) : this(isChecked, context.getString(textStringResourceId))
-
-
- override val type: Int
- get() = R.id.checkable_value_item_id
-
- override val layoutRes: Int
- get() = R.layout.list_item_checkable_value
-
-
- override fun getViewHolder(v: View): CheckableValueViewHolder {
- return CheckableValueViewHolder(v)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/DraggableBankAccountAdapterItem.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/DraggableBankAccountAdapterItem.kt
deleted file mode 100644
index 1eb9022e..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/DraggableBankAccountAdapterItem.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.View
-import com.mikepenz.fastadapter.drag.IDraggable
-import com.mikepenz.fastadapter.items.AbstractItem
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.viewholder.DraggableBankAccountViewHolder
-import net.dankito.banking.ui.model.TypedBankAccount
-
-
-open class DraggableBankAccountAdapterItem(open val account: TypedBankAccount) : AbstractItem(), IDraggable {
-
- override var isDraggable = true
-
- override val type: Int
- get() = R.id.draggable_bank_account_item_id
-
- override val layoutRes: Int
- get() = R.layout.list_item_draggable_bank_account
-
- override fun getViewHolder(v: View): DraggableBankAccountViewHolder {
- return DraggableBankAccountViewHolder(v)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/FastAdapterRecyclerView.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/FastAdapterRecyclerView.kt
deleted file mode 100644
index 5351e464..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/FastAdapterRecyclerView.kt
+++ /dev/null
@@ -1,86 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import androidx.recyclerview.widget.DefaultItemAnimator
-import androidx.recyclerview.widget.ItemTouchHelper
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import com.mikepenz.fastadapter.FastAdapter
-import com.mikepenz.fastadapter.GenericItem
-import com.mikepenz.fastadapter.adapters.ItemAdapter
-import com.mikepenz.fastadapter.adapters.ItemAdapter.Companion.items
-import com.mikepenz.fastadapter.drag.ItemTouchCallback
-import com.mikepenz.fastadapter.drag.SimpleDragCallback
-import com.mikepenz.fastadapter.select.getSelectExtension
-import com.mikepenz.fastadapter.utils.DragDropUtil
-
-
-open class FastAdapterRecyclerView- (
- recyclerView: RecyclerView,
- items: List
- = listOf(),
- enableDragAndDrop: Boolean = false,
- open var itemDropped: ((oldPosition: Int, oldItem: Item, newPosition: Int, newItem: Item) -> Unit)? = null,
- open var onClickListener: ((Item) -> Unit)? = null
-) : ItemTouchCallback {
-
-
- protected val fastAdapter: FastAdapter
-
- protected val itemAdapter: ItemAdapter
-
-
- private lateinit var touchCallback: SimpleDragCallback
- private lateinit var touchHelper: ItemTouchHelper
-
-
- init {
- itemAdapter = items()
-
- fastAdapter = FastAdapter.with(itemAdapter)
-
- init(recyclerView, items, enableDragAndDrop)
- }
-
-
- protected open fun init(recyclerView: RecyclerView, items: List
- , enableDragAndDrop: Boolean = true) {
- val selectExtension = fastAdapter.getSelectExtension()
- selectExtension.isSelectable = true
-
- fastAdapter.onClickListener = { _, _, item, _ ->
- onClickListener?.invoke(item)
- false
- }
-
- recyclerView.layoutManager = LinearLayoutManager(recyclerView.context)
- recyclerView.itemAnimator = DefaultItemAnimator()
- recyclerView.adapter = fastAdapter
-
- itemAdapter.set(items)
-
-
- if (enableDragAndDrop) {
- touchCallback = SimpleDragCallback(this)
- touchHelper = ItemTouchHelper(touchCallback)
- touchHelper.attachToRecyclerView(recyclerView)
- }
- }
-
-
- override fun itemTouchStartDrag(viewHolder: RecyclerView.ViewHolder) {
- // add visual highlight to dragged item
- }
-
- override fun itemTouchOnMove(oldPosition: Int, newPosition: Int): Boolean {
- DragDropUtil.onMove(itemAdapter, oldPosition, newPosition) // change position
- return true
- }
-
- override fun itemTouchDropped(oldPosition: Int, newPosition: Int) {
- // remove visual highlight to dropped item
-
- itemDropped?.invoke(oldPosition, itemAdapter.getAdapterItem(oldPosition), newPosition, itemAdapter.getAdapterItem(newPosition))
- }
-
-
- open fun setItems(items: List
- ) {
- itemAdapter.set(items)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/IconedBankAccountsAdapter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/IconedBankAccountsAdapter.kt
deleted file mode 100644
index 715cbf6e..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/IconedBankAccountsAdapter.kt
+++ /dev/null
@@ -1,32 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.content.Context
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import kotlinx.android.synthetic.main.list_item_iconed_bank_account.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.extensions.setIcon
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.utils.android.ui.adapter.ListAdapter
-
-
-open class IconedBankAccountsAdapter(accounts: List) : ListAdapter(accounts) {
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
-
- val item = getItem(position)
-
- val inflater = parent?.context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater
- val view = convertView ?: inflater?.inflate(R.layout.list_item_iconed_bank_account, parent, false)
-
- view?.let {
- view.txtBankAccountDisplayName.text = item.displayName
-
- view.imgBankIcon.setIcon(item.bank)
- }
-
- return view
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/RecipientListAdapter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/RecipientListAdapter.kt
deleted file mode 100644
index e46c03c1..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/RecipientListAdapter.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.View
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.viewholder.RecipientViewHolder
-import net.dankito.banking.search.TransactionParty
-import net.dankito.utils.android.extensions.isGone
-import net.dankito.utils.android.ui.adapter.ListRecyclerAdapter
-
-
-open class RecipientListAdapter(protected val itemClicked: ((TransactionParty) -> Unit)? = null) : ListRecyclerAdapter() {
-
- override fun getListItemLayoutId() = R.layout.list_item_recipient
-
- override fun createViewHolder(itemView: View): RecipientViewHolder {
- return RecipientViewHolder(itemView)
- }
-
- override fun bindItemToView(viewHolder: RecipientViewHolder, item: TransactionParty) {
- viewHolder.txtvwRecipientName.text = item.name
-
- viewHolder.txtvwRecipientBankName.text = item.bankName
- viewHolder.txtvwRecipientBankName.isGone = item.bankName.isNullOrBlank()
-
- viewHolder.txtvwRecipientAccountId.text = item.iban
-
- viewHolder.txtvwRecipientBankCode.text = item.bic
-
- viewHolder.itemView.setOnClickListener {
- itemClicked?.invoke(item)
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMediumAdapter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMediumAdapter.kt
deleted file mode 100644
index de02b008..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMediumAdapter.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.model.tan.TanMedium
-import net.dankito.utils.android.extensions.asActivity
-import net.dankito.utils.android.ui.adapter.ListAdapter
-
-
-open class TanMediumAdapter : ListAdapter() {
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
- val tanMedium = getItem(position)
-
- val view = convertView ?: parent?.context?.asActivity()?.layoutInflater?.inflate(
- R.layout.list_item_tan_medium, parent, false)
-
- view?.findViewById(R.id.txtTanMediumDisplayName)?.text = tanMedium.displayName
-
- return view
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMethodAdapterItem.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMethodAdapterItem.kt
deleted file mode 100644
index 49798d3a..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMethodAdapterItem.kt
+++ /dev/null
@@ -1,7 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import net.dankito.banking.ui.model.tan.TanMethod
-
-
-open class TanMethodAdapterItem(open val tanMethod: TanMethod, isSelectedTanMethod: Boolean)
- : CheckableValueAdapterItem(isSelectedTanMethod, tanMethod.displayName)
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMethodsAdapter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMethodsAdapter.kt
deleted file mode 100644
index 4be49be7..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/TanMethodsAdapter.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.ui.android.adapter
-
-import android.view.View
-import android.view.ViewGroup
-import android.widget.TextView
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.model.tan.TanMethod
-import net.dankito.utils.android.extensions.asActivity
-import net.dankito.utils.android.ui.adapter.ListAdapter
-
-
-open class TanMethodsAdapter : ListAdapter() {
-
- override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? {
- val method = getItem(position)
-
- val view = convertView ?: parent?.context?.asActivity()?.layoutInflater?.inflate(
- R.layout.list_item_tan_method, parent, false)
-
- view?.findViewById(R.id.txtTanMethodDisplayName)?.text = method.displayName
-
- return view
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/presenter/BankInfoPresenter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/presenter/BankInfoPresenter.kt
deleted file mode 100644
index 4fd503b8..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/presenter/BankInfoPresenter.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.dankito.banking.ui.android.adapter.presenter
-
-import android.content.Context
-import androidx.recyclerview.widget.RecyclerView
-import com.otaliastudios.autocomplete.RecyclerViewPresenter
-import kotlinx.coroutines.*
-import net.dankito.banking.ui.android.adapter.BankListAdapter
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.banking.bankfinder.BankInfo
-import net.dankito.banking.ui.android.extensions.addHorizontalItemDivider
-
-
-open class BankInfoPresenter(protected val presenter: BankingPresenter, context: Context) : RecyclerViewPresenter(context) {
-
- protected val adapter = BankListAdapter { dispatchClick(it) }
-
- protected var lastSearchBanksJob: Job? = null
-
-
- override fun instantiateAdapter(): RecyclerView.Adapter<*> {
- recyclerView?.addHorizontalItemDivider()
-
- return adapter
- }
-
- override fun onQuery(query: CharSequence?) {
- lastSearchBanksJob?.cancel()
-
- lastSearchBanksJob = GlobalScope.launch(Dispatchers.IO) {
- val filteredBanks = presenter.findBanksByNameBankCodeOrCity(query?.toString())
-
- withContext(Dispatchers.Main) {
- adapter.items = filteredBanks
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/presenter/RecipientPresenter.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/presenter/RecipientPresenter.kt
deleted file mode 100644
index cc71845c..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/presenter/RecipientPresenter.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-package net.dankito.banking.ui.android.adapter.presenter
-
-import android.content.Context
-import androidx.recyclerview.widget.RecyclerView
-import com.otaliastudios.autocomplete.RecyclerViewPresenter
-import kotlinx.coroutines.*
-import net.dankito.banking.ui.android.adapter.RecipientListAdapter
-import net.dankito.banking.search.TransactionParty
-import net.dankito.banking.ui.android.extensions.addHorizontalItemDivider
-import net.dankito.banking.ui.presenter.BankingPresenter
-
-
-open class RecipientPresenter(protected val bankingPresenter: BankingPresenter, context: Context) : RecyclerViewPresenter(context) {
-
- protected val adapter = RecipientListAdapter { dispatchClick(it) }
-
- protected var lastSearchRecipientJob: Job? = null
-
-
- override fun instantiateAdapter(): RecyclerView.Adapter<*> {
- recyclerView?.addHorizontalItemDivider()
-
- return adapter
- }
-
- override fun onQuery(query: CharSequence?) {
- lastSearchRecipientJob?.cancel()
-
- lastSearchRecipientJob = GlobalScope.launch(Dispatchers.IO) {
- val potentialRecipients = bankingPresenter.findRecipientsForName(query?.toString() ?: "")
-
- withContext(Dispatchers.Main) {
- adapter.items = potentialRecipients
- }
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/AccountTransactionViewHolder.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/AccountTransactionViewHolder.kt
deleted file mode 100644
index d05eb757..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/AccountTransactionViewHolder.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package net.dankito.banking.ui.android.adapter.viewholder
-
-import android.view.View
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import kotlinx.android.synthetic.main.list_item_account_transaction.view.*
-
-
-open class AccountTransactionViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-
- val txtvwDate: TextView = itemView.txtvwDate
-
- val txtvwTransactionLabel: TextView = itemView.txtvwTransactionLabel
-
- val txtvwReference: TextView = itemView.txtvwReference
-
- val txtvwAmount: TextView = itemView.txtvwAmount
-
- val imgvwBankIcon: ImageView = itemView.imgvwBankIcon
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/BankDataViewHolder.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/BankDataViewHolder.kt
deleted file mode 100644
index 8f166ee3..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/BankDataViewHolder.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.dankito.banking.ui.android.adapter.viewholder
-
-import android.view.View
-import android.widget.ImageView
-import android.widget.TextView
-import com.mikepenz.fastadapter.FastAdapter
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.BankDataAdapterItem
-import net.dankito.banking.ui.android.extensions.setIcon
-
-
-open class BankDataViewHolder(view: View) : FastAdapter.ViewHolder(view) {
-
- protected var bankIcon: ImageView = view.findViewById(R.id.imgBankIcon)
- protected var bankDisplayName: TextView = view.findViewById(R.id.txtBankDisplayName)
-
-
- override fun bindView(item: BankDataAdapterItem, payloads: List) {
- bankIcon.setIcon(item.bank)
- bankDisplayName.text = item.bank.displayName
- }
-
- override fun unbindView(item: BankDataAdapterItem) {
- bankDisplayName.text = null
- bankIcon.setImageURI(null)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/BankInfoViewHolder.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/BankInfoViewHolder.kt
deleted file mode 100644
index b19ad1a3..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/BankInfoViewHolder.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.dankito.banking.ui.android.adapter.viewholder
-
-import android.view.View
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import kotlinx.android.synthetic.main.list_item_bank_info.view.*
-
-
-open class BankInfoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-
- val imgSupportsFints30: ImageView = itemView.imgSupportsFints30
-
- val txtvwBankName: TextView = itemView.txtvwBankName
-
- val txtvwBankCode: TextView = itemView.txtvwBankCode
-
- val txtvwBankAddress: TextView = itemView.txtvwBankAddress
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/CheckableValueViewHolder.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/CheckableValueViewHolder.kt
deleted file mode 100644
index 4d364c69..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/CheckableValueViewHolder.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package net.dankito.banking.ui.android.adapter.viewholder
-
-import android.view.View
-import android.widget.ImageView
-import android.widget.TextView
-import com.mikepenz.fastadapter.FastAdapter
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.CheckableValueAdapterItem
-import net.dankito.utils.android.extensions.setVisibleOrInvisible
-
-
-open class CheckableValueViewHolder(view: View) : FastAdapter.ViewHolder(view) {
-
- protected var imgCheckmark: ImageView = view.findViewById(R.id.imgCheckmark)
-
- protected var txtValue: TextView = view.findViewById(R.id.txtValue)
-
-
- override fun bindView(item: CheckableValueAdapterItem, payloads: List) {
- imgCheckmark.setVisibleOrInvisible(item.isChecked)
-
- txtValue.text = item.text
- }
-
- override fun unbindView(item: CheckableValueAdapterItem) {
- imgCheckmark.setImageURI(null)
-
- txtValue.text = null
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/DraggableBankAccountViewHolder.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/DraggableBankAccountViewHolder.kt
deleted file mode 100644
index 0e33ab52..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/DraggableBankAccountViewHolder.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package net.dankito.banking.ui.android.adapter.viewholder
-
-import android.view.View
-import android.widget.TextView
-import com.mikepenz.fastadapter.FastAdapter
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.DraggableBankAccountAdapterItem
-
-
-open class DraggableBankAccountViewHolder(view: View) : FastAdapter.ViewHolder(view) {
-
- protected var accountDisplayName: TextView = view.findViewById(R.id.txtBankDisplayName)
-
-
- override fun bindView(item: DraggableBankAccountAdapterItem, payloads: List) {
- accountDisplayName.text = item.account.displayName
- }
-
- override fun unbindView(item: DraggableBankAccountAdapterItem) {
- accountDisplayName.text = null
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/RecipientViewHolder.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/RecipientViewHolder.kt
deleted file mode 100644
index 80ad493f..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/adapter/viewholder/RecipientViewHolder.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.dankito.banking.ui.android.adapter.viewholder
-
-import android.view.View
-import android.widget.TextView
-import androidx.recyclerview.widget.RecyclerView
-import kotlinx.android.synthetic.main.list_item_recipient.view.*
-
-
-open class RecipientViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-
- val txtvwRecipientName: TextView = itemView.txtvwRecipientName
-
- val txtvwRecipientBankName: TextView = itemView.txtvwRecipientBankName
-
- val txtvwRecipientAccountId: TextView = itemView.txtvwRecipientAccountId
-
- val txtvwRecipientBankCode: TextView = itemView.txtvwRecipientBankCode
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/alerts/AskDeleteAccountAlert.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/alerts/AskDeleteAccountAlert.kt
deleted file mode 100644
index 61665151..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/alerts/AskDeleteAccountAlert.kt
+++ /dev/null
@@ -1,25 +0,0 @@
-package net.dankito.banking.ui.android.alerts
-
-import android.content.Context
-import androidx.appcompat.app.AlertDialog
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.presenter.BankingPresenter
-
-
-open class AskDeleteAccountAlert {
-
- open fun show(bank: TypedBankData, presenter: BankingPresenter, context: Context, accountDeleted: (() -> Unit)? = null) {
- AlertDialog.Builder(context)
- .setTitle(context.getString(R.string.alert_ask_delete_account_title))
- .setMessage(context.getString(R.string.alert_ask_delete_account_message, bank.displayName))
- .setPositiveButton(R.string.delete) { dialog, _ ->
- presenter.deleteAccount(bank)
- dialog.dismiss()
- accountDeleted?.invoke()
- }
- .setNegativeButton(R.string.cancel) { dialog, _ -> dialog.dismiss() }
- .show()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/alerts/AskDismissChangesAlert.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/alerts/AskDismissChangesAlert.kt
deleted file mode 100644
index 6e01711d..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/alerts/AskDismissChangesAlert.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package net.dankito.banking.ui.android.alerts
-
-import androidx.appcompat.app.AlertDialog
-import androidx.fragment.app.DialogFragment
-import net.dankito.banking.ui.android.R
-
-
-open class AskDismissChangesAlert {
-
- open fun show(dialog: DialogFragment) {
- val context = dialog.requireContext()
-
- AlertDialog.Builder(context)
- .setTitle(context.getString(R.string.alert_ask_discard_changes_title))
- .setMessage(context.getString(R.string.alert_ask_discard_changes_message))
- .setPositiveButton(R.string.discard) { alert, _ ->
- alert.dismiss()
- dialog.dismiss()
- }
- .setNegativeButton(R.string.cancel) { alert, _ -> alert.dismiss() }
- .show()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationResult.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationResult.kt
deleted file mode 100644
index d6c8111d..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationResult.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package net.dankito.banking.ui.android.authentication
-
-
-open class AuthenticationResult(
- open val successful: Boolean,
- open val error: String? = null
-) {
-
- override fun toString(): String {
- return if (successful) {
- "Successful"
- }
- else {
- "Error occurred: $error"
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt
deleted file mode 100644
index a95624f5..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationService.kt
+++ /dev/null
@@ -1,305 +0,0 @@
-package net.dankito.banking.ui.android.authentication
-
-import android.content.Context
-import android.util.Base64
-import at.favre.lib.crypto.bcrypt.BCrypt
-import com.yakivmospan.scytale.Crypto
-import com.yakivmospan.scytale.Options
-import com.yakivmospan.scytale.Store
-import net.dankito.banking.persistence.IBankingPersistence
-import net.dankito.banking.ui.android.security.CryptographyManager
-import net.dankito.banking.util.ISerializer
-import net.dankito.utils.multiplatform.File
-import net.dankito.utils.multiplatform.asString
-import org.slf4j.LoggerFactory
-import javax.crypto.Cipher
-import javax.crypto.SecretKey
-
-
-open class AuthenticationService(
- protected open val applicationContext: Context,
- protected open val biometricAuthenticationService: IBiometricAuthenticationService,
- protected open val persistence: IBankingPersistence,
- protected open val dataFolder: File,
- protected open val serializer: ISerializer,
- protected open val cryptographyManager: CryptographyManager = CryptographyManager()
-) {
-
- companion object {
- private const val AuthenticationSettingsFilename = "a"
-
- private const val AuthenticationSettingsFileKey = "AuthenticationSettingsFileKey"
-
- private val AuthenticationSettingsFileKeyPassword = "AuthenticationSettingsFileKeyAuthenticationSettingsFileKeyPassword".toCharArray() // TODO: store in a secure place
-
- private const val EncryptionKeyName = "BankingAndroidKey"
-
- private const val DefaultPasswordEncryptionKey = "AnyData" // TODO: store in a secure place
-
- private val log = LoggerFactory.getLogger(AuthenticationService::class.java)
- }
-
-
- open val isBiometricAuthenticationSupported: Boolean
- get() = biometricAuthenticationService.supportsBiometricAuthentication
-
- open var authenticationType: AuthenticationType = AuthenticationType.None
- protected set
-
- protected open var encryptionCipherForBiometric: Cipher? = null
-
-
- init {
- log.info("Initializing AuthenticationService (at the end database must get opened) ...")
-
- val settings = loadAuthenticationSettings()
-
- if (settings == null) { // first app run -> create a default password
- removeAppProtection()
- }
- else {
- authenticationType = settings.type
-
- if (settings.type == AuthenticationType.None) {
- openDatabase(settings)
- }
- }
- }
-
-
- open fun loginUserWithPassword(enteredPassword: CharArray): Boolean {
- if (isCorrectUserPassword(enteredPassword)) {
- loadAuthenticationSettings()?.let { settings ->
- return openDatabase(settings, enteredPassword)
- }
- }
-
- return false
- }
-
- open fun isCorrectUserPassword(enteredPassword: CharArray): Boolean {
- loadAuthenticationSettings()?.let { settings ->
- val result = BCrypt.verifyer().verify(enteredPassword, settings.hashedUserPassword)
-
- return result.verified
- }
-
- return false
- }
-
- open fun authenticateUserWithBiometricToSetAsNewAuthenticationMethod(authenticationResult: (AuthenticationResult) -> Unit) {
- if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
- authenticationResult(AuthenticationResult(false, "Biometric authentication is only supported on Android 6 and above"))
- return
- }
-
- val cipher = cryptographyManager.getInitializedCipherForEncryption(EncryptionKeyName)
-
- biometricAuthenticationService.authenticate(cipher) { result ->
- if (result.successful) {
- this.encryptionCipherForBiometric = cipher
- }
-
- authenticationResult(result)
- }
- }
-
- open fun loginUserWithBiometric(result: (Boolean) -> Unit) {
- // Biometric authentication is only supported on Android 6 and above
- if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
- result(false)
- return
- }
-
- loadAuthenticationSettings()?.let { settings ->
- val iv = decodeFromBase64(settings.initializationVector ?: "")
-
- val cipher = cryptographyManager.getInitializedCipherForDecryption(EncryptionKeyName, iv)
- biometricAuthenticationService.authenticate(cipher) { authenticationResult ->
- if (authenticationResult.successful) {
- settings.defaultPassword?.let {
- val encryptedUserPassword = decodeFromBase64(it)
- val decrypted = cryptographyManager.decryptData(encryptedUserPassword, cipher)
-
- result(openDatabase(decrypted))
- }
- }
- else {
- result(false)
- }
- }
- }
- ?: run { result(false) }
- }
-
- protected open fun openDatabase(settings: AuthenticationSettings, userPassword: CharArray? = null): Boolean {
- settings.defaultPassword?.let { encryptedPassword ->
- settings.initializationVector?.let { iv ->
- settings.salt?.let { salt ->
- val defaultPassword = cryptographyManager.decryptDataWithPbe(decodeFromBase64(encryptedPassword), DefaultPasswordEncryptionKey,
- decodeFromBase64(iv), decodeFromBase64(salt))
-
- if (userPassword != null) {
- return openDatabase(concatPasswords(userPassword, defaultPassword))
- }
- else {
- return openDatabase(defaultPassword)
- }
- }
- }
- }
-
- return false
- }
-
- protected open fun openDatabase(password: CharArray): Boolean {
- val result = persistence.decryptData(password)
-
- log.info("Did decrypting data / opening database succeed? $result")
-
- return result
- }
-
-
- open fun setAuthenticationMethodToBiometric() {
- saveNewAuthenticationMethod(AuthenticationType.Biometric, null)
- }
-
- open fun setAuthenticationMethodToPassword(newPassword: CharArray) {
- saveNewAuthenticationMethod(AuthenticationType.Password, newPassword)
- }
-
- open fun removeAppProtection() {
- saveNewAuthenticationMethod(AuthenticationType.None, null)
- }
-
-
- protected open fun saveNewAuthenticationMethod(type: AuthenticationType, newUserPassword: CharArray?): Boolean {
- val settings = loadOrCreateDefaultAuthenticationSettings()
- val newDefaultPassword = generateRandomPassword()
- var newDatabasePassword = newDefaultPassword
-
- settings.type = type
- settings.hashedUserPassword = null
- settings.initializationVector = null
- settings.salt = null
-
- if (type == AuthenticationType.Biometric) {
- encryptionCipherForBiometric?.let { encryptionCipher ->
- val encryptedPassword = cryptographyManager.encryptData(newDefaultPassword, encryptionCipher)
- settings.defaultPassword = encodeToBase64(encryptedPassword)
- settings.initializationVector = encodeToBase64(encryptionCipher.iv)
- }
- }
- else {
- val salt = cryptographyManager.generateRandomBytes(8)
- val (encryptedPassword, iv) = cryptographyManager.encryptDataWithPbe(newDefaultPassword, DefaultPasswordEncryptionKey, salt)
- settings.defaultPassword = encodeToBase64(encryptedPassword)
- settings.initializationVector = encodeToBase64(iv)
- settings.salt = encodeToBase64(salt)
-
- if (newUserPassword != null) {
- settings.hashedUserPassword = BCrypt.withDefaults().hashToString(6, newUserPassword)
- newDatabasePassword = concatPasswords(newUserPassword, newDefaultPassword)
- }
- }
-
- if (persistence.changePassword(newDatabasePassword)) {
- if (saveAuthenticationSettings(settings)) {
- this.authenticationType = type
- this.encryptionCipherForBiometric = null
-
- return true
- }
- }
-
- return false
- }
-
- protected open fun concatPasswords(userPassword: CharArray, defaultPassword: CharArray): CharArray {
- val concatenated = StringBuilder(userPassword.size + defaultPassword.size + 1)
-
- concatenated.append(userPassword)
- concatenated.append("_")
- concatenated.append(defaultPassword)
-
- return concatenated.toList().toCharArray()
- }
-
- protected open fun loadOrCreateDefaultAuthenticationSettings(): AuthenticationSettings {
- return loadAuthenticationSettings() ?: AuthenticationSettings(AuthenticationType.None)
- }
-
- protected open fun loadAuthenticationSettings(): AuthenticationSettings? {
- try {
- val file = File(dataFolder, AuthenticationSettingsFilename)
-
- if (file.exists()) {
- val (key, crypto) = getAuthenticationSettingsFileKey()
- val encryptedJson = file.readText()
-
- val json = crypto.decrypt(encryptedJson, key)
-
- return serializer.deserializeObject(json, AuthenticationSettings::class)
- }
- } catch (e: Exception) {
- log.error("Could not load AuthenticationSettings", e)
- }
-
- return null
- }
-
- protected open fun saveAuthenticationSettings(settings: AuthenticationSettings): Boolean {
- try {
- serializer.serializeObjectToString(settings)?.let { json ->
- val (key, crypto) = getAuthenticationSettingsFileKey()
- val encryptedJson = crypto.encrypt(json, key)
-
- val file = File(dataFolder, AuthenticationSettingsFilename)
-
- file.writeText(encryptedJson)
-
- return true
- }
- } catch (e: Exception) {
- log.error("Could not save AuthenticationSettings", e)
- }
-
- return false
- }
-
- protected open fun getAuthenticationSettingsFileKey(): Pair {
- val store = Store(applicationContext)
-
- val key = if (store.hasKey(AuthenticationSettingsFileKey)) store.getSymmetricKey(AuthenticationSettingsFileKey, AuthenticationSettingsFileKeyPassword)
- else store.generateSymmetricKey(AuthenticationSettingsFileKey, AuthenticationSettingsFileKeyPassword)
-
- return Pair(key, Crypto(Options.TRANSFORMATION_SYMMETRIC))
- }
-
-
- open fun generateRandomPassword(): CharArray {
- return generateRandomPassword(30)
- }
-
- open fun generateRandomPassword(passwordLength: Int): CharArray {
- val dictionary = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789§±!@#$%^&*-_=+;:|/?.>,<"
-
- val password = CharArray(passwordLength)
- IntRange(0, passwordLength - 1).forEach { index ->
- password[index] = dictionary.random()
- }
-
- return password
- }
-
-
- open fun encodeToBase64(data: ByteArray): String {
- return Base64.encodeToString(data, Base64.DEFAULT)
- }
-
- open fun decodeFromBase64(data: String): ByteArray {
- return Base64.decode(data, Base64.DEFAULT)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationSettings.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationSettings.kt
deleted file mode 100644
index 1b490ad6..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationSettings.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package net.dankito.banking.ui.android.authentication
-
-
-open class AuthenticationSettings(
- open var type: AuthenticationType,
- open var hashedUserPassword: String? = null,
- open var defaultPassword: String? = null,
- open var initializationVector: String? = null,
- open var salt: String? = null
-) {
-
- internal constructor() : this(AuthenticationType.None) // for object deserializers
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationType.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationType.kt
deleted file mode 100644
index 578613a1..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/AuthenticationType.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package net.dankito.banking.ui.android.authentication
-
-
-enum class AuthenticationType(internal val rawValue: Int) {
-
- None(3),
-
- Password(7),
-
- Biometric(9)
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/BiometricAuthenticationService.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/BiometricAuthenticationService.kt
deleted file mode 100644
index 740f7d28..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/BiometricAuthenticationService.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-package net.dankito.banking.ui.android.authentication
-
-import android.content.Context
-import androidx.biometric.BiometricManager
-import androidx.biometric.BiometricPrompt
-import androidx.core.content.ContextCompat
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.util.CurrentActivityTracker
-import javax.crypto.Cipher
-
-
-open class BiometricAuthenticationService(
- protected open val context: Context,
- protected open val activityTracker: CurrentActivityTracker,
- protected open val biometricManager: BiometricManager = BiometricManager.from(context)
-) : IBiometricAuthenticationService {
-
- override val supportsBiometricAuthentication: Boolean
- get() = biometricManager.canAuthenticate() == BiometricManager.BIOMETRIC_SUCCESS
-
-
- override fun authenticate(cipher: Cipher?, authenticationResult: (AuthenticationResult) -> Unit) {
- activityTracker.currentOrNextActivity { activity ->
- val executor = ContextCompat.getMainExecutor(context)
-
- val biometricPrompt = BiometricPrompt(activity, executor,
- object : BiometricPrompt.AuthenticationCallback() {
-
- override fun onAuthenticationError(errorCode: Int, errorString: CharSequence) {
- super.onAuthenticationError(errorCode, errorString)
- authenticationResult(AuthenticationResult(false, errorString.toString()))
- }
-
- override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
- super.onAuthenticationSucceeded(result)
-
- authenticationResult(AuthenticationResult(true))
- }
-
- override fun onAuthenticationFailed() {
- super.onAuthenticationFailed()
- authenticationResult(AuthenticationResult(false))
- }
- })
-
- val promptInfo = BiometricPrompt.PromptInfo.Builder()
- .setTitle(context.getString(R.string.activity_login_authenticate_with_biometrics_prompt))
- .setNegativeButtonText(context.getString(android.R.string.cancel))
- .build()
-
- if (cipher == null) {
- biometricPrompt.authenticate(promptInfo)
- }
- else {
- biometricPrompt.authenticate(promptInfo, BiometricPrompt.CryptoObject(cipher))
- }
- }
-
- }
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/IBiometricAuthenticationService.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/IBiometricAuthenticationService.kt
deleted file mode 100644
index 1b890988..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/authentication/IBiometricAuthenticationService.kt
+++ /dev/null
@@ -1,13 +0,0 @@
-package net.dankito.banking.ui.android.authentication
-
-import javax.crypto.Cipher
-
-
-interface IBiometricAuthenticationService {
-
- val supportsBiometricAuthentication: Boolean
-
-
- fun authenticate(cipher: Cipher? = null, authenticationResult: (AuthenticationResult) -> Unit)
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingComponent.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingComponent.kt
deleted file mode 100644
index b0c88668..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingComponent.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-package net.dankito.banking.ui.android.di
-
-import dagger.Component
-import net.dankito.banking.ui.android.MainActivity
-import net.dankito.banking.ui.android.activities.BaseActivity
-import net.dankito.banking.ui.android.activities.LandingActivity
-import net.dankito.banking.ui.android.activities.LoginActivity
-import net.dankito.banking.ui.android.dialogs.AddAccountDialog
-import net.dankito.banking.ui.android.dialogs.EnterTanDialog
-import net.dankito.banking.ui.android.dialogs.SendMessageLogDialog
-import net.dankito.banking.ui.android.dialogs.TransferMoneyDialog
-import net.dankito.banking.ui.android.dialogs.settings.ProtectAppSettingsDialog
-import net.dankito.banking.ui.android.dialogs.settings.SettingsDialog
-import net.dankito.banking.ui.android.dialogs.settings.SettingsDialogBase
-import net.dankito.banking.ui.android.home.HomeFragment
-import net.dankito.banking.ui.android.views.BiometricAuthenticationButton
-import javax.inject.Singleton
-
-
-@Singleton
-@Component(modules = arrayOf(BankingModule::class))
-interface BankingComponent {
-
- companion object {
- lateinit var component: BankingComponent
- }
-
-
- fun inject(baseActivity: BaseActivity)
-
- fun inject(landingActivity: LandingActivity)
-
- fun inject(loginActivity: LoginActivity)
-
- fun inject(mainActivity: MainActivity)
-
- fun inject(homeFragment: HomeFragment)
-
- fun inject(addAccountDialog: AddAccountDialog)
-
- fun inject(enterTanDialog: EnterTanDialog)
-
- fun inject(transferMoneyDialog: TransferMoneyDialog)
-
- fun inject(settingsDialogBase: SettingsDialogBase)
-
- fun inject(settingsDialog: SettingsDialog)
-
- fun inject(protectAppSettingsDialog: ProtectAppSettingsDialog)
-
- fun inject(biometricAuthenticationButton: BiometricAuthenticationButton)
-
- fun inject(sendMessageLogDialog: SendMessageLogDialog)
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt
deleted file mode 100644
index 277d91ed..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/di/BankingModule.kt
+++ /dev/null
@@ -1,209 +0,0 @@
-package net.dankito.banking.ui.android.di
-
-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.fints4kBankingClientCreator
-import net.dankito.banking.persistence.IBankingPersistence
-import net.dankito.banking.search.ITransactionPartySearcher
-import net.dankito.banking.ui.IBankingClientCreator
-import net.dankito.banking.ui.IRouter
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.banking.bankfinder.IBankFinder
-import net.dankito.banking.bankfinder.InMemoryBankFinder
-import net.dankito.banking.bankfinder.LuceneBankFinder
-import net.dankito.banking.persistence.RoomBankingPersistence
-import net.dankito.banking.persistence.model.RoomModelCreator
-import net.dankito.banking.ui.android.authentication.AuthenticationService
-import net.dankito.banking.ui.android.authentication.BiometricAuthenticationService
-import net.dankito.banking.ui.android.authentication.IBiometricAuthenticationService
-import net.dankito.banking.ui.model.mapper.IModelCreator
-import net.dankito.banking.ui.util.CurrencyInfoProvider
-import net.dankito.utils.multiplatform.toFile
-import net.dankito.banking.util.*
-import net.dankito.banking.util.extraction.*
-import net.dankito.text.extraction.TextExtractorRegistry
-import net.dankito.text.extraction.pdf.PdfBoxAndroidPdfTextExtractor
-import net.dankito.text.extraction.pdf.iText2PdfTextExtractor
-import net.dankito.utils.ThreadPool
-import net.dankito.utils.android.permissions.IPermissionsService
-import net.dankito.utils.android.permissions.PermissionsService
-import net.dankito.utils.web.client.IWebClient
-import net.dankito.utils.web.client.OkHttpWebClient
-import javax.inject.Named
-import javax.inject.Singleton
-
-
-@Module
-class BankingModule(private val applicationContext: Context) {
-
- companion object {
-
- const val DataFolderKey = "data.folder"
-
- const val DatabaseFolderKey = "database.folder"
-
- const val IndexFolderKey = "index.folder"
-
- // TODO: implement activity listener to always get latest activity
- lateinit var mainActivity: AppCompatActivity
- }
-
-
- @Provides
- @Singleton
- fun provideApplicationContext() : Context {
- return applicationContext
- }
-
- @Provides
- @Singleton
- @Named(DataFolderKey)
- fun provideDataFolder(applicationContext: Context) : File {
- return ensureFolderExists(applicationContext.filesDir.toFile(), "data")
- }
-
- @Provides
- @Singleton
- @Named(DatabaseFolderKey)
- fun provideDatabaseFolder(@Named(DataFolderKey) dataFolder: File) : File {
- return ensureFolderExists(dataFolder, "db")
- }
-
- @Provides
- @Singleton
- @Named(IndexFolderKey)
- fun provideIndexFolder(@Named(DataFolderKey) dataFolder: File) : File {
- return ensureFolderExists(dataFolder, "index")
- }
-
- private fun ensureFolderExists(parentFolder: File, folderName: String): File {
- val folder = File(parentFolder, folderName)
-
- folder.mkdirs()
-
- return folder
- }
-
-
- @Provides
- @Singleton
- fun providePermissionsService() : IPermissionsService {
- return PermissionsService(mainActivity)
- }
-
-
- @Provides
- @Singleton
- fun provideAuthenticationService(biometricAuthenticationService: IBiometricAuthenticationService, persistence: IBankingPersistence,
- @Named(DataFolderKey) dataFolder: File, serializer: ISerializer) : AuthenticationService {
- return AuthenticationService(applicationContext, biometricAuthenticationService, persistence, dataFolder, serializer)
- }
-
- @Provides
- @Singleton
- fun provideBiometricAuthenticationService(context: Context, currentActivityTracker: CurrentActivityTracker) : IBiometricAuthenticationService {
- return BiometricAuthenticationService(context, currentActivityTracker)
- }
-
-
- @Provides
- @Singleton
- fun provideBankingPresenter(bankingClientCreator: IBankingClientCreator, bankFinder: IBankFinder,
- @Named(DataFolderKey) dataFolder: File,
- persister: IBankingPersistence, transactionPartySearcher: ITransactionPartySearcher, bankIconFinder: IBankIconFinder,
- textExtractorRegistry: ITextExtractorRegistry, router: IRouter, invoiceDataExtractor: IInvoiceDataExtractor,
- modelCreator: IModelCreator, asyncRunner: IAsyncRunner) : BankingPresenter {
- return BankingPresenter(bankingClientCreator, bankFinder, dataFolder, persister, router, modelCreator,
- transactionPartySearcher, bankIconFinder, textExtractorRegistry, invoiceDataExtractor, CurrencyInfoProvider(), asyncRunner)
- }
-
- @Provides
- @Singleton
- fun provideBankFinder(@Named(IndexFolderKey) indexFolder: File) : IBankFinder {
- //return LuceneBankFinder(indexFolder) // TODO: undo
- return InMemoryBankFinder()
- }
-
- @Provides
- @Singleton
- fun provideBankIconFinder() : IBankIconFinder {
- return BankIconFinder()
- }
-
- @Provides
- @Singleton
- fun provideBankingClientCreator(modelCreator: IModelCreator, serializer: ISerializer) : IBankingClientCreator {
- return fints4kBankingClientCreator(modelCreator, serializer)
- }
-
- @Provides
- @Singleton
- fun provideBankingPersistence() : IBankingPersistence {
- return RoomBankingPersistence(applicationContext)
- }
-
- @Provides
- @Singleton
- fun provideTransactionPartySearcher(bankingPersistence: IBankingPersistence) : ITransactionPartySearcher {
- return bankingPersistence as RoomBankingPersistence
- }
-
- @Provides
- @Singleton
- fun provideCurrentActivityTracker() : CurrentActivityTracker {
- return CurrentActivityTracker()
- }
-
- @Provides
- @Singleton
- fun provideRouter(currentActivityTracker: CurrentActivityTracker) : IRouter {
- return RouterAndroid(currentActivityTracker)
- }
-
-
- @Provides
- @Singleton
- fun provideTextExtractorRegistry(applicationContext: Context) : ITextExtractorRegistry {
- // TODO: add PdfTypeDetector
- return JavaTextExtractorRegistry(TextExtractorRegistry(listOf(
- iText2PdfTextExtractor(), PdfBoxAndroidPdfTextExtractor(applicationContext)
- )))
- }
-
- @Provides
- @Singleton
- fun provideInvoiceDataExtractor() : IInvoiceDataExtractor {
- return JavaInvoiceDataExtractor()
- }
-
-
- @Provides
- @Singleton
- fun provideWebClient() : IWebClient {
- return OkHttpWebClient()
- }
-
- @Provides
- @Singleton
- fun provideSerializer() : ISerializer {
- return JacksonJsonSerializer()
- }
-
- @Provides
- @Singleton
- fun provideModelCreator() : IModelCreator {
- return RoomModelCreator()
- }
-
- @Provides
- @Singleton
- fun provideAsyncRunner() : IAsyncRunner {
- return ThreadPoolAsyncRunner(ThreadPool())
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/AccountTransactionDetailsDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/AccountTransactionDetailsDialog.kt
deleted file mode 100644
index 4edff1b1..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/AccountTransactionDetailsDialog.kt
+++ /dev/null
@@ -1,80 +0,0 @@
-package net.dankito.banking.ui.android.dialogs
-
-import android.os.Bundle
-import android.view.*
-import androidx.fragment.app.FragmentActivity
-import kotlinx.android.synthetic.main.dialog_account_transaction_details.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.dialogs.settings.SettingsDialogBase
-import net.dankito.banking.ui.android.views.FormLabelledValue
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.utils.multiplatform.BigDecimal
-
-
-open class AccountTransactionDetailsDialog : SettingsDialogBase() {
-
- companion object {
- const val DialogTag = "AccountTransactionDetailsDialog"
- }
-
-
- protected lateinit var transaction: IAccountTransaction
-
-
-
- fun show(transaction: IAccountTransaction, activity: FragmentActivity) {
- this.transaction = transaction
-
- show(activity, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_account_transaction_details, container, false)
-
- setupUI(rootView)
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- rootView.apply {
- toolbar.apply {
- setupToolbar(this, context.getString(R.string.dialog_account_transaction_details_title), false)
- }
-
- sender_or_recipient_section_title.setTitle(if (transaction.amount.isPositive) R.string.dialog_account_transaction_details_sender else R.string.dialog_account_transaction_details_recipient)
- lvlOtherPartyName.value = transaction.otherPartyName ?: ""
- lvlOtherPartyAccountId.value = transaction.otherPartyAccountId ?: ""
- lvlOtherPartyBankCode.value = transaction.otherPartyBankCode ?: ""
-
- lvlAmount.showAmount(presenter, transaction.amount, transaction.currency)
- lvlReference.value = transaction.reference
-
- lvlBookingText.value = transaction.bookingText ?: ""
- lvlBookingDate.value = presenter.formatToMediumDate(transaction.bookingDate)
- lvlValueDate.value = presenter.formatToMediumDate(transaction.valueDate)
-
- showAmountIfSet(lvlOpeningBalance, transaction.openingBalance, transaction.account.currency)
- showAmountIfSet(lvlClosingBalance, transaction.closingBalance, transaction.account.currency)
- }
- }
-
- protected open fun showAmountIfSet(labelledValue: FormLabelledValue, amount: BigDecimal?, currencyCode: String) {
- if (amount != null) {
- labelledValue.showAmount(presenter, amount, currencyCode)
- }
- else {
- labelledValue.visibility = View.GONE
- }
- }
-
-
- override val hasUnsavedChanges: Boolean
- get() = false
-
- override fun saveChanges() {
-
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/AddAccountDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/AddAccountDialog.kt
deleted file mode 100644
index 39792b0d..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/AddAccountDialog.kt
+++ /dev/null
@@ -1,222 +0,0 @@
-package net.dankito.banking.ui.android.dialogs
-
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
-import android.os.Bundle
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.EditText
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.DialogFragment
-import com.otaliastudios.autocomplete.Autocomplete
-import kotlinx.android.synthetic.main.dialog_add_account.*
-import kotlinx.android.synthetic.main.dialog_add_account.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.adapter.presenter.BankInfoPresenter
-import net.dankito.banking.ui.android.extensions.addEnterPressedListener
-import net.dankito.banking.ui.android.extensions.closePopupOnBackButtonPress
-import net.dankito.banking.ui.android.util.StandardAutocompleteCallback
-import net.dankito.banking.ui.model.responses.AddAccountResponse
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.banking.bankfinder.BankInfo
-import net.dankito.banking.ui.android.util.StandardTextWatcher
-import net.dankito.utils.android.extensions.asActivity
-import net.dankito.utils.android.extensions.hide
-import net.dankito.utils.android.extensions.show
-import net.dankito.utils.android.extensions.showKeyboardDelayed
-import javax.inject.Inject
-
-
-open class AddAccountDialog : DialogFragment() {
-
- companion object {
- const val DialogTag = "AddAccountDialog"
- }
-
-
- protected var selectedBank: BankInfo? = null
-
- protected var justDidSelectBank: Boolean = false
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- fun show(activity: AppCompatActivity, fullscreen: Boolean = true) {
- val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
- setStyle(STYLE_NORMAL, style)
-
- show(activity.supportFragmentManager, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_add_account, container, false)
-
- rootView?.let {
- setupUI(rootView)
- }
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- rootView.apply {
- initBankListAutocompletion(edtxtBank.actualEditText)
-
- edtxtUserName.actualEditText.addTextChangedListener(otherEditTextChangedWatcher)
- bankCredentialsPassword.passwordBox.addTextChangedListener(otherEditTextChangedWatcher)
-
- addAccountIfEnterPressed(edtxtBank.actualEditText)
- addAccountIfEnterPressed(edtxtUserName.actualEditText)
- addAccountIfEnterPressed(bankCredentialsPassword.passwordBox)
-
- btnAddAccount.setOnClickListener { addAccount() }
- btnCancel.setOnClickListener { dismiss() }
-
- edtxtBank.actualEditText.showKeyboardDelayed(250)
- }
- }
-
- private fun initBankListAutocompletion(edtxtBank: EditText) {
- edtxtBank.addTextChangedListener(StandardTextWatcher {
- mayClearSelectedBank()
- })
-
- val autocompleteCallback = StandardAutocompleteCallback { _, item ->
- bankSelected(item)
- true
- }
-
- Autocomplete.on(edtxtBank)
- .with(6f)
- .with(ColorDrawable(Color.WHITE))
- .with(autocompleteCallback)
- .with(BankInfoPresenter(presenter, edtxtBank.context))
- .build()
- .closePopupOnBackButtonPress(dialog)
- }
-
- private fun addAccountIfEnterPressed(editText: EditText) {
- editText.addEnterPressedListener {
- if (btnAddAccount.isEnabled) { // required data has been entered
- addAccount()
-
- return@addEnterPressedListener true
- }
-
- false
- }
- }
-
-
- protected open fun addAccount() {
- selectedBank?.let { selectedBank -> // should always be non-null at this stage
- val userName = edtxtUserName.text
- val password = bankCredentialsPassword.password
-
- btnAddAccount.isEnabled = false
- pgrbrAddAccount.show()
-
- presenter.addAccountAsync(selectedBank, userName, password) { response ->
- context?.asActivity()?.runOnUiThread {
- btnAddAccount.isEnabled = true
- pgrbrAddAccount.hide()
-
- handleAccountCheckResponseOnUiThread(response)
- }
- }
- }
- }
-
- protected open fun handleAccountCheckResponseOnUiThread(response: AddAccountResponse) {
- context?.let { context ->
- if (response.successful) {
- this.dismiss()
- }
- else {
- AlertDialog.Builder(context)
- .setMessage(context.getString(R.string.dialog_add_account_message_could_not_add_account, response.errorToShowToUser))
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
- }
- }
-
-
- protected val otherEditTextChangedWatcher = object : TextWatcher {
-
- override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { }
-
- override fun onTextChanged(enteredText: CharSequence?, start: Int, before: Int, count: Int) {
- checkIfRequiredDataEnteredOnUiThread()
- }
-
- override fun afterTextChanged(s: Editable?) { }
-
- }
-
- protected open fun bankSelected(bank: BankInfo) {
- val didSelectSupportedBank = bank.supportsFinTs3_0
-
- selectedBank = if (didSelectSupportedBank) bank else null
-
- justDidSelectBank = true
-
- if (didSelectSupportedBank) {
- edtxtBank.text = bank.bankCode + " " + bank.name
- }
-
- justDidSelectBank = false
-
- checkIfRequiredDataEnteredOnUiThread()
-
- if (didSelectSupportedBank) {
- edtxtUserName.requestFocus()
- }
- else {
- showBankDoesNotSupportFinTs30ErrorMessage(bank)
- edtxtBank.actualEditText.selectAll()
- }
- }
-
- protected open fun mayClearSelectedBank() {
- if (justDidSelectBank == false) {
- selectedBank = null
- }
-
- checkIfRequiredDataEnteredOnUiThread()
- }
-
- private fun showBankDoesNotSupportFinTs30ErrorMessage(bank: BankInfo) {
- activity?.let { context ->
- val errorMessage = context.getString(R.string.dialog_add_account_bank_does_not_support_fints_3_error_message, bank.name)
-
- AlertDialog.Builder(context)
- .setMessage(errorMessage)
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
- }
-
- protected open fun checkIfRequiredDataEnteredOnUiThread() {
- val requiredDataEntered = selectedBank != null
- && selectedBank?.supportsFinTs3_0 == true
- && edtxtUserName.text.isNotEmpty()
- && bankCredentialsPassword.password.isNotEmpty()
-
- btnAddAccount.isEnabled = requiredDataEntered
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/EnterAtcDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/EnterAtcDialog.kt
deleted file mode 100644
index ba1ea367..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/EnterAtcDialog.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-package net.dankito.banking.ui.android.dialogs
-
-import android.os.Bundle
-import android.text.Html
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.DialogFragment
-import kotlinx.android.synthetic.main.dialog_enter_atc.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.model.tan.EnterTanGeneratorAtcResult
-import net.dankito.banking.ui.model.tan.TanMedium
-import net.dankito.utils.android.extensions.getSpannedFromHtml
-
-
-open class EnterAtcDialog : DialogFragment() {
-
- companion object {
- const val DialogTag = "EnterAtcDialog"
- }
-
-
- protected lateinit var tanMedium: TanMedium
-
- protected lateinit var atcEnteredCallback: (EnterTanGeneratorAtcResult) -> Unit
-
-
- open fun show(tanMedium: TanMedium, activity: AppCompatActivity,
- fullscreen: Boolean = false, atcEnteredCallback: (EnterTanGeneratorAtcResult) -> Unit) {
-
- this.tanMedium = tanMedium
- this.atcEnteredCallback = atcEnteredCallback
-
- val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
- setStyle(STYLE_NORMAL, style)
-
- show(activity.supportFragmentManager, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_enter_atc, container, false)
-
- setupUI(rootView)
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- val explanationHtml = rootView.context.getString(R.string.dialog_enter_atc_explanation, tanMedium.displayName)
- rootView.txtAtcExplanationToShowToUser.text = explanationHtml.getSpannedFromHtml()
-
- rootView.btnCancel.setOnClickListener { enteringAtcDone(null, null) }
-
- rootView.btnEnteringAtcDone.setOnClickListener { enteringAtcDone(rootView.edtxtEnteredTan.text.toString(), rootView.edtxtEnteredAtc.text.toString()) }
- }
-
-
- protected open fun enteringAtcDone(enteredTan: String?, enteredAtcString: String?) {
- var enteredAtc: Int? = null
-
- if (enteredAtcString != null) {
- try {
- enteredAtc = enteredAtcString.toInt()
- } catch (e: Exception) {
- showEnteredAtcIsNotANumberError(enteredAtcString)
-
- return
- }
- }
-
- val result = if (enteredTan == null || enteredAtc == null) EnterTanGeneratorAtcResult.userDidNotEnterAtc()
- else EnterTanGeneratorAtcResult.userEnteredAtc(enteredTan, enteredAtc)
-
- atcEnteredCallback(result)
-
- dismiss()
- }
-
- protected open fun showEnteredAtcIsNotANumberError(enteredAtcString: String) {
- activity?.let { context ->
- AlertDialog.Builder(context)
- .setMessage(context.getString(R.string.dialog_enter_atc_error_entered_atc_is_not_a_number, enteredAtcString))
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/EnterTanDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/EnterTanDialog.kt
deleted file mode 100644
index 9685bc36..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/EnterTanDialog.kt
+++ /dev/null
@@ -1,272 +0,0 @@
-package net.dankito.banking.ui.android.dialogs
-
-import android.content.Context
-import android.os.Bundle
-import android.os.Handler
-import android.text.InputFilter
-import android.text.InputType
-import android.view.KeyEvent
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Spinner
-import androidx.appcompat.app.AlertDialog
-import androidx.fragment.app.DialogFragment
-import androidx.fragment.app.FragmentActivity
-import kotlinx.android.synthetic.main.dialog_enter_tan.*
-import kotlinx.android.synthetic.main.dialog_enter_tan.view.*
-import kotlinx.android.synthetic.main.view_collapsible_text.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.TanMediumAdapter
-import net.dankito.banking.ui.android.adapter.TanMethodsAdapter
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.listener.ListItemSelectedListener
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.responses.BankingClientResponse
-import net.dankito.banking.ui.model.tan.*
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.utils.android.extensions.getSpannedFromHtml
-import net.dankito.utils.android.extensions.show
-import javax.inject.Inject
-
-
-open class EnterTanDialog : DialogFragment() {
-
- companion object {
- const val DialogTag = "EnterTanDialog"
- }
-
-
- protected lateinit var bank: TypedBankData
-
- protected lateinit var tanChallenge: TanChallenge
-
- protected lateinit var tanEnteredCallback: (EnterTanResult) -> Unit
-
- protected val tanMediumAdapter = TanMediumAdapter()
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- open fun show(bank: TypedBankData, tanChallenge: TanChallenge, activity: FragmentActivity,
- fullscreen: Boolean = false, tanEnteredCallback: (EnterTanResult) -> Unit) {
-
- this.bank = bank
- this.tanChallenge = tanChallenge
- this.tanEnteredCallback = tanEnteredCallback
-
- val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
- setStyle(STYLE_NORMAL, style)
-
- show(activity.supportFragmentManager, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_enter_tan, container, false)
-
- setupUI(rootView)
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- setupSelectTanMethodView(rootView)
-
- setupTanView(rootView)
-
- setupEnteringTan(rootView)
-
- rootView.txtvwCollapsibleText.text = tanChallenge.messageToShowToUser.getSpannedFromHtml()
-
- rootView.btnCancel.setOnClickListener { enteringTanDone(null) }
-
- rootView.btnEnteringTanDone.setOnClickListener { enteringTanDone(rootView.edtxtEnteredTan.text.toString()) }
- }
-
- protected open fun setupSelectTanMethodView(rootView: View) {
- val adapter = TanMethodsAdapter()
- val tanMethodsWithoutUnsupported = bank.supportedTanMethods.filterNot { it.type == TanMethodType.ChipTanUsb } // USB tan generators are not supported on Android
- adapter.setItems(tanMethodsWithoutUnsupported)
-
- rootView.findViewById(R.id.spnTanMethods)?.let { spinner ->
- spinner.adapter = adapter
-
- val selectedTanMethod = bank.selectedTanMethod
- ?: tanMethodsWithoutUnsupported.firstOrNull { it.type != TanMethodType.ChipTanManuell && it.type != TanMethodType.ChipTanUsb }
- ?: tanMethodsWithoutUnsupported.firstOrNull()
- selectedTanMethod?.let { spinner.setSelection(adapter.getItems().indexOf(selectedTanMethod)) }
-
- spinner.onItemSelectedListener = ListItemSelectedListener(adapter) { newSelectedTanMethod ->
- if (newSelectedTanMethod != selectedTanMethod) {
- tanEnteredCallback(EnterTanResult.userAsksToChangeTanMethod(newSelectedTanMethod))
- // TODO: find a way to update account.selectedTanMethod afterwards
-
- dismiss()
- }
- }
- }
- }
-
- protected open fun setupSelectTanMediumView(rootView: View) {
- val tanMediaForTanMethod = presenter.getTanMediaForTanMethod(bank, tanChallenge.tanMethod)
-
- if (tanMediaForTanMethod.size > 1) {
- rootView.lytTanMedium.show()
-
- tanMediumAdapter.setItems(bank.tanMediaSorted)
-
- rootView.spnTanMedium.adapter = tanMediumAdapter
- rootView.spnTanMedium.onItemSelectedListener = ListItemSelectedListener(tanMediumAdapter) { selectedTanMedium ->
- // TODO: implement logic to change a mobile phone as TAN medium
- if (selectedTanMedium.status != TanMediumStatus.Used) {
- (selectedTanMedium as? TanGeneratorTanMedium)?.let { tanGeneratorTanMedium ->
- tanEnteredCallback(EnterTanResult.userAsksToChangeTanMedium(tanGeneratorTanMedium) { response ->
- handleChangeTanMediumResponse(selectedTanMedium, response)
- })
- // TODO: find a way to update account.tanMedia afterwards
- }
-
- // TODO: ensure that only TanGeneratorTanMedium instances get added to spinner?
- }
- }
- }
- }
-
- protected open fun setupTanView(rootView: View) {
- if (presenter.isOpticalTanMethod(tanChallenge.tanMethod)) {
- setupSelectTanMediumView(rootView)
-
- if (tanChallenge is FlickerCodeTanChallenge) {
- setupFlickerCodeTanView(rootView)
- }
- else if (tanChallenge is ImageTanChallenge) {
- setupImageTanView(rootView)
- }
- }
- }
-
- protected open fun setupEnteringTan(rootView: View) {
- if (tanChallenge.tanMethod.isNumericTan) {
- rootView.edtxtEnteredTan.inputType = InputType.TYPE_CLASS_NUMBER
- }
-
- tanChallenge.tanMethod.maxTanInputLength?.let { maxInputLength ->
- rootView.edtxtEnteredTan.filters = arrayOf(InputFilter.LengthFilter(maxInputLength))
- }
-
- rootView.edtxtEnteredTan.setOnKeyListener { _, keyCode, _ ->
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- enteringTanDone(rootView.edtxtEnteredTan.text.toString())
- return@setOnKeyListener true
- }
- false
- }
- }
-
- protected open fun setupFlickerCodeTanView(rootView: View) {
- val flickerCodeView = rootView.flickerCodeView
- flickerCodeView.show()
-
- val flickerCode = (tanChallenge as FlickerCodeTanChallenge).flickerCode
- if (flickerCode.decodingSuccessful) {
- flickerCodeView.setCode(flickerCode, presenter.appSettings.flickerCodeSettings)
- }
- else {
- showDecodingTanChallengeFailedErrorDelayed(flickerCode.decodingError)
- }
- }
-
- protected open fun setupImageTanView(rootView: View) {
- rootView.tanImageView.show()
-
- val decodedImage = (tanChallenge as ImageTanChallenge).image
- if (decodedImage.decodingSuccessful) {
- rootView.tanImageView.setImage(tanChallenge as ImageTanChallenge, if (isQrTan(tanChallenge)) presenter.appSettings.qrCodeSettings else presenter.appSettings.photoTanSettings)
- }
- else {
- showDecodingTanChallengeFailedErrorDelayed(decodedImage.decodingError)
- }
- }
-
-
- /**
- * This method gets called right on start up before dialog is shown -> Alert would get displayed before dialog and
- * therefore covered by dialog -> delay displaying alert.
- */
- protected open fun showDecodingTanChallengeFailedErrorDelayed(error: Exception?) {
- val handler = Handler()
-
- handler.postDelayed({ showDecodingTanChallengeFailedError(error) }, 500)
- }
-
- protected open fun showDecodingTanChallengeFailedError(error: Exception?) {
- activity?.let { context ->
- AlertDialog.Builder(context)
- .setMessage(context.getString(R.string.dialog_enter_tan_error_could_not_decode_tan_image, error?.localizedMessage))
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
- }
-
-
- protected open fun handleChangeTanMediumResponse(newUsedTanMedium: TanMedium, response: BankingClientResponse) {
- activity?.let { activity ->
- activity.runOnUiThread {
- handleChangeTanMediumResponseOnUiThread(activity, newUsedTanMedium, response)
- }
- }
- }
-
- protected open fun handleChangeTanMediumResponseOnUiThread(context: Context, newUsedTanMedium: TanMedium, response: BankingClientResponse) {
- if (response.successful) {
- AlertDialog.Builder(context)
- .setMessage(context.getString(R.string.dialog_enter_tan_tan_medium_successfully_changed, newUsedTanMedium.displayName))
- .setPositiveButton(android.R.string.ok) { dialog, _ ->
- dialog.dismiss()
- dismiss()
- }
- .show()
- }
- else if (response.userCancelledAction == false) {
- AlertDialog.Builder(context)
- .setMessage(context.getString(R.string.dialog_enter_tan_error_changing_tan_medium, newUsedTanMedium.displayName, response.errorToShowToUser))
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
- }
-
-
- protected open fun enteringTanDone(enteredTan: String?) {
- val result = if (enteredTan != null) EnterTanResult.userEnteredTan(enteredTan) else EnterTanResult.userDidNotEnterTan()
-
- tanEnteredCallback(result)
-
- checkIfAppSettingsChanged()
-
- dismiss()
- }
-
-
- protected open fun checkIfAppSettingsChanged() {
- if (flickerCodeView.didTanMethodSettingsChange) {
- presenter.updateTanMethodSettings(tanChallenge.tanMethod, flickerCodeView.tanMethodSettings)
- }
-
- if (tanImageView.didTanMethodSettingsChange) {
- presenter.updateTanMethodSettings(tanChallenge.tanMethod, tanImageView.tanMethodSettings)
- }
- }
-
- protected open fun isQrTan(tanChallenge: TanChallenge): Boolean {
- return presenter.isQrTanMethod(tanChallenge.tanMethod)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/SendMessageLogDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/SendMessageLogDialog.kt
deleted file mode 100644
index fad45448..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/SendMessageLogDialog.kt
+++ /dev/null
@@ -1,165 +0,0 @@
-package net.dankito.banking.ui.android.dialogs
-
-import android.content.ActivityNotFoundException
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.Toast
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.DialogFragment
-import kotlinx.android.synthetic.main.dialog_send_message_log.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.utils.android.extensions.hide
-import net.dankito.utils.android.extensions.show
-import net.dankito.utils.multiplatform.getInnerExceptionMessage
-import net.dankito.utils.multiplatform.os.DeviceInfo
-import net.dankito.banking.ui.model.issues.CreateTicketRequestDto
-import net.dankito.banking.ui.model.issues.IssueDescriptionFormat
-import net.dankito.utils.android.extensions.asActivity
-import net.dankito.utils.serialization.JacksonJsonSerializer
-import net.dankito.utils.web.client.OkHttpWebClient
-import net.dankito.utils.web.client.RequestParameters
-import net.dankito.utils.web.client.WebClientResponse
-import javax.inject.Inject
-
-
-open class SendMessageLogDialog : DialogFragment() {
-
- companion object {
- const val DialogTag = "SendMessageLogDialog"
- }
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- fun show(activity: AppCompatActivity, fullscreen: Boolean = true) {
- val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
- setStyle(STYLE_NORMAL, style)
-
- show(activity.supportFragmentManager, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_send_message_log, container, false)
-
- rootView?.let {
- setupUI(rootView)
- }
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- val messageLog = presenter.getFormattedMessageLogForAccounts(presenter.allBanksSortedByDisplayIndex)
-
- if (messageLog.isBlank()) {
- rootView.txtvwInfoNoMessageLogEntriesYet.show()
- rootView.lytMessageLog.hide()
-
- rootView.btnSendMessageLogDirectly.isEnabled = false
- rootView.btnSendMessageLogViaEMail.isEnabled = false
- }
- else {
- rootView.edtxtMessageLog.setText(context?.getString(R.string.dialog_send_message_courteously_add_error_description, getDeviceInfoLine() + "\n\n" + messageLog))
- }
-
- rootView.btnSendMessageLogDirectly.setOnClickListener { sendMessageLogDirectly(rootView.edtxtMessageLog.text.toString()) }
- rootView.btnSendMessageLogViaEMail.setOnClickListener { sendMessageLogViaEMail(rootView.edtxtMessageLog.text.toString()) }
-
- rootView.btnCancel.setOnClickListener { dismiss() }
- }
-
- protected open fun sendMessageLogViaEMail(messageLog: String) {
- // TODO: check if message log exceeds 120.000 characters
-
- val sendMailActivity = Intent(Intent.ACTION_SEND)
- sendMailActivity.type = "message/rfc822"
- sendMailActivity.putExtra(Intent.EXTRA_EMAIL, arrayOf("issues@bankmeister.de"))
- sendMailActivity.putExtra(Intent.EXTRA_SUBJECT, context?.getString(R.string.dialog_send_message_log_mail_subject))
- sendMailActivity.putExtra(Intent.EXTRA_TEXT, messageLog)
-
- try {
- startActivity(Intent.createChooser(sendMailActivity, context?.getString(R.string.dialog_send_message_log_action_send_chooser_title)))
-
- showSuccessfullySentMessageLog()
- } catch (e: ActivityNotFoundException) {
- Toast.makeText(context, context?.getString(R.string.dialog_send_message_log_error_no_app_to_send_message_found), Toast.LENGTH_LONG).show()
- }
- }
-
- protected open fun sendMessageLogDirectly(messageLog: String) {
- val deviceInfo = getDeviceInfo()
-
- // TODO: sending with Ktor did not work
- //presenter.sendMessageLogDirectly(messageLog, deviceInfo)
-
- val requestBodyDto = CreateTicketRequestDto(messageLog, "Bankmeister", IssueDescriptionFormat.PlainText,
- deviceInfo.osName, deviceInfo.osVersion, deviceInfo.manufacturer, deviceInfo.deviceModel)
- val requestBody = JacksonJsonSerializer().serializeObject(requestBodyDto)
-
- OkHttpWebClient().postAsync(RequestParameters("https://codinux.uber.space/issues", requestBody, "application/json")) { response ->
- context?.asActivity()?.runOnUiThread {
- handleSendMessageLogDirectlyResponseOnUiThread(response)
- }
- }
- }
-
- protected open fun getDeviceInfoLine(): String {
- val deviceInfo = getDeviceInfo()
-
- var line = deviceInfo.manufacturer ?: ""
-
- deviceInfo.deviceModel?.let { model ->
- line += (if (line.isEmpty()) "" else " ") + model
- }
-
- deviceInfo.osName?.let { osName ->
- line += (if (line.isEmpty()) "" else " - ") + osName
- }
-
- deviceInfo.osVersion?.let { osVersion ->
- line += (if (line.isEmpty()) "" else " ") + osVersion
- }
-
- deviceInfo.osArch?.let { osArch ->
- line += (if (line.isEmpty()) "" else " ") + osArch
- }
-
- return line
-
- }
-
- protected open fun getDeviceInfo(): DeviceInfo {
- return DeviceInfo(Build.MANUFACTURER.capitalize(), Build.MODEL, "Android", Build.VERSION.RELEASE, System.getProperty("os.arch") ?: "")
- }
-
- protected open fun handleSendMessageLogDirectlyResponseOnUiThread(response: WebClientResponse) {
- if (response.isSuccessResponse) {
- showSuccessfullySentMessageLog()
- }
- else {
- Toast.makeText(context, context?.getString(R.string.dialog_send_message_log_error_could_not_sent_message_log, response.error?.getInnerExceptionMessage()),
- Toast.LENGTH_LONG).show()
- }
- }
-
- protected open fun showSuccessfullySentMessageLog() {
- Toast.makeText(context, context?.getString(R.string.dialog_send_message_log_thanks_for_helping_making_app_better), Toast.LENGTH_LONG).show()
-
- dismiss()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt
deleted file mode 100644
index cf979ad3..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/TransferMoneyDialog.kt
+++ /dev/null
@@ -1,485 +0,0 @@
-package net.dankito.banking.ui.android.dialogs
-
-import android.graphics.Color
-import android.graphics.drawable.ColorDrawable
-import android.os.Bundle
-import android.text.TextWatcher
-import android.text.method.DigitsKeyListener
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.*
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.DialogFragment
-import com.google.android.material.textfield.TextInputLayout
-import com.otaliastudios.autocomplete.Autocomplete
-import kotlinx.android.synthetic.main.dialog_transfer_money.*
-import kotlinx.android.synthetic.main.dialog_transfer_money.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.adapter.IconedBankAccountsAdapter
-import net.dankito.banking.ui.android.adapter.presenter.RecipientPresenter
-import net.dankito.banking.ui.android.extensions.addEnterPressedListener
-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.TransactionParty
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.parameters.TransferMoneyData
-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.banking.ui.android.extensions.isEllipsized
-import net.dankito.banking.ui.android.views.InfoPopupWindow
-import net.dankito.banking.util.ValidationResult
-import net.dankito.utils.android.extensions.*
-import net.dankito.utils.multiplatform.toBigDecimal
-import java.math.BigDecimal
-import java.text.DecimalFormatSymbols
-import java.util.*
-import javax.inject.Inject
-import kotlin.concurrent.schedule
-
-
-open class TransferMoneyDialog : DialogFragment() {
-
- companion object {
- const val DialogTag = "TransferMoneyDialog"
- }
-
-
- protected lateinit var account: TypedBankAccount
-
- protected var preselectedValues: TransferMoneyData? = null
-
- protected val inputValidator = InputValidator() // TODO: move to presenter
-
-
- protected var recipientBic: String? = null
-
-
- protected var validRecipientNameEntered = false
-
- protected var validRecipientIbanEntered = false
-
- protected var validRecipientBicEntered = false
-
- protected var validReferenceEntered = true
-
- protected var validAmountEntered = false
-
- protected var didJustCorrectInput = mutableMapOf()
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
- open fun show(activity: AppCompatActivity, fullscreen: Boolean = true) {
- show(activity, null, fullscreen)
- }
-
- open fun show(activity: AppCompatActivity, preselectedValues: TransferMoneyData?, fullscreen: Boolean = true) {
- this.preselectedValues = preselectedValues
-
- val style = if(fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
- setStyle(STYLE_NORMAL, style)
-
- show(activity.supportFragmentManager, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return inflater.inflate(R.layout.dialog_transfer_money, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- setupUI(view)
- }
-
- protected open fun setupUI(rootView: View) {
- val accountsSupportingTransferringMoney = presenter.accountsSupportingTransferringMoneySortedByDisplayIndex
- account = preselectedValues?.account ?: accountsSupportingTransferringMoney.first()
-
- if (accountsSupportingTransferringMoney.size > 1) {
- rootView.lytSelectBankAccount.show()
-
- val adapter = IconedBankAccountsAdapter(accountsSupportingTransferringMoney)
- rootView.spnBankAccounts.adapter = adapter
- rootView.spnBankAccounts.onItemSelectedListener = ListItemSelectedListener(adapter) { selectedBankAccount ->
- this.account = selectedBankAccount
- setRealTimeTransferControlsVisibility(rootView)
- }
- preselectedValues?.account?.let { rootView.spnBankAccounts.setSelection(adapter.getItems().indexOf(it)) }
- }
-
- initRecipientAutocompletion(rootView.edtxtRecipientName)
-
- rootView.edtxtRecipientName.addTextChangedListener(checkRequiredDataWatcher {
- checkIfEnteredRecipientNameIsValidWhileUserIsTyping()
- })
-
- rootView.edtxtRecipientIban.addTextChangedListener(StandardTextWatcher {
- checkIfEnteredRecipientIbanIsValidWhileUserIsTyping()
- tryToGetBicFromIban(it)
- })
-
- rootView.edtxtAmount.addTextChangedListener(checkRequiredDataWatcher {
- checkIfEnteredAmountIsValid()
- })
- rootView.edtxtReference.addTextChangedListener(checkRequiredDataWatcher {
- checkIfEnteredReferenceTextIsValid()
- })
-
- rootView.edtxtRecipientName.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredRecipientNameIsValidAfterFocusLost() }
- rootView.edtxtRecipientIban.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredRecipientIbanIsValidAfterFocusLost() }
- rootView.edtxtAmount.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredAmountIsValid() }
- rootView.edtxtReference.setOnFocusChangeListener { _, hasFocus -> if (hasFocus == false) checkIfEnteredReferenceTextIsValid() }
-
- transferMoneyIfEnterPressed(rootView.edtxtRecipientName)
- transferMoneyIfEnterPressed(rootView.edtxtRecipientIban)
- transferMoneyIfEnterPressed(rootView.edtxtAmount)
- transferMoneyIfEnterPressed(rootView.edtxtReference)
-
- rootView.btnShowRealTimeTransferInfo.setOnClickListener { showRealTimeTransferInfo(rootView.btnShowRealTimeTransferInfo) }
-
- setRealTimeTransferControlsVisibility(rootView)
-
- rootView.btnCancel.setOnClickListener { dismiss() }
-
- rootView.btnTransferMoney.setOnClickListener { transferMoney() }
-
- adjustCheckBoxRealTimeTransferWidth()
- }
-
-
- protected open fun adjustCheckBoxRealTimeTransferWidth() {
- // wait some time till CheckBox is layout and lineCount is set
- val timer = Timer()
- timer.schedule(10) { activity?.runOnUiThread { adjustCheckBoxRealTimeTransferWidthOnUiThread() }}
- timer.schedule(2500) { activity?.runOnUiThread { adjustCheckBoxRealTimeTransferWidthOnUiThread() }}
- }
-
- protected open fun adjustCheckBoxRealTimeTransferWidthOnUiThread() {
- if (chkbxRealTimeTransfer.isEllipsized == false) {
- // by default chkbxRealTimeTransfer uses full width, even though if its text doesn't need this space -> there
- chkbxRealTimeTransfer.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT, 0f)
- chkbxRealTimeTransfer.requestLayout()
- }
- }
-
- protected open fun setRealTimeTransferControlsVisibility(rootView: View) {
- rootView.lytRealTimeTransfer.setVisibility(account.supportsRealTimeTransfer)
- }
-
- protected open fun showRealTimeTransferInfo(btnShowRealTimeTransferInfo: ImageButton) {
- activity?.let { activity ->
- InfoPopupWindow(activity, R.string.dialog_transfer_money_real_time_transfer_info)
- .show(btnShowRealTimeTransferInfo)
- }
- }
-
- private fun transferMoneyIfEnterPressed(editText: EditText) {
- editText.addEnterPressedListener {
- if (isRequiredDataEntered()) {
- transferMoney()
-
- return@addEnterPressedListener true
- }
-
- false
- }
- }
-
- private fun isRequiredDataEntered() = btnTransferMoney.isEnabled
-
- private fun initRecipientAutocompletion(edtxtRecipientName: EditText) {
- val autocompleteCallback = StandardAutocompleteCallback { _, item ->
- recipientSelected(item)
- true
- }
-
- Autocomplete.on(edtxtRecipientName)
- .with(6f)
- .with(ColorDrawable(Color.WHITE))
- .with(autocompleteCallback)
- .with(RecipientPresenter(presenter, edtxtRecipientName.context))
- .build()
- .closePopupOnBackButtonPress(dialog)
- }
-
-
- override fun onStart() {
- super.onStart()
-
- setPreselectedValues()
-
- if (recipientBic != null) {
- tryToGetBicFromIban(edtxtRecipientIban.text.toString())
- }
- }
-
-
- protected open fun setPreselectedValues() {
- preselectedValues?.let { data ->
- preselectedValues = null
-
- edtxtRecipientName.setText(data.recipientName)
-
- if (data.recipientAccountId.isNotBlank()) { // set only if recipientAccountId has a value as otherwise recipientBankCode would be overridden by empty search result
- edtxtRecipientIban.setText(data.recipientAccountId)
- }
-
- // a little bit inconsistent as if IBAN is not set bank's name won't be displayed even though it can be retrieved by BIC
- recipientBic = data.recipientBankCode
-
- if (data.amount > BigDecimal.ZERO) {
- edtxtAmount.setText(data.amount.toString())
- }
-
- edtxtReference.setText(data.reference)
-
- focusEditTextAccordingToPreselectedValues()
- }
- }
-
- protected open fun focusEditTextAccordingToPreselectedValues() {
- when {
- edtxtRecipientName.text.toString().isBlank() -> edtxtRecipientName.requestFocus()
- edtxtRecipientIban.text.toString().isBlank() -> edtxtRecipientIban.requestFocus()
- edtxtAmount.text.toString().isBlank() -> edtxtAmount.requestFocus()
- edtxtReference.text.toString().isBlank() -> edtxtReference.requestFocus()
- else -> edtxtReference.requestFocus()
- }
- }
-
-
- protected open fun recipientSelected(item: TransactionParty) {
- edtxtRecipientName.setText(item.name)
- edtxtRecipientIban.setText(item.iban)
- recipientBic = item.bic
-
- focusEditTextAccordingToPreselectedValues()
- }
-
- protected open fun transferMoney() {
- getEnteredAmount()?.let { amount -> // should only come at this stage when a valid amount has been entered
- val data = TransferMoneyData(
- account,
- inputValidator.convertToAllowedSepaCharacters(edtxtRecipientName.text.toString()),
- edtxtRecipientIban.text.toString().replace(" ", ""),
- recipientBic?.replace(" ", "") ?: "", // should always be != null at this point
- amount.toBigDecimal(),
- inputValidator.convertToAllowedSepaCharacters(edtxtReference.text.toString()),
- chkbxRealTimeTransfer.isChecked
- )
-
- presenter.transferMoneyAsync(data) {
- context?.asActivity()?.runOnUiThread {
- handleTransferMoneyResultOnUiThread(data, it)
- }
- }
- }
- }
-
- protected open fun handleTransferMoneyResultOnUiThread(transferData: TransferMoneyData, response: BankingClientResponse) {
- context?.let { context ->
- if (response.userCancelledAction == false) {
- val message = if (response.successful) {
- context.getString(R.string.dialog_transfer_money_message_transfer_successful,
- String.format("%.02f", transferData.amount), "€", transferData.recipientName) // TODO: where to get currency from?
- }
- else {
- context.getString(R.string.dialog_transfer_money_message_transfer_failed,
- String.format("%.02f", transferData.amount), "€", transferData.recipientName, // TODO: where to get currency from?
- response.errorToShowToUser
- )
- }
-
- AlertDialog.Builder(context)
- .setMessage(message)
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
-
- if (response.successful || response.userCancelledAction) { // do not close dialog if an error occurred
- this.dismiss()
- }
- }
- }
-
-
- protected fun checkRequiredDataWatcher(additionalCheck: (() -> Unit)? = null): TextWatcher {
- return StandardTextWatcher {
- additionalCheck?.invoke()
-
- checkIfRequiredDataEnteredOnUiThread()
- }
- }
-
- protected open fun tryToGetBicFromIban(enteredIban: CharSequence) {
- presenter.findUniqueBankForIbanAsync(enteredIban.toString()) { foundBank ->
- context?.asActivity()?.runOnUiThread {
- showValuesForFoundBankOnUiThread(enteredIban, foundBank)
- }
- }
- }
-
- private fun showValuesForFoundBankOnUiThread(enteredIban: CharSequence, foundBank: BankInfo?) {
- validRecipientBicEntered = foundBank != null
- recipientBic = foundBank?.bic
-
- if (foundBank != null) {
- txtRecipientBankInfo.text = getString(R.string.dialog_transfer_money_bic_detected_from_iban, foundBank.bic, foundBank.name)
- txtRecipientBankInfo.show()
- setIbanValidationErrorVisibility()
- }
- else if (enteredIban.length >= InputValidator.MinimumLengthToDetermineBicFromIban) {
- txtRecipientBankInfo.text = getString(R.string.dialog_transfer_money_could_not_determine_bic_from_iban, enteredIban.substring(4, InputValidator.MinimumLengthToDetermineBicFromIban))
- txtRecipientBankInfo.show()
- setIbanValidationErrorVisibility()
- }
- else {
- txtRecipientBankInfo.hide()
- }
-
- checkIfRequiredDataEnteredOnUiThread()
- }
-
- protected open fun setIbanValidationErrorVisibility() {
- getIbanTextInputErrorView()?.let { textInputError ->
- val displaysErrorOrHint = lytRecipientIban.error != null || lytRecipientIban.helperText != null
- (textInputError.parent?.parent as? ViewGroup)?.setVisibility(displaysErrorOrHint)
- }
- }
-
- protected open fun getIbanTextInputErrorView(): TextView? {
- requireContext().getResourceIdentifier("textinput_error", "id")?.let { textInputErrorId ->
- return lytRecipientIban.findViewById(textInputErrorId)
- }
-
- return null
- }
-
- protected open fun checkIfRequiredDataEnteredOnUiThread() {
- btnTransferMoney.isEnabled = validRecipientNameEntered && validRecipientIbanEntered
- && validRecipientBicEntered
- && validAmountEntered && validReferenceEntered
- }
-
- protected open fun checkIfEnteredRecipientNameIsValidWhileUserIsTyping() {
- val enteredRecipientName = edtxtRecipientName.text.toString()
- val validationResult = inputValidator.validateRecipientNameWhileTyping(enteredRecipientName)
-
- this.validRecipientNameEntered = validationResult.validationSuccessfulOrCouldCorrectString
-
- showValidationResult(lytRecipientName, validationResult)
- }
-
- protected open fun checkIfEnteredRecipientNameIsValidAfterFocusLost() {
- val enteredRecipientName = edtxtRecipientName.text.toString()
- val validationResult = inputValidator.validateRecipientName(enteredRecipientName)
-
- this.validRecipientNameEntered = validationResult.validationSuccessfulOrCouldCorrectString
-
- if (validationResult.validationSuccessful == false) { // only update hint / error if validation fails, don't hide previous hint / error otherwise
- showValidationResult(lytRecipientName, validationResult)
- }
- }
-
- protected open fun checkIfEnteredRecipientIbanIsValidWhileUserIsTyping() {
- val enteredIban = edtxtRecipientIban.text.toString()
- val validationResult = inputValidator.validateIbanWhileTyping(enteredIban)
-
- this.validRecipientIbanEntered = validationResult.validationSuccessfulOrCouldCorrectString
-
- showValidationResult(lytRecipientIban, validationResult)
- setIbanValidationErrorVisibility()
- }
-
- protected open fun checkIfEnteredRecipientIbanIsValidAfterFocusLost() {
- val validationResult = inputValidator.validateIban(edtxtRecipientIban.text.toString())
-
- this.validRecipientIbanEntered = validationResult.validationSuccessfulOrCouldCorrectString
-
- if (validationResult.validationSuccessful == false) { // only update hint / error if validation fails, don't hide previous hint / error otherwise
- showValidationResult(lytRecipientIban, validationResult)
- setIbanValidationErrorVisibility()
- }
- }
-
- protected open fun checkIfEnteredAmountIsValid() {
- val validationResult = inputValidator.validateAmount(edtxtAmount.text.toString())
-
- this.validAmountEntered = validationResult.validationSuccessfulOrCouldCorrectString
-
- showValidationResult(lytAmount, validationResult)
- }
-
- protected open fun getEnteredAmount(): BigDecimal? {
- try {
- val amountString = edtxtAmount.text.toString().replace(',', '.')
-
- return amountString.toBigDecimal()
- } catch (ignored: Exception) { }
-
- return null
- }
-
- protected open fun checkIfEnteredReferenceTextIsValid() {
- val validationResult = inputValidator.validateReference(edtxtReference.text.toString())
-
- this.validReferenceEntered = validationResult.validationSuccessfulOrCouldCorrectString
-
- showValidationResult(lytReference, validationResult)
- }
-
- protected open fun showValidationResult(textInputLayout: TextInputLayout, validationResult: ValidationResult) {
- if (didJustCorrectInput.containsKey(textInputLayout)) { // we have just auto corrected TextInputLayout's EditText's text below, don't overwrite its displayed hints and error
- return
- }
-
- if (validationResult.didCorrectString) {
- textInputLayout.editText?.let { editText ->
- val selectionStart = editText.selectionStart
- val selectionEnd = editText.selectionEnd
- val lengthDiff = validationResult.correctedInputString.length - validationResult.inputString.length
-
- didJustCorrectInput.put(textInputLayout, true)
-
- editText.setText(validationResult.correctedInputString)
-
- if (validationResult.correctedInputString.isNotEmpty()) {
- editText.setSelection(selectionStart + lengthDiff, selectionEnd + lengthDiff)
- }
-
- didJustCorrectInput.remove(textInputLayout)
- }
- }
-
- val showHintOrError = validationResult.validationError != null || validationResult.validationHint != null
-
- val textInputErrorLayout = textInputLayout.getResourceIdentifier("textinput_error", "id")?.let { textInputErrorId -> textInputLayout.findViewById(textInputErrorId)?.parent?.parent as? View }
- textInputErrorLayout?.setVisibility(showHintOrError)
-
- textInputLayout.error = validationResult.validationError
- if (validationResult.validationError == null) { // don't overwrite error text
- textInputLayout.helperText = validationResult.validationHint
- }
-
- (textInputLayout.layoutParams as? ViewGroup.MarginLayoutParams)?.let { params ->
- params.bottomMargin = if (showHintOrError == false || textInputLayout == lytReference) 0
- else context!!.getDimension(R.dimen.dialog_transfer_money_input_fields_bottom_margin_when_displaying_validation_label)
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/BankAccountSettingsDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/BankAccountSettingsDialog.kt
deleted file mode 100644
index 669eefb5..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/BankAccountSettingsDialog.kt
+++ /dev/null
@@ -1,125 +0,0 @@
-package net.dankito.banking.ui.android.dialogs.settings
-
-import android.content.Intent
-import android.os.Bundle
-import android.view.*
-import androidx.fragment.app.FragmentActivity
-import kotlinx.android.synthetic.main.dialog_bank_account_settings.*
-import kotlinx.android.synthetic.main.dialog_bank_account_settings.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.CheckableValueAdapterItem
-import net.dankito.banking.ui.android.adapter.FastAdapterRecyclerView
-import net.dankito.banking.ui.model.BankAccountType
-import net.dankito.banking.ui.model.TypedBankAccount
-
-
-open class BankAccountSettingsDialog : SettingsDialogBase() {
-
- companion object {
- const val DialogTag = "BankAccountSettingsDialog"
- }
-
-
- protected lateinit var account: TypedBankAccount
-
-
-
- fun show(account: TypedBankAccount, activity: FragmentActivity) {
- this.account = account
-
- show(activity, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return inflater.inflate(R.layout.dialog_bank_account_settings, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- toolbar.apply {
- setupToolbar(this, account.displayName)
- }
-
- edtxtBankAccountName.text = account.displayName
-
- swtchHideAccount.setOnCheckedChangeListener { _, hideAccount -> swtchIncludeInAutomaticAccountsUpdate.isEnabled = hideAccount == false }
-
- swtchHideAccount.isChecked = account.hideAccount
- swtchIncludeInAutomaticAccountsUpdate.isChecked = account.includeInAutomaticAccountsUpdate
-
- btnShareAccountData.setOnClickListener { shareAccountData() }
-
- lvlAccountHolderName.value = account.accountHolderName
- lvlAccountIdentifier.value = account.identifier
- lvlSubAccountNumber.setValueAndVisibilityIfValueIsSet(account.subAccountNumber)
- lvlIban.setValueAndVisibilityIfValueIsSet(account.iban)
- lvlAccountType.value = getString(getBankAccountTypeResId(account.type))
-
- val context = view.context
- val accountFeaturesItems = listOf(
- CheckableValueAdapterItem(account.supportsRetrievingBalance, context, R.string.dialog_bank_account_settings_account_features_supports_retrieving_balance),
- CheckableValueAdapterItem(account.supportsRetrievingAccountTransactions, context, R.string.dialog_bank_account_settings_account_features_supports_retrieving_account_transactions),
- CheckableValueAdapterItem(account.supportsTransferringMoney, context, R.string.dialog_bank_account_settings_account_features_supports_money_transfer),
- CheckableValueAdapterItem(account.supportsRealTimeTransfer, context, R.string.dialog_bank_account_settings_account_features_supports_real_time_transfer)
- )
- FastAdapterRecyclerView(view.rcyAccountFeatures, accountFeaturesItems)
- }
-
- protected open fun getBankAccountTypeResId(type: BankAccountType): Int {
- return when (type) {
- BankAccountType.CheckingAccount -> R.string.checking_account
- BankAccountType.SavingsAccount -> R.string.savings_account
- BankAccountType.FixedTermDepositAccount -> R.string.fixed_term_deposit_account
- BankAccountType.SecuritiesAccount -> R.string.securities_account
- BankAccountType.LoanAccount -> R.string.loan_account
- BankAccountType.CreditCardAccount -> R.string.credit_card_account
- BankAccountType.FundDeposit -> R.string.fund_deposit
- BankAccountType.BuildingLoanContract -> R.string.building_loan_contract
- BankAccountType.InsuranceContract -> R.string.insurance_contract
- else -> R.string.other
- }
- }
-
-
- protected open fun shareAccountData() {
- val accountData = StringBuilder(account.accountHolderName + "\n" + account.bank.bankName)
-
- account.iban?.let { iban ->
- accountData.append("\n" + getString(R.string.share_account_data_iban, iban))
- }
-
- accountData.append("\n" + getString(R.string.share_account_data_bic, account.bank.bic))
- accountData.append("\n" + getString(R.string.share_account_data_bank_code, account.bank.bankCode))
- accountData.append("\n" + getString(R.string.share_account_data_account_number, account.identifier))
-
-
- val sendIntent: Intent = Intent().apply {
- action = Intent.ACTION_SEND
- putExtra(Intent.EXTRA_TEXT, accountData.toString())
- type = "text/plain"
- }
-
- val shareIntent = Intent.createChooser(sendIntent, null)
- startActivity(shareIntent)
-
- }
-
-
- override val hasUnsavedChanges: Boolean
- get() = didChange(edtxtBankAccountName, account.displayName)
- || swtchHideAccount.isChecked != account.hideAccount
- || swtchIncludeInAutomaticAccountsUpdate.isChecked != account.includeInAutomaticAccountsUpdate
-
- override fun saveChanges() {
- account.userSetDisplayName = edtxtBankAccountName.text
-
- val didHideAccountChange = account.hideAccount != swtchHideAccount.isChecked
- account.hideAccount = swtchHideAccount.isChecked
- account.includeInAutomaticAccountsUpdate = swtchIncludeInAutomaticAccountsUpdate.isChecked
-
- presenter.accountUpdated(account, didHideAccountChange)
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/BankSettingsDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/BankSettingsDialog.kt
deleted file mode 100644
index 5009c749..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/BankSettingsDialog.kt
+++ /dev/null
@@ -1,143 +0,0 @@
-package net.dankito.banking.ui.android.dialogs.settings
-
-import android.os.Bundle
-import android.view.*
-import androidx.appcompat.app.AppCompatActivity
-import androidx.fragment.app.FragmentActivity
-import kotlinx.android.synthetic.main.dialog_bank_settings.*
-import kotlinx.android.synthetic.main.dialog_bank_settings.view.*
-import kotlinx.android.synthetic.main.dialog_bank_settings.view.toolbar
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.DraggableBankAccountAdapterItem
-import net.dankito.banking.ui.android.adapter.FastAdapterRecyclerView
-import net.dankito.banking.ui.android.adapter.TanMethodAdapterItem
-import net.dankito.banking.ui.android.alerts.AskDeleteAccountAlert
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.banking.ui.model.tan.TanMethod
-
-
-open class BankSettingsDialog : SettingsDialogBase() {
-
- companion object {
- const val DialogTag = "BankSettingsDialog"
- }
-
-
- protected lateinit var bank: TypedBankData
-
- protected var selectedTanMethod: TanMethod? = null
-
- protected lateinit var bankAccountsAdapter: FastAdapterRecyclerView
-
- protected var banksChangedListener = { _: List ->
- updateBankAccountsAdapterItems()
- }
-
-
-
- fun show(bank: TypedBankData, activity: FragmentActivity) {
- this.bank = bank
- this.selectedTanMethod = bank.selectedTanMethod
-
- show(activity, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_bank_settings, container, false)
-
- setupUI(rootView)
-
- presenter.addBanksChangedListener(banksChangedListener)
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- rootView.apply {
- toolbar.apply {
- setupToolbar(this, bank.displayName)
- }
-
- edtxtBankName.text = bank.displayName
- edtxtUserName.text = bank.userName
- bankCredentialsPassword.password = bank.password
-
- val tanMethodItems = createTanMethodItems()
- val tanMethodsAdapter = FastAdapterRecyclerView(rootView.rcyTanMethods, tanMethodItems)
- tanMethodsAdapter.onClickListener = {
- selectedTanMethod = it.tanMethod
- tanMethodsAdapter.setItems(createTanMethodItems())
- }
-
- lvlBankCode.value = bank.bankCode
- lvlBic.value = bank.bic
- lvlCustomerName.value = bank.customerName
- lvlFinTsServerAddress.value = bank.finTsServerAddress
-
- val items = createBankAccountsAdapterItems()
- bankAccountsAdapter = FastAdapterRecyclerView(rootView.rcyBankAccounts, items, true)
- bankAccountsAdapter.onClickListener = { navigationToBankAccountSettingsDialog(it.account) }
- bankAccountsAdapter.itemDropped = { oldPosition, oldItem, newPosition, newItem -> reorderedBankAccounts(oldPosition, oldItem.account, newPosition, newItem.account) }
-
- btnDeleteAccount.setOnClickListener { askUserToDeleteAccount() }
- }
- }
-
-
- override fun onDestroy() {
- presenter.removeBanksChangedListener(banksChangedListener)
-
- super.onDestroy()
- }
-
-
- protected open fun createTanMethodItems(): List {
- return bank.supportedTanMethods.map { TanMethodAdapterItem(it, it == selectedTanMethod) }
- }
-
-
- protected open fun createBankAccountsAdapterItems(): List {
- return bank.accountsSorted.map { DraggableBankAccountAdapterItem(it) }
- }
-
- protected open fun updateBankAccountsAdapterItems() {
- bankAccountsAdapter.setItems(createBankAccountsAdapterItems())
- }
-
-
- protected open fun navigationToBankAccountSettingsDialog(account: TypedBankAccount) {
- (activity as? AppCompatActivity)?.let { activity ->
- BankAccountSettingsDialog().show(account, requireActivity() as AppCompatActivity)
- }
- }
-
- protected open fun reorderedBankAccounts(oldPosition: Int, oldItem: TypedBankAccount, newPosition: Int, newItem: TypedBankAccount) {
- oldItem.displayIndex = oldPosition
- newItem.displayIndex = newPosition
-
- presenter.accountUpdated(oldItem, false)
- presenter.accountUpdated(newItem, false)
- }
-
-
- override val hasUnsavedChanges: Boolean
- get() = didChange(edtxtBankName, bank.displayName)
- || didChange(edtxtUserName, bank.userName)
- || bankCredentialsPassword.password != bank.password
- || bank.selectedTanMethod != selectedTanMethod
-
- override fun saveChanges() {
- bank.userSetDisplayName = edtxtBankName.text
-
- presenter.bankUpdated(bank, edtxtUserName.text, bankCredentialsPassword.password, selectedTanMethod)
- }
-
- protected open fun askUserToDeleteAccount() {
- AskDeleteAccountAlert().show(bank, presenter, requireContext()) {
- closeDialog()
- }
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/ProtectAppSettingsDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/ProtectAppSettingsDialog.kt
deleted file mode 100644
index 404152d3..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/ProtectAppSettingsDialog.kt
+++ /dev/null
@@ -1,183 +0,0 @@
-package net.dankito.banking.ui.android.dialogs.settings
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.core.view.doOnNextLayout
-import androidx.fragment.app.FragmentActivity
-import kotlinx.android.synthetic.main.dialog_protect_app_settings.*
-import kotlinx.android.synthetic.main.dialog_protect_app_settings.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.authentication.AuthenticationService
-import net.dankito.banking.ui.android.authentication.AuthenticationType
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.extensions.addEnterPressedListener
-import net.dankito.banking.ui.android.util.StandardTextWatcher
-import net.dankito.utils.android.extensions.hideKeyboardDelayed
-import net.dankito.utils.android.extensions.hide
-import net.dankito.utils.android.extensions.setVisibility
-import net.dankito.utils.android.extensions.show
-import org.slf4j.LoggerFactory
-import javax.inject.Inject
-
-
-open class ProtectAppSettingsDialog : SettingsDialogBase() {
-
- companion object {
- const val DialogTag = "ProtectAppSettingsDialog"
-
- private val log = LoggerFactory.getLogger(ProtectAppSettingsDialog::class.java)
- }
-
-
- @Inject
- protected lateinit var authenticationService: AuthenticationService
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- fun show(activity: FragmentActivity) {
- show(activity, SettingsDialog.DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- return inflater.inflate(R.layout.dialog_protect_app_settings, container, false)
- }
-
- override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
- super.onViewCreated(view, savedInstanceState)
-
- setupUI(view)
- }
-
- protected open fun setupUI(rootView: View) {
- rootView.apply {
- toolbar.apply {
- setupToolbar(this, context.getString(R.string.settings), false)
- }
-
- val authenticationType = authenticationService.authenticationType
- val isBiometricAuthenticationSupported = authenticationService.isBiometricAuthenticationSupported
-
- val showAuthenticationMethods = isBiometricAuthenticationSupported || authenticationType != AuthenticationType.None // hide select authentication method if password is the only option to choose
- segmentedGroup.setVisibility(showAuthenticationMethods)
- segmentedGroup.doOnNextLayout {
- val segmentedControlButtonWidth = segmentedGroup.measuredWidth / 3
- btnShowBiometricAuthenticationSection.layoutParams.width = segmentedControlButtonWidth
- btnShowPasswordAuthenticationSection.layoutParams.width = segmentedControlButtonWidth
- btnShowRemoveAppProtectionSection.layoutParams.width = segmentedControlButtonWidth
- }
-
- btnShowBiometricAuthenticationSection.setVisibility(isBiometricAuthenticationSupported)
- btnShowBiometricAuthenticationSection.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- showAuthenticationLayout(rootView, lytBiometricAuthentication)
- }
- }
-
- btnShowPasswordAuthenticationSection.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- showAuthenticationLayout(rootView, lytPasswordAuthentication)
- checkIfEnteredPasswordsMatch()
- }
- }
-
- btnShowRemoveAppProtectionSection.setOnCheckedChangeListener { _, isChecked ->
- if (isChecked) {
- showAuthenticationLayout(rootView, lytRemoveAppProtection)
- }
- }
-
- btnBiometricAuthentication.customButtonClickHandler = {
- authenticationService.authenticateUserWithBiometricToSetAsNewAuthenticationMethod { result ->
- btnSetAuthenticationMethod.isEnabled = result.successful
- }
- }
-
- edtxtPassword.actualEditText.addTextChangedListener(StandardTextWatcher { checkIfEnteredPasswordsMatch() } )
- edtxtPassword.actualEditText.addEnterPressedListener { checkIfEnteredPasswordsMatchAndSetAuthenticationMethod() }
- edtxtPasswordConfirmation.actualEditText.addTextChangedListener(StandardTextWatcher { checkIfEnteredPasswordsMatch() } )
- edtxtPasswordConfirmation.actualEditText.addEnterPressedListener { checkIfEnteredPasswordsMatchAndSetAuthenticationMethod() }
-
- btnSetAuthenticationMethod.setOnClickListener { setAuthenticationMethod() }
-
- if (isBiometricAuthenticationSupported && authenticationType == AuthenticationType.Biometric) {
- btnShowBiometricAuthenticationSection.isChecked = true
- }
- else {
- btnShowPasswordAuthenticationSection.isChecked = true
- }
-
- }
- }
-
- protected open fun showAuthenticationLayout(rootView: View, authenticationLayoutToShow: ViewGroup) {
- lytBiometricAuthentication.hide()
- lytPasswordAuthentication.hide()
- lytRemoveAppProtection.hide()
-
- authenticationLayoutToShow.show()
-
- if (authenticationLayoutToShow == lytRemoveAppProtection) {
- btnSetAuthenticationMethod.setText(R.string.dialog_protect_app_settings_button_remove_app_protection_title)
- btnSetAuthenticationMethod.setBackgroundResource(R.color.destructiveColor)
- btnSetAuthenticationMethod.isEnabled = true
- }
- else {
- btnSetAuthenticationMethod.setText(R.string.dialog_protect_app_settings_button_set_new_authentication_method_title)
- btnSetAuthenticationMethod.setBackgroundResource(R.drawable.conditionally_disabled_view_background)
- btnSetAuthenticationMethod.isEnabled = false
- }
-
- authenticationLayoutToShow.hideKeyboardDelayed(10)
- }
-
-
- protected open fun checkIfEnteredPasswordsMatchAndSetAuthenticationMethod(): Boolean {
- if (checkIfEnteredPasswordsMatch()) {
- setAuthenticationMethod()
-
- return true
- }
-
- return false
- }
-
- protected open fun checkIfEnteredPasswordsMatch(): Boolean {
- val enteredPassword = edtxtPassword.text
-
- if (enteredPassword.isNotBlank() && enteredPassword == edtxtPasswordConfirmation.text) {
- btnSetAuthenticationMethod.isEnabled = true
- return true
- }
- else {
- btnSetAuthenticationMethod.isEnabled = false
- return false
- }
- }
-
- protected open fun setAuthenticationMethod() {
- when {
- btnShowPasswordAuthenticationSection.isChecked -> authenticationService.setAuthenticationMethodToPassword(edtxtPassword.chars)
- btnShowBiometricAuthenticationSection.isChecked -> authenticationService.setAuthenticationMethodToBiometric()
- btnShowRemoveAppProtectionSection.isChecked -> authenticationService.removeAppProtection()
- else -> log.error("This should never occur! Has there a new authentication method been added?")
- }
-
- closeDialog()
- }
-
-
- override val hasUnsavedChanges: Boolean
- get() = false
-
- override fun saveChanges() {
-
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/SettingsDialog.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/SettingsDialog.kt
deleted file mode 100644
index 2c02c78b..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/SettingsDialog.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-package net.dankito.banking.ui.android.dialogs.settings
-
-import android.os.Bundle
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import androidx.appcompat.content.res.AppCompatResources
-import androidx.fragment.app.FragmentActivity
-import kotlinx.android.synthetic.main.dialog_settings.*
-import kotlinx.android.synthetic.main.dialog_settings.view.*
-import net.codinux.banking.tools.importerexporter.CsvAccountTransactionsExporter
-import net.codinux.banking.tools.importerexporter.model.AccountTransaction
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.BankDataAdapterItem
-import net.dankito.banking.ui.android.adapter.FastAdapterRecyclerView
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.model.IAccountTransaction
-import net.dankito.banking.ui.model.TypedBankData
-import net.dankito.filechooserdialog.FileChooserDialog
-import net.dankito.filechooserdialog.model.FileChooserDialogConfig
-import net.dankito.utils.android.permissions.IPermissionsService
-import net.dankito.utils.multiplatform.toFile
-import java.io.File
-import java.text.SimpleDateFormat
-import javax.inject.Inject
-
-
-open class SettingsDialog : SettingsDialogBase() {
-
- companion object {
- val ExportTransactionsDateFormat = SimpleDateFormat("yyyyMMdd")
-
- const val DialogTag = "SettingsDialog"
- }
-
-
- @Inject
- protected lateinit var permissionsService: IPermissionsService
-
- protected lateinit var banksAdapter: FastAdapterRecyclerView
-
- protected var banksChangedListener = { _: List ->
- updateBanksAdapterItems()
- }
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
- fun show(activity: FragmentActivity) {
- show(activity, DialogTag)
- }
-
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.dialog_settings, container, false)
-
- setupUI(rootView)
-
- presenter.addBanksChangedListener(banksChangedListener)
-
- return rootView
- }
-
- protected open fun setupUI(rootView: View) {
- rootView.apply {
- toolbar.apply {
- setupToolbar(this, rootView.context.getString(R.string.settings))
- }
-
- val items = createBanksAdapterItems()
- banksAdapter = FastAdapterRecyclerView(rootView.rcyBankCredentials, items, true)
- banksAdapter.onClickListener = { navigationToBankSettingsDialog(it.bank) }
- banksAdapter.itemDropped = { oldPosition, oldItem, newPosition, newItem -> reorderedBanks(oldPosition, oldItem.bank, newPosition, newItem.bank) }
-
- btnAddAccount.setOnClickListener { presenter.showAddAccountDialog() }
-
- selectUpdateAccountsAfter.periodInMinutes = presenter.appSettings.automaticallyUpdateAccountsAfterMinutes
-
- btnSetAppProtection.setOnClickListener { navigateToProtectAppSettingsDialog() }
- selectLockAppAfter.periodInMinutes = presenter.appSettings.lockAppAfterMinutes
-
- btnExportAccountTransactions.setOnClickListener { exportAccountTransactions() }
-
- // on Pre Lollipop devices setting vector drawables in xml is not supported -> set left drawable here
- val sendIcon = AppCompatResources.getDrawable(context, R.drawable.ic_baseline_send_24)
- btnShowSendMessageLogDialog.setCompoundDrawablesWithIntrinsicBounds(sendIcon, null, null, null)
- btnShowSendMessageLogDialog.setOnClickListener { presenter.showSendMessageLogDialog() }
- }
- }
-
-
- override fun onDestroy() {
- presenter.removeBanksChangedListener(banksChangedListener)
-
- super.onDestroy()
- }
-
-
- protected open fun createBanksAdapterItems(): List {
- return presenter.allBanksSortedByDisplayIndex.map { BankDataAdapterItem(it) }
- }
-
- protected open fun updateBanksAdapterItems() {
- activity?.runOnUiThread {
- banksAdapter.setItems(createBanksAdapterItems())
- }
- }
-
-
- protected open fun navigationToBankSettingsDialog(bank: TypedBankData) {
- activity?.let { activity ->
- BankSettingsDialog().show(bank, activity)
- }
- }
-
- protected open fun navigateToProtectAppSettingsDialog() {
- activity?.let { activity ->
- ProtectAppSettingsDialog().show(activity)
- }
- }
-
-
- protected open fun exportAccountTransactions() {
- val initialDirectory = presenter.appSettings.lastSelectedExportFolder.toFile()
- val suggestedFilename = getExportCsvSuggestedFilename()
-
-// val intent = Intent(Intent.ACTION_CREATE_DOCUMENT)
-// intent.addCategory(Intent.CATEGORY_OPENABLE)
-// intent.type = "text/csv"
-//
-// intent.putExtra(Intent.EXTRA_TITLE, suggestedFilename)
-//
-// startActivityForResult(intent, 1)
-
- activity?.let { activity ->
- val config = FileChooserDialogConfig(initialDirectory = initialDirectory, suggestedFilenameForSaveFileDialog = suggestedFilename)
- FileChooserDialog().showSaveFileInFullscreenDialog(activity, permissionsService, config) { _, selectedFile ->
- selectedFile?.let {
- val transactions = presenter.allTransactionsSorted.map { mapTransaction(it) }
-
- CsvAccountTransactionsExporter().export(selectedFile, transactions)
-
- presenter.appSettings.lastSelectedExportFolder = selectedFile.parentFile.absolutePath
- presenter.appSettingsChanged()
- }
- }
- }
- }
-
- // TODO: this is almost the same code as in JavaFX MainMenuBar.getExportCsvSuggestedFilename() -> merge
- protected open fun getExportCsvSuggestedFilename(): String? {
- val transactions = presenter.allTransactions
- val transactionsDates = transactions.map { it.valueDate }
- val transactionsStartDate = transactionsDates.min()
- val transactionsEndDate = transactionsDates.max()
-
- return context?.getString(R.string.dialog_settings_export_account_transactions_suggested_file_name,
- transactionsStartDate?.let { ExportTransactionsDateFormat.format(it) } ?: "", transactionsEndDate?.let { ExportTransactionsDateFormat.format(it) } ?: "")
- }
-
- // TODO: this is exactly the same code as in JavaFX MainMenuBar.mapTransaction() -> merge
- protected open fun mapTransaction(transaction: IAccountTransaction): AccountTransaction {
- return AccountTransaction(
- transaction.account.iban ?: transaction.account.identifier,
- transaction.amount,
- transaction.currency,
- transaction.reference,
- transaction.bookingDate,
- transaction.valueDate,
- transaction.otherPartyName,
- transaction.otherPartyBankCode,
- transaction.otherPartyAccountId,
- transaction.bookingText
- )
- }
-
-
- protected open fun reorderedBanks(oldPosition: Int, oldItem: TypedBankData, newPosition: Int, newItem: TypedBankData) {
- oldItem.displayIndex = oldPosition
- newItem.displayIndex = newPosition
-
- presenter.bankDisplayIndexUpdated(oldItem)
- presenter.bankDisplayIndexUpdated(newItem)
- }
-
-
- override val hasUnsavedChanges: Boolean
- get() = presenter.appSettings.automaticallyUpdateAccountsAfterMinutes != selectUpdateAccountsAfter.periodInMinutes
- || presenter.appSettings.lockAppAfterMinutes != selectLockAppAfter.periodInMinutes
-
- override fun saveChanges() {
- presenter.appSettings.automaticallyUpdateAccountsAfterMinutes = selectUpdateAccountsAfter.periodInMinutes
- presenter.appSettings.lockAppAfterMinutes = selectLockAppAfter.periodInMinutes
- presenter.appSettingsChanged()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/SettingsDialogBase.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/SettingsDialogBase.kt
deleted file mode 100644
index a21f6ffd..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/dialogs/settings/SettingsDialogBase.kt
+++ /dev/null
@@ -1,149 +0,0 @@
-package net.dankito.banking.ui.android.dialogs.settings
-
-import android.app.Dialog
-import android.content.DialogInterface
-import android.os.Bundle
-import android.view.*
-import androidx.appcompat.widget.Toolbar
-import androidx.fragment.app.DialogFragment
-import androidx.fragment.app.FragmentActivity
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.alerts.AskDismissChangesAlert
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.views.FormEditText
-import net.dankito.banking.ui.presenter.BankingPresenter
-import org.slf4j.LoggerFactory
-import javax.inject.Inject
-
-
-abstract class SettingsDialogBase : DialogFragment() {
-
- companion object {
- private val log = LoggerFactory.getLogger(SettingsDialogBase::class.java)
- }
-
-
- protected abstract val hasUnsavedChanges: Boolean
-
- protected abstract fun saveChanges()
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
-
- init {
- BankingComponent.component.inject(this)
- }
-
-
-
- fun show(activity: FragmentActivity, dialogTag: String, fullscreen: Boolean = true) {
- val style = if (fullscreen) R.style.FullscreenDialogWithStatusBar else R.style.FloatingDialog
- setStyle(STYLE_NORMAL, style)
-
- show(activity.supportFragmentManager, dialogTag)
- }
-
-
- override fun setupDialog(dialog: Dialog, style: Int) {
- super.setupDialog(dialog, style)
-
- dialog.setOnKeyListener { _, keyCode, event ->
- if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
- return@setOnKeyListener handleBackButtonPress()
- }
-
- false
- }
- }
-
- protected open fun handleBackButtonPress(): Boolean {
- askToDismissChanges()
-
- return hasUnsavedChanges
- }
-
-
- protected open fun setupToolbar(toolbar: Toolbar, dialogTitle: String, showSaveButton: Boolean = true) {
- toolbar.apply {
- title = dialogTitle
-
- inflateMenu(R.menu.menu_settings_dialog)
- menu.findItem(R.id.mnitmSaveChanges).isVisible = showSaveButton
-
- setOnMenuItemClickListener { item -> onOptionsItemSelected(item) }
-
- setNavigationOnClickListener { askToDismissChanges() }
- }
- }
-
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- return when (item.itemId) {
- R.id.mnitmSaveChanges -> saveChangesAndCloseDialog()
- else -> super.onOptionsItemSelected(item)
- }
- }
-
-
- protected open fun didChange(editedValue: FormEditText, originalValue: String): Boolean {
- return editedValue.text != originalValue
- }
-
-
- protected open fun saveChangesAndCloseDialog(): Boolean {
- if (hasUnsavedChanges) {
- saveChanges()
- }
-
- closeDialog()
-
- return true
- }
-
- protected open fun askToDismissChanges() {
- if (hasUnsavedChanges) {
- AskDismissChangesAlert().show(this)
- }
- else {
- closeDialog()
- }
- }
-
- protected open fun closeDialog() {
- dismiss()
- }
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- log.info("Creating Fragment $this")
- }
-
- override fun onDismiss(dialog: DialogInterface) {
- log.info("Dismissing Fragment $this")
-
- super.onDismiss(dialog)
- }
-
- override fun onPause() {
- log.info("Pausing Fragment $this")
-
- super.onPause()
- }
-
- override fun onStop() {
- log.info("Stopping Fragment $this")
-
- super.onStop()
- }
-
- override fun onDestroy() {
- log.info("Destroying Fragment $this")
-
- super.onDestroy()
- }
-
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/AutocompleteExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/AutocompleteExtensions.kt
deleted file mode 100644
index 9b764549..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/AutocompleteExtensions.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.app.Dialog
-import android.view.KeyEvent
-import com.otaliastudios.autocomplete.Autocomplete
-
-
-/**
- * This will not work if Dialog is null!
- *
- * Making the Dialog parameter nullable is just for convienience to be able to call
- * Autocomplete
- * .on<>(view)
- * .build()
- * .closePopupOnBackButtonPress(dialog)
- */
-fun Autocomplete<*>.closePopupOnBackButtonPress(dialog: Dialog?) {
- dialog?.setOnKeyListener { _, keyCode, _ ->
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (this.isPopupShowing) { // close autocomplete popup on back button press
- this.dismissPopup()
- return@setOnKeyListener true
- }
- }
-
- false
- }
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ByteArrayExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ByteArrayExtensions.kt
deleted file mode 100644
index 8692542b..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ByteArrayExtensions.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.content.res.Resources
-import android.graphics.Bitmap
-import android.graphics.BitmapFactory
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.Drawable
-
-
-fun ByteArray.toBitmap(): Bitmap {
- return BitmapFactory.decodeByteArray(this, 0, this.size)
-}
-
-fun ByteArray.toDrawable(resources: Resources): Drawable {
- return BitmapDrawable(resources, this.toBitmap())
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ContextExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ContextExtensions.kt
deleted file mode 100644
index b562f6b6..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ContextExtensions.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.content.Context
-import android.os.IBinder
-import android.view.View
-import android.view.inputmethod.InputMethodManager
-
-
-fun Context.hideKeyboard(anyViewInHierarchy: View, flags: Int = 0) {
- hideKeyboard(anyViewInHierarchy.windowToken, flags)
-}
-
-fun Context.hideKeyboard(windowToken: IBinder, flags: Int = 0) {
- val keyboard = this.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
- keyboard.hideSoftInputFromWindow(windowToken, flags)
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/EditTextExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/EditTextExtensions.kt
deleted file mode 100644
index 5bceda8e..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/EditTextExtensions.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.view.KeyEvent
-import android.widget.EditText
-
-
-val EditText.textString: String
- get() = this.text.toString()
-
-
-fun EditText.addEnterPressedListener(enterPressed: () -> Boolean) {
- this.setOnKeyListener { _, keyCode, event ->
- if (keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_UP) {
- return@setOnKeyListener enterPressed()
- }
-
- false
- }
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/IDrawerItemExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/IDrawerItemExtensions.kt
deleted file mode 100644
index 53e9106e..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/IDrawerItemExtensions.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.content.Context
-import com.mikepenz.iconics.typeface.IIcon
-import com.mikepenz.materialdrawer.iconics.withIcon
-import com.mikepenz.materialdrawer.model.BaseDescribeableDrawerItem
-import com.mikepenz.materialdrawer.model.BaseViewHolder
-import com.mikepenz.materialdrawer.model.interfaces.withIconColor
-import net.dankito.utils.android.extensions.createColorStateList
-
-
-fun BaseDescribeableDrawerItem.withIcon(context: Context, icon: IIcon, iconColorId: Int)
- : BaseDescribeableDrawerItem {
-
- withIcon(icon)
-
- withIconColor(context.createColorStateList(iconColorId))
-
- return this
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ImageViewExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ImageViewExtensions.kt
deleted file mode 100644
index 2dd1b018..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/ImageViewExtensions.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.widget.ImageView
-import net.dankito.banking.ui.model.IBankData
-import net.dankito.utils.android.extensions.hide
-import net.dankito.utils.android.extensions.show
-
-
-fun ImageView.setIcon(bank: IBankData<*, *>) {
- try {
- val iconData = bank.iconData
-
- if (iconData != null) {
- this.show()
- this.setImageFromBytes(iconData)
- }
- else {
- this.hide()
- this.setImageURI(null)
- }
- } catch (e: Exception) {
- this.hide()
- }
-}
-
-fun ImageView.setImageFromBytes(data: ByteArray) {
- this.setImageBitmap(data.toBitmap())
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/RecyclerViewExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/RecyclerViewExtensions.kt
deleted file mode 100644
index 9f86f958..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/RecyclerViewExtensions.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import androidx.recyclerview.widget.DividerItemDecoration
-import androidx.recyclerview.widget.RecyclerView
-
-
-fun RecyclerView.addHorizontalItemDivider() {
- this.addItemDecoration(DividerItemDecoration(context, DividerItemDecoration.VERTICAL))
-}
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/TextViewExtensions.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/TextViewExtensions.kt
deleted file mode 100644
index 8c399563..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/extensions/TextViewExtensions.kt
+++ /dev/null
@@ -1,30 +0,0 @@
-package net.dankito.banking.ui.android.extensions
-
-import android.widget.TextView
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.utils.android.extensions.setTextColorToColorResource
-import net.dankito.utils.multiplatform.BigDecimal
-
-
-fun TextView.showAmount(presenter: BankingPresenter, amount: BigDecimal, currencyIsoCode: String? = null) {
- text = presenter.formatAmount(amount, currencyIsoCode)
- setTextColorForAmount(amount)
-}
-
-fun TextView.setTextColorForAmount(amount: BigDecimal) {
- setTextColorToColorResource(if (amount >= java.math.BigDecimal.ZERO) R.color.positiveAmount else R.color.negativeAmount)
-}
-
-val TextView.isEllipsized: Boolean
- get() {
- this.layout?.let { layout ->
- for (i in 0..layout.lineCount) {
- if (layout.getEllipsisCount(i) > 0) {
- return true
- }
- }
- }
-
- return false
- }
\ No newline at end of file
diff --git a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt b/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt
deleted file mode 100644
index 7d0d6e2c..00000000
--- a/ui/BankingAndroidApp/src/main/java/net/dankito/banking/ui/android/home/HomeFragment.kt
+++ /dev/null
@@ -1,363 +0,0 @@
-package net.dankito.banking.ui.android.home
-
-import android.app.SearchManager
-import android.content.Context
-import android.os.Bundle
-import android.view.*
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.ImageButton
-import androidx.appcompat.widget.Toolbar
-import androidx.appcompat.app.AlertDialog
-import androidx.appcompat.widget.SearchView
-import androidx.core.content.ContextCompat
-import androidx.core.graphics.drawable.DrawableCompat
-import androidx.fragment.app.Fragment
-import androidx.recyclerview.widget.LinearLayoutManager
-import androidx.recyclerview.widget.RecyclerView
-import kotlinx.android.synthetic.main.fragment_home.*
-import kotlinx.android.synthetic.main.fragment_home.view.*
-import net.dankito.banking.ui.android.R
-import net.dankito.banking.ui.android.adapter.AccountTransactionAdapter
-import net.dankito.banking.ui.android.di.BankingComponent
-import net.dankito.banking.ui.android.extensions.addHorizontalItemDivider
-import net.dankito.banking.ui.android.extensions.showAmount
-import net.dankito.banking.ui.android.views.InfoPopupWindow
-import net.dankito.banking.ui.model.SelectedAccountType
-import net.dankito.banking.ui.model.TransactionsRetrievalState
-import net.dankito.banking.ui.model.TypedBankAccount
-import net.dankito.banking.ui.model.parameters.TransferMoneyData
-import net.dankito.banking.ui.model.responses.GetTransactionsResponse
-import net.dankito.banking.ui.presenter.BankingPresenter
-import net.dankito.utils.android.extensions.*
-import net.dankito.utils.multiplatform.sum
-import javax.inject.Inject
-
-
-class HomeFragment : Fragment() {
-
- companion object {
-
- val TransactionsCannotBeRetrievedStates = listOf(TransactionsRetrievalState.AccountTypeNotSupported, TransactionsRetrievalState.AccountDoesNotSupportFetchingTransactions)
-
- }
-
-
- private lateinit var mnitmSearchTransactions: MenuItem
-
- private lateinit var mnitmUpdateTransactions: MenuItem
-
-
- private var accountsForWhichNotAllTransactionsHaveBeenFetched = listOf()
-
- private var showTopFetchAllTransactionsView = true // TODO: read from db
-
-
- private val transactionAdapter: AccountTransactionAdapter
-
- protected var appliedTransactionsFilter = ""
-
-
- @Inject
- protected lateinit var presenter: BankingPresenter
-
-
- init {
- BankingComponent.component.inject(this)
-
- transactionAdapter = AccountTransactionAdapter(presenter)
- }
-
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
-
- setHasOptionsMenu(true)
- }
-
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
- val rootView = inflater.inflate(R.layout.fragment_home, container, false)
-
- val rcyvwAccountTransactions: RecyclerView = rootView.findViewById(R.id.rcyvwAccountTransactions)
- rcyvwAccountTransactions.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
- rcyvwAccountTransactions.adapter = transactionAdapter
- rcyvwAccountTransactions.addHorizontalItemDivider()
- rcyvwAccountTransactions.isNestedScrollingEnabled = false
-
- registerForContextMenu(rcyvwAccountTransactions) // this is actually bad, splits code as context menu is created in AccountTransactionAdapter
-
- rootView.btnTopFetchAllTransactions.setOnClickListener {
- fetchAllTransactions()
- }
-
- rootView.btnBottomFetchAllTransactions.setOnClickListener {
- fetchAllTransactions()
- }
-
- rootView.btnShowFetchAllTransactionsInfo.setOnClickListener { showFetchAllTransactionsInfo(rootView.btnShowFetchAllTransactionsInfo) }
-
- rootView.btnHideTopFetchAllTransactionsView.setOnClickListener {
- hideTopFetchAllTransactionsView()
- }
-
- rootView.btnRetrieveTransactions.setOnClickListener { fetchTransactions() }
- rootView.btnAddAccount.setOnClickListener { presenter.showAddAccountDialog() }
-
- return rootView
- }
-
- override fun onResume() {
- super.onResume()
-
- if (this::mnitmSearchTransactions.isInitialized) { // restore displayed transactions after onStop()
- updateMenuItemsStateAndTransactionsToDisplay()
- }
- }
-
-
- override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
- super.onCreateOptionsMenu(menu, inflater)
-
- mnitmSearchTransactions = menu.findItem(R.id.mnitmSearchTransactions)
- mnitmUpdateTransactions = menu.findItem(R.id.mnitmUpdateTransactions)
-
- initSearchView()
-
- initLogicAfterUiInitialized()
- }
-
- override fun onOptionsItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- R.id.mnitmUpdateTransactions -> {
- updateAccountsTransactions()
- return true
- }
- }
-
- return super.onOptionsItemSelected(item)
- }
-
- private fun initSearchView() {
- context?.asActivity()?.let { context ->
- (context.getSystemService(Context.SEARCH_SERVICE) as? SearchManager)?.let { searchManager ->
- (mnitmSearchTransactions.actionView as? SearchView)?.let { searchView ->
- searchView.setSearchableInfo(searchManager.getSearchableInfo(context.componentName))
-
- // if imeOptions aren't set like this searchView would take whole remaining screen when focused in landscape mode (see https://stackoverflow.com/questions/15296129/searchview-and-keyboard)
- val searchInput =
- searchView.findViewById(androidx.appcompat.R.id.search_src_text) as? EditText
- searchInput?.imeOptions = EditorInfo.IME_ACTION_SEARCH or EditorInfo.IME_FLAG_NO_EXTRACT_UI
-
- searchView.setOnQueryTextListener(searchAccountTransactionsTextListener)
- }
- }
- }
- }
-
-
- override fun onContextItemSelected(item: MenuItem): Boolean {
- when (item.itemId) {
- R.id.mnitmNewTransferToSameTransactionParty -> {
- newTransferToSameTransactionParty()
- return true
- }
- R.id.mnitmNewTransferWithSameData -> {
- newTransferWithSameData()
- return true
- }
- }
-
- return super.onContextItemSelected(item)
- }
-
-
- private fun initLogicAfterUiInitialized() {
- presenter.addBanksChangedListener { updateMenuItemsStateAndTransactionsToDisplay() } // on account addition or deletion may menu items' state changes
- presenter.addSelectedAccountsChangedListener { updateMenuItemsStateAndTransactionsToDisplay() }
-
- presenter.addRetrievedAccountTransactionsResponseListener { response ->
- handleGetTransactionsResponseOffUiThread(response)
- }
-
- updateMenuItemsStateAndTransactionsToDisplay()
- }
-
-
- private fun updateMenuItemsStateAndTransactionsToDisplay() {
- context?.asActivity()?.runOnUiThread {
- mnitmSearchTransactions.isVisible = presenter.doSelectedAccountsSupportRetrievingTransactions
- mnitmUpdateTransactions.isVisible = presenter.doSelectedAccountsSupportRetrievingTransactions
-
- updateTransactionsToDisplayOnUiThread()
- }
- }
-
- private fun updateAccountsTransactions() {
- mnitmUpdateTransactions.isEnabled = false
-
- val icon = mnitmUpdateTransactions.icon?.let { DrawableCompat.wrap(it) }
- icon?.let { DrawableCompat.setTint(it, ContextCompat.getColor(context!!, R.color.disabledColor)) }
-
- presenter.updateSelectedAccountsTransactionsAsync {
- context?.asActivity()?.runOnUiThread {
- mnitmUpdateTransactions.isEnabled = true
- icon?.let { DrawableCompat.setTintList(it, null) }
- }
- }
- }
-
- private fun handleGetTransactionsResponseOffUiThread(response: GetTransactionsResponse) {
- context?.asActivity()?.let { activity ->
- activity.runOnUiThread {
- handleGetTransactionsResponseOnUiThread(activity, response)
- }
- }
- }
-
- private fun handleGetTransactionsResponseOnUiThread(context: Context, response: GetTransactionsResponse) {
- response.retrievedData.forEach { retrievedData ->
- if (retrievedData.successfullyRetrievedData) {
- updateTransactionsToDisplayOnUiThread()
- }
- else if (response.userCancelledAction == false) { // if user cancelled entering TAN then don't show a error message
- AlertDialog.Builder(context)
- .setMessage(context.getString(R.string.fragment_home_could_not_retrieve_account_transactions,
- retrievedData.account.displayName, response.errorToShowToUser))
- .setPositiveButton(android.R.string.ok) { dialog, _ -> dialog.dismiss() }
- .show()
- }
- }
- }
-
-
- private fun newTransferToSameTransactionParty() {
- transactionAdapter.selectedTransaction?.let { selectedTransaction ->
- presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransactionWithoutAmountAndReference(selectedTransaction))
- }
- }
-
- private fun newTransferWithSameData() {
- transactionAdapter.selectedTransaction?.let { selectedTransaction ->
- presenter.showTransferMoneyDialog(TransferMoneyData.fromAccountTransaction(selectedTransaction))
- }
- }
-
-
- private val searchAccountTransactionsTextListener: SearchView.OnQueryTextListener = object : SearchView.OnQueryTextListener {
- override fun onQueryTextChange(query: String): Boolean {
- appliedTransactionsFilter = query
-
- updateTransactionsToDisplayOnUiThread()
-
- return true
- }
-
- override fun onQueryTextSubmit(query: String): Boolean {
- return true
- }
- }
-
-
- private fun updateTransactionsToDisplayOnUiThread() {
- setToolbarTitle()
-
- transactionAdapter.items = presenter.searchSelectedAccountTransactions(appliedTransactionsFilter)
-
- lytTransactionsSummary.setVisibility(presenter.doSelectedAccountsSupportRetrievingBalance)
-
- txtCountTransactions.text = context?.getString(R.string.fragment_home_count_transactions, transactionAdapter.items.size)
-
- val sumOfDisplayedTransactions = if (appliedTransactionsFilter.isBlank()) presenter.balanceOfSelectedAccounts
- else transactionAdapter.items.map { it.amount }.sum()
- txtTransactionsBalance.showAmount(presenter, sumOfDisplayedTransactions)
-
- setRecyclerViewAndNoTransactionsFetchedView()
-
- setFetchAllTransactionsView()
- }
-
- private fun setToolbarTitle() {
- // TODO: also set selected account's icon
-
- if (presenter.allBanks.isNotEmpty()) {
- activity?.findViewById(R.id.toolbar)?.let { toolbar ->
- toolbar.title = when (presenter.selectedAccountType) {
- SelectedAccountType.AllAccounts -> context?.getString(R.string.drawer_menu_all_bank_accounts_title)
- SelectedAccountType.SingleBank -> presenter.getSingleSelectedBank()?.displayName
- SelectedAccountType.SingleAccount -> presenter.getSingleSelectedAccount()?.displayName
- }
- }
- }
- }
-
- private fun setRecyclerViewAndNoTransactionsFetchedView() {
- val transactionsRetrievalState = presenter.selectedAccountsTransactionRetrievalState
- val haveTransactionsBeenRetrieved = transactionsRetrievalState == TransactionsRetrievalState.RetrievedTransactions
- val noAccountsAddedYet = presenter.allBanks.isEmpty()
-
- lytTransactionsTopBar.setVisibility(haveTransactionsBeenRetrieved)
- rcyvwAccountTransactions.setVisibility(haveTransactionsBeenRetrieved)
- lytNoTransactionsFetched.isGone = haveTransactionsBeenRetrieved || noAccountsAddedYet
- btnRetrieveTransactions.isGone = TransactionsCannotBeRetrievedStates.contains(transactionsRetrievalState)
- btnAddAccount.setVisibility(noAccountsAddedYet)
-
- val messageArgs = mutableListOf