diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index f8e7233486..e43d7fba6d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -1025,11 +1025,14 @@ class Account( } } - suspend fun changeBottomBarItems(items: List) { - 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): 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 diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt index dec68a0ded..286030e4f8 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/AccountViewModel.kt @@ -1937,10 +1937,15 @@ class AccountViewModel( fun bottomBarItemsFlow(): StateFlow> = account.settings.syncedSettings.navigation.bottomBarItems - fun changeBottomBarItems(items: List) = - launchSigner { - account.changeBottomBarItems(items) + fun changeBottomBarItems(items: List) { + // 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> = account.settings.syncedSettings.chats.pinnedChatrooms