diff --git a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailSupport.swift b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailSupport.swift index 7145a0e..c07efd1 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailSupport.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailSupport.swift @@ -22,6 +22,7 @@ struct ScrollOffsetPreferenceKey: PreferenceKey { struct ScrollOffsetReader: View { @Binding var offsetY: CGFloat + @State private var baseline: CGFloat? = nil var body: some View { Color.clear @@ -35,9 +36,10 @@ struct ScrollOffsetReader: View { } ) .onPreferenceChange(ScrollOffsetPreferenceKey.self) { minY in - let normalizedOffset = max(0, -minY) - if abs(offsetY - normalizedOffset) > 0.5 { - offsetY = normalizedOffset + if baseline == nil { baseline = minY } + let offset = max(0, (baseline ?? 0) - minY) + if abs(offsetY - offset) > 0.5 { + offsetY = offset } } } diff --git a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Components.swift b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Components.swift index e426626..41b03ee 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Components.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Components.swift @@ -195,10 +195,15 @@ extension StoreDetailView { } } - func categoryTabs(proxy: ScrollViewProxy, topExtension: CGFloat = 0, stickyProgress: CGFloat = 0) -> some View { - let chipPaddingH: CGFloat = 10 + 6 * stickyProgress - let chipPaddingV: CGFloat = 4 + 5 * stickyProgress - let containerPaddingV: CGFloat = 2 + 8 * stickyProgress + func categoryTabs(proxy: ScrollViewProxy, isPinned: Bool = false) -> some View { + let safeTop: CGFloat = { + guard isPinned else { return 0 } + #if canImport(UIKit) + return UIDevice.appSafeAreaTop + #else + return 0 + #endif + }() return ScrollView(.horizontal, showsIndicators: false) { HStack(spacing: 10) { @@ -217,8 +222,8 @@ extension StoreDetailView { Text(category.name) .font(AppTypography.heading3) .foregroundStyle(active ? AppColors.textInverse : AppColors.textMuted) - .padding(.horizontal, chipPaddingH) - .padding(.vertical, chipPaddingV) + .padding(.horizontal, 16) + .padding(.vertical, 9) .background(active ? AppColors.primary : AppColors.surface) .clipShape(Capsule()) } @@ -226,16 +231,11 @@ extension StoreDetailView { } } .padding(.horizontal, 16) - .padding(.vertical, containerPaddingV) + .padding(.vertical, 10) } + .padding(.top, safeTop) .background(AppColors.backgroundLight) - .overlay(alignment: .top) { - AppColors.backgroundLight - .frame(height: topExtension) - .frame(maxWidth: .infinity) - .offset(y: -topExtension) - .allowsHitTesting(false) - } + .animation(.easeInOut(duration: 0.15), value: isPinned) } func productCard(_ item: StoreCatalogListItem, in category: StoreCatalogCategory) -> some View { diff --git a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift index b0dba94..1cd504e 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView+Logic.swift @@ -51,8 +51,8 @@ extension StoreDetailView { } var deliveryValueLabel: String { - if let minOrder = info?.minOrder { - return formatCurrency(minOrder) + if let fee = storeDeliveryFee { + return formatCurrency(fee) } return "R$ --" } diff --git a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView.swift b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView.swift index 8180a3f..5b96dd9 100644 --- a/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView.swift +++ b/pedi-foods/Sources/PediFoods/Views/Main/StoreDetailView.swift @@ -34,15 +34,10 @@ struct StoreDetailView: View { @State var didLoad = false @State var categoryHeaderOffsets: [String: CGFloat] = [:] @State var isProgrammaticCategoryScroll = false - @State var scrollOffset: CGFloat = 0 - var safeAreaTop: CGFloat { - #if canImport(UIKit) - return UIDevice.appSafeAreaTop - #else - return 0.0 - #endif - } @State var isFavoriteRequestInFlight = false + @State var scrollOffset: CGFloat = 0 + + var isCategoryTabsPinned: Bool { scrollOffset >= topSectionHeight } let cardTopInset: CGFloat = 180 let summaryCardBaseHeight: CGFloat = 212 @@ -52,48 +47,23 @@ struct StoreDetailView: View { var body: some View { ScrollViewReader { proxy in - let stickyProgress = categoryTabsStickyProgress(safeTop: safeAreaTop) - - ZStack(alignment: .top) { - AppColors.backgroundLight.ignoresSafeArea() - - ScrollView(showsIndicators: false) { - LazyVStack(spacing: 0) { - topSection - Section { - sectionedProducts - } header: { - categoryTabs(proxy: proxy, topExtension: 0, stickyProgress: 1) - .opacity(Double(1 - stickyProgress)) - } - } - .background( - GeometryReader { geometry in - Color.clear.preference( - key: ScrollOffsetPreferenceKey.self, - value: geometry.frame(in: .named(StoreDetailScrollCoordinateSpace.name)).minY - ) - } - ) - } - .coordinateSpace(name: StoreDetailScrollCoordinateSpace.name) - .onPreferenceChange(ScrollOffsetPreferenceKey.self) { minY in - let normalizedOffset = max(0, -minY) - if abs(scrollOffset - normalizedOffset) > 0.5 { - scrollOffset = normalizedOffset + ScrollView(showsIndicators: false) { + ScrollOffsetReader(offsetY: $scrollOffset) + LazyVStack(spacing: 0, pinnedViews: [.sectionHeaders]) { + topSection + Section { + sectionedProducts + } header: { + categoryTabs(proxy: proxy, isPinned: isCategoryTabsPinned) } } - .refreshable { - await loadStoreData(forceRefresh: true) - } - .ignoresSafeArea(edges: .top) - - categoryTabs(proxy: proxy, topExtension: stickyProgress * safeAreaTop, stickyProgress: 1) - .opacity(Double(stickyProgress)) - .allowsHitTesting(stickyProgress > 0.1) - .offset(y: safeAreaTop) + } + .coordinateSpace(name: StoreDetailScrollCoordinateSpace.name) + .refreshable { + await loadStoreData(forceRefresh: true) } .ignoresSafeArea(edges: .top) + .background(AppColors.backgroundLight) .saturation(isStoreOpen ? 1 : 0) } .navigationBarBackButtonHidden(true)