From b5706564d92f368446dbf1ed066e4d5b286ddd33 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 26 Jun 2026 15:38:55 +0000 Subject: [PATCH] refactor: build the draft note from the tag inside DraftTagState MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of capturing the AddressableNote returned by each save (and on load) and re-assigning it, DraftTagState now builds the note from the current tag via an injected (tag -> AddressableNote) builder and rebuilds it whenever the tag changes. Because that note is the live cached object for the address, its event tracks the draft automatically as it is saved or removed, so: - the note is never null inside the state (lateinit, wired by start()); - createAndSendDraftIgnoreErrors no longer needs to return the note, and load no longer needs to capture it — set(oldTag) rebuilds it; - the writer's existence check becomes "is there a real, non-deleted draft event in the note" (DraftWrapEvent.isDeleted()), which also stops a second blank-delete from re-signing an already-emptied draft. ViewModels just wire draftTag.start(account::getOrCreateDraftNote) in init() and reference draftTag.note; the per-VM field and held() are gone. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_016aj4ajZ4uQ58Bqts7riJ5i --- .../vitorpamplona/amethyst/model/Account.kt | 34 ++++++++++--------- .../note/creators/draftTags/DraftTagState.kt | 28 ++++++++------- .../nip22Comments/CommentPostViewModel.kt | 5 ++- .../privateDM/send/ChatNewMessageViewModel.kt | 5 ++- .../send/ChannelNewMessageViewModel.kt | 5 ++- .../nip23LongForm/LongFormPostViewModel.kt | 5 ++- .../nip99Classifieds/NewProductViewModel.kt | 5 ++- .../loggedIn/home/ShortNotePostViewModel.kt | 5 ++- .../room/chat/NestNewMessageViewModel.kt | 4 +-- .../NewPublicMessageViewModel.kt | 5 ++- 10 files changed, 50 insertions(+), 51 deletions(-) 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 c938742658..88a70560bc 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -2046,29 +2046,31 @@ class Account( } /** - * Returns the local [AddressableNote] that now holds the draft so the caller (the - * composer ViewModel) can keep a strong reference to it. [LocalCache.addressables] only - * keeps weak references, so without an owner holding the note it can be garbage collected - * and a later deletion would not find it locally (leaving an orphan on the relays). + * The live [AddressableNote] backing a draft tag for this account. It is the same cached + * note that draft events are consumed into, so its `event` tracks the draft over time. The + * composer holds onto it (via DraftTagState) so [LocalCache]'s weak reference can't collect + * it before a deletion needs it, which would otherwise orphan the draft on the relays. */ + fun getOrCreateDraftNote(draftTag: String): AddressableNote = cache.getOrCreateAddressableNote(DraftWrapEvent.createAddress(signer.pubKey, draftTag)) + suspend fun createAndSendDraftIgnoreErrors( draftTag: String, template: EventTemplate, broadcast: Set = emptySet(), - ): AddressableNote? = + ) { try { createAndSendDraftInner(draftTag, template, broadcast) } catch (e: Exception) { if (e is CancellationException) throw e - null } + } suspend fun createAndSendDraftInner( draftTag: String, template: EventTemplate, broadcast: Set = emptySet(), - ): AddressableNote? { - if (!isWriteable()) return null + ) { + if (!isWriteable()) return val extraRelays = cache.getAddressableNoteIfExists(DraftWrapEvent.createAddressTag(signer.pubKey, draftTag))?.relays ?: emptyList() @@ -2085,11 +2087,9 @@ class Account( client.publish(it, relayList.toSet()) } } - - return cache.getOrCreateAddressableNote(draftEvent.address()) } - suspend fun deleteDraftIgnoreErrors(draftNote: AddressableNote?) { + suspend fun deleteDraftIgnoreErrors(draftNote: AddressableNote) { try { deleteDraftInner(draftNote) } catch (e: Exception) { @@ -2097,13 +2097,15 @@ class Account( } } - suspend fun deleteDraftInner(draftNote: AddressableNote?) { + suspend fun deleteDraftInner(draftNote: AddressableNote) { if (!isWriteable()) return - // Nothing to delete means nothing to sign. The caller passes the note it has been - // holding (so it can't be garbage collected before we get here); a null note or one - // without an event means no draft was ever created, so we avoid prompting the signer. - if (draftNote?.event == null) return + // Only a real, still-present draft needs a deletion signed. The note is always non-null + // (it's the live cache note for the tag), but its event is null when no draft was ever + // saved (e.g. auto-drafts disabled) and already empty once it has been deleted — in both + // cases there is nothing to delete, so we avoid prompting the signer. + val draftEvent = draftNote.event as? DraftWrapEvent + if (draftEvent == null || draftEvent.isDeleted()) return val draftTag = draftNote.dTag() val extraRelays = draftNote.relays diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt index 1a387abd9f..f62f78e444 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/creators/draftTags/DraftTagState.kt @@ -37,14 +37,17 @@ class DraftTagState { var current: String by mutableStateOf(newTag()) var usedDraftTags by mutableStateOf(setOf(current)) + private var noteBuilder: ((tag: String) -> AddressableNote)? = null + /** - * Strong reference to the AddressableNote backing the current draft tag. LocalCache only - * keeps weak references to addressables, so without an owner holding the note it can be - * garbage-collected and a later deletion would not find it locally, orphaning the draft on - * the relays. Its lifecycle is tied to the tag: [held] when a draft is saved or an existing - * draft is loaded, and dropped by [rotate] when we move on to a fresh draft. + * Strong reference to the AddressableNote backing the [current] draft tag, kept alive so + * LocalCache's weak reference can't garbage-collect it before a deletion needs it (which + * would orphan the draft on the relays). It is the live cached note for the tag, so its + * `event` reflects the draft automatically as it is saved or removed — no need to re-assign + * it after each save. Rebuilt whenever the tag changes ([set]/[rotate]); valid once [start] + * wires the builder, which happens when the composer is initialized. */ - var note: AddressableNote? = null + lateinit var note: AddressableNote private set private val _versions = MutableStateFlow(0) @@ -55,20 +58,21 @@ class DraftTagState { @OptIn(ExperimentalUuidApi::class) fun newTag() = Uuid.random().toString() + /** Wires the tag -> note builder and builds the note for the current tag. */ + fun start(builder: (tag: String) -> AddressableNote) { + noteBuilder = builder + note = builder(current) + } + fun rotate() { set(newTag()) - note = null _versions.update { 0 } } fun set(existingTag: String) { current = existingTag usedDraftTags += existingTag - } - - /** Keeps a strong reference to the note that backs the current draft. */ - fun held(note: AddressableNote?) { - this.note = note + noteBuilder?.let { note = it(existingTag) } } fun newVersion() { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt index 2202628679..a7f01eb8e9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/note/nip22Comments/CommentPostViewModel.kt @@ -39,7 +39,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.commons.ui.text.setTextAndPlaceCursorAtBeginning import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -238,6 +237,7 @@ open class CommentPostViewModel : open fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -257,7 +257,6 @@ open class CommentPostViewModel : val noteAuthor = draft.author if (noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -517,7 +516,7 @@ open class CommentPostViewModel : } val template = createTemplate() ?: return - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt index 247b79dfd7..e7a989b769 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/ChatNewMessageViewModel.kt @@ -37,7 +37,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -258,6 +257,7 @@ class ChatNewMessageViewModel : fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -323,7 +323,6 @@ class ChatNewMessageViewModel : val noteAuthor = draft.author if (noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -619,7 +618,7 @@ class ChatNewMessageViewModel : } if (draftTag != null) { - this.draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag, template)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag, template) } else { accountViewModel.account.sendNip17PrivateMessage(template) } 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 6989a6411d..5ba50c7a11 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 @@ -43,7 +43,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -185,6 +184,7 @@ open class ChannelNewMessageViewModel : open fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -225,7 +225,6 @@ open class ChannelNewMessageViewModel : val noteAuthor = draft.author if (noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -325,7 +324,7 @@ open class ChannelNewMessageViewModel : } val template = createTemplate() ?: return - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt index 683cf29ae2..e5e6c7fc7d 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip23LongForm/LongFormPostViewModel.kt @@ -39,7 +39,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -215,6 +214,7 @@ class LongFormPostViewModel : fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -233,7 +233,6 @@ class LongFormPostViewModel : val noteAuthor = draft?.author if (draft != null && noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -353,7 +352,7 @@ class LongFormPostViewModel : accountViewModel.account.deleteDraftIgnoreErrors(draftTag.note) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val template = createTemplate() ?: return - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, emptySet())) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, emptySet()) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt index c5875d2c61..d1dce35892 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductViewModel.kt @@ -38,7 +38,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -199,6 +198,7 @@ open class NewProductViewModel : open fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -214,7 +214,6 @@ open class NewProductViewModel : val noteAuthor = draft.author if (noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -331,7 +330,7 @@ open class NewProductViewModel : accountViewModel.account.deleteDraftIgnoreErrors(draftTag.note) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val template = createTemplate() ?: return - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt index ad297038fa..f8f2a34214 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/home/ShortNotePostViewModel.kt @@ -41,7 +41,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.commons.ui.text.setTextAndPlaceCursorAtBeginning import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.BooleanType import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note @@ -458,6 +457,7 @@ open class ShortNotePostViewModel : open fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -479,7 +479,6 @@ open class ShortNotePostViewModel : val noteAuthor = draft?.author if (draft != null && noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -978,7 +977,7 @@ open class ShortNotePostViewModel : } val template = createTemplate() ?: return - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt index df825041dc..a1218de29b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/nests/room/chat/NestNewMessageViewModel.kt @@ -190,6 +190,7 @@ open class NestNewMessageViewModel : open fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -230,7 +231,6 @@ open class NestNewMessageViewModel : val noteAuthor = draft.author if (noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -328,7 +328,7 @@ open class NestNewMessageViewModel : } val template = createTemplate() ?: return - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, attachments) } } diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt index bf1703bd5a..d112b93f0b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/notifications/publicMessages/NewPublicMessageViewModel.kt @@ -38,7 +38,6 @@ import com.vitorpamplona.amethyst.commons.ui.text.currentWord import com.vitorpamplona.amethyst.commons.ui.text.insertUrlAtCursor import com.vitorpamplona.amethyst.commons.ui.text.replaceCurrentWord import com.vitorpamplona.amethyst.model.Account -import com.vitorpamplona.amethyst.model.AddressableNote import com.vitorpamplona.amethyst.model.LocalCache import com.vitorpamplona.amethyst.model.Note import com.vitorpamplona.amethyst.model.User @@ -209,6 +208,7 @@ class NewPublicMessageViewModel : fun init(accountVM: AccountViewModel) { this.accountViewModel = accountVM this.account = accountVM.account + draftTag.start(account::getOrCreateDraftNote) this.canAddInvoice = hasLnAddress() this.canAddZapRaiser = hasLnAddress() @@ -258,7 +258,6 @@ class NewPublicMessageViewModel : val noteAuthor = draft.author if (noteEvent is DraftWrapEvent && noteAuthor != null) { - draftTag.held(draft as? AddressableNote) viewModelScope.launch(Dispatchers.IO) { accountViewModel.createTempDraftNote(noteEvent)?.let { innerNote -> val oldTag = (draft.event as? AddressableEvent)?.dTag() @@ -362,7 +361,7 @@ class NewPublicMessageViewModel : } val template = createTemplate() - draftTag.held(accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, broadcast)) + accountViewModel.account.createAndSendDraftIgnoreErrors(draftTag.current, template, broadcast) } }