[
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non: [push]\n\njobs:\n  build:\n    runs-on: macOS-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - name: Bundle install\n        working-directory: ./\n        run: bundle install\n\n      - name: Unit tests\n        run: bundle exec fastlane tests\n\n      - name: SPM lint\n        run: bundle exec fastlane spm_lint\n\n      - name: Carthage lint\n        run: bundle exec fastlane carthage_lint\n\n      - name: Pod lint\n        run: bundle exec fastlane pod_lint\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "\nname: Release\n\non:\n  workflow_dispatch:\n    inputs:\n          name:\n            description: 'Version name'\n            required: true\n\njobs:\n  build:\n    runs-on: macOS-latest\n    steps:\n    - uses: maxim-lobanov/setup-xcode@v1\n      with:\n        xcode-version: latest-stable\n\n    - name: Checkout\n      uses: actions/checkout@v2\n\n    - name: Bundle install\n      working-directory: ./\n      run: bundle install\n\n    - name: Release\n      env:\n        LC_ALL: en_US.UTF-8\n        LANG: en_US.UTF-8\n        GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN_CI }}\n        COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_GZ_TOKEN }}\n        GIT_COMMITTER_NAME: Bot Fabernovel\n        GIT_AUTHOR_NAME: Bot Fabernovel\n        GIT_COMMITTER_EMAIL: ci@fabernovel.com\n        GIT_AUTHOR_EMAIL: ci@fabernovel.com\n      run: bundle exec fastlane release version:${{ github.event.inputs.name }} bypass_confirmations:true\n"
  },
  {
    "path": ".gitignore",
    "content": "# OS X\n.DS_Store\n\n# Xcode\n\n## Build generated\nDerivedData/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n*.xccheckout\nprofile\n## Other\n*.moved-aside\n*.xccheckout\nDerivedData\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n!Carthage/Build/**/*.dSYM\n\n# Bundler\n.bundle\n\n# Swift Package Manager\n.build\n.swiftpm\n\nExample/Pods/\nPods/\n\n.idea/\n\n# fastlane specific\nfastlane/report.xml\n\n# deliver temporary files\nfastlane/Preview.html\n\n# snapshot generated screenshots\nfastlane/screenshots/**/*.png\nfastlane/screenshots/screenshots.html\n\n# scan temporary files\nfastlane/test_output\ntest_output\nfastlane/.env\npre-change.yml\n.build\nfastlane/README.md\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [1.0.2]\n\n### Fixed\n\n- Jumping animation issue. #42\n\n## [1.0.0]\n\n### Fixed\n\n- Overlay with multiple scroll views #16\n\n## [1.0.0-beta.10]\n\n### Fixed\n\n- Crash with drivingScrollView a List and a condition #21\n- Bump OverlayContainer to `3.5.2`\n"
  },
  {
    "path": "DynamicOverlay.podspec",
    "content": "#\n# Be sure to run `pod lib lint DynamicOverlay.podspec' to ensure this is a\n# valid spec before submitting.\n#\n# Any lines starting with a # are optional, but their use is encouraged\n# To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html\n#\n\nPod::Spec.new do |s|\n  s.name             = 'DynamicOverlay'\n  s.version          = '1.0.2'\n  s.summary          = 'OverlayContainer is a SwiftUI library which makes it easier to develop overlay based interfaces.'\n  s.swift_version    = \"5.0\"\n\n  s.description      = <<-DESC\n  OverlayContainer is a SwiftUI library written in Swift. It makes it easier to develop overlay based interfaces, such as the one presented in the Apple Maps, Stocks or Shortcuts apps.\n                       DESC\n\n  s.homepage         = 'https://github.com/fabernovel/DynamicOverlay'\n  s.license          = { :type => 'MIT', :file => 'LICENSE' }\n  s.author           = { 'gaetanzanella' => 'gaetan.zanella@fabernovel.com' }\n  s.source           = { :git => 'https://github.com/fabernovel/DynamicOverlay.git', :tag => s.version.to_s }\n  s.dependency       'OverlayContainer', '~> 3.5'\n\n  s.ios.deployment_target = '13.0'\n  s.source_files = 'Source/**/*.swift'\nend\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/Classes/MapApp.swift",
    "content": "//\n//  MapApp.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 05/03/2019.\n//  Copyright © 2019 Fabernovel. All rights reserved.\n//\n\nimport UIKit\nimport SwiftUI\nimport DynamicOverlay\n\n@main\nstruct MapApp: App {\n\n    @UIApplicationDelegateAdaptor(UIKitAppDelegate.self)\n    private var delegate: UIKitAppDelegate\n\n    var body: some Scene {\n        WindowGroup {\n            MapRootView()\n        }\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/Configuration/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n</dict>\n</plist>\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/Resources/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/Resources/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"14460.31\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <device id=\"retina4_7\" orientation=\"portrait\">\n        <adaptation id=\"fullscreen\"/>\n    </device>\n    <dependencies>\n        <deployment identifier=\"iOS\"/>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"14460.20\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/UIKit/UIKitAppDelegate.swift",
    "content": "//\n//  UIKitAppDelegate.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 18/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport UIKit\n\nclass UIKitAppDelegate: NSObject, UIApplicationDelegate {\n\n    func application(_ application: UIApplication,\n                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {\n        UITableView.appearance().backgroundColor = .systemBackground\n        return true\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/ActionCell.swift",
    "content": "//\n//  ActionCell.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 19/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nstruct ActionCell: View {\n\n    var body: some View {\n        Label(\"New Guide…\", systemImage: \"plus\")\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/BackdropView.swift",
    "content": "//\n//  Backdropview.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 19/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nstruct BackdropView: View {\n\n    var body: some View {\n        Color.black.opacity(0.3)\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/FavoriteCell.swift",
    "content": "//\n//  FavoriteCell.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 19/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nstruct FavoriteCell: View {\n\n    let imageName: String\n    let title: String\n\n    var body: some View {\n        VStack {\n            Circle()\n                .foregroundColor(Color(.secondarySystemFill))\n                .frame(width: 70, height: 70)\n                .overlay(Image(systemName: imageName).font(.title2).foregroundColor(.blue))\n            Text(title)\n        }\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/MapRootView.swift",
    "content": "//\n//  MapRootView.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 17/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport DynamicOverlay\n\nenum Notch: CaseIterable, Equatable {\n    case min, max\n}\n\nstruct MapRootView: View {\n\n    struct State {\n        var notch: Notch = .min\n        var isEditing = false\n        var progress = 0.0\n    }\n\n    @SwiftUI.State\n    private var state = State()\n\n    // MARK: - View\n\n    var body: some View {\n        background\n            .dynamicOverlay(overlay)\n            .dynamicOverlayBehavior(behavior)\n            .ignoresSafeArea()\n    }\n\n    // MARK: - Private\n\n    private var behavior: some DynamicOverlayBehavior {\n        MagneticNotchOverlayBehavior<Notch> { notch in\n            switch notch {\n            case .max:\n                return .fractional(0.8)\n            case .min:\n                return .fractional(0.3)\n            }\n        }\n        .disable(.min, state.isEditing)\n        .notchChange($state.notch)\n        .onTranslation { translation in\n            state.progress = translation.progress\n        }\n    }\n\n    private var background: some View {\n        ZStack {\n            MapView()\n            BackdropView().opacity(state.progress)\n        }\n        .ignoresSafeArea()\n    }\n\n    private var overlay: some View {\n        OverlayView { event in\n            switch event {\n            case .didBeginEditing:\n                state.isEditing = true\n                withAnimation { state.notch = .max }\n            case .didEndEditing:\n                state.isEditing = false\n                withAnimation { state.notch = .min }\n            }\n        }\n        .drivingScrollView()\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/MapView.swift",
    "content": "//\n//  MapView.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 17/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport MapKit\nimport SwiftUI\n\nstruct MapView: View {\n\n    var body: some View {\n        MapViewAdaptor().ignoresSafeArea()\n    }\n}\n\nprivate struct MapViewAdaptor: UIViewRepresentable {\n\n    func makeUIView(context: Context) -> MKMapView {\n        MKMapView()\n    }\n\n    func updateUIView(_ uiView: MKMapView, context: Context) {}\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/OverlayBackgroundView.swift",
    "content": "//\n//  OverlayBackgroundView.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 19/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct OverlayBackgroundView: View {\n\n    var body: some View {\n        Color(.systemBackground)\n            .cornerRadius(8.0, corners: [.topLeft, .topRight])\n            .shadow(color: Color.black.opacity(0.3), radius: 8.0)\n    }\n}\n\nprivate extension View {\n\n    func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {\n        clipShape(RoundedCorner(radius: radius, corners: corners))\n    }\n}\n\nprivate struct RoundedCorner: Shape {\n\n    var radius: CGFloat = 0.0\n    var corners: UIRectCorner = .allCorners\n\n    func path(in rect: CGRect) -> Path {\n        Path(\n            UIBezierPath(\n                roundedRect: rect,\n                byRoundingCorners: corners,\n                cornerRadii: CGSize(width: radius, height: radius)\n            )\n            .cgPath\n        )\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/OverlayView.swift",
    "content": "//\n//  OverlayView.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 17/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport DynamicOverlay\n\nstruct OverlayView: View {\n\n    enum Event {\n        case didBeginEditing\n        case didEndEditing\n    }\n\n    let eventHandler: (Event) -> Void\n\n    // MARK: - View\n\n    var body: some View {\n        VStack(spacing: 0.0) {\n            header.draggable()\n            list\n        }\n        .background(OverlayBackgroundView())\n    }\n\n    // MARK: - Private\n\n    private var list: some View {\n        List {\n            Section(header: Text(\"Favorites\")) {\n                ScrollView(.horizontal) {\n                    HStack {\n                        FavoriteCell(imageName: \"house.fill\", title: \"House\")\n                        FavoriteCell(imageName: \"briefcase.fill\", title: \"Work\")\n                        FavoriteCell(imageName: \"plus\", title: \"Add\")\n                    }\n                }\n            }\n            Section(header: Text(\"My Guides\")) {\n                ActionCell()\n            }\n        }\n        .listStyle(GroupedListStyle())\n    }\n\n    private var header: some View {\n        SearchBar { event in\n            switch event {\n            case .didBeginEditing:\n                eventHandler(.didBeginEditing)\n            case .didCancel:\n                eventHandler(.didEndEditing)\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example/View/SearchBar.swift",
    "content": "//\n//  SearchBar.swift\n//  DynamicOverlay_Example\n//\n//  Created by Gaétan Zanella on 18/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport UIKit\n\nstruct SearchBar: View {\n\n    enum Event {\n        case didBeginEditing\n        case didCancel\n    }\n\n    let eventHandler: (Event) -> Void\n\n    var body: some View {\n        SearchBarAdaptor(\n            didBeginEditing: { eventHandler(.didBeginEditing) },\n            didCancel: { eventHandler(.didCancel) }\n        )\n    }\n}\n\nprivate class SearchBarCoordinator: NSObject, UISearchBarDelegate {\n\n    var didBeginEditing: (() -> Void)?\n    var didCancel: (() -> Void)?\n\n    // MARK: - UISearchBarDelegate\n\n    func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) {\n        didBeginEditing?()\n    }\n\n    func searchBarCancelButtonClicked(_ searchBar: UISearchBar) {\n        searchBar.endEditing(true)\n        didCancel?()\n    }\n}\n\nprivate struct SearchBarAdaptor: UIViewRepresentable {\n\n    let didBeginEditing: () -> Void\n    let didCancel: () -> Void\n\n    func makeCoordinator() -> SearchBarCoordinator {\n        let coordinator = SearchBarCoordinator()\n        coordinator.didBeginEditing = didBeginEditing\n        coordinator.didCancel = didCancel\n        return coordinator\n    }\n\n    func makeUIView(context: Context) -> UISearchBar {\n        let searchBar = UISearchBar()\n        searchBar.searchBarStyle = .minimal\n        searchBar.showsCancelButton = true\n        searchBar.placeholder = \"Search for a place or address\"\n        searchBar.delegate = context.coordinator\n        return searchBar\n    }\n\n    func updateUIView(_ uiView: UISearchBar, context: Context) {}\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 52;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\tE739AD94291D45F00076B2AC /* DynamicOverlay in Frameworks */ = {isa = PBXBuildFile; productRef = E739AD93291D45F00076B2AC /* DynamicOverlay */; };\n\t\tE73A7CE9262B2A8400959344 /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73A7CE8262B2A8400959344 /* MapView.swift */; };\n\t\tE73A7CEC262B2AA400959344 /* MapRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E73A7CEB262B2AA400959344 /* MapRootView.swift */; };\n\t\tE750EE4E262B2B4800E79C6B /* OverlayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE4D262B2B4800E79C6B /* OverlayView.swift */; };\n\t\tE750EE51262C30F600E79C6B /* SearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE50262C30F600E79C6B /* SearchBar.swift */; };\n\t\tE750EE63262C463100E79C6B /* MapApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = E742E3C422302B4B002A2BED /* MapApp.swift */; };\n\t\tE750EE68262C69A900E79C6B /* UIKitAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE67262C69A900E79C6B /* UIKitAppDelegate.swift */; };\n\t\tE750EE96262D772700E79C6B /* OverlayBackgroundView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE95262D772700E79C6B /* OverlayBackgroundView.swift */; };\n\t\tE750EE98262D798F00E79C6B /* ActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE97262D798F00E79C6B /* ActionCell.swift */; };\n\t\tE750EE9A262D799B00E79C6B /* FavoriteCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE99262D799B00E79C6B /* FavoriteCell.swift */; };\n\t\tE750EE9C262D7C9000E79C6B /* BackdropView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E750EE9B262D7C9000E79C6B /* BackdropView.swift */; };\n\t\tE7691574222EA78B00FDEE7F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E7691573222EA78B00FDEE7F /* Assets.xcassets */; };\n\t\tE7691577222EA78B00FDEE7F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E7691575222EA78B00FDEE7F /* LaunchScreen.storyboard */; };\n\t\tE79705A0292F83100047839F /* OverlayContainerRepresentableAdaptorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7970598292F83100047839F /* OverlayContainerRepresentableAdaptorTests.swift */; };\n\t\tE79705A1292F83100047839F /* NotchDimensionDynamicOverlayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7970599292F83100047839F /* NotchDimensionDynamicOverlayTests.swift */; };\n\t\tE79705A2292F83100047839F /* OverlayNotchIndexMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E797059A292F83100047839F /* OverlayNotchIndexMapperTests.swift */; };\n\t\tE79705A3292F83100047839F /* DrivingScrollViewModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E797059B292F83100047839F /* DrivingScrollViewModifierTests.swift */; };\n\t\tE79705A4292F83100047839F /* DragHandleViewModifierTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E797059C292F83100047839F /* DragHandleViewModifierTests.swift */; };\n\t\tE79705A5292F83100047839F /* NotchTranslationDynamicOverlayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E797059D292F83100047839F /* NotchTranslationDynamicOverlayTests.swift */; };\n\t\tE79705A6292F83100047839F /* MagneticNotchOverlayBehaviorValueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E797059E292F83100047839F /* MagneticNotchOverlayBehaviorValueTests.swift */; };\n\t\tE79705A7292F83100047839F /* NotchBindingDynamicOverlayTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E797059F292F83100047839F /* NotchBindingDynamicOverlayTests.swift */; };\n\t\tE79705AC292F83190047839F /* ViewInspector.swift in Sources */ = {isa = PBXBuildFile; fileRef = E79705A8292F83190047839F /* ViewInspector.swift */; };\n\t\tE79705AD292F83190047839F /* ValuePublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = E79705A9292F83190047839F /* ValuePublisher.swift */; };\n\t\tE79705AE292F83190047839F /* View+Measure.swift in Sources */ = {isa = PBXBuildFile; fileRef = E79705AA292F83190047839F /* View+Measure.swift */; };\n\t\tE79705AF292F83190047839F /* ViewRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E79705AB292F83190047839F /* ViewRenderer.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\tE7970593292F817F0047839F /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = E7691561222EA78A00FDEE7F /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = E7691568222EA78A00FDEE7F;\n\t\t\tremoteInfo = DynamicOverlay_Example;\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\tE739AD92291D45B10076B2AC /* DynamicOverlay */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = DynamicOverlay; path = ..; sourceTree = \"<group>\"; };\n\t\tE73A7CE8262B2A8400959344 /* MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = \"<group>\"; };\n\t\tE73A7CEB262B2AA400959344 /* MapRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapRootView.swift; sourceTree = \"<group>\"; };\n\t\tE741EE722576B10D0073FF6B /* DynamicOverlay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DynamicOverlay.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE742E3C422302B4B002A2BED /* MapApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MapApp.swift; path = Classes/MapApp.swift; sourceTree = \"<group>\"; };\n\t\tE750EE4D262B2B4800E79C6B /* OverlayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlayView.swift; sourceTree = \"<group>\"; };\n\t\tE750EE50262C30F600E79C6B /* SearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBar.swift; sourceTree = \"<group>\"; };\n\t\tE750EE67262C69A900E79C6B /* UIKitAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIKitAppDelegate.swift; sourceTree = \"<group>\"; };\n\t\tE750EE95262D772700E79C6B /* OverlayBackgroundView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlayBackgroundView.swift; sourceTree = \"<group>\"; };\n\t\tE750EE97262D798F00E79C6B /* ActionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionCell.swift; sourceTree = \"<group>\"; };\n\t\tE750EE99262D799B00E79C6B /* FavoriteCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoriteCell.swift; sourceTree = \"<group>\"; };\n\t\tE750EE9B262D7C9000E79C6B /* BackdropView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackdropView.swift; sourceTree = \"<group>\"; };\n\t\tE7691569222EA78A00FDEE7F /* DynamicOverlay_Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DynamicOverlay_Example.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE7691573222EA78B00FDEE7F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\tE7691576222EA78B00FDEE7F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\tE7691578222EA78B00FDEE7F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\tE797058F292F817F0047839F /* DynamicOverlay_ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DynamicOverlay_ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\tE7970598292F83100047839F /* OverlayContainerRepresentableAdaptorTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OverlayContainerRepresentableAdaptorTests.swift; path = ../../Tests/DynamicOverlayTests/OverlayContainerRepresentableAdaptorTests.swift; sourceTree = \"<group>\"; };\n\t\tE7970599292F83100047839F /* NotchDimensionDynamicOverlayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotchDimensionDynamicOverlayTests.swift; path = ../../Tests/DynamicOverlayTests/NotchDimensionDynamicOverlayTests.swift; sourceTree = \"<group>\"; };\n\t\tE797059A292F83100047839F /* OverlayNotchIndexMapperTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OverlayNotchIndexMapperTests.swift; path = ../../Tests/DynamicOverlayTests/OverlayNotchIndexMapperTests.swift; sourceTree = \"<group>\"; };\n\t\tE797059B292F83100047839F /* DrivingScrollViewModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DrivingScrollViewModifierTests.swift; path = ../../Tests/DynamicOverlayTests/DrivingScrollViewModifierTests.swift; sourceTree = \"<group>\"; };\n\t\tE797059C292F83100047839F /* DragHandleViewModifierTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DragHandleViewModifierTests.swift; path = ../../Tests/DynamicOverlayTests/DragHandleViewModifierTests.swift; sourceTree = \"<group>\"; };\n\t\tE797059D292F83100047839F /* NotchTranslationDynamicOverlayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotchTranslationDynamicOverlayTests.swift; path = ../../Tests/DynamicOverlayTests/NotchTranslationDynamicOverlayTests.swift; sourceTree = \"<group>\"; };\n\t\tE797059E292F83100047839F /* MagneticNotchOverlayBehaviorValueTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MagneticNotchOverlayBehaviorValueTests.swift; path = ../../Tests/DynamicOverlayTests/MagneticNotchOverlayBehaviorValueTests.swift; sourceTree = \"<group>\"; };\n\t\tE797059F292F83100047839F /* NotchBindingDynamicOverlayTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NotchBindingDynamicOverlayTests.swift; path = ../../Tests/DynamicOverlayTests/NotchBindingDynamicOverlayTests.swift; sourceTree = \"<group>\"; };\n\t\tE79705A8292F83190047839F /* ViewInspector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewInspector.swift; path = ../../Tests/DynamicOverlayTests/Utils/ViewInspector.swift; sourceTree = \"<group>\"; };\n\t\tE79705A9292F83190047839F /* ValuePublisher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ValuePublisher.swift; path = ../../Tests/DynamicOverlayTests/Utils/ValuePublisher.swift; sourceTree = \"<group>\"; };\n\t\tE79705AA292F83190047839F /* View+Measure.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = \"View+Measure.swift\"; path = \"../../Tests/DynamicOverlayTests/Utils/View+Measure.swift\"; sourceTree = \"<group>\"; };\n\t\tE79705AB292F83190047839F /* ViewRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ViewRenderer.swift; path = ../../Tests/DynamicOverlayTests/Utils/ViewRenderer.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\tE7691566222EA78A00FDEE7F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE739AD94291D45F00076B2AC /* DynamicOverlay in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE797058C292F817F0047839F /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\tE739AD91291D45B10076B2AC /* Packages */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE739AD92291D45B10076B2AC /* DynamicOverlay */,\n\t\t\t);\n\t\t\tname = Packages;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE73A7CEA262B2A8B00959344 /* View */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE73A7CEB262B2AA400959344 /* MapRootView.swift */,\n\t\t\t\tE73A7CE8262B2A8400959344 /* MapView.swift */,\n\t\t\t\tE750EE4D262B2B4800E79C6B /* OverlayView.swift */,\n\t\t\t\tE750EE50262C30F600E79C6B /* SearchBar.swift */,\n\t\t\t\tE750EE95262D772700E79C6B /* OverlayBackgroundView.swift */,\n\t\t\t\tE750EE97262D798F00E79C6B /* ActionCell.swift */,\n\t\t\t\tE750EE99262D799B00E79C6B /* FavoriteCell.swift */,\n\t\t\t\tE750EE9B262D7C9000E79C6B /* BackdropView.swift */,\n\t\t\t);\n\t\t\tpath = View;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE741EE712576B10D0073FF6B /* Frameworks */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE741EE722576B10D0073FF6B /* DynamicOverlay.framework */,\n\t\t\t);\n\t\t\tname = Frameworks;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE750EE66262C699C00E79C6B /* UIKit */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE750EE67262C69A900E79C6B /* UIKitAppDelegate.swift */,\n\t\t\t);\n\t\t\tpath = UIKit;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE7691560222EA78A00FDEE7F = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE739AD91291D45B10076B2AC /* Packages */,\n\t\t\t\tE769156B222EA78A00FDEE7F /* DynamicOverlay_Example */,\n\t\t\t\tE7970590292F817F0047839F /* DynamicOverlay_ExampleTests */,\n\t\t\t\tE769156A222EA78A00FDEE7F /* Products */,\n\t\t\t\tE741EE712576B10D0073FF6B /* Frameworks */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE769156A222EA78A00FDEE7F /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE7691569222EA78A00FDEE7F /* DynamicOverlay_Example.app */,\n\t\t\t\tE797058F292F817F0047839F /* DynamicOverlay_ExampleTests.xctest */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE769156B222EA78A00FDEE7F /* DynamicOverlay_Example */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE742E3C422302B4B002A2BED /* MapApp.swift */,\n\t\t\t\tE750EE66262C699C00E79C6B /* UIKit */,\n\t\t\t\tE73A7CEA262B2A8B00959344 /* View */,\n\t\t\t\tE7691582222EA7C100FDEE7F /* Resources */,\n\t\t\t\tE7691581222EA7B400FDEE7F /* Configuration */,\n\t\t\t);\n\t\t\tpath = DynamicOverlay_Example;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE7691581222EA7B400FDEE7F /* Configuration */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE7691578222EA78B00FDEE7F /* Info.plist */,\n\t\t\t);\n\t\t\tpath = Configuration;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE7691582222EA7C100FDEE7F /* Resources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE7691575222EA78B00FDEE7F /* LaunchScreen.storyboard */,\n\t\t\t\tE7691573222EA78B00FDEE7F /* Assets.xcassets */,\n\t\t\t);\n\t\t\tpath = Resources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tE7970590292F817F0047839F /* DynamicOverlay_ExampleTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tE797059C292F83100047839F /* DragHandleViewModifierTests.swift */,\n\t\t\t\tE797059B292F83100047839F /* DrivingScrollViewModifierTests.swift */,\n\t\t\t\tE797059E292F83100047839F /* MagneticNotchOverlayBehaviorValueTests.swift */,\n\t\t\t\tE797059F292F83100047839F /* NotchBindingDynamicOverlayTests.swift */,\n\t\t\t\tE7970599292F83100047839F /* NotchDimensionDynamicOverlayTests.swift */,\n\t\t\t\tE797059D292F83100047839F /* NotchTranslationDynamicOverlayTests.swift */,\n\t\t\t\tE7970598292F83100047839F /* OverlayContainerRepresentableAdaptorTests.swift */,\n\t\t\t\tE797059A292F83100047839F /* OverlayNotchIndexMapperTests.swift */,\n\t\t\t\tE79705A9292F83190047839F /* ValuePublisher.swift */,\n\t\t\t\tE79705AA292F83190047839F /* View+Measure.swift */,\n\t\t\t\tE79705A8292F83190047839F /* ViewInspector.swift */,\n\t\t\t\tE79705AB292F83190047839F /* ViewRenderer.swift */,\n\t\t\t);\n\t\t\tpath = DynamicOverlay_ExampleTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXNativeTarget section */\n\t\tE7691568222EA78A00FDEE7F /* DynamicOverlay_Example */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E769157B222EA78B00FDEE7F /* Build configuration list for PBXNativeTarget \"DynamicOverlay_Example\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE7691565222EA78A00FDEE7F /* Sources */,\n\t\t\t\tE7691566222EA78A00FDEE7F /* Frameworks */,\n\t\t\t\tE7691567222EA78A00FDEE7F /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = DynamicOverlay_Example;\n\t\t\tpackageProductDependencies = (\n\t\t\t\tE739AD93291D45F00076B2AC /* DynamicOverlay */,\n\t\t\t);\n\t\t\tproductName = DynamicOverlay_Example;\n\t\t\tproductReference = E7691569222EA78A00FDEE7F /* DynamicOverlay_Example.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\tE797058E292F817F0047839F /* DynamicOverlay_ExampleTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = E7970595292F817F0047839F /* Build configuration list for PBXNativeTarget \"DynamicOverlay_ExampleTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\tE797058B292F817F0047839F /* Sources */,\n\t\t\t\tE797058C292F817F0047839F /* Frameworks */,\n\t\t\t\tE797058D292F817F0047839F /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\tE7970594292F817F0047839F /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = DynamicOverlay_ExampleTests;\n\t\t\tproductName = DynamicOverlay_ExampleTests;\n\t\t\tproductReference = E797058F292F817F0047839F /* DynamicOverlay_ExampleTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\tE7691561222EA78A00FDEE7F /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tLastSwiftUpdateCheck = 1410;\n\t\t\t\tLastUpgradeCheck = 1220;\n\t\t\t\tORGANIZATIONNAME = Fabernovel;\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\tE7691568222EA78A00FDEE7F = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 10.1;\n\t\t\t\t\t};\n\t\t\t\t\tE797058E292F817F0047839F = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 14.1;\n\t\t\t\t\t\tLastSwiftMigration = 1410;\n\t\t\t\t\t\tTestTargetID = E7691568222EA78A00FDEE7F;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = E7691564222EA78A00FDEE7F /* Build configuration list for PBXProject \"DynamicOverlay_Example\" */;\n\t\t\tcompatibilityVersion = \"Xcode 9.3\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = E7691560222EA78A00FDEE7F;\n\t\t\tproductRefGroup = E769156A222EA78A00FDEE7F /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\tE7691568222EA78A00FDEE7F /* DynamicOverlay_Example */,\n\t\t\t\tE797058E292F817F0047839F /* DynamicOverlay_ExampleTests */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\tE7691567222EA78A00FDEE7F /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE7691577222EA78B00FDEE7F /* LaunchScreen.storyboard in Resources */,\n\t\t\t\tE7691574222EA78B00FDEE7F /* Assets.xcassets in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE797058D292F817F0047839F /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\tE7691565222EA78A00FDEE7F /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE750EE68262C69A900E79C6B /* UIKitAppDelegate.swift in Sources */,\n\t\t\t\tE750EE98262D798F00E79C6B /* ActionCell.swift in Sources */,\n\t\t\t\tE73A7CEC262B2AA400959344 /* MapRootView.swift in Sources */,\n\t\t\t\tE73A7CE9262B2A8400959344 /* MapView.swift in Sources */,\n\t\t\t\tE750EE9A262D799B00E79C6B /* FavoriteCell.swift in Sources */,\n\t\t\t\tE750EE4E262B2B4800E79C6B /* OverlayView.swift in Sources */,\n\t\t\t\tE750EE63262C463100E79C6B /* MapApp.swift in Sources */,\n\t\t\t\tE750EE96262D772700E79C6B /* OverlayBackgroundView.swift in Sources */,\n\t\t\t\tE750EE9C262D7C9000E79C6B /* BackdropView.swift in Sources */,\n\t\t\t\tE750EE51262C30F600E79C6B /* SearchBar.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\tE797058B292F817F0047839F /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tE79705A2292F83100047839F /* OverlayNotchIndexMapperTests.swift in Sources */,\n\t\t\t\tE79705A7292F83100047839F /* NotchBindingDynamicOverlayTests.swift in Sources */,\n\t\t\t\tE79705AD292F83190047839F /* ValuePublisher.swift in Sources */,\n\t\t\t\tE79705A1292F83100047839F /* NotchDimensionDynamicOverlayTests.swift in Sources */,\n\t\t\t\tE79705A4292F83100047839F /* DragHandleViewModifierTests.swift in Sources */,\n\t\t\t\tE79705A3292F83100047839F /* DrivingScrollViewModifierTests.swift in Sources */,\n\t\t\t\tE79705A0292F83100047839F /* OverlayContainerRepresentableAdaptorTests.swift in Sources */,\n\t\t\t\tE79705AF292F83190047839F /* ViewRenderer.swift in Sources */,\n\t\t\t\tE79705A5292F83100047839F /* NotchTranslationDynamicOverlayTests.swift in Sources */,\n\t\t\t\tE79705AC292F83190047839F /* ViewInspector.swift in Sources */,\n\t\t\t\tE79705A6292F83100047839F /* MagneticNotchOverlayBehaviorValueTests.swift in Sources */,\n\t\t\t\tE79705AE292F83190047839F /* View+Measure.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\tE7970594292F817F0047839F /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = E7691568222EA78A00FDEE7F /* DynamicOverlay_Example */;\n\t\t\ttargetProxy = E7970593292F817F0047839F /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\tE7691575222EA78B00FDEE7F /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\tE7691576222EA78B00FDEE7F /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\tE7691579222EA78B00FDEE7F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE769157A222EA78B00FDEE7F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15.0;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE769157C222EA78B00FDEE7F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINFOPLIST_FILE = DynamicOverlay_Example/Configuration/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fabernovel.DynamicOverlay-Example\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE769157D222EA78B00FDEE7F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tINFOPLIST_FILE = DynamicOverlay_Example/Configuration/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 15;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.fabernovel.DynamicOverlay-Example\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 4.2;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\tE7970596292F817F0047839F /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_TEAM = C7G63Q6LZ9;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 16.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.gaetanzanella.DynamicOverlay-ExampleTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/DynamicOverlay_Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/DynamicOverlay_Example\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\tE7970597292F817F0047839F /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tBUNDLE_LOADER = \"$(TEST_HOST)\";\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++20\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEVELOPMENT_TEAM = C7G63Q6LZ9;\n\t\t\t\tGENERATE_INFOPLIST_FILE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 16.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.0;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.gaetanzanella.DynamicOverlay-ExampleTests\";\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_EMIT_LOC_STRINGS = NO;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/DynamicOverlay_Example.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/DynamicOverlay_Example\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\tE7691564222EA78A00FDEE7F /* Build configuration list for PBXProject \"DynamicOverlay_Example\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE7691579222EA78B00FDEE7F /* Debug */,\n\t\t\t\tE769157A222EA78B00FDEE7F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE769157B222EA78B00FDEE7F /* Build configuration list for PBXNativeTarget \"DynamicOverlay_Example\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE769157C222EA78B00FDEE7F /* Debug */,\n\t\t\t\tE769157D222EA78B00FDEE7F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\tE7970595292F817F0047839F /* Build configuration list for PBXNativeTarget \"DynamicOverlay_ExampleTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\tE7970596292F817F0047839F /* Debug */,\n\t\t\t\tE7970597292F817F0047839F /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\n/* Begin XCSwiftPackageProductDependency section */\n\t\tE739AD93291D45F00076B2AC /* DynamicOverlay */ = {\n\t\t\tisa = XCSwiftPackageProductDependency;\n\t\t\tproductName = DynamicOverlay;\n\t\t};\n/* End XCSwiftPackageProductDependency section */\n\t};\n\trootObject = E7691561222EA78A00FDEE7F /* Project object */;\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved",
    "content": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"OverlayContainer\",\n        \"repositoryURL\": \"https://github.com/applidium/OverlayContainer.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"f1c8fc38bb1ad9a810397f1d06f7026a35e0760c\",\n          \"version\": \"3.5.2\"\n        }\n      }\n    ]\n  },\n  \"version\": 1\n}\n"
  },
  {
    "path": "DynamicOverlay_Example/DynamicOverlay_Example.xcodeproj/xcshareddata/xcschemes/DynamicOverlay_Example.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"E7691568222EA78A00FDEE7F\"\n               BuildableName = \"DynamicOverlay_Example.app\"\n               BlueprintName = \"DynamicOverlay_Example\"\n               ReferencedContainer = \"container:DynamicOverlay_Example.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"E797058E292F817F0047839F\"\n               BuildableName = \"DynamicOverlay_ExampleTests.xctest\"\n               BlueprintName = \"DynamicOverlay_ExampleTests\"\n               ReferencedContainer = \"container:DynamicOverlay_Example.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"E7691568222EA78A00FDEE7F\"\n            BuildableName = \"DynamicOverlay_Example.app\"\n            BlueprintName = \"DynamicOverlay_Example\"\n            ReferencedContainer = \"container:DynamicOverlay_Example.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"E7691568222EA78A00FDEE7F\"\n            BuildableName = \"DynamicOverlay_Example.app\"\n            BlueprintName = \"DynamicOverlay_Example\"\n            ReferencedContainer = \"container:DynamicOverlay_Example.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "Gemfile",
    "content": "source 'https://rubygems.org'\n\ngem \"cocoapods\", \"~> 1.11\"\ngem \"fastlane\", \"~> 2.1\"\nplugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')\neval_gemfile(plugins_path) if File.exist?(plugins_path)\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2020 Fabernovel\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "Package.resolved",
    "content": "{\n  \"object\": {\n    \"pins\": [\n      {\n        \"package\": \"OverlayContainer\",\n        \"repositoryURL\": \"https://github.com/applidium/OverlayContainer.git\",\n        \"state\": {\n          \"branch\": null,\n          \"revision\": \"f1c8fc38bb1ad9a810397f1d06f7026a35e0760c\",\n          \"version\": \"3.5.2\"\n        }\n      }\n    ]\n  },\n  \"version\": 1\n}\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.1\nimport PackageDescription\n\nlet package = Package(\n    name: \"DynamicOverlay\",\n    platforms: [\n        .iOS(.v13)\n    ],\n    products: [\n        .library(\n            name: \"DynamicOverlay\",\n            targets: [\"DynamicOverlay\"]\n        ),\n    ],\n    dependencies: [\n        .package(url: \"https://github.com/applidium/OverlayContainer.git\", from: \"3.5.2\")\n    ],\n    targets: [\n        .target(\n            name: \"DynamicOverlay\",\n            dependencies: [\"OverlayContainer\"],\n            path: \"Source\"\n        ),\n        .testTarget(\n            name: \"DynamicOverlayTests\",\n            dependencies: [\n                \"DynamicOverlay\",\n            ]\n        )\n    ],\n    swiftLanguageVersions: [.v5]\n)\n"
  },
  {
    "path": "Package.xcconfig",
    "content": "IPHONEOS_DEPLOYMENT_TARGET = 10.0\n\nSDKROOT =\nSUPPORTED_PLATFORMS = iphoneos iphonesimulator\nTARGETED_DEVICE_FAMILY = 1,2\nVALID_ARCHS[sdk=iphoneos*] = arm64 armv7 armv7s\nVALID_ARCHS[sdk=iphonesimulator*] = i386 x86_64\n\nCODE_SIGN_IDENTITY =\nCODE_SIGN_STYLE = Manual\nINSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks\nSKIP_INSTALL = YES\nDYLIB_COMPATIBILITY_VERSION = 1\nDYLIB_CURRENT_VERSION = 1\nDYLIB_INSTALL_NAME_BASE = @rpath\nLD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/Frameworks @loader_path/../Frameworks\nDEFINES_MODULE = NO\n"
  },
  {
    "path": "README.md",
    "content": "# DynamicOverlay\n\n<H4 align=\"center\">\nDynamicOverlay is a SwiftUI library. It makes easier to develop overlay based interfaces, such as the one presented in the Apple Maps, Stocks or Shortcuts apps.\n</H4>\n\n<p align=\"center\">\n  <a href=\"https://developer.apple.com/\"><img alt=\"Platform\" src=\"https://img.shields.io/badge/platform-iOS-green.svg\"/></a>\n  <a href=\"https://developer.apple.com/swift\"><img alt=\"Swift5\" src=\"https://img.shields.io/badge/language-Swift%205.0-orange.svg\"/></a>\n  <a href=\"https://cocoapods.org/pods/DynamicOverlay\"><img alt=\"CocoaPods\" src=\"https://img.shields.io/cocoapods/v/DynamicOverlay.svg?style=flat\"/></a>\n  <a href=\"https://github.com/Carthage/Carthage\"><img alt=\"Carthage\" src=\"https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat\"/></a>\n  <a href=\"https://github.com/fabernovel/DynamicOverlay/actions\"><img alt=\"Build Status\" src=\"https://github.com/fabernovel/DynamicOverlay/workflows/CI/badge.svg?branch=main\"/></a>\n  <a href=\"https://github.com/fabernovel/DynamicOverlay/blob/main/LICENSE\"><img alt=\"License\" src=\"https://img.shields.io/cocoapods/l/DynamicOverlay.svg?style=flat\"/></a>\n</p>\n\n---\n\n- [Requirements](#requirements)\n- [Getting started](#getting-started)\n- [Examples](#examples)\n- [Magnetic notch overlay](#magnetic-notch-overlay)\n  - [Specifying the notches](#specifying-the-notches)\n  - [Drag gesture support](#drag-gesture-support)\n  - [Scroll view support](#scroll-view-support)\n  - [Responding to overlay update](#responding-to-overlay-update)\n  - [Moving the overlay](#moving-the-overlay)\n  - [Disabling notches](#disabling-notches)\n  - [Installation](#installation)\n    - [CocoaPods](#cocoapods)\n    - [Carthage](#carthage)\n    - [Swift Package Manager](#swift-package-manager)\n- [Under the hood](#under-the-hood)\n- [Release](#release)\n- [Author](#author)\n- [License](#license)\n\n## Requirements\n\n`DynamicOverlay` is written in Swift 5. Compatible with iOS 13.0+.\n\n## Getting started\n\nA dynamic overlay is an overlay that dynamically reveals or hides the content underneath it.\n\nYou add a dynamic overlay as a [regular one](https://developer.apple.com/documentation/swiftui/view/overlay(_:alignment:)) using a view modifier:\n\n```swift\nColor.blue.dynamicOverlay(Color.red)\n```\nIts behavior is defined by the `DynamicOverlayBehavior` associated to it if any.\n\n```swift\n\nColor.blue\n    .dynamicOverlay(Color.red)\n    .dynamicOverlayBehavior(myOverlayBehavior)\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    ...\n}\n```\nIf you do not specify a behavior in the overlay view hierarchy, it uses a default one.\n\n## Examples\n\n- [Map App](https://github.com/faberNovel/DynamicOverlay/blob/main/DynamicOverlay_Example/DynamicOverlay_Example/View/MapRootView.swift)\n\n| Min | Max |\n| ------------------- | ------------------ |\n| <img src=\"https://github.com/faberNovel/DynamicOverlay/blob/main/Screenshots/min.png\" width=200 /> | <img src=\"https://github.com/faberNovel/DynamicOverlay/blob/main/Screenshots/max.png\" width=200 /> |\n\n## Magnetic notch overlay\n\n`MagneticNotchOverlayBehavior` is a `DynamicOverlayBehavior` instance. It is the only behavior available for now.\n\nIt describes an overlay that can be dragged up and down alongside predefined notches. Whenever a drag gesture ends, the overlay motion will continue until it reaches one of its notches.\n\n### Specifying the notches\n\nThe preferred way to define the notches is to declare an `CaseIterable` enum:\n\n```swift\nenum Notch: CaseIterable, Equatable {\n    case min, max\n}\n```\nYou specify the dimensions of each notch when you create a  `MagneticNotchOverlayBehavior`  instance:\n\n```swift\n@State var isCompact = false\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    MagneticNotchOverlayBehavior<Notch> { notch in\n        switch notch {\n        case .max:\n            return isCompact ? .fractional(0.5) : .fractional(0.8)\n        case .min:\n            return .fractional(0.3)\n        }\n    }\n}\n```\nThere are two kinds of dimension:\n```swift\nextension NotchDimension {\n\n    /// Creates a dimension with an absolute point value.\n    static func absolute(_ value: Double) -> NotchDimension\n\n    /// Creates a dimension that is computed as a fraction of the height of the overlay parent view.\n    static func fractional(_ value: Double) -> NotchDimension\n}\n```\n### Drag gesture support\n\nBy default, all the content of the overlay is draggable but you can limit this behavior using the `draggable`  view modifier.\n\nHere only the list header is draggable:\n\n```swift\nvar body: some View {\n    Color.green\n        .dynamicOverlay(myOverlayContent)\n        .dynamicOverlayBehavior(myOverlayBehavior)\n}\n\nvar myOverlayContent: some View {\n    VStack {\n        Text(\"Header\").draggable()\n        List {\n            Text(\"Row 1\")\n            Text(\"Row 2\")\n            Text(\"Row 3\")\n        }\n    }\n}\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    MagneticNotchOverlayBehavior<Notch> { ... }\n}\n```\nHere we disable the drag gesture entirely:\n```swift\nvar myOverlayContent: some View {\n    VStack {\n        Text(\"Header\")\n        List {\n            Text(\"Row 1\")\n            Text(\"Row 2\")\n            Text(\"Row 3\")\n        }\n    }\n    .draggable(false)\n}\n```\n\n### Scroll view support\n\nA magnetic notch overlay can coordinate its motion with the scrolling of a scroll view.\n\nMark the ScrollView or List that should dictate the overlays movement with `divingScrollView()`.\n\n```swift\nvar myOverlayContent: some View {\n    VStack {\n        Text(\"Header\").draggable()\n        List {\n            Text(\"Row 1\")\n            Text(\"Row 2\")\n            Text(\"Row 3\")\n        }\n        .drivingScrollView()\n    }\n}\n```\n\n### Responding to overlay updates\n\nYou can track the overlay motions using the `onTranslation(_:)` view modifier. It is a great occasion to update your UI based on the current overlay state.\n\nHere we define a control that should be right above the overlay:\n\n```swift\nstruct ControlView: View {\n\n    let height: CGFloat\n    let action: () -> Void\n\n    var body: some View {\n        VStack {\n            Button(\"Action\", action: action)\n            Spacer().frame(height: height)\n        }\n    }\n}\n```\nWe make sure the control is always visible thanks to the translation parameter:\n\n```swift\n@State var height: CGFloat = 0.0\n\nvar body: some View {\n    ZStack {\n        Color.blue\n        ControlView(height: height, action: {})\n    }\n    .dynamicOverlay(Color.red)\n    .dynamicOverlayBehavior(myOverlayBehavior)\n}\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    MagneticNotchOverlayBehavior<Notch> { ... }\n    .onTranslation { translation in\n        height = translation.height\n    }\n}\n```\nYou can also be notified when a notch is reached using a binding:\n```swift\n@State var notch: Notch = .min\n\nvar body: some View {\n    Color.blue\n        .dynamicOverlay(Text(\"\\(notch)\"))\n        .dynamicOverlayBehavior(myOverlayBehavior)\n}\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    MagneticNotchOverlayBehavior<Notch> { ... }\n    .notchChange($notch)\n}\n```\n\n### Moving the overlay\n\nYou can move explicitly the overlay using a notch binding.\n\n```swift\n@State var notch: Notch = .min\n\nvar body: some View {\n    ZStack {\n        Color.green\n        Button(\"Move to top\") {\n            notch = .max\n        }\n    }\n    .dynamicOverlay(Color.red)\n    .dynamicOverlayBehavior(myOverlayBehavior)\n}\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    MagneticNotchOverlayBehavior<Notch> { ... }\n    .notchChange($notch)\n}\n```\nWrap the change in an animation block to animate the change.\n\n```swift\nButton(\"Move to top\") {\n    withAnimation {\n        notch = .max\n    }\n}\n```\n\n### Disabling notches\n\nWhen a notch is disabled, the overlay will ignore it. Here we block the overlay in its `min` position:\n\n```swift\n@State var notch: Notch = .max\n\nvar myOverlayBehavior: some DynamicOverlayBehavior {\n    MagneticNotchOverlayBehavior<Notch> { ... }\n    .notchChange($notch)\n    .disable(.max, notch == .min)\n}\n```\n\n## Under the hood\n\n`DynamicOverlay` is built on top of [OverlayContainer](https://github.com/applidium/OverlayContainer). If you need more control, consider using it or open an issue.\n\n## Installation\n\n`DynamicOverlay` is available through [CocoaPods](https://cocoapods.org). To install it, simply add the following line to your Podfile:\n\n### Cocoapods\n\n```ruby\npod 'DynamicOverlay'\n```\n\n### Carthage\n\nAdd the following to your Cartfile:\n\n```ruby\ngithub \"https://github.com/fabernovel/DynamicOverlay\"\n```\n\n### Swift Package Manager\n\n`DynamicOverlay` can be installed as a Swift Package with Xcode 11 or higher. To install it, add a package using Xcode or a dependency to your Package.swift file:\n\n```swift\n.package(url: \"https://github.com/fabernovel/DynamicOverlay.git\")\n```\n\n## Release\n\n- Create a release branch for the new version (release/#version#)\n- Update the [CHANGELOG.md](https://github.com/faberNovel/DynamicOverlay/blob/main/CHANGELOG.md) (Be sure to spell your release version correctly)\n- Push your release branch\n- Run the [release workflow](https://github.com/faberNovel/DynamicOverlay/actions/workflows/release.yml) from your release branch\n\n## Author\n\n[@gaetanzanella](https://twitter.com/gaetanzanella), gaetan.zanella@fabernovel.com\n\n## License\n\n`DynamicOverlay` is available under the MIT license. See the LICENSE file for more info.\n"
  },
  {
    "path": "Source/DynamicOverlay.h",
    "content": "//\n//  DynamicOverlay.h\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 05/03/2019.\n//  Copyright © 2019 Fabernovel. All rights reserved.\n//\n\n#import <UIKit/UIKit.h>\n\n//! Project version number for DynamicOverlay.\nFOUNDATION_EXPORT double DynamicOverlayVersionNumber;\n\n//! Project version string for DynamicOverlay.\nFOUNDATION_EXPORT const unsigned char DynamicOverlayVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <DynamicOverlay/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Source/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>13</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Source/Internal/DynamicOverlayBehaviorValue.swift",
    "content": "//\n//  EmptyFile.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 05/03/2019.\n//  Copyright © 2019 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct OverlayTranslation {\n    let height: CGFloat\n    let transaction: Transaction\n    let isDragging: Bool\n    let translationProgress: CGFloat\n    let containerFrame: CGRect\n    let velocity: CGPoint\n    let heightForNotchIndex: (Int) -> CGFloat\n}\n\nstruct DynamicOverlayBehaviorValue {\n\n    let notchDimensions: [Int: NotchDimension]?\n    let block: ((OverlayTranslation) -> Void)?\n    let binding: Binding<Int>?\n    let disabledNotchIndexes: Set<Int>\n\n    init(notchDimensions: [Int: NotchDimension]? = nil,\n         block: ((OverlayTranslation) -> Void)? = nil,\n         binding: Binding<Int>? = nil,\n         disabledNotchIndexes: Set<Int> = []) {\n        self.notchDimensions = notchDimensions\n        self.block = block\n        self.binding = binding\n        self.disabledNotchIndexes = disabledNotchIndexes\n    }\n}\n\nextension DynamicOverlayBehaviorValue {\n\n    static var `default`: DynamicOverlayBehaviorValue {\n        DynamicOverlayBehaviorValue(\n            notchDimensions: [\n                0 : .fractional(0.3),\n                1 : .fractional(0.5),\n                2 : .fractional(0.7)\n            ]\n        )\n    }\n}\n\nstruct DynamicOverlayBehaviorKey: EnvironmentKey {\n\n    static var defaultValue: DynamicOverlayBehaviorValue = .default\n}\n\nextension EnvironmentValues {\n\n    var behaviorValue: DynamicOverlayBehaviorValue {\n        set {\n            self[DynamicOverlayBehaviorKey.self] = newValue\n        }\n        get {\n            self[DynamicOverlayBehaviorKey.self]\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Internal/DynamicOverlayNotchTransition+DynamicOverlayBehavior.swift",
    "content": "//\n//  MagneticNotchOverlayBehavior+DynamicOverlayBehavior.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nextension NotchDimension {\n\n    enum ValueType: Hashable {\n        case absolute\n        case fractional\n    }\n}\n\nextension MagneticNotchOverlayBehavior {\n\n    // MARK: - DynamicOverlayBehavior\n\n    func buildValue() -> DynamicOverlayBehaviorValue {\n        DynamicOverlayBehaviorValue(\n            notchDimensions: Dictionary(\n                uniqueKeysWithValues: Notch.allCases.enumerated().map { i, notch in (i, value.dimensions(notch)) }\n            ),\n            block: value.translationBlocks.isEmpty ? nil : { translation in\n                value.translationBlocks.forEach {\n                    $0(\n                        Translation(\n                            height: translation.height,\n                            transaction: translation.transaction,\n                            progress: Double(min(max(translation.translationProgress, 0), 1)),\n                            containerSize: translation.containerFrame.size,\n                            heightForNotch: { notch in\n                                translation.heightForNotchIndex(Notch.index(of: notch))\n                            }\n                        )\n                    )\n                }\n            },\n            binding: value.binding?.indexBinding(),\n            disabledNotchIndexes: Set(value.disabledNotches.map { Notch.index(of: $0) })\n        )\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/ActivatedOverlayArea.swift",
    "content": "//\n//  ActivatedOverlayArea.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 04/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct ActivatedOverlayArea: Equatable {\n\n    private struct Spot: Equatable {\n        let frame: CGRect\n    }\n\n    private var spots: [Spot]\n\n    mutating func merge(_ handle: ActivatedOverlayArea) {\n        spots += handle.spots\n    }\n\n    var isEmpty: Bool {\n        spots.isEmpty\n    }\n\n    func contains(_ rect: CGRect) -> Bool {\n        spots.contains { $0.frame == rect }\n    }\n\n    func contains(_ point: CGPoint) -> Bool {\n        spots.contains { $0.frame.contains(point) }\n    }\n\n    func intersects(_ rect: CGRect) -> Bool {\n        spots.contains {\n            // (gz) 2022-01-29 `SwiftUI` rounds the `UIKit` view frames.\n            // A 0.25pt-width `SwiftUI` view can contain a 0.5pt-width `UIView`.\n            rect.intersection($0.frame).width >= 0.5\n            && $0.frame != .zero\n        }\n    }\n}\n\nextension ActivatedOverlayArea {\n\n    static func active(_ frame: CGRect) -> ActivatedOverlayArea {\n        ActivatedOverlayArea(spots: [Spot(frame: frame)])\n    }\n\n    static func inactive() -> ActivatedOverlayArea {\n        ActivatedOverlayArea(spots: [Spot(frame: .zero)])\n    }\n\n    static var `default`: ActivatedOverlayArea {\n        .empty\n    }\n\n    static var empty: ActivatedOverlayArea {\n        ActivatedOverlayArea(spots: [])\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/ActiveOverlayAreaViewModifier.swift",
    "content": "//\n//  ActiveOverlayAreaViewModifier.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 28/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct ActiveOverlayAreaViewModifier<Key: PreferenceKey>: ViewModifier where Key.Value == ActivatedOverlayArea {\n\n    let key: Key.Type\n    let isActive: Bool\n\n    func body(content: Content) -> some View {\n        content.background(\n            GeometryReader { proxy in\n                Spacer().preference(\n                    key: key,\n                    value: isActive ? .active(proxy.frame(in: .overlay)) : .inactive()\n                )\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/Drag/DynamicOverlayDragArea.swift",
    "content": "//\n//  DynamicOverlayDragArea.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 29/01/2022.\n//  Copyright © 2022 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nstruct DynamicOverlayDragArea: Equatable {\n\n    private let area: ActivatedOverlayArea\n\n    init(area: ActivatedOverlayArea) {\n        self.area = area\n    }\n\n    static var `default`: DynamicOverlayDragArea {\n        DynamicOverlayDragArea(area: .default)\n    }\n\n    var isEmpty: Bool {\n        area.isEmpty\n    }\n\n    func contains(_ rect: CGRect) -> Bool {\n        area.contains(rect)\n    }\n\n    func contains(_ point: CGPoint) -> Bool {\n        return area.contains(point)\n    }\n}\n\nstruct DynamicOverlayDragAreaPreferenceKey: PreferenceKey {\n\n    typealias Value = ActivatedOverlayArea\n\n    static var defaultValue: ActivatedOverlayArea = .default\n\n    static func reduce(value: inout Value, nextValue: () -> Value) {\n        value.merge(nextValue())\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/Drag/OnDragAreaChangeViewModifier.swift",
    "content": "//\n//  OnDragAreaChangeViewModifier.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nprivate struct OnDragAreaChangeViewModifier: ViewModifier {\n\n    let handler: (DynamicOverlayDragArea) -> Void\n\n    func body(content: Content) -> some View {\n        content.onPreferenceChange(DynamicOverlayDragAreaPreferenceKey.self) { area in\n            handler(DynamicOverlayDragArea(area: area))\n        }\n    }\n}\n\nextension View {\n\n    func onDragAreaChange(handler: @escaping (DynamicOverlayDragArea) -> Void) -> some View {\n        modifier(OnDragAreaChangeViewModifier(handler: handler))\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/DrivingScrollView/DynamicOverlayScrollViewProxy.swift",
    "content": "//\n//  DynamicOverlayScrollViewProxyPreferenceKey.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 11/01/2022.\n//  Copyright © 2022 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct DynamicOverlayScrollViewProxy: Equatable {\n\n    private let area: ActivatedOverlayArea\n\n    init(area: ActivatedOverlayArea) {\n        self.area = area\n    }\n\n    static var `default`: DynamicOverlayScrollViewProxy {\n        DynamicOverlayScrollViewProxy(area: .default)\n    }\n\n    func findScrollView(in space: UIView) -> UIScrollView? {\n        space.findScrollView(in: area, coordinate: space)\n    }\n}\n\n\nstruct DynamicOverlayScrollViewProxyPreferenceKey: PreferenceKey {\n\n    typealias Value = ActivatedOverlayArea\n\n    static var defaultValue: ActivatedOverlayArea = .default\n\n    static func reduce(value: inout Value, nextValue: () -> Value) {\n        value.merge(nextValue())\n    }\n}\n\nprivate extension UIView {\n\n    func findScrollView(in area: ActivatedOverlayArea,\n                        coordinate: UICoordinateSpace) -> UIScrollView? {\n        let frame = coordinate.convert(bounds, from: self)\n        guard area.intersects(frame) else { return nil }\n        if let result = self as? UIScrollView {\n            return result\n        }\n        for subview in subviews {\n            if let result = subview.findScrollView(in: area, coordinate: coordinate) {\n                return result\n            }\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/DrivingScrollView/OnDrivingScrollViewChangeViewModifier.swift",
    "content": "//\n//  OnDrivingScrollViewChangeViewModifier.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nprivate struct OnDrivingScrollViewChangeViewModifier: ViewModifier {\n\n    let handler: (DynamicOverlayScrollViewProxy) -> Void\n\n    func body(content: Content) -> some View {\n        content.onPreferenceChange(DynamicOverlayScrollViewProxyPreferenceKey.self, perform: { value in\n            handler(DynamicOverlayScrollViewProxy(area: value))\n        })\n    }\n}\n\nextension View {\n\n    func onDrivingScrollViewChange(handler: @escaping (DynamicOverlayScrollViewProxy) -> Void) -> some View {\n        modifier(OnDrivingScrollViewChangeViewModifier(handler: handler))\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Handle/OverlayContainerCoordinateSpace.swift",
    "content": "//\n//  OverlayContainer+CoordinateSpace.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 28/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nextension CoordinateSpace {\n\n    static var overlay: CoordinateSpace {\n        .named(\"Overlay\")\n    }\n}\n\nextension View {\n\n    func overlayCoordinateSpace() -> some View {\n        modifier(OverlayCoordinateSpaceViewModifier())\n    }\n}\n\nprivate struct OverlayCoordinateSpaceViewModifier: ViewModifier {\n\n    func body(content: Content) -> some View {\n        content.coordinateSpace(name: \"Overlay\")\n    }\n}\n"
  },
  {
    "path": "Source/Internal/MagneticNotchOverlayBehaviorValue.swift",
    "content": "//\n//  MagneticNotchOverlayBehaviorValue.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nextension MagneticNotchOverlayBehavior {\n\n    struct Value {\n\n        let dimensions: (Notch) -> NotchDimension\n        let translationBlocks: [(Translation) -> Void]\n        let binding: Binding<Notch>?\n        let disabledNotches: [Notch]\n\n        init(dimensions: @escaping (Notch) -> NotchDimension,\n             translationBlocks: [(Translation) -> Void],\n             binding: Binding<Notch>?,\n             disabledNotches: [Notch]) {\n            self.dimensions = dimensions\n            self.translationBlocks = translationBlocks\n            self.binding = binding\n            self.disabledNotches = disabledNotches\n        }\n\n        init(dimensions: @escaping (Notch) -> NotchDimension) {\n            self.dimensions = dimensions\n            self.translationBlocks = []\n            self.binding = nil\n            self.disabledNotches = []\n        }\n\n        // MARK: - Public\n\n        func appending(_ block: @escaping (Translation) -> Void) -> Self {\n            Value(\n                dimensions: dimensions,\n                translationBlocks: translationBlocks + [block],\n                binding: binding,\n                disabledNotches: disabledNotches\n            )\n        }\n\n        func setting(_ binding: Binding<Notch>) -> Self {\n            Value(\n                dimensions: dimensions,\n                translationBlocks: translationBlocks,\n                binding: binding,\n                disabledNotches: disabledNotches\n            )\n        }\n\n        func disabling(_ isDisabled: Bool, _ notch: Notch) -> Self {\n            Value(\n                dimensions: dimensions,\n                translationBlocks: translationBlocks,\n                binding: binding,\n                disabledNotches: isDisabled ? disabledNotches + [notch] : disabledNotches\n            )\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContainer/DynamicOverlayContainerAnimationController.swift",
    "content": "//\n//  DynamicOverlayContainerAnimationController.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 28/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport UIKit\nimport SwiftUI\nimport OverlayContainer\n\nprivate struct Constant {\n    static let defaultMass: CGFloat = 1\n    static let defaultDamping: CGFloat = 0.7\n    static let defaultRigidDamping: CGFloat = 0.9\n    static let defaultResponse: CGFloat = 0.3\n    static let minimumDamping: CGFloat = 1\n    static let minimumVelocityConsideration: CGFloat = 150\n    static let maximumVelocityConsideration: CGFloat = 3000\n}\n\nstruct DynamicOverlayContainerAnimationController: OverlayAnimatedTransitioning {\n\n    private var mass: CGFloat = Constant.defaultMass\n    private var damping: CGFloat = Constant.defaultDamping\n    private var response: CGFloat = Constant.defaultResponse\n\n    // MARK: - Life Cycle\n\n    public init(style: OverlayContainerViewController.OverlayStyle) {\n        switch style {\n        case .expandableHeight, .rigid:\n            // (gz) 2019-06-15 We also nullify the damping value when using rigid styles\n            // to avoid the panel to be lifted above the bottom of the screen.\n            damping = Constant.defaultRigidDamping\n        case .flexibleHeight:\n            damping = Constant.defaultDamping\n        }\n    }\n\n    // MARK: - Public\n\n    public func animation(using context: OverlayContainerTransitionCoordinatorContext) -> Animation? {\n        guard context.isAnimated else { return nil }\n        return .interpolatingSpring(\n            mass: Double(springMass(context: context)),\n            stiffness: Double(springStiffness(context: context)),\n            damping: Double(springDamping(context: context)),\n            initialVelocity: Double(springVelocity(context: context))\n        )\n    }\n\n    // MARK: - OverlayAnimatedTransitioning\n\n    public func interruptibleAnimator(using context: OverlayContainerContextTransitioning) -> UIViewImplicitlyAnimating {\n        let timing = UISpringTimingParameters(\n            mass: springMass(context: context),\n            stiffness: springStiffness(context: context),\n            damping: springDamping(context: context),\n            initialVelocity: CGVector(dx: springVelocity(context: context), dy: springVelocity(context: context))\n        )\n        return UIViewPropertyAnimator(\n            duration: 0, // duration is ignored when using `UISpringTimingParameters.init(mass:stiffness:damping:initialVelocity)`\n            timingParameters: timing\n        )\n    }\n\n    private func springMass(context: OverlayContainerTransitionContext) -> CGFloat {\n        mass\n    }\n\n    private func springStiffness(context: OverlayContainerTransitionContext) -> CGFloat {\n        pow(2 * .pi / response, 2)\n    }\n\n    private func springDamping(context: OverlayContainerTransitionContext) -> CGFloat {\n        let velocity = min(\n            Constant.maximumVelocityConsideration,\n            max(abs(context.velocity.y), Constant.minimumVelocityConsideration)\n        )\n        let velocityRange = Constant.maximumVelocityConsideration - Constant.minimumVelocityConsideration\n        let normalizedVelocity = (velocity - Constant.minimumVelocityConsideration) / velocityRange\n        let normalizedDamping = normalizedVelocity * (damping - Constant.minimumDamping) + Constant.minimumDamping\n        return 4 * .pi * normalizedDamping / response\n    }\n\n    private func springVelocity(context: OverlayContainerTransitionContext) -> CGFloat {\n        0\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContainer/OverlayContainerCoordinator.swift",
    "content": "//\n//  OverlayContainerCoordinator.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport UIKit\nimport SwiftUI\nimport OverlayContainer\n\nstruct OverlayContainerLayout: Equatable {\n    let indexToDimension: [Int: NotchDimension]\n}\n\n// (gz) 2022-01-30 `SwiftUI` compares struct properties one by one to determine either to update the view or not.\n// To avoid useless updates, we wrap the passive values inside this class.\nclass OverlayContainerPassiveContainer: Equatable {\n\n    var onTranslation: ((OverlayTranslation) -> Void)?\n    var onNotchChange: ((Int) -> Void)?\n\n    static func == (lhs: OverlayContainerPassiveContainer, rhs: OverlayContainerPassiveContainer) -> Bool {\n        lhs === rhs\n    }\n}\n\nstruct OverlayContainerState: Equatable {\n    let dragArea: DynamicOverlayDragArea\n    let drivingScrollViewProxy: DynamicOverlayScrollViewProxy\n    let notchIndex: Int?\n    let disabledNotches: Set<Int>\n    let layout: OverlayContainerLayout\n}\n\nclass OverlayContainerCoordinator {\n\n    private let background: UIViewController\n    private let content: UIViewController\n\n    private let indexMapper = OverlayNotchIndexMapper()\n\n    typealias State = OverlayContainerState\n\n    private var state: State\n    private let style: OverlayContainerViewController.OverlayStyle\n    private let passiveContainer: OverlayContainerPassiveContainer\n\n    private var animationController: DynamicOverlayContainerAnimationController {\n        DynamicOverlayContainerAnimationController(style: style)\n    }\n\n    // MARK: - Life Cycle\n\n    init(style: OverlayContainerViewController.OverlayStyle,\n         layout: OverlayContainerLayout,\n         passiveContainer: OverlayContainerPassiveContainer,\n         background: UIViewController,\n         content: UIViewController) {\n        self.state = .initial(layout)\n        self.passiveContainer = passiveContainer\n        self.background = background\n        self.content = content\n        self.style = style\n    }\n\n    // MARK: - Public\n\n    func move(_ container: OverlayContainerViewController, to state: State, animated: Bool) {\n        if container.viewControllers.isEmpty {\n            container.viewControllers = [background, content]\n        }\n        let changes = OverlayContainerStateDiffer().diff(\n            from: self.state,\n            to: state\n        )\n        let requiresLayoutUpdate = changes.contains(.index) || changes.contains(.layout)\n        if requiresLayoutUpdate && animated {\n            // we update the content first\n            container.drivingScrollView = nil // issue #21\n            container.view.layoutIfNeeded()\n        }\n        if changes.contains(.layout) {\n            container.invalidateNotchHeights()\n        }\n        if let index = state.notchIndex, changes.contains(.index) {\n            container.moveOverlay(toNotchAt: index, animated: animated)\n        }\n        if changes.contains(.scrollView) {\n            CATransaction.setCompletionBlock { [weak container] in\n                guard let overlay = container?.topViewController?.view else { return }\n                container?.drivingScrollView = state.drivingScrollViewProxy.findScrollView(in: overlay)\n            }\n        }\n        self.state = state\n        if changes.contains(.layout) && !animated {\n            UIView.performWithoutAnimation {\n                container.view.layoutIfNeeded()\n            }\n        }\n    }\n}\n\nextension OverlayContainerCoordinator: OverlayContainerViewControllerDelegate {\n\n    // MARK: - OverlayContainerViewControllerDelegate\n\n    func numberOfNotches(in containerViewController: OverlayContainerViewController) -> Int {\n        indexMapper.reload(\n            layout: state.layout,\n            availableHeight: containerViewController.availableSpace\n        )\n        return indexMapper.numberOfOverlayIndexes()\n    }\n\n    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,\n                                        heightForNotchAt index: Int,\n                                        availableSpace: CGFloat) -> CGFloat {\n        indexMapper.height(forOverlayIndex: index)\n    }\n\n    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,\n                                        didMoveOverlay overlayViewController: UIViewController,\n                                        toNotchAt index: Int) {\n        let newState = state.withNewNotch(index)\n        guard newState != state else { return }\n        passiveContainer.onNotchChange?(indexMapper.dynamicIndex(forOverlayIndex: index))\n    }\n\n    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,\n                                        willTranslateOverlay overlayViewController: UIViewController,\n                                        transitionCoordinator: OverlayContainerTransitionCoordinator) {\n        let animation = animationController.animation(using: transitionCoordinator)\n        let transaction = Transaction(animation: animation)\n        let translation = OverlayTranslation(\n            height: transitionCoordinator.targetTranslationHeight,\n            transaction: transaction,\n            isDragging: transitionCoordinator.isDragging,\n            translationProgress: transitionCoordinator.overallTranslationProgress(),\n            containerFrame: containerViewController.view.frame,\n            velocity: transitionCoordinator.velocity,\n            heightForNotchIndex: { transitionCoordinator.height(forNotchAt: $0) }\n        )\n        withTransaction(transaction) { [weak passiveContainer] in\n            passiveContainer?.onTranslation?(translation)\n        }\n    }\n\n    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,\n                                        canReachNotchAt index: Int,\n                                        forOverlay overlayViewController: UIViewController) -> Bool {\n        !state.disabledNotches.map { indexMapper.overlayIndex(forDynamicIndex: $0) }.contains(index)\n    }\n\n    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,\n                                        shouldStartDraggingOverlay overlayViewController: UIViewController,\n                                        at point: CGPoint,\n                                        in coordinateSpace: UICoordinateSpace) -> Bool {\n        guard let overlay = containerViewController.topViewController else { return false }\n        let inOverlayPoint = overlay.view.convert(point, from: coordinateSpace)\n        if state.dragArea.isEmpty {\n            return overlay.view.frame.contains(inOverlayPoint)\n        }\n        return state.dragArea.contains(inOverlayPoint)\n    }\n\n    func overlayContainerViewController(_ containerViewController: OverlayContainerViewController,\n                                        transitioningDelegateForOverlay overlayViewController: UIViewController) -> OverlayTransitioningDelegate? {\n        self\n    }\n}\n\nextension OverlayContainerCoordinator: OverlayTransitioningDelegate {\n\n    // MARK: - OverlayTransitioningDelegate\n\n    func animationController(for overlayViewController: UIViewController) -> OverlayAnimatedTransitioning? {\n        animationController\n    }\n}\n\nprivate extension OverlayContainerState {\n\n    static func initial(_ layout: OverlayContainerLayout) -> OverlayContainerState {\n        OverlayContainerState(\n            dragArea: .default,\n            drivingScrollViewProxy: .default,\n            notchIndex: nil,\n            disabledNotches: [],\n            layout: layout\n        )\n    }\n\n    func withNewNotch(_ notch: Int) -> OverlayContainerState {\n        OverlayContainerState(\n            dragArea: dragArea,\n            drivingScrollViewProxy: drivingScrollViewProxy,\n            notchIndex: notch,\n            disabledNotches: disabledNotches,\n            layout: layout\n        )\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContainer/OverlayContainerDynamicOverlayView.swift",
    "content": "//\n//  OverlayContainerView.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct OverlayContainerDynamicOverlayView<Background: View, Content: View>: View {\n\n    @State\n    private var dragArea: DynamicOverlayDragArea = .default\n\n    @State\n    private var scrollViewProxy: DynamicOverlayScrollViewProxy = .default\n\n    @State\n    private var passiveContainer = OverlayContainerPassiveContainer()\n\n    @Environment(\\.behaviorValue)\n    private var behavior: DynamicOverlayBehaviorValue\n\n    let background: Background\n    let content: Content\n\n    // MARK: - View\n\n    var body: some View {\n        SwiftUIOverlayContainerRepresentableAdaptor(\n            adaptor: OverlayContainerRepresentableAdaptor(\n                containerState: makeContainerState(),\n                passiveContainer: passiveContainer,\n                content: OverlayContentHostingView(),\n                background: background\n            )\n        )\n        .overlayContent(content.overlayCoordinateSpace())\n        .onUpdate {\n            passiveContainer.onTranslation = behavior.block\n            // This is tricky. `OverlayContainerPassiveContainer` is a class inside a struct,\n            // `passiveContainer.onNotchChange = { self.behavior.binding?.wrappedValue = $0 }`\n            // would create a retain cycle as `self` includes a ref to `passiveContainer`.\n            let behavior = behavior\n            passiveContainer.onNotchChange = { behavior.binding?.wrappedValue = $0 }\n        }\n        .onDragAreaChange {\n            dragArea = $0\n        }\n        .onDrivingScrollViewChange {\n            scrollViewProxy = $0\n        }\n    }\n\n    // MARK: - Private\n\n    private func makeContainerState() -> OverlayContainerState {\n        OverlayContainerState(\n            dragArea: dragArea,\n            drivingScrollViewProxy: scrollViewProxy,\n            notchIndex: behavior.binding?.wrappedValue,\n            disabledNotches: behavior.disabledNotchIndexes,\n            layout: OverlayContainerLayout(indexToDimension: behavior.notchDimensions ?? [:])\n        )\n    }\n}\n\nprivate extension View {\n\n    func onUpdate(_ block: () -> Void) -> some View {\n        block()\n        return self\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContainer/OverlayContainerRepresentableAdaptor.swift",
    "content": "//\n//  OverlayContainerRepresentableAdaptor.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 20/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport OverlayContainer\n\nstruct OverlayContainerRepresentableAdaptor<Content: View, Background: View> {\n\n    struct Context {\n        let coordinator: OverlayContainerCoordinator\n        let transaction: Transaction\n    }\n\n    let containerState: OverlayContainerState\n    let passiveContainer: OverlayContainerPassiveContainer\n    let content: Content\n    let background: Background\n\n    private let style: OverlayContainerViewController.OverlayStyle = .expandableHeight\n\n    // MARK: - UIViewControllerRepresentable\n\n    func makeCoordinator() -> OverlayContainerCoordinator {\n        let contentController = UIHostingController(rootView: content)\n        contentController.view.backgroundColor = .clear\n        contentController.view.setContentCompressionResistancePriority(.defaultLow, for: .vertical)\n        contentController.view.setContentHuggingPriority(.defaultLow, for: .vertical)\n        let backgroundController = UIHostingController(rootView: background)\n        backgroundController.view.backgroundColor = .clear\n        return OverlayContainerCoordinator(\n            style: style,\n            layout: containerState.layout,\n            passiveContainer: passiveContainer,\n            background: backgroundController,\n            content: contentController\n        )\n    }\n\n    func makeUIViewController(context: Context) -> OverlayContainerViewController {\n        let controller = OverlayContainerViewController(style: style)\n        controller.delegate = context.coordinator\n        return controller\n    }\n\n    func updateUIViewController(_ container: OverlayContainerViewController,\n                                context: Context) {\n        context.coordinator.move(\n            container,\n            to: containerState,\n            animated: context.transaction.animation != nil\n        )\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContainer/OverlayContainerStateDiffer.swift",
    "content": "//\n//  OverlayContainerStateDiffer.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 23/07/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\n\nstruct OverlayContainerStateDiffer {\n\n    struct Changes: OptionSet {\n        let rawValue: Int\n\n        static let layout = Changes(rawValue: 1 << 0)\n        static let index = Changes(rawValue: 1 << 1)\n        static let scrollView = Changes(rawValue: 1 << 2)\n    }\n\n    func diff(from previous: OverlayContainerState, to next: OverlayContainerState) -> Changes {\n        var changes: Changes = []\n        if previous.notchIndex != next.notchIndex {\n            changes.insert(.index)\n        }\n        // issue #21\n        // The scroll view depends on the content, we need to first for a potential new scroll view\n        // at each update\n        changes.insert(.scrollView)\n        if previous.layout != next.layout {\n            changes.insert(.layout)\n        }\n        return changes\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContainer/SwiftUIOverlayContainerRepresentableAdaptor.swift",
    "content": "//\n//  SwiftUIOverlayContainerRepresentableAdaptor.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport OverlayContainer\n\nstruct SwiftUIOverlayContainerRepresentableAdaptor<Content: View, Background: View>: UIViewControllerRepresentable {\n\n    let adaptor: OverlayContainerRepresentableAdaptor<Content, Background>\n\n    // MARK: - UIViewControllerRepresentable\n\n    func makeCoordinator() -> OverlayContainerCoordinator {\n        adaptor.makeCoordinator()\n    }\n\n    func makeUIViewController(context: Context) -> OverlayContainerViewController {\n        adaptor.makeUIViewController(context: map(context))\n    }\n\n    func updateUIViewController(_ uiViewController: OverlayContainerViewController, context: Context) {\n        adaptor.updateUIViewController(uiViewController, context: map(context))\n    }\n\n    private func map(_ context: Context) -> OverlayContainerRepresentableAdaptor<Content, Background>.Context {\n        OverlayContainerRepresentableAdaptor<Content, Background>.Context(\n            coordinator: context.coordinator,\n            transaction: context.transaction\n        )\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayContentModifier.swift",
    "content": "//\n//  OverlayContentModifier.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 03/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nstruct OverlayContentModifier<Overlay: View>: ViewModifier {\n\n    let overlay: Overlay\n\n    func body(content: Content) -> some View {\n        content.environment(\\.overlayContentKey, AnyView(overlay))\n    }\n}\n\nextension View {\n\n    func overlayContent<Content: View>(_ content: Content) -> ModifiedContent<Self, OverlayContentModifier<Content>> {\n        modifier(OverlayContentModifier(overlay: content))\n    }\n}\n\n/// The root view of the overlay content\nstruct OverlayContentHostingView: View {\n\n    /// We use an environment variable to avoid UIViewController allocations each time the content changes.\n    @Environment(\\.overlayContentKey)\n    var content: AnyView\n\n    var body: some View {\n        content\n    }\n}\n\nprivate struct OverlayContentKey: EnvironmentKey {\n\n    static var defaultValue = AnyView(EmptyView())\n}\n\nprivate extension EnvironmentValues {\n\n    var overlayContentKey: AnyView {\n        set {\n            self[OverlayContentKey.self] = newValue\n        }\n        get {\n            self[OverlayContentKey.self]\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Internal/OverlayNotchIndexMapper.swift",
    "content": "//\n//  OverlayNotchIndexMapper.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 29/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nclass OverlayNotchIndexMapper {\n\n    private var overlayIndexToDynamicIndex: [Int: Int] = [:]\n    private var overlayIndexToHeight: [Int: CGFloat] = [:]\n    private var dynamicIndexToOverlayIndex: [Int: Int] = [:]\n\n    func reload(layout: OverlayContainerLayout, availableHeight: CGFloat) {\n        overlayIndexToDynamicIndex = [:]\n        overlayIndexToHeight = [:]\n        dynamicIndexToOverlayIndex = [:]\n        let sortedIndexes = layout.indexToDimension.sorted(by: {\n            height(for: $0.value, availableHeight: availableHeight) < height(for: $1.value, availableHeight: availableHeight)\n        })\n        sortedIndexes.enumerated().forEach{ overlayIndex, dynamicValue in\n            overlayIndexToHeight[overlayIndex] = height(for: dynamicValue.value, availableHeight: availableHeight)\n            dynamicIndexToOverlayIndex[dynamicValue.key] = overlayIndex\n            overlayIndexToDynamicIndex[overlayIndex] = dynamicValue.key\n        }\n    }\n\n    func numberOfOverlayIndexes() -> Int {\n        overlayIndexToDynamicIndex.count\n    }\n\n    func dynamicIndex(forOverlayIndex index: Int) -> Int {\n        dynamicIndexToOverlayIndex[index] ?? 0\n    }\n\n    func overlayIndex(forDynamicIndex index: Int) -> Int {\n        overlayIndexToDynamicIndex[index] ?? 0\n    }\n\n    func height(forOverlayIndex index: Int) -> CGFloat {\n        overlayIndexToHeight[index] ?? 0\n    }\n\n    private func height(for dimension: NotchDimension,\n                        availableHeight: CGFloat) -> CGFloat {\n        switch dimension.type {\n        case .absolute:\n            return CGFloat(dimension.value)\n        case .fractional:\n            return availableHeight * CGFloat(dimension.value)\n        }\n    }\n}\n"
  },
  {
    "path": "Source/Internal/Utils/Binding+CaseIterable.swift",
    "content": "//\n//  Binding+CaseIterable.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\nextension Binding where Value: Equatable, Value: CaseIterable {\n\n    func indexBinding() -> Binding<Int> {\n        Binding<Int>(\n            get: {\n                Value.index(of: wrappedValue)\n            },\n            set: { index in\n                wrappedValue = Value.value(at: index)\n            }\n        )\n    }\n}\n\nextension CaseIterable where Self: Equatable {\n\n    static func index(of target: AllCases.Element) -> Int {\n        var index = 0\n        for value in allCases {\n            if value == target {\n                return index\n            }\n            index += 1\n        }\n        fatalError(\"Cannot find a valid index for \\(target)\")\n    }\n\n    static func value(at index: Int) -> AllCases.Element {\n        allCases[allCases.index(allCases.startIndex, offsetBy: index)]\n    }\n}\n"
  },
  {
    "path": "Source/Public/DynamicOverlayBehavior.swift",
    "content": "//\n//  DynamicOverlayBehavior.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\n/// A protocol that describes the overlay behavior.\npublic protocol DynamicOverlayBehavior {\n\n    func makeModifier() -> AddDynamicOverlayBehaviorModifier\n}\n"
  },
  {
    "path": "Source/Public/DynamicOverlayHandle.swift",
    "content": "//\n//  DynamicOverlayHandle.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 04/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\npublic extension View {\n\n    /// Defines the target as a draggable view.\n    ///\n    /// - parameter isActive: Boolean indicating whether the target is draggable.\n    func draggable(_ isActive: Bool = true) -> some View {\n        modifier(\n            ActiveOverlayAreaViewModifier(\n                key: DynamicOverlayDragAreaPreferenceKey.self,\n                isActive: isActive\n            )\n        )\n    }\n\n    /// Defines the target as the container of a driving scroll view.\n    /// When specified a driving scroll view coordinates its scrolling with the overlay translation.\n    ///\n    /// - parameter isActive: Boolean indicating whether the scroll view is active.\n    func drivingScrollView(_ isActive: Bool = true) -> some View {\n        modifier(\n            ActiveOverlayAreaViewModifier(\n                key: DynamicOverlayScrollViewProxyPreferenceKey.self,\n                isActive: isActive\n            )\n        )\n    }\n}\n"
  },
  {
    "path": "Source/Public/DynamicOverlayModifier.swift",
    "content": "//\n//  DynamicOverlayModifier.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 01/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\npublic extension View {\n\n    /// Adds a dynamic overlay above this view.\n    ///\n    /// - parameter content: the content of the overlay.\n    ///\n    /// - returns: A view with a dynamic overlay added above this view.\n    func dynamicOverlay<Content: View>(_ content: Content) -> some View {\n        modifier(AddDynamicOverlayModifier(overlay: content))\n    }\n\n    /// Sets the overlay behavior for dynamic overlays within this view.\n    ///\n    /// - parameter behavior: the behavior to apply.\n    ///\n    /// - returns: A view with the specified behavior set.\n    /// \n    /// This modifier affects the given view, as well as that view’s descendant views. It has no effect outside the view hierarchy on which you call it.\n    func dynamicOverlayBehavior<Behavior: DynamicOverlayBehavior>(_ behavior: Behavior) -> some View {\n        modifier(behavior.makeModifier())\n    }\n}\n\npublic struct AddDynamicOverlayModifier<Overlay: View>: ViewModifier {\n\n    let overlay: Overlay\n\n    // MARK: - ViewModifier\n\n    public func body(content: Content) -> some View {\n        OverlayContainerDynamicOverlayView(\n            background: content,\n            content: overlay\n        )\n    }\n}\n\npublic struct AddDynamicOverlayBehaviorModifier: ViewModifier {\n\n    let value: DynamicOverlayBehaviorValue\n\n    // MARK: - ViewModifier\n\n    public func body(content: Content) -> some View {\n        content.environment(\\.behaviorValue, value)\n    }\n}\n"
  },
  {
    "path": "Source/Public/MagneticNotchOverlayBehavior.swift",
    "content": "//\n//  MagneticNotchOverlayBehavior.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 02/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport SwiftUI\n\n/// A `DynamicOverlayBehavior` instance describing an overlay that can be dragged up and down alongside predefined notches.\n/// Whenever a drag gesture ends, the overlay motion will continue until it reaches one of its notches.\npublic struct MagneticNotchOverlayBehavior<Notch> where Notch: CaseIterable, Notch: Equatable {\n\n    let value: Value\n\n    /// Creates a behavior with the given notches.\n    ///\n    /// - parameter notches: The notches.\n    ///\n    /// - returns: A behavior with the specified notches.\n    public init(notches: @escaping (Notch) -> NotchDimension) {\n        self.value = Value(dimensions: notches)\n    }\n\n    init(value: Value) {\n        self.value = value\n    }\n}\n\npublic extension MagneticNotchOverlayBehavior {\n\n    /// The attributes of a translation\n    struct Translation {\n        /// The current overlay height.\n        public let height: CGFloat\n        /// The transaction associated to the translation.\n        public let transaction: Transaction\n        /// The overlay translation progress (from 0.0 to 1.0).\n        public let progress: Double\n        /// The overlay container size.\n        public let containerSize: CGSize\n\n        let heightForNotch: (Notch) -> CGFloat\n\n        /// returns the height of the given notch.\n        public func height(for notch: Notch) -> CGFloat {\n            heightForNotch(notch)\n        }\n    }\n\n    /// Adds an action to perform when the overlay moves.\n    ///\n    /// - parameter action: The action to perform when the translation changes. The action closure’s parameter contains the current translation.\n    ///\n    /// - returns: A version of the behavior that triggers the action when the translation changes.\n    func onTranslation(_ action: @escaping (Translation) -> Void) -> Self {\n        MagneticNotchOverlayBehavior(value: value.appending(action))\n    }\n}\n\npublic extension MagneticNotchOverlayBehavior {\n\n    /// Updates the current overlay notch as it changes.\n    ///\n    /// - parameter binding: A binding to a notch property.\n    ///\n    /// - returns: A version of the behavior that updates the current overlay notch as it changes.\n    func notchChange(_ binding: Binding<Notch>) -> Self {\n        MagneticNotchOverlayBehavior(value: value.setting(binding))\n    }\n}\n\npublic extension MagneticNotchOverlayBehavior {\n\n    /// Disables a notch.\n    ///\n    /// - parameter notch: The notch to disable.\n    /// - parameter isDisabled: A boolean indicating whether the notch should be disabled.\n    ///\n    /// - returns: A version of the behavior that disables the specified notch.\n    ///\n    /// When a notch is disabled the overlay can not be dragged to it.\n    /// The `notchChange` binding is still effective though.\n    func disable(_ notch: Notch, _ isDisabled: Bool = true) -> Self {\n        MagneticNotchOverlayBehavior(value: value.disabling(isDisabled, notch))\n    }\n}\n\nextension MagneticNotchOverlayBehavior: DynamicOverlayBehavior {\n\n    public func makeModifier() -> AddDynamicOverlayBehaviorModifier {\n        AddDynamicOverlayBehaviorModifier(value: buildValue())\n    }\n}\n\n/// A dimension of a notch.\npublic struct NotchDimension: Hashable {\n\n    let type: ValueType\n    let value: Double\n}\n\npublic extension NotchDimension {\n\n    /// Creates a dimension with an absolute point value.\n    static func absolute(_ value: Double) -> NotchDimension {\n        NotchDimension(type: .absolute, value: value)\n    }\n\n    /// Creates a dimension that is computed as a fraction of the height of the overlay parent view.\n    static func fractional(_ value: Double) -> NotchDimension {\n        NotchDimension(type: .fractional, value: value)\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/DragHandleViewModifierTests.swift",
    "content": "//\n//  DragHandleTests.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport SwiftUI\n@testable import DynamicOverlay\n\nprivate struct HandleView: View {\n\n    var body: some View {\n        Color.red\n    }\n}\n\nprivate struct ContainerView: View {\n\n    let isActive: Bool\n    let frame: CGRect\n    let handler: (DynamicOverlayDragArea) -> Void\n\n    var body: some View {\n        GeometryReader { _ in\n            HandleView()\n                .frame(width: frame.width, height: frame.height)\n                .draggable(isActive)\n                .offset(x: frame.origin.x, y: frame.origin.y)\n        }\n        .onDragAreaChange(handler: handler)\n        .overlayCoordinateSpace()\n    }\n}\n\nprivate struct MultipleHandlesView: View {\n\n    let handler: (DynamicOverlayDragArea) -> Void\n\n    var body: some View {\n        VStack {\n            Color.orange.draggable()\n            Color.red.draggable()\n        }\n        .overlayCoordinateSpace()\n        .onDragAreaChange(handler: handler)\n    }\n}\n\nclass DragHandleViewModifierTests: XCTestCase {\n\n    func testActiveState() {\n        let frame = CGRect(x: 0, y: 0, width: 200, height: 200)\n        let activeHandle = DynamicOverlayDragArea(area: .active(frame))\n        let notActiveHandle = DynamicOverlayDragArea(area: .inactive())\n        let point = CGPoint(x: 20.0, y: 20.0)\n        XCTAssertTrue(activeHandle.contains(point))\n        XCTAssertFalse(notActiveHandle.contains(point))\n    }\n\n    func testMultipleFrames() {\n        let values: [(Bool, CGRect)] = [\n            (true, CGRect(x: 30, y: 30, width: 50, height: 100)),\n            (false, CGRect(x: 0, y: 0, width: 400, height: 400)),\n            (true, CGRect(x: 0, y: 0, width: 400, height: 400)),\n        ]\n        values.forEach { isActive, frame in\n            let expectation = XCTestExpectation()\n            let view = ContainerView(\n                isActive: isActive,\n                frame: frame,\n                handler: { handler in\n                    XCTAssertEqual(handler.contains(frame), isActive)\n                    expectation.fulfill()\n                }\n            )\n            ViewRenderer(view: view).render()\n            wait(for: [expectation], timeout: 0.3)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/DrivingScrollViewModifierTests.swift",
    "content": "//\n//  DrivingScrollViewModifierTests.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport SwiftUI\n@testable import DynamicOverlay\n\nprivate struct ContainerView: View {\n\n    let isActive: Bool\n    let isActiveHandler: (DynamicOverlayScrollViewProxy) -> Void\n\n    var body: some View {\n        ScrollView {\n            Color.green\n        }\n        .overlayCoordinateSpace()\n        .drivingScrollView(isActive)\n        .onDrivingScrollViewChange(handler: isActiveHandler)\n    }\n}\n\nprivate class IdentifiedScrollView: UIScrollView {\n    var id = \"\"\n}\n\nclass DrivingScrollViewModifierTests: XCTestCase {\n\n    func testScrollViewSearch() {\n        let container = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))\n        let layer = UIView(frame: container.bounds)\n        container.addSubview(layer)\n        let scrollViews = Array(repeating: IdentifiedScrollView(), count: 4)\n        for i in scrollViews.indices {\n            let scrollView = scrollViews[i]\n            scrollView.frame.size.height = container.bounds.height / 2\n            scrollView.frame.size.width = container.bounds.width / 2\n            scrollView.frame.origin.x = container.bounds.width / 2 * CGFloat(i % 2)\n            scrollView.frame.origin.y = i > 1 ? container.bounds.height / 2 : 0\n            if i.isMultiple(of: 2) {\n                layer.addSubview(scrollView)\n            } else {\n                container.addSubview(scrollView)\n            }\n        }\n        for scrollView in scrollViews {\n            scrollViews.forEach { $0.id = \"lure\" }\n            scrollView.id = \"target\"\n            let proxy = DynamicOverlayScrollViewProxy(\n                area: .active(scrollView.frame)\n            )\n            let scrollView = proxy.findScrollView(in: container) as! IdentifiedScrollView\n            XCTAssertEqual(scrollView.id, \"target\")\n        }\n    }\n\n    func testDrivingScrollView() {\n        [false, true].forEach { shouldBeActive in\n            let expectation = XCTestExpectation()\n            var window: UIWindow!\n            let view = ContainerView(\n                isActive: shouldBeActive,\n                isActiveHandler: { handle in\n                    CATransaction.setCompletionBlock {\n                        if shouldBeActive {\n                            XCTAssertNotNil(handle.findScrollView(in: window))\n                        } else {\n                            XCTAssertNil(handle.findScrollView(in: window))\n                        }\n                        expectation.fulfill()\n                    }\n                }\n            )\n            let renderer = ViewRenderer(view: view)\n            window = renderer.window\n            renderer.render()\n            wait(for: [expectation], timeout: 0.1)\n        }\n    }\n\n    func testNoneDrivingScrollView() {\n        let expectation = XCTestExpectation()\n        expectation.isInverted = true\n        let view = Color.red.onDrivingScrollViewChange { _ in\n            expectation.fulfill()\n        }\n        ViewRenderer(view: view).render()\n        wait(for: [expectation], timeout: 0.1)\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/MagneticNotchOverlayBehaviorValueTests.swift",
    "content": "//\n//  MagneticNotchOverlayBehaviorValueTests.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport SwiftUI\n@testable import DynamicOverlay\n\nprivate enum Constant {\n\n    static func dimension(for notch: TestNotch) -> NotchDimension {\n        switch notch {\n        case .min:\n            return .fractional(0.3)\n        case .max:\n            return .fractional(0.5)\n        }\n    }\n}\n\nprivate enum TestNotch: CaseIterable, Equatable {\n    case min, max\n}\n\nprivate typealias Behavior = MagneticNotchOverlayBehavior<TestNotch>\n\nclass MagneticNotchOverlayBehaviorValueTests: XCTestCase {\n\n    func testDisabledIndexesOverlayValue() {\n        var behavior = Behavior.empty()\n        XCTAssertEqual(behavior.buildValue().disabledNotchIndexes, [])\n        behavior = behavior.disable(.min)\n        XCTAssertEqual(behavior.buildValue().disabledNotchIndexes, [0])\n        behavior = behavior.disable(.max)\n        XCTAssertEqual(behavior.buildValue().disabledNotchIndexes, [0, 1])\n    }\n\n    func testNotchChangeOverlayValue() {\n        var behavior = Behavior.empty()\n        XCTAssertTrue(behavior.buildValue().binding == nil)\n        behavior = behavior.notchChange(.constant(.min))\n        XCTAssertTrue(behavior.buildValue().binding?.wrappedValue == 0)\n        behavior = behavior.notchChange(.constant(.max))\n        XCTAssertTrue(behavior.buildValue().binding?.wrappedValue == 1)\n    }\n\n    func testNotchDimensionOverlayValue() {\n        XCTAssertEqual(\n            Behavior.empty().buildValue().notchDimensions,\n            [\n                0: Constant.dimension(for: .min),\n                1: Constant.dimension(for: .max),\n            ]\n        )\n    }\n\n    func testBlockOverlayValue() {\n        var behavior = Behavior.empty()\n        XCTAssertTrue(behavior.buildValue().block == nil)\n        behavior = behavior.onTranslation { _ in }\n        XCTAssertTrue(behavior.buildValue().block != nil)\n        behavior = behavior.onTranslation { _ in }\n        XCTAssertTrue(behavior.buildValue().block != nil)\n    }\n\n    func testTranslationMapping() {\n        let expectation = XCTestExpectation()\n        let overlayTranslations = OverlayTranslation.translations()\n        let expectedTranslations = Behavior.Translation.translations()\n        XCTAssertEqual(overlayTranslations.count, expectedTranslations.count)\n        expectation.expectedFulfillmentCount = overlayTranslations.count\n        class Context {\n            var translation: Behavior.Translation!\n        }\n        let context = Context()\n        let action = { (translation: Behavior.Translation) in\n            XCTAssertEqual(context.translation.containerSize, translation.containerSize)\n            XCTAssertEqual(context.translation.height, translation.height)\n            XCTAssertEqual(context.translation.progress, translation.progress)\n            TestNotch.allCases.forEach {\n                XCTAssertEqual(context.translation.height(for: $0), translation.height(for: $0))\n            }\n            expectation.fulfill()\n        }\n        zip(overlayTranslations, expectedTranslations).forEach { value, translation in\n            context.translation = translation\n            Behavior.empty().onTranslation(action).buildValue().block?(value)\n        }\n    }\n}\n\nprivate extension MagneticNotchOverlayBehavior.Translation where Notch == TestNotch {\n\n    static func translations() -> [Self] {\n        [\n            Behavior.Translation(\n                height: 30.0,\n                transaction: Transaction(),\n                progress: 0.0,\n                containerSize: CGSize(width: 30.0, height: 30.0),\n                heightForNotch: {\n                    switch $0 {\n                    case .max:\n                        return 400\n                    case .min:\n                        return 200\n                    }\n                }\n            ),\n            Behavior.Translation(\n                height: 30.0,\n                transaction: Transaction(),\n                progress: 0.0,\n                containerSize: CGSize(width: 30.0, height: 30.0),\n                heightForNotch: {\n                    switch $0 {\n                    case .max:\n                        return 400\n                    case .min:\n                        return 200\n                    }\n                }\n            ),\n            Behavior.Translation(\n                height: 30.0,\n                transaction: Transaction(),\n                progress: 0.5,\n                containerSize: CGSize(width: 30.0, height: 30.0),\n                heightForNotch: {\n                    switch $0 {\n                    case .max:\n                        return 400\n                    case .min:\n                        return 200\n                    }\n                }\n            ),\n            Behavior.Translation(\n                height: 10.0,\n                transaction: Transaction(),\n                progress: 1.0,\n                containerSize: CGSize(width: 60.0, height: 90.0),\n                heightForNotch: {\n                    switch $0 {\n                    case .max:\n                        return 400\n                    case .min:\n                        return 200\n                    }\n                }\n            )\n        ]\n    }\n}\n\nprivate extension OverlayTranslation {\n\n    static func translations() -> [OverlayTranslation] {\n        [\n            OverlayTranslation(\n                height: 30.0,\n                transaction: Transaction(),\n                isDragging: false,\n                translationProgress: 0.0,\n                containerFrame: CGRect(origin: .zero, size: CGSize(width: 30.0, height: 30.0)),\n                velocity: .zero,\n                heightForNotchIndex: { i -> CGFloat in\n                    switch i {\n                    case 0:\n                        return 200.0\n                    case 1:\n                        return 400.0\n                    default:\n                        fatalError()\n                    }\n                }\n            ),\n            OverlayTranslation(\n                height: 30.0,\n                transaction: Transaction(),\n                isDragging: false,\n                translationProgress: -1.0,\n                containerFrame: CGRect(origin: .zero, size: CGSize(width: 30.0, height: 30.0)),\n                velocity: .zero,\n                heightForNotchIndex: { i -> CGFloat in\n                    switch i {\n                    case 0:\n                        return 200.0\n                    case 1:\n                        return 400.0\n                    default:\n                        fatalError()\n                    }\n                }\n            ),\n            OverlayTranslation(\n                height: 30.0,\n                transaction: Transaction(),\n                isDragging: false,\n                translationProgress: 0.5,\n                containerFrame: CGRect(origin: .zero, size: CGSize(width: 30.0, height: 30.0)),\n                velocity: .zero,\n                heightForNotchIndex: { i -> CGFloat in\n                    switch i {\n                    case 0:\n                        return 200.0\n                    case 1:\n                        return 400.0\n                    default:\n                        fatalError()\n                    }\n                }\n            ),\n            OverlayTranslation(\n                height: 10.0,\n                transaction: Transaction(),\n                isDragging: false,\n                translationProgress: 1.5,\n                containerFrame: CGRect(origin: .zero, size: CGSize(width: 60.0, height: 90.0)),\n                velocity: .zero,\n                heightForNotchIndex: { i -> CGFloat in\n                    switch i {\n                    case 0:\n                        return 200.0\n                    case 1:\n                        return 400.0\n                    default:\n                        fatalError()\n                    }\n                }\n            )\n        ]\n    }\n}\n\nprivate extension Behavior {\n\n    static func empty() -> Self {\n        Behavior { Constant.dimension(for: $0) }\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/NotchBindingDynamicOverlayTests.swift",
    "content": "//\n//  NotchBindingDynamicOverlayTests.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 10/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport XCTest\nimport DynamicOverlay\n\nprivate enum Notch: CaseIterable, Equatable {\n    case min\n    case max\n}\n\nprivate struct Constants {\n\n    static func height(for notch: Notch) -> CGFloat {\n        switch notch {\n        case .max:\n            return 300.0\n        case .min:\n            return 200.0\n        }\n    }\n}\n\nprivate struct NotchChangeView: View {\n\n    @ObservedObject\n    var target: ValuePublisher<Notch>\n    let onFrameChange: (CGRect) -> Void\n\n    var body: some View {\n        Color.red\n            .dynamicOverlay(Color.green.onFrameChange(onFrameChange))\n            .dynamicOverlayBehavior(behavior)\n    }\n\n    var behavior: some DynamicOverlayBehavior {\n        MagneticNotchOverlayBehavior<Notch> { notch in\n            .absolute(Double(Constants.height(for: notch)))\n        }\n        .notchChange($target.value)\n    }\n}\n\nclass NotchBindingDynamicOverlayTests: XCTestCase {\n\n    func testInitialMaxNotch() {\n        expectNotchHeight(.max)\n    }\n\n    func testInitialMinNotch() {\n        expectNotchHeight(.min)\n    }\n\n    func testNotchChange() {\n        class Context {\n            var expectedHeight: CGFloat = 0.0\n            var current = Notch.min\n            var displayedFrame = CGRect.zero\n            var expectations: [Notch: XCTestExpectation] = [:]\n        }\n        let target = ValuePublisher(Notch.min)\n        let notches: [Notch] = [.min, .max]\n        let context = Context()\n        context.expectations = Dictionary(uniqueKeysWithValues: notches.map { ($0, XCTestExpectation()) })\n        let view = NotchChangeView(target: target) { rect in\n            context.displayedFrame = rect\n            context.expectations[context.current]?.fulfill()\n        }\n        let renderer = ViewRenderer(view: view)\n        notches.forEach { notch in\n            guard let expectation = context.expectations[notch] else { return }\n            context.current = notch\n            target.update(notch)\n            renderer.render()\n            wait(for: [expectation], timeout: 1.0)\n            let overlayFrame = renderer.window.bounds.intersection(context.displayedFrame)\n            XCTAssertEqual(overlayFrame.height, Constants.height(for: notch))\n            context.displayedFrame = .zero\n        }\n    }\n\n    private func expectNotchHeight(_ notch: Notch) {\n        let target = ValuePublisher(notch)\n        var displayedFrame: CGRect = .zero\n        let view = NotchChangeView(target: target) { rect in\n            displayedFrame = rect\n        }\n        let renderer = ViewRenderer(view: view)\n        renderer.render()\n        let overlayFrame = renderer.window.bounds.intersection(displayedFrame)\n        XCTAssertEqual(overlayFrame.height, Constants.height(for: notch))\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/NotchDimensionDynamicOverlayTests.swift",
    "content": "//\n//  NotchDimensionDynamicOverlayTests.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport SwiftUI\nimport DynamicOverlay\n\nprivate enum Notch: CaseIterable, Equatable {\n    case min\n}\n\nprivate struct NotchDimensionView: View {\n\n    let dimension: () -> NotchDimension\n    let onHeightChange: (CGFloat) -> Void\n\n    var body: some View {\n        Color.red\n            .dynamicOverlay(Color.green.onHeightChange(onHeightChange))\n            .dynamicOverlayBehavior(behavior)\n    }\n\n    var behavior: some DynamicOverlayBehavior {\n        MagneticNotchOverlayBehavior<Notch> { _ in\n            dimension()\n        }\n    }\n}\n\nclass NotchDimensionDynamicOverlayTests: XCTestCase {\n\n    func testVariousDimensions() {\n        class Context {\n            var dimension: NotchDimension = .absolute(0)\n            var expectedHeight: CGFloat = 0.0\n            var expectation = XCTestExpectation()\n        }\n        let renderer = ViewRenderer(view: EmptyView())\n        let resultByDimension: [NotchDimension: CGFloat] = [\n            .absolute(-1) : 0.0,\n            .absolute(0) : 0.0,\n            .absolute(200.0) : 200.0,\n            .fractional(-1.0) : 0.0,\n            .fractional(0.0) : 0.0,\n            .fractional(2.0) : renderer.safeBounds.height * 2.0,\n            .fractional(0.5) : renderer.safeBounds.height * 0.5,\n        ]\n        resultByDimension.forEach { dimension, expectedHeight in\n            let context = Context()\n            let view = NotchDimensionView(dimension: { context.dimension }) { height in\n                context.expectation.fulfill()\n                XCTAssertEqual(context.expectedHeight.rounded(.up), height.rounded(.up))\n            }\n            context.expectedHeight = expectedHeight\n            context.expectation = XCTestExpectation()\n            context.dimension = dimension\n            ViewRenderer(view: view).render()\n            wait(for: [context.expectation], timeout: 0.3)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/NotchTranslationDynamicOverlayTests.swift",
    "content": "//\n//  NotchTranslationDynamicOverlayTests.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 15/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\nimport XCTest\n@testable import DynamicOverlay\n\nprivate enum Notch: CaseIterable, Equatable {\n    case min, max\n}\n\nprivate struct Constants {\n\n    static func insets(for layout: TranslationLayout) -> UIEdgeInsets {\n        switch layout {\n        case .compact:\n            return UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)\n        case .full:\n            return .zero\n        }\n    }\n\n    static func height(for notch: Notch) -> CGFloat {\n        switch notch {\n        case .max:\n            return 300.0\n        case .min:\n            return 100.0\n        }\n    }\n}\n\nprivate typealias OverlayTranslation = MagneticNotchOverlayBehavior<Notch>.Translation\n\nprivate struct TranslationView: View {\n\n    @ObservedObject\n    var target: ValuePublisher<Notch>\n    let onTranslation: (OverlayTranslation) -> Void\n\n    var body: some View {\n        Color.red\n            .dynamicOverlay(Color.green)\n            .dynamicOverlayBehavior(behavior)\n    }\n\n    private var behavior: MagneticNotchOverlayBehavior<Notch> {\n        MagneticNotchOverlayBehavior { notch in\n            .absolute(Double(Constants.height(for: notch)))\n        }\n        .notchChange($target.value)\n        .onTranslation(onTranslation)\n        .disable(.min)\n    }\n}\n\nprivate enum TranslationLayout {\n    case full, compact\n}\n\nprivate struct TranslationContainerView: View {\n\n    let layout: TranslationLayout\n    @ObservedObject\n    var target: ValuePublisher<Notch>\n    let onTranslation: (OverlayTranslation) -> Void\n\n    var body: some View {\n        TranslationView(\n            target: target,\n            onTranslation: onTranslation\n        )\n        .padding(insets)\n    }\n\n    private var insets: EdgeInsets {\n        let layoutInsets = Constants.insets(for: layout)\n        return EdgeInsets(\n            top: layoutInsets.top,\n            leading: layoutInsets.left,\n            bottom: layoutInsets.bottom,\n            trailing: layoutInsets.bottom\n        )\n    }\n}\n\nclass NotchTranslationDynamicOverlayTests: XCTestCase {\n\n    func testInitialTranslation() {\n        class Context {\n            var expectedTranslation = OverlayTranslation.none\n        }\n        let context = Context()\n        let expectation = XCTestExpectation()\n        expectation.expectedFulfillmentCount = Notch.allCases.count\n        Notch.allCases.forEach { notch in\n            let target = ValuePublisher(notch)\n            let view = TranslationView(target: target) { translation in\n                expectation.fulfill()\n                self.expect(translation, toEqual: context.expectedTranslation)\n            }\n            let renderer = ViewRenderer(view: view)\n            context.expectedTranslation = .initial(for: notch, in: renderer.safeBounds)\n            renderer.render()\n        }\n        wait(for: [expectation], timeout: 1.0)\n    }\n\n    func testNotchMovesTranslation() {\n        class Context {\n            var expectedTranslation = OverlayTranslation.none\n            var expectation = XCTestExpectation()\n        }\n        let context = Context()\n        let target = ValuePublisher(Notch.min)\n        let view = TranslationView(target: target) { translation in\n            context.expectation.fulfill()\n            self.expect(translation, toEqual: context.expectedTranslation)\n        }\n        // Initial\n        let renderer = ViewRenderer(view: view)\n        context.expectedTranslation = .initial(for: .min, in: renderer.safeBounds)\n        renderer.render()\n        wait(for: [context.expectation], timeout: 0.3)\n        // Max not animated\n        context.expectation = XCTestExpectation()\n        context.expectedTranslation = .moved(to: .max, animated: false, in: renderer.safeBounds)\n        target.update(.max)\n        wait(for: [context.expectation], timeout: 0.3)\n        // Min animated\n        context.expectation = XCTestExpectation()\n        context.expectedTranslation = .moved(to: .min, animated: true, in: renderer.safeBounds)\n        withAnimation {\n            target.update(.min)\n        }\n        wait(for: [context.expectation], timeout: 0.3)\n        // Max animated\n        context.expectation = XCTestExpectation()\n        context.expectedTranslation = .moved(to: .max, animated: true, in: renderer.safeBounds)\n        withAnimation {\n            target.update(.max)\n        }\n        wait(for: [context.expectation], timeout: 0.3)\n    }\n\n    func testLayoutChangesTranslation() {\n        class Context {\n            var expected = OverlayTranslation.none\n        }\n        let layouts: [TranslationLayout] = [.compact, .full]\n        layouts.forEach { layout in\n            let context = Context()\n            let expectation = XCTestExpectation()\n            let target = ValuePublisher(Notch.min)\n            let view = TranslationContainerView(\n                layout: layout,\n                target: target,\n                onTranslation: { translation in\n                    expectation.fulfill()\n                    self.expect(translation, toEqual: context.expected)\n                }\n            )\n            let renderer = ViewRenderer(view: view)\n            context.expected = .layout(layout, in: renderer.safeBounds)\n            renderer.render()\n            wait(for: [expectation], timeout: 0.3)\n        }\n    }\n\n    // MARK: - Private\n\n    private func expect(_ lhs: OverlayTranslation, toEqual rhs: OverlayTranslation) {\n        XCTAssertEqual(lhs.containerSize, rhs.containerSize)\n        XCTAssertEqual(lhs.progress, rhs.progress)\n        XCTAssertEqual(lhs.height, rhs.height)\n        let lhsHasAnimation = lhs.transaction.animation != nil\n        let rhsHasAnimation = rhs.transaction.animation != nil\n        XCTAssertEqual(lhsHasAnimation, rhsHasAnimation)\n        Notch.allCases.forEach {\n            XCTAssertEqual(lhs.height(for: $0), rhs.height(for: $0))\n        }\n    }\n}\n\nprivate extension OverlayTranslation {\n\n    static var none: OverlayTranslation {\n        OverlayTranslation(height: 0, transaction: Transaction(), progress: 0, containerSize: .zero, heightForNotch: { _ in 0 })\n    }\n\n    static func initial(for notch: Notch, in bounds: CGRect) -> OverlayTranslation {\n        .notch(notch, animated: false, in: bounds)\n    }\n\n    static func moved(to notch: Notch, animated: Bool, in bounds: CGRect) -> OverlayTranslation {\n        .notch(notch, animated: animated, in: bounds)\n    }\n\n    static func layout(_ layout: TranslationLayout, in bounds: CGRect) -> OverlayTranslation {\n        OverlayTranslation(\n            height: Constants.height(for: .min),\n            transaction: Transaction(),\n            progress: 0.0,\n            containerSize: bounds.inset(by: Constants.insets(for: layout)).size,\n            heightForNotch: Constants.height(for:)\n        )\n    }\n\n    private static func notch(_ notch: Notch, animated: Bool, in bounds: CGRect) -> OverlayTranslation {\n        OverlayTranslation(\n            height: Constants.height(for: notch),\n            transaction: Transaction(animation: animated ? .default : nil),\n            progress: notch == .max ? 1.0 : 0.0,\n            containerSize: bounds.size,\n            heightForNotch: Constants.height(for:)\n        )\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/OverlayContainerRepresentableAdaptorTests.swift",
    "content": "//\n//  OverlayContainerRepresentableAdaptorTests.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 20/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\nimport SwiftUI\nimport OverlayContainer\n@testable import DynamicOverlay\n\nprivate struct AdaptorParameters {\n    var drivingHandle: DynamicOverlayScrollViewProxy\n    var handleValue: DynamicOverlayDragArea\n    var disabledNotches: Set<Int> = []\n    var indexToDimension: [Int: NotchDimension] = [:]\n    var onIndexChange: ((Int) -> Void)?\n}\n\nclass OverlayContainerRepresentableAdaptorTests: XCTestCase {\n\n    class Context {\n        let container: OverlayContainerViewController\n        let coordinator: OverlayContainerCoordinator\n\n        var overlay: UIViewController {\n            container.topViewController!\n        }\n\n        init(container: OverlayContainerViewController,\n             coordinator: OverlayContainerCoordinator) {\n            self.container = container\n            self.coordinator = coordinator\n        }\n\n        func layout() {\n            container.view.frame = CGRect(origin: .zero, size: CGSize(width: 400, height: 400))\n            container.view.layoutIfNeeded()\n        }\n    }\n\n    func testViewControllersSetup() {\n        let context = makeContext(\n            for: AdaptorParameters(\n                drivingHandle: .default,\n                handleValue: .default,\n                indexToDimension: [0: .absolute(200.0)]\n            )\n        )\n        context.layout()\n        XCTAssertEqual(context.container.viewControllers.count, 2)\n    }\n\n    func testDefaultDraggingStart() {\n        let context = makeContext(\n            for: AdaptorParameters(\n                drivingHandle: .default,\n                handleValue: .default,\n                indexToDimension: [0: .absolute(200.0)]\n            )\n        )\n        context.layout()\n        let aboveOverlayPoint = CGPoint(x: 100, y: -10)\n        XCTAssertEqual(\n            context.container.delegate?.overlayContainerViewController(\n                context.container,\n                shouldStartDraggingOverlay: context.overlay,\n                at: aboveOverlayPoint,\n                in: context.overlay.view\n            ),\n            false\n        )\n        let inOverlayPoint = CGPoint(x: 100, y: 100)\n        XCTAssertEqual(\n            context.container.delegate?.overlayContainerViewController(\n                context.container,\n                shouldStartDraggingOverlay: context.overlay,\n                at: inOverlayPoint,\n                in: context.overlay.view\n            ),\n            true\n        )\n    }\n\n    func testDisabledDraggingStart() {\n        let context = makeContext(\n            for: AdaptorParameters(\n                drivingHandle: .default,\n                handleValue: DynamicOverlayDragArea(area: .inactive()),\n                indexToDimension: [0: .absolute(200.0)]\n            )\n        )\n        context.layout()\n        let aboveOverlayPoint = CGPoint(x: 100, y: -10)\n        XCTAssertEqual(\n            context.container.delegate?.overlayContainerViewController(\n                context.container,\n                shouldStartDraggingOverlay: context.overlay,\n                at: aboveOverlayPoint,\n                in: context.overlay.view\n            ),\n            false\n        )\n        let inOverlayPoint = CGPoint(x: 100, y: 100)\n        XCTAssertEqual(\n            context.container.delegate?.overlayContainerViewController(\n                context.container,\n                shouldStartDraggingOverlay: context.overlay,\n                at: inOverlayPoint,\n                in: context.overlay.view\n            ),\n            false\n        )\n    }\n\n    func testEnabledDraggingStart() {\n        let context = makeContext(\n            for: AdaptorParameters(\n                drivingHandle: .default,\n                handleValue: DynamicOverlayDragArea(\n                    area: .active(CGRect(origin: .zero, size: CGSize(width: 200, height: 300)))\n                ),\n                indexToDimension: [0: .absolute(200.0)]\n            )\n        )\n        context.layout()\n        let inZonePoint = CGPoint(x: 100, y: 100)\n        XCTAssertEqual(\n            context.container.delegate?.overlayContainerViewController(\n                context.container,\n                shouldStartDraggingOverlay: context.overlay,\n                at: inZonePoint,\n                in: context.overlay.view\n            ),\n            true\n        )\n        let outZonePoint = CGPoint(x: 300, y: 100)\n        XCTAssertEqual(\n            context.container.delegate?.overlayContainerViewController(\n                context.container,\n                shouldStartDraggingOverlay: context.overlay,\n                at: outZonePoint,\n                in: context.overlay.view\n            ),\n            false\n        )\n    }\n\n    func testOverlayMoveNotification() {\n        var index = 0\n        let context = makeContext(\n            for: AdaptorParameters(\n                drivingHandle: .default,\n                handleValue: DynamicOverlayDragArea(area: .default),\n                indexToDimension: [0: .absolute(200.0), 1: .absolute(300.0)],\n                onIndexChange: { index = $0 }\n            )\n        )\n        context.layout()\n        context.container.moveOverlay(toNotchAt: 1, animated: false)\n        context.layout()\n        XCTAssertEqual(index, 1)\n    }\n\n    func testNumberOfNotches() {\n        let dimensions: [[Int: NotchDimension]] = [\n            [0: .absolute(200)],\n            [0: .absolute(200), 1: .absolute(300)],\n            [0: .absolute(200), 1: .absolute(300), 3: .absolute(400)],\n        ]\n        dimensions.forEach { layout in\n            let context = makeContext(\n                for: AdaptorParameters(\n                    drivingHandle: .default,\n                    handleValue: .default,\n                    indexToDimension: layout\n                )\n            )\n            context.layout()\n            XCTAssertEqual(\n                context.container.delegate?.numberOfNotches(in: context.container) ?? 0,\n                layout.count\n            )\n        }\n    }\n\n    func testDisabledNotches() {\n        let all: [Int] = [0, 1, 2]\n        let indexes: [Set<Int>] = [\n            [],\n            [0],\n            [0, 1],\n            [0, 1, 2],\n            [2],\n        ]\n        indexes.forEach { disabledIndexes in\n            let context = makeContext(\n                for: AdaptorParameters(\n                    drivingHandle: .default,\n                    handleValue: .default,\n                    disabledNotches: disabledIndexes,\n                    indexToDimension: Dictionary(uniqueKeysWithValues: all.map { ($0, .absolute(100 * Double($0))) })\n                )\n            )\n            context.layout()\n            Set(all).subtracting(disabledIndexes).forEach { index in\n                XCTAssertEqual(\n                    context.container.delegate?.overlayContainerViewController(\n                        context.container,\n                        canReachNotchAt: index,\n                        forOverlay: context.overlay\n                    ) ?? false,\n                    true\n                )\n            }\n            disabledIndexes.forEach { index in\n                XCTAssertEqual(\n                    context.container.delegate?.overlayContainerViewController(\n                        context.container,\n                        canReachNotchAt: index,\n                        forOverlay: context.overlay\n                    ) ?? true,\n                    false\n                )\n            }\n        }\n    }\n\n    private func makeContext(for parameters: AdaptorParameters) -> Context {\n        let holder = OverlayContainerPassiveContainer()\n        holder.onNotchChange = parameters.onIndexChange\n        let adaptor = OverlayContainerRepresentableAdaptor.init(\n            containerState: OverlayContainerState(\n                dragArea: parameters.handleValue,\n                drivingScrollViewProxy: parameters.drivingHandle,\n                notchIndex: nil,\n                disabledNotches: parameters.disabledNotches,\n                layout: OverlayContainerLayout(indexToDimension: parameters.indexToDimension)\n            ),\n            passiveContainer: holder,\n            content: ContentView(),\n            background: Color.green\n        )\n        let coordinator = adaptor.makeCoordinator()\n        let context = OverlayContainerRepresentableAdaptor<ContentView, Color>.Context(\n            coordinator: coordinator,\n            transaction: Transaction()\n        )\n        let container = adaptor.makeUIViewController(context: context)\n        adaptor.updateUIViewController(container, context: context)\n        return Context(container: container, coordinator: coordinator)\n    }\n}\n\nprivate struct ContentView: View {\n\n    var body: some View {\n        List { Text(\"\") }\n    }\n}\n\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/OverlayNotchIndexMapperTests.swift",
    "content": "//\n//  OverlayNotchIndexMapperTests.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 29/12/2020.\n//  Copyright © 2020 Fabernovel. All rights reserved.\n//\n\nimport XCTest\n@testable import DynamicOverlay\n\nclass OverlayNotchIndexMapperTests: XCTestCase {\n\n    private var mapper: OverlayNotchIndexMapper!\n\n    override func setUp() {\n        self.mapper = OverlayNotchIndexMapper()\n    }\n\n    func testAlreadyOrderedIndexesMapping() {\n        let layout = OverlayContainerLayout(\n            indexToDimension: [\n                0: NotchDimension(type: .fractional, value: 0.1),\n                1: NotchDimension(type: .fractional, value: 0.2),\n                2: NotchDimension(type: .fractional, value: 0.3),\n            ]\n        )\n        mapper.reload(\n            layout: layout,\n            availableHeight: 200.0\n        )\n        XCTAssert(mapper.numberOfOverlayIndexes() == 3)\n        XCTAssert(mapper.dynamicIndex(forOverlayIndex: 0) == 0)\n        XCTAssert(mapper.dynamicIndex(forOverlayIndex: 1) == 1)\n        XCTAssert(mapper.dynamicIndex(forOverlayIndex: 2) == 2)\n        XCTAssert(mapper.overlayIndex(forDynamicIndex: 0) == 0)\n        XCTAssert(mapper.overlayIndex(forDynamicIndex: 1) == 1)\n        XCTAssert(mapper.overlayIndex(forDynamicIndex: 2) == 2)\n    }\n\n    func testFractionalNotchDimensionReordering() {\n        let layout = OverlayContainerLayout(\n            indexToDimension: [\n                0: NotchDimension(type: .absolute, value: 100),\n                1: NotchDimension(type: .fractional, value: 0.1),\n            ]\n        )\n        mapper.reload(\n            layout: layout,\n            availableHeight: 200.0\n        )\n        XCTAssert(mapper.numberOfOverlayIndexes() == 2)\n        XCTAssert(mapper.dynamicIndex(forOverlayIndex: 0) == 1)\n        XCTAssert(mapper.dynamicIndex(forOverlayIndex: 1) == 0)\n        XCTAssert(mapper.overlayIndex(forDynamicIndex: 1) == 0)\n        XCTAssert(mapper.overlayIndex(forDynamicIndex: 0) == 1)\n    }\n\n    func testNotchFractionalHeights() {\n        let layout = OverlayContainerLayout(\n            indexToDimension: [\n                0: NotchDimension(type: .fractional, value: 0.1),\n                1: NotchDimension(type: .fractional, value: 0.5),\n                2: NotchDimension(type: .fractional, value: 1),\n            ]\n        )\n        mapper.reload(\n            layout: layout,\n            availableHeight: 200.0\n        )\n        XCTAssert(mapper.numberOfOverlayIndexes() == 3)\n        XCTAssert(mapper.height(forOverlayIndex: 0) == 20.0)\n        XCTAssert(mapper.height(forOverlayIndex: 1) == 100.0)\n        XCTAssert(mapper.height(forOverlayIndex: 2) == 200.0)\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/Utils/ValuePublisher.swift",
    "content": "//\n//  ValuePublisher.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 15/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\n\nclass ValuePublisher<V>: ObservableObject {\n\n    @Published\n    var value: V\n\n    init(_ value: V) {\n        self.value = value\n    }\n\n    func update(_ value: V) {\n        self.value = value\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/Utils/View+Measure.swift",
    "content": "//\n//  View+OnHeightCHange.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 15/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nextension View {\n\n    func onHeightChange(_ block: @escaping (CGFloat) -> Void) -> some View {\n        onFrameChange { block($0.height) }\n    }\n\n    func onFrameChange(in coordinateSpace: CoordinateSpace = .global,\n                       _ block: @escaping (CGRect) -> Void) -> some View {\n        modifier(OnFrameChangeViewModifier(coordinateSpace: coordinateSpace, block: block))\n    }\n}\n\nprivate struct OnFrameChangeViewModifier: ViewModifier {\n\n    let coordinateSpace: CoordinateSpace\n    let block: (CGRect) -> Void\n\n    func body(content: Content) -> some View {\n        content.background(\n            GeometryReader { proxy -> Color in\n                let frame = proxy.frame(in: coordinateSpace)\n                block(frame)\n                return Color.clear\n            }\n        )\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/Utils/ViewInspector.swift",
    "content": "//\n//  ViewInspector.swift\n//  DynamicOverlayTests\n//\n//  Created by Gaétan Zanella on 16/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport UIKit\n\nstruct ViewInspector {\n\n    let view: UIView\n\n    func search<V: UIView>(_ type: V.Type) -> V {\n        guard let result = view.search(type) else {\n            fatalError(\"\\(type) does not exist\")\n        }\n        return result\n    }\n}\n\nprivate extension UIView {\n\n    func search<V: UIView>(_ type: V.Type) -> V? {\n        if let result = self as? V {\n            return result\n        }\n        for subview in subviews {\n            if let target = subview.search(type) {\n                return target\n            }\n        }\n        return nil\n    }\n}\n"
  },
  {
    "path": "Tests/DynamicOverlayTests/Utils/ViewRenderer.swift",
    "content": "//\n//  ViewRenderer.swift\n//  DynamicOverlay\n//\n//  Created by Gaétan Zanella on 12/04/2021.\n//  Copyright © 2021 Fabernovel. All rights reserved.\n//\n\nimport Foundation\nimport SwiftUI\n\nclass ViewRenderer<V: View> {\n\n    var size: CGSize {\n        window.frame.size\n    }\n\n    var safeAreaInsets: UIEdgeInsets {\n        window.safeAreaInsets\n    }\n\n    var bounds: CGRect {\n        window.bounds\n    }\n\n    var safeBounds: CGRect {\n        bounds.inset(by: safeAreaInsets)\n    }\n\n    var window: UIWindow {\n        UIApplication.shared.windows.first!\n    }\n\n    private let hostController: UIHostingController<V>\n\n    init(view: V) {\n        self.hostController = UIHostingController(rootView: view)\n    }\n\n    func render() {\n        if window.rootViewController !== hostController {\n            window.rootViewController = hostController\n        }\n        CATransaction.flush()\n    }\n}\n"
  },
  {
    "path": "fastlane/Fastfile",
    "content": "\ndefault_platform(:ios)\n\nplatform :ios do\n    desc \"Run all unit tests\"\n    lane :tests do\n        scan(\n            scheme: \"DynamicOverlay_Example\",\n            project: \"DynamicOverlay_Example/DynamicOverlay_Example.xcodeproj\",\n            clean: true\n        )\n    end\n\n    desc \"Pod linting\"\n    lane :pod_lint do\n        pod_lib_lint(allow_warnings: true)\n    end\n\n    desc \"Carthage linting\"\n    lane :carthage_lint do\n        # FIX lint\n        # carthage(command: \"build\", no_skip_current: true, platform: \"iOS\")\n    end\n\n    desc \"SPM linting\"\n    lane :spm_lint do\n        output = \"Package.xcodeproj\"\n        Dir.chdir(\"..\") do\n            sh(\"swift package generate-xcodeproj --output #{output} --xcconfig-overrides #{ENV[\"XCCONFIG\"]}\")\n        end\n        xcodebuild(\n            project: output,\n            scheme: \"#{ENV[\"SCHEME\"]}-Package\"\n        )\n        Dir.chdir(\"..\") do\n            sh(\"rm Package.resolved\")\n            sh(\"rm -rf Package.xcodeproj\")\n        end\n    end\n\n    desc \"Release a new version\"\n    lane :release do |options|\n        target_version = options[:version]\n        raise \"The version is missed. Use `fastlane release version:{version_number}`.`\" if target_version.nil?\n\n        ensure_git_branch(branch: \"(release/*)|(hotfix/*)\")\n        ensure_git_status_clean\n\n        podspec = ENV[\"PODSPEC\"]\n        version_bump_podspec(path: podspec, version_number: target_version)\n        git_add\n        git_commit(\n            path: [\"DynamicOverlay.podspec\"],\n            message: \"Bump to #{target_version}\"\n        )\n        ensure_git_status_clean\n        add_git_tag(tag: target_version)\n\n        changelog = read_changelog(\n            changelog_path: \"CHANGELOG.md\",\n            section_identifier: \"[#{target_version}]\"\n        )\n\n        # Push\n        push_to_git_remote\n        push_git_tags(tag: target_version)\n        UI.success \"Pushed 🎉\"\n\n        # Release cocoapods\n        pod_push\n        UI.success \"Released 🎉\"\n\n        # Release Github\n\n        set_github_release(\n            repository_name: \"faberNovel/DynamicOverlay\",\n            api_token: ENV[\"GITHUB_TOKEN\"],\n            name: \"v#{target_version}\",\n            tag_name: \"#{target_version}\",\n            description: changelog,\n        )\n\n        # Make PR\n        create_pull_request(\n            api_token: ENV[\"GITHUB_TOKEN\"],\n            repo: \"faberNovel/DynamicOverlay\",\n            title: \"Release #{target_version}\",\n            base: \"main\",\n            body: changelog\n        )\n    end\nend\n"
  },
  {
    "path": "fastlane/Pluginfile",
    "content": "# Autogenerated by fastlane\n#\n# Ensure this file is checked in to source control!\n\ngem 'fastlane-plugin-changelog'\n"
  }
]