Add a basic room database system for further features
This commit is contained in:
@@ -5,6 +5,7 @@ plugins {
|
||||
alias(libs.plugins.kotlin.android)
|
||||
alias(libs.plugins.kotlin.compose)
|
||||
alias(libs.plugins.kotlin.serialization)
|
||||
alias(libs.plugins.ksp)
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -59,6 +60,10 @@ dependencies {
|
||||
implementation(libs.androidx.navigation3.runtime)
|
||||
implementation(libs.androidx.navigation3.ui)
|
||||
|
||||
implementation(libs.androidx.room.runtime)
|
||||
implementation(libs.androidx.room.ktx)
|
||||
ksp(libs.androidx.room.compiler)
|
||||
|
||||
testImplementation(libs.junit)
|
||||
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:name=".TomatoApplication"
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
|
||||
13
app/src/main/java/org/nsh07/pomodoro/TomatoApplication.kt
Normal file
13
app/src/main/java/org/nsh07/pomodoro/TomatoApplication.kt
Normal file
@@ -0,0 +1,13 @@
|
||||
package org.nsh07.pomodoro
|
||||
|
||||
import android.app.Application
|
||||
import org.nsh07.pomodoro.data.AppContainer
|
||||
import org.nsh07.pomodoro.data.DefaultAppContainer
|
||||
|
||||
class TomatoApplication : Application() {
|
||||
lateinit var container: AppContainer
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
container = DefaultAppContainer(this)
|
||||
}
|
||||
}
|
||||
17
app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt
Normal file
17
app/src/main/java/org/nsh07/pomodoro/data/AppContainer.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package org.nsh07.pomodoro.data
|
||||
|
||||
import android.content.Context
|
||||
|
||||
interface AppContainer {
|
||||
val appPreferencesRepository: AppPreferenceRepository
|
||||
}
|
||||
|
||||
class DefaultAppContainer(context: Context) : AppContainer {
|
||||
|
||||
override val appPreferencesRepository: AppPreferenceRepository by lazy {
|
||||
AppPreferenceRepository(
|
||||
AppDatabase.getDatabase(context).preferenceDao()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
29
app/src/main/java/org/nsh07/pomodoro/data/AppDatabase.kt
Normal file
29
app/src/main/java/org/nsh07/pomodoro/data/AppDatabase.kt
Normal file
@@ -0,0 +1,29 @@
|
||||
package org.nsh07.pomodoro.data
|
||||
|
||||
import android.content.Context
|
||||
import androidx.room.Database
|
||||
import androidx.room.Room
|
||||
import androidx.room.RoomDatabase
|
||||
|
||||
@Database(
|
||||
entities = [IntPreference::class],
|
||||
version = 1
|
||||
)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
abstract fun preferenceDao(): PreferenceDao
|
||||
|
||||
companion object {
|
||||
|
||||
@Volatile
|
||||
private var Instance: AppDatabase? = null
|
||||
|
||||
fun getDatabase(context: Context): AppDatabase {
|
||||
return Instance ?: synchronized(this) {
|
||||
Room.databaseBuilder(context, AppDatabase::class.java, "app_database")
|
||||
.build()
|
||||
.also { Instance = it }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
app/src/main/java/org/nsh07/pomodoro/data/Preference.kt
Normal file
11
app/src/main/java/org/nsh07/pomodoro/data/Preference.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package org.nsh07.pomodoro.data
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "int_preference")
|
||||
data class IntPreference(
|
||||
@PrimaryKey
|
||||
val key: String,
|
||||
val value: Int
|
||||
)
|
||||
19
app/src/main/java/org/nsh07/pomodoro/data/PreferenceDao.kt
Normal file
19
app/src/main/java/org/nsh07/pomodoro/data/PreferenceDao.kt
Normal file
@@ -0,0 +1,19 @@
|
||||
package org.nsh07.pomodoro.data
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface PreferenceDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun insertIntPreference(preference: IntPreference)
|
||||
|
||||
@Query("DELETE FROM int_preference")
|
||||
suspend fun resetIntPreferences()
|
||||
|
||||
@Query("SELECT value FROM int_preference WHERE `key` = :key")
|
||||
fun getIntPreference(key: String): Flow<Int?>
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package org.nsh07.pomodoro.data
|
||||
|
||||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
interface PreferencesRepository {
|
||||
suspend fun saveIntPreference(key: String, value: Int)
|
||||
|
||||
fun getIntPreference(key: String): Flow<Int?>
|
||||
|
||||
suspend fun resetSettings()
|
||||
}
|
||||
|
||||
class AppPreferenceRepository(
|
||||
private val preferenceDao: PreferenceDao,
|
||||
private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
|
||||
): PreferencesRepository {
|
||||
override suspend fun saveIntPreference(key: String, value: Int) =
|
||||
withContext(ioDispatcher) {
|
||||
preferenceDao.insertIntPreference(IntPreference(key, value))
|
||||
}
|
||||
|
||||
override fun getIntPreference(key: String): Flow<Int?> =
|
||||
preferenceDao.getIntPreference(key)
|
||||
|
||||
override suspend fun resetSettings() = withContext(ioDispatcher) {
|
||||
preferenceDao.resetIntPreferences()
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ import org.nsh07.pomodoro.ui.viewModel.UiViewModel
|
||||
@Composable
|
||||
fun AppScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: UiViewModel = viewModel()
|
||||
viewModel: UiViewModel = viewModel(factory = UiViewModel.Factory)
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
||||
val remainingTime by viewModel.time.collectAsStateWithLifecycle()
|
||||
|
||||
@@ -2,7 +2,11 @@ package org.nsh07.pomodoro.ui.viewModel
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory.Companion.APPLICATION_KEY
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import androidx.lifecycle.viewmodel.initializer
|
||||
import androidx.lifecycle.viewmodel.viewModelFactory
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
@@ -10,10 +14,14 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import org.nsh07.pomodoro.TomatoApplication
|
||||
import org.nsh07.pomodoro.data.AppPreferenceRepository
|
||||
import java.util.Locale
|
||||
import kotlin.math.ceil
|
||||
|
||||
class UiViewModel : ViewModel() {
|
||||
class UiViewModel(
|
||||
private val preferenceRepository: AppPreferenceRepository
|
||||
) : ViewModel() {
|
||||
val focusTime = 25 * 60 * 1000
|
||||
val shortBreakTime = 5 * 60 * 1000
|
||||
val longBreakTime = 15 * 60 * 1000
|
||||
@@ -153,6 +161,8 @@ class UiViewModel : ViewModel() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
toggleTimer()
|
||||
} else {
|
||||
_uiState.update { currentState ->
|
||||
currentState.copy(
|
||||
@@ -172,4 +182,14 @@ class UiViewModel : ViewModel() {
|
||||
val sec = (ceil(t / 1000.0).toInt() % 60)
|
||||
return String.format(locale = Locale.getDefault(), "%02d:%02d", min, sec)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val Factory: ViewModelProvider.Factory = viewModelFactory {
|
||||
initializer {
|
||||
val application = (this[APPLICATION_KEY] as TomatoApplication)
|
||||
val appPreferenceRepository = application.container.appPreferencesRepository
|
||||
UiViewModel(preferenceRepository = appPreferenceRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,4 +4,5 @@ plugins {
|
||||
alias(libs.plugins.kotlin.android) apply false
|
||||
alias(libs.plugins.kotlin.compose) apply false
|
||||
alias(libs.plugins.kotlin.serialization) apply false
|
||||
alias(libs.plugins.ksp) apply false
|
||||
}
|
||||
@@ -1,37 +1,43 @@
|
||||
[versions]
|
||||
activityCompose = "1.10.1"
|
||||
agp = "8.11.0"
|
||||
kotlin = "2.2.0"
|
||||
composeBom = "2025.06.02"
|
||||
coreKtx = "1.16.0"
|
||||
espressoCore = "3.6.1"
|
||||
junit = "4.13.2"
|
||||
junitVersion = "1.2.1"
|
||||
espressoCore = "3.6.1"
|
||||
kotlin = "2.2.0"
|
||||
ksp = "2.2.0-2.0.2"
|
||||
lifecycleRuntimeKtx = "2.9.1"
|
||||
activityCompose = "1.10.1"
|
||||
composeBom = "2025.06.02"
|
||||
navigation3Runtime = "1.0.0-alpha05"
|
||||
room = "2.7.2"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version.ref = "lifecycleRuntimeKtx" }
|
||||
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }
|
||||
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3Runtime" }
|
||||
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3Runtime" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||
androidx-activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activityCompose" }
|
||||
androidx-compose-bom = { group = "androidx.compose", name = "compose-bom-alpha", version.ref = "composeBom" }
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||
androidx-lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "lifecycleRuntimeKtx" }
|
||||
androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version.ref = "lifecycleRuntimeKtx" }
|
||||
androidx-lifecycle-viewmodel-compose = { module = "androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleRuntimeKtx" }
|
||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "navigation3Runtime" }
|
||||
androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "navigation3Runtime" }
|
||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
|
||||
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
|
||||
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
|
||||
androidx-ui = { group = "androidx.compose.ui", name = "ui" }
|
||||
androidx-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
|
||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||
androidx-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
|
||||
androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
|
||||
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" }
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
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"}
|
||||
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
|
||||
|
||||
Reference in New Issue
Block a user