FF for QR code login + Login with qr code button (#2643)

This commit is contained in:
Mauro
2024-04-04 10:37:42 +02:00
committed by GitHub
parent 3fea635d67
commit df242e3f1c
14 changed files with 70 additions and 25 deletions
@@ -54,6 +54,7 @@ final class AppSettings {
case markAsFavouriteEnabled case markAsFavouriteEnabled
case roomModerationEnabled case roomModerationEnabled
case publicSearchEnabled case publicSearchEnabled
case qrCodeLoginEnabled
} }
private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
@@ -287,6 +288,9 @@ final class AppSettings {
@UserPreference(key: UserDefaultsKeys.publicSearchEnabled, defaultValue: false, storageType: .volatile) @UserPreference(key: UserDefaultsKeys.publicSearchEnabled, defaultValue: false, storageType: .volatile)
var publicSearchEnabled var publicSearchEnabled
@UserPreference(key: UserDefaultsKeys.qrCodeLoginEnabled, defaultValue: false, storageType: .userDefaults(store))
var qrCodeLoginEnabled
#endif #endif
// MARK: - Shared // MARK: - Shared
@@ -80,15 +80,18 @@ class AuthenticationFlowCoordinator: FlowCoordinatorProtocol {
// MARK: - Private // MARK: - Private
private func showStartScreen() { private func showStartScreen() {
let coordinator = AuthenticationStartScreenCoordinator() let coordinator = AuthenticationStartScreenCoordinator(parameters: .init(appSettings: appSettings))
coordinator.actions coordinator.actions
.sink { [weak self] action in .sink { [weak self] action in
guard let self else { return } guard let self else { return }
switch action { switch action {
case .login: case .loginManually:
Task { await self.startAuthentication() } Task { await self.startAuthentication() }
case .loginWithQR:
// TODO: Implement QR code login navigation
break
case .reportProblem: case .reportProblem:
showReportProblemScreen() showReportProblemScreen()
} }
@@ -125,6 +125,7 @@ enum A11yIdentifiers {
struct AuthenticationStartScreen { struct AuthenticationStartScreen {
let signIn = "authentication_start-sign_in" let signIn = "authentication_start-sign_in"
let signInWithQr = "authentication_start-sign_in_with_qr"
let hidden = "authentication_start-hidden" let hidden = "authentication_start-hidden"
} }
@@ -17,6 +17,10 @@
import Combine import Combine
import SwiftUI import SwiftUI
struct AuthenticationStartScreenCoordinatorParameters {
let appSettings: AppSettings
}
final class AuthenticationStartScreenCoordinator: CoordinatorProtocol { final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
private var viewModel: AuthenticationStartScreenViewModelProtocol private var viewModel: AuthenticationStartScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<AuthenticationStartScreenCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<AuthenticationStartScreenCoordinatorAction, Never> = .init()
@@ -26,8 +30,8 @@ final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init() { init(parameters: AuthenticationStartScreenCoordinatorParameters) {
viewModel = AuthenticationStartScreenViewModel() viewModel = AuthenticationStartScreenViewModel(appSettings: parameters.appSettings)
} }
// MARK: - Public // MARK: - Public
@@ -38,8 +42,10 @@ final class AuthenticationStartScreenCoordinator: CoordinatorProtocol {
guard let self else { return } guard let self else { return }
switch action { switch action {
case .login: case .loginManually:
actionsSubject.send(.login) actionsSubject.send(.loginManually)
case .loginWithQR:
actionsSubject.send(.loginWithQR)
case .reportProblem: case .reportProblem:
actionsSubject.send(.reportProblem) actionsSubject.send(.reportProblem)
} }
@@ -19,18 +19,23 @@ import SwiftUI
// MARK: - Coordinator // MARK: - Coordinator
enum AuthenticationStartScreenCoordinatorAction { enum AuthenticationStartScreenCoordinatorAction {
case login case loginManually
case loginWithQR
case reportProblem case reportProblem
} }
enum AuthenticationStartScreenViewModelAction { enum AuthenticationStartScreenViewModelAction {
case login case loginManually
case loginWithQR
case reportProblem case reportProblem
} }
struct AuthenticationStartScreenViewState: BindableState { } struct AuthenticationStartScreenViewState: BindableState {
var isQRCodeLoginEnabled = false
}
enum AuthenticationStartScreenViewAction { enum AuthenticationStartScreenViewAction {
case login case loginManually
case loginWithQR
case reportProblem case reportProblem
} }
@@ -20,20 +20,27 @@ import SwiftUI
typealias AuthenticationStartScreenViewModelType = StateStoreViewModel<AuthenticationStartScreenViewState, AuthenticationStartScreenViewAction> typealias AuthenticationStartScreenViewModelType = StateStoreViewModel<AuthenticationStartScreenViewState, AuthenticationStartScreenViewAction>
class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType, AuthenticationStartScreenViewModelProtocol { class AuthenticationStartScreenViewModel: AuthenticationStartScreenViewModelType, AuthenticationStartScreenViewModelProtocol {
private let appSettings: AppSettings
private var actionsSubject: PassthroughSubject<AuthenticationStartScreenViewModelAction, Never> = .init() private var actionsSubject: PassthroughSubject<AuthenticationStartScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<AuthenticationStartScreenViewModelAction, Never> { var actions: AnyPublisher<AuthenticationStartScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init() { init(appSettings: AppSettings) {
self.appSettings = appSettings
super.init(initialViewState: AuthenticationStartScreenViewState()) super.init(initialViewState: AuthenticationStartScreenViewState())
appSettings.$qrCodeLoginEnabled
.weakAssign(to: \.state.isQRCodeLoginEnabled, on: self)
.store(in: &cancellables)
} }
override func process(viewAction: AuthenticationStartScreenViewAction) { override func process(viewAction: AuthenticationStartScreenViewAction) {
switch viewAction { switch viewAction {
case .login: case .loginManually:
actionsSubject.send(.login) actionsSubject.send(.loginManually)
case .loginWithQR:
actionsSubject.send(.loginWithQR)
case .reportProblem: case .reportProblem:
actionsSubject.send(.reportProblem) actionsSubject.send(.reportProblem)
} }
@@ -94,9 +94,17 @@ struct AuthenticationStartScreen: View {
/// The main action buttons. /// The main action buttons.
var buttons: some View { var buttons: some View {
VStack(spacing: 12) { VStack(spacing: 16) {
Button { context.send(viewAction: .login) } label: { if context.viewState.isQRCodeLoginEnabled {
Text(L10n.actionContinue) Button { context.send(viewAction: .loginManually) } label: {
Label(L10n.screenOnboardingSignInWithQrCode, icon: \.qrCode)
}
.buttonStyle(.compound(.primary))
.accessibilityIdentifier(A11yIdentifiers.authenticationStartScreen.signInWithQr)
}
Button { context.send(viewAction: .loginManually) } label: {
Text(context.viewState.isQRCodeLoginEnabled ? L10n.screenOnboardingSignInManually : L10n.actionContinue)
} }
.buttonStyle(.compound(.primary)) .buttonStyle(.compound(.primary))
.accessibilityIdentifier(A11yIdentifiers.authenticationStartScreen.signIn) .accessibilityIdentifier(A11yIdentifiers.authenticationStartScreen.signIn)
@@ -109,7 +117,10 @@ struct AuthenticationStartScreen: View {
// MARK: - Previews // MARK: - Previews
struct AuthenticationStartScreen_Previews: PreviewProvider, TestablePreview { struct AuthenticationStartScreen_Previews: PreviewProvider, TestablePreview {
static let viewModel = AuthenticationStartScreenViewModel() static let viewModel = {
ServiceLocator.shared.settings.qrCodeLoginEnabled = true
return AuthenticationStartScreenViewModel(appSettings: ServiceLocator.shared.settings)
}()
static var previews: some View { static var previews: some View {
AuthenticationStartScreen(context: viewModel.context) AuthenticationStartScreen(context: viewModel.context)
@@ -51,6 +51,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
var roomModerationEnabled: Bool { get set } var roomModerationEnabled: Bool { get set }
var elementCallBaseURL: URL { get set } var elementCallBaseURL: URL { get set }
var publicSearchEnabled: Bool { get set } var publicSearchEnabled: Bool { get set }
var qrCodeLoginEnabled: Bool { get set }
} }
extension AppSettings: DeveloperOptionsProtocol { } extension AppSettings: DeveloperOptionsProtocol { }
@@ -53,6 +53,12 @@ struct DeveloperOptionsScreen: View {
} }
} }
Section("QR Code") {
Toggle(isOn: $context.qrCodeLoginEnabled) {
Text("QR code login")
}
}
Section("Element Call") { Section("Element Call") {
TextField(context.elementCallBaseURL.absoluteString, text: $elementCallBaseURLString) TextField(context.elementCallBaseURL.absoluteString, text: $elementCallBaseURLString)
.submitLabel(.done) .submitLabel(.done)
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:6e28c5cbf66f7166b6cce05acdef3da61c396aab82a2648b36cc1995c4538c52 oid sha256:5db96b5725e55787e772dda0698e7d2d9c9c33b33e56a3746905582a4fe7c567
size 1320362 size 1299604
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:5ca6c56a318aac4e14429770b14e1a068c6028dbbdae614065ce756569a2c513 oid sha256:ac5c752f55f6a5102ea8cb964aaad872e66636c98e84ba921a04c19f54fbfe27
size 1373995 size 1360762
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:75c51f7fd3ca983ef9906c7208238f00b053a68f7b5f81d9eea7623eecaac1a4 oid sha256:71a18a8153f97586c0c8ceb6d02bbade1522a1b82509dc47106617a28f829bcf
size 549598 size 551048
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1 version https://git-lfs.github.com/spec/v1
oid sha256:2e1e82e135acc71f6cfd30b3dd9274e5aa83226f120c938fab87692581a7a36f oid sha256:ab7ba10a2568b1b39f8f1fd27bdd1d1c4f66019c5c182b7bbcdbae65119c9f2d
size 598130 size 601043
+1
View File
@@ -0,0 +1 @@
Added an FF for QR code login, and a CTA in the auth screen, to start the flow.