Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ extension EuriaWebViewDelegate: WKNavigationDelegate {
}

func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
isLoaded = false
isReadyToReceiveEvents = false

webView.reload()
reloadWebView()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ extension EuriaWebViewDelegate: WKScriptMessageHandler {
case unauthenticated
case keepDeviceAwake
case ready
case logIn
case signUp
}

func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
Expand All @@ -46,6 +48,12 @@ extension EuriaWebViewDelegate: WKScriptMessageHandler {
case .ready:
isReadyToReceiveEvents = true
navigateIfPossible()
case .logIn:
Task {
await loginHandler.login()
}
case .signUp:
isShowingRegisterView = true
}
}

Expand Down
16 changes: 16 additions & 0 deletions EuriaFeatures/MainView/Delegate/EuriaWebViewDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

import EuriaCore
import EuriaOnboardingView
import InfomaniakCore
import InfomaniakDI
import InfomaniakLogin
Expand All @@ -29,9 +30,11 @@ import WebKit
@MainActor
final class EuriaWebViewDelegate: NSObject, WebViewCoordinator, ObservableObject {
@Published var isLoaded = false
@Published var isShowingRegisterView = false

@Published var isPresentingDocument: URL?
@Published var error: ErrorDomain?
@ObservedObject var loginHandler = LoginHandler()

let host: String
let webConfiguration: WKWebViewConfiguration
Expand Down Expand Up @@ -154,4 +157,17 @@ final class EuriaWebViewDelegate: NSObject, WebViewCoordinator, ObservableObject
try await webView?.evaluateJavaScript(JSBridge.goTo(destination))
}
}

func updateSessionToken(_ session: any UserSessionable) {
if let token = session.apiFetcher.currentToken {
addCookies(token: token)
reloadWebView()
}
}

func reloadWebView() {
isLoaded = false
isReadyToReceiveEvents = false
webView?.reload()
}
}
22 changes: 20 additions & 2 deletions EuriaFeatures/MainView/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,23 @@
import AVFoundation
import EuriaCore
import EuriaCoreUI
import EuriaOnboardingView
import InAppTwoFactorAuthentication
import InfomaniakConcurrency
import InfomaniakCore
import InfomaniakCoreCommonUI
import InfomaniakCoreUIResources
import InfomaniakCreateAccount
import InfomaniakDI
import InfomaniakLogin
import InfomaniakNotifications
import SwiftUI
import WebKit

public struct MainView: View {
@InjectService var orientationManager: OrientationManageable
@InjectService var accountManager: AccountManagerable

@EnvironmentObject private var universalLinksState: UniversalLinksState

@StateObject private var webViewDelegate: EuriaWebViewDelegate
Expand All @@ -39,6 +44,7 @@ public struct MainView: View {
@State private var isShowingErrorAlert = false

@ObservedObject var networkMonitor = NetworkMonitor.shared
@ObservedObject var loginHandler = LoginHandler()

private let session: any UserSessionable

Expand Down Expand Up @@ -88,7 +94,6 @@ public struct MainView: View {
.appBackground()
.onAppear {
networkMonitor.start()
@InjectService var orientationManager: OrientationManageable
orientationManager.setOrientationLock(.all)
}
.onChange(of: networkMonitor.isConnected) { isConnected in
Expand All @@ -101,6 +106,20 @@ public struct MainView: View {
webViewDelegate.enqueueNavigation(destination: navigationDestination.string)
universalLinksState.linkedWebView = nil
}
.sheet(isPresented: $webViewDelegate.isShowingRegisterView) {
RegisterView(registrationProcess: .mail) { viewController in
guard let viewController else { return }
loginHandler.loginAfterAccountCreation(from: viewController)
}
}
.onReceive(accountManager.objectWillChange) { _ in
Task {
guard let session = await accountManager.currentSession else {
return
}
webViewDelegate.updateSessionToken(session)
}
}
.sceneLifecycle(willEnterForeground: willEnterForeground, didEnterBackground: didEnterBackground)
}

Expand All @@ -127,7 +146,6 @@ public struct MainView: View {
}

private func checkTwoFAChallenges() async {
@InjectService var accountManager: AccountManagerable
let sessions: [InAppTwoFactorAuthenticationSession] = await accountManager.accounts.asyncCompactMap { account in
guard let user = await accountManager.userProfileStore.getUserProfile(id: account.userId) else {
return nil
Expand Down
12 changes: 7 additions & 5 deletions EuriaFeatures/OnboardingView/LoginHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,16 @@ import InterAppLogin
import SwiftUI

@MainActor
final class LoginHandler: InfomaniakLoginDelegate, ObservableObject {
public final class LoginHandler: InfomaniakLoginDelegate, ObservableObject {
@LazyInjectService private var loginService: InfomaniakLoginable
@LazyInjectService private var tokenService: InfomaniakNetworkLoginable
@LazyInjectService private var accountManager: AccountManagerable

@Published var isLoading = false
@Published var error: ErrorDomain?

public init() {}

enum ErrorDomain: Error, LocalizedError, Equatable {
case loginFailed(error: Error)
case genericError
Expand All @@ -63,17 +65,17 @@ final class LoginHandler: InfomaniakLoginDelegate, ObservableObject {
}
}

func didCompleteLoginWith(code: String, verifier: String) {
public func didCompleteLoginWith(code: String, verifier: String) {
Task {
try await loginSuccessful(code: code, codeVerifier: verifier)
}
}

func didFailLoginWith(error: any Error) {
public func didFailLoginWith(error: any Error) {
loginFailed(error: error)
}

func loginAfterAccountCreation(from viewController: UIViewController) {
public func loginAfterAccountCreation(from viewController: UIViewController) {
isLoading = true
defer { isLoading = false }

Expand All @@ -88,7 +90,7 @@ final class LoginHandler: InfomaniakLoginDelegate, ObservableObject {
loginService.webviewLoginFrom(viewController: viewController, hideCreateAccountButton: true, delegate: self)
}

func login() async {
public func login() async {
isLoading = true
defer { isLoading = false }

Expand Down
45 changes: 34 additions & 11 deletions EuriaFeatures/OnboardingView/OnboardingBottomButtonsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import AuthenticationServices
import DesignSystem
import EuriaCore
import EuriaCoreUI
import EuriaResources
import InfomaniakCoreUIResources
import InfomaniakCreateAccount
Expand All @@ -28,31 +29,43 @@ import InterAppLogin
import SwiftUI

struct OnboardingBottomButtonsView: View {
@InjectService var accountManager: AccountManagerable
@InjectService var connectedAccountsManager: ConnectedAccountManagerable

@EnvironmentObject private var rootViewState: RootViewState

@ObservedObject var loginHandler = LoginHandler()

@State private var excludedUserIds: [AccountManagerable.UserId] = []
@State private var isPresentingCreateAccount = false
@State private var isPresentingInterAppLogin = false

@Binding var selection: Int

let slideCount: Int
var showButtonStartOnly = false

private var isLastSlide: Bool {
return selection == slideCount - 1
}

var body: some View {
VStack(spacing: IKPadding.mini) {
ContinueWithAccountView(
isLoading: loginHandler.isLoading,
excludingUserIds: excludedUserIds,
allowsMultipleSelection: false
) {
loginPressed()
} onLoginWithAccountsPressed: { accounts in
loginWithAccountsPressed(accounts: accounts)
} onCreateAccountPressed: {
isPresentingCreateAccount = true
if showButtonStartOnly && !isPresentingInterAppLogin {
Button(EuriaResourcesStrings.buttonStart, action: openGuestSession)
.buttonStyle(.ikBorderedProminent)
} else {
ContinueWithAccountView(
isLoading: loginHandler.isLoading,
excludingUserIds: excludedUserIds,
allowsMultipleSelection: false
) {
loginPressed()
} onLoginWithAccountsPressed: { accounts in
loginWithAccountsPressed(accounts: accounts)
} onCreateAccountPressed: {
isPresentingCreateAccount = true
}
}
}
.ikButtonFullWidth(true)
Expand Down Expand Up @@ -81,8 +94,11 @@ struct OnboardingBottomButtonsView: View {
}
}
.task {
@InjectService var accountManager: AccountManagerable
excludedUserIds = await accountManager.getAccountIds()
let accounts = await connectedAccountsManager.listAllLocalAccounts()
if !accounts.isEmpty {
isPresentingInterAppLogin = true
}
}
}

Expand All @@ -92,6 +108,13 @@ struct OnboardingBottomButtonsView: View {
}
}

private func openGuestSession() {
Task {
let currentSession = await accountManager.createGuestAccount()
rootViewState.transition(toState: .mainView(MainViewState(userSession: currentSession)))
}
}

private func loginWithAccountsPressed(accounts: [ConnectedAccount]) {
Task {
await loginHandler.loginWith(accounts: accounts)
Expand Down
3 changes: 2 additions & 1 deletion EuriaFeatures/OnboardingView/OnboardingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ public struct OnboardingView: View {
WaveView(slides: slides, selectedSlide: $selectedSlideIndex) { slideIndex in
slideIndex == slides.count - 1 || (slideIndex == slides.count - 2 && selectedSlideIndex == slides.count - 1)
} bottomView: { _ in
OnboardingBottomButtonsView(loginHandler: loginHandler, selection: $selectedSlideIndex, slideCount: slides.count)
OnboardingBottomButtonsView(loginHandler: loginHandler, selection: $selectedSlideIndex,
slideCount: slides.count, showButtonStartOnly: true)
}
.appBackground()
.ignoresSafeArea()
Expand Down
7 changes: 5 additions & 2 deletions EuriaResources/Localizable/de.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Project: Euria
* Locale: de, German
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Tue, 11 Nov 2025 13:46:09 +0100
* Exported by: Baptiste Griva
* Exported at: Wed, 26 Nov 2025 15:27:09 +0100
*/

/* loco:68ff77d06bd131d99b010d73 */
Expand All @@ -13,6 +13,9 @@
/* loco:68ff4981634f6375880c8ba2 */
"buttonLogin" = "Anmeldung";

/* loco:69270bbbe4fa8bf1fe0d5ee5 */
"buttonStart" = "Starten";

/* loco:68ff7cb3182d19eb830448e3 */
"connectionError" = "Problem mit der Internetverbindung";

Expand Down
7 changes: 5 additions & 2 deletions EuriaResources/Localizable/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Project: Euria
* Locale: en, English
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Tue, 11 Nov 2025 13:46:09 +0100
* Exported by: Baptiste Griva
* Exported at: Wed, 26 Nov 2025 15:27:09 +0100
*/

/* loco:68ff77d06bd131d99b010d73 */
Expand All @@ -13,6 +13,9 @@
/* loco:68ff4981634f6375880c8ba2 */
"buttonLogin" = "Login";

/* loco:69270bbbe4fa8bf1fe0d5ee5 */
"buttonStart" = "Start";

/* loco:68ff7cb3182d19eb830448e3 */
"connectionError" = "Internet connection problem";

Expand Down
7 changes: 5 additions & 2 deletions EuriaResources/Localizable/es.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Project: Euria
* Locale: es, Spanish
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Tue, 11 Nov 2025 13:46:09 +0100
* Exported by: Baptiste Griva
* Exported at: Wed, 26 Nov 2025 15:27:09 +0100
*/

/* loco:68ff77d06bd131d99b010d73 */
Expand All @@ -13,6 +13,9 @@
/* loco:68ff4981634f6375880c8ba2 */
"buttonLogin" = "Inicio de sesión";

/* loco:69270bbbe4fa8bf1fe0d5ee5 */
"buttonStart" = "Empezar";

/* loco:68ff7cb3182d19eb830448e3 */
"connectionError" = "Problema de conexión a Internet";

Expand Down
7 changes: 5 additions & 2 deletions EuriaResources/Localizable/fr.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Project: Euria
* Locale: fr, French
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Tue, 11 Nov 2025 13:46:09 +0100
* Exported by: Baptiste Griva
* Exported at: Wed, 26 Nov 2025 15:27:09 +0100
*/

/* loco:68ff77d06bd131d99b010d73 */
Expand All @@ -13,6 +13,9 @@
/* loco:68ff4981634f6375880c8ba2 */
"buttonLogin" = "Connexion";

/* loco:69270bbbe4fa8bf1fe0d5ee5 */
"buttonStart" = "Commencer";

/* loco:68ff7cb3182d19eb830448e3 */
"connectionError" = "Problème de connexion à Internet";

Expand Down
7 changes: 5 additions & 2 deletions EuriaResources/Localizable/it.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
* Project: Euria
* Locale: it, Italian
* Tagged: ios
* Exported by: Valentin Perignon
* Exported at: Tue, 11 Nov 2025 13:46:09 +0100
* Exported by: Baptiste Griva
* Exported at: Wed, 26 Nov 2025 15:27:09 +0100
*/

/* loco:68ff77d06bd131d99b010d73 */
Expand All @@ -13,6 +13,9 @@
/* loco:68ff4981634f6375880c8ba2 */
"buttonLogin" = "Accesso";

/* loco:69270bbbe4fa8bf1fe0d5ee5 */
"buttonStart" = "Inizia";

/* loco:68ff7cb3182d19eb830448e3 */
"connectionError" = "Problema di connessione a Internet";

Expand Down
Loading
Loading