diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewRepository.kt index 2607fe27c..1dbf25c06 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewRepository.kt @@ -1,15 +1,20 @@ package org.thoughtcrime.securesms.mediapreview +import android.content.Context +import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log import org.signal.core.util.requireLong import org.thoughtcrime.securesms.attachments.AttachmentId +import org.thoughtcrime.securesms.attachments.DatabaseAttachment import org.thoughtcrime.securesms.database.AttachmentDatabase import org.thoughtcrime.securesms.database.MediaDatabase import org.thoughtcrime.securesms.database.MediaDatabase.Sorting import org.thoughtcrime.securesms.database.SignalDatabase.Companion.media +import org.thoughtcrime.securesms.sms.MessageSender +import org.thoughtcrime.securesms.util.AttachmentUtil /** * Repository for accessing the attachments in the encrypted database. @@ -64,5 +69,17 @@ class MediaPreviewRepository { }.subscribeOn(Schedulers.io()).toFlowable() } + fun localDelete(context: Context, attachment: DatabaseAttachment): Completable { + return Completable.fromRunnable { + AttachmentUtil.deleteAttachment(context.applicationContext, attachment) + }.subscribeOn(Schedulers.io()) + } + + fun remoteDelete(attachment: DatabaseAttachment): Completable { + return Completable.fromRunnable { + MessageSender.sendRemoteDelete(attachment.mmsId, true) + }.subscribeOn(Schedulers.io()) + } + data class Result(val initialPosition: Int, val records: List) } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt index d5cf54e73..cd3e3bcaf 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt @@ -34,6 +34,7 @@ import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.snackbar.Snackbar import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.kotlin.subscribeBy import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.logging.Log import org.thoughtcrime.securesms.R @@ -42,6 +43,7 @@ import org.thoughtcrime.securesms.components.ViewBinderDelegate import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs import org.thoughtcrime.securesms.database.MediaDatabase +import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.databinding.FragmentMediaPreviewV2Binding import org.thoughtcrime.securesms.mediapreview.mediarail.CenterDecoration import org.thoughtcrime.securesms.mediapreview.mediarail.MediaRailAdapter @@ -57,6 +59,7 @@ import org.thoughtcrime.securesms.util.Debouncer import org.thoughtcrime.securesms.util.FullscreenHelper import org.thoughtcrime.securesms.util.LifecycleDisposable import org.thoughtcrime.securesms.util.MediaUtil +import org.thoughtcrime.securesms.util.RemoteDeleteUtil import org.thoughtcrime.securesms.util.SaveAttachmentTask import org.thoughtcrime.securesms.util.StorageUtil import org.thoughtcrime.securesms.util.ViewUtil @@ -472,21 +475,50 @@ class MediaPreviewV2Fragment : Fragment(R.layout.fragment_media_preview_v2), Med private fun deleteMedia(mediaItem: MediaDatabase.MediaRecord) { val attachment: DatabaseAttachment = mediaItem.attachment ?: return - MaterialAlertDialogBuilder(requireContext()) - .setIcon(R.drawable.ic_warning) - .setTitle(R.string.MediaPreviewActivity_media_delete_confirmation_title) - .setMessage(R.string.MediaPreviewActivity_media_delete_confirmation_message) - .setCancelable(true) - .setPositiveButton(R.string.delete) { _, _ -> - viewModel.deleteItem(requireContext(), attachment, onSuccess = { - requireActivity().finish() - }, onError = { - Log.e(TAG, "Delete failed!", it) - requireActivity().finish() - }) + MaterialAlertDialogBuilder(requireContext()).apply { + setIcon(R.drawable.ic_warning) + setTitle(R.string.MediaPreviewActivity_media_delete_confirmation_title) + setMessage(R.string.MediaPreviewActivity_media_delete_confirmation_message) + setCancelable(true) + setNegativeButton(android.R.string.cancel, null) + setPositiveButton(R.string.ConversationFragment_delete_for_me) { _, _ -> + lifecycleDisposable += viewModel.localDelete(requireContext(), attachment) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy( + onComplete = { + requireActivity().finish() + }, + onError = { + Log.e(TAG, "Delete failed!", it) + Toast.makeText(requireContext(), R.string.MediaPreviewFragment_media_delete_error, Toast.LENGTH_LONG).show() + requireActivity().finish() + } + ) } - .setNegativeButton(android.R.string.cancel, null) - .show() + + if (canRemotelyDelete(attachment)) { + setNeutralButton(R.string.ConversationFragment_delete_for_everyone) { _, _ -> + lifecycleDisposable += viewModel.remoteDelete(attachment) + .observeOn(AndroidSchedulers.mainThread()) + .subscribeBy( + onComplete = { + requireActivity().finish() + }, + onError = { + Log.e(TAG, "Delete failed!", it) + Toast.makeText(requireContext(), R.string.MediaPreviewFragment_media_delete_error, Toast.LENGTH_LONG).show() + requireActivity().finish() + } + ) + } + } + }.show() + } + + fun canRemotelyDelete(attachment: DatabaseAttachment): Boolean { + val mmsId = attachment.mmsId + val attachmentCount = SignalDatabase.attachments.getAttachmentsForMessage(mmsId).size + return attachmentCount <= 1 && RemoteDeleteUtil.isValidSend(listOf(SignalDatabase.mms.getMessageRecord(mmsId)), System.currentTimeMillis()) } private fun editMediaItem(currentItem: MediaDatabase.MediaRecord) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2ViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2ViewModel.kt index 20c8aa495..8cfd61fef 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2ViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2ViewModel.kt @@ -3,10 +3,9 @@ package org.thoughtcrime.securesms.mediapreview import android.content.Context import androidx.lifecycle.ViewModel import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Flowable -import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable -import io.reactivex.rxjava3.functions.Consumer import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.schedulers.Schedulers import org.signal.core.util.logging.Log @@ -14,7 +13,6 @@ import org.thoughtcrime.securesms.attachments.AttachmentId import org.thoughtcrime.securesms.attachments.DatabaseAttachment import org.thoughtcrime.securesms.database.MediaDatabase import org.thoughtcrime.securesms.mediasend.Media -import org.thoughtcrime.securesms.util.AttachmentUtil import org.thoughtcrime.securesms.util.rx.RxStore import java.util.Optional @@ -76,11 +74,12 @@ class MediaPreviewV2ViewModel : ViewModel() { } } - fun deleteItem(context: Context, attachment: DatabaseAttachment, onSuccess: Consumer, onError: Consumer) { - disposables += Single.fromCallable { AttachmentUtil.deleteAttachment(context.applicationContext, attachment) } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(onSuccess, onError) + fun remoteDelete(attachment: DatabaseAttachment): Completable { + return repository.remoteDelete(attachment).subscribeOn(Schedulers.io()) + } + + fun localDelete(context: Context, attachment: DatabaseAttachment): Completable { + return repository.localDelete(context, attachment).subscribeOn(Schedulers.io()) } override fun onCleared() { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f50fde489..ed6a59d8c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2079,6 +2079,8 @@ Can\'t find an app able to share this media. Close Media Error + + Error Deleting Message, Message May Still Exist %1$d new messages in %2$d conversations