carousel: switch to media carousel and include video

This commit is contained in:
William Casarin
2023-05-26 10:16:14 -07:00
parent 6214ab8d8f
commit 80fac1903e
4 changed files with 103 additions and 58 deletions

View File

@@ -54,7 +54,7 @@ enum ImageShape {
// MARK: - Image Carousel // MARK: - Image Carousel
struct ImageCarousel: View { struct ImageCarousel: View {
var urls: [URL] var urls: [MediaUrl]
let evid: String let evid: String
@@ -69,8 +69,9 @@ struct ImageCarousel: View {
@State private var firstImageHeight: CGFloat? = nil @State private var firstImageHeight: CGFloat? = nil
@State private var currentImageHeight: CGFloat? @State private var currentImageHeight: CGFloat?
@State private var selectedIndex = 0 @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) _open_sheet = State(initialValue: false)
_current_url = State(initialValue: nil) _current_url = State(initialValue: nil)
_image_fill = State(initialValue: state.previews.lookup_image_meta(evid)) _image_fill = State(initialValue: state.previews.lookup_image_meta(evid))
@@ -112,47 +113,79 @@ struct ImageCarousel: View {
} }
} }
var Images: some View { func Media(geo: GeometryProxy, url: MediaUrl, index: Int) -> some View {
TabView(selection: $selectedIndex) { 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 ForEach(urls.indices, id: \.self) { index in
let url = urls[index]
GeometryReader { geo in GeometryReader { geo in
KFAnimatedImage(url) Media(geo: geo, url: urls[index], index: index)
.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)
} }
} }
} }
@@ -165,14 +198,14 @@ struct ImageCarousel: View {
open_sheet = true open_sheet = true
} }
.onChange(of: selectedIndex) { value in .onChange(of: selectedIndex) { value in
selectedIndex = value selectedIndex = value
} }
.tabViewStyle(PageTabViewStyle()) .tabViewStyle(PageTabViewStyle())
} }
var body: some View { var body: some View {
VStack { VStack {
Images Medias
// This is our custom carousel image indicator // This is our custom carousel image indicator
CarouselDotsView(urls: urls, selectedIndex: $selectedIndex) CarouselDotsView(urls: urls, selectedIndex: $selectedIndex)
@@ -181,8 +214,8 @@ struct ImageCarousel: View {
} }
// MARK: - Custom Carousel // MARK: - Custom Carousel
struct CarouselDotsView: View { struct CarouselDotsView<T>: View {
let urls: [URL] let urls: [T]
@Binding var selectedIndex: Int @Binding var selectedIndex: Int
var body: some View { var body: some View {
@@ -254,7 +287,8 @@ public struct ImageFill {
// MARK: - Preview Provider // MARK: - Preview Provider
struct ImageCarousel_Previews: PreviewProvider { struct ImageCarousel_Previews: PreviewProvider {
static var previews: some View { 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])
} }
} }

View File

@@ -10,10 +10,11 @@ import Kingfisher
struct ImageContainerView: View { struct ImageContainerView: View {
let url: URL? let url: MediaUrl
@State private var image: UIImage? @State private var image: UIImage?
@State private var showShareSheet = false @State private var showShareSheet = false
@State private var video_size: CGSize? = nil
let disable_animation: Bool let disable_animation: Bool
@@ -26,8 +27,7 @@ struct ImageContainerView: View {
} }
} }
var body: some View { func Img(url: URL) -> some View {
KFAnimatedImage(url) KFAnimatedImage(url)
.imageContext(.note, disable_animation: disable_animation) .imageContext(.note, disable_animation: disable_animation)
.configure { view in .configure { view in
@@ -40,12 +40,23 @@ struct ImageContainerView: View {
ShareSheet(activityItems: [url]) 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")! let test_image_url = URL(string: "https://jb55.com/red-me.jpg")!
struct ImageContainerView_Previews: PreviewProvider { struct ImageContainerView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
ImageContainerView(url: test_image_url, disable_animation: false) ImageContainerView(url: .image(test_image_url), disable_animation: false)
} }
} }

View File

@@ -8,8 +8,7 @@
import SwiftUI import SwiftUI
struct ImageView: View { struct ImageView: View {
let urls: [MediaUrl]
let urls: [URL?]
@Environment(\.presentationMode) var presentationMode @Environment(\.presentationMode) var presentationMode
@@ -79,6 +78,7 @@ struct ImageView: View {
struct ImageView_Previews: PreviewProvider { struct ImageView_Previews: PreviewProvider {
static var previews: some View { 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)
} }
} }

View File

@@ -130,11 +130,11 @@ struct NoteContentView: View {
} }
} }
if show_images && artifacts.images.count > 0 { if show_images && artifacts.media.count > 0 {
ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.images) ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.media)
} else if !show_images && artifacts.images.count > 0 { } else if !show_images && artifacts.media.count > 0 {
ZStack { ZStack {
ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.images) ImageCarousel(state: damus_state, evid: event.id, urls: artifacts.media)
Blur() Blur()
.disabled(true) .disabled(true)
} }