android, desktop: fix draft loss when switching to chat where user cannot send messages (#7239)

* android, desktop: save draft when switching to chat where user cannot send messages

On desktop, chat and chatId change in the same recomposition when another
chat is opened from the always-visible chat list. The effect clearing
compose state of a non-sendable chat (observer, channel subscriber,
review by admins) was composed before the draft-saving KeyChangeEffect
and ran first, wiping the live compose state before it could be saved
and then clearing the previously saved draft via clearPrevDraft.

Effects launch in composition order, so the clearing effect is moved
after KeyChangeEffect: the previous chat's draft is saved first, and
clearCurrentDraft is a no-op for it because draftChatId no longer
matches the opened chat. Clearing the opened chat's own draft when it
cannot send is preserved, as is clearing when the open chat itself
becomes non-sendable (only the sendMsgEnabled key changes).

* plans: investigation and justification for draft message loss fix
This commit is contained in:
Narasimha-sc
2026-07-22 08:32:37 +01:00
committed by GitHub
parent 9586c97439
commit 7fc2a6e6bd
2 changed files with 75 additions and 7 deletions
@@ -1308,13 +1308,6 @@ fun ComposeView(
}
}
LaunchedEffect(rememberUpdatedState(chat.chatInfo.sendMsgEnabled).value) {
if (!chat.chatInfo.sendMsgEnabled) {
clearCurrentDraft()
clearState()
}
}
KeyChangeEffect(chatModel.chatId.value) { prevChatId ->
val cs = composeState.value
if (cs.liveMessage != null && (cs.message.text.isNotEmpty() || cs.liveMessage.sent)) {
@@ -1345,6 +1338,14 @@ fun ComposeView(
chatModel.removeLiveDummy()
CIFile.cachedRemoteFileRequests.clear()
}
// Must be composed after KeyChangeEffect above (effects run in composition order),
// so that on chat switch the previous chat's draft is saved before it is cleared here.
LaunchedEffect(rememberUpdatedState(chat.chatInfo.sendMsgEnabled).value) {
if (!chat.chatInfo.sendMsgEnabled) {
clearCurrentDraft()
clearState()
}
}
// keep the attach size limit in sync with the chat: the user's active badge raises it, but not in incognito chats where no badge is presented
LaunchedEffect(chat.chatInfo) {
val incognito = if (chat.chatInfo.profileChangeProhibited) chat.chatInfo.incognito else chatModel.controller.appPrefs.incognito.get()