feat(store): stretch cover image on pull-down overscroll

- Remove max(0) clamp in ScrollOffsetReader to allow negative values during bounce
- Add stretchAmount computed var (max(0, -scrollOffset))
- Hero image frame grows by stretchAmount and offsets upward on overscroll
- isCategoryTabsPinned still uses max(0, scrollOffset) via >= check
This commit is contained in:
Daniel Arantes Loverde
2026-06-03 15:01:23 -03:00
parent f51319b486
commit d2189bb701
3 changed files with 4 additions and 2 deletions

View File

@@ -37,7 +37,7 @@ struct ScrollOffsetReader: View {
) )
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { minY in .onPreferenceChange(ScrollOffsetPreferenceKey.self) { minY in
if baseline == nil { baseline = minY } if baseline == nil { baseline = minY }
let offset = max(0, (baseline ?? 0) - minY) let offset = (baseline ?? 0) - minY
if abs(offsetY - offset) > 0.5 { if abs(offsetY - offset) > 0.5 {
offsetY = offset offsetY = offset
} }

View File

@@ -26,7 +26,7 @@ extension StoreDetailView {
var heroSection: some View { var heroSection: some View {
ZStack(alignment: .top) { ZStack(alignment: .top) {
AsyncStoreImage(imageURL: resolvedURL(storeCoverURL)) AsyncStoreImage(imageURL: resolvedURL(storeCoverURL))
.frame(height: topSectionHeight) .frame(height: topSectionHeight + stretchAmount)
.overlay( .overlay(
LinearGradient( LinearGradient(
colors: [Color.black.opacity(0.32), Color.black.opacity(0.05)], colors: [Color.black.opacity(0.32), Color.black.opacity(0.05)],
@@ -34,6 +34,7 @@ extension StoreDetailView {
endPoint: .bottom endPoint: .bottom
) )
) )
.offset(y: -stretchAmount)
.ignoresSafeArea(.container, edges: .top) .ignoresSafeArea(.container, edges: .top)
VStack(spacing: 0) { VStack(spacing: 0) {

View File

@@ -38,6 +38,7 @@ struct StoreDetailView: View {
@State var scrollOffset: CGFloat = 0 @State var scrollOffset: CGFloat = 0
var isCategoryTabsPinned: Bool { scrollOffset >= topSectionHeight } var isCategoryTabsPinned: Bool { scrollOffset >= topSectionHeight }
var stretchAmount: CGFloat { max(0, -scrollOffset) }
let cardTopInset: CGFloat = 180 let cardTopInset: CGFloat = 180
let summaryCardBaseHeight: CGFloat = 212 let summaryCardBaseHeight: CGFloat = 212