jeziellago / compose-markdown

Markdown Text for Android Jetpack Compose 📋.
MIT License
567 stars 47 forks source link

Missing context when using in app widget glance #59

Open YukiGasai opened 1 year ago

YukiGasai commented 1 year ago

Hi, I am trying to use the MarkdownText component inside my widget. The editor is not showing any errors until I add the widget. I get the following error.

Work [ id=72ffacc4-21eb-4b3a-98db-3968e91cbd5f, tags={ androidx.glance.session.SessionWorker } ] failed because it threw an exception/error
                                                                                                    java.util.concurrent.ExecutionException: java.lang.IllegalStateException: CompositionLocal LocalContext not present
                                                                                                        at androidx.work.impl.utils.futures.AbstractFuture.getDoneValue(AbstractFuture.java:516)
                                                                                                        at androidx.work.impl.utils.futures.AbstractFuture.get(AbstractFuture.java:475)
                                                                                                        at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:311)
                                                                                                        at androidx.work.impl.utils.SerialExecutor$Task.run(SerialExecutor.java:91)
                                                                                                        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
                                                                                                        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
                                                                                                        at java.lang.Thread.run(Thread.java:1012)
                                                                                                    Caused by: java.lang.IllegalStateException: CompositionLocal LocalContext not present
                                                                                                        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.noLocalProvidedFor(AndroidCompositionLocals.android.kt:168)
                                                                                                        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt.access$noLocalProvidedFor(AndroidCompositionLocals.android.kt:1)
                                                                                                        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$LocalContext$1.invoke(AndroidCompositionLocals.android.kt:54)
                                                                                                        at androidx.compose.ui.platform.AndroidCompositionLocals_androidKt$LocalContext$1.invoke(AndroidCompositionLocals.android.kt:53)
                                                                                                        at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
                                                                                                        at androidx.compose.runtime.LazyValueHolder.getCurrent(ValueHolders.kt:29)
                                                                                                        at androidx.compose.runtime.LazyValueHolder.getValue(ValueHolders.kt:31)
                                                                                                        at androidx.compose.runtime.ComposerImpl.resolveCompositionLocal(Composer.kt:2069)
                                                                                                        at androidx.compose.runtime.ComposerImpl.consume(Composer.kt:2037)
                                                                                                        at dev.jeziellago.compose.markdowntext.MarkdownTextKt.MarkdownText-Jo_eG7I(MarkdownText.kt:232)
                                                                                                        at de.yukigasai.obsidiantodowidget.ComposableSingletons$TodoWidgetKt$lambda-2$1.invoke(TodoWidget.kt:135)
                                                                                                        at de.yukigasai.obsidiantodowidget.ComposableSingletons$TodoWidgetKt$lambda-2$1.invoke(TodoWidget.kt:134)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:107)
                                                                                                        at androidx.compose.runtime.internal.ComposableLambdaImpl.invoke(ComposableLambda.jvm.kt:34)
                                                                                                        at androidx.compose.runtime.CompositionLocalKt.CompositionLocalProvider(CompositionLocal.kt:228)
                                                                                                        at de.yukigasai.obsidiantodowidget.TodoWidgetKt.LocalContextProvider(TodoWidget.kt:120)

I am using the minimal example:

override suspend fun provideGlance(context: Context, id: GlanceId) {
    refreshTodos(context, id)
    provideContent { Content() }
}

@Composable
fun Content() {
    val markdownContent = """  
            # Sample  
            * Markdown  
            * [Link](https://example.com)  
            ![Image](https://example.com/img.png)  
            <a href="https://www.google.com/">Google</a>  
        """.trimIndent()
    MarkdownText(markdown = markdownContent)
}

I already tried wrapping it in a LocalContextProvider, but that didn't seem to change anything.

override suspend fun provideGlance(context: Context, id: GlanceId) {
    refreshTodos(context, id)
    provideContent { Content() }
}

@Composable
fun LocalContextProvider(context: Context, content: @Composable () -> Unit) {
    CompositionLocalProvider(LocalContext provides context, content = content)
}

@Composable
fun Content() {
    val markdownContent = """  
            # Sample  
            * Markdown  
            * [Link](https://example.com)  
            ![Image](https://example.com/img.png)  
            <a href="https://www.google.com/">Google</a>  
        """.trimIndent()
    val context = LocalContext.current
    LocalContextProvider(context) {
        MarkdownText(markdown = markdownContent)
    }
}

Thank you for creating this library, any help would be appreciated ^^.

jeziellago commented 1 year ago

Hi, @YukiGasai! Thanks for reporting! Would be great if you could share more details or provide a sample app just to debugging better the issue and collect more data.

KieronQuinn commented 6 months ago

The reason this isn't working is that Jetpack Glance isn't like regular Compose. It has its own composition system and you can't use custom components like this unfortunately.

You also cannot use custom Spannables, so even with the Glance Interoperability with XML declared RemoteViews, it's not possible to send Markwon parsed content to a widget.

See also this issue on Markwon: https://github.com/noties/Markwon/issues/403