Rename screens (#826)

* Rename: AnalyticsPrompt -> AnalyticsPromptScreen

* Rename: AnalyticsSettings -> AnalyticsSettingsScreen

* Rename: Settings -> SettingsScreen

* Rename: SessionVerification -> SessionVerificationScreen

* Rename: BugReport -> BugReportScreen

* Rename: FilePreview -> FilePreviewScreen

* Rename: AnalyticsPrompt -> AnalyticsPromptScreen

* Rename: Invites -> InvitesScreen

* Rename: InviteUsers -> InviteUsersScreen

* Rename: MediaPicker -> MediaPickerScreen

* Delete unused UIActivityViewControllerWrapper

* Rename: ReportContent -> ReportContentScreen

* Rename: RoomDetails -> RoomDetailsScreen

* Rename: RoomMemberDetails -> RoomMemberDetailsScreen

* Rename: RoomMemberList -> RoomMemberListScreen

* Rename: Cleanup

* Renaming missed items

* Low effort attempt at fixing the flakey unit tests
This commit is contained in:
Stefan Ceriu
2023-04-24 18:48:07 +03:00
committed by GitHub
parent 9911ad2b9b
commit 24572c6582
88 changed files with 492 additions and 520 deletions
@@ -16,13 +16,13 @@
import SwiftUI import SwiftUI
final class AnalyticsPromptCoordinator: CoordinatorProtocol { final class AnalyticsPromptScreenCoordinator: CoordinatorProtocol {
private var viewModel: AnalyticsPromptViewModel private var viewModel: AnalyticsPromptScreenViewModel
var callback: (@MainActor () -> Void)? var callback: (@MainActor () -> Void)?
init() { init() {
viewModel = AnalyticsPromptViewModel() viewModel = AnalyticsPromptScreenViewModel()
} }
// MARK: - Public // MARK: - Public
@@ -45,6 +45,6 @@ final class AnalyticsPromptCoordinator: CoordinatorProtocol {
} }
func toPresentable() -> AnyView { func toPresentable() -> AnyView {
AnyView(AnalyticsPrompt(context: viewModel.context)) AnyView(AnalyticsPromptScreen(context: viewModel.context))
} }
} }
@@ -16,27 +16,27 @@
import Foundation import Foundation
enum AnalyticsPromptViewAction { enum AnalyticsPromptScreenViewAction {
/// Enable analytics. /// Enable analytics.
case enable case enable
/// Disable analytics. /// Disable analytics.
case disable case disable
} }
enum AnalyticsPromptViewModelAction { enum AnalyticsPromptScreenViewModelAction {
/// Enable analytics. /// Enable analytics.
case enable case enable
/// Disable analytics. /// Disable analytics.
case disable case disable
} }
struct AnalyticsPromptViewState: BindableState { struct AnalyticsPromptScreenViewState: BindableState {
/// Attributed strings created from localized HTML. /// Attributed strings created from localized HTML.
let strings: AnalyticsPromptStrings let strings: AnalyticsPromptScreenStrings
} }
/// A collection of strings for the UI that need to be parsed from HTML /// A collection of strings for the UI that need to be parsed from HTML
struct AnalyticsPromptStrings { struct AnalyticsPromptScreenStrings {
let optInContent: AttributedString let optInContent: AttributedString
let point1 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptDataUsage) ?? AttributedString(L10n.screenAnalyticsPromptDataUsage) let point1 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptDataUsage) ?? AttributedString(L10n.screenAnalyticsPromptDataUsage)
let point2 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptThirdPartySharing) ?? AttributedString(L10n.screenAnalyticsPromptThirdPartySharing) let point2 = AttributedStringBuilder().fromHTML(L10n.screenAnalyticsPromptThirdPartySharing) ?? AttributedString(L10n.screenAnalyticsPromptThirdPartySharing)
@@ -17,20 +17,20 @@
import Combine import Combine
import SwiftUI import SwiftUI
typealias AnalyticsPromptViewModelType = StateStoreViewModel<AnalyticsPromptViewState, AnalyticsPromptViewAction> typealias AnalyticsPromptScreenViewModelType = StateStoreViewModel<AnalyticsPromptScreenViewState, AnalyticsPromptScreenViewAction>
class AnalyticsPromptViewModel: AnalyticsPromptViewModelType, AnalyticsPromptViewModelProtocol { class AnalyticsPromptScreenViewModel: AnalyticsPromptScreenViewModelType, AnalyticsPromptScreenViewModelProtocol {
var callback: (@MainActor (AnalyticsPromptViewModelAction) -> Void)? var callback: (@MainActor (AnalyticsPromptScreenViewModelAction) -> Void)?
/// Initialize a view model with the specified prompt type and app display name. /// Initialize a view model with the specified prompt type and app display name.
init() { init() {
let promptStrings = AnalyticsPromptStrings(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL) let promptStrings = AnalyticsPromptScreenStrings(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL)
super.init(initialViewState: AnalyticsPromptViewState(strings: promptStrings)) super.init(initialViewState: AnalyticsPromptScreenViewState(strings: promptStrings))
} }
// MARK: - Public // MARK: - Public
override func process(viewAction: AnalyticsPromptViewAction) { override func process(viewAction: AnalyticsPromptScreenViewAction) {
switch viewAction { switch viewAction {
case .enable: case .enable:
callback?(.enable) callback?(.enable)
@@ -17,7 +17,7 @@
import Foundation import Foundation
@MainActor @MainActor
protocol AnalyticsPromptViewModelProtocol { protocol AnalyticsPromptScreenViewModelProtocol {
var callback: (@MainActor (AnalyticsPromptViewModelAction) -> Void)? { get set } var callback: (@MainActor (AnalyticsPromptScreenViewModelAction) -> Void)? { get set }
var context: AnalyticsPromptViewModelType.Context { get } var context: AnalyticsPromptScreenViewModelType.Context { get }
} }
@@ -17,10 +17,10 @@
import SwiftUI import SwiftUI
/// A prompt that asks the user whether they would like to enable Analytics or not. /// A prompt that asks the user whether they would like to enable Analytics or not.
struct AnalyticsPrompt: View { struct AnalyticsPromptScreen: View {
private let horizontalPadding: CGFloat = 16 private let horizontalPadding: CGFloat = 16
@ObservedObject var context: AnalyticsPromptViewModel.Context @ObservedObject var context: AnalyticsPromptScreenViewModel.Context
var body: some View { var body: some View {
GeometryReader { geometry in GeometryReader { geometry in
@@ -83,9 +83,9 @@ struct AnalyticsPrompt: View {
/// The list of re-assurances about analytics. /// The list of re-assurances about analytics.
private var checkmarkList: some View { private var checkmarkList: some View {
VStack(alignment: .leading, spacing: 8) { VStack(alignment: .leading, spacing: 8) {
AnalyticsPromptCheckmarkItem(attributedString: context.viewState.strings.point1) AnalyticsPromptScreenCheckmarkItem(attributedString: context.viewState.strings.point1)
AnalyticsPromptCheckmarkItem(attributedString: context.viewState.strings.point2) AnalyticsPromptScreenCheckmarkItem(attributedString: context.viewState.strings.point2)
AnalyticsPromptCheckmarkItem(string: context.viewState.strings.point3) AnalyticsPromptScreenCheckmarkItem(string: context.viewState.strings.point3)
} }
.fixedSize(horizontal: false, vertical: true) .fixedSize(horizontal: false, vertical: true)
.font(.element.body) .font(.element.body)
@@ -115,9 +115,9 @@ struct AnalyticsPrompt: View {
// MARK: - Previews // MARK: - Previews
struct AnalyticsPrompt_Previews: PreviewProvider { struct AnalyticsPromptScreen_Previews: PreviewProvider {
static let viewModel = AnalyticsPromptViewModel() static let viewModel = AnalyticsPromptScreenViewModel()
static var previews: some View { static var previews: some View {
AnalyticsPrompt(context: viewModel.context) AnalyticsPromptScreen(context: viewModel.context)
} }
} }
@@ -16,7 +16,7 @@
import SwiftUI import SwiftUI
struct AnalyticsPromptCheckmarkItem: View { struct AnalyticsPromptScreenCheckmarkItem: View {
private let attributedString: AttributedString private let attributedString: AttributedString
init(attributedString: AttributedString) { init(attributedString: AttributedString) {
@@ -37,15 +37,15 @@ struct AnalyticsPromptCheckmarkItem: View {
// MARK: - Previews // MARK: - Previews
struct AnalyticsPromptCheckmarkItem_Previews: PreviewProvider { struct AnalyticsPromptScreenCheckmarkItem_Previews: PreviewProvider {
static let strings = AnalyticsPromptStrings(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL) static let strings = AnalyticsPromptScreenStrings(termsURL: ServiceLocator.shared.settings.analyticsConfiguration.termsURL)
static var previews: some View { static var previews: some View {
VStack(alignment: .leading) { VStack(alignment: .leading) {
AnalyticsPromptCheckmarkItem(attributedString: strings.point1) AnalyticsPromptScreenCheckmarkItem(attributedString: strings.point1)
AnalyticsPromptCheckmarkItem(attributedString: strings.point2) AnalyticsPromptScreenCheckmarkItem(attributedString: strings.point2)
AnalyticsPromptCheckmarkItem(attributedString: AttributedString("This is a short string.")) AnalyticsPromptScreenCheckmarkItem(attributedString: AttributedString("This is a short string."))
AnalyticsPromptCheckmarkItem(attributedString: AttributedString("This is a very long string that will be used to test the layout over multiple lines of text to ensure everything is correct.")) AnalyticsPromptScreenCheckmarkItem(attributedString: AttributedString("This is a very long string that will be used to test the layout over multiple lines of text to ensure everything is correct."))
} }
.padding() .padding()
} }
@@ -120,7 +120,7 @@ class AuthenticationCoordinator: CoordinatorProtocol {
completion() completion()
return return
} }
let coordinator = AnalyticsPromptCoordinator() let coordinator = AnalyticsPromptScreenCoordinator()
coordinator.callback = { coordinator.callback = {
completion() completion()
} }
@@ -17,12 +17,12 @@
import Combine import Combine
import SwiftUI import SwiftUI
enum BugReportCoordinatorResult { enum BugReportScreenCoordinatorResult {
case cancel case cancel
case finish case finish
} }
struct BugReportCoordinatorParameters { struct BugReportScreenCoordinatorParameters {
let bugReportService: BugReportServiceProtocol let bugReportService: BugReportServiceProtocol
let userID: String let userID: String
let deviceID: String? let deviceID: String?
@@ -32,21 +32,21 @@ struct BugReportCoordinatorParameters {
let isModallyPresented: Bool let isModallyPresented: Bool
} }
final class BugReportCoordinator: CoordinatorProtocol { final class BugReportScreenCoordinator: CoordinatorProtocol {
private let parameters: BugReportCoordinatorParameters private let parameters: BugReportScreenCoordinatorParameters
private var viewModel: BugReportViewModelProtocol private var viewModel: BugReportScreenViewModelProtocol
private var cancellables: Set<AnyCancellable> = .init() private var cancellables: Set<AnyCancellable> = .init()
var completion: ((BugReportCoordinatorResult) -> Void)?
init(parameters: BugReportCoordinatorParameters) { var completion: ((BugReportScreenCoordinatorResult) -> Void)?
init(parameters: BugReportScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = BugReportViewModel(bugReportService: parameters.bugReportService, viewModel = BugReportScreenViewModel(bugReportService: parameters.bugReportService,
userID: parameters.userID, userID: parameters.userID,
deviceID: parameters.deviceID, deviceID: parameters.deviceID,
screenshot: parameters.screenshot, screenshot: parameters.screenshot,
isModallyPresented: parameters.isModallyPresented) isModallyPresented: parameters.isModallyPresented)
} }
// MARK: - Public // MARK: - Public
@@ -17,25 +17,25 @@
import Foundation import Foundation
import UIKit import UIKit
enum BugReportViewModelAction { enum BugReportScreenViewModelAction {
case cancel case cancel
case submitStarted(progressTracker: ProgressTracker) case submitStarted(progressTracker: ProgressTracker)
case submitFinished case submitFinished
case submitFailed(error: Error) case submitFailed(error: Error)
} }
struct BugReportViewState: BindableState { struct BugReportScreenViewState: BindableState {
var screenshot: UIImage? var screenshot: UIImage?
var bindings: BugReportViewStateBindings var bindings: BugReportScreenViewStateBindings
let isModallyPresented: Bool let isModallyPresented: Bool
} }
struct BugReportViewStateBindings { struct BugReportScreenViewStateBindings {
var reportText: String var reportText: String
var sendingLogsEnabled: Bool var sendingLogsEnabled: Bool
} }
enum BugReportViewAction { enum BugReportScreenViewAction {
case cancel case cancel
case submit case submit
case removeScreenshot case removeScreenshot
@@ -17,15 +17,15 @@
import Combine import Combine
import SwiftUI import SwiftUI
typealias BugReportViewModelType = StateStoreViewModel<BugReportViewState, BugReportViewAction> typealias BugReportScreenViewModelType = StateStoreViewModel<BugReportScreenViewState, BugReportScreenViewAction>
class BugReportViewModel: BugReportViewModelType, BugReportViewModelProtocol { class BugReportScreenViewModel: BugReportScreenViewModelType, BugReportScreenViewModelProtocol {
private let bugReportService: BugReportServiceProtocol private let bugReportService: BugReportServiceProtocol
private let userID: String private let userID: String
private let deviceID: String? private let deviceID: String?
private let actionsSubject: PassthroughSubject<BugReportViewModelAction, Never> = .init() private let actionsSubject: PassthroughSubject<BugReportScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<BugReportViewModelAction, Never> { var actions: AnyPublisher<BugReportScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
@@ -38,15 +38,15 @@ class BugReportViewModel: BugReportViewModelType, BugReportViewModelProtocol {
self.userID = userID self.userID = userID
self.deviceID = deviceID self.deviceID = deviceID
let bindings = BugReportViewStateBindings(reportText: "", sendingLogsEnabled: true) let bindings = BugReportScreenViewStateBindings(reportText: "", sendingLogsEnabled: true)
super.init(initialViewState: BugReportViewState(screenshot: screenshot, super.init(initialViewState: BugReportScreenViewState(screenshot: screenshot,
bindings: bindings, bindings: bindings,
isModallyPresented: isModallyPresented)) isModallyPresented: isModallyPresented))
} }
// MARK: - Public // MARK: - Public
override func process(viewAction: BugReportViewAction) { override func process(viewAction: BugReportScreenViewAction) {
switch viewAction { switch viewAction {
case .cancel: case .cancel:
actionsSubject.send(.cancel) actionsSubject.send(.cancel)
@@ -17,7 +17,7 @@
import Combine import Combine
@MainActor @MainActor
protocol InvitesViewModelProtocol { protocol BugReportScreenViewModelProtocol {
var actions: AnyPublisher<InvitesViewModelAction, Never> { get } var actions: AnyPublisher<BugReportScreenViewModelAction, Never> { get }
var context: InvitesViewModelType.Context { get } var context: BugReportScreenViewModelType.Context { get }
} }
@@ -21,7 +21,7 @@ import SwiftUI
struct BugReportScreen: View { struct BugReportScreen: View {
@State private var selectedScreenshot: PhotosPickerItem? @State private var selectedScreenshot: PhotosPickerItem?
@ObservedObject var context: BugReportViewModel.Context @ObservedObject var context: BugReportScreenViewModel.Context
var body: some View { var body: some View {
Form { Form {
@@ -131,28 +131,28 @@ struct BugReportScreen: View {
// MARK: - Previews // MARK: - Previews
struct BugReport_Previews: PreviewProvider { struct BugReport_Previews: PreviewProvider {
static let viewModel = BugReportViewModel(bugReportService: BugReportServiceMock(), static let viewModel = BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: nil, screenshot: nil,
isModallyPresented: false) isModallyPresented: false)
static var previews: some View { static var previews: some View {
NavigationStack { NavigationStack {
BugReportScreen(context: BugReportViewModel(bugReportService: BugReportServiceMock(), BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: nil, screenshot: nil,
isModallyPresented: false).context) isModallyPresented: false).context)
.previewDisplayName("Without Screenshot") .previewDisplayName("Without Screenshot")
} }
NavigationStack { NavigationStack {
BugReportScreen(context: BugReportViewModel(bugReportService: BugReportServiceMock(), BugReportScreen(context: BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: Asset.Images.appLogo.image, screenshot: Asset.Images.appLogo.image,
isModallyPresented: false).context) isModallyPresented: false).context)
.previewDisplayName("With Screenshot") .previewDisplayName("With Screenshot")
} }
} }
@@ -25,7 +25,7 @@ struct EmojiPickerScreen: View {
ScrollView { ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: minimumWidth))], spacing: 16) { LazyVGrid(columns: [GridItem(.adaptive(minimum: minimumWidth))], spacing: 16) {
ForEach(context.viewState.categories) { category in ForEach(context.viewState.categories) { category in
Section(header: EmojiPickerHeaderView(title: category.name) Section(header: EmojiPickerScreenHeaderView(title: category.name)
.padding(.horizontal, 13) .padding(.horizontal, 13)
.padding(.top, 10)) { .padding(.top, 10)) {
ForEach(category.emojis) { emoji in ForEach(category.emojis) { emoji in
@@ -16,7 +16,7 @@
import SwiftUI import SwiftUI
struct EmojiPickerHeaderView: View { struct EmojiPickerScreenHeaderView: View {
let title: String let title: String
var body: some View { var body: some View {
@@ -29,10 +29,10 @@ struct EmojiPickerHeaderView: View {
} }
} }
struct EmojiPickerHeaderView_Previews: PreviewProvider { struct EmojiPickerScreenHeaderView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
Group { Group {
EmojiPickerHeaderView(title: "") EmojiPickerScreenHeaderView(title: "")
} }
} }
} }
@@ -16,25 +16,25 @@
import SwiftUI import SwiftUI
struct FilePreviewCoordinatorParameters { struct FilePreviewScreenCoordinatorParameters {
let mediaFile: MediaFileHandleProxy let mediaFile: MediaFileHandleProxy
let title: String? let title: String?
} }
enum FilePreviewCoordinatorAction { enum FilePreviewScreenCoordinatorAction {
case cancel case cancel
} }
final class FilePreviewCoordinator: CoordinatorProtocol { final class FilePreviewScreenCoordinator: CoordinatorProtocol {
private let parameters: FilePreviewCoordinatorParameters private let parameters: FilePreviewScreenCoordinatorParameters
private var viewModel: FilePreviewViewModelProtocol private var viewModel: FilePreviewScreenViewModelProtocol
var callback: ((FilePreviewCoordinatorAction) -> Void)? var callback: ((FilePreviewScreenCoordinatorAction) -> Void)?
init(parameters: FilePreviewCoordinatorParameters) { init(parameters: FilePreviewScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = FilePreviewViewModel(mediaFile: parameters.mediaFile, title: parameters.title) viewModel = FilePreviewScreenViewModel(mediaFile: parameters.mediaFile, title: parameters.title)
} }
// MARK: - Public // MARK: - Public
@@ -16,15 +16,15 @@
import Foundation import Foundation
enum FilePreviewViewModelAction { enum FilePreviewScreenViewModelAction {
case cancel case cancel
} }
struct FilePreviewViewState: BindableState { struct FilePreviewScreenViewState: BindableState {
let mediaFile: MediaFileHandleProxy let mediaFile: MediaFileHandleProxy
let title: String? let title: String?
} }
enum FilePreviewViewAction { enum FilePreviewScreenViewAction {
case cancel case cancel
} }
@@ -16,16 +16,16 @@
import SwiftUI import SwiftUI
typealias FilePreviewViewModelType = StateStoreViewModel<FilePreviewViewState, FilePreviewViewAction> typealias FilePreviewScreenViewModelType = StateStoreViewModel<FilePreviewScreenViewState, FilePreviewScreenViewAction>
class FilePreviewViewModel: FilePreviewViewModelType, FilePreviewViewModelProtocol { class FilePreviewScreenViewModel: FilePreviewScreenViewModelType, FilePreviewScreenViewModelProtocol {
var callback: ((FilePreviewViewModelAction) -> Void)? var callback: ((FilePreviewScreenViewModelAction) -> Void)?
init(mediaFile: MediaFileHandleProxy, title: String? = nil) { init(mediaFile: MediaFileHandleProxy, title: String? = nil) {
super.init(initialViewState: FilePreviewViewState(mediaFile: mediaFile, title: title)) super.init(initialViewState: FilePreviewScreenViewState(mediaFile: mediaFile, title: title))
} }
override func process(viewAction: FilePreviewViewAction) { override func process(viewAction: FilePreviewScreenViewAction) {
switch viewAction { switch viewAction {
case .cancel: case .cancel:
callback?(.cancel) callback?(.cancel)
@@ -17,7 +17,7 @@
import Foundation import Foundation
@MainActor @MainActor
protocol RoomMemberDetailsViewModelProtocol { protocol FilePreviewScreenViewModelProtocol {
var callback: ((RoomMemberDetailsViewModelAction) -> Void)? { get set } var callback: ((FilePreviewScreenViewModelAction) -> Void)? { get set }
var context: RoomMemberDetailsViewModelType.Context { get } var context: FilePreviewScreenViewModelType.Context { get }
} }
@@ -19,7 +19,7 @@ import SwiftUI
import UIKit import UIKit
struct FilePreviewScreen: View { struct FilePreviewScreen: View {
@ObservedObject var context: FilePreviewViewModel.Context @ObservedObject var context: FilePreviewScreenViewModel.Context
var body: some View { var body: some View {
ZStack(alignment: .leading) { ZStack(alignment: .leading) {
@@ -40,7 +40,7 @@ struct FilePreviewScreen: View {
} }
private struct PreviewView: UIViewControllerRepresentable { private struct PreviewView: UIViewControllerRepresentable {
let context: FilePreviewViewModel.Context let context: FilePreviewScreenViewModel.Context
let fileURL: URL let fileURL: URL
let title: String? let title: String?
@@ -92,8 +92,8 @@ private class PreviewItem: NSObject, QLPreviewItem {
// MARK: - Previews // MARK: - Previews
struct FilePreview_Previews: PreviewProvider { struct FilePreviewScreen_Previews: PreviewProvider {
static let viewModel = FilePreviewViewModel(mediaFile: .unmanaged(url: URL(staticString: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"))) static let viewModel = FilePreviewScreenViewModel(mediaFile: .unmanaged(url: URL(staticString: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")))
static var previews: some View { static var previews: some View {
FilePreviewScreen(context: viewModel.context) FilePreviewScreen(context: viewModel.context)
@@ -17,29 +17,29 @@
import Combine import Combine
import SwiftUI import SwiftUI
struct InviteUsersCoordinatorParameters { struct InviteUsersScreenCoordinatorParameters {
let userSession: UserSessionProtocol let userSession: UserSessionProtocol
let userDiscoveryService: UserDiscoveryServiceProtocol let userDiscoveryService: UserDiscoveryServiceProtocol
} }
enum InviteUsersCoordinatorAction { enum InviteUsersScreenCoordinatorAction {
case close case close
} }
final class InviteUsersCoordinator: CoordinatorProtocol { final class InviteUsersScreenCoordinator: CoordinatorProtocol {
private let parameters: InviteUsersCoordinatorParameters private let parameters: InviteUsersScreenCoordinatorParameters
private let viewModel: InviteUsersViewModelProtocol private let viewModel: InviteUsersScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<InviteUsersCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<InviteUsersScreenCoordinatorAction, Never> = .init()
private var cancellables: Set<AnyCancellable> = .init() private var cancellables: Set<AnyCancellable> = .init()
var actions: AnyPublisher<InviteUsersCoordinatorAction, Never> { var actions: AnyPublisher<InviteUsersScreenCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(parameters: InviteUsersCoordinatorParameters) { init(parameters: InviteUsersScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = InviteUsersViewModel(userSession: parameters.userSession, userDiscoveryService: parameters.userDiscoveryService) viewModel = InviteUsersScreenViewModel(userSession: parameters.userSession, userDiscoveryService: parameters.userDiscoveryService)
} }
func start() { func start() {
@@ -16,16 +16,16 @@
import Foundation import Foundation
enum InviteUsersErrorType: Error { enum InviteUsersScreenErrorType: Error {
case unknown case unknown
} }
enum InviteUsersViewModelAction { enum InviteUsersScreenViewModelAction {
case close case close
} }
struct InviteUsersViewState: BindableState { struct InviteUsersScreenViewState: BindableState {
var bindings = InviteUsersViewStateBindings() var bindings = InviteUsersScreenViewStateBindings()
var usersSection: UserDiscoverySection = .init(type: .suggestions, users: []) var usersSection: UserDiscoverySection = .init(type: .suggestions, users: [])
var selectedUsers: [UserProfile] = [] var selectedUsers: [UserProfile] = []
@@ -45,14 +45,14 @@ struct InviteUsersViewState: BindableState {
} }
} }
struct InviteUsersViewStateBindings { struct InviteUsersScreenViewStateBindings {
var searchQuery = "" var searchQuery = ""
/// Information describing the currently displayed alert. /// Information describing the currently displayed alert.
var alertInfo: AlertInfo<InviteUsersErrorType>? var alertInfo: AlertInfo<InviteUsersScreenErrorType>?
} }
enum InviteUsersViewAction { enum InviteUsersScreenViewAction {
case close case close
case proceed case proceed
case tapUser(UserProfile) case tapUser(UserProfile)
@@ -17,28 +17,28 @@
import Combine import Combine
import SwiftUI import SwiftUI
typealias InviteUsersViewModelType = StateStoreViewModel<InviteUsersViewState, InviteUsersViewAction> typealias InviteUsersScreenViewModelType = StateStoreViewModel<InviteUsersScreenViewState, InviteUsersScreenViewAction>
class InviteUsersViewModel: InviteUsersViewModelType, InviteUsersViewModelProtocol { class InviteUsersScreenViewModel: InviteUsersScreenViewModelType, InviteUsersScreenViewModelProtocol {
private let userSession: UserSessionProtocol private let userSession: UserSessionProtocol
private let userDiscoveryService: UserDiscoveryServiceProtocol private let userDiscoveryService: UserDiscoveryServiceProtocol
private let actionsSubject: PassthroughSubject<InviteUsersViewModelAction, Never> = .init() private let actionsSubject: PassthroughSubject<InviteUsersScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<InviteUsersViewModelAction, Never> { var actions: AnyPublisher<InviteUsersScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(userSession: UserSessionProtocol, userDiscoveryService: UserDiscoveryServiceProtocol) { init(userSession: UserSessionProtocol, userDiscoveryService: UserDiscoveryServiceProtocol) {
self.userSession = userSession self.userSession = userSession
self.userDiscoveryService = userDiscoveryService self.userDiscoveryService = userDiscoveryService
super.init(initialViewState: InviteUsersViewState(), imageProvider: userSession.mediaProvider) super.init(initialViewState: InviteUsersScreenViewState(), imageProvider: userSession.mediaProvider)
setupSubscriptions() setupSubscriptions()
} }
// MARK: - Public // MARK: - Public
override func process(viewAction: InviteUsersViewAction) { override func process(viewAction: InviteUsersScreenViewAction) {
switch viewAction { switch viewAction {
case .close: case .close:
actionsSubject.send(.close) actionsSubject.send(.close)
@@ -17,7 +17,7 @@
import Combine import Combine
@MainActor @MainActor
protocol InviteUsersViewModelProtocol { protocol InviteUsersScreenViewModelProtocol {
var actions: AnyPublisher<InviteUsersViewModelAction, Never> { get } var actions: AnyPublisher<InviteUsersScreenViewModelAction, Never> { get }
var context: InviteUsersViewModelType.Context { get } var context: InviteUsersScreenViewModelType.Context { get }
} }
@@ -17,7 +17,7 @@
import SwiftUI import SwiftUI
struct InviteUsersScreen: View { struct InviteUsersScreen: View {
@ObservedObject var context: InviteUsersViewModel.Context @ObservedObject var context: InviteUsersScreenViewModel.Context
var body: some View { var body: some View {
VStack { VStack {
@@ -86,7 +86,7 @@ struct InviteUsersScreen: View {
ScrollViewReader { scrollView in ScrollViewReader { scrollView in
HStack(spacing: 28) { HStack(spacing: 28) {
ForEach(context.viewState.selectedUsers, id: \.userID) { user in ForEach(context.viewState.selectedUsers, id: \.userID) { user in
InviteUsersSelectedItem(user: user, imageProvider: context.imageProvider) { InviteUsersScreenSelectedItem(user: user, imageProvider: context.imageProvider) {
deselect(user) deselect(user)
} }
.frame(width: cellWidth) .frame(width: cellWidth)
@@ -123,7 +123,7 @@ struct InviteUsersScreen_Previews: PreviewProvider {
let userDiscoveryService = UserDiscoveryServiceMock() let userDiscoveryService = UserDiscoveryServiceMock()
userDiscoveryService.fetchSuggestionsReturnValue = .success([.mockAlice]) userDiscoveryService.fetchSuggestionsReturnValue = .success([.mockAlice])
userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice]) userDiscoveryService.searchProfilesWithReturnValue = .success([.mockAlice])
return InviteUsersViewModel(userSession: userSession, userDiscoveryService: userDiscoveryService) return InviteUsersScreenViewModel(userSession: userSession, userDiscoveryService: userDiscoveryService)
}() }()
static var previews: some View { static var previews: some View {
@@ -16,7 +16,7 @@
import SwiftUI import SwiftUI
struct InviteUsersSelectedItem: View { struct InviteUsersScreenSelectedItem: View {
let user: UserProfile let user: UserProfile
let imageProvider: ImageProviderProtocol? let imageProvider: ImageProviderProtocol?
let dismissAction: () -> Void let dismissAction: () -> Void
@@ -43,8 +43,8 @@ struct InviteUsersSelectedItem: View {
} }
} }
struct InviteUsersSelectedItem_Previews: PreviewProvider { struct InviteUsersScreenSelectedItem_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
InviteUsersSelectedItem(user: .mockAlice, imageProvider: MockMediaProvider(), dismissAction: { }) InviteUsersScreenSelectedItem(user: .mockAlice, imageProvider: MockMediaProvider(), dismissAction: { })
} }
} }
@@ -17,27 +17,27 @@
import Combine import Combine
import SwiftUI import SwiftUI
struct InvitesCoordinatorParameters { struct InvitesScreenCoordinatorParameters {
let userSession: UserSessionProtocol let userSession: UserSessionProtocol
} }
enum InvitesCoordinatorAction { enum InvitesScreenCoordinatorAction {
case openRoom(withIdentifier: String) case openRoom(withIdentifier: String)
} }
final class InvitesCoordinator: CoordinatorProtocol { final class InvitesScreenCoordinator: CoordinatorProtocol {
private let parameters: InvitesCoordinatorParameters private let parameters: InvitesScreenCoordinatorParameters
private var viewModel: InvitesViewModelProtocol private var viewModel: InvitesScreenViewModelProtocol
private let actionsSubject: PassthroughSubject<InvitesCoordinatorAction, Never> = .init() private let actionsSubject: PassthroughSubject<InvitesScreenCoordinatorAction, Never> = .init()
private var cancellables: Set<AnyCancellable> = .init() private var cancellables: Set<AnyCancellable> = .init()
var actions: AnyPublisher<InvitesCoordinatorAction, Never> { var actions: AnyPublisher<InvitesScreenCoordinatorAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(parameters: InvitesCoordinatorParameters) { init(parameters: InvitesScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = InvitesViewModel(userSession: parameters.userSession) viewModel = InvitesScreenViewModel(userSession: parameters.userSession)
} }
func start() { func start() {
@@ -14,20 +14,20 @@
// limitations under the License. // limitations under the License.
// //
enum InvitesViewModelAction { enum InvitesScreenViewModelAction {
case openRoom(withIdentifier: String) case openRoom(withIdentifier: String)
} }
struct InvitesViewState: BindableState { struct InvitesScreenViewState: BindableState {
var invites: [InvitesRoomDetails]? var invites: [InvitesScreenRoomDetails]?
var bindings: InvitesViewStateBindings = .init() var bindings: InvitesScreenViewStateBindings = .init()
} }
struct InvitesViewStateBindings { struct InvitesScreenViewStateBindings {
var alertInfo: AlertInfo<Bool>? var alertInfo: AlertInfo<Bool>?
} }
struct InvitesRoomDetails { struct InvitesScreenRoomDetails {
let roomDetails: RoomSummaryDetails let roomDetails: RoomSummaryDetails
var inviter: RoomMemberProxyProtocol? var inviter: RoomMemberProxyProtocol?
var isUnread: Bool var isUnread: Bool
@@ -37,7 +37,7 @@ struct InvitesRoomDetails {
} }
} }
enum InvitesViewAction { enum InvitesScreenViewAction {
case accept(InvitesRoomDetails) case accept(InvitesScreenRoomDetails)
case decline(InvitesRoomDetails) case decline(InvitesScreenRoomDetails)
} }
@@ -17,27 +17,27 @@
import Combine import Combine
import SwiftUI import SwiftUI
typealias InvitesViewModelType = StateStoreViewModel<InvitesViewState, InvitesViewAction> typealias InvitesScreenViewModelType = StateStoreViewModel<InvitesScreenViewState, InvitesScreenViewAction>
class InvitesViewModel: InvitesViewModelType, InvitesViewModelProtocol { class InvitesScreenViewModel: InvitesScreenViewModelType, InvitesScreenViewModelProtocol {
private var actionsSubject: PassthroughSubject<InvitesViewModelAction, Never> = .init() private var actionsSubject: PassthroughSubject<InvitesScreenViewModelAction, Never> = .init()
private let userSession: UserSessionProtocol private let userSession: UserSessionProtocol
private let previouslySeenInvites: Set<String> private let previouslySeenInvites: Set<String>
var actions: AnyPublisher<InvitesViewModelAction, Never> { var actions: AnyPublisher<InvitesScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
init(userSession: UserSessionProtocol) { init(userSession: UserSessionProtocol) {
self.userSession = userSession self.userSession = userSession
previouslySeenInvites = ServiceLocator.shared.settings.seenInvites previouslySeenInvites = ServiceLocator.shared.settings.seenInvites
super.init(initialViewState: InvitesViewState(), imageProvider: userSession.mediaProvider) super.init(initialViewState: InvitesScreenViewState(), imageProvider: userSession.mediaProvider)
setupSubscriptions() setupSubscriptions()
} }
// MARK: - Public // MARK: - Public
override func process(viewAction: InvitesViewAction) { override func process(viewAction: InvitesScreenViewAction) {
switch viewAction { switch viewAction {
case .accept(let invite): case .accept(let invite):
accept(invite: invite) accept(invite: invite)
@@ -78,12 +78,12 @@ class InvitesViewModel: InvitesViewModelType, InvitesViewModelProtocol {
.store(in: &cancellables) .store(in: &cancellables)
} }
private func buildInvites(from summaries: [RoomSummary]) -> [InvitesRoomDetails] { private func buildInvites(from summaries: [RoomSummary]) -> [InvitesScreenRoomDetails] {
summaries.compactMap { summary in summaries.compactMap { summary in
guard case .filled(let details) = summary else { guard case .filled(let details) = summary else {
return nil return nil
} }
return InvitesRoomDetails(roomDetails: details, isUnread: !previouslySeenInvites.contains(details.id)) return InvitesScreenRoomDetails(roomDetails: details, isUnread: !previouslySeenInvites.contains(details.id))
} }
} }
@@ -103,7 +103,7 @@ class InvitesViewModel: InvitesViewModelType, InvitesViewModelProtocol {
} }
} }
private func startDeclineFlow(invite: InvitesRoomDetails) { private func startDeclineFlow(invite: InvitesScreenRoomDetails) {
let roomPlaceholder = invite.isDirect ? (invite.inviter?.displayName ?? invite.roomDetails.name) : invite.roomDetails.name let roomPlaceholder = invite.isDirect ? (invite.inviter?.displayName ?? invite.roomDetails.name) : invite.roomDetails.name
let title = invite.isDirect ? L10n.screenInvitesDeclineDirectChatTitle : L10n.screenInvitesDeclineChatTitle let title = invite.isDirect ? L10n.screenInvitesDeclineDirectChatTitle : L10n.screenInvitesDeclineChatTitle
let message = invite.isDirect ? L10n.screenInvitesDeclineDirectChatMessage(roomPlaceholder) : L10n.screenInvitesDeclineChatMessage(roomPlaceholder) let message = invite.isDirect ? L10n.screenInvitesDeclineDirectChatMessage(roomPlaceholder) : L10n.screenInvitesDeclineChatMessage(roomPlaceholder)
@@ -115,7 +115,7 @@ class InvitesViewModel: InvitesViewModelType, InvitesViewModelProtocol {
secondaryButton: .init(title: L10n.actionDecline, role: .destructive, action: { self.decline(invite: invite) })) secondaryButton: .init(title: L10n.actionDecline, role: .destructive, action: { self.decline(invite: invite) }))
} }
private func accept(invite: InvitesRoomDetails) { private func accept(invite: InvitesScreenRoomDetails) {
Task { Task {
let roomID = invite.roomDetails.id let roomID = invite.roomDetails.id
defer { defer {
@@ -138,7 +138,7 @@ class InvitesViewModel: InvitesViewModelType, InvitesViewModelProtocol {
} }
} }
private func decline(invite: InvitesRoomDetails) { private func decline(invite: InvitesScreenRoomDetails) {
Task { Task {
let roomID = invite.roomDetails.id let roomID = invite.roomDetails.id
defer { defer {
@@ -17,7 +17,7 @@
import Combine import Combine
@MainActor @MainActor
protocol BugReportViewModelProtocol { protocol InvitesScreenViewModelProtocol {
var actions: AnyPublisher<BugReportViewModelAction, Never> { get } var actions: AnyPublisher<InvitesScreenViewModelAction, Never> { get }
var context: BugReportViewModelType.Context { get } var context: InvitesScreenViewModelType.Context { get }
} }
@@ -17,7 +17,7 @@
import SwiftUI import SwiftUI
struct InvitesScreen: View { struct InvitesScreen: View {
@ObservedObject var context: InvitesViewModel.Context @ObservedObject var context: InvitesScreenViewModel.Context
var body: some View { var body: some View {
ScrollView { ScrollView {
@@ -56,32 +56,32 @@ struct InvitesScreen: View {
struct InvitesScreen_Previews: PreviewProvider { struct InvitesScreen_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
NavigationView { NavigationView {
InvitesScreen(context: InvitesViewModel.noInvites.context) InvitesScreen(context: InvitesScreenViewModel.noInvites.context)
} }
.previewDisplayName("No Invites") .previewDisplayName("No Invites")
NavigationView { NavigationView {
InvitesScreen(context: InvitesViewModel.someInvite.context) InvitesScreen(context: InvitesScreenViewModel.someInvite.context)
} }
.previewDisplayName("Some Invite") .previewDisplayName("Some Invite")
} }
} }
private extension InvitesViewModel { private extension InvitesScreenViewModel {
static let noInvites: InvitesViewModel = { static let noInvites: InvitesScreenViewModel = {
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "@userid:example.com"), let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "@userid:example.com"),
mediaProvider: MockMediaProvider()) mediaProvider: MockMediaProvider())
let regularViewModel = InvitesViewModel(userSession: userSession) let regularViewModel = InvitesScreenViewModel(userSession: userSession)
return regularViewModel return regularViewModel
}() }()
static let someInvite: InvitesViewModel = { static let someInvite: InvitesScreenViewModel = {
let clientProxy = MockClientProxy(userID: "@userid:example.com") let clientProxy = MockClientProxy(userID: "@userid:example.com")
clientProxy.invitesSummaryProvider = MockRoomSummaryProvider(state: .loaded(.mockInvites)) clientProxy.invitesSummaryProvider = MockRoomSummaryProvider(state: .loaded(.mockInvites))
clientProxy.visibleRoomsSummaryProvider = MockRoomSummaryProvider(state: .loaded(.mockInvites)) clientProxy.visibleRoomsSummaryProvider = MockRoomSummaryProvider(state: .loaded(.mockInvites))
let userSession = MockUserSession(clientProxy: clientProxy, let userSession = MockUserSession(clientProxy: clientProxy,
mediaProvider: MockMediaProvider()) mediaProvider: MockMediaProvider())
let regularViewModel = InvitesViewModel(userSession: userSession) let regularViewModel = InvitesScreenViewModel(userSession: userSession)
return regularViewModel return regularViewModel
}() }()
} }
@@ -18,7 +18,7 @@ import SwiftUI
@MainActor @MainActor
struct InvitesScreenCell: View { struct InvitesScreenCell: View {
let invite: InvitesRoomDetails let invite: InvitesScreenRoomDetails
let imageProvider: ImageProviderProtocol? let imageProvider: ImageProviderProtocol?
let acceptAction: () -> Void let acceptAction: () -> Void
let declineAction: () -> Void let declineAction: () -> Void
@@ -169,8 +169,8 @@ struct InvitesScreenCell_Previews: PreviewProvider {
} }
@MainActor @MainActor
private extension InvitesRoomDetails { private extension InvitesScreenRoomDetails {
static var dm: InvitesRoomDetails { static var dm: InvitesScreenRoomDetails {
let dmRoom = RoomSummaryDetails(id: "@someone:somewhere.com", let dmRoom = RoomSummaryDetails(id: "@someone:somewhere.com",
name: "Some Guy", name: "Some Guy",
isDirect: true, isDirect: true,
@@ -186,7 +186,7 @@ private extension InvitesRoomDetails {
return .init(roomDetails: dmRoom, inviter: inviter, isUnread: false) return .init(roomDetails: dmRoom, inviter: inviter, isUnread: false)
} }
static func room(alias: String?) -> InvitesRoomDetails { static func room(alias: String?) -> InvitesScreenRoomDetails {
let dmRoom = RoomSummaryDetails(id: "@someone:somewhere.com", let dmRoom = RoomSummaryDetails(id: "@someone:somewhere.com",
name: "Awesome Room", name: "Awesome Room",
isDirect: false, isDirect: false,
@@ -16,23 +16,23 @@
import SwiftUI import SwiftUI
enum MediaPickerSource { enum MediaPickerScreenSource {
case camera case camera
case photoLibrary case photoLibrary
case documents case documents
} }
enum MediaPickerCoordinatorAction { enum MediaPickerScreenCoordinatorAction {
case selectMediaAtURL(URL) case selectMediaAtURL(URL)
case cancel case cancel
case error(Error?) case error(Error?)
} }
class MediaPickerCoordinator: CoordinatorProtocol { class MediaPickerScreenCoordinator: CoordinatorProtocol {
private let source: MediaPickerSource private let source: MediaPickerScreenSource
private let callback: ((MediaPickerCoordinatorAction) -> Void)? private let callback: ((MediaPickerScreenCoordinatorAction) -> Void)?
init(source: MediaPickerSource, callback: @escaping (MediaPickerCoordinatorAction) -> Void) { init(source: MediaPickerScreenSource, callback: @escaping (MediaPickerScreenCoordinatorAction) -> Void) {
self.source = source self.source = source
self.callback = callback self.callback = callback
} }
@@ -1,28 +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 SwiftUI
struct UIActivityViewControllerWrapper: UIViewControllerRepresentable {
var activityItems: [Any]
var applicationActivities: [UIActivity]?
func makeUIViewController(context: UIViewControllerRepresentableContext<UIActivityViewControllerWrapper>) -> UIActivityViewController {
UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
}
func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<UIActivityViewControllerWrapper>) { }
}
@@ -17,29 +17,29 @@
import Combine import Combine
import SwiftUI import SwiftUI
struct ReportContentCoordinatorParameters { struct ReportContentScreenCoordinatorParameters {
let itemID: String let itemID: String
let senderID: String let senderID: String
let roomProxy: RoomProxyProtocol let roomProxy: RoomProxyProtocol
weak var userIndicatorController: UserIndicatorControllerProtocol? weak var userIndicatorController: UserIndicatorControllerProtocol?
} }
enum ReportContentCoordinatorAction { enum ReportContentScreenCoordinatorAction {
case cancel case cancel
case finish case finish
} }
final class ReportContentCoordinator: CoordinatorProtocol { final class ReportContentScreenCoordinator: CoordinatorProtocol {
private let parameters: ReportContentCoordinatorParameters private let parameters: ReportContentScreenCoordinatorParameters
private var viewModel: ReportContentViewModelProtocol private var viewModel: ReportContentScreenViewModelProtocol
private var cancellables: Set<AnyCancellable> = .init() private var cancellables: Set<AnyCancellable> = .init()
var callback: ((ReportContentCoordinatorAction) -> Void)? var callback: ((ReportContentScreenCoordinatorAction) -> Void)?
init(parameters: ReportContentCoordinatorParameters) { init(parameters: ReportContentScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = ReportContentViewModel(itemID: parameters.itemID, senderID: parameters.senderID, roomProxy: parameters.roomProxy) viewModel = ReportContentScreenViewModel(itemID: parameters.itemID, senderID: parameters.senderID, roomProxy: parameters.roomProxy)
} }
// MARK: - Public // MARK: - Public
@@ -16,23 +16,23 @@
import Foundation import Foundation
enum ReportContentViewModelAction { enum ReportContentScreenViewModelAction {
case cancel case cancel
case submitStarted case submitStarted
case submitFinished case submitFinished
case submitFailed(error: Error) case submitFailed(error: Error)
} }
struct ReportContentViewState: BindableState { struct ReportContentScreenViewState: BindableState {
var bindings: ReportContentViewStateBindings var bindings: ReportContentScreenViewStateBindings
} }
struct ReportContentViewStateBindings { struct ReportContentScreenViewStateBindings {
var reasonText: String var reasonText: String
var ignoreUser: Bool var ignoreUser: Bool
} }
enum ReportContentViewAction { enum ReportContentScreenViewAction {
case cancel case cancel
case submit case submit
} }
@@ -17,15 +17,15 @@
import Combine import Combine
import SwiftUI import SwiftUI
typealias ReportContentViewModelType = StateStoreViewModel<ReportContentViewState, ReportContentViewAction> typealias ReportContentScreenViewModelType = StateStoreViewModel<ReportContentScreenViewState, ReportContentScreenViewAction>
class ReportContentViewModel: ReportContentViewModelType, ReportContentViewModelProtocol { class ReportContentScreenViewModel: ReportContentScreenViewModelType, ReportContentScreenViewModelProtocol {
private let itemID: String private let itemID: String
private let senderID: String private let senderID: String
private let roomProxy: RoomProxyProtocol private let roomProxy: RoomProxyProtocol
private let actionsSubject: PassthroughSubject<ReportContentViewModelAction, Never> = .init() private let actionsSubject: PassthroughSubject<ReportContentScreenViewModelAction, Never> = .init()
var actions: AnyPublisher<ReportContentViewModelAction, Never> { var actions: AnyPublisher<ReportContentScreenViewModelAction, Never> {
actionsSubject.eraseToAnyPublisher() actionsSubject.eraseToAnyPublisher()
} }
@@ -34,12 +34,12 @@ class ReportContentViewModel: ReportContentViewModelType, ReportContentViewModel
self.senderID = senderID self.senderID = senderID
self.roomProxy = roomProxy self.roomProxy = roomProxy
super.init(initialViewState: ReportContentViewState(bindings: ReportContentViewStateBindings(reasonText: "", ignoreUser: false))) super.init(initialViewState: ReportContentScreenViewState(bindings: ReportContentScreenViewStateBindings(reasonText: "", ignoreUser: false)))
} }
// MARK: - Public // MARK: - Public
override func process(viewAction: ReportContentViewAction) { override func process(viewAction: ReportContentScreenViewAction) {
switch viewAction { switch viewAction {
case .cancel: case .cancel:
actionsSubject.send(.cancel) actionsSubject.send(.cancel)
@@ -18,7 +18,7 @@ import Combine
import Foundation import Foundation
@MainActor @MainActor
protocol ReportContentViewModelProtocol { protocol ReportContentScreenViewModelProtocol {
var actions: AnyPublisher<ReportContentViewModelAction, Never> { get } var actions: AnyPublisher<ReportContentScreenViewModelAction, Never> { get }
var context: ReportContentViewModelType.Context { get } var context: ReportContentScreenViewModelType.Context { get }
} }
@@ -19,7 +19,7 @@ import SwiftUI
struct ReportContentScreen: View { struct ReportContentScreen: View {
@Environment(\.horizontalSizeClass) private var horizontalSizeClass @Environment(\.horizontalSizeClass) private var horizontalSizeClass
@ObservedObject var context: ReportContentViewModel.Context @ObservedObject var context: ReportContentScreenViewModel.Context
private var horizontalPadding: CGFloat { private var horizontalPadding: CGFloat {
horizontalSizeClass == .regular ? 50 : 16 horizontalSizeClass == .regular ? 50 : 16
@@ -83,10 +83,10 @@ struct ReportContentScreen: View {
// MARK: - Previews // MARK: - Previews
struct ReportContent_Previews: PreviewProvider { struct ReportContentScreen_Previews: PreviewProvider {
static let viewModel = ReportContentViewModel(itemID: "", static let viewModel = ReportContentScreenViewModel(itemID: "",
senderID: "", senderID: "",
roomProxy: RoomProxyMock(with: .init(displayName: nil))) roomProxy: RoomProxyMock(with: .init(displayName: nil)))
static var previews: some View { static var previews: some View {
NavigationStack { NavigationStack {
@@ -16,29 +16,29 @@
import SwiftUI import SwiftUI
struct RoomDetailsCoordinatorParameters { struct RoomDetailsScreenCoordinatorParameters {
let navigationStackCoordinator: NavigationStackCoordinator let navigationStackCoordinator: NavigationStackCoordinator
let roomProxy: RoomProxyProtocol let roomProxy: RoomProxyProtocol
let mediaProvider: MediaProviderProtocol let mediaProvider: MediaProviderProtocol
} }
enum RoomDetailsCoordinatorAction { enum RoomDetailsScreenCoordinatorAction {
case cancel case cancel
case leftRoom case leftRoom
} }
final class RoomDetailsCoordinator: CoordinatorProtocol { final class RoomDetailsScreenCoordinator: CoordinatorProtocol {
private let parameters: RoomDetailsCoordinatorParameters private let parameters: RoomDetailsScreenCoordinatorParameters
private var viewModel: RoomDetailsViewModelProtocol private var viewModel: RoomDetailsScreenViewModelProtocol
private var navigationStackCoordinator: NavigationStackCoordinator { parameters.navigationStackCoordinator } private var navigationStackCoordinator: NavigationStackCoordinator { parameters.navigationStackCoordinator }
var callback: ((RoomDetailsCoordinatorAction) -> Void)? var callback: ((RoomDetailsScreenCoordinatorAction) -> Void)?
init(parameters: RoomDetailsCoordinatorParameters) { init(parameters: RoomDetailsScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = RoomDetailsViewModel(roomProxy: parameters.roomProxy, viewModel = RoomDetailsScreenViewModel(roomProxy: parameters.roomProxy,
mediaProvider: parameters.mediaProvider) mediaProvider: parameters.mediaProvider)
} }
// MARK: - Public // MARK: - Public
@@ -57,16 +57,16 @@ final class RoomDetailsCoordinator: CoordinatorProtocol {
} }
} }
} }
func toPresentable() -> AnyView { func toPresentable() -> AnyView {
AnyView(RoomDetailsScreen(context: viewModel.context)) AnyView(RoomDetailsScreen(context: viewModel.context))
} }
private func presentRoomMembersList(_ members: [RoomMemberProxyProtocol]) { private func presentRoomMembersList(_ members: [RoomMemberProxyProtocol]) {
let params = RoomMembersListCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator, let params = RoomMembersListScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator,
mediaProvider: parameters.mediaProvider, mediaProvider: parameters.mediaProvider,
members: members) members: members)
let coordinator = RoomMembersListCoordinator(parameters: params) let coordinator = RoomMembersListScreenCoordinator(parameters: params)
navigationStackCoordinator.push(coordinator) navigationStackCoordinator.push(coordinator)
} }
@@ -21,7 +21,7 @@ import UIKit
// MARK: View model // MARK: View model
enum RoomDetailsViewModelAction { enum RoomDetailsScreenViewModelAction {
case requestMemberDetailsPresentation([RoomMemberProxyProtocol]) case requestMemberDetailsPresentation([RoomMemberProxyProtocol])
case leftRoom case leftRoom
case cancel case cancel
@@ -29,7 +29,7 @@ enum RoomDetailsViewModelAction {
// MARK: View // MARK: View
struct RoomDetailsViewState: BindableState { struct RoomDetailsScreenViewState: BindableState {
let roomId: String let roomId: String
let canonicalAlias: String? let canonicalAlias: String?
let isEncrypted: Bool let isEncrypted: Bool
@@ -45,7 +45,7 @@ struct RoomDetailsViewState: BindableState {
members.isEmpty members.isEmpty
} }
var bindings: RoomDetailsViewStateBindings var bindings: RoomDetailsScreenViewStateBindings
var dmRecipient: RoomMemberDetails? var dmRecipient: RoomMemberDetails?
@@ -54,7 +54,7 @@ struct RoomDetailsViewState: BindableState {
} }
} }
struct RoomDetailsViewStateBindings { struct RoomDetailsScreenViewStateBindings {
struct IgnoreUserAlertItem: AlertItem, Equatable { struct IgnoreUserAlertItem: AlertItem, Equatable {
enum Action { enum Action {
case ignore case ignore
@@ -85,7 +85,7 @@ struct RoomDetailsViewStateBindings {
} }
} }
var viewAction: RoomDetailsViewAction { var viewAction: RoomDetailsScreenViewAction {
switch action { switch action {
case .ignore: return .ignoreConfirmed case .ignore: return .ignoreConfirmed
case .unignore: return .unignoreConfirmed case .unignore: return .unignoreConfirmed
@@ -94,7 +94,7 @@ struct RoomDetailsViewStateBindings {
} }
/// Information describing the currently displayed alert. /// Information describing the currently displayed alert.
var alertInfo: AlertInfo<RoomDetailsErrorType>? var alertInfo: AlertInfo<RoomDetailsScreenErrorType>?
var leaveRoomAlertItem: LeaveRoomAlertItem? var leaveRoomAlertItem: LeaveRoomAlertItem?
var ignoreUserRoomAlertItem: IgnoreUserAlertItem? var ignoreUserRoomAlertItem: IgnoreUserAlertItem?
} }
@@ -120,7 +120,7 @@ struct LeaveRoomAlertItem: AlertItem {
} }
} }
enum RoomDetailsViewAction { enum RoomDetailsScreenViewAction {
case processTapPeople case processTapPeople
case processTapLeave case processTapLeave
case processTapIgnore case processTapIgnore
@@ -130,7 +130,7 @@ enum RoomDetailsViewAction {
case unignoreConfirmed case unignoreConfirmed
} }
enum RoomDetailsErrorType: Hashable { enum RoomDetailsScreenErrorType: Hashable {
/// A specific error message shown in an alert. /// A specific error message shown in an alert.
case alert(String) case alert(String)
/// Leaving room has failed.. /// Leaving room has failed..
@@ -17,9 +17,9 @@
import Combine import Combine
import SwiftUI import SwiftUI
typealias RoomDetailsViewModelType = StateStoreViewModel<RoomDetailsViewState, RoomDetailsViewAction> typealias RoomDetailsScreenViewModelType = StateStoreViewModel<RoomDetailsScreenViewState, RoomDetailsScreenViewAction>
class RoomDetailsViewModel: RoomDetailsViewModelType, RoomDetailsViewModelProtocol { class RoomDetailsScreenViewModel: RoomDetailsScreenViewModelType, RoomDetailsScreenViewModelProtocol {
private let roomProxy: RoomProxyProtocol private let roomProxy: RoomProxyProtocol
private var members: [RoomMemberProxyProtocol] = [] { private var members: [RoomMemberProxyProtocol] = [] {
didSet { didSet {
@@ -42,7 +42,7 @@ class RoomDetailsViewModel: RoomDetailsViewModelType, RoomDetailsViewModelProtoc
} }
} }
var callback: ((RoomDetailsViewModelAction) -> Void)? var callback: ((RoomDetailsScreenViewModelAction) -> Void)?
init(roomProxy: RoomProxyProtocol, init(roomProxy: RoomProxyProtocol,
mediaProvider: MediaProviderProtocol) { mediaProvider: MediaProviderProtocol) {
@@ -70,7 +70,7 @@ class RoomDetailsViewModel: RoomDetailsViewModelType, RoomDetailsViewModelProtoc
// MARK: - Public // MARK: - Public
override func process(viewAction: RoomDetailsViewAction) { override func process(viewAction: RoomDetailsScreenViewAction) {
switch viewAction { switch viewAction {
case .processTapPeople: case .processTapPeople:
callback?(.requestMemberDetailsPresentation(members)) callback?(.requestMemberDetailsPresentation(members))
@@ -17,7 +17,7 @@
import Foundation import Foundation
@MainActor @MainActor
protocol RoomMembersListViewModelProtocol { protocol RoomDetailsScreenViewModelProtocol {
var callback: ((RoomMembersListViewModelAction) -> Void)? { get set } var callback: ((RoomDetailsScreenViewModelAction) -> Void)? { get set }
var context: RoomMembersListViewModelType.Context { get } var context: RoomDetailsScreenViewModelType.Context { get }
} }
@@ -17,7 +17,7 @@
import SwiftUI import SwiftUI
struct RoomDetailsScreen: View { struct RoomDetailsScreen: View {
@ObservedObject var context: RoomDetailsViewModel.Context @ObservedObject var context: RoomDetailsScreenViewModel.Context
var body: some View { var body: some View {
Form { Form {
@@ -199,7 +199,7 @@ struct RoomDetailsScreen: View {
} }
@ViewBuilder @ViewBuilder
private func blockUserAlertActions(_ item: RoomDetailsViewStateBindings.IgnoreUserAlertItem) -> some View { private func blockUserAlertActions(_ item: RoomDetailsScreenViewStateBindings.IgnoreUserAlertItem) -> some View {
Button(item.cancelTitle, role: .cancel) { } Button(item.cancelTitle, role: .cancel) { }
Button(item.confirmationTitle, Button(item.confirmationTitle,
role: item.action == .ignore ? .destructive : nil) { role: item.action == .ignore ? .destructive : nil) {
@@ -207,14 +207,14 @@ struct RoomDetailsScreen: View {
} }
} }
private func blockUserAlertMessage(_ item: RoomDetailsViewStateBindings.IgnoreUserAlertItem) -> some View { private func blockUserAlertMessage(_ item: RoomDetailsScreenViewStateBindings.IgnoreUserAlertItem) -> some View {
Text(item.description) Text(item.description)
} }
} }
// MARK: - Previews // MARK: - Previews
struct RoomDetails_Previews: PreviewProvider { struct RoomDetailsScreen_Previews: PreviewProvider {
static let genericRoomViewModel = { static let genericRoomViewModel = {
let members: [RoomMemberProxyMock] = [ let members: [RoomMemberProxyMock] = [
.mockAlice, .mockAlice,
@@ -228,25 +228,25 @@ struct RoomDetails_Previews: PreviewProvider {
canonicalAlias: "#alias:domain.com", canonicalAlias: "#alias:domain.com",
members: members)) members: members))
return RoomDetailsViewModel(roomProxy: roomProxy, return RoomDetailsScreenViewModel(roomProxy: roomProxy,
mediaProvider: MockMediaProvider()) mediaProvider: MockMediaProvider())
}() }()
static let dmRoomViewModel = { static let dmRoomViewModel = {
let members: [RoomMemberProxyMock] = [ let members: [RoomMemberProxyMock] = [
.mockMe, .mockMe,
.mockDan .mockDan
] ]
let roomProxy = RoomProxyMock(with: .init(displayName: "DM Room", let roomProxy = RoomProxyMock(with: .init(displayName: "DM Room",
topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.", topic: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
isDirect: true, isDirect: true,
isEncrypted: true, isEncrypted: true,
canonicalAlias: "#alias:domain.com", canonicalAlias: "#alias:domain.com",
members: members)) members: members))
return RoomDetailsViewModel(roomProxy: roomProxy, return RoomDetailsScreenViewModel(roomProxy: roomProxy,
mediaProvider: MockMediaProvider()) mediaProvider: MockMediaProvider())
}() }()
static var previews: some View { static var previews: some View {
@@ -16,23 +16,23 @@
import SwiftUI import SwiftUI
struct RoomMemberDetailsCoordinatorParameters { struct RoomMemberDetailsScreenCoordinatorParameters {
let roomMemberProxy: RoomMemberProxyProtocol let roomMemberProxy: RoomMemberProxyProtocol
let mediaProvider: MediaProviderProtocol let mediaProvider: MediaProviderProtocol
} }
enum RoomMemberDetailsCoordinatorAction { } enum RoomMemberDetailsScreenCoordinatorAction { }
final class RoomMemberDetailsCoordinator: CoordinatorProtocol { final class RoomMemberDetailsScreenCoordinator: CoordinatorProtocol {
private let parameters: RoomMemberDetailsCoordinatorParameters private let parameters: RoomMemberDetailsScreenCoordinatorParameters
private var viewModel: RoomMemberDetailsViewModelProtocol private var viewModel: RoomMemberDetailsScreenViewModelProtocol
var callback: ((RoomMemberDetailsCoordinatorAction) -> Void)? var callback: ((RoomMemberDetailsScreenCoordinatorAction) -> Void)?
init(parameters: RoomMemberDetailsCoordinatorParameters) { init(parameters: RoomMemberDetailsScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: parameters.roomMemberProxy, mediaProvider: parameters.mediaProvider) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: parameters.roomMemberProxy, mediaProvider: parameters.mediaProvider)
} }
func start() { } func start() { }
@@ -16,16 +16,16 @@
import Foundation import Foundation
enum RoomMemberDetailsViewModelAction { } enum RoomMemberDetailsScreenViewModelAction { }
struct RoomMemberDetailsViewState: BindableState { struct RoomMemberDetailsScreenViewState: BindableState {
var details: RoomMemberDetails var details: RoomMemberDetails
var isProcessingIgnoreRequest = false var isProcessingIgnoreRequest = false
var bindings: RoomMemberDetailsViewStateBindings var bindings: RoomMemberDetailsScreenViewStateBindings
} }
struct RoomMemberDetailsViewStateBindings { struct RoomMemberDetailsScreenViewStateBindings {
struct IgnoreUserAlertItem: AlertItem, Equatable { struct IgnoreUserAlertItem: AlertItem, Equatable {
enum Action { enum Action {
case ignore case ignore
@@ -56,7 +56,7 @@ struct RoomMemberDetailsViewStateBindings {
} }
} }
var viewAction: RoomMemberDetailsViewAction { var viewAction: RoomMemberDetailsScreenViewAction {
switch action { switch action {
case .ignore: return .ignoreConfirmed case .ignore: return .ignoreConfirmed
case .unignore: return .unignoreConfirmed case .unignore: return .unignoreConfirmed
@@ -68,7 +68,7 @@ struct RoomMemberDetailsViewStateBindings {
var errorAlert: ErrorAlertItem? var errorAlert: ErrorAlertItem?
} }
enum RoomMemberDetailsViewAction { enum RoomMemberDetailsScreenViewAction {
case showUnignoreAlert case showUnignoreAlert
case showIgnoreAlert case showIgnoreAlert
case ignoreConfirmed case ignoreConfirmed
@@ -16,23 +16,23 @@
import SwiftUI import SwiftUI
typealias RoomMemberDetailsViewModelType = StateStoreViewModel<RoomMemberDetailsViewState, RoomMemberDetailsViewAction> typealias RoomMemberDetailsScreenViewModelType = StateStoreViewModel<RoomMemberDetailsScreenViewState, RoomMemberDetailsScreenViewAction>
class RoomMemberDetailsViewModel: RoomMemberDetailsViewModelType, RoomMemberDetailsViewModelProtocol { class RoomMemberDetailsScreenViewModel: RoomMemberDetailsScreenViewModelType, RoomMemberDetailsScreenViewModelProtocol {
let roomMemberProxy: RoomMemberProxyProtocol let roomMemberProxy: RoomMemberProxyProtocol
var callback: ((RoomMemberDetailsViewModelAction) -> Void)? var callback: ((RoomMemberDetailsScreenViewModelAction) -> Void)?
init(roomMemberProxy: RoomMemberProxyProtocol, mediaProvider: MediaProviderProtocol) { init(roomMemberProxy: RoomMemberProxyProtocol, mediaProvider: MediaProviderProtocol) {
self.roomMemberProxy = roomMemberProxy self.roomMemberProxy = roomMemberProxy
let initialViewState = RoomMemberDetailsViewState(details: RoomMemberDetails(withProxy: roomMemberProxy), let initialViewState = RoomMemberDetailsScreenViewState(details: RoomMemberDetails(withProxy: roomMemberProxy),
bindings: .init()) bindings: .init())
super.init(initialViewState: initialViewState, imageProvider: mediaProvider) super.init(initialViewState: initialViewState, imageProvider: mediaProvider)
} }
// MARK: - Public // MARK: - Public
override func process(viewAction: RoomMemberDetailsViewAction) { override func process(viewAction: RoomMemberDetailsScreenViewAction) {
switch viewAction { switch viewAction {
case .showUnignoreAlert: case .showUnignoreAlert:
state.bindings.ignoreUserAlert = .init(action: .unignore) state.bindings.ignoreUserAlert = .init(action: .unignore)
@@ -17,7 +17,7 @@
import Foundation import Foundation
@MainActor @MainActor
protocol RoomDetailsViewModelProtocol { protocol RoomMemberDetailsScreenViewModelProtocol {
var callback: ((RoomDetailsViewModelAction) -> Void)? { get set } var callback: ((RoomMemberDetailsScreenViewModelAction) -> Void)? { get set }
var context: RoomDetailsViewModelType.Context { get } var context: RoomMemberDetailsScreenViewModelType.Context { get }
} }
@@ -17,7 +17,7 @@
import SwiftUI import SwiftUI
struct RoomMemberDetailsScreen: View { struct RoomMemberDetailsScreen: View {
@ObservedObject var context: RoomMemberDetailsViewModel.Context @ObservedObject var context: RoomMemberDetailsScreenViewModel.Context
var body: some View { var body: some View {
Form { Form {
@@ -69,7 +69,7 @@ struct RoomMemberDetailsScreen: View {
.formSectionStyle() .formSectionStyle()
} }
private var blockUserButtonAction: RoomMemberDetailsViewAction { private var blockUserButtonAction: RoomMemberDetailsScreenViewAction {
context.viewState.details.isIgnored ? .showUnignoreAlert : .showIgnoreAlert context.viewState.details.isIgnored ? .showUnignoreAlert : .showIgnoreAlert
} }
@@ -82,7 +82,7 @@ struct RoomMemberDetailsScreen: View {
} }
@ViewBuilder @ViewBuilder
private func blockUserAlertActions(_ item: RoomMemberDetailsViewStateBindings.IgnoreUserAlertItem) -> some View { private func blockUserAlertActions(_ item: RoomMemberDetailsScreenViewStateBindings.IgnoreUserAlertItem) -> some View {
Button(item.cancelTitle, role: .cancel) { } Button(item.cancelTitle, role: .cancel) { }
Button(item.confirmationTitle, Button(item.confirmationTitle,
role: item.action == .ignore ? .destructive : nil) { role: item.action == .ignore ? .destructive : nil) {
@@ -90,27 +90,27 @@ struct RoomMemberDetailsScreen: View {
} }
} }
private func blockUserAlertMessage(_ item: RoomMemberDetailsViewStateBindings.IgnoreUserAlertItem) -> some View { private func blockUserAlertMessage(_ item: RoomMemberDetailsScreenViewStateBindings.IgnoreUserAlertItem) -> some View {
Text(item.description) Text(item.description)
} }
} }
// MARK: - Previews // MARK: - Previews
struct RoomMemberDetails_Previews: PreviewProvider { struct RoomMemberDetailsScreen_Previews: PreviewProvider {
static let otherUserViewModel = { static let otherUserViewModel = {
let member = RoomMemberProxyMock.mockDan let member = RoomMemberProxyMock.mockDan
return RoomMemberDetailsViewModel(roomMemberProxy: member, mediaProvider: MockMediaProvider()) return RoomMemberDetailsScreenViewModel(roomMemberProxy: member, mediaProvider: MockMediaProvider())
}() }()
static let accountOwnerViewModel = { static let accountOwnerViewModel = {
let member = RoomMemberProxyMock.mockMe let member = RoomMemberProxyMock.mockMe
return RoomMemberDetailsViewModel(roomMemberProxy: member, mediaProvider: MockMediaProvider()) return RoomMemberDetailsScreenViewModel(roomMemberProxy: member, mediaProvider: MockMediaProvider())
}() }()
static let ignoredUserViewModel = { static let ignoredUserViewModel = {
let member = RoomMemberProxyMock.mockIgnored let member = RoomMemberProxyMock.mockIgnored
return RoomMemberDetailsViewModel(roomMemberProxy: member, mediaProvider: MockMediaProvider()) return RoomMemberDetailsScreenViewModel(roomMemberProxy: member, mediaProvider: MockMediaProvider())
}() }()
static var previews: some View { static var previews: some View {
@@ -16,26 +16,26 @@
import SwiftUI import SwiftUI
struct RoomMembersListCoordinatorParameters { struct RoomMembersListScreenCoordinatorParameters {
let navigationStackCoordinator: NavigationStackCoordinator let navigationStackCoordinator: NavigationStackCoordinator
let mediaProvider: MediaProviderProtocol let mediaProvider: MediaProviderProtocol
let members: [RoomMemberProxyProtocol] let members: [RoomMemberProxyProtocol]
} }
enum RoomMembersListCoordinatorAction { } enum RoomMembersListScreenCoordinatorAction { }
final class RoomMembersListCoordinator: CoordinatorProtocol { final class RoomMembersListScreenCoordinator: CoordinatorProtocol {
private let parameters: RoomMembersListCoordinatorParameters private let parameters: RoomMembersListScreenCoordinatorParameters
private var viewModel: RoomMembersListViewModelProtocol private var viewModel: RoomMembersListScreenViewModelProtocol
private var navigationStackCoordinator: NavigationStackCoordinator { parameters.navigationStackCoordinator } private var navigationStackCoordinator: NavigationStackCoordinator { parameters.navigationStackCoordinator }
var callback: ((RoomMembersListCoordinatorAction) -> Void)? var callback: ((RoomMembersListScreenCoordinatorAction) -> Void)?
init(parameters: RoomMembersListCoordinatorParameters) { init(parameters: RoomMembersListScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = RoomMembersListViewModel(mediaProvider: parameters.mediaProvider, viewModel = RoomMembersListScreenViewModel(mediaProvider: parameters.mediaProvider,
members: parameters.members) members: parameters.members)
} }
func start() { func start() {
@@ -56,8 +56,8 @@ final class RoomMembersListCoordinator: CoordinatorProtocol {
// MARK: - Private // MARK: - Private
private func selectMember(_ member: RoomMemberProxyProtocol) { private func selectMember(_ member: RoomMemberProxyProtocol) {
let parameters = RoomMemberDetailsCoordinatorParameters(roomMemberProxy: member, mediaProvider: parameters.mediaProvider) let parameters = RoomMemberDetailsScreenCoordinatorParameters(roomMemberProxy: member, mediaProvider: parameters.mediaProvider)
let coordinator = RoomMemberDetailsCoordinator(parameters: parameters) let coordinator = RoomMemberDetailsScreenCoordinator(parameters: parameters)
navigationStackCoordinator.push(coordinator) navigationStackCoordinator.push(coordinator)
} }
@@ -16,14 +16,14 @@
import Foundation import Foundation
enum RoomMembersListViewModelAction { enum RoomMembersListScreenViewModelAction {
case selectMember(_ member: RoomMemberProxyProtocol) case selectMember(_ member: RoomMemberProxyProtocol)
} }
struct RoomMembersListViewState: BindableState { struct RoomMembersListScreenViewState: BindableState {
var members: [RoomMemberDetails] var members: [RoomMemberDetails]
var bindings: RoomMembersListViewStateBindings var bindings: RoomMembersListScreenViewStateBindings
var visibleMembers: [RoomMemberDetails] { var visibleMembers: [RoomMemberDetails] {
if bindings.searchQuery.isEmpty { if bindings.searchQuery.isEmpty {
@@ -37,13 +37,13 @@ struct RoomMembersListViewState: BindableState {
} }
} }
struct RoomMembersListViewStateBindings { struct RoomMembersListScreenViewStateBindings {
var searchQuery = "" var searchQuery = ""
/// Information describing the currently displayed alert. /// Information describing the currently displayed alert.
var alertInfo: AlertInfo<RoomDetailsErrorType>? var alertInfo: AlertInfo<RoomDetailsScreenErrorType>?
} }
enum RoomMembersListViewAction { enum RoomMembersListScreenViewAction {
case selectMember(id: String) case selectMember(id: String)
} }
@@ -16,13 +16,13 @@
import SwiftUI import SwiftUI
typealias RoomMembersListViewModelType = StateStoreViewModel<RoomMembersListViewState, RoomMembersListViewAction> typealias RoomMembersListScreenViewModelType = StateStoreViewModel<RoomMembersListScreenViewState, RoomMembersListScreenViewAction>
class RoomMembersListViewModel: RoomMembersListViewModelType, RoomMembersListViewModelProtocol { class RoomMembersListScreenViewModel: RoomMembersListScreenViewModelType, RoomMembersListScreenViewModelProtocol {
private let mediaProvider: MediaProviderProtocol private let mediaProvider: MediaProviderProtocol
private let members: [RoomMemberProxyProtocol] private let members: [RoomMemberProxyProtocol]
var callback: ((RoomMembersListViewModelAction) -> Void)? var callback: ((RoomMembersListScreenViewModelAction) -> Void)?
init(mediaProvider: MediaProviderProtocol, init(mediaProvider: MediaProviderProtocol,
members: [RoomMemberProxyProtocol]) { members: [RoomMemberProxyProtocol]) {
@@ -35,7 +35,7 @@ class RoomMembersListViewModel: RoomMembersListViewModelType, RoomMembersListVie
// MARK: - Public // MARK: - Public
override func process(viewAction: RoomMembersListViewAction) { override func process(viewAction: RoomMembersListScreenViewAction) {
switch viewAction { switch viewAction {
case .selectMember(let id): case .selectMember(let id):
guard let member = members.first(where: { $0.userID == id }) else { guard let member = members.first(where: { $0.userID == id }) else {
@@ -17,7 +17,7 @@
import Foundation import Foundation
@MainActor @MainActor
protocol FilePreviewViewModelProtocol { protocol RoomMembersListScreenViewModelProtocol {
var callback: ((FilePreviewViewModelAction) -> Void)? { get set } var callback: ((RoomMembersListScreenViewModelAction) -> Void)? { get set }
var context: FilePreviewViewModelType.Context { get } var context: RoomMembersListScreenViewModelType.Context { get }
} }
@@ -19,14 +19,14 @@ import SwiftUI
struct RoomMembersListScreen: View { struct RoomMembersListScreen: View {
@Environment(\.colorScheme) private var colorScheme @Environment(\.colorScheme) private var colorScheme
@ObservedObject var context: RoomMembersListViewModel.Context @ObservedObject var context: RoomMembersListScreenViewModel.Context
var body: some View { var body: some View {
ScrollView { ScrollView {
LazyVStack(alignment: .leading) { LazyVStack(alignment: .leading) {
Section { Section {
ForEach(context.viewState.visibleMembers) { member in ForEach(context.viewState.visibleMembers) { member in
RoomMembersListMemberCell(member: member, context: context) RoomMembersListScreenMemberCell(member: member, context: context)
.id(member.id) .id(member.id)
} }
} header: { } header: {
@@ -48,15 +48,15 @@ struct RoomMembersListScreen: View {
// MARK: - Previews // MARK: - Previews
struct RoomMembersList_Previews: PreviewProvider { struct RoomMembersListScreen_Previews: PreviewProvider {
static let viewModel = { static let viewModel = {
let members: [RoomMemberProxyMock] = [ let members: [RoomMemberProxyMock] = [
.mockAlice, .mockAlice,
.mockBob, .mockBob,
.mockCharlie .mockCharlie
] ]
return RoomMembersListViewModel(mediaProvider: MockMediaProvider(), return RoomMembersListScreenViewModel(mediaProvider: MockMediaProvider(),
members: members) members: members)
}() }()
static var previews: some View { static var previews: some View {
@@ -16,11 +16,11 @@
import SwiftUI import SwiftUI
struct RoomMembersListMemberCell: View { struct RoomMembersListScreenMemberCell: View {
@ScaledMetric private var avatarSize = AvatarSize.user(on: .roomDetails).value @ScaledMetric private var avatarSize = AvatarSize.user(on: .roomDetails).value
let member: RoomMemberDetails let member: RoomMemberDetails
let context: RoomMembersListViewModel.Context let context: RoomMembersListScreenViewModel.Context
var body: some View { var body: some View {
Button { Button {
@@ -53,12 +53,12 @@ struct RoomMembersListMemberCell_Previews: PreviewProvider {
.mockBob, .mockBob,
.mockCharlie .mockCharlie
] ]
let viewModel = RoomMembersListViewModel(mediaProvider: MockMediaProvider(), let viewModel = RoomMembersListScreenViewModel(mediaProvider: MockMediaProvider(),
members: members) members: members)
return VStack { return VStack {
ForEach(members, id: \.userID) { member in ForEach(members, id: \.userID) { member in
RoomMembersListMemberCell(member: .init(withProxy: member), context: viewModel.context) RoomMembersListScreenMemberCell(member: .init(withProxy: member), context: viewModel.context)
} }
} }
} }
@@ -83,8 +83,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
// MARK: - Private // MARK: - Private
private func displayMediaPickerWithSource(_ source: MediaPickerSource) { private func displayMediaPickerWithSource(_ source: MediaPickerScreenSource) {
let mediaPickerCoordinator = MediaPickerCoordinator(source: source) { [weak self] action in let mediaPickerCoordinator = MediaPickerScreenCoordinator(source: source) { [weak self] action in
switch action { switch action {
case .cancel: case .cancel:
self?.navigationStackCoordinator.setSheetCoordinator(nil) self?.navigationStackCoordinator.setSheetCoordinator(nil)
@@ -125,8 +125,8 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
} }
private func displayFilePreview(for file: MediaFileHandleProxy, with title: String?) { private func displayFilePreview(for file: MediaFileHandleProxy, with title: String?) {
let params = FilePreviewCoordinatorParameters(mediaFile: file, title: title) let params = FilePreviewScreenCoordinatorParameters(mediaFile: file, title: title)
let coordinator = FilePreviewCoordinator(parameters: params) let coordinator = FilePreviewScreenCoordinator(parameters: params)
coordinator.callback = { [weak self] _ in coordinator.callback = { [weak self] _ in
self?.navigationStackCoordinator.pop() self?.navigationStackCoordinator.pop()
} }
@@ -160,10 +160,10 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
} }
private func displayRoomDetails() { private func displayRoomDetails() {
let params = RoomDetailsCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator, let params = RoomDetailsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator,
roomProxy: parameters.roomProxy, roomProxy: parameters.roomProxy,
mediaProvider: parameters.mediaProvider) mediaProvider: parameters.mediaProvider)
let coordinator = RoomDetailsCoordinator(parameters: params) let coordinator = RoomDetailsScreenCoordinator(parameters: params)
coordinator.callback = { [weak self] action in coordinator.callback = { [weak self] action in
switch action { switch action {
case .cancel: case .cancel:
@@ -175,15 +175,15 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
navigationStackCoordinator.push(coordinator) navigationStackCoordinator.push(coordinator)
} }
private func displayReportContent(for itemID: String, from senderID: String) { private func displayReportContent(for itemID: String, from senderID: String) {
let navigationCoordinator = NavigationStackCoordinator() let navigationCoordinator = NavigationStackCoordinator()
let userIndicatorController = UserIndicatorController(rootCoordinator: navigationCoordinator) let userIndicatorController = UserIndicatorController(rootCoordinator: navigationCoordinator)
let parameters = ReportContentCoordinatorParameters(itemID: itemID, let parameters = ReportContentScreenCoordinatorParameters(itemID: itemID,
senderID: senderID, senderID: senderID,
roomProxy: parameters.roomProxy, roomProxy: parameters.roomProxy,
userIndicatorController: userIndicatorController) userIndicatorController: userIndicatorController)
let coordinator = ReportContentCoordinator(parameters: parameters) let coordinator = ReportContentScreenCoordinator(parameters: parameters)
coordinator.callback = { [weak self] completion in coordinator.callback = { [weak self] completion in
self?.navigationStackCoordinator.setSheetCoordinator(nil) self?.navigationStackCoordinator.setSheetCoordinator(nil)
switch completion { switch completion {
@@ -16,20 +16,20 @@
import SwiftUI import SwiftUI
struct SessionVerificationCoordinatorParameters { struct SessionVerificationScreenCoordinatorParameters {
let sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol let sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol
} }
final class SessionVerificationCoordinator: CoordinatorProtocol { final class SessionVerificationScreenCoordinator: CoordinatorProtocol {
private let parameters: SessionVerificationCoordinatorParameters private let parameters: SessionVerificationScreenCoordinatorParameters
private var viewModel: SessionVerificationViewModelProtocol private var viewModel: SessionVerificationScreenViewModelProtocol
var callback: (() -> Void)? var callback: (() -> Void)?
init(parameters: SessionVerificationCoordinatorParameters) { init(parameters: SessionVerificationScreenCoordinatorParameters) {
self.parameters = parameters self.parameters = parameters
viewModel = SessionVerificationViewModel(sessionVerificationControllerProxy: parameters.sessionVerificationControllerProxy) viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: parameters.sessionVerificationControllerProxy)
} }
// MARK: - Public // MARK: - Public
@@ -16,12 +16,12 @@
import Foundation import Foundation
enum SessionVerificationViewModelAction { enum SessionVerificationScreenViewModelAction {
case finished case finished
} }
struct SessionVerificationViewState: BindableState { struct SessionVerificationScreenViewState: BindableState {
var verificationState: SessionVerificationStateMachine.State = .initial var verificationState: SessionVerificationScreenStateMachine.State = .initial
var title: String? { var title: String? {
switch verificationState { switch verificationState {
@@ -78,7 +78,7 @@ struct SessionVerificationViewState: BindableState {
} }
} }
enum SessionVerificationViewAction { enum SessionVerificationScreenViewAction {
case requestVerification case requestVerification
case startSasVerification case startSasVerification
case restart case restart
@@ -17,7 +17,7 @@
import Foundation import Foundation
import SwiftState import SwiftState
class SessionVerificationStateMachine { class SessionVerificationScreenStateMachine {
/// States the SessionVerificationViewModel can find itself in /// States the SessionVerificationViewModel can find itself in
enum State: StateType { enum State: StateType {
/// The initial state, before verification started /// The initial state, before verification started
@@ -16,20 +16,20 @@
import SwiftUI import SwiftUI
typealias SessionVerificationViewModelType = StateStoreViewModel<SessionVerificationViewState, SessionVerificationViewAction> typealias SessionVerificationViewModelType = StateStoreViewModel<SessionVerificationScreenViewState, SessionVerificationScreenViewAction>
class SessionVerificationViewModel: SessionVerificationViewModelType, SessionVerificationViewModelProtocol { class SessionVerificationScreenViewModel: SessionVerificationViewModelType, SessionVerificationScreenViewModelProtocol {
private let sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol private let sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol
private var stateMachine: SessionVerificationStateMachine private var stateMachine: SessionVerificationScreenStateMachine
var callback: ((SessionVerificationViewModelAction) -> Void)? var callback: ((SessionVerificationScreenViewModelAction) -> Void)?
init(sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol, init(sessionVerificationControllerProxy: SessionVerificationControllerProxyProtocol,
initialState: SessionVerificationViewState = SessionVerificationViewState()) { initialState: SessionVerificationScreenViewState = SessionVerificationScreenViewState()) {
self.sessionVerificationControllerProxy = sessionVerificationControllerProxy self.sessionVerificationControllerProxy = sessionVerificationControllerProxy
stateMachine = SessionVerificationStateMachine() stateMachine = SessionVerificationScreenStateMachine()
super.init(initialViewState: initialState) super.init(initialViewState: initialState)
@@ -63,7 +63,7 @@ class SessionVerificationViewModel: SessionVerificationViewModelType, SessionVer
.store(in: &cancellables) .store(in: &cancellables)
} }
override func process(viewAction: SessionVerificationViewAction) { override func process(viewAction: SessionVerificationScreenViewAction) {
switch viewAction { switch viewAction {
case .requestVerification: case .requestVerification:
stateMachine.processEvent(.requestVerification) stateMachine.processEvent(.requestVerification)
@@ -17,7 +17,7 @@
import Foundation import Foundation
@MainActor @MainActor
protocol SessionVerificationViewModelProtocol { protocol SessionVerificationScreenViewModelProtocol {
var callback: ((SessionVerificationViewModelAction) -> Void)? { get set } var callback: ((SessionVerificationScreenViewModelAction) -> Void)? { get set }
var context: SessionVerificationViewModelType.Context { get } var context: SessionVerificationViewModelType.Context { get }
} }
@@ -17,7 +17,7 @@
import SwiftUI import SwiftUI
struct SessionVerificationScreen: View { struct SessionVerificationScreen: View {
@ObservedObject var context: SessionVerificationViewModel.Context @ObservedObject var context: SessionVerificationScreenViewModel.Context
var body: some View { var body: some View {
NavigationStack { NavigationStack {
@@ -245,9 +245,9 @@ struct SessionVerification_Previews: PreviewProvider {
.previewDisplayName("Verified") .previewDisplayName("Verified")
} }
static func sessionVerificationScreen(state: SessionVerificationStateMachine.State) -> some View { static func sessionVerificationScreen(state: SessionVerificationScreenStateMachine.State) -> some View {
let viewModel = SessionVerificationViewModel(sessionVerificationControllerProxy: SessionVerificationControllerProxyMock.configureMock(), let viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: SessionVerificationControllerProxyMock.configureMock(),
initialState: SessionVerificationViewState(verificationState: state)) initialState: SessionVerificationScreenViewState(verificationState: state))
return SessionVerificationScreen(context: viewModel.context) return SessionVerificationScreen(context: viewModel.context)
} }
@@ -74,13 +74,13 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
} }
private func presentBugReportScreen() { private func presentBugReportScreen() {
let params = BugReportCoordinatorParameters(bugReportService: parameters.bugReportService, let params = BugReportScreenCoordinatorParameters(bugReportService: parameters.bugReportService,
userID: parameters.userSession.userID, userID: parameters.userSession.userID,
deviceID: parameters.userSession.deviceID, deviceID: parameters.userSession.deviceID,
userIndicatorController: parameters.userIndicatorController, userIndicatorController: parameters.userIndicatorController,
screenshot: nil, screenshot: nil,
isModallyPresented: false) isModallyPresented: false)
let coordinator = BugReportCoordinator(parameters: params) let coordinator = BugReportScreenCoordinator(parameters: params)
coordinator.completion = { [weak self] result in coordinator.completion = { [weak self] result in
switch result { switch result {
case .finish: case .finish:
@@ -100,8 +100,8 @@ final class SettingsScreenCoordinator: CoordinatorProtocol {
fatalError("The sessionVerificationController should aways be valid at this point") fatalError("The sessionVerificationController should aways be valid at this point")
} }
let verificationParameters = SessionVerificationCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController) let verificationParameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController)
let coordinator = SessionVerificationCoordinator(parameters: verificationParameters) let coordinator = SessionVerificationScreenCoordinator(parameters: verificationParameters)
coordinator.callback = { [weak self] in coordinator.callback = { [weak self] in
self?.parameters.navigationStackCoordinator?.setSheetCoordinator(nil) self?.parameters.navigationStackCoordinator?.setSheetCoordinator(nil)
@@ -70,8 +70,8 @@ final class StartChatCoordinator: CoordinatorProtocol {
// MARK: - Private // MARK: - Private
private func presentInviteUsersScreen() { private func presentInviteUsersScreen() {
let inviteParameters = InviteUsersCoordinatorParameters(userSession: parameters.userSession, userDiscoveryService: parameters.userDiscoveryService) let inviteParameters = InviteUsersScreenCoordinatorParameters(userSession: parameters.userSession, userDiscoveryService: parameters.userDiscoveryService)
let coordinator = InviteUsersCoordinator(parameters: inviteParameters) let coordinator = InviteUsersScreenCoordinator(parameters: inviteParameters)
coordinator.actions.sink { [weak self] result in coordinator.actions.sink { [weak self] result in
switch result { switch result {
case .close: case .close:
@@ -269,9 +269,9 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
fatalError("The sessionVerificationController should aways be valid at this point") fatalError("The sessionVerificationController should aways be valid at this point")
} }
let parameters = SessionVerificationCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController) let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationController)
let coordinator = SessionVerificationCoordinator(parameters: parameters) let coordinator = SessionVerificationScreenCoordinator(parameters: parameters)
coordinator.callback = { [weak self] in coordinator.callback = { [weak self] in
self?.navigationSplitCoordinator.setSheetCoordinator(nil) self?.navigationSplitCoordinator.setSheetCoordinator(nil)
@@ -309,7 +309,7 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
self?.stateMachine.processEvent(.dismissedStartChatScreen) self?.stateMachine.processEvent(.dismissedStartChatScreen)
} }
} }
// MARK: Bug reporting // MARK: Bug reporting
private func presentFeedbackScreen(animated: Bool, for image: UIImage? = nil) { private func presentFeedbackScreen(animated: Bool, for image: UIImage? = nil) {
@@ -317,13 +317,13 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
let userIndicatorController = UserIndicatorController(rootCoordinator: feedbackNavigationStackCoordinator) let userIndicatorController = UserIndicatorController(rootCoordinator: feedbackNavigationStackCoordinator)
let parameters = BugReportCoordinatorParameters(bugReportService: bugReportService, let parameters = BugReportScreenCoordinatorParameters(bugReportService: bugReportService,
userID: userSession.userID, userID: userSession.userID,
deviceID: userSession.deviceID, deviceID: userSession.deviceID,
userIndicatorController: userIndicatorController, userIndicatorController: userIndicatorController,
screenshot: image, screenshot: image,
isModallyPresented: true) isModallyPresented: true)
let coordinator = BugReportCoordinator(parameters: parameters) let coordinator = BugReportScreenCoordinator(parameters: parameters)
coordinator.completion = { [weak self] _ in coordinator.completion = { [weak self] _ in
self?.navigationSplitCoordinator.setSheetCoordinator(nil) self?.navigationSplitCoordinator.setSheetCoordinator(nil)
} }
@@ -338,8 +338,8 @@ class UserSessionFlowCoordinator: CoordinatorProtocol {
// MARK: Invites list // MARK: Invites list
private func presentInvitesList(animated: Bool) { private func presentInvitesList(animated: Bool) {
let parameters = InvitesCoordinatorParameters(userSession: userSession) let parameters = InvitesScreenCoordinatorParameters(userSession: userSession)
let coordinator = InvitesCoordinator(parameters: parameters) let coordinator = InvitesScreenCoordinator(parameters: parameters)
coordinator.actions coordinator.actions
.sink { [weak self] action in .sink { [weak self] action in
@@ -78,7 +78,7 @@ class MockScreen: Identifiable {
userIndicatorController: MockUserIndicatorController(), userIndicatorController: MockUserIndicatorController(),
isModallyPresented: false)) isModallyPresented: false))
case .analyticsPrompt: case .analyticsPrompt:
return AnalyticsPromptCoordinator() return AnalyticsPromptScreenCoordinator()
case .analyticsSettingsScreen: case .analyticsSettingsScreen:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = AnalyticsSettingsScreenCoordinator() let coordinator = AnalyticsSettingsScreenCoordinator()
@@ -124,22 +124,22 @@ class MockScreen: Identifiable {
return navigationStackCoordinator return navigationStackCoordinator
case .bugReport: case .bugReport:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = BugReportCoordinator(parameters: .init(bugReportService: BugReportServiceMock(), let coordinator = BugReportScreenCoordinator(parameters: .init(bugReportService: BugReportServiceMock(),
userID: "@mock:client.com", userID: "@mock:client.com",
deviceID: nil, deviceID: nil,
userIndicatorController: nil, userIndicatorController: nil,
screenshot: nil, screenshot: nil,
isModallyPresented: true)) isModallyPresented: true))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .bugReportWithScreenshot: case .bugReportWithScreenshot:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = BugReportCoordinator(parameters: .init(bugReportService: BugReportServiceMock(), let coordinator = BugReportScreenCoordinator(parameters: .init(bugReportService: BugReportServiceMock(),
userID: "@mock:client.com", userID: "@mock:client.com",
deviceID: nil, deviceID: nil,
userIndicatorController: nil, userIndicatorController: nil,
screenshot: Asset.Images.appLogo.image, screenshot: Asset.Images.appLogo.image,
isModallyPresented: false)) isModallyPresented: false))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .onboarding: case .onboarding:
@@ -255,8 +255,8 @@ class MockScreen: Identifiable {
return navigationStackCoordinator return navigationStackCoordinator
case .sessionVerification: case .sessionVerification:
var sessionVerificationControllerProxy = SessionVerificationControllerProxyMock.configureMock(requestDelay: .seconds(2)) var sessionVerificationControllerProxy = SessionVerificationControllerProxyMock.configureMock(requestDelay: .seconds(2))
let parameters = SessionVerificationCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy) let parameters = SessionVerificationScreenCoordinatorParameters(sessionVerificationControllerProxy: sessionVerificationControllerProxy)
return SessionVerificationCoordinator(parameters: parameters) return SessionVerificationScreenCoordinator(parameters: parameters)
case .userSessionScreen: case .userSessionScreen:
let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: SplashScreenCoordinator()) let navigationSplitCoordinator = NavigationSplitCoordinator(placeholderCoordinator: SplashScreenCoordinator())
@@ -279,9 +279,9 @@ class MockScreen: Identifiable {
displayName: "Room", displayName: "Room",
isEncrypted: true, isEncrypted: true,
members: members)) members: members))
let coordinator = RoomDetailsCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator, let coordinator = RoomDetailsScreenCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator,
roomProxy: roomProxy, roomProxy: roomProxy,
mediaProvider: MockMediaProvider())) mediaProvider: MockMediaProvider()))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .roomDetailsScreenWithRoomAvatar: case .roomDetailsScreenWithRoomAvatar:
@@ -294,24 +294,24 @@ class MockScreen: Identifiable {
isEncrypted: true, isEncrypted: true,
canonicalAlias: "#mock:room.org", canonicalAlias: "#mock:room.org",
members: members)) members: members))
let coordinator = RoomDetailsCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator, let coordinator = RoomDetailsScreenCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator,
roomProxy: roomProxy, roomProxy: roomProxy,
mediaProvider: MockMediaProvider())) mediaProvider: MockMediaProvider()))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .roomMembersListScreen: case .roomMembersListScreen:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let members: [RoomMemberProxyMock] = [.mockAlice, .mockBob, .mockCharlie] let members: [RoomMemberProxyMock] = [.mockAlice, .mockBob, .mockCharlie]
let coordinator = RoomMembersListCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator, let coordinator = RoomMembersListScreenCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator,
mediaProvider: MockMediaProvider(), mediaProvider: MockMediaProvider(),
members: members)) members: members))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .reportContent: case .reportContent:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = ReportContentCoordinator(parameters: .init(itemID: "test", let coordinator = ReportContentScreenCoordinator(parameters: .init(itemID: "test",
senderID: RoomMemberProxyMock.mockAlice.userID, senderID: RoomMemberProxyMock.mockAlice.userID,
roomProxy: RoomProxyMock(with: .init(displayName: "test")))) roomProxy: RoomProxyMock(with: .init(displayName: "test"))))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .startChat: case .startChat:
@@ -337,17 +337,17 @@ class MockScreen: Identifiable {
return navigationStackCoordinator return navigationStackCoordinator
case .roomMemberDetailsAccountOwner: case .roomMemberDetailsAccountOwner:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = RoomMemberDetailsCoordinator(parameters: .init(roomMemberProxy: RoomMemberProxyMock.mockMe, mediaProvider: MockMediaProvider())) let coordinator = RoomMemberDetailsScreenCoordinator(parameters: .init(roomMemberProxy: RoomMemberProxyMock.mockMe, mediaProvider: MockMediaProvider()))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .roomMemberDetails: case .roomMemberDetails:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = RoomMemberDetailsCoordinator(parameters: .init(roomMemberProxy: RoomMemberProxyMock.mockAlice, mediaProvider: MockMediaProvider())) let coordinator = RoomMemberDetailsScreenCoordinator(parameters: .init(roomMemberProxy: RoomMemberProxyMock.mockAlice, mediaProvider: MockMediaProvider()))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .roomMemberDetailsIgnoredUser: case .roomMemberDetailsIgnoredUser:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let coordinator = RoomMemberDetailsCoordinator(parameters: .init(roomMemberProxy: RoomMemberProxyMock.mockIgnored, mediaProvider: MockMediaProvider())) let coordinator = RoomMemberDetailsScreenCoordinator(parameters: .init(roomMemberProxy: RoomMemberProxyMock.mockIgnored, mediaProvider: MockMediaProvider()))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .roomDetailsScreenDmDetails: case .roomDetailsScreenDmDetails:
@@ -359,9 +359,9 @@ class MockScreen: Identifiable {
isDirect: true, isDirect: true,
isEncrypted: true, isEncrypted: true,
members: members)) members: members))
let coordinator = RoomDetailsCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator, let coordinator = RoomDetailsScreenCoordinator(parameters: .init(navigationStackCoordinator: navigationStackCoordinator,
roomProxy: roomProxy, roomProxy: roomProxy,
mediaProvider: MockMediaProvider())) mediaProvider: MockMediaProvider()))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .invitesWithBadges: case .invitesWithBadges:
@@ -373,7 +373,7 @@ class MockScreen: Identifiable {
clientProxy.visibleRoomsSummaryProvider = summaryProvider clientProxy.visibleRoomsSummaryProvider = summaryProvider
clientProxy.invitesSummaryProvider = summaryProvider clientProxy.invitesSummaryProvider = summaryProvider
let coordinator = InvitesCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()))) let coordinator = InvitesScreenCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .invites: case .invites:
@@ -385,13 +385,13 @@ class MockScreen: Identifiable {
clientProxy.visibleRoomsSummaryProvider = summaryProvider clientProxy.visibleRoomsSummaryProvider = summaryProvider
clientProxy.invitesSummaryProvider = summaryProvider clientProxy.invitesSummaryProvider = summaryProvider
let coordinator = InvitesCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()))) let coordinator = InvitesScreenCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .invitesNoInvites: case .invitesNoInvites:
let navigationStackCoordinator = NavigationStackCoordinator() let navigationStackCoordinator = NavigationStackCoordinator()
let clientProxy = MockClientProxy(userID: "@mock:client.com") let clientProxy = MockClientProxy(userID: "@mock:client.com")
let coordinator = InvitesCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()))) let coordinator = InvitesScreenCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
case .inviteUsers: case .inviteUsers:
@@ -400,7 +400,7 @@ class MockScreen: Identifiable {
let userDiscoveryMock = UserDiscoveryServiceMock() let userDiscoveryMock = UserDiscoveryServiceMock()
userDiscoveryMock.fetchSuggestionsReturnValue = .success([.mockAlice, .mockBob, .mockCharlie]) userDiscoveryMock.fetchSuggestionsReturnValue = .success([.mockAlice, .mockBob, .mockCharlie])
userDiscoveryMock.searchProfilesWithReturnValue = .success([]) userDiscoveryMock.searchProfilesWithReturnValue = .success([])
let coordinator = InviteUsersCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: MockClientProxy(userID: "@mock:client.com"), mediaProvider: MockMediaProvider()), userDiscoveryService: userDiscoveryMock)) let coordinator = InviteUsersScreenCoordinator(parameters: .init(userSession: MockUserSession(clientProxy: MockClientProxy(userID: "@mock:client.com"), mediaProvider: MockMediaProvider()), userDiscoveryService: userDiscoveryMock))
navigationStackCoordinator.setRootCoordinator(coordinator) navigationStackCoordinator.setRootCoordinator(coordinator)
return navigationStackCoordinator return navigationStackCoordinator
} }
+24 -24
View File
@@ -23,13 +23,13 @@ class BugReportViewModelTests: XCTestCase {
enum TestError: Error { enum TestError: Error {
case testError case testError
} }
func testInitialState() { func testInitialState() {
let viewModel = BugReportViewModel(bugReportService: BugReportServiceMock(), let viewModel = BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: nil, screenshot: nil,
isModallyPresented: false) isModallyPresented: false)
let context = viewModel.context let context = viewModel.context
XCTAssertEqual(context.reportText, "") XCTAssertEqual(context.reportText, "")
@@ -38,11 +38,11 @@ class BugReportViewModelTests: XCTestCase {
} }
func testClearScreenshot() async throws { func testClearScreenshot() async throws {
let viewModel = BugReportViewModel(bugReportService: BugReportServiceMock(), let viewModel = BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: UIImage.actions, screenshot: UIImage.actions,
isModallyPresented: false) isModallyPresented: false)
let context = viewModel.context let context = viewModel.context
context.send(viewAction: .removeScreenshot) context.send(viewAction: .removeScreenshot)
@@ -50,23 +50,23 @@ class BugReportViewModelTests: XCTestCase {
} }
func testAttachScreenshot() async throws { func testAttachScreenshot() async throws {
let viewModel = BugReportViewModel(bugReportService: BugReportServiceMock(), let viewModel = BugReportScreenViewModel(bugReportService: BugReportServiceMock(),
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: nil, isModallyPresented: false) screenshot: nil, isModallyPresented: false)
let context = viewModel.context let context = viewModel.context
XCTAssertNil(context.viewState.screenshot) XCTAssertNil(context.viewState.screenshot)
context.send(viewAction: .attachScreenshot(UIImage.actions)) context.send(viewAction: .attachScreenshot(UIImage.actions))
XCTAssert(context.viewState.screenshot == UIImage.actions) XCTAssert(context.viewState.screenshot == UIImage.actions)
} }
func testSendReportWithSuccess() async throws { func testSendReportWithSuccess() async throws {
let mockService = BugReportServiceMock() let mockService = BugReportServiceMock()
mockService.submitBugReportProgressListenerReturnValue = SubmitBugReportResponse(reportUrl: "https://test.test") mockService.submitBugReportProgressListenerReturnValue = SubmitBugReportResponse(reportUrl: "https://test.test")
let viewModel = BugReportViewModel(bugReportService: mockService, let viewModel = BugReportScreenViewModel(bugReportService: mockService,
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: nil, isModallyPresented: false) screenshot: nil, isModallyPresented: false)
let context = viewModel.context let context = viewModel.context
context.send(viewAction: .submit) context.send(viewAction: .submit)
@@ -89,10 +89,10 @@ class BugReportViewModelTests: XCTestCase {
mockService.submitBugReportProgressListenerClosure = { _, _ in mockService.submitBugReportProgressListenerClosure = { _, _ in
throw TestError.testError throw TestError.testError
} }
let viewModel = BugReportViewModel(bugReportService: mockService, let viewModel = BugReportScreenViewModel(bugReportService: mockService,
userID: "@mock.client.com", userID: "@mock.client.com",
deviceID: nil, deviceID: nil,
screenshot: nil, isModallyPresented: false) screenshot: nil, isModallyPresented: false)
let context = viewModel.context let context = viewModel.context
context.send(viewAction: .submit) context.send(viewAction: .submit)
@@ -20,11 +20,11 @@ import XCTest
@MainActor @MainActor
class FilePreviewScreenViewModelTests: XCTestCase { class FilePreviewScreenViewModelTests: XCTestCase {
var viewModel: FilePreviewViewModelProtocol! var viewModel: FilePreviewScreenViewModelProtocol!
var context: FilePreviewViewModelType.Context! var context: FilePreviewScreenViewModelType.Context!
override func setUpWithError() throws { override func setUpWithError() throws {
viewModel = FilePreviewViewModel(mediaFile: .unmanaged(url: URL(staticString: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"))) viewModel = FilePreviewScreenViewModel(mediaFile: .unmanaged(url: URL(staticString: "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf")))
context = viewModel.context context = viewModel.context
} }
@@ -20,11 +20,11 @@ import XCTest
@MainActor @MainActor
class InviteUsersScreenViewModelTests: XCTestCase { class InviteUsersScreenViewModelTests: XCTestCase {
var viewModel: InviteUsersViewModelProtocol! var viewModel: InviteUsersScreenViewModelProtocol!
var clientProxy: MockClientProxy! var clientProxy: MockClientProxy!
var userDiscoveryService: UserDiscoveryServiceMock! var userDiscoveryService: UserDiscoveryServiceMock!
var context: InviteUsersViewModel.Context { var context: InviteUsersScreenViewModel.Context {
viewModel.context viewModel.context
} }
@@ -34,7 +34,7 @@ class InviteUsersScreenViewModelTests: XCTestCase {
userDiscoveryService.fetchSuggestionsReturnValue = .success([]) userDiscoveryService.fetchSuggestionsReturnValue = .success([])
userDiscoveryService.searchProfilesWithReturnValue = .success([]) userDiscoveryService.searchProfilesWithReturnValue = .success([])
let userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider()) let userSession = MockUserSession(clientProxy: clientProxy, mediaProvider: MockMediaProvider())
let viewModel = InviteUsersViewModel(userSession: userSession, userDiscoveryService: userDiscoveryService) let viewModel = InviteUsersScreenViewModel(userSession: userSession, userDiscoveryService: userDiscoveryService)
viewModel.state.usersSection = .init(type: .suggestions, users: [.mockAlice, .mockBob, .mockCharlie]) viewModel.state.usersSection = .init(type: .suggestions, users: [.mockAlice, .mockBob, .mockCharlie])
self.viewModel = viewModel self.viewModel = viewModel
} }
@@ -19,11 +19,11 @@ import XCTest
@MainActor @MainActor
class InvitesViewModelTests: XCTestCase { class InvitesViewModelTests: XCTestCase {
var viewModel: InvitesViewModelProtocol! var viewModel: InvitesScreenViewModelProtocol!
var clientProxy: MockClientProxy! var clientProxy: MockClientProxy!
var userSession: MockUserSession! var userSession: MockUserSession!
var context: InvitesViewModelType.Context { var context: InvitesScreenViewModelType.Context {
viewModel.context viewModel.context
} }
@@ -54,7 +54,7 @@ class InvitesViewModelTests: XCTestCase {
} }
setupViewModel(roomSummaries: invites) setupViewModel(roomSummaries: invites)
context.send(viewAction: .accept(.init(roomDetails: details, isUnread: false))) context.send(viewAction: .accept(.init(roomDetails: details, isUnread: false)))
let action: InvitesViewModelAction? = await viewModel.actions.values.first() let action: InvitesScreenViewModelAction? = await viewModel.actions.values.first()
guard case .openRoom(let roomID) = action else { guard case .openRoom(let roomID) = action else {
XCTFail("Wrong view model action") XCTFail("Wrong view model action")
return return
@@ -82,6 +82,6 @@ class InvitesViewModelTests: XCTestCase {
clientProxy.visibleRoomsSummaryProvider = summaryProvider clientProxy.visibleRoomsSummaryProvider = summaryProvider
} }
viewModel = InvitesViewModel(userSession: userSession) viewModel = InvitesScreenViewModel(userSession: userSession)
} }
} }
@@ -28,9 +28,9 @@ class ReportContentScreenViewModelTests: XCTestCase {
// Given the report content view for some content. // Given the report content view for some content.
let roomProxy = RoomProxyMock(with: .init(displayName: "test")) let roomProxy = RoomProxyMock(with: .init(displayName: "test"))
roomProxy.reportContentReasonReturnValue = .success(()) roomProxy.reportContentReasonReturnValue = .success(())
let viewModel = ReportContentViewModel(itemID: itemID, let viewModel = ReportContentScreenViewModel(itemID: itemID,
senderID: senderID, senderID: senderID,
roomProxy: roomProxy) roomProxy: roomProxy)
// When reporting the content without ignoring the user. // When reporting the content without ignoring the user.
viewModel.state.bindings.reasonText = reportReason viewModel.state.bindings.reasonText = reportReason
@@ -52,9 +52,9 @@ class ReportContentScreenViewModelTests: XCTestCase {
let roomProxy = RoomProxyMock(with: .init(displayName: "test")) let roomProxy = RoomProxyMock(with: .init(displayName: "test"))
roomProxy.reportContentReasonReturnValue = .success(()) roomProxy.reportContentReasonReturnValue = .success(())
roomProxy.ignoreUserReturnValue = .success(()) roomProxy.ignoreUserReturnValue = .success(())
let viewModel = ReportContentViewModel(itemID: itemID, let viewModel = ReportContentScreenViewModel(itemID: itemID,
senderID: senderID, senderID: senderID,
roomProxy: roomProxy) roomProxy: roomProxy)
// When reporting the content and also ignoring the user. // When reporting the content and also ignoring the user.
viewModel.state.bindings.reasonText = reportReason viewModel.state.bindings.reasonText = reportReason
@@ -20,19 +20,19 @@ import XCTest
@MainActor @MainActor
class RoomDetailsScreenViewModelTests: XCTestCase { class RoomDetailsScreenViewModelTests: XCTestCase {
var viewModel: RoomDetailsViewModelProtocol! var viewModel: RoomDetailsScreenViewModelProtocol!
var roomProxyMock: RoomProxyMock! var roomProxyMock: RoomProxyMock!
var context: RoomDetailsViewModelType.Context { viewModel.context } var context: RoomDetailsScreenViewModelType.Context { viewModel.context }
override func setUp() { override func setUp() {
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test")) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test"))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
} }
func testLeaveRoomTappedWhenPublic() async { func testLeaveRoomTappedWhenPublic() async {
let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice] let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isPublic: true, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isPublic: true, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
context.send(viewAction: .processTapLeave) context.send(viewAction: .processTapLeave)
XCTAssertEqual(context.leaveRoomAlertItem?.state, .public) XCTAssertEqual(context.leaveRoomAlertItem?.state, .public)
XCTAssertEqual(context.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertSubtitle) XCTAssertEqual(context.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertSubtitle)
@@ -41,7 +41,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
func testLeaveRoomTappedWhenRoomNotPublic() async { func testLeaveRoomTappedWhenRoomNotPublic() async {
let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice] let mockedMembers: [RoomMemberProxyMock] = [.mockBob, .mockAlice]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isPublic: false, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isPublic: false, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
context.send(viewAction: .processTapLeave) context.send(viewAction: .processTapLeave)
XCTAssertEqual(context.leaveRoomAlertItem?.state, .private) XCTAssertEqual(context.leaveRoomAlertItem?.state, .private)
XCTAssertEqual(context.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertPrivateSubtitle) XCTAssertEqual(context.leaveRoomAlertItem?.subtitle, L10n.leaveRoomAlertPrivateSubtitle)
@@ -84,19 +84,19 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
let recipient = RoomMemberProxyMock.mockDan let recipient = RoomMemberProxyMock.mockDan
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient))
} }
func testIgnoreSuccess() async throws { func testIgnoreSuccess() async throws {
let recipient = RoomMemberProxyMock.mockDan let recipient = RoomMemberProxyMock.mockDan
recipient.ignoreUserClosure = { recipient.ignoreUserClosure = {
try? await Task.sleep(for: .milliseconds(10)) try? await Task.sleep(for: .milliseconds(100))
return .success(()) return .success(())
} }
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient))
context.send(viewAction: .ignoreConfirmed) context.send(viewAction: .ignoreConfirmed)
@@ -116,7 +116,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
} }
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient))
context.send(viewAction: .ignoreConfirmed) context.send(viewAction: .ignoreConfirmed)
@@ -137,7 +137,7 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
} }
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient))
context.send(viewAction: .unignoreConfirmed) context.send(viewAction: .unignoreConfirmed)
@@ -152,12 +152,12 @@ class RoomDetailsScreenViewModelTests: XCTestCase {
func testUnignoreFailure() async throws { func testUnignoreFailure() async throws {
let recipient = RoomMemberProxyMock.mockIgnored let recipient = RoomMemberProxyMock.mockIgnored
recipient.unignoreUserClosure = { recipient.unignoreUserClosure = {
try? await Task.sleep(for: .milliseconds(10)) try? await Task.sleep(for: .milliseconds(100))
return .failure(.unignoreUserFailed) return .failure(.unignoreUserFailed)
} }
let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient] let mockedMembers: [RoomMemberProxyMock] = [.mockMe, recipient]
roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers)) roomProxyMock = RoomProxyMock(with: .init(displayName: "Test", isDirect: true, isEncrypted: true, members: mockedMembers))
viewModel = RoomDetailsViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomDetailsScreenViewModel(roomProxy: roomProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient)) XCTAssertEqual(context.viewState.dmRecipient, RoomMemberDetails(withProxy: recipient))
context.send(viewAction: .unignoreConfirmed) context.send(viewAction: .unignoreConfirmed)
@@ -20,13 +20,13 @@ import XCTest
@MainActor @MainActor
class RoomMemberDetailsViewModelTests: XCTestCase { class RoomMemberDetailsViewModelTests: XCTestCase {
var viewModel: RoomMemberDetailsViewModelProtocol! var viewModel: RoomMemberDetailsScreenViewModelProtocol!
var roomMemberProxyMock: RoomMemberProxyMock! var roomMemberProxyMock: RoomMemberProxyMock!
var context: RoomMemberDetailsViewModelType.Context { viewModel.context } var context: RoomMemberDetailsScreenViewModelType.Context { viewModel.context }
func testInitialState() async { func testInitialState() async {
roomMemberProxyMock = RoomMemberProxyMock.mockAlice roomMemberProxyMock = RoomMemberProxyMock.mockAlice
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.details, RoomMemberDetails(withProxy: roomMemberProxyMock)) XCTAssertEqual(context.viewState.details, RoomMemberDetails(withProxy: roomMemberProxyMock))
XCTAssertNil(context.ignoreUserAlert) XCTAssertNil(context.ignoreUserAlert)
@@ -36,10 +36,10 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testIgnoreSuccess() async throws { func testIgnoreSuccess() async throws {
roomMemberProxyMock = RoomMemberProxyMock.mockAlice roomMemberProxyMock = RoomMemberProxyMock.mockAlice
roomMemberProxyMock.ignoreUserClosure = { roomMemberProxyMock.ignoreUserClosure = {
try? await Task.sleep(for: .milliseconds(10)) try? await Task.sleep(for: .milliseconds(100))
return .success(()) return .success(())
} }
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
context.send(viewAction: .showIgnoreAlert) context.send(viewAction: .showIgnoreAlert)
XCTAssertEqual(context.ignoreUserAlert, .init(action: .ignore)) XCTAssertEqual(context.ignoreUserAlert, .init(action: .ignore))
@@ -56,10 +56,10 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testIgnoreFailure() async throws { func testIgnoreFailure() async throws {
roomMemberProxyMock = RoomMemberProxyMock.mockAlice roomMemberProxyMock = RoomMemberProxyMock.mockAlice
roomMemberProxyMock.ignoreUserClosure = { roomMemberProxyMock.ignoreUserClosure = {
try? await Task.sleep(for: .milliseconds(10)) try? await Task.sleep(for: .milliseconds(100))
return .failure(.ignoreUserFailed) return .failure(.ignoreUserFailed)
} }
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
context.send(viewAction: .showIgnoreAlert) context.send(viewAction: .showIgnoreAlert)
XCTAssertEqual(context.ignoreUserAlert, .init(action: .ignore)) XCTAssertEqual(context.ignoreUserAlert, .init(action: .ignore))
@@ -76,10 +76,10 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testUnignoreSuccess() async throws { func testUnignoreSuccess() async throws {
roomMemberProxyMock = RoomMemberProxyMock.mockIgnored roomMemberProxyMock = RoomMemberProxyMock.mockIgnored
roomMemberProxyMock.unignoreUserClosure = { roomMemberProxyMock.unignoreUserClosure = {
try? await Task.sleep(for: .milliseconds(10)) try? await Task.sleep(for: .milliseconds(100))
return .success(()) return .success(())
} }
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
context.send(viewAction: .showUnignoreAlert) context.send(viewAction: .showUnignoreAlert)
XCTAssertEqual(context.ignoreUserAlert, .init(action: .unignore)) XCTAssertEqual(context.ignoreUserAlert, .init(action: .unignore))
@@ -96,10 +96,10 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testUnignoreFailure() async throws { func testUnignoreFailure() async throws {
roomMemberProxyMock = RoomMemberProxyMock.mockIgnored roomMemberProxyMock = RoomMemberProxyMock.mockIgnored
roomMemberProxyMock.unignoreUserClosure = { roomMemberProxyMock.unignoreUserClosure = {
try? await Task.sleep(for: .milliseconds(10)) try? await Task.sleep(for: .milliseconds(100))
return .failure(.unignoreUserFailed) return .failure(.unignoreUserFailed)
} }
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
context.send(viewAction: .showUnignoreAlert) context.send(viewAction: .showUnignoreAlert)
XCTAssertEqual(context.ignoreUserAlert, .init(action: .unignore)) XCTAssertEqual(context.ignoreUserAlert, .init(action: .unignore))
@@ -116,7 +116,7 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testInitialStateAccountOwner() async { func testInitialStateAccountOwner() async {
roomMemberProxyMock = RoomMemberProxyMock.mockMe roomMemberProxyMock = RoomMemberProxyMock.mockMe
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.details, RoomMemberDetails(withProxy: roomMemberProxyMock)) XCTAssertEqual(context.viewState.details, RoomMemberDetails(withProxy: roomMemberProxyMock))
XCTAssertNil(context.ignoreUserAlert) XCTAssertNil(context.ignoreUserAlert)
@@ -125,7 +125,7 @@ class RoomMemberDetailsViewModelTests: XCTestCase {
func testInitialStateIgnoredUser() async { func testInitialStateIgnoredUser() async {
roomMemberProxyMock = RoomMemberProxyMock.mockIgnored roomMemberProxyMock = RoomMemberProxyMock.mockIgnored
viewModel = RoomMemberDetailsViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider()) viewModel = RoomMemberDetailsScreenViewModel(roomMemberProxy: roomMemberProxyMock, mediaProvider: MockMediaProvider())
XCTAssertEqual(context.viewState.details, RoomMemberDetails(withProxy: roomMemberProxyMock)) XCTAssertEqual(context.viewState.details, RoomMemberDetails(withProxy: roomMemberProxyMock))
XCTAssertNil(context.ignoreUserAlert) XCTAssertNil(context.ignoreUserAlert)
@@ -20,11 +20,11 @@ import XCTest
@MainActor @MainActor
class SessionVerificationStateMachineTests: XCTestCase { class SessionVerificationStateMachineTests: XCTestCase {
private var stateMachine: SessionVerificationStateMachine! private var stateMachine: SessionVerificationScreenStateMachine!
@MainActor @MainActor
override func setUpWithError() throws { override func setUpWithError() throws {
stateMachine = SessionVerificationStateMachine() stateMachine = SessionVerificationScreenStateMachine()
} }
func testAcceptChallenge() { func testAcceptChallenge() {
@@ -21,13 +21,13 @@ import XCTest
@MainActor @MainActor
class SessionVerificationViewModelTests: XCTestCase { class SessionVerificationViewModelTests: XCTestCase {
var viewModel: SessionVerificationViewModelProtocol! var viewModel: SessionVerificationScreenViewModelProtocol!
var context: SessionVerificationViewModelType.Context! var context: SessionVerificationViewModelType.Context!
var sessionVerificationController: SessionVerificationControllerProxyMock! var sessionVerificationController: SessionVerificationControllerProxyMock!
override func setUpWithError() throws { override func setUpWithError() throws {
sessionVerificationController = SessionVerificationControllerProxyMock.configureMock() sessionVerificationController = SessionVerificationControllerProxyMock.configureMock()
viewModel = SessionVerificationViewModel(sessionVerificationControllerProxy: sessionVerificationController) viewModel = SessionVerificationScreenViewModel(sessionVerificationControllerProxy: sessionVerificationController)
context = viewModel.context context = viewModel.context
} }