commit b14858b4b1f7ee3bab800cb710963c0027f4a362
parent f236ea52e126b2d73347cafc22c0f428f00a2dca
Author: mainvolume <sina@mainvolume.com>
Date: Wed, 5 Apr 2023 11:47:08 +0200
Improve display logic for images
Changelog-Fixed: Reduce chopping of images
Closes: #869
Diffstat:
1 file changed, 66 insertions(+), 51 deletions(-)
diff --git a/damus/Components/ImageCarousel.swift b/damus/Components/ImageCarousel.swift
@@ -45,12 +45,12 @@ struct ImageCarousel: View {
let evid: String
let previews: PreviewCache
- let minHeight: CGFloat = 150
- let maxHeight: CGFloat = 500
@State private var open_sheet: Bool = false
@State private var current_url: URL? = nil
@State private var image_fill: ImageFill? = nil
+ @State private var fillHeight: CGFloat = 350
+ @State private var maxHeight: CGFloat = UIScreen.main.bounds.height * 0.85
init(previews: PreviewCache, evid: String, urls: [URL]) {
_open_sheet = State(initialValue: false)
@@ -65,6 +65,10 @@ struct ImageCarousel: View {
image_fill?.filling == true
}
+ var height: CGFloat {
+ image_fill?.height ?? 0
+ }
+
var body: some View {
TabView {
ForEach(urls, id: \.absoluteString) { url in
@@ -73,23 +77,17 @@ struct ImageCarousel: View {
.overlay {
GeometryReader { geo in
KFAnimatedImage(url)
+ .callbackQueue(.dispatch(.global(qos:.background)))
+ .backgroundDecode(true)
.imageContext(.note)
.cancelOnDisappear(true)
.configure { view in
view.framePreloadCount = 3
}
- .imageModifier({ img in
- let img_size = img.size
- let is_animated = img.kf.imageFrameCount != nil
-
- DispatchQueue.main.async {
- let geo_size = geo.size
- let fill = calculate_image_fill(geo_size: geo_size, img_size: img_size, is_animated: is_animated, maxHeight: maxHeight, minHeight: minHeight)
-
- self.previews.cache_image_meta(evid: evid, image_fill: fill)
- self.image_fill = fill
- }
- })
+ .imageFill(for: geo.size, max: maxHeight, fill: fillHeight) { fill in
+ previews.cache_image_meta(evid: evid, image_fill: fill)
+ image_fill = fill
+ }
.aspectRatio(contentMode: filling ? .fill : .fit)
.tabItem {
Text(url.absoluteString)
@@ -102,7 +100,7 @@ struct ImageCarousel: View {
.fullScreenCover(isPresented: $open_sheet) {
ImageView(urls: urls)
}
- .frame(height: image_fill?.height ?? 0)
+ .frame(height: height)
.onTapGesture {
open_sheet = true
}
@@ -110,48 +108,65 @@ struct ImageCarousel: View {
}
}
-func determine_image_shape(_ size: CGSize) -> ImageShape {
- guard size.height > 0 else {
- return .unknown
- }
- let imageRatio = size.width / size.height
- switch imageRatio {
- case 1.0: return .square
- case ..<1.0: return .portrait
- case 1.0...: return .landscape
- default: return .unknown
+// MARK: - Image Modifier
+extension KFOptionSetter {
+ /// Sets a block to get image size
+ ///
+ /// - Parameter block: The block which is used to read the image object.
+ /// - Returns: `Self` value after read size
+ public func imageFill(for size: CGSize, max: CGFloat, fill: CGFloat, block: @escaping (ImageFill) throws -> Void) -> Self {
+ let modifier = AnyImageModifier { image -> KFCrossPlatformImage in
+ let img_size = image.size
+ let geo_size = size
+ let fill = ImageFill.calculate_image_fill(geo_size: geo_size,
+ img_size: img_size,
+ maxHeight: max,
+ fillHeight: fill)
+ DispatchQueue.main.async { [block, fill] in
+ try? block(fill)
+ }
+ return image
+ }
+ options.imageModifier = modifier
+ return self
}
}
-struct ImageFill {
+
+public struct ImageFill {
let filling: Bool?
let height: CGFloat
-}
-
-func calculate_image_fill(geo_size: CGSize, img_size: CGSize, is_animated: Bool, maxHeight: CGFloat, minHeight: CGFloat) -> ImageFill {
- let shape = determine_image_shape(img_size)
+
+
+ static func determine_image_shape(_ size: CGSize) -> ImageShape {
+ guard size.height > 0 else {
+ return .unknown
+ }
+ let imageRatio = size.width / size.height
+ switch imageRatio {
+ case 1.0: return .square
+ case ..<1.0: return .portrait
+ case 1.0...: return .landscape
+ default: return .unknown
+ }
+ }
+
+ static func calculate_image_fill(geo_size: CGSize, img_size: CGSize, maxHeight: CGFloat, fillHeight: CGFloat) -> ImageFill {
+ let shape = determine_image_shape(img_size)
- let xfactor = geo_size.width / img_size.width
- let scaled = img_size.height * xfactor
- let yfactor = maxHeight / scaled
- // calculate scaled image height
- // set scale factor and constrain images to minimum 150
- // and animations to scaled factor for dynamic size adjustment
- switch shape {
- case .portrait:
- let filling = yfactor <= 1.0
- let height = filling ? maxHeight : max(scaled, minHeight)
- return ImageFill(filling: filling, height: height)
- case .square:
- let height = max(min(maxHeight, scaled), minHeight)
- return ImageFill(filling: nil, height: height)
- case .landscape:
- let filling = scaled > maxHeight || xfactor < 1.0
- let height = is_animated ? scaled : filling ? min(maxHeight, scaled) : max(scaled, minHeight)
- return ImageFill(filling: filling, height: height)
- case .unknown:
- let height = max(img_size.height, minHeight)
- return ImageFill(filling: nil, height: height)
+ let xfactor = geo_size.width / img_size.width
+ let scaled = img_size.height * xfactor
+ // calculate scaled image height
+ // set scale factor and constrain images to minimum 150
+ // and animations to scaled factor for dynamic size adjustment
+ switch shape {
+ case .portrait, .landscape:
+ let filling = scaled > maxHeight
+ let height = filling ? fillHeight : scaled
+ return ImageFill(filling: filling, height: height)
+ case .square, .unknown:
+ return ImageFill(filling: nil, height: scaled)
+ }
}
}