Caching the room proxies and their messages. Improved performance throughout.

This commit is contained in:
Stefan Ceriu
2022-03-31 15:37:52 +03:00
parent b50bf724a3
commit 49f7678ce8
22 changed files with 191 additions and 189 deletions
@@ -91,8 +91,6 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
// MARK: - Private
func updateRoomsList() {
parameters.userSession.getRoomList { [weak self] rooms in
self?.viewModel.updateWithRoomList(rooms)
}
self.viewModel.updateWithRoomList(parameters.userSession.rooms)
}
}
@@ -67,7 +67,7 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
self.roomList = roomList
state.rooms = roomList.map { roomProxy in
roomFromProxy(roomProxy)
buildRoomFromProxy(roomProxy)
}
roomUpdateListeners.removeAll()
@@ -75,10 +75,8 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
roomList.forEach({ roomProxy in
roomProxy.callbacks.sink { [weak self] callback in
switch callback {
case .updatedLastMessage:
case .updatedMessages:
self?.loadLastMessageForRoomWithIdentifier(roomProxy.id)
default:
break
}
}
.store(in: &roomUpdateListeners)
@@ -92,9 +90,19 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
// MARK: - Private
private func loadRoomDataForIdentifier(_ roomIdentifier: String) {
loadAvatarForRoomWithIdentifier(roomIdentifier)
loadRoomDisplayNameForRoomWithIdentifier(roomIdentifier)
loadLastMessageForRoomWithIdentifier(roomIdentifier)
let room = state.rooms.first(where: { $0.id == roomIdentifier })
if room?.avatar == nil {
loadAvatarForRoomWithIdentifier(roomIdentifier)
}
if room?.displayName == nil {
loadRoomDisplayNameForRoomWithIdentifier(roomIdentifier)
}
if room?.lastMessage == nil {
loadLastMessageForRoomWithIdentifier(roomIdentifier)
}
}
private func loadAvatarForRoomWithIdentifier(_ roomIdentifier: String) {
@@ -149,22 +157,12 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
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.body, forRoomWithIdentifier: roomIdentifier)
default:
break
}
}
if let lastMessage = room.messages.last {
self.updateLastMessage(lastMessage.body, forRoomWithIdentifier: roomIdentifier)
return
}
room.paginateBackwards(count: 1, callback: nil)
}
private func updateLastMessage(_ lastMessage: String, forRoomWithIdentifier roomIdentifier: String) {
@@ -174,15 +172,18 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
self.state.rooms[index].lastMessage = lastMessage
}
private func buildRoomFromProxy(_ roomProxy: RoomProxyProtocol) -> HomeScreenRoom {
let avatar = mediaProvider.imageForURL(roomProxy.avatarURL)
private func roomFromProxy(_ roomProxy: RoomProxyProtocol) -> HomeScreenRoom {
HomeScreenRoom(id: roomProxy.id,
displayName: roomProxy.name,
topic: roomProxy.topic,
lastMessage: roomProxy.lastMessage,
isDirect: roomProxy.isDirect,
isEncrypted: roomProxy.isEncrypted,
isSpace: roomProxy.isSpace,
isTombstoned: roomProxy.isTombstoned)
return HomeScreenRoom(id: roomProxy.id,
displayName: roomProxy.name,
topic: roomProxy.topic,
lastMessage: roomProxy.messages.last?.body,
avatar: avatar,
isDirect: roomProxy.isDirect,
isEncrypted: roomProxy.isEncrypted,
isSpace: roomProxy.isSpace,
isTombstoned: roomProxy.isTombstoned)
}
}
@@ -38,9 +38,7 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
self.timelineController = timelineController
self.timelineViewFactory = timelineViewFactory
super.init(initialViewState: RoomScreenViewState(roomTitle: roomName ?? "💥"))
buildTimelineViews()
super.init(initialViewState: RoomScreenViewState(roomTitle: roomName ?? "Unknown room 💥"))
timelineController.callbacks.sink { [weak self] callback in
guard let self = self else { return }
@@ -57,6 +55,8 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
self.state.items[viewIndex] = timelineViewFactory.buildTimelineViewFor(timelineItem)
}
}.store(in: &cancellables)
buildTimelineViews()
}
// MARK: - Public
@@ -80,8 +80,10 @@ class RoomScreenViewModel: RoomScreenViewModelType, RoomScreenViewModelProtocol
// MARK: - Private
private func buildTimelineViews() {
state.items = timelineController.timelineItems.map { item in
let stateItems = timelineController.timelineItems.map { item in
timelineViewFactory.buildTimelineViewFor(item)
}
state.items = stateItems
}
}
@@ -30,7 +30,7 @@ struct EmoteRoomTimelineView: View {
struct EmoteRoomTimelineView_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -51,7 +51,7 @@ struct EventBasedTimelineView: View {
struct EventBasedTimelineView_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -35,7 +35,7 @@ struct FormattedBodyText: View {
struct FormattedBodyText_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -35,7 +35,7 @@ struct ImageRoomTimelineView: View {
struct ImageRoomTimelineView_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -30,7 +30,7 @@ struct NoticeRoomTimelineView: View {
struct NoticeRoomTimelineView_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -36,7 +36,7 @@ struct PlaceholderAvatarImage: View {
struct PlaceholderAvatarImage_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -44,7 +44,7 @@ struct LabelledDivider: View {
struct SeparatorRoomTimelineView_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -27,7 +27,7 @@ struct TextRoomTimelineView: View {
struct TextRoomTimelineView_Previews: PreviewProvider {
static var previews: some View {
body
body.preferredColorScheme(.light)
body.preferredColorScheme(.dark)
}
@@ -59,9 +59,16 @@ struct TimelineView: View {
tableViewObserver = TableViewObserver(tableView: tableView,
topDetectionOffset: (tableView.bounds.size.height / 3.0))
tableViewObserver.scrollToBottom()
// Check if there are enough items. Otherwise ask for more
attemptBackPagination()
}
.onAppear(perform: {
if timelineItems != context.viewState.items {
timelineItems = context.viewState.items
}
})
.onReceive(tableViewObserver.scrollViewDidReachTop, perform: {
if context.viewState.isBackPaginating {
return
@@ -202,6 +209,20 @@ private class TableViewObserver: NSObject, UITableViewDelegate {
return (scrollView.contentOffset.y + scrollView.adjustedContentInset.top) <= topDetectionOffset
}
func scrollToBottom() {
guard let tableView = tableView,
tableView.numberOfSections > 0 else {
return
}
let currentItemCount = tableView.numberOfRows(inSection: 0)
guard currentItemCount > 1 else {
return
}
tableView.scrollToRow(at: .init(row: currentItemCount - 1, section: 0), at: .bottom, animated: false)
}
// MARK: - UIScrollViewDelegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {