icerockdev / moko-resources

Resources access for mobile (android & ios) Kotlin Multiplatform development
https://moko.icerock.dev/
Apache License 2.0
1.12k stars 124 forks source link

Calling localized() outside of Composable function #740

Closed anox1337 closed 5 months ago

anox1337 commented 5 months ago

Hello,

within my commonMain business logic I have a Flow that contains one-time information events. These events are collected inside a composable function so that I can show the information as a toast to the user. Since these are one-time events I have to use a LaunchedEffect for my Flow data. My problem is that inside the LaunchedEffect I cannot call localized() on the StringDesc because it is a Composable function.

Is there any way I can show the user localized strings from within a LaunchedEffect?

@Composable
fun RenderHomeUI(component: HomeComponent) {
    LaunchedEffect(Unit) {
        component.labels.collectLatest {
            toaster.show(it.message.desc().localized(), type = ToastType.Error)
        }
    }
}
Alex009 commented 5 months ago

@anox1337 hi. use directly toString(context: Context) on android. if you use compose multiplatform and @Composable inside common code - create something like

// common
expect class StringProvider {
    fun localized(stringDesc: StringDesc): String
}

@Composable
expect fun rememberStringProvider(): StringProvider

// android
actual class StringProvider(private val context: Context) {
    actual fun localized(stringDesc: StringDesc): String = stringDesc.toString(context)
}

@Composable
actual fun rememberStringProvider(): StringProvider {
    val context = LocalContext.current
    return remember(context) { StringProvider(context) }
}

// ios
actual class StringProvider {
    actual fun localized(stringDesc: StringDesc): String = stringDesc.localized()
}

@Composable
actual fun rememberStringProvider(): StringProvider {
    return remember { StringProvider() }
}

then use in this way:

@Composable
fun RenderHomeUI(component: HomeComponent) {
    val stringProvider = rememberStringProvider()

    LaunchedEffect(Unit) {
        component.labels.collectLatest {
            toaster.show(stringProvider.localized(it.message.desc()), type = ToastType.Error)
        }
    }
}
anox1337 commented 5 months ago

Ah, that is clever! Thank you, very appreciated. Btw nice work on all those KMM libs :)