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 0c14a14089..9f214f91b9 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -2045,6 +2045,14 @@ class Account( extraNotesToBroadcast.forEach { client.publish(it, 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, @@ -2081,18 +2089,25 @@ class Account( } } - suspend fun deleteDraftIgnoreErrors(draftTag: String) { + suspend fun deleteDraftIgnoreErrors(draftNote: AddressableNote?) { try { - deleteDraftInner(draftTag) + deleteDraftInner(draftNote) } catch (e: Exception) { if (e is CancellationException) throw e } } - suspend fun deleteDraftInner(draftTag: String) { + suspend fun deleteDraftInner(draftNote: AddressableNote?) { if (!isWriteable()) return - val extraRelays = cache.getAddressableNoteIfExists(DraftWrapEvent.createAddressTag(signer.pubKey, draftTag))?.relays ?: emptyList() + // Only a real, still-present draft needs a deletion signed. The note's 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 val deletedDraft = DraftWrapEvent.createDeletedEvent(draftTag, signer) val deletionEvent = signer.sign(DeletionEvent.build(listOf(deletedDraft))) 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 7df304cae5..3c3973b09e 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,6 +39,7 @@ 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 @@ -136,11 +137,17 @@ open class CommentPostViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) sendDraftSync() } } @@ -261,6 +268,7 @@ open class CommentPostViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -489,7 +497,7 @@ open class CommentPostViewModel : } } - val version = draftTag.current + val draftToDelete = draftNote val anonymous = wantsAnonymousPost cancel() @@ -500,14 +508,14 @@ open class CommentPostViewModel : } accountViewModel.viewModelScope.launch(Dispatchers.IO) { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - accountViewModel.account.deleteDraftIgnoreErrors(draftTag.current) - } else { + accountViewModel.account.deleteDraftIgnoreErrors(draftNote) + } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val attachments = mutableSetOf() nip95attachments.forEach { attachments.add(it.first) 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 8bbc1f2fe6..c5c94e64c6 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,6 +37,7 @@ 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 @@ -126,6 +127,11 @@ class ChatNewMessageViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + lateinit var accountViewModel: AccountViewModel lateinit var account: Account @@ -134,6 +140,7 @@ class ChatNewMessageViewModel : draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -327,6 +334,7 @@ class ChatNewMessageViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -418,17 +426,17 @@ class ChatNewMessageViewModel : } suspend fun sendPostSync() { - val version = draftTag.current + val draftToDelete = draftNote innerSendPost(null) cancel() accountViewModel.viewModelScope.launch(Dispatchers.IO) { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - account.deleteDraftIgnoreErrors(draftTag.current) + account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { innerSendPost(draftTag.current) } 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 510b42a501..142c025d54 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,6 +43,7 @@ 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 @@ -112,11 +113,17 @@ open class ChannelNewMessageViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -229,6 +236,7 @@ open class ChannelNewMessageViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -301,20 +309,20 @@ open class ChannelNewMessageViewModel : val template = createTemplate() ?: return val channelRelays = channel?.relays() ?: emptySet() - val version = draftTag.current + val draftToDelete = draftNote cancel() accountViewModel.account.signAndSendPrivatelyOrBroadcast(template) { channelRelays.toList() } accountViewModel.viewModelScope.launch(Dispatchers.IO) { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - account.deleteDraftIgnoreErrors(draftTag.current) + account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val attachments = mutableSetOf() nip95attachments.forEach { 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 b986a8be8e..cac2107755 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,6 +39,7 @@ 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 @@ -128,6 +129,11 @@ class LongFormPostViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + lateinit var accountViewModel: AccountViewModel lateinit var account: Account @@ -136,6 +142,7 @@ class LongFormPostViewModel : draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -237,6 +244,7 @@ class LongFormPostViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -324,7 +332,7 @@ class LongFormPostViewModel : suspend fun sendPostSync() { val template = createTemplate() ?: return - val version = draftTag.current + val draftToDelete = draftNote cancel() if (accountViewModel.settings.useTrackedBroadcasts()) { @@ -342,13 +350,13 @@ class LongFormPostViewModel : } accountViewModel.launchSigner { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank() && title.text.isBlank()) { - accountViewModel.account.deleteDraftIgnoreErrors(draftTag.current) + accountViewModel.account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val template = createTemplate() ?: return 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 5574c773b8..0cbfe7a650 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,6 +38,7 @@ 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 @@ -114,6 +115,11 @@ open class NewProductViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + lateinit var accountViewModel: AccountViewModel lateinit var account: Account @@ -122,6 +128,7 @@ open class NewProductViewModel : draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -218,6 +225,7 @@ open class NewProductViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -315,18 +323,18 @@ open class NewProductViewModel : suspend fun sendPostSync() { val template = createTemplate() ?: return - val version = draftTag.current + val draftToDelete = draftNote cancel() accountViewModel.account.signAndSendPrivatelyOrBroadcast(template, relayList = { relayList }) accountViewModel.viewModelScope.launch(Dispatchers.IO) { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - accountViewModel.account.deleteDraftIgnoreErrors(draftTag.current) + accountViewModel.account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val template = createTemplate() ?: return 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 96590b55e1..a447dbcdca 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,6 +41,7 @@ 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 @@ -183,6 +184,11 @@ open class ShortNotePostViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + lateinit var accountViewModel: AccountViewModel lateinit var account: Account @@ -191,6 +197,7 @@ open class ShortNotePostViewModel : draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -483,6 +490,7 @@ open class ShortNotePostViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -889,7 +897,7 @@ open class ShortNotePostViewModel : } } - val version = draftTag.current + val draftToDelete = draftNote val anonymous = wantsAnonymousPost val scheduledFor = scheduledForSec val privately = wantsPrivateNote @@ -903,7 +911,7 @@ open class ShortNotePostViewModel : @Suppress("UNCHECKED_CAST") accountViewModel.account.sendPrivateNote(template as EventTemplate) accountViewModel.launchSigner { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } return } @@ -935,7 +943,7 @@ open class ShortNotePostViewModel : ), ) accountViewModel.launchSigner { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } return } @@ -961,13 +969,13 @@ open class ShortNotePostViewModel : } accountViewModel.launchSigner { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - accountViewModel.account.deleteDraftIgnoreErrors(draftTag.current) + accountViewModel.account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val attachments = mutableSetOf() nip95attachments.forEach { 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 a9e7993a97..44bfb87c27 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 @@ -118,11 +118,17 @@ open class NestNewMessageViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -235,6 +241,7 @@ open class NestNewMessageViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -303,7 +310,7 @@ open class NestNewMessageViewModel : suspend fun sendPostSync() { val template = createTemplate() ?: return - val version = draftTag.current + val draftToDelete = draftNote cancel() // Broadcast to the user's default relays — the nest has no @@ -312,13 +319,13 @@ open class NestNewMessageViewModel : // `account.signAndComputeBroadcast(...)`. accountViewModel.account.signAndComputeBroadcast(template) accountViewModel.viewModelScope.launch(Dispatchers.IO) { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - account.deleteDraftIgnoreErrors(draftTag.current) + account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val attachments = mutableSetOf() nip95attachments.forEach { 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 dac12b57dc..a97e2068da 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,6 +38,7 @@ 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 @@ -129,6 +130,11 @@ class NewPublicMessageViewModel : IExpiration { val draftTag = DraftTagState() + // Strong reference to the live cache note for the current draft tag (derived from the + // versions flow below), so LocalCache cannot weakly collect it before a deletion needs it. + var draftNote: AddressableNote? = null + private set + lateinit var accountViewModel: AccountViewModel lateinit var account: Account @@ -137,6 +143,7 @@ class NewPublicMessageViewModel : draftTag.versions.collectLatest { // don't save the first if (it > 0) { + draftNote = account.getOrCreateDraftNote(draftTag.current) accountViewModel.launchSigner { sendDraftSync() } @@ -262,6 +269,7 @@ class NewPublicMessageViewModel : val oldTag = (draft.event as? AddressableEvent)?.dTag() if (oldTag != null) { draftTag.set(oldTag) + draftNote = account.getOrCreateDraftNote(oldTag) } loadFromDraft(innerNote) } @@ -340,18 +348,18 @@ class NewPublicMessageViewModel : } } - val version = draftTag.current + val draftToDelete = draftNote cancel() accountViewModel.account.signAndComputeBroadcast(template, extraNotesToBroadcast) accountViewModel.viewModelScope.launch(Dispatchers.IO) { - accountViewModel.account.deleteDraftIgnoreErrors(version) + accountViewModel.account.deleteDraftIgnoreErrors(draftToDelete) } } suspend fun sendDraftSync() { if (message.text.toString().isBlank()) { - accountViewModel.account.deleteDraftIgnoreErrors(draftTag.current) + accountViewModel.account.deleteDraftIgnoreErrors(draftNote) } else if (accountViewModel.settings.automaticallyCreateDrafts()) { val broadcast = mutableSetOf() nip95attachments.forEach {