mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
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:
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user