Compare commits
18 Commits
f5a93bdddd
...
b5dbf92b9b
Author | SHA1 | Date |
---|---|---|
dankito | b5dbf92b9b | |
dankito | d549b96e7b | |
dankito | b384f6bc00 | |
dankito | 5d0669c5fe | |
dankito | 6a8b913bc4 | |
dankito | 7d9a2695a9 | |
dankito | 7ce76d73ea | |
dankito | 1f19da85f3 | |
dankito | 8707c5e3d7 | |
dankito | ff8bf80f6d | |
dankito | df093d0cd3 | |
dankito | 08e3096892 | |
dankito | 931d41d610 | |
dankito | fc0d2642e5 | |
dankito | 7712102af2 | |
dankito | 6564a9d33d | |
dankito | 0f89314ba3 | |
dankito | 4fa7adeeb1 |
|
@ -21,5 +21,7 @@ xcuserdata
|
|||
!*.xcodeproj/project.xcworkspace/
|
||||
!*.xcworkspace/contents.xcworkspacedata
|
||||
**/xcshareddata/WorkspaceSettings.xcsettings
|
||||
**/*.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
|
||||
|
||||
composeApp/data/
|
||||
BankingPersistence/data/
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlinMultiplatform)
|
||||
|
||||
alias(libs.plugins.androidLibrary)
|
||||
|
||||
alias(libs.plugins.sqldelight)
|
||||
}
|
||||
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(11)
|
||||
|
||||
jvm()
|
||||
|
||||
js {
|
||||
moduleName = "BankingPersistence"
|
||||
binaries.executable()
|
||||
|
||||
browser()
|
||||
}
|
||||
|
||||
androidTarget {
|
||||
|
||||
}
|
||||
|
||||
|
||||
listOf(
|
||||
iosX64(),
|
||||
iosArm64(),
|
||||
iosSimulatorArm64()
|
||||
).forEach { iosTarget ->
|
||||
iosTarget.binaries.framework {
|
||||
baseName = "BankingPersistence"
|
||||
isStatic = true
|
||||
}
|
||||
}
|
||||
|
||||
applyDefaultHierarchyTemplate()
|
||||
|
||||
|
||||
sourceSets {
|
||||
commonMain.dependencies {
|
||||
implementation(libs.banking.client.model)
|
||||
implementation(libs.kotlinx.datetime)
|
||||
|
||||
implementation(libs.sqldelight.runtime)
|
||||
implementation(libs.sqldelight.coroutines.extensions)
|
||||
implementation(libs.sqldelight.paging.extensions)
|
||||
|
||||
implementation(libs.klf)
|
||||
}
|
||||
|
||||
commonTest.dependencies {
|
||||
implementation(libs.kotlin.test)
|
||||
|
||||
implementation(libs.coroutines.test)
|
||||
}
|
||||
|
||||
jvmMain.dependencies {
|
||||
implementation(libs.sqldelight.sqlite.driver)
|
||||
}
|
||||
|
||||
jvmTest.dependencies {
|
||||
implementation(libs.kotlin.test.junit)
|
||||
}
|
||||
|
||||
androidMain.dependencies {
|
||||
implementation(libs.sqldelight.android.driver)
|
||||
}
|
||||
|
||||
iosMain.dependencies {
|
||||
implementation(libs.sqldelight.native.driver)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sqldelight {
|
||||
databases {
|
||||
create("BankmeisterDb") {
|
||||
packageName.set("net.codinux.banking.persistence")
|
||||
generateAsync = true
|
||||
|
||||
schemaOutputDirectory = file("src/commonMain/sqldelight/databases")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
android {
|
||||
namespace = "net.codinux.banking.persistence"
|
||||
compileSdk = libs.versions.android.compileSdk.get().toInt()
|
||||
|
||||
// sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
|
||||
defaultConfig {
|
||||
minSdk = libs.versions.android.minSdk.get().toInt()
|
||||
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
consumerProguardFiles("consumer-rules.pro")
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
isMinifyEnabled = false
|
||||
// proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
|
||||
}
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package net.codinux.banking.persistence
|
||||
|
||||
import android.content.Context
|
||||
|
||||
object AndroidContext {
|
||||
lateinit var applicationContext: Context
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package net.codinux.banking.persistence
|
||||
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.db.QueryResult
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.db.SqlSchema
|
||||
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
|
||||
|
||||
actual fun createSqlDriverDriver(dbName: String, schema: SqlSchema<QueryResult.AsyncValue<Unit>>, version: Long): SqlDriver =
|
||||
AndroidSqliteDriver(schema.synchronous(), AndroidContext.applicationContext, dbName)
|
|
@ -1,15 +1,15 @@
|
|||
package net.codinux.banking.dataaccess
|
||||
package net.codinux.banking.persistence
|
||||
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.BankAccess
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.HoldingEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.UiSettingsEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.settings.UiSettings
|
||||
|
||||
interface BankingRepository {
|
||||
|
||||
|
@ -17,9 +17,9 @@ interface BankingRepository {
|
|||
|
||||
suspend fun saveAppSettings(settings: AppSettings)
|
||||
|
||||
fun getUiSettings(settings: UiSettings)
|
||||
fun getUiSettings(): UiSettingsEntity?
|
||||
|
||||
suspend fun saveUiSettings(settings: UiSettings)
|
||||
suspend fun saveUiSettings(settings: UiSettingsEntity)
|
||||
|
||||
|
||||
fun getAllBanks(): List<BankAccessEntity>
|
|
@ -1,15 +1,16 @@
|
|||
package net.codinux.banking.dataaccess
|
||||
package net.codinux.banking.persistence
|
||||
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.BankAccess
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.HoldingEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.UiSettingsEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.settings.UiSettings
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
class InMemoryBankingRepository(
|
||||
banks: Collection<BankAccess> = emptyList(),
|
||||
|
@ -23,7 +24,7 @@ class InMemoryBankingRepository(
|
|||
|
||||
private val transactions = transactions.map { map(it) }.toMutableList()
|
||||
|
||||
private lateinit var uiSettings: UiSettings
|
||||
private var uiSettings: UiSettingsEntity = UiSettingsEntity(true, TransactionsGrouping.Month, true, true, true)
|
||||
|
||||
|
||||
override fun getAppSettings(): AppSettings? = appSettings
|
||||
|
@ -32,11 +33,9 @@ class InMemoryBankingRepository(
|
|||
this.appSettings = settings
|
||||
}
|
||||
|
||||
override fun getUiSettings(settings: UiSettings) {
|
||||
this.uiSettings = settings
|
||||
}
|
||||
override fun getUiSettings() = this.uiSettings
|
||||
|
||||
override suspend fun saveUiSettings(settings: UiSettings) {
|
||||
override suspend fun saveUiSettings(settings: UiSettingsEntity) {
|
||||
this.uiSettings = settings
|
||||
}
|
||||
|
|
@ -1,25 +1,45 @@
|
|||
package net.codinux.banking.dataaccess
|
||||
package net.codinux.banking.persistence
|
||||
|
||||
import app.cash.sqldelight.db.QueryResult
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.db.SqlSchema
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.*
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.client.model.BankAccess
|
||||
import net.codinux.banking.client.model.BankAccount
|
||||
import net.codinux.banking.client.model.BankAccountFeatures
|
||||
import net.codinux.banking.client.model.BankAccountType
|
||||
import net.codinux.banking.client.model.BankingGroup
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
import net.codinux.banking.dataaccess.entities.*
|
||||
import net.codinux.banking.client.model.tan.AllowedTanFormat
|
||||
import net.codinux.banking.client.model.tan.MobilePhoneTanMedium
|
||||
import net.codinux.banking.client.model.tan.TanGeneratorTanMedium
|
||||
import net.codinux.banking.client.model.tan.TanMedium
|
||||
import net.codinux.banking.client.model.tan.TanMediumStatus
|
||||
import net.codinux.banking.client.model.tan.TanMediumType
|
||||
import net.codinux.banking.client.model.tan.TanMethod
|
||||
import net.codinux.banking.client.model.tan.TanMethodType
|
||||
import net.codinux.banking.persistence.entities.*
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.AppAuthenticationMethod
|
||||
import net.codinux.banking.ui.model.settings.AppSettings
|
||||
import net.codinux.banking.ui.settings.UiSettings
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
import net.codinux.log.logger
|
||||
import kotlin.enums.EnumEntries
|
||||
import kotlin.js.JsName
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
open class SqliteBankingRepository(
|
||||
sqlDriver: SqlDriver
|
||||
) : BankingRepository {
|
||||
|
||||
expect fun createSqlDriverDriver(dbName: String, schema: SqlSchema<QueryResult.AsyncValue<Unit>>, version: Long): SqlDriver
|
||||
|
||||
|
||||
open class SqliteBankingRepository : BankingRepository {
|
||||
|
||||
private val schema = BankmeisterDb.Schema
|
||||
|
||||
private val sqlDriver = createSqlDriverDriver("Bankmeister.db", schema, 1L)
|
||||
|
||||
private val database = BankmeisterDb(sqlDriver)
|
||||
|
||||
|
@ -52,18 +72,20 @@ open class SqliteBankingRepository(
|
|||
}
|
||||
|
||||
|
||||
override fun getUiSettings(settings: UiSettings) {
|
||||
settingsQueries.getUiSettings { _, transactionsGrouping, showBalance, showBankIcons, showColoredAmounts, showTransactionsInAlternatingColors ->
|
||||
settings.transactionsGrouping.value = mapToEnum(transactionsGrouping, TransactionsGrouping.entries)
|
||||
settings.showBalance.value = showBalance
|
||||
settings.showBankIcons.value = showBankIcons
|
||||
settings.showColoredAmounts.value = showColoredAmounts
|
||||
settings.showTransactionsInAlternatingColors.value = showTransactionsInAlternatingColors
|
||||
override fun getUiSettings(): UiSettingsEntity? {
|
||||
return settingsQueries.getUiSettings { _, transactionsGrouping, showBalance, showBankIcons, showColoredAmounts, showTransactionsInAlternatingColors ->
|
||||
UiSettingsEntity(
|
||||
showBalance,
|
||||
mapToEnum(transactionsGrouping, TransactionsGrouping.entries),
|
||||
showTransactionsInAlternatingColors,
|
||||
showBankIcons,
|
||||
showColoredAmounts
|
||||
)
|
||||
}.executeAsOneOrNull()
|
||||
}
|
||||
|
||||
override suspend fun saveUiSettings(settings: UiSettings) {
|
||||
settingsQueries.upsertUiSettings(mapEnum(settings.transactionsGrouping.value), settings.showBalance.value, settings.showBankIcons.value, settings.showColoredAmounts.value, settings.showTransactionsInAlternatingColors.value)
|
||||
override suspend fun saveUiSettings(settings: UiSettingsEntity) {
|
||||
settingsQueries.upsertUiSettings(mapEnum(settings.transactionsGrouping), settings.showBalance, settings.showBankIcons, settings.showColoredAmounts, settings.showTransactionsInAlternatingColors)
|
||||
}
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
|
@ -1,8 +1,7 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import net.codinux.banking.client.model.BankAccess
|
||||
import net.codinux.banking.client.model.BankingGroup
|
||||
import net.codinux.banking.client.model.tan.TanMedium
|
||||
|
||||
class BankAccessEntity(
|
||||
val id: Long,
|
|
@ -1,4 +1,4 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
|
@ -1,4 +1,4 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import kotlinx.datetime.Instant
|
||||
import kotlinx.datetime.LocalDate
|
|
@ -1,4 +1,4 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import net.codinux.banking.client.model.tan.*
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package net.codinux.banking.dataaccess.entities
|
||||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import net.codinux.banking.client.model.tan.AllowedTanFormat
|
||||
import net.codinux.banking.client.model.tan.TanMethod
|
|
@ -0,0 +1,17 @@
|
|||
package net.codinux.banking.persistence.entities
|
||||
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
class UiSettingsEntity(
|
||||
|
||||
val showBalance: Boolean,
|
||||
|
||||
val transactionsGrouping: TransactionsGrouping,
|
||||
|
||||
val showTransactionsInAlternatingColors: Boolean,
|
||||
|
||||
val showBankIcons: Boolean,
|
||||
|
||||
val showColoredAmounts: Boolean
|
||||
|
||||
)
|
|
@ -3,7 +3,7 @@ package net.codinux.banking.ui.model
|
|||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
|
||||
data class AccountTransactionViewModel(
|
||||
val id: Long,
|
|
@ -1,4 +1,4 @@
|
|||
package net.codinux.banking.ui.model
|
||||
package net.codinux.banking.ui.model.settings
|
||||
|
||||
enum class TransactionsGrouping {
|
||||
None,
|
|
@ -0,0 +1,10 @@
|
|||
package net.codinux.banking.persistence
|
||||
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.db.QueryResult
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.db.SqlSchema
|
||||
import app.cash.sqldelight.driver.native.NativeSqliteDriver
|
||||
|
||||
actual fun createSqlDriverDriver(dbName: String, schema: SqlSchema<QueryResult.AsyncValue<Unit>>, version: Long): SqlDriver =
|
||||
NativeSqliteDriver(schema.synchronous(), dbName)
|
|
@ -0,0 +1,9 @@
|
|||
package net.codinux.banking.persistence
|
||||
|
||||
import app.cash.sqldelight.db.QueryResult
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.db.SqlSchema
|
||||
|
||||
actual fun createSqlDriverDriver(dbName: String, schema: SqlSchema<QueryResult.AsyncValue<Unit>>, version: Long): SqlDriver {
|
||||
throw NotImplementedError("TODO")
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package net.codinux.banking.persistence
|
||||
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.db.QueryResult
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.db.SqlSchema
|
||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||
import java.io.File
|
||||
|
||||
|
||||
val dataDirectory: File = determineDataDirectory()
|
||||
|
||||
actual fun createSqlDriverDriver(dbName: String, schema: SqlSchema<QueryResult.AsyncValue<Unit>>, version: Long): SqlDriver {
|
||||
val dbDir = File(dataDirectory, "db").also { it.mkdirs() }
|
||||
val databaseFile = File(dbDir, dbName)
|
||||
|
||||
return JdbcSqliteDriver("jdbc:sqlite:${databaseFile.path}").also { driver ->
|
||||
schema.synchronous().also { schema ->
|
||||
if (databaseFile.exists() == false) {
|
||||
schema.create(driver)
|
||||
}
|
||||
|
||||
schema.migrate(driver, schema.version, version)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun determineDataDirectory(): File {
|
||||
val currentDir = File(System.getProperty("user.dir"))
|
||||
|
||||
val dataDir = if (currentDir.canWrite()) { // if the current directory is writable, use that one (the default for development)
|
||||
File(currentDir, "data")
|
||||
} else { // otherwise use .bankmeister dir in user's home dir (the default for releases)
|
||||
val userHome = System.getProperty("user.home")
|
||||
File(userHome, ".bankmeister")
|
||||
}
|
||||
|
||||
return dataDir.also { it.mkdirs() }
|
||||
}
|
|
@ -1,23 +1,18 @@
|
|||
package net.codinux.banking.dataaccess
|
||||
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.*
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.SqliteBankingRepository
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
|
||||
class SqliteBankingRepositoryTest {
|
||||
|
||||
private val sqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY).apply {
|
||||
BankmeisterDb.Schema.synchronous().create(this)
|
||||
}
|
||||
|
||||
private val underTest = object : SqliteBankingRepository(sqlDriver) {
|
||||
override public suspend fun persistTransaction(bankId: Long, accountId: Long, transaction: AccountTransaction): AccountTransactionEntity =
|
||||
private val underTest = object : SqliteBankingRepository() {
|
||||
public override suspend fun persistTransaction(bankId: Long, accountId: Long, transaction: AccountTransaction): AccountTransactionEntity =
|
||||
super.persistTransaction(bankId, accountId, transaction)
|
||||
}
|
||||
|
|
@ -10,18 +10,23 @@ plugins {
|
|||
alias(libs.plugins.compose.compiler)
|
||||
|
||||
alias(libs.plugins.kotlinxSerialization)
|
||||
|
||||
alias(libs.plugins.sqldelight)
|
||||
}
|
||||
|
||||
|
||||
kotlin {
|
||||
@OptIn(ExperimentalKotlinGradlePluginApi::class)
|
||||
compilerOptions {
|
||||
// suppresses compiler warning: [EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING] 'expect'/'actual' classes (including interfaces, objects, annotations, enums, and 'actual' typealiases) are in Beta.
|
||||
freeCompilerArgs.add("-Xexpect-actual-classes")
|
||||
}
|
||||
|
||||
|
||||
js {
|
||||
moduleName = "composeApp"
|
||||
moduleName = "Bankmeister"
|
||||
browser {
|
||||
val projectDirPath = project.projectDir.path
|
||||
commonWebpackConfig {
|
||||
outputFileName = "composeApp.js"
|
||||
outputFileName = "Bankmeister.js"
|
||||
devServer = (devServer ?: KotlinWebpackConfig.DevServer()).apply {
|
||||
static = (static ?: mutableListOf()).apply {
|
||||
// Serve sources to debug inside browser
|
||||
|
@ -49,15 +54,27 @@ kotlin {
|
|||
iosSimulatorArm64()
|
||||
).forEach { iosTarget ->
|
||||
iosTarget.binaries.framework {
|
||||
baseName = "ComposeApp"
|
||||
isStatic = true
|
||||
baseName = "BankmeisterFramework"
|
||||
isStatic = false
|
||||
}
|
||||
|
||||
// don't know why but this has to be added here, adding it in BankingPersistence.build.gradle.kt does not work
|
||||
iosTarget.binaries.forEach { binary ->
|
||||
if (binary is org.jetbrains.kotlin.gradle.plugin.mpp.Framework) {
|
||||
binary.linkerOpts.add("-lsqlite3") // without this we get a lot of "Undefined symbol _co_touchlab_sqliter..." errors in Xcode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
applyDefaultHierarchyTemplate()
|
||||
|
||||
|
||||
sourceSets {
|
||||
val desktopMain by getting
|
||||
|
||||
commonMain.dependencies {
|
||||
implementation(project(":BankingPersistence"))
|
||||
|
||||
implementation(libs.banking.client.model)
|
||||
implementation(libs.fints4k.banking.client)
|
||||
|
||||
|
@ -65,10 +82,6 @@ kotlin {
|
|||
implementation(libs.klf)
|
||||
implementation(libs.kotlinx.serializable)
|
||||
|
||||
implementation(libs.sqldelight.runtime)
|
||||
implementation(libs.sqldelight.coroutines.extensions)
|
||||
implementation(libs.sqldelight.paging.extensions)
|
||||
|
||||
// UI
|
||||
implementation(compose.runtime)
|
||||
implementation(compose.foundation)
|
||||
|
@ -93,13 +106,11 @@ kotlin {
|
|||
implementation(libs.androidx.activity.compose)
|
||||
implementation(libs.androidx.biometric)
|
||||
|
||||
implementation(libs.sqldelight.android.driver)
|
||||
|
||||
implementation(libs.favre.bcrypt)
|
||||
}
|
||||
|
||||
nativeMain.dependencies {
|
||||
implementation(libs.sqldelight.native.driver)
|
||||
iosMain.dependencies {
|
||||
|
||||
}
|
||||
|
||||
jvmTest.dependencies {
|
||||
|
@ -110,23 +121,10 @@ kotlin {
|
|||
implementation(compose.desktop.currentOs)
|
||||
implementation(libs.kotlinx.coroutines.swing)
|
||||
|
||||
implementation(libs.sqldelight.sqlite.driver)
|
||||
|
||||
implementation(libs.favre.bcrypt)
|
||||
|
||||
implementation(libs.logback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sqldelight {
|
||||
databases {
|
||||
create("BankmeisterDb") {
|
||||
packageName.set("net.codinux.banking.dataaccess")
|
||||
generateAsync = true
|
||||
|
||||
schemaOutputDirectory = file("src/commonMain/sqldelight/databases")
|
||||
implementation(libs.janino)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,12 +190,28 @@ compose.desktop {
|
|||
mainClass = "net.codinux.banking.ui.MainKt"
|
||||
|
||||
nativeDistributions {
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
|
||||
packageName = "net.codinux.banking.ui"
|
||||
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb, TargetFormat.Rpm)
|
||||
|
||||
modules("java.sql", "java.naming") // java.naming is required by logback
|
||||
|
||||
packageName = "Bankmeister"
|
||||
packageVersion = "1.0.0"
|
||||
description = "Datenschutzfreundliche Multi-Banking App für die meisten deutschen Banken"
|
||||
copyright = "© 2024 codinux GmbH & Co.KG. All rights reserved."
|
||||
vendor = "codinux GmbH & Co.KG"
|
||||
|
||||
macOS {
|
||||
bundleID = "net.codinux.banking.ui"
|
||||
appCategory = "public.app-category.finance"
|
||||
|
||||
iconFile = project.file("../docs/res/AppIcons/distributions/AppIcon.icns")
|
||||
}
|
||||
windows {
|
||||
iconFile = project.file("../docs/res/AppIcons/distributions/AppIcon.ico")
|
||||
}
|
||||
linux {
|
||||
iconFile = project.file("../docs/res/AppIcons/distributions/AppIcon.png")
|
||||
}
|
||||
}
|
||||
|
||||
buildTypes.release.proguard {
|
||||
|
|
|
@ -5,9 +5,8 @@ import androidx.activity.compose.setContent
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.driver.android.AndroidSqliteDriver
|
||||
import net.codinux.banking.dataaccess.BankmeisterDb
|
||||
import net.codinux.banking.persistence.AndroidContext
|
||||
import net.codinux.banking.persistence.SqliteBankingRepository
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.service.AuthenticationService
|
||||
import net.codinux.banking.ui.service.BiometricAuthenticationService
|
||||
|
@ -17,11 +16,11 @@ class MainActivity : FragmentActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
AndroidContext.applicationContext = this.applicationContext
|
||||
|
||||
ImageService.context = this.applicationContext
|
||||
AuthenticationService.biometricAuthenticationService = BiometricAuthenticationService(this)
|
||||
|
||||
DI.setRepository(AndroidSqliteDriver(BankmeisterDb.Schema.synchronous(), this, "Bankmeister.db"))
|
||||
|
||||
setContent {
|
||||
App()
|
||||
}
|
||||
|
|
|
@ -7,11 +7,14 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.sp
|
||||
import kotlinx.coroutines.launch
|
||||
import net.codinux.banking.persistence.BankingRepository
|
||||
import net.codinux.banking.persistence.SqliteBankingRepository
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.model.settings.AppAuthenticationMethod
|
||||
import net.codinux.banking.ui.screens.LoginScreen
|
||||
import net.codinux.banking.ui.screens.MainScreen
|
||||
import net.codinux.log.Log
|
||||
import net.codinux.log.LoggerFactory
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
||||
|
@ -21,9 +24,10 @@ private val typography = Typography(
|
|||
|
||||
@Composable
|
||||
@Preview
|
||||
fun App() {
|
||||
fun App(repository: BankingRepository? = null) {
|
||||
LoggerFactory.defaultLoggerName = "net.codinux.banking.ui.Bankmeister"
|
||||
|
||||
|
||||
val colors = MaterialTheme.colors.copy(primary = Colors.Primary, primaryVariant = Colors.PrimaryDark, onPrimary = Color.White,
|
||||
secondary = Colors.Accent, secondaryVariant = Colors.Accent, onSecondary = Color.White)
|
||||
|
||||
|
@ -35,6 +39,14 @@ fun App() {
|
|||
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
try {
|
||||
if (isInitialized == false) {
|
||||
DI.setRepository(repository ?: SqliteBankingRepository())
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
Log.error(e) { "Could not set repository" }
|
||||
}
|
||||
|
||||
|
||||
MaterialTheme(colors = colors, typography = typography) {
|
||||
if (isLoggedIn == false) {
|
||||
|
|
|
@ -13,7 +13,7 @@ import net.codinux.banking.ui.config.DI
|
|||
import net.codinux.banking.ui.config.Internationalization
|
||||
import net.codinux.banking.ui.forms.RoundedCornersCard
|
||||
import net.codinux.banking.ui.forms.Select
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
private val uiState = DI.uiState
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
||||
private val uiState = DI.uiState
|
||||
|
|
|
@ -19,8 +19,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
||||
|
@ -101,7 +101,7 @@ fun NavigationMenuItem(
|
|||
if (balance != null) {
|
||||
Text(
|
||||
formatUtil.formatAmount(balance, calculator.getTransactionsCurrency(emptyList())),
|
||||
color = formatUtil.getColorForAmount(balance, showColoredAmounts),
|
||||
color = if (showColoredAmounts) formatUtil.getColorForAmount(balance, showColoredAmounts) else textColor,
|
||||
modifier = Modifier.padding(start = 4.dp)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import net.codinux.banking.ui.config.DI
|
|||
import net.codinux.banking.ui.config.Internationalization
|
||||
import net.codinux.banking.ui.forms.BooleanOption
|
||||
import net.codinux.banking.ui.forms.Select
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
@Composable
|
||||
fun UiSettings(modifier: Modifier, textColor: Color = Color.Unspecified) {
|
||||
|
|
|
@ -14,13 +14,13 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.compose.ui.unit.sp
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.config.Style
|
||||
import net.codinux.banking.ui.forms.RoundedCornersCard
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
import net.codinux.banking.ui.service.TransactionsGroupingService
|
||||
|
||||
private val calculator = DI.calculator
|
||||
|
|
|
@ -12,7 +12,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
import net.codinux.banking.ui.settings.UiSettings
|
||||
import net.codinux.banking.ui.state.UiState
|
||||
import org.jetbrains.compose.ui.tooling.preview.Preview
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
package net.codinux.banking.ui.config
|
||||
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import net.codinux.banking.dataaccess.BankingRepository
|
||||
import net.codinux.banking.dataaccess.InMemoryBankingRepository
|
||||
import net.codinux.banking.dataaccess.SqliteBankingRepository
|
||||
import net.codinux.banking.persistence.BankingRepository
|
||||
import net.codinux.banking.persistence.InMemoryBankingRepository
|
||||
import net.codinux.banking.ui.Platform
|
||||
import net.codinux.banking.ui.getPlatform
|
||||
import net.codinux.banking.ui.service.*
|
||||
|
@ -39,8 +37,6 @@ object DI {
|
|||
val bankingService by lazy { BankingService(uiState, uiSettings, bankingRepository, bankFinder) }
|
||||
|
||||
|
||||
fun setRepository(sqlDriver: SqlDriver) = setRepository(SqliteBankingRepository(sqlDriver))
|
||||
|
||||
fun setRepository(repository: BankingRepository) {
|
||||
this.bankingRepository = repository
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.codinux.banking.ui.config
|
|||
|
||||
import net.codinux.banking.client.model.BankAccountType
|
||||
import net.codinux.banking.client.model.tan.ActionRequiringTan
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.AppAuthenticationMethod
|
||||
|
||||
object Internationalization {
|
||||
|
|
|
@ -23,6 +23,7 @@ import net.codinux.banking.ui.config.DI
|
|||
import net.codinux.banking.ui.forms.*
|
||||
import net.codinux.banking.ui.forms.OutlinedTextField
|
||||
import net.codinux.banking.ui.model.BankInfo
|
||||
import net.codinux.log.Log
|
||||
|
||||
|
||||
private val bankingService = DI.bankingService
|
||||
|
@ -37,7 +38,7 @@ fun AddAccountDialog(
|
|||
var selectedBank by remember { mutableStateOf<BankInfo?>(null) }
|
||||
var loginName by remember { mutableStateOf("") }
|
||||
var password by remember { mutableStateOf("") }
|
||||
var retrieveAllTransactions by remember { mutableStateOf(false) }
|
||||
var retrieveAllTransactions by remember { mutableStateOf(true) }
|
||||
|
||||
val isRequiredDataEntered by remember(selectedBank, loginName, password) {
|
||||
derivedStateOf { selectedBank != null && loginName.length > 3 && password.length > 3 }
|
||||
|
@ -69,7 +70,12 @@ fun AddAccountDialog(
|
|||
isAddingAccount = true
|
||||
|
||||
addAccountJob = coroutineScope.launch(Dispatchers.IOorDefault) {
|
||||
val successful = DI.bankingService.addAccount(bank, loginName, password, retrieveAllTransactions)
|
||||
val successful = try {
|
||||
DI.bankingService.addAccount(bank, loginName, password, retrieveAllTransactions)
|
||||
} catch (e: Throwable) {
|
||||
Log.error(e) { "Could not add account for $bank" }
|
||||
false
|
||||
}
|
||||
|
||||
addAccountJob = null
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package net.codinux.banking.ui.model
|
||||
|
||||
import androidx.compose.runtime.*
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
|
||||
class AccountTransactionsFilter {
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.codinux.banking.ui.model
|
||||
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
|
||||
data class BankAccountFilter(
|
||||
val bank: BankAccessEntity,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.codinux.banking.ui.model
|
||||
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
|
||||
data class ShowTransferMoneyDialogData(
|
||||
val senderAccount: BankAccountEntity? = null,
|
||||
|
|
|
@ -7,7 +7,7 @@ import androidx.compose.runtime.collectAsState
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.client.model.isNegative
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.extensions.verticalScroll
|
||||
import net.codinux.banking.ui.forms.LabelledValue
|
||||
|
|
|
@ -6,7 +6,7 @@ import androidx.compose.material.Text
|
|||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.ui.config.Internationalization
|
||||
import net.codinux.banking.ui.extensions.verticalScroll
|
||||
import net.codinux.banking.ui.forms.*
|
||||
|
|
|
@ -5,7 +5,7 @@ import androidx.compose.material.Text
|
|||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.unit.dp
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import net.codinux.banking.ui.extensions.verticalScroll
|
||||
import net.codinux.banking.ui.forms.*
|
||||
|
|
|
@ -13,7 +13,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import net.codinux.banking.dataaccess.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.ui.IOorDefault
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package net.codinux.banking.ui.service
|
||||
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.HoldingEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
||||
import net.codinux.banking.ui.model.BankAccountFilter
|
||||
|
@ -46,7 +46,7 @@ class AccountTransactionsFilterService {
|
|||
|
||||
private fun matchesSearchTerm(transaction: AccountTransactionViewModel, searchTerm: String): Boolean =
|
||||
transaction.reference?.contains(searchTerm, true) == true
|
||||
|| (transaction.otherPartyName != null && transaction.otherPartyName.contains(searchTerm, true))
|
||||
|| transaction.otherPartyName?.contains(searchTerm, true) == true
|
||||
|
||||
|
||||
fun filterHoldings(holdings: List<HoldingEntity>, filter: AccountTransactionsFilter): List<HoldingEntity> {
|
||||
|
|
|
@ -16,8 +16,12 @@ import net.codinux.banking.client.model.request.TransferMoneyRequestForUser
|
|||
import net.codinux.banking.client.model.response.*
|
||||
import net.codinux.banking.client.model.securitiesaccount.Holding
|
||||
import net.codinux.banking.client.service.BankingModelService
|
||||
import net.codinux.banking.dataaccess.BankingRepository
|
||||
import net.codinux.banking.dataaccess.entities.*
|
||||
import net.codinux.banking.persistence.BankingRepository
|
||||
import net.codinux.banking.persistence.entities.AccountTransactionEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.HoldingEntity
|
||||
import net.codinux.banking.persistence.entities.UiSettingsEntity
|
||||
import net.codinux.banking.ui.IOorDefault
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.BankInfo
|
||||
|
@ -57,7 +61,13 @@ class BankingService(
|
|||
}
|
||||
uiState.appSettings.value = appSettings
|
||||
|
||||
bankingRepository.getUiSettings(uiSettings)
|
||||
bankingRepository.getUiSettings()?.let {
|
||||
uiSettings.showBalance.value = it.showBalance
|
||||
uiSettings.transactionsGrouping.value = it.transactionsGrouping
|
||||
uiSettings.showTransactionsInAlternatingColors.value = it.showTransactionsInAlternatingColors
|
||||
uiSettings.showBankIcons.value = it.showBankIcons
|
||||
uiSettings.showColoredAmounts.value = it.showColoredAmounts
|
||||
}
|
||||
|
||||
updateOnChanges(uiSettings)
|
||||
|
||||
|
@ -76,7 +86,9 @@ class BankingService(
|
|||
|
||||
suspend fun saveAppSettings(settings: AppSettings) = bankingRepository.saveAppSettings(settings)
|
||||
|
||||
suspend fun saveUiSettings(settings: UiSettings) = bankingRepository.saveUiSettings(settings)
|
||||
suspend fun saveUiSettings(settings: UiSettings) = bankingRepository.saveUiSettings(UiSettingsEntity(
|
||||
settings.showBalance.value, settings.transactionsGrouping.value, settings.showTransactionsInAlternatingColors.value, settings.showBankIcons.value, settings.showColoredAmounts.value
|
||||
))
|
||||
|
||||
|
||||
fun getAllBanks() = bankingRepository.getAllBanks()
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package net.codinux.banking.ui.service
|
||||
|
||||
import net.codinux.banking.client.model.*
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.AccountTransactionsFilter
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import kotlinx.datetime.*
|
|||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.client.model.isNegative
|
||||
import net.codinux.banking.ui.config.Colors
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
class FormatUtil {
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import kotlinx.datetime.LocalDate
|
|||
import kotlinx.datetime.Month
|
||||
import net.codinux.banking.client.model.extensions.minusDays
|
||||
import net.codinux.banking.ui.model.AccountTransactionViewModel
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
class TransactionsGroupingService {
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package net.codinux.banking.ui.settings
|
|||
|
||||
import androidx.lifecycle.ViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import net.codinux.banking.ui.model.TransactionsGrouping
|
||||
import net.codinux.banking.ui.model.settings.TransactionsGrouping
|
||||
|
||||
class UiSettings : ViewModel() {
|
||||
|
||||
|
@ -14,6 +14,6 @@ class UiSettings : ViewModel() {
|
|||
|
||||
val showBankIcons = MutableStateFlow(true)
|
||||
|
||||
val showColoredAmounts = MutableStateFlow(true)
|
||||
val showColoredAmounts = MutableStateFlow(false)
|
||||
|
||||
}
|
|
@ -7,9 +7,9 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import net.codinux.banking.client.model.tan.EnterTanResult
|
||||
import net.codinux.banking.client.model.tan.TanChallenge
|
||||
import net.codinux.banking.dataaccess.entities.HoldingEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccessEntity
|
||||
import net.codinux.banking.dataaccess.entities.BankAccountEntity
|
||||
import net.codinux.banking.persistence.entities.HoldingEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccessEntity
|
||||
import net.codinux.banking.persistence.entities.BankAccountEntity
|
||||
import net.codinux.banking.ui.model.*
|
||||
import net.codinux.banking.ui.model.error.ApplicationError
|
||||
import net.codinux.banking.ui.model.error.BankingClientError
|
||||
|
|
|
@ -6,19 +6,14 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.unit.DpSize
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.*
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.db.SqlDriver
|
||||
import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
|
||||
import bankmeister.composeapp.generated.resources.AppIcon_svg
|
||||
import bankmeister.composeapp.generated.resources.Res
|
||||
import kotlinx.datetime.LocalDate
|
||||
import net.codinux.banking.client.model.AccountTransaction
|
||||
import net.codinux.banking.client.model.Amount
|
||||
import net.codinux.banking.dataaccess.BankmeisterDb
|
||||
import net.codinux.banking.dataaccess.InMemoryBankingRepository
|
||||
import net.codinux.banking.persistence.InMemoryBankingRepository
|
||||
import net.codinux.banking.ui.config.DI
|
||||
import org.jetbrains.compose.resources.painterResource
|
||||
import java.io.File
|
||||
|
||||
fun main() = application {
|
||||
Window(
|
||||
|
@ -27,34 +22,20 @@ fun main() = application {
|
|||
icon = painterResource(Res.drawable.AppIcon_svg),
|
||||
state = WindowState(position = WindowPosition(Alignment.Center), size = DpSize(1000.dp, 800.dp)),
|
||||
) {
|
||||
DI.setRepository(createSqlDriverDriver())
|
||||
|
||||
App()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createSqlDriverDriver(): SqlDriver {
|
||||
File("data/db").mkdirs()
|
||||
|
||||
return JdbcSqliteDriver("jdbc:sqlite:data/db/Bankmeister.db").also { driver ->
|
||||
BankmeisterDb.Schema.synchronous().also { schema ->
|
||||
if (File("data/db/Bankmeister.db").exists() == false) {
|
||||
schema.create(driver)
|
||||
}
|
||||
|
||||
schema.migrate(driver, schema.version, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AppPreview() {
|
||||
DI.setRepository(InMemoryBankingRepository(
|
||||
DI.setRepository(
|
||||
InMemoryBankingRepository(
|
||||
emptyList(),
|
||||
listOf(AccountTransaction(Amount("12.34"), "EUR", "Lohn", LocalDate(2024, 7, 5), LocalDate(2024, 6, 15), "Dein Boss"))
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
App()
|
||||
}
|
|
@ -2,6 +2,7 @@ package net.codinux.banking.ui.service
|
|||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||
import net.codinux.banking.persistence.dataDirectory
|
||||
import net.codinux.log.Log
|
||||
import org.jetbrains.skia.Image
|
||||
import java.io.File
|
||||
|
@ -9,7 +10,7 @@ import java.net.URL
|
|||
import java.security.MessageDigest
|
||||
|
||||
|
||||
private val cacheDir = File("data/imageCache").also { it.mkdirs() }
|
||||
private val cacheDir = File(dataDirectory, "imageCache").also { it.mkdirs() }
|
||||
|
||||
private val messageDigest = MessageDigest.getInstance("SHA-256")
|
||||
|
||||
|
|
|
@ -1,5 +1,19 @@
|
|||
<configuration>
|
||||
|
||||
<property name="logDir" value="${user.home}/.bankmeister" /> <!-- For Release, write to the user's home directory -->
|
||||
|
||||
<if condition='property("ENV").equalsIgnoreCase("debug")'>
|
||||
<then>
|
||||
<property name="logDir" value="${user.dir}/data" /> <!-- For Debug/Development, write to the current directory -->
|
||||
</then>
|
||||
</if>
|
||||
|
||||
<if condition='property("ENV") == "debug"'>
|
||||
<then>
|
||||
<property name="logDir" value="${user.dir}/data" /> <!-- For Debug/Development, write to the current directory -->
|
||||
</then>
|
||||
</if>
|
||||
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
|
||||
|
@ -17,11 +31,11 @@
|
|||
<timestamp key="bySecond" datePattern="yyyyMMdd'T'HHmmss"/>
|
||||
|
||||
<appender name="file" class="ch.qos.logback.core.FileAppender">
|
||||
<file>data/logs/Bankmeister-${bySecond}.log</file>
|
||||
<file>${logDir}/logs/Bankmeister-${bySecond}.log</file>
|
||||
<!-- encoders are assigned the type
|
||||
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
|
||||
<encoder>
|
||||
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg%n</pattern>
|
||||
</encoder>
|
||||
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
package net.codinux.banking.ui
|
||||
|
||||
import androidx.compose.ui.window.ComposeUIViewController
|
||||
import app.cash.sqldelight.async.coroutines.synchronous
|
||||
import app.cash.sqldelight.driver.native.NativeSqliteDriver
|
||||
import net.codinux.banking.dataaccess.BankmeisterDb
|
||||
import net.codinux.banking.persistence.SqliteBankingRepository
|
||||
import net.codinux.banking.ui.config.DI
|
||||
|
||||
fun MainViewController() = ComposeUIViewController {
|
||||
DI.setRepository(NativeSqliteDriver(Database.Schema.synchronous(), "Bankmeister.db"))
|
||||
|
||||
App()
|
||||
}
|
|
@ -1,6 +1,36 @@
|
|||
package net.codinux.banking.ui
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.unit.dp
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.cinterop.useContents
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.IO
|
||||
import platform.CoreGraphics.CGRect
|
||||
import platform.UIKit.UIDevice
|
||||
import platform.UIKit.UIScreen
|
||||
|
||||
actual val Dispatchers.IOorDefault: CoroutineDispatcher
|
||||
get() = Dispatchers.IO
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
@Composable
|
||||
actual fun rememberScreenSizeInfo(): ScreenSizeInfo {
|
||||
val density = LocalDensity.current
|
||||
val screenBounds: CGRect = UIScreen.mainScreen.bounds.useContents { this }
|
||||
val screenWidth = screenBounds.size.width
|
||||
val screenHeight = screenBounds.size.height
|
||||
|
||||
return remember(density, screenWidth, screenHeight) {
|
||||
ScreenSizeInfo(
|
||||
heightDp = with(density) { screenHeight.dp },
|
||||
widthDp = with(density) { screenWidth.dp }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class IOSPlatform: Platform {
|
||||
override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package net.codinux.banking.ui.service
|
||||
|
||||
import androidx.compose.ui.graphics.ImageBitmap
|
||||
import androidx.compose.ui.graphics.toComposeImageBitmap
|
||||
import kotlinx.cinterop.ExperimentalForeignApi
|
||||
import kotlinx.cinterop.readBytes
|
||||
import org.jetbrains.skia.Image
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import platform.Foundation.*
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.resumeWithException
|
||||
|
||||
actual fun createImageBitmap(imageBytes: ByteArray): ImageBitmap =
|
||||
Image.makeFromEncoded(imageBytes).toComposeImageBitmap()
|
||||
|
||||
@OptIn(ExperimentalForeignApi::class)
|
||||
actual suspend fun fetchBytesFromUrl(url: String): ByteArray {
|
||||
val nsUrl = NSURL(string = url) ?: throw IllegalArgumentException("Invalid URL")
|
||||
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
val request = NSURLRequest.requestWithURL(nsUrl)
|
||||
val session = NSURLSession.sharedSession
|
||||
val task = session.dataTaskWithRequest(request) { data, response, error ->
|
||||
when {
|
||||
error != null -> continuation.resumeWithException(Exception(error.localizedDescription))
|
||||
data != null -> continuation.resume(data.bytes!!.readBytes(data.length.toInt()))
|
||||
else -> continuation.resumeWithException(Exception("Unknown error"))
|
||||
}
|
||||
}
|
||||
|
||||
continuation.invokeOnCancellation {
|
||||
task.cancel() // Cancel the task if the coroutine is cancelled
|
||||
}
|
||||
|
||||
task.resume()
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 576 B |
After Width: | Height: | Size: 254 B |
After Width: | Height: | Size: 1.0 KiB |
After Width: | Height: | Size: 316 B |
After Width: | Height: | Size: 365 B |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 398 B |
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,21 @@
|
|||
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<rect width="60" height="60" fill="white"/>
|
||||
<rect width="60" height="60" fill="white"/>
|
||||
<circle cx="29.9999" cy="30" r="25.9091" fill="black" fill-opacity="0.09"/>
|
||||
<circle cx="29.9999" cy="30" r="25.6591" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||
<circle cx="30.0001" cy="30" r="16.3636" fill="black" fill-opacity="0.09"/>
|
||||
<circle cx="30.0001" cy="30" r="16.1136" stroke="#2869BF" stroke-opacity="0.04" stroke-width="0.5"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.25 0H29.75V29.75H0V30.25H29.75V60H30.25V30.25H60V29.75H30.25V0Z" fill="#6277A1" fill-opacity="0.1"/>
|
||||
<path d="M0 0L60 0L60 60L0 60L0 0Z" fill="#003832"/>
|
||||
<path d="M16.2969 18.9254C16.2969 17.9348 17.022 17.0935 18.0018 16.9473L29.5243 15.2286C29.7173 15.1998 29.9135 15.1994 30.1067 15.2275L41.9916 16.953C42.9749 17.0957 43.7043 17.9387 43.7043 18.9322V20.963C43.7043 22.0675 42.8089 22.963 41.7043 22.963L18.2969 22.963C17.1923 22.963 16.2969 22.0675 16.2969 20.963V18.9254Z" fill="#77A83F"/>
|
||||
<rect x="16.2961" y="25.5555" width="7.40741" height="19.2593" rx="2" fill="#079326"/>
|
||||
<rect x="26.2961" y="25.5555" width="7.40741" height="19.2593" rx="2" fill="#68A93D"/>
|
||||
<rect x="36.2961" y="25.5555" width="7.40741" height="19.2593" rx="2" fill="#CCFFB4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="60" height="60" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1,7 @@
|
|||
<svg width="162" height="162" viewBox="0 0 162 162" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="81" cy="81" r="81" fill="#003832"/>
|
||||
<path d="M44 48.1682C44 47.1776 44.7252 46.3363 45.7049 46.1901L80.2089 41.0434C80.4019 41.0146 80.5981 41.0142 80.7913 41.0423L116.287 46.1958C117.271 46.3385 118 47.1815 118 48.175V60C118 61.1046 117.105 62 116 62H46C44.8954 62 44 61.1046 44 60V48.1682Z" fill="#77A83F"/>
|
||||
<rect x="44" y="69" width="20" height="52" rx="2" fill="#079326"/>
|
||||
<rect x="71" y="69" width="20" height="52" rx="2" fill="#68A93D"/>
|
||||
<rect x="98" y="69" width="20" height="52" rx="2" fill="#CCFFB4"/>
|
||||
</svg>
|
After Width: | Height: | Size: 630 B |
|
@ -0,0 +1,19 @@
|
|||
# converts a 1024x1024 png - here named 'AppIcon.png' - to all size relevant to create
|
||||
# an .icns file in AppIcon.iconset subfolder and then creates AppIcon.icns file
|
||||
|
||||
mkdir AppIcon.iconset
|
||||
|
||||
sips -z 16 16 AppIcon.png --out AppIcon.iconset/icon_16x16.png
|
||||
sips -z 32 32 AppIcon.png --out AppIcon.iconset/icon_16x16@2.png
|
||||
sips -z 32 32 AppIcon.png --out AppIcon.iconset/icon_32x32.png
|
||||
sips -z 64 64 AppIcon.png --out AppIcon.iconset/icon_32x32@2.png
|
||||
sips -z 128 128 AppIcon.png --out AppIcon.iconset/icon_128x128.png
|
||||
sips -z 256 256 AppIcon.png --out AppIcon.iconset/icon_128x128@2.png
|
||||
sips -z 256 256 AppIcon.png --out AppIcon.iconset/icon_256x256.png
|
||||
sips -z 512 512 AppIcon.png --out AppIcon.iconset/icon_256x256@2.png
|
||||
sips -z 512 512 AppIcon.png --out AppIcon.iconset/icon_512x512.png
|
||||
cp AppIcon.png AppIcon.iconset/icon_512x512@2.png
|
||||
|
||||
iconutil -c icns AppIcon.iconset
|
||||
|
||||
# rm -R AppIcon.iconset
|
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 1.5 KiB |
|
@ -2,15 +2,17 @@
|
|||
kotlin = "2.0.10"
|
||||
kotlinx-coroutines = "1.8.1"
|
||||
|
||||
banking-client = "0.6.1-SNAPSHOT"
|
||||
banking-client = "0.6.1"
|
||||
|
||||
kcsv = "2.2.0"
|
||||
kotlinx-serializable = "1.7.1"
|
||||
kotlinx-datetime = "0.5.0"
|
||||
|
||||
favre-bcrypt = "0.10.2"
|
||||
|
||||
klf = "1.6.1"
|
||||
klf = "1.6.2"
|
||||
logback = "1.5.7"
|
||||
janino = "3.1.12"
|
||||
|
||||
sqlDelight = "2.0.2"
|
||||
|
||||
|
@ -38,11 +40,13 @@ fints4k-banking-client = { group = "net.codinux.banking.client", name = "fints4k
|
|||
kcsv = { group = "net.codinux.csv", name = "kcsv", version.ref = "kcsv" }
|
||||
coroutines-test = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
|
||||
kotlinx-serializable = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serializable" }
|
||||
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" }
|
||||
|
||||
favre-bcrypt = { group = "at.favre.lib", name = "bcrypt", version.ref = "favre-bcrypt" }
|
||||
|
||||
klf = { group = "net.codinux.log", name = "klf", version.ref = "klf" }
|
||||
logback = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" }
|
||||
janino = { group = "org.codehaus.janino", name = "janino", version.ref = "janino" }
|
||||
|
||||
sqldelight-runtime = { module = "app.cash.sqldelight:runtime", version.ref = "sqlDelight" }
|
||||
sqldelight-coroutines-extensions = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqlDelight" }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
TEAM_ID=
|
||||
BUNDLE_ID=net.codinux.banking.ui.Bankmeister
|
||||
BUNDLE_ID=net.codinux.banking.bankmeister
|
||||
APP_NAME=Bankmeister
|
|
@ -318,20 +318,24 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 10;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "${TEAM_ID}";
|
||||
DEVELOPMENT_TEAM = 7WVYN7QA7Z;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
|
||||
);
|
||||
INFOPLIST_FILE = iosApp/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
|
||||
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = net.codinux.banking.bankmeister;
|
||||
PRODUCT_NAME = "${APP_NAME}";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -345,20 +349,24 @@
|
|||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 10;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = "${TEAM_ID}";
|
||||
DEVELOPMENT_TEAM = 7WVYN7QA7Z;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
|
||||
);
|
||||
INFOPLIST_FILE = iosApp/Info.plist;
|
||||
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.finance";
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 15.3;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
|
||||
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = net.codinux.banking.bankmeister;
|
||||
PRODUCT_NAME = "${APP_NAME}";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_VERSION = 5.0;
|
||||
|
@ -390,4 +398,4 @@
|
|||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 7555FF73242A565900829871 /* Project object */;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
|
@ -1,6 +1,6 @@
|
|||
import UIKit
|
||||
import SwiftUI
|
||||
import ComposeApp
|
||||
import BankmeisterFramework
|
||||
|
||||
struct ComposeView: UIViewControllerRepresentable {
|
||||
func makeUIViewController(context: Context) -> UIViewController {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
@ -15,13 +17,11 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>CADisableMinimumFrameDurationOnPhone</key>
|
||||
<true/>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
|
@ -36,15 +36,14 @@
|
|||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -33,4 +33,7 @@ dependencyResolutionManagement {
|
|||
}
|
||||
|
||||
|
||||
// had to extract Sql'delight' dependencies to an extra project as they conflict with Compose dependencies on iOS
|
||||
include(":BankingPersistence")
|
||||
|
||||
include(":composeApp")
|