wip
This commit is contained in:
parent
4b092a8831
commit
6a5555a603
|
@ -49,17 +49,17 @@ struct Message: DBStorable, Equatable {
|
|||
static let databaseTableName = "messages"
|
||||
|
||||
let id: String
|
||||
let type: MessageType
|
||||
var type: MessageType
|
||||
let date: Date
|
||||
var contentType: MessageContentType
|
||||
var status: MessageStatus
|
||||
|
||||
let from: String
|
||||
let to: String?
|
||||
var from: String
|
||||
var to: String?
|
||||
|
||||
var body: String?
|
||||
let subject: String?
|
||||
let thread: String?
|
||||
var subject: String?
|
||||
var thread: String?
|
||||
var oobUrl: String?
|
||||
}
|
||||
|
||||
|
@ -77,4 +77,20 @@ extension Message {
|
|||
try updatedMessage.update(db, columns: ["status"])
|
||||
}
|
||||
}
|
||||
|
||||
static var blank: Message {
|
||||
Message(
|
||||
id: UUID().uuidString,
|
||||
type: .chat,
|
||||
date: Date(),
|
||||
contentType: .text,
|
||||
status: .pending,
|
||||
from: "",
|
||||
to: nil,
|
||||
body: nil,
|
||||
subject: nil,
|
||||
thread: nil,
|
||||
oobUrl: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@ final class ConversationStore: ObservableObject {
|
|||
|
||||
private(set) var roster: Roster
|
||||
private let client: Client
|
||||
private let blockSize = Const.messagesPageSize
|
||||
private let messagesMax = Const.messagesMaxSize
|
||||
|
||||
private var messagesCancellable: AnyCancellable?
|
||||
|
||||
|
@ -25,28 +23,18 @@ final class ConversationStore: ObservableObject {
|
|||
|
||||
extension ConversationStore {
|
||||
func sendMessage(_ message: String) async {
|
||||
// prepare message
|
||||
let message = Message(
|
||||
id: UUID().uuidString,
|
||||
type: .chat,
|
||||
date: Date(),
|
||||
contentType: .text,
|
||||
status: .pending,
|
||||
from: roster.bareJid,
|
||||
to: roster.contactBareJid,
|
||||
body: message,
|
||||
subject: nil,
|
||||
thread: nil,
|
||||
oobUrl: nil
|
||||
)
|
||||
var msg = Message.blank
|
||||
msg.from = roster.bareJid
|
||||
msg.to = roster.contactBareJid
|
||||
msg.body = message
|
||||
|
||||
// store as pending on db, and send
|
||||
do {
|
||||
try await message.save()
|
||||
try await client.sendMessage(message)
|
||||
try await message.setStatus(.sent)
|
||||
try await msg.save()
|
||||
try await client.sendMessage(msg)
|
||||
try await msg.setStatus(.sent)
|
||||
} catch {
|
||||
try? await message.setStatus(.error)
|
||||
try? await msg.setStatus(.error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -67,7 +55,10 @@ extension ConversationStore {
|
|||
|
||||
func sendCaptured(_ data: Data, _ type: GalleryMediaType) async {
|
||||
// save locally and make message
|
||||
let messageId = UUID().uuidString
|
||||
var message = Message.blank
|
||||
message.from = roster.bareJid
|
||||
message.to = roster.contactBareJid
|
||||
|
||||
let localName: String
|
||||
let msgType: AttachmentType
|
||||
do {
|
||||
|
@ -78,11 +69,11 @@ extension ConversationStore {
|
|||
let msgType: AttachmentType
|
||||
switch type {
|
||||
case .photo:
|
||||
localName = "\(messageId)_\(fileId).jpg"
|
||||
localName = "\(message.id)_\(fileId).jpg"
|
||||
msgType = .image
|
||||
|
||||
case .video:
|
||||
localName = "\(messageId)_\(fileId).mov"
|
||||
localName = "\(message.id)_\(fileId).mov"
|
||||
msgType = .video
|
||||
}
|
||||
|
||||
|
@ -97,25 +88,13 @@ extension ConversationStore {
|
|||
}
|
||||
|
||||
// save message
|
||||
let message = Message(
|
||||
id: UUID().uuidString,
|
||||
type: .chat,
|
||||
date: Date(),
|
||||
contentType: .attachment(
|
||||
message.contentType = .attachment(
|
||||
Attachment(
|
||||
type: msgType,
|
||||
localName: localName,
|
||||
thumbnailName: nil,
|
||||
remotePath: nil
|
||||
)
|
||||
),
|
||||
status: .pending,
|
||||
from: roster.bareJid,
|
||||
to: roster.contactBareJid,
|
||||
body: nil,
|
||||
subject: nil,
|
||||
thread: nil,
|
||||
oobUrl: nil
|
||||
)
|
||||
do {
|
||||
try await message.save()
|
||||
|
|
|
@ -2,15 +2,6 @@ import Foundation
|
|||
import UIKit
|
||||
|
||||
enum Const {
|
||||
// // Network
|
||||
// #if DEBUG
|
||||
// static let baseUrl = "staging.some.com/api"
|
||||
// #else
|
||||
// static let baseUrl = "prod.some.com/api"
|
||||
// #endif
|
||||
// static let requestTimeout = 15.0
|
||||
// static let networkLogging = true
|
||||
|
||||
// App
|
||||
static var appVersion: String {
|
||||
let info = Bundle.main.infoDictionary
|
||||
|
@ -54,8 +45,4 @@ enum Const {
|
|||
|
||||
// Lenght in days for MAM request
|
||||
static let mamRequestDaysLength = 30
|
||||
|
||||
// Limits for messages pagination
|
||||
static let messagesPageSize = 20 // size for block requesting
|
||||
static let messagesMaxSize = 100 // total messages in memory
|
||||
}
|
||||
|
|
|
@ -12,8 +12,8 @@ struct ConversationMessageContainer: View {
|
|||
EmbededMapView(location: msgText.getLatLon)
|
||||
} else if let msgText = message.body, msgText.isContact {
|
||||
ContactView(message: message)
|
||||
// } else if message.attachmentType != nil {
|
||||
// AttachmentView(message: message)
|
||||
} else if case .attachment(let attachment) = message.contentType {
|
||||
AttachmentView(message: message, attachment: attachment)
|
||||
} else {
|
||||
Text(message.body ?? "...")
|
||||
.font(.body2)
|
||||
|
@ -98,107 +98,108 @@ private struct ContactView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// private struct AttachmentView: View {
|
||||
// let message: Message
|
||||
//
|
||||
// var body: some View {
|
||||
// if message.attachmentDownloadFailed || (message.attachmentLocalName != nil && message.sentError) {
|
||||
// failed
|
||||
// } else {
|
||||
// switch message.attachmentType {
|
||||
// case .image:
|
||||
// if let thumbnail = thumbnail() {
|
||||
// thumbnail
|
||||
// .resizable()
|
||||
// .aspectRatio(contentMode: .fit)
|
||||
// .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
// } else {
|
||||
// placeholder
|
||||
// }
|
||||
//
|
||||
// case .movie:
|
||||
// if let file = message.attachmentLocalPath {
|
||||
// VideoPlayerView(url: file)
|
||||
// .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
// } else {
|
||||
// placeholder
|
||||
// }
|
||||
//
|
||||
// case .file:
|
||||
// if let file = message.attachmentLocalPath {
|
||||
// DocumentPreview(url: file)
|
||||
// .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
// } else {
|
||||
// placeholder
|
||||
// }
|
||||
//
|
||||
// default:
|
||||
// placeholder
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @ViewBuilder private var placeholder: some View {
|
||||
// Rectangle()
|
||||
// .foregroundColor(.Material.Background.dark)
|
||||
// .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
// .overlay {
|
||||
// ZStack {
|
||||
// ProgressView()
|
||||
// .scaleEffect(1.5)
|
||||
// .progressViewStyle(CircularProgressViewStyle(tint: .Material.Elements.active))
|
||||
// let imageName = progressImageName(message.attachmentType ?? .file)
|
||||
// Image(systemName: imageName)
|
||||
// .font(.body1)
|
||||
// .foregroundColor(.Material.Elements.active)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @ViewBuilder private var failed: some View {
|
||||
// Rectangle()
|
||||
// .foregroundColor(.Material.Background.dark)
|
||||
// .frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
// .overlay {
|
||||
// ZStack {
|
||||
// VStack {
|
||||
// Text(L10n.Attachment.Downloading.retry)
|
||||
// .font(.body3)
|
||||
// .foregroundColor(.Rainbow.red500)
|
||||
// Image(systemName: "exclamationmark.arrow.triangle.2.circlepath")
|
||||
// .font(.body1)
|
||||
// .foregroundColor(.Rainbow.red500)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// .onTapGesture {
|
||||
// if let url = message.attachmentRemotePath {
|
||||
// store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: url)))
|
||||
// } else if message.attachmentLocalName != nil && message.sentError {
|
||||
// store.dispatch(.sharingAction(.retrySharing(messageId: message.id)))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private func progressImageName(_ type: MessageAttachmentType) -> String {
|
||||
// switch type {
|
||||
// case .image:
|
||||
// return "photo"
|
||||
// case .audio:
|
||||
// return "music.note"
|
||||
// case .movie:
|
||||
// return "film"
|
||||
// case .file:
|
||||
// return "doc"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private func thumbnail() -> Image? {
|
||||
// guard let thumbnailPath = message.attachmentThumbnailPath else { return nil }
|
||||
// guard let uiImage = UIImage(contentsOfFile: thumbnailPath.path()) else { return nil }
|
||||
// return Image(uiImage: uiImage)
|
||||
// }
|
||||
// }
|
||||
private struct AttachmentView: View {
|
||||
let message: Message
|
||||
let attachment: Attachment
|
||||
|
||||
var body: some View {
|
||||
if message.status == .error {
|
||||
failed
|
||||
} else {
|
||||
switch attachment.type {
|
||||
case .image:
|
||||
if let thumbnail = thumbnail() {
|
||||
thumbnail
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
} else {
|
||||
placeholder
|
||||
}
|
||||
|
||||
case .video:
|
||||
if let file = attachment.localPath {
|
||||
VideoPlayerView(url: file)
|
||||
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
} else {
|
||||
placeholder
|
||||
}
|
||||
|
||||
case .file:
|
||||
if let file = attachment.localPath {
|
||||
DocumentPreview(url: file)
|
||||
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
} else {
|
||||
placeholder
|
||||
}
|
||||
|
||||
default:
|
||||
placeholder
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private var placeholder: some View {
|
||||
Rectangle()
|
||||
.foregroundColor(.Material.Background.dark)
|
||||
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
.overlay {
|
||||
ZStack {
|
||||
ProgressView()
|
||||
.scaleEffect(1.5)
|
||||
.progressViewStyle(CircularProgressViewStyle(tint: .Material.Elements.active))
|
||||
let imageName = progressImageName(attachment.type ?? .file)
|
||||
Image(systemName: imageName)
|
||||
.font(.body1)
|
||||
.foregroundColor(.Material.Elements.active)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder private var failed: some View {
|
||||
Rectangle()
|
||||
.foregroundColor(.Material.Background.dark)
|
||||
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
.overlay {
|
||||
ZStack {
|
||||
VStack {
|
||||
Text(L10n.Attachment.Downloading.retry)
|
||||
.font(.body3)
|
||||
.foregroundColor(.Rainbow.red500)
|
||||
Image(systemName: "exclamationmark.arrow.triangle.2.circlepath")
|
||||
.font(.body1)
|
||||
.foregroundColor(.Rainbow.red500)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
// if let url = message.attachmentRemotePath {
|
||||
// store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: url)))
|
||||
// } else if message.attachmentLocalName != nil && message.sentError {
|
||||
// store.dispatch(.sharingAction(.retrySharing(messageId: message.id)))
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
private func progressImageName(_ type: AttachmentType) -> String {
|
||||
switch type {
|
||||
case .image:
|
||||
return "photo"
|
||||
case .audio:
|
||||
return "music.note"
|
||||
case .video:
|
||||
return "film"
|
||||
case .file:
|
||||
return "doc"
|
||||
}
|
||||
}
|
||||
|
||||
private func thumbnail() -> Image? {
|
||||
guard let thumbnailPath = attachment.thumbnailPath else { return nil }
|
||||
guard let uiImage = UIImage(contentsOfFile: thumbnailPath.path()) else { return nil }
|
||||
return Image(uiImage: uiImage)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Make video player better!
|
||||
private struct VideoPlayerView: UIViewControllerRepresentable {
|
||||
|
|
|
@ -50,7 +50,7 @@ struct ConversationMessageRow: View {
|
|||
}
|
||||
if value.translation.width <= targetWidth {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.02) {
|
||||
// store.dispatch(.conversationAction(.setReplyText(message.body ?? "")))
|
||||
conversation.replyText = message.body ?? ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue