From e10332c957df3527472c28489f0272fa31aaea2b Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 20 May 2025 18:21:19 -0400 Subject: [PATCH] - Only saves draft after the first change in the UI. - Adjusts coroutine scopes to make sure it cannot be cancelled while posting --- .../nip22Comments/CommentPostViewModel.kt | 5 ++++- .../privateDM/send/ChatNewMessageViewModel.kt | 11 ++++------ .../chats/privateDM/send/NewGroupDMScreen.kt | 18 ++++++++++------- .../send/ChannelNewMessageViewModel.kt | 11 ++++------ .../nip99Classifieds/NewProductScreen.kt | 20 ++++++++----------- .../nip99Classifieds/NewProductViewModel.kt | 17 ++++------------ .../loggedIn/home/ShortNotePostViewModel.kt | 5 ++++- 7 files changed, 39 insertions(+), 48 deletions(-) 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 0123b8de14..d9fb112547 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 @@ -118,7 +118,10 @@ open class CommentPostViewModel : init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { - sendDraftSync() + // don't save the first + if (it > 0) { + sendDraftSync() + } } } } 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 4440924129..e20c597ecb 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 @@ -108,7 +108,10 @@ class ChatNewMessageViewModel : init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { - sendDraft() + // don't save the first + if (it > 0) { + sendDraftSync() + } } } } @@ -359,12 +362,6 @@ class ChatNewMessageViewModel : cancel() } - fun sendDraft() { - viewModelScope.launch(Dispatchers.IO) { - sendDraftSync() - } - } - suspend fun sendDraftSync() { if (message.text.isBlank()) { account?.deleteDraft(draftTag.current) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt index 95bd78742c..d2c440c7c1 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/chats/privateDM/send/NewGroupDMScreen.kt @@ -75,6 +75,7 @@ import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.core.net.toUri import androidx.lifecycle.compose.collectAsStateWithLifecycle +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.Amethyst import com.vitorpamplona.amethyst.R @@ -133,7 +134,6 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext @OptIn(ExperimentalMaterial3Api::class, FlowPreview::class) @Composable @@ -195,13 +195,13 @@ fun NewGroupDMScreen( CloseButton( modifier = HalfStartPadding, onPress = { - scope.launch { - withContext(Dispatchers.IO) { - postViewModel.sendDraftSync() - postViewModel.cancel() - } + // uses the accountViewModel scope to avoid cancelling this + // function when the postViewModel is released + accountViewModel.viewModelScope.launch(Dispatchers.IO) { + postViewModel.sendDraftSync() delay(100) nav.popBack() + postViewModel.cancel() } }, ) @@ -234,10 +234,14 @@ fun ActionButton( PostButton( modifier = HalfEndPadding, onPost = { - postViewModel.sendPost { + // uses the accountViewModel scope to avoid cancelling this + // function when the postViewModel is released + accountViewModel.viewModelScope.launch(Dispatchers.IO) { + postViewModel.sendPostSync() postViewModel.room?.let { nav.nav(routeToMessage(it, null, null, null, accountViewModel)) } + postViewModel.cancel() } nav.popBack() }, 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 705061ccdf..a2b3b03a3c 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 @@ -104,7 +104,10 @@ open class ChannelNewMessageViewModel : init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { - sendDraft() + // don't save the first + if (it > 0) { + sendDraftSync() + } } } } @@ -279,12 +282,6 @@ open class ChannelNewMessageViewModel : cancel() } - fun sendDraft() { - viewModelScope.launch(Dispatchers.IO) { - sendDraftSync() - } - } - suspend fun sendDraftSync() { val accountViewModel = accountViewModel ?: return diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt index c7f882447f..9466877f0f 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/discover/nip99Classifieds/NewProductScreen.kt @@ -49,7 +49,6 @@ import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment.Companion.CenterVertically @@ -57,6 +56,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.Note @@ -99,7 +99,6 @@ import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.toImmutableList import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -153,7 +152,6 @@ fun NewProductScreen( ) { WatchAndLoadMyEmojiList(accountViewModel) - val scope = rememberCoroutineScope() var showRelaysDialog by remember { mutableStateOf(false) } Scaffold( @@ -182,10 +180,10 @@ fun NewProductScreen( } PostButton( onPost = { - postViewModel.sendPost() - scope.launch { - delay(100) + accountViewModel.viewModelScope.launch(Dispatchers.IO) { + postViewModel.sendPostSync() nav.popBack() + postViewModel.cancel() } }, isActive = postViewModel.canPost(), @@ -197,13 +195,11 @@ fun NewProductScreen( Spacer(modifier = StdHorzSpacer) CloseButton( onPress = { - scope.launch { - withContext(Dispatchers.IO) { - postViewModel.sendDraftSync() - postViewModel.cancel() - } + accountViewModel.viewModelScope.launch(Dispatchers.IO) { + postViewModel.sendDraftSync() + nav.popBack() + postViewModel.cancel() } - nav.popBack() }, ) } 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 9358763956..d9fce20a7e 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 @@ -106,7 +106,10 @@ open class NewProductViewModel : init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { - sendDraft() + // don't save the first + if (it > 0) { + sendDraftSync() + } } } } @@ -285,12 +288,6 @@ open class NewProductViewModel : urlPreviews.update(message) } - fun sendPost() { - viewModelScope.launch(Dispatchers.IO) { - sendPostSync() - } - } - suspend fun sendPostSync() { val template = createTemplate() ?: return @@ -304,12 +301,6 @@ open class NewProductViewModel : cancel() } - fun sendDraft() { - viewModelScope.launch(Dispatchers.IO) { - sendDraftSync() - } - } - suspend fun sendDraftSync() { val accountViewModel = accountViewModel ?: return 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 272dcdbccc..00f4996d58 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 @@ -139,7 +139,10 @@ open class ShortNotePostViewModel : init { viewModelScope.launch(Dispatchers.IO) { draftTag.versions.collectLatest { - sendDraftSync() + // don't save the first + if (it > 0) { + sendDraftSync() + } } } }