Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline images mail slow to display #758

Merged
merged 6 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 44 additions & 14 deletions Mail/Views/Thread/MessageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,53 @@ struct MessageView: View {
presentableBody.quote = messageBodyQuote.quote
}

private func insertInlineAttachments() async throws {
let attachmentsArray = message.attachments.filter { $0.disposition == .inline }.toArray()
for attachment in attachmentsArray {
if let contentId = attachment.contentId {
let attachmentData = try await mailboxManager.attachmentData(attachment: attachment)

presentableBody.body?.value = presentableBody.body?.value?.replacingOccurrences(
of: "cid:\(contentId)",
with: "data:\(attachment.mimeType);base64,\(attachmentData.base64EncodedString())"
)
presentableBody.compactBody = presentableBody.compactBody?.replacingOccurrences(
of: "cid:\(contentId)",
with: "data:\(attachment.mimeType);base64,\(attachmentData.base64EncodedString())"
)
private func insertInlineAttachments() {
Task.detached() {
// Since mutation of the DOM is costly, I batch the processing of images, then mutate the DOM.
let attachmentsArray = await message.attachments.filter { $0.disposition == .inline }.toArray()
let chunks = attachmentsArray.chunked(into: 10)

for chunk in chunks {
// Download images for the current chunk
let dataArray = try await chunk.asyncMap {
try await mailboxManager.attachmentData(attachment: $0)
}

// Read the DOM once
var mailBody = await presentableBody.body?.value
var compactBody = await presentableBody.compactBody

// Prepare the new DOM with the loaded images
for (index, attachment) in chunk.enumerated() {
guard let contentId = attachment.contentId,
let data = dataArray[safe: index] else {
continue
}

mailBody = mailBody?.replacingOccurrences(
of: "cid:\(contentId)",
with: "data:\(attachment.mimeType);base64,\(data.base64EncodedString())"
)
compactBody = compactBody?.replacingOccurrences(
of: "cid:\(contentId)",
with: "data:\(attachment.mimeType);base64,\(data.base64EncodedString())"
)
}

// Mutate DOM
await self.mutate(body: mailBody, compactBody: compactBody)

// Delay between each chunk processing just enough, so the user feels the UI is responsive.
try await Task.sleep(nanoseconds: 4_000_000_000)
adrien-coye marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

/// Update the DOM in the main thread
@MainActor func mutate(body: String?, compactBody: String?) {
presentableBody.body?.value = body
presentableBody.compactBody = compactBody
}
}

struct MessageView_Previews: PreviewProvider {
Expand Down
2 changes: 1 addition & 1 deletion Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ let project = Project(name: "Mail",
packages: [
.package(url: "https://github.com/Infomaniak/ios-login", .upToNextMajor(from: "4.0.0")),
.package(url: "https://github.com/Infomaniak/ios-dependency-injection", .upToNextMajor(from: "1.1.6")),
.package(url: "https://github.com/Infomaniak/ios-core", .revision("4c0c389de2e10e615ad79a854d2489977017efe5")),
.package(url: "https://github.com/Infomaniak/ios-core", .revision("9fc1a0f41ce0e830189b756d3b1a42d4e67421cc")),
.package(url: "https://github.com/Infomaniak/ios-core-ui", .upToNextMajor(from: "2.3.0")),
.package(url: "https://github.com/Infomaniak/ios-notifications", .upToNextMajor(from: "2.1.0")),
.package(url: "https://github.com/Infomaniak/ios-create-account", .upToNextMajor(from: "1.1.0")),
Expand Down