diff --git a/core/datastore-proto/src/androidMain/AndroidManifest.xml b/core/datastore-proto/src/androidMain/AndroidManifest.xml
deleted file mode 100644
index 961389810..000000000
--- a/core/datastore-proto/src/androidMain/AndroidManifest.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto b/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto
deleted file mode 100644
index 03791d71b..000000000
--- a/core/datastore-proto/src/androidMain/proto/org.mifospay.core.data/user_preferences.proto
+++ /dev/null
@@ -1,13 +0,0 @@
-syntax = "proto3";
-
-option java_package = "org.mifospay.core.datastore.proto";
-option java_multiple_files = true;
-
-message UserPreferences {
- string auth_token = 1;
- string user = 2;
- string user_email = 3;
- string client = 4;
-
- // NEXT AVAILABLE ID: 5
-}
diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt
new file mode 100644
index 000000000..f3d4a9bf3
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/ClientPreferences.kt
@@ -0,0 +1,24 @@
+package org.mifospay.core.datastore.proto
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class ClientPreferences(
+ val name: String,
+ val image: String,
+ val externalId: String,
+ val clientId: Long,
+ val displayName: String,
+ val mobileNo: String,
+) {
+ companion object {
+ val DEFAULT = ClientPreferences(
+ name = "",
+ image = "",
+ externalId = "",
+ clientId = 0,
+ displayName = "",
+ mobileNo = "",
+ )
+ }
+}
\ No newline at end of file
diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt
new file mode 100644
index 000000000..5568d8e46
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/RolePreferences.kt
@@ -0,0 +1,20 @@
+package org.mifospay.core.datastore.proto
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class RolePreferences(
+ val id: String,
+ val name: String,
+ val description: String,
+ val disabled: Boolean
+) {
+ companion object {
+ val DEFAULT = RolePreferences(
+ id = "",
+ name = "",
+ description = "",
+ disabled = false
+ )
+ }
+}
diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt
new file mode 100644
index 000000000..179ca3c3b
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserInfoPreferences.kt
@@ -0,0 +1,34 @@
+package org.mifospay.core.datastore.proto
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class UserInfoPreferences(
+ val username: String,
+ val userId: Int,
+ val base64EncodedAuthenticationKey: String,
+ val authenticated: Boolean,
+ val officeId: Int,
+ val officeName: String,
+ val roles: List,
+ val permissions: List,
+ val clients: List,
+ val shouldRenewPassword: Boolean,
+ val isTwoFactorAuthenticationRequired: Boolean
+) {
+ companion object {
+ val DEFAULT = UserInfoPreferences(
+ username = "",
+ userId = 0,
+ base64EncodedAuthenticationKey = "",
+ authenticated = false,
+ officeId = 0,
+ officeName = "",
+ roles = emptyList(),
+ permissions = emptyList(),
+ clients = emptyList(),
+ shouldRenewPassword = false,
+ isTwoFactorAuthenticationRequired = false
+ )
+ }
+}
diff --git a/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt
new file mode 100644
index 000000000..07113fc78
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/org/mifospay/core/datastore/proto/UserPreferences.kt
@@ -0,0 +1,36 @@
+package org.mifospay.core.datastore.proto
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class UserPreferences(
+ val token: String,
+ val name: String,
+ val username: String,
+ val email: String,
+ val mobileNo: String,
+ val userId: Int,
+ val clientId: Int,
+ val clientVpa: String,
+ val accountId: Int,
+ val firebaseRegId: String,
+ val client: ClientPreferences,
+ val user: UserInfoPreferences,
+) {
+ companion object {
+ val DEFAULT = UserPreferences(
+ token = "",
+ name = "",
+ username = "",
+ email = "",
+ mobileNo = "",
+ userId = 0,
+ clientId = 0,
+ clientVpa = "",
+ accountId = 0,
+ firebaseRegId = "",
+ client = ClientPreferences.DEFAULT,
+ user = UserInfoPreferences.DEFAULT,
+ )
+ }
+}
diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto
new file mode 100644
index 000000000..f845e980c
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/client_info.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+option java_package = "org.mifospay.core.datastore.proto";
+option java_multiple_files = true;
+
+message Client {
+ string name = 1;
+ string image = 2;
+ string external_id = 3;
+ int64 client_id = 4;
+ string display_name = 5;
+ string mobile_no = 6;
+}
\ No newline at end of file
diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto
new file mode 100644
index 000000000..b9756aa52
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/role_info.proto
@@ -0,0 +1,11 @@
+syntax = "proto3";
+
+option java_package = "org.mifospay.core.datastore.proto";
+option java_multiple_files = true;
+
+message Role {
+ string id = 1;
+ string name = 2;
+ string description = 3;
+ bool disabled = 4;
+}
\ No newline at end of file
diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto
new file mode 100644
index 000000000..9d38f3d91
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_info.proto
@@ -0,0 +1,20 @@
+syntax = "proto3";
+
+import "proto/org/mifospay/core/datastore/proto/role_info.proto";
+
+option java_package = "org.mifospay.core.datastore.proto";
+option java_multiple_files = true;
+
+message User {
+ string username = 1;
+ int64 userId = 2;
+ string base64EncodedAuthenticationKey = 3;
+ bool authenticated = 4;
+ int32 officeId = 5;
+ string officeName = 6;
+ repeated Role roles = 7;
+ repeated string permissions = 8;
+ repeated int64 clients = 9;
+ bool shouldRenewPassword = 10;
+ bool isTwoFactorAuthenticationRequired = 11;
+}
\ No newline at end of file
diff --git a/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto
new file mode 100644
index 000000000..762a78145
--- /dev/null
+++ b/core/datastore-proto/src/commonMain/kotlin/proto/org/mifospay/core/datastore/proto/user_preference.proto
@@ -0,0 +1,22 @@
+syntax = "proto3";
+
+import "org.mifospay.core.datastore.proto.client_info.proto";
+import "org.mifospay.core.datastore.proto.user_info.proto";
+
+option java_package = "org.mifospay.core.datastore.proto";
+option java_multiple_files = true;
+
+message UserPreferences {
+ string token = 1;
+ string name = 2;
+ string username = 3;
+ string email = 4;
+ string mobile_no = 5;
+ int32 user_id = 6;
+ int32 client_id = 7;
+ string client_vpa = 8;
+ int32 account_id = 9;
+ string firebase_reg_id = 10;
+ Client client = 11;
+ User user = 12;
+}
\ No newline at end of file
diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt
new file mode 100644
index 000000000..a1fc33861
--- /dev/null
+++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/PreferencesMapper.kt
@@ -0,0 +1,116 @@
+package org.mifospay.core.datastore
+
+import org.mifospay.core.datastore.proto.ClientPreferences
+import org.mifospay.core.datastore.proto.RolePreferences
+import org.mifospay.core.datastore.proto.UserInfoPreferences
+import org.mifospay.core.datastore.proto.UserPreferences
+import org.mifospay.core.model.ClientInfo
+import org.mifospay.core.model.RoleInfo
+import org.mifospay.core.model.UserData
+import org.mifospay.core.model.UserInfo
+
+fun ClientPreferences.toClientInfo(): ClientInfo {
+ return ClientInfo(
+ name = name,
+ image = image,
+ externalId = externalId,
+ clientId = clientId,
+ displayName = displayName,
+ mobileNo = mobileNo,
+ )
+}
+
+fun ClientInfo.toClientPreferences(): ClientPreferences {
+ return ClientPreferences(
+ name = name,
+ image = image,
+ externalId = externalId,
+ clientId = clientId,
+ displayName = displayName,
+ mobileNo = mobileNo,
+ )
+}
+
+fun RolePreferences.toRoleInfo(): RoleInfo {
+ return RoleInfo(
+ id = id,
+ name = name,
+ description = description,
+ disabled = disabled,
+ )
+}
+
+fun RoleInfo.toRolePreferences(): RolePreferences {
+ return RolePreferences(
+ id = id,
+ name = name,
+ description = description,
+ disabled = disabled,
+ )
+}
+
+fun UserInfoPreferences.toUserInfo(): UserInfo {
+ return UserInfo(
+ username = username,
+ userId = userId,
+ base64EncodedAuthenticationKey = base64EncodedAuthenticationKey,
+ authenticated = authenticated,
+ officeId = officeId,
+ officeName = officeName,
+ roles = roles.map { it.toRoleInfo() },
+ permissions = permissions,
+ clients = clients,
+ shouldRenewPassword = shouldRenewPassword,
+ isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired,
+ )
+}
+
+fun UserInfo.toUserInfoPreferences(): UserInfoPreferences {
+ return UserInfoPreferences(
+ username = username,
+ userId = userId,
+ base64EncodedAuthenticationKey = base64EncodedAuthenticationKey,
+ authenticated = authenticated,
+ officeId = officeId,
+ officeName = officeName,
+ roles = roles.map { it.toRolePreferences() },
+ permissions = permissions,
+ clients = clients,
+ shouldRenewPassword = shouldRenewPassword,
+ isTwoFactorAuthenticationRequired = isTwoFactorAuthenticationRequired,
+ )
+}
+
+fun UserPreferences.toUserData(): UserData {
+ return UserData(
+ token = token,
+ name = name,
+ username = username,
+ email = email,
+ mobileNo = mobileNo,
+ userId = userId,
+ clientId = clientId,
+ clientVpa = clientVpa,
+ accountId = accountId,
+ firebaseRegId = firebaseRegId,
+ client = client.toClientInfo(),
+ user = user.toUserInfo(),
+ )
+}
+
+fun UserData.toUserPreferences(): UserPreferences {
+ return UserPreferences(
+ token = token,
+ name = name,
+ username = username,
+ email = email,
+ mobileNo = mobileNo,
+ userId = userId,
+ clientId = clientId,
+ clientVpa = clientVpa,
+ accountId = accountId,
+ firebaseRegId = firebaseRegId,
+ client = client.toClientPreferences(),
+ user = user.toUserInfoPreferences(),
+ )
+}
\ No newline at end of file
diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt
new file mode 100644
index 000000000..a15d60c56
--- /dev/null
+++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/UserPreferencesDataSource.kt
@@ -0,0 +1,150 @@
+@file:OptIn(ExperimentalSerializationApi::class, ExperimentalSettingsApi::class)
+
+package org.mifospay.core.datastore
+
+import com.russhwolf.settings.ExperimentalSettingsApi
+import com.russhwolf.settings.Settings
+import com.russhwolf.settings.serialization.decodeValue
+import com.russhwolf.settings.serialization.decodeValueOrNull
+import com.russhwolf.settings.serialization.encodeValue
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.withContext
+import kotlinx.serialization.ExperimentalSerializationApi
+import org.mifospay.core.datastore.proto.ClientPreferences
+import org.mifospay.core.datastore.proto.RolePreferences
+import org.mifospay.core.datastore.proto.UserInfoPreferences
+import org.mifospay.core.datastore.proto.UserPreferences
+import org.mifospay.core.model.ClientInfo
+import org.mifospay.core.model.RoleInfo
+import org.mifospay.core.model.UserData
+import org.mifospay.core.model.UserInfo
+
+private const val USER_DATA_KEY = "userData"
+private const val USER_INFO_KEY = "userInfo"
+private const val CLIENT_INFO_KEY = "clientInfo"
+private const val ROLE_INFO_KEY = "roleInfo"
+
+class UserPreferencesDataSource(
+ private val settings: Settings,
+ private val dispatcher: CoroutineDispatcher,
+) {
+ private val _userData = MutableStateFlow(
+ settings.decodeValue(
+ key = USER_DATA_KEY,
+ serializer = UserPreferences.serializer(),
+ defaultValue = settings.decodeValueOrNull(
+ key = USER_DATA_KEY,
+ serializer = UserPreferences.serializer(),
+ ) ?: UserPreferences.DEFAULT,
+ ),
+ )
+
+ private val _userInfo = MutableStateFlow(
+ settings.decodeValue(
+ key = USER_INFO_KEY,
+ serializer = UserInfoPreferences.serializer(),
+ defaultValue = settings.decodeValueOrNull(
+ key = USER_INFO_KEY,
+ serializer = UserInfoPreferences.serializer(),
+ ) ?: UserInfoPreferences.DEFAULT,
+ ),
+ )
+
+ private val _clientInfo = MutableStateFlow(
+ settings.decodeValue(
+ key = CLIENT_INFO_KEY,
+ serializer = ClientPreferences.serializer(),
+ defaultValue = settings.decodeValueOrNull(
+ key = CLIENT_INFO_KEY,
+ serializer = ClientPreferences.serializer(),
+ ) ?: ClientPreferences.DEFAULT,
+ ),
+ )
+
+ private val _roleInfo = MutableStateFlow(
+ settings.decodeValue(
+ key = ROLE_INFO_KEY,
+ serializer = RolePreferences.serializer(),
+ defaultValue = settings.decodeValueOrNull(
+ key = ROLE_INFO_KEY,
+ serializer = RolePreferences.serializer(),
+ ) ?: RolePreferences.DEFAULT,
+ ),
+ )
+
+ val userData = _userData.map(UserPreferences::toUserData)
+ val token = _userData.map(UserPreferences::toUserData).map { it.token }
+ val userInfo = _userInfo.map(UserInfoPreferences::toUserInfo)
+ val clientInfo = _clientInfo.map(ClientPreferences::toClientInfo)
+ val roleInfo = _roleInfo.map(RolePreferences::toRoleInfo)
+
+ suspend fun updateRoleInfo(roleInfo: RoleInfo) {
+ withContext(dispatcher) {
+ settings.putRolePreference(roleInfo.toRolePreferences())
+ _roleInfo.value = roleInfo.toRolePreferences()
+ }
+ }
+
+ suspend fun updateClientInfo(clientInfo: ClientInfo) {
+ withContext(dispatcher) {
+ settings.putClientPreference(clientInfo.toClientPreferences())
+ _clientInfo.value = clientInfo.toClientPreferences()
+ }
+ }
+
+ suspend fun updateUserInfo(userInfo: UserInfo) {
+ withContext(dispatcher) {
+ settings.putUserInfoPreference(userInfo.toUserInfoPreferences())
+ _userInfo.value = userInfo.toUserInfoPreferences()
+ }
+ }
+
+ suspend fun updateUserData(userData: UserData) {
+ withContext(dispatcher) {
+ settings.putUserPreference(userData.toUserPreferences())
+ _userData.value = userData.toUserPreferences()
+ }
+ }
+}
+
+private fun Settings.putClientPreference(preference: ClientPreferences) {
+ encodeValue(
+ key = CLIENT_INFO_KEY,
+ serializer = ClientPreferences.serializer(),
+ value = preference,
+ )
+}
+
+private fun Settings.putRolePreference(preference: RolePreferences) {
+ encodeValue(
+ key = CLIENT_INFO_KEY,
+ serializer = RolePreferences.serializer(),
+ value = preference,
+ )
+}
+
+private fun Settings.putUserInfoPreference(preference: UserInfoPreferences) {
+ encodeValue(
+ key = USER_INFO_KEY,
+ serializer = UserInfoPreferences.serializer(),
+ value = preference,
+ )
+}
+
+private fun Settings.putUserPreference(preference: UserPreferences) {
+ encodeValue(
+ key = USER_DATA_KEY,
+ serializer = UserPreferences.serializer(),
+ value = preference,
+ )
+}
+
+private fun Settings.getUserPreference(): UserPreferences {
+ return decodeValue(
+ key = USER_DATA_KEY,
+ serializer = UserPreferences.serializer(),
+ defaultValue = UserPreferences.DEFAULT,
+ )
+}
diff --git a/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt
new file mode 100644
index 000000000..fb8139122
--- /dev/null
+++ b/core/datastore/src/commonMain/kotlin/org/mifospay/core/datastore/di/PreferenceModule.kt
@@ -0,0 +1,12 @@
+package org.mifospay.core.datastore.di
+
+import com.russhwolf.settings.Settings
+import org.koin.core.qualifier.named
+import org.koin.dsl.module
+import org.mifospay.core.datastore.UserPreferencesDataSource
+
+val PreferencesModule = module {
+ factory { Settings() }
+ // Use the IO dispatcher name - MifosDispatchers.IO.name
+ factory { UserPreferencesDataSource(get(), get(named("IO"))) }
+}
\ No newline at end of file
diff --git a/core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt b/core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt
deleted file mode 100644
index e4d40ddc7..000000000
--- a/core/datastore/src/test/java/org/mifospay/core/datastore/ExampleUnitTest.kt
+++ /dev/null
@@ -1,25 +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/mobile-wallet/blob/master/LICENSE.md
- */
-package org.mifospay.core.datastore
-
-import org.junit.Assert.assertEquals
-import org.junit.Test
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt
new file mode 100644
index 000000000..54213d788
--- /dev/null
+++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/ClientInfo.kt
@@ -0,0 +1,10 @@
+package org.mifospay.core.model
+
+data class ClientInfo(
+ val name: String,
+ val image: String,
+ val externalId: String,
+ val clientId: Long,
+ val displayName: String,
+ val mobileNo: String,
+)
diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt
new file mode 100644
index 000000000..c100f8e69
--- /dev/null
+++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/RoleInfo.kt
@@ -0,0 +1,8 @@
+package org.mifospay.core.model
+
+data class RoleInfo(
+ val id: String,
+ val name: String,
+ val description: String,
+ val disabled: Boolean
+)
diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt
index 180afee4a..93e6a2875 100644
--- a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt
+++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserData.kt
@@ -10,7 +10,16 @@
package org.mifospay.core.model
data class UserData(
- val isAuthenticated: Boolean,
- val userName: String,
- val clientId: Long,
+ val token: String,
+ val name: String,
+ val username: String,
+ val email: String,
+ val mobileNo: String,
+ val userId: Int,
+ val clientId: Int,
+ val clientVpa: String,
+ val accountId: Int,
+ val firebaseRegId: String,
+ val client: ClientInfo,
+ val user: UserInfo,
)
diff --git a/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt
new file mode 100644
index 000000000..c5274d25d
--- /dev/null
+++ b/core/model/src/commonMain/kotlin/org/mifospay/core/model/UserInfo.kt
@@ -0,0 +1,15 @@
+package org.mifospay.core.model
+
+data class UserInfo(
+ val username: String,
+ val userId: Int,
+ val base64EncodedAuthenticationKey: String,
+ val authenticated: Boolean,
+ val officeId: Int,
+ val officeName: String,
+ val roles: List,
+ val permissions: List,
+ val clients: List,
+ val shouldRenewPassword: Boolean,
+ val isTwoFactorAuthenticationRequired: Boolean
+)