compose-multiplatform icon indicating copy to clipboard operation
compose-multiplatform copied to clipboard

Crash on js: An operation is not implemented: implement native toLanguageTag

Open jeran opened this issue 2 years ago • 3 comments

Describe the bug

Using compose-jb on js can cause an "An operation is not implemented" crash in certain scenarios. Related to https://github.com/JetBrains/compose-jb/issues/2773 but this is ticket is for js. I'm not entirely sure in what scenario this is triggered, but I believe it requires using a TextField and swapping out the theme's colors (for us it occurs when switching to dark mode).

Affected platforms

  • Web (K/JS) - Canvas based API

Versions

  • Kotlin version*: 1.7.20
  • Compose Multiplatform version*: 1.3.0
  • OS architecture (x86 or arm64): arm64

To Reproduce Steps and/or the code snippet to reproduce the behavior: I haven't isolated this in a standalone project, but the source code shows it's just an unimplemented method.

Expected behavior The application should not crash

Additional context In JsPlatformLocale, the method is not implemented. See: JsPlatformLocale.js.kt#L29

jeran avatar Mar 01 '23 21:03 jeran

@eymar Recently i fixed the same for iOS. https://github.com/JetBrains/androidx/pull/408/files

The easiest workaround is always return "en-US"

dima-avdeev-jb avatar Mar 02 '23 13:03 dima-avdeev-jb

Found a minimal code reproducing an error (for JS, works on other).

// main.js.kt
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.material.TextField
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Window
import org.jetbrains.skiko.wasm.onWasmReady

fun main() {
    onWasmReady {
        Window("DelmeApp") {
            Column(modifier = Modifier.fillMaxSize()) {
                val enabled = remember { mutableStateOf(true) }
                TextField("Hello", {}, enabled = enabled.value)
                Button( {
                    enabled.value = !enabled.value
                }){
                    Text("Toggle")
                }
            }
        }
    }
}

When you press the button, error appears:

NotImplementedError
cause: undefined
message: "An operation is not implemented: implement native toLanguageTag"
name: "NotImplementedError"
stack: "captureStack@↵NotImplementedError@↵@↵@↵@↵@↵@↵@↵@↵@↵@↵@↵@↵@↵materialize@↵@↵@↵SimpleLayout$composable@↵@↵@↵invoke$invoke@↵@↵…"

@dima-avdeev-jb could tell more about workaround, where I should return "en-US" from?

dimitree54 avatar Mar 14 '23 20:03 dimitree54

@dimitree54 This workaround should be applied on our side.

dima-avdeev-jb avatar Mar 21 '23 07:03 dima-avdeev-jb

I'm experiencing the same issue with JS target when trying to switch from light to dark theme. Where is the right place to provide locale? The error still persists in 1.4.0 Compose version

gleb-skobinsky avatar Apr 29 '23 13:04 gleb-skobinsky

This is especially frustrating since switching UI themes seems to have nothing to do with locales...

gleb-skobinsky avatar Apr 29 '23 13:04 gleb-skobinsky

I'm experiencing the same as @gleb-skobinsky with 1.5.0-dev1043

eygraber avatar May 09 '23 15:05 eygraber

for those who need a very short term solution, we ended up editing the js directly after it's built via our gradle build script.

in our case we are publishing our js module as a library to github using the npm-publish plugin, so right before that task we swap out the NotImplementedError with an empty string return.

not much of a gradle smith, so there's almost definitely a better way to do this

tasks.getByName("publishJsPackageToGithubRegistry").doFirst {
    val error =
        "throw new NotImplementedError('An operation is not implemented: implement native toLanguageTag');"
    val implementation = "return \"\";"
    val file = file("build/packages/js/androidx-ui-text.js")
    val buffer = StringBuffer()
    file.forEachLine { line ->
        buffer.appendLine(line.replace(error, implementation))
    }
    file.writeText(buffer.toString())
}

jeran avatar May 10 '23 14:05 jeran

Thanks! A similar workaround helped me to override the error for the browser app. It looks too ugly to be posted here, but does the trick at least for now

gleb-skobinsky avatar May 10 '23 15:05 gleb-skobinsky

I believe this is fixed, but I'll let ya'll close it out.

jeran avatar Sep 14 '23 18:09 jeran

Done, fixed here: https://github.com/JetBrains/compose-multiplatform-core/blob/e92f3b2860e19da41f2ef615d5c0646f413d7b32/compose/ui/ui-text/src/jsWasmMain/kotlin/androidx/compose/ui/text/intl/JsPlatformLocale.js.kt#L32

dima-avdeev-jb avatar Sep 15 '23 08:09 dima-avdeev-jb

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

okushnikov avatar Jul 14 '24 16:07 okushnikov