fun PlotPanelAndroidView()

in lets-plot-compose/src/androidMain/kotlin/org/jetbrains/letsPlot/compose/PlotPanelAndroidView.kt [33:118]


fun PlotPanelAndroidView(
    rawSpec: MutableMap<String, Any>,
    preserveAspectRatio: Boolean,
    modifier: Modifier,
    errorTextStyle: TextStyle,
    errorModifier: Modifier,
    computationMessagesHandler: (List<String>) -> Unit
) {
    if (logRecompositions) {
        println("PlotPanel: recomposition")
    }

    var plotCanvasFigure: PlotCanvasFigure2? by remember { mutableStateOf(null) }
    val sizingPolicy = SizingPolicy.fitContainerSize(preserveAspectRatio)

    // Cache processed plot spec to avoid reprocessing the same raw spec on every recomposition.

    // Note: Use remember(rawSpec.hashCode()), to bypass the equality check and use the content hash directly.
    // The issue was that remember(rawSpec) uses some kind of comparison (equals()?) which somehow not working for `MutableMap`.
    val processedPlotSpec = remember(rawSpec.hashCode()) {
        processRawSpecs(rawSpec, frontendOnly = false)
    }

    var errorMessage: String? by remember(processedPlotSpec) { mutableStateOf(null) } // Reset error on spec change

    LaunchedEffect(processedPlotSpec, sizingPolicy, computationMessagesHandler) {
        runCatching {
            if (PlotConfig.isFailure(processedPlotSpec)) {
                errorMessage = PlotConfig.getErrorMessage(processedPlotSpec)
            } else {
                plotCanvasFigure?.update(processedPlotSpec, sizingPolicy, computationMessagesHandler)
                    ?: LOG.info { "Error updating plot figure - plotCanvasFigure is null" }
            }
        }.onFailure { e ->
            errorMessage = e.message ?: "Unknown error: ${e::class.simpleName}"
            LOG.error(e) { "Error updating plot figure" }
        }
    }

    // Background
    val finalModifier = if (errorMessage != null) {
        modifier.background(Color.LightGray)
    } else {
        if (containsBackground(modifier)) {
            // Do not change the user-defined background
            modifier
        } else {
            // Use background color from the plot theme
            val lpColor = PlotThemeHelper.plotBackground(processedPlotSpec)
            val lpBackground = Color(lpColor.red, lpColor.green, lpColor.blue, lpColor.alpha)
            modifier.background(lpBackground)
        }
    }

    errorMessage?.let { errMsg ->
        // Reset the figure to resolve the 'Registration already removed' error.
        // On error, the CanvasView is removed and the plotCanvasFigure changes state to 'detached',
        // meaning it cannot be reused.
        plotCanvasFigure = null

        // Show error message
        BasicTextField(
            value = errMsg,
            onValueChange = { },
            readOnly = true,
            textStyle = errorTextStyle,
            modifier = errorModifier
        )
    } ?: run {
        @Suppress("COMPOSE_APPLIER_CALL_MISMATCH") // Gemini says that this is a false positive
        AndroidView(
            modifier = finalModifier,
            factory = { ctx ->
                plotCanvasFigure = plotCanvasFigure ?: PlotCanvasFigure2()
                CanvasView2(ctx).apply {
                    figure = plotCanvasFigure
                    onError = { e ->
                        @Suppress("AssignedValueIsNeverRead")
                        errorMessage = e.message ?: "Unknown error: ${e::class.simpleName}"
                        LOG.error(e) { "Error in CanvasView" }
                    }
                }
            }
        )
    }
}