tombstoned and upgraded rooms implementation

added tests

tombstoned room avatar
This commit is contained in:
Mauro Romito
2025-06-03 12:52:31 +02:00
committed by Mauro
parent b628f5d2c2
commit 155b47e849
76 changed files with 438 additions and 171 deletions
@@ -28,6 +28,7 @@ enum TimelineViewModelAction {
case composer(action: TimelineComposerAction)
case hasScrolled(direction: ScrollDirection)
case viewInRoomTimeline(eventID: String)
case displayRoom(roomID: String)
}
enum TimelineViewPollAction {
@@ -77,6 +78,8 @@ enum TimelineViewAction {
case hasScrolled(direction: ScrollDirection)
case setOpenURLAction(OpenURLAction)
case seePredecessorTapped
}
enum TimelineComposerAction {
@@ -106,6 +109,8 @@ struct TimelineViewState: BindableState {
var isViewSourceEnabled: Bool
var areThreadsEnabled: Bool
var hideTimelineMedia: Bool
let hasPredecessor: Bool
// The `pinnedEventIDs` are used only to determine if an item is already pinned or not.
// It's updated from the room info, so it's faster than using the timeline
@@ -104,6 +104,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
isViewSourceEnabled: appSettings.viewSourceEnabled,
areThreadsEnabled: appSettings.threadsEnabled,
hideTimelineMedia: hideTimelineMedia,
hasPredecessor: roomProxy.predecessorRoom != nil,
pinnedEventIDs: roomProxy.infoPublisher.value.pinnedEventIDs,
emojiProvider: emojiProvider,
mapTilerConfiguration: appSettings.mapTilerConfiguration,
@@ -211,6 +212,9 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
actionsSubject.send(.hasScrolled(direction: direction))
case .setOpenURLAction(let action):
state.openURL = action
case .seePredecessorTapped:
guard let predecessorID = roomProxy.predecessorRoom?.roomId else { return }
actionsSubject.send(.displayRoom(roomID: predecessorID))
}
}
@@ -1018,11 +1022,12 @@ private extension RoomInfoProxy {
extension TimelineViewModel {
static let mock = mock(timelineKind: .live)
static func mock(timelineKind: TimelineKind = .live, timelineController: MockTimelineController? = nil) -> TimelineViewModel {
static func mock(timelineKind: TimelineKind = .live, timelineController: MockTimelineController? = nil, hasPredecessor: Bool = false) -> TimelineViewModel {
let clientProxyMock = ClientProxyMock(.init())
clientProxyMock.roomSummaryForAliasReturnValue = .mock(id: "!room:matrix.org", name: "Room")
clientProxyMock.roomSummaryForIdentifierReturnValue = .mock(id: "!room:matrix.org", name: "Room", canonicalAlias: "#room:matrix.org")
return TimelineViewModel(roomProxy: JoinedRoomProxyMock(.init(name: "Preview room")),
let roomProxy = JoinedRoomProxyMock(.init(name: "Preview room", predecessor: hasPredecessor ? .init(roomId: UUID().uuidString, lastEventId: UUID().uuidString) : nil))
return TimelineViewModel(roomProxy: roomProxy,
focussedEventID: nil,
timelineController: timelineController ?? MockTimelineController(timelineKind: timelineKind),
mediaProvider: MediaProviderMock(configuration: .init()),
@@ -5,20 +5,50 @@
// Please see LICENSE files in the repository root for full details.
//
import Compound
import SwiftUI
struct TimelineStartRoomTimelineView: View {
let timelineItem: TimelineStartRoomTimelineItem
@Environment(\.timelineContext) private var context
var body: some View {
Text(title)
.font(.compound.bodySM)
.foregroundColor(.compound.textSecondary)
.padding(.vertical, 24)
.frame(maxWidth: .infinity)
VStack(spacing: 14) {
if context?.viewState.hasPredecessor == true {
upgrade
}
if context?.viewState.isDirectOneToOneRoom != true {
Text(title)
.font(.compound.bodySM)
.foregroundColor(.compound.textSecondary)
.padding(.bottom, 24)
.padding(.top, context?.viewState.hasPredecessor == true ? 0 : 24)
.frame(maxWidth: .infinity)
}
}
}
var title: String {
private var upgrade: some View {
VStack(spacing: 16) {
Text(L10n.screenRoomTimelineUpgradedRoomMessage)
.font(.compound.bodyMD)
.foregroundColor(.compound.textPrimary)
Button {
context?.send(viewAction: .seePredecessorTapped)
} label: {
Text(L10n.screenRoomTimelineUpgradedRoomAction)
.frame(maxWidth: .infinity)
}
.buttonStyle(.compound(.primary, size: .medium))
.frame(maxWidth: .infinity)
}
.padding(.top, 16)
.padding(.bottom, 8)
.padding(.horizontal, 16)
.highlight(borderColor: .compound.borderInfoSubtle, primaryColor: .compound.bgInfoSubtle, secondaryColor: Color.clear)
}
private var title: String {
var text = L10n.screenRoomTimelineBeginningOfRoomNoName
if let name = timelineItem.name {
text = L10n.screenRoomTimelineBeginningOfRoom(name)
@@ -28,8 +58,15 @@ struct TimelineStartRoomTimelineView: View {
}
struct TimelineStartRoomTimelineView_Previews: PreviewProvider, TestablePreview {
static let viewModel = TimelineViewModel.mock(hasPredecessor: true)
static var previews: some View {
let item = TimelineStartRoomTimelineItem(name: "Alice and Bob")
TimelineStartRoomTimelineView(timelineItem: item)
.previewLayout(.sizeThatFits)
TimelineStartRoomTimelineView(timelineItem: item)
.environment(\.timelineContext, viewModel.context)
.previewLayout(.sizeThatFits)
.previewDisplayName("with predecessor")
}
}