Render Gif and video files while composing posts

Changelog-Added: Render Gif and video files while composing posts
Signed-off-by: Swift Coder <scoder1747@gmail.com>
This commit is contained in:
Swift Coder
2024-12-11 13:38:59 -05:00
committed by Daniel D’Aquino
parent fa7740948b
commit 3986308638

View File

@@ -6,7 +6,8 @@
//
import SwiftUI
import AVFoundation
import AVKit
import Kingfisher
enum NostrPostResult {
case post(NostrPost)
@@ -609,38 +610,79 @@ struct PVImageCarouselView: View {
var body: some View {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(media.map({$0.representingImage}), id: \.self) { image in
ZStack(alignment: .topTrailing) {
Image(uiImage: image)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: media.count == 1 ? deviceWidth*0.8 : 250, height: media.count == 1 ? 400 : 250)
ForEach(media.indices, id: \.self) { index in
ZStack(alignment: .topLeading) {
if isSupportedVideo(url: media[index].uploadedURL) {
VideoPlayer(player: configurePlayer(with: media[index].localURL))
.frame(width: media.count == 1 ? deviceWidth * 0.8 : 250, height: media.count == 1 ? 400 : 250)
.cornerRadius(10)
.padding()
.contextMenu {
if let uploadedURL = media.first(where: { $0.representingImage == image })?.uploadedURL {
Button(action: {
UIPasteboard.general.string = uploadedURL.absoluteString
}) {
Label(NSLocalizedString("Copy URL", comment: "Label for button in context menu to copy URL of the selected uploaded media asset."), image: "copy")
}
.contextMenu { contextMenuContent(for: media[index]) }
} else if is_animated_image(url: media[index].uploadedURL) {
KFAnimatedImage(media[index].uploadedURL)
.imageContext(.note, disable_animation: false)
.configure { view in
view.framePreloadCount = 3
}
.frame(width: media.count == 1 ? deviceWidth * 0.8 : 250, height: media.count == 1 ? 400 : 250)
.cornerRadius(10)
.padding()
.contextMenu { contextMenuContent(for: media[index]) }
} else {
Image(uiImage: media[index].representingImage)
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: media.count == 1 ? deviceWidth * 0.8 : 250, height: media.count == 1 ? 400 : 250)
.cornerRadius(10)
.padding()
.contextMenu { contextMenuContent(for: media[index]) }
}
VStack { // Set spacing to 0 to remove the gap between items
Image("close-circle")
.foregroundColor(.white)
.padding(20)
.shadow(radius: 5)
.onTapGesture {
if let index = media.map({$0.representingImage}).firstIndex(of: image) {
media.remove(at: index)
media.remove(at: index) // Direct removal using index
}
if isSupportedVideo(url: media[index].uploadedURL) {
Spacer()
Image(systemName: "video")
.foregroundColor(.white)
.padding(10)
.shadow(radius: 5)
.opacity(0.6)
}
}
.padding(.bottom, 35)
}
}
}
.padding()
}
}
// Helper Function for Context Menu
@ViewBuilder
private func contextMenuContent(for mediaItem: UploadedMedia) -> some View {
Button(action: {
UIPasteboard.general.string = mediaItem.uploadedURL.absoluteString
}) {
Label(
NSLocalizedString("Copy URL", comment: "Copy URL of the selected uploaded media asset."),
systemImage: "doc.on.doc"
)
}
}
private func configurePlayer(with url: URL) -> AVPlayer {
let player = AVPlayer(url: url)
player.allowsExternalPlayback = false
player.usesExternalPlaybackWhileExternalScreenIsActive = false
return player
}
}
fileprivate func getImage(media: MediaUpload) -> UIImage {
@@ -813,3 +855,14 @@ func build_post(state: DamusState, post: NSMutableAttributedString, action: Post
return NostrPost(content: content, kind: .text, tags: tags)
}
func isSupportedVideo(url: URL?) -> Bool {
guard let url = url else { return false }
let fileExtension = url.pathExtension.lowercased()
let supportedUTIs = AVURLAsset.audiovisualTypes().map { $0.rawValue }
return supportedUTIs.contains { utiString in
if let utType = UTType(utiString), let fileUTType = UTType(filenameExtension: fileExtension) {
return fileUTType.conforms(to: utType)
}
return false
}
}