blueprints / blueprints / iOS18 Photos / HomeScreen.swift
HomeScreen.swift
Raw
/// Thanks to this SO. https://stackoverflow.com/questions/25793141/continuous-vertical-scrolling-between-uicollectionview-nested-in-uiscrollview
import SwiftUI

#Preview {
    Home()
        .ignoresSafeArea()
}

struct Home: View {
    let viewSize = UIScreen.main.bounds.size

    @StateObject private var csvDelegate = CSVDelegate()
    @State var dragOffset: CGFloat = 0
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        let innerBaseHeight: CGFloat = viewSize.height * 0.7
        let outerBaseHeight = viewSize.height - innerBaseHeight

        CSVRepresentable(delegate: csvDelegate) {
            ZStack(alignment: .top) {
                // MARK: - Below Scroll View

                InnerContent(
                    dragOffset: $dragOffset,
                    scrollDelegate: csvDelegate,
                    viewSize: viewSize,
                    innerBaseHeight: innerBaseHeight,
                    bottomSectionHeight: outerBaseHeight
                )

                // MARK: - Above Scroll View

                OuterContent(
                    dragOffset: $dragOffset,
                    innerBaseHeight: innerBaseHeight,
                    bottomSectionHeight: outerBaseHeight
                )
            }
            .frame( 
                maxWidth: .infinity,
                maxHeight: .infinity,
                alignment: .top
            )
        }
        .onAppear {
            csvDelegate.viewSize = viewSize
            csvDelegate.innerBaseHeight = innerBaseHeight
            csvDelegate.outerBaseHeight = outerBaseHeight
        }
        .onChange(of: csvDelegate.dragOffset) { _, offset in
            withAnimation() {
                dragOffset = offset
            }
        }
        .toolbar {
            ToolbarItem(placement: .cancellationAction) {
                Button("Cancel", systemImage: "xmark") {
                    dismiss()
                }
            }

        }
    }
}

struct OuterContent: View {
    @Binding var dragOffset: CGFloat
    let innerBaseHeight: CGFloat
    let bottomSectionHeight: CGFloat
    
 
    // // Compute bounded offset for outer content
    // private var boundedOffset: CGFloat {
    //     // Start at upperSectionHeight (minimum)
    //     // Can increase up to upperSectionHeight + bottomSectionHeight (maximum)
    //     let minOffset: CGFloat = innerBaseHeight
    //     let maxOffset = innerBaseHeight + bottomSectionHeight
    //     return min(maxOffset, max(minOffset, innerBaseHeight + dragOffset))
    // }

    
    var body: some View {
        VStack(spacing: 8) {
            LazyVGrid(columns: [GridItem(.adaptive(minimum: 200))], spacing: 16) {
                ForEach(0..<100) { _ in
                    RoundedRectangle(cornerRadius: 16, style: .continuous)
                        .fill(.clear)
                        .frame(height: 100)
                }
            }
            .background(.thinMaterial)
            .padding(.top, innerBaseHeight)
        }
        .frame(
            maxWidth: .infinity,
            alignment: .top
        )
        .background(.clear)
        .padding(.bottom, innerBaseHeight)
        .offset(y: dragOffset)
    }
}

struct InnerContent: View {
    @Binding var dragOffset: CGFloat
    let scrollDelegate: CSVDelegate
    let viewSize: CGSize
    let innerBaseHeight: CGFloat
    let bottomSectionHeight: CGFloat

    private var boundedOffset: CGFloat {
        // Start at -bottomSectionHeight (minimum)
        // Can increase up to 0 (maximum)
        let minOffset = -bottomSectionHeight
        let maxOffset: CGFloat = 0
        return min(maxOffset, max(minOffset, -bottomSectionHeight + dragOffset))
    }
    
    let columns = [GridItem(.adaptive(minimum: 200), spacing: 16)]

    var body: some View {
        CSVRepresentable(isInner: true, delegate: scrollDelegate) {
            VStack(spacing: 1) {
                Grid(horizontalSpacing: 1, verticalSpacing: 1) {
                    ForEach(1...4, id: \.self) { _ in
                        GridRow {
                            ForEach(1...3, id: \.self) { _ in
                                Color(white: 0.5 + Double.random(in: 0.0 ... 0.5), opacity: 1.0)
                            }
                        }
                    }
                }
                .aspectRatio(0.75, contentMode: .fit)
                Grid(horizontalSpacing: 1, verticalSpacing: 1) {
                    ForEach(1...4, id: \.self) { _ in
                        GridRow {
                            ForEach(1...3, id: \.self) { _ in
                                Color(white: 0.5 + Double.random(in: 0.0 ... 0.5), opacity: 1.0)
                            }
                        }
                    }
                }
                .aspectRatio(0.75, contentMode: .fit)
                Grid(horizontalSpacing: 1, verticalSpacing: 1) {
                    ForEach(1...4, id: \.self) { _ in
                        GridRow {
                            ForEach(1...3, id: \.self) { _ in
                                Color(white: 0.5 + Double.random(in: 0.0 ... 0.5), opacity: 1.0)
                            }
                        }
                    }
                }
                .aspectRatio(0.75, contentMode: .fit)
            }
        }
        .frame(height: viewSize.height)
        .offset(y: boundedOffset)
    }
}