Bump the RustSDK, adopt new marking/flagging rooms as (un)read API and fix sending read receipts when entering rooms or making the app active again
This commit is contained in:
committed by
Stefan Ceriu
parent
db2ce05e77
commit
8107d12844
@@ -6779,7 +6779,7 @@
|
||||
repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 1.1.38;
|
||||
version = 1.1.39;
|
||||
};
|
||||
};
|
||||
821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = {
|
||||
|
||||
@@ -129,8 +129,8 @@
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
|
||||
"state" : {
|
||||
"revision" : "691d8b0f0994d9669fadbd2452bef7270f3713ad",
|
||||
"version" : "1.1.38"
|
||||
"revision" : "8a5813a3cdf541bee3ceb4776c362d1f6b767581",
|
||||
"version" : "1.1.39"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -262,7 +262,7 @@
|
||||
{
|
||||
"identity" : "swiftui-introspect",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/siteline/SwiftUI-Introspect",
|
||||
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
|
||||
"state" : {
|
||||
"revision" : "b94da693e57eaf79d16464b8b7c90d09cba4e290",
|
||||
"version" : "0.9.2"
|
||||
|
||||
@@ -409,9 +409,8 @@ class RoomFlowCoordinator: FlowCoordinatorProtocol {
|
||||
self.roomProxy = roomProxy
|
||||
|
||||
Task {
|
||||
// Mark the room as read on entering but don't send read receipts
|
||||
// as those will be handled by the timeline
|
||||
await roomProxy.markAsRead(sendReadReceipts: false, receiptType: appSettings.sharePresence ? .read : .readPrivate)
|
||||
// Flag the room as read on entering, the timeline will take care of the read receipts
|
||||
await roomProxy.flagAsRead()
|
||||
}
|
||||
|
||||
let userID = userSession.clientProxy.userID
|
||||
|
||||
@@ -2232,42 +2232,59 @@ class RoomProxyMock: RoomProxyProtocol {
|
||||
return canUserTriggerRoomNotificationUserIDReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - markAsUnread
|
||||
//MARK: - flagAsUnread
|
||||
|
||||
var markAsUnreadCallsCount = 0
|
||||
var markAsUnreadCalled: Bool {
|
||||
return markAsUnreadCallsCount > 0
|
||||
var flagAsUnreadCallsCount = 0
|
||||
var flagAsUnreadCalled: Bool {
|
||||
return flagAsUnreadCallsCount > 0
|
||||
}
|
||||
var markAsUnreadReturnValue: Result<Void, RoomProxyError>!
|
||||
var markAsUnreadClosure: (() async -> Result<Void, RoomProxyError>)?
|
||||
var flagAsUnreadReturnValue: Result<Void, RoomProxyError>!
|
||||
var flagAsUnreadClosure: (() async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func markAsUnread() async -> Result<Void, RoomProxyError> {
|
||||
markAsUnreadCallsCount += 1
|
||||
if let markAsUnreadClosure = markAsUnreadClosure {
|
||||
return await markAsUnreadClosure()
|
||||
func flagAsUnread() async -> Result<Void, RoomProxyError> {
|
||||
flagAsUnreadCallsCount += 1
|
||||
if let flagAsUnreadClosure = flagAsUnreadClosure {
|
||||
return await flagAsUnreadClosure()
|
||||
} else {
|
||||
return markAsUnreadReturnValue
|
||||
return flagAsUnreadReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - flagAsRead
|
||||
|
||||
var flagAsReadCallsCount = 0
|
||||
var flagAsReadCalled: Bool {
|
||||
return flagAsReadCallsCount > 0
|
||||
}
|
||||
var flagAsReadReturnValue: Result<Void, RoomProxyError>!
|
||||
var flagAsReadClosure: (() async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func flagAsRead() async -> Result<Void, RoomProxyError> {
|
||||
flagAsReadCallsCount += 1
|
||||
if let flagAsReadClosure = flagAsReadClosure {
|
||||
return await flagAsReadClosure()
|
||||
} else {
|
||||
return flagAsReadReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - markAsRead
|
||||
|
||||
var markAsReadSendReadReceiptsReceiptTypeCallsCount = 0
|
||||
var markAsReadSendReadReceiptsReceiptTypeCalled: Bool {
|
||||
return markAsReadSendReadReceiptsReceiptTypeCallsCount > 0
|
||||
var markAsReadReceiptTypeCallsCount = 0
|
||||
var markAsReadReceiptTypeCalled: Bool {
|
||||
return markAsReadReceiptTypeCallsCount > 0
|
||||
}
|
||||
var markAsReadSendReadReceiptsReceiptTypeReceivedArguments: (sendReadReceipts: Bool, receiptType: ReceiptType)?
|
||||
var markAsReadSendReadReceiptsReceiptTypeReceivedInvocations: [(sendReadReceipts: Bool, receiptType: ReceiptType)] = []
|
||||
var markAsReadSendReadReceiptsReceiptTypeReturnValue: Result<Void, RoomProxyError>!
|
||||
var markAsReadSendReadReceiptsReceiptTypeClosure: ((Bool, ReceiptType) async -> Result<Void, RoomProxyError>)?
|
||||
var markAsReadReceiptTypeReceivedReceiptType: ReceiptType?
|
||||
var markAsReadReceiptTypeReceivedInvocations: [ReceiptType] = []
|
||||
var markAsReadReceiptTypeReturnValue: Result<Void, RoomProxyError>!
|
||||
var markAsReadReceiptTypeClosure: ((ReceiptType) async -> Result<Void, RoomProxyError>)?
|
||||
|
||||
func markAsRead(sendReadReceipts: Bool, receiptType: ReceiptType) async -> Result<Void, RoomProxyError> {
|
||||
markAsReadSendReadReceiptsReceiptTypeCallsCount += 1
|
||||
markAsReadSendReadReceiptsReceiptTypeReceivedArguments = (sendReadReceipts: sendReadReceipts, receiptType: receiptType)
|
||||
markAsReadSendReadReceiptsReceiptTypeReceivedInvocations.append((sendReadReceipts: sendReadReceipts, receiptType: receiptType))
|
||||
if let markAsReadSendReadReceiptsReceiptTypeClosure = markAsReadSendReadReceiptsReceiptTypeClosure {
|
||||
return await markAsReadSendReadReceiptsReceiptTypeClosure(sendReadReceipts, receiptType)
|
||||
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError> {
|
||||
markAsReadReceiptTypeCallsCount += 1
|
||||
markAsReadReceiptTypeReceivedReceiptType = receiptType
|
||||
markAsReadReceiptTypeReceivedInvocations.append(receiptType)
|
||||
if let markAsReadReceiptTypeClosure = markAsReadReceiptTypeClosure {
|
||||
return await markAsReadReceiptTypeClosure(receiptType)
|
||||
} else {
|
||||
return markAsReadSendReadReceiptsReceiptTypeReturnValue
|
||||
return markAsReadReceiptTypeReturnValue
|
||||
}
|
||||
}
|
||||
//MARK: - sendTypingNotification
|
||||
|
||||
@@ -80,7 +80,10 @@ extension RoomProxyMock {
|
||||
canUserRedactOtherUserIDReturnValue = .success(false)
|
||||
canUserTriggerRoomNotificationUserIDReturnValue = .success(configuration.canUserTriggerRoomNotification)
|
||||
canUserJoinCallUserIDReturnValue = .success(configuration.canUserJoinCall)
|
||||
markAsReadSendReadReceiptsReceiptTypeReturnValue = .success(())
|
||||
|
||||
flagAsReadReturnValue = .success(())
|
||||
flagAsUnreadReturnValue = .success(())
|
||||
markAsReadReceiptTypeReturnValue = .success(())
|
||||
|
||||
let widgetDriver = ElementCallWidgetDriverMock()
|
||||
widgetDriver.underlyingMessagePublisher = .init()
|
||||
|
||||
@@ -167,7 +167,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
switch await roomProxy.markAsUnread() {
|
||||
switch await roomProxy.flagAsUnread() {
|
||||
case .success:
|
||||
ServiceLocator.shared.analytics.trackInteraction(name: .MobileRoomListRoomContextMenuUnreadToggle)
|
||||
case .failure(let error):
|
||||
@@ -181,11 +181,15 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
return
|
||||
}
|
||||
|
||||
switch await roomProxy.markAsRead(sendReadReceipts: true, receiptType: appSettings.sharePresence ? .read : .readPrivate) {
|
||||
switch await roomProxy.flagAsRead() {
|
||||
case .success:
|
||||
ServiceLocator.shared.analytics.trackInteraction(name: .MobileRoomListRoomContextMenuUnreadToggle)
|
||||
|
||||
if case .failure(let error) = await roomProxy.markAsRead(receiptType: appSettings.sharePresence ? .read : .readPrivate) {
|
||||
MXLog.error("Failed marking room \(roomIdentifier) as read with error: \(error)")
|
||||
}
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed marking room \(roomIdentifier) as read with error: \(error)")
|
||||
MXLog.error("Failed flagging room \(roomIdentifier) as read with error: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,12 +418,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
|
||||
notificationCenter.post(name: .roomMarkedAsRead, object: roomProxy.id)
|
||||
}
|
||||
|
||||
switch await timelineController.sendReadReceipt(for: lastVisibleItemID) {
|
||||
case .success:
|
||||
break
|
||||
case let .failure(error):
|
||||
MXLog.error("[TimelineViewController] Failed to send read receipt: \(error)")
|
||||
}
|
||||
await timelineController.sendReadReceipt(for: lastVisibleItemID)
|
||||
}
|
||||
|
||||
private func handleItemTapped(with itemID: TimelineItemIdentifier) async {
|
||||
|
||||
@@ -64,7 +64,7 @@ class TimelineTableViewController: UIViewController {
|
||||
paginateBackwardsPublisher.send()
|
||||
}
|
||||
|
||||
sendReadReceiptIfNeeded()
|
||||
sendLastVisibleItemReadReceipt()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,6 +144,12 @@ class TimelineTableViewController: UIViewController {
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
NotificationCenter.default.publisher(for: UIApplication.didBecomeActiveNotification)
|
||||
.sink { [weak self] _ in
|
||||
self?.sendLastVisibleItemReadReceipt()
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
configureDataSource()
|
||||
}
|
||||
|
||||
@@ -153,6 +159,8 @@ class TimelineTableViewController: UIViewController {
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
sendLastVisibleItemReadReceipt()
|
||||
|
||||
guard !hasAppearedOnce else { return }
|
||||
tableView.contentOffset.y = -1
|
||||
hasAppearedOnce = true
|
||||
@@ -287,13 +295,20 @@ class TimelineTableViewController: UIViewController {
|
||||
coordinator.send(viewAction: .paginateBackwards)
|
||||
}
|
||||
|
||||
private func sendReadReceiptIfNeeded() {
|
||||
guard let lastVisibleItemIndexPath = tableView.indexPathsForVisibleRows?.first,
|
||||
let lastVisibleItemTimelineID = dataSource?.itemIdentifier(for: lastVisibleItemIndexPath),
|
||||
let lastVisibleItemID = timelineItemsDictionary[lastVisibleItemTimelineID]?.identifier
|
||||
else { return }
|
||||
private func sendLastVisibleItemReadReceipt() {
|
||||
// Find the last visible timeline item and send a read receipt for it
|
||||
guard let visibleIndexPaths = tableView.indexPathsForVisibleRows else {
|
||||
return
|
||||
}
|
||||
|
||||
coordinator.send(viewAction: .sendReadReceiptIfNeeded(lastVisibleItemID))
|
||||
// These are already in reverse order because the table view is flipped
|
||||
for indexPath in visibleIndexPaths {
|
||||
if let visibleItemTimelineID = dataSource?.itemIdentifier(for: indexPath),
|
||||
let visibleItemID = timelineItemsDictionary[visibleItemTimelineID]?.identifier {
|
||||
coordinator.send(viewAction: .sendReadReceiptIfNeeded(visibleItemID))
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,15 +342,15 @@ extension TimelineTableViewController: UITableViewDelegate {
|
||||
}
|
||||
|
||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
||||
sendReadReceiptIfNeeded()
|
||||
sendLastVisibleItemReadReceipt()
|
||||
}
|
||||
|
||||
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
sendReadReceiptIfNeeded()
|
||||
sendLastVisibleItemReadReceipt()
|
||||
}
|
||||
|
||||
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
||||
sendReadReceiptIfNeeded()
|
||||
sendLastVisibleItemReadReceipt()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -368,28 +368,33 @@ class RoomProxy: RoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func markAsUnread() async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Marking room \(id) as unread")
|
||||
func flagAsUnread() async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Flagging room \(id) as unread")
|
||||
|
||||
do {
|
||||
try await room.markAsUnread()
|
||||
try await room.setUnreadFlag(newValue: true)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed marking room \(id) as unread with error: \(error)")
|
||||
return .failure(.failedMarkingAsUnread)
|
||||
return .failure(.failedFlaggingAsUnread)
|
||||
}
|
||||
}
|
||||
|
||||
func markAsRead(sendReadReceipts: Bool, receiptType: ReceiptType) async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Marking room \(id) as read, sending read receipts: \(sendReadReceipts)")
|
||||
func flagAsRead() async -> Result<Void, RoomProxyError> {
|
||||
MXLog.info("Flagging room \(id) as read")
|
||||
|
||||
do {
|
||||
if sendReadReceipts {
|
||||
try await room.markAsReadAndSendReadReceipt(receiptType: receiptType)
|
||||
} else {
|
||||
try await room.markAsRead()
|
||||
}
|
||||
|
||||
try await room.setUnreadFlag(newValue: false)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed marking room \(id) as read with error: \(error)")
|
||||
return .failure(.failedFlaggingAsRead)
|
||||
}
|
||||
}
|
||||
|
||||
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)")
|
||||
|
||||
@@ -31,8 +31,9 @@ enum RoomProxyError: Error, Equatable {
|
||||
case failedRemovingAvatar
|
||||
case failedUploadingAvatar
|
||||
case failedCheckingPermission
|
||||
case failedFlaggingAsUnread
|
||||
case failedFlaggingAsRead
|
||||
case failedMarkingAsRead
|
||||
case failedMarkingAsUnread
|
||||
case failedSendingTypingNotice
|
||||
}
|
||||
|
||||
@@ -108,9 +109,11 @@ protocol RoomProxyProtocol {
|
||||
|
||||
func canUserTriggerRoomNotification(userID: String) async -> Result<Bool, RoomProxyError>
|
||||
|
||||
func markAsUnread() async -> Result<Void, RoomProxyError>
|
||||
func flagAsUnread() async -> Result<Void, RoomProxyError>
|
||||
|
||||
func markAsRead(sendReadReceipts: Bool, receiptType: ReceiptType) async -> Result<Void, RoomProxyError>
|
||||
func flagAsRead() async -> Result<Void, RoomProxyError>
|
||||
|
||||
func markAsRead(receiptType: ReceiptType) async -> Result<Void, RoomProxyError>
|
||||
|
||||
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
|
||||
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>
|
||||
|
||||
@@ -55,14 +55,9 @@ class MockRoomTimelineController: RoomTimelineControllerProtocol {
|
||||
return .success(())
|
||||
}
|
||||
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async -> Result<Void, RoomTimelineControllerError> {
|
||||
guard let roomProxy, let eventID = itemID.eventID else { return .failure(.generic) }
|
||||
switch await roomProxy.timeline.sendReadReceipt(for: eventID, type: .read) {
|
||||
case .success:
|
||||
return .success(())
|
||||
case .failure:
|
||||
return .failure(.generic)
|
||||
}
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async {
|
||||
guard let roomProxy, let eventID = itemID.eventID else { return }
|
||||
_ = await roomProxy.timeline.sendReadReceipt(for: eventID, type: .read)
|
||||
}
|
||||
|
||||
func processItemAppearance(_ itemID: TimelineItemIdentifier) async { }
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MatrixRustSDK
|
||||
import UIKit
|
||||
|
||||
class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
@@ -91,17 +92,18 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async -> Result<Void, RoomTimelineControllerError> {
|
||||
guard let eventID = itemID.eventID else {
|
||||
return .failure(.generic)
|
||||
}
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async {
|
||||
let receiptType: MatrixRustSDK.ReceiptType = appSettings.sharePresence ? .read : .readPrivate
|
||||
|
||||
switch await roomProxy.timeline.sendReadReceipt(for: eventID,
|
||||
type: appSettings.sharePresence ? .read : .readPrivate) {
|
||||
case .success:
|
||||
return .success(())
|
||||
case .failure:
|
||||
return .failure(.generic)
|
||||
// Mark the whole room as read if it's the last timeline item
|
||||
if timelineItems.last?.id == itemID {
|
||||
_ = await roomProxy.markAsRead(receiptType: receiptType)
|
||||
} else {
|
||||
guard let eventID = itemID.eventID else {
|
||||
return
|
||||
}
|
||||
|
||||
_ = await roomProxy.timeline.sendReadReceipt(for: eventID, type: receiptType)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ protocol RoomTimelineControllerProtocol {
|
||||
|
||||
func paginateBackwards(requestSize: UInt, untilNumberOfItems: UInt) async -> Result<Void, RoomTimelineControllerError>
|
||||
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async -> Result<Void, RoomTimelineControllerError>
|
||||
func sendReadReceipt(for itemID: TimelineItemIdentifier) async
|
||||
|
||||
func sendMessage(_ message: String,
|
||||
html: String?,
|
||||
|
||||
@@ -454,7 +454,7 @@ final class TimelineProxy: TimelineProxyProtocol {
|
||||
}
|
||||
|
||||
func sendReadReceipt(for eventID: String, type: ReceiptType) async -> Result<Void, TimelineProxyError> {
|
||||
MXLog.info("Sending read receipt for eventID: \(eventID)")
|
||||
MXLog.verbose("Sending read receipt for eventID: \(eventID)")
|
||||
|
||||
sendMessageBackgroundTask = await backgroundTaskService.startBackgroundTask(withName: backgroundTaskName, isReusable: true)
|
||||
defer {
|
||||
|
||||
@@ -47,7 +47,7 @@ packages:
|
||||
# Element/Matrix dependencies
|
||||
MatrixRustSDK:
|
||||
url: https://github.com/matrix-org/matrix-rust-components-swift
|
||||
exactVersion: 1.1.38
|
||||
exactVersion: 1.1.39
|
||||
# path: ../matrix-rust-sdk
|
||||
Compound:
|
||||
url: https://github.com/element-hq/compound-ios
|
||||
|
||||
Reference in New Issue
Block a user