mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 16:10:20 +00:00
Loading images and user avatars.
This commit is contained in:
@@ -7,11 +7,17 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
struct ImageRoomTimelineItem: TimelineItemProtocol, Identifiable, Equatable {
|
||||
struct ImageRoomTimelineItem: BaseRoomTimelineItemProtocol, Identifiable, Equatable {
|
||||
let id: String
|
||||
let senderDisplayName: String
|
||||
let text: String
|
||||
let timestamp: String
|
||||
let shouldShowSenderDetails: Bool
|
||||
|
||||
let sender: String
|
||||
var senderAvatar: UIImage?
|
||||
|
||||
let url: String?
|
||||
var image: UIImage?
|
||||
}
|
||||
|
||||
@@ -11,16 +11,50 @@ import SwiftUI
|
||||
|
||||
struct ImageRoomTimelineView: View {
|
||||
let timelineItem: ImageRoomTimelineItem
|
||||
var loadedImage: UIImage?
|
||||
|
||||
var body: some View {
|
||||
if let loadedImage = loadedImage {
|
||||
Image(uiImage: loadedImage)
|
||||
} else {
|
||||
if let image = timelineItem.image {
|
||||
VStack {
|
||||
Image(systemName: "photo")
|
||||
ProgressView()
|
||||
HStack {
|
||||
Text(timelineItem.text)
|
||||
Spacer()
|
||||
}
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
}
|
||||
} else {
|
||||
VStack(alignment: .center) {
|
||||
HStack {
|
||||
Text(timelineItem.text)
|
||||
Spacer()
|
||||
}
|
||||
ProgressView("Loading")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ImageRoomTimelineView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack {
|
||||
let timelineItem = ImageRoomTimelineItem(id: UUID().uuidString,
|
||||
text: "Some image",
|
||||
timestamp: "Now",
|
||||
shouldShowSenderDetails: false,
|
||||
sender: "Bob",
|
||||
url: nil,
|
||||
image: UIImage(systemName: "photo"))
|
||||
ImageRoomTimelineView(timelineItem: timelineItem)
|
||||
|
||||
let timelineItem = ImageRoomTimelineItem(id: UUID().uuidString,
|
||||
text: "Some other image",
|
||||
timestamp: "Now",
|
||||
shouldShowSenderDetails: false,
|
||||
sender: "Bob",
|
||||
url: nil,
|
||||
image: nil)
|
||||
ImageRoomTimelineView(timelineItem: timelineItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+27
-6
@@ -7,22 +7,43 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
struct TimelineItemFactory {
|
||||
func buildTimelineItemFor(_ roomMessage: RoomMessageProtocol, showSenderDetails: Bool) -> TimelineItemProtocol {
|
||||
struct RoomTimelineItemFactory {
|
||||
private let mediaProvider: MediaProviderProtocol
|
||||
|
||||
init(mediaProvider: MediaProviderProtocol) {
|
||||
self.mediaProvider = mediaProvider
|
||||
}
|
||||
|
||||
func buildTimelineItemFor(_ roomMessage: RoomMessageProtocol, showSenderDetails: Bool) -> RoomTimelineItemProtocol {
|
||||
switch roomMessage {
|
||||
case let message as TextRoomMessage:
|
||||
return TextRoomTimelineItem(id: message.id,
|
||||
senderDisplayName: message.sender,
|
||||
text: message.content,
|
||||
timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened),
|
||||
shouldShowSenderDetails: showSenderDetails)
|
||||
shouldShowSenderDetails: showSenderDetails,
|
||||
sender: message.sender)
|
||||
case let message as ImageRoomMessage:
|
||||
var image: UIImage?
|
||||
|
||||
if let url = message.url {
|
||||
if mediaProvider.hasImageCachedForURL(url) {
|
||||
mediaProvider.loadImageFromURL(url, { result in
|
||||
if case let .success(cachedImage) = result {
|
||||
image = cachedImage
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return ImageRoomTimelineItem(id: message.id,
|
||||
senderDisplayName: message.sender,
|
||||
text: message.content,
|
||||
timestamp: message.originServerTs.formatted(date: .omitted, time: .shortened),
|
||||
shouldShowSenderDetails: showSenderDetails)
|
||||
shouldShowSenderDetails: showSenderDetails,
|
||||
sender: message.sender,
|
||||
url: message.url,
|
||||
image: image)
|
||||
default:
|
||||
fatalError("Unknown room message.")
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// RoomTimelineItemProtocol.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 16/03/2022.
|
||||
// Copyright © 2022 Element. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
protocol RoomTimelineItemProtocol {
|
||||
var id: String { get }
|
||||
}
|
||||
|
||||
protocol BaseRoomTimelineItemProtocol: RoomTimelineItemProtocol {
|
||||
var text: String { get }
|
||||
var timestamp: String { get }
|
||||
var shouldShowSenderDetails: Bool { get }
|
||||
|
||||
var sender: String { get }
|
||||
var senderAvatar: UIImage? { get set }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
//
|
||||
// TimelineViewFactory.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 16/03/2022.
|
||||
// Copyright © 2022 Element. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct RoomTimelineViewFactory {
|
||||
func buildTimelineViewFor(_ timelineItem: RoomTimelineItemProtocol) -> RoomTimelineViewProvider {
|
||||
switch timelineItem {
|
||||
case let item as TextRoomTimelineItem:
|
||||
return .text(item)
|
||||
case let item as ImageRoomTimelineItem:
|
||||
return .image(item)
|
||||
case let item as SeparatorRoomTimelineItem:
|
||||
return .separator(item)
|
||||
default:
|
||||
fatalError("Unknown timeline item")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SeparatorRoomTimelineItem: TimelineItemProtocol, Identifiable, Equatable {
|
||||
struct SeparatorRoomTimelineItem: RoomTimelineItemProtocol, Identifiable, Equatable {
|
||||
let id: String
|
||||
let text: String
|
||||
}
|
||||
|
||||
@@ -7,11 +7,14 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
struct TextRoomTimelineItem: TimelineItemProtocol, Identifiable, Equatable {
|
||||
struct TextRoomTimelineItem: BaseRoomTimelineItemProtocol, Identifiable, Equatable {
|
||||
let id: String
|
||||
let senderDisplayName: String
|
||||
let text: String
|
||||
let timestamp: String
|
||||
let shouldShowSenderDetails: Bool
|
||||
|
||||
let sender: String
|
||||
var senderAvatar: UIImage?
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ struct TextRoomTimelineView: View {
|
||||
VStack(alignment: .leading) {
|
||||
if timelineItem.shouldShowSenderDetails {
|
||||
HStack {
|
||||
Text(timelineItem.senderDisplayName)
|
||||
avatar
|
||||
Text(timelineItem.sender)
|
||||
.font(.footnote)
|
||||
.bold()
|
||||
Spacer()
|
||||
@@ -24,10 +25,48 @@ struct TextRoomTimelineView: View {
|
||||
.font(.footnote)
|
||||
}
|
||||
Divider()
|
||||
Spacer()
|
||||
}
|
||||
Text(timelineItem.text)
|
||||
}
|
||||
.id(timelineItem.id)
|
||||
}
|
||||
|
||||
@ViewBuilder var avatar: some View {
|
||||
ZStack(alignment: .center) {
|
||||
Circle()
|
||||
.fill(Color(.sRGB, red: 0.05, green: 0.74, blue: 0.55, opacity: 1.0))
|
||||
if let avatar = timelineItem.senderAvatar {
|
||||
Image(uiImage: avatar)
|
||||
.resizable()
|
||||
.clipShape(Circle())
|
||||
} else {
|
||||
Text(timelineItem.sender.prefix(2).suffix(1))
|
||||
.foregroundColor(.white)
|
||||
.font(.title)
|
||||
.bold()
|
||||
}
|
||||
}
|
||||
.frame(width: 44.0, height: 44.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct TextRoomTimelineView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
VStack(spacing: 20.0) {
|
||||
let timelineItem = TextRoomTimelineItem(id: UUID().uuidString,
|
||||
text: "Short loin ground round tongue hamburger, fatback salami shoulder. Beef turkey sausage kielbasa strip steak. Alcatra capicola pig tail pancetta chislic.",
|
||||
timestamp: "Now",
|
||||
shouldShowSenderDetails: true,
|
||||
sender: "Bob")
|
||||
TextRoomTimelineView(timelineItem: timelineItem)
|
||||
|
||||
let timelineItem = TextRoomTimelineItem(id: UUID().uuidString,
|
||||
text: "Some other text",
|
||||
timestamp: "Later",
|
||||
shouldShowSenderDetails: true,
|
||||
sender: "Anne")
|
||||
TextRoomTimelineView(timelineItem: timelineItem)
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
//
|
||||
// TimelineItemProtocol.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 16/03/2022.
|
||||
// Copyright © 2022 Element. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
protocol TimelineItemProtocol {
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
//
|
||||
// TimelineViewFactory.swift
|
||||
// ElementX
|
||||
//
|
||||
// Created by Stefan Ceriu on 16/03/2022.
|
||||
// Copyright © 2022 Element. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct TimelineViewFactory {
|
||||
func buildTimelineViewFor(_ timelineItem: TimelineItemProtocol) -> RoomTimelineViewProvider {
|
||||
switch timelineItem {
|
||||
case let textItem as TextRoomTimelineItem:
|
||||
return .text(textItem)
|
||||
case let imageItem as ImageRoomTimelineItem:
|
||||
return .image(imageItem)
|
||||
default:
|
||||
fatalError("Unknown timeline item")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user