mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
parent
eda7d59518
commit
9bc24e2038
@ -901,6 +901,18 @@ class ApplicationMock: ApplicationProtocol {
|
|||||||
openReceivedInvocations.append(url)
|
openReceivedInvocations.append(url)
|
||||||
openClosure?(url)
|
openClosure?(url)
|
||||||
}
|
}
|
||||||
|
//MARK: - openAppSettings
|
||||||
|
|
||||||
|
var openAppSettingsCallsCount = 0
|
||||||
|
var openAppSettingsCalled: Bool {
|
||||||
|
return openAppSettingsCallsCount > 0
|
||||||
|
}
|
||||||
|
var openAppSettingsClosure: (() -> Void)?
|
||||||
|
|
||||||
|
func openAppSettings() {
|
||||||
|
openAppSettingsCallsCount += 1
|
||||||
|
openAppSettingsClosure?()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
class AudioConverterMock: AudioConverterProtocol {
|
class AudioConverterMock: AudioConverterProtocol {
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ struct HeroImage: View {
|
|||||||
case normal
|
case normal
|
||||||
case positive
|
case positive
|
||||||
case subtle
|
case subtle
|
||||||
|
case critical
|
||||||
|
|
||||||
var foregroundColor: Color {
|
var foregroundColor: Color {
|
||||||
switch self {
|
switch self {
|
||||||
@ -34,6 +35,8 @@ struct HeroImage: View {
|
|||||||
return .compound.iconSuccessPrimary
|
return .compound.iconSuccessPrimary
|
||||||
case .subtle:
|
case .subtle:
|
||||||
return .compound.iconSecondary
|
return .compound.iconSecondary
|
||||||
|
case .critical:
|
||||||
|
return .compound.iconCriticalPrimary
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,6 +48,8 @@ struct HeroImage: View {
|
|||||||
return .compound.bgSuccessSubtle
|
return .compound.bgSuccessSubtle
|
||||||
case .subtle:
|
case .subtle:
|
||||||
return .compound.bgSubtlePrimary
|
return .compound.bgSubtlePrimary
|
||||||
|
case .critical:
|
||||||
|
return .compound.bgCanvasDefault
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,11 +49,7 @@ final class StaticLocationScreenCoordinator: CoordinatorProtocol {
|
|||||||
case .close:
|
case .close:
|
||||||
actionsSubject.send(.close)
|
actionsSubject.send(.close)
|
||||||
case .openSystemSettings:
|
case .openSystemSettings:
|
||||||
guard let url = URL(string: UIApplication.openSettingsURLString),
|
UIApplication.shared.openAppSettings()
|
||||||
UIApplication.shared.canOpenURL(url) else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
UIApplication.shared.open(url)
|
|
||||||
case .sendLocation(let geoURI, let isUserLocation):
|
case .sendLocation(let geoURI, let isUserLocation):
|
||||||
actionsSubject.send(.selectedLocation(geoURI, isUserLocation: isUserLocation))
|
actionsSubject.send(.selectedLocation(geoURI, isUserLocation: isUserLocation))
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,8 @@ final class QRCodeLoginScreenCoordinator: CoordinatorProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
init(parameters: QRCodeLoginScreenCoordinatorParameters) {
|
init(parameters: QRCodeLoginScreenCoordinatorParameters) {
|
||||||
viewModel = QRCodeLoginScreenViewModel(qrCodeLoginService: parameters.qrCodeLoginService)
|
viewModel = QRCodeLoginScreenViewModel(qrCodeLoginService: parameters.qrCodeLoginService,
|
||||||
|
application: UIApplication.shared)
|
||||||
orientationManager = parameters.orientationManager
|
orientationManager = parameters.orientationManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ enum QRCodeLoginScreenViewModelAction {
|
|||||||
struct QRCodeLoginScreenViewState: BindableState {
|
struct QRCodeLoginScreenViewState: BindableState {
|
||||||
var state: QRCodeLoginState = .initial
|
var state: QRCodeLoginState = .initial
|
||||||
|
|
||||||
private let listItem3AttributedText = {
|
private static let initialStateListItem3AttributedText = {
|
||||||
let boldPlaceholder = "{bold}"
|
let boldPlaceholder = "{bold}"
|
||||||
var finalString = AttributedString(L10n.screenQrCodeLoginInitialStateItem3(boldPlaceholder))
|
var finalString = AttributedString(L10n.screenQrCodeLoginInitialStateItem3(boldPlaceholder))
|
||||||
var boldString = AttributedString(L10n.screenQrCodeLoginInitialStateItem3Action)
|
var boldString = AttributedString(L10n.screenQrCodeLoginInitialStateItem3Action)
|
||||||
@ -32,7 +32,7 @@ struct QRCodeLoginScreenViewState: BindableState {
|
|||||||
return finalString
|
return finalString
|
||||||
}()
|
}()
|
||||||
|
|
||||||
private let listItem4AttributedText = {
|
private static let initialStateListItem4AttributedText = {
|
||||||
let boldPlaceholder = "{bold}"
|
let boldPlaceholder = "{bold}"
|
||||||
var finalString = AttributedString(L10n.screenQrCodeLoginInitialStateItem4(boldPlaceholder))
|
var finalString = AttributedString(L10n.screenQrCodeLoginInitialStateItem4(boldPlaceholder))
|
||||||
var boldString = AttributedString(L10n.screenQrCodeLoginInitialStateItem4Action)
|
var boldString = AttributedString(L10n.screenQrCodeLoginInitialStateItem4Action)
|
||||||
@ -41,19 +41,24 @@ struct QRCodeLoginScreenViewState: BindableState {
|
|||||||
return finalString
|
return finalString
|
||||||
}()
|
}()
|
||||||
|
|
||||||
var listItems: [AttributedString] {
|
let initialStateListItems = [
|
||||||
[
|
AttributedString(L10n.screenQrCodeLoginInitialStateItem1(InfoPlistReader.main.productionAppName)),
|
||||||
AttributedString(L10n.screenQrCodeLoginInitialStateItem1(InfoPlistReader.main.productionAppName)),
|
AttributedString(L10n.screenQrCodeLoginInitialStateItem2),
|
||||||
AttributedString(L10n.screenQrCodeLoginInitialStateItem2),
|
initialStateListItem3AttributedText,
|
||||||
listItem3AttributedText,
|
initialStateListItem4AttributedText
|
||||||
listItem4AttributedText
|
]
|
||||||
]
|
|
||||||
}
|
let connectionNotSecureListItems = [
|
||||||
|
AttributedString(L10n.screenQrCodeLoginConnectionNoteSecureStateListItem1),
|
||||||
|
AttributedString(L10n.screenQrCodeLoginConnectionNoteSecureStateListItem2),
|
||||||
|
AttributedString(L10n.screenQrCodeLoginConnectionNoteSecureStateListItem3)
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QRCodeLoginScreenViewAction {
|
enum QRCodeLoginScreenViewAction {
|
||||||
case cancel
|
case cancel
|
||||||
case startScan
|
case startScan
|
||||||
|
case openSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QRCodeLoginState: Equatable {
|
enum QRCodeLoginState: Equatable {
|
||||||
@ -66,6 +71,8 @@ enum QRCodeLoginState: Equatable {
|
|||||||
|
|
||||||
enum QRCodeLoginErrorState: Equatable {
|
enum QRCodeLoginErrorState: Equatable {
|
||||||
case noCameraPermission
|
case noCameraPermission
|
||||||
|
case connectionNotSecure
|
||||||
|
case unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
enum QRCodeLoginScanningState: Equatable {
|
enum QRCodeLoginScanningState: Equatable {
|
||||||
|
@ -22,14 +22,17 @@ typealias QRCodeLoginScreenViewModelType = StateStoreViewModel<QRCodeLoginScreen
|
|||||||
|
|
||||||
class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScreenViewModelProtocol {
|
class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScreenViewModelProtocol {
|
||||||
private let qrCodeLoginService: QRCodeLoginServiceProtocol
|
private let qrCodeLoginService: QRCodeLoginServiceProtocol
|
||||||
|
private let application: ApplicationProtocol
|
||||||
|
|
||||||
private let actionsSubject: PassthroughSubject<QRCodeLoginScreenViewModelAction, Never> = .init()
|
private let actionsSubject: PassthroughSubject<QRCodeLoginScreenViewModelAction, Never> = .init()
|
||||||
var actionsPublisher: AnyPublisher<QRCodeLoginScreenViewModelAction, Never> {
|
var actionsPublisher: AnyPublisher<QRCodeLoginScreenViewModelAction, Never> {
|
||||||
actionsSubject.eraseToAnyPublisher()
|
actionsSubject.eraseToAnyPublisher()
|
||||||
}
|
}
|
||||||
|
|
||||||
init(qrCodeLoginService: QRCodeLoginServiceProtocol) {
|
init(qrCodeLoginService: QRCodeLoginServiceProtocol,
|
||||||
|
application: ApplicationProtocol) {
|
||||||
self.qrCodeLoginService = qrCodeLoginService
|
self.qrCodeLoginService = qrCodeLoginService
|
||||||
|
self.application = application
|
||||||
super.init(initialViewState: QRCodeLoginScreenViewState())
|
super.init(initialViewState: QRCodeLoginScreenViewState())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,6 +44,8 @@ class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScr
|
|||||||
actionsSubject.send(.cancel)
|
actionsSubject.send(.cancel)
|
||||||
case .startScan:
|
case .startScan:
|
||||||
Task { await startScanIfPossible() }
|
Task { await startScanIfPossible() }
|
||||||
|
case .openSettings:
|
||||||
|
application.openAppSettings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +56,7 @@ class QRCodeLoginScreenViewModel: QRCodeLoginScreenViewModelType, QRCodeLoginScr
|
|||||||
/// Only for mocking initial states
|
/// Only for mocking initial states
|
||||||
fileprivate init(state: QRCodeLoginState) {
|
fileprivate init(state: QRCodeLoginState) {
|
||||||
qrCodeLoginService = QRCodeLoginServiceMock(configuration: .init())
|
qrCodeLoginService = QRCodeLoginServiceMock(configuration: .init())
|
||||||
|
application = ApplicationMock()
|
||||||
super.init(initialViewState: .init(state: state))
|
super.init(initialViewState: .init(state: state))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,8 +40,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
case .scan:
|
case .scan:
|
||||||
qrScanContent
|
qrScanContent
|
||||||
case .error:
|
case .error:
|
||||||
// TODO: Handle error states
|
errorContent
|
||||||
EmptyView()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +57,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
}
|
}
|
||||||
.padding(.horizontal, 24)
|
.padding(.horizontal, 24)
|
||||||
|
|
||||||
SFNumberedListView(items: context.viewState.listItems)
|
SFNumberedListView(items: context.viewState.initialStateListItems)
|
||||||
}
|
}
|
||||||
} bottomContent: {
|
} bottomContent: {
|
||||||
Button(L10n.actionContinue) {
|
Button(L10n.actionContinue) {
|
||||||
@ -107,7 +106,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
case .invalid:
|
case .invalid:
|
||||||
VStack(spacing: 16) {
|
VStack(spacing: 16) {
|
||||||
Button(L10n.screenQrCodeLoginInvalidScanStateRetryButton) {
|
Button(L10n.screenQrCodeLoginInvalidScanStateRetryButton) {
|
||||||
// TODO: Implement try again
|
context.send(viewAction: .startScan)
|
||||||
}
|
}
|
||||||
.buttonStyle(.compound(.primary))
|
.buttonStyle(.compound(.primary))
|
||||||
|
|
||||||
@ -125,7 +124,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var qrScanner: some View {
|
private var qrScanner: some View {
|
||||||
QRCodeScannerView()
|
QRCodeScannerView()
|
||||||
.aspectRatio(1.0, contentMode: .fill)
|
.aspectRatio(1.0, contentMode: .fill)
|
||||||
@ -136,7 +135,7 @@ struct QRCodeLoginScreen: View {
|
|||||||
QRScannerViewOverlay(length: qrFrame.height)
|
QRScannerViewOverlay(length: qrFrame.height)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ToolbarContentBuilder
|
@ToolbarContentBuilder
|
||||||
private var toolbar: some ToolbarContent {
|
private var toolbar: some ToolbarContent {
|
||||||
ToolbarItem(placement: .cancellationAction) {
|
ToolbarItem(placement: .cancellationAction) {
|
||||||
@ -145,6 +144,98 @@ struct QRCodeLoginScreen: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var errorContent: some View {
|
||||||
|
if case let .error(errorState) = context.viewState.state {
|
||||||
|
FullscreenDialog {
|
||||||
|
errorContentHeader(errorState: errorState)
|
||||||
|
} bottomContent: {
|
||||||
|
errorContentFooter(errorState: errorState)
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private func errorContentHeader(errorState: QRCodeLoginState.QRCodeLoginErrorState) -> some View {
|
||||||
|
switch errorState {
|
||||||
|
case .noCameraPermission:
|
||||||
|
VStack(spacing: 16) {
|
||||||
|
HeroImage(icon: \.takePhotoSolid, style: .subtle)
|
||||||
|
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
Text(L10n.screenQrCodeLoginNoCameraPermissionStateTitle)
|
||||||
|
.foregroundColor(.compound.textPrimary)
|
||||||
|
.font(.compound.headingMDBold)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
|
Text(L10n.screenQrCodeLoginNoCameraPermissionStateDescription)
|
||||||
|
.foregroundColor(.compound.textSecondary)
|
||||||
|
.font(.compound.bodyMD)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .connectionNotSecure:
|
||||||
|
VStack(spacing: 40) {
|
||||||
|
VStack(spacing: 16) {
|
||||||
|
HeroImage(icon: \.error, style: .critical)
|
||||||
|
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
Text(L10n.screenQrCodeLoginConnectionNoteSecureStateTitle)
|
||||||
|
.foregroundColor(.compound.textPrimary)
|
||||||
|
.font(.compound.headingMDBold)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
|
Text(L10n.screenQrCodeLoginConnectionNoteSecureStateDescription)
|
||||||
|
.foregroundColor(.compound.textSecondary)
|
||||||
|
.font(.compound.bodyMD)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VStack(spacing: 24) {
|
||||||
|
Text(L10n.screenQrCodeLoginConnectionNoteSecureStateListHeader)
|
||||||
|
.foregroundColor(.compound.textPrimary)
|
||||||
|
.font(.compound.bodyLGSemibold)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
|
SFNumberedListView(items: context.viewState.connectionNotSecureListItems)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case .unknown:
|
||||||
|
VStack(spacing: 16) {
|
||||||
|
HeroImage(icon: \.error, style: .critical)
|
||||||
|
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
Text(L10n.commonSomethingWentWrong)
|
||||||
|
.foregroundColor(.compound.textPrimary)
|
||||||
|
.font(.compound.headingMDBold)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
|
||||||
|
Text(L10n.screenQrCodeLoginUnknownErrorDescription)
|
||||||
|
.foregroundColor(.compound.textSecondary)
|
||||||
|
.font(.compound.bodyMD)
|
||||||
|
.multilineTextAlignment(.center)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func errorContentFooter(errorState: QRCodeLoginState.QRCodeLoginErrorState) -> some View {
|
||||||
|
switch errorState {
|
||||||
|
case .noCameraPermission:
|
||||||
|
Button(L10n.screenQrCodeLoginNoCameraPermissionButton) {
|
||||||
|
context.send(viewAction: .openSettings)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.primary))
|
||||||
|
case .connectionNotSecure, .unknown:
|
||||||
|
Button(L10n.screenQrCodeLoginStartOverButton) {
|
||||||
|
context.send(viewAction: .startScan)
|
||||||
|
}
|
||||||
|
.buttonStyle(.compound(.primary))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct QRScannerViewOverlay: View {
|
private struct QRScannerViewOverlay: View {
|
||||||
@ -183,6 +274,12 @@ struct QRCodeLoginScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
static let invalidStateViewModel = QRCodeLoginScreenViewModel.mock(state: .scan(.invalid))
|
static let invalidStateViewModel = QRCodeLoginScreenViewModel.mock(state: .scan(.invalid))
|
||||||
|
|
||||||
|
static let noCameraPermissionStateViewModel = QRCodeLoginScreenViewModel.mock(state: .error(.noCameraPermission))
|
||||||
|
|
||||||
|
static let connectionNotSecureStateViewModel = QRCodeLoginScreenViewModel.mock(state: .error(.connectionNotSecure))
|
||||||
|
|
||||||
|
static let unknownErrorStateViewModel = QRCodeLoginScreenViewModel.mock(state: .error(.unknown))
|
||||||
|
|
||||||
static var previews: some View {
|
static var previews: some View {
|
||||||
QRCodeLoginScreen(context: initialStateViewModel.context)
|
QRCodeLoginScreen(context: initialStateViewModel.context)
|
||||||
.previewDisplayName("Initial")
|
.previewDisplayName("Initial")
|
||||||
@ -195,5 +292,14 @@ struct QRCodeLoginScreen_Previews: PreviewProvider, TestablePreview {
|
|||||||
|
|
||||||
QRCodeLoginScreen(context: invalidStateViewModel.context)
|
QRCodeLoginScreen(context: invalidStateViewModel.context)
|
||||||
.previewDisplayName("Invalid")
|
.previewDisplayName("Invalid")
|
||||||
|
|
||||||
|
QRCodeLoginScreen(context: noCameraPermissionStateViewModel.context)
|
||||||
|
.previewDisplayName("No Camera Permission")
|
||||||
|
|
||||||
|
QRCodeLoginScreen(context: connectionNotSecureStateViewModel.context)
|
||||||
|
.previewDisplayName("Connection not secure")
|
||||||
|
|
||||||
|
QRCodeLoginScreen(context: unknownErrorStateViewModel.context)
|
||||||
|
.previewDisplayName("Unknown error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -619,8 +619,7 @@ class RoomScreenInteractionHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func openSystemSettings() {
|
private func openSystemSettings() {
|
||||||
guard let url = URL(string: UIApplication.openSettingsURLString) else { return }
|
application.openAppSettings()
|
||||||
application.open(url)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func displayMediaActionIfPossible(timelineItem: RoomTimelineItemProtocol) async -> RoomTimelineControllerAction {
|
private func displayMediaActionIfPossible(timelineItem: RoomTimelineItemProtocol) async -> RoomTimelineControllerAction {
|
||||||
|
@ -24,6 +24,8 @@ protocol ApplicationProtocol {
|
|||||||
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)
|
func endBackgroundTask(_ identifier: UIBackgroundTaskIdentifier)
|
||||||
|
|
||||||
func open(_ url: URL)
|
func open(_ url: URL)
|
||||||
|
|
||||||
|
func openAppSettings()
|
||||||
|
|
||||||
var backgroundTimeRemaining: TimeInterval { get }
|
var backgroundTimeRemaining: TimeInterval { get }
|
||||||
|
|
||||||
@ -34,4 +36,11 @@ extension UIApplication: ApplicationProtocol {
|
|||||||
func open(_ url: URL) {
|
func open(_ url: URL) {
|
||||||
open(url, options: [:], completionHandler: nil)
|
open(url, options: [:], completionHandler: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func openAppSettings() {
|
||||||
|
guard let url = URL(string: UIApplication.openSettingsURLString) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
open(url)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-en-GB.Connection-not-secure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-en-GB.Connection-not-secure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-en-GB.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-en-GB.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-en-GB.Unknown-error.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-en-GB.Unknown-error.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-pseudo.Connection-not-secure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-pseudo.Connection-not-secure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-pseudo.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-pseudo.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-pseudo.Unknown-error.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPad-pseudo.Unknown-error.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-en-GB.Connection-not-secure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-en-GB.Connection-not-secure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-en-GB.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-en-GB.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-en-GB.Unknown-error.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-en-GB.Unknown-error.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-pseudo.Connection-not-secure.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-pseudo.Connection-not-secure.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-pseudo.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-pseudo.No-Camera-Permission.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-pseudo.Unknown-error.png
(Stored with Git LFS)
Normal file
BIN
PreviewTests/__Snapshots__/PreviewTests/test_qRCodeLoginScreen-iPhone-15-pseudo.Unknown-error.png
(Stored with Git LFS)
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user