Skip to content

Commit a470490

Browse files
committed
Fix: Save all option overrides attachment files
1 parent 2ad0cc4 commit a470490

2 files changed

Lines changed: 69 additions & 5 deletions

File tree

legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/AttachmentController.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import android.content.ActivityNotFoundException
44
import android.content.Context
55
import android.content.Intent
66
import android.net.Uri
7+
import android.provider.DocumentsContract
78
import android.widget.Toast
89
import androidx.annotation.WorkerThread
910
import app.k9mail.legacy.message.controller.SimpleMessagingListener
@@ -66,6 +67,21 @@ class AttachmentController internal constructor(
6667
}
6768
}
6869

70+
fun saveAttachmentToDirectory(scope: CoroutineScope, directoryUri: Uri?) {
71+
if (directoryUri == null) return
72+
scope.launch {
73+
if (!attachment.isContentAvailable) {
74+
val success = downloadAttachment()
75+
if (success) {
76+
attachmentDisplayController.refreshAttachmentThumbnail(attachment)
77+
saveLocalAttachmentToDirectory(directoryUri)
78+
}
79+
} else {
80+
saveLocalAttachmentToDirectory(directoryUri)
81+
}
82+
}
83+
}
84+
6985
private suspend fun saveLocalAttachmentTo(documentUri: Uri) {
7086
val success = withContext(ioDispatcher) {
7187
try {
@@ -79,6 +95,33 @@ class AttachmentController internal constructor(
7995
if (!success) displayAttachmentNotSavedMessage()
8096
}
8197

98+
private suspend fun saveLocalAttachmentToDirectory(directoryUri: Uri) {
99+
val success = withContext(ioDispatcher) {
100+
try {
101+
val contentResolver = context.contentResolver
102+
val treeId = DocumentsContract.getTreeDocumentId(directoryUri)
103+
val rootDocUri = DocumentsContract.buildDocumentUriUsingTree(directoryUri, treeId)
104+
105+
val documentUri = attachment.mimeType?.let {
106+
attachment.displayName?.let { displayName ->
107+
DocumentsContract.createDocument(
108+
contentResolver,
109+
rootDocUri,
110+
it,
111+
displayName
112+
)
113+
}
114+
} ?: return@withContext false
115+
writeAttachment(documentUri)
116+
true
117+
} catch (e: IOException) {
118+
logger.error(throwable = e) { "Error saving attachment to directory" }
119+
false
120+
}
121+
}
122+
if (!success) displayAttachmentNotSavedMessage()
123+
}
124+
82125
private suspend fun downloadAttachment(): Boolean = suspendCancellableCoroutine { continuation ->
83126
attachmentDisplayController.showAttachmentLoadingDialog()
84127
controller.loadAttachment(

legacy/ui/legacy/src/main/java/com/fsck/k9/ui/messageview/MessageViewFragment.kt

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import android.view.ViewGroup
2020
import android.view.inputmethod.InputMethodManager
2121
import android.widget.Toast
2222
import androidx.activity.result.ActivityResultLauncher
23+
import androidx.activity.result.contract.ActivityResultContracts
2324
import androidx.compose.runtime.collectAsState
2425
import androidx.compose.runtime.getValue
2526
import androidx.compose.ui.platform.ComposeView
@@ -119,6 +120,10 @@ class MessageViewFragment :
119120
registerForActivityResult(CreateDocumentResultContract()) { documentUri ->
120121
onCreateDocumentResult(documentUri)
121122
}
123+
private val openDocumentTreeLauncher: ActivityResultLauncher<Uri?> =
124+
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { directoryUri ->
125+
onOpenDocumentTreeResult(directoryUri)
126+
}
122127
private val chooseFolderForCopyLauncher: ActivityResultLauncher<ChooseFolderResultContract.Input> =
123128
registerForActivityResult(ChooseFolderResultContract(ChooseFolderActivity.Action.COPY)) { result ->
124129
onChooseFolderCopyResult(result)
@@ -245,11 +250,7 @@ class MessageViewFragment :
245250
onSaveClick = { attachment ->
246251
onSaveAttachment(attachment)
247252
},
248-
onSaveAllClick = {
249-
attachments.forEach { item ->
250-
onSaveAttachment(item.attachment)
251-
}
252-
},
253+
onSaveAllClick = { onSaveAllAttachments() },
253254
)
254255
}
255256
}
@@ -828,6 +829,18 @@ class MessageViewFragment :
828829
}
829830
}
830831

832+
private fun onOpenDocumentTreeResult(directoryUri: Uri?) {
833+
if (directoryUri == null) return
834+
835+
val messageView = mMessageViewInfo ?: return
836+
val attachments = messageView.attachments.filter { !it.inlineAttachment }
837+
attachments.forEach {
838+
currentAttachmentViewInfo = it
839+
createAttachmentController(it)
840+
.saveAttachmentToDirectory(lifecycleScope ,directoryUri)
841+
}
842+
}
843+
831844
private fun onChooseFolderMoveResult(result: ChooseFolderResultContract.Result?) {
832845
if (result == null) return
833846

@@ -1190,6 +1203,14 @@ class MessageViewFragment :
11901203
createAttachmentController(attachment).viewAttachment(lifecycleScope)
11911204
}
11921205

1206+
fun onSaveAllAttachments() {
1207+
try {
1208+
openDocumentTreeLauncher.launch(null)
1209+
} catch (_: ActivityNotFoundException) {
1210+
Toast.makeText(requireContext(), R.string.error_activity_not_found, Toast.LENGTH_LONG).show()
1211+
}
1212+
}
1213+
11931214
override fun onSaveAttachment(attachment: AttachmentViewInfo) {
11941215
currentAttachmentViewInfo = attachment
11951216

0 commit comments

Comments
 (0)