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 ff7d7717eb..00ee756dae 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 @@ -2381,7 +2381,7 @@ class ConversationFragment : val attachments = SaveAttachmentUtil.getAttachmentsForRecord(record) - SaveAttachmentUtil.showWarningDialog(requireContext(), attachments.size) { _, _ -> + SaveAttachmentUtil.showWarningDialogIfNecessary(requireContext()) { if (StorageUtil.canWriteToMediaStore()) { performAttachmentSave(attachments) } else { diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java index 5bb3ab8b71..40c2b6e2a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java +++ b/app/src/main/java/org/thoughtcrime/securesms/keyvalue/UiHintValues.java @@ -29,8 +29,9 @@ public class UiHintValues extends SignalStoreValues { private static final String LAST_SUPPORT_VERSION_SEEN = "uihints.last_support_version_seen"; private static final String HAS_EVER_ENABLED_REMOTE_BACKUPS = "uihints.has_ever_enabled_remote_backups"; private static final String HAS_SEEN_CHAT_FOLDERS_EDUCATION_SHEET = "uihints.has_seen_chat_folders_education_sheet"; - private static final String HAS_SEEN_LINK_DEVICE_QR_EDUCATION_SHEET = "uihints.has_seen_link_device_qr_education_sheet"; - private static final String HAS_SEEN_LINK_DEVICE_AUTH_SHEET = "uihints.has_seen_link_device_auth_sheet"; + private static final String HAS_SEEN_LINK_DEVICE_QR_EDUCATION_SHEET = "uihints.has_seen_link_device_qr_education_sheet"; + private static final String HAS_SEEN_LINK_DEVICE_AUTH_SHEET = "uihints.has_seen_link_device_auth_sheet"; + private static final String HAS_DISMISSED_SAVE_STORAGE_WARNING = "uihints.has_dismissed_save_storage_warning"; UiHintValues(@NonNull KeyValueStore store) { super(store); @@ -236,4 +237,12 @@ public class UiHintValues extends SignalStoreValues { public boolean hasSeenLinkDeviceAuthSheet() { return getBoolean(HAS_SEEN_LINK_DEVICE_AUTH_SHEET, false); } + + public boolean hasDismissedSaveStorageWarning() { + return getBoolean(HAS_DISMISSED_SAVE_STORAGE_WARNING, false); + } + + public void markDismissedSaveStorageWarning() { + putBoolean(HAS_DISMISSED_SAVE_STORAGE_WARNING, true); + } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaActions.java b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaActions.java index 239d858917..b0fc247415 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaActions.java +++ b/app/src/main/java/org/thoughtcrime/securesms/mediaoverview/MediaActions.java @@ -16,11 +16,9 @@ import org.thoughtcrime.securesms.database.MediaTable; import org.thoughtcrime.securesms.database.model.MessageRecord; import org.thoughtcrime.securesms.jobs.MultiDeviceDeleteSyncJob; import org.thoughtcrime.securesms.permissions.Permissions; -import org.thoughtcrime.securesms.recipients.Recipient; import org.thoughtcrime.securesms.util.AttachmentUtil; import org.thoughtcrime.securesms.util.SaveAttachmentTask; import org.thoughtcrime.securesms.util.StorageUtil; -import org.thoughtcrime.securesms.util.TextSecurePreferences; import org.thoughtcrime.securesms.util.Util; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; @@ -46,13 +44,13 @@ final class MediaActions { return; } - SaveAttachmentTask.showWarningDialog(context, (dialogInterface, which) -> Permissions.with(fragment) + SaveAttachmentTask.showWarningDialogIfNecessary(context, () -> Permissions.with(fragment) .request(Manifest.permission.WRITE_EXTERNAL_STORAGE) .ifNecessary() .withPermanentDenialDialog(fragment.getString(R.string.MediaPreviewActivity_signal_needs_the_storage_permission_in_order_to_write_to_external_storage_but_it_has_been_permanently_denied)) .onAnyDenied(() -> Toast.makeText(context, R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, Toast.LENGTH_LONG).show()) .onAllGranted(() -> performSaveToDisk(context, mediaRecords, postExecute)) - .execute(), mediaRecords.size()); + .execute()); } static void handleDeleteMedia(@NonNull Context context, 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 81c668b36c..b483e533d5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediapreview/MediaPreviewV2Fragment.kt @@ -4,7 +4,6 @@ import android.Manifest import android.annotation.SuppressLint import android.content.ActivityNotFoundException import android.content.Context -import android.content.DialogInterface import android.content.Intent import android.graphics.PorterDuff import android.graphics.PorterDuffColorFilter @@ -558,10 +557,10 @@ class MediaPreviewV2Fragment : LoggingFragment(R.layout.fragment_media_preview_v } private fun saveToDisk(mediaItem: MediaTable.MediaRecord) { - SaveAttachmentTask.showWarningDialog(requireContext()) { _: DialogInterface?, _: Int -> + SaveAttachmentTask.showWarningDialogIfNecessary(requireContext()) { if (StorageUtil.canWriteToMediaStore()) { performSaveToDisk(mediaItem) - return@showWarningDialog + return@showWarningDialogIfNecessary } Permissions.with(this) .request(Manifest.permission.WRITE_EXTERNAL_STORAGE) diff --git a/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java b/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java index cf28eabd73..48f244f5f2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java +++ b/app/src/main/java/org/thoughtcrime/securesms/scribbles/ImageEditorFragment.java @@ -653,7 +653,7 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu @Override public void onSave() { - SaveAttachmentTask.showWarningDialog(requireContext(), (dialogInterface, i) -> { + SaveAttachmentTask.showWarningDialogIfNecessary(requireContext(), () -> { if (StorageUtil.canWriteToMediaStore()) { performSaveToDisk(); return; diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.java b/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.java index d02e6574bc..92bc60efd7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.java +++ b/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentTask.java @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.util; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; -import android.content.DialogInterface.OnClickListener; import android.database.Cursor; import android.media.MediaScannerConnection; import android.net.Uri; @@ -11,6 +10,7 @@ import android.os.Build; import android.os.Environment; import android.provider.MediaStore; import android.webkit.MimeTypeMap; +import android.widget.CheckBox; import android.widget.Toast; import androidx.annotation.NonNull; @@ -24,6 +24,7 @@ import org.signal.core.util.StreamUtil; import org.signal.core.util.logging.Log; import org.signal.libsignal.protocol.util.Pair; import org.thoughtcrime.securesms.R; +import org.thoughtcrime.securesms.keyvalue.SignalStore; import org.thoughtcrime.securesms.mms.PartAuthority; import org.thoughtcrime.securesms.util.task.ProgressDialogAsyncTask; @@ -434,20 +435,25 @@ public class SaveAttachmentTask extends ProgressDialogAsyncTask { + CheckBox checkbox = ((AlertDialog) dialog).findViewById(R.id.checkbox); + if (checkbox.isChecked()) { + SignalStore.uiHints().markDismissedSaveStorageWarning(); + } + onSave.run(); + })) + .setNegativeButton(android.R.string.cancel, null) + .show(); + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentUtil.kt b/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentUtil.kt index 6e5b26c354..507a5ec1bb 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentUtil.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/SaveAttachmentUtil.kt @@ -9,7 +9,6 @@ import android.annotation.SuppressLint import android.content.ContentResolver import android.content.ContentValues import android.content.Context -import android.content.DialogInterface.OnClickListener import android.database.Cursor import android.media.MediaScannerConnection import android.net.Uri @@ -17,8 +16,10 @@ import android.os.Build import android.os.Environment import android.provider.MediaStore import android.webkit.MimeTypeMap +import android.widget.CheckBox import android.widget.Toast import androidx.annotation.WorkerThread +import androidx.appcompat.app.AlertDialog import androidx.core.content.contentValuesOf import com.google.android.material.dialog.MaterialAlertDialogBuilder import io.reactivex.rxjava3.core.Single @@ -28,6 +29,7 @@ import org.signal.core.util.orNull import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.database.model.MmsMessageRecord import org.thoughtcrime.securesms.dependencies.AppDependencies +import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.mms.PartAuthority import java.io.File import java.io.FileOutputStream @@ -52,15 +54,25 @@ object SaveAttachmentUtil { private val TAG = Log.tag(SaveAttachmentUtil::class.java) - fun showWarningDialog(context: Context, count: Int, onAcceptListener: OnClickListener) { - MaterialAlertDialogBuilder(context) - .setTitle(R.string.ConversationFragment_save_to_sd_card) - .setIcon(R.drawable.symbol_error_triangle_fill_24) - .setCancelable(true) - .setMessage(context.resources.getQuantityString(R.plurals.ConversationFragment_saving_n_media_to_storage_warning, count, count)) - .setPositiveButton(R.string.yes, onAcceptListener) - .setNegativeButton(R.string.no, null) - .show() + fun showWarningDialogIfNecessary(context: Context, onSave: () -> Unit) { + if (SignalStore.uiHints.hasDismissedSaveStorageWarning()) { + onSave() + } else { + MaterialAlertDialogBuilder(context) + .setView(R.layout.dialog_save_attachment) + .setTitle(R.string.ConversationFragment__save_to_phone) + .setCancelable(true) + .setMessage(R.string.ConversationFragment__this_media_will_be_saved) + .setPositiveButton(R.string.save) { dialog, _ -> + val checkbox = (dialog as AlertDialog).findViewById(R.id.checkbox)!! + if (checkbox.isChecked) { + SignalStore.uiHints.markDismissedSaveStorageWarning() + } + onSave() + } + .setNegativeButton(android.R.string.cancel, null) + .show() + } } fun getAttachmentsForRecord(record: MmsMessageRecord): Set { diff --git a/app/src/main/res/layout/dialog_save_attachment.xml b/app/src/main/res/layout/dialog_save_attachment.xml new file mode 100644 index 0000000000..f1fd1dfa6c --- /dev/null +++ b/app/src/main/res/layout/dialog_save_attachment.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b9ad26f56..f9d8903b4c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -586,6 +586,12 @@ Saving attachment to storage… Saving %1$d attachments to storage… + + Save to phone? + + This media will be saved to your phone\'s storage. Other apps may be able to access it depending on your phone\'s permissions. + + Don\'t show again Pending… Data (Signal)