Skip to content

Commit 9b2e013

Browse files
biplab1niyajali
andauthored
fix(feature): fix DialogState serialization error (#1899)
Co-authored-by: Sk Niyaj Ali <[email protected]>
1 parent 33652bc commit 9b2e013

File tree

7 files changed

+122
-11
lines changed

7 files changed

+122
-11
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2025 Mifos Initiative
3+
*
4+
* This Source Code Form is subject to the terms of the Mozilla Public
5+
* License, v. 2.0. If a copy of the MPL was not distributed with this
6+
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
7+
*
8+
* See https://github.com/openMF/mobile-wallet/blob/master/LICENSE.md
9+
*/
10+
package org.mifospay.core.common
11+
12+
import kotlinx.serialization.KSerializer
13+
import kotlinx.serialization.descriptors.PrimitiveKind
14+
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
15+
import kotlinx.serialization.descriptors.SerialDescriptor
16+
import kotlinx.serialization.encoding.Decoder
17+
import kotlinx.serialization.encoding.Encoder
18+
import org.jetbrains.compose.resources.StringResource
19+
20+
/**
21+
* A custom [KSerializer] for [StringResource] that enables serialization of StringResource objects.
22+
*
23+
* This serializer extracts the resource key from StringResource during serialization
24+
* and reconstructs the StringResource during deserialization using a registry.
25+
*
26+
* ### Usage:
27+
* ```kotlin
28+
* @Serializable
29+
* data class DialogState(
30+
* @Serializable(with = StringResourceSerializer::class)
31+
* val message: StringResource
32+
* )
33+
* ```
34+
*/
35+
object StringResourceSerializer : KSerializer<StringResource> {
36+
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
37+
serialName = "StringResource",
38+
kind = PrimitiveKind.STRING,
39+
)
40+
41+
override fun serialize(encoder: Encoder, value: StringResource) {
42+
val resourceKey = extractResourceKey(value)
43+
encoder.encodeString(resourceKey)
44+
}
45+
46+
override fun deserialize(decoder: Decoder): StringResource {
47+
val resourceKey = decoder.decodeString()
48+
return StringResourceRegistry.getResource(resourceKey)
49+
?: throw IllegalArgumentException("StringResource not found for key: $resourceKey")
50+
}
51+
}
52+
53+
/**
54+
* Extracts the resource key from a StringResource object.
55+
*
56+
* @param stringResource The StringResource to extract the key from
57+
* @return The resource key as a string
58+
*/
59+
private fun extractResourceKey(stringResource: StringResource): String {
60+
val stringRepresentation = stringResource.toString()
61+
62+
val keyPattern = Regex("key=([^,\\s)]+)")
63+
val match = keyPattern.find(stringRepresentation)
64+
65+
return if (match != null) {
66+
match.groupValues[1]
67+
} else {
68+
stringRepresentation.substringAfterLast("=").substringBefore(")")
69+
.ifEmpty { stringRepresentation }
70+
}
71+
}
72+
73+
/**
74+
* A registry that maps resource keys to their corresponding StringResource objects.
75+
*
76+
* Used during deserialization to reconstruct StringResource objects from their serialized resource keys.
77+
*/
78+
object StringResourceRegistry {
79+
private val resourceMap = mutableMapOf<String, StringResource>()
80+
81+
fun register(resourceKey: String, stringResource: StringResource) {
82+
resourceMap[resourceKey] = stringResource
83+
}
84+
85+
fun getResource(resourceKey: String): StringResource? {
86+
return resourceMap[resourceKey]
87+
}
88+
}

feature/make-transfer/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
plugins {
1111
alias(libs.plugins.cmp.feature.convention)
12+
alias(libs.plugins.kotlin.serialization)
1213
}
1314

1415
android {

feature/make-transfer/src/commonMain/kotlin/org/mifospay/feature/make/transfer/MakeTransferViewModel.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import mobile_wallet.feature.make_transfer.generated.resources.feature_make_tran
3131
import org.jetbrains.compose.resources.StringResource
3232
import org.mifospay.core.common.DataState
3333
import org.mifospay.core.common.DateHelper
34+
import org.mifospay.core.common.StringResourceSerializer
3435
import org.mifospay.core.common.getSerialized
3536
import org.mifospay.core.common.setSerialized
3637
import org.mifospay.core.common.utils.capitalizeWords
@@ -238,9 +239,15 @@ internal data class MakeTransferState(
238239
data object Loading : DialogState
239240

240241
@Serializable
241-
sealed interface Error : DialogState {
242-
data class StringMessage(val message: String) : Error
243-
data class ResourceMessage(val message: StringResource) : Error
242+
sealed class Error : DialogState {
243+
@Serializable
244+
data class StringMessage(val message: String) : Error()
245+
246+
@Serializable
247+
data class ResourceMessage(
248+
@Serializable(with = StringResourceSerializer::class)
249+
val message: StringResource,
250+
) : Error()
244251
}
245252
}
246253
}

feature/profile/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
plugins {
1212
alias(libs.plugins.cmp.feature.convention)
13+
alias(libs.plugins.kotlin.serialization)
1314
}
1415

1516
android {

feature/profile/src/commonMain/kotlin/org/mifospay/feature/profile/edit/EditProfileViewModel.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import mobile_wallet.feature.profile.generated.resources.feature_profile_profile
3232
import mobile_wallet.feature.profile.generated.resources.feature_profile_profile_updated_successfully
3333
import org.jetbrains.compose.resources.StringResource
3434
import org.mifospay.core.common.DataState
35+
import org.mifospay.core.common.StringResourceSerializer
3536
import org.mifospay.core.common.getSerialized
3637
import org.mifospay.core.common.setSerialized
3738
import org.mifospay.core.common.utils.isValidEmail
@@ -301,11 +302,19 @@ internal data class EditProfileState(
301302

302303
@Serializable
303304
sealed interface DialogState {
305+
@Serializable
304306
data object Loading : DialogState
305307

306-
sealed interface Error : DialogState {
307-
data class StringMessage(val message: String) : Error
308-
data class ResourceMessage(val message: StringResource) : Error
308+
@Serializable
309+
sealed class Error : DialogState {
310+
@Serializable
311+
data class StringMessage(val message: String) : Error()
312+
313+
@Serializable
314+
data class ResourceMessage(
315+
@Serializable(with = StringResourceSerializer::class)
316+
val message: StringResource,
317+
) : Error()
309318
}
310319
}
311320

feature/send-money/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
*/
1010
plugins {
1111
alias(libs.plugins.cmp.feature.convention)
12+
alias(libs.plugins.kotlin.serialization)
1213
}
1314

1415
android {

feature/send-money/src/commonMain/kotlin/org/mifospay/feature/send/money/SendMoneyViewModel.kt

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import kotlinx.coroutines.flow.onEach
2525
import kotlinx.coroutines.flow.stateIn
2626
import kotlinx.coroutines.flow.update
2727
import kotlinx.coroutines.launch
28-
import kotlinx.serialization.Contextual
2928
import kotlinx.serialization.Serializable
3029
import mobile_wallet.feature.send_money.generated.resources.Res
3130
import mobile_wallet.feature.send_money.generated.resources.feature_send_money_error_account_cannot_be_empty
@@ -35,6 +34,7 @@ import mobile_wallet.feature.send_money.generated.resources.feature_send_money_e
3534
import mobile_wallet.feature.send_money.generated.resources.feature_send_money_error_requesting_payment_qr_data_missing
3635
import org.jetbrains.compose.resources.StringResource
3736
import org.mifospay.core.common.DataState
37+
import org.mifospay.core.common.StringResourceSerializer
3838
import org.mifospay.core.common.getSerialized
3939
import org.mifospay.core.common.setSerialized
4040
import org.mifospay.core.data.repository.AccountRepository
@@ -235,15 +235,19 @@ data class SendMoneyState(
235235
data object Loading : DialogState
236236

237237
@Serializable
238-
sealed interface Error : DialogState {
238+
sealed class Error : DialogState {
239239
@Serializable
240-
data class ResourceMessage(@Contextual val message: StringResource) : Error
240+
data class ResourceMessage(
241+
@Serializable(with = StringResourceSerializer::class)
242+
val message: StringResource,
243+
) : Error()
241244

242245
@Serializable
243246
data class GenericResourceMessage(
244-
@Contextual val message: StringResource,
247+
@Serializable(with = StringResourceSerializer::class)
248+
val message: StringResource,
245249
val args: List<String>,
246-
) : Error
250+
) : Error()
247251
}
248252
}
249253
}

0 commit comments

Comments
 (0)