mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Mark rooms as read on push and pop. (#462)
We don't have visibility into timeline item read status so can't do this continuously yet. * Simplify RoomTimelineProvider's responsibilities.
This commit is contained in:
+12
-12
@@ -26,7 +26,7 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
/// An array of timeline items that will be appended in order when ``simulateIncomingItems()`` is called.
|
||||
var incomingItems: [RoomTimelineItemProtocol] = []
|
||||
|
||||
let roomId = "MockRoomIdentifier"
|
||||
let roomID = "MockRoomIdentifier"
|
||||
|
||||
let callbacks = PassthroughSubject<RoomTimelineControllerCallback, Never>()
|
||||
|
||||
@@ -46,27 +46,27 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
return .success(())
|
||||
}
|
||||
|
||||
func processItemAppearance(_ itemId: String) async { }
|
||||
func markRoomAsRead() async -> Result<Void, RoomTimelineControllerError> { .success(()) }
|
||||
|
||||
func processItemDisappearance(_ itemId: String) async { }
|
||||
func processItemAppearance(_ itemID: String) async { }
|
||||
|
||||
func processItemDisappearance(_ itemID: String) async { }
|
||||
|
||||
func processItemTap(_ itemId: String) async -> RoomTimelineControllerAction { .none }
|
||||
func processItemTap(_ itemID: String) async -> RoomTimelineControllerAction { .none }
|
||||
|
||||
func sendMessage(_ message: String) async { }
|
||||
func sendMessage(_ message: String, inReplyTo itemID: String?) async { }
|
||||
|
||||
func sendReply(_ message: String, to itemId: String) async { }
|
||||
|
||||
func sendReaction(_ reaction: String, for itemId: String) async { }
|
||||
func sendReaction(_ reaction: String, to itemID: String) async { }
|
||||
|
||||
func editMessage(_ newMessage: String, of itemId: String) async { }
|
||||
func editMessage(_ newMessage: String, original itemID: String) async { }
|
||||
|
||||
func redact(_ eventID: String) async { }
|
||||
func redact(_ itemID: String) async { }
|
||||
|
||||
func debugDescriptionFor(_ itemId: String) -> String {
|
||||
func debugDescription(for itemID: String) -> String {
|
||||
"Mock debug description"
|
||||
}
|
||||
|
||||
func retryDecryption(forSessionId sessionId: String) async { }
|
||||
func retryDecryption(for sessionID: String) async { }
|
||||
|
||||
// MARK: - UI Test signalling
|
||||
|
||||
|
||||
+67
-46
@@ -37,7 +37,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
|
||||
private(set) var timelineItems = [RoomTimelineItemProtocol]()
|
||||
|
||||
var roomId: String {
|
||||
var roomID: String {
|
||||
roomProxy.id
|
||||
}
|
||||
|
||||
@@ -68,19 +68,35 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineControllerError> {
|
||||
switch await timelineProvider.paginateBackwards(requestSize: requestSize, untilNumberOfItems: untilNumberOfItems) {
|
||||
MXLog.info("Started back pagination request")
|
||||
switch await roomProxy.paginateBackwards(requestSize: requestSize, untilNumberOfItems: untilNumberOfItems) {
|
||||
case .success:
|
||||
MXLog.info("Finished back pagination request")
|
||||
return .success(())
|
||||
case .failure(.noMoreMessagesToBackPaginate):
|
||||
MXLog.warning("Back pagination requested when all messages have been loaded.")
|
||||
return .success(())
|
||||
case .failure(let error):
|
||||
if error == .noMoreMessagesToBackPaginate {
|
||||
return .success(())
|
||||
}
|
||||
MXLog.error("Failed back pagination request with error: \(error)")
|
||||
return .failure(.generic)
|
||||
}
|
||||
}
|
||||
|
||||
func processItemAppearance(_ itemId: String) async {
|
||||
guard let timelineItem = timelineItems.first(where: { $0.id == itemId }) else {
|
||||
func markRoomAsRead() async -> Result<Void, RoomTimelineControllerError> {
|
||||
guard roomProxy.hasUnreadNotifications,
|
||||
let eventID = timelineItems.last?.id
|
||||
else { return .success(()) }
|
||||
|
||||
switch await roomProxy.sendReadReceipt(for: eventID) {
|
||||
case .success:
|
||||
return .success(())
|
||||
case .failure:
|
||||
return .failure(.generic)
|
||||
}
|
||||
}
|
||||
|
||||
func processItemAppearance(_ itemID: String) async {
|
||||
guard let timelineItem = timelineItems.first(where: { $0.id == itemID }) else {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -101,18 +117,18 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func processItemDisappearance(_ itemId: String) { }
|
||||
func processItemDisappearance(_ itemID: String) { }
|
||||
|
||||
// swiftlint:disable:next cyclomatic_complexity
|
||||
func processItemTap(_ itemId: String) async -> RoomTimelineControllerAction {
|
||||
guard let timelineItem = timelineItems.first(where: { $0.id == itemId }) else {
|
||||
func processItemTap(_ itemID: String) async -> RoomTimelineControllerAction {
|
||||
guard let timelineItem = timelineItems.first(where: { $0.id == itemID }) else {
|
||||
return .none
|
||||
}
|
||||
|
||||
switch timelineItem {
|
||||
case let item as ImageRoomTimelineItem:
|
||||
await loadFileForImageTimelineItem(item)
|
||||
guard let index = timelineItems.firstIndex(where: { $0.id == itemId }),
|
||||
guard let index = timelineItems.firstIndex(where: { $0.id == itemID }),
|
||||
let item = timelineItems[index] as? ImageRoomTimelineItem else {
|
||||
return .none
|
||||
}
|
||||
@@ -122,7 +138,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
return .none
|
||||
case let item as VideoRoomTimelineItem:
|
||||
await loadVideoForTimelineItem(item)
|
||||
guard let index = timelineItems.firstIndex(where: { $0.id == itemId }),
|
||||
guard let index = timelineItems.firstIndex(where: { $0.id == itemID }),
|
||||
let item = timelineItems[index] as? VideoRoomTimelineItem else {
|
||||
return .none
|
||||
}
|
||||
@@ -132,7 +148,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
return .none
|
||||
case let item as FileRoomTimelineItem:
|
||||
await loadFileForTimelineItem(item)
|
||||
guard let index = timelineItems.firstIndex(where: { $0.id == itemId }),
|
||||
guard let index = timelineItems.firstIndex(where: { $0.id == itemID }),
|
||||
let item = timelineItems[index] as? FileRoomTimelineItem else {
|
||||
return .none
|
||||
}
|
||||
@@ -145,54 +161,59 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func sendMessage(_ message: String) async {
|
||||
MXLog.info("Send message in \(roomId)")
|
||||
switch await timelineProvider.sendMessage(message) {
|
||||
default:
|
||||
break
|
||||
func sendMessage(_ message: String, inReplyTo itemID: String?) async {
|
||||
if itemID == nil {
|
||||
MXLog.info("Send message in \(roomID)")
|
||||
} else {
|
||||
MXLog.info("Send reply in \(roomID)")
|
||||
}
|
||||
|
||||
switch await roomProxy.sendMessage(message, inReplyTo: itemID) {
|
||||
case .success:
|
||||
MXLog.info("Finished sending message")
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed sending message with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func sendReply(_ message: String, to itemId: String) async {
|
||||
MXLog.info("Send reply in \(roomId)")
|
||||
switch await timelineProvider.sendMessage(message, inReplyToItemId: itemId) {
|
||||
default:
|
||||
break
|
||||
func sendReaction(_ reaction: String, to itemID: String) async {
|
||||
MXLog.info("Send reaction in \(roomID)")
|
||||
switch await roomProxy.sendReaction(reaction, to: itemID) {
|
||||
case .success:
|
||||
MXLog.info("Finished sending reaction")
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed sending reaction with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func sendReaction(_ reaction: String, for itemId: String) async {
|
||||
MXLog.info("Send reaction in \(roomId)")
|
||||
switch await timelineProvider.sendReaction(reaction, for: itemId) {
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func editMessage(_ newMessage: String, of itemId: String) async {
|
||||
MXLog.info("Edit message in \(roomId)")
|
||||
switch await timelineProvider.editMessage(newMessage, originalItemId: itemId) {
|
||||
default:
|
||||
break
|
||||
func editMessage(_ newMessage: String, original itemID: String) async {
|
||||
MXLog.info("Edit message in \(roomID)")
|
||||
switch await roomProxy.editMessage(newMessage, original: itemID) {
|
||||
case .success:
|
||||
MXLog.info("Finished editing message")
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed editing message with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
func redact(_ eventID: String) async {
|
||||
MXLog.info("Send redaction in \(roomId)")
|
||||
switch await timelineProvider.redact(eventID) {
|
||||
default:
|
||||
break
|
||||
func redact(_ itemID: String) async {
|
||||
MXLog.info("Send redaction in \(roomID)")
|
||||
switch await roomProxy.redact(itemID) {
|
||||
case .success:
|
||||
MXLog.info("Finished redacting message")
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed redacting message with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
// Handle this paralel to the timeline items so we're not forced
|
||||
// Handle this parallel to the timeline items so we're not forced
|
||||
// to bundle the Rust side objects within them
|
||||
func debugDescriptionFor(_ itemId: String) -> String {
|
||||
func debugDescription(for itemID: String) -> String {
|
||||
var description = "Unknown item"
|
||||
timelineProvider.itemsPublisher.value.forEach { timelineItemProxy in
|
||||
switch timelineItemProxy {
|
||||
case .event(let item):
|
||||
if item.id == itemId {
|
||||
if item.id == itemID {
|
||||
description = item.debugDescription
|
||||
return
|
||||
}
|
||||
@@ -204,8 +225,8 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
return description
|
||||
}
|
||||
|
||||
func retryDecryption(forSessionId sessionId: String) async {
|
||||
await timelineProvider.retryDecryption(forSessionId: sessionId)
|
||||
func retryDecryption(for sessionID: String) async {
|
||||
await roomProxy.retryDecryption(for: sessionID)
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
+17
-11
@@ -37,30 +37,36 @@ enum RoomTimelineControllerError: Error {
|
||||
|
||||
@MainActor
|
||||
protocol RoomTimelineControllerProtocol {
|
||||
var roomId: String { get }
|
||||
var roomID: String { get }
|
||||
|
||||
var timelineItems: [RoomTimelineItemProtocol] { get }
|
||||
var callbacks: PassthroughSubject<RoomTimelineControllerCallback, Never> { get }
|
||||
|
||||
func processItemAppearance(_ itemId: String) async
|
||||
func processItemAppearance(_ itemID: String) async
|
||||
|
||||
func processItemDisappearance(_ itemId: String) async
|
||||
func processItemDisappearance(_ itemID: String) async
|
||||
|
||||
func processItemTap(_ itemId: String) async -> RoomTimelineControllerAction
|
||||
func processItemTap(_ itemID: String) async -> RoomTimelineControllerAction
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineControllerError>
|
||||
|
||||
func sendMessage(_ message: String) async
|
||||
func markRoomAsRead() async -> Result<Void, RoomTimelineControllerError>
|
||||
|
||||
func sendReply(_ message: String, to itemId: String) async
|
||||
func sendMessage(_ message: String, inReplyTo itemID: String?) async
|
||||
|
||||
func editMessage(_ newMessage: String, of itemId: String) async
|
||||
func editMessage(_ newMessage: String, original itemID: String) async
|
||||
|
||||
func sendReaction(_ reaction: String, for itemId: String) async
|
||||
func sendReaction(_ reaction: String, to itemID: String) async
|
||||
|
||||
func redact(_ eventID: String) async
|
||||
func redact(_ itemID: String) async
|
||||
|
||||
func debugDescriptionFor(_ itemId: String) -> String
|
||||
func debugDescription(for itemID: String) -> String
|
||||
|
||||
func retryDecryption(forSessionId sessionId: String) async
|
||||
func retryDecryption(for sessionID: String) async
|
||||
}
|
||||
|
||||
extension RoomTimelineControllerProtocol {
|
||||
func sendMessage(_ message: String) async {
|
||||
await sendMessage(message, inReplyTo: nil)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user