mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 18:30:20 +01:00
Consolidate attachment saving logic into unified AttachmentSaver class.
Introduces `AttachmentSaver` to centralize all of the steps needed to save message attachments to the device storage. It handles the entire workflow including: - Showing the save to storage warning/confirmation dialog. - Requesting `WRITE_EXTERNAL_STORAGE` permission. - Showing/dismissing media save progress. Goals of this new class: - Make it easy to save media attachments anywhere with just a few lines of code (and easier to replace the deprecated `SaveAttachmentTask`). - Ensure all of the necessary steps are consistently performed at each usage site (which wasn't the case before). - Make it easier to unit test the save attachment logic.
This commit is contained in:
committed by
Cody Henthorne
parent
86afafac31
commit
b9dc5cbe4f
@@ -89,7 +89,6 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.rx3.rxSingle
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
@@ -111,6 +110,7 @@ import org.thoughtcrime.securesms.LoggingFragment
|
||||
import org.thoughtcrime.securesms.MainActivity
|
||||
import org.thoughtcrime.securesms.MuteDialog
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.attachments.AttachmentSaver
|
||||
import org.thoughtcrime.securesms.audio.AudioRecorder
|
||||
import org.thoughtcrime.securesms.badges.gifts.OpenableGift
|
||||
import org.thoughtcrime.securesms.badges.gifts.OpenableGiftItemDecoration
|
||||
@@ -126,8 +126,6 @@ import org.thoughtcrime.securesms.components.HidingLinearLayout
|
||||
import org.thoughtcrime.securesms.components.InputAwareConstraintLayout
|
||||
import org.thoughtcrime.securesms.components.InputPanel
|
||||
import org.thoughtcrime.securesms.components.InsetAwareConstraintLayout
|
||||
import org.thoughtcrime.securesms.components.ProgressCardDialogFragment
|
||||
import org.thoughtcrime.securesms.components.ProgressCardDialogFragmentArgs
|
||||
import org.thoughtcrime.securesms.components.ScrollToPositionDelegate
|
||||
import org.thoughtcrime.securesms.components.SendButton
|
||||
import org.thoughtcrime.securesms.components.ViewBinderDelegate
|
||||
@@ -322,9 +320,7 @@ import org.thoughtcrime.securesms.util.MessageConstraintsUtil.getEditMessageThre
|
||||
import org.thoughtcrime.securesms.util.MessageConstraintsUtil.isValidEditMessageSend
|
||||
import org.thoughtcrime.securesms.util.PlayStoreUtil
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.SaveAttachmentUtil
|
||||
import org.thoughtcrime.securesms.util.SignalLocalMetrics
|
||||
import org.thoughtcrime.securesms.util.StorageUtil
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.WindowUtil
|
||||
@@ -2421,38 +2417,11 @@ class ConversationFragment :
|
||||
error("Cannot save a view-once message")
|
||||
}
|
||||
|
||||
val attachments = SaveAttachmentUtil.getAttachmentsForRecord(record)
|
||||
|
||||
SaveAttachmentUtil.showWarningDialogIfNecessary(requireContext(), attachments.size) {
|
||||
if (StorageUtil.canWriteToMediaStore()) {
|
||||
performAttachmentSave(attachments)
|
||||
} else {
|
||||
Permissions.with(this)
|
||||
.request(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
||||
.ifNecessary()
|
||||
.withPermanentDenialDialog(getString(R.string.MediaPreviewActivity_signal_needs_the_storage_permission_in_order_to_write_to_external_storage_but_it_has_been_permanently_denied))
|
||||
.onAnyDenied { toast(R.string.MediaPreviewActivity_unable_to_write_to_external_storage_without_permission, toastDuration = Toast.LENGTH_LONG) }
|
||||
.onAllGranted { performAttachmentSave(attachments) }
|
||||
.execute()
|
||||
}
|
||||
lifecycleScope.launch {
|
||||
AttachmentSaver(this@ConversationFragment).saveAttachments(record)
|
||||
}
|
||||
}
|
||||
|
||||
private fun performAttachmentSave(attachments: Set<SaveAttachmentUtil.SaveAttachment>) {
|
||||
val progressDialog = ProgressCardDialogFragment.create()
|
||||
progressDialog.arguments = ProgressCardDialogFragmentArgs.Builder(
|
||||
resources.getQuantityString(R.plurals.ConversationFragment_saving_n_attachments_to_sd_card, attachments.size, attachments.size)
|
||||
).build().toBundle()
|
||||
|
||||
rxSingle { SaveAttachmentUtil.saveAttachments(attachments) }
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.doOnSubscribe { progressDialog.show(parentFragmentManager, null) }
|
||||
.doOnTerminate { progressDialog.dismissAllowingStateLoss() }
|
||||
.subscribeBy { result -> Toast.makeText(context, result.getMessage(requireContext()), Toast.LENGTH_LONG).show() }
|
||||
.addTo(disposables)
|
||||
}
|
||||
|
||||
private fun handleCopyMessage(messageParts: Set<MultiselectPart>) {
|
||||
viewModel.copyToClipboard(requireContext(), messageParts).subscribe().addTo(disposables)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user