RoomTimeline… refactor (drop the Room). (#3728)

* Add the timeline controller factory to the timeline view model.

In preparation for building a timeline to swipe through media in QuickLook.

* Refactor RoomTimelineControllerFactory.

* Refactor RoomTimelineController.

* Refactor RoomTimelineProvider.
This commit is contained in:
Doug
2025-02-03 14:14:01 +00:00
committed by GitHub
parent 9df5a8fddb
commit d195e603c9
53 changed files with 688 additions and 631 deletions
@@ -29,7 +29,7 @@ enum TimelineInteractionHandlerAction {
@MainActor
class TimelineInteractionHandler {
private let roomProxy: JoinedRoomProxyProtocol
private let timelineController: RoomTimelineControllerProtocol
private let timelineController: TimelineControllerProtocol
private let mediaProvider: MediaProviderProtocol
private let mediaPlayerProvider: MediaPlayerProviderProtocol
private let voiceMessageRecorder: VoiceMessageRecorderProtocol
@@ -38,6 +38,8 @@ class TimelineInteractionHandler {
private let appMediator: AppMediatorProtocol
private let appSettings: AppSettings
private let analyticsService: AnalyticsService
private let emojiProvider: EmojiProviderProtocol
private let timelineControllerFactory: TimelineControllerFactoryProtocol
private let pollInteractionHandler: PollInteractionHandlerProtocol
private let actionsSubject: PassthroughSubject<TimelineInteractionHandlerAction, Never> = .init()
@@ -54,7 +56,7 @@ class TimelineInteractionHandler {
private var resumeVoiceMessagePlaybackAfterScrubbing = false
init(roomProxy: JoinedRoomProxyProtocol,
timelineController: RoomTimelineControllerProtocol,
timelineController: TimelineControllerProtocol,
mediaProvider: MediaProviderProtocol,
mediaPlayerProvider: MediaPlayerProviderProtocol,
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
@@ -62,7 +64,9 @@ class TimelineInteractionHandler {
userIndicatorController: UserIndicatorControllerProtocol,
appMediator: AppMediatorProtocol,
appSettings: AppSettings,
analyticsService: AnalyticsService) {
analyticsService: AnalyticsService,
emojiProvider: EmojiProviderProtocol,
timelineControllerFactory: TimelineControllerFactoryProtocol) {
self.roomProxy = roomProxy
self.timelineController = timelineController
self.mediaProvider = mediaProvider
@@ -73,6 +77,8 @@ class TimelineInteractionHandler {
self.appMediator = appMediator
self.appSettings = appSettings
self.analyticsService = analyticsService
self.emojiProvider = emojiProvider
self.timelineControllerFactory = timelineControllerFactory
pollInteractionHandler = PollInteractionHandler(analyticsService: analyticsService, roomProxy: roomProxy)
}
@@ -495,7 +501,7 @@ class TimelineInteractionHandler {
actionsSubject.send(.displayEmojiPicker(itemID: itemID, selectedEmojis: selectedEmojis))
}
func processItemTap(_ itemID: TimelineItemIdentifier) async -> RoomTimelineControllerAction {
func processItemTap(_ itemID: TimelineItemIdentifier) async -> TimelineControllerAction {
guard let timelineItem = timelineController.timelineItems.firstUsingStableID(itemID) else {
return .none
}
@@ -522,7 +528,7 @@ class TimelineInteractionHandler {
}
}
private func displayMediaActionIfPossible(timelineItem: RoomTimelineItemProtocol) async -> RoomTimelineControllerAction {
private func displayMediaActionIfPossible(timelineItem: RoomTimelineItemProtocol) async -> TimelineControllerAction {
var source: MediaSourceProxy?
var filename: String
var caption: String?
@@ -22,13 +22,14 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
}
private let roomProxy: JoinedRoomProxyProtocol
private let timelineController: RoomTimelineControllerProtocol
private let timelineController: TimelineControllerProtocol
private let mediaPlayerProvider: MediaPlayerProviderProtocol
private let userIndicatorController: UserIndicatorControllerProtocol
private let appMediator: AppMediatorProtocol
private let appSettings: AppSettings
private let analyticsService: AnalyticsService
private let emojiProvider: EmojiProviderProtocol
private let timelineControllerFactory: TimelineControllerFactoryProtocol
private let timelineInteractionHandler: TimelineInteractionHandler
@@ -44,7 +45,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
init(roomProxy: JoinedRoomProxyProtocol,
focussedEventID: String? = nil,
timelineController: RoomTimelineControllerProtocol,
timelineController: TimelineControllerProtocol,
mediaProvider: MediaProviderProtocol,
mediaPlayerProvider: MediaPlayerProviderProtocol,
voiceMessageMediaManager: VoiceMessageMediaManagerProtocol,
@@ -52,7 +53,8 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
appMediator: AppMediatorProtocol,
appSettings: AppSettings,
analyticsService: AnalyticsService,
emojiProvider: EmojiProviderProtocol) {
emojiProvider: EmojiProviderProtocol,
timelineControllerFactory: TimelineControllerFactoryProtocol) {
self.timelineController = timelineController
self.mediaPlayerProvider = mediaPlayerProvider
self.roomProxy = roomProxy
@@ -61,6 +63,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
self.userIndicatorController = userIndicatorController
self.appMediator = appMediator
self.emojiProvider = emojiProvider
self.timelineControllerFactory = timelineControllerFactory
let voiceMessageRecorder = VoiceMessageRecorder(audioRecorder: AudioRecorder(), mediaPlayerProvider: mediaPlayerProvider)
@@ -73,7 +76,9 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
userIndicatorController: userIndicatorController,
appMediator: appMediator,
appSettings: appSettings,
analyticsService: analyticsService)
analyticsService: analyticsService,
emojiProvider: emojiProvider,
timelineControllerFactory: timelineControllerFactory)
super.init(initialViewState: TimelineViewState(timelineKind: timelineController.timelineKind,
roomID: roomProxy.id,
@@ -865,10 +870,10 @@ private extension RoomInfoProxy {
extension TimelineViewModel {
static let mock = mock(timelineKind: .live)
static func mock(timelineKind: TimelineKind = .live, timelineController: MockRoomTimelineController? = nil) -> TimelineViewModel {
static func mock(timelineKind: TimelineKind = .live, timelineController: MockTimelineController? = nil) -> TimelineViewModel {
TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Preview room")),
focussedEventID: nil,
timelineController: timelineController ?? MockRoomTimelineController(timelineKind: timelineKind),
timelineController: timelineController ?? MockTimelineController(timelineKind: timelineKind),
mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
@@ -876,7 +881,8 @@ extension TimelineViewModel {
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
}
}
@@ -44,7 +44,7 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview {
]
let roomProxyMock = JoinedRoomProxyMock(.init(name: "Room", members: members))
let mock = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
timelineController: MockTimelineController(),
mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
@@ -52,7 +52,8 @@ struct ReadReceiptsSummaryView_Previews: PreviewProvider, TestablePreview {
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
return mock
}()
@@ -330,7 +330,7 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
let roomProxy = JoinedRoomProxyMock(.init(name: "Preview Room", pinnedEventIDs: ["pinned"]))
return TimelineViewModel(roomProxy: roomProxy,
focussedEventID: nil,
timelineController: MockRoomTimelineController(),
timelineController: MockTimelineController(),
mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
@@ -338,7 +338,8 @@ struct TimelineItemBubbledStylerView_Previews: PreviewProvider, TestablePreview
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
}()
static var previews: some View {
@@ -79,7 +79,7 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview {
]
static let viewModel = TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Test", members: members)),
timelineController: MockRoomTimelineController(),
timelineController: MockTimelineController(),
mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
@@ -87,7 +87,8 @@ struct TimelineReadReceiptsView_Previews: PreviewProvider, TestablePreview {
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
static let singleReceipt = [ReadReceipt(userID: RoomMemberProxyMock.mockAlice.userID, formattedTimestamp: "Now")]
static let doubleReceipt = [ReadReceipt(userID: RoomMemberProxyMock.mockAlice.userID, formattedTimestamp: "Now"),
@@ -89,7 +89,7 @@ struct HighlightedTimelineItemTimeline_Previews: PreviewProvider {
static let focussedEventID = "RoomTimelineItemFixtures.default.5"
static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock,
focussedEventID: focussedEventID,
timelineController: MockRoomTimelineController(),
timelineController: MockTimelineController(),
mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
@@ -97,7 +97,8 @@ struct HighlightedTimelineItemTimeline_Previews: PreviewProvider {
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
static var previews: some View {
NavigationStack {
@@ -82,7 +82,7 @@ struct TimelineView_Previews: PreviewProvider, TestablePreview {
name: "Preview room"))
static let roomViewModel = RoomScreenViewModel.mock(roomProxyMock: roomProxyMock)
static let timelineViewModel = TimelineViewModel(roomProxy: roomProxyMock,
timelineController: MockRoomTimelineController(),
timelineController: MockTimelineController(),
mediaProvider: MediaProviderMock(configuration: .init()),
mediaPlayerProvider: MediaPlayerProviderMock(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock(),
@@ -90,7 +90,8 @@ struct TimelineView_Previews: PreviewProvider, TestablePreview {
appMediator: AppMediatorMock.default,
appSettings: ServiceLocator.shared.settings,
analyticsService: ServiceLocator.shared.analytics,
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings))
emojiProvider: EmojiProvider(appSettings: ServiceLocator.shared.settings),
timelineControllerFactory: TimelineControllerFactoryMock(.init()))
static var previews: some View {
NavigationStack {