From 7dcf2afa0fc82c01846aedad9d4d30d3442be751 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 18 Jul 2026 01:25:52 +0000 Subject: [PATCH] perf(chats): make ChannelNewMessageViewModel.init idempotent across recompositions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every channel composer screen (NIP-28 public chat, NIP-29 relay group, NIP-53 live activity, ephemeral and geohash chats) calls `init(accountViewModel)` directly from its composable body, so it ran on the main thread on every recomposition of that body — re-allocating UserSuggestionState, EmojiSuggestionState and a fresh ChatFileUploadState each time. Besides the wasted main-thread allocations, blindly re-initializing `uploadState` would reset an in-progress upload. Guard the setup so it only (re)runs when the account actually changes, matching the pattern the sibling ConcordNewMessageViewModel already uses. Repeated calls with the same account are now cheap no-ops, so leaving the call in the composable body stays correct while dropping the per-recomposition work. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01CDK63toGbE7DQxKxrQnhMU --- .../publicChannels/send/ChannelNewMessageViewModel.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt index 17a13aee09..7ca1594deb 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/publicChannels/send/ChannelNewMessageViewModel.kt @@ -213,6 +213,13 @@ open class ChannelNewMessageViewModel : fun user(): User = account.userProfile() open fun init(accountVM: AccountViewModel) { + // The channel screens call this straight from their composable body, so it runs on the main + // thread on every recomposition of that body. Guard against re-running the allocating setup + // (new UserSuggestionState/EmojiSuggestionState/ChatFileUploadState) when nothing changed: + // only (re)initialize when the account actually differs. Beyond the wasted allocations, a + // blind re-init would also reset `uploadState` mid-upload, discarding in-flight progress. + if (::accountViewModel.isInitialized && this.accountViewModel === accountVM) return + this.accountViewModel = accountVM this.account = accountVM.account this.canAddInvoice = hasLnAddress()