ET-2530 Make migration work seamlessly while offline

This commit is contained in:
Jacek Krasiukianis
2025-04-02 09:30:54 +00:00
parent c6b3b93907
commit cdf4270a0f
8 changed files with 57 additions and 11 deletions
+21 -3
View File
@@ -119,6 +119,11 @@ private struct RootView: View {
case .activeSessionTransition:
EmptyView()
case .waitingForSessionInitialization:
OperationInProgressView(
text: nil,
toast: .error(message: L10n.Session.initializationDifficulties.string)
)
}
}
.transition(.opacity)
@@ -132,7 +137,7 @@ private struct RootView: View {
case .checkingIfMigrationIsNeeded:
EmptyView()
case .inProgress:
MigrationInProgressView()
OperationInProgressView(text: L10n.LegacyMigration.migrationInProgress, toast: nil)
case .pinRequired(let errorFromLatestAttempt):
PINLockScreen(error: .constant(errorFromLatestAttempt)) { output in
switch output {
@@ -154,13 +159,26 @@ private struct RootView: View {
}
}
private struct MigrationInProgressView: View {
private struct OperationInProgressView: View {
let text: LocalizedStringResource?
let toast: Toast?
var body: some View {
ZStack(alignment: .center) {
Color.clear
ProgressView() {
Text(L10n.LegacyMigration.migrationInProgress)
if let text {
Text(text)
}
}
if let toast {
VStack {
Spacer()
ToastView(model: toast) {}
}
}
}
}
@@ -2605,6 +2605,9 @@
"Protection" : {
"comment" : "Protection setting title in app settings."
},
"Proton Mail needs to connect to the server to finish initialization. Please ensure you have a good internet connection." : {
"comment" : "Error when the connection fails during session initialization."
},
"Provided value is not a valid PIN" : {
"comment" : "Error message when setting up PIN"
},
@@ -23,6 +23,7 @@ struct ApplicationServices {
var enterBackgroundServices: [ApplicationServiceDidEnterBackground] = []
var terminateServices: [ApplicationServiceTerminate] = []
@MainActor
func setUp() {
setUpServices.forEach { $0.setUpService() }
}
@@ -41,6 +42,7 @@ struct ApplicationServices {
}
protocol ApplicationServiceSetUp {
@MainActor
func setUpService()
}
+19 -6
View File
@@ -69,6 +69,7 @@ final class AppContext: Sendable, ObservableObject {
self.dependencies = dependencies
}
@MainActor
private func start() throws {
AppLogger.log(message: "AppContext.start", category: .appLifeCycle)
@@ -87,12 +88,7 @@ final class AppContext: Sendable, ObservableObject {
setupAccountBindings()
if let currentSession = accountAuthCoordinator.primaryAccountSignedInSession() {
switch mailSession.userContextFromSession(session: currentSession) {
case .ok(let newUserSession):
withAnimation { sessionState = .activeSession(session: newUserSession) }
case .error(let error):
throw error
}
setupActiveUserSession(session: currentSession)
}
}
}
@@ -127,9 +123,26 @@ extension AppContext: AccountAuthDelegate {
@MainActor
private func setupActiveUserSession(session: StoredSession) {
let start = ContinuousClock.now
switch mailSession.userContextFromSession(session: session) {
case .ok(let newUserSession):
withAnimation { self.sessionState = .activeSession(session: newUserSession) }
case .error(.other(.network)):
AppLogger.log(
message: "Failed to initialize session due to network error, will retry...",
category: .userSessions,
isError: true
)
withAnimation { sessionState = .waitingForSessionInitialization }
Task {
let minimumTimeBetweenRetries = Duration.seconds(5)
let earliestNextAttemptTime = start + minimumTimeBetweenRetries
try! await Task.sleep(until: earliestNextAttemptTime)
setupActiveUserSession(session: session)
}
case .error(let error):
AppLogger.log(error: error, category: .userSessions)
}
@@ -22,6 +22,7 @@ enum SessionState: Equatable {
case noSession
case activeSession(session: MailUserSession)
case activeSessionTransition
case waitingForSessionInitialization
var userSession: MailUserSession? {
guard case .activeSession(let session) = self else { return nil }
@@ -34,6 +35,8 @@ enum SessionState: Equatable {
return true
case (.activeSessionTransition, .activeSessionTransition):
return true
case (.waitingForSessionInitialization, .waitingForSessionInitialization):
return true
case (.activeSession(let lhsSession), .activeSession(let rhsSession)):
return lhsSession.sessionId() == rhsSession.sessionId()
default:
@@ -22,7 +22,7 @@ extension SessionState {
switch self {
case .activeSession:
true
case .noSession, .activeSessionTransition:
case .noSession, .activeSessionTransition, .waitingForSessionInitialization:
false
}
}
+7
View File
@@ -665,6 +665,13 @@ enum L10n {
)
}
enum Session {
static let initializationDifficulties = LocalizedStringResource(
"Proton Mail needs to connect to the server to finish initialization. Please ensure you have a good internet connection.",
comment: "Error when the connection fails during session initialization."
)
}
enum Settings {
enum App {
static let title = LocalizedStringResource(
@@ -61,7 +61,7 @@ final class UserNotificationCenterDelegateTests {
mailSession.onPrimaryAccountChanged = nil
}
@Test
@MainActor @Test
func whenServicesAreSetUp_assignsItselfAsUserNotificationCenterDelegate() {
sut.setUpService()