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

fix: Improve offline error handling #978

Merged
merged 4 commits into from
Sep 13, 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
4 changes: 4 additions & 0 deletions Mail/Utils/NetworkMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class NetworkMonitor: ObservableObject {
private var monitor: NWPathMonitor?
private let queue = DispatchQueue.global()

public static let shared = NetworkMonitor()

private init() {}

public func start() {
if monitor == nil {
monitor = NWPathMonitor()
Expand Down
4 changes: 3 additions & 1 deletion Mail/Views/Thread List/ThreadListSwipeAction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ private struct SwipeActionView: View {

@EnvironmentObject private var actionsManager: ActionsManager

@ObservedObject private var networkMonitor = NetworkMonitor.shared

@Binding var actionPanelMessages: [Message]?
@Binding var moveSheetMessages: [Message]?

let thread: Thread
let action: Action

var body: some View {
Button(role: action.isDestructive ? .destructive : nil) {
Button(role: action.isDestructive && networkMonitor.isConnected ? .destructive : nil) {
matomo.track(eventWithCategory: .swipeActions, action: .drag, name: action.matomoName)
Task {
await tryOrDisplayError {
Expand Down
2 changes: 1 addition & 1 deletion Mail/Views/Thread List/ThreadListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct ThreadListView: View {

@StateObject var viewModel: ThreadListViewModel
@StateObject var multipleSelectionViewModel: ThreadListMultipleSelectionViewModel
@StateObject private var networkMonitor = NetworkMonitor()
@ObservedObject private var networkMonitor = NetworkMonitor.shared

private var shouldDisplayEmptyView: Bool {
viewModel.folder.lastUpdate != nil && viewModel.sections.isEmpty && !viewModel.isLoadingPage
Expand Down
4 changes: 3 additions & 1 deletion Mail/Views/Thread/MoveEmailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ struct MoveEmailView: View {
private func move(to folder: Folder) {
let frozenOriginFolder = originFolder?.freezeIfNeeded()
Task {
try await actionsManager.performMove(messages: movedMessages, from: frozenOriginFolder, to: folder)
await tryOrDisplayError {
try await actionsManager.performMove(messages: movedMessages, from: frozenOriginFolder, to: folder)
}
}
dismissModal()
}
Expand Down
35 changes: 21 additions & 14 deletions Mail/Views/Thread/ThreadView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ struct ThreadView: View {
.multilineTextAlignment(.leading)
.lineSpacing(8)

let externalTag = thread.displayExternalRecipientState(mailboxManager: mailboxManager, recipientsList: thread.from)
let externalTag = thread.displayExternalRecipientState(
mailboxManager: mailboxManager,
recipientsList: thread.from
)
switch externalTag {
case .many, .one:
Button {
Expand Down Expand Up @@ -121,11 +124,13 @@ struct ThreadView: View {
let messages = thread.messages.freeze().toArray()
let originFolder = thread.folder?.freezeIfNeeded()
Task {
try await actionsManager.performAction(
target: messages,
action: thread.flagged ? .unstar : .star,
origin: .toolbar(originFolder: originFolder)
)
await tryOrDisplayError {
try await actionsManager.performAction(
target: messages,
action: thread.flagged ? .unstar : .star,
origin: .toolbar(originFolder: originFolder)
)
}
}
} label: {
(thread.flagged ? MailResourcesAsset.starFull : MailResourcesAsset.star).swiftUIImage
Expand Down Expand Up @@ -177,7 +182,7 @@ struct ThreadView: View {

private func markThreadAsReadIfNeeded(thread: Thread) async {
guard thread.hasUnseenMessages else { return }

let originFolder = thread.folder?.freezeIfNeeded()
try? await actionsManager.performAction(
target: thread.messages.toArray(),
Expand All @@ -200,13 +205,15 @@ struct ThreadView: View {

let originFolder = thread.folder?.freezeIfNeeded()
Task {
try await actionsManager.performAction(
target: messages,
action: action,
origin: .toolbar(originFolder: originFolder)
)
if action == .archive || action == .delete {
dismiss()
await tryOrDisplayError {
try await actionsManager.performAction(
target: messages,
action: action,
origin: .toolbar(originFolder: originFolder)
)
if action == .archive || action == .delete {
dismiss()
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions MailCore/API/MailApiFetcher/MailApiFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,15 @@ public final class MailApiFetcher: ApiFetcher, MailApiFetchable {
"Decoded type": String(describing: T.self),
"Raw JSON": rawJson])
}
} else if case .sessionTaskFailed(let error) = afError,
(error as NSError).code == NSURLErrorNotConnectedToInternet {
throw MailError.noConnection

} else if case .requestAdaptationFailed(let error) = afError,
(error as NSError).code == NSURLErrorNotConnectedToInternet {
throw MailError.noConnection
}

throw AFErrorWithContext(request: request, afError: afError)
} else {
throw error
Expand Down
4 changes: 4 additions & 0 deletions MailCore/API/MailError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ public class MailError: LocalizedError {
shouldDisplay: true)
public static let incoherentThreadDate = MailError(code: "incoherentThreadDate")

public static let noConnection = MailError(code: "noConnection",
localizedDescription: MailResourcesStrings.Localizable.noConnection,
shouldDisplay: true)

/// After an update from the server we are still without a default signature
public static let defaultSignatureMissing = MailError(code: "defaultSignatureMissing")

Expand Down
2 changes: 1 addition & 1 deletion MailCore/API/SyncedAuthenticator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ final class SyncedAuthenticator: OAuthAuthenticator {
SentrySDK
.addBreadcrumb(oldToken.generateBreadcrumb(level: .error,
message: "Refreshing token failed - Other \(error.debugDescription)"))
return .success(oldToken)
return .failure(error ?? MailError.unknownError)
}

// Couldn't refresh the token, API says it's invalid
Expand Down
7 changes: 5 additions & 2 deletions MailResources/Localizable/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* Release: Working copy
* Locale: de, German
* Tagged: ios
* Exported by: elena willen
* Exported at: Thu, 31 Aug 2023 13:09:24 +0200
* Exported by: Philippe Weidmann
* Exported at: Wed, 13 Sep 2023 10:20:38 +0200
*/

/* loco:6256793050618f7416758a32 */
Expand Down Expand Up @@ -1276,3 +1276,6 @@

/* loco:64edf250cb0c86ab3001d1b2 */
"buttonStart" = "Anfangen";

/* loco:65016e82bd99726dde081533 */
"noConnection" = "Keine Verbindung";
7 changes: 5 additions & 2 deletions MailResources/Localizable/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* Release: Working copy
* Locale: en, English
* Tagged: ios
* Exported by: elena willen
* Exported at: Thu, 31 Aug 2023 13:09:24 +0200
* Exported by: Philippe Weidmann
* Exported at: Wed, 13 Sep 2023 10:20:38 +0200
*/

/* loco:6256793050618f7416758a32 */
Expand Down Expand Up @@ -1276,3 +1276,6 @@

/* loco:64edf250cb0c86ab3001d1b2 */
"buttonStart" = "Start";

/* loco:65016e82bd99726dde081533 */
"noConnection" = "No connection";
7 changes: 5 additions & 2 deletions MailResources/Localizable/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* Release: Working copy
* Locale: es, Spanish
* Tagged: ios
* Exported by: elena willen
* Exported at: Thu, 31 Aug 2023 13:09:24 +0200
* Exported by: Philippe Weidmann
* Exported at: Wed, 13 Sep 2023 10:20:38 +0200
*/

/* loco:6256793050618f7416758a32 */
Expand Down Expand Up @@ -1276,3 +1276,6 @@

/* loco:64edf250cb0c86ab3001d1b2 */
"buttonStart" = "Empezar";

/* loco:65016e82bd99726dde081533 */
"noConnection" = "Sin conexión";
7 changes: 5 additions & 2 deletions MailResources/Localizable/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* Release: Working copy
* Locale: fr, French
* Tagged: ios
* Exported by: elena willen
* Exported at: Thu, 31 Aug 2023 13:09:24 +0200
* Exported by: Philippe Weidmann
* Exported at: Wed, 13 Sep 2023 10:20:38 +0200
*/

/* loco:6256793050618f7416758a32 */
Expand Down Expand Up @@ -1276,3 +1276,6 @@

/* loco:64edf250cb0c86ab3001d1b2 */
"buttonStart" = "Commencer";

/* loco:65016e82bd99726dde081533 */
"noConnection" = "Pas de connexion";
7 changes: 5 additions & 2 deletions MailResources/Localizable/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* Release: Working copy
* Locale: it, Italian
* Tagged: ios
* Exported by: elena willen
* Exported at: Thu, 31 Aug 2023 13:09:24 +0200
* Exported by: Philippe Weidmann
* Exported at: Wed, 13 Sep 2023 10:20:38 +0200
*/

/* loco:6256793050618f7416758a32 */
Expand Down Expand Up @@ -1276,3 +1276,6 @@

/* loco:64edf250cb0c86ab3001d1b2 */
"buttonStart" = "Inizia";

/* loco:65016e82bd99726dde081533 */
"noConnection" = "Nessuna connessione";
Loading