Skip to content

Commit d9c1761

Browse files
authored
Merge pull request #1992 from Infomaniak/remove-unused-cids
Remove associated inline attachements when removing quote
2 parents 1f42cd8 + caa05b0 commit d9c1761

File tree

3 files changed

+84
-32
lines changed

3 files changed

+84
-32
lines changed

app/src/main/java/com/infomaniak/mail/data/cache/mailboxContent/ReplyForwardFooterManager.kt

+7-32
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ import com.infomaniak.mail.R
2222
import com.infomaniak.mail.data.models.Attachment
2323
import com.infomaniak.mail.data.models.correspondent.Recipient
2424
import com.infomaniak.mail.data.models.message.Message
25-
import com.infomaniak.mail.ui.main.thread.MessageWebViewClient
25+
import com.infomaniak.mail.utils.HtmlUtils.CID_PROTOCOL
26+
import com.infomaniak.mail.utils.HtmlUtils.SRC_ATTRIBUTE
27+
import com.infomaniak.mail.utils.HtmlUtils.processCids
2628
import com.infomaniak.mail.utils.JsoupParserUtil.jsoupParseBodyFragmentWithLog
2729
import com.infomaniak.mail.utils.JsoupParserUtil.jsoupParseWithLog
2830
import com.infomaniak.mail.utils.MailDateFormatUtils.formatForHeader
@@ -42,12 +44,12 @@ class ReplyForwardFooterManager @Inject constructor(private val appContext: Cont
4244
fun createForwardFooter(message: Message, attachmentsToForward: List<Attachment>): String {
4345
val previousBody = getHtmlDocument(message)?.let { document ->
4446
document.processCids(
45-
message = message,
47+
attachments = message.attachments,
4648
associateDataToCid = { oldAttachment ->
4749
val newAttachment = attachmentsToForward.find { it.originalContentId == oldAttachment.contentId }
4850
newAttachment?.contentId
4951
},
50-
applyAssociatedDataToImage = { newContentId, imageElement ->
52+
onCidImageFound = { newContentId, imageElement ->
5153
imageElement.attr(SRC_ATTRIBUTE, "${CID_PROTOCOL}$newContentId")
5254
},
5355
)
@@ -66,9 +68,9 @@ class ReplyForwardFooterManager @Inject constructor(private val appContext: Cont
6668

6769
val previousBody = getHtmlDocument(message)?.let { document ->
6870
document.processCids(
69-
message = message,
71+
attachments = message.attachments,
7072
associateDataToCid = Attachment::name,
71-
applyAssociatedDataToImage = { name, imageElement ->
73+
onCidImageFound = { name, imageElement ->
7274
imageElement.replaceWith(TextNode("<$name>"))
7375
},
7476
)
@@ -80,22 +82,6 @@ class ReplyForwardFooterManager @Inject constructor(private val appContext: Cont
8082
return assembleReplyHtmlFooter(messageReplyHeader, previousFullBody)
8183
}
8284

83-
private fun Document.processCids(
84-
message: Message,
85-
associateDataToCid: (Attachment) -> String?,
86-
applyAssociatedDataToImage: (String, Element) -> Unit
87-
) {
88-
val attachmentsMap = message.attachments.associate {
89-
it.contentId to associateDataToCid(it)
90-
}
91-
92-
doOnHtmlImage { imageElement ->
93-
attachmentsMap[getCid(imageElement)]?.let { associatedData ->
94-
applyAssociatedDataToImage(associatedData, imageElement)
95-
}
96-
}
97-
}
98-
9985
private fun Message.fromName(): String = sender?.quotedDisplayName() ?: appContext.getString(R.string.unknownRecipientTitle)
10086

10187
private fun getHtmlDocument(message: Message): Document? {
@@ -109,11 +95,6 @@ class ReplyForwardFooterManager @Inject constructor(private val appContext: Cont
10995
return html?.let(::jsoupParseWithLog)
11096
}
11197

112-
private fun Document.doOnHtmlImage(actionOnImage: (Element) -> Unit) {
113-
select(CID_IMAGE_CSS_QUERY).forEach { imageElement -> actionOnImage(imageElement) }
114-
}
115-
116-
private fun getCid(imageElement: Element) = imageElement.attr(SRC_ATTRIBUTE).removePrefix(CID_PROTOCOL)
11798

11899
private fun computePreviousFullBody(previousBody: String, message: Message): String {
119100
return message.body?.let { body ->
@@ -187,10 +168,4 @@ class ReplyForwardFooterManager @Inject constructor(private val appContext: Cont
187168
private fun formatRecipientList(recipientList: List<Recipient>): String? {
188169
return if (recipientList.isNotEmpty()) recipientList.joinToString { it.quotedDisplayName() } else null
189170
}
190-
191-
companion object {
192-
private const val CID_PROTOCOL = "${MessageWebViewClient.CID_SCHEME}:"
193-
private const val SRC_ATTRIBUTE = "src"
194-
private const val CID_IMAGE_CSS_QUERY = "img[${SRC_ATTRIBUTE}^='${CID_PROTOCOL}']"
195-
}
196171
}

app/src/main/java/com/infomaniak/mail/ui/newMessage/NewMessageFragment.kt

+25
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ import com.infomaniak.mail.ui.main.thread.AttachmentAdapter
6767
import com.infomaniak.mail.ui.newMessage.NewMessageRecipientFieldsManager.FieldType
6868
import com.infomaniak.mail.ui.newMessage.NewMessageViewModel.ImportationResult
6969
import com.infomaniak.mail.ui.newMessage.NewMessageViewModel.UiFrom
70+
import com.infomaniak.mail.utils.HtmlUtils.processCids
71+
import com.infomaniak.mail.utils.JsoupParserUtil.jsoupParseWithLog
7072
import com.infomaniak.mail.utils.SentryDebug
7173
import com.infomaniak.mail.utils.SignatureUtils
7274
import com.infomaniak.mail.utils.UiUtils.PRIMARY_COLOR_CODE
@@ -423,10 +425,33 @@ class NewMessageFragment : Fragment() {
423425
}
424426
removeQuote.setOnClickListener {
425427
trackNewMessageEvent("deleteQuote")
428+
removeInlineAttachmentsUsedInQuote()
426429
newMessageViewModel.uiQuoteLiveData.value = null
427430
}
428431
}
429432

433+
private fun removeInlineAttachmentsUsedInQuote() {
434+
newMessageViewModel.uiQuoteLiveData.value?.let { html ->
435+
newMessageViewModel.attachmentsLiveData.value?.let { attachments ->
436+
newMessageViewModel.attachmentsLiveData.value = attachments.filterOutHtmlCids(html)
437+
}
438+
}
439+
}
440+
441+
private fun List<Attachment>.filterOutHtmlCids(html: String): List<Attachment> {
442+
return buildList {
443+
addAll(this@filterOutHtmlCids)
444+
445+
jsoupParseWithLog(html).processCids(
446+
attachments = this@filterOutHtmlCids,
447+
associateDataToCid = { it },
448+
onCidImageFound = { attachment, _ ->
449+
remove(attachment)
450+
}
451+
)
452+
}
453+
}
454+
430455
private fun WebView.loadSignatureContent(html: String, webViewGroup: Group) {
431456
val processedHtml = webViewUtils.processSignatureHtmlForDisplay(html, context.isNightModeEnabled())
432457
loadProcessedContent(processedHtml, webViewGroup)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Infomaniak Mail - Android
3+
* Copyright (C) 2024 Infomaniak Network SA
4+
*
5+
* This program is free software: you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation, either version 3 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package com.infomaniak.mail.utils
19+
20+
import com.infomaniak.mail.data.models.Attachment
21+
import com.infomaniak.mail.ui.main.thread.MessageWebViewClient
22+
import org.jsoup.nodes.Document
23+
import org.jsoup.nodes.Element
24+
25+
object HtmlUtils {
26+
27+
const val CID_PROTOCOL = "${MessageWebViewClient.CID_SCHEME}:"
28+
const val SRC_ATTRIBUTE = "src"
29+
private const val CID_IMAGE_CSS_QUERY = "img[$SRC_ATTRIBUTE^='$CID_PROTOCOL']"
30+
31+
fun <T> Document.processCids(
32+
attachments: List<Attachment>,
33+
associateDataToCid: (Attachment) -> T?,
34+
onCidImageFound: (T, Element) -> Unit,
35+
) {
36+
val attachmentsMap = attachments.associate {
37+
it.contentId to associateDataToCid(it)
38+
}
39+
40+
doOnHtmlImage { imageElement ->
41+
attachmentsMap[getCid(imageElement)]?.let { associatedData ->
42+
onCidImageFound(associatedData, imageElement)
43+
}
44+
}
45+
}
46+
47+
private fun Document.doOnHtmlImage(actionOnImage: (Element) -> Unit) {
48+
select(CID_IMAGE_CSS_QUERY).forEach { imageElement -> actionOnImage(imageElement) }
49+
}
50+
51+
private fun getCid(imageElement: Element) = imageElement.attr(SRC_ATTRIBUTE).removePrefix(CID_PROTOCOL)
52+
}

0 commit comments

Comments
 (0)