Merge branch 'feature/4231_add_new_loginflow' into 'develop'

MESSENGER-4231 add new loginflow

See merge request bwmessenger/bundesmessenger/bundesmessenger-ios!98
This commit is contained in:
Arnfried Griesert
2023-03-02 13:09:34 +00:00
12 changed files with 182 additions and 36 deletions
@@ -33,6 +33,8 @@ enum AuthenticationLoginViewModelResult: CustomStringConvertible {
case fallback
/// Continue with QR login
case qrLogin
/// bwi: register info
case register
/// A string representation of the result, ignoring any associated values that could leak PII.
var description: String {
@@ -51,6 +53,8 @@ enum AuthenticationLoginViewModelResult: CustomStringConvertible {
return "fallback"
case .qrLogin:
return "qrLogin"
case .register:
return "register"
}
}
}
@@ -112,6 +116,8 @@ enum AuthenticationLoginViewAction {
case continueWithSSO(SSOIdentityProvider)
/// Continue using QR login
case qrLogin
/// bwi: register info
case register
}
enum AuthenticationLoginErrorType: Hashable {
@@ -52,6 +52,8 @@ class AuthenticationLoginViewModel: AuthenticationLoginViewModelType, Authentica
Task { await callback?(.continueWithSSO(provider)) }
case .qrLogin:
Task { await callback?(.qrLogin) }
case .register:
Task { await callback?(.register) }
}
}
@@ -78,4 +80,20 @@ class AuthenticationLoginViewModel: AuthenticationLoginViewModelType, Authentica
state.bindings.alertInfo = AlertInfo(id: type)
}
}
// bwi: show custom alert
@MainActor func displayInfoAlert(_ type: AuthenticationLoginViewAction) {
switch type {
case .forgotPassword:
state.bindings.alertInfo = AlertInfo(id: .unknown,
title: BWIL10n.authForgotPassword,
message: BWIL10n.bwiAuthForgotPasswordAlertText)
case .register:
state.bindings.alertInfo = AlertInfo(id: .unknown,
title: BWIL10n.bwiAuthRegisterAlertTitle,
message: BWIL10n.bwiAuthRegisterAlertText)
default:
return
}
}
}
@@ -31,4 +31,8 @@ protocol AuthenticationLoginViewModelProtocol {
/// Display an error to the user.
/// - Parameter type: The type of error to be displayed.
@MainActor func displayError(_ type: AuthenticationLoginErrorType)
/// bwi: Display an info alert.
/// - Parameter type: The type of the message to be displayed.
@MainActor func displayInfoAlert(_ type: AuthenticationLoginViewAction)
}
@@ -123,7 +123,12 @@ final class AuthenticationLoginCoordinator: Coordinator, Presentable {
case .parseUsername(let username):
self.parseUsername(username)
case .forgotPassword:
self.showForgotPasswordScreen()
// bwi: show info alert
if BWIBuildSettings.shared.forgotPasswordInformationAlert {
self.authenticationLoginViewModel.displayInfoAlert(.forgotPassword)
} else {
self.showForgotPasswordScreen()
}
case .login(let username, let password):
self.login(username: username, password: password)
case .continueWithSSO(let identityProvider):
@@ -132,6 +137,9 @@ final class AuthenticationLoginCoordinator: Coordinator, Presentable {
self.callback?(.fallback)
case .qrLogin:
self.showQRLoginScreen()
case .register:
// bwi: show info alert
self.authenticationLoginViewModel.displayInfoAlert(.register)
}
}
}
@@ -20,6 +20,9 @@ struct AuthenticationLoginScreen: View {
// MARK: - Properties
// MARK: Private
private enum CustomText {
case username, submit
}
@Environment(\.theme) private var theme: ThemeSwiftUI
@@ -35,8 +38,8 @@ struct AuthenticationLoginScreen: View {
VStack {
ScrollView {
VStack(spacing: 0) {
if BWIBuildSettings.shared.bumLoginFlowLayout {
ServerIcon(image: Asset.SharedImages.loginFlowLogo, size: OnboardingMetrics.iconSize)
if BWIBuildSettings.shared.bumLoginFlowLayout || BWIBuildSettings.shared.bwiLoginFlowLayout {
ServerIcon(image: getServerIcon(), size: OnboardingMetrics.iconSize)
.padding(.top, OnboardingMetrics.topPaddingToNavigationBar)
.padding(.bottom, 16)
} else {
@@ -45,14 +48,19 @@ struct AuthenticationLoginScreen: View {
.padding(.bottom, 28)
}
serverInfo
.padding(.leading, 12)
.padding(.bottom, 16)
if !BWIBuildSettings.shared.bwiLoginFlowLayout {
serverInfo
.padding(.leading, 12)
.padding(.bottom, 16)
Rectangle()
.fill(theme.colors.quinaryContent)
.frame(height: 1)
.padding(.bottom, 22)
Rectangle()
.fill(theme.colors.quinaryContent)
.frame(height: 1)
.padding(.bottom, 22)
} else {
// bwi: show cutom header
authLoginHeaderlineText
}
if BWIBuildSettings.shared.bumLoginFlowLayout {
loginDescription
@@ -115,7 +123,7 @@ struct AuthenticationLoginScreen: View {
/// The form with text fields for username and password, along with a submit button.
var loginForm: some View {
VStack(spacing: 14) {
RoundedBorderTextField(placeHolder: BWIL10n.authenticationLoginUsername,
RoundedBorderTextField(placeHolder: getCustomText(text: .username),
text: $viewModel.username,
isFirstResponder: false,
configuration: UIKitTextInputConfiguration(returnKeyType: .next,
@@ -134,8 +142,8 @@ struct AuthenticationLoginScreen: View {
onEditingChanged: passwordEditingChanged,
onCommit: submit)
.accessibilityIdentifier("passwordTextField")
if !BWIBuildSettings.shared.bumLoginFlowLayout {
// bwi: hide nv forgot password button
if !BWIBuildSettings.shared.bumLoginFlowLayout && !BWIBuildSettings.shared.bwiLoginFlowLayout {
Button { viewModel.send(viewAction: .forgotPassword) } label: {
Text(VectorL10n.authenticationLoginForgotPassword)
.font(theme.fonts.body)
@@ -145,11 +153,20 @@ struct AuthenticationLoginScreen: View {
}
Button(action: submit) {
Text(VectorL10n.next)
Text(getCustomText(text: .submit))
}
.buttonStyle(PrimaryActionButtonStyle())
.disabled(!viewModel.viewState.canSubmit)
.accessibilityIdentifier("nextButton")
.padding([.vertical], BWIBuildSettings.shared.bwiLoginFlowLayout ? 36 : 0)
if BWIBuildSettings.shared.authScreenShowForgotPassword {
forgotPasswordButton
}
if BWIBuildSettings.shared.bwiEnableRegisterInfo {
registerButton
}
}
}
@@ -239,6 +256,59 @@ struct AuthenticationLoginScreen: View {
func qrLogin() {
viewModel.send(viewAction: .qrLogin)
}
// bwi: custom forgot password button
var forgotPasswordButton: some View {
Button {
viewModel.send(viewAction: .forgotPassword)
} label: {
Text(BWIL10n.authForgotPassword)
.font(theme.fonts.body)
}
.frame(maxWidth: .infinity, alignment: .center)
.padding(.bottom, 8)
}
// bwi: custom register button
var registerButton: some View {
Button {
viewModel.send(viewAction: .register)
} label: {
Text(BWIL10n.bwiAuthRegisterButtonTitle)
.font(theme.fonts.body)
}
.frame(maxWidth: .infinity, alignment: .center)
.padding(.bottom, 8)
}
// bwi: custom header
var authLoginHeaderlineText: some View {
VStack(alignment: .leading) {
Text(BWIL10n.authLoginHeadlineText)
.font(theme.fonts.body)
.foregroundColor(theme.colors.primaryContent)
Text(BWIL10n.authLoginSubheadlineText)
.font(theme.fonts.subheadline)
.foregroundColor(theme.colors.secondaryContent)
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding([.vertical], 36)
}
// bwi: get app specific ServerIcon
func getServerIcon() -> ImageAsset {
return BWIBuildSettings.shared.bwiLoginFlowLayout ? Asset.Images.launchScreenLogo : Asset.SharedImages.loginFlowLogo
}
// bwi: get app specific text
private func getCustomText(text: CustomText) -> String {
switch text {
case .submit:
return BWIBuildSettings.shared.bwiLoginFlowLayout ? BWIL10n.authenticationServerSelectionSubmitButtonTitle : VectorL10n.next
case .username:
return BWIBuildSettings.shared.bwiLoginFlowLayout ? BWIL10n.authUserIdPlaceholder : BWIL10n.authenticationLoginUsername
}
}
}
// MARK: - Previews
@@ -67,6 +67,9 @@ struct AuthenticationServerSelectionScreen: View {
message: Text(BWIL10n.authenticationServerSelectionServerDeniedMessage),
dismissButton: .default(Text(VectorL10n.ok)))
}
if BWIBuildSettings.shared.authScreenShowTestServerOptions {
serverSelectionButton
}
}
.readableFrame()
.padding(.horizontal, 16)
@@ -221,6 +224,24 @@ struct AuthenticationServerSelectionScreen: View {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
// bwi: show server selection button
var serverSelectionButton: some View {
VStack() {
Menu(content: {
ForEach(ServerURLHelper.shared.serverSettings, id: \.self) { server in
Button(server.name, action: {
viewModel.homeserverAddress = server.serverUrl
})
}
}, label: {
Button(action: { return }) {
Text(BWIL10n.bwiAuthBetaSelectionButtonTitle)
}
.buttonStyle(PrimaryActionButtonStyle())
})
}
}
}