Fix media list rendering in chat bubble

This commit is contained in:
Benoit Martins 2024-11-22 16:57:32 +01:00 committed by QuentinArguillere
parent f51e92adee
commit 1763f21359
6 changed files with 627 additions and 430 deletions

View file

@ -123,6 +123,9 @@
},
"%lld selected participants" : {
},
"%lld%%" : {
},
"+" : {

View file

@ -538,68 +538,48 @@ struct ChatBubbleView: View {
if eventLogMessage.message.attachments.first!.type == .image || eventLogMessage.message.attachments.first!.type == .video {
if #available(iOS 16.0, *) {
AsyncImage(url: eventLogMessage.message.attachments.first!.thumbnail) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
ZStack {
image
CachedAsyncImage(
url: eventLogMessage.message.attachments.first!.thumbnail,
placeholder: ProgressView(),
onImageTapped: {
selectedURLAttachment = eventLogMessage.message.attachments.first!.full
})
.overlay(
Group {
if eventLogMessage.message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
if eventLogMessage.message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 40, height: 40, alignment: .leading)
}
.foregroundStyle(.white)
.frame(width: 40, height: 40)
}
case .failure:
Image("image-broken")
@unknown default:
EmptyView()
}
}
)
.layoutPriority(-1)
.clipShape(RoundedRectangle(cornerRadius: 4))
.onTapGesture {
selectedURLAttachment = eventLogMessage.message.attachments.first!.full
}
} else {
AsyncImage(url: eventLogMessage.message.attachments.first!.thumbnail) { phase in
switch phase {
case .empty:
ProgressView()
case .success(let image):
ZStack {
image
CachedAsyncImage(
url: eventLogMessage.message.attachments.first!.thumbnail,
placeholder: ProgressView(),
onImageTapped: {
selectedURLAttachment = eventLogMessage.message.attachments.first!.full
})
.overlay(
Group {
if eventLogMessage.message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
if eventLogMessage.message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 40, height: 40, alignment: .leading)
}
.foregroundStyle(.white)
.frame(width: 40, height: 40)
}
case .failure:
Image("image-broken")
@unknown default:
EmptyView()
}
}
)
.layoutPriority(-1)
.clipShape(RoundedRectangle(cornerRadius: 4))
.id(UUID())
.onTapGesture {
selectedURLAttachment = eventLogMessage.message.attachments.first!.full
}
}
} else if eventLogMessage.message.attachments.first!.type == .gif {
if #available(iOS 16.0, *) {
@ -633,22 +613,29 @@ struct ChatBubbleView: View {
} else {
HStack {
VStack {
Image(getImageOfType(type: eventLogMessage.message.attachments.first!.type))
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c700)
.frame(width: 60, height: 60, alignment: .leading)
if conversationViewModel.attachmentTransferInProgress != nil && conversationViewModel.attachmentTransferInProgress!.id == eventLogMessage.message.attachments.first!.id {
CircularProgressView(progress: Double(conversationViewModel.attachmentTransferInProgress!.transferProgressIndication) / 100.0)
.frame(width: 80, height: 80)
} else {
Image(getImageOfType(type: eventLogMessage.message.attachments.first!.type))
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c700)
.frame(width: 60, height: 60, alignment: .leading)
}
}
.frame(width: 100, height: 100)
.background(Color.grayMain2c200)
.onTapGesture {
if eventLogMessage.message.attachments.first!.type == .fileTransfer && !eventLogMessage.message.isFileTransferInProgress {
if eventLogMessage.message.attachments.first!.type == .fileTransfer && eventLogMessage.message.attachments.first!.transferProgressIndication == -1 {
CoreContext.shared.doOnCoreQueue { _ in
conversationViewModel.downloadContent(
chatMessage: eventLogMessage.eventModel.eventLog.chatMessage!,
content: eventLogMessage.eventModel.eventLog.chatMessage!.contents.first!
)
}
} else {
selectedURLAttachment = eventLogMessage.message.attachments.first!.full
}
}
@ -676,121 +663,117 @@ struct ChatBubbleView: View {
}
} else if eventLogMessage.message.attachments.count > 1 {
let sizeCard = ((geometryProxy.size.width - 150)/2)-2
let columns = [
GridItem(.adaptive(minimum: sizeCard), spacing: 1)]
let columns = [GridItem(.adaptive(minimum: sizeCard), spacing: 1)]
LazyVStack {
VStack {
LazyVGrid(columns: columns) {
ForEach(eventLogMessage.message.attachments, id: \.id) { attachment in
if attachment.type == .image || attachment.type == .gif
|| attachment.type == .video {
ForEach(eventLogMessage.message.attachments.filter({ $0.type == .image || $0.type == .gif
|| $0.type == .video }), id: \.id) { attachment in
ZStack {
Rectangle()
.fill(Color(.white))
.frame(width: sizeCard, height: sizeCard)
if #available(iOS 16.0, *) {
AsyncImage(url: attachment.thumbnail) { image in
ZStack {
image
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
CachedAsyncImage(
url: attachment.thumbnail,
placeholder: ProgressView(),
onImageTapped: {
selectedURLAttachment = attachment.full
})
.overlay(
Group {
if attachment.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 40, height: 40, alignment: .leading)
.frame(width: 40, height: 40)
}
}
} placeholder: {
ProgressView()
}
)
.layoutPriority(-1)
.onTapGesture {
selectedURLAttachment = attachment.full
}
} else {
AsyncImage(url: attachment.thumbnail) { image in
ZStack {
image
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
CachedAsyncImage(
url: attachment.thumbnail,
placeholder: ProgressView(),
onImageTapped: {
selectedURLAttachment = attachment.full
})
.overlay(
Group {
if attachment.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 40, height: 40, alignment: .leading)
.frame(width: 40, height: 40)
}
}
} placeholder: {
ProgressView()
}
)
.id(UUID())
.layoutPriority(-1)
.onTapGesture {
selectedURLAttachment = attachment.full
}
}
}
.clipShape(RoundedRectangle(cornerRadius: 4))
.contentShape(Rectangle())
}
}
}
ForEach(eventLogMessage.message.attachments, id: \.id) { attachment in
if !(attachment.type == .image || attachment.type == .gif
|| attachment.type == .video) {
HStack {
VStack {
ForEach(eventLogMessage.message.attachments.filter({ $0.type != .image && $0.type != .gif
&& $0.type != .video }), id: \.id) { attachment in
HStack {
VStack {
if conversationViewModel.attachmentTransferInProgress != nil && conversationViewModel.attachmentTransferInProgress!.id == attachment.id {
CircularProgressView(progress: Double(conversationViewModel.attachmentTransferInProgress!.transferProgressIndication) / 100.0)
.frame(width: 80, height: 80)
} else {
Image(getImageOfType(type: attachment.type))
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c700)
.frame(width: 60, height: 60, alignment: .leading)
}
.frame(width: 100, height: 100)
.background(Color.grayMain2c200)
.onTapGesture {
if attachment.type == .fileTransfer && !eventLogMessage.message.isFileTransferInProgress {
if let content = eventLogMessage.eventModel.eventLog.chatMessage!.contents.first(where: {$0.filePath == attachment.full.absoluteString}) {
CoreContext.shared.doOnCoreQueue { _ in
conversationViewModel.downloadContent(
chatMessage: eventLogMessage.eventModel.eventLog.chatMessage!,
content: content
)
}
}
.frame(width: 100, height: 100)
.background(Color.grayMain2c200)
.onTapGesture {
if attachment.type == .fileTransfer && attachment.transferProgressIndication == -1 {
CoreContext.shared.doOnCoreQueue { _ in
if let content = eventLogMessage.eventModel.eventLog.chatMessage!.contents.first(where: {$0.name == attachment.name}) {
conversationViewModel.downloadContent(
chatMessage: eventLogMessage.eventModel.eventLog.chatMessage!,
content: content
)
}
}
} else {
selectedURLAttachment = attachment.full
}
}
VStack {
Text(attachment.name)
.foregroundStyle(Color.grayMain2c700)
.default_text_style_600(styleSize: 14)
.truncationMode(.middle)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
VStack {
Text(attachment.name)
.foregroundStyle(Color.grayMain2c700)
.default_text_style_600(styleSize: 14)
.truncationMode(.middle)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
Text(attachment.size.formatBytes())
.default_text_style_300(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
}
.padding(.horizontal, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
.background(.white)
.clipShape(RoundedRectangle(cornerRadius: 10))
.onTapGesture {
selectedURLAttachment = attachment.full
Text(attachment.size.formatBytes())
.default_text_style_300(styleSize: 14)
.frame(maxWidth: .infinity, alignment: .leading)
.lineLimit(1)
}
.padding(.horizontal, 10)
.frame(maxWidth: .infinity, alignment: .leading)
}
.background(.white)
.clipShape(RoundedRectangle(cornerRadius: 10))
.onTapGesture {
selectedURLAttachment = attachment.full
}
}
}
@ -1083,6 +1066,82 @@ struct CustomSlider: View {
}
}
struct CircularProgressView: View {
var progress: Double
var body: some View {
ZStack {
Circle()
.stroke(Color(.systemGray4), lineWidth: 5)
Circle()
.trim(from: 0, to: progress)
.stroke(
Color.orangeMain500,
style: StrokeStyle(lineWidth: 5, lineCap: .round))
.rotationEffect(Angle(degrees: -90))
.animation(.easeInOut(duration: 0.5), value: progress)
.overlay(
Text("\(Int(progress * 100))%")
.font(.system(size: 15, weight: .bold, design: .rounded))
.foregroundColor(Color.orangeMain500)
)
}
.padding()
}
}
class ImageCache {
static let shared = NSCache<NSURL, UIImage>()
}
struct CachedAsyncImage<Placeholder: View>: View {
let url: URL
let placeholder: Placeholder
let onImageTapped: (() -> Void)?
@State private var image: UIImage?
var body: some View {
ZStack {
if let image = image {
Image(uiImage: image)
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
.onTapGesture {
onImageTapped?()
}
} else {
placeholder
.onAppear {
loadImage()
}
}
}
}
private func loadImage() {
if let cachedImage = ImageCache.shared.object(forKey: url as NSURL) {
self.image = cachedImage
return
}
Task {
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let downloadedImage = UIImage(data: data) {
ImageCache.shared.setObject(downloadedImage, forKey: url as NSURL)
await MainActor.run {
self.image = downloadedImage
}
}
} catch {
print("Error loading image: \(error.localizedDescription)")
}
}
}
}
/*
#Preview {
ChatBubbleView(conversationViewModel: ConversationViewModel(), index: 0)

View file

@ -757,139 +757,115 @@ struct ConversationFragment: View {
if conversationViewModel.selectedMessage != nil && conversationViewModel.displayedConversation != nil {
let iconSize = ((geometry.size.width - (conversationViewModel.displayedConversation!.isGroup ? 43 : 10) - 10) / 6) - 30
VStack {
Spacer()
ScrollView {
VStack {
HStack {
if conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
Spacer()
VStack {
HStack {
if conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
HStack {
Button {
conversationViewModel.sendReaction(emoji: "👍")
} label: {
Text("👍")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "👍" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "❤️")
} label: {
Text("❤️")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "❤️" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "😂")
} label: {
Text("😂")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😂" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "😮")
} label: {
Text("😮")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😮" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "😢")
} label: {
Text("😢")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😢" ? Color.gray200 : .white)
.cornerRadius(10)
/*
Button {
} label: {
Image("plus-circle")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: iconSize > 50 ? 50 : iconSize, height: iconSize > 50 ? 50 : iconSize, alignment: .leading)
}
.padding(.trailing, 5)
*/
}
.padding(.vertical, 5)
.padding(.horizontal, 10)
.background(.white)
.cornerRadius(20)
if !conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 10)
.padding(.leading, conversationViewModel.displayedConversation!.isGroup ? 43 : 0)
.shadow(color: .black.opacity(0.1), radius: 10)
ChatBubbleView(conversationViewModel: conversationViewModel, eventLogMessage: conversationViewModel.selectedMessage!, geometryProxy: geometry)
.padding(.horizontal, 10)
.padding(.vertical, 1)
.shadow(color: .black.opacity(0.1), radius: 10)
HStack {
Button {
conversationViewModel.sendReaction(emoji: "👍")
} label: {
Text("👍")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "👍" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "❤️")
} label: {
Text("❤️")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "❤️" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "😂")
} label: {
Text("😂")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😂" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "😮")
} label: {
Text("😮")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😮" ? Color.gray200 : .white)
.cornerRadius(10)
Button {
conversationViewModel.sendReaction(emoji: "😢")
} label: {
Text("😢")
.default_text_style(styleSize: iconSize > 50 ? 50 : iconSize)
}
.padding(.horizontal, 8)
.background(conversationViewModel.selectedMessage?.message.ownReaction == "😢" ? Color.gray200 : .white)
.cornerRadius(10)
/*
Button {
} label: {
Image("plus-circle")
.renderingMode(.template)
.resizable()
.foregroundStyle(Color.grayMain2c500)
.frame(width: iconSize > 50 ? 50 : iconSize, height: iconSize > 50 ? 50 : iconSize, alignment: .leading)
}
.padding(.trailing, 5)
*/
}
.padding(.vertical, 5)
.padding(.horizontal, 10)
.background(.white)
.cornerRadius(20)
if !conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 10)
.padding(.leading, conversationViewModel.displayedConversation!.isGroup ? 43 : 0)
.shadow(color: .black.opacity(0.1), radius: 10)
ChatBubbleView(conversationViewModel: conversationViewModel, eventLogMessage: conversationViewModel.selectedMessage!, geometryProxy: geometry)
.padding(.horizontal, 10)
.padding(.vertical, 1)
.shadow(color: .black.opacity(0.1), radius: 10)
HStack {
if conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
VStack {
Button {
let indexMessage = conversationViewModel.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.id == conversationViewModel.selectedMessage!.message.id})
conversationViewModel.selectedMessage = nil
conversationViewModel.replyToMessage(index: indexMessage ?? 0)
} label: {
HStack {
Text("menu_reply_to_chat_message")
.default_text_style(styleSize: 15)
Spacer()
Image("reply")
.resizable()
.frame(width: 20, height: 20, alignment: .leading)
}
.padding(.vertical, 5)
.padding(.horizontal, 20)
if conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
Divider()
if !conversationViewModel.selectedMessage!.message.text.isEmpty {
VStack {
Button {
UIPasteboard.general.setValue(
conversationViewModel.selectedMessage?.message.text ?? "Error_message_not_available",
forPasteboardType: UTType.plainText.identifier
)
ToastViewModel.shared.toastMessage = "Success_message_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
let indexMessage = conversationViewModel.conversationMessagesSection[0].rows.firstIndex(where: {$0.message.id == conversationViewModel.selectedMessage!.message.id})
conversationViewModel.selectedMessage = nil
conversationViewModel.replyToMessage(index: indexMessage ?? 0)
} label: {
HStack {
Text("menu_copy_chat_message")
Text("menu_reply_to_chat_message")
.default_text_style(styleSize: 15)
Spacer()
Image("copy")
Image("reply")
.resizable()
.frame(width: 20, height: 20, alignment: .leading)
}
@ -898,65 +874,93 @@ struct ConversationFragment: View {
}
Divider()
if !conversationViewModel.selectedMessage!.message.text.isEmpty {
Button {
UIPasteboard.general.setValue(
conversationViewModel.selectedMessage?.message.text ?? "Error_message_not_available",
forPasteboardType: UTType.plainText.identifier
)
ToastViewModel.shared.toastMessage = "Success_message_copied_into_clipboard"
ToastViewModel.shared.displayToast = true
conversationViewModel.selectedMessage = nil
} label: {
HStack {
Text("menu_copy_chat_message")
.default_text_style(styleSize: 15)
Spacer()
Image("copy")
.resizable()
.frame(width: 20, height: 20, alignment: .leading)
}
.padding(.vertical, 5)
.padding(.horizontal, 20)
}
Divider()
}
Button {
conversationForwardMessageViewModel.initConversationsLists(convsList: conversationsListViewModel.conversationsListTmp)
conversationForwardMessageViewModel.selectedMessage = conversationViewModel.selectedMessage
conversationViewModel.selectedMessage = nil
withAnimation {
isShowConversationForwardMessageFragment = true
}
} label: {
HStack {
Text("menu_forward_chat_message")
.default_text_style(styleSize: 15)
Spacer()
Image("forward")
.resizable()
.frame(width: 20, height: 20, alignment: .leading)
}
.padding(.vertical, 5)
.padding(.horizontal, 20)
}
Divider()
Button {
conversationViewModel.deleteMessage()
} label: {
HStack {
Text("menu_delete_selected_item")
.foregroundStyle(.red)
.default_text_style(styleSize: 15)
Spacer()
Image("trash-simple-red")
.renderingMode(.template)
.resizable()
.foregroundStyle(.red)
.frame(width: 20, height: 20, alignment: .leading)
}
.padding(.vertical, 5)
.padding(.horizontal, 20)
}
}
.frame(maxWidth: geometry.size.width / 1.5)
.padding(.vertical, 8)
.background(.white)
.cornerRadius(20)
Button {
conversationForwardMessageViewModel.initConversationsLists(convsList: conversationsListViewModel.conversationsListTmp)
conversationForwardMessageViewModel.selectedMessage = conversationViewModel.selectedMessage
conversationViewModel.selectedMessage = nil
withAnimation {
isShowConversationForwardMessageFragment = true
}
} label: {
HStack {
Text("menu_forward_chat_message")
.default_text_style(styleSize: 15)
Spacer()
Image("forward")
.resizable()
.frame(width: 20, height: 20, alignment: .leading)
}
.padding(.vertical, 5)
.padding(.horizontal, 20)
}
Divider()
Button {
conversationViewModel.deleteMessage()
} label: {
HStack {
Text("menu_delete_selected_item")
.foregroundStyle(.red)
.default_text_style(styleSize: 15)
Spacer()
Image("trash-simple-red")
.renderingMode(.template)
.resizable()
.foregroundStyle(.red)
.frame(width: 20, height: 20, alignment: .leading)
}
.padding(.vertical, 5)
.padding(.horizontal, 20)
if !conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
}
.frame(maxWidth: geometry.size.width / 1.5)
.padding(.vertical, 8)
.background(.white)
.cornerRadius(20)
if !conversationViewModel.selectedMessage!.message.isOutgoing {
Spacer()
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 10)
.padding(.bottom, 20)
.padding(.leading, conversationViewModel.displayedConversation!.isGroup ? 43 : 0)
.shadow(color: .black.opacity(0.1), radius: 10)
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 10)
.padding(.bottom, 20)
.padding(.leading, conversationViewModel.displayedConversation!.isGroup ? 43 : 0)
.shadow(color: .black.opacity(0.1), radius: 10)
}
.frame(maxWidth: .infinity)
.frame(minHeight: geometry.size.height)
}
.frame(maxWidth: .infinity)
.background(.gray.opacity(0.1))
.onTapGesture {
withAnimation {

View file

@ -85,8 +85,9 @@ public struct Attachment: Codable, Identifiable, Hashable {
public let type: AttachmentType
public let duration: Int
public let size: Int
public var transferProgressIndication: Int
public init(id: String, name: String, thumbnail: URL, full: URL, type: AttachmentType, duration: Int = 0, size: Int = 0) {
public init(id: String, name: String, thumbnail: URL, full: URL, type: AttachmentType, duration: Int = 0, size: Int = 0, transferProgressIndication: Int = 0) {
self.id = id
self.name = name
self.thumbnail = thumbnail
@ -94,9 +95,16 @@ public struct Attachment: Codable, Identifiable, Hashable {
self.type = type
self.duration = duration
self.size = size
self.transferProgressIndication = transferProgressIndication
}
public init(id: String, name: String, url: URL, type: AttachmentType, duration: Int = 0, size: Int = 0) {
self.init(id: id, name: name, thumbnail: url, full: url, type: type, duration: duration, size: size)
public init(id: String, name: String, url: URL, type: AttachmentType, duration: Int = 0, size: Int = 0, transferProgressIndication: Int = 0) {
self.init(id: id, name: name, thumbnail: url, full: url, type: type, duration: duration, size: size, transferProgressIndication: transferProgressIndication)
}
}
extension Attachment: Equatable {
public static func == (lhs: Attachment, rhs: Attachment) -> Bool {
lhs.id == rhs.id && lhs.transferProgressIndication == rhs.transferProgressIndication
}
}

View file

@ -88,8 +88,6 @@ public struct Message: Identifiable, Hashable {
public var isIcalendar: Bool
public var messageConferenceInfo: MessageConferenceInfo?
public var isFileTransferInProgress: Bool
public init(
id: String,
appData: String = "",
@ -111,8 +109,7 @@ public struct Message: Identifiable, Hashable {
ephemeralExpireTime: Int = 0,
ephemeralLifetime: Int = 0,
isIcalendar: Bool = false,
messageConferenceInfo: MessageConferenceInfo? = nil,
isFileTransferInProgress: Bool = false
messageConferenceInfo: MessageConferenceInfo? = nil
) {
self.id = id
self.appData = appData
@ -135,7 +132,6 @@ public struct Message: Identifiable, Hashable {
self.ephemeralLifetime = ephemeralLifetime
self.isIcalendar = isIcalendar
self.messageConferenceInfo = messageConferenceInfo
self.isFileTransferInProgress = isFileTransferInProgress
}
public static func makeMessage(
@ -188,7 +184,7 @@ extension Message {
extension Message: Equatable {
public static func == (lhs: Message, rhs: Message) -> Bool {
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isFirstMessage == rhs.isFirstMessage && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions && lhs.ephemeralExpireTime == rhs.ephemeralExpireTime
lhs.id == rhs.id && lhs.status == rhs.status && lhs.isFirstMessage == rhs.isFirstMessage && lhs.ownReaction == rhs.ownReaction && lhs.reactions == rhs.reactions && lhs.ephemeralExpireTime == rhs.ephemeralExpireTime && lhs.attachments == rhs.attachments
}
}

View file

@ -104,6 +104,7 @@ class ConversationViewModel: ObservableObject {
@Published var progress: Double = 0.0
@Published var attachments: [Attachment] = []
@Published var attachmentTransferInProgress: Attachment?
struct SheetCategory: Identifiable {
let id = UUID()
@ -165,115 +166,231 @@ class ConversationViewModel: ObservableObject {
}
func addChatMessageDelegate(message: ChatMessage) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
if self.displayedConversation != nil {
var statusTmp: Message.Status? = .sending
switch message.state {
case .InProgress:
statusTmp = .sending
case .Delivered:
statusTmp = .sent
case .DeliveredToUser:
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
if self.displayedConversation != nil {
var statusTmp: Message.Status? = .sending
switch message.state {
case .InProgress:
statusTmp = .sending
case .Delivered:
statusTmp = .sent
case .DeliveredToUser:
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
if !self.conversationMessagesSection.isEmpty && !self.conversationMessagesSection[0].rows.isEmpty {
if let indexMessageEventLogId = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId.isEmpty && $0.eventModel.eventLog.chatMessage != nil ? $0.eventModel.eventLog.chatMessage!.messageId == message.messageId : false}) {
self.conversationMessagesSection[0].rows[indexMessageEventLogId].eventModel.eventLogId = message.messageId
}
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
if !self.conversationMessagesSection.isEmpty && !self.conversationMessagesSection[0].rows.isEmpty {
if let indexMessageEventLogId = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId.isEmpty && $0.eventModel.eventLog.chatMessage != nil ? $0.eventModel.eventLog.chatMessage!.messageId == message.messageId : false}) {
self.conversationMessagesSection[0].rows[indexMessageEventLogId].eventModel.eventLogId = message.messageId
}
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId}) {
if indexMessage < self.conversationMessagesSection[0].rows.count {
if self.conversationMessagesSection[0].rows[indexMessage].message.status != statusTmp {
DispatchQueue.main.async {
self.conversationMessagesSection[0].rows[indexMessage].message.status = statusTmp ?? .error
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId}) {
if indexMessage < self.conversationMessagesSection[0].rows.count {
if self.conversationMessagesSection[0].rows[indexMessage].message.status != statusTmp {
DispatchQueue.main.async {
self.conversationMessagesSection[0].rows[indexMessage].message.status = statusTmp ?? .error
self.conversationMessagesSection[0].rows[indexMessage].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
} else {
DispatchQueue.main.async {
if indexMessage < self.conversationMessagesSection[0].rows.count {
self.conversationMessagesSection[0].rows[indexMessage].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
} else {
DispatchQueue.main.async {
if indexMessage < self.conversationMessagesSection[0].rows.count {
self.conversationMessagesSection[0].rows[indexMessage].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
}
}
}
}
self.coreContext.doOnCoreQueue { _ in
let chatMessageDelegate = ChatMessageDelegateStub(onMsgStateChanged: { (message: ChatMessage, msgState: ChatMessage.State) in
var statusTmp: Message.Status?
switch message.state {
case .InProgress:
statusTmp = .sending
case .Delivered:
statusTmp = .sent
case .DeliveredToUser:
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
if msgState == .FileTransferDone {
message.contents.forEach { content in
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId}) {
if let contentIndex = self.conversationMessagesSection[0].rows[indexMessage].message.attachments.firstIndex(where: {$0.name == content.name && $0.full.pathExtension.isEmpty && $0.full.absoluteString != content.filePath}) {
let filePathSep = content.filePath!.components(separatedBy: "/Library/Images/")
let contentTmp = self.conversationMessagesSection[0].rows[indexMessage].message.attachments[contentIndex]
if let pathThumbnail = content.type == "video" ? URL(string: self.generateThumbnail(name: content.name ?? "")) : contentTmp.thumbnail {
if let path = URL(string: self.getNewFilePath(name: filePathSep[1])) {
if path != contentTmp.full {
var typeTmp: AttachmentType = .other
switch content.type {
case "image":
typeTmp = (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
case "audio":
typeTmp = content.isVoiceRecording ? .voiceRecording : .audio
case "application":
typeTmp = content.subtype.lowercased() == "pdf" ? .pdf : .other
case "text":
typeTmp = .text
case "video":
typeTmp = .video
default:
typeTmp = .other
}
let newAttachment = Attachment(
id: UUID().uuidString,
name: content.name ?? contentTmp.name,
thumbnail: content.type == "video" ? pathThumbnail : path,
full: path,
type: typeTmp,
duration: contentTmp.duration,
size: contentTmp.size,
transferProgressIndication: 100
)
DispatchQueue.main.async {
self.conversationMessagesSection[0].rows[indexMessage].message.attachments[contentIndex] = newAttachment
}
}
}
}
}
}
}
}
}
self.coreContext.doOnCoreQueue { _ in
let chatMessageDelegate = ChatMessageDelegateStub(onMsgStateChanged: { (message: ChatMessage, msgState: ChatMessage.State) in
var statusTmp: Message.Status?
switch message.state {
case .InProgress:
statusTmp = .sending
case .Delivered:
statusTmp = .sent
case .DeliveredToUser:
statusTmp = .received
case .Displayed:
statusTmp = .read
case .NotDelivered:
statusTmp = .error
default:
statusTmp = .sending
}
if let indexMessageEventLogId = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId.isEmpty && $0.eventModel.eventLog.chatMessage != nil ? $0.eventModel.eventLog.chatMessage!.messageId == message.messageId : false}) {
self.conversationMessagesSection[0].rows[indexMessageEventLogId].eventModel.eventLogId = message.messageId
}
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.status = statusTmp ?? .error
}
}
}, onNewMessageReaction: { (message: ChatMessage, _: ChatMessageReaction) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
})
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
}, onReactionRemoved: { (message: ChatMessage, _: Address) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
})
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
}, onEphemeralMessageTimerStarted: { (message: ChatMessage) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
if let indexMessageEventLogId = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId.isEmpty && $0.eventModel.eventLog.chatMessage != nil ? $0.eventModel.eventLog.chatMessage!.messageId == message.messageId : false}) {
self.conversationMessagesSection[0].rows[indexMessageEventLogId].eventModel.eventLogId = message.messageId
}
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.status = statusTmp ?? .error
}
}
}, onNewMessageReaction: { (message: ChatMessage, _: ChatMessageReaction) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
})
self.chatMessageDelegateHolders.append(ChatMessageDelegateHolder(message: message, delegate: chatMessageDelegate))
}
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
}, onReactionRemoved: { (message: ChatMessage, _: Address) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
var reactionsTmp: [String] = []
message.reactions.forEach({ chatMessageReaction in
reactionsTmp.append(chatMessageReaction.body)
})
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.reactions = reactionsTmp
}
}
}, onFileTransferProgressIndication: { (message: ChatMessage, content: Content, offset: Int, total: Int) in
if let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId}) {
let filePathSep = content.filePath!.components(separatedBy: "/Library/Images/")
let path = URL(string: self.getNewFilePath(name: filePathSep[1]))
if let contentTmp = self.conversationMessagesSection[0].rows[indexMessage].message.attachments.first(where: {$0.full == path}) {
DispatchQueue.main.async {
self.attachmentTransferInProgress = contentTmp
self.attachmentTransferInProgress!.transferProgressIndication = ((offset * 100) / total)
}
if ((offset * 100) / total) >= 100 {
DispatchQueue.main.async {
self.attachmentTransferInProgress = nil
}
}
/*
if ((offset * 100) / total) >= 100 {
var typeTmp: AttachmentType = .other
switch content.type {
case "image":
typeTmp = (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
case "audio":
typeTmp = content.isVoiceRecording ? .voiceRecording : .audio
case "application":
typeTmp = content.subtype.lowercased() == "pdf" ? .pdf : .other
case "text":
typeTmp = .text
case "video":
typeTmp = .video
default:
typeTmp = .other
}
if let pathThumbnail = content.type == "video" ? URL(string: self.generateThumbnail(name: content.name ?? "")) : contentTmp.thumbnail {
if content.filePath != nil {
let filePathSep = content.filePath!.components(separatedBy: "/Library/Images/")
if let path = URL(string: self.getNewFilePath(name: filePathSep[1])) {
let newAttachment = Attachment(
id: UUID().uuidString,
name: content.name ?? contentTmp.name,
thumbnail: content.type == "video" ? pathThumbnail : path,
full: path,
type: typeTmp,
duration: contentTmp.duration,
size: contentTmp.size,
transferProgressIndication: 100
)
if let contentIndex = self.conversationMessagesSection[0].rows[indexMessage].message.attachments.firstIndex(where: {$0.full == path}) {
DispatchQueue.main.async {
print("attachmentattachment ----------------")
print("attachmentattachment ---------------- \(content.name ?? "")")
print("attachmentattachment ---------------- \(filePathSep[1])")
print("attachmentattachment ----------------")
self.conversationMessagesSection[0].rows[indexMessage].message.attachments[contentIndex] = newAttachment
}
}
}
}
}
}
*/
}
}
}, onEphemeralMessageTimerStarted: { (message: ChatMessage) in
let indexMessage = self.conversationMessagesSection[0].rows.firstIndex(where: {$0.eventModel.eventLogId == message.messageId})
let ephemeralExpireTimeTmp = message.ephemeralExpireTime
DispatchQueue.main.async {
if indexMessage != nil {
self.conversationMessagesSection[0].rows[indexMessage!].message.ephemeralExpireTime = ephemeralExpireTimeTmp
}
}
})
self.chatMessageDelegateHolders.append(ChatMessageDelegateHolder(message: message, delegate: chatMessageDelegate))
}
}
}
@ -425,7 +542,8 @@ class ConversationViewModel: ObservableObject {
name: content.name!,
url: path!,
type: .fileTransfer,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -458,7 +576,8 @@ class ConversationViewModel: ObservableObject {
url: path!,
type: typeTmp,
duration: typeTmp == .voiceRecording ? content.fileDuration : 0,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -481,7 +600,8 @@ class ConversationViewModel: ObservableObject {
thumbnail: pathThumbnail!,
full: path!,
type: .video,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -595,8 +715,7 @@ class ConversationViewModel: ObservableObject {
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false,
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil,
isFileTransferInProgress: eventLog.chatMessage!.isFileTransferInProgress
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil
)
)
)
@ -648,7 +767,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil && !eventLog.chatMessage!.contents.isEmpty {
eventLog.chatMessage!.contents.forEach { content in
if content.isText {
if content.isText && content.name == nil {
contentText = content.utf8Text ?? ""
} else if content.name != nil && !content.name!.isEmpty {
if content.filePath == nil || content.filePath!.isEmpty {
@ -662,7 +781,8 @@ class ConversationViewModel: ObservableObject {
name: content.name!,
url: path!,
type: .fileTransfer,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -694,7 +814,8 @@ class ConversationViewModel: ObservableObject {
url: path!,
type: typeTmp,
duration: typeTmp == . voiceRecording ? content.fileDuration : 0,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -717,7 +838,8 @@ class ConversationViewModel: ObservableObject {
thumbnail: pathThumbnail!,
full: path!,
type: .video,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -831,8 +953,7 @@ class ConversationViewModel: ObservableObject {
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false,
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil,
isFileTransferInProgress: eventLog.chatMessage!.isFileTransferInProgress
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil
)
), at: 0
)
@ -882,7 +1003,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil && !eventLog.chatMessage!.contents.isEmpty {
eventLog.chatMessage!.contents.forEach { content in
if content.isText {
if content.isText && content.name == nil {
contentText = content.utf8Text ?? ""
} else {
if content.filePath == nil || content.filePath!.isEmpty {
@ -896,7 +1017,8 @@ class ConversationViewModel: ObservableObject {
name: content.name ?? "???",
url: path!,
type: .fileTransfer,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name ?? "???")"
attachmentList.append(attachment)
@ -905,6 +1027,7 @@ class ConversationViewModel: ObservableObject {
if content.type != "video" {
let filePathSep = content.filePath!.components(separatedBy: "/Library/Images/")
let path = URL(string: self.getNewFilePath(name: filePathSep[1]))
var typeTmp: AttachmentType = .other
switch content.type {
@ -928,7 +1051,8 @@ class ConversationViewModel: ObservableObject {
url: path!,
type: typeTmp,
duration: typeTmp == . voiceRecording ? content.fileDuration : 0,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -951,7 +1075,8 @@ class ConversationViewModel: ObservableObject {
thumbnail: pathThumbnail!,
full: path!,
type: .video,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -1059,6 +1184,7 @@ class ConversationViewModel: ObservableObject {
}
if eventLog.chatMessage != nil {
let message = EventLogMessage(
eventModel: EventModel(eventLog: eventLog),
message: Message(
@ -1080,8 +1206,7 @@ class ConversationViewModel: ObservableObject {
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false,
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil,
isFileTransferInProgress: eventLog.chatMessage!.isFileTransferInProgress
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil
)
)
@ -1194,7 +1319,7 @@ class ConversationViewModel: ObservableObject {
if eventLog.chatMessage != nil && !eventLog.chatMessage!.contents.isEmpty {
eventLog.chatMessage!.contents.forEach { content in
if content.isText {
if content.isText && content.name == nil {
contentText = content.utf8Text ?? ""
} else if content.name != nil && !content.name!.isEmpty {
if content.filePath == nil || content.filePath!.isEmpty {
@ -1208,7 +1333,8 @@ class ConversationViewModel: ObservableObject {
name: content.name!,
url: path!,
type: .fileTransfer,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -1240,7 +1366,8 @@ class ConversationViewModel: ObservableObject {
url: path!,
type: typeTmp,
duration: typeTmp == . voiceRecording ? content.fileDuration : 0,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -1263,7 +1390,8 @@ class ConversationViewModel: ObservableObject {
thumbnail: pathThumbnail!,
full: path!,
type: .video,
size: content.fileSize
size: content.fileSize,
transferProgressIndication: content.filePath != nil && !content.filePath!.isEmpty ? 100 : -1
)
attachmentNameList += ", \(content.name!)"
attachmentList.append(attachment)
@ -1377,8 +1505,7 @@ class ConversationViewModel: ObservableObject {
ephemeralExpireTime: eventLog.chatMessage?.ephemeralExpireTime ?? 0,
ephemeralLifetime: eventLog.chatMessage?.ephemeralLifetime ?? 0,
isIcalendar: eventLog.chatMessage?.contents.first?.isIcalendar ?? false,
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil,
isFileTransferInProgress: eventLog.chatMessage!.isFileTransferInProgress
messageConferenceInfo: eventLog.chatMessage != nil && eventLog.chatMessage!.contents.first != nil && eventLog.chatMessage!.contents.first!.isIcalendar == true ? self.parseConferenceInvite(content: eventLog.chatMessage!.contents.first!) : nil
)
), at: 0
)
@ -1624,7 +1751,7 @@ class ConversationViewModel: ObservableObject {
func downloadContent(chatMessage: ChatMessage, content: Content) {
// Log.debug("[ConversationViewModel] Starting downloading content for file \(model.fileName)")
if self.displayedConversation != nil {
if !chatMessage.isFileTransferInProgress && (content.filePath == nil || content.filePath!.isEmpty) {
if content.filePath == nil || content.filePath!.isEmpty {
if let contentName = content.name {
// let isImage = FileUtil.isExtensionImage(path: contentName)
var file = FileUtil.sharedContainerUrl().appendingPathComponent("Library/Images").absoluteString + (contentName.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "")