Update SDK to 1.0.102-alpha (#1408)

* Update SDK to 1.0.102-alpha

* Log error

* Notification Improvements API part 1 (#1410)

* changes

* WIP

* progress

* updated test

* removed unused

* code improvement

* Process diffs as batches provided by the SDK.

---------

Co-authored-by: Mauro <34335419+Velin92@users.noreply.github.com>
Co-authored-by: Doug <douglase@element.io>
This commit is contained in:
Alfonso Grillo
2023-07-27 11:48:56 +02:00
committed by GitHub
parent 188d41e59d
commit 1529b5b8ca
12 changed files with 117 additions and 160 deletions
@@ -378,17 +378,21 @@ class SDKClientMock: SDKClientProtocol {
}
//MARK: - `notificationClient`
public var notificationClientThrowableError: Error?
public var notificationClientCallsCount = 0
public var notificationClientCalled: Bool {
return notificationClientCallsCount > 0
}
public var notificationClientReturnValue: NotificationClientBuilder!
public var notificationClientClosure: (() -> NotificationClientBuilder)?
public var notificationClientClosure: (() throws -> NotificationClientBuilder)?
public func `notificationClient`() -> NotificationClientBuilder {
public func `notificationClient`() throws -> NotificationClientBuilder {
if let error = notificationClientThrowableError {
throw error
}
notificationClientCallsCount += 1
if let notificationClientClosure = notificationClientClosure {
return notificationClientClosure()
return try notificationClientClosure()
} else {
return notificationClientReturnValue
}
@@ -21,7 +21,11 @@ import UserNotifications
import MatrixRustSDK
protocol NotificationItemProxyProtocol {
var event: TimelineEventProxyProtocol { get }
var event: NotificationEvent? { get }
var eventID: String { get }
var senderID: String { get }
var roomID: String { get }
@@ -46,16 +50,21 @@ protocol NotificationItemProxyProtocol {
extension NotificationItemProxyProtocol {
var isEncrypted: Bool {
switch event.type {
case .messageLike(let content):
switch content {
case .roomEncrypted:
return true
switch event {
case .none, .invite:
return false
case .timeline(let event):
switch try? event.eventType() {
case .messageLike(let content):
switch content {
case .roomEncrypted:
return true
default:
return false
}
default:
return false
}
default:
return false
}
}
@@ -66,17 +75,22 @@ extension NotificationItemProxyProtocol {
struct NotificationItemProxy: NotificationItemProxyProtocol {
let notificationItem: NotificationItem
let eventID: String
let receiverID: String
let roomID: String
var event: TimelineEventProxyProtocol {
TimelineEventProxy(timelineEvent: notificationItem.event)
var event: NotificationEvent? {
notificationItem.event
}
var senderDisplayName: String? {
notificationItem.senderInfo.displayName
}
var senderID: String {
notificationItem.senderInfo.userId
}
var roomDisplayName: String {
notificationItem.roomInfo.displayName
}
@@ -94,7 +108,7 @@ struct NotificationItemProxy: NotificationItemProxyProtocol {
}
var isNoisy: Bool {
notificationItem.isNoisy
notificationItem.isNoisy ?? false
}
var senderAvatarMediaSource: MediaSourceProxy? {
@@ -117,14 +131,16 @@ struct NotificationItemProxy: NotificationItemProxyProtocol {
struct EmptyNotificationItemProxy: NotificationItemProxyProtocol {
let eventID: String
var event: TimelineEventProxyProtocol {
MockTimelineEventProxy(eventID: eventID)
var event: NotificationEvent? {
nil
}
let roomID: String
let receiverID: String
var senderID: String { "" }
var senderDisplayName: String? { nil }
var senderAvatarURL: String? { nil }
@@ -155,7 +171,7 @@ extension NotificationItemProxyProtocol {
let notification = UNMutableNotificationContent()
notification.receiverID = receiverID
notification.roomID = roomID
notification.eventID = event.eventID
notification.eventID = eventID
notification.sound = isNoisy ? UNNotificationSound(named: UNNotificationSoundName(rawValue: "message.caf")) : nil
// So that the UI groups notification that are received for the same room but also for the same user
notification.threadIdentifier = "\(receiverID)\(roomID)"
@@ -167,20 +183,25 @@ extension NotificationItemProxyProtocol {
(!isDM && roomAvatarMediaSource != nil) {
return true
}
switch event.type {
case .state, .none:
switch event {
case .invite, .none:
return false
case let .messageLike(content):
switch content {
case let .roomMessage(messageType):
switch messageType {
case .image, .video, .audio:
return true
case .timeline(let event):
switch try? event.eventType() {
case .state, .none:
return false
case let .messageLike(content):
switch content {
case let .roomMessage(messageType):
switch messageType {
case .image, .video, .audio:
return true
default:
return false
}
default:
return false
}
default:
return false
}
}
}
@@ -201,14 +222,13 @@ extension NotificationItemProxyProtocol {
/// - mediaProvider: Media provider to process also media. May be passed nil to ignore media operations.
/// - Returns: A notification content object if the notification should be displayed. Otherwise nil.
func process(mediaProvider: MediaProviderProtocol?) async throws -> UNMutableNotificationContent {
if self is EmptyNotificationItemProxy {
switch event {
case .none:
return processEmpty()
} else {
switch event.type {
case .none:
return processEmpty()
case let .state(content):
return try await processStateEvent(content: content, mediaProvider: mediaProvider)
case .invite:
return try await processInvited(mediaProvider: mediaProvider)
case .timeline(let event):
switch try? event.eventType() {
case let .messageLike(content):
switch content {
case .roomMessage(messageType: let messageType):
@@ -216,30 +236,14 @@ extension NotificationItemProxyProtocol {
default:
return processEmpty()
}
default:
return processEmpty()
}
}
}
// MARK: - Private
private func processStateEvent(content: StateEventContent, mediaProvider: MediaProviderProtocol?) async throws -> UNMutableNotificationContent {
switch content {
case let .roomMemberContent(userId, membershipState):
switch membershipState {
case .invite:
if userId == receiverID {
return try await processInvited(mediaProvider: mediaProvider)
} else {
return processEmpty()
}
default:
return processEmpty()
}
default:
return processEmpty()
}
}
private func processInvited(mediaProvider: MediaProviderProtocol?) async throws -> UNMutableNotificationContent {
var notification = baseMutableContent
@@ -253,7 +257,7 @@ extension NotificationItemProxyProtocol {
}
notification = try await notification.addSenderIcon(using: mediaProvider,
senderID: event.senderID,
senderID: senderID,
senderName: senderDisplayName ?? roomDisplayName,
icon: icon)
notification.body = body
@@ -299,7 +303,7 @@ extension NotificationItemProxyProtocol {
notification.categoryIdentifier = NotificationConstants.Category.message
notification = try await notification.addSenderIcon(using: mediaProvider,
senderID: event.senderID,
senderID: senderID,
senderName: senderDisplayName ?? roomDisplayName,
icon: icon)
return notification
@@ -666,7 +666,11 @@ class RoomProxy: RoomProxyProtocol {
/// This should become automatic on the RustSDK side at some point
private func fetchMembers() async {
await Task.dispatch(on: .global()) {
self.room.fetchMembers()
do {
_ = try self.room.fetchMembers()
} catch {
MXLog.error("Failed fetching members: \(error)")
}
}
}
@@ -76,6 +76,8 @@ struct RoomEventStringBuilder {
member: sender.id,
memberIsYou: isOutgoing)
.map(AttributedString.init)
case .poll, .pollEnd:
return nil
}
}
@@ -35,7 +35,7 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
private let stateSubject = CurrentValueSubject<RoomSummaryProviderState, Never>(.notLoaded)
private let countSubject = CurrentValueSubject<UInt, Never>(0)
private let diffPublisher = PassthroughSubject<RoomListEntriesUpdate, Never>()
private let diffsPublisher = PassthroughSubject<[RoomListEntriesUpdate], Never>()
var roomListPublisher: CurrentValuePublisher<[RoomSummary], Never> {
roomListSubject.asCurrentValuePublisher()
@@ -59,8 +59,8 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
self.eventStringBuilder = eventStringBuilder
self.name = name
diffPublisher
.collect(.byTime(serialDispatchQueue, 0.025))
diffsPublisher
.receive(on: serialDispatchQueue)
.sink { [weak self] in self?.updateRoomsWithDiffs($0) }
.store(in: &cancellables)
}
@@ -73,10 +73,10 @@ class RoomSummaryProvider: RoomSummaryProviderProtocol {
self.roomList = roomList
do {
let listUpdatesSubscriptionResult = try roomList.entries(listener: RoomListEntriesListenerProxy { [weak self] update in
let listUpdatesSubscriptionResult = try roomList.entries(listener: RoomListEntriesListenerProxy { [weak self] updates in
guard let self else { return }
MXLog.verbose("\(name): Received list update")
diffPublisher.send(update)
diffsPublisher.send(updates)
})
listUpdatesTaskHandle = listUpdatesSubscriptionResult.entriesStream
@@ -324,13 +324,13 @@ extension MatrixRustSDK.RoomListEntry {
}
private class RoomListEntriesListenerProxy: RoomListEntriesListener {
private let onUpdateClosure: (RoomListEntriesUpdate) -> Void
private let onUpdateClosure: ([RoomListEntriesUpdate]) -> Void
init(_ onUpdateClosure: @escaping (RoomListEntriesUpdate) -> Void) {
init(_ onUpdateClosure: @escaping ([RoomListEntriesUpdate]) -> Void) {
self.onUpdateClosure = onUpdateClosure
}
func onUpdate(roomEntriesUpdate: RoomListEntriesUpdate) {
func onUpdate(roomEntriesUpdate: [RoomListEntriesUpdate]) {
onUpdateClosure(roomEntriesUpdate)
}
}
@@ -1,59 +0,0 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import MatrixRustSDK
protocol TimelineEventProxyProtocol {
var type: TimelineEventType? { get }
var eventID: String { get }
var senderID: String { get }
var timestamp: Date { get }
}
final class TimelineEventProxy: TimelineEventProxyProtocol {
private let timelineEvent: TimelineEvent
init(timelineEvent: TimelineEvent) {
self.timelineEvent = timelineEvent
}
var eventID: String {
timelineEvent.eventId()
}
var senderID: String {
timelineEvent.senderId()
}
var type: TimelineEventType? {
try? timelineEvent.eventType()
}
var timestamp: Date {
Date(timeIntervalSince1970: TimeInterval(timelineEvent.timestamp() / 1000))
}
}
struct MockTimelineEventProxy: TimelineEventProxyProtocol {
let eventID: String
let senderID = ""
let type: TimelineEventType? = nil
let timestamp = Date()
}
@@ -90,6 +90,8 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
avatarURLString: avatarUrl,
previousAvatarURLString: prevAvatarUrl,
isOutgoing: isOutgoing)
case .poll, .pollEnd:
return nil
}
}
@@ -498,7 +500,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
return .notLoaded(eventID: details.eventId)
case .pending:
return .loading(eventID: details.eventId)
case let .ready(message, senderID, senderProfile):
case let .ready(timelineItem, senderID, senderProfile):
let sender: TimelineItemSender
switch senderProfile {
case let .ready(displayName, _, avatarUrl):
@@ -512,7 +514,7 @@ struct RoomTimelineItemFactory: RoomTimelineItemFactoryProtocol {
}
let replyContent: EventBasedMessageTimelineItemContentType
switch message.msgtype() {
switch timelineItem.asMessage()?.msgtype() {
case .audio(let content):
replyContent = .audio(buildAudioTimelineItemContent(content))
case .emote(let content):