diff --git a/Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/SelectedTreatmentView.swift b/Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/SelectedTreatmentView.swift index 360103a4..feda1339 100644 --- a/Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/SelectedTreatmentView.swift +++ b/Cherrish-iOS/Cherrish-iOS/Presentation/Feature/Calendar/Treatment/Components/SelectedTreatmentView.swift @@ -21,6 +21,10 @@ struct SelectedTreatmentView: View { return contentHeight + 24.adjustedH } + @State private var topGlobalY: CGFloat = .zero + @State private var initialTopGlobalY: CGFloat? = nil + @State private var bottomOffsetY: CGFloat = .zero + var body: some View { VStack(spacing: 0) { VStack(spacing: 0) { @@ -46,24 +50,86 @@ struct SelectedTreatmentView: View { x: 0, y: -5 ) - ScrollView(.vertical, showsIndicators: false) { - VStack(spacing: spacing) { - ForEach(selectedTreatments, id: \.id) { treatment in - TreatmentRowView( - displayMode: .summary, - treatmentEntity: treatment, - isSelected: .constant(true), - action: { removeTreatment(treatment) } - ) - .frame(height: itemHeight) + ZStack { + ScrollView(.vertical, showsIndicators: false) { + VStack(spacing: spacing) { + scrollViewTopMarkerView + .allowsHitTesting(false) + + ForEach(selectedTreatments, id: \.id) { treatment in + TreatmentRowView( + displayMode: .summary, + treatmentEntity: treatment, + isSelected: .constant(true), + action: { removeTreatment(treatment) } + ) + .frame(height: itemHeight) + } + + scrollViewBottomMarkerView + .allowsHitTesting(false) } + .padding(.vertical, 14.adjustedH) } - .padding(.vertical, 14.adjustedH) + + GradientBox(isTop: true) + .frame(height: 42) + .allowsHitTesting(false) + .opacity(shouldShowGradientTop ? 1 : 0) + .frame(maxHeight: .infinity, alignment: .top) + + GradientBox(isTop: false) + .frame(height: 42) + .allowsHitTesting(false) + .opacity(shouldShowGradientBottom ? 1 : 0) + .frame(maxHeight: .infinity, alignment: .bottom) } .frame(height: scrollViewHeight) .scrollDisabled(selectedTreatments.count <= maxVisibleCount) .padding(.horizontal, 24.5.adjustedW) + .coordinateSpace(name: "SelectedTreatmentScroll") + .onPreferenceChange(ScrollTopPreferenceKey.self) { minY in + if initialTopGlobalY == nil { initialTopGlobalY = minY } + topGlobalY = minY + } + .onPreferenceChange(ScrollBottomPreferenceKey.self) { height in + bottomOffsetY = height + } } } } +extension SelectedTreatmentView { + private var scrollViewTopMarkerView: some View { + GeometryReader { proxy in + Color.clear + .preference( + key: ScrollTopPreferenceKey.self, + value: proxy.frame(in: .named("SelectedTreatmentScroll")).minY + ) + } + .frame(height: 0) + } + + private var scrollViewBottomMarkerView: some View { + GeometryReader { proxy in + Color.clear + .preference( + key: ScrollBottomPreferenceKey.self, + value: proxy.frame(in: .named("SelectedTreatmentScroll")).maxY + ) + } + .frame(height: 0) + } + + private var shouldShowGradientTop: Bool { + guard selectedTreatments.count > maxVisibleCount else { return false } + guard let initial = initialTopGlobalY else { return false } + return topGlobalY < initial - 1 + } + + private var shouldShowGradientBottom: Bool { + let remaining = bottomOffsetY - scrollViewHeight.adjustedH + return remaining > 1 + } +} diff --git a/Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTabbar/TabBarCoordinatorView.swift b/Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTabbar/TabBarCoordinatorView.swift index 89f86ec2..9df6b1ac 100644 --- a/Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTabbar/TabBarCoordinatorView.swift +++ b/Cherrish-iOS/Cherrish-iOS/Presentation/Global/Components/CherrishTabbar/TabBarCoordinatorView.swift @@ -31,13 +31,12 @@ struct TabBarCoordinatorView: View { } .padding(.bottom, tabBarCoordinator.isTabbarHidden ? 0 : 54.adjustedH) .id(tabBarCoordinator.selectedTab) - .environmentObject(tabBarCoordinator) if !tabBarCoordinator.isTabbarHidden { CherrishTabBar(selectedTab: $tabBarCoordinator.selectedTab) } } .environmentObject(tabBarCoordinator) - .onChange(of: tabBarCoordinator.selectedTab) { oldTab, newTab in + .onChange(of: tabBarCoordinator.selectedTab) { _, newTab in switch newTab { case .home: tabBarCoordinator.homeCoordinator.popToRoot()