Adopt various rust side Timeline API additions (#3423)

* Adopt new reaction toggling API introduced in matrix-org/matrix-rust-sdk/pull/4127

* Adopt the changes introduced in matrix-org/matrix-rust-sdk/pull/4111: use the new `TimelineUniqueId` type instead of `String` for unique timeline identifiers.

* Bump the RustSDK to v1.0.58.

* Fix unit tests
This commit is contained in:
Stefan Ceriu
2024-10-16 19:08:34 +03:00
committed by GitHub
parent 5a89219f9a
commit 0651314e3e
35 changed files with 201 additions and 184 deletions
@@ -132,8 +132,12 @@ class TimelineInteractionHandler {
UIPasteboard.general.url = permalinkURL
}
case .redact:
guard case let .event(_, eventOrTransactionID) = itemID else {
fatalError()
}
Task {
await timelineController.redact(itemID)
await timelineController.redact(eventOrTransactionID)
}
case .reply:
guard let eventID = eventTimelineItem.id.eventID else {
@@ -159,7 +163,13 @@ class TimelineInteractionHandler {
case .react:
displayEmojiPicker(for: itemID)
case .toggleReaction(let key):
Task { await timelineController.toggleReaction(key, to: itemID) }
Task {
guard case let .event(_, eventOrTransactionID) = itemID else {
fatalError()
}
await timelineController.toggleReaction(key, to: eventOrTransactionID)
}
case .endPoll(let pollStartID):
endPoll(pollStartID: pollStartID)
case .pin:
@@ -6,6 +6,7 @@
//
import Combine
import MatrixRustSDK
import OrderedCollections
import SwiftUI
@@ -202,9 +203,9 @@ struct TimelineState {
// These can be removed when we have full swiftUI and moved as @State values in the view
var scrollToBottomPublisher = PassthroughSubject<Void, Never>()
var itemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
var itemsDictionary = OrderedDictionary<TimelineUniqueId, RoomTimelineItemViewState>()
var uniqueIDs: [String] {
var uniqueIDs: [TimelineUniqueId] {
itemsDictionary.keys.elements
}
@@ -7,6 +7,7 @@
import Combine
import Compound
import MatrixRustSDK
import SwiftUI
import OrderedCollections
@@ -47,7 +48,7 @@ class TimelineTableViewController: UIViewController {
private let coordinator: TimelineView.Coordinator
private let tableView = UITableView(frame: .zero, style: .plain)
var timelineItemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>() {
var timelineItemsDictionary = OrderedDictionary<TimelineUniqueId, RoomTimelineItemViewState>() {
didSet {
guard canApplySnapshot else {
hasPendingItems = true
@@ -145,12 +146,12 @@ class TimelineTableViewController: UIViewController {
@Binding private var isScrolledToBottom: Bool
private var timelineItemsIDs: [String] {
private var timelineItemsIDs: [TimelineUniqueId] {
timelineItemsDictionary.keys.elements.reversed()
}
/// The table's diffable data source.
private var dataSource: UITableViewDiffableDataSource<TimelineSection, String>?
private var dataSource: UITableViewDiffableDataSource<TimelineSection, TimelineUniqueId>?
private var cancellables = Set<AnyCancellable>()
/// A publisher used to throttle back pagination requests.
@@ -246,7 +247,7 @@ class TimelineTableViewController: UIViewController {
private func configureDataSource() {
dataSource = .init(tableView: tableView) { [weak self] tableView, indexPath, id in
switch id {
case TimelineTypingIndicatorCell.reuseIdentifier:
case TimelineUniqueId(id: TimelineTypingIndicatorCell.reuseIdentifier):
let cell = tableView.dequeueReusableCell(withIdentifier: TimelineTypingIndicatorCell.reuseIdentifier, for: indexPath)
guard let self else {
return cell
@@ -312,12 +313,12 @@ class TimelineTableViewController: UIViewController {
private func applySnapshot() {
guard let dataSource else { return }
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, String>()
var snapshot = NSDiffableDataSourceSnapshot<TimelineSection, TimelineUniqueId>()
// We don't want to display the typing notification in this timeline
if !coordinator.context.viewState.isPinnedEventsTimeline {
snapshot.appendSections([.typingIndicator])
snapshot.appendItems([TimelineTypingIndicatorCell.reuseIdentifier])
snapshot.appendItems([TimelineUniqueId(id: TimelineTypingIndicatorCell.reuseIdentifier)])
}
snapshot.appendSections([.main])
snapshot.appendItems(timelineItemsIDs)
@@ -516,7 +517,7 @@ extension TimelineTableViewController {
}
/// Returns the frame of the cell for a particular timeline item.
private func cellFrame(for uniqueID: String) -> CGRect? {
private func cellFrame(for uniqueID: TimelineUniqueId) -> CGRect? {
guard let timelineCell = tableView.visibleCells.first(where: { ($0 as? TimelineItemCell)?.item?.identifier.uniqueID == uniqueID }) else {
return nil
}
@@ -536,13 +537,13 @@ extension TimelineTableViewController {
}
}
private extension NSDiffableDataSourceSnapshot<TimelineTableViewController.TimelineSection, String> {
private extension NSDiffableDataSourceSnapshot<TimelineTableViewController.TimelineSection, TimelineUniqueId> {
var numberOfMainItems: Int {
guard sectionIdentifiers.contains(.main) else { return 0 }
return numberOfItems(inSection: .main)
}
var mainItemIdentifiers: [String] {
var mainItemIdentifiers: [TimelineUniqueId] {
guard sectionIdentifiers.contains(.main) else { return [] }
return itemIdentifiers(inSection: .main)
}
@@ -131,8 +131,12 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
Task { await handleItemTapped(with: id) }
case .itemSendInfoTapped(let itemID):
handleItemSendInfoTapped(itemID: itemID)
case .toggleReaction(let emoji, let itemId):
Task { await timelineController.toggleReaction(emoji, to: itemId) }
case .toggleReaction(let emoji, let itemID):
guard case let .event(_, eventOrTransactionID) = itemID else {
fatalError()
}
Task { await timelineController.toggleReaction(emoji, to: eventOrTransactionID) }
case .sendReadReceiptIfNeeded(let lastVisibleItemID):
Task { await sendReadReceiptIfNeeded(for: lastVisibleItemID) }
case .paginateBackwards:
@@ -639,7 +643,7 @@ class TimelineViewModel: TimelineViewModelType, TimelineViewModelProtocol {
// MARK: - Timeline Item Building
private func buildTimelineViews(timelineItems: [RoomTimelineItemProtocol], isSwitchingTimelines: Bool = false) {
var timelineItemsDictionary = OrderedDictionary<String, RoomTimelineItemViewState>()
var timelineItemsDictionary = OrderedDictionary<TimelineUniqueId, RoomTimelineItemViewState>()
timelineItems.filter { $0 is RedactedRoomTimelineItem }.forEach { timelineItem in
// Stops the audio player when a voice message is redacted.
@@ -623,7 +623,7 @@ private struct MockTimelineContent: View {
}
func makeItemIdentifier() -> TimelineItemIdentifier {
isPinned ? .event(uniqueID: "", eventOrTransactionID: .eventId(eventId: "pinned")) : .randomEvent
isPinned ? .event(uniqueID: .init(id: ""), eventOrTransactionID: .eventId(eventId: "pinned")) : .randomEvent
}
var replyDetails: TimelineItemReplyDetails? {
@@ -79,7 +79,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
}()
static let sendingLast: TextRoomTimelineItem = {
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? .init(id: UUID().uuidString)
var result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
timestamp: "Now",
isOutgoing: true,
@@ -99,7 +99,7 @@ struct TimelineItemStyler_Previews: PreviewProvider, TestablePreview {
}()
static let sentLast: TextRoomTimelineItem = {
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? UUID().uuidString
let id = viewModel.state.timelineViewState.uniqueIDs.last ?? .init(id: UUID().uuidString)
let result = TextRoomTimelineItem(id: .event(uniqueID: id, eventOrTransactionID: .eventId(eventId: UUID().uuidString)),
timestamp: "Now",
isOutgoing: true,
@@ -52,8 +52,8 @@ struct CollapsibleRoomTimelineView: View {
struct CollapsibleRoomTimelineView_Previews: PreviewProvider, TestablePreview {
static let item = CollapsibleTimelineItem(items: [
SeparatorRoomTimelineItem(id: .virtual(uniqueID: "First separator"), text: "This is a separator"),
SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Second separator"), text: "This is another separator")
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "First separator")), text: "This is a separator"),
SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Second separator")), text: "This is another separator")
])
static var previews: some View {
@@ -33,7 +33,7 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
VStack(alignment: .leading, spacing: 0) {
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init(id: "Separator")), text: "Today")), groupStyle: .single))
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
timestamp: "",
isOutgoing: true,
@@ -45,7 +45,7 @@ struct ReadMarkerRoomTimelineView_Previews: PreviewProvider, TestablePreview {
ReadMarkerRoomTimelineView(timelineItem: item)
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: "Separator"), text: "Today")), groupStyle: .single))
RoomTimelineItemView(viewState: .init(type: .separator(.init(id: .virtual(uniqueID: .init(id: "Separator")), text: "Today")), groupStyle: .single))
RoomTimelineItemView(viewState: .init(type: .text(.init(id: .randomEvent,
timestamp: "",
isOutgoing: false,
@@ -23,7 +23,7 @@ struct SeparatorRoomTimelineView: View {
struct SeparatorRoomTimelineView_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: "Separator"),
let item = SeparatorRoomTimelineItem(id: .virtual(uniqueID: .init(id: "Separator")),
text: "This is a separator")
SeparatorRoomTimelineView(timelineItem: item)
}