Skip to content

Commit 8e935e6

Browse files
refactor(core:datastore): Implement real settings storage in core/datastore for theme and language
1 parent bd67899 commit 8e935e6

File tree

12 files changed

+192
-30
lines changed

12 files changed

+192
-30
lines changed

cmp-android/dependencies/prodReleaseRuntimeClasspath.tree.txt

+1
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,7 @@
15261526
| | | +--- org.jetbrains.compose.components:components-resources:1.7.0-rc01 (*)
15271527
| | | +--- org.jetbrains.compose.components:components-ui-tooling-preview:1.7.0-rc01 (*)
15281528
| | | +--- org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.3 (*)
1529+
| | | +--- project :core:datastore (*)
15291530
| | | \--- org.jetbrains.kotlin:kotlin-parcelize-runtime:2.1.0 (*)
15301531
| | +--- org.jetbrains.compose.material3:material3:1.7.0-rc01 (*)
15311532
| | +--- org.jetbrains.compose.foundation:foundation:1.7.0-rc01 (*)

cmp-android/prodRelease-badging.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package: name='cmp.android.app' versionCode='1' versionName='2025.3.3-beta.0.3' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15'
1+
package: name='cmp.android.app' versionCode='1' versionName='2025.3.3-beta.0.2' platformBuildVersionName='15' platformBuildVersionCode='35' compileSdkVersion='35' compileSdkVersionCodename='15'
22
sdkVersion:'26'
33
targetSdkVersion:'34'
44
uses-permission: name='android.permission.INTERNET'

cmp-navigation/src/commonMain/kotlin/cmp/navigation/di/KoinModules.kt

+4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ package cmp.navigation.di
1212
import org.koin.dsl.module
1313
import org.mifos.core.common.di.DispatchersModule
1414
import org.mifos.core.data.di.DataModule
15+
import org.mifos.core.datastore.di.DatastoreModule
16+
import org.mifos.feature.settings.SettingsModule
1517

1618
object KoinModules {
1719
private val dataModule = module {
@@ -25,5 +27,7 @@ object KoinModules {
2527
val allModules = listOf(
2628
dataModule,
2729
dispatcherModule,
30+
DatastoreModule,
31+
SettingsModule,
2832
)
2933
}

core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepository.kt

+3-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,9 @@
99
*/
1010
package org.mifos.core.datastore
1111

12-
import org.mifos.core.datastore.model.SampleUser
12+
import org.mifos.core.datastore.model.AppSettings
1313

1414
interface UserPreferencesRepository {
15-
16-
suspend fun saveUser(key: String, user: SampleUser)
17-
suspend fun getUser(key: String, defaultValue: SampleUser): SampleUser
18-
19-
suspend fun getDoubleNumber(key: String, defaultValue: Double): Double
20-
suspend fun saveDoubleNumber(key: String, number: Double)
15+
suspend fun updateSettings(settings: AppSettings)
16+
suspend fun getSettings(defaultValue: AppSettings): AppSettings
2117
}

core/datastore/src/commonMain/kotlin/org/mifos/core/datastore/UserPreferencesRepositoryImpl.kt

+11-22
Original file line numberDiff line numberDiff line change
@@ -9,39 +9,28 @@
99
*/
1010
package org.mifos.core.datastore
1111

12-
import org.mifos.core.datastore.model.SampleUser
12+
import org.mifos.core.datastore.model.AppSettings
1313
import org.mifos.corebase.datastore.UserPreferencesDataStore
1414

15+
private const val APP_SETTINGS_KEY = "app_settings"
16+
1517
class UserPreferencesRepositoryImpl(
1618
private val dataStore: UserPreferencesDataStore,
1719
) : UserPreferencesRepository {
18-
override suspend fun saveUser(
19-
key: String,
20-
user: SampleUser,
21-
) {
20+
21+
override suspend fun updateSettings(settings: AppSettings) {
2222
dataStore.putValue(
23-
key = key,
24-
value = user,
25-
serializer = SampleUser.serializer(),
23+
key = APP_SETTINGS_KEY,
24+
value = settings,
25+
serializer = AppSettings.serializer(),
2626
)
2727
}
2828

29-
override suspend fun getUser(
30-
key: String,
31-
defaultValue: SampleUser,
32-
): SampleUser {
29+
override suspend fun getSettings(defaultValue: AppSettings): AppSettings {
3330
return dataStore.getValue(
34-
key = key,
31+
key = APP_SETTINGS_KEY,
3532
default = defaultValue,
36-
serializer = SampleUser.serializer(),
33+
serializer = AppSettings.serializer(),
3734
)
3835
}
39-
40-
override suspend fun getDoubleNumber(key: String, defaultValue: Double): Double {
41-
return dataStore.getValue(key, defaultValue)
42-
}
43-
44-
override suspend fun saveDoubleNumber(key: String, number: Double) {
45-
dataStore.putValue(key, number)
46-
}
4736
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See See https://github.com/openMF/kmp-project-template/blob/main/LICENSE
9+
*/
10+
package org.mifos.core.datastore.model
11+
12+
enum class AppLanguage(val code: String, val displayName: String) {
13+
SYSTEM_LANGUAGE("System_Language", "System Language"),
14+
ENGLISH("en", "English"),
15+
HINDI("hi", "हिंदी"),
16+
ARABIC("ar", "عربى"),
17+
URDU("ur", "اُردُو"),
18+
BENGALI("bn", "বাঙালি"),
19+
SPANISH("es", "Español"),
20+
FRENCH("fr", "français"),
21+
INDONESIAN("in", "bahasa Indonesia"),
22+
KHMER("km", "ភាសាខ្មែរ"),
23+
KANNADA("kn", "ಕನ್ನಡ"),
24+
TELUGU("te", "తెలుగు"),
25+
BURMESE("my", "မြန်မာ"),
26+
POLISH("pl", "Polski"),
27+
PORTUGUESE("pt", "Português"),
28+
RUSSIAN("ru", "русский"),
29+
SWAHILI("sw", "Kiswahili"),
30+
FARSI("fa", "فارسی"),
31+
;
32+
33+
companion object {
34+
fun fromCode(code: String): AppLanguage {
35+
return entries.find { it.code.equals(code, ignoreCase = true) } ?: ENGLISH
36+
}
37+
}
38+
39+
override fun toString(): String {
40+
return displayName
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See See https://github.com/openMF/kmp-project-template/blob/main/LICENSE
9+
*/
10+
package org.mifos.core.datastore.model
11+
12+
import kotlinx.serialization.Serializable
13+
14+
@Serializable
15+
data class AppSettings(
16+
val theme: String,
17+
val language: String,
18+
) {
19+
companion object {
20+
val DEFAULT = AppSettings(
21+
theme = AppTheme.SYSTEM_DEFAULT.themeName,
22+
language = AppLanguage.ENGLISH.code,
23+
)
24+
}
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See See https://github.com/openMF/kmp-project-template/blob/main/LICENSE
9+
*/
10+
package org.mifos.core.datastore.model
11+
12+
enum class AppTheme(val themeName: String) {
13+
SYSTEM_DEFAULT("System Default"),
14+
LIGHT("Light"),
15+
DARK("Dark"),
16+
}

feature/settings/build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ kotlin {
2525
implementation(compose.components.resources)
2626
implementation(compose.components.uiToolingPreview)
2727
implementation(libs.kotlinx.serialization.json)
28+
29+
implementation(projects.core.datastore)
2830
}
2931
}
3032
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See See https://github.com/openMF/kmp-project-template/blob/main/LICENSE
9+
*/
10+
package org.mifos.feature.settings
11+
12+
import org.koin.core.module.dsl.viewModelOf
13+
import org.koin.dsl.module
14+
15+
val SettingsModule = module {
16+
viewModelOf(::SettingsViewmodel)
17+
}

feature/settings/src/commonMain/kotlin/org/mifos/feature/settings/SettingsScreen.kt

+32
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,18 @@ import androidx.compose.foundation.layout.Arrangement
1313
import androidx.compose.foundation.layout.Column
1414
import androidx.compose.foundation.layout.fillMaxSize
1515
import androidx.compose.foundation.layout.padding
16+
import androidx.compose.material3.Button
1617
import androidx.compose.material3.Text
1718
import androidx.compose.runtime.Composable
19+
import androidx.compose.runtime.getValue
1820
import androidx.compose.ui.Alignment
1921
import androidx.compose.ui.Modifier
2022
import androidx.compose.ui.text.font.FontWeight
23+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
24+
import org.koin.compose.viewmodel.koinViewModel
25+
import org.mifos.core.datastore.model.AppLanguage
26+
import org.mifos.core.datastore.model.AppSettings
27+
import org.mifos.core.datastore.model.AppTheme
2128
import org.mifos.core.designsystem.component.MifosScaffold
2229

2330
@Composable
@@ -36,6 +43,10 @@ internal fun SettingsScreenContent(
3643
onBackClick: () -> Unit,
3744
modifier: Modifier = Modifier,
3845
) {
46+
val viewmodel: SettingsViewmodel = koinViewModel()
47+
48+
val uiState by viewmodel.settingsUiState.collectAsStateWithLifecycle()
49+
3950
MifosScaffold(
4051
topBarTitle = "Settings",
4152
backPress = onBackClick,
@@ -50,6 +61,27 @@ internal fun SettingsScreenContent(
5061
) {
5162
// SettingsScreenContent
5263
Text(text = "Settings Screen", fontWeight = FontWeight.SemiBold)
64+
Button(onClick = {
65+
viewmodel.updateSettings(
66+
settings = AppSettings(
67+
theme = AppTheme.LIGHT.themeName,
68+
language = AppLanguage.ENGLISH.code,
69+
),
70+
)
71+
}) {
72+
Text(text = "Light")
73+
}
74+
Button(onClick = {
75+
viewmodel.updateSettings(
76+
settings = AppSettings(
77+
theme = AppTheme.DARK.themeName,
78+
language = AppLanguage.ENGLISH.code,
79+
),
80+
)
81+
}) {
82+
Text(text = "Dark")
83+
}
84+
Text(text = "Theme = ${uiState.theme}")
5385
}
5486
}
5587
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See See https://github.com/openMF/kmp-project-template/blob/main/LICENSE
9+
*/
10+
package org.mifos.feature.settings
11+
12+
import androidx.lifecycle.ViewModel
13+
import androidx.lifecycle.viewModelScope
14+
import kotlinx.coroutines.flow.MutableStateFlow
15+
import kotlinx.coroutines.flow.asStateFlow
16+
import kotlinx.coroutines.launch
17+
import org.mifos.core.datastore.UserPreferencesRepository
18+
import org.mifos.core.datastore.model.AppSettings
19+
20+
class SettingsViewmodel(
21+
private val settingsRepository: UserPreferencesRepository,
22+
) : ViewModel() {
23+
private val _settingsUiState = MutableStateFlow(AppSettings.DEFAULT)
24+
val settingsUiState = _settingsUiState.asStateFlow()
25+
26+
private suspend fun getSettings() {
27+
_settingsUiState.value = settingsRepository.getSettings(
28+
defaultValue = AppSettings.DEFAULT,
29+
)
30+
}
31+
32+
fun updateSettings(settings: AppSettings) {
33+
viewModelScope.launch {
34+
settingsRepository.updateSettings(settings)
35+
getSettings()
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)