Cached avatar support (from Rust) (#633)

* loading a cached avatar at first, and then actually doing the request so that the avatar can still be displayed without connection

* improved the code

* fix + changelog

* policy on how to fetch the avatar url added

* code improvements

* addressed al PR comments

* improved the error handling

* improved the async task code

* fixed a typo

* fixed another typo
This commit is contained in:
Mauro
2023-03-08 18:50:06 +01:00
committed by GitHub
parent c67c4e362e
commit fb27efee10
10 changed files with 62 additions and 31 deletions
@@ -58,6 +58,15 @@ class ClientProxy: ClientProxyProtocol {
var allRoomsSlidingSyncView: SlidingSyncList?
var allRoomsSummaryProvider: RoomSummaryProviderProtocol?
private var loadCachedAvatarURLTask: Task<Void, Never>?
private let avatarURLSubject = CurrentValueSubject<URL?, Never>(nil)
var avatarURLPublisher: AnyPublisher<URL?, Never> {
avatarURLSubject
.removeDuplicates()
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
}
private var cancellables = Set<AnyCancellable>()
private var visibleRoomsViewProxyStateObservationToken: AnyCancellable?
@@ -82,6 +91,8 @@ class ClientProxy: ClientProxyProtocol {
client.setDelegate(delegate: WeakClientProxyWrapper(clientProxy: self))
configureSlidingSync()
loadUserAvatarURLFromCache()
}
var userID: String {
@@ -147,6 +158,7 @@ class ClientProxy: ClientProxyProtocol {
func loadUserDisplayName() async -> Result<String, ClientProxyError> {
await Task.dispatch(on: clientQueue) {
do {
self.loadCachedAvatarURLTask?.cancel()
let displayName = try self.client.displayName()
return .success(displayName)
} catch {
@@ -154,24 +166,19 @@ class ClientProxy: ClientProxyProtocol {
}
}
}
func loadUserAvatarURL() async -> Result<URL, ClientProxyError> {
func loadUserAvatarURL() async {
await Task.dispatch(on: clientQueue) {
do {
let urlString = try self.client.avatarUrl()
guard let url = URL(string: urlString) else {
MXLog.error("Invalid avatar URL string: \(String(describing: urlString))")
return .failure(.failedRetrievingAvatarURL)
}
return .success(url)
self.avatarURLSubject.value = urlString.flatMap(URL.init)
} catch {
return .failure(.failedRetrievingAvatarURL)
MXLog.error("Failed fetching the user avatar url: \(error)")
return
}
}
}
func accountDataEvent<Content>(type: String) async -> Result<Content?, ClientProxyError> where Content: Decodable {
await Task.dispatch(on: clientQueue) {
.failure(.failedRetrievingAccountData)
@@ -232,6 +239,21 @@ class ClientProxy: ClientProxyProtocol {
}
// MARK: Private
private func loadUserAvatarURLFromCache() {
loadCachedAvatarURLTask = Task {
let urlString = await Task.dispatch(on: clientQueue) {
do {
return try self.client.cachedAvatarUrl()
} catch {
MXLog.error("Failed to look for the avatar url in the cache: \(error)")
return nil
}
}
guard !Task.isCancelled else { return }
self.avatarURLSubject.value = urlString.flatMap(URL.init)
}
}
private func restartSync() {
MXLog.info("Restarting sync")