Use the timeline when marking a room as read (#4319)

* Forward JoinedRoomProxy.markAsRead to the timeline

The room version was building a fresh timeline even though we already had one.

* Run swiftformat 0.57.0.
This commit is contained in:
Doug
2025-07-14 12:20:41 +01:00
committed by GitHub
parent 53774e26fb
commit e46165119f
8 changed files with 98 additions and 11 deletions
@@ -17520,6 +17520,76 @@ class TimelineProxyMock: TimelineProxyProtocol, @unchecked Sendable {
return sendReadReceiptForTypeReturnValue
}
}
//MARK: - markAsRead
var markAsReadReceiptTypeUnderlyingCallsCount = 0
var markAsReadReceiptTypeCallsCount: Int {
get {
if Thread.isMainThread {
return markAsReadReceiptTypeUnderlyingCallsCount
} else {
var returnValue: Int? = nil
DispatchQueue.main.sync {
returnValue = markAsReadReceiptTypeUnderlyingCallsCount
}
return returnValue!
}
}
set {
if Thread.isMainThread {
markAsReadReceiptTypeUnderlyingCallsCount = newValue
} else {
DispatchQueue.main.sync {
markAsReadReceiptTypeUnderlyingCallsCount = newValue
}
}
}
}
var markAsReadReceiptTypeCalled: Bool {
return markAsReadReceiptTypeCallsCount > 0
}
var markAsReadReceiptTypeReceivedReceiptType: ReceiptType?
var markAsReadReceiptTypeReceivedInvocations: [ReceiptType] = []
var markAsReadReceiptTypeUnderlyingReturnValue: Result<Void, TimelineProxyError>!
var markAsReadReceiptTypeReturnValue: Result<Void, TimelineProxyError>! {
get {
if Thread.isMainThread {
return markAsReadReceiptTypeUnderlyingReturnValue
} else {
var returnValue: Result<Void, TimelineProxyError>? = nil
DispatchQueue.main.sync {
returnValue = markAsReadReceiptTypeUnderlyingReturnValue
}
return returnValue!
}
}
set {
if Thread.isMainThread {
markAsReadReceiptTypeUnderlyingReturnValue = newValue
} else {
DispatchQueue.main.sync {
markAsReadReceiptTypeUnderlyingReturnValue = newValue
}
}
}
}
var markAsReadReceiptTypeClosure: ((ReceiptType) async -> Result<Void, TimelineProxyError>)?
func markAsRead(receiptType: ReceiptType) async -> Result<Void, TimelineProxyError> {
markAsReadReceiptTypeCallsCount += 1
markAsReadReceiptTypeReceivedReceiptType = receiptType
DispatchQueue.main.async {
self.markAsReadReceiptTypeReceivedInvocations.append(receiptType)
}
if let markAsReadReceiptTypeClosure = markAsReadReceiptTypeClosure {
return await markAsReadReceiptTypeClosure(receiptType)
} else {
return markAsReadReceiptTypeReturnValue
}
}
//MARK: - sendMessageEventContent
var sendMessageEventContentUnderlyingCallsCount = 0
@@ -69,7 +69,7 @@ struct DocumentPicker: UIViewControllerRepresentable {
}
do {
let _ = url.startAccessingSecurityScopedResource()
_ = url.startAccessingSecurityScopedResource()
let newURL = try FileManager.default.copyFileToTemporaryDirectory(file: url)
url.stopAccessingSecurityScopedResource()
documentPicker.callback(.selectFile(newURL))
@@ -78,7 +78,7 @@ struct PhotoLibraryPicker: UIViewControllerRepresentable {
}
do {
let _ = url.startAccessingSecurityScopedResource()
_ = url.startAccessingSecurityScopedResource()
let newURL = try FileManager.default.copyFileToTemporaryDirectory(file: url)
url.stopAccessingSecurityScopedResource()
@@ -402,14 +402,16 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
return .failure(.sdkError(error))
}
}
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError> {
do {
try await room.markAsRead(receiptType: receiptType)
return .success(())
} catch {
MXLog.error("Failed marking room \(id) as read with error: \(error)")
return .failure(.sdkError(error))
// Defer to the timeline here as room.markAsRead will build a fresh timeline.
switch await timeline.markAsRead(receiptType: receiptType) {
case .success:
.success(())
case .failure(.sdkError(let error)):
.failure(.sdkError(error))
case .failure(let error):
.failure(.timelineError(error))
}
}
@@ -17,6 +17,7 @@ enum RoomProxyError: Error {
case eventNotFound
case missingTransactionID
case failedCreatingPinnedTimeline
case timelineError(TimelineProxyError)
}
/// An enum that describes the relationship between the current user and the room, and contains a reference to the specific implementation of the `RoomProxy`.
@@ -514,6 +514,19 @@ final class TimelineProxy: TimelineProxyProtocol {
}
}
func markAsRead(receiptType: ReceiptType) async -> Result<Void, TimelineProxyError> {
MXLog.info("Marking as \(receiptType)")
do {
try await timeline.markAsRead(receiptType: receiptType)
MXLog.info("Finished marking as read")
return .success(())
} catch {
MXLog.error("Failed marking as \(receiptType) with error: \(error)")
return .failure(.sdkError(error))
}
}
func toggleReaction(_ reaction: String, to eventOrTransactionID: TimelineItemIdentifier.EventOrTransactionID) async -> Result<Void, TimelineProxyError> {
MXLog.info("Toggling reaction \(reaction) for event: \(eventOrTransactionID)")
@@ -119,6 +119,7 @@ protocol TimelineProxyProtocol {
requestHandle: @MainActor (SendAttachmentJoinHandleProtocol) -> Void) async -> Result<Void, TimelineProxyError>
func sendReadReceipt(for eventID: String, type: ReceiptType) async -> Result<Void, TimelineProxyError>
func markAsRead(receiptType: ReceiptType) async -> Result<Void, TimelineProxyError>
func sendMessageEventContent(_ messageContent: RoomMessageEventContentWithoutRelation) async -> Result<Void, TimelineProxyError>
@@ -182,7 +182,7 @@ enum SlidingSyncVersionV1: Equatable {
}
extension SessionV1: Codable {
public init(from decoder: Decoder) throws {
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let slidingSyncProxy = try container.decodeIfPresent(String.self, forKey: .slidingSyncProxy)
self = try .init(accessToken: container.decode(String.self, forKey: .accessToken),
@@ -194,7 +194,7 @@ extension SessionV1: Codable {
slidingSyncVersion: slidingSyncProxy.map { .proxy(url: $0) } ?? .native)
}
public func encode(to encoder: Encoder) throws {
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(accessToken, forKey: .accessToken)
try container.encode(refreshToken, forKey: .refreshToken)