mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Made room state event collapsing configurable, expose it in the developer menu. Allow the UserSetting property wrappers to only store values in memory (+11 squashed commits)
Squashed commits: [42e45fc] Even more tweaks following code review [5dcd5be] Add swift-algoritms and switch bubbling detection to its `chunked` method [4ac70ed] Move the groupBy implementation to Collection instead of Array [6aeffc3] Tweaks following code review [0ca5ac2] Bubbles working again, grouping computed closer to the UI level [3a66030] Refactor how timeline items are built in the RoomTimelineController [57d51e9] Remove grouping from timeline items [8608950] Remove the RoomTimelineViewFactory, update the GroupRoomTimelineView [9e52e61] Add array grouping extension, unit tests and switched the timeline controller to it [7d213a1] First attempt [90bb1d7] Remove now unused `RoomTimelineController` `updatedTimelineItem` calback
This commit is contained in:
committed by
Stefan Ceriu
parent
64902190d4
commit
a3c7c47a69
+69
-86
@@ -230,61 +230,30 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
updateTimelineItems()
|
||||
}
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
private func updateTimelineItems() {
|
||||
var newTimelineItems = [RoomTimelineItemProtocol]()
|
||||
var canBackPaginate = true
|
||||
var isBackPaginating = false
|
||||
|
||||
var createdIdentifiers = [String: Bool]()
|
||||
|
||||
for (index, itemProxy) in timelineProvider.itemsPublisher.value.enumerated() {
|
||||
if Task.isCancelled {
|
||||
return
|
||||
}
|
||||
|
||||
let previousItemProxy = timelineProvider.itemsPublisher.value[safe: index - 1]
|
||||
let nextItemProxy = timelineProvider.itemsPublisher.value[safe: index + 1]
|
||||
|
||||
let groupState = computeGroupState(for: itemProxy, previousItemProxy: previousItemProxy, nextItemProxy: nextItemProxy)
|
||||
|
||||
switch itemProxy {
|
||||
case .event(let eventItemProxy):
|
||||
if let timelineItem = timelineItemFactory.buildTimelineItemFor(eventItemProxy: eventItemProxy, groupState: groupState) {
|
||||
#warning("This works around duplicated items coming out of the SDK, remove once fixed")
|
||||
if createdIdentifiers[timelineItem.id] == nil {
|
||||
newTimelineItems.append(timelineItem)
|
||||
createdIdentifiers[timelineItem.id] = true
|
||||
} else {
|
||||
MXLog.error("Found duplicated timeline item, ignoring")
|
||||
}
|
||||
}
|
||||
case .virtual(let virtualItem):
|
||||
switch virtualItem {
|
||||
case .dayDivider(let timestamp):
|
||||
// These components will be replaced by a timestamp in upcoming releases
|
||||
let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000))
|
||||
let dateString = date.formatted(date: .complete, time: .omitted)
|
||||
newTimelineItems.append(SeparatorRoomTimelineItem(text: dateString))
|
||||
case .readMarker:
|
||||
// Don't show the read marker if it's the last item in the timeline
|
||||
if index != timelineProvider.itemsPublisher.value.indices.last {
|
||||
newTimelineItems.append(ReadMarkerRoomTimelineItem())
|
||||
}
|
||||
case .loadingIndicator:
|
||||
newTimelineItems.append(PaginationIndicatorRoomTimelineItem())
|
||||
isBackPaginating = true
|
||||
case .timelineStart:
|
||||
newTimelineItems.append(TimelineStartRoomTimelineItem(name: roomProxy.displayName ?? roomProxy.name))
|
||||
canBackPaginate = false
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if Task.isCancelled {
|
||||
return
|
||||
let collapsibleChunks = timelineProvider.itemsPublisher.value.groupBy { isItemCollapsible($0) }
|
||||
|
||||
for (index, itemGroup) in collapsibleChunks.enumerated() {
|
||||
if itemGroup.count == 1, let itemProxy = itemGroup.first {
|
||||
let isLastItem = index == collapsibleChunks.indices.last
|
||||
if let item = buildTimelineItemFor(itemProxy: itemProxy, isLastItem: isLastItem, createdIdentifiers: &createdIdentifiers, isBackPaginating: &isBackPaginating, canBackPaginate: &canBackPaginate) {
|
||||
newTimelineItems.append(item)
|
||||
}
|
||||
} else {
|
||||
let items = itemGroup.compactMap { itemProxy in
|
||||
buildTimelineItemFor(itemProxy: itemProxy, isLastItem: false, createdIdentifiers: &createdIdentifiers, isBackPaginating: &isBackPaginating, canBackPaginate: &canBackPaginate)
|
||||
}
|
||||
|
||||
if !items.isEmpty {
|
||||
newTimelineItems.append(CollapsibleTimelineItem(items: items))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timelineItems = newTimelineItems
|
||||
@@ -294,49 +263,63 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
callbacks.send(.isBackPaginating(isBackPaginating))
|
||||
}
|
||||
|
||||
private func computeGroupState(for itemProxy: TimelineItemProxy,
|
||||
previousItemProxy: TimelineItemProxy?,
|
||||
nextItemProxy: TimelineItemProxy?) -> TimelineItemGroupState {
|
||||
guard let previousItem = previousItemProxy else {
|
||||
// no previous item, check next item
|
||||
guard let nextItem = nextItemProxy else {
|
||||
// no next item neither, this is single
|
||||
return .single
|
||||
private func buildTimelineItemFor(itemProxy: TimelineItemProxy,
|
||||
isLastItem: Bool,
|
||||
createdIdentifiers: inout [String: Bool],
|
||||
isBackPaginating: inout Bool,
|
||||
canBackPaginate: inout Bool) -> RoomTimelineItemProtocol? {
|
||||
switch itemProxy {
|
||||
case .event(let eventItemProxy):
|
||||
if let timelineItem = timelineItemFactory.buildTimelineItemFor(eventItemProxy: eventItemProxy) {
|
||||
#warning("This works around duplicated items coming out of the SDK, remove once fixed")
|
||||
if createdIdentifiers[timelineItem.id] == nil {
|
||||
createdIdentifiers[timelineItem.id] = true
|
||||
return timelineItem
|
||||
} else {
|
||||
MXLog.error("Found duplicated timeline item, ignoring")
|
||||
}
|
||||
}
|
||||
guard nextItem.canBeGrouped(with: itemProxy) else {
|
||||
// there is a next item but can't be grouped, this is single
|
||||
return .single
|
||||
case .virtual(let virtualItem):
|
||||
switch virtualItem {
|
||||
case .dayDivider(let timestamp):
|
||||
// These components will be replaced by a timestamp in upcoming releases
|
||||
let date = Date(timeIntervalSince1970: TimeInterval(timestamp / 1000))
|
||||
let dateString = date.formatted(date: .complete, time: .omitted)
|
||||
return SeparatorRoomTimelineItem(text: dateString)
|
||||
case .readMarker:
|
||||
// Don't show the read marker if it's the last item in the timeline
|
||||
if !isLastItem {
|
||||
return ReadMarkerRoomTimelineItem()
|
||||
}
|
||||
case .loadingIndicator:
|
||||
isBackPaginating = true
|
||||
return PaginationIndicatorRoomTimelineItem()
|
||||
case .timelineStart:
|
||||
canBackPaginate = false
|
||||
return TimelineStartRoomTimelineItem(name: roomProxy.displayName ?? roomProxy.name)
|
||||
}
|
||||
// next will be grouped with this one, this is the start
|
||||
return .beginning
|
||||
case .unknown:
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let nextItem = nextItemProxy else {
|
||||
// no next item
|
||||
guard itemProxy.canBeGrouped(with: previousItem) else {
|
||||
// there is a previous item but can't be grouped, this is single
|
||||
return .single
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
private func isItemCollapsible(_ item: TimelineItemProxy) -> Bool {
|
||||
if !ServiceLocator.shared.settings.shouldCollapseRoomStateEvents {
|
||||
return false
|
||||
}
|
||||
|
||||
if case let .event(eventItem) = item {
|
||||
switch eventItem.content.kind() {
|
||||
case .profileChange, .roomMembership, .state:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
// will be grouped with previous, this is the end
|
||||
return .end
|
||||
}
|
||||
|
||||
guard itemProxy.canBeGrouped(with: previousItem) else {
|
||||
guard nextItem.canBeGrouped(with: itemProxy) else {
|
||||
// there is a next item but can't be grouped, this is single
|
||||
return .single
|
||||
}
|
||||
// next will be grouped with this one, this is the start
|
||||
return .beginning
|
||||
}
|
||||
|
||||
guard nextItem.canBeGrouped(with: itemProxy) else {
|
||||
// there is a next item but can't be grouped, this is the end
|
||||
return .end
|
||||
}
|
||||
|
||||
// next will be grouped with this one, this is the start
|
||||
return .middle
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private func loadVideoForTimelineItem(_ timelineItem: VideoRoomTimelineItem) async {
|
||||
|
||||
Reference in New Issue
Block a user