fix(feature): fix DialogState serialization error (#1899)

Co-authored-by: Sk Niyaj Ali <niyaj639@gmail.com>
This commit is contained in:
Biplab Dutta 2025-08-29 13:19:21 +05:30 committed by GitHub
parent 33652bcc1e
commit 9b2e013c55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 122 additions and 11 deletions

View File

@ -0,0 +1,88 @@
/*
* 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-wallet/blob/master/LICENSE.md
*/
package org.mifospay.core.common
import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.Decoder
import kotlinx.serialization.encoding.Encoder
import org.jetbrains.compose.resources.StringResource
/**
* A custom [KSerializer] for [StringResource] that enables serialization of StringResource objects.
*
* This serializer extracts the resource key from StringResource during serialization
* and reconstructs the StringResource during deserialization using a registry.
*
* ### Usage:
* ```kotlin
* @Serializable
* data class DialogState(
* @Serializable(with = StringResourceSerializer::class)
* val message: StringResource
* )
* ```
*/
object StringResourceSerializer : KSerializer<StringResource> {
override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor(
serialName = "StringResource",
kind = PrimitiveKind.STRING,
)
override fun serialize(encoder: Encoder, value: StringResource) {
val resourceKey = extractResourceKey(value)
encoder.encodeString(resourceKey)
}
override fun deserialize(decoder: Decoder): StringResource {
val resourceKey = decoder.decodeString()
return StringResourceRegistry.getResource(resourceKey)
?: throw IllegalArgumentException("StringResource not found for key: $resourceKey")
}
}
/**
* Extracts the resource key from a StringResource object.
*
* @param stringResource The StringResource to extract the key from
* @return The resource key as a string
*/
private fun extractResourceKey(stringResource: StringResource): String {
val stringRepresentation = stringResource.toString()
val keyPattern = Regex("key=([^,\\s)]+)")
val match = keyPattern.find(stringRepresentation)
return if (match != null) {
match.groupValues[1]
} else {
stringRepresentation.substringAfterLast("=").substringBefore(")")
.ifEmpty { stringRepresentation }
}
}
/**
* A registry that maps resource keys to their corresponding StringResource objects.
*
* Used during deserialization to reconstruct StringResource objects from their serialized resource keys.
*/
object StringResourceRegistry {
private val resourceMap = mutableMapOf<String, StringResource>()
fun register(resourceKey: String, stringResource: StringResource) {
resourceMap[resourceKey] = stringResource
}
fun getResource(resourceKey: String): StringResource? {
return resourceMap[resourceKey]
}
}

View File

@ -9,6 +9,7 @@
*/
plugins {
alias(libs.plugins.cmp.feature.convention)
alias(libs.plugins.kotlin.serialization)
}
android {

View File

@ -31,6 +31,7 @@ import mobile_wallet.feature.make_transfer.generated.resources.feature_make_tran
import org.jetbrains.compose.resources.StringResource
import org.mifospay.core.common.DataState
import org.mifospay.core.common.DateHelper
import org.mifospay.core.common.StringResourceSerializer
import org.mifospay.core.common.getSerialized
import org.mifospay.core.common.setSerialized
import org.mifospay.core.common.utils.capitalizeWords
@ -238,9 +239,15 @@ internal data class MakeTransferState(
data object Loading : DialogState
@Serializable
sealed interface Error : DialogState {
data class StringMessage(val message: String) : Error
data class ResourceMessage(val message: StringResource) : Error
sealed class Error : DialogState {
@Serializable
data class StringMessage(val message: String) : Error()
@Serializable
data class ResourceMessage(
@Serializable(with = StringResourceSerializer::class)
val message: StringResource,
) : Error()
}
}
}

View File

@ -10,6 +10,7 @@
plugins {
alias(libs.plugins.cmp.feature.convention)
alias(libs.plugins.kotlin.serialization)
}
android {

View File

@ -32,6 +32,7 @@ import mobile_wallet.feature.profile.generated.resources.feature_profile_profile
import mobile_wallet.feature.profile.generated.resources.feature_profile_profile_updated_successfully
import org.jetbrains.compose.resources.StringResource
import org.mifospay.core.common.DataState
import org.mifospay.core.common.StringResourceSerializer
import org.mifospay.core.common.getSerialized
import org.mifospay.core.common.setSerialized
import org.mifospay.core.common.utils.isValidEmail
@ -301,11 +302,19 @@ internal data class EditProfileState(
@Serializable
sealed interface DialogState {
@Serializable
data object Loading : DialogState
sealed interface Error : DialogState {
data class StringMessage(val message: String) : Error
data class ResourceMessage(val message: StringResource) : Error
@Serializable
sealed class Error : DialogState {
@Serializable
data class StringMessage(val message: String) : Error()
@Serializable
data class ResourceMessage(
@Serializable(with = StringResourceSerializer::class)
val message: StringResource,
) : Error()
}
}

View File

@ -9,6 +9,7 @@
*/
plugins {
alias(libs.plugins.cmp.feature.convention)
alias(libs.plugins.kotlin.serialization)
}
android {

View File

@ -25,7 +25,6 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.serialization.Contextual
import kotlinx.serialization.Serializable
import mobile_wallet.feature.send_money.generated.resources.Res
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
import mobile_wallet.feature.send_money.generated.resources.feature_send_money_error_requesting_payment_qr_data_missing
import org.jetbrains.compose.resources.StringResource
import org.mifospay.core.common.DataState
import org.mifospay.core.common.StringResourceSerializer
import org.mifospay.core.common.getSerialized
import org.mifospay.core.common.setSerialized
import org.mifospay.core.data.repository.AccountRepository
@ -235,15 +235,19 @@ data class SendMoneyState(
data object Loading : DialogState
@Serializable
sealed interface Error : DialogState {
sealed class Error : DialogState {
@Serializable
data class ResourceMessage(@Contextual val message: StringResource) : Error
data class ResourceMessage(
@Serializable(with = StringResourceSerializer::class)
val message: StringResource,
) : Error()
@Serializable
data class GenericResourceMessage(
@Contextual val message: StringResource,
@Serializable(with = StringResourceSerializer::class)
val message: StringResource,
val args: List<String>,
) : Error
) : Error()
}
}
}