diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 34d6d08..ab93a07 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5778b11..008908c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ xmlns:tools="http://schemas.android.com/tools"> +} \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/data/PreferenceRepository.kt b/app/src/main/java/org/nsh07/pomodoro/data/PreferenceRepository.kt new file mode 100644 index 0000000..bf12c5a --- /dev/null +++ b/app/src/main/java/org/nsh07/pomodoro/data/PreferenceRepository.kt @@ -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 + + 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 = + preferenceDao.getIntPreference(key) + + override suspend fun resetSettings() = withContext(ioDispatcher) { + preferenceDao.resetIntPreferences() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt index afbfb1e..c54ac8c 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/AppScreen.kt @@ -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() diff --git a/app/src/main/java/org/nsh07/pomodoro/ui/viewModel/UiViewModel.kt b/app/src/main/java/org/nsh07/pomodoro/ui/viewModel/UiViewModel.kt index ef54923..a423b7c 100644 --- a/app/src/main/java/org/nsh07/pomodoro/ui/viewModel/UiViewModel.kt +++ b/app/src/main/java/org/nsh07/pomodoro/ui/viewModel/UiViewModel.kt @@ -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) + } + } + } } \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 5ba8ae0..f370cb1 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -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 } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index d7e6a71..21cfb54 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -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" }