From 76729430ece3b7e5ef26e795c7d87e1f3a2a9aff Mon Sep 17 00:00:00 2001 From: 2ndbeam <2ndbeam@disroot.org> Date: Mon, 28 Jul 2025 15:11:46 +0300 Subject: [PATCH] Basic Room integration --- app/build.gradle.kts | 7 +++ .../com/mirenkov/ktheightmap/MainActivity.kt | 56 ++++++++++++++----- .../java/com/mirenkov/ktheightmap/Tile.kt | 30 ++++++++++ .../java/com/mirenkov/ktheightmap/TileDB.kt | 28 ++++++++++ .../java/com/mirenkov/ktheightmap/TileDao.kt | 17 ++++++ .../mirenkov/ktheightmap/TileRepository.kt | 20 +++++++ .../com/mirenkov/ktheightmap/TileViewModel.kt | 15 +++++ build.gradle.kts | 1 + gradle/libs.versions.toml | 6 ++ 9 files changed, 166 insertions(+), 14 deletions(-) create mode 100644 app/src/main/java/com/mirenkov/ktheightmap/Tile.kt create mode 100644 app/src/main/java/com/mirenkov/ktheightmap/TileDB.kt create mode 100644 app/src/main/java/com/mirenkov/ktheightmap/TileDao.kt create mode 100644 app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt create mode 100644 app/src/main/java/com/mirenkov/ktheightmap/TileViewModel.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 33ed375..8a647cf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,6 +2,7 @@ plugins { alias(libs.plugins.android.application) alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.compose) + id("com.google.devtools.ksp") } android { @@ -40,6 +41,12 @@ android { } dependencies { + implementation(libs.androidx.room.common.jvm) + implementation(libs.androidx.room.runtime.android) + implementation(libs.androidx.lifecycle.viewmodel.compose.android) + val room_version = "2.7.2" + + ksp("androidx.room:room-compiler:$room_version") implementation(libs.androidx.core.ktx) implementation(libs.androidx.lifecycle.runtime.ktx) diff --git a/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt b/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt index 7ddf23e..f11bc4a 100644 --- a/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt +++ b/app/src/main/java/com/mirenkov/ktheightmap/MainActivity.kt @@ -1,5 +1,6 @@ package com.mirenkov.ktheightmap +import android.app.Application import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -20,31 +21,58 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.tooling.preview.Preview +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner +import androidx.lifecycle.viewmodel.compose.viewModel import com.mirenkov.ktheightmap.ui.theme.KtHeightMapTheme const val TAG = "KtHeightMap" const val TILE_SIZE: Float = 256F +class TileViewModelFactory(val application: Application): + ViewModelProvider.Factory { + override fun create(modelClass: Class): T { + @Suppress("UNCHECKED_CAST") + return TileViewModel(application) as T + } +} + class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContent { - KtHeightMapTheme { - Surface { - Scaffold( - modifier = Modifier.fillMaxSize() - .safeDrawingPadding(), - floatingActionButton = { ToolButton() } - ) { innerPadding -> - MapCanvas( - gridColor = colorScheme.primary, - backColor = colorScheme.background, - modifier = Modifier.padding(innerPadding), - ) - } - } + val owner = LocalViewModelStoreOwner.current + + owner?.let { + val viewModel: TileViewModel = viewModel( + it, + "TileViewModel", + TileViewModelFactory(LocalContext.current.applicationContext as Application) + ) + Main(viewModel) + } + } + } +} + +@Composable +fun Main(vm: TileViewModel = viewModel()) { + KtHeightMapTheme { + Surface { + Scaffold( + modifier = Modifier.fillMaxSize() + .safeDrawingPadding(), + floatingActionButton = { ToolButton() } + ) { innerPadding -> + MapCanvas( + gridColor = colorScheme.primary, + backColor = colorScheme.background, + modifier = Modifier.padding(innerPadding), + ) } } } diff --git a/app/src/main/java/com/mirenkov/ktheightmap/Tile.kt b/app/src/main/java/com/mirenkov/ktheightmap/Tile.kt new file mode 100644 index 0000000..359aa5b --- /dev/null +++ b/app/src/main/java/com/mirenkov/ktheightmap/Tile.kt @@ -0,0 +1,30 @@ +package com.mirenkov.ktheightmap + +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey + +@Entity(tableName = "tiles", primaryKeys = [ "x", "y", "level" ]) +class Tile { + @ColumnInfo(name = "x") + var x: Int = 0 + + @ColumnInfo(name = "y") + var y: Int = 0 + + @ColumnInfo(name = "level") + var level: Int = 0 + + @ColumnInfo(name = "data") + var base64: String? = null + + + + constructor() {} + + constructor(x: Int, y: Int, level: Int) { + this.x = x + this.y = y + this.level = level + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mirenkov/ktheightmap/TileDB.kt b/app/src/main/java/com/mirenkov/ktheightmap/TileDB.kt new file mode 100644 index 0000000..dec6d5f --- /dev/null +++ b/app/src/main/java/com/mirenkov/ktheightmap/TileDB.kt @@ -0,0 +1,28 @@ +package com.mirenkov.ktheightmap + +import android.content.Context +import androidx.room.Database +import androidx.room.Room +import androidx.room.RoomDatabase + +@Database(entities = [Tile::class], version = 1) +abstract class TileDB: RoomDatabase() { + abstract fun tileDao(): TileDao + + companion object { + private var INSTANCE: TileDB? = null + fun getInstance(context: Context): TileDB { + synchronized(this) { + var instance = INSTANCE + if (instance == null) { + instance = Room.databaseBuilder(context.applicationContext, + TileDB::class.java, + "tiledb" + ).fallbackToDestructiveMigration(true).build() + INSTANCE = instance + } + return instance + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mirenkov/ktheightmap/TileDao.kt b/app/src/main/java/com/mirenkov/ktheightmap/TileDao.kt new file mode 100644 index 0000000..60f38f2 --- /dev/null +++ b/app/src/main/java/com/mirenkov/ktheightmap/TileDao.kt @@ -0,0 +1,17 @@ +package com.mirenkov.ktheightmap + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.Query + +@Dao +interface TileDao { + @Query("select * from tiles where x = :x and y = :y and level = :level") + fun getTile(x: Int, y: Int, level: Int): Tile? + + @Insert + fun pushTile(tile: Tile) + + @Query("delete from tiles") + fun clearTiles() +} \ No newline at end of file diff --git a/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt b/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt new file mode 100644 index 0000000..ef3e5e5 --- /dev/null +++ b/app/src/main/java/com/mirenkov/ktheightmap/TileRepository.kt @@ -0,0 +1,20 @@ +package com.mirenkov.ktheightmap + +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers + +class TileRepository(private val tileDao: TileDao) { + private val coroutineScope = CoroutineScope(Dispatchers.Main) + + fun pushTile(tile: Tile) { + tileDao.pushTile(tile) + } + + fun getTile(x: Int, y: Int, level: Int): Tile? { + return tileDao.getTile(x, y, level) + } + + fun clearTiles() { + tileDao.clearTiles() + } +} \ No newline at end of file diff --git a/app/src/main/java/com/mirenkov/ktheightmap/TileViewModel.kt b/app/src/main/java/com/mirenkov/ktheightmap/TileViewModel.kt new file mode 100644 index 0000000..cbd9a14 --- /dev/null +++ b/app/src/main/java/com/mirenkov/ktheightmap/TileViewModel.kt @@ -0,0 +1,15 @@ +package com.mirenkov.ktheightmap + +import android.app.Application +import androidx.compose.runtime.mutableStateOf +import androidx.lifecycle.ViewModel + +class TileViewModel(application: Application): ViewModel() { + private val repository: TileRepository + + init { + val tileDb = TileDB.getInstance(application) + val tileDao = tileDb.tileDao() + repository = TileRepository(tileDao) + } +} \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 952b930..b162aa1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -3,4 +3,5 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.compose) apply false + id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c653bb2..1290105 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -8,6 +8,9 @@ espressoCore = "3.6.1" lifecycleRuntimeKtx = "2.9.2" activityCompose = "1.10.1" composeBom = "2024.09.00" +roomCommonJvm = "2.7.2" +roomRuntimeAndroid = "2.7.2" +lifecycleViewmodelComposeAndroid = "2.9.2" [libraries] androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" } @@ -24,6 +27,9 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" } androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" } androidx-material3 = { group = "androidx.compose.material3", name = "material3" } +androidx-room-common-jvm = { group = "androidx.room", name = "room-common-jvm", version.ref = "roomCommonJvm" } +androidx-room-runtime-android = { group = "androidx.room", name = "room-runtime-android", version.ref = "roomRuntimeAndroid" } +androidx-lifecycle-viewmodel-compose-android = { group = "androidx.lifecycle", name = "lifecycle-viewmodel-compose-android", version.ref = "lifecycleViewmodelComposeAndroid" } [plugins] android-application = { id = "com.android.application", version.ref = "agp" }