From 1f05937752bba0f65dc1ab49e7e29de571560c63 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Mon, 28 Sep 2026 10:48:32 -0400 Subject: [PATCH] fix(marmot): an out-of-sync reset survives leaving the chat The reset ran on the banner's rememberCoroutineScope, cancelled as soon as the chat closed; leaving right after confirming could stop it between dropping the local state, flagging the group as awaiting a re-invite, and publishing the KeyPackage the admin needs. It now runs on the account scope. Co-Authored-By: Claude Opus 5.5 --- .../amethyst/ui/screen/loggedIn/AccountViewModel.kt | 9 ++++++++- .../loggedIn/chats/marmotGroup/MarmotGroupChatView.kt | 3 +-- 2 files changed, 9 insertions(+), 3 deletions(-) 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 d8bcd839b5..f92eae835c 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 @@ -2556,7 +2556,14 @@ class AccountViewModel( /** True when this account has somewhere to upload a group's encrypted media. */ fun hasBlossomServers(): Boolean = account.marmot.marmotMediaPolicyServers().isNotEmpty() - suspend fun resetOutOfSyncMarmotGroup(nostrGroupId: String) = account.marmot.resetOutOfSyncMarmotGroup(nostrGroupId) + /** + * On the account scope, not the screen's: the reset drops local state, flags the group as + * awaiting a re-invite and publishes a KeyPackage, and leaving the chat mid-way must not + * stop it between those steps. + */ + fun resetOutOfSyncMarmotGroup(nostrGroupId: String) { + account.scope.launch(Dispatchers.IO) { account.marmot.resetOutOfSyncMarmotGroup(nostrGroupId) } + } suspend fun enableMarmotEncryptedMediaV2(nostrGroupId: String) { account.marmot.enableMarmotEncryptedMediaV2(nostrGroupId) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt index 53ad82a1a6..f31fc28a75 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/marmotGroup/MarmotGroupChatView.kt @@ -416,7 +416,6 @@ private fun MarmotOutOfSyncBanner( nostrGroupId: HexKey, accountViewModel: AccountViewModel, ) { - val scope = rememberCoroutineScope() var confirming by remember { mutableStateOf(false) } Column(modifier = Modifier.fillMaxWidth().padding(horizontal = 12.dp, vertical = 6.dp)) { @@ -439,7 +438,7 @@ private fun MarmotOutOfSyncBanner( TextButton( onClick = { confirming = false - scope.launch(Dispatchers.IO) { accountViewModel.resetOutOfSyncMarmotGroup(nostrGroupId) } + accountViewModel.resetOutOfSyncMarmotGroup(nostrGroupId) }, ) { Text(stringRes(Res.string.marmot_out_of_sync_reset)) } },