Loading images and user avatars.

This commit is contained in:
Stefan Ceriu
2022-03-17 18:09:29 +02:00
parent 30378ae6a9
commit 120bcaf012
31 changed files with 542 additions and 207 deletions
@@ -8,31 +8,31 @@
import Foundation
import Combine
import MatrixRustSDK
class RoomTimelineController: RoomTimelineControllerProtocol {
private let timelineProvider: RoomTimelineProvider
private let timelineItemFactory: TimelineItemFactory
private let timelineViewFactory: TimelineViewFactory
private let timelineItemFactory: RoomTimelineItemFactory
private let mediaProvider: MediaProviderProtocol
private var cancellables = Set<AnyCancellable>()
let callbacks = PassthroughSubject<RoomTimelineControllerCallback, Never>()
private(set) var timelineItems = [RoomTimelineViewProvider]()
private(set) var timelineItems = [RoomTimelineItemProtocol]()
init(timelineProvider: RoomTimelineProvider,
timelineItemFactory: TimelineItemFactory,
timelineViewFactory: TimelineViewFactory) {
timelineItemFactory: RoomTimelineItemFactory,
mediaProvider: MediaProviderProtocol) {
self.timelineProvider = timelineProvider
self.timelineItemFactory = timelineItemFactory
self.timelineViewFactory = timelineViewFactory
self.mediaProvider = mediaProvider
self.timelineProvider.callbacks.sink { [weak self] callback in
guard let self = self else { return }
switch callback {
case .addedMessage:
self.rebuildTimeline()
self.updateTimelineItems()
}
}.store(in: &cancellables)
}
@@ -42,17 +42,58 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
switch result {
case .success:
callback(.success(()))
self?.rebuildTimeline()
self?.updateTimelineItems()
case .failure:
callback(.failure(.generic))
}
}
}
func processItemAppearance(_ itemId: String) {
guard let timelineItem = self.timelineItems.filter({ $0.id == itemId}).first else {
return
}
loadAvatarIfNeededForTimelineItem(timelineItem)
switch timelineItem {
case var item as ImageRoomTimelineItem:
if item.image != nil {
return
}
guard let url = item.url else {
return
}
mediaProvider.loadImageFromURL(url) { [weak self] result in
guard let self = self else {
return
}
if case let .success(image) = result {
guard let index = self.timelineItems.firstIndex(where: { $0.id == itemId }) else {
return
}
item.image = image
self.timelineItems[index] = item
self.callbacks.send(.updatedTimelineItem(itemId))
}
}
default:
break
}
}
func processItemDisappearance(_ itemId: String) {
}
// MARK: - Private
private func rebuildTimeline() {
var newTimelineItems = [RoomTimelineViewProvider]()
private func updateTimelineItems() {
var newTimelineItems = [RoomTimelineItemProtocol]()
var previousMessage: RoomMessageProtocol?
for message in self.timelineProvider.messages {
@@ -60,17 +101,14 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
let shouldAddSectionHeader = !areMessagesFromTheSameDay
if shouldAddSectionHeader {
let item = SeparatorRoomTimelineItem(id: message.originServerTs.ISO8601Format(),
text: message.originServerTs.formatted(date: .long, time: .omitted))
newTimelineItems.append(RoomTimelineViewProvider.separator(item))
newTimelineItems.append(SeparatorRoomTimelineItem(id: message.originServerTs.ISO8601Format(),
text: message.originServerTs.formatted(date: .long, time: .omitted)))
}
let areMessagesFromTheSameSender = (previousMessage?.sender == message.sender)
let shouldShowSenderDetails = !areMessagesFromTheSameSender || !areMessagesFromTheSameDay
let timelineItem = timelineItemFactory.buildTimelineItemFor(message, showSenderDetails: shouldShowSenderDetails)
newTimelineItems.append(timelineViewFactory.buildTimelineViewFor(timelineItem))
newTimelineItems.append(timelineItemFactory.buildTimelineItemFor(message, showSenderDetails: shouldShowSenderDetails))
previousMessage = message
}
@@ -87,4 +125,43 @@ class RoomTimelineController: RoomTimelineControllerProtocol {
return Calendar.current.isDate(lhs.originServerTs, inSameDayAs: rhs.originServerTs)
}
private func loadAvatarIfNeededForTimelineItem(_ timelineItem: RoomTimelineItemProtocol) {
switch timelineItem {
case var item as BaseRoomTimelineItemProtocol:
if item.shouldShowSenderDetails == false {
break
}
timelineProvider.avatarURLForUserId(item.sender) { [weak self] result in
guard let self = self else {
return
}
switch result {
case .success(let userAvatarURL):
guard let avatarURL = userAvatarURL else {
return
}
self.mediaProvider.loadImageFromURL(avatarURL) { result in
if case let .success(image) = result {
guard let index = self.timelineItems.firstIndex(where: { $0.id == timelineItem.id }) else {
return
}
item.senderAvatar = image
self.timelineItems[index] = item
self.callbacks.send(.updatedTimelineItem(timelineItem.id))
}
}
case .failure:
MXLog.error("Failed retrieving user avatar")
}
}
default:
break
}
}
}