MESSENGER-3895 qr code login

This commit is contained in:
Arnfried Griesert
2023-02-08 12:19:07 +00:00
committed by Frank Rotermund
parent fd8ab8e648
commit d7a23d53dc
15 changed files with 294 additions and 20 deletions
@@ -15,6 +15,7 @@
//
import SwiftUI
import AVKit
struct AuthenticationServerSelectionScreen: View {
// MARK: - Properties
@@ -23,8 +24,12 @@ struct AuthenticationServerSelectionScreen: View {
@Environment(\.theme) private var theme
@State private var showAlertForMissingCameraAuthorization = false
@State private var showAlertForInvalidServer = false
@State private var isEditingTextField = false
@State private var presentQRCodeScanner = false
@State private var qrCode = ""
private var textFieldFooterColor: Color {
viewModel.viewState.hasValidationError ? theme.colors.alert : theme.colors.tertiaryContent
}
@@ -38,31 +43,67 @@ struct AuthenticationServerSelectionScreen: View {
var body: some View {
GeometryReader { _ in
ScrollView {
VStack(spacing: 0) {
VStack(spacing: 8) {
header
.padding(.top, OnboardingMetrics.topPaddingToNavigationBar)
.padding(.bottom, 36)
.padding(.bottom, 16)
if BWIBuildSettings.shared.scanServerQRCode {
scanButton
}
serverForm
}
.readableFrame()
.padding(.horizontal, 16)
}
.alert(isPresented: $showAlertForInvalidServer) {
Alert(
title: Text(BWIL10n.authenticationServerSelectionServerDeniedTitle),
message: Text(BWIL10n.authenticationServerSelectionServerDeniedMessage),
dismissButton: .default(Text(VectorL10n.ok)))
}
}
.background(theme.colors.background.ignoresSafeArea())
.toolbar { toolbar }
.alert(item: $viewModel.alertInfo) { $0.alert }
.alert(isPresented: $showAlertForMissingCameraAuthorization) {
Alert(
title: Text(BWIL10n.authenticationServerSelectionQrMissingAuthorizationTitle),
message: Text(BWIL10n.authenticationServerSelectionQrMissingAuthorizationMessage),
primaryButton: .default(Text(VectorL10n.settingsTitle), action: openSettingsApp),
secondaryButton: .cancel())
}
.alert(isPresented: $showAlertForInvalidServer) {
Alert(
title: Text(BWIL10n.authenticationServerSelectionServerDeniedTitle),
message: Text(BWIL10n.authenticationServerSelectionServerDeniedMessage),
dismissButton: .default(Text(VectorL10n.ok)))
}
.accentColor(theme.colors.accent)
.sheet(isPresented: $presentQRCodeScanner) {
AuthenticationServerSelectionQRCodeScanner(qrCode: $qrCode)
}
.onChange(of: qrCode) { newValue in
if !qrCode.isEmpty {
viewModel.homeserverAddress = qrCode
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
self.submit()
}
}
}
}
/// The title, message and icon at the top of the screen.
var header: some View {
VStack(spacing: 8) {
if BWIBuildSettings.shared.bumLoginFlowLayout {
ServerIcon(image: Asset.Images.welcomeExperience1, size: OnboardingMetrics.iconSize)
ServerIcon(image: Asset.SharedImages.loginFlowLogo, size: OnboardingMetrics.iconSize)
.padding(.bottom, 16)
} else {
OnboardingIconImage(image: Asset.Images.welcomeExperience1)
.padding(.bottom, 8)
.padding(.bottom, 16)
}
Text(viewModel.viewState.headerTitle)
@@ -79,6 +120,28 @@ struct AuthenticationServerSelectionScreen: View {
}
}
var scanButton: some View {
VStack(spacing: 8) {
Button {
if AVCaptureDevice.authorizationStatus(for: .video) == .denied {
showAlertForMissingCameraAuthorization = true
} else {
qrCode = ""
presentQRCodeScanner = true
}
} label: {
Text(viewModel.viewState.scanCodeButtonTitle)
}
.buttonStyle(PrimaryActionButtonStyle())
.accessibilityIdentifier("qrCodeButton")
Text(VectorL10n.or)
.foregroundColor(theme.colors.secondaryContent)
.padding(5)
}
}
/// The text field and confirm button where the user enters a server URL.
var serverForm: some View {
VStack(alignment: .leading, spacing: 12) {
@@ -136,10 +199,34 @@ struct AuthenticationServerSelectionScreen: View {
}
/// Sends the `confirm` view action so long as the text field input is valid.
func submit() {
private func submit() {
guard !viewModel.viewState.hasValidationError else { return }
viewModel.send(viewAction: .confirm)
if isHomeserverAddressValid(viewModel.homeserverAddress) {
viewModel.send(viewAction: .confirm)
} else {
showAlertForInvalidServer = true
}
}
private func isHomeserverAddressValid(_ homeserverAddress: String) -> Bool {
if BWIBuildSettings.shared.bwiEnableLoginProtection {
let protectionService = LoginProtectionService()
protectionService.hashes = BWIBuildSettings.shared.bwiHashes
return protectionService.isValid(homeserverAddress)
} else {
return true
}
}
/// bwi: jump directly into the iOS settings app to allow camera access
private func openSettingsApp() {
if let url = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
}
// MARK: - Previews