Load room details on appearance. Avoid overwhelming the rust runtime and slow down the room timeline loading.

This commit is contained in:
Stefan Ceriu
2022-03-16 14:52:25 +02:00
parent 59e42ec938
commit 43f78d0a26
7 changed files with 65 additions and 29 deletions
@@ -64,7 +64,7 @@ struct HomeScreenRoom: Identifiable {
var displayName: String? var displayName: String?
let topic: String? let topic: String?
let lastMessage: String? var lastMessage: String?
var avatar: UIImage? var avatar: UIImage?
@@ -28,7 +28,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
private var roomUpdateListeners = Set<AnyCancellable>() private var roomUpdateListeners = Set<AnyCancellable>()
private var roomList: [RoomProxyProtocol]? { private var roomList: [RoomProxyProtocol]? {
didSet { didSet {
self.state.isLoadingRooms = (roomList == nil) self.state.isLoadingRooms = (roomList?.count ?? 0 == 0)
} }
} }
@@ -50,8 +50,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
case .logout: case .logout:
self.completion?(.logout) self.completion?(.logout)
case .loadRoomData(let roomIdentifier): case .loadRoomData(let roomIdentifier):
self.loadAvatarForRoomWithIdentifier(roomIdentifier) self.loadRoomDataForIdentifier(roomIdentifier)
self.loadRoomDisplayNameForRoomWithIdentifier(roomIdentifier)
case .loadUserAvatar: case .loadUserAvatar:
self.completion?(.loadUserAvatar) self.completion?(.loadUserAvatar)
case .selectRoom(let roomIdentifier): case .selectRoom(let roomIdentifier):
@@ -60,27 +59,25 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
} }
func updateWithRoomList(_ roomList: [RoomProxyProtocol]) { func updateWithRoomList(_ roomList: [RoomProxyProtocol]) {
self.roomList = roomList
state.rooms = roomList.map { roomProxy in
roomFromProxy(roomProxy)
}
roomUpdateListeners.removeAll() roomUpdateListeners.removeAll()
self.roomList = roomList
roomList.forEach({ roomProxy in roomList.forEach({ roomProxy in
roomProxy.paginateBackwards(count: 1, callback: nil)
roomProxy.callbacks.sink { [weak self] callback in roomProxy.callbacks.sink { [weak self] callback in
switch callback { switch callback {
case .updatedLastMessage: case .updatedLastMessage:
self?.updateRoomForProxy(roomProxy) self?.loadLastMessageForRoomWithIdentifier(roomProxy.id)
default: default:
break break
} }
} }
.store(in: &roomUpdateListeners) .store(in: &roomUpdateListeners)
}) })
state.rooms = roomList.map { roomProxy in
roomFromProxy(roomProxy)
}
} }
func updateWithUserAvatar(_ avatar: UIImage?) { func updateWithUserAvatar(_ avatar: UIImage?) {
@@ -89,6 +86,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// MARK: - Private // MARK: - Private
private func loadRoomDataForIdentifier(_ roomIdentifier: String) {
loadAvatarForRoomWithIdentifier(roomIdentifier)
loadRoomDisplayNameForRoomWithIdentifier(roomIdentifier)
loadLastMessageForRoomWithIdentifier(roomIdentifier)
}
private func loadAvatarForRoomWithIdentifier(_ roomIdentifier: String) { private func loadAvatarForRoomWithIdentifier(_ roomIdentifier: String) {
guard let room = roomList?.filter({ $0.id == roomIdentifier }).first, guard let room = roomList?.filter({ $0.id == roomIdentifier }).first,
let cacheKey = room.avatarURL?.path else { let cacheKey = room.avatarURL?.path else {
@@ -126,6 +129,14 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
} }
} }
private func updateAvatar(_ avatar: UIImage?, forRoomWithIdentifier roomIdentifier: String) {
guard let index = self.state.rooms.firstIndex(where: { $0.id == roomIdentifier }) else {
return
}
self.state.rooms[index].avatar = avatar
}
private func loadRoomDisplayNameForRoomWithIdentifier(_ roomIdentifier: String) { private func loadRoomDisplayNameForRoomWithIdentifier(_ roomIdentifier: String) {
guard let room = roomList?.filter({ $0.id == roomIdentifier }).first else { guard let room = roomList?.filter({ $0.id == roomIdentifier }).first else {
return return
@@ -151,24 +162,37 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
self.state.rooms[index].displayName = displayName self.state.rooms[index].displayName = displayName
} }
private func updateAvatar(_ avatar: UIImage?, forRoomWithIdentifier roomIdentifier: String) { private func loadLastMessageForRoomWithIdentifier(_ roomIdentifier: String) {
guard let room = roomList?.filter({ $0.id == roomIdentifier }).first else {
return
}
if let lastMessage = room.lastMessage {
self.updateLastMessage(lastMessage, forRoomWithIdentifier: roomIdentifier)
} else {
room.paginateBackwards(count: 1) { result in
switch result {
case .success(let messages):
guard let lastMessage = messages.last else {
return
}
self.updateLastMessage(lastMessage.content(), forRoomWithIdentifier: roomIdentifier)
default:
break
}
}
}
}
private func updateLastMessage(_ lastMessage: String, forRoomWithIdentifier roomIdentifier: String) {
guard let index = self.state.rooms.firstIndex(where: { $0.id == roomIdentifier }) else { guard let index = self.state.rooms.firstIndex(where: { $0.id == roomIdentifier }) else {
return return
} }
self.state.rooms[index].avatar = avatar self.state.rooms[index].lastMessage = lastMessage
} }
private func updateRoomForProxy(_ roomProxy: RoomProxyProtocol) {
state.rooms.updateEach { room in
if room.id != roomProxy.id {
return
}
room = roomFromProxy(roomProxy)
}
}
private func roomFromProxy(_ roomProxy: RoomProxyProtocol) -> HomeScreenRoom { private func roomFromProxy(_ roomProxy: RoomProxyProtocol) -> HomeScreenRoom {
HomeScreenRoom(id: roomProxy.id, HomeScreenRoom(id: roomProxy.id,
displayName: roomProxy.name, displayName: roomProxy.name,
@@ -114,7 +114,6 @@ struct RoomCell: View {
.frame(width: 40, height: 40) .frame(width: 40, height: 40)
.mask(Circle()) .mask(Circle())
} else { } else {
let _ = context.send(viewAction: .loadRoomData(roomIdentifier: room.id))
Image(systemName: "person.3") Image(systemName: "person.3")
.frame(width: 40, height: 40) .frame(width: 40, height: 40)
} }
@@ -140,6 +139,9 @@ struct RoomCell: View {
} }
} }
.frame(minHeight: 60.0) .frame(minHeight: 60.0)
.onAppear {
context.send(viewAction: .loadRoomData(roomIdentifier: room.id))
}
} }
} }
@@ -34,8 +34,8 @@ class LoginScreenViewModel: LoginScreenViewModelType, LoginScreenViewModelProtoc
// MARK: - Setup // MARK: - Setup
init() { init() {
super.init(initialViewState: LoginScreenViewState(bindings: LoginScreenViewStateBindings(username: "", super.init(initialViewState: LoginScreenViewState(bindings: LoginScreenViewStateBindings(username: "@stefan.ceriu-element01:matrix.org",
password: ""))) password: "radeon")))
} }
// MARK: - Public // MARK: - Public
@@ -134,6 +134,8 @@ class AuthenticationCoordinator: Coordinator {
completion(.success(())) completion(.success(()))
} }
} catch { } catch {
MXLog.error("Failed logging in with error: \(error)")
DispatchQueue.main.async { DispatchQueue.main.async {
completion(.failure(.failedLoggingIn)) completion(.failure(.failedLoggingIn))
} }
@@ -156,6 +158,8 @@ class AuthenticationCoordinator: Coordinator {
completion(.success(())) completion(.success(()))
} }
} catch { } catch {
MXLog.error("Failed restoring login with error: \(error)")
DispatchQueue.main.async { DispatchQueue.main.async {
completion(.failure(.failedRestoringLogin)) completion(.failure(.failedRestoringLogin))
} }
@@ -101,6 +101,8 @@ class UserSession: ClientDelegate {
self.rooms = rooms self.rooms = rooms
} }
} }
client.setDelegate(delegate: nil)
} }
// MARK: Private // MARK: Private
+5 -1
View File
@@ -82,6 +82,10 @@ class RoomProxy: RoomProxyProtocol, Equatable {
var lastMessage: String? { var lastMessage: String? {
didSet { didSet {
if lastMessage == oldValue {
return
}
callbacks.send(.updatedLastMessage) callbacks.send(.updatedLastMessage)
} }
} }
@@ -141,7 +145,7 @@ class RoomProxy: RoomProxyProtocol, Equatable {
callback?(.success(messages)) callback?(.success(messages))
if self.lastMessage == nil { if self.lastMessage == nil {
self.lastMessage = messages.last?.content() self.lastMessage = messages.last?.content() ?? ""
} }
} }
} }