mirror of
https://gitlab.linphone.org/BC/public/linphone-iphone.git
synced 2026-01-17 02:58:07 +00:00
Add video preview in message bubble
This commit is contained in:
parent
84ad957568
commit
0682489645
4 changed files with 107 additions and 22 deletions
21
Linphone/Assets.xcassets/play-fill.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/play-fill.imageset/Contents.json
vendored
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
1
Linphone/Assets.xcassets/play-fill.imageset/play-fill.svg
vendored
Normal file
1
Linphone/Assets.xcassets/play-fill.imageset/play-fill.svg
vendored
Normal 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 |
|
|
@ -160,7 +160,7 @@ struct ChatBubbleView: View {
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
func messageAttachments() -> some View {
|
func messageAttachments() -> some View {
|
||||||
if message.attachments.count == 1 {
|
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)
|
let result = imageDimensions(url: message.attachments.first!.full.absoluteString)
|
||||||
ZStack {
|
ZStack {
|
||||||
Rectangle()
|
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
|
AsyncImage(url: message.attachments.first!.full) { image in
|
||||||
image
|
ZStack {
|
||||||
.resizable()
|
image
|
||||||
.interpolation(.medium)
|
.resizable()
|
||||||
.aspectRatio(contentMode: .fill)
|
.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: {
|
} placeholder: {
|
||||||
ProgressView()
|
ProgressView()
|
||||||
}
|
}
|
||||||
|
|
@ -212,26 +222,34 @@ struct ChatBubbleView: View {
|
||||||
GridItem(.adaptive(minimum: 120), spacing: 1)
|
GridItem(.adaptive(minimum: 120), spacing: 1)
|
||||||
], spacing: 3) {
|
], spacing: 3) {
|
||||||
ForEach(message.attachments) { attachment in
|
ForEach(message.attachments) { attachment in
|
||||||
if attachment.type == .image || attachment.type == .gif {
|
ZStack {
|
||||||
ZStack {
|
Rectangle()
|
||||||
Rectangle()
|
.fill(Color(.white))
|
||||||
.fill(Color(.white))
|
.frame(width: 120, height: 120)
|
||||||
.frame(width: 120, height: 120)
|
|
||||||
|
AsyncImage(url: attachment.full) { image in
|
||||||
AsyncImage(url: attachment.full) { image in
|
ZStack {
|
||||||
image
|
image
|
||||||
.resizable()
|
.resizable()
|
||||||
.interpolation(.medium)
|
.interpolation(.medium)
|
||||||
.aspectRatio(contentMode: .fill)
|
.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())
|
} placeholder: {
|
||||||
.layoutPriority(-1)
|
ProgressView()
|
||||||
}
|
}
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 4))
|
.id(UUID())
|
||||||
.clipped()
|
.layoutPriority(-1)
|
||||||
}
|
}
|
||||||
|
.clipShape(RoundedRectangle(cornerRadius: 4))
|
||||||
|
.clipped()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.frame(
|
.frame(
|
||||||
|
|
|
||||||
|
|
@ -127,9 +127,28 @@ class ConversationViewModel: ObservableObject {
|
||||||
if content.filePath == nil || content.filePath!.isEmpty {
|
if content.filePath == nil || content.filePath!.isEmpty {
|
||||||
self.downloadContent(chatMessage: eventLog.chatMessage!, content: content)
|
self.downloadContent(chatMessage: eventLog.chatMessage!, content: content)
|
||||||
} else {
|
} else {
|
||||||
if URL(string: self.getNewFilePath(name: content.name ?? "")) != nil {
|
if content.type != "video" {
|
||||||
let attachment = Attachment(id: UUID().uuidString, url: URL(string: self.getNewFilePath(name: content.name ?? ""))!, type: (content.name?.lowercased().hasSuffix("gif"))! ? .gif : .image)
|
let path = URL(string: self.getNewFilePath(name: content.name ?? ""))
|
||||||
attachmentList.append(attachment)
|
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) ?? "")
|
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 {
|
func getMessageTime(startDate: time_t) -> String {
|
||||||
let timeInterval = TimeInterval(startDate)
|
let timeInterval = TimeInterval(startDate)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue