Avoid race and duplication conditions between local and remote notifications (#848)

* added timestamp control of the local notification

* improved the code, and implemented the solution, just needs some testing

* sdk bump

* UserPreference init with initialValue instead of defaultValue

* pr suggestions

* changelog

* notifications sliding sync view added
This commit is contained in:
Mauro
2023-05-03 16:28:07 +02:00
committed by GitHub
parent 60c2692a26
commit 95492d7e10
15 changed files with 251 additions and 108 deletions
@@ -45,7 +45,8 @@ private class WeakClientProxyWrapper: ClientDelegate, NotificationDelegate, Slid
// MARK: - NotificationDelegate
func didReceiveNotification(notification: MatrixRustSDK.NotificationItem) {
clientProxy?.didReceiveNotification(notification: NotificationItemProxy(notificationItem: notification))
guard let userID = clientProxy?.userID else { return }
clientProxy?.didReceiveNotification(notification: NotificationItemProxy(notificationItem: notification, receiverID: userID))
}
}
@@ -71,6 +72,8 @@ class ClientProxy: ClientProxyProtocol {
var invitesViewProxy: SlidingSyncViewProxy?
var invitesSummaryProvider: RoomSummaryProviderProtocol?
var notificationsSlidingSyncView: SlidingSyncList?
private var loadCachedAvatarURLTask: Task<Void, Never>?
private let avatarURLSubject = CurrentValueSubject<URL?, Never>(nil)
var avatarURLPublisher: AnyPublisher<URL?, Never> {
@@ -103,9 +106,9 @@ class ClientProxy: ClientProxyProtocol {
let delegate = WeakClientProxyWrapper(clientProxy: self)
client.setDelegate(delegate: delegate)
// Uncomment to test local notifications
// await Task.dispatch(on: clientQueue) {
// client.setNotificationDelegate(notificationDelegate: delegate)
// }
await Task.dispatch(on: clientQueue) {
client.setNotificationDelegate(notificationDelegate: delegate)
}
configureSlidingSync()
@@ -319,6 +322,7 @@ class ClientProxy: ClientProxyProtocol {
buildAndConfigureVisibleRoomsSlidingSyncView()
buildAndConfigureAllRoomsSlidingSyncView()
buildAndConfigureInvitesSlidingSyncView()
buildAndConfigureNotificationSyncView()
guard let visibleRoomsSlidingSyncView else {
MXLog.error("Visible rooms sliding sync view unavailable")
@@ -438,7 +442,28 @@ class ClientProxy: ClientProxyProtocol {
MXLog.error("Failed building the invites sliding sync view with error: \(error)")
}
}
private func buildAndConfigureNotificationSyncView() {
guard notificationsSlidingSyncView == nil else {
fatalError("This shouldn't be called more than once")
}
do {
let notificationsSlidingSyncView = try SlidingSyncListBuilder()
.noTimelineLimit()
.requiredState(requiredState: slidingSyncNotificationsRequiredState)
.filters(filters: slidingSyncNotificationsFilters)
.name(name: "Notifications")
.syncMode(mode: .growing)
.batchSize(batchSize: 100)
.build()
self.notificationsSlidingSyncView = notificationsSlidingSyncView
} catch {
MXLog.error("Failed building the notification sliding sync view with error: \(error)")
}
}
private func buildRoomSummaryProviders() {
guard visibleRoomsSummaryProvider == nil, allRoomsSummaryProvider == nil, invitesSummaryProvider == nil else {
fatalError("This shouldn't be called more than once")
@@ -459,17 +484,12 @@ class ClientProxy: ClientProxyProtocol {
eventStringBuilder: RoomEventStringBuilder(stateEventStringBuilder: RoomStateEventStringBuilder(userID: userID)))
}
private lazy var slidingSyncRequiredState = [
RequiredState(key: "m.room.avatar", value: ""),
RequiredState(key: "m.room.encryption", value: "")
// These are required for notifications
// The idea is to create another SS
// to listen to them separately
// only here for testing purposes when enabling local notifications
// RequiredState(key: "m.room.member", value: "$ME"),
// RequiredState(key: "m.room.power_levels", value: ""),
// RequiredState(key: "m.room.name", value: "")
]
private lazy var slidingSyncRequiredState = [RequiredState(key: "m.room.avatar", value: ""),
RequiredState(key: "m.room.encryption", value: "")]
private lazy var slidingSyncNotificationsRequiredState = [RequiredState(key: "m.room.member", value: "$ME"),
RequiredState(key: "m.room.power_levels", value: ""),
RequiredState(key: "m.room.name", value: "")]
private lazy var slidingSyncInvitesRequiredState = [RequiredState(key: "m.room.avatar", value: ""),
RequiredState(key: "m.room.encryption", value: ""),
@@ -486,6 +506,17 @@ class ClientProxy: ClientProxyProtocol {
roomNameLike: nil,
tags: [],
notTags: [])
private lazy var slidingSyncNotificationsFilters = SlidingSyncRequestListFilters(isDm: nil,
spaces: [],
isEncrypted: nil,
isInvite: nil,
isTombstoned: false,
roomTypes: [],
notRoomTypes: ["m.space"],
roomNameLike: nil,
tags: [],
notTags: [])
private lazy var slidingSyncInviteFilters = SlidingSyncRequestListFilters(isDm: nil,
spaces: [],
@@ -519,6 +550,13 @@ class ClientProxy: ClientProxyProtocol {
} else {
MXLog.error("Invites sliding sync view unavailable")
}
if let notificationsSlidingSyncView {
MXLog.info("Registering notifications view")
_ = slidingSync?.addList(list: notificationsSlidingSyncView)
} else {
MXLog.error("Notifications sliding sync view unavailable")
}
restartSync()
}