Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions androidApp/dependencies/demoDebugRuntimeClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions androidApp/dependencies/demoReleaseRuntimeClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions androidApp/dependencies/prodDebugRuntimeClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 8 additions & 0 deletions androidApp/dependencies/prodReleaseRuntimeClasspath.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
23 changes: 15 additions & 8 deletions core/datastore/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
}
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
/*
* 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<String?> = callbackFlow<String?> {
trySend(settings.getStringOrNull(keyForString))

val listener = settings.addStringOrNullListener(keyForString) { newValue ->
trySend(newValue)
}

awaitClose {
listener.deactivate()
}
}

fun getIntFlowForKey(keyForInt: String, settings: ObservableSettings): Flow<Int?> = callbackFlow<Int?> {
trySend(settings.getIntOrNull(keyForInt))

val listener = settings.addIntOrNullListener(keyForInt) { newValue ->
trySend(newValue)
}

awaitClose {
listener.deactivate()
}
}
}
Original file line number Diff line number Diff line change
@@ -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> { Settings() }
single { PreferencesHelper(settings = get()) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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(
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,
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* 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"),
;

companion object {
fun fromOrdinal(ordinal: Int): AppTheme {
return entries.firstOrNull { it.ordinal == ordinal } ?: SYSTEM
}
}
}
Loading
Loading