Files
letro-ios/ElementX/Sources/Services/Client/ClientProxy.swift
ismailgulek 9e31db011d Some Post-demo Cleanups (#200)
* Remove redundant string

* Use placeholder avatar on home screen

* Add initial home screen ui test

* Fix settings screen PR remarks

* Remove UIKit alert from home screen sign out

* Remove UIKit alert from soft logout clear all data

* Add reference screenshots for home screen UI tests

* Formatting fixes

* Add clearing room method to client proxy

* Clear room proxies on screen dismiss

* Fix retain cycle in room view model

* Do not go into authentication state immediately

* Define sizes for user and room avatars on different screens

* Use defined avatar sizes everywhere

* Disable image disk caching

* Rename rounded corner shape

* Fix text color of placeholder avatars

* Fix PR reviews on formatted body text

* Fix merge conflict

* Remove shouldShowSenderDetails everywhere and just use it from inGroupState

* Remove redundant linter disablings

* Fix PR remarks

* Rename media provider size parameter
2022-09-23 12:21:41 +03:00

260 lines
8.6 KiB
Swift

//
// Copyright 2022 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 Combine
import Foundation
import MatrixRustSDK
import UIKit
private class WeakClientProxyWrapper: ClientDelegate, SlidingSyncObserver {
private weak var clientProxy: ClientProxy?
init(clientProxy: ClientProxy) {
self.clientProxy = clientProxy
}
// MARK: - ClientDelegate
func didReceiveSyncUpdate() { }
func didReceiveAuthError(isSoftLogout: Bool) {
Task {
await clientProxy?.didReceiveAuthError(isSoftLogout: isSoftLogout)
}
}
func didUpdateRestoreToken() {
Task {
await clientProxy?.didUpdateRestoreToken()
}
}
// MARK: - SlidingSyncDelegate
func didReceiveSyncUpdate(summary: UpdateSummary) {
Task {
await self.clientProxy?.didReceiveSlidingSyncUpdate(summary: summary)
}
}
}
class ClientProxy: ClientProxyProtocol {
/// The maximum number of timeline events required during a sync request.
static let syncLimit: UInt16 = 50
private let client: ClientProtocol
private let backgroundTaskService: BackgroundTaskServiceProtocol
private var sessionVerificationControllerProxy: SessionVerificationControllerProxy?
private var slidingSyncObserverToken: StoppableSpawn?
private let slidingSync: SlidingSync
let roomSummaryProvider: RoomSummaryProviderProtocol
deinit {
// These need to be inlined instead of using stopSync()
// as we can't call async methods safely from deinit
client.setDelegate(delegate: nil)
slidingSyncObserverToken?.cancel()
slidingSync.setObserver(observer: nil)
}
let callbacks = PassthroughSubject<ClientProxyCallback, Never>()
init(client: ClientProtocol,
backgroundTaskService: BackgroundTaskServiceProtocol) {
self.client = client
self.backgroundTaskService = backgroundTaskService
do {
let slidingSyncBuilder = try client.slidingSync().homeserver(url: BuildSettings.slidingSyncProxyBaseURL.absoluteString)
let slidingSyncView = try SlidingSyncViewBuilder()
.timelineLimit(limit: 10)
.requiredState(requiredState: [RequiredState(key: "m.room.avatar", value: "")])
.name(name: "HomeScreenView")
.syncMode(mode: .fullSync)
.build()
slidingSync = try slidingSyncBuilder
.addView(view: slidingSyncView)
// .withCommonExtensions()
.build()
roomSummaryProvider = RoomSummaryProvider(slidingSyncController: slidingSync,
slidingSyncView: slidingSyncView,
roomMessageFactory: RoomMessageFactory())
} catch {
fatalError("Failed configuring sliding sync")
}
client.setDelegate(delegate: WeakClientProxyWrapper(clientProxy: self))
}
var userIdentifier: String {
do {
return try client.userId()
} catch {
MXLog.error("Failed retrieving room info with error: \(error)")
return "Unknown user identifier"
}
}
var isSoftLogout: Bool {
client.isSoftLogout()
}
var deviceId: String? {
do {
return try client.deviceId()
} catch {
MXLog.error("Failed retrieving device id with error: \(error)")
return nil
}
}
var homeserver: String {
client.homeserver()
}
var restoreToken: String? {
do {
return try client.restoreToken()
} catch {
MXLog.error("Failed retrieving restore token with error: \(error)")
return nil
}
}
func startSync() {
guard !client.isSoftLogout() else {
return
}
slidingSync.setObserver(observer: WeakClientProxyWrapper(clientProxy: self))
slidingSyncObserverToken = slidingSync.sync()
}
func stopSync() {
client.setDelegate(delegate: nil)
slidingSyncObserverToken?.cancel()
slidingSync.setObserver(observer: nil)
}
func roomForIdentifier(_ identifier: String) -> RoomProxyProtocol? {
do {
guard let slidingSyncRoom = try slidingSync.getRoom(roomId: identifier),
let room = slidingSyncRoom.fullRoom() else {
MXLog.error("Failed retrieving room with identifier: \(identifier)")
return nil
}
let roomProxy = RoomProxy(slidingSyncRoom: slidingSyncRoom,
room: room,
backgroundTaskService: backgroundTaskService)
return roomProxy
} catch {
MXLog.error("Failed retrieving room with identifier: \(identifier)")
return nil
}
}
func loadUserDisplayName() async -> Result<String, ClientProxyError> {
await Task.dispatch(on: .global()) {
do {
let displayName = try self.client.displayName()
return .success(displayName)
} catch {
return .failure(.failedRetrievingDisplayName)
}
}
}
func loadUserAvatarURLString() async -> Result<String, ClientProxyError> {
await Task.dispatch(on: .global()) {
do {
let avatarURL = try self.client.avatarUrl()
return .success(avatarURL)
} catch {
return .failure(.failedRetrievingAvatarURL)
}
}
}
func accountDataEvent<Content>(type: String) async -> Result<Content?, ClientProxyError> where Content: Decodable {
.failure(.failedRetrievingAccountData)
}
func setAccountData<Content: Encodable>(content: Content, type: String) async -> Result<Void, ClientProxyError> {
.failure(.failedSettingAccountData)
}
func mediaSourceForURLString(_ urlString: String) -> MatrixRustSDK.MediaSource {
MatrixRustSDK.mediaSourceFromUrl(url: urlString)
}
func loadMediaContentForSource(_ source: MatrixRustSDK.MediaSource) async throws -> Data {
try await Task.dispatch(on: .global()) {
let bytes = try self.client.getMediaContent(source: source)
return Data(bytes: bytes, count: bytes.count)
}
}
func loadMediaThumbnailForSource(_ source: MatrixRustSDK.MediaSource, width: UInt, height: UInt) async throws -> Data {
try await Task.dispatch(on: .global()) {
let bytes = try self.client.getMediaThumbnail(source: source, width: UInt64(width), height: UInt64(height))
return Data(bytes: bytes, count: bytes.count)
}
}
func sessionVerificationControllerProxy() async -> Result<SessionVerificationControllerProxyProtocol, ClientProxyError> {
await Task.dispatch(on: .global()) {
do {
let sessionVerificationController = try self.client.getSessionVerificationController()
return .success(SessionVerificationControllerProxy(sessionVerificationController: sessionVerificationController))
} catch {
return .failure(.failedRetrievingSessionVerificationController)
}
}
}
func logout() async {
do {
try client.logout()
} catch {
MXLog.error("Failed logging out with error: \(error)")
}
}
// MARK: Private
fileprivate func didReceiveAuthError(isSoftLogout: Bool) {
callbacks.send(.receivedAuthError(isSoftLogout: isSoftLogout))
}
fileprivate func didUpdateRestoreToken() {
callbacks.send(.updatedRestoreToken)
}
fileprivate func didReceiveSlidingSyncUpdate(summary: UpdateSummary) {
roomSummaryProvider.updateRoomsWithIdentifiers(summary.rooms)
// callbacks.send(.receivedSyncUpdate)
}
}