mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Squashed commits: Add unit tests and move the state machine into the FlowCoordinator [bb686861] Replace the RoomFlowCoordinator's public interface with just `handleAppRoute` [0d9a4f8d] Remove the navigationStackCoordinator dependency from the roomScreenCoordinator [4b5fbdf2] Allow rooms to be selected from any other state [41dbd127] Move all missing coordinators to the RoomFlowCoordinator and state machines [f32431b7] The UserSessionFlowCoordinator does not need to conform to the CoordinatorProtocol [0f07e87d] Fix leaving a room dismissing the currently selected one when different [138385a2] Rewind the navigation stack when re-selecting the same room (iPad) [0727eb93] Fix presenting different room details from the side menu on iPads [faf4cc60] Fix selecting the same room multiple times [fb3391da] Move room details presentation responsibility to the RoomFlowCoordinator. Fixed invitation flows. [fa2a68d9] Rename RoomTimelineFlowCoordinator -> RoomFlowCoordinator [0c9c06b5] Start moving things away from the RoomScreenCoordinator and into the RoomTimelineFlowCoordinator [86cbbdcc] Introduce a RoomTimelineFlowCoordinator to deal with timeline related operations [9b2381be] Introduce the FlowCoordinatorProtocol
This commit is contained in:
committed by
Stefan Ceriu
parent
f2b7faa183
commit
0082aba9d4
@@ -14,30 +14,34 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct RoomScreenCoordinatorParameters {
|
||||
let navigationStackCoordinator: NavigationStackCoordinator
|
||||
let roomProxy: RoomProxyProtocol
|
||||
let timelineController: RoomTimelineControllerProtocol
|
||||
let mediaProvider: MediaProviderProtocol
|
||||
let emojiProvider: EmojiProviderProtocol
|
||||
let userDiscoveryService: UserDiscoveryServiceProtocol
|
||||
}
|
||||
|
||||
enum RoomScreenCoordinatorAction {
|
||||
case leftRoom
|
||||
case presentMediaViewer(file: MediaFileHandleProxy, title: String?)
|
||||
case presentReportContent(itemID: String, senderID: String)
|
||||
case presentMediaUploadPicker(MediaPickerScreenSource)
|
||||
case presentMediaUploadPreviewScreen(URL)
|
||||
case presentRoomDetails
|
||||
case presentEmojiPicker(itemID: String)
|
||||
}
|
||||
|
||||
final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
private var parameters: RoomScreenCoordinatorParameters
|
||||
|
||||
private var viewModel: RoomScreenViewModelProtocol
|
||||
private var navigationStackCoordinator: NavigationStackCoordinator {
|
||||
parameters.navigationStackCoordinator
|
||||
}
|
||||
|
||||
var callback: ((RoomScreenCoordinatorAction) -> Void)?
|
||||
private let actionsSubject: PassthroughSubject<RoomScreenCoordinatorAction, Never> = .init()
|
||||
var actions: AnyPublisher<RoomScreenCoordinatorAction, Never> {
|
||||
actionsSubject.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(parameters: RoomScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
@@ -55,21 +59,21 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
|
||||
switch action {
|
||||
case .displayRoomDetails:
|
||||
self.displayRoomDetails()
|
||||
case .displayMediaFile(let file, let title):
|
||||
self.displayFilePreview(for: file, with: title)
|
||||
actionsSubject.send(.presentRoomDetails)
|
||||
case .displayMediaViewer(let file, let title):
|
||||
actionsSubject.send(.presentMediaViewer(file: file, title: title))
|
||||
case .displayEmojiPicker(let itemID):
|
||||
self.displayEmojiPickerScreen(for: itemID)
|
||||
actionsSubject.send(.presentEmojiPicker(itemID: itemID))
|
||||
case .displayReportContent(let itemID, let senderID):
|
||||
self.displayReportContent(for: itemID, from: senderID)
|
||||
actionsSubject.send(.presentReportContent(itemID: itemID, senderID: senderID))
|
||||
case .displayCameraPicker:
|
||||
self.displayMediaPickerWithSource(.camera)
|
||||
actionsSubject.send(.presentMediaUploadPicker(.camera))
|
||||
case .displayMediaPicker:
|
||||
self.displayMediaPickerWithSource(.photoLibrary)
|
||||
actionsSubject.send(.presentMediaUploadPicker(.photoLibrary))
|
||||
case .displayDocumentPicker:
|
||||
self.displayMediaPickerWithSource(.documents)
|
||||
actionsSubject.send(.presentMediaUploadPicker(.documents))
|
||||
case .displayMediaUploadPreviewScreen(let url):
|
||||
self.displayMediaUploadPreviewScreenForFile(at: url)
|
||||
actionsSubject.send(.presentMediaUploadPreviewScreen(url))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,123 +85,4 @@ final class RoomScreenCoordinator: CoordinatorProtocol {
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(RoomScreen(context: viewModel.context))
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func displayMediaPickerWithSource(_ source: MediaPickerScreenSource) {
|
||||
let stackCoordinator = NavigationStackCoordinator()
|
||||
let userIndicatorController = UserIndicatorController(rootCoordinator: stackCoordinator)
|
||||
|
||||
let mediaPickerCoordinator = MediaPickerScreenCoordinator(userIndicatorController: userIndicatorController, source: source) { [weak self] action in
|
||||
switch action {
|
||||
case .cancel:
|
||||
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
case .selectMediaAtURL(let url):
|
||||
self?.displayMediaUploadPreviewScreenForFile(at: url)
|
||||
}
|
||||
}
|
||||
|
||||
stackCoordinator.setRootCoordinator(mediaPickerCoordinator)
|
||||
|
||||
navigationStackCoordinator.setSheetCoordinator(userIndicatorController)
|
||||
}
|
||||
|
||||
private func displayMediaUploadPreviewScreenForFile(at url: URL) {
|
||||
let stackCoordinator = NavigationStackCoordinator()
|
||||
let userIndicatorController = UserIndicatorController(rootCoordinator: stackCoordinator)
|
||||
|
||||
let parameters = MediaUploadPreviewScreenCoordinatorParameters(userIndicatorController: userIndicatorController,
|
||||
roomProxy: parameters.roomProxy,
|
||||
mediaUploadingPreprocessor: MediaUploadingPreprocessor(),
|
||||
title: url.lastPathComponent,
|
||||
url: url)
|
||||
|
||||
let mediaUploadPreviewScreenCoordinator = MediaUploadPreviewScreenCoordinator(parameters: parameters) { [weak self] action in
|
||||
switch action {
|
||||
case .dismiss:
|
||||
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
}
|
||||
}
|
||||
|
||||
stackCoordinator.setRootCoordinator(mediaUploadPreviewScreenCoordinator)
|
||||
|
||||
navigationStackCoordinator.setSheetCoordinator(userIndicatorController)
|
||||
}
|
||||
|
||||
private func displayFilePreview(for file: MediaFileHandleProxy, with title: String?) {
|
||||
let params = FilePreviewScreenCoordinatorParameters(mediaFile: file, title: title)
|
||||
let coordinator = FilePreviewScreenCoordinator(parameters: params)
|
||||
coordinator.callback = { [weak self] _ in
|
||||
self?.navigationStackCoordinator.pop()
|
||||
}
|
||||
|
||||
navigationStackCoordinator.push(coordinator)
|
||||
}
|
||||
|
||||
private func displayEmojiPickerScreen(for itemId: String) {
|
||||
let emojiPickerNavigationStackCoordinator = NavigationStackCoordinator()
|
||||
|
||||
let params = EmojiPickerScreenCoordinatorParameters(emojiProvider: parameters.emojiProvider,
|
||||
itemId: itemId)
|
||||
let coordinator = EmojiPickerScreenCoordinator(parameters: params)
|
||||
coordinator.callback = { [weak self] action in
|
||||
switch action {
|
||||
case let .emojiSelected(emoji: emoji, itemId: itemId):
|
||||
MXLog.debug("Selected \(emoji) for \(itemId)")
|
||||
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
Task {
|
||||
await self?.parameters.timelineController.sendReaction(emoji, to: itemId)
|
||||
}
|
||||
case .dismiss:
|
||||
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
}
|
||||
}
|
||||
|
||||
emojiPickerNavigationStackCoordinator.setRootCoordinator(coordinator)
|
||||
emojiPickerNavigationStackCoordinator.presentationDetents = [.medium, .large]
|
||||
|
||||
navigationStackCoordinator.setSheetCoordinator(emojiPickerNavigationStackCoordinator)
|
||||
}
|
||||
|
||||
private func displayRoomDetails() {
|
||||
let params = RoomDetailsScreenCoordinatorParameters(navigationStackCoordinator: navigationStackCoordinator,
|
||||
roomProxy: parameters.roomProxy,
|
||||
mediaProvider: parameters.mediaProvider,
|
||||
userDiscoveryService: parameters.userDiscoveryService)
|
||||
let coordinator = RoomDetailsScreenCoordinator(parameters: params)
|
||||
coordinator.callback = { [weak self] action in
|
||||
switch action {
|
||||
case .cancel:
|
||||
self?.navigationStackCoordinator.pop()
|
||||
case .leftRoom:
|
||||
self?.callback?(.leftRoom)
|
||||
}
|
||||
}
|
||||
|
||||
navigationStackCoordinator.push(coordinator)
|
||||
}
|
||||
|
||||
private func displayReportContent(for itemID: String, from senderID: String) {
|
||||
let navigationCoordinator = NavigationStackCoordinator()
|
||||
let userIndicatorController = UserIndicatorController(rootCoordinator: navigationCoordinator)
|
||||
let parameters = ReportContentScreenCoordinatorParameters(itemID: itemID,
|
||||
senderID: senderID,
|
||||
roomProxy: parameters.roomProxy,
|
||||
userIndicatorController: userIndicatorController)
|
||||
let coordinator = ReportContentScreenCoordinator(parameters: parameters)
|
||||
coordinator.callback = { [weak self] completion in
|
||||
self?.navigationStackCoordinator.setSheetCoordinator(nil)
|
||||
switch completion {
|
||||
case .cancel: break
|
||||
case .finish:
|
||||
self?.showSuccess(label: L10n.commonReportSubmitted)
|
||||
}
|
||||
}
|
||||
navigationCoordinator.setRootCoordinator(coordinator)
|
||||
navigationStackCoordinator.setSheetCoordinator(userIndicatorController)
|
||||
}
|
||||
|
||||
private func showSuccess(label: String) {
|
||||
ServiceLocator.shared.userIndicatorController.submitIndicator(UserIndicator(title: label, iconName: "checkmark"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import UIKit
|
||||
|
||||
enum RoomScreenViewModelAction {
|
||||
case displayRoomDetails
|
||||
case displayMediaFile(file: MediaFileHandleProxy, title: String?)
|
||||
case displayMediaViewer(file: MediaFileHandleProxy, title: String?)
|
||||
case displayEmojiPicker(itemID: String)
|
||||
case displayReportContent(itemID: String, senderID: String)
|
||||
case displayCameraPicker
|
||||
|
||||
@@ -154,7 +154,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
|
||||
switch action {
|
||||
case .displayMediaFile(let file, let title):
|
||||
callback?(.displayMediaFile(file: file, title: title))
|
||||
callback?(.displayMediaViewer(file: file, title: title))
|
||||
case .none:
|
||||
break
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user