mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
Timeline: add a Jump to Unread button and a new-message badge on the scroll-to-bottom button. (#5506)
* Timeline: add a Jump to Unread button and a new-message badge on the scroll-to-bottom button. * Rename scrollToFirstUnread to scrollToReadMarker for consistency with isReadMarkerVisible. * Cache readMarkerUniqueID and unreadMessageCount as stored properties on TimelineState. * TimelineViewModel: rename newTimelineItems and drop redundant ordering comment. * Use Compound chevron icons in TimelineScrollButton. * Fix TimelineScrollButton layout at large dynamic type sizes. * Add a trailingAccessory slot to topBanners and use it to dodge banners with the jump-to-read-marker button. * Put jump-to-read-marker behind a developer-options feature flag. * Fine-tune TimelineScrollButton sizing and badge colour. * Remove TimelineScrollButton chevron offset that was compensating for SF Symbol centering. * Drop the new-messages count, replace with a presence dot. * Move both timeline scroll buttons to bottom-right and revert topBanners trailingAccessory slot. * Position TimelineScrollButton badge above for up direction and below for down direction. * Add long-press mark-as-read pill to the timeline scroll buttons * Read isSwitchingTimelines from state in updateHasNewMessagesAtBottom. * Use assertionFailure when scrollToReadMarker is called with no read marker. * Add TimelineScrollButton preview snapshots. * (fix) design and various self-review issues * (fix) suppress scroll button tap after long-press * (feat) fall back to RoomInfo.fullyReadEventID for jump-to-unread * (fix) hide jump-to-unread immediately after mark-as-read * (fix) align with newer matrix-rust-sdk surface * Bump the RustSDK to v26.05.20 --------- Signed-off-by: Daniel Anderson <daniel.anderson@toptal.com> Co-authored-by: Stefan Ceriu <stefan.ceriu@gmail.com>
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright 2026 Element Creations Ltd.
|
||||
// Copyright 2025 New Vector Ltd.
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
// Please see LICENSE files in the repository root for full details.
|
||||
//
|
||||
|
||||
@testable import ElementX
|
||||
import OrderedCollections
|
||||
import Testing
|
||||
|
||||
struct TimelineStateTests {
|
||||
// MARK: - Read marker
|
||||
|
||||
@Test("Read marker unique ID is captured when present in the timeline")
|
||||
func readMarkerUniqueIDPresent() {
|
||||
var state = TimelineState()
|
||||
state.itemsDictionary[.init("msg1")] = makeTextViewState(uniqueID: "msg1")
|
||||
state.itemsDictionary[.init("read-marker")] = makeReadMarkerViewState(uniqueID: "read-marker")
|
||||
state.itemsDictionary[.init("msg2")] = makeTextViewState(uniqueID: "msg2")
|
||||
state.recomputeReadMarkerUniqueID()
|
||||
|
||||
#expect(state.readMarkerUniqueID == .init("read-marker"))
|
||||
}
|
||||
|
||||
@Test("Read marker unique ID is nil when no marker exists")
|
||||
func readMarkerUniqueIDAbsent() {
|
||||
var state = TimelineState()
|
||||
state.itemsDictionary[.init("msg1")] = makeTextViewState(uniqueID: "msg1")
|
||||
state.itemsDictionary[.init("msg2")] = makeTextViewState(uniqueID: "msg2")
|
||||
state.recomputeReadMarkerUniqueID()
|
||||
|
||||
#expect(state.readMarkerUniqueID == nil)
|
||||
}
|
||||
|
||||
// MARK: - Helpers
|
||||
|
||||
private func makeTextViewState(uniqueID: String) -> RoomTimelineItemViewState {
|
||||
let item = TextRoomTimelineItem(id: .virtual(uniqueID: .init(uniqueID)),
|
||||
timestamp: .mock,
|
||||
isOutgoing: false,
|
||||
isEditable: false,
|
||||
canBeRepliedTo: true,
|
||||
sender: .init(id: "@sender:example.com"),
|
||||
content: .init(body: "Test message"))
|
||||
return RoomTimelineItemViewState(type: .text(item), groupStyle: .single)
|
||||
}
|
||||
|
||||
private func makeReadMarkerViewState(uniqueID: String) -> RoomTimelineItemViewState {
|
||||
let item = ReadMarkerRoomTimelineItem(id: .virtual(uniqueID: .init(uniqueID)))
|
||||
return RoomTimelineItemViewState(type: .readMarker(item), groupStyle: .single)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user