From ab8a87acadbb51e5003ff04aaa3d4a8c1da7ecca Mon Sep 17 00:00:00 2001 From: Stanislav Dmitrenko <7953703+avently@users.noreply.github.com> Date: Wed, 17 Jan 2024 19:50:48 +0700 Subject: [PATCH] android, desktop: fix alerts/modals when they are shown before UI init (#3697) --- .../simplex/common/views/helpers/AlertManager.kt | 15 +++++++++------ .../simplex/common/views/helpers/ModalView.kt | 7 +++++-- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt index f518f1c96..082d73320 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/AlertManager.kt @@ -22,24 +22,27 @@ import chat.simplex.common.ui.theme.* import chat.simplex.res.MR import dev.icerock.moko.resources.StringResource import dev.icerock.moko.resources.compose.painterResource +import kotlinx.coroutines.flow.MutableStateFlow class AlertManager { - private var alertViews = mutableStateListOf<(@Composable () -> Unit)>() + // Don't use mutableStateOf() here, because it produces this if showing from SimpleXAPI.startChat(): + // java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied + private var alertViews = MutableStateFlow(listOf<(@Composable () -> Unit)>()) fun showAlert(alert: @Composable () -> Unit) { Log.d(TAG, "AlertManager.showAlert") - alertViews.add(alert) + alertViews.value += alert } fun hideAlert() { - alertViews.removeLastOrNull() + alertViews.value = ArrayList(alertViews.value).also { it.removeLastOrNull() } } fun hideAllAlerts() { - alertViews.clear() + alertViews.value = listOf() } - fun hasAlertsShown() = alertViews.isNotEmpty() + fun hasAlertsShown() = alertViews.value.isNotEmpty() fun showAlertDialogButtons( title: String, @@ -242,7 +245,7 @@ class AlertManager { @Composable fun showInView() { - remember { alertViews }.lastOrNull()?.invoke() + alertViews.collectAsState().value.lastOrNull()?.invoke() } companion object { diff --git a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt index f64bd321f..f41d21764 100644 --- a/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt +++ b/apps/multiplatform/common/src/commonMain/kotlin/chat/simplex/common/views/helpers/ModalView.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.graphics.Color import chat.simplex.common.model.ChatModel import chat.simplex.common.platform.* import chat.simplex.common.ui.theme.* +import kotlinx.coroutines.flow.MutableStateFlow import java.util.concurrent.atomic.AtomicBoolean import kotlin.math.min @@ -49,7 +50,9 @@ class ModalManager(private val placement: ModalPlacement? = null) { private val modalCount = mutableStateOf(0) private val toRemove = mutableSetOf() private var oldViewChanging = AtomicBoolean(false) - private var passcodeView: MutableState<(@Composable (close: () -> Unit) -> Unit)?> = mutableStateOf(null) + // Don't use mutableStateOf() here, because it produces this if showing from SimpleXAPI.startChat(): + // java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied + private var passcodeView: MutableStateFlow<(@Composable (close: () -> Unit) -> Unit)?> = MutableStateFlow(null) fun showModal(settings: Boolean = false, showClose: Boolean = true, endButtons: @Composable RowScope.() -> Unit = {}, content: @Composable ModalData.() -> Unit) { val data = ModalData() @@ -140,7 +143,7 @@ class ModalManager(private val placement: ModalPlacement? = null) { @Composable fun showPasscodeInView() { - remember { passcodeView }.value?.invoke { passcodeView.value = null } + passcodeView.collectAsState().value?.invoke { passcodeView.value = null } } /**