Add video preview in message bubble

This commit is contained in:
Benoit Martins 2024-05-21 10:29:22 +02:00
parent 84ad957568
commit 0682489645
4 changed files with 107 additions and 22 deletions

View file

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "play-fill.svg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" fill="#000000" viewBox="0 0 256 256"><path d="M240,128a15.74,15.74,0,0,1-7.6,13.51L88.32,229.65a16,16,0,0,1-16.2.3A15.86,15.86,0,0,1,64,216.13V39.87a15.86,15.86,0,0,1,8.12-13.82,16,16,0,0,1,16.2.3L232.4,114.49A15.74,15.74,0,0,1,240,128Z"></path></svg>

After

Width:  |  Height:  |  Size: 314 B

View file

@ -160,7 +160,7 @@ struct ChatBubbleView: View {
@ViewBuilder
func messageAttachments() -> some View {
if message.attachments.count == 1 {
if message.attachments.first!.type == .image || message.attachments.first!.type == .gif {
if message.attachments.first!.type == .image || message.attachments.first!.type == .gif || message.attachments.first!.type == .video {
let result = imageDimensions(url: message.attachments.first!.full.absoluteString)
ZStack {
Rectangle()
@ -185,12 +185,22 @@ struct ChatBubbleView: View {
)
}
if message.attachments.first!.type == .image {
if message.attachments.first!.type == .image || message.attachments.first!.type == .video {
AsyncImage(url: message.attachments.first!.full) { image in
image
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
ZStack {
image
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
if message.attachments.first!.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 40, height: 40, alignment: .leading)
}
}
} placeholder: {
ProgressView()
}
@ -212,26 +222,34 @@ struct ChatBubbleView: View {
GridItem(.adaptive(minimum: 120), spacing: 1)
], spacing: 3) {
ForEach(message.attachments) { attachment in
if attachment.type == .image || attachment.type == .gif {
ZStack {
Rectangle()
.fill(Color(.white))
.frame(width: 120, height: 120)
AsyncImage(url: attachment.full) { image in
ZStack {
Rectangle()
.fill(Color(.white))
.frame(width: 120, height: 120)
AsyncImage(url: attachment.full) { image in
ZStack {
image
.resizable()
.interpolation(.medium)
.aspectRatio(contentMode: .fill)
} placeholder: {
ProgressView()
if attachment.type == .video {
Image("play-fill")
.renderingMode(.template)
.resizable()
.foregroundStyle(.white)
.frame(width: 40, height: 40, alignment: .leading)
}
}
.id(UUID())
.layoutPriority(-1)
} placeholder: {
ProgressView()
}
.clipShape(RoundedRectangle(cornerRadius: 4))
.clipped()
.id(UUID())
.layoutPriority(-1)
}
.clipShape(RoundedRectangle(cornerRadius: 4))
.clipped()
}
}
.frame(

View file

@ -127,9 +127,28 @@ class ConversationViewModel: ObservableObject {
if content.filePath == nil || content.filePath!.isEmpty {
self.downloadContent(chatMessage: eventLog.chatMessage!, content: content)
} else {
if URL(string: self.getNewFilePath(name: content.name ?? "")) != nil {
let attachment = Attachment(id: UUID().uuidString, url: URL(string: self.getNewFilePath(name: content.name ?? ""))!, type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image)
attachmentList.append(attachment)
if content.type != "video" {
let path = URL(string: self.getNewFilePath(name: content.name ?? ""))
if path != nil {
let attachment =
Attachment(
id: UUID().uuidString,
url: path!,
type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image
)
attachmentList.append(attachment)
}
} else if content.type == "video" {
let path = URL(string: self.generateThumbnail(name: content.name ?? ""))
if path != nil {
let attachment =
Attachment(
id: UUID().uuidString,
url: path!,
type: .video
)
attachmentList.append(attachment)
}
}
}
}
@ -483,6 +502,32 @@ class ConversationViewModel: ObservableObject {
return "file://" + Factory.Instance.getDownloadDir(context: nil) + (name.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "")
}
func generateThumbnail(name: String) -> String {
do {
let path = URL(string: "file://" + Factory.Instance.getDownloadDir(context: nil) + (name.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? ""))
let asset = AVURLAsset(url: path!, options: nil)
let imgGenerator = AVAssetImageGenerator(asset: asset)
imgGenerator.appliesPreferredTrackTransform = true
let cgImage = try imgGenerator.copyCGImage(at: CMTimeMake(value: 0, timescale: 1), actualTime: nil)
let thumbnail = UIImage(cgImage: cgImage)
guard let data = thumbnail.jpegData(compressionQuality: 1) ?? thumbnail.pngData() else {
return ""
}
let urlName = URL(string: "file://" + Factory.Instance.getDownloadDir(context: nil) + "preview_" + (name.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? "") + ".png")
if urlName != nil {
let decodedData: () = try data.write(to: urlName!)
}
return urlName!.absoluteString
} catch let error {
print("*** Error generating thumbnail: \(error.localizedDescription)")
return ""
}
}
func getMessageTime(startDate: time_t) -> String {
let timeInterval = TimeInterval(startDate)