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:
committed by
Daniel D’Aquino
parent
fa7740948b
commit
3986308638
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user