Improve display logic for images
Changelog-Fixed: Reduce chopping of images Closes: #869
This commit is contained in:
committed by
William Casarin
parent
f236ea52e1
commit
b14858b4b1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user