Introduced the concepts of room summary and event brief.

This commit is contained in:
Stefan Ceriu
2022-04-01 14:07:33 +03:00
parent 77942b3dc0
commit 86d85f4d2c
12 changed files with 402 additions and 104 deletions
@@ -0,0 +1,17 @@
//
// EventBrief.swift
// ElementX
//
// Created by Stefan Ceriu on 01/04/2022.
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
struct EventBrief {
let id: String
let senderName: String
let body: String
let htmlBody: String?
let date: Date
}
@@ -0,0 +1,41 @@
//
// EventBriefFactory.swift
// ElementX
//
// Created by Stefan Ceriu on 01/04/2022.
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
struct EventBriefFactory: EventBriefFactoryProtocol {
func eventBriefForMessage(_ message: RoomMessageProtocol?) -> EventBrief? {
guard let message = message else {
return nil
}
switch message {
case is ImageRoomMessage:
return nil
case let message as TextRoomMessage:
return buildEventBrief(message: message, htmlBody: message.htmlBody)
case let message as NoticeRoomMessage:
return buildEventBrief(message: message, htmlBody: message.htmlBody)
case let message as EmoteRoomMessage:
return buildEventBrief(message: message, htmlBody: message.htmlBody)
default:
fatalError("Unknown room message.")
}
}
// MARK: - Private
private func buildEventBrief(message: RoomMessageProtocol, htmlBody: String?) -> EventBrief {
return EventBrief(id: message.id,
senderName: message.sender,
body: message.body,
htmlBody: htmlBody,
date: message.originServerTs)
}
}
@@ -0,0 +1,13 @@
//
// EventBriefFactoryProtocol.swift
// ElementX
//
// Created by Stefan Ceriu on 01/04/2022.
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
protocol EventBriefFactoryProtocol {
func eventBriefForMessage(_ message: RoomMessageProtocol?) -> EventBrief?
}
@@ -0,0 +1,38 @@
//
// MockRoomSummary.swift
// ElementX
//
// Created by Stefan Ceriu on 01/04/2022.
// Copyright © 2022 Element. All rights reserved.
//
import UIKit
import Combine
struct MockRoomSummary: RoomSummaryProtocol {
var id: String = UUID().uuidString
var name: String?
var topic: String?
var isDirect: Bool = false
var isEncrypted: Bool = false
var isSpace: Bool = false
var isTombstoned: Bool = false
var displayName: String?
var lastMessage: EventBrief?
var avatar: UIImage?
func loadData() {
}
var callbacks = PassthroughSubject<RoomSummaryCallback, Never>()
}
@@ -0,0 +1,145 @@
//
// RoomSummary.swift
// ElementX
//
// Created by Stefan Ceriu on 01/04/2022.
// Copyright © 2022 Element. All rights reserved.
//
import Foundation
import UIKit
import Combine
class RoomSummary: RoomSummaryProtocol {
private let roomProxy: RoomProxyProtocol
private let mediaProvider: MediaProviderProtocol
private let eventBriefFactory: EventBriefFactoryProtocol
private var hasLoadedData = false
private var roomUpdateListeners = Set<AnyCancellable>()
var id: String {
roomProxy.id
}
var name: String? {
roomProxy.name
}
var topic: String? {
roomProxy.topic
}
var isDirect: Bool {
roomProxy.isDirect
}
var isEncrypted: Bool {
roomProxy.isEncrypted
}
var isSpace: Bool {
roomProxy.isSpace
}
var isTombstoned: Bool {
roomProxy.isTombstoned
}
private(set) var displayName: String? {
didSet {
self.callbacks.send(.updatedData)
}
}
private(set) var lastMessage: EventBrief? {
didSet {
self.callbacks.send(.updatedData)
}
}
private(set) var avatar: UIImage? {
didSet {
self.callbacks.send(.updatedData)
}
}
let callbacks = PassthroughSubject<RoomSummaryCallback, Never>()
init(roomProxy: RoomProxyProtocol, mediaProvider: MediaProviderProtocol, eventBriefFactory: EventBriefFactoryProtocol) {
self.roomProxy = roomProxy
self.mediaProvider = mediaProvider
self.eventBriefFactory = eventBriefFactory
lastMessage = eventBriefFactory.eventBriefForMessage(roomProxy.messages.last)
roomProxy.callbacks.sink { [weak self] callback in
guard let self = self else {
return
}
switch callback {
case .updatedMessages:
self.lastMessage = self.eventBriefFactory.eventBriefForMessage(self.roomProxy.messages.last)
}
}
.store(in: &roomUpdateListeners)
}
func loadData() {
if hasLoadedData {
return
}
loadDisplayName()
loadLastMessage()
loadAvatar()
hasLoadedData = true
}
// MARK: - Private
private func loadDisplayName() {
roomProxy.displayName { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let displayName):
self.displayName = displayName
case .failure(let error):
MXLog.error("Failed fetching room display name with error: \(error)")
}
}
}
private func loadLastMessage() {
if roomProxy.messages.last == nil {
roomProxy.paginateBackwards(count: 1) { [weak self] result in
guard let self = self else { return }
switch result {
case .success:
self.lastMessage = self.eventBriefFactory.eventBriefForMessage(self.roomProxy.messages.last)
case .failure(let error):
MXLog.error("Failed back paginating with error: \(error)")
}
}
}
}
private func loadAvatar() {
if let avatarURL = roomProxy.avatarURL {
mediaProvider.loadImageFromURL(avatarURL) { [weak self] result in
guard let self = self else { return }
switch result {
case .success(let image):
self.avatar = image
case .failure(let error):
MXLog.error("Failed fetching room avatar with error: \(error)")
}
}
}
}
}
@@ -0,0 +1,32 @@
//
// RoomSummaryProtocol.swift
// ElementX
//
// Created by Stefan Ceriu on 01/04/2022.
// Copyright © 2022 Element. All rights reserved.
//
import UIKit
import Combine
enum RoomSummaryCallback {
case updatedData
}
protocol RoomSummaryProtocol {
var id: String { get }
var name: String? { get }
var topic: String? { get }
var isDirect: Bool { get }
var isEncrypted: Bool { get }
var isSpace: Bool { get }
var isTombstoned: Bool { get }
var displayName: String? { get }
var lastMessage: EventBrief? { get }
var avatar: UIImage? { get }
var callbacks: PassthroughSubject<RoomSummaryCallback, Never> { get }
func loadData()
}