Skip to content

Commit

Permalink
Merge pull request #848 from Infomaniak/fix-composeview
Browse files Browse the repository at this point in the history
fix(ComposeMessageView): Move up message fetching methods to avoid re…
  • Loading branch information
valentinperignon committed Jul 4, 2023
2 parents c78cd61 + a5fe7a7 commit 4f961bc
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 106 deletions.
101 changes: 1 addition & 100 deletions Mail/Views/New Message/ComposeMessageBodyView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,13 @@ import RealmSwift
import SwiftUI

struct ComposeMessageBodyView: View {
@EnvironmentObject private var mailboxManager: MailboxManager

/// Something to track the initial loading of a default signature
@EnvironmentObject private var signatureManager: SignaturesManager

@State private var isShowingCamera = false
@State private var isShowingFileSelection = false
@State private var isShowingPhotoLibrary = false

@StateObject private var editorModel = RichTextEditorModel()

@StateRealmObject var draft: Draft
@ObservedRealmObject var draft: Draft

@Binding var isLoadingContent: Bool
@Binding var editorFocus: Bool
Expand Down Expand Up @@ -66,24 +61,6 @@ struct ComposeMessageBodyView: View {
.frame(height: editorModel.height + 20)
.padding(.vertical, 8)
}
.task {
await prepareCompleteDraft()
}
.task {
await prepareReplyForwardBodyAndAttachments()
}
.onChange(of: signatureManager.loadingSignatureState) { state in
switch state {
case .success:
setSignature()
case .error:
// Unable to get signatures, "An error occurred" and close modal.
IKSnackBar.showSnackBar(message: MailError.unknownError.localizedDescription)
dismiss()
case .progress:
break
}
}
.fullScreenCover(isPresented: $isShowingCamera) {
CameraPicker { data in
attachmentsManager.importAttachments(attachments: [data])
Expand All @@ -103,84 +80,9 @@ struct ComposeMessageBodyView: View {
.ignoresSafeArea()
}
}

private func prepareCompleteDraft() async {
guard draft.messageUid != nil && draft.remoteUUID.isEmpty else { return }

do {
if let fetchedDraft = try await mailboxManager.draft(partialDraft: draft),
let liveFetchedDraft = fetchedDraft.thaw() {
draft = liveFetchedDraft
}
isLoadingContent = false
} catch {
dismiss()
IKSnackBar.showSnackBar(message: MailError.unknownError.localizedDescription)
}
}

private func prepareReplyForwardBodyAndAttachments() async {
guard let messageReply else { return }

let prepareTask = Task.detached {
try await prepareBody(message: messageReply.message, replyMode: messageReply.replyMode)
try await prepareAttachments(message: messageReply.message, replyMode: messageReply.replyMode)
}

do {
_ = try await prepareTask.value

isLoadingContent = false
} catch {
dismiss()
IKSnackBar.showSnackBar(message: MailError.unknownError.localizedDescription)
}
}

private func setSignature() {
guard draft.identityId == nil || draft.identityId?.isEmpty == true else {
return
}

guard let defaultSignature = mailboxManager.getStoredSignatures().defaultSignature else {
return
}

let body = $draft.body.wrappedValue
let signedBody = defaultSignature.appendSignature(to: body)

// At this point we have signatures in base up to date, we use the default one.
$draft.identityId.wrappedValue = "\(defaultSignature.id)"
$draft.body.wrappedValue = signedBody
}

private func prepareBody(message: Message, replyMode: ReplyMode) async throws {
if !message.fullyDownloaded {
try await mailboxManager.message(message: message)
}

guard let freshMessage = message.thaw() else { return }
freshMessage.realm?.refresh()
$draft.body.wrappedValue = Draft.replyingBody(message: freshMessage, replyMode: replyMode)
}

private func prepareAttachments(message: Message, replyMode: ReplyMode) async throws {
guard replyMode == .forward else { return }
let attachments = try await mailboxManager.apiFetcher.attachmentsToForward(
mailbox: mailboxManager.mailbox,
message: message
).attachments

for attachment in attachments {
$draft.attachments.append(attachment)
}
attachmentsManager.completeUploadedAttachments()
}
}

struct ComposeMessageBodyView_Previews: PreviewProvider {
static let signaturesManager = SignaturesManager(mailboxManager: PreviewHelper.sampleMailboxManager)

static var previews: some View {
@Environment(\.dismiss) var dismiss

Expand All @@ -194,6 +96,5 @@ struct ComposeMessageBodyView_Previews: PreviewProvider {
alert: NewMessageAlert(),
dismiss: dismiss,
messageReply: nil)
.environmentObject(signaturesManager)
}
}
91 changes: 89 additions & 2 deletions Mail/Views/New Message/ComposeMessageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,27 @@ struct ComposeMessageView: View {
dismiss: dismiss,
messageReply: messageReply
)
.environmentObject(signatureManager)
}
}
}
.task {
await prepareCompleteDraft()
}
.task {
await prepareReplyForwardBodyAndAttachments()
}
.onChange(of: signatureManager.loadingSignatureState) { state in
switch state {
case .success:
setSignature()
case .error:
// Unable to get signatures, "An error occurred" and close modal.
IKSnackBar.showSnackBar(message: MailError.unknownError.localizedDescription)
dismiss()
case .progress:
break
}
}
.background(MailResourcesAsset.backgroundColor.swiftUIColor)
.onAppear {
switch messageReply?.replyMode {
Expand Down Expand Up @@ -198,7 +215,7 @@ struct ComposeMessageView: View {
.background(MailResourcesAsset.backgroundColor.swiftUIColor)
}

// MAK: - Func
// MARK: - Func

private func didTouchDismiss() {
guard attachmentsManager.allAttachmentsUploaded else {
Expand Down Expand Up @@ -235,6 +252,76 @@ struct ComposeMessageView: View {
realm.add(draft, update: .modified)
}
}

private func prepareCompleteDraft() async {
guard draft.messageUid != nil && draft.remoteUUID.isEmpty else { return }

do {
try await mailboxManager.draft(partialDraft: draft)
isLoadingContent = false
} catch {
dismiss()
IKSnackBar.showSnackBar(message: MailError.unknownError.localizedDescription)
}
}

private func prepareReplyForwardBodyAndAttachments() async {
guard let messageReply else { return }

let prepareTask = Task.detached {
try await prepareBody(message: messageReply.message, replyMode: messageReply.replyMode)
try await prepareAttachments(message: messageReply.message, replyMode: messageReply.replyMode)
}

do {
_ = try await prepareTask.value

isLoadingContent = false
} catch {
dismiss()
IKSnackBar.showSnackBar(message: MailError.unknownError.localizedDescription)
}
}

private func prepareBody(message: Message, replyMode: ReplyMode) async throws {
if !message.fullyDownloaded {
try await mailboxManager.message(message: message)
}

guard let freshMessage = message.thaw() else { return }
freshMessage.realm?.refresh()
$draft.body.wrappedValue = Draft.replyingBody(message: freshMessage, replyMode: replyMode)
}

private func prepareAttachments(message: Message, replyMode: ReplyMode) async throws {
guard replyMode == .forward else { return }
let attachments = try await mailboxManager.apiFetcher.attachmentsToForward(
mailbox: mailboxManager.mailbox,
message: message
).attachments

for attachment in attachments {
$draft.attachments.append(attachment)
}
attachmentsManager.completeUploadedAttachments()
}

private func setSignature() {
guard draft.identityId == nil || draft.identityId?.isEmpty == true else {
return
}

guard let defaultSignature = mailboxManager.getStoredSignatures().defaultSignature else {
return
}

let body = $draft.body.wrappedValue
let signedBody = defaultSignature.appendSignature(to: body)

// At this point we have signatures in base up to date, we use the default one.
$draft.identityId.wrappedValue = "\(defaultSignature.id)"
$draft.body.wrappedValue = signedBody
}
}

struct ComposeMessageView_Previews: PreviewProvider {
Expand Down
6 changes: 2 additions & 4 deletions MailCore/Cache/MailboxManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1120,9 +1120,9 @@ public class MailboxManager: ObservableObject {
return realm.objects(Draft.self).where { $0.action != nil }
}

public func draft(partialDraft: Draft) async throws -> Draft? {
public func draft(partialDraft: Draft) async throws {
guard let associatedMessage = getRealm().object(ofType: Message.self, forPrimaryKey: partialDraft.messageUid)?.freeze()
else { return nil }
else { throw MailError.localMessageNotFound }

// Get from API
let draft = try await apiFetcher.draft(from: associatedMessage)
Expand All @@ -1140,8 +1140,6 @@ public class MailboxManager: ObservableObject {
realm.add(draft.detached(), update: .modified)
}
}

return getRealm().object(ofType: Draft.self, forPrimaryKey: draft.localUUID)?.freeze()
}

public func draft(messageUid: String, using realm: Realm? = nil) -> Draft? {
Expand Down

0 comments on commit 4f961bc

Please sign in to comment.