Commit
This commit is contained in:
76
Sources/PediFoods/Views/Main/StoreDetailSupport.swift
Normal file
76
Sources/PediFoods/Views/Main/StoreDetailSupport.swift
Normal file
@@ -0,0 +1,76 @@
|
||||
import SwiftUI
|
||||
|
||||
struct CategoryHeaderOffsetPreferenceKey: PreferenceKey {
|
||||
static let defaultValue: [String: CGFloat] = [:]
|
||||
|
||||
static func reduce(value: inout [String: CGFloat], nextValue: () -> [String: CGFloat]) {
|
||||
value.merge(nextValue(), uniquingKeysWith: { _, new in new })
|
||||
}
|
||||
}
|
||||
|
||||
enum StoreDetailScrollCoordinateSpace {
|
||||
static let name = "store-detail-scroll"
|
||||
}
|
||||
|
||||
struct ScrollOffsetPreferenceKey: PreferenceKey {
|
||||
static let defaultValue: CGFloat = 0
|
||||
|
||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
|
||||
value = nextValue()
|
||||
}
|
||||
}
|
||||
|
||||
struct ScrollOffsetReader: View {
|
||||
@Binding var offsetY: CGFloat
|
||||
@State private var baseline: CGFloat? = nil
|
||||
|
||||
var body: some View {
|
||||
Color.clear
|
||||
.frame(height: 0)
|
||||
.background(
|
||||
GeometryReader { geometry in
|
||||
Color.clear.preference(
|
||||
key: ScrollOffsetPreferenceKey.self,
|
||||
value: geometry.frame(in: .named(StoreDetailScrollCoordinateSpace.name)).minY
|
||||
)
|
||||
}
|
||||
)
|
||||
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { minY in
|
||||
if baseline == nil { baseline = minY }
|
||||
let offset = (baseline ?? 0) - minY
|
||||
if abs(offsetY - offset) > 0.5 {
|
||||
offsetY = offset
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AsyncStoreImage: View {
|
||||
let imageURL: String?
|
||||
var fallbackImageName: String = "placeholder-product"
|
||||
var fitMode: ImageFitMode = .fill
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
CachedRemoteImage(imageURL: imageURL, fitMode: fitMode) {
|
||||
fallback
|
||||
}
|
||||
// Lock the scaledToFill image to the actually proposed box.
|
||||
// Without this, a wide/landscape source image's fill-scaled
|
||||
// ideal width can exceed the box and balloon the parent
|
||||
// ZStack's ideal width, pushing sibling content off-screen.
|
||||
.frame(width: geometry.size.width, height: geometry.size.height)
|
||||
.clipped()
|
||||
}
|
||||
.background(AppColors.brandSoft)
|
||||
}
|
||||
|
||||
private var fallback: some View {
|
||||
Image(fallbackImageName)
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user