diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index ad6dc1bac..e7c34d7aa 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -28,6 +28,8 @@ 18C5745427E1D88E00D70937 /* TextRoomMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C5745327E1D88E00D70937 /* TextRoomMessage.swift */; }; 18C5745627E1DCA800D70937 /* RoomMessageFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C5745527E1DCA800D70937 /* RoomMessageFactory.swift */; }; 18C5745827E1EB6E00D70937 /* TimelineItemFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C5745727E1EB6E00D70937 /* TimelineItemFactory.swift */; }; + 18DF7C2A27E23E3A00291672 /* TimelineItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18DF7C2927E23E3A00291672 /* TimelineItemProtocol.swift */; }; + 18DF7C2C27E23EC000291672 /* TimelineViewFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18DF7C2B27E23EC000291672 /* TimelineViewFactory.swift */; }; 18F2BADA27D25B4000DD1988 /* RoomTimelineProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2BA7727D25B4000DD1988 /* RoomTimelineProvider.swift */; }; 18F2BADB27D25B4000DD1988 /* AuthenticationCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2BA7927D25B4000DD1988 /* AuthenticationCoordinator.swift */; }; 18F2BADC27D25B4000DD1988 /* UserSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18F2BA7A27D25B4000DD1988 /* UserSession.swift */; }; @@ -132,6 +134,8 @@ 18C5745327E1D88E00D70937 /* TextRoomMessage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomMessage.swift; sourceTree = ""; }; 18C5745527E1DCA800D70937 /* RoomMessageFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageFactory.swift; sourceTree = ""; }; 18C5745727E1EB6E00D70937 /* TimelineItemFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemFactory.swift; sourceTree = ""; }; + 18DF7C2927E23E3A00291672 /* TimelineItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineItemProtocol.swift; sourceTree = ""; }; + 18DF7C2B27E23EC000291672 /* TimelineViewFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineViewFactory.swift; sourceTree = ""; }; 18F2BA7727D25B4000DD1988 /* RoomTimelineProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoomTimelineProvider.swift; sourceTree = ""; }; 18F2BA7927D25B4000DD1988 /* AuthenticationCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationCoordinator.swift; sourceTree = ""; }; 18F2BA7A27D25B4000DD1988 /* UserSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserSession.swift; sourceTree = ""; }; @@ -303,6 +307,8 @@ isa = PBXGroup; children = ( 18C5745727E1EB6E00D70937 /* TimelineItemFactory.swift */, + 18DF7C2927E23E3A00291672 /* TimelineItemProtocol.swift */, + 18DF7C2B27E23EC000291672 /* TimelineViewFactory.swift */, 18A318DB27DA42C9000867CD /* RoomTimelineViewProvider.swift */, 18F9889727DB7473002F48B4 /* ImageRoomTimelineItem.swift */, 18F9889D27DB752B002F48B4 /* ImageRoomTimelineView.swift */, @@ -798,6 +804,7 @@ 18F2BB1527D25B4000DD1988 /* LoginScreenViewModelProtocol.swift in Sources */, 18F2BAEB27D25B4000DD1988 /* LabelledActivityIndicatorView.swift in Sources */, 18F2BAE427D25B4000DD1988 /* Presentable.swift in Sources */, + 18DF7C2A27E23E3A00291672 /* TimelineItemProtocol.swift in Sources */, 18F2BAF927D25B4000DD1988 /* SplashViewController.swift in Sources */, 18F2BAE327D25B4000DD1988 /* RootRouter.swift in Sources */, 18F2BAE527D25B4000DD1988 /* NavigationModule.swift in Sources */, @@ -853,6 +860,7 @@ 18C5744E27E1D84000D70937 /* MockRoomProxy.swift in Sources */, 18F2BADC27D25B4000DD1988 /* UserSession.swift in Sources */, 18F2BAEF27D25B4000DD1988 /* ActivityRequest.swift in Sources */, + 18DF7C2C27E23EC000291672 /* TimelineViewFactory.swift in Sources */, 18C5745827E1EB6E00D70937 /* TimelineItemFactory.swift in Sources */, 18F2BAEE27D25B4000DD1988 /* Activity.swift in Sources */, 18F2BAEC27D25B4000DD1988 /* ToastActivityPresenter.swift in Sources */, diff --git a/ElementX/Sources/AppCoordinator.swift b/ElementX/Sources/AppCoordinator.swift index 7bfa888c2..f51603bc1 100644 --- a/ElementX/Sources/AppCoordinator.swift +++ b/ElementX/Sources/AppCoordinator.swift @@ -117,10 +117,6 @@ class AppCoordinator: AuthenticationCoordinatorDelegate, Coordinator { let parameters = RoomScreenCoordinatorParameters(roomProxy: roomProxy) let coordinator = RoomScreenCoordinator(parameters: parameters) - coordinator.completion = { _ in - - } - self.add(childCoordinator: coordinator) self.navigationRouter.push(coordinator) { [weak self] in guard let self = self else { return } diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift index 22a6ea331..a7f3ef8e8 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenCoordinator.swift @@ -34,7 +34,6 @@ final class RoomScreenCoordinator: Coordinator, Presentable { // Must be used only internally var childCoordinators: [Coordinator] = [] - var completion: ((RoomScreenViewModelResult) -> Void)? // MARK: - Setup @@ -43,7 +42,9 @@ final class RoomScreenCoordinator: Coordinator, Presentable { self.parameters = parameters let timelineProvider = RoomTimelineProvider(roomProxy: parameters.roomProxy) - let timelineController = RoomTimelineController(timelineProvider: timelineProvider) + let timelineController = RoomTimelineController(timelineProvider: timelineProvider, + timelineItemFactory: TimelineItemFactory(), + timelineViewFactory: TimelineViewFactory()) let viewModel = RoomScreenViewModel(roomProxy: parameters.roomProxy, timelineController: timelineController) let view = RoomScreen(context: viewModel.context) @@ -53,12 +54,7 @@ final class RoomScreenCoordinator: Coordinator, Presentable { // MARK: - Public func start() { - MXLog.debug("[RoomScreenCoordinator] did start.") - roomScreenViewModel.completion = { [weak self] result in - MXLog.debug("[RoomScreenCoordinator] RoomScreenViewModel did complete with result: \(result).") - guard let self = self else { return } - self.completion?(result) - } + } func toPresentable() -> UIViewController { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift index bca369fe0..de5ebaa84 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModel.swift @@ -30,8 +30,6 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol private let roomProxy: RoomProxyProtocol private let timelineController: RoomTimelineControllerProtocol - var completion: ((RoomScreenViewModelResult) -> Void)? - // MARK: - Setup init(roomProxy: RoomProxyProtocol, timelineController: RoomTimelineControllerProtocol) { diff --git a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModelProtocol.swift b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModelProtocol.swift index 557b8e2e8..f33e5181e 100644 --- a/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModelProtocol.swift +++ b/ElementX/Sources/Screens/RoomScreen/RoomScreenViewModelProtocol.swift @@ -17,8 +17,5 @@ import Foundation protocol RoomScreenViewModelProtocol { - - var completion: ((RoomScreenViewModelResult) -> Void)? { get set } - @available(iOS 14, *) var context: RoomScreenViewModelType.Context { get } } diff --git a/ElementX/Sources/Services/Timeline/RoomTimelineController.swift b/ElementX/Sources/Services/Timeline/RoomTimelineController.swift index 2b9f63926..1eaa655f9 100644 --- a/ElementX/Sources/Services/Timeline/RoomTimelineController.swift +++ b/ElementX/Sources/Services/Timeline/RoomTimelineController.swift @@ -12,14 +12,20 @@ import MatrixRustSDK class RoomTimelineController: RoomTimelineControllerProtocol { private let timelineProvider: RoomTimelineProvider + private let timelineItemFactory: TimelineItemFactory + private let timelineViewFactory: TimelineViewFactory private var cancellables = Set() let callbacks = PassthroughSubject() private(set) var timelineItems = [RoomTimelineViewProvider]() - init(timelineProvider: RoomTimelineProvider) { + init(timelineProvider: RoomTimelineProvider, + timelineItemFactory: TimelineItemFactory, + timelineViewFactory: TimelineViewFactory) { self.timelineProvider = timelineProvider + self.timelineItemFactory = timelineItemFactory + self.timelineViewFactory = timelineViewFactory self.timelineProvider.callbacks.sink { [weak self] callback in guard let self = self else { return } @@ -63,13 +69,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol { let areMessagesFromTheSameSender = (previousMessage?.sender == message.sender) let shouldShowSenderDetails = !areMessagesFromTheSameSender || !areMessagesFromTheSameDay - let item = TextRoomTimelineItem(id: message.id, - senderDisplayName: message.sender, - text: message.content, - timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), - shouldShowSenderDetails: shouldShowSenderDetails) - - newTimelineItems.append(RoomTimelineViewProvider.text(item)) + let timelineItem = timelineItemFactory.buildTimelineItemFor(message, showSenderDetails: shouldShowSenderDetails) + newTimelineItems.append(timelineViewFactory.buildTimelineViewFor(timelineItem)) previousMessage = message } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineItem.swift index 1727fbbac..09e2308e9 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineItem.swift @@ -8,7 +8,10 @@ import Foundation -struct ImageRoomTimelineItem: Identifiable, Equatable { +struct ImageRoomTimelineItem: TimelineItemProtocol, Identifiable, Equatable { let id: String + let senderDisplayName: String let text: String + let timestamp: String + let shouldShowSenderDetails: Bool } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineView.swift b/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineView.swift index 0b858278e..8c207dc8f 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineView.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/ImageRoomTimelineView.swift @@ -17,7 +17,10 @@ struct ImageRoomTimelineView: View { if let loadedImage = loadedImage { Image(uiImage: loadedImage) } else { - ProgressView() + VStack { + Image(systemName: "photo") + ProgressView() + } } } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/SeparatorRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/SeparatorRoomTimelineItem.swift index 06d9bc88a..75fa313fe 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/SeparatorRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/SeparatorRoomTimelineItem.swift @@ -8,7 +8,7 @@ import Foundation -struct SeparatorRoomTimelineItem: Identifiable, Equatable { +struct SeparatorRoomTimelineItem: TimelineItemProtocol, Identifiable, Equatable { let id: String let text: String } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/TextRoomTimelineItem.swift b/ElementX/Sources/Services/Timeline/TimelineItems/TextRoomTimelineItem.swift index 366b02a34..3b1f3abd5 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/TextRoomTimelineItem.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/TextRoomTimelineItem.swift @@ -8,7 +8,7 @@ import Foundation -struct TextRoomTimelineItem: Identifiable, Equatable { +struct TextRoomTimelineItem: TimelineItemProtocol, Identifiable, Equatable { let id: String let senderDisplayName: String let text: String diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemFactory.swift index 1ecb8854e..3b095b39a 100644 --- a/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemFactory.swift +++ b/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemFactory.swift @@ -9,7 +9,22 @@ import Foundation struct TimelineItemFactory { - func buildTimelineItemFor(_ message: RoomMessageProtocol) { - + func buildTimelineItemFor(_ roomMessage: RoomMessageProtocol, showSenderDetails: Bool) -> TimelineItemProtocol { + switch roomMessage { + case let message as TextRoomMessage: + return TextRoomTimelineItem(id: message.id, + senderDisplayName: message.sender, + text: message.content, + timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), + shouldShowSenderDetails: showSenderDetails) + case let message as ImageRoomMessage: + return ImageRoomTimelineItem(id: message.id, + senderDisplayName: message.sender, + text: message.content, + timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened), + shouldShowSenderDetails: showSenderDetails) + default: + fatalError("Unknown room message.") + } } } diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemProtocol.swift b/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemProtocol.swift new file mode 100644 index 000000000..eae97e5ad --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/TimelineItemProtocol.swift @@ -0,0 +1,13 @@ +// +// TimelineItemProtocol.swift +// ElementX +// +// Created by Stefan Ceriu on 16/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation + +protocol TimelineItemProtocol { + +} diff --git a/ElementX/Sources/Services/Timeline/TimelineItems/TimelineViewFactory.swift b/ElementX/Sources/Services/Timeline/TimelineItems/TimelineViewFactory.swift new file mode 100644 index 000000000..276d53b82 --- /dev/null +++ b/ElementX/Sources/Services/Timeline/TimelineItems/TimelineViewFactory.swift @@ -0,0 +1,22 @@ +// +// TimelineViewFactory.swift +// ElementX +// +// Created by Stefan Ceriu on 16/03/2022. +// Copyright © 2022 Element. All rights reserved. +// + +import Foundation + +struct TimelineViewFactory { + func buildTimelineViewFor(_ timelineItem: TimelineItemProtocol) -> RoomTimelineViewProvider { + switch timelineItem { + case let textItem as TextRoomTimelineItem: + return .text(textItem) + case let imageItem as ImageRoomTimelineItem: + return .image(imageItem) + default: + fatalError("Unknown timeline item") + } + } +}