diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailModels.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailModels.swift index 805b77954..28e4a612f 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailModels.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailModels.swift @@ -25,6 +25,8 @@ enum AuthenticationVerifyEmailViewModelResult { case resend /// Cancel the flow. case cancel + /// Go back to the email form + case goBack } // MARK: View @@ -65,6 +67,8 @@ enum AuthenticationVerifyEmailViewAction { case resend /// Cancel the flow. case cancel + /// Go back to enter email adress screen + case goBack } enum AuthenticationVerifyEmailErrorType: Hashable { diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModel.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModel.swift index ec07b3532..e28ac99e9 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModel.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModel.swift @@ -46,12 +46,18 @@ class AuthenticationVerifyEmailViewModel: AuthenticationVerifyEmailViewModelType Task { await callback?(.resend) } case .cancel: Task { await callback?(.cancel) } + case .goBack: + Task { await callback?(.goBack) } } } @MainActor func updateForSentEmail() { state.hasSentEmail = true } + + @MainActor func goBackToEnterEmailForm() { + state.hasSentEmail = false + } @MainActor func displayError(_ type: AuthenticationVerifyEmailErrorType) { switch type { diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModelProtocol.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModelProtocol.swift index cd4fd433e..1c72824e5 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModelProtocol.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/AuthenticationVerifyEmailViewModelProtocol.swift @@ -23,6 +23,9 @@ protocol AuthenticationVerifyEmailViewModelProtocol { /// Updates the view to reflect that a verification email was successfully sent. @MainActor func updateForSentEmail() + + /// Goes back to the email form + @MainActor func goBackToEnterEmailForm() /// Display an error to the user. @MainActor func displayError(_ type: AuthenticationVerifyEmailErrorType) diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/Coordinator/AuthenticationVerifyEmailCoordinator.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/Coordinator/AuthenticationVerifyEmailCoordinator.swift index c214d0e8a..dcc2eea4e 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/Coordinator/AuthenticationVerifyEmailCoordinator.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/Coordinator/AuthenticationVerifyEmailCoordinator.swift @@ -91,6 +91,8 @@ final class AuthenticationVerifyEmailCoordinator: Coordinator, Presentable { self.resendEmail() case .cancel: self.callback?(.cancel) + case .goBack: + self.authenticationVerifyEmailViewModel.goBackToEnterEmailForm() } } } diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/UI/AuthenticationVerifyEmailUITests.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/UI/AuthenticationVerifyEmailUITests.swift index 0992d2cd7..3913539c7 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/UI/AuthenticationVerifyEmailUITests.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/UI/AuthenticationVerifyEmailUITests.swift @@ -53,6 +53,10 @@ class AuthenticationVerifyEmailUITests: MockScreenTest { XCTAssertFalse(app.staticTexts["waitingTitleLabel"].exists, "The waiting title should be hidden until an email is sent.") XCTAssertFalse(app.staticTexts["waitingMessageLabel"].exists, "The waiting message should be hidden until an email is sent.") + + let cancelButton = app.navigationBars.firstMatch.buttons["cancelButton"] + XCTAssertTrue(cancelButton.exists, "Cancel button should be shown.") + XCTAssertEqual(cancelButton.label, "Cancel") } func verifyEnteredAddress() { @@ -69,6 +73,10 @@ class AuthenticationVerifyEmailUITests: MockScreenTest { XCTAssertFalse(app.staticTexts["waitingTitleLabel"].exists, "The waiting title should be hidden until an email is sent.") XCTAssertFalse(app.staticTexts["waitingMessageLabel"].exists, "The waiting message should be hidden until an email is sent.") + + let cancelButton = app.navigationBars.firstMatch.buttons["cancelButton"] + XCTAssertTrue(cancelButton.exists, "Cancel button should be shown.") + XCTAssertEqual(cancelButton.label, "Cancel") } func verifyWaitingForEmailLink() { @@ -79,6 +87,10 @@ class AuthenticationVerifyEmailUITests: MockScreenTest { XCTAssertTrue(app.staticTexts["waitingTitleLabel"].exists, "The waiting title should be shown once an email has been sent.") XCTAssertTrue(app.staticTexts["waitingMessageLabel"].exists, "The waiting title should be shown once an email has been sent.") + + let backButton = app.navigationBars.firstMatch.buttons["cancelButton"] + XCTAssertTrue(backButton.exists, "Back button should be shown.") + XCTAssertEqual(backButton.label, "Back") } } diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/Unit/AuthenticationVerifyEmailViewModelTests.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/Unit/AuthenticationVerifyEmailViewModelTests.swift index 24b4ed9ed..fa2acc2e4 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/Unit/AuthenticationVerifyEmailViewModelTests.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/Test/Unit/AuthenticationVerifyEmailViewModelTests.swift @@ -19,10 +19,7 @@ import XCTest @testable import RiotSwiftUI class AuthenticationVerifyEmailViewModelTests: XCTestCase { - private enum Constants { - static let counterInitialValue = 0 - } - + var viewModel: AuthenticationVerifyEmailViewModelProtocol! var context: AuthenticationVerifyEmailViewModelType.Context! @@ -31,15 +28,22 @@ class AuthenticationVerifyEmailViewModelTests: XCTestCase { context = viewModel.context } - func testSentEmailState() async { + @MainActor func testSentEmailState() async { // Given a view model where the user hasn't yet sent the verification email. XCTAssertFalse(context.viewState.hasSentEmail, "The view model should start with hasSentEmail equal to false.") // When updating to indicate that an email has been send. - let task = Task { await viewModel.updateForSentEmail() } - _ = await task.result + viewModel.updateForSentEmail() // Then the view model should update to reflect a sent email. XCTAssertTrue(context.viewState.hasSentEmail, "The view model should update hasSentEmail after sending an email.") } + + @MainActor func testGoBack() async { + viewModel.updateForSentEmail() + + viewModel.goBackToEnterEmailForm() + + XCTAssertFalse(context.viewState.hasSentEmail, "The view model should update hasSentEmail after going back.") + } } diff --git a/RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailScreen.swift b/RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailScreen.swift index 5ad70a4fb..eb654d712 100644 --- a/RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailScreen.swift +++ b/RiotSwiftUI/Modules/Authentication/VerifyEmail/View/AuthenticationVerifyEmailScreen.swift @@ -137,9 +137,14 @@ struct AuthenticationVerifyEmailScreen: View { /// A simple toolbar with a cancel button. var toolbar: some ToolbarContent { ToolbarItem(placement: .cancellationAction) { - Button(VectorL10n.cancel) { - viewModel.send(viewAction: .cancel) + Button(viewModel.viewState.hasSentEmail ? VectorL10n.back : VectorL10n.cancel) { + if viewModel.viewState.hasSentEmail { + viewModel.send(viewAction: .goBack) + } else { + viewModel.send(viewAction: .cancel) + } } + .accessibilityIdentifier("cancelButton") } } }