mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
vector-im/element-x-ios/issues/53 - Converted most callback based methods to async/await
This commit is contained in:
committed by
Stefan Ceriu
parent
f2fe39eca7
commit
dde7786152
@@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
class MemberDetailProvider: MemberDetailProviderProtocol {
|
||||
private let roomProxy: RoomProxyProtocol?
|
||||
private let roomProxy: RoomProxyProtocol
|
||||
private var memberAvatars = [String: String]()
|
||||
private var memberDisplayNames = [String: String]()
|
||||
|
||||
@@ -18,58 +18,38 @@ class MemberDetailProvider: MemberDetailProviderProtocol {
|
||||
}
|
||||
|
||||
func avatarURLForUserId(_ userId: String) -> String? {
|
||||
self.memberAvatars[userId]
|
||||
memberAvatars[userId]
|
||||
}
|
||||
|
||||
func avatarURLForUserId(_ userId: String, completion: @escaping (Result<String?, MemberDetailProviderError>) -> Void) {
|
||||
guard let roomProxy = roomProxy else {
|
||||
return
|
||||
}
|
||||
|
||||
func loadAvatarURLForUserId(_ userId: String) async -> Result<String?, MemberDetailProviderError> {
|
||||
if let avatarURL = avatarURLForUserId(userId) {
|
||||
completion(.success(avatarURL))
|
||||
return .success(avatarURL)
|
||||
}
|
||||
|
||||
roomProxy.avatarURLForUserId(userId, completion: { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let avatarURL):
|
||||
self.memberAvatars[userId] = avatarURL
|
||||
completion(.success(avatarURL))
|
||||
case .failure:
|
||||
completion(.failure(.failedRetrievingUserAvatarURL))
|
||||
}
|
||||
})
|
||||
switch await roomProxy.loadAvatarURLForUserId(userId) {
|
||||
case .success(let avatarURL):
|
||||
memberAvatars[userId] = avatarURL
|
||||
return .success(avatarURL)
|
||||
case .failure:
|
||||
return .failure(.failedRetrievingUserAvatarURL)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func displayNameForUserId(_ userId: String) -> String? {
|
||||
self.memberDisplayNames[userId]
|
||||
memberDisplayNames[userId]
|
||||
}
|
||||
|
||||
func displayNameForUserId(_ userId: String, completion: @escaping (Result<String?, MemberDetailProviderError>) -> Void) {
|
||||
guard let roomProxy = roomProxy else {
|
||||
return
|
||||
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, MemberDetailProviderError> {
|
||||
if let displayName = displayNameForUserId(userId) {
|
||||
return .success(displayName)
|
||||
}
|
||||
|
||||
if let avatarURL = displayNameForUserId(userId) {
|
||||
completion(.success(avatarURL))
|
||||
switch await roomProxy.loadDisplayNameForUserId(userId) {
|
||||
case .success(let displayName):
|
||||
memberDisplayNames[userId] = displayName
|
||||
return .success(displayName)
|
||||
case .failure:
|
||||
return .failure(.failedRetrievingUserDisplayName)
|
||||
}
|
||||
|
||||
roomProxy.displayNameForUserId(userId, completion: { [weak self] result in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch result {
|
||||
case .success(let displayName):
|
||||
self.memberDisplayNames[userId] = displayName
|
||||
completion(.success(displayName))
|
||||
case .failure:
|
||||
completion(.failure(.failedRetrievingUserDisplayName))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@ enum MemberDetailProviderError: Error {
|
||||
|
||||
protocol MemberDetailProviderProtocol {
|
||||
func avatarURLForUserId(_ userId: String) -> String?
|
||||
func avatarURLForUserId(_ userId: String, completion: @escaping (Result<String?, MemberDetailProviderError>) -> Void)
|
||||
func loadAvatarURLForUserId(_ userId: String) async -> Result<String?, MemberDetailProviderError>
|
||||
|
||||
func displayNameForUserId(_ userId: String) -> String?
|
||||
func displayNameForUserId(_ userId: String, completion: @escaping (Result<String?, MemberDetailProviderError>) -> Void)
|
||||
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, MemberDetailProviderError>
|
||||
}
|
||||
|
||||
@@ -27,27 +27,27 @@ struct MockRoomProxy: RoomProxyProtocol {
|
||||
|
||||
var callbacks = PassthroughSubject<RoomProxyCallback, Never>()
|
||||
|
||||
func displayName(_ completion: @escaping (Result<String, RoomProxyError>) -> Void) {
|
||||
completion(.success("Room display name"))
|
||||
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, RoomProxyError> {
|
||||
return .failure(.failedRetrievingMemberDisplayName)
|
||||
}
|
||||
|
||||
func loadAvatarURLForUserId(_ userId: String) async -> Result<String?, RoomProxyError> {
|
||||
return .failure(.failedRetrievingMemberAvatarURL)
|
||||
}
|
||||
|
||||
func loadDisplayName() async -> Result<String, RoomProxyError> {
|
||||
return .failure(.failedRetrievingDisplayName)
|
||||
}
|
||||
|
||||
func startLiveEventListener() {
|
||||
|
||||
}
|
||||
|
||||
func paginateBackwards(count: UInt, callback: ((Result<Void, RoomProxyError>) -> Void)?) {
|
||||
|
||||
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError> {
|
||||
return .failure(.backwardStreamNotAvailable)
|
||||
}
|
||||
|
||||
func avatarURLForUserId(_ userId: String, completion: @escaping (Result<String?, RoomProxyError>) -> Void) {
|
||||
|
||||
}
|
||||
|
||||
func displayNameForUserId(_ userId: String, completion: @escaping (Result<String?, RoomProxyError>) -> Void) {
|
||||
|
||||
}
|
||||
|
||||
func sendMessage(_ message: String, callback: ((Result<Void, RoomProxyError>) -> Void)?) {
|
||||
|
||||
func sendMessage(_ message: String) async -> Result<Void, RoomProxyError> {
|
||||
return .failure(.failedSendingMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,7 @@ private class WeakRoomProxyWrapper: RoomDelegate {
|
||||
// MARK: - RoomDelegate
|
||||
|
||||
func didReceiveMessage(message: AnyMessage) {
|
||||
DispatchQueue.main.async {
|
||||
self.roomProxy?.appendMessage(message)
|
||||
}
|
||||
self.roomProxy?.appendMessage(message)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +29,6 @@ class RoomProxy: RoomProxyProtocol {
|
||||
private let room: Room
|
||||
private let messageFactory: RoomMessageFactory
|
||||
|
||||
private let generalProcessingQueue: DispatchQueue
|
||||
private let messageProcessingQueue: DispatchQueue
|
||||
|
||||
private var backwardStream: BackwardsStreamProtocol?
|
||||
|
||||
private(set) var displayName: String?
|
||||
@@ -45,18 +40,13 @@ class RoomProxy: RoomProxyProtocol {
|
||||
init(room: Room, messageFactory: RoomMessageFactory) {
|
||||
self.room = room
|
||||
self.messageFactory = messageFactory
|
||||
generalProcessingQueue = DispatchQueue(label: "RoomProxyGeneralProcessingQueue")
|
||||
messageProcessingQueue = DispatchQueue(label: "RoomProxyMessageProcessingQueue")
|
||||
messages = []
|
||||
|
||||
messageProcessingQueue.async {
|
||||
let backwardStream = room.startLiveEventListener()
|
||||
DispatchQueue.main.async {
|
||||
self.backwardStream = backwardStream
|
||||
}
|
||||
}
|
||||
|
||||
room.setDelegate(delegate: WeakRoomProxyWrapper(roomProxy: self))
|
||||
|
||||
Task {
|
||||
backwardStream = room.startLiveEventListener()
|
||||
}
|
||||
}
|
||||
|
||||
var id: String {
|
||||
@@ -95,66 +85,50 @@ class RoomProxy: RoomProxyProtocol {
|
||||
room.avatarUrl()
|
||||
}
|
||||
|
||||
func avatarURLForUserId(_ userId: String, completion: @escaping (Result<String?, RoomProxyError>) -> Void) {
|
||||
generalProcessingQueue.async {
|
||||
func loadAvatarURLForUserId(_ userId: String) async -> Result<String?, RoomProxyError> {
|
||||
await withCheckedContinuation({ continuation in
|
||||
do {
|
||||
let avatarURL = try self.room.memberAvatarUrl(userId: userId)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(avatarURL))
|
||||
}
|
||||
continuation.resume(returning: .success(avatarURL))
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(RoomProxyError.failedRetrievingMemberAvatarURL))
|
||||
}
|
||||
continuation.resume(returning: .failure(.failedRetrievingMemberAvatarURL))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func displayNameForUserId(_ userId: String, completion: @escaping (Result<String?, RoomProxyError>) -> Void) {
|
||||
generalProcessingQueue.async {
|
||||
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, RoomProxyError> {
|
||||
await withCheckedContinuation({ continuation in
|
||||
do {
|
||||
let displayName = try self.room.memberDisplayName(userId: userId)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(displayName))
|
||||
}
|
||||
continuation.resume(returning: .success(displayName))
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(RoomProxyError.failedRetrievingMemberDisplayName))
|
||||
}
|
||||
continuation.resume(returning: .failure(.failedRetrievingMemberDisplayName))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func displayName(_ completion: @escaping (Result<String, RoomProxyError>) -> Void) {
|
||||
if let displayName = displayName {
|
||||
completion(.success(displayName))
|
||||
return
|
||||
}
|
||||
|
||||
generalProcessingQueue.async {
|
||||
func loadDisplayName() async -> Result<String, RoomProxyError> {
|
||||
await withCheckedContinuation({ continuation in
|
||||
if let displayName = displayName {
|
||||
continuation.resume(returning: .success(displayName))
|
||||
return
|
||||
}
|
||||
|
||||
do {
|
||||
let displayName = try self.room.displayName()
|
||||
self.displayName = displayName
|
||||
|
||||
DispatchQueue.main.async {
|
||||
completion(.success(displayName))
|
||||
}
|
||||
|
||||
continuation.resume(returning: .success(displayName))
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
completion(.failure(.failedRetrievingDisplayName))
|
||||
}
|
||||
continuation.resume(returning: .failure(.failedRetrievingDisplayName))
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func paginateBackwards(count: UInt, callback: ((Result<Void, RoomProxyError>) -> Void)?) {
|
||||
messageProcessingQueue.async {
|
||||
|
||||
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError> {
|
||||
await withCheckedContinuation { continuation in
|
||||
guard let backwardStream = self.backwardStream else {
|
||||
DispatchQueue.main.async {
|
||||
callback?(.failure(.backwardStreamNotAvailable))
|
||||
}
|
||||
continuation.resume(returning: .failure(.backwardStreamNotAvailable))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -166,28 +140,22 @@ class RoomProxy: RoomProxyProtocol {
|
||||
self.messageFactory.buildRoomMessageFrom(message)
|
||||
}.reversed()
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.messages.insert(contentsOf: messages, at: 0)
|
||||
callback?(.success(()))
|
||||
}
|
||||
self.messages.insert(contentsOf: messages, at: 0)
|
||||
|
||||
continuation.resume(returning: .success(()))
|
||||
}
|
||||
}
|
||||
|
||||
func sendMessage(_ message: String, callback: ((Result<Void, RoomProxyError>) -> Void)?) {
|
||||
func sendMessage(_ message: String) async -> Result<Void, RoomProxyError> {
|
||||
let messageContent = messageEventContentFromMarkdown(md: message)
|
||||
let transactionId = genTransactionId()
|
||||
|
||||
messageProcessingQueue.async {
|
||||
return await withCheckedContinuation { continuation in
|
||||
do {
|
||||
try self.room.send(msg: messageContent, txnId: transactionId)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
callback?(.success(()))
|
||||
}
|
||||
continuation.resume(returning: .success(()))
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
callback?(.failure(.failedSendingMessage))
|
||||
}
|
||||
continuation.resume(returning: .failure(.failedSendingMessage))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,15 +37,15 @@ protocol RoomProxyProtocol {
|
||||
|
||||
var avatarURL: String? { get }
|
||||
|
||||
func displayName(_ completion: @escaping (Result<String, RoomProxyError>) -> Void)
|
||||
func loadAvatarURLForUserId(_ userId: String) async -> Result<String?, RoomProxyError>
|
||||
|
||||
func avatarURLForUserId(_ userId: String, completion: @escaping (Result<String?, RoomProxyError>) -> Void)
|
||||
func loadDisplayNameForUserId(_ userId: String) async -> Result<String?, RoomProxyError>
|
||||
|
||||
func displayNameForUserId(_ userId: String, completion: @escaping (Result<String?, RoomProxyError>) -> Void)
|
||||
func loadDisplayName() async -> Result<String, RoomProxyError>
|
||||
|
||||
func paginateBackwards(count: UInt, callback: ((Result<Void, RoomProxyError>) -> Void)?)
|
||||
func paginateBackwards(count: UInt) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func sendMessage(_ message: String, callback: ((Result<Void, RoomProxyError>) -> Void)?)
|
||||
func sendMessage(_ message: String) async -> Result<Void, RoomProxyError>
|
||||
|
||||
var callbacks: PassthroughSubject<RoomProxyCallback, Never> { get }
|
||||
}
|
||||
|
||||
@@ -16,21 +16,20 @@ struct EventBriefFactory: EventBriefFactoryProtocol {
|
||||
self.memberDetailProvider = memberDetailProvider
|
||||
}
|
||||
|
||||
func eventBriefForMessage(_ message: RoomMessageProtocol?, completion: @escaping ((EventBrief?) -> Void)) {
|
||||
func eventBriefForMessage(_ message: RoomMessageProtocol?) async -> EventBrief? {
|
||||
guard let message = message else {
|
||||
completion(nil)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
switch message {
|
||||
case is ImageRoomMessage:
|
||||
completion(nil)
|
||||
return nil
|
||||
case let message as TextRoomMessage:
|
||||
buildEventBrief(message: message, htmlBody: message.htmlBody, completion: completion)
|
||||
return await buildEventBrief(message: message, htmlBody: message.htmlBody)
|
||||
case let message as NoticeRoomMessage:
|
||||
buildEventBrief(message: message, htmlBody: message.htmlBody, completion: completion)
|
||||
return await buildEventBrief(message: message, htmlBody: message.htmlBody)
|
||||
case let message as EmoteRoomMessage:
|
||||
buildEventBrief(message: message, htmlBody: message.htmlBody, completion: completion)
|
||||
return await buildEventBrief(message: message, htmlBody: message.htmlBody)
|
||||
default:
|
||||
fatalError("Unknown room message.")
|
||||
}
|
||||
@@ -38,26 +37,24 @@ struct EventBriefFactory: EventBriefFactoryProtocol {
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func buildEventBrief(message: RoomMessageProtocol, htmlBody: String?, completion: @escaping ((EventBrief?) -> Void)) {
|
||||
memberDetailProvider.displayNameForUserId(message.sender) { result in
|
||||
switch result {
|
||||
case .success(let displayName):
|
||||
completion(EventBrief(eventId: message.id,
|
||||
senderId: message.sender,
|
||||
senderDisplayName: displayName,
|
||||
body: message.body,
|
||||
htmlBody: htmlBody,
|
||||
date: message.originServerTs))
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed fetching sender display name with error: \(error)")
|
||||
|
||||
completion(EventBrief(eventId: message.id,
|
||||
senderId: message.sender,
|
||||
senderDisplayName: nil,
|
||||
body: message.body,
|
||||
htmlBody: htmlBody,
|
||||
date: message.originServerTs))
|
||||
}
|
||||
private func buildEventBrief(message: RoomMessageProtocol, htmlBody: String?) async -> EventBrief? {
|
||||
switch await memberDetailProvider.loadDisplayNameForUserId(message.sender) {
|
||||
case .success(let displayName):
|
||||
return EventBrief(eventId: message.id,
|
||||
senderId: message.sender,
|
||||
senderDisplayName: displayName,
|
||||
body: message.body,
|
||||
htmlBody: htmlBody,
|
||||
date: message.originServerTs)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed fetching sender display name with error: \(error)")
|
||||
|
||||
return EventBrief(eventId: message.id,
|
||||
senderId: message.sender,
|
||||
senderDisplayName: nil,
|
||||
body: message.body,
|
||||
htmlBody: htmlBody,
|
||||
date: message.originServerTs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
import Foundation
|
||||
|
||||
protocol EventBriefFactoryProtocol {
|
||||
func eventBriefForMessage(_ message: RoomMessageProtocol?, completion: @escaping ((EventBrief?) -> Void))
|
||||
func eventBriefForMessage(_ message: RoomMessageProtocol?) async -> EventBrief?
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ struct MockRoomSummary: RoomSummaryProtocol {
|
||||
|
||||
var avatar: UIImage?
|
||||
|
||||
func loadData() {
|
||||
func loadDetails() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -71,81 +71,81 @@ class RoomSummary: RoomSummaryProtocol {
|
||||
self.mediaProvider = mediaProvider
|
||||
self.eventBriefFactory = eventBriefFactory
|
||||
|
||||
eventBriefFactory.eventBriefForMessage(roomProxy.messages.last) { [weak self] result in
|
||||
self?.lastMessage = result
|
||||
Task {
|
||||
lastMessage = await eventBriefFactory.eventBriefForMessage(roomProxy.messages.last)
|
||||
}
|
||||
|
||||
roomProxy.callbacks.sink { [weak self] callback in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch callback {
|
||||
case .updatedMessages:
|
||||
self.eventBriefFactory.eventBriefForMessage(self.roomProxy.messages.last) { [weak self] result in
|
||||
self?.lastMessage = result
|
||||
roomProxy.callbacks
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] callback in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
|
||||
switch callback {
|
||||
case .updatedMessages:
|
||||
Task {
|
||||
self.lastMessage = await eventBriefFactory.eventBriefForMessage(roomProxy.messages.last)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.store(in: &roomUpdateListeners)
|
||||
.store(in: &roomUpdateListeners)
|
||||
}
|
||||
|
||||
func loadData() {
|
||||
func loadDetails() async {
|
||||
if hasLoadedData {
|
||||
return
|
||||
}
|
||||
|
||||
loadDisplayName()
|
||||
loadLastMessage()
|
||||
loadAvatar()
|
||||
await withTaskGroup(of: Void.self) { group in
|
||||
group.addTask {
|
||||
await self.loadDisplayName()
|
||||
}
|
||||
group.addTask {
|
||||
await self.loadAvatar()
|
||||
}
|
||||
group.addTask {
|
||||
await self.loadLastMessage()
|
||||
}
|
||||
}
|
||||
|
||||
hasLoadedData = true
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func loadDisplayName() {
|
||||
roomProxy.displayName { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let displayName):
|
||||
self.displayName = displayName
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed fetching room display name with error: \(error)")
|
||||
}
|
||||
private func loadDisplayName() async {
|
||||
switch await roomProxy.loadDisplayName() {
|
||||
case .success(let displayName):
|
||||
self.displayName = displayName
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed fetching room display name with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func loadLastMessage() {
|
||||
if roomProxy.messages.last == nil {
|
||||
roomProxy.paginateBackwards(count: 1) { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch result {
|
||||
case .success:
|
||||
self.eventBriefFactory.eventBriefForMessage(self.roomProxy.messages.last) { [weak self] result in
|
||||
self?.lastMessage = result
|
||||
}
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed back paginating with error: \(error)")
|
||||
}
|
||||
}
|
||||
private func loadAvatar() async {
|
||||
guard let avatarURL = roomProxy.avatarURL else {
|
||||
return
|
||||
}
|
||||
|
||||
switch await mediaProvider.loadImageFromURL(avatarURL) {
|
||||
case .success(let avatar):
|
||||
self.avatar = avatar
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed fetching room avatar with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func loadAvatar() {
|
||||
if let avatarURL = roomProxy.avatarURL {
|
||||
mediaProvider.loadImageFromURL(avatarURL) { [weak self] result in
|
||||
guard let self = self else { return }
|
||||
|
||||
switch result {
|
||||
case .success(let image):
|
||||
self.avatar = image
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed fetching room avatar with error: \(error)")
|
||||
}
|
||||
}
|
||||
private func loadLastMessage() async {
|
||||
guard roomProxy.messages.last == nil else {
|
||||
return
|
||||
}
|
||||
|
||||
switch await roomProxy.paginateBackwards(count: 1) {
|
||||
case .success:
|
||||
self.lastMessage = await self.eventBriefFactory.eventBriefForMessage(self.roomProxy.messages.last)
|
||||
case .failure(let error):
|
||||
MXLog.error("Failed back paginating with error: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,5 +28,5 @@ protocol RoomSummaryProtocol {
|
||||
|
||||
var callbacks: PassthroughSubject<RoomSummaryCallback, Never> { get }
|
||||
|
||||
func loadData()
|
||||
func loadDetails() async
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user