diff --git a/.gitignore b/.gitignore index 50f4949..5f1b5ea 100644 --- a/.gitignore +++ b/.gitignore @@ -22,4 +22,4 @@ xcuserdata !*.xcworkspace/contents.xcworkspacedata **/xcshareddata/WorkspaceSettings.xcsettings -composeApp/data/logs +composeApp/data/ diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts index df2b800..0c12130 100644 --- a/composeApp/build.gradle.kts +++ b/composeApp/build.gradle.kts @@ -11,6 +11,8 @@ plugins { alias(libs.plugins.compose.compiler) alias(libs.plugins.kotlinxSerialization) + + alias(libs.plugins.sqldelight) } @@ -63,6 +65,10 @@ 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) @@ -75,20 +81,50 @@ kotlin { implementation(libs.androidx.lifecycle.runtime.compose) } + commonTest.dependencies { + implementation(libs.kotlin.test) + } + androidMain.dependencies { implementation(compose.preview) implementation(libs.androidx.activity.compose) + + implementation(libs.sqldelight.android.driver) + } + + nativeMain.dependencies { + implementation(libs.sqldelight.native.driver) + } + + jvmMain.dependencies { + implementation(libs.sqldelight.sqlite.driver) + } + jvmTest.dependencies { + implementation(libs.kotlin.test.junit) } desktopMain.dependencies { implementation(compose.desktop.currentOs) implementation(libs.kotlinx.coroutines.swing) + implementation(libs.sqldelight.sqlite.driver) + implementation(libs.logback) } } } + +sqldelight { + databases { + create("BankmeisterDb") { + packageName.set("net.codinux.banking.dataaccess") + generateAsync.set(true) + } + } +} + + android { namespace = "net.codinux.banking.ui" compileSdk = libs.versions.android.compileSdk.get().toInt() diff --git a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt index 09ed6ff..25440e7 100644 --- a/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt +++ b/composeApp/src/androidMain/kotlin/net/codinux/banking/ui/MainActivity.kt @@ -5,11 +5,17 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.runtime.Composable import androidx.compose.ui.tooling.preview.Preview +import app.cash.sqldelight.async.coroutines.synchronous +import app.cash.sqldelight.driver.android.AndroidSqliteDriver +import net.codinux.banking.dataaccess.BankmeisterDb +import net.codinux.banking.ui.config.DI class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + DI.setRepository(AndroidSqliteDriver(BankmeisterDb.Schema.synchronous(), this, "Bankmeister.db")) + setContent { App() } diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/BankingRepository.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/BankingRepository.kt new file mode 100644 index 0000000..8f0b550 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/BankingRepository.kt @@ -0,0 +1,12 @@ +package net.codinux.banking.dataaccess + +import net.codinux.banking.client.model.AccountTransaction +import net.codinux.banking.dataaccess.entities.AccountTransactionEntity + +interface BankingRepository { + + fun getAllAccountTransactions(): List + + suspend fun persistAccountTransactions(transactions: Collection) + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/InMemoryBankingRepository.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/InMemoryBankingRepository.kt new file mode 100644 index 0000000..2ca694c --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/InMemoryBankingRepository.kt @@ -0,0 +1,30 @@ +package net.codinux.banking.dataaccess + +import net.codinux.banking.client.model.AccountTransaction +import net.codinux.banking.dataaccess.entities.AccountTransactionEntity + +class InMemoryBankingRepository( + transactions: Collection +) : BankingRepository { + + private var nextId = 0L // TODO: make thread-safe + + private val transactions = transactions.map { map(it) }.toMutableList() + + + override fun getAllAccountTransactions(): List = transactions.toList() + + override suspend fun persistAccountTransactions(transactions: Collection) { + this.transactions.addAll(transactions.map { map(it) }) + } + + + private fun map(transaction: AccountTransaction) = AccountTransactionEntity( + nextId++, + transaction.amount, transaction.currency, transaction.reference, + transaction.bookingDate, transaction.valueDate, + transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, + transaction.bookingText + ) + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/SqliteBankingRepository.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/SqliteBankingRepository.kt new file mode 100644 index 0000000..45466d2 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/SqliteBankingRepository.kt @@ -0,0 +1,92 @@ +package net.codinux.banking.dataaccess + +import app.cash.sqldelight.db.SqlDriver +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 + +class SqliteBankingRepository( + sqlDriver: SqlDriver +) : BankingRepository { + + private val database = BankmeisterDb(sqlDriver) + + private val accountTransactionQueries = database.accountTransactionQueries + + + override fun getAllAccountTransactions(): List { + return accountTransactionQueries.selectAllTransactions { id, amount, currency, reference, bookingDate, valueDate, otherPartyName, otherPartyBankCode, otherPartyAccountId, bookingText, userSetDisplayName, notes, information, statementNumber, sequenceNumber, openingBalance, closingBalance, endToEndReference, customerReference, mandateReference, creditorIdentifier, originatorsIdentificationCode, compensationAmount, originalAmount, sepaReference, deviantOriginator, deviantRecipient, referenceWithNoSpecialType, primaNotaNumber, textKeySupplement, currencyType, bookingKey, referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution, supplementaryDetails, transactionReferenceNumber, relatedReferenceNumber -> + AccountTransactionEntity( + id, + Amount(amount), currency, reference, + mapToDate(bookingDate), mapToDate(valueDate), + otherPartyName, otherPartyBankCode, otherPartyAccountId, + bookingText, + + userSetDisplayName, notes, + + information, + statementNumber?.toInt(), sequenceNumber?.toInt(), + + mapToAmount(openingBalance), mapToAmount(closingBalance), + + endToEndReference, customerReference, mandateReference, + creditorIdentifier, originatorsIdentificationCode, + compensationAmount, originalAmount, + sepaReference, + deviantOriginator, deviantRecipient, + referenceWithNoSpecialType, primaNotaNumber, + textKeySupplement, + + currencyType, bookingKey, + referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution, + supplementaryDetails, + + transactionReferenceNumber, relatedReferenceNumber + ) + }.executeAsList() + } + + override suspend fun persistAccountTransactions(transactions: Collection) { + transactions.forEach { + saveAccountTransaction(it) + } + } + + private suspend fun saveAccountTransaction(transaction: AccountTransaction) { + accountTransactionQueries.insertTransaction( + transaction.amount.amount, transaction.currency, transaction.reference, + mapDate(transaction.bookingDate), mapDate(transaction.valueDate), + transaction.otherPartyName, transaction.otherPartyBankCode, transaction.otherPartyAccountId, + transaction.bookingText, + + transaction.userSetDisplayName, transaction.notes, + + transaction.information, + transaction.statementNumber?.toLong(), transaction.sequenceNumber?.toLong(), + transaction.openingBalance?.amount, transaction.closingBalance?.amount, + + transaction.endToEndReference, transaction.customerReference, transaction.mandateReference, + transaction.creditorIdentifier, transaction.originatorsIdentificationCode, + transaction.compensationAmount, transaction.originalAmount, + transaction.sepaReference, + transaction.deviantOriginator, transaction.deviantRecipient, + transaction.referenceWithNoSpecialType, transaction.primaNotaNumber, transaction.textKeySupplement, + + transaction.currencyType, transaction.bookingKey, + transaction.referenceForTheAccountOwner, transaction.referenceOfTheAccountServicingInstitution, + transaction.supplementaryDetails, + + transaction.transactionReferenceNumber, transaction.relatedReferenceNumber + ) + } + + + private fun mapToAmount(serializedAmount: String?): Amount? = serializedAmount?.let { Amount(it) } + + private fun mapDate(date: LocalDate): String = date.toString() + + private fun mapToDate(serializedDate: String): LocalDate = LocalDate.parse(serializedDate) + +} \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/entities/AccountTransactionEntity.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/entities/AccountTransactionEntity.kt new file mode 100644 index 0000000..1795ee2 --- /dev/null +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/dataaccess/entities/AccountTransactionEntity.kt @@ -0,0 +1,80 @@ +package net.codinux.banking.dataaccess.entities + +import kotlinx.datetime.LocalDate +import net.codinux.banking.client.model.AccountTransaction +import net.codinux.banking.client.model.Amount + +class AccountTransactionEntity( + val id: Long, + + amount: Amount, + currency: String, + reference: String, + + bookingDate: LocalDate, + valueDate: LocalDate, + + otherPartyName: String? = null, + otherPartyBankCode: String? = null, + otherPartyAccountId: String? = null, + + bookingText: String? = null, + + userSetDisplayName: String? = null, + notes: String? = null, + information: String? = null, + + statementNumber: Int? = null, + sequenceNumber: Int? = null, + + openingBalance: Amount? = null, + closingBalance: Amount? = null, + + endToEndReference: String? = null, + customerReference: String? = null, + mandateReference: String? = null, + creditorIdentifier: String? = null, + originatorsIdentificationCode: String? = null, + compensationAmount: String? = null, + originalAmount: String? = null, + sepaReference: String? = null, + deviantOriginator: String? = null, + deviantRecipient: String? = null, + referenceWithNoSpecialType: String? = null, + primaNotaNumber: String? = null, + textKeySupplement: String? = null, + + currencyType: String? = null, + bookingKey: String? = null, + referenceForTheAccountOwner: String? = null, + referenceOfTheAccountServicingInstitution: String? = null, + supplementaryDetails: String? = null, + + transactionReferenceNumber: String? = null, + relatedReferenceNumber: String? = null +) : AccountTransaction( + amount, currency, reference, + bookingDate, valueDate, + otherPartyName, otherPartyBankCode, otherPartyAccountId, + bookingText, + + information, + statementNumber, sequenceNumber, + openingBalance, closingBalance, + + endToEndReference, customerReference, mandateReference, + creditorIdentifier, originatorsIdentificationCode, + compensationAmount, originalAmount, + sepaReference, + deviantOriginator, deviantRecipient, + referenceWithNoSpecialType, primaNotaNumber, + textKeySupplement, + + currencyType, bookingKey, + referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution, + supplementaryDetails, + + transactionReferenceNumber, relatedReferenceNumber, + + userSetDisplayName, notes +) \ No newline at end of file diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt index a5875e5..dbbef41 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/App.kt @@ -14,7 +14,6 @@ import androidx.compose.ui.text.TextStyle import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import kotlinx.coroutines.launch -import net.codinux.banking.client.model.AccountTransaction import net.codinux.banking.ui.composables.StateHandler import net.codinux.banking.ui.composables.TransactionsList import net.codinux.banking.ui.dialogs.AddAccountDialog diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt index 38c793d..7320ec8 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/config/DI.kt @@ -1,10 +1,12 @@ 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.ui.Platform import net.codinux.banking.ui.getPlatform -import net.codinux.banking.ui.service.BankFinder -import net.codinux.banking.ui.service.BankingService -import net.codinux.banking.ui.service.FormatUtil +import net.codinux.banking.ui.service.* import net.codinux.banking.ui.state.UiState object DI { @@ -13,12 +15,24 @@ object DI { val platform: Platform = getPlatform() - val bankFinder = BankFinder() - - val bankingService = BankingService(uiState, bankFinder) val formatUtil = FormatUtil() + val bankFinder = BankFinder() + + + var bankingRepository: BankingRepository = InMemoryBankingRepository(emptyList()) + + val bankingService by lazy { + BankingService(uiState, bankingRepository, bankFinder) } + + + fun setRepository(sqlDriver: SqlDriver) = setRepository(SqliteBankingRepository(sqlDriver)) + + fun setRepository(repository: BankingRepository) { + this.bankingRepository = repository + } + suspend fun init() { bankingService.init() diff --git a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt index 9d4dffd..28a4425 100644 --- a/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt +++ b/composeApp/src/commonMain/kotlin/net/codinux/banking/ui/service/BankingService.kt @@ -10,6 +10,7 @@ import net.codinux.banking.client.model.options.GetAccountDataOptions import net.codinux.banking.client.model.options.RetrieveTransactions import net.codinux.banking.client.model.request.GetAccountDataRequest import net.codinux.banking.client.model.response.* +import net.codinux.banking.dataaccess.BankingRepository import net.codinux.banking.fints.config.FinTsClientConfiguration import net.codinux.banking.fints.config.FinTsClientOptions import net.codinux.banking.ui.model.BankInfo @@ -25,6 +26,7 @@ import org.jetbrains.compose.resources.ExperimentalResourceApi @OptIn(ExperimentalResourceApi::class) class BankingService( private val uiState: UiState, + private val bankingRepository: BankingRepository, private val bankFinder: BankFinder ) { @@ -36,9 +38,11 @@ class BankingService( suspend fun init() { - val transactions = readTransactionsFromCsv() - - uiState.transactions.value = transactions + try { + uiState.transactions.value = bankingRepository.getAllAccountTransactions() + } catch (e: Throwable) { + log.error(e) { "Could not read all account transactions from repository" } + } } suspend fun findBanks(query: String): List = @@ -64,13 +68,21 @@ class BankingService( } } - private fun handleSuccessfulGetAccountDataResponse(response: GetAccountDataResponse) { + private suspend fun handleSuccessfulGetAccountDataResponse(response: GetAccountDataResponse) { // TODO: save customer val transactions = uiState.transactions.value.toMutableList() transactions.addAll(response.bookedTransactions) uiState.transactions.value = transactions.sortedByDescending { it.valueDate } + + try { + bankingRepository.persistAccountTransactions(response.bookedTransactions) + + log.info { "Saved ${response.bookedTransactions.size} transactions" } + } catch (e: Throwable) { + log.error(e) { "Could not save account transactions ${response.bookedTransactions}" } + } } private fun handleUnsuccessfulBankingClientResponse(action: BankingClientAction, response: Response<*>) { diff --git a/composeApp/src/commonMain/sqldelight/net/codinux/banking/ui/AccountTransaction.sq b/composeApp/src/commonMain/sqldelight/net/codinux/banking/ui/AccountTransaction.sq new file mode 100644 index 0000000..5edf3a6 --- /dev/null +++ b/composeApp/src/commonMain/sqldelight/net/codinux/banking/ui/AccountTransaction.sq @@ -0,0 +1,110 @@ +CREATE TABLE IF NOT EXISTS AccountTransaction ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + + amount TEXT NOT NULL, + currency TEXT NOT NULL, + reference TEXT NOT NULL, + + bookingDate TEXT NOT NULL, + valueDate TEXT NOT NULL, + + otherPartyName TEXT, + otherPartyBankCode TEXT, + otherPartyAccountId TEXT, + + bookingText TEXT, + + userSetDisplayName TEXT, + notes TEXT, + + information TEXT, + + statementNumber INTEGER, + sequenceNumber INTEGER, + + openingBalance TEXT, + closingBalance TEXT, + + endToEndReference TEXT, + customerReference TEXT, + mandateReference TEXT, + creditorIdentifier TEXT, + originatorsIdentificationCode TEXT, + compensationAmount TEXT, + originalAmount TEXT, + sepaReference TEXT, + deviantOriginator TEXT, + deviantRecipient TEXT, + referenceWithNoSpecialType TEXT, + primaNotaNumber TEXT, + textKeySupplement TEXT, + + currencyType TEXT, + bookingKey TEXT, + referenceForTheAccountOwner TEXT, + referenceOfTheAccountServicingInstitution TEXT, + supplementaryDetails TEXT, + + transactionReferenceNumber TEXT, + relatedReferenceNumber TEXT +); + + +insertTransaction: +INSERT INTO AccountTransaction( + amount, currency, reference, + bookingDate, valueDate, + otherPartyName, otherPartyBankCode, otherPartyAccountId, + bookingText, + + userSetDisplayName, notes, + + information, + statementNumber, sequenceNumber, + openingBalance, closingBalance, + + endToEndReference, customerReference, mandateReference, + creditorIdentifier, originatorsIdentificationCode, + compensationAmount, originalAmount, + sepaReference, + deviantOriginator, deviantRecipient, + referenceWithNoSpecialType, + primaNotaNumber, textKeySupplement, + + currencyType, bookingKey, + referenceForTheAccountOwner, referenceOfTheAccountServicingInstitution, + supplementaryDetails, + + transactionReferenceNumber, relatedReferenceNumber +) +VALUES( + ?, ?, ?, + ?, ?, + ?, ?, ?, + ?, + + ?, ?, + + ?, + ?, ?, + ?, ?, + + ?, ?, ?, + ?, ?, + ?, ?, + ?, + ?, ?, + ?, + ?, ?, + + ?, ?, + ?, ?, + ?, + + ?, ? +); + + +selectAllTransactions: +SELECT AccountTransaction.* +FROM AccountTransaction; \ No newline at end of file diff --git a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt index 84ff6a4..d9e03a7 100644 --- a/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt +++ b/composeApp/src/desktopMain/kotlin/net/codinux/banking/ui/main.kt @@ -4,9 +4,15 @@ 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.driver.jdbc.sqlite.JdbcSqliteDriver import bankmeister.composeapp.generated.resources.AppIcon_svg import bankmeister.composeapp.generated.resources.Res +import net.codinux.banking.dataaccess.BankmeisterDb +import net.codinux.banking.ui.config.DI +import net.codinux.log.Log import org.jetbrains.compose.resources.painterResource +import java.io.File fun main() = application { Window( @@ -15,6 +21,11 @@ fun main() = application { icon = painterResource(Res.drawable.AppIcon_svg), state = WindowState(position = WindowPosition(Alignment.Center), size = DpSize(900.dp, 800.dp)), ) { + File("data/db").mkdirs() + DI.setRepository(JdbcSqliteDriver("jdbc:sqlite:data/db/Bankmeister.db").apply { + val schema = BankmeisterDb.Schema.synchronous().create(this) + }) + App() } } \ No newline at end of file diff --git a/composeApp/src/desktopTest/kotlin/net/codinux/banking/dataaccess/SqliteBankingRepositoryTest.kt b/composeApp/src/desktopTest/kotlin/net/codinux/banking/dataaccess/SqliteBankingRepositoryTest.kt new file mode 100644 index 0000000..6b951d7 --- /dev/null +++ b/composeApp/src/desktopTest/kotlin/net/codinux/banking/dataaccess/SqliteBankingRepositoryTest.kt @@ -0,0 +1,43 @@ +package net.codinux.banking.dataaccess + +import app.cash.sqldelight.async.coroutines.synchronous +import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver +import kotlinx.coroutines.runBlocking +import kotlinx.datetime.LocalDate +import net.codinux.banking.client.model.AccountTransaction +import net.codinux.banking.client.model.Amount +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 = SqliteBankingRepository(sqlDriver) + + + @Test + fun saveTransaction() = runBlocking { + val transaction = AccountTransaction(Amount("12.45"), "EUR", "Lohn", LocalDate(2024, 5, 7), LocalDate(2024, 6, 15), "Dein Boss") + + underTest.persistAccountTransactions(listOf(transaction)) + + val result = underTest.getAllAccountTransactions() + + assertEquals(1, result.size) + + val persisted = result.first() + assertNotNull(persisted.id) + + assertEquals(transaction.amount, persisted.amount) + assertEquals(transaction.currency, persisted.currency) + assertEquals(transaction.reference, persisted.reference) + assertEquals(transaction.bookingDate, persisted.bookingDate) + assertEquals(transaction.valueDate, persisted.valueDate) + assertEquals(transaction.otherPartyName, persisted.otherPartyName) + } + +} \ No newline at end of file diff --git a/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/MainViewController.kt b/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/MainViewController.kt index 5f6a284..ab2542d 100644 --- a/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/MainViewController.kt +++ b/composeApp/src/iosMain/kotlin/net/codinux/banking/ui/MainViewController.kt @@ -1,5 +1,13 @@ 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.ui.config.DI -fun MainViewController() = ComposeUIViewController { App() } \ No newline at end of file +fun MainViewController() = ComposeUIViewController { + DI.setRepository(NativeSqliteDriver(Database.Schema.synchronous(), "Bankmeister.db")) + + App() +} \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b2e8584..ac7d01c 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,6 +10,8 @@ kotlinx-serializable = "1.7.1" klf = "1.6.0" logback = "1.5.7" +sqlDelight = "2.0.2" + agp = "8.2.2" android-compileSdk = "34" android-minSdk = "24" @@ -36,6 +38,13 @@ kotlinx-serializable = { group = "org.jetbrains.kotlinx", name = "kotlinx-serial klf = { group = "net.codinux.log", name = "klf", version.ref = "klf" } logback = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logback" } +sqldelight-runtime = { module = "app.cash.sqldelight:runtime", version.ref = "sqlDelight" } +sqldelight-coroutines-extensions = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqlDelight" } +sqldelight-paging-extensions = { module = "app.cash.sqldelight:androidx-paging3-extensions", version.ref = "sqlDelight" } +sqldelight-sqlite-driver = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqlDelight" } +sqldelight-android-driver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqlDelight" } +sqldelight-native-driver = { module = "app.cash.sqldelight:native-driver", version.ref = "sqlDelight" } + androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" } androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" } androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" } @@ -57,4 +66,6 @@ kotlinxSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", versi jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } androidLibrary = { id = "com.android.library", version.ref = "agp" } -androidApplication = { id = "com.android.application", version.ref = "agp" } \ No newline at end of file +androidApplication = { id = "com.android.application", version.ref = "agp" } + +sqldelight = { id = "app.cash.sqldelight", version.ref = "sqlDelight" } \ No newline at end of file