diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java index f3a7f9f3a8..7a14582a5e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationFragment.java @@ -1085,6 +1085,10 @@ public class ConversationFragment extends LoggingFragment implements Multiselect return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + + for (MessageRecord messageRecord : messageRecords) { + listener.onDeleteMessage(messageRecord.getId()); + } }); int deleteForEveryoneResId = isNoteToSelfDelete ? R.string.ConversationFragment_delete_everywhere : R.string.ConversationFragment_delete_for_everyone; @@ -1110,6 +1114,9 @@ public class ConversationFragment extends LoggingFragment implements Multiselect private void handleDeleteForEveryone(Set messageRecords) { Runnable deleteForEveryone = () -> { + for (MessageRecord messageRecord : messageRecords) { + listener.onRemoteDeleteMessage(messageRecord.getId()); + } SignalExecutors.BOUNDED.execute(() -> { for (MessageRecord message : messageRecords) { MessageSender.sendRemoteDelete(message.getId()); @@ -1477,6 +1484,8 @@ public class ConversationFragment extends LoggingFragment implements Multiselect void onRegisterVoiceNoteCallbacks(@NonNull Observer onPlaybackStartObserver); void onUnregisterVoiceNoteCallbacks(@NonNull Observer onPlaybackStartObserver); void onInviteToSignal(); + void onDeleteMessage(long id); + void onRemoteDeleteMessage(long targetId); boolean isInBubble(); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java index bad1e9d39c..4c6d892036 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationParentFragment.java @@ -4054,6 +4054,22 @@ public class ConversationParentFragment extends Fragment handleInviteLink(); } + @Override + public void onDeleteMessage(long id) { + MessageId messageId = inputPanel.getEditMessageId(); + if (messageId != null && messageId.getId() == id) { + inputPanel.exitEditMessageMode(); + } + } + + @Override + public void onRemoteDeleteMessage(long targetId) { + MessageId messageId = inputPanel.getEditMessageId(); + if (messageId != null && messageId.getId() == targetId) { + inputPanel.exitEditMessageMode(); + } + } + @Override public void onCursorChanged() { if (!reactionDelegate.isShowing()) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt index 0072726f97..d02068d4a7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationFragment.kt @@ -2119,10 +2119,17 @@ class ConversationFragment : } private fun handleDeleteMessages(messageParts: Set) { + val records = messageParts.map(MultiselectPart::getMessageRecord).toSet() disposables += DeleteDialog.show( context = requireContext(), - messageRecords = messageParts.map(MultiselectPart::getMessageRecord).toSet() - ).subscribe() + messageRecords = records + ).subscribe { (deleted: Boolean, _: Boolean) -> + if (!deleted) return@subscribe + val editMessageId = inputPanel.editMessageId?.id + if (editMessageId != null && records.any { it.id == editMessageId }) { + inputPanel.exitEditMessageMode() + } + } } private inner class SwipeAvailabilityProvider : ConversationItemSwipeCallback.SwipeAvailabilityProvider { diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt index 29d166f317..9176875403 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/dialogs/StoryContextMenu.kt @@ -45,7 +45,7 @@ object StoryContextMenu { title = context.getString(R.string.MyStories__delete_story), message = context.getString(R.string.MyStories__this_story_will_be_deleted), forceRemoteDelete = true - ) + ).map { (_, deletedThread) -> deletedThread } } fun save(context: Context, messageRecord: MessageRecord) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt index bfa8a208b0..dd1401044a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/viewer/reply/group/StoryGroupReplyFragment.kt @@ -312,7 +312,7 @@ class StoryGroupReplyFragment : } private fun onDeleteClick(messageRecord: MessageRecord) { - lifecycleDisposable += DeleteDialog.show(requireActivity(), setOf(messageRecord)).subscribe { didDeleteThread -> + lifecycleDisposable += DeleteDialog.show(requireActivity(), setOf(messageRecord)).subscribe { (_, didDeleteThread) -> if (didDeleteThread) { throw AssertionError("We should never end up deleting a Group Thread like this.") } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/DeleteDialog.kt b/app/src/main/java/org/thoughtcrime/securesms/util/DeleteDialog.kt index 83d353ded8..44d0731438 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/DeleteDialog.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/DeleteDialog.kt @@ -23,7 +23,8 @@ object DeleteDialog { * @param message The dialog message, or null * @param forceRemoteDelete Allow remote deletion, even if it would normally be disallowed * - * @return a Single, who's value notes whether or not a thread deletion occurred. + * @return a Single, who's value is a pair that notes whether or not a deletion attempt + * happened at all, as well as if a thread deletion occurred. */ fun show( context: Context, @@ -31,7 +32,7 @@ object DeleteDialog { title: CharSequence = context.resources.getQuantityString(R.plurals.ConversationFragment_delete_selected_messages, messageRecords.size, messageRecords.size), message: CharSequence? = null, forceRemoteDelete: Boolean = false - ): Single = Single.create { emitter -> + ): Single> = Single.create { emitter -> val builder = MaterialAlertDialogBuilder(context) builder.setTitle(title) @@ -44,7 +45,9 @@ object DeleteDialog { builder.setPositiveButton(R.string.ConversationFragment_delete_for_everyone) { _, _ -> deleteForEveryone(messageRecords, emitter) } } else { builder.setPositiveButton(if (isNoteToSelfDelete) R.string.ConversationFragment_delete_on_this_device else R.string.ConversationFragment_delete_for_me) { _, _ -> - DeleteProgressDialogAsyncTask(context, messageRecords, emitter::onSuccess).executeOnExecutor(SignalExecutors.BOUNDED) + DeleteProgressDialogAsyncTask(context, messageRecords) { + emitter.onSuccess(Pair(true, it)) + }.executeOnExecutor(SignalExecutors.BOUNDED) } if (MessageConstraintsUtil.isValidRemoteDeleteSend(messageRecords, System.currentTimeMillis()) && (!isNoteToSelfDelete || TextSecurePreferences.isMultiDevice(context))) { @@ -52,8 +55,8 @@ object DeleteDialog { } } - builder.setNegativeButton(android.R.string.cancel) { _, _ -> emitter.onSuccess(false) } - builder.setOnCancelListener { emitter.onSuccess(false) } + builder.setNegativeButton(android.R.string.cancel) { _, _ -> emitter.onSuccess(Pair(false, false)) } + builder.setOnCancelListener { emitter.onSuccess(Pair(false, false)) } builder.show() } @@ -61,8 +64,8 @@ object DeleteDialog { return messageRecords.all { messageRecord: MessageRecord -> messageRecord.isOutgoing && messageRecord.toRecipient.isSelf } } - private fun handleDeleteForEveryone(context: Context, messageRecords: Set, emitter: SingleEmitter) { - if (SignalStore.uiHints().hasConfirmedDeleteForEveryoneOnce() || isNoteToSelfDelete(messageRecords)) { + private fun handleDeleteForEveryone(context: Context, messageRecords: Set, emitter: SingleEmitter>) { + if (SignalStore.uiHints().hasConfirmedDeleteForEveryoneOnce()) { deleteForEveryone(messageRecords, emitter) } else { MaterialAlertDialogBuilder(context) @@ -71,19 +74,19 @@ object DeleteDialog { SignalStore.uiHints().markHasConfirmedDeleteForEveryoneOnce() deleteForEveryone(messageRecords, emitter) } - .setNegativeButton(android.R.string.cancel) { _, _ -> emitter.onSuccess(false) } - .setOnCancelListener { emitter.onSuccess(false) } + .setNegativeButton(android.R.string.cancel) { _, _ -> emitter.onSuccess(Pair(false, false)) } + .setOnCancelListener { emitter.onSuccess(Pair(false, false)) } .show() } } - private fun deleteForEveryone(messageRecords: Set, emitter: SingleEmitter) { + private fun deleteForEveryone(messageRecords: Set, emitter: SingleEmitter>) { SignalExecutors.BOUNDED.execute { messageRecords.forEach { message -> MessageSender.sendRemoteDelete(message.id) } - emitter.onSuccess(false) + emitter.onSuccess(Pair(true, false)) } }