Renaming screens returns (#829)
* Rename: StartChat -> StartChatScreen * Rename: Login -> LoginScreen * Rename: ServerSelection -> ServerSelectionScreen * Rename: SoftLogout -> SoftLogoutScreen
This commit is contained in:
@@ -220,18 +220,18 @@ class AppCoordinator: AppCoordinatorProtocol {
|
||||
displayName = name
|
||||
}
|
||||
|
||||
let credentials = SoftLogoutCredentials(userId: userSession.userID,
|
||||
homeserverName: userSession.homeserver,
|
||||
userDisplayName: displayName,
|
||||
deviceId: userSession.deviceID)
|
||||
let credentials = SoftLogoutScreenCredentials(userId: userSession.userID,
|
||||
homeserverName: userSession.homeserver,
|
||||
userDisplayName: displayName,
|
||||
deviceId: userSession.deviceID)
|
||||
|
||||
let authenticationService = AuthenticationServiceProxy(userSessionStore: userSessionStore)
|
||||
_ = await authenticationService.configure(for: userSession.homeserver)
|
||||
|
||||
let parameters = SoftLogoutCoordinatorParameters(authenticationService: authenticationService,
|
||||
credentials: credentials,
|
||||
keyBackupNeeded: false)
|
||||
let coordinator = SoftLogoutCoordinator(parameters: parameters)
|
||||
let parameters = SoftLogoutScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
credentials: credentials,
|
||||
keyBackupNeeded: false)
|
||||
let coordinator = SoftLogoutScreenCoordinator(parameters: parameters)
|
||||
coordinator.callback = { result in
|
||||
switch result {
|
||||
case .signedIn(let session):
|
||||
|
||||
@@ -72,10 +72,10 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func showServerSelectionScreen() {
|
||||
let parameters = ServerSelectionCoordinatorParameters(authenticationService: authenticationService,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
isModallyPresented: false)
|
||||
let coordinator = ServerSelectionCoordinator(parameters: parameters)
|
||||
let parameters = ServerSelectionScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
isModallyPresented: false)
|
||||
let coordinator = ServerSelectionScreenCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.callback = { [weak self] action in
|
||||
guard let self else { return }
|
||||
@@ -92,10 +92,10 @@ class AuthenticationCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
private func showLoginScreen() {
|
||||
let parameters = LoginCoordinatorParameters(authenticationService: authenticationService,
|
||||
navigationStackCoordinator: navigationStackCoordinator)
|
||||
let coordinator = LoginCoordinator(parameters: parameters)
|
||||
|
||||
let parameters = LoginScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
navigationStackCoordinator: navigationStackCoordinator)
|
||||
let coordinator = LoginScreenCoordinator(parameters: parameters)
|
||||
|
||||
coordinator.callback = { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
|
||||
@@ -17,21 +17,21 @@
|
||||
import AppAuth
|
||||
import SwiftUI
|
||||
|
||||
struct LoginCoordinatorParameters {
|
||||
struct LoginScreenCoordinatorParameters {
|
||||
/// The service used to authenticate the user.
|
||||
let authenticationService: AuthenticationServiceProxyProtocol
|
||||
/// The navigation router used to present the server selection screen.
|
||||
let navigationStackCoordinator: NavigationStackCoordinator
|
||||
}
|
||||
|
||||
enum LoginCoordinatorAction {
|
||||
enum LoginScreenCoordinatorAction {
|
||||
/// Login was successful.
|
||||
case signedIn(UserSessionProtocol)
|
||||
}
|
||||
|
||||
final class LoginCoordinator: CoordinatorProtocol {
|
||||
private let parameters: LoginCoordinatorParameters
|
||||
private var viewModel: LoginViewModelProtocol
|
||||
final class LoginScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: LoginScreenCoordinatorParameters
|
||||
private var viewModel: LoginScreenViewModelProtocol
|
||||
private let hostingController: UIViewController
|
||||
/// Passed to the OIDC service to provide a view controller from which to present the authentication session.
|
||||
private let oidcUserAgent: OIDExternalUserAgentIOS?
|
||||
@@ -45,14 +45,14 @@ final class LoginCoordinator: CoordinatorProtocol {
|
||||
private var authenticationService: AuthenticationServiceProxyProtocol { parameters.authenticationService }
|
||||
private var navigationStackCoordinator: NavigationStackCoordinator { parameters.navigationStackCoordinator }
|
||||
|
||||
var callback: (@MainActor (LoginCoordinatorAction) -> Void)?
|
||||
var callback: (@MainActor (LoginScreenCoordinatorAction) -> Void)?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(parameters: LoginCoordinatorParameters) {
|
||||
init(parameters: LoginScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = LoginViewModel(homeserver: parameters.authenticationService.homeserver)
|
||||
viewModel = LoginScreenViewModel(homeserver: parameters.authenticationService.homeserver)
|
||||
|
||||
hostingController = UIHostingController(rootView: LoginScreen(context: viewModel.context))
|
||||
oidcUserAgent = OIDExternalUserAgentIOS(presenting: hostingController)
|
||||
@@ -199,11 +199,11 @@ final class LoginCoordinator: CoordinatorProtocol {
|
||||
|
||||
/// Presents the server selection screen as a modal.
|
||||
private func presentServerSelectionScreen() {
|
||||
let parameters = ServerSelectionCoordinatorParameters(authenticationService: authenticationService,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
isModallyPresented: false)
|
||||
let parameters = ServerSelectionScreenCoordinatorParameters(authenticationService: authenticationService,
|
||||
userIndicatorController: ServiceLocator.shared.userIndicatorController,
|
||||
isModallyPresented: false)
|
||||
|
||||
let coordinator = ServerSelectionCoordinator(parameters: parameters)
|
||||
let coordinator = ServerSelectionScreenCoordinator(parameters: parameters)
|
||||
coordinator.callback = { [weak self, weak coordinator] action in
|
||||
guard let self, let coordinator else { return }
|
||||
self.serverSelectionCoordinator(coordinator, didCompleteWith: action)
|
||||
@@ -213,8 +213,8 @@ final class LoginCoordinator: CoordinatorProtocol {
|
||||
}
|
||||
|
||||
/// Handles the result from the server selection modal, dismissing it after updating the view.
|
||||
private func serverSelectionCoordinator(_ coordinator: ServerSelectionCoordinator,
|
||||
didCompleteWith action: ServerSelectionCoordinatorAction) {
|
||||
private func serverSelectionCoordinator(_ coordinator: ServerSelectionScreenCoordinator,
|
||||
didCompleteWith action: ServerSelectionScreenCoordinatorAction) {
|
||||
if action == .updated {
|
||||
updateViewModel()
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum LoginViewModelAction: CustomStringConvertible {
|
||||
enum LoginScreenViewModelAction: CustomStringConvertible {
|
||||
/// The user would like to select another server.
|
||||
case selectServer
|
||||
/// Parse the username and update the homeserver if included.
|
||||
@@ -45,13 +45,13 @@ enum LoginViewModelAction: CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
struct LoginViewState: BindableState {
|
||||
struct LoginScreenViewState: BindableState {
|
||||
/// Data about the selected homeserver.
|
||||
var homeserver: LoginHomeserver
|
||||
/// Whether a new homeserver is currently being loaded.
|
||||
var isLoading = false
|
||||
/// View state that can be bound to from SwiftUI.
|
||||
var bindings: LoginBindings
|
||||
var bindings: LoginScreenBindings
|
||||
|
||||
/// The types of login supported by the homeserver.
|
||||
var loginMode: LoginMode { homeserver.loginMode }
|
||||
@@ -67,16 +67,16 @@ struct LoginViewState: BindableState {
|
||||
}
|
||||
}
|
||||
|
||||
struct LoginBindings {
|
||||
struct LoginScreenBindings {
|
||||
/// The username input by the user.
|
||||
var username = ""
|
||||
/// The password input by the user.
|
||||
var password = ""
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<LoginErrorType>?
|
||||
var alertInfo: AlertInfo<LoginScreenErrorType>?
|
||||
}
|
||||
|
||||
enum LoginViewAction {
|
||||
enum LoginScreenViewAction {
|
||||
/// The user would like to select another server.
|
||||
case selectServer
|
||||
/// Parse the username to detect if a homeserver is included.
|
||||
@@ -89,7 +89,7 @@ enum LoginViewAction {
|
||||
case continueWithOIDC
|
||||
}
|
||||
|
||||
enum LoginErrorType: Hashable {
|
||||
enum LoginScreenErrorType: Hashable {
|
||||
/// A specific error message shown in an alert.
|
||||
case alert(String)
|
||||
/// Looking up the homeserver from the username failed.
|
||||
@@ -16,19 +16,19 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
typealias LoginViewModelType = StateStoreViewModel<LoginViewState, LoginViewAction>
|
||||
typealias LoginScreenViewModelType = StateStoreViewModel<LoginScreenViewState, LoginScreenViewAction>
|
||||
|
||||
class LoginViewModel: LoginViewModelType, LoginViewModelProtocol {
|
||||
var callback: (@MainActor (LoginViewModelAction) -> Void)?
|
||||
class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtocol {
|
||||
var callback: (@MainActor (LoginScreenViewModelAction) -> Void)?
|
||||
|
||||
init(homeserver: LoginHomeserver) {
|
||||
let bindings = LoginBindings()
|
||||
let viewState = LoginViewState(homeserver: homeserver, bindings: bindings)
|
||||
let bindings = LoginScreenBindings()
|
||||
let viewState = LoginScreenViewState(homeserver: homeserver, bindings: bindings)
|
||||
|
||||
super.init(initialViewState: viewState)
|
||||
}
|
||||
|
||||
override func process(viewAction: LoginViewAction) {
|
||||
override func process(viewAction: LoginScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .selectServer:
|
||||
callback?(.selectServer)
|
||||
@@ -52,7 +52,7 @@ class LoginViewModel: LoginViewModelType, LoginViewModelProtocol {
|
||||
state.homeserver = homeserver
|
||||
}
|
||||
|
||||
func displayError(_ type: LoginErrorType) {
|
||||
func displayError(_ type: LoginScreenErrorType) {
|
||||
switch type {
|
||||
case .alert(let message):
|
||||
state.bindings.alertInfo = AlertInfo(id: type,
|
||||
@@ -17,9 +17,9 @@
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
protocol LoginViewModelProtocol {
|
||||
var callback: (@MainActor (LoginViewModelAction) -> Void)? { get set }
|
||||
var context: LoginViewModelType.Context { get }
|
||||
protocol LoginScreenViewModelProtocol {
|
||||
var callback: (@MainActor (LoginScreenViewModelAction) -> Void)? { get set }
|
||||
var context: LoginScreenViewModelType.Context { get }
|
||||
|
||||
/// Update the view to reflect that a new homeserver is being loaded.
|
||||
/// - Parameter isLoading: Whether or not the homeserver is being loaded.
|
||||
@@ -31,5 +31,5 @@ protocol LoginViewModelProtocol {
|
||||
|
||||
/// Display an error to the user.
|
||||
/// - Parameter type: The type of error to be displayed.
|
||||
func displayError(_ type: LoginErrorType)
|
||||
func displayError(_ type: LoginScreenErrorType)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ struct LoginScreen: View {
|
||||
/// The focus state of the password text field.
|
||||
@FocusState private var isPasswordFocused: Bool
|
||||
|
||||
@ObservedObject var context: LoginViewModel.Context
|
||||
@ObservedObject var context: LoginScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
@@ -146,26 +146,26 @@ struct LoginScreen: View {
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct Login_Previews: PreviewProvider {
|
||||
static let credentialsViewModel: LoginViewModel = {
|
||||
let viewModel = LoginViewModel(homeserver: .mockMatrixDotOrg)
|
||||
struct LoginScreen_Previews: PreviewProvider {
|
||||
static let credentialsViewModel: LoginScreenViewModel = {
|
||||
let viewModel = LoginScreenViewModel(homeserver: .mockMatrixDotOrg)
|
||||
viewModel.context.username = "alice"
|
||||
viewModel.context.password = "password"
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
static var previews: some View {
|
||||
screen(for: LoginViewModel(homeserver: .mockMatrixDotOrg))
|
||||
screen(for: LoginScreenViewModel(homeserver: .mockMatrixDotOrg))
|
||||
.previewDisplayName("matrix.org")
|
||||
screen(for: credentialsViewModel)
|
||||
.previewDisplayName("Credentials Entered")
|
||||
screen(for: LoginViewModel(homeserver: .mockOIDC))
|
||||
screen(for: LoginScreenViewModel(homeserver: .mockOIDC))
|
||||
.previewDisplayName("OIDC")
|
||||
screen(for: LoginViewModel(homeserver: .mockUnsupported))
|
||||
screen(for: LoginScreenViewModel(homeserver: .mockUnsupported))
|
||||
.previewDisplayName("Unsupported")
|
||||
}
|
||||
|
||||
static func screen(for viewModel: LoginViewModel) -> some View {
|
||||
static func screen(for viewModel: LoginScreenViewModel) -> some View {
|
||||
NavigationStack {
|
||||
LoginScreen(context: viewModel.context)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
|
||||
@@ -23,22 +23,22 @@ enum MockServerSelectionScreenState: CaseIterable {
|
||||
case nonModal
|
||||
|
||||
/// Generate the view struct for the screen state.
|
||||
@MainActor var viewModel: ServerSelectionViewModel {
|
||||
@MainActor var viewModel: ServerSelectionScreenViewModel {
|
||||
switch self {
|
||||
case .matrix:
|
||||
return ServerSelectionViewModel(homeserverAddress: "https://matrix.org",
|
||||
isModallyPresented: true)
|
||||
return ServerSelectionScreenViewModel(homeserverAddress: "https://matrix.org",
|
||||
isModallyPresented: true)
|
||||
case .emptyAddress:
|
||||
return ServerSelectionViewModel(homeserverAddress: "",
|
||||
isModallyPresented: true)
|
||||
return ServerSelectionScreenViewModel(homeserverAddress: "",
|
||||
isModallyPresented: true)
|
||||
case .invalidAddress:
|
||||
let viewModel = ServerSelectionViewModel(homeserverAddress: "thisisbad",
|
||||
isModallyPresented: true)
|
||||
let viewModel = ServerSelectionScreenViewModel(homeserverAddress: "thisisbad",
|
||||
isModallyPresented: true)
|
||||
viewModel.displayError(.footerMessage(L10n.errorUnknown))
|
||||
return viewModel
|
||||
case .nonModal:
|
||||
return ServerSelectionViewModel(homeserverAddress: "https://matrix.org",
|
||||
isModallyPresented: false)
|
||||
return ServerSelectionScreenViewModel(homeserverAddress: "https://matrix.org",
|
||||
isModallyPresented: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ServerSelectionCoordinatorParameters {
|
||||
struct ServerSelectionScreenCoordinatorParameters {
|
||||
/// The service used to authenticate the user.
|
||||
let authenticationService: AuthenticationServiceProxyProtocol
|
||||
let userIndicatorController: UserIndicatorControllerProtocol
|
||||
@@ -24,23 +24,23 @@ struct ServerSelectionCoordinatorParameters {
|
||||
let isModallyPresented: Bool
|
||||
}
|
||||
|
||||
enum ServerSelectionCoordinatorAction {
|
||||
enum ServerSelectionScreenCoordinatorAction {
|
||||
case updated
|
||||
case dismiss
|
||||
}
|
||||
|
||||
final class ServerSelectionCoordinator: CoordinatorProtocol {
|
||||
private let parameters: ServerSelectionCoordinatorParameters
|
||||
final class ServerSelectionScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: ServerSelectionScreenCoordinatorParameters
|
||||
private let userIndicatorController: UserIndicatorControllerProtocol
|
||||
private var viewModel: ServerSelectionViewModelProtocol
|
||||
private var viewModel: ServerSelectionScreenViewModelProtocol
|
||||
private var authenticationService: AuthenticationServiceProxyProtocol { parameters.authenticationService }
|
||||
|
||||
var callback: (@MainActor (ServerSelectionCoordinatorAction) -> Void)?
|
||||
var callback: (@MainActor (ServerSelectionScreenCoordinatorAction) -> Void)?
|
||||
|
||||
init(parameters: ServerSelectionCoordinatorParameters) {
|
||||
init(parameters: ServerSelectionScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
viewModel = ServerSelectionViewModel(homeserverAddress: parameters.authenticationService.homeserver.address,
|
||||
isModallyPresented: parameters.isModallyPresented)
|
||||
viewModel = ServerSelectionScreenViewModel(homeserverAddress: parameters.authenticationService.homeserver.address,
|
||||
isModallyPresented: parameters.isModallyPresented)
|
||||
userIndicatorController = parameters.userIndicatorController
|
||||
}
|
||||
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum ServerSelectionViewModelAction {
|
||||
enum ServerSelectionScreenViewModelAction {
|
||||
/// The user would like to use the homeserver at the given address.
|
||||
case confirm(homeserverAddress: String)
|
||||
/// Dismiss the view without using the entered address.
|
||||
case dismiss
|
||||
}
|
||||
|
||||
struct ServerSelectionViewState: BindableState {
|
||||
struct ServerSelectionScreenViewState: BindableState {
|
||||
/// The message to be shown in the text field footer when no error has occurred.
|
||||
private let regularFooterMessage = {
|
||||
let linkPlaceholder = "{link}"
|
||||
@@ -35,7 +35,7 @@ struct ServerSelectionViewState: BindableState {
|
||||
}()
|
||||
|
||||
/// View state that can be bound to from SwiftUI.
|
||||
var bindings: ServerSelectionBindings
|
||||
var bindings: ServerSelectionScreenBindings
|
||||
/// An error message to be shown in the text field footer.
|
||||
var footerErrorMessage: String?
|
||||
/// Whether the screen is presented modally or within a navigation stack.
|
||||
@@ -62,14 +62,14 @@ struct ServerSelectionViewState: BindableState {
|
||||
}
|
||||
}
|
||||
|
||||
struct ServerSelectionBindings {
|
||||
struct ServerSelectionScreenBindings {
|
||||
/// The homeserver address input by the user.
|
||||
var homeserverAddress: String
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<ServerSelectionErrorType>?
|
||||
var alertInfo: AlertInfo<ServerSelectionScreenErrorType>?
|
||||
}
|
||||
|
||||
enum ServerSelectionViewAction {
|
||||
enum ServerSelectionScreenViewAction {
|
||||
/// The user would like to use the homeserver at the input address.
|
||||
case confirm
|
||||
/// Dismiss the view without using the entered address.
|
||||
@@ -78,7 +78,7 @@ enum ServerSelectionViewAction {
|
||||
case clearFooterError
|
||||
}
|
||||
|
||||
enum ServerSelectionErrorType: Hashable {
|
||||
enum ServerSelectionScreenErrorType: Hashable {
|
||||
/// An error message to be shown in the text field footer.
|
||||
case footerMessage(String)
|
||||
/// An alert that allows the user to learn about sliding sync.
|
||||
@@ -16,19 +16,19 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
typealias ServerSelectionViewModelType = StateStoreViewModel<ServerSelectionViewState, ServerSelectionViewAction>
|
||||
typealias ServerSelectionScreenViewModelType = StateStoreViewModel<ServerSelectionScreenViewState, ServerSelectionScreenViewAction>
|
||||
|
||||
class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionViewModelProtocol {
|
||||
var callback: (@MainActor (ServerSelectionViewModelAction) -> Void)?
|
||||
class ServerSelectionScreenViewModel: ServerSelectionScreenViewModelType, ServerSelectionScreenViewModelProtocol {
|
||||
var callback: (@MainActor (ServerSelectionScreenViewModelAction) -> Void)?
|
||||
|
||||
init(homeserverAddress: String, isModallyPresented: Bool) {
|
||||
let bindings = ServerSelectionBindings(homeserverAddress: homeserverAddress)
|
||||
let bindings = ServerSelectionScreenBindings(homeserverAddress: homeserverAddress)
|
||||
|
||||
super.init(initialViewState: ServerSelectionViewState(bindings: bindings,
|
||||
isModallyPresented: isModallyPresented))
|
||||
super.init(initialViewState: ServerSelectionScreenViewState(bindings: bindings,
|
||||
isModallyPresented: isModallyPresented))
|
||||
}
|
||||
|
||||
override func process(viewAction: ServerSelectionViewAction) {
|
||||
|
||||
override func process(viewAction: ServerSelectionScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .confirm:
|
||||
callback?(.confirm(homeserverAddress: state.bindings.homeserverAddress))
|
||||
@@ -39,7 +39,7 @@ class ServerSelectionViewModel: ServerSelectionViewModelType, ServerSelectionVie
|
||||
}
|
||||
}
|
||||
|
||||
func displayError(_ type: ServerSelectionErrorType) {
|
||||
func displayError(_ type: ServerSelectionScreenErrorType) {
|
||||
switch type {
|
||||
case .footerMessage(let message):
|
||||
withElementAnimation {
|
||||
@@ -17,10 +17,10 @@
|
||||
import Foundation
|
||||
|
||||
@MainActor
|
||||
protocol ServerSelectionViewModelProtocol {
|
||||
var callback: (@MainActor (ServerSelectionViewModelAction) -> Void)? { get set }
|
||||
var context: ServerSelectionViewModelType.Context { get }
|
||||
protocol ServerSelectionScreenViewModelProtocol {
|
||||
var callback: (@MainActor (ServerSelectionScreenViewModelAction) -> Void)? { get set }
|
||||
var context: ServerSelectionScreenViewModelType.Context { get }
|
||||
|
||||
/// Displays an error to the user.
|
||||
func displayError(_ type: ServerSelectionErrorType)
|
||||
func displayError(_ type: ServerSelectionScreenErrorType)
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ServerSelectionScreen: View {
|
||||
@ObservedObject var context: ServerSelectionViewModel.Context
|
||||
@ObservedObject var context: ServerSelectionScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
@@ -1,68 +0,0 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/// Using an enum for the screen allows you define the different state cases with
|
||||
/// the relevant associated data for each case.
|
||||
enum MockSoftLogoutScreenState: String, CaseIterable {
|
||||
// A case for each state you want to represent
|
||||
// with specific, minimal associated data that will allow you
|
||||
// mock that screen.
|
||||
case emptyPassword
|
||||
case enteredPassword
|
||||
case oidc
|
||||
case unsupported
|
||||
case keyBackupNeeded
|
||||
|
||||
/// Generate the view struct for the screen state.
|
||||
@MainActor var viewModel: SoftLogoutViewModel {
|
||||
let credentials = SoftLogoutCredentials(userId: "@mock:matrix.org",
|
||||
homeserverName: "matrix.org",
|
||||
userDisplayName: "mock",
|
||||
deviceId: nil)
|
||||
switch self {
|
||||
case .emptyPassword:
|
||||
return SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: false)
|
||||
case .enteredPassword:
|
||||
return SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: false,
|
||||
password: "12345678")
|
||||
case .oidc:
|
||||
return SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockOIDC,
|
||||
keyBackupNeeded: false)
|
||||
case .unsupported:
|
||||
return SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockUnsupported,
|
||||
keyBackupNeeded: false)
|
||||
case .keyBackupNeeded:
|
||||
return SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MockSoftLogoutScreenState: Identifiable {
|
||||
var id: String {
|
||||
rawValue
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
//
|
||||
// Copyright 2022 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
/// Using an enum for the screen allows you define the different state cases with
|
||||
/// the relevant associated data for each case.
|
||||
enum MockSoftLogoutScreenState: String, CaseIterable {
|
||||
// A case for each state you want to represent
|
||||
// with specific, minimal associated data that will allow you
|
||||
// mock that screen.
|
||||
case emptyPassword
|
||||
case enteredPassword
|
||||
case oidc
|
||||
case unsupported
|
||||
case keyBackupNeeded
|
||||
|
||||
/// Generate the view struct for the screen state.
|
||||
@MainActor var viewModel: SoftLogoutScreenViewModel {
|
||||
let credentials = SoftLogoutScreenCredentials(userId: "@mock:matrix.org",
|
||||
homeserverName: "matrix.org",
|
||||
userDisplayName: "mock",
|
||||
deviceId: nil)
|
||||
switch self {
|
||||
case .emptyPassword:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: false)
|
||||
case .enteredPassword:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: false,
|
||||
password: "12345678")
|
||||
case .oidc:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockOIDC,
|
||||
keyBackupNeeded: false)
|
||||
case .unsupported:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockUnsupported,
|
||||
keyBackupNeeded: false)
|
||||
case .keyBackupNeeded:
|
||||
return SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MockSoftLogoutScreenState: Identifiable {
|
||||
var id: String {
|
||||
rawValue
|
||||
}
|
||||
}
|
||||
@@ -17,13 +17,13 @@
|
||||
import AppAuth
|
||||
import SwiftUI
|
||||
|
||||
struct SoftLogoutCoordinatorParameters {
|
||||
struct SoftLogoutScreenCoordinatorParameters {
|
||||
let authenticationService: AuthenticationServiceProxyProtocol
|
||||
let credentials: SoftLogoutCredentials
|
||||
let credentials: SoftLogoutScreenCredentials
|
||||
let keyBackupNeeded: Bool
|
||||
}
|
||||
|
||||
enum SoftLogoutCoordinatorResult: CustomStringConvertible {
|
||||
enum SoftLogoutScreenCoordinatorResult: CustomStringConvertible {
|
||||
/// Login was successful.
|
||||
case signedIn(UserSessionProtocol)
|
||||
/// Clear all user data
|
||||
@@ -40,26 +40,26 @@ enum SoftLogoutCoordinatorResult: CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
final class SoftLogoutCoordinator: CoordinatorProtocol {
|
||||
private let parameters: SoftLogoutCoordinatorParameters
|
||||
private var viewModel: SoftLogoutViewModelProtocol
|
||||
final class SoftLogoutScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: SoftLogoutScreenCoordinatorParameters
|
||||
private var viewModel: SoftLogoutScreenViewModelProtocol
|
||||
private let hostingController: UIViewController
|
||||
/// Passed to the OIDC service to provide a view controller from which to present the authentication session.
|
||||
private let oidcUserAgent: OIDExternalUserAgentIOS?
|
||||
|
||||
/// The wizard used to handle the registration flow.
|
||||
private var authenticationService: AuthenticationServiceProxyProtocol { parameters.authenticationService }
|
||||
|
||||
var callback: (@MainActor (SoftLogoutCoordinatorResult) -> Void)?
|
||||
|
||||
@MainActor init(parameters: SoftLogoutCoordinatorParameters) {
|
||||
var callback: (@MainActor (SoftLogoutScreenCoordinatorResult) -> Void)?
|
||||
|
||||
@MainActor init(parameters: SoftLogoutScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
|
||||
let homeserver = parameters.authenticationService.homeserver
|
||||
|
||||
viewModel = SoftLogoutViewModel(credentials: parameters.credentials,
|
||||
homeserver: homeserver,
|
||||
keyBackupNeeded: parameters.keyBackupNeeded)
|
||||
viewModel = SoftLogoutScreenViewModel(credentials: parameters.credentials,
|
||||
homeserver: homeserver,
|
||||
keyBackupNeeded: parameters.keyBackupNeeded)
|
||||
|
||||
hostingController = UIHostingController(rootView: SoftLogoutScreen(context: viewModel.context))
|
||||
oidcUserAgent = OIDExternalUserAgentIOS(presenting: hostingController)
|
||||
@@ -16,14 +16,14 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SoftLogoutCredentials {
|
||||
struct SoftLogoutScreenCredentials {
|
||||
let userId: String
|
||||
let homeserverName: String
|
||||
let userDisplayName: String
|
||||
let deviceId: String?
|
||||
}
|
||||
|
||||
enum SoftLogoutViewModelAction: CustomStringConvertible {
|
||||
enum SoftLogoutScreenViewModelAction: CustomStringConvertible {
|
||||
/// Login with password
|
||||
case login(String)
|
||||
/// Forgot password
|
||||
@@ -48,9 +48,9 @@ enum SoftLogoutViewModelAction: CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
struct SoftLogoutViewState: BindableState {
|
||||
struct SoftLogoutScreenViewState: BindableState {
|
||||
/// Soft logout credentials
|
||||
var credentials: SoftLogoutCredentials
|
||||
var credentials: SoftLogoutScreenCredentials
|
||||
|
||||
/// Data about the selected homeserver.
|
||||
var homeserver: LoginHomeserver
|
||||
@@ -59,7 +59,7 @@ struct SoftLogoutViewState: BindableState {
|
||||
var keyBackupNeeded: Bool
|
||||
|
||||
/// View state that can be bound to from SwiftUI.
|
||||
var bindings: SoftLogoutBindings
|
||||
var bindings: SoftLogoutScreenBindings
|
||||
|
||||
/// The types of login supported by the homeserver.
|
||||
var loginMode: LoginMode { homeserver.loginMode }
|
||||
@@ -75,14 +75,14 @@ struct SoftLogoutViewState: BindableState {
|
||||
}
|
||||
}
|
||||
|
||||
struct SoftLogoutBindings {
|
||||
struct SoftLogoutScreenBindings {
|
||||
/// The password input by the user.
|
||||
var password: String
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<SoftLogoutErrorType>?
|
||||
var alertInfo: AlertInfo<SoftLogoutScreenErrorType>?
|
||||
}
|
||||
|
||||
enum SoftLogoutViewAction {
|
||||
enum SoftLogoutScreenViewAction {
|
||||
/// Login.
|
||||
case login
|
||||
/// Forgot password
|
||||
@@ -93,7 +93,7 @@ enum SoftLogoutViewAction {
|
||||
case continueWithOIDC
|
||||
}
|
||||
|
||||
enum SoftLogoutErrorType: Hashable {
|
||||
enum SoftLogoutScreenErrorType: Hashable {
|
||||
/// A specific error message shown in an alert.
|
||||
case alert(String)
|
||||
/// An unknown error occurred.
|
||||
@@ -16,24 +16,24 @@
|
||||
|
||||
import SwiftUI
|
||||
|
||||
typealias SoftLogoutViewModelType = StateStoreViewModel<SoftLogoutViewState, SoftLogoutViewAction>
|
||||
typealias SoftLogoutScreenViewModelType = StateStoreViewModel<SoftLogoutScreenViewState, SoftLogoutScreenViewAction>
|
||||
|
||||
class SoftLogoutViewModel: SoftLogoutViewModelType, SoftLogoutViewModelProtocol {
|
||||
var callback: (@MainActor (SoftLogoutViewModelAction) -> Void)?
|
||||
class SoftLogoutScreenViewModel: SoftLogoutScreenViewModelType, SoftLogoutScreenViewModelProtocol {
|
||||
var callback: (@MainActor (SoftLogoutScreenViewModelAction) -> Void)?
|
||||
|
||||
init(credentials: SoftLogoutCredentials,
|
||||
init(credentials: SoftLogoutScreenCredentials,
|
||||
homeserver: LoginHomeserver,
|
||||
keyBackupNeeded: Bool,
|
||||
password: String = "") {
|
||||
let bindings = SoftLogoutBindings(password: password)
|
||||
let viewState = SoftLogoutViewState(credentials: credentials,
|
||||
homeserver: homeserver,
|
||||
keyBackupNeeded: keyBackupNeeded,
|
||||
bindings: bindings)
|
||||
let bindings = SoftLogoutScreenBindings(password: password)
|
||||
let viewState = SoftLogoutScreenViewState(credentials: credentials,
|
||||
homeserver: homeserver,
|
||||
keyBackupNeeded: keyBackupNeeded,
|
||||
bindings: bindings)
|
||||
super.init(initialViewState: viewState)
|
||||
}
|
||||
|
||||
override func process(viewAction: SoftLogoutViewAction) {
|
||||
override func process(viewAction: SoftLogoutScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .login:
|
||||
callback?(.login(state.bindings.password))
|
||||
@@ -46,7 +46,7 @@ class SoftLogoutViewModel: SoftLogoutViewModelType, SoftLogoutViewModelProtocol
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor func displayError(_ type: SoftLogoutErrorType) {
|
||||
@MainActor func displayError(_ type: SoftLogoutScreenErrorType) {
|
||||
switch type {
|
||||
case .alert(let message):
|
||||
state.bindings.alertInfo = AlertInfo(id: type,
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol SoftLogoutViewModelProtocol {
|
||||
var callback: (@MainActor (SoftLogoutViewModelAction) -> Void)? { get set }
|
||||
var context: SoftLogoutViewModelType.Context { get }
|
||||
protocol SoftLogoutScreenViewModelProtocol {
|
||||
var callback: (@MainActor (SoftLogoutScreenViewModelAction) -> Void)? { get set }
|
||||
var context: SoftLogoutScreenViewModelType.Context { get }
|
||||
|
||||
/// Display an error to the user.
|
||||
@MainActor func displayError(_ type: SoftLogoutErrorType)
|
||||
@MainActor func displayError(_ type: SoftLogoutScreenErrorType)
|
||||
}
|
||||
@@ -22,7 +22,7 @@ struct SoftLogoutScreen: View {
|
||||
/// The focus state of the password text field.
|
||||
@FocusState private var isPasswordFocused: Bool
|
||||
|
||||
@ObservedObject var context: SoftLogoutViewModel.Context
|
||||
@ObservedObject var context: SoftLogoutScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
@@ -171,14 +171,14 @@ struct SoftLogoutScreen: View {
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct SoftLogout_Previews: PreviewProvider {
|
||||
struct SoftLogoutScreen_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
ForEach(MockSoftLogoutScreenState.allCases) { state in
|
||||
screen(for: state.viewModel)
|
||||
}
|
||||
}
|
||||
|
||||
static func screen(for viewModel: SoftLogoutViewModel) -> some View {
|
||||
static func screen(for viewModel: SoftLogoutScreenViewModel) -> some View {
|
||||
NavigationStack {
|
||||
SoftLogoutScreen(context: viewModel.context)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
@@ -17,32 +17,32 @@
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct StartChatCoordinatorParameters {
|
||||
struct StartChatScreenCoordinatorParameters {
|
||||
let userSession: UserSessionProtocol
|
||||
weak var userIndicatorController: UserIndicatorControllerProtocol?
|
||||
let navigationStackCoordinator: NavigationStackCoordinator?
|
||||
let userDiscoveryService: UserDiscoveryServiceProtocol
|
||||
}
|
||||
|
||||
enum StartChatCoordinatorAction {
|
||||
enum StartChatScreenCoordinatorAction {
|
||||
case close
|
||||
case openRoom(withIdentifier: String)
|
||||
}
|
||||
|
||||
final class StartChatCoordinator: CoordinatorProtocol {
|
||||
private let parameters: StartChatCoordinatorParameters
|
||||
private var viewModel: StartChatViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<StartChatCoordinatorAction, Never> = .init()
|
||||
final class StartChatScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: StartChatScreenCoordinatorParameters
|
||||
private var viewModel: StartChatScreenViewModelProtocol
|
||||
private let actionsSubject: PassthroughSubject<StartChatScreenCoordinatorAction, Never> = .init()
|
||||
private var cancellables: Set<AnyCancellable> = .init()
|
||||
|
||||
var actions: AnyPublisher<StartChatCoordinatorAction, Never> {
|
||||
var actions: AnyPublisher<StartChatScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: StartChatCoordinatorParameters) {
|
||||
init(parameters: StartChatScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = StartChatViewModel(userSession: parameters.userSession, userIndicatorController: parameters.userIndicatorController, userDiscoveryService: parameters.userDiscoveryService)
|
||||
viewModel = StartChatScreenViewModel(userSession: parameters.userSession, userIndicatorController: parameters.userIndicatorController, userDiscoveryService: parameters.userDiscoveryService)
|
||||
}
|
||||
|
||||
func start() {
|
||||
@@ -16,18 +16,18 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum StartChatErrorType: Error {
|
||||
enum StartChatScreenErrorType: Error {
|
||||
case failedCreatingRoom
|
||||
case unknown
|
||||
}
|
||||
|
||||
enum StartChatViewModelAction {
|
||||
enum StartChatScreenViewModelAction {
|
||||
case close
|
||||
case createRoom
|
||||
case openRoom(withIdentifier: String)
|
||||
}
|
||||
|
||||
struct StartChatViewState: BindableState {
|
||||
struct StartChatScreenViewState: BindableState {
|
||||
var bindings = StartChatScreenViewStateBindings()
|
||||
var usersSection: UserDiscoverySection = .init(type: .suggestions, users: [])
|
||||
|
||||
@@ -44,10 +44,10 @@ struct StartChatScreenViewStateBindings {
|
||||
var searchQuery = ""
|
||||
|
||||
/// Information describing the currently displayed alert.
|
||||
var alertInfo: AlertInfo<StartChatErrorType>?
|
||||
var alertInfo: AlertInfo<StartChatScreenErrorType>?
|
||||
}
|
||||
|
||||
enum StartChatViewAction {
|
||||
enum StartChatScreenViewAction {
|
||||
case close
|
||||
case createRoom
|
||||
case inviteFriends
|
||||
@@ -17,14 +17,14 @@
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias StartChatViewModelType = StateStoreViewModel<StartChatViewState, StartChatViewAction>
|
||||
typealias StartChatScreenViewModelType = StateStoreViewModel<StartChatScreenViewState, StartChatScreenViewAction>
|
||||
|
||||
class StartChatViewModel: StartChatViewModelType, StartChatViewModelProtocol {
|
||||
class StartChatScreenViewModel: StartChatScreenViewModelType, StartChatScreenViewModelProtocol {
|
||||
private let userSession: UserSessionProtocol
|
||||
private let actionsSubject: PassthroughSubject<StartChatViewModelAction, Never> = .init()
|
||||
private let actionsSubject: PassthroughSubject<StartChatScreenViewModelAction, Never> = .init()
|
||||
private let userDiscoveryService: UserDiscoveryServiceProtocol
|
||||
|
||||
var actions: AnyPublisher<StartChatViewModelAction, Never> {
|
||||
var actions: AnyPublisher<StartChatScreenViewModelAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
@@ -34,14 +34,14 @@ class StartChatViewModel: StartChatViewModelType, StartChatViewModelProtocol {
|
||||
self.userSession = userSession
|
||||
self.userIndicatorController = userIndicatorController
|
||||
self.userDiscoveryService = userDiscoveryService
|
||||
super.init(initialViewState: StartChatViewState(), imageProvider: userSession.mediaProvider)
|
||||
super.init(initialViewState: StartChatScreenViewState(), imageProvider: userSession.mediaProvider)
|
||||
|
||||
setupBindings()
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
override func process(viewAction: StartChatViewAction) {
|
||||
override func process(viewAction: StartChatScreenViewAction) {
|
||||
switch viewAction {
|
||||
case .close:
|
||||
actionsSubject.send(.close)
|
||||
@@ -17,7 +17,7 @@
|
||||
import Combine
|
||||
|
||||
@MainActor
|
||||
protocol StartChatViewModelProtocol {
|
||||
var actions: AnyPublisher<StartChatViewModelAction, Never> { get }
|
||||
var context: StartChatViewModelType.Context { get }
|
||||
protocol StartChatScreenViewModelProtocol {
|
||||
var actions: AnyPublisher<StartChatScreenViewModelAction, Never> { get }
|
||||
var context: StartChatScreenViewModelType.Context { get }
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct StartChatScreen: View {
|
||||
@ObservedObject var context: StartChatViewModel.Context
|
||||
@ObservedObject var context: StartChatScreenViewModel.Context
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
@@ -130,14 +130,14 @@ struct StartChatScreen: View {
|
||||
|
||||
// MARK: - Previews
|
||||
|
||||
struct StartChat_Previews: PreviewProvider {
|
||||
struct StartChatScreen_Previews: PreviewProvider {
|
||||
static let viewModel = {
|
||||
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "@userid:example.com"),
|
||||
mediaProvider: MockMediaProvider())
|
||||
let userDiscoveryService = UserDiscoveryServiceMock()
|
||||
userDiscoveryService.fetchSuggestionsReturnValue = .success([.mockAlice])
|
||||
userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
|
||||
let viewModel = StartChatViewModel(userSession: userSession, userIndicatorController: nil, userDiscoveryService: userDiscoveryService)
|
||||
let viewModel = StartChatScreenViewModel(userSession: userSession, userIndicatorController: nil, userDiscoveryService: userDiscoveryService)
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
@@ -289,8 +289,8 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
|
||||
|
||||
let userIndicatorController = UserIndicatorController(rootCoordinator: startChatNavigationStackCoordinator)
|
||||
let userDiscoveryService = UserDiscoveryService(clientProxy: userSession.clientProxy)
|
||||
let parameters = StartChatCoordinatorParameters(userSession: userSession, userIndicatorController: userIndicatorController, navigationStackCoordinator: startChatNavigationStackCoordinator, userDiscoveryService: userDiscoveryService)
|
||||
let coordinator = StartChatCoordinator(parameters: parameters)
|
||||
let parameters = StartChatScreenCoordinatorParameters(userSession: userSession, userIndicatorController: userIndicatorController, navigationStackCoordinator: startChatNavigationStackCoordinator, userDiscoveryService: userDiscoveryService)
|
||||
let coordinator = StartChatScreenCoordinator(parameters: parameters)
|
||||
coordinator.actions.sink { [weak self] action in
|
||||
guard let self else { return }
|
||||
switch action {
|
||||
|
||||
@@ -62,21 +62,21 @@ class MockScreen: Identifiable {
|
||||
switch id {
|
||||
case .login:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let coordinator = LoginCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
navigationStackCoordinator: navigationStackCoordinator))
|
||||
let coordinator = LoginScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
navigationStackCoordinator: navigationStackCoordinator))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .serverSelection:
|
||||
let navigationStackCoordinator = NavigationStackCoordinator()
|
||||
let coordinator = ServerSelectionCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
userIndicatorController: MockUserIndicatorController(),
|
||||
isModallyPresented: true))
|
||||
let coordinator = ServerSelectionScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
userIndicatorController: MockUserIndicatorController(),
|
||||
isModallyPresented: true))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .serverSelectionNonModal:
|
||||
return ServerSelectionCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
userIndicatorController: MockUserIndicatorController(),
|
||||
isModallyPresented: false))
|
||||
return ServerSelectionScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
userIndicatorController: MockUserIndicatorController(),
|
||||
isModallyPresented: false))
|
||||
case .analyticsPrompt:
|
||||
return AnalyticsPromptScreenCoordinator()
|
||||
case .analyticsSettingsScreen:
|
||||
@@ -92,13 +92,13 @@ class MockScreen: Identifiable {
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .softLogout:
|
||||
let credentials = SoftLogoutCredentials(userId: "@mock:matrix.org",
|
||||
homeserverName: "matrix.org",
|
||||
userDisplayName: "mock",
|
||||
deviceId: "ABCDEFGH")
|
||||
return SoftLogoutCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
credentials: credentials,
|
||||
keyBackupNeeded: false))
|
||||
let credentials = SoftLogoutScreenCredentials(userId: "@mock:matrix.org",
|
||||
homeserverName: "matrix.org",
|
||||
userDisplayName: "mock",
|
||||
deviceId: "ABCDEFGH")
|
||||
return SoftLogoutScreenCoordinator(parameters: .init(authenticationService: MockAuthenticationServiceProxy(),
|
||||
credentials: credentials,
|
||||
keyBackupNeeded: false))
|
||||
case .simpleRegular:
|
||||
return TemplateScreenCoordinator(parameters: .init(promptType: .regular))
|
||||
case .simpleUpgrade:
|
||||
@@ -321,8 +321,8 @@ class MockScreen: Identifiable {
|
||||
userDiscoveryMock.fetchSuggestionsReturnValue = .success([.mockAlice, .mockBob, .mockCharlie])
|
||||
userDiscoveryMock.searchProfilesWithReturnValue = .success([])
|
||||
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "@mock:client.com"), mediaProvider: MockMediaProvider())
|
||||
let parameters: StartChatCoordinatorParameters = .init(userSession: userSession, navigationStackCoordinator: navigationStackCoordinator, userDiscoveryService: userDiscoveryMock)
|
||||
let coordinator = StartChatCoordinator(parameters: parameters)
|
||||
let parameters: StartChatScreenCoordinatorParameters = .init(userSession: userSession, navigationStackCoordinator: navigationStackCoordinator, userDiscoveryService: userDiscoveryMock)
|
||||
let coordinator = StartChatScreenCoordinator(parameters: parameters)
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .startChatWithSearchResults:
|
||||
@@ -332,7 +332,7 @@ class MockScreen: Identifiable {
|
||||
userDiscoveryMock.fetchSuggestionsReturnValue = .success([])
|
||||
userDiscoveryMock.searchProfilesWithReturnValue = .success([.mockBob, .mockBobby])
|
||||
let userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
|
||||
let coordinator = StartChatCoordinator(parameters: .init(userSession: userSession, navigationStackCoordinator: navigationStackCoordinator, userDiscoveryService: userDiscoveryMock))
|
||||
let coordinator = StartChatScreenCoordinator(parameters: .init(userSession: userSession, navigationStackCoordinator: navigationStackCoordinator, userDiscoveryService: userDiscoveryMock))
|
||||
navigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
return navigationStackCoordinator
|
||||
case .roomMemberDetailsAccountOwner:
|
||||
|
||||
@@ -21,11 +21,11 @@ import XCTest
|
||||
@MainActor
|
||||
class LoginViewModelTests: XCTestCase {
|
||||
let defaultHomeserver = LoginHomeserver.mockMatrixDotOrg
|
||||
var viewModel: LoginViewModelProtocol!
|
||||
var context: LoginViewModelType.Context!
|
||||
var viewModel: LoginScreenViewModelProtocol!
|
||||
var context: LoginScreenViewModelType.Context!
|
||||
|
||||
@MainActor override func setUp() async throws {
|
||||
viewModel = LoginViewModel(homeserver: defaultHomeserver)
|
||||
viewModel = LoginScreenViewModel(homeserver: defaultHomeserver)
|
||||
context = viewModel.context
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class LoginViewModelTests: XCTestCase {
|
||||
func testLogsForPassword() {
|
||||
// Given the coordinator and view model results that contain passwords.
|
||||
let password = "supersecretpassword"
|
||||
let viewModelAction: LoginViewModelAction = .login(username: "Alice", password: password)
|
||||
let viewModelAction: LoginScreenViewModelAction = .login(username: "Alice", password: password)
|
||||
|
||||
// When creating a string representation of those results (e.g. for logging).
|
||||
let viewModelActionString = "\(viewModelAction)"
|
||||
|
||||
@@ -24,11 +24,11 @@ class ServerSelectionViewModelTests: XCTestCase {
|
||||
static let counterInitialValue = 0
|
||||
}
|
||||
|
||||
var viewModel: ServerSelectionViewModelProtocol!
|
||||
var context: ServerSelectionViewModelType.Context!
|
||||
var viewModel: ServerSelectionScreenViewModelProtocol!
|
||||
var context: ServerSelectionScreenViewModelType.Context!
|
||||
|
||||
@MainActor override func setUp() {
|
||||
viewModel = ServerSelectionViewModel(homeserverAddress: "", isModallyPresented: true)
|
||||
viewModel = ServerSelectionScreenViewModel(homeserverAddress: "", isModallyPresented: true)
|
||||
context = viewModel.context
|
||||
}
|
||||
|
||||
|
||||
@@ -19,17 +19,17 @@ import XCTest
|
||||
@testable import ElementX
|
||||
|
||||
class SoftLogoutViewModelTests: XCTestCase {
|
||||
let credentials = SoftLogoutCredentials(userId: "mock_user_id",
|
||||
homeserverName: "https://matrix.org",
|
||||
userDisplayName: "mock_username",
|
||||
deviceId: "ABCDEFGH")
|
||||
|
||||
let credentials = SoftLogoutScreenCredentials(userId: "mock_user_id",
|
||||
homeserverName: "https://matrix.org",
|
||||
userDisplayName: "mock_username",
|
||||
deviceId: "ABCDEFGH")
|
||||
|
||||
@MainActor func testInitialStateForMatrixOrg() {
|
||||
let viewModel = SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true)
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true)
|
||||
let context = viewModel.context
|
||||
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
XCTAssert(context.password.isEmpty, "The view model should start with an empty password.")
|
||||
XCTAssertFalse(context.viewState.canSubmit, "The view model should start with an invalid password.")
|
||||
@@ -38,10 +38,10 @@ class SoftLogoutViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
@MainActor func testInitialStateForMatrixOrgPasswordEntered() {
|
||||
let viewModel = SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true,
|
||||
password: "12345678")
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockMatrixDotOrg,
|
||||
keyBackupNeeded: true,
|
||||
password: "12345678")
|
||||
let context = viewModel.context
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
@@ -49,13 +49,13 @@ class SoftLogoutViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(context.viewState.loginMode, .password, "The view model should show login form for the given homeserver.")
|
||||
XCTAssert(context.viewState.showRecoverEncryptionKeysMessage, "The view model should show recover encryption keys message.")
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testInitialStateForBasicServer() {
|
||||
let viewModel = SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockBasicServer,
|
||||
keyBackupNeeded: false)
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockBasicServer,
|
||||
keyBackupNeeded: false)
|
||||
let context = viewModel.context
|
||||
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
XCTAssert(context.password.isEmpty, "The view model should start with an empty password.")
|
||||
XCTAssertFalse(context.viewState.canSubmit, "The view model should start with an invalid password.")
|
||||
@@ -64,22 +64,22 @@ class SoftLogoutViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
@MainActor func testInitialStateForOIDC() {
|
||||
let viewModel = SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockOIDC,
|
||||
keyBackupNeeded: false)
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockOIDC,
|
||||
keyBackupNeeded: false)
|
||||
let context = viewModel.context
|
||||
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
XCTAssert(context.password.isEmpty, "The view model should start with an empty password.")
|
||||
XCTAssertFalse(context.viewState.canSubmit, "The view model should start with an invalid password.")
|
||||
XCTAssertTrue(context.viewState.loginMode.supportsOIDCFlow, "The view model should show OIDC button for the given homeserver.")
|
||||
XCTAssertFalse(context.viewState.showRecoverEncryptionKeysMessage, "The view model should not show recover encryption keys message.")
|
||||
}
|
||||
|
||||
|
||||
@MainActor func testInitialStateForUnsupported() {
|
||||
let viewModel = SoftLogoutViewModel(credentials: credentials,
|
||||
homeserver: .mockUnsupported,
|
||||
keyBackupNeeded: false)
|
||||
let viewModel = SoftLogoutScreenViewModel(credentials: credentials,
|
||||
homeserver: .mockUnsupported,
|
||||
keyBackupNeeded: false)
|
||||
let context = viewModel.context
|
||||
|
||||
// Given a view model where the user hasn't yet sent the verification email.
|
||||
|
||||
@@ -20,11 +20,11 @@ import XCTest
|
||||
|
||||
@MainActor
|
||||
class StartChatScreenViewModelTests: XCTestCase {
|
||||
var viewModel: StartChatViewModelProtocol!
|
||||
var viewModel: StartChatScreenViewModelProtocol!
|
||||
var clientProxy: MockClientProxy!
|
||||
var userDiscoveryService: UserDiscoveryServiceMock!
|
||||
|
||||
var context: StartChatViewModel.Context {
|
||||
var context: StartChatScreenViewModel.Context {
|
||||
viewModel.context
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class StartChatScreenViewModelTests: XCTestCase {
|
||||
userDiscoveryService.fetchSuggestionsReturnValue = .success([])
|
||||
userDiscoveryService.searchProfilesWithReturnValue = .success([])
|
||||
let userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
|
||||
viewModel = StartChatViewModel(userSession: userSession, userIndicatorController: nil, userDiscoveryService: userDiscoveryService)
|
||||
viewModel = StartChatScreenViewModel(userSession: userSession, userIndicatorController: nil, userDiscoveryService: userDiscoveryService)
|
||||
|
||||
setupAppSettings()
|
||||
ServiceLocator.shared.settings.startChatUserSuggestionsEnabled = true
|
||||
@@ -65,7 +65,7 @@ class StartChatScreenViewModelTests: XCTestCase {
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
private func search(query: String) async -> StartChatViewState? {
|
||||
private func search(query: String) async -> StartChatScreenViewState? {
|
||||
viewModel.context.searchQuery = query
|
||||
return await context.$viewState.nextValue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user