mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-08-08 23:54:39 +00:00
fix: keep bottom-bar edits ordered to prevent a stale revert
Persisting a bottom-bar edit went through `launchSigner { account.change... }`,
which dispatches on a multi-threaded pool. Because the reactive StateFlow emit
happened inside that coroutine, two quick edits (e.g. tapping Add on several
catalog rows) could complete out of order: the older list would win the flow,
and the settings screen — which re-seeds its editable list from the flow via
`LaunchedEffect(savedItems) { syncFrom(...) }` — would visibly revert the newer
edit and publish the stale list in the NIP-78 event.
Apply the change to the in-memory flow synchronously on the caller (UI) thread
via `Account.applyBottomBarItems` (a non-suspending emit + local save, both
non-blocking) so rapid edits stay strictly ordered, and run only the
sign/encrypt/publish off-thread. Restores the ordering guarantee the previous
synchronous `tryEmit` had.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MJiPHArXZ7P5EvZa7GN9fP
This commit is contained in:
@@ -1025,11 +1025,14 @@ class Account(
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun changeBottomBarItems(items: List<BottomBarEntry>) {
|
||||
if (settings.changeBottomBarItems(items)) {
|
||||
sendNewAppSpecificData()
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Applies the new bottom-bar list to the reactive synced-settings flow and returns whether it
|
||||
* changed. Non-suspending and only touches in-memory state, so callers invoke it synchronously on
|
||||
* the UI thread — rapid edits then stay strictly ordered instead of racing on the multi-threaded
|
||||
* signer dispatcher (an out-of-order write would revert the newer edit, which the settings screen
|
||||
* re-seeds from this flow). Pair a `true` result with [sendNewAppSpecificData] to publish.
|
||||
*/
|
||||
fun applyBottomBarItems(items: List<BottomBarEntry>): Boolean = settings.changeBottomBarItems(items)
|
||||
|
||||
suspend fun toggleChatroomPin(room: ChatroomKey) {
|
||||
settings.toggleChatroomPin(room)
|
||||
@@ -1082,7 +1085,7 @@ class Account(
|
||||
sendNewAppSpecificData()
|
||||
}
|
||||
|
||||
private suspend fun sendNewAppSpecificData() = sendMyPublicAndPrivateOutbox(appSpecific.saveNewAppSpecificData())
|
||||
internal suspend fun sendNewAppSpecificData() = sendMyPublicAndPrivateOutbox(appSpecific.saveNewAppSpecificData())
|
||||
|
||||
// ---
|
||||
// NIP-13 proof-of-work publishing
|
||||
|
||||
+8
-3
@@ -1937,10 +1937,15 @@ class AccountViewModel(
|
||||
|
||||
fun bottomBarItemsFlow(): StateFlow<List<BottomBarEntry>> = account.settings.syncedSettings.navigation.bottomBarItems
|
||||
|
||||
fun changeBottomBarItems(items: List<BottomBarEntry>) =
|
||||
launchSigner {
|
||||
account.changeBottomBarItems(items)
|
||||
fun changeBottomBarItems(items: List<BottomBarEntry>) {
|
||||
// Apply to the reactive flow synchronously on the caller (UI) thread so rapid edits stay
|
||||
// ordered — launchSigner dispatches on a multi-threaded pool, so wrapping the emit too would
|
||||
// let two quick edits complete out of order and revert the newer one (the settings screen
|
||||
// re-seeds its editable list from this flow). Only the sign + encrypt + publish runs off-thread.
|
||||
if (account.applyBottomBarItems(items)) {
|
||||
launchSigner { account.sendNewAppSpecificData() }
|
||||
}
|
||||
}
|
||||
|
||||
fun pinnedChatroomsFlow(): StateFlow<Set<ChatroomKey>> = account.settings.syncedSettings.chats.pinnedChatrooms
|
||||
|
||||
|
||||
Reference in New Issue
Block a user