Add AttachmentView

This commit is contained in:
Djorkaeff Alexandre 2024-01-18 19:49:49 -03:00
parent 9668aed381
commit 2fdf0e2c3b
10 changed files with 144 additions and 28 deletions

View File

@ -1,5 +1,7 @@
import Foundation
let HISTORY_MESSAGE_COUNT = 50
struct HistoryRequest: Request {
typealias Response = HistoryResponse
@ -11,6 +13,7 @@ struct HistoryRequest: Request {
queryItems = [
URLQueryItem(name: "roomId", value: roomId),
URLQueryItem(name: "count", value: String(HISTORY_MESSAGE_COUNT)),
URLQueryItem(name: "latest", value: latest.iso8601withFractionalSeconds)
]
}

View File

@ -0,0 +1,7 @@
import CoreData
extension Attachment {
var aspectRatio: Double {
return width / height
}
}

View File

@ -3,10 +3,12 @@ import Foundation
final class MessageFormatter {
private let message: Message
private let previousMessage: Message?
private let lastOpen: Date?
init(message: Message, previousMessage: Message?) {
init(message: Message, previousMessage: Message?, lastOpen: Date?) {
self.message = message
self.previousMessage = previousMessage
self.lastOpen = lastOpen
}
func hasDateSeparator() -> Bool {
@ -19,6 +21,20 @@ final class MessageFormatter {
return true
}
func hasUnreadSeparator() -> Bool {
guard let messageTS = message.ts, let lastOpen else {
return false
}
if previousMessage == nil {
return messageTS > lastOpen
} else if let previousMessage, let previousMessageTS = previousMessage.ts {
return messageTS >= lastOpen && previousMessageTS < lastOpen
} else {
return false
}
}
func isHeader() -> Bool {
if let previousMessage,
let previousMessageTS = previousMessage.ts,

View File

@ -74,8 +74,10 @@ final class MessagesLoader {
} receiveValue: { [weak self] messagesResponse in
let messages = messagesResponse.messages
if let lastMessage = messages.last, self?.database.message(id: lastMessage._id) == nil, messages.count == 20 {
if messages.count == HISTORY_MESSAGE_COUNT {
room.hasMoreMessages = true
} else {
room.hasMoreMessages = false
}
for message in messages {

View File

@ -19,6 +19,9 @@
},
"Try Again" : {
},
"Unread messages" : {
}
},
"version" : "1.0"

View File

@ -7,10 +7,14 @@ final class MessageViewModel: ObservableObject {
let messageFormatter: MessageFormatter
init(message: Message, previousMessage: Message? = nil, server: Server?) {
init(message: Message, previousMessage: Message? = nil, server: Server?, lastOpen: Date?) {
self.message = message
self.previousMessage = previousMessage
self.messageFormatter = MessageFormatter(message: message, previousMessage: previousMessage)
self.messageFormatter = MessageFormatter(
message: message,
previousMessage: previousMessage,
lastOpen: lastOpen
)
self.server = server
}

View File

@ -0,0 +1,36 @@
import SwiftUI
struct AttachmentView: View {
private let attachment: Attachment
private let client: RocketChatClientProtocol
init(attachment: Attachment, client: RocketChatClientProtocol) {
self.attachment = attachment
self.client = client
}
var body: some View {
if let rawURL = attachment.imageURL {
VStack(alignment: .leading) {
if let msg = attachment.msg {
Text(msg)
.font(.caption)
.foregroundStyle(.white)
}
AsyncImage(url: client.authorizedURL(url: rawURL)) { image in
image
.resizable()
.scaledToFit()
} placeholder: {
Rectangle()
.foregroundStyle(.secondary)
.aspectRatio(attachment.aspectRatio, contentMode: .fit)
.overlay(ProgressView())
}
.cornerRadius(4)
}
} else {
EmptyView()
}
}
}

View File

@ -11,6 +11,9 @@ struct MessageListView: View {
private let server: Server
private let room: Room
@State private var lastMessageID: String?
@State private var lastOpen: Date?
@FetchRequest<Message> private var messages: FetchedResults<Message>
init(
@ -29,6 +32,7 @@ struct MessageListView: View {
self.room = room
self.server = server
_messages = FetchRequest(fetchRequest: room.messagesRequest, animation: .none)
_lastOpen = State(wrappedValue: room.updatedSince)
}
var body: some View {
@ -47,12 +51,17 @@ struct MessageListView: View {
let message = messages[index]
let previousMessage = messages.indices.contains(index - 1) ? messages[index - 1] : nil
MessageView(viewModel: .init(message: message, previousMessage: previousMessage, server: server))
.transition(.move(edge: .bottom))
MessageView(
client: client,
viewModel: .init(message: message, previousMessage: previousMessage, server: server, lastOpen: lastOpen)
)
.transition(.move(edge: .bottom))
}
MessageComposerView(room: room) {
messageSender.sendMessage($0, in: room)
lastOpen = nil
}
.id(messageComposer)
}
@ -69,7 +78,10 @@ struct MessageListView: View {
messagesLoader.stop()
}
.onReceive(messages.publisher) { _ in
reader.scrollTo(messageComposer, anchor: .bottom)
if lastMessageID != messages.last?.id {
reader.scrollTo(messageComposer, anchor: .bottom)
lastMessageID = messages.last?.id
}
}
}
}

View File

@ -3,28 +3,53 @@ import SwiftUI
struct MessageView: View {
@ObservedObject private var viewModel: MessageViewModel
init(viewModel: MessageViewModel) {
private let client: RocketChatClientProtocol
init(client: RocketChatClientProtocol, viewModel: MessageViewModel) {
self.client = client
self.viewModel = viewModel
}
@ViewBuilder
private var unreadSeparator: some View {
HStack(alignment: .center) {
Text("Unread messages")
.lineLimit(1)
.font(.footnote)
.foregroundStyle(.red)
.layoutPriority(1)
VStack(alignment: .center) {
Divider()
.overlay(.red)
}
}
}
@ViewBuilder
private var dateSeparator: some View {
HStack(alignment: .center) {
VStack(alignment: .center) {
Divider()
.overlay(.secondary)
}
Text(viewModel.messageFormatter.date() ?? "")
.lineLimit(1)
.font(.footnote)
.foregroundStyle(.secondary)
.layoutPriority(1)
VStack(alignment: .center) {
Divider()
.overlay(.secondary)
}
}
}
var body: some View {
VStack(alignment: .leading) {
if viewModel.messageFormatter.hasDateSeparator() {
HStack(alignment: .center) {
VStack(alignment: .center) {
Divider()
.overlay(.secondary)
}
Text(viewModel.messageFormatter.date() ?? "")
.lineLimit(1)
.font(.footnote)
.foregroundStyle(.secondary)
.layoutPriority(1)
VStack(alignment: .center) {
Divider()
.overlay(.secondary)
}
}
dateSeparator
} else if viewModel.messageFormatter.hasUnreadSeparator() {
unreadSeparator
}
if viewModel.messageFormatter.isHeader() {
HStack(alignment: .center) {
@ -49,11 +74,11 @@ struct MessageView: View {
.font(.caption)
.foregroundStyle(viewModel.message.status == "temp" ? .secondary : .primary)
}
// if let attachments = message.attachments?.allObjects as? Array<Attachment> {
// ForEach(attachments) { attachment in
// AttachmentView(attachment: attachment)
// }
// }
if let attachments = viewModel.message.attachments?.allObjects as? Array<Attachment> {
ForEach(attachments) { attachment in
AttachmentView(attachment: attachment, client: client)
}
}
}
}
}

View File

@ -111,6 +111,8 @@
1E76CBDA25152C8E0067298C /* SendMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E598AE825151A63002BDFBD /* SendMessage.swift */; };
1E9A71672B599E6300477BA2 /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71662B599E6300477BA2 /* NotificationController.swift */; };
1E9A71692B59B6E100477BA2 /* MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71682B59B6E100477BA2 /* MessageSender.swift */; };
1E9A716F2B59CBCA00477BA2 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */; };
1E9A71712B59CC1300477BA2 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E9A71702B59CC1300477BA2 /* Attachment.swift */; };
1EB375892B55DBFB00AEC3D7 /* Server.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EB375882B55DBFB00AEC3D7 /* Server.swift */; };
1EB8EF722510F1EE00F352B7 /* Storage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1EB8EF712510F1EE00F352B7 /* Storage.swift */; };
1EC6ACB722CB9FC300A41C61 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1EC6ACB522CB9FC300A41C61 /* MainInterface.storyboard */; };
@ -396,6 +398,8 @@
1E9A71652B599D3F00477BA2 /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = "<group>"; };
1E9A71662B599E6300477BA2 /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = "<group>"; };
1E9A71682B59B6E100477BA2 /* MessageSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSender.swift; sourceTree = "<group>"; };
1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttachmentView.swift; sourceTree = "<group>"; };
1E9A71702B59CC1300477BA2 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = "<group>"; };
1EB375882B55DBFB00AEC3D7 /* Server.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Server.swift; sourceTree = "<group>"; };
1EB8EF712510F1EE00F352B7 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
1EC6ACB022CB9FC300A41C61 /* ShareRocketChatRN.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareRocketChatRN.appex; sourceTree = BUILT_PRODUCTS_DIR; };
@ -738,6 +742,7 @@
1EB375882B55DBFB00AEC3D7 /* Server.swift */,
1E29A30D2B58608C0093C03C /* LoggedUser.swift */,
1E29A3112B5866090093C03C /* Room.swift */,
1E9A71702B59CC1300477BA2 /* Attachment.swift */,
);
path = Models;
sourceTree = "<group>";
@ -776,6 +781,7 @@
1E29A3152B5868DF0093C03C /* MessageListView.swift */,
1E29A3172B5868E50093C03C /* MessageView.swift */,
1E29A3232B5874FF0093C03C /* MessageComposerView.swift */,
1E9A716E2B59CBCA00477BA2 /* AttachmentView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -1843,6 +1849,7 @@
1E29A2FD2B585B070093C03C /* RoomsRequest.swift in Sources */,
1ED038CA2B50A58400C007D4 /* WatchConnection.swift in Sources */,
1E29A3222B5871CE0093C03C /* MessageFormatter.swift in Sources */,
1E9A716F2B59CBCA00477BA2 /* AttachmentView.swift in Sources */,
1E29A3002B585B070093C03C /* JSONAdapter.swift in Sources */,
1E29A3022B585B070093C03C /* DateCodingStrategy.swift in Sources */,
1ED033B62B55B4A5004F4930 /* ServerListView.swift in Sources */,
@ -1887,6 +1894,7 @@
1ED033B82B55B4BE004F4930 /* ServerListViewModel.swift in Sources */,
1ED033C42B55C65C004F4930 /* RocketChatAppRouter.swift in Sources */,
1ED033B02B55B25A004F4930 /* Database.swift in Sources */,
1E9A71712B59CC1300477BA2 /* Attachment.swift in Sources */,
1ED033C82B55CE78004F4930 /* DependencyStore.swift in Sources */,
1E29A30A2B585B370093C03C /* Data+Extensions.swift in Sources */,
1E29A2F72B585B070093C03C /* ReadResponse.swift in Sources */,