Hook up the RoomThreadList to the RoomFlowCoordinator state machine and presenting threads.

This commit is contained in:
Stefan Ceriu
2026-04-01 09:27:39 +03:00
committed by Stefan Ceriu
parent 212cd42161
commit a358cacf31
9 changed files with 67 additions and 17 deletions
@@ -394,6 +394,11 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case (.room, .presentPinnedEventsTimeline, .pinnedEventsTimeline):
startPinnedEventsTimelineFlow()
// Thread List
case (.room, .presentThreadList, .threadList):
Task { await self.presentThreadList(animated: animated) }
// Thread
case (_, .presentThread(let threadRootEventID, let focusEventID), .thread):
@@ -721,9 +726,7 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
case .presentKnockRequestsList:
stateMachine.tryEvent(.presentKnockRequestsListScreen)
case .presentThreadList:
Task {
await self.presentThreadList(animated: true)
}
stateMachine.tryEvent(.presentThreadList, userInfo: EventUserInfo(animated: animated))
case .presentThread(let threadRootEventID, let focussedEventID):
stateMachine.tryEvent(.presentThread(threadRootEventID: threadRootEventID, focusEventID: focussedEventID))
case .presentRoom(let roomID, let via):
@@ -738,12 +741,21 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
}
private func presentThreadList(animated: Bool) async {
let coordinator = await RoomThreadListScreenCoordinator(parameters: .init(threadListServiceProxy: roomProxy.threadListService(),
mediaProvider: userSession.mediaProvider))
let coordinator = RoomThreadListScreenCoordinator(parameters: .init(threadListServiceProxy: roomProxy.threadListService(),
mediaProvider: userSession.mediaProvider))
coordinator.actionsPublisher.sink { [weak self] _ in }.store(in: &cancellables)
coordinator.actionsPublisher.sink { [weak self] action in
guard let self else { return }
switch action {
case .presentThread(let threadRootEventID):
stateMachine.tryEvent(.presentThread(threadRootEventID: threadRootEventID, focusEventID: nil))
}
}.store(in: &cancellables)
navigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in }
navigationStackCoordinator.push(coordinator, animated: animated) { [weak self] in
guard let self else { return }
stateMachine.tryEvent(.dismissThreadList)
}
}
private func presentThread(threadRootEventID: String, focusEventID: String?, animated: Bool) async {
@@ -59,6 +59,7 @@ extension RoomFlowCoordinator {
case initial
case joinRoomScreen
case room
case threadList
case thread(threadRootEventID: String, previousState: State)
case roomDetails(isRoot: Bool)
case roomDetailsEditScreen
@@ -113,6 +114,9 @@ extension RoomFlowCoordinator {
case presentThread(threadRootEventID: String, focusEventID: String?)
case dismissThread
case presentThreadList
case dismissThreadList
case startSpaceFlow
case finishedSpaceFlow
@@ -236,6 +240,14 @@ extension RoomFlowCoordinator {
case (.pinnedEventsTimeline(let previousState), .dismissPinnedEventsTimeline):
return previousState
// Thread List
case (.room, .presentThreadList):
return .threadList
case (.threadList, .dismissThreadList):
return .room
case (.threadList, .presentThread(let threadRootEventID, _)):
return .thread(threadRootEventID: threadRootEventID, previousState: fromState)
// Thread
case (.room, .presentThread(let threadRootEventID, _)):
return .thread(threadRootEventID: threadRootEventID, previousState: fromState)
@@ -6984,12 +6984,12 @@ class JoinedRoomProxyMock: JoinedRoomProxyProtocol, @unchecked Sendable {
}
}
}
var threadListServiceClosure: (() async -> RoomThreadListServiceProxyProtocol)?
var threadListServiceClosure: (() -> RoomThreadListServiceProxyProtocol)?
func threadListService() async -> RoomThreadListServiceProxyProtocol {
func threadListService() -> RoomThreadListServiceProxyProtocol {
threadListServiceCallsCount += 1
if let threadListServiceClosure = threadListServiceClosure {
return await threadListServiceClosure()
return threadListServiceClosure()
} else {
return threadListServiceReturnValue
}
@@ -13,7 +13,9 @@ struct RoomThreadListScreenCoordinatorParameters {
let mediaProvider: MediaProviderProtocol
}
enum RoomThreadListScreenCoordinatorAction { }
enum RoomThreadListScreenCoordinatorAction {
case presentThread(threadRootEventID: String)
}
final class RoomThreadListScreenCoordinator: CoordinatorProtocol {
private let parameters: RoomThreadListScreenCoordinatorParameters
@@ -35,7 +37,13 @@ final class RoomThreadListScreenCoordinator: CoordinatorProtocol {
func start() {
viewModel.actionsPublisher.sink { [weak self] action in
guard let self else { return }
MXLog.info("Coordinator: received view model action: \(action)")
switch action {
case .presentThread(let threadRootEventID):
actionsSubject.send(.presentThread(threadRootEventID: threadRootEventID))
}
}
.store(in: &cancellables)
}
@@ -7,7 +7,9 @@
import Foundation
enum RoomThreadListScreenViewModelAction { }
enum RoomThreadListScreenViewModelAction {
case presentThread(threadRootEventID: String)
}
struct RoomThreadListScreenViewState: BindableState {
var items = [RoomThreadListItem]()
@@ -22,4 +24,5 @@ struct RoomThreadListScreenViewStateBindings { }
enum RoomThreadListScreenViewAction {
case oldestItemDidAppear
case oldestItemDidDisappear
case tappedThread(threadRootEventID: String)
}
@@ -58,6 +58,8 @@ class RoomThreadListScreenViewModel: RoomThreadListScreenViewModelType, RoomThre
}
case .oldestItemDidDisappear:
isOldestItemVisible = false
case .tappedThread(let threadRootEventID):
actionsSubject.send(.presentThread(threadRootEventID: threadRootEventID))
}
}
@@ -15,9 +15,14 @@ struct RoomThreadListScreen: View {
ScrollView {
LazyVStack(spacing: 0) {
ForEach(context.viewState.items) { item in
RoomThreadListCell(item: item, mediaProvider: context.mediaProvider)
.padding(.horizontal, 16)
.padding(.vertical, 8)
Button {
context.send(viewAction: .tappedThread(threadRootEventID: item.id))
} label: {
RoomThreadListCell(item: item, mediaProvider: context.mediaProvider)
.padding(.horizontal, 16)
.padding(.vertical, 8)
}
.buttonStyle(ThreadCellButtonStyle())
}
footer
@@ -137,6 +142,14 @@ private struct RoomThreadListCell: View {
}
}
private struct ThreadCellButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.background(configuration.isPressed ? Color.compound.bgSubtleSecondary : Color.compound.bgCanvasDefault)
.contentShape(Rectangle())
}
}
// MARK: - Previews
struct RoomThreadListScreen_Previews: PreviewProvider, TestablePreview {
@@ -203,7 +203,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
}
}
func threadListService() async -> RoomThreadListServiceProxyProtocol {
func threadListService() -> RoomThreadListServiceProxyProtocol {
RoomThreadListProxy(threadListService: room.threadListService(), eventStringBuilder: eventStringBuilder)
}
@@ -98,7 +98,7 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
func threadTimeline(eventID: String) async -> Result<TimelineProxyProtocol, RoomProxyError>
func threadListService() async -> RoomThreadListServiceProxyProtocol
func threadListService() -> RoomThreadListServiceProxyProtocol
func loadOrFetchEventDetails(for eventID: String) async -> Result<TimelineEvent, RoomProxyError>