diff --git a/Mail/UserAccountScene.swift b/Mail/UserAccountScene.swift index cd9d1a92d..1d7a111fb 100644 --- a/Mail/UserAccountScene.swift +++ b/Mail/UserAccountScene.swift @@ -25,6 +25,7 @@ import InfomaniakDI import InfomaniakLogin import InfomaniakNotifications import MailCore +import MailCoreUI import MailResources import SwiftUI import UIKit @@ -45,29 +46,7 @@ struct UserAccountScene: Scene { RootView() .standardWindow() .environmentObject(rootViewState) - .onReceive(NotificationCenter.default.publisher(for: UIScene.willEnterForegroundNotification)) { _ in - /* - On iOS: - `scenePhase` changes each time a pop-up is presented. - We have to listen to `UIScene.willEnterForegroundNotification` to increase the `appLaunchCounter` - only when the app enters foreground. - - On macOS: - `scenePhase` stays always active even when the app is on the background. - */ - - appLaunchCounter.increase() - cacheManager.refreshCacheData(account: rootViewState.account) - reviewManager.decreaseOpeningUntilReview() - rootViewState.transitionToLockViewIfNeeded() - checkAppVersion() - } - .onReceive(NotificationCenter.default.publisher(for: UIScene.didEnterBackgroundNotification)) { _ in - refreshAppBackgroundTask.scheduleForBackgroundLaunchIfNeeded() - if UserDefaults.shared.isAppLockEnabled && rootViewState.state != .appLocked { - appLockHelper.setTime() - } - } + .sceneLifecycle(willEnterForeground: willEnterForeground, didEnterBackground: didEnterBackground) .task(id: rootViewState.account) { cacheManager.refreshCacheData(account: rootViewState.account) } @@ -95,7 +74,22 @@ struct UserAccountScene: Scene { } } - func checkAppVersion() { + private func willEnterForeground() { + appLaunchCounter.increase() + reviewManager.decreaseOpeningUntilReview() + cacheManager.refreshCacheData(account: rootViewState.account) + rootViewState.transitionToLockViewIfNeeded() + checkAppVersion() + } + + private func didEnterBackground() { + refreshAppBackgroundTask.scheduleForBackgroundLaunchIfNeeded() + if UserDefaults.shared.isAppLockEnabled && rootViewState.state != .appLocked { + appLockHelper.setTime() + } + } + + private func checkAppVersion() { Task { do { let platform: Platform = platformDetector.isMacCatalyst ? .macOS : .ios diff --git a/Mail/Views/LockedAppView.swift b/Mail/Views/LockedAppView.swift index 5e9ac6c41..9b8844224 100644 --- a/Mail/Views/LockedAppView.swift +++ b/Mail/Views/LockedAppView.swift @@ -27,6 +27,8 @@ struct LockedAppView: View { @EnvironmentObject var navigationState: RootViewState + @State private var isEvaluatingPolicy = false + var body: some View { ZStack { VStack(spacing: UIPadding.medium) { @@ -49,6 +51,7 @@ struct LockedAppView: View { .buttonStyle(.ikPlain) .controlSize(.large) .ikButtonFullWidth(true) + .ikButtonLoading(isEvaluatingPolicy) } .padding(.top, UIPadding.onBoardingLogoTop) .padding(.bottom, value: .large) @@ -61,12 +64,17 @@ struct LockedAppView: View { } private func unlockApp() { + guard !isEvaluatingPolicy else { return } + Task { + isEvaluatingPolicy = true if await (try? appLockHelper.evaluatePolicy(reason: MailResourcesStrings.Localizable.lockAppTitle)) == true { appLockHelper.setTime() Task { navigationState.transitionToRootViewDestination(.mainView) } + } else { + isEvaluatingPolicy = false } } } diff --git a/MailCoreUI/Utils/SceneLifecycleModifier.swift b/MailCoreUI/Utils/SceneLifecycleModifier.swift new file mode 100644 index 000000000..b69206358 --- /dev/null +++ b/MailCoreUI/Utils/SceneLifecycleModifier.swift @@ -0,0 +1,62 @@ +/* + Infomaniak Mail - iOS App + Copyright (C) 2024 Infomaniak Network SA + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + */ + +import InfomaniakCore +import InfomaniakDI +import SwiftUI + +public extension View { + func sceneLifecycle(willEnterForeground: (() -> Void)? = nil, didEnterBackground: (() -> Void)? = nil) -> some View { + return modifier(SceneLifecycleModifier(willEnterForeground: willEnterForeground, didEnterBackground: didEnterBackground)) + } +} + +struct SceneLifecycleModifier: ViewModifier { + @LazyInjectService private var platformDetector: PlatformDetectable + + var willEnterForeground: (() -> Void)? + var didEnterBackground: (() -> Void)? + + func body(content: Content) -> some View { + content + .onAppear { + /* + On iOS/iPadOS, the `UIScene.willEnterForegroundNotification` notification is not posted when + the app is opened for the first time. + */ + if !platformDetector.isMac { + willEnterForeground?() + } + } + .onReceive(NotificationCenter.default.publisher(for: UIScene.willEnterForegroundNotification)) { _ in + /* + On iOS/iPadOS: + `scenePhase` changes each time a pop-up is presented. + We have to listen to `UIScene.willEnterForegroundNotification` to increase the `appLaunchCounter` + only when the app enters foreground. + + On macOS: + `scenePhase` stays always active even when the app is on the background. + */ + willEnterForeground?() + } + .onReceive(NotificationCenter.default.publisher(for: UIScene.didEnterBackgroundNotification)) { _ in + didEnterBackground?() + } + } +}