feat(shared): add shared module with common DTO models
New Gradle module :shared (pure Kotlin/JVM) containing @Serializable DTO classes for use by both the Android app and future Ktor server. shared/src/main/kotlin/de/krisenvorrat/shared/model/: - InventoryDto: root DTO replacing ExportData (version, categories, locations, items, settings) - CategoryDto, LocationDto, ItemDto, SettingDto: extracted from the former *Export data classes in :app Migration in :app: - ExportData.kt deleted (classes moved to :shared) - ImportExportRepositoryImpl now imports from de.krisenvorrat.shared.model - app/build.gradle.kts adds implementation(project(:shared)) Build config: - libs.versions.toml: added kotlin-jvm plugin entry - build.gradle.kts (root): registered kotlin-jvm plugin - settings.gradle.kts: include(:shared) JSON wire format is unchanged; all 165 existing tests pass. Closes #39
This commit is contained in:
parent
309587bc36
commit
c0c4978ccf
12 changed files with 100 additions and 56 deletions
|
|
@ -71,6 +71,9 @@ dependencies {
|
|||
// Serialization
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
||||
// Shared module
|
||||
implementation(project(":shared"))
|
||||
|
||||
testImplementation(libs.junit)
|
||||
testImplementation(libs.kotlinx.coroutines.test)
|
||||
testImplementation(libs.mockk)
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
package de.krisenvorrat.app.data.export
|
||||
|
||||
import kotlinx.serialization.EncodeDefault
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Serializable
|
||||
internal data class ExportData(
|
||||
@EncodeDefault(EncodeDefault.Mode.ALWAYS) val version: Int = 1,
|
||||
val categories: List<CategoryExport>,
|
||||
val locations: List<LocationExport>,
|
||||
val items: List<ItemExport>,
|
||||
val settings: List<SettingExport>
|
||||
)
|
||||
|
||||
@Serializable
|
||||
internal data class CategoryExport(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
internal data class LocationExport(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
|
||||
@Serializable
|
||||
internal data class ItemExport(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val categoryId: Int,
|
||||
val quantity: Double,
|
||||
val unit: String,
|
||||
val unitPrice: Double,
|
||||
val kcalPer100g: Int?,
|
||||
val expiryDate: String?,
|
||||
val locationId: Int,
|
||||
val minStock: Double,
|
||||
val notes: String,
|
||||
val lastUpdated: Long
|
||||
)
|
||||
|
||||
@Serializable
|
||||
internal data class SettingExport(
|
||||
val key: String,
|
||||
val value: String
|
||||
)
|
||||
|
|
@ -9,6 +9,11 @@ import de.krisenvorrat.app.data.db.entity.ItemEntity
|
|||
import de.krisenvorrat.app.data.db.entity.LocationEntity
|
||||
import de.krisenvorrat.app.data.db.entity.SettingsEntity
|
||||
import de.krisenvorrat.app.domain.repository.ImportExportRepository
|
||||
import de.krisenvorrat.shared.model.CategoryDto
|
||||
import de.krisenvorrat.shared.model.InventoryDto
|
||||
import de.krisenvorrat.shared.model.ItemDto
|
||||
import de.krisenvorrat.shared.model.LocationDto
|
||||
import de.krisenvorrat.shared.model.SettingDto
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.withContext
|
||||
|
|
@ -37,11 +42,11 @@ internal class ImportExportRepositoryImpl @Inject constructor(
|
|||
val items = itemDao.getAll().first()
|
||||
val settings = settingsDao.getAll().first()
|
||||
|
||||
val exportData = ExportData(
|
||||
categories = categories.map { CategoryExport(id = it.id, name = it.name) },
|
||||
locations = locations.map { LocationExport(id = it.id, name = it.name) },
|
||||
val exportData = InventoryDto(
|
||||
categories = categories.map { CategoryDto(id = it.id, name = it.name) },
|
||||
locations = locations.map { LocationDto(id = it.id, name = it.name) },
|
||||
items = items.map { item ->
|
||||
ItemExport(
|
||||
ItemDto(
|
||||
id = item.id,
|
||||
name = item.name,
|
||||
categoryId = item.categoryId,
|
||||
|
|
@ -56,14 +61,14 @@ internal class ImportExportRepositoryImpl @Inject constructor(
|
|||
lastUpdated = item.lastUpdated
|
||||
)
|
||||
},
|
||||
settings = settings.map { SettingExport(key = it.key, value = it.value) }
|
||||
settings = settings.map { SettingDto(key = it.key, value = it.value) }
|
||||
)
|
||||
jsonSerializer.encodeToString(ExportData.serializer(), exportData)
|
||||
jsonSerializer.encodeToString(InventoryDto.serializer(), exportData)
|
||||
}
|
||||
|
||||
override suspend fun importFromJson(json: String): Result<Unit> = withContext(Dispatchers.IO) {
|
||||
runCatching {
|
||||
val exportData = jsonSerializer.decodeFromString<ExportData>(json)
|
||||
val exportData = jsonSerializer.decodeFromString<InventoryDto>(json)
|
||||
check(exportData.version == 1) { "Unsupported export format version: ${exportData.version}" }
|
||||
transaction.execute {
|
||||
categoryDao.upsertAll(exportData.categories.map { CategoryEntity(id = it.id, name = it.name) })
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
plugins {
|
||||
alias(libs.plugins.android.application) apply false
|
||||
alias(libs.plugins.kotlin.jvm) apply false
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.compose) apply false
|
||||
alias(libs.plugins.kotlin.serialization) apply false
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ mockk = { group = "io.mockk", name = "mockk", version.ref = "mockk" }
|
|||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
|
||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
|
|
|
|||
|
|
@ -21,3 +21,4 @@ dependencyResolutionManagement {
|
|||
|
||||
rootProject.name = "krisenvorrat"
|
||||
include(":app")
|
||||
include(":shared")
|
||||
|
|
|
|||
21
shared/build.gradle.kts
Normal file
21
shared/build.gradle.kts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
plugins {
|
||||
alias(libs.plugins.kotlin.jvm)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.kotlinx.serialization.json)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package de.krisenvorrat.shared.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class CategoryDto(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package de.krisenvorrat.shared.model
|
||||
|
||||
import kotlinx.serialization.EncodeDefault
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@Serializable
|
||||
data class InventoryDto(
|
||||
@EncodeDefault(EncodeDefault.Mode.ALWAYS) val version: Int = 1,
|
||||
val categories: List<CategoryDto>,
|
||||
val locations: List<LocationDto>,
|
||||
val items: List<ItemDto>,
|
||||
val settings: List<SettingDto>
|
||||
)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package de.krisenvorrat.shared.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class ItemDto(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val categoryId: Int,
|
||||
val quantity: Double,
|
||||
val unit: String,
|
||||
val unitPrice: Double,
|
||||
val kcalPer100g: Int?,
|
||||
val expiryDate: String?,
|
||||
val locationId: Int,
|
||||
val minStock: Double,
|
||||
val notes: String,
|
||||
val lastUpdated: Long
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package de.krisenvorrat.shared.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class LocationDto(
|
||||
val id: Int,
|
||||
val name: String
|
||||
)
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package de.krisenvorrat.shared.model
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class SettingDto(
|
||||
val key: String,
|
||||
val value: String
|
||||
)
|
||||
Loading…
Reference in a new issue