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

feat: make sure refreshing folder task is not killed randomly in background #956

Merged
merged 3 commits into from
Aug 31, 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
2 changes: 1 addition & 1 deletion Mail/Views/Menu Drawer/FolderListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ struct NestableFolder: Identifiable {
}
}

class FolderListViewModel: ObservableObject {
final class FolderListViewModel: ObservableObject {
/// Special folders (eg. Inbox) for the current mailbox
@Published var roleFolders = [NestableFolder]()
/// User created folders for the current mailbox
Expand Down
4 changes: 2 additions & 2 deletions Mail/Views/SplitView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ struct SplitView: View {
.onChange(of: scenePhase) { newScenePhase in
guard newScenePhase == .active else { return }
Task {
async let _ = try? mailboxManager.folders()
async let _ = try? mailboxManager.refreshAllFolders()
async let _ = try? mailboxManager.refreshAllSignatures()
}
}
Expand Down Expand Up @@ -202,7 +202,7 @@ struct SplitView: View {

private func fetchFolders() async {
await tryOrDisplayError {
try await mailboxManager.folders()
try await mailboxManager.refreshAllFolders()
}
}

Expand Down
2 changes: 1 addition & 1 deletion Mail/Views/Thread List/ThreadListViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ final class DateSection: Identifiable, Equatable {
isLoadingPage = true
}

await mailboxManager.refresh(folder: folder.freezeIfNeeded())
await mailboxManager.refreshFolderContent(folder.freezeIfNeeded())

withAnimation {
isLoadingPage = false
Expand Down
6 changes: 3 additions & 3 deletions MailCore/Cache/DraftManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public final class DraftManager {

private func refreshDraftFolder(latestSendDate: Date?, mailboxManager: MailboxManager) async throws {
if let draftFolder = mailboxManager.getFolder(with: .draft)?.freeze() {
await mailboxManager.refresh(folder: draftFolder)
await mailboxManager.refreshFolderContent(draftFolder)

if let latestSendDate {
/*
Expand All @@ -264,7 +264,7 @@ public final class DraftManager {
*/
let delay = latestSendDate.timeIntervalSinceNow
try await Task.sleep(nanoseconds: UInt64(1_000_000_000 * max(Double(delay), 1.5)))
await mailboxManager.refresh(folder: draftFolder)
await mailboxManager.refreshFolderContent(draftFolder)
}

await mailboxManager.deleteOrphanDrafts()
Expand All @@ -278,7 +278,7 @@ public final class DraftManager {
try await mailboxManager.delete(draft: liveDraft.freeze())
alertDisplayable.show(message: MailResourcesStrings.Localizable.snackbarDraftDeleted)
if let draftFolder = mailboxManager.getFolder(with: .draft)?.freeze() {
await mailboxManager.refresh(folder: draftFolder)
await mailboxManager.refreshFolderContent(draftFolder)
}
}
}
Expand Down
20 changes: 15 additions & 5 deletions MailCore/Cache/MailboxManager/MailboxManager+Folders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,21 @@

import Foundation
import InfomaniakCore
import InfomaniakCoreUI
import RealmSwift

// MARK: - Folders

public extension MailboxManager {
func folders() async throws {
// Get from Realm
/// Get all remote folders in DB
func refreshAllFolders() async throws {
let backgroundTracker = await ApplicationBackgroundTaskTracker(identifier: #function + UUID().uuidString)

// Network check
guard ReachabilityListener.instance.currentStatus != .offline else {
return
}

// Get from API
let folderResult = try await apiFetcher.folders(mailbox: mailbox)
let newFolders = getSubFolders(from: folderResult)
Expand All @@ -37,12 +42,12 @@ public extension MailboxManager {
self.keepCacheAttributes(for: folder, using: realm)
}

// Get from Realm
let cachedFolders = realm.objects(Folder.self)

// Update folders in Realm
try? realm.safeWrite {
// Remove old folders
realm.add(folderResult, update: .modified)
let toDeleteFolders = Set(cachedFolders).subtracting(Set(newFolders)).filter { $0.id != Constants.searchFolderId }
var toDeleteThreads = [Thread]()

Expand All @@ -59,8 +64,13 @@ public extension MailboxManager {
realm.delete(toDeleteMessages)
realm.delete(toDeleteThreads)
realm.delete(toDeleteFolders)

// Insert fresh remote folders
realm.add(folderResult, update: .modified)
}
}

await backgroundTracker.end()
}

/// Get the folder with the corresponding role in Realm.
Expand Down Expand Up @@ -106,8 +116,8 @@ public extension MailboxManager {
try await refreshActor.refreshFolder(from: messages, additionalFolder: additionalFolder)
}

func refresh(folder: Folder) async {
await refreshActor.refresh(folder: folder)
func refreshFolderContent(_ folder: Folder) async {
await refreshActor.refreshFolderContent(folder)
}

func cancelRefresh() async {
Expand Down
35 changes: 26 additions & 9 deletions MailCore/Cache/RefreshActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import Foundation
import InfomaniakCoreUI

public actor RefreshActor {
weak var mailboxManager: MailboxManager?
Expand All @@ -29,25 +30,41 @@ public actor RefreshActor {

public func flushFolder(folder: Folder, mailbox: Mailbox, apiFetcher: MailApiFetcher) async throws -> Bool {
let response = try await apiFetcher.flushFolder(mailbox: mailbox, folderId: folder.id)
await refresh(folder: folder)
await refreshFolderContent(folder)
return response
}

public func refreshFolder(from messages: [Message], additionalFolder: Folder?) async throws {
var folders = messages.map(\.folder)
if let additionalFolder {
folders.append(additionalFolder)
let updateFolders = Task {
var folders = messages.map(\.folder)
if let additionalFolder {
folders.append(additionalFolder)
}

let orderedSet = NSOrderedSet(array: folders as [Any])

for folder in orderedSet {
guard !Task.isCancelled else { break }
guard let impactedFolder = folder as? Folder else { continue }
await refreshFolderContent(impactedFolder)
}
}

let orderedSet = NSOrderedSet(array: folders as [Any])
// Track progress in background with a cancelation handler
let backgroundTracker = await ApplicationBackgroundTaskTracker(identifier: #function + UUID().uuidString) {
updateFolders.cancel()

for folder in orderedSet {
guard let impactedFolder = folder as? Folder else { continue }
await refresh(folder: impactedFolder)
Task {
await self.cancelRefresh()
}
}

await updateFolders.finish()

await backgroundTracker.end()
}

public func refresh(folder: Folder) async {
public func refreshFolderContent(_ folder: Folder) async {
await cancelRefresh()

refreshTask = Task {
Expand Down
2 changes: 1 addition & 1 deletion MailNotificationServiceExtension/NotificationService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ final class NotificationService: UNNotificationServiceExtension {
// We do nothing if we don't have an initial cursor
return nil
}
await mailboxManager.refresh(folder: inboxFolder.freezeIfNeeded())
await mailboxManager.refreshFolderContent(inboxFolder.freezeIfNeeded())

@ThreadSafe var message = mailboxManager.getRealm().object(ofType: Message.self, forPrimaryKey: uid)

Expand Down
2 changes: 1 addition & 1 deletion MailTests/MailboxManagerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ final class MailboxManagerTests: XCTestCase {
// MARK: Tests methods

func testFolders() async throws {
try await MailboxManagerTests.mailboxManager.folders()
try await MailboxManagerTests.mailboxManager.refreshAllFolders()
}

func testThreads() async throws {
Expand Down
Loading