mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
Loading images and user avatars.
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user