@@ -27,7 +27,7 @@ private val LOG = PortableLogging.logger(name = "[PlotPanelRaw]")
2727
2828// This flag is mentioned in the ComposeMinDemoActivity.kt
2929// In a case of changes update the comment there too.
30- private const val logRecompositions = false
30+ private const val logRecompositions = true
3131
3232@Suppress(" FunctionName" )
3333@Composable
@@ -39,7 +39,12 @@ actual fun PlotPanelRaw(
3939 errorModifier : Modifier ,
4040 computationMessagesHandler : (List <String >) -> Unit
4141) {
42- var plotCanvasFigure by remember { mutableStateOf(PlotCanvasFigure ()) }
42+ if (logRecompositions) {
43+ println (" PlotPanel: recomposition" )
44+ }
45+
46+ var plotCanvasFigure: PlotCanvasFigure ? by remember { mutableStateOf(null ) }
47+ val sizingPolicy = SizingPolicy .fitContainerSize(preserveAspectRatio)
4348
4449 // Cache processed plot spec to avoid reprocessing the same raw spec on every recomposition.
4550
@@ -48,15 +53,14 @@ actual fun PlotPanelRaw(
4853 val processedPlotSpec = remember(rawSpec.hashCode()) {
4954 processRawSpecs(rawSpec, frontendOnly = false )
5055 }
56+ var errorMessage: String? by remember { mutableStateOf(null ) }
5157
52- val showErrorMessage = PlotConfig .isFailure(processedPlotSpec)
53-
54- if (logRecompositions) {
55- println (" PlotPanel: recomposition" )
58+ if (PlotConfig .isFailure(processedPlotSpec)) {
59+ errorMessage = PlotConfig .getErrorMessage(processedPlotSpec)
5660 }
5761
5862 // Background
59- val finalModifier = if (showErrorMessage ) {
63+ val finalModifier = if (errorMessage != null ) {
6064 modifier.background(Color .LightGray )
6165 } else {
6266 if (containsBackground(modifier)) {
@@ -70,37 +74,46 @@ actual fun PlotPanelRaw(
7074 }
7175 }
7276
73- // LOG.info { "Recompose PlotPanel()" }
74- if (showErrorMessage) {
77+ LaunchedEffect (processedPlotSpec, sizingPolicy, computationMessagesHandler) {
78+ runCatching {
79+ plotCanvasFigure?.update(processedPlotSpec, sizingPolicy, computationMessagesHandler)
80+ ? : LOG .info { " Error updating plot figure - plotCanvasFigure is null" }
81+ }.onFailure { e ->
82+ errorMessage = e.message ? : " Unknown error: ${e::class .simpleName} "
83+ LOG .error(e) { " Error updating plot figure" }
84+ }
85+
86+ }
87+
88+ errorMessage?.let { errMsg ->
7589 // Reset the figure to resolve the 'Registration already removed' error.
7690 // On error, the CanvasView is removed and the plotCanvasFigure changes state to 'detached',
7791 // meaning it cannot be reused.
78- @Suppress(" AssignedValueIsNeverRead" ) // false positive? The variable is used in AndroidView below.
79- plotCanvasFigure = PlotCanvasFigure ()
92+ plotCanvasFigure = null
8093
8194 // Show error message
8295 BasicTextField (
83- value = PlotConfig .getErrorMessage(processedPlotSpec) ,
96+ value = errMsg ,
8497 onValueChange = { },
8598 readOnly = true ,
8699 textStyle = errorTextStyle,
87100 modifier = errorModifier
88101 )
89- } else {
102+ } ? : run {
90103 @Suppress(" COMPOSE_APPLIER_CALL_MISMATCH" ) // Gemini says that this is a false positive
91104 AndroidView (
92105 modifier = finalModifier,
93106 factory = { ctx ->
107+ plotCanvasFigure = plotCanvasFigure ? : PlotCanvasFigure ()
108+
94109 CanvasView (ctx).apply {
95110 figure = plotCanvasFigure
111+ onError = { e ->
112+ @Suppress(" AssignedValueIsNeverRead" )
113+ errorMessage = e.message ? : " Unknown error: ${e::class .simpleName} "
114+ LOG .error(e) { " Error in CanvasView" }
115+ }
96116 }
97- },
98- update = { _ ->
99- plotCanvasFigure.update(
100- processedPlotSpec,
101- SizingPolicy .fitContainerSize(preserveAspectRatio),
102- computationMessagesHandler
103- )
104117 }
105118 )
106119 }
0 commit comments