diff --git a/damus/Components/ImageCarousel.swift b/damus/Components/ImageCarousel.swift index ee146565..afad2665 100644 --- a/damus/Components/ImageCarousel.swift +++ b/damus/Components/ImageCarousel.swift @@ -54,7 +54,7 @@ enum ImageShape { // MARK: - Image Carousel struct ImageCarousel: View { - var urls: [URL] + var urls: [MediaUrl] let evid: String @@ -69,8 +69,9 @@ struct ImageCarousel: View { @State private var firstImageHeight: CGFloat? = nil @State private var currentImageHeight: CGFloat? @State private var selectedIndex = 0 + @State private var video_size: CGSize? = nil - init(state: DamusState, evid: String, urls: [URL]) { + init(state: DamusState, evid: String, urls: [MediaUrl]) { _open_sheet = State(initialValue: false) _current_url = State(initialValue: nil) _image_fill = State(initialValue: state.previews.lookup_image_meta(evid)) @@ -112,47 +113,79 @@ struct ImageCarousel: View { } } - var Images: some View { - TabView(selection: $selectedIndex) { + func Media(geo: GeometryProxy, url: MediaUrl, index: Int) -> some View { + Group { + switch url { + case .image(let url): + Img(geo: geo, url: url, index: index) + .onTapGesture { + open_sheet = true + } + case .video(let url): + DamusVideoPlayer(url: url, video_size: $video_size) + .onTapGesture { + print("video tap") + } + .onChange(of: video_size) { size in + guard image_fill == nil, let size else { + return + } + let fill = ImageFill.calculate_image_fill(geo_size: geo.size, img_size: size, maxHeight: maxHeight, fillHeight: fillHeight) + image_fill = fill + state.previews.cache_image_meta(evid: evid, image_fill: fill) + + if index == 0 { + firstImageHeight = fill.height + } + } + } + } + } + + func Img(geo: GeometryProxy, url: URL, index: Int) -> some View { + KFAnimatedImage(url) + .callbackQueue(.dispatch(.global(qos:.background))) + .backgroundDecode(true) + .imageContext(.note, disable_animation: state.settings.disable_animation) + .image_fade(duration: 0.25) + .cancelOnDisappear(true) + .configure { view in + view.framePreloadCount = 3 + } + .imageFill(for: geo.size, max: maxHeight, fill: fillHeight) { fill in + state.previews.cache_image_meta(evid: evid, image_fill: fill) + // blur hash can be discarded when we have the url + // NOTE: this is the wrong place for this... we need to remove + // it when the image is loaded in memory. This may happen + // earlier than this (by the preloader, etc) + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + state.events.lookup_img_metadata(url: url)?.state = .not_needed + } + image_fill = fill + if index == 0 { + firstImageHeight = fill.height + //maxHeight = firstImageHeight ?? maxHeight + } else { + //maxHeight = firstImageHeight ?? fill.height + } + } + .background { + Placeholder(url: url, geo_size: geo.size, num_urls: urls.count) + } + .aspectRatio(contentMode: filling ? .fill : .fit) + .tabItem { + Text(url.absoluteString) + } + .id(url.absoluteString) + .padding(0) + + } + + var Medias: some View { + TabView { ForEach(urls.indices, id: \.self) { index in - let url = urls[index] GeometryReader { geo in - KFAnimatedImage(url) - .callbackQueue(.dispatch(.global(qos:.background))) - .backgroundDecode(true) - .imageContext(.note, disable_animation: state.settings.disable_animation) - .image_fade(duration: 0.25) - .cancelOnDisappear(true) - .configure { view in - view.framePreloadCount = 3 - } - .imageFill(for: geo.size, max: maxHeight, fill: fillHeight) { fill in - state.previews.cache_image_meta(evid: evid, image_fill: fill) - // blur hash can be discarded when we have the url - // NOTE: this is the wrong place for this... we need to remove - // it when the image is loaded in memory. This may happen - // earlier than this (by the preloader, etc) - DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { - state.events.lookup_img_metadata(url: url)?.state = .not_needed - } - image_fill = fill - if index == 0 { - firstImageHeight = fill.height - //maxHeight = firstImageHeight ?? maxHeight - } else { - //maxHeight = firstImageHeight ?? fill.height - } - } - .background { - Placeholder(url: url, geo_size: geo.size, num_urls: urls.count) - } - .aspectRatio(contentMode: filling ? .fill : .fit) - .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) - .tabItem { - Text(url.absoluteString) - } - .id(url.absoluteString) - .padding(0) + Media(geo: geo, url: urls[index], index: index) } } } @@ -165,14 +198,14 @@ struct ImageCarousel: View { open_sheet = true } .onChange(of: selectedIndex) { value in - selectedIndex = value - } + selectedIndex = value + } .tabViewStyle(PageTabViewStyle()) } var body: some View { VStack { - Images + Medias // This is our custom carousel image indicator CarouselDotsView(urls: urls, selectedIndex: $selectedIndex) @@ -181,8 +214,8 @@ struct ImageCarousel: View { } // MARK: - Custom Carousel -struct CarouselDotsView: View { - let urls: [URL] +struct CarouselDotsView: View { + let urls: [T] @Binding var selectedIndex: Int var body: some View { @@ -254,7 +287,8 @@ public struct ImageFill { // MARK: - Preview Provider struct ImageCarousel_Previews: PreviewProvider { static var previews: some View { - ImageCarousel(state: test_damus_state(), evid: "evid", urls: [URL(string: "https://jb55.com/red-me.jpg")!,URL(string: "https://jb55.com/red-me.jpg")!]) + let url: MediaUrl = .image(URL(string: "https://jb55.com/red-me.jpg")!) + ImageCarousel(state: test_damus_state(), evid: "evid", urls: [url, url]) } } diff --git a/damus/Views/Images/ImageContainerView.swift b/damus/Views/Images/ImageContainerView.swift index 9c35471a..5ebd55de 100644 --- a/damus/Views/Images/ImageContainerView.swift +++ b/damus/Views/Images/ImageContainerView.swift @@ -10,10 +10,11 @@ import Kingfisher struct ImageContainerView: View { - let url: URL? + let url: MediaUrl @State private var image: UIImage? @State private var showShareSheet = false + @State private var video_size: CGSize? = nil let disable_animation: Bool @@ -26,8 +27,7 @@ struct ImageContainerView: View { } } - var body: some View { - + func Img(url: URL) -> some View { KFAnimatedImage(url) .imageContext(.note, disable_animation: disable_animation) .configure { view in @@ -40,12 +40,23 @@ struct ImageContainerView: View { ShareSheet(activityItems: [url]) } } + + var body: some View { + Group { + switch url { + case .image(let url): + Img(url: url) + case .video(let url): + DamusVideoPlayer(url: url, video_size: $video_size) + } + } + } } let test_image_url = URL(string: "https://jb55.com/red-me.jpg")! struct ImageContainerView_Previews: PreviewProvider { static var previews: some View { - ImageContainerView(url: test_image_url, disable_animation: false) + ImageContainerView(url: .image(test_image_url), disable_animation: false) } } diff --git a/damus/Views/Images/ImageView.swift b/damus/Views/Images/ImageView.swift index c06d0c32..0ca00d1d 100644 --- a/damus/Views/Images/ImageView.swift +++ b/damus/Views/Images/ImageView.swift @@ -8,8 +8,7 @@ import SwiftUI struct ImageView: View { - - let urls: [URL?] + let urls: [MediaUrl] @Environment(\.presentationMode) var presentationMode @@ -79,6 +78,7 @@ struct ImageView: View { struct ImageView_Previews: PreviewProvider { static var previews: some View { - ImageView(urls: [URL(string: "https://jb55.com/red-me.jpg")], disable_animation: false) + let url: MediaUrl = .image(URL(string: "https://jb55.com/red-me.jpg")!) + ImageView(urls: [url], disable_animation: false) } } diff --git a/damus/Views/NoteContentView.swift b/damus/Views/NoteContentView.swift index a9e5dd1e..cde2c789 100644 --- a/damus/Views/NoteContentView.swift +++ b/damus/Views/NoteContentView.swift @@ -130,11 +130,11 @@ struct NoteContentView: View { } } - if show_images && artifacts.images.count > 0 { - ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.images) - } else if !show_images && artifacts.images.count > 0 { + if show_images && artifacts.media.count > 0 { + ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.media) + } else if !show_images && artifacts.media.count > 0 { ZStack { - ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.images) + ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.media) Blur() .disabled(true) }