diff --git a/ios/TwakeCore/Jmap/JmapClient.swift b/ios/TwakeCore/Jmap/JmapClient.swift index cfac87c69..6033ef770 100644 --- a/ios/TwakeCore/Jmap/JmapClient.swift +++ b/ios/TwakeCore/Jmap/JmapClient.swift @@ -9,6 +9,11 @@ class JmapClient { private var authentication: Authentication? private var tokenRefreshManager: TokenRefreshManager? private var authenticationInterceptor: AuthenticationInterceptor? + + private var hasMoreChanges: Bool = true + private var currentSinceState: String? + private var totalListEmails = [Email]() + private var listErrors = [Error]() func getNewEmails( apiUrl: String, @@ -19,8 +24,7 @@ class JmapClient { basicAuth: String?, tokenEndpointUrl: String?, oidcScopes: [String]?, - onSuccess: @escaping ([Email]) -> Void, - onFailure: @escaping (Error) -> Void + onComplete: @escaping ([Email], [Error]) -> Void ) { if (authenticationType == AuthenticationType.basic) { authentication = AuthenticationCredential( @@ -47,7 +51,26 @@ class JmapClient { accountId: accountId, tokenRefreshManager: tokenRefreshManager ) - + + hasMoreChanges = true + currentSinceState = sinceState + totalListEmails = [Email]() + listErrors = [Error]() + + self.handleGetEmailChanges( + apiUrl: apiUrl, + accountId: accountId, + onComplete: onComplete + ) + } + + private func handleGetEmailChanges(apiUrl: String, + accountId: String, + onComplete: @escaping ([Email], [Error]) -> Void) { + guard hasMoreChanges, let sinceState = currentSinceState else { + return onComplete(self.totalListEmails, self.listErrors) + } + let jmapRequestObject = JmapRequestGenerator.shared.createEmailChangesRequest( accountId: accountId, sinceState: sinceState @@ -59,13 +82,29 @@ class JmapClient { headers: HTTPHeaders([jmapHeader]), interceptor: authenticationInterceptor, onSuccess: { (data: JmapResponseObject) in - if let listEmail = data.parsing(methodName: JmapConstants.EMAIL_GET_METHOD_NAME, methodCallId: "c1"), !listEmail.isEmpty { - onSuccess(listEmail) + if let response = data.parsing(methodName: JmapConstants.EMAIL_GET_METHOD_NAME, methodCallId: "c1") { + if let listEmail = response.list, !listEmail.isEmpty { + self.totalListEmails.append(contentsOf: listEmail) + } + self.hasMoreChanges = response.hasMoreChanges ?? false + self.currentSinceState = response.newState + + self.handleGetEmailChanges(apiUrl: apiUrl, accountId: accountId, onComplete: onComplete) } else { - onFailure(JmapExceptions.notFoundNewEmails) + self.listErrors.append(JmapExceptions.notFoundNewEmails) + self.hasMoreChanges = false + self.currentSinceState = nil + + onComplete(self.totalListEmails, self.listErrors) } }, - onFailure: onFailure + onFailure: { error in + self.listErrors.append(error) + self.hasMoreChanges = false + self.currentSinceState = nil + + onComplete(self.totalListEmails, self.listErrors) + } ) } } diff --git a/ios/TwakeCore/Jmap/Model/Response/JmapResponseObject.swift b/ios/TwakeCore/Jmap/Model/Response/JmapResponseObject.swift index e6fb2d743..97d63b177 100644 --- a/ios/TwakeCore/Jmap/Model/Response/JmapResponseObject.swift +++ b/ios/TwakeCore/Jmap/Model/Response/JmapResponseObject.swift @@ -38,6 +38,13 @@ enum ResponseInvocation: Codable { case .string(_): return nil } } + + var response: MethodResponse? { + switch self { + case .methodResponse(let method): return method + case .string(_): return nil + } + } } struct MethodResponse: Codable { @@ -54,7 +61,7 @@ struct MethodResponse: Codable { } extension JmapResponseObject { - func parsing(methodName: String, methodCallId: String) -> [T]? { + func parsing(methodName: String, methodCallId: String) -> MethodResponse? { let invocations = methodResponses.first { (responseInvocations: [ResponseInvocation]) in return responseInvocations.contains { (responseInvocation: ResponseInvocation) in return validateResponseInvocation(response: responseInvocation, methodName: methodName, methodCallId: methodCallId) @@ -68,7 +75,7 @@ extension JmapResponseObject { return validateMethodResponse(response: response) } - return invocation?.listObject + return invocation?.response } } diff --git a/ios/TwakeCore/Network/AlamofireService.swift b/ios/TwakeCore/Network/AlamofireService.swift index 64e6d1c16..d5213cb46 100644 --- a/ios/TwakeCore/Network/AlamofireService.swift +++ b/ios/TwakeCore/Network/AlamofireService.swift @@ -19,13 +19,15 @@ class AlamofireService { request.httpBody = payloadData - AF.request(request, interceptor: interceptor).validate().responseDecodable(of: T.self) { response in - switch(response.result) { - case .success(let data): - onSuccess(data) - case .failure(let error): - onFailure(NetworkExceptions(value: "\(error.localizedDescription)")) + AF.request(request, interceptor: interceptor) + .validate() + .responseDecodable(of: T.self, queue: .global(qos: .default)) { response in + switch(response.result) { + case .success(let data): + onSuccess(data) + case .failure(let error): + onFailure(NetworkExceptions(value: "\(error.localizedDescription)")) + } } - } } } diff --git a/ios/TwakeCore/Network/TokenRefreshManager.swift b/ios/TwakeCore/Network/TokenRefreshManager.swift index 83dbfbb0c..8f73a1dc5 100644 --- a/ios/TwakeCore/Network/TokenRefreshManager.swift +++ b/ios/TwakeCore/Network/TokenRefreshManager.swift @@ -53,17 +53,18 @@ class TokenRefreshManager { request.httpBody = data - AF.request(request).responseDecodable(of: TokenResponse.self) { response in - if (response.response?.statusCode != 200) { - onFailure(NetworkExceptions(value: "Failed to get token: \(response.error?.localizedDescription ?? "Unknown Error")")) - } else { - switch(response.result) { - case .success(let data): - onSuccess(data) - case .failure(let error): - onFailure(NetworkExceptions(value: "Failed to get token \(error.localizedDescription)")) + AF.request(request) + .responseDecodable(of: TokenResponse.self, queue: .global(qos: .default)) { response in + if (response.response?.statusCode != 200) { + onFailure(NetworkExceptions(value: "Failed to get token: \(response.error?.localizedDescription ?? "Unknown Error")")) + } else { + switch(response.result) { + case .success(let data): + onSuccess(data) + case .failure(let error): + onFailure(NetworkExceptions(value: "Failed to get token \(error.localizedDescription)")) + } } } - } } } diff --git a/ios/TwakeMailNSE/NotificationService.swift b/ios/TwakeMailNSE/NotificationService.swift index d2ef2bb41..417c680e5 100644 --- a/ios/TwakeMailNSE/NotificationService.swift +++ b/ios/TwakeMailNSE/NotificationService.swift @@ -63,38 +63,41 @@ class NotificationService: UNNotificationServiceExtension { basicAuth: keychainSharingSession.basicAuth, tokenEndpointUrl: keychainSharingSession.tokenEndpoint, oidcScopes: keychainSharingSession.oidcScopes, - onSuccess: { emails in - self.keychainController.updateEmailStateToKeychain(accountId: keychainSharingSession.accountId, newState: newEmailState) - - if (emails.count > 1) { - for email in emails { - if (email.id == emails.last?.id) { - break + onComplete: { (emails, errors) in + if emails.isEmpty { + self.modifiedContent?.body = self.newEmailDefaultMessage + self.modifiedContent?.badge = NSNumber(value: 1) + return self.notify() + } else { + self.keychainController.updateEmailStateToKeychain(accountId: keychainSharingSession.accountId, newState: newEmailState) + + if (emails.count > 1) { + for email in emails { + if (email.id == emails.last?.id) { + break + } + self.scheduleLocalNotification(email: email) } - self.scheduleLocalNotification(email: email) - } - let delayTimeIntervalNotification: TimeInterval = TimeInterval(self.timeIntervalNotificationTriggerInSecond * (emails.count - 1)) + let delayTimeIntervalNotification: TimeInterval = TimeInterval(self.timeIntervalNotificationTriggerInSecond * (emails.count - 1)) - DispatchQueue.main.asyncAfter(deadline: .now() + delayTimeIntervalNotification) { - self.modifiedContent?.subtitle = emails.last?.subject ?? "" - self.modifiedContent?.body = emails.last?.preview ?? "" - self.modifiedContent?.badge = NSNumber(value: emails.count) - self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.last?.id ?? "" + DispatchQueue.main.asyncAfter(deadline: .now() + delayTimeIntervalNotification) { + self.modifiedContent?.subtitle = emails.last?.subject ?? "" + self.modifiedContent?.body = emails.last?.preview ?? "" + self.modifiedContent?.badge = NSNumber(value: emails.count) + self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.last?.id ?? "" + return self.notify() + } + } else { + self.modifiedContent?.subtitle = emails.first?.subject ?? "" + self.modifiedContent?.body = emails.first?.preview ?? "" + self.modifiedContent?.badge = NSNumber(value: 1) + self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.first?.id ?? "" return self.notify() } - } else { - self.modifiedContent?.subtitle = emails.first?.subject ?? "" - self.modifiedContent?.body = emails.first?.preview ?? "" - self.modifiedContent?.badge = NSNumber(value: 1) - self.modifiedContent?.userInfo[JmapConstants.EMAIL_ID] = emails.first?.id ?? "" - return self.notify() } - }, - onFailure: { error in - self.modifiedContent?.body = self.newEmailDefaultMessage - self.modifiedContent?.badge = NSNumber(value: 1) - return self.notify() + + } ) }