From 84f7ccb5f71652a0c2825d236cb426d795ad3b75 Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Sat, 11 Jan 2025 11:31:27 +0530 Subject: [PATCH 01/11] Converted dataStore to KMP --- core/datastore/build.gradle.kts | 23 +- .../{main => androidMain}/AndroidManifest.xml | 0 .../core/datastore/PreferencesHelper.kt | 249 ++++++++++++++++++ .../core/datastore/di/PreferenceModule.kt | 19 ++ .../mobile/core/datastore/model/AppTheme.kt | 18 ++ .../core/datastore/model/MifosAppLanguage.kt | 42 +++ .../core/datastore/PreferencesHelper.kt | 235 ----------------- 7 files changed, 343 insertions(+), 243 deletions(-) rename core/datastore/src/{main => androidMain}/AndroidManifest.xml (100%) create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/MifosAppLanguage.kt delete mode 100644 core/datastore/src/main/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index d2ac74110c..994b5dbb96 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -7,10 +7,10 @@ * * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md */ + plugins { - alias(libs.plugins.mifos.android.library) - alias(libs.plugins.mifos.android.hilt) - alias(libs.plugins.kotlin.serialization) + alias(libs.plugins.mifos.kmp.library) + id("kotlinx-serialization") } android { @@ -22,9 +22,16 @@ android { } -dependencies { - implementation(projects.core.common) - implementation(projects.core.model) +kotlin{ + + sourceSets{ + commonMain.dependencies { + implementation(libs.multiplatform.settings) + implementation(libs.multiplatform.settings.serialization) + implementation(libs.multiplatform.settings.coroutines) + implementation(libs.kotlinx.coroutines.core) + implementation(libs.kotlinx.serialization.core) + } + } +} - -} \ No newline at end of file diff --git a/core/datastore/src/main/AndroidManifest.xml b/core/datastore/src/androidMain/AndroidManifest.xml similarity index 100% rename from core/datastore/src/main/AndroidManifest.xml rename to core/datastore/src/androidMain/AndroidManifest.xml diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt new file mode 100644 index 0000000000..b5b953af78 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt @@ -0,0 +1,249 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore + +import com.russhwolf.settings.ObservableSettings +import com.russhwolf.settings.Settings +import com.russhwolf.settings.get +import com.russhwolf.settings.set +import kotlinx.coroutines.channels.awaitClose +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.callbackFlow +import org.mifos.mobile.core.datastore.model.AppTheme +import org.mifos.mobile.core.datastore.model.MifosAppLanguage + +class PreferencesHelper(private val settings: Settings) { + + fun clear() { + val keysToPreserve = setOf(BASE_URL, TENANT) + settings.keys.filter { it !in keysToPreserve } + .forEach { key -> + settings.remove(key) + } + } + + private fun getInt(preferenceKey: String?, preferenceDefaultValue: Int?): Int? { + return if (preferenceKey != null && preferenceDefaultValue != null) { + settings[preferenceKey, preferenceDefaultValue] + } else { + null + } + } + + private fun putInt(preferenceKey: String?, preferenceValue: Int?) { + if (preferenceKey != null && preferenceValue != null) { + settings[preferenceKey] = preferenceValue + } + } + + private fun getLong(preferenceKey: String?, preferenceDefaultValue: Long?): Long? { + return if (preferenceKey == null || preferenceDefaultValue == null) { + null + } else { + settings[preferenceKey, preferenceDefaultValue] + } + } + + private fun putLong(preferenceKey: String?, preferenceValue: Long?) { + if (preferenceKey != null && preferenceValue != null) { + settings[preferenceKey] = preferenceValue + } + } + + private fun getString(preferenceKey: String?, preferenceDefaultValue: String?): String? { + return if (preferenceKey == null || preferenceDefaultValue == null) { + null + } else { + settings[preferenceKey, preferenceDefaultValue] + } + } + + private fun putString(preferenceKey: String?, preferenceValue: String?) { + if (preferenceKey != null && preferenceValue != null) { + settings[preferenceKey] = preferenceValue + } + } + + private fun getBoolean(preferenceKey: String?, preferenceDefaultValue: Boolean?): Boolean? { + return if (preferenceKey == null || preferenceDefaultValue == null) { + null + } else { + settings[preferenceKey, preferenceDefaultValue] + } + } + + private fun putBoolean(preferenceKey: String?, preferenceValue: Boolean?) { + if (preferenceKey != null && preferenceValue != null) { + settings[preferenceKey] = preferenceValue + } + } + + fun saveToken(token: String) { + putString(TOKEN, token) + } + + fun clearToken() { + putString(TOKEN, "") + } + + private val token: String? + get() = getString(TOKEN, "") + + val isAuthenticated: Boolean + get() = !token.isNullOrEmpty() + + var userId: Long? + get() = getLong(USER_ID, -1) + set(value) { + putLong(USER_ID, value) + } + + var username: String? + get() = getString(USER_NAME, "") + set(value) { + putString(USER_NAME, value) + } + + var tenant: String? + get() = getString(TENANT, DEFAULT_TENANT) + set(value) { + putString(TENANT, value) + } + + var passcode: String? + get() = getString(PASSCODE, "") + set(value) { + putString(PASSCODE, value) + } + + var clientId: Long? + get() = getLong(CLIENT_ID, -1) + set(value) { + putLong(CLIENT_ID, value) + } + + var userName: String? + get() = getString(USER_NAME, "") + set(value) { + putString(USER_NAME, value) + } + + var clientName: String? + get() = getString(CLIENT_NAME, "") + set(value) { + putString(CLIENT_NAME, value) + } + + var officeName: String? + get() = getString(OFFICE_NAME, "") + set(value) { + putString(OFFICE_NAME, value) + } + + fun setOverviewState(state: Boolean?) { + putBoolean(OVERVIEW_STATE, state) + } + + fun overviewState(): Boolean? = getBoolean(OVERVIEW_STATE, true) + + fun saveGcmToken(token: String?) { + putString(GCM_TOKEN, token) + } + + var userProfileImage: String? + get() = getString(PROFILE_IMAGE, null.toString()) + set(value) { + putString(PROFILE_IMAGE, value) + } + + val gcmToken: String? + get() = getString(GCM_TOKEN, "") + + fun setSentTokenToServer(state: Boolean?) { + putBoolean(SENT_TOKEN_TO_SERVER, state) + } + + fun sentTokenToServerState(): Boolean? = getBoolean(SENT_TOKEN_TO_SERVER, false) + + fun updateConfiguration(baseUrl: String?, tenant: String?) { + settings.apply { + putString(BASE_URL, baseUrl) + putString(TENANT, tenant) + } + } + + val baseUrl: String? + get() = getString(BASE_URL, DEFAULT_BASE_URL) + + var appTheme: Int? + get() = getInt(APPLICATION_THEME, AppTheme.SYSTEM.ordinal) + set(value) { + putInt(APPLICATION_THEME, value) + } + + var language: String? + get() = getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code) + ?: MifosAppLanguage.SYSTEM_LANGUAGE.code + set(value) { + putString(LANGUAGE_TYPE, value) + } + + var isDefaultSystemLanguage: Boolean? + get() = getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) + set(value) { + putBoolean(DEFAULT_SYSTEM_LANGUAGE, value) + } + + companion object { + private const val USER_ID = "preferences_user_id" + private const val TOKEN = "preferences_token" + private const val CLIENT_ID = "preferences_client" + private const val OFFICE_NAME = "preferences_office_name" + private const val USER_NAME = "preferences_user_name" + const val PASSCODE = "preferences_passcode" + private const val OVERVIEW_STATE = "preferences_overview_state" + private const val SENT_TOKEN_TO_SERVER = "sentTokenToServer" + private const val GCM_TOKEN = "gcm_token" + const val TENANT = "preferences_base_tenant" + const val BASE_URL = "preferences_base_url_key" + private const val PROFILE_IMAGE = "preferences_profile_image" + const val CLIENT_NAME = "client_name" + const val APPLICATION_THEME = "application_theme" + const val LANGUAGE_TYPE = "language_type" + const val DEFAULT_SYSTEM_LANGUAGE = "default_system_language" + + private const val DEFAULT_TENANT = "default" + private const val DEFAULT_BASE_URL = "https://demo.mifos.community" + } + + fun getStringFlowForKey(keyForString: String, settings: ObservableSettings): Flow = callbackFlow { + trySend(settings.getStringOrNull(keyForString)) + + val listener = settings.addStringOrNullListener(keyForString) { newValue -> + trySend(newValue) + } + + awaitClose { + listener.deactivate() + } + } + + fun getIntFlowForKey(keyForInt: String, settings: ObservableSettings): Flow = callbackFlow { + trySend(settings.getIntOrNull(keyForInt)) + + val listener = settings.addIntOrNullListener(keyForInt) { newValue -> + trySend(newValue) + } + + awaitClose { + listener.deactivate() + } + } +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt new file mode 100644 index 0000000000..c23b210e99 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore.di + +import com.russhwolf.settings.Settings +import org.koin.dsl.module +import org.mifos.mobile.core.datastore.PreferencesHelper + +val PreferencesModule = module { + single { Settings() } + single { PreferencesHelper(settings = get()) } +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt new file mode 100644 index 0000000000..c2e1ee93f9 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore.model + +enum class AppTheme( + val themeName: String, +) { + SYSTEM(themeName = "System Theme"), + LIGHT(themeName = "Light Theme"), + DARK(themeName = "Dark Theme"), +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/MifosAppLanguage.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/MifosAppLanguage.kt new file mode 100644 index 0000000000..18b96b9f81 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/MifosAppLanguage.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore.model + +enum class MifosAppLanguage(val code: String, val displayName: String) { + SYSTEM_LANGUAGE("System_Language", "System Language"), + ENGLISH("en", "English"), + HINDI("hi", "हिंदी"), + ARABIC("ar", "عربى"), + URDU("ur", "اُردُو"), + BENGALI("bn", "বাঙালি"), + SPANISH("es", "Español"), + FRENCH("fr", "français"), + INDONESIAN("in", "bahasa Indonesia"), + KHMER("km", "ភាសាខ្មែរ"), + KANNADA("kn", "ಕನ್ನಡ"), + TELUGU("te", "తెలుగు"), + BURMESE("my", "မြန်မာ"), + POLISH("pl", "Polski"), + PORTUGUESE("pt", "Português"), + RUSSIAN("ru", "русский"), + SWAHILI("sw", "Kiswahili"), + FARSI("fa", "فارسی"), + ; + + companion object { + fun fromCode(code: String): MifosAppLanguage { + return entries.find { it.code.equals(code, ignoreCase = true) } ?: ENGLISH + } + } + + override fun toString(): String { + return displayName + } +} diff --git a/core/datastore/src/main/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/main/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt deleted file mode 100644 index 54428fc847..0000000000 --- a/core/datastore/src/main/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2025 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md - */ -package org.mifos.mobile.core.datastore - -import android.content.Context -import android.content.SharedPreferences -import android.preference.PreferenceManager -import android.text.TextUtils -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.buffer -import kotlinx.coroutines.flow.callbackFlow -import org.mifos.mobile.core.model.enums.AppTheme -import org.mifos.mobile.core.model.enums.MifosAppLanguage -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class PreferencesHelper @Inject constructor(@ApplicationContext context: Context?) { - private val sharedPreferences: SharedPreferences? = - PreferenceManager.getDefaultSharedPreferences(context) - - fun clear() { - val editor = sharedPreferences?.edit() - // prevent deletion of url and tenant - sharedPreferences?.all?.keys?.forEach { key -> - if (key != BASE_URL && key != TENANT) { - editor?.remove(key) - } - } - editor?.apply() - } - - fun getInt(preferenceKey: String?, preferenceDefaultValue: Int): Int? { - return sharedPreferences?.getInt(preferenceKey, preferenceDefaultValue) - } - - fun putInt(preferenceKey: String?, preferenceValue: Int) { - sharedPreferences?.edit()?.putInt(preferenceKey, preferenceValue)?.apply() - } - - fun getLong(preferenceKey: String?, preferenceDefaultValue: Long): Long? { - return sharedPreferences?.getLong(preferenceKey, preferenceDefaultValue) - } - - fun putLong(preferenceKey: String?, preferenceValue: Long) { - sharedPreferences?.edit()?.putLong(preferenceKey, preferenceValue)?.apply() - } - - fun getString(preferenceKey: String?, preferenceDefaultValue: String?): String? { - return sharedPreferences?.getString(preferenceKey, preferenceDefaultValue) - } - - private fun putString(preferenceKey: String?, preferenceValue: String?) { - sharedPreferences?.edit()?.putString(preferenceKey, preferenceValue)?.apply() - } - - fun putBoolean(preferenceKey: String?, preferenceValue: Boolean) { - sharedPreferences?.edit()?.putBoolean(preferenceKey, preferenceValue)?.apply() - } - - fun getBoolean(preferenceKey: String?, preferenceDefaultValue: Boolean): Boolean? { - return sharedPreferences?.getBoolean(preferenceKey, preferenceDefaultValue) - } - - fun saveToken(token: String?) { - putString(TOKEN, token) - } - - fun clearToken() { - putString(TOKEN, "") - } - - val token: String? - get() = getString(TOKEN, "") - - val isAuthenticated: Boolean - get() = !TextUtils.isEmpty(token) - - var userId: Long? - get() = getLong(USER_ID, -1) - set(id) { - id?.let { - putLong(USER_ID, it) - } - } - - var tenant: String? - get() = getString(TENANT, DEFAULT_TENANT) - set(tenant) { - putString(TENANT, tenant) - } - - var passcode: String? - get() = getString(PASSCODE, "") - set(passcode) { - putString(PASSCODE, passcode) - } - - var clientId: Long? - get() = getLong(CLIENT_ID, -1) - set(clientId) { - clientId?.let { - putLong(CLIENT_ID, it) - } - } - - var userName: String? - get() = getString(USER_NAME, "") - set(userName) { - putString(USER_NAME, userName) - } - - var clientName: String? - get() = getString(CLIENT_NAME, "") - set(clientName) { - putString(CLIENT_NAME, clientName) - } - - var officeName: String? - get() = getString(OFFICE_NAME, "") - set(officeName) { - putString(OFFICE_NAME, officeName) - } - - fun setOverviewState(state: Boolean) { - putBoolean(OVERVIEW_STATE, state) - } - - fun overviewState(): Boolean? { - return getBoolean(OVERVIEW_STATE, true) - } - - fun saveGcmToken(token: String?) { - putString(GCM_TOKEN, token) - } - - var userProfileImage: String? - get() = getString(PROFILE_IMAGE, null) - set(image) { - putString(PROFILE_IMAGE, image) - } - - val gcmToken: String? - get() = getString(GCM_TOKEN, "") - - fun setSentTokenToServer(sentTokenToServer: Boolean) { - putBoolean(SENT_TOKEN_TO_SERVER, sentTokenToServer) - } - - fun sentTokenToServerState(): Boolean? { - return getBoolean(SENT_TOKEN_TO_SERVER, false) - } - - fun updateConfiguration(baseUrl: String?, tenant: String?) { - sharedPreferences?.edit() - ?.putString(BASE_URL, baseUrl) - ?.putString(TENANT, tenant) - ?.apply() - } - - val baseUrl: String? - get() = getString(BASE_URL, DEFAULT_BASE_URL) - - var appTheme - get() = getInt(APPLICATION_THEME, AppTheme.SYSTEM.ordinal) ?: AppTheme.SYSTEM.ordinal - set(value) { - putInt(APPLICATION_THEME, value) - } - - var language - get() = getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code) - ?: MifosAppLanguage.SYSTEM_LANGUAGE.code - set(language) { - putString(LANGUAGE_TYPE, language) - } - - var isDefaultSystemLanguage - get() = getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) == true - set(value) { - putBoolean(DEFAULT_SYSTEM_LANGUAGE, value) - } - - companion object { - private const val USER_ID = "preferences_user_id" - private const val TOKEN = "preferences_token" - private const val CLIENT_ID = "preferences_client" - private const val OFFICE_NAME = "preferences_office_name" - private const val USER_NAME = "preferences_user_name" - const val PASSCODE = "preferences_passcode" - private const val OVERVIEW_STATE = "preferences_overview_state" - private const val SENT_TOKEN_TO_SERVER = "sentTokenToServer" - private const val GCM_TOKEN = "gcm_token" - const val TENANT = "preferences_base_tenant" - const val BASE_URL = "preferences_base_url_key" - private const val PROFILE_IMAGE = "preferences_profile_image" - const val CLIENT_NAME = "client_name" - const val APPLICATION_THEME = "application_theme" - const val LANGUAGE_TYPE = "language_type" - const val DEFAULT_SYSTEM_LANGUAGE = "default_system_language" - - private const val DEFAULT_TENANT = "default" - private const val DEFAULT_BASE_URL = "https://demo.mifos.community" - } - - fun getStringFlowForKey(keyForString: String) = callbackFlow { - val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> - if (keyForString == key) { - trySend(getString(keyForString, null)) - } - } - sharedPreferences?.registerOnSharedPreferenceChangeListener(listener) - send(getString(keyForString, null)) - awaitClose { sharedPreferences?.unregisterOnSharedPreferenceChangeListener(listener) } - }.buffer(Channel.Factory.UNLIMITED) - - fun getIntFlowForKey(keyForInt: String) = callbackFlow { - val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> - if (keyForInt == key) { - trySend(getInt(keyForInt, -1)) - } - } - sharedPreferences?.registerOnSharedPreferenceChangeListener(listener) - send(getInt(keyForInt, -1)) - awaitClose { sharedPreferences?.unregisterOnSharedPreferenceChangeListener(listener) } - }.buffer(Channel.Factory.UNLIMITED) -} From af009a16a499ee8b2b2e051ffdedade02e8afeb9 Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Sat, 11 Jan 2025 12:02:03 +0530 Subject: [PATCH 02/11] Update dataStore module for KMP conversion --- androidApp/dependencies/demoDebugRuntimeClasspath.txt | 8 ++++++++ androidApp/dependencies/demoReleaseRuntimeClasspath.txt | 8 ++++++++ androidApp/dependencies/prodDebugRuntimeClasspath.txt | 8 ++++++++ androidApp/dependencies/prodReleaseRuntimeClasspath.txt | 8 ++++++++ 4 files changed, 32 insertions(+) diff --git a/androidApp/dependencies/demoDebugRuntimeClasspath.txt b/androidApp/dependencies/demoDebugRuntimeClasspath.txt index b6e6f4a169..1df8f65b29 100644 --- a/androidApp/dependencies/demoDebugRuntimeClasspath.txt +++ b/androidApp/dependencies/demoDebugRuntimeClasspath.txt @@ -175,6 +175,14 @@ com.google.j2objc:j2objc-annotations:1.3 com.google.maps.android:maps-compose:4.4.1 com.google.maps.android:maps-ktx:5.0.0 com.google.zxing:core:3.5.3 +com.russhwolf:multiplatform-settings-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-coroutines-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-coroutines:1.2.0 +com.russhwolf:multiplatform-settings-no-arg-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-no-arg:1.2.0 +com.russhwolf:multiplatform-settings-serialization-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-serialization:1.2.0 +com.russhwolf:multiplatform-settings:1.2.0 com.squareup.okhttp3:logging-interceptor:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 com.squareup.okio:okio-jvm:3.6.0 diff --git a/androidApp/dependencies/demoReleaseRuntimeClasspath.txt b/androidApp/dependencies/demoReleaseRuntimeClasspath.txt index a2d888fbbc..1ee00633bf 100644 --- a/androidApp/dependencies/demoReleaseRuntimeClasspath.txt +++ b/androidApp/dependencies/demoReleaseRuntimeClasspath.txt @@ -170,6 +170,14 @@ com.google.j2objc:j2objc-annotations:1.3 com.google.maps.android:maps-compose:4.4.1 com.google.maps.android:maps-ktx:5.0.0 com.google.zxing:core:3.5.3 +com.russhwolf:multiplatform-settings-android:1.2.0 +com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 +com.russhwolf:multiplatform-settings-coroutines:1.2.0 +com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 +com.russhwolf:multiplatform-settings-no-arg:1.2.0 +com.russhwolf:multiplatform-settings-serialization-android:1.2.0 +com.russhwolf:multiplatform-settings-serialization:1.2.0 +com.russhwolf:multiplatform-settings:1.2.0 com.squareup.okhttp3:logging-interceptor:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 com.squareup.okio:okio-jvm:3.6.0 diff --git a/androidApp/dependencies/prodDebugRuntimeClasspath.txt b/androidApp/dependencies/prodDebugRuntimeClasspath.txt index b6e6f4a169..1df8f65b29 100644 --- a/androidApp/dependencies/prodDebugRuntimeClasspath.txt +++ b/androidApp/dependencies/prodDebugRuntimeClasspath.txt @@ -175,6 +175,14 @@ com.google.j2objc:j2objc-annotations:1.3 com.google.maps.android:maps-compose:4.4.1 com.google.maps.android:maps-ktx:5.0.0 com.google.zxing:core:3.5.3 +com.russhwolf:multiplatform-settings-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-coroutines-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-coroutines:1.2.0 +com.russhwolf:multiplatform-settings-no-arg-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-no-arg:1.2.0 +com.russhwolf:multiplatform-settings-serialization-android-debug:1.2.0 +com.russhwolf:multiplatform-settings-serialization:1.2.0 +com.russhwolf:multiplatform-settings:1.2.0 com.squareup.okhttp3:logging-interceptor:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 com.squareup.okio:okio-jvm:3.6.0 diff --git a/androidApp/dependencies/prodReleaseRuntimeClasspath.txt b/androidApp/dependencies/prodReleaseRuntimeClasspath.txt index a2d888fbbc..1ee00633bf 100644 --- a/androidApp/dependencies/prodReleaseRuntimeClasspath.txt +++ b/androidApp/dependencies/prodReleaseRuntimeClasspath.txt @@ -170,6 +170,14 @@ com.google.j2objc:j2objc-annotations:1.3 com.google.maps.android:maps-compose:4.4.1 com.google.maps.android:maps-ktx:5.0.0 com.google.zxing:core:3.5.3 +com.russhwolf:multiplatform-settings-android:1.2.0 +com.russhwolf:multiplatform-settings-coroutines-android:1.2.0 +com.russhwolf:multiplatform-settings-coroutines:1.2.0 +com.russhwolf:multiplatform-settings-no-arg-android:1.2.0 +com.russhwolf:multiplatform-settings-no-arg:1.2.0 +com.russhwolf:multiplatform-settings-serialization-android:1.2.0 +com.russhwolf:multiplatform-settings-serialization:1.2.0 +com.russhwolf:multiplatform-settings:1.2.0 com.squareup.okhttp3:logging-interceptor:4.12.0 com.squareup.okhttp3:okhttp:4.12.0 com.squareup.okio:okio-jvm:3.6.0 From e837a6ff4b23a87517226a365e4be4f2f8732361 Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Sat, 11 Jan 2025 16:43:59 +0530 Subject: [PATCH 03/11] Added Some data classes --- .../core/datastore/PreferencesHelper.kt | 60 ++++++++++++++++--- .../core/datastore/model/AppSettings.kt | 9 +++ .../mifos/mobile/core/datastore/model/User.kt | 6 ++ .../mobile/core/datastore/model/UserData.kt | 7 +++ 4 files changed, 74 insertions(+), 8 deletions(-) create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt index b5b953af78..5d0ffc364a 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt @@ -16,8 +16,11 @@ import com.russhwolf.settings.set import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow +import org.mifos.mobile.core.datastore.model.AppSettings import org.mifos.mobile.core.datastore.model.AppTheme import org.mifos.mobile.core.datastore.model.MifosAppLanguage +import org.mifos.mobile.core.datastore.model.User +import org.mifos.mobile.core.datastore.model.UserData class PreferencesHelper(private val settings: Settings) { @@ -96,7 +99,7 @@ class PreferencesHelper(private val settings: Settings) { private val token: String? get() = getString(TOKEN, "") - val isAuthenticated: Boolean + var isAuthenticated: Boolean = false get() = !token.isNullOrEmpty() var userId: Long? @@ -105,7 +108,7 @@ class PreferencesHelper(private val settings: Settings) { putLong(USER_ID, value) } - var username: String? + var userName: String? get() = getString(USER_NAME, "") set(value) { putString(USER_NAME, value) @@ -129,12 +132,6 @@ class PreferencesHelper(private val settings: Settings) { putLong(CLIENT_ID, value) } - var userName: String? - get() = getString(USER_NAME, "") - set(value) { - putString(USER_NAME, value) - } - var clientName: String? get() = getString(CLIENT_NAME, "") set(value) { @@ -201,6 +198,53 @@ class PreferencesHelper(private val settings: Settings) { putBoolean(DEFAULT_SYSTEM_LANGUAGE, value) } + fun getUserData(): UserData { + return UserData( + clientId = clientId, + userName = userName, + isAuthenticated = isAuthenticated + + ) + } + + fun saveUserData(userData: UserData) { + clientId = userData.clientId + userName = userData.userName + isAuthenticated=userData.isAuthenticated + } + + fun getUser(): User { + return User( + userId = userId, + userName = userName, + ) + } + + fun saveUser(user: User) { + userId = user.userId + userName = user.userName + + } + + fun getAppSettings(): AppSettings { + return AppSettings( + tenant = tenant, + baseUrl = baseUrl, + passcode = passcode, + appTheme = appTheme, + language = language + ) + } + + fun saveAppSettings(appSettings: AppSettings) { + putString(TENANT, appSettings.tenant) + putString(BASE_URL, appSettings.baseUrl) + putString(PASSCODE, appSettings.passcode) + putInt(APPLICATION_THEME, appSettings.appTheme) + putString(LANGUAGE_TYPE, appSettings.language) + } + + companion object { private const val USER_ID = "preferences_user_id" private const val TOKEN = "preferences_token" diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt new file mode 100644 index 0000000000..27018aab36 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt @@ -0,0 +1,9 @@ +package org.mifos.mobile.core.datastore.model + +data class AppSettings( + val tenant: String?, + val baseUrl: String?, + val passcode: String?, + val appTheme: Int?, + val language: String?, +) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt new file mode 100644 index 0000000000..30b179cd77 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt @@ -0,0 +1,6 @@ +package org.mifos.mobile.core.datastore.model + +data class User( + val userName: String?, + val userId: Long?, +) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt new file mode 100644 index 0000000000..025cc26ff6 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt @@ -0,0 +1,7 @@ +package org.mifos.mobile.core.datastore.model + +data class UserData( + val isAuthenticated: Boolean, + val userName: String?, + val clientId: Long?, +) \ No newline at end of file From 9018f282be7517641314df76f0fa8d380c57f785 Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Sat, 11 Jan 2025 16:52:13 +0530 Subject: [PATCH 04/11] Added Some data classes --- .../mifos/mobile/core/datastore/PreferencesHelper.kt | 8 +++----- .../mifos/mobile/core/datastore/model/AppSettings.kt | 9 +++++++++ .../org/mifos/mobile/core/datastore/model/User.kt | 9 +++++++++ .../org/mifos/mobile/core/datastore/model/UserData.kt | 11 ++++++++++- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt index 5d0ffc364a..a14a6b1825 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt @@ -202,7 +202,7 @@ class PreferencesHelper(private val settings: Settings) { return UserData( clientId = clientId, userName = userName, - isAuthenticated = isAuthenticated + isAuthenticated = isAuthenticated, ) } @@ -210,7 +210,7 @@ class PreferencesHelper(private val settings: Settings) { fun saveUserData(userData: UserData) { clientId = userData.clientId userName = userData.userName - isAuthenticated=userData.isAuthenticated + isAuthenticated = userData.isAuthenticated } fun getUser(): User { @@ -223,7 +223,6 @@ class PreferencesHelper(private val settings: Settings) { fun saveUser(user: User) { userId = user.userId userName = user.userName - } fun getAppSettings(): AppSettings { @@ -232,7 +231,7 @@ class PreferencesHelper(private val settings: Settings) { baseUrl = baseUrl, passcode = passcode, appTheme = appTheme, - language = language + language = language, ) } @@ -244,7 +243,6 @@ class PreferencesHelper(private val settings: Settings) { putString(LANGUAGE_TYPE, appSettings.language) } - companion object { private const val USER_ID = "preferences_user_id" private const val TOKEN = "preferences_token" diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt index 27018aab36..23192b32fc 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ package org.mifos.mobile.core.datastore.model data class AppSettings( diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt index 30b179cd77..765ce40705 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt @@ -1,3 +1,12 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ package org.mifos.mobile.core.datastore.model data class User( diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt index 025cc26ff6..22b1776704 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt @@ -1,7 +1,16 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ package org.mifos.mobile.core.datastore.model data class UserData( val isAuthenticated: Boolean, val userName: String?, val clientId: Long?, -) \ No newline at end of file +) From b94c9ca2d3a01a9e8ff6ae7670cafe0034239733 Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Sat, 11 Jan 2025 18:32:38 +0530 Subject: [PATCH 05/11] Updated --- .../core/datastore/PreferencesHelper.kt | 177 ++++++------------ .../core/datastore/model/AppSettings.kt | 19 +- .../mobile/core/datastore/model/AppTheme.kt | 8 +- .../mifos/mobile/core/datastore/model/User.kt | 15 -- .../mobile/core/datastore/model/UserData.kt | 5 +- 5 files changed, 77 insertions(+), 147 deletions(-) delete mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt index a14a6b1825..fb22e345c6 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt @@ -19,7 +19,6 @@ import kotlinx.coroutines.flow.callbackFlow import org.mifos.mobile.core.datastore.model.AppSettings import org.mifos.mobile.core.datastore.model.AppTheme import org.mifos.mobile.core.datastore.model.MifosAppLanguage -import org.mifos.mobile.core.datastore.model.User import org.mifos.mobile.core.datastore.model.UserData class PreferencesHelper(private val settings: Settings) { @@ -32,170 +31,116 @@ class PreferencesHelper(private val settings: Settings) { } } - private fun getInt(preferenceKey: String?, preferenceDefaultValue: Int?): Int? { - return if (preferenceKey != null && preferenceDefaultValue != null) { - settings[preferenceKey, preferenceDefaultValue] - } else { - null - } - } - - private fun putInt(preferenceKey: String?, preferenceValue: Int?) { - if (preferenceKey != null && preferenceValue != null) { - settings[preferenceKey] = preferenceValue - } - } - private fun getLong(preferenceKey: String?, preferenceDefaultValue: Long?): Long? { - return if (preferenceKey == null || preferenceDefaultValue == null) { - null - } else { - settings[preferenceKey, preferenceDefaultValue] - } - } - - private fun putLong(preferenceKey: String?, preferenceValue: Long?) { - if (preferenceKey != null && preferenceValue != null) { - settings[preferenceKey] = preferenceValue - } - } - - private fun getString(preferenceKey: String?, preferenceDefaultValue: String?): String? { - return if (preferenceKey == null || preferenceDefaultValue == null) { - null - } else { - settings[preferenceKey, preferenceDefaultValue] - } - } - - private fun putString(preferenceKey: String?, preferenceValue: String?) { - if (preferenceKey != null && preferenceValue != null) { - settings[preferenceKey] = preferenceValue - } - } - - private fun getBoolean(preferenceKey: String?, preferenceDefaultValue: Boolean?): Boolean? { - return if (preferenceKey == null || preferenceDefaultValue == null) { - null - } else { - settings[preferenceKey, preferenceDefaultValue] - } - } - - private fun putBoolean(preferenceKey: String?, preferenceValue: Boolean?) { - if (preferenceKey != null && preferenceValue != null) { - settings[preferenceKey] = preferenceValue - } - } fun saveToken(token: String) { - putString(TOKEN, token) + settings.putString(TOKEN, token) } fun clearToken() { - putString(TOKEN, "") + settings.putString(TOKEN, "") } private val token: String? - get() = getString(TOKEN, "") + get() = settings.getString(TOKEN, "") var isAuthenticated: Boolean = false get() = !token.isNullOrEmpty() - var userId: Long? - get() = getLong(USER_ID, -1) + var userId: Long + get() = settings.getLong(USER_ID, -1) set(value) { - putLong(USER_ID, value) + settings.putLong(USER_ID, value) } - var userName: String? - get() = getString(USER_NAME, "") + var userName: String + get() = settings.getString(USER_NAME, "") set(value) { - putString(USER_NAME, value) + settings.putString(USER_NAME, value) } - var tenant: String? - get() = getString(TENANT, DEFAULT_TENANT) + var tenant: String + get() = settings.getString(TENANT, DEFAULT_TENANT) set(value) { - putString(TENANT, value) + settings.putString(TENANT, value) } - var passcode: String? - get() = getString(PASSCODE, "") + var passcode: String + get() = settings.getString(PASSCODE, "") set(value) { - putString(PASSCODE, value) + settings.putString(PASSCODE, value) } - var clientId: Long? - get() = getLong(CLIENT_ID, -1) + var clientId: Long + get() = settings.getLong(CLIENT_ID, -1) set(value) { - putLong(CLIENT_ID, value) + settings.putLong(CLIENT_ID, value) } - var clientName: String? - get() = getString(CLIENT_NAME, "") + var clientName: String + get() = settings.getString(CLIENT_NAME, "") set(value) { - putString(CLIENT_NAME, value) + settings.putString(CLIENT_NAME, value) } - var officeName: String? - get() = getString(OFFICE_NAME, "") + var officeName: String + get() = settings.getString(OFFICE_NAME, "") set(value) { - putString(OFFICE_NAME, value) + settings.putString(OFFICE_NAME, value) } - fun setOverviewState(state: Boolean?) { - putBoolean(OVERVIEW_STATE, state) + fun setOverviewState(state: Boolean) { + settings.putBoolean(OVERVIEW_STATE, state) } - fun overviewState(): Boolean? = getBoolean(OVERVIEW_STATE, true) + fun overviewState(): Boolean = settings.getBoolean(OVERVIEW_STATE, true) - fun saveGcmToken(token: String?) { - putString(GCM_TOKEN, token) + fun saveGcmToken(token: String) { + settings.putString(GCM_TOKEN, token) } - var userProfileImage: String? - get() = getString(PROFILE_IMAGE, null.toString()) + var userProfileImage: String + get() = settings.getString(PROFILE_IMAGE, null.toString()) set(value) { - putString(PROFILE_IMAGE, value) + settings.putString(PROFILE_IMAGE, value) } - val gcmToken: String? - get() = getString(GCM_TOKEN, "") + val gcmToken: String + get() = settings.getString(GCM_TOKEN, "") - fun setSentTokenToServer(state: Boolean?) { - putBoolean(SENT_TOKEN_TO_SERVER, state) + fun setSentTokenToServer(state: Boolean) { + settings.putBoolean(SENT_TOKEN_TO_SERVER, state) } - fun sentTokenToServerState(): Boolean? = getBoolean(SENT_TOKEN_TO_SERVER, false) + fun sentTokenToServerState(): Boolean = settings.getBoolean(SENT_TOKEN_TO_SERVER, false) - fun updateConfiguration(baseUrl: String?, tenant: String?) { + fun updateConfiguration(baseUrl: String, tenant: String) { settings.apply { putString(BASE_URL, baseUrl) putString(TENANT, tenant) } } - val baseUrl: String? - get() = getString(BASE_URL, DEFAULT_BASE_URL) + val baseUrl: String + get() = settings.getString(BASE_URL, DEFAULT_BASE_URL) - var appTheme: Int? - get() = getInt(APPLICATION_THEME, AppTheme.SYSTEM.ordinal) + var appTheme: AppTheme + get() = AppTheme.fromOrdinal(settings.getInt(APPLICATION_THEME, AppTheme.SYSTEM.ordinal)) set(value) { - putInt(APPLICATION_THEME, value) + settings.putInt(APPLICATION_THEME, value.ordinal) } - var language: String? - get() = getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code) + var language: String + get() = settings.getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code) ?: MifosAppLanguage.SYSTEM_LANGUAGE.code set(value) { - putString(LANGUAGE_TYPE, value) + settings.putString(LANGUAGE_TYPE, value) } - var isDefaultSystemLanguage: Boolean? - get() = getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) + var isDefaultSystemLanguage: Boolean + get() = settings.getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) set(value) { - putBoolean(DEFAULT_SYSTEM_LANGUAGE, value) + settings.putBoolean(DEFAULT_SYSTEM_LANGUAGE, value) } fun getUserData(): UserData { @@ -203,7 +148,7 @@ class PreferencesHelper(private val settings: Settings) { clientId = clientId, userName = userName, isAuthenticated = isAuthenticated, - + userId = userId ) } @@ -213,34 +158,20 @@ class PreferencesHelper(private val settings: Settings) { isAuthenticated = userData.isAuthenticated } - fun getUser(): User { - return User( - userId = userId, - userName = userName, - ) - } - - fun saveUser(user: User) { - userId = user.userId - userName = user.userName - } - fun getAppSettings(): AppSettings { return AppSettings( tenant = tenant, baseUrl = baseUrl, passcode = passcode, appTheme = appTheme, - language = language, ) } fun saveAppSettings(appSettings: AppSettings) { - putString(TENANT, appSettings.tenant) - putString(BASE_URL, appSettings.baseUrl) - putString(PASSCODE, appSettings.passcode) - putInt(APPLICATION_THEME, appSettings.appTheme) - putString(LANGUAGE_TYPE, appSettings.language) + settings.putString(TENANT, appSettings.tenant) + settings.putString(BASE_URL, appSettings.baseUrl) + appSettings.passcode?.let { settings.putString(PASSCODE, it) } + settings.putInt(APPLICATION_THEME, appSettings.appTheme.ordinal) } companion object { diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt index 23192b32fc..dba970599e 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt @@ -10,9 +10,16 @@ package org.mifos.mobile.core.datastore.model data class AppSettings( - val tenant: String?, - val baseUrl: String?, - val passcode: String?, - val appTheme: Int?, - val language: String?, -) + val tenant: String, + val baseUrl: String, + val passcode: String? = null, + val appTheme: AppTheme = AppTheme.SYSTEM, +) { + companion object { + fun default() = AppSettings( + tenant = "default_tenant", + baseUrl = "https://default.url", + appTheme = AppTheme.SYSTEM, + ) + } +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt index c2e1ee93f9..fa990ad6ca 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt @@ -14,5 +14,11 @@ enum class AppTheme( ) { SYSTEM(themeName = "System Theme"), LIGHT(themeName = "Light Theme"), - DARK(themeName = "Dark Theme"), + DARK(themeName = "Dark Theme"); + + companion object { + fun fromOrdinal(ordinal: Int): AppTheme { + return entries.firstOrNull { it.ordinal == ordinal } ?: SYSTEM + } + } } diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt deleted file mode 100644 index 765ce40705..0000000000 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/User.kt +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright 2025 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md - */ -package org.mifos.mobile.core.datastore.model - -data class User( - val userName: String?, - val userId: Long?, -) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt index 22b1776704..acb73bd1c7 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt @@ -11,6 +11,7 @@ package org.mifos.mobile.core.datastore.model data class UserData( val isAuthenticated: Boolean, - val userName: String?, - val clientId: Long?, + val userName: String, + val clientId: Long, + val userId: Long, ) From 4bf625ce1a6c82bc9e331f7e7e99b2f6dd71fb4c Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Sat, 11 Jan 2025 18:39:13 +0530 Subject: [PATCH 06/11] Updated --- .../org/mifos/mobile/core/datastore/PreferencesHelper.kt | 4 +--- .../kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt | 3 ++- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt index fb22e345c6..e9234b22b5 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt @@ -31,8 +31,6 @@ class PreferencesHelper(private val settings: Settings) { } } - - fun saveToken(token: String) { settings.putString(TOKEN, token) } @@ -148,7 +146,7 @@ class PreferencesHelper(private val settings: Settings) { clientId = clientId, userName = userName, isAuthenticated = isAuthenticated, - userId = userId + userId = userId, ) } diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt index fa990ad6ca..b65b7fe47d 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt @@ -14,7 +14,8 @@ enum class AppTheme( ) { SYSTEM(themeName = "System Theme"), LIGHT(themeName = "Light Theme"), - DARK(themeName = "Dark Theme"); + DARK(themeName = "Dark Theme"), + ; companion object { fun fromOrdinal(ordinal: Int): AppTheme { From f4d75b66af66a2c05839b8d1b40f65e88ba9725a Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Mon, 13 Jan 2025 10:21:52 +0530 Subject: [PATCH 07/11] Refactored PreferenceHelper --- .../mifos/mobile/core/datastore/DataState.kt | 30 +++ .../mobile/core/datastore/PreferenceHelper.kt | 105 +++++++++ .../core/datastore/PreferencesHelper.kt | 220 ------------------ .../datastore/UserPreferenceDataSource.kt | 144 ++++++++++++ .../datastore/UserPreferencesRepository.kt | 42 ++++ .../core/datastore/model/AppSettings.kt | 9 +- .../mobile/core/datastore/model/AppTheme.kt | 7 - .../mobile/core/datastore/model/UserData.kt | 20 +- 8 files changed, 344 insertions(+), 233 deletions(-) create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt delete mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt create mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepository.kt diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt new file mode 100644 index 0000000000..474ac98d4a --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore + +// Should be deleted once common module is migrated +sealed class DataState { + abstract val data: T? + + data object Loading : DataState() { + override val data: Nothing? get() = null + } + + data class Success( + override val data: T, + ) : DataState() + + data class Error( + val exception: Throwable, + override val data: T? = null, + ) : DataState() { + val message = exception.message.toString() + } +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt new file mode 100644 index 0000000000..a658c9d934 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt @@ -0,0 +1,105 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore + +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.stateIn +import org.mifos.mobile.core.datastore.model.AppSettings +import org.mifos.mobile.core.datastore.model.AppTheme +import org.mifos.mobile.core.datastore.model.UserData + +class PreferenceHelper( + private val preferenceManager: UserPreferenceDataSource, + unconfinedDispatcher: CoroutineDispatcher, +) : UserPreferencesRepository { + private val unconfinedScope = CoroutineScope(unconfinedDispatcher) + + override val userInfo: Flow + get() = preferenceManager.userInfo + + override val settingsInfo: Flow + get() = preferenceManager.settingsInfo + + override val appTheme: StateFlow + get() = preferenceManager.appTheme.stateIn( + scope = unconfinedScope, + initialValue = null, + started = SharingStarted.Eagerly, + ) + override val token: StateFlow + get() = preferenceManager.token.stateIn( + scope = unconfinedScope, + initialValue = null, + started = SharingStarted.Eagerly, + ) + + override val clientId: StateFlow + get() = preferenceManager.clientId.stateIn( + scope = unconfinedScope, + initialValue = null, + started = SharingStarted.Eagerly, + ) + + override val profileImage: String? + get() = preferenceManager.getProfileImage() + + override suspend fun updateToken(token: String): DataState { + return try { + val result = preferenceManager.updateToken(token) + DataState.Success(result) + } catch (e: Exception) { + DataState.Error(e) + } + } + + override suspend fun updateTheme(theme: AppTheme): DataState { + return try { + val result = preferenceManager.updateTheme(theme) + DataState.Success(result) + } catch (e: Exception) { + DataState.Error(e) + } + } + + override suspend fun updateUser(user: UserData): DataState { + return try { + val result = preferenceManager.updateUserInfo(user) + DataState.Success(result) + } catch (e: Exception) { + DataState.Error(e) + } + } + + override suspend fun updateSettings(appSettings: AppSettings): DataState { + return try { + val result = preferenceManager.updateSettingsInfo(appSettings) + DataState.Success(result) + } catch (e: Exception) { + DataState.Error(e) + } + } + + override suspend fun updateProfileImage(image: String): DataState { + return try { + val result = preferenceManager.updateProfileImage(image) + DataState.Success(result) + } catch (e: Exception) { + DataState.Error(e) + } + } + + override suspend fun logOut() { + preferenceManager.clearInfo() + } +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt deleted file mode 100644 index e9234b22b5..0000000000 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferencesHelper.kt +++ /dev/null @@ -1,220 +0,0 @@ -/* - * Copyright 2025 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md - */ -package org.mifos.mobile.core.datastore - -import com.russhwolf.settings.ObservableSettings -import com.russhwolf.settings.Settings -import com.russhwolf.settings.get -import com.russhwolf.settings.set -import kotlinx.coroutines.channels.awaitClose -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.callbackFlow -import org.mifos.mobile.core.datastore.model.AppSettings -import org.mifos.mobile.core.datastore.model.AppTheme -import org.mifos.mobile.core.datastore.model.MifosAppLanguage -import org.mifos.mobile.core.datastore.model.UserData - -class PreferencesHelper(private val settings: Settings) { - - fun clear() { - val keysToPreserve = setOf(BASE_URL, TENANT) - settings.keys.filter { it !in keysToPreserve } - .forEach { key -> - settings.remove(key) - } - } - - fun saveToken(token: String) { - settings.putString(TOKEN, token) - } - - fun clearToken() { - settings.putString(TOKEN, "") - } - - private val token: String? - get() = settings.getString(TOKEN, "") - - var isAuthenticated: Boolean = false - get() = !token.isNullOrEmpty() - - var userId: Long - get() = settings.getLong(USER_ID, -1) - set(value) { - settings.putLong(USER_ID, value) - } - - var userName: String - get() = settings.getString(USER_NAME, "") - set(value) { - settings.putString(USER_NAME, value) - } - - var tenant: String - get() = settings.getString(TENANT, DEFAULT_TENANT) - set(value) { - settings.putString(TENANT, value) - } - - var passcode: String - get() = settings.getString(PASSCODE, "") - set(value) { - settings.putString(PASSCODE, value) - } - - var clientId: Long - get() = settings.getLong(CLIENT_ID, -1) - set(value) { - settings.putLong(CLIENT_ID, value) - } - - var clientName: String - get() = settings.getString(CLIENT_NAME, "") - set(value) { - settings.putString(CLIENT_NAME, value) - } - - var officeName: String - get() = settings.getString(OFFICE_NAME, "") - set(value) { - settings.putString(OFFICE_NAME, value) - } - - fun setOverviewState(state: Boolean) { - settings.putBoolean(OVERVIEW_STATE, state) - } - - fun overviewState(): Boolean = settings.getBoolean(OVERVIEW_STATE, true) - - fun saveGcmToken(token: String) { - settings.putString(GCM_TOKEN, token) - } - - var userProfileImage: String - get() = settings.getString(PROFILE_IMAGE, null.toString()) - set(value) { - settings.putString(PROFILE_IMAGE, value) - } - - val gcmToken: String - get() = settings.getString(GCM_TOKEN, "") - - fun setSentTokenToServer(state: Boolean) { - settings.putBoolean(SENT_TOKEN_TO_SERVER, state) - } - - fun sentTokenToServerState(): Boolean = settings.getBoolean(SENT_TOKEN_TO_SERVER, false) - - fun updateConfiguration(baseUrl: String, tenant: String) { - settings.apply { - putString(BASE_URL, baseUrl) - putString(TENANT, tenant) - } - } - - val baseUrl: String - get() = settings.getString(BASE_URL, DEFAULT_BASE_URL) - - var appTheme: AppTheme - get() = AppTheme.fromOrdinal(settings.getInt(APPLICATION_THEME, AppTheme.SYSTEM.ordinal)) - set(value) { - settings.putInt(APPLICATION_THEME, value.ordinal) - } - - var language: String - get() = settings.getString(LANGUAGE_TYPE, MifosAppLanguage.ENGLISH.code) - ?: MifosAppLanguage.SYSTEM_LANGUAGE.code - set(value) { - settings.putString(LANGUAGE_TYPE, value) - } - - var isDefaultSystemLanguage: Boolean - get() = settings.getBoolean(DEFAULT_SYSTEM_LANGUAGE, false) - set(value) { - settings.putBoolean(DEFAULT_SYSTEM_LANGUAGE, value) - } - - fun getUserData(): UserData { - return UserData( - clientId = clientId, - userName = userName, - isAuthenticated = isAuthenticated, - userId = userId, - ) - } - - fun saveUserData(userData: UserData) { - clientId = userData.clientId - userName = userData.userName - isAuthenticated = userData.isAuthenticated - } - - fun getAppSettings(): AppSettings { - return AppSettings( - tenant = tenant, - baseUrl = baseUrl, - passcode = passcode, - appTheme = appTheme, - ) - } - - fun saveAppSettings(appSettings: AppSettings) { - settings.putString(TENANT, appSettings.tenant) - settings.putString(BASE_URL, appSettings.baseUrl) - appSettings.passcode?.let { settings.putString(PASSCODE, it) } - settings.putInt(APPLICATION_THEME, appSettings.appTheme.ordinal) - } - - companion object { - private const val USER_ID = "preferences_user_id" - private const val TOKEN = "preferences_token" - private const val CLIENT_ID = "preferences_client" - private const val OFFICE_NAME = "preferences_office_name" - private const val USER_NAME = "preferences_user_name" - const val PASSCODE = "preferences_passcode" - private const val OVERVIEW_STATE = "preferences_overview_state" - private const val SENT_TOKEN_TO_SERVER = "sentTokenToServer" - private const val GCM_TOKEN = "gcm_token" - const val TENANT = "preferences_base_tenant" - const val BASE_URL = "preferences_base_url_key" - private const val PROFILE_IMAGE = "preferences_profile_image" - const val CLIENT_NAME = "client_name" - const val APPLICATION_THEME = "application_theme" - const val LANGUAGE_TYPE = "language_type" - const val DEFAULT_SYSTEM_LANGUAGE = "default_system_language" - - private const val DEFAULT_TENANT = "default" - private const val DEFAULT_BASE_URL = "https://demo.mifos.community" - } - - fun getStringFlowForKey(keyForString: String, settings: ObservableSettings): Flow = callbackFlow { - trySend(settings.getStringOrNull(keyForString)) - - val listener = settings.addStringOrNullListener(keyForString) { newValue -> - trySend(newValue) - } - - awaitClose { - listener.deactivate() - } - } - - fun getIntFlowForKey(keyForInt: String, settings: ObservableSettings): Flow = callbackFlow { - trySend(settings.getIntOrNull(keyForInt)) - - val listener = settings.addIntOrNullListener(keyForInt) { newValue -> - trySend(newValue) - } - - awaitClose { - listener.deactivate() - } - } -} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt new file mode 100644 index 0000000000..d696ec1126 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + +package org.mifos.mobile.core.datastore + +import com.russhwolf.settings.ExperimentalSettingsApi +import com.russhwolf.settings.Settings +import com.russhwolf.settings.serialization.decodeValue +import com.russhwolf.settings.serialization.decodeValueOrNull +import com.russhwolf.settings.serialization.encodeValue +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.withContext +import kotlinx.serialization.ExperimentalSerializationApi +import org.mifos.mobile.core.datastore.model.AppSettings +import org.mifos.mobile.core.datastore.model.AppTheme +import org.mifos.mobile.core.datastore.model.UserData + +private const val USER_DATA = "userData" +private const val APP_SETTINGS = "appSettings" + +class UserPreferenceDataSource( + private val settings: Settings, + private val dispatcher: CoroutineDispatcher, +) { + + private val _userInfo = MutableStateFlow( + settings.decodeValue( + key = USER_DATA, + serializer = UserData.serializer(), + defaultValue = settings.decodeValueOrNull( + key = USER_DATA, + serializer = UserData.serializer(), + ) ?: UserData.DEFAULT, + ), + ) + + private val _settingsInfo = MutableStateFlow( + settings.decodeValue( + key = APP_SETTINGS, + serializer = AppSettings.serializer(), + defaultValue = settings.decodeValueOrNull( + key = APP_SETTINGS, + serializer = AppSettings.serializer(), + ) ?: AppSettings.DEFAULT, + ), + ) + + val token = _userInfo.map { + it.base64EncodedAuthenticationKey + } + + val userInfo = _userInfo + + val settingsInfo = _settingsInfo + + val clientId = _userInfo.map { it.clientId } + + val appTheme = _settingsInfo.map { it.appTheme } + + suspend fun updateSettingsInfo(appSettings: AppSettings) { + withContext(dispatcher) { + settings.putSettingsPreference(appSettings) + _settingsInfo.value = appSettings + } + } + + suspend fun updateUserInfo(user: UserData) { + withContext(dispatcher) { + settings.putUserPreference(user) + _userInfo.value = user + } + } + + suspend fun updateToken(token: String) { + withContext(dispatcher) { + settings.putUserPreference( + UserData.DEFAULT.copy( + base64EncodedAuthenticationKey = token, + ), + ) + _userInfo.value = UserData.DEFAULT.copy( + base64EncodedAuthenticationKey = token, + ) + } + } + + suspend fun updateTheme(theme: AppTheme) { + withContext(dispatcher) { + settings.putSettingsPreference( + AppSettings.DEFAULT.copy( + appTheme = theme, + ), + ) + _settingsInfo.value = AppSettings.DEFAULT.copy( + appTheme = theme, + ) + } + } + + fun updateProfileImage(image: String) { + settings.putString(PROFILE_IMAGE, image) + } + + fun getProfileImage(): String? { + return settings.getString(PROFILE_IMAGE, "").ifEmpty { null } + } + + suspend fun clearInfo() { + withContext(dispatcher) { + settings.clear() + } + } + + companion object { + private const val PROFILE_IMAGE = "preferences_profile_image" + } +} + +@OptIn(ExperimentalSerializationApi::class) +private fun Settings.putUserPreference(user: UserData) { + encodeValue( + key = USER_DATA, + serializer = UserData.serializer(), + value = user, + ) +} + +private fun Settings.putSettingsPreference(settings: AppSettings) { + encodeValue( + key = APP_SETTINGS, + serializer = AppSettings.serializer(), + value = settings, + ) +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepository.kt new file mode 100644 index 0000000000..af03136e28 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepository.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2025 Mifos Initiative + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + * + * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md + */ +package org.mifos.mobile.core.datastore + +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow +import org.mifos.mobile.core.datastore.model.AppSettings +import org.mifos.mobile.core.datastore.model.AppTheme +import org.mifos.mobile.core.datastore.model.UserData + +interface UserPreferencesRepository { + val userInfo: Flow + + val settingsInfo: Flow + + val token: StateFlow + + val clientId: StateFlow + + val appTheme: StateFlow + + val profileImage: String? + + suspend fun updateToken(token: String): DataState + + suspend fun updateTheme(theme: AppTheme): DataState + + suspend fun updateUser(user: UserData): DataState + + suspend fun updateSettings(appSettings: AppSettings): DataState + + suspend fun updateProfileImage(image: String): DataState + + suspend fun logOut(): Unit +} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt index dba970599e..737ed9e11d 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt @@ -9,6 +9,9 @@ */ package org.mifos.mobile.core.datastore.model +import kotlinx.serialization.Serializable + +@Serializable data class AppSettings( val tenant: String, val baseUrl: String, @@ -16,9 +19,9 @@ data class AppSettings( val appTheme: AppTheme = AppTheme.SYSTEM, ) { companion object { - fun default() = AppSettings( - tenant = "default_tenant", - baseUrl = "https://default.url", + val DEFAULT = AppSettings( + tenant = "default", + baseUrl = "https://demo.mifos.community", appTheme = AppTheme.SYSTEM, ) } diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt index b65b7fe47d..c2e1ee93f9 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppTheme.kt @@ -15,11 +15,4 @@ enum class AppTheme( SYSTEM(themeName = "System Theme"), LIGHT(themeName = "Light Theme"), DARK(themeName = "Dark Theme"), - ; - - companion object { - fun fromOrdinal(ordinal: Int): AppTheme { - return entries.firstOrNull { it.ordinal == ordinal } ?: SYSTEM - } - } } diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt index acb73bd1c7..59123f47db 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/UserData.kt @@ -9,9 +9,23 @@ */ package org.mifos.mobile.core.datastore.model +import kotlinx.serialization.Serializable + +@Serializable data class UserData( - val isAuthenticated: Boolean, + val userId: Long, val userName: String, val clientId: Long, - val userId: Long, -) + val isAuthenticated: Boolean, + val base64EncodedAuthenticationKey: String, +) { + companion object { + val DEFAULT = UserData( + userId = -1, + userName = "", + clientId = -1, + isAuthenticated = false, + base64EncodedAuthenticationKey = "", + ) + } +} From c7bc4e4f3c51670f6acf0a33c4556453bd6be4cb Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Mon, 13 Jan 2025 10:39:04 +0530 Subject: [PATCH 08/11] Refactored PreferenceHelper --- .../mobile/core/datastore/PreferenceHelper.kt | 3 +- ...Source.kt => UserPreferencesDataSource.kt} | 2 +- .../core/datastore/di/PreferenceModule.kt | 31 +++++++++++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) rename core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/{UserPreferenceDataSource.kt => UserPreferencesDataSource.kt} (99%) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt index a658c9d934..c97ce02067 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt @@ -20,7 +20,8 @@ import org.mifos.mobile.core.datastore.model.AppTheme import org.mifos.mobile.core.datastore.model.UserData class PreferenceHelper( - private val preferenceManager: UserPreferenceDataSource, + private val preferenceManager: UserPreferencesDataSource, + private val ioDispatcher: CoroutineDispatcher, unconfinedDispatcher: CoroutineDispatcher, ) : UserPreferencesRepository { private val unconfinedScope = CoroutineScope(unconfinedDispatcher) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesDataSource.kt similarity index 99% rename from core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt rename to core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesDataSource.kt index d696ec1126..12cd51e1fa 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferenceDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesDataSource.kt @@ -28,7 +28,7 @@ import org.mifos.mobile.core.datastore.model.UserData private const val USER_DATA = "userData" private const val APP_SETTINGS = "appSettings" -class UserPreferenceDataSource( +class UserPreferencesDataSource( private val settings: Settings, private val dispatcher: CoroutineDispatcher, ) { diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt index c23b210e99..c9a12eeb6d 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt @@ -10,10 +10,35 @@ package org.mifos.mobile.core.datastore.di import com.russhwolf.settings.Settings +import org.koin.core.qualifier.named import org.koin.dsl.module -import org.mifos.mobile.core.datastore.PreferencesHelper +import org.mifos.mobile.core.datastore.PreferenceHelper +import org.mifos.mobile.core.datastore.UserPreferencesDataSource +import org.mifos.mobile.core.datastore.UserPreferencesRepository + val PreferencesModule = module { - single { Settings() } - single { PreferencesHelper(settings = get()) } + factory { Settings() } + + factory { + UserPreferencesDataSource( + settings = get(), + dispatcher = get(named(MifosDispatchers.IO.name)) + ) + } + + single { + PreferenceHelper( + preferenceManager = get(), + ioDispatcher = get(named(MifosDispatchers.IO.name)), + unconfinedDispatcher = get(named(MifosDispatchers.Unconfined.name)), + ) + } } + +// Should be removed after common module conversion +enum class MifosDispatchers { + Default, + IO, + Unconfined +} \ No newline at end of file From e321d79373f76f551cb5df1496a47d8e79d9472b Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Mon, 13 Jan 2025 10:54:38 +0530 Subject: [PATCH 09/11] updated --- .../org/mifos/mobile/core/datastore/di/PreferenceModule.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt index c9a12eeb6d..49f211ae32 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt @@ -16,14 +16,13 @@ import org.mifos.mobile.core.datastore.PreferenceHelper import org.mifos.mobile.core.datastore.UserPreferencesDataSource import org.mifos.mobile.core.datastore.UserPreferencesRepository - val PreferencesModule = module { factory { Settings() } factory { UserPreferencesDataSource( settings = get(), - dispatcher = get(named(MifosDispatchers.IO.name)) + dispatcher = get(named(MifosDispatchers.IO.name)), ) } @@ -40,5 +39,5 @@ val PreferencesModule = module { enum class MifosDispatchers { Default, IO, - Unconfined -} \ No newline at end of file + Unconfined, +} From f60c93559e03c66f4d8bd8e23abc388d95ac094e Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Tue, 14 Jan 2025 14:48:20 +0530 Subject: [PATCH 10/11] deleted DataState class --- .../mifos/mobile/core/datastore/DataState.kt | 30 ----------------- ...er.kt => UserPreferencesRepositoryImpl.kt} | 33 ++++++++++--------- .../core/datastore/di/PreferenceModule.kt | 4 +-- .../core/datastore/model/AppSettings.kt | 2 +- 4 files changed, 20 insertions(+), 49 deletions(-) delete mode 100644 core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt rename core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/{PreferenceHelper.kt => UserPreferencesRepositoryImpl.kt} (80%) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt deleted file mode 100644 index 474ac98d4a..0000000000 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/DataState.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2025 Mifos Initiative - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at https://mozilla.org/MPL/2.0/. - * - * See https://github.com/openMF/mobile-mobile/blob/master/LICENSE.md - */ -package org.mifos.mobile.core.datastore - -// Should be deleted once common module is migrated -sealed class DataState { - abstract val data: T? - - data object Loading : DataState() { - override val data: Nothing? get() = null - } - - data class Success( - override val data: T, - ) : DataState() - - data class Error( - val exception: Throwable, - override val data: T? = null, - ) : DataState() { - val message = exception.message.toString() - } -} diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepositoryImpl.kt similarity index 80% rename from core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt rename to core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepositoryImpl.kt index c97ce02067..42a0300a71 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/PreferenceHelper.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/UserPreferencesRepositoryImpl.kt @@ -18,8 +18,9 @@ import kotlinx.coroutines.flow.stateIn import org.mifos.mobile.core.datastore.model.AppSettings import org.mifos.mobile.core.datastore.model.AppTheme import org.mifos.mobile.core.datastore.model.UserData +import kotlin.Result -class PreferenceHelper( +class UserPreferencesRepositoryImpl( private val preferenceManager: UserPreferencesDataSource, private val ioDispatcher: CoroutineDispatcher, unconfinedDispatcher: CoroutineDispatcher, @@ -55,48 +56,48 @@ class PreferenceHelper( override val profileImage: String? get() = preferenceManager.getProfileImage() - override suspend fun updateToken(token: String): DataState { + override suspend fun updateToken(token: String): Result { return try { val result = preferenceManager.updateToken(token) - DataState.Success(result) + Result.success(result) } catch (e: Exception) { - DataState.Error(e) + Result.failure(e) } } - override suspend fun updateTheme(theme: AppTheme): DataState { + override suspend fun updateTheme(theme: AppTheme): Result { return try { val result = preferenceManager.updateTheme(theme) - DataState.Success(result) + Result.success(result) } catch (e: Exception) { - DataState.Error(e) + Result.failure(e) } } - override suspend fun updateUser(user: UserData): DataState { + override suspend fun updateUser(user: UserData): Result { return try { val result = preferenceManager.updateUserInfo(user) - DataState.Success(result) + Result.success(result) } catch (e: Exception) { - DataState.Error(e) + Result.failure(e) } } - override suspend fun updateSettings(appSettings: AppSettings): DataState { + override suspend fun updateSettings(appSettings: AppSettings): Result { return try { val result = preferenceManager.updateSettingsInfo(appSettings) - DataState.Success(result) + Result.success(result) } catch (e: Exception) { - DataState.Error(e) + Result.failure(e) } } - override suspend fun updateProfileImage(image: String): DataState { + override suspend fun updateProfileImage(image: String): Result { return try { val result = preferenceManager.updateProfileImage(image) - DataState.Success(result) + Result.success(result) } catch (e: Exception) { - DataState.Error(e) + Result.failure(e) } } diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt index 49f211ae32..ba673f53d2 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt @@ -12,7 +12,7 @@ package org.mifos.mobile.core.datastore.di import com.russhwolf.settings.Settings import org.koin.core.qualifier.named import org.koin.dsl.module -import org.mifos.mobile.core.datastore.PreferenceHelper +import org.mifos.mobile.core.datastore.UserPreferencesRepositoryImpl import org.mifos.mobile.core.datastore.UserPreferencesDataSource import org.mifos.mobile.core.datastore.UserPreferencesRepository @@ -27,7 +27,7 @@ val PreferencesModule = module { } single { - PreferenceHelper( + UserPreferencesRepositoryImpl( preferenceManager = get(), ioDispatcher = get(named(MifosDispatchers.IO.name)), unconfinedDispatcher = get(named(MifosDispatchers.Unconfined.name)), diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt index 737ed9e11d..c8eaf0e3e5 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/model/AppSettings.kt @@ -21,7 +21,7 @@ data class AppSettings( companion object { val DEFAULT = AppSettings( tenant = "default", - baseUrl = "https://demo.mifos.community", + baseUrl = "https://gsoc.mifos.community/", appTheme = AppTheme.SYSTEM, ) } From 9c61d7519049de610f88d4ce9caf72f91e560b05 Mon Sep 17 00:00:00 2001 From: revanthkumarJ Date: Tue, 14 Jan 2025 14:56:56 +0530 Subject: [PATCH 11/11] updated --- .../org/mifos/mobile/core/datastore/di/PreferenceModule.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt index ba673f53d2..fcaa14d14a 100644 --- a/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/org/mifos/mobile/core/datastore/di/PreferenceModule.kt @@ -12,9 +12,9 @@ package org.mifos.mobile.core.datastore.di import com.russhwolf.settings.Settings import org.koin.core.qualifier.named import org.koin.dsl.module -import org.mifos.mobile.core.datastore.UserPreferencesRepositoryImpl import org.mifos.mobile.core.datastore.UserPreferencesDataSource import org.mifos.mobile.core.datastore.UserPreferencesRepository +import org.mifos.mobile.core.datastore.UserPreferencesRepositoryImpl val PreferencesModule = module { factory { Settings() }