diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chess/ChessLobbyState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chess/ChessLobbyState.kt index f60b777d32..6323e99b99 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chess/ChessLobbyState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/chess/ChessLobbyState.kt @@ -29,7 +29,6 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.flow.update -import java.util.concurrent.atomic.AtomicLong /** * Challenge expiry: 24 hours @@ -245,9 +244,9 @@ class ChessLobbyState( private val _selectedGameId = MutableStateFlow(null) val selectedGameId: StateFlow = _selectedGameId.asStateFlow() - // State version counter - increments on every game state update - // UI can observe this to force recomposition when internal state changes - private val stateVersionCounter = AtomicLong(0) + // State version counter — bumped on every game state update so the UI + // can force recomposition when internal state changes. MutableStateFlow.update + // is itself atomic, so a separate counter is not needed. private val _stateVersion = MutableStateFlow(0L) val stateVersion: StateFlow = _stateVersion.asStateFlow() @@ -383,13 +382,11 @@ class ChessLobbyState( if (inActiveGames) { _activeGames.update { it + (gameId to stateToUse) } - // Increment version to force UI recomposition even if map equals() returns true - val newVersion = stateVersionCounter.incrementAndGet() - _stateVersion.value = newVersion + // Bump version to force UI recomposition even if map equals() returns true + _stateVersion.update { it + 1 } } else if (inSpectatingGames) { _spectatingGames.update { it + (gameId to stateToUse) } - val newVersion = stateVersionCounter.incrementAndGet() - _stateVersion.value = newVersion + _stateVersion.update { it + 1 } } } diff --git a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/signing/SigningState.kt b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/signing/SigningState.kt index 743cc70398..c6a8752554 100644 --- a/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/signing/SigningState.kt +++ b/commons/src/commonMain/kotlin/com/vitorpamplona/amethyst/commons/ui/signing/SigningState.kt @@ -27,7 +27,8 @@ import androidx.compose.runtime.setValue import com.vitorpamplona.quartz.nip01Core.signers.SignerExceptions import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import java.util.concurrent.atomic.AtomicInteger +import kotlin.concurrent.atomics.AtomicInt +import kotlin.concurrent.atomics.ExperimentalAtomicApi import kotlin.coroutines.cancellation.CancellationException sealed class SigningOpState { @@ -44,26 +45,27 @@ sealed class SigningOpState { * Global signing status — any [SigningState] instance updates this when signing starts/ends. * Observe [globalState] from a screen-level composable to show a persistent status bar. */ +@OptIn(ExperimentalAtomicApi::class) object GlobalSigningStatus { var globalState by mutableStateOf(SigningOpState.Idle) private set - private val activeCount = AtomicInteger(0) + private val activeCount = AtomicInt(0) fun onPending() { - activeCount.incrementAndGet() + activeCount.addAndFetch(1) globalState = SigningOpState.Pending } fun onIdle() { - if (activeCount.decrementAndGet() <= 0) { - activeCount.set(0) + if (activeCount.addAndFetch(-1) <= 0) { + activeCount.store(0) globalState = SigningOpState.Idle } } fun onError(message: String) { - activeCount.decrementAndGet() + activeCount.addAndFetch(-1) globalState = SigningOpState.Error(message) } }