diff --git a/build.gradle b/build.gradle index 839be3dd..be65aec7 100644 --- a/build.gradle +++ b/build.gradle @@ -58,6 +58,8 @@ ext { multiDexVersion = "2.0.1" + androidXCoreVersion = "1.3.1" + appCompatVersion = "1.1.0" constraintLayoutVersion = "1.1.3" @@ -66,6 +68,8 @@ ext { daggerVersion = "2.27" + roomVersion = "2.2.5" + /* JavaFX */ diff --git a/persistence/database/RoomBankingPersistence/build.gradle b/persistence/database/RoomBankingPersistence/build.gradle new file mode 100644 index 00000000..7e904f27 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/build.gradle @@ -0,0 +1,37 @@ +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" + +} \ No newline at end of file diff --git a/persistence/database/RoomBankingPersistence/consumer-rules.pro b/persistence/database/RoomBankingPersistence/consumer-rules.pro new file mode 100644 index 00000000..e69de29b diff --git a/persistence/database/RoomBankingPersistence/proguard-rules.pro b/persistence/database/RoomBankingPersistence/proguard-rules.pro new file mode 100644 index 00000000..481bb434 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/proguard-rules.pro @@ -0,0 +1,21 @@ +# 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 new file mode 100644 index 00000000..622eda74 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/AndroidManifest.xml @@ -0,0 +1,5 @@ + + + / + \ 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 new file mode 100644 index 00000000..0ce032c6 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/BankingDatabase.kt @@ -0,0 +1,25 @@ +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, TanProcedure::class, TanMedium::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 tanProcedureDao(): TanProcedureDao + + abstract fun tanMediumDao(): TanMediumDao + +} \ 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 new file mode 100644 index 00000000..78cd1523 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/RoomBankingPersistence.kt @@ -0,0 +1,134 @@ +package net.dankito.banking.persistence + +import android.content.Context +import androidx.room.Room +import net.dankito.banking.persistence.dao.saveOrUpdate +import 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.TypedCustomer +import net.dankito.banking.ui.model.tan.MobilePhoneTanMedium +import net.dankito.banking.ui.model.tan.TanGeneratorTanMedium +import net.dankito.banking.util.persistence.doSaveUrlToFile +import net.dankito.utils.multiplatform.File + + +open class RoomBankingPersistence(applicationContext: Context) : IBankingPersistence { + + protected val db = Room.databaseBuilder( + applicationContext, + BankingDatabase::class.java, "banking-database" + ).build() + + + override fun saveOrUpdateAccount(customer: TypedCustomer, allCustomers: List) { + (customer as? Bank)?.let { bank -> + bank.selectedTanProcedureId = bank.selectedTanProcedure?.technicalId + + db.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 } + db.bankAccountDao().saveOrUpdate(accounts) + + // TODO: in this way removed TAN procedures won't be deleted from DB and therefore still be visible to user + val tanProcedures = bank.supportedTanProcedures.filterIsInstance() + tanProcedures.forEach { it.bankId = bank.id } + db.tanProcedureDao().saveOrUpdate(tanProcedures) + + // TODO: in this way removed TAN procedures won't be deleted from DB and therefore still be visible to user + val tanMedia = bank.tanMedia.map { map(bank, it) } + db.tanMediumDao().saveOrUpdate(tanMedia) + } + } + + override fun deleteAccount(customer: TypedCustomer, allCustomers: List) { + (customer as? Bank)?.let { bank -> + db.accountTransactionDao().delete(bank.accounts.flatMap { it.bookedTransactions }.filterIsInstance()) + + db.bankAccountDao().delete(bank.accounts.filterIsInstance()) + + db.tanProcedureDao().delete(bank.supportedTanProcedures.filterIsInstance()) + db.tanMediumDao().delete(bank.tanMedia.filterIsInstance()) + + db.bankDao().delete(bank) + } + } + + override fun readPersistedAccounts(): List { + val banks = db.bankDao().getAll() + + val accounts = db.bankAccountDao().getAll() + + val transactions = db.accountTransactionDao().getAll() + + val tanProcedures = db.tanProcedureDao().getAll() + + val tanMedia = db.tanMediumDao().getAll() + + banks.forEach { bank -> + bank.accounts = accounts.filter { it.bankId == bank.id } + + bank.accounts.filterIsInstance().forEach { account -> + account.customer = bank + + account.bookedTransactions = transactions.filter { it.bankAccountId == account.id } + + account.bookedTransactions.filterIsInstance().forEach { transaction -> + transaction.bankAccount = account + } + } + + bank.supportedTanProcedures = tanProcedures.filter { it.bankId == bank.id } + bank.selectedTanProcedure = bank.supportedTanProcedures.firstOrNull { it.technicalId == bank.selectedTanProcedureId } + + bank.tanMedia = tanMedia.filter { it.bankId == bank.id }.map { map(it) } + } + + return banks + } + + override fun saveOrUpdateAccountTransactions(bankAccount: TypedBankAccount, transactions: List) { + val accountId = (bankAccount as? BankAccount)?.id ?: bankAccount.technicalId.toLong() + + val mappedTransactions = transactions.filterIsInstance() + + mappedTransactions.forEach { it.bankAccountId = accountId } + + db.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 saveUrlToFile(url: String, file: File) { + doSaveUrlToFile(url, file) + } + +} \ 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 new file mode 100644 index 00000000..8536262c --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/TypeConverters.kt @@ -0,0 +1,91 @@ +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.TanProcedureType +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 fromTanProcedureType(value: TanProcedureType): Int { + return value.ordinal + } + + @TypeConverter + fun toTanProcedureType(value: Int): TanProcedureType { + return TanProcedureType.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 new file mode 100644 index 00000000..3aeab1b8 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/AccountTransactionDao.kt @@ -0,0 +1,14 @@ +package net.dankito.banking.persistence.dao + +import androidx.room.Dao +import androidx.room.Query +import net.dankito.banking.persistence.model.AccountTransaction + + +@Dao +interface AccountTransactionDao : BaseDao { + + @Query("SELECT * FROM AccountTransaction") + 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 new file mode 100644 index 00000000..3a4e2af6 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankAccountDao.kt @@ -0,0 +1,14 @@ +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 new file mode 100644 index 00000000..ed23ede9 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BankDao.kt @@ -0,0 +1,13 @@ +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 new file mode 100644 index 00000000..794362cb --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDao.kt @@ -0,0 +1,35 @@ +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 new file mode 100644 index 00000000..28dc3c97 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/BaseDaoExtensions.kt @@ -0,0 +1,58 @@ +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 new file mode 100644 index 00000000..676c48b0 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanMediumDao.kt @@ -0,0 +1,14 @@ +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/TanProcedureDao.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanProcedureDao.kt new file mode 100644 index 00000000..9152264e --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/dao/TanProcedureDao.kt @@ -0,0 +1,14 @@ +package net.dankito.banking.persistence.dao + +import androidx.room.Dao +import androidx.room.Query +import net.dankito.banking.persistence.model.TanProcedure + + +@Dao +interface TanProcedureDao : BaseDao { + + @Query("SELECT * FROM TanProcedure") + 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 new file mode 100644 index 00000000..3006a714 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/AccountTransaction.kt @@ -0,0 +1,94 @@ +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 bankAccount: BankAccount, + + override var amount: BigDecimal, + override var currency: String, + override var unparsedUsage: 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 sepaUsage: String?, + override var deviantOriginator: String?, + override var deviantRecipient: String?, + override var usageWithNoSpecialType: 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(bankAccount: BankAccount, otherPartyName: String?, unparsedUsage: String, amount: BigDecimal, valueDate: Date, bookingText: String?) + : this(bankAccount, amount, "EUR", unparsedUsage, valueDate, + otherPartyName, null, null, bookingText, valueDate) + + + constructor(bankAccount: BankAccount, amount: BigDecimal, currency: String, unparsedUsage: String, bookingDate: Date, + otherPartyName: String?, otherPartyBankCode: String?, otherPartyAccountId: String?, + bookingText: String?, valueDate: Date) + : this(bankAccount, amount, currency, unparsedUsage, 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 bankAccountId: 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/Bank.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt new file mode 100644 index 00000000..471020a0 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/Bank.kt @@ -0,0 +1,55 @@ +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.TypedCustomer +import net.dankito.banking.ui.model.tan.TanMedium +import net.dankito.banking.ui.model.tan.TanProcedure + + +@Entity +open class Bank( + override var bankCode: String, + override var customerId: 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 = customerId, + override var iconUrl: String? = null, + + @Ignore + override var accounts: List = listOf(), + + @Ignore + override var supportedTanProcedures: List = listOf(), + @Ignore + override var selectedTanProcedure: TanProcedure? = null, + @Ignore + override var tanMedia: List = listOf(), + + @PrimaryKey(autoGenerate = true) + open var id: Long = BaseDao.IdNotSet, + + override var technicalId: String = id.toString(), + + override var userSetDisplayName: String? = null, + override var displayIndex: Int = 0 +) : TypedCustomer { + + internal constructor() : this("", "", "", "", "", "", "") // for object deserializers + + + open var selectedTanProcedureId: String? = null + + + 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 new file mode 100644 index 00000000..41cf56a6 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/BankAccount.kt @@ -0,0 +1,71 @@ +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 customer: TypedCustomer, + override var identifier: String, + override var accountHolderName: String, + override var iban: String?, + override var subAccountNumber: String?, + override var customerId: String, + override var balance: BigDecimal = BigDecimal.Zero, + override var currency: String = "EUR", + override var type: BankAccountType = BankAccountType.Girokonto, + override var productName: String? = null, + override var accountLimit: String? = null, + override var lastRetrievedTransactionsTimestamp: Date? = null, + + override var supportsRetrievingAccountTransactions: Boolean = false, + override var supportsRetrievingBalance: Boolean = false, + override var supportsTransferringMoney: Boolean = false, + override var supportsInstantPaymentMoneyTransfer: 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(customer: TypedCustomer, productName: String?, identifier: String) : this(customer, productName, identifier, BankAccountType.Girokonto) + + constructor(customer: TypedCustomer, productName: String?, identifier: String, type: BankAccountType = BankAccountType.Girokonto, balance: BigDecimal = BigDecimal.Zero) + : this(customer, 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 haveAllTransactionsBeenFetched: Boolean = false + + + override var userSetDisplayName: String? = null + + override var displayIndex: Int = 0 + + + 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 new file mode 100644 index 00000000..db8579dc --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/RoomModelCreator.kt @@ -0,0 +1,73 @@ +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.TypedCustomer +import net.dankito.banking.ui.model.mapper.IModelCreator +import net.dankito.banking.ui.model.tan.AllowedTanFormat +import net.dankito.banking.ui.model.tan.TanProcedureType +import net.dankito.utils.multiplatform.BigDecimal +import net.dankito.utils.multiplatform.Date + + +open class RoomModelCreator : IModelCreator { + + override fun createCustomer(bankCode: String, customerId: String, password: String, finTsServerAddress: String, bankName: String, + bic: String, customerName: String, userId: String, iconUrl: String?): TypedCustomer { + + return Bank(bankCode, customerId, password, finTsServerAddress, bankName, bic, customerName, userId, iconUrl) + } + + override fun createBankAccount(customer: TypedCustomer, productName: String?, identifier: String): TypedBankAccount { + return BankAccount(customer, productName, identifier) + } + + override fun createTransaction( + bankAccount: TypedBankAccount, + amount: BigDecimal, + currency: String, + unparsedUsage: 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?, + sepaUsage: String?, + deviantOriginator: String?, + deviantRecipient: String?, + usageWithNoSpecialType: String?, + primaNotaNumber: String?, + textKeySupplement: String?, + currencyType: String?, + bookingKey: String, + referenceForTheAccountOwner: String, + referenceOfTheAccountServicingInstitution: String?, + supplementaryDetails: String?, + transactionReferenceNumber: String, + relatedReferenceNumber: String? + ): IAccountTransaction { + return AccountTransaction(bankAccount as BankAccount, amount, currency, unparsedUsage, bookingDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, + bookingText, valueDate, statementNumber, sequenceNumber, openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, + creditorIdentifier, originatorsIdentificationCode, compensationAmount, originalAmount, sepaUsage, deviantOriginator, deviantRecipient, + usageWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner, + referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber) + } + + + override fun createTanProcedure(displayName: String, type: TanProcedureType, bankInternalProcedureCode: String, maxTanInputLength: Int?, allowedTanFormat: AllowedTanFormat): net.dankito.banking.ui.model.tan.TanProcedure { + return TanProcedure(displayName, type, bankInternalProcedureCode, 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 new file mode 100644 index 00000000..9be6843b --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMedium.kt @@ -0,0 +1,24 @@ +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 new file mode 100644 index 00000000..719273a4 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanMediumType.kt @@ -0,0 +1,12 @@ +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/TanProcedure.kt b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanProcedure.kt new file mode 100644 index 00000000..7a6a0424 --- /dev/null +++ b/persistence/database/RoomBankingPersistence/src/main/java/net/dankito/banking/persistence/model/TanProcedure.kt @@ -0,0 +1,29 @@ +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.TanProcedure +import net.dankito.banking.ui.model.tan.TanProcedureType + + +@Entity +open class TanProcedure( + displayName: String, + type: TanProcedureType, + bankInternalProcedureCode: String, + maxTanInputLength: Int? = null, + allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric +) : TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength, allowedTanFormat) { + + internal constructor() : this("", TanProcedureType.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/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/BankingPersistenceJson.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/BankingPersistenceJson.kt index 32769af6..eb9bed57 100644 --- 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 @@ -4,8 +4,7 @@ import net.dankito.banking.persistence.model.CustomerEntity import net.dankito.banking.ui.model.* import net.dankito.utils.multiplatform.File import net.dankito.banking.util.ISerializer -import java.io.FileOutputStream -import java.net.URL +import net.dankito.banking.util.persistence.doSaveUrlToFile open class BankingPersistenceJson( @@ -43,11 +42,7 @@ open class BankingPersistenceJson( override fun saveUrlToFile(url: String, file: File) { - URL(url).openConnection().getInputStream().buffered().use { iconInputStream -> - FileOutputStream(file).use { fileOutputStream -> - iconInputStream.copyTo(fileOutputStream) - } - } + doSaveUrlToFile(url, file) } } \ 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 index 058cc61e..0b0d55b8 100644 --- 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 @@ -70,4 +70,8 @@ open class AccountTransactionEntity( 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 index 56d24334..6ad2e3bd 100644 --- 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 @@ -38,4 +38,9 @@ open class BankAccountEntity( internal constructor() : this(CustomerEntity(), "", "", 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/CustomerEntity.kt b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/CustomerEntity.kt index 9aa46cc8..2bda1e34 100644 --- a/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/CustomerEntity.kt +++ b/persistence/json/BankingPersistenceJson/src/main/kotlin/net/dankito/banking/persistence/model/CustomerEntity.kt @@ -30,4 +30,9 @@ open class CustomerEntity( internal constructor() : this("", "", "", "", "", "", "") // for object deserializers + + override fun toString(): String { + return stringRepresentation + } + } \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 12207d17..c88874f0 100644 --- a/settings.gradle +++ b/settings.gradle @@ -18,6 +18,7 @@ include ':hbci4jBankingClient' include ':BankingPersistenceJson' include ':LuceneBankingPersistence' +include ':RoomBankingPersistence' include ':BankingAndroidApp' @@ -41,6 +42,7 @@ project(':BankingUiNativeIntegration').projectDir = "$rootDir/ui/BankingUiNative 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 diff --git a/ui/BankingAndroidApp/build.gradle b/ui/BankingAndroidApp/build.gradle index 29f517d5..280f05ce 100644 --- a/ui/BankingAndroidApp/build.gradle +++ b/ui/BankingAndroidApp/build.gradle @@ -91,6 +91,7 @@ dependencies { implementation project(':BankingPersistenceJson') implementation project(':LuceneBankingPersistence') + implementation project(':RoomBankingPersistence') implementation "net.dankito.text.extraction:itext2-text-extractor:$textExtractorVersion" 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 index 5468c0a8..68bf6a36 100644 --- 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 @@ -9,7 +9,6 @@ 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.persistence.LuceneBankingPersistence import net.dankito.banking.search.IRemitteeSearcher import net.dankito.banking.search.LuceneRemitteeSearcher import net.dankito.banking.ui.IBankingClientCreator @@ -17,7 +16,8 @@ import net.dankito.banking.ui.IRouter import net.dankito.banking.ui.presenter.BankingPresenter import net.dankito.banking.bankfinder.IBankFinder import net.dankito.banking.bankfinder.LuceneBankFinder -import net.dankito.banking.persistence.mapper.EntitiesModelCreator +import net.dankito.banking.persistence.RoomBankingPersistence +import net.dankito.banking.persistence.model.RoomModelCreator import net.dankito.banking.ui.model.mapper.IModelCreator import net.dankito.utils.multiplatform.toFile import net.dankito.banking.util.* @@ -115,8 +115,8 @@ class BankingModule(private val applicationContext: Context) { @Provides @Singleton - fun provideBankingPersistence(@Named(IndexFolderKey) indexFolder: File, @Named(DatabaseFolderKey) databaseFolder: File, serializer: ISerializer) : IBankingPersistence { - return LuceneBankingPersistence(indexFolder, databaseFolder, serializer) + fun provideBankingPersistence() : IBankingPersistence { + return RoomBankingPersistence(applicationContext) } @Provides @@ -169,7 +169,7 @@ class BankingModule(private val applicationContext: Context) { @Provides @Singleton fun provideModelCreator() : IModelCreator { - return EntitiesModelCreator() + return RoomModelCreator() } @Provides diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/AccountTransaction.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/AccountTransaction.kt index 9fb41cc0..1b188117 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/AccountTransaction.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/AccountTransaction.kt @@ -77,7 +77,7 @@ open class AccountTransaction( override fun toString(): String { - return "${DateFormatter(DateFormatStyle.Medium).format(valueDate)} $amount $otherPartyName: $usage" + return stringRepresentation } } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt index 3b3df0a0..27db5f39 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/BankAccount.kt @@ -49,7 +49,7 @@ open class BankAccount @JvmOverloads constructor( override fun toString(): String { - return "$accountHolderName ($identifier)" + return stringRepresentation } } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/Customer.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/Customer.kt index bf71546f..a6441b9d 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/Customer.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/Customer.kt @@ -43,7 +43,7 @@ open class Customer( override fun toString(): String { - return "$bankName $customerId" + return stringRepresentation } } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IAccountTransaction.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IAccountTransaction.kt index a2594e52..daf92551 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IAccountTransaction.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IAccountTransaction.kt @@ -2,6 +2,7 @@ package net.dankito.banking.ui.model import net.dankito.utils.multiplatform.BigDecimal import net.dankito.utils.multiplatform.Date +import net.dankito.utils.multiplatform.DateFormatStyle import net.dankito.utils.multiplatform.DateFormatter @@ -106,5 +107,8 @@ interface IAccountTransaction { result = 31 * result + valueDate.hashCode() return result } + + val stringRepresentation: String + get() = "${DateFormatter(DateFormatStyle.Medium).format(valueDate)} $amount $otherPartyName: $usage" } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt index d1ffa9f4..63ab391b 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/IBankAccount.kt @@ -52,5 +52,9 @@ interface IBankAccount : OrderedDisplayable { this.unbookedTransactions = uniqueUnbookedTransactions.toList() } + + + val stringRepresentation: String + get() = "$accountHolderName ($identifier)" } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/ICustomer.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/ICustomer.kt index 29ed0a76..475d9c6f 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/ICustomer.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/ICustomer.kt @@ -53,4 +53,8 @@ interface ICustomer, TAccountTransac val tanMediaSorted: List get() = tanMedia.sortedByDescending { it.status == TanMediumStatus.Used } + + val stringRepresentation: String + get() = "$bankName $customerId" + } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/mapper/IModelCreator.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/mapper/IModelCreator.kt index 3de107cb..ffe9e37d 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/mapper/IModelCreator.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/mapper/IModelCreator.kt @@ -1,6 +1,7 @@ package net.dankito.banking.ui.model.mapper import net.dankito.banking.ui.model.* +import net.dankito.banking.ui.model.tan.* import net.dankito.utils.multiplatform.BigDecimal import net.dankito.utils.multiplatform.Date @@ -54,4 +55,22 @@ interface IModelCreator { relatedReferenceNumber: String? ) : IAccountTransaction + + fun createTanProcedure(displayName: String, type: TanProcedureType, bankInternalProcedureCode: String, + maxTanInputLength: Int? = null, allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric): TanProcedure { + return TanProcedure(displayName, type, bankInternalProcedureCode, maxTanInputLength) + } + + fun createTanMedium(displayName: String, status: TanMediumStatus): TanMedium { + return TanMedium(displayName, status) + } + + fun createTanGeneratorTanMedium(displayName: String, status: TanMediumStatus, cardNumber: String): TanGeneratorTanMedium { + return TanGeneratorTanMedium(displayName, status, cardNumber) + } + + fun createMobilePhoneTanMedium(displayName: String, status: TanMediumStatus, phoneNumber: String?): MobilePhoneTanMedium { + return MobilePhoneTanMedium(displayName, status, phoneNumber) + } + } \ No newline at end of file diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanMedium.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanMedium.kt index ee0c8c01..9225f6e7 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanMedium.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanMedium.kt @@ -6,7 +6,7 @@ import net.dankito.utils.multiplatform.UUID open class TanMedium( override val displayName: String, - val status: TanMediumStatus + open val status: TanMediumStatus ) : Displayable { diff --git a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt index bcd27265..326cac21 100644 --- a/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt +++ b/ui/BankingUiCommon/src/commonMain/kotlin/net/dankito/banking/ui/model/tan/TanProcedure.kt @@ -2,21 +2,23 @@ package net.dankito.banking.ui.model.tan import net.dankito.banking.ui.model.Displayable import net.dankito.utils.multiplatform.UUID +import kotlin.jvm.Transient open class TanProcedure( override val displayName: String, - val type: TanProcedureType, - val bankInternalProcedureCode: String, - val maxTanInputLength: Int? = null, - val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric + open val type: TanProcedureType, + open val bankInternalProcedureCode: String, + open val maxTanInputLength: Int? = null, + open val allowedTanFormat: AllowedTanFormat = AllowedTanFormat.Alphanumeric ) : Displayable { internal constructor() : this("", TanProcedureType.EnterTan, "") // for object deserializers - val isNumericTan: Boolean = allowedTanFormat == AllowedTanFormat.Numeric + @Transient + open val isNumericTan: Boolean = allowedTanFormat == AllowedTanFormat.Numeric open var technicalId: String = UUID.random() diff --git a/ui/BankingUiCommon/src/jvmMain/kotlin/net/dankito/banking/util/persistence/IBankingPersistenceExtensions.kt b/ui/BankingUiCommon/src/jvmMain/kotlin/net/dankito/banking/util/persistence/IBankingPersistenceExtensions.kt new file mode 100644 index 00000000..2529c6d2 --- /dev/null +++ b/ui/BankingUiCommon/src/jvmMain/kotlin/net/dankito/banking/util/persistence/IBankingPersistenceExtensions.kt @@ -0,0 +1,15 @@ +package net.dankito.banking.util.persistence + +import net.dankito.banking.persistence.IBankingPersistence +import net.dankito.utils.multiplatform.File +import java.io.FileOutputStream +import java.net.URL + + +fun IBankingPersistence.doSaveUrlToFile(url: String, file: File) { + URL(url).openConnection().getInputStream().buffered().use { iconInputStream -> + FileOutputStream(file).use { fileOutputStream -> + iconInputStream.copyTo(fileOutputStream) + } + } +} \ No newline at end of file diff --git a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt index 75cec669..d8017c59 100644 --- a/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt +++ b/ui/fints4kBankingClient/src/commonMain/kotlin/net/dankito/banking/mapper/fints4kModelMapper.kt @@ -253,7 +253,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) { account.selectedTanProcedure = null } - account.tanMedia = mapTanMediums(bank.tanMedia) + account.tanMedia = mapTanMedia(bank.tanMedia) } @@ -262,7 +262,7 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) { } open fun mapTanProcedure(tanProcedure: net.dankito.banking.fints.model.TanProcedure): TanProcedure { - return TanProcedure( + return modelCreator.createTanProcedure( tanProcedure.displayName, mapTanProcedureType(tanProcedure.type), tanProcedure.securityFunction.code, @@ -306,40 +306,34 @@ open class fints4kModelMapper(protected val modelCreator: IModelCreator) { } - open fun mapTanMediums(tanMediums: List): List { + open fun mapTanMedia(tanMediums: List): List { return tanMediums.map { mapTanMedium(it) } } open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): TanMedium { + val displayName = getDisplayNameForTanMedium(tanMedium) + val status = mapTanMediumStatus(tanMedium) + // TODO: irgendwas ging hier schief if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium) { - return mapTanMedium(tanMedium) + return mapTanMedium(tanMedium, displayName, status) } if (tanMedium is net.dankito.banking.fints.messages.datenelemente.implementierte.tan.MobilePhoneTanMedium) { - return mapTanMedium(tanMedium) + return modelCreator.createMobilePhoneTanMedium(displayName, status, tanMedium.phoneNumber ?: tanMedium.concealedPhoneNumber) } - return TanMedium( - getDisplayNameForTanMedium(tanMedium), - mapTanMediumStatus(tanMedium) - ) + return modelCreator.createTanMedium(displayName, status) } open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium): TanGeneratorTanMedium { - return TanGeneratorTanMedium( - getDisplayNameForTanMedium(tanMedium), - mapTanMediumStatus(tanMedium), - tanMedium.cardNumber - ) + return mapTanMedium(tanMedium, getDisplayNameForTanMedium(tanMedium), mapTanMediumStatus(tanMedium)) } - open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.MobilePhoneTanMedium): MobilePhoneTanMedium { - return MobilePhoneTanMedium( - getDisplayNameForTanMedium(tanMedium), - mapTanMediumStatus(tanMedium), - tanMedium.phoneNumber ?: tanMedium.concealedPhoneNumber - ) + protected open fun mapTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanGeneratorTanMedium, + displayName: String, status: TanMediumStatus): TanGeneratorTanMedium { + + return modelCreator.createTanGeneratorTanMedium(displayName, status, tanMedium.cardNumber) } protected open fun getDisplayNameForTanMedium(tanMedium: net.dankito.banking.fints.messages.datenelemente.implementierte.tan.TanMedium): String { diff --git a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt index 314177aa..65548fa8 100644 --- a/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt +++ b/ui/hbci4jBankingClient/src/main/kotlin/net/dankito/banking/util/hbci4jModelMapper.kt @@ -106,15 +106,15 @@ open class hbci4jModelMapper( // TODO: implement all TAN procedures displayNameLowerCase.contains("chiptan") -> { if (displayNameLowerCase.contains("qr")) { - net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanQrCode, code) + modelCreator.createTanProcedure(displayName, TanProcedureType.ChipTanQrCode, code) } else { - net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.ChipTanFlickercode, code) + modelCreator.createTanProcedure(displayName, TanProcedureType.ChipTanFlickercode, code) } } - displayNameLowerCase.contains("sms") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.SmsTan, code) - displayNameLowerCase.contains("push") -> net.dankito.banking.ui.model.tan.TanProcedure(displayName, TanProcedureType.AppTan, code) + displayNameLowerCase.contains("sms") -> modelCreator.createTanProcedure(displayName, TanProcedureType.SmsTan, code) + displayNameLowerCase.contains("push") -> modelCreator.createTanProcedure(displayName, TanProcedureType.AppTan, code) // we filter out iTAN and Einschritt-Verfahren as they are not permitted anymore according to PSD2 else -> null