diff --git a/core/datastore/build.gradle.kts b/core/datastore/build.gradle.kts index f7bd49852b0..cb0dc91dd4a 100644 --- a/core/datastore/build.gradle.kts +++ b/core/datastore/build.gradle.kts @@ -8,9 +8,10 @@ * 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(libs.plugins.kotlin.parcelize.get().pluginId) +// id("kotlinx-serialization") + alias(libs.plugins.kotlin.serialization) } android { @@ -19,22 +20,20 @@ android { defaultConfig { consumerProguardFiles("consumer-proguard-rules.pro") } - testOptions { - unitTests { - isReturnDefaultValues = true - } - } + } dependencies { - api(projects.core.model) - api(projects.core.common) - - api(libs.converter.gson) - - // 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/PrefManager.kt b/core/datastore/src/commonMain/PrefManager.kt new file mode 100644 index 00000000000..7c1a5e0d23e --- /dev/null +++ b/core/datastore/src/commonMain/PrefManager.kt @@ -0,0 +1,95 @@ +/* + * 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: ServerConfig = +// preference.getString(serverConfigKey.value, null)?.let { +// gson.fromJson(it, ServerConfig::class.java) +// } ?: BuildConfig.DEMO_SERVER_CONFIG.asServerConfig() +// +// fun updateServerConfig(config: ServerConfig?) { +// this.put(serverConfigKey, config) +// } +// + +// +// fun setStringValue(key: String, value: String) { +// preference.edit().putString(key, value).apply() +// } +//} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesDataSource.kt new file mode 100644 index 00000000000..e70c80e6190 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesDataSource.kt @@ -0,0 +1,62 @@ +///* +// * 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 kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.serialization.ExperimentalSerializationApi +import org.mifos.core.datastore.model.UserData + +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, + ) +} \ No newline at end of file diff --git a/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesRepository.kt b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesRepository.kt new file mode 100644 index 00000000000..1a76e1ab832 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesRepository.kt @@ -0,0 +1,21 @@ +/* + * 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 kotlinx.coroutines.flow.Flow +import org.mifos.core.datastore.model.UserData + + +interface UserPreferencesRepository { + val userInfo: Flow + + suspend fun updateUser(user: UserData): Result + suspend fun logOut(): Unit +} diff --git a/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesRepositoryImpl.kt b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesRepositoryImpl.kt new file mode 100644 index 00000000000..e1de6eafaa5 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/UserPreferencesRepositoryImpl.kt @@ -0,0 +1,37 @@ +/* + * 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 kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.flow.Flow +import org.mifos.core.datastore.model.UserData + +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/org.mifos.core.datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/di/PreferenceModule.kt new file mode 100644 index 00000000000..0a97634f518 --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/di/PreferenceModule.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.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() } + // Use the IO dispatcher name - MifosDispatchers.IO.name + factory { UserPreferencesDataSource(get(), 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, +} diff --git a/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/model/User.kt b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/model/User.kt new file mode 100644 index 00000000000..20cbc03746d --- /dev/null +++ b/core/datastore/src/commonMain/kotlin/org.mifos.core.datastore/model/User.kt @@ -0,0 +1,19 @@ +package org.mifos.core.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 index 1a8e8b1d746..ca77c5a931f 100644 --- a/core/datastore/src/main/java/com/mifos/core/datastore/PrefManager.kt +++ b/core/datastore/src/main/java/com/mifos/core/datastore/PrefManager.kt @@ -9,89 +9,89 @@ */ 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: ServerConfig = - preference.getString(serverConfigKey.value, null)?.let { - gson.fromJson(it, ServerConfig::class.java) - } ?: BuildConfig.DEMO_SERVER_CONFIG.asServerConfig() - - fun updateServerConfig(config: 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() - } -} +//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: ServerConfig = +// preference.getString(serverConfigKey.value, null)?.let { +// gson.fromJson(it, ServerConfig::class.java) +// } ?: BuildConfig.DEMO_SERVER_CONFIG.asServerConfig() +// +// fun updateServerConfig(config: 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/gradle/libs.versions.toml b/gradle/libs.versions.toml index 67ab31e3b3b..d32c073d1e9 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -7,7 +7,7 @@ androidDesugarJdkLibs = "2.1.4" androidIconifyMaterial = "2.2.2" androidJob = "1.2.6" androidMapsUtils = "0.4.2" -androidGradlePlugin = "8.8.0" +androidGradlePlugin = "8.7.2" androidTools = "31.8.0" androidxActivity = "1.9.3" androidxAppCompat = "1.7.0"