Add AttachmentView
This commit is contained in:
parent
9668aed381
commit
2fdf0e2c3b
|
@ -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)
|
||||
]
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import CoreData
|
||||
|
||||
extension Attachment {
|
||||
var aspectRatio: Double {
|
||||
return width / height
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
},
|
||||
"Try Again" : {
|
||||
|
||||
},
|
||||
"Unread messages" : {
|
||||
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
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
|
||||
if lastMessageID != messages.last?.id {
|
||||
reader.scrollTo(messageComposer, anchor: .bottom)
|
||||
lastMessageID = messages.last?.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,30 @@ 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
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
if viewModel.messageFormatter.hasDateSeparator() {
|
||||
@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()
|
||||
|
@ -26,6 +43,14 @@ struct MessageView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
if viewModel.messageFormatter.hasDateSeparator() {
|
||||
dateSeparator
|
||||
} else if viewModel.messageFormatter.hasUnreadSeparator() {
|
||||
unreadSeparator
|
||||
}
|
||||
if viewModel.messageFormatter.isHeader() {
|
||||
HStack(alignment: .center) {
|
||||
Text(viewModel.sender ?? "")
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 */,
|
||||
|
|
Loading…
Reference in New Issue