├── .editorconfig
├── .github
├── CODE_OF_CONDUCT.md
├── ISSUE_TEMPLATE
│ ├── bug_report.yml
│ └── config.yml
└── workflows
│ ├── ci.yml
│ ├── format.yml
│ └── release.yml
├── .gitignore
├── .spi.yml
├── Examples
├── CaseStudies
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── CaseStudiesApp.swift
│ ├── Info.plist
│ ├── Internal
│ │ ├── CaseStudy.swift
│ │ ├── DetentsHelper.swift
│ │ ├── FactClient.swift
│ │ └── Text+Template.swift
│ ├── RootView.swift
│ ├── SwiftUI
│ │ ├── AlertDialogState.swift
│ │ ├── EnumControls.swift
│ │ ├── EnumNavigation.swift
│ │ ├── OptionalNavigation.swift
│ │ ├── SwiftUICaseStudies.swift
│ │ └── SynchronizedBindings.swift
│ └── UIKit
│ │ ├── AnimationsViewController.swift
│ │ ├── BasicsNavigationViewController.swift
│ │ ├── ConciseEnumNavigationViewController.swift
│ │ ├── EnumControlsViewController.swift
│ │ ├── ErasedNavigationStackController.swift
│ │ ├── FocusViewController.swift
│ │ ├── MinimalObservationViewController.swift
│ │ ├── StaticNavigationStackController.swift
│ │ ├── UIControlBindingsViewController.swift
│ │ ├── UIKitCaseStudies.swift
│ │ └── WiFiFeature
│ │ ├── ConnectToNetworkFeature.swift
│ │ ├── Network.swift
│ │ ├── NetworkDetailFeature.swift
│ │ └── WiFiSettingsFeature.swift
├── CaseStudiesTests
│ ├── CaseStudies.xctestplan
│ ├── Internal
│ │ ├── AssertEventually.swift
│ │ ├── SetUp.swift
│ │ └── XCTTODO.swift
│ ├── NavigationPathTests.swift
│ ├── NavigationStackTests.swift
│ ├── PresentationTests.swift
│ └── RuntimeWarningTests.swift
├── DynamicFramework
│ ├── DynamicFramework.h
│ └── Import.swift
├── Examples.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcshareddata
│ │ └── xcschemes
│ │ ├── CaseStudies.xcscheme
│ │ └── Inventory.xcscheme
├── Inventory
│ ├── App.swift
│ ├── Assets.xcassets
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ ├── AppIcon.appiconset
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Inventory.swift
│ ├── Item.swift
│ └── ItemRow.swift
└── Package.swift
├── LICENSE
├── Makefile
├── Package.resolved
├── Package.swift
├── Package@swift-6.0.swift
├── README.md
├── Sources
├── AppKitNavigation
│ ├── AppKitAnimation.swift
│ ├── Documentation.docc
│ │ ├── AppKitNavigation.md
│ │ └── Extensions
│ │ │ └── AppKitAnimation.md
│ ├── Internal
│ │ └── Exports.swift
│ ├── SwiftUI
│ │ └── Representable.swift
│ ├── UIBinding.swift
│ └── UITransaction.swift
├── SwiftNavigation
│ ├── AlertState.swift
│ ├── Bind.swift
│ ├── Binding.swift
│ ├── ButtonState.swift
│ ├── ButtonStateBuilder.swift
│ ├── ConfirmationDialogState.swift
│ ├── Documentation.docc
│ │ ├── Articles
│ │ │ ├── CrossPlatform.md
│ │ │ └── WhatIsNavigation.md
│ │ ├── Extensions
│ │ │ ├── AlertState.md
│ │ │ ├── ButtonState.md
│ │ │ ├── ConfirmationDialogState.md
│ │ │ ├── NSObjectObserve.md
│ │ │ ├── Observe.md
│ │ │ ├── TextState.md
│ │ │ ├── UIBindable.md
│ │ │ └── UIBinding.md
│ │ └── SwiftNavigation.md
│ ├── HashableObject.swift
│ ├── Internal
│ │ ├── AssumeIsolated.swift
│ │ ├── Deprecations.swift
│ │ ├── ErrorMechanism.swift
│ │ ├── Exports.swift
│ │ ├── HashableStaticString.swift
│ │ ├── KeyPath+Sendable.swift
│ │ └── ToOptionalUnit.swift
│ ├── NSObject+Observe.swift
│ ├── Observe.swift
│ ├── TextState.swift
│ ├── UIBindable.swift
│ ├── UIBinding.swift
│ ├── UINavigationPath.swift
│ └── UITransaction.swift
├── SwiftUINavigation
│ ├── Alert.swift
│ ├── Binding.swift
│ ├── ConfirmationDialog.swift
│ ├── Documentation.docc
│ │ ├── Articles
│ │ │ ├── AlertsDialogs.md
│ │ │ ├── Bindings.md
│ │ │ ├── Navigation.md
│ │ │ ├── SheetsPopoversCovers.md
│ │ │ └── SwiftUINavigationTools.md
│ │ └── SwiftUINavigation.md
│ ├── FullScreenCover.swift
│ ├── Internal
│ │ ├── Binding+Internal.swift
│ │ ├── Exports.swift
│ │ └── Identified.swift
│ ├── NavigationDestination.swift
│ ├── NavigationLink.swift
│ ├── Popover.swift
│ ├── Sheet.swift
│ └── WithState.swift
├── UIKitNavigation
│ ├── Bindings
│ │ ├── UIColorWell.swift
│ │ ├── UIControl.swift
│ │ ├── UIDatePicker.swift
│ │ ├── UIPageControl.swift
│ │ ├── UISegmentedControl.swift
│ │ ├── UISlider.swift
│ │ ├── UIStepper.swift
│ │ ├── UISwitch.swift
│ │ ├── UITabBarController.swift
│ │ └── UITextField.swift
│ ├── Documentation.docc
│ │ ├── Extensions
│ │ │ ├── UIColorWell.md
│ │ │ ├── UIControlProtocol.md
│ │ │ ├── UIDatePicker.md
│ │ │ ├── UIKitAnimation.md
│ │ │ ├── UIPageControl.md
│ │ │ ├── UISlider.md
│ │ │ ├── UIStepper.md
│ │ │ ├── UISwitch.md
│ │ │ ├── UITextField.md
│ │ │ └── UIViewController.md
│ │ └── UIKitNavigation.md
│ ├── Internal
│ │ ├── Exports.swift
│ │ └── PopFromViewController.swift
│ ├── Navigation
│ │ ├── Dismiss.swift
│ │ ├── NavigationStackController.swift
│ │ ├── Presentation.swift
│ │ ├── Push.swift
│ │ └── UIAlertController.swift
│ ├── SwiftUI
│ │ └── Representable.swift
│ ├── UIBinding.swift
│ ├── UIKitAnimation.swift
│ └── UITransaction.swift
└── UIKitNavigationShim
│ ├── include
│ └── shim.h
│ └── shim.m
├── SwiftNavigation.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ ├── swiftpm
│ └── Package.resolved
│ └── xcschemes
│ ├── SwiftNavigation.xcscheme
│ ├── SwiftUINavigation.xcscheme
│ └── UIKitNavigation.xcscheme
└── Tests
├── SwiftNavigation.xctestplan
├── SwiftNavigationTests
├── ButtonStateTests.swift
├── IsolationTests.swift
├── LifetimeTests.swift
├── ObserveTests.swift
├── TextStateTests.swift
├── UIBindableTests.swift
├── UIBindingTests.swift
├── UINavigationPathTests.swift
└── UITransactionTests.swift
├── SwiftUINavigation.xctestplan
├── SwiftUINavigationTests
├── AlertTests.swift
├── BindingTests.swift
└── SwiftUINavigationTests.swift
├── UIKitNavigation.xctestplan
└── UIKitNavigationTests
├── MemoryManagementTests.swift
├── ObserveTests.swift
├── UIControlTests.swift
├── UITransactionTests.swift
└── ViewControllerRepresentingTests.swift
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 2
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Something isn't working as expected
3 | labels: [bug]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Thank you for contributing to the SwiftUI Navigation!
9 |
10 | Before you submit your issue, please complete each text area below with the relevant details for your bug, and complete the steps in the checklist.
11 | - type: textarea
12 | attributes:
13 | label: Description
14 | description: |
15 | A short description of the incorrect behavior.
16 |
17 | If you think this issue has been recently introduced and did not occur in an earlier version, please note that. If possible, include the last version that the behavior was correct in addition to your current version.
18 | validations:
19 | required: true
20 | - type: checkboxes
21 | attributes:
22 | label: Checklist
23 | options:
24 | - label: I have determined whether this bug is also reproducible in a vanilla SwiftUI project.
25 | required: false
26 | - label: If possible, I've reproduced the issue using the `main` branch of this package.
27 | required: false
28 | - label: This issue hasn't been addressed in an [existing GitHub issue](https://github.com/pointfreeco/swift-navigation/issues) or [discussion](https://github.com/pointfreeco/swiftui-navigation/discussions).
29 | required: true
30 | - type: textarea
31 | attributes:
32 | label: Expected behavior
33 | description: Describe what you expected to happen.
34 | validations:
35 | required: false
36 | - type: textarea
37 | attributes:
38 | label: Actual behavior
39 | description: Describe or copy/paste the behavior you observe.
40 | validations:
41 | required: false
42 | - type: textarea
43 | attributes:
44 | label: Steps to reproduce
45 | description: |
46 | Explanation of how to reproduce the incorrect behavior.
47 |
48 | This could include an attached project or link to code that is exhibiting the issue, and/or a screen recording.
49 | placeholder: |
50 | 1. ...
51 | validations:
52 | required: false
53 | - type: input
54 | attributes:
55 | label: SwiftUI Navigation version information
56 | description: The version of SwiftUI Navigation used to reproduce this issue.
57 | placeholder: "'0.7.0' for example, or a commit hash"
58 | - type: input
59 | attributes:
60 | label: Destination operating system
61 | description: The OS running your application.
62 | placeholder: "'iOS 16' for example"
63 | - type: input
64 | attributes:
65 | label: Xcode version information
66 | description: The version of Xcode used to reproduce this issue.
67 | placeholder: "The version displayed from 'Xcode 〉About Xcode'"
68 | - type: textarea
69 | attributes:
70 | label: Swift Compiler version information
71 | description: The version of Swift used to reproduce this issue.
72 | placeholder: Output from 'xcrun swiftc --version'
73 | render: shell
74 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 |
3 | contact_links:
4 | - name: Project Discussion
5 | url: https://github.com/pointfreeco/swift-navigation/discussions
6 | about: SwiftUI Navigation Q&A, ideas, and more
7 | - name: Documentation
8 | url: https://pointfreeco.github.io/swift-navigation/main/documentation/swiftnavigation/
9 | about: Read SwiftUI Navigation's documentation
10 | - name: Videos
11 | url: https://www.pointfree.co/
12 | about: Watch videos to get a behind-the-scenes look at how SwiftUI Navigation was motivated and built
13 | - name: Slack
14 | url: https://www.pointfree.co/slack-invite
15 | about: Community chat
16 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 | pull_request:
8 | branches:
9 | - '*'
10 | workflow_dispatch:
11 |
12 | concurrency:
13 | group: ci-${{ github.ref }}
14 | cancel-in-progress: true
15 |
16 | jobs:
17 | library:
18 | runs-on: macos-15
19 | strategy:
20 | matrix:
21 | xcode:
22 | - '16.2'
23 | variation:
24 | - ios
25 | - macos
26 | - tvos
27 | - watchos
28 | - examples
29 |
30 | steps:
31 | - uses: actions/checkout@v4
32 | - name: Select Xcode ${{ matrix.xcode }}
33 | run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
34 | - name: Skip macro validation
35 | run: defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES
36 | - name: Run tests
37 | run: make test-${{ matrix.variation }}
38 |
39 | library-15-4-compatibility:
40 | runs-on: macos-14
41 | strategy:
42 | matrix:
43 | xcode:
44 | - '15.4'
45 | ios_version:
46 | - '17.5'
47 | variation:
48 | - ios
49 | steps:
50 | - uses: actions/checkout@v4
51 | - name: Select Xcode ${{ matrix.xcode }}
52 | run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
53 | - name: Skip macro validation
54 | run: defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES
55 | - name: Run tests
56 | run: make IOS_VERSION=${{matrix.ios_version}} test-${{ matrix.variation }}
57 |
58 | library-evolution:
59 | name: Library Evolution
60 | runs-on: macos-15
61 | strategy:
62 | matrix:
63 | xcode:
64 | - '16.2'
65 | steps:
66 | - uses: actions/checkout@v4
67 | - name: Select Xcode ${{ matrix.xcode }}
68 | run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app
69 | - name: Skip macro validation
70 | run: defaults write com.apple.dt.Xcode IDESkipMacroFingerprintValidation -bool YES
71 | - name: Build for Library Evolution
72 | run: make build-for-library-evolution
73 |
74 | wasm:
75 | name: Wasm
76 | runs-on: ubuntu-latest
77 | steps:
78 | - uses: actions/checkout@v4
79 | - uses: bytecodealliance/actions/wasmtime/setup@v1
80 | - name: Install Swift and Swift SDK for WebAssembly
81 | run: |
82 | PREFIX=/opt/swift
83 | set -ex
84 | curl -f -o /tmp/swift.tar.gz "https://download.swift.org/swift-6.0.3-release/ubuntu2204/swift-6.0.3-RELEASE/swift-6.0.3-RELEASE-ubuntu22.04.tar.gz"
85 | sudo mkdir -p $PREFIX; sudo tar -xzf /tmp/swift.tar.gz -C $PREFIX --strip-component 1
86 | $PREFIX/usr/bin/swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.0.3-RELEASE/swift-wasm-6.0.3-RELEASE-wasm32-unknown-wasi.artifactbundle.zip --checksum 31d3585b06dd92de390bacc18527801480163188cd7473f492956b5e213a8618
87 | echo "$PREFIX/usr/bin" >> $GITHUB_PATH
88 |
89 | - name: Build tests
90 | run: swift build --swift-sdk wasm32-unknown-wasi --build-tests -Xlinker -z -Xlinker stack-size=$((1024 * 1024))
91 | - name: Run tests
92 | run: wasmtime --dir . .build/debug/swift-navigationPackageTests.wasm
93 |
94 | # windows:
95 | # name: Windows
96 | # strategy:
97 | # matrix:
98 | # os: [windows-latest]
99 | # config: ['debug', 'release']
100 | # fail-fast: false
101 | # runs-on: ${{ matrix.os }}
102 | # steps:
103 | # - uses: compnerd/gha-setup-swift@main
104 | # with:
105 | # branch: swift-5.10-release
106 | # tag: 5.10-RELEASE
107 | # - uses: actions/checkout@v4
108 | # - name: Build
109 | # run: swift build -c ${{ matrix.config }}
110 |
--------------------------------------------------------------------------------
/.github/workflows/format.yml:
--------------------------------------------------------------------------------
1 | name: Format
2 |
3 | on:
4 | push:
5 | branches:
6 | - main
7 |
8 | jobs:
9 | swift_format:
10 | name: swift-format
11 | runs-on: macOS-14
12 | steps:
13 | - uses: actions/checkout@v4
14 | - name: Xcode Select
15 | run: sudo xcode-select -s /Applications/Xcode_15.4.app
16 | - name: Install
17 | run: brew install swift-format
18 | - name: Format
19 | run: make format
20 | - uses: stefanzweifel/git-auto-commit-action@v4
21 | with:
22 | commit_message: Run swift-format
23 | branch: 'main'
24 | env:
25 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 | on:
3 | release:
4 | types: [published]
5 | workflow_dispatch:
6 | jobs:
7 | project-channel:
8 | runs-on: ubuntu-latest
9 | steps:
10 | - name: Dump Github context
11 | env:
12 | GITHUB_CONTEXT: ${{ toJSON(github) }}
13 | run: echo "$GITHUB_CONTEXT"
14 | - name: Slack Notification on SUCCESS
15 | if: success()
16 | uses: tokorom/action-slack-incoming-webhook@main
17 | env:
18 | INCOMING_WEBHOOK_URL: ${{ secrets.SLACK_PROJECT_CHANNEL_WEBHOOK_URL }}
19 | with:
20 | text: swift-navigation ${{ github.event.release.tag_name }} has been released.
21 | blocks: |
22 | [
23 | {
24 | "type": "header",
25 | "text": {
26 | "type": "plain_text",
27 | "text": "swift-navigation ${{ github.event.release.tag_name}}"
28 | }
29 | },
30 | {
31 | "type": "section",
32 | "text": {
33 | "type": "mrkdwn",
34 | "text": ${{ toJSON(github.event.release.body) }}
35 | }
36 | },
37 | {
38 | "type": "section",
39 | "text": {
40 | "type": "mrkdwn",
41 | "text": "${{ github.event.release.html_url }}"
42 | }
43 | }
44 | ]
45 |
46 | releases-channel:
47 | runs-on: ubuntu-latest
48 | steps:
49 | - name: Dump Github context
50 | env:
51 | GITHUB_CONTEXT: ${{ toJSON(github) }}
52 | run: echo "$GITHUB_CONTEXT"
53 | - name: Slack Notification on SUCCESS
54 | if: success()
55 | uses: tokorom/action-slack-incoming-webhook@main
56 | env:
57 | INCOMING_WEBHOOK_URL: ${{ secrets.SLACK_RELEASES_WEBHOOK_URL }}
58 | with:
59 | text: swift-navigation ${{ github.event.release.tag_name }} has been released.
60 | blocks: |
61 | [
62 | {
63 | "type": "header",
64 | "text": {
65 | "type": "plain_text",
66 | "text": "swift-navigation ${{ github.event.release.tag_name}}"
67 | }
68 | },
69 | {
70 | "type": "section",
71 | "text": {
72 | "type": "mrkdwn",
73 | "text": ${{ toJSON(github.event.release.body) }}
74 | }
75 | },
76 | {
77 | "type": "section",
78 | "text": {
79 | "type": "mrkdwn",
80 | "text": "${{ github.event.release.html_url }}"
81 | }
82 | }
83 | ]
84 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /.swiftpm
4 | /Packages
5 | /*.xcodeproj
6 | xcuserdata/
7 | DerivedData/
8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata
9 |
--------------------------------------------------------------------------------
/.spi.yml:
--------------------------------------------------------------------------------
1 | version: 1
2 | builder:
3 | configs:
4 | - documentation_targets:
5 | - SwiftNavigation
6 | - AppKitNavigation
7 | - SwiftUINavigation
8 | - UIKitNavigation
9 | swift_version: 6.0
10 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/CaseStudiesApp.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | @main
4 | struct CaseStudiesApp: App {
5 | var body: some Scene {
6 | WindowGroup {
7 | RootView()
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Internal/DetentsHelper.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 |
3 | extension UIViewController {
4 | func mediumDetents() {
5 | if let sheet = sheetPresentationController {
6 | sheet.detents = [.medium()]
7 | sheet.prefersScrollingExpandsWhenScrolledToEdge = false
8 | sheet.prefersEdgeAttachedInCompactHeight = true
9 | sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Internal/FactClient.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct Fact: Identifiable {
4 | var description: String
5 | let number: Int
6 |
7 | var id: Int {
8 | number
9 | }
10 | }
11 |
12 | func getNumberFact(_ count: Int) async -> Fact {
13 | let fact: String
14 | do {
15 | let (data, _) = try await URLSession.shared.data(
16 | from: URL(string: "http://numbersapi.com/\(count)/trivia")!
17 | )
18 | fact = String(decoding: data, as: UTF8.self)
19 | } catch {
20 | // Sometimes numbersapi.com can be flakey, so if it ever fails we will just
21 | // default to a mock response.
22 | fact = "\(count) is a good number Brent"
23 | }
24 | try? await Task.sleep(nanoseconds: NSEC_PER_SEC)
25 | return Fact(description: fact, number: count)
26 | }
27 |
--------------------------------------------------------------------------------
/Examples/CaseStudies/Internal/Text+Template.swift:
--------------------------------------------------------------------------------
1 | import SwiftUI
2 |
3 | extension Text {
4 | init(template: String, _ style: Font.TextStyle = .body) {
5 | enum Style: Hashable {
6 | case code
7 | case emphasis
8 | case strong
9 | }
10 |
11 | var segments: [Text] = []
12 | var currentValue = ""
13 | var currentStyles: Set