From 47fedc62fcb63eab9d9a068078a2f6fc60457587 Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Tue, 11 Feb 2025 22:55:37 +0530 Subject: [PATCH 1/8] datastore-migration-kmp --- core/datastore/build.gradle.kts | 28 ++++-- .../kotlin/datastore/PrefManager.kt | 97 +++++++++++++++++++ .../datastore/UserPreferencesDataSource.kt | 60 ++++++++++++ .../datastore/UserPreferencesRepository.kt | 20 ++++ .../UserPreferencesRepositoryImpl.kt | 38 ++++++++ .../kotlin/datastore/di/PreferenceModule.kt | 39 ++++++++ .../commonMain/kotlin/datastore/model/User.kt | 19 ++++ .../com/mifos/core/datastore/PrefManager.kt | 97 ------------------- 8 files changed, 293 insertions(+), 105 deletions(-) create mode 100644 core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt create mode 100644 core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt create mode 100644 core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt create mode 100644 core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt create mode 100644 core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt create mode 100644 core/datastore/src/commonMain/kotlin/datastore/model/User.kt delete mode 100644 core/datastore/src/main/java/com/mifos/core/datastore/PrefManager.kt diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index f7bd49852b..4020f04176 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -8,9 +8,8 @@ * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ plugins { - alias(libs.plugins.mifos.android.library) - alias(libs.plugins.mifos.android.library.jacoco) - alias(libs.plugins.mifos.android.hilt) + alias(libs.plugins.mifos.kmp.library) + id("kotlinx-serialization") } android { @@ -31,10 +30,23 @@ dependencies { api(projects.core.common) api(libs.converter.gson) + implementation(project(":core:common")) + implementation(project(":core:common")) + implementation(project(":core:common")) + implementation(project(":core:common")) + implementation(project(":core:common")) + implementation(project(":core:common")) - // fineract sdk dependencies - api(libs.mifos.android.sdk.arch) - - // sdk client - api(libs.fineract.client) + 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) +// implementation(projects.core.common) + } + } + } } \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt b/core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt new file mode 100644 index 0000000000..0f3082d710 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt @@ -0,0 +1,97 @@ +/* + * Copyright 2024 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/android-client/blob/master/LICENSE.md + */ +package datastore + +//import android.content.Context +//import android.content.SharedPreferences +//import android.preference.PreferenceManager +//import com.mifos.core.common.BuildConfig +//import com.mifos.core.common.model.user.User +//import com.mifos.core.common.utils.Constants +//import com.mifos.core.common.utils.asServerConfig +//import com.mifos.core.model.ServerConfig +//import dagger.hilt.android.qualifiers.ApplicationContext +//import kotlinx.coroutines.flow.Flow +//import kotlinx.coroutines.flow.flow +//import org.mifos.core.sharedpreference.Key +//import org.mifos.core.sharedpreference.UserPreferences +//import org.openapitools.client.models.PostAuthenticationResponse +//import javax.inject.Inject +// +///** +// * Created by Aditya Gupta on 19/08/23. +// */ +//const val USER_DETAILS = "user_details" +//const val AUTH_USERNAME = "auth_username" +//const val AUTH_PASSWORD = "auth_password" +// +//class PrefManager @Inject constructor( +// @ApplicationContext context: Context, +//) : UserPreferences() { +// +// private val serverConfigKey = Key.Custom("SERVER_CONFIG_KEY") +// +// override val preference: SharedPreferences = +// PreferenceManager.getDefaultSharedPreferences(context) +// +// override fun getUser(): User { +// return gson.fromJson(preference.getString(USER_DETAILS, ""), User::class.java) +// } +// +// override fun saveUser(user: User) { +// preference.edit().putString(USER_DETAILS, gson.toJson(user)).apply() +// } +// +// // Created this to store userDetails +// fun savePostAuthenticationResponse(user: PostAuthenticationResponse) { +// preference.edit().putString(USER_DETAILS, gson.toJson(user)).apply() +// } +// +// fun setPermissionDeniedStatus(permissionDeniedStatus: String, status: Boolean) { +// preference.edit().putBoolean(permissionDeniedStatus, status).apply() +// } +// +// fun getPermissionDeniedStatus(permissionDeniedStatus: String): Boolean { +// return preference.getBoolean(permissionDeniedStatus, true) +// } +// +// var userStatus: Boolean +// get() = preference.getBoolean(Constants.SERVICE_STATUS, false) +// set(status) { +// preference.edit().putBoolean(Constants.SERVICE_STATUS, status).apply() +// } +// +// var usernamePassword: Pair +// get() = Pair( +// preference.getString(AUTH_USERNAME, "")!!, +// preference.getString(AUTH_PASSWORD, "")!!, +// ) +// set(value) { +// preference.edit().putString(AUTH_USERNAME, value.first).apply() +// preference.edit().putString(AUTH_PASSWORD, value.second).apply() +// } +// +// val getServerConfig: com.mifos.core.model.ServerConfig = +// preference.getString(serverConfigKey.value, null)?.let { +// gson.fromJson(it, com.mifos.core.model.ServerConfig::class.java) +// } ?: BuildConfig.DEMO_SERVER_CONFIG.asServerConfig() +// +// fun updateServerConfig(config: com.mifos.core.model.ServerConfig?) { +// this.put(serverConfigKey, config) +// } +// +// fun getStringValue(key: String): Flow = flow { +// emit(preference.getString(key, "")) +// } +// +// fun setStringValue(key: String, value: String) { +// preference.edit().putString(key, value).apply() +// } +//} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt new file mode 100644 index 0000000000..24c19555cf --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2024 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-wallet/blob/master/LICENSE.md + */ +@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + +package org.mifos.core.datastore + +import com.russhwolf.settings.serialization.decodeValue +import com.russhwolf.settings.serialization.decodeValueOrNull +import kotlinx.coroutines.withContext +import com.russhwolf.settings.ExperimentalSettingsApi +import com.russhwolf.settings.Settings +import com.russhwolf.settings.serialization.encodeValue +import datastore.model.UserData +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.serialization.ExperimentalSerializationApi +private const val USER_DATA = "userData" +class UserPreferencesDataSource( + private val settings: Settings, + private val dispatcher: CoroutineDispatcher, +) { + @OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + private val _userInfo = MutableStateFlow( + settings.decodeValue( + key = USER_DATA, + serializer = UserData.serializer(), + defaultValue = settings.decodeValueOrNull( + key = USER_DATA, + serializer = UserData.serializer(), + ) ?: UserData.DEFAULT, + ), + ) + val userInfo = _userInfo + suspend fun updateUserInfo(user: UserData) { + withContext(dispatcher) { + settings.putUserPreference(user) + _userInfo.value = user + } + } + suspend fun clearInfo() { + withContext(dispatcher) { + settings.clear() + } + } +} +@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) +private fun Settings.putUserPreference(user: UserData) { + encodeValue( + key = USER_DATA, + serializer = UserData.serializer(), + value = user, + ) +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt new file mode 100644 index 0000000000..8fc1dabe16 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt @@ -0,0 +1,20 @@ +/* + * Copyright 2024 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-wallet/blob/master/LICENSE.md + */ +package org.mifos.core.datastore + + +import datastore.model.UserData +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.StateFlow +interface UserPreferencesRepository { + val userInfo: Flow + suspend fun updateUser(user: UserData): Result + suspend fun logOut(): Unit +} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt new file mode 100644 index 0000000000..397c2c274f --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2024 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-wallet/blob/master/LICENSE.md + */ +package org.mifos.core.datastore + + +import datastore.model.UserData +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +class UserPreferencesRepositoryImpl( + private val preferenceManager: UserPreferencesDataSource, + private val ioDispatcher: CoroutineDispatcher, + unconfinedDispatcher: CoroutineDispatcher, +) : UserPreferencesRepository { + private val unconfinedScope = CoroutineScope(unconfinedDispatcher) + override val userInfo: Flow + get() = preferenceManager.userInfo + + override suspend fun updateUser(user: UserData): Result { + return try { + val result = preferenceManager.updateUserInfo(user) + Result.success(result) + } catch (e: Exception) { + Result.failure(e) + } + } + + override suspend fun logOut() { + preferenceManager.clearInfo() + } +} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt new file mode 100644 index 0000000000..a768e3ae03 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2024 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-wallet/blob/master/LICENSE.md + */ +package org.mifos.core.datastore.di + +import com.russhwolf.settings.Settings +import org.koin.core.qualifier.named +import org.koin.dsl.module +import org.mifos.core.datastore.UserPreferencesDataSource +import org.mifos.core.datastore.UserPreferencesRepository +import org.mifos.core.datastore.UserPreferencesRepositoryImpl + +val PreferencesModule = module { + factory { Settings() } + factory { + UserPreferencesDataSource( + settings = get(), + dispatcher = get(named(MifosDispatchers.IO.name)), + ) + } + single { + UserPreferencesRepositoryImpl( + preferenceManager = get(), + ioDispatcher = get(named(MifosDispatchers.IO.name)), + unconfinedDispatcher = get(named(MifosDispatchers.Unconfined.name)), + ) + } +} +enum class MifosDispatchers { + Default, + IO, + Unconfined, +} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/datastore/model/User.kt b/core/datastore/src/commonMain/kotlin/datastore/model/User.kt new file mode 100644 index 0000000000..eb4da6864d --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/datastore/model/User.kt @@ -0,0 +1,19 @@ +package datastore.model + +import kotlinx.serialization.Serializable +@Serializable +data class UserData( + val userId: Long, + val userName: String, + val clientId: Long, + val isAuthenticated: Boolean +) { + companion object { + val DEFAULT = UserData( + userId = -1, + userName = "", + clientId = -1, + isAuthenticated = false, + ) + } +} \ No newline at end of file diff --git a/core/datastore/src/main/java/com/mifos/core/datastore/PrefManager.kt b/core/datastore/src/main/java/com/mifos/core/datastore/PrefManager.kt deleted file mode 100644 index d8ca072efb..0000000000 --- a/core/datastore/src/main/java/com/mifos/core/datastore/PrefManager.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2024 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/android-client/blob/master/LICENSE.md - */ -package com.mifos.core.datastore - -import android.content.Context -import android.content.SharedPreferences -import android.preference.PreferenceManager -import com.mifos.core.common.BuildConfig -import com.mifos.core.common.model.user.User -import com.mifos.core.common.utils.Constants -import com.mifos.core.common.utils.asServerConfig -import com.mifos.core.model.ServerConfig -import dagger.hilt.android.qualifiers.ApplicationContext -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow -import org.mifos.core.sharedpreference.Key -import org.mifos.core.sharedpreference.UserPreferences -import org.openapitools.client.models.PostAuthenticationResponse -import javax.inject.Inject - -/** - * Created by Aditya Gupta on 19/08/23. - */ -const val USER_DETAILS = "user_details" -const val AUTH_USERNAME = "auth_username" -const val AUTH_PASSWORD = "auth_password" - -class PrefManager @Inject constructor( - @ApplicationContext context: Context, -) : UserPreferences() { - - private val serverConfigKey = Key.Custom("SERVER_CONFIG_KEY") - - override val preference: SharedPreferences = - PreferenceManager.getDefaultSharedPreferences(context) - - override fun getUser(): User { - return gson.fromJson(preference.getString(USER_DETAILS, ""), User::class.java) - } - - override fun saveUser(user: User) { - preference.edit().putString(USER_DETAILS, gson.toJson(user)).apply() - } - - // Created this to store userDetails - fun savePostAuthenticationResponse(user: PostAuthenticationResponse) { - preference.edit().putString(USER_DETAILS, gson.toJson(user)).apply() - } - - fun setPermissionDeniedStatus(permissionDeniedStatus: String, status: Boolean) { - preference.edit().putBoolean(permissionDeniedStatus, status).apply() - } - - fun getPermissionDeniedStatus(permissionDeniedStatus: String): Boolean { - return preference.getBoolean(permissionDeniedStatus, true) - } - - var userStatus: Boolean - get() = preference.getBoolean(Constants.SERVICE_STATUS, false) - set(status) { - preference.edit().putBoolean(Constants.SERVICE_STATUS, status).apply() - } - - var usernamePassword: Pair - get() = Pair( - preference.getString(AUTH_USERNAME, "")!!, - preference.getString(AUTH_PASSWORD, "")!!, - ) - set(value) { - preference.edit().putString(AUTH_USERNAME, value.first).apply() - preference.edit().putString(AUTH_PASSWORD, value.second).apply() - } - - val getServerConfig: com.mifos.core.model.ServerConfig = - preference.getString(serverConfigKey.value, null)?.let { - gson.fromJson(it, com.mifos.core.model.ServerConfig::class.java) - } ?: BuildConfig.DEMO_SERVER_CONFIG.asServerConfig() - - fun updateServerConfig(config: com.mifos.core.model.ServerConfig?) { - this.put(serverConfigKey, config) - } - - fun getStringValue(key: String): Flow = flow { - emit(preference.getString(key, "")) - } - - fun setStringValue(key: String, value: String) { - preference.edit().putString(key, value).apply() - } -} From d85cf0ce1157bdae573ed852cfc30039b9620111 Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Tue, 11 Feb 2025 23:45:29 +0530 Subject: [PATCH 2/8] datastore-migration-kmp --- core/datastore/build.gradle.kts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index 4020f04176..cb99460770 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -9,7 +9,8 @@ */ plugins { alias(libs.plugins.mifos.kmp.library) - id("kotlinx-serialization") + alias(libs.plugins.kotlin.serialization) + } android { From 2928f347276d3e2d5e805e26deff2efabf45288b Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Wed, 12 Feb 2025 23:15:03 +0530 Subject: [PATCH 3/8] datastore-migration-kmp --- core/datastore/build.gradle.kts | 19 ++-- .../kotlin/datastore/PrefManager.kt | 97 ------------------- .../datastore/UserPreferencesDataSource.kt | 9 +- .../datastore/UserPreferencesRepository.kt | 6 +- .../UserPreferencesRepositoryImpl.kt | 5 +- .../kotlin/datastore/di/PreferenceModule.kt | 4 +- .../datastore/model/{User.kt => UserData.kt} | 13 ++- 7 files changed, 29 insertions(+), 124 deletions(-) delete mode 100644 core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt rename core/datastore/src/commonMain/kotlin/datastore/model/{User.kt => UserData.kt} (50%) diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index cb99460770..9a7fd9f1a4 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -26,17 +26,8 @@ android { } } -dependencies { - api(projects.core.model) - api(projects.core.common) - - api(libs.converter.gson) - implementation(project(":core:common")) - implementation(project(":core:common")) - implementation(project(":core:common")) - implementation(project(":core:common")) - implementation(project(":core:common")) - implementation(project(":core:common")) + + kotlin{ sourceSets{ @@ -47,7 +38,11 @@ dependencies { implementation(libs.kotlinx.coroutines.core) implementation(libs.kotlinx.serialization.core) // implementation(projects.core.common) + api(projects.core.model) + api(projects.core.common) + + api(libs.converter.gson) + } } } -} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt b/core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt deleted file mode 100644 index 0f3082d710..0000000000 --- a/core/datastore/src/commonMain/kotlin/datastore/PrefManager.kt +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2024 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/android-client/blob/master/LICENSE.md - */ -package datastore - -//import android.content.Context -//import android.content.SharedPreferences -//import android.preference.PreferenceManager -//import com.mifos.core.common.BuildConfig -//import com.mifos.core.common.model.user.User -//import com.mifos.core.common.utils.Constants -//import com.mifos.core.common.utils.asServerConfig -//import com.mifos.core.model.ServerConfig -//import dagger.hilt.android.qualifiers.ApplicationContext -//import kotlinx.coroutines.flow.Flow -//import kotlinx.coroutines.flow.flow -//import org.mifos.core.sharedpreference.Key -//import org.mifos.core.sharedpreference.UserPreferences -//import org.openapitools.client.models.PostAuthenticationResponse -//import javax.inject.Inject -// -///** -// * Created by Aditya Gupta on 19/08/23. -// */ -//const val USER_DETAILS = "user_details" -//const val AUTH_USERNAME = "auth_username" -//const val AUTH_PASSWORD = "auth_password" -// -//class PrefManager @Inject constructor( -// @ApplicationContext context: Context, -//) : UserPreferences() { -// -// private val serverConfigKey = Key.Custom("SERVER_CONFIG_KEY") -// -// override val preference: SharedPreferences = -// PreferenceManager.getDefaultSharedPreferences(context) -// -// override fun getUser(): User { -// return gson.fromJson(preference.getString(USER_DETAILS, ""), User::class.java) -// } -// -// override fun saveUser(user: User) { -// preference.edit().putString(USER_DETAILS, gson.toJson(user)).apply() -// } -// -// // Created this to store userDetails -// fun savePostAuthenticationResponse(user: PostAuthenticationResponse) { -// preference.edit().putString(USER_DETAILS, gson.toJson(user)).apply() -// } -// -// fun setPermissionDeniedStatus(permissionDeniedStatus: String, status: Boolean) { -// preference.edit().putBoolean(permissionDeniedStatus, status).apply() -// } -// -// fun getPermissionDeniedStatus(permissionDeniedStatus: String): Boolean { -// return preference.getBoolean(permissionDeniedStatus, true) -// } -// -// var userStatus: Boolean -// get() = preference.getBoolean(Constants.SERVICE_STATUS, false) -// set(status) { -// preference.edit().putBoolean(Constants.SERVICE_STATUS, status).apply() -// } -// -// var usernamePassword: Pair -// get() = Pair( -// preference.getString(AUTH_USERNAME, "")!!, -// preference.getString(AUTH_PASSWORD, "")!!, -// ) -// set(value) { -// preference.edit().putString(AUTH_USERNAME, value.first).apply() -// preference.edit().putString(AUTH_PASSWORD, value.second).apply() -// } -// -// val getServerConfig: com.mifos.core.model.ServerConfig = -// preference.getString(serverConfigKey.value, null)?.let { -// gson.fromJson(it, com.mifos.core.model.ServerConfig::class.java) -// } ?: BuildConfig.DEMO_SERVER_CONFIG.asServerConfig() -// -// fun updateServerConfig(config: com.mifos.core.model.ServerConfig?) { -// this.put(serverConfigKey, config) -// } -// -// fun getStringValue(key: String): Flow = flow { -// emit(preference.getString(key, "")) -// } -// -// fun setStringValue(key: String, value: String) { -// preference.edit().putString(key, value).apply() -// } -//} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt index 24c19555cf..f8c8d928d8 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt @@ -5,21 +5,21 @@ * 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-wallet/blob/master/LICENSE.md + * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ @file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) package org.mifos.core.datastore -import com.russhwolf.settings.serialization.decodeValue -import com.russhwolf.settings.serialization.decodeValueOrNull -import kotlinx.coroutines.withContext 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 datastore.model.UserData import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi private const val USER_DATA = "userData" class UserPreferencesDataSource( @@ -50,6 +50,7 @@ class UserPreferencesDataSource( } } } + @OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) private fun Settings.putUserPreference(user: UserData) { encodeValue( diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt index 8fc1dabe16..ac239cb42b 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt @@ -5,16 +5,14 @@ * 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-wallet/blob/master/LICENSE.md + * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ package org.mifos.core.datastore - import datastore.model.UserData import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.StateFlow interface UserPreferencesRepository { val userInfo: Flow suspend fun updateUser(user: UserData): Result suspend fun logOut(): Unit -} \ No newline at end of file +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt index 397c2c274f..af8da29014 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt @@ -5,11 +5,10 @@ * 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-wallet/blob/master/LICENSE.md + * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ package org.mifos.core.datastore - import datastore.model.UserData import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope @@ -35,4 +34,4 @@ class UserPreferencesRepositoryImpl( override suspend fun logOut() { preferenceManager.clearInfo() } -} \ No newline at end of file +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt index a768e3ae03..b26eda4cd1 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt @@ -5,7 +5,7 @@ * 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-wallet/blob/master/LICENSE.md + * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ package org.mifos.core.datastore.di @@ -36,4 +36,4 @@ enum class MifosDispatchers { Default, IO, Unconfined, -} \ No newline at end of file +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/model/User.kt b/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt similarity index 50% rename from core/datastore/src/commonMain/kotlin/datastore/model/User.kt rename to core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt index eb4da6864d..dcee299aa9 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/model/User.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/model/UserData.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/android-client/blob/master/LICENSE.md + */ package datastore.model import kotlinx.serialization.Serializable @@ -6,7 +15,7 @@ data class UserData( val userId: Long, val userName: String, val clientId: Long, - val isAuthenticated: Boolean + val isAuthenticated: Boolean, ) { companion object { val DEFAULT = UserData( @@ -16,4 +25,4 @@ data class UserData( isAuthenticated = false, ) } -} \ No newline at end of file +} From 8b68b9716f52dbb5dc96c027225531e5137d186d Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Fri, 14 Feb 2025 20:39:39 +0530 Subject: [PATCH 4/8] datastore-migration-kmp --- core/datastore/build.gradle.kts | 26 ++++++++----------- .../datastore/UserPreferencesDataSource.kt | 3 +++ .../datastore/UserPreferencesRepository.kt | 1 + .../UserPreferencesRepositoryImpl.kt | 1 + .../kotlin/datastore/di/PreferenceModule.kt | 1 + .../kotlin/datastore/model/UserData.kt | 1 + 6 files changed, 18 insertions(+), 15 deletions(-) diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index 9a7fd9f1a4..f8f393e185 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -26,23 +26,19 @@ android { } } - - - - 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) +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) // implementation(projects.core.common) - api(projects.core.model) - api(projects.core.common) + api(projects.core.model) + api(projects.core.common) - api(libs.converter.gson) - } } } +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt index f8c8d928d8..f6821533af 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt @@ -21,7 +21,9 @@ import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi + private const val USER_DATA = "userData" + class UserPreferencesDataSource( private val settings: Settings, private val dispatcher: CoroutineDispatcher, @@ -44,6 +46,7 @@ class UserPreferencesDataSource( _userInfo.value = user } } + suspend fun clearInfo() { withContext(dispatcher) { settings.clear() diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt index ac239cb42b..2b96fde829 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt @@ -11,6 +11,7 @@ package org.mifos.core.datastore import datastore.model.UserData import kotlinx.coroutines.flow.Flow + interface UserPreferencesRepository { val userInfo: Flow suspend fun updateUser(user: UserData): Result diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt index af8da29014..9ceecbd3ed 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt @@ -13,6 +13,7 @@ import datastore.model.UserData import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow + class UserPreferencesRepositoryImpl( private val preferenceManager: UserPreferencesDataSource, private val ioDispatcher: CoroutineDispatcher, diff --git a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt index b26eda4cd1..cf70f269aa 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt @@ -32,6 +32,7 @@ val PreferencesModule = module { ) } } + enum class MifosDispatchers { Default, IO, diff --git a/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt b/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt index dcee299aa9..84bd8a5ae5 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt +++ b/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt @@ -10,6 +10,7 @@ package datastore.model import kotlinx.serialization.Serializable + @Serializable data class UserData( val userId: Long, From e9d7531b095101254b1c2c76c17806d168f0c700 Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Mon, 17 Feb 2025 18:19:31 +0530 Subject: [PATCH 5/8] datastore-migration-kmp --- .../{main => androidMain}/AndroidManifest.xml | 0 .../datastore/UserPreferencesDataSource.kt | 158 ++++++++++++++++++ .../datastore/UserPreferencesRepository.kt | 15 +- .../UserPreferencesRepositoryImpl.kt | 69 ++++++++ .../core}/datastore/di/PreferenceModule.kt | 8 +- .../datastore/UserPreferencesDataSource.kt | 64 ------- .../UserPreferencesRepositoryImpl.kt | 38 ----- .../kotlin/datastore/model/UserData.kt | 29 ---- .../core/model/objects/DarkThemeConfig.kt | 17 ++ .../core/model/objects/MifosAppLanguage.kt | 34 ++++ .../mifos/core/model/objects}/ServerConfig.kt | 21 ++- .../mifos/core/model/objects/ThemeBrand.kt | 16 ++ .../com/mifos/core/model/objects/UserData.kt | 33 ++++ .../mifos/core/model/objects/clients/Role.kt | 4 + .../mifos/core/model/objects/users/User.kt | 43 ++--- 15 files changed, 376 insertions(+), 173 deletions(-) rename core/datastore/src/{main => androidMain}/AndroidManifest.xml (100%) create mode 100644 core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt rename core/datastore/src/commonMain/kotlin/{ => com/mifos/core}/datastore/UserPreferencesRepository.kt (57%) create mode 100644 core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt rename core/datastore/src/commonMain/kotlin/{ => com/mifos/core}/datastore/di/PreferenceModule.kt (82%) delete mode 100644 core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt delete mode 100644 core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt delete mode 100644 core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt create mode 100644 core/model/src/commonMain/kotlin/com/mifos/core/model/objects/DarkThemeConfig.kt create mode 100644 core/model/src/commonMain/kotlin/com/mifos/core/model/objects/MifosAppLanguage.kt rename core/{common/src/commonMain/kotlin/com/mifos/core/common/utils => model/src/commonMain/kotlin/com/mifos/core/model/objects}/ServerConfig.kt (62%) create mode 100644 core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ThemeBrand.kt create mode 100644 core/model/src/commonMain/kotlin/com/mifos/core/model/objects/UserData.kt 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/com/mifos/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt new file mode 100644 index 0000000000..201c2a8de3 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt @@ -0,0 +1,158 @@ +/* + * Copyright 2024 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/android-client/blob/master/LICENSE.md + */ +@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + +package com.mifos.core.datastore + +import com.mifos.core.model.objects.ServerConfig +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 com.mifos.core.model.objects.UserData +import com.mifos.core.model.objects.users.User +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.withContext +import kotlinx.serialization.ExperimentalSerializationApi + + +private const val USER_DATA = "userData" +private const val AUTH_USER = "user_details" +private const val SERVER_CONFIG_KEY = "server_config" +private const val USER_STATUS = "user_status" +private const val AUTH_USERNAME = "auth_username" +private const val AUTH_PASSWORD = "auth_password" + +@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) + +class UserPreferencesDataSource( + 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, + ), + ) + val userInfo = _userInfo.asStateFlow() + + private val _userData = MutableStateFlow( + settings.decodeValue( + key = AUTH_USER, + serializer = User.serializer(), + defaultValue = settings.decodeValueOrNull( + key = AUTH_USER, + serializer = User.serializer(), + ) ?: User(), + ), + ) + val userData = _userData.asStateFlow() + + + private val _serverConfig = MutableStateFlow( + settings.decodeValue( + key = SERVER_CONFIG_KEY, + serializer = ServerConfig.serializer(), + defaultValue = settings.decodeValueOrNull( + key = SERVER_CONFIG_KEY, + serializer = ServerConfig.serializer(), + ) ?: ServerConfig.DEFAULT, + ), + ) + val serverConfig = _serverConfig.asStateFlow() + + val userStatus: Boolean + get() = settings.getBoolean(USER_STATUS, false) + + var usernamePassword: Pair + get() = Pair( + settings.getString(AUTH_USERNAME, "") ?: "", + settings.getString(AUTH_PASSWORD, "") ?: "", + ) + set(value) { + settings.putString(AUTH_USERNAME, value.first) + settings.putString(AUTH_PASSWORD, value.second) + } + + val isAuthenticated: Boolean + get() = _userData.value.isAuthenticated == true + + val token: String + get() = _userData.value.base64EncodedAuthenticationKey?.let { "Basic $it" } ?: "" + + fun updateUserStatus(status: Boolean) { + settings.putBoolean(USER_STATUS, status) + } + + suspend fun updateUserInfo(user: UserData) { + withContext(dispatcher) { + settings.putUserPreference(user) + _userInfo.value = user + } + } + + suspend fun updateUser(user: User) { + withContext(dispatcher) { + settings.putAuth(user) + _userData.value = user + } + } + + suspend fun updateServerConfig(serverConfig: ServerConfig) { + withContext(dispatcher) { + settings.putServerConfig(serverConfig) + _serverConfig.value = serverConfig + } + } + + suspend fun clearInfo() { + withContext(dispatcher) { + settings.remove(AUTH_USER) + } + } + + +} + +@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) +private fun Settings.putUserPreference(user: UserData) { + encodeValue( + key = USER_DATA, + serializer = UserData.serializer(), + value = user, + ) +} + +@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) +private fun Settings.putAuth(user: User) { + encodeValue( + key = AUTH_USER, + serializer = User.serializer(), + value = user, + ) +} + +@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) +private fun Settings.putServerConfig(serverConfig: ServerConfig) { + encodeValue( + key = SERVER_CONFIG_KEY, + serializer = ServerConfig.serializer(), + value = serverConfig, + ) +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt similarity index 57% rename from core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt rename to core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt index 2b96fde829..7e4e2c2e09 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepository.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt @@ -7,13 +7,24 @@ * * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ -package org.mifos.core.datastore +package com.mifos.core.datastore -import datastore.model.UserData +import com.mifos.core.model.objects.ServerConfig +import com.mifos.core.model.objects.UserData +import com.mifos.core.model.objects.users.User import kotlinx.coroutines.flow.Flow interface UserPreferencesRepository { val userInfo: Flow + val userData: Flow + val serverConfig: Flow + suspend fun updateUser(user: UserData): Result + suspend fun logOut(): Unit + + suspend fun updateServerConfig(serverConfig: ServerConfig):Result + + suspend fun updateUserInfo(user: UserData):Result + } diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt new file mode 100644 index 0000000000..442f417a9d --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt @@ -0,0 +1,69 @@ +package com.mifos.core.datastore + +import com.mifos.core.model.objects.ServerConfig +import com.mifos.core.model.objects.UserData +import com.mifos.core.model.objects.users.User +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.withContext + +class UserPreferencesRepositoryImpl( + private val preferenceManager: UserPreferencesDataSource, + private val ioDispatcher: CoroutineDispatcher, + unconfinedDispatcher: CoroutineDispatcher, +) : UserPreferencesRepository { + + private val unconfinedScope = CoroutineScope(unconfinedDispatcher) + + override val userInfo: Flow + get() = preferenceManager.userInfo + + override val userData: Flow + get() = preferenceManager.userData + + override val serverConfig: Flow + get() = preferenceManager.serverConfig + + // Implementing updateUserInfo as required by the interface + override suspend fun updateUserInfo(user: UserData): Result { + return withContext(ioDispatcher) { + try { + preferenceManager.updateUserInfo(user) + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) + } + } + } + + // Implementing updateUser as required by the interface + override suspend fun updateUser(user: UserData): Result { + return withContext(ioDispatcher) { + try { + preferenceManager.updateUserInfo(user) + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) + } + } + } + + // Implementing updateServerConfig correctly + override suspend fun updateServerConfig(serverConfig: ServerConfig): Result { + return withContext(ioDispatcher) { + try { + preferenceManager.updateServerConfig(serverConfig) + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) + } + } + } + + override suspend fun logOut() { + withContext(ioDispatcher) { + preferenceManager.clearInfo() + } + } +} diff --git a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt similarity index 82% rename from core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt rename to core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt index cf70f269aa..17c9a98b09 100644 --- a/core/datastore/src/commonMain/kotlin/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt @@ -7,14 +7,14 @@ * * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ -package org.mifos.core.datastore.di +package com.mifos.core.datastore.di import com.russhwolf.settings.Settings import org.koin.core.qualifier.named import org.koin.dsl.module -import org.mifos.core.datastore.UserPreferencesDataSource -import org.mifos.core.datastore.UserPreferencesRepository -import org.mifos.core.datastore.UserPreferencesRepositoryImpl +import com.mifos.core.datastore.UserPreferencesDataSource +import com.mifos.core.datastore.UserPreferencesRepository +import com.mifos.core.datastore.UserPreferencesRepositoryImpl val PreferencesModule = module { factory { Settings() } diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt deleted file mode 100644 index f6821533af..0000000000 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesDataSource.kt +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2024 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/android-client/blob/master/LICENSE.md - */ -@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) - -package org.mifos.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 datastore.model.UserData -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.MutableStateFlow -import kotlinx.coroutines.withContext -import kotlinx.serialization.ExperimentalSerializationApi - -private const val USER_DATA = "userData" - -class UserPreferencesDataSource( - private val settings: Settings, - private val dispatcher: CoroutineDispatcher, -) { - @OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) - private val _userInfo = MutableStateFlow( - settings.decodeValue( - key = USER_DATA, - serializer = UserData.serializer(), - defaultValue = settings.decodeValueOrNull( - key = USER_DATA, - serializer = UserData.serializer(), - ) ?: UserData.DEFAULT, - ), - ) - val userInfo = _userInfo - suspend fun updateUserInfo(user: UserData) { - withContext(dispatcher) { - settings.putUserPreference(user) - _userInfo.value = user - } - } - - suspend fun clearInfo() { - withContext(dispatcher) { - settings.clear() - } - } -} - -@OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) -private fun Settings.putUserPreference(user: UserData) { - encodeValue( - key = USER_DATA, - serializer = UserData.serializer(), - value = user, - ) -} diff --git a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt deleted file mode 100644 index 9ceecbd3ed..0000000000 --- a/core/datastore/src/commonMain/kotlin/datastore/UserPreferencesRepositoryImpl.kt +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2024 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/android-client/blob/master/LICENSE.md - */ -package org.mifos.core.datastore - -import datastore.model.UserData -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow - -class UserPreferencesRepositoryImpl( - private val preferenceManager: UserPreferencesDataSource, - private val ioDispatcher: CoroutineDispatcher, - unconfinedDispatcher: CoroutineDispatcher, -) : UserPreferencesRepository { - private val unconfinedScope = CoroutineScope(unconfinedDispatcher) - override val userInfo: Flow - get() = preferenceManager.userInfo - - override suspend fun updateUser(user: UserData): Result { - return try { - val result = preferenceManager.updateUserInfo(user) - Result.success(result) - } catch (e: Exception) { - Result.failure(e) - } - } - - override suspend fun logOut() { - preferenceManager.clearInfo() - } -} diff --git a/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt b/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt deleted file mode 100644 index 84bd8a5ae5..0000000000 --- a/core/datastore/src/commonMain/kotlin/datastore/model/UserData.kt +++ /dev/null @@ -1,29 +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/android-client/blob/master/LICENSE.md - */ -package datastore.model - -import kotlinx.serialization.Serializable - -@Serializable -data class UserData( - val userId: Long, - val userName: String, - val clientId: Long, - val isAuthenticated: Boolean, -) { - companion object { - val DEFAULT = UserData( - userId = -1, - userName = "", - clientId = -1, - isAuthenticated = false, - ) - } -} diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/DarkThemeConfig.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/DarkThemeConfig.kt new file mode 100644 index 0000000000..b7f03d2631 --- /dev/null +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/DarkThemeConfig.kt @@ -0,0 +1,17 @@ +package com.mifos.core.model.objects + +/* + * 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/android-client/blob/master/LICENSE.md + */ + +enum class DarkThemeConfig { + FOLLOW_SYSTEM, + LIGHT, + DARK, +} \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/MifosAppLanguage.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/MifosAppLanguage.kt new file mode 100644 index 0000000000..44137758ad --- /dev/null +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/MifosAppLanguage.kt @@ -0,0 +1,34 @@ +package com.mifos.core.model.objects + + +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 + } +} \ No newline at end of file diff --git a/core/common/src/commonMain/kotlin/com/mifos/core/common/utils/ServerConfig.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ServerConfig.kt similarity index 62% rename from core/common/src/commonMain/kotlin/com/mifos/core/common/utils/ServerConfig.kt rename to core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ServerConfig.kt index f0de6cbcc2..f9edba6e7f 100644 --- a/core/common/src/commonMain/kotlin/com/mifos/core/common/utils/ServerConfig.kt +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ServerConfig.kt @@ -7,19 +7,30 @@ * * See https://github.com/openMF/android-client/blob/master/LICENSE.md */ -package com.mifos.core.common.utils +package com.mifos.core.model.objects + + +import kotlinx.serialization.Serializable @Serializable data class ServerConfig( val protocol: String, - @SerialName("end_point") val endPoint: String, - @SerialName("api_path") val apiPath: String, val port: String, val tenant: String, -) +) { + companion object { + val DEFAULT = ServerConfig( + protocol = "https://", + endPoint = "dev.mifos.io", + apiPath = "/fineract-provider/api/v1/", + port = "80", + tenant = "default", + ) + } +} fun ServerConfig.getInstanceUrl(): String { return "$protocol$endPoint$apiPath" -} +} \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ThemeBrand.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ThemeBrand.kt new file mode 100644 index 0000000000..18bdba3b34 --- /dev/null +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/ThemeBrand.kt @@ -0,0 +1,16 @@ +package com.mifos.core.model.objects + +/* + * 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/android-client/blob/master/LICENSE.md + */ + +enum class ThemeBrand { + DEFAULT, + ANDROID, +} \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/UserData.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/UserData.kt new file mode 100644 index 0000000000..9edcfe926f --- /dev/null +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/UserData.kt @@ -0,0 +1,33 @@ +/* + * 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/android-client/blob/master/LICENSE.md + */ +package com.mifos.core.model.objects + +import com.mifos.core.common.utils.Parcelable +import com.mifos.core.common.utils.Parcelize +import kotlinx.serialization.Serializable + + +@Parcelize +@Serializable +data class UserData( + val themeBrand: ThemeBrand, + val darkThemeConfig: DarkThemeConfig, + val useDynamicColor: Boolean, + val language: MifosAppLanguage, +) : Parcelable { + companion object { + val DEFAULT = UserData( + themeBrand = ThemeBrand.DEFAULT, + darkThemeConfig = DarkThemeConfig.FOLLOW_SYSTEM, + useDynamicColor = false, + language = MifosAppLanguage.SYSTEM_LANGUAGE, + ) + } +} \ No newline at end of file diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/clients/Role.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/clients/Role.kt index a8d8e22a2c..f5e687c7a1 100644 --- a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/clients/Role.kt +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/clients/Role.kt @@ -9,9 +9,13 @@ */ package com.mifos.core.model.objects.clients +import kotlinx.serialization.Serializable + /** * Created by ishankhanna on 09/02/14. */ + +@Serializable data class Role( var id: Int = 0, diff --git a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/users/User.kt b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/users/User.kt index 8dc8b9d6c6..30862e4ca0 100644 --- a/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/users/User.kt +++ b/core/model/src/commonMain/kotlin/com/mifos/core/model/objects/users/User.kt @@ -10,35 +10,16 @@ package com.mifos.core.model.objects.users import com.mifos.core.model.objects.clients.Role +import kotlinx.serialization.Serializable -class User { - // {"username":"User1","userId":1,"base64EncodedAuthenticationKey":"VXNlcjE6dGVjaDRtZg\u003d - // \u003d", - // "authenticated":true,"officeId":1,"officeName":"Office1", - // "roles":[{"id":1,"name":"Admin","description":"Admin"}], - // "permissions":["ALL_FUNCTIONS"],"shouldRenewPassword":false} - var username: String? = null - var userId = 0 - var base64EncodedAuthenticationKey: String? = null - var isAuthenticated = false - var officeId = 0 - var officeName: String? = null - var roles: List = ArrayList() - var permissions: List = ArrayList() - override fun toString(): String { - return "User{" + - "username='" + username + '\'' + - ", userId=" + userId + - ", base64EncodedAuthenticationKey='" + base64EncodedAuthenticationKey + '\'' + - ", authenticated=" + isAuthenticated + - ", officeId=" + officeId + - ", officeName='" + officeName + '\'' + - ", roles=" + roles + - ", permissions=" + permissions + - '}' - } - - companion object { - const val AUTHENTICATION_KEY = "authenticationKey" - } -} +@Serializable +data class User ( + val username: String? = null, + val userId : Long = 0, + val base64EncodedAuthenticationKey: String? = null, + val isAuthenticated :Boolean = false, + val officeId : Long = 0, + val officeName: String? = null, + val roles: List = emptyList(), + val permissions: List = emptyList() +) From 2cd514c9be90ea25841971f9b4924adb93000b5b Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Mon, 17 Feb 2025 18:23:43 +0530 Subject: [PATCH 6/8] datastore-migration-kmp --- .../mifos/core/datastore/UserPreferencesDataSource.kt | 9 ++------- .../mifos/core/datastore/UserPreferencesRepository.kt | 5 ++--- .../core/datastore/UserPreferencesRepositoryImpl.kt | 9 +++++++++ .../com/mifos/core/datastore/di/PreferenceModule.kt | 6 +++--- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt index 201c2a8de3..9a3d3d81e4 100644 --- a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesDataSource.kt @@ -12,20 +12,19 @@ package com.mifos.core.datastore import com.mifos.core.model.objects.ServerConfig +import com.mifos.core.model.objects.UserData +import com.mifos.core.model.objects.users.User 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 com.mifos.core.model.objects.UserData -import com.mifos.core.model.objects.users.User import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.withContext import kotlinx.serialization.ExperimentalSerializationApi - private const val USER_DATA = "userData" private const val AUTH_USER = "user_details" private const val SERVER_CONFIG_KEY = "server_config" @@ -34,7 +33,6 @@ private const val AUTH_USERNAME = "auth_username" private const val AUTH_PASSWORD = "auth_password" @OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) - class UserPreferencesDataSource( private val settings: Settings, private val dispatcher: CoroutineDispatcher, @@ -64,7 +62,6 @@ class UserPreferencesDataSource( ) val userData = _userData.asStateFlow() - private val _serverConfig = MutableStateFlow( settings.decodeValue( key = SERVER_CONFIG_KEY, @@ -126,8 +123,6 @@ class UserPreferencesDataSource( settings.remove(AUTH_USER) } } - - } @OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class) diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt index 7e4e2c2e09..ac890a2659 100644 --- a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepository.kt @@ -23,8 +23,7 @@ interface UserPreferencesRepository { suspend fun logOut(): Unit - suspend fun updateServerConfig(serverConfig: ServerConfig):Result - - suspend fun updateUserInfo(user: UserData):Result + suspend fun updateServerConfig(serverConfig: ServerConfig): Result + suspend fun updateUserInfo(user: UserData): Result } diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt index 442f417a9d..0b965d3219 100644 --- a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.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/android-client/blob/master/LICENSE.md + */ package com.mifos.core.datastore import com.mifos.core.model.objects.ServerConfig diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt index 17c9a98b09..fecc90546d 100644 --- a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt @@ -9,12 +9,12 @@ */ package com.mifos.core.datastore.di -import com.russhwolf.settings.Settings -import org.koin.core.qualifier.named -import org.koin.dsl.module import com.mifos.core.datastore.UserPreferencesDataSource import com.mifos.core.datastore.UserPreferencesRepository import com.mifos.core.datastore.UserPreferencesRepositoryImpl +import com.russhwolf.settings.Settings +import org.koin.core.qualifier.named +import org.koin.dsl.module val PreferencesModule = module { factory { Settings() } From c29b70535538fc395a6e2e4a9a52a8d77cd9a39f Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Mon, 17 Feb 2025 23:42:47 +0530 Subject: [PATCH 7/8] datastore-migration-kmp --- .../com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt index 0b965d3219..1ec92eabf6 100644 --- a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/UserPreferencesRepositoryImpl.kt @@ -34,7 +34,6 @@ class UserPreferencesRepositoryImpl( override val serverConfig: Flow get() = preferenceManager.serverConfig - // Implementing updateUserInfo as required by the interface override suspend fun updateUserInfo(user: UserData): Result { return withContext(ioDispatcher) { try { @@ -46,7 +45,6 @@ class UserPreferencesRepositoryImpl( } } - // Implementing updateUser as required by the interface override suspend fun updateUser(user: UserData): Result { return withContext(ioDispatcher) { try { @@ -58,7 +56,6 @@ class UserPreferencesRepositoryImpl( } } - // Implementing updateServerConfig correctly override suspend fun updateServerConfig(serverConfig: ServerConfig): Result { return withContext(ioDispatcher) { try { From ea5bd997e26fb6ea3a649dec4ec7b08653dfa7fd Mon Sep 17 00:00:00 2001 From: kapmaurya Date: Tue, 18 Feb 2025 00:09:12 +0530 Subject: [PATCH 8/8] datastore-migration-kmp --- .../kotlin/com/mifos/core/datastore/di/PreferenceModule.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt index fecc90546d..d7bfadace8 100644 --- a/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt +++ b/core/datastore/src/commonMain/kotlin/com/mifos/core/datastore/di/PreferenceModule.kt @@ -38,3 +38,4 @@ enum class MifosDispatchers { IO, Unconfined, } +// TODO: Remove this after :core:common migration \ No newline at end of file