mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-23 01:52:44 +02:00
MESSENGER-3895 qr code login
This commit is contained in:
committed by
Frank Rotermund
parent
fd8ab8e648
commit
d7a23d53dc
+94
-7
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user