Fixes #2347, #2348, #2349 - Add support for typing notifications

This commit is contained in:
Stefan Ceriu
2024-02-13 15:27:52 +02:00
committed by GitHub
parent 2b2accaca6
commit f2e9c32e8d
26 changed files with 346 additions and 47 deletions
+56 -1
View File
@@ -31,15 +31,24 @@ class RoomProxy: RoomProxyProtocol {
private var sendMessageBackgroundTask: BackgroundTaskProtocol?
private(set) var displayName: String?
// periphery:ignore - required for instance retention in the rust codebase
private var roomInfoObservationToken: TaskHandle?
// periphery:ignore - required for instance retention in the rust codebase
private var typingNotificationObservationToken: TaskHandle?
private var subscribedForUpdates = false
private(set) var displayName: String?
private let membersSubject = CurrentValueSubject<[RoomMemberProxyProtocol], Never>([])
var members: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> {
membersSubject.asCurrentValuePublisher()
}
private let typingMembersSubject = CurrentValueSubject<[String], Never>([])
var typingMembers: CurrentValuePublisher<[String], Never> {
typingMembersSubject.asCurrentValuePublisher()
}
private let actionsSubject = PassthroughSubject<RoomProxyAction, Never>()
var actions: AnyPublisher<RoomProxyAction, Never> {
@@ -86,6 +95,8 @@ class RoomProxy: RoomProxyProtocol {
await timeline.subscribeForUpdates()
subscribeToRoomStateUpdates()
subscribeToTypingNotifications()
}
func unsubscribeFromUpdates() {
@@ -386,6 +397,18 @@ class RoomProxy: RoomProxyProtocol {
}
}
func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError> {
MXLog.info("Sending typing notification isTyping: \(isTyping)")
do {
try await room.typingNotice(isTyping: isTyping)
return .success(())
} catch {
MXLog.error("Failed sending typing notice with error: \(error)")
return .failure(.failedSendingTypingNotice)
}
}
// MARK: - Element Call
func canUserJoinCall(userID: String) async -> Result<Bool, RoomProxyError> {
@@ -409,6 +432,26 @@ class RoomProxy: RoomProxyProtocol {
self?.actionsSubject.send(.stateUpdate)
})
}
private func subscribeToTypingNotifications() {
Task {
typingNotificationObservationToken = await room.subscribeToTypingNotifications(listener: RoomTypingNotificationUpdateListener { [weak self] typingUserIDs in
guard let self else { return }
MXLog.info("Received typing notification update, typingUsers: \(typingUserIDs)")
let typingMembers = typingUserIDs.compactMap { userID in
if let member = self.members.value.filter({ $0.userID == userID }).first {
return member.displayName ?? member.userID
} else {
return userID
}
}
typingMembersSubject.send(typingMembers)
})
}
}
}
private final class RoomInfoUpdateListener: RoomInfoListener {
@@ -422,3 +465,15 @@ private final class RoomInfoUpdateListener: RoomInfoListener {
onUpdateClosure()
}
}
private final class RoomTypingNotificationUpdateListener: TypingNotificationsListener {
private let onUpdateClosure: ([String]) -> Void
init(_ onUpdateClosure: @escaping ([String]) -> Void) {
self.onUpdateClosure = onUpdateClosure
}
func call(typingUserIds: [String]) {
onUpdateClosure(typingUserIds)
}
}
@@ -33,6 +33,7 @@ enum RoomProxyError: Error, Equatable {
case failedCheckingPermission
case failedMarkingAsRead
case failedMarkingAsUnread
case failedSendingTypingNotice
}
enum RoomProxyAction {
@@ -52,6 +53,7 @@ protocol RoomProxyProtocol {
var ownUserID: String { get }
var name: String? { get }
var displayName: String? { get }
var topic: String? { get }
@@ -59,6 +61,8 @@ protocol RoomProxyProtocol {
var avatarURL: URL? { get }
var members: CurrentValuePublisher<[RoomMemberProxyProtocol], Never> { get }
var typingMembers: CurrentValuePublisher<[String], Never> { get }
var joinedMembersCount: Int { get }
@@ -108,6 +112,9 @@ protocol RoomProxyProtocol {
func markAsRead(sendReadReceipts: Bool, 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>
// MARK: - Element Call
func canUserJoinCall(userID: String) async -> Result<Bool, RoomProxyError>
@@ -97,7 +97,7 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
}
switch await roomProxy.timeline.sendReadReceipt(for: eventID,
type: appSettings.sendReadReceiptsEnabled ? .read : .readPrivate) {
type: appSettings.sharePresence ? .read : .readPrivate) {
case .success:
return .success(())
case .failure: