├── .editorconfig ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ └── config.yml ├── package.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ ├── swiftpm │ │ └── Package.resolved │ │ └── xcschemes │ │ ├── ComposableArchitecture.xcscheme │ │ └── swift-composable-architecture-benchmark.xcscheme └── workflows │ ├── ci.yml │ ├── documentation.yml │ ├── format.yml │ └── release.yml ├── .gitignore ├── .spi.yml ├── Benchmarks ├── Benchmarks │ └── swift-composable-architecture-benchmark │ │ └── Benchmarks.swift ├── Package.resolved └── Package.swift ├── ComposableArchitecture.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ ├── WorkspaceSettings.xcsettings │ ├── swiftpm │ └── Package.resolved │ └── xcschemes │ ├── ComposableArchitecture.xcscheme │ └── swift-composable-architecture-benchmark.xcscheme ├── Examples ├── .swiftpm │ └── xcode │ │ └── package.xcworkspace │ │ └── contents.xcworkspacedata ├── CaseStudies │ ├── CaseStudies.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── CaseStudies (SwiftUI).xcscheme │ │ │ ├── CaseStudies (UIKit).xcscheme │ │ │ └── tvOSCaseStudies.xcscheme │ ├── README.md │ ├── SwiftUICaseStudies │ │ ├── 00-RootView.swift │ │ ├── 01-GettingStarted-AlertsAndConfirmationDialogs.swift │ │ ├── 01-GettingStarted-Animations.swift │ │ ├── 01-GettingStarted-Bindings-Basics.swift │ │ ├── 01-GettingStarted-Bindings-Forms.swift │ │ ├── 01-GettingStarted-Composition-TwoCounters.swift │ │ ├── 01-GettingStarted-Counter.swift │ │ ├── 01-GettingStarted-FocusState.swift │ │ ├── 01-GettingStarted-OptionalState.swift │ │ ├── 02-Effects-SystemEnvironment.swift │ │ ├── 02-SharedState-FileStorage.swift │ │ ├── 02-SharedState-InMemory.swift │ │ ├── 02-SharedState-Onboarding.swift │ │ ├── 02-SharedState-UserDefaults.swift │ │ ├── 03-Effects-Basics.swift │ │ ├── 03-Effects-Cancellation.swift │ │ ├── 03-Effects-LongLiving.swift │ │ ├── 03-Effects-Refreshable.swift │ │ ├── 03-Effects-Timers.swift │ │ ├── 03-Effects-WebSocket.swift │ │ ├── 04-Navigation-Lists-NavigateAndLoad.swift │ │ ├── 04-Navigation-Multiple-Destinations.swift │ │ ├── 04-Navigation-NavigateAndLoad.swift │ │ ├── 04-Navigation-Sheet-LoadThenPresent.swift │ │ ├── 04-Navigation-Sheet-PresentAndLoad.swift │ │ ├── 04-NavigationStack.swift │ │ ├── 05-HigherOrderReducers-Recursion.swift │ │ ├── 05-HigherOrderReducers-ResuableOfflineDownloads │ │ │ ├── DownloadClient.swift │ │ │ ├── DownloadComponent.swift │ │ │ └── ReusableComponents-Download.swift │ │ ├── 05-HigherOrderReducers-ReusableFavoriting.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-60@2x.png │ │ │ │ ├── AppIcon-76@2x.png │ │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ │ ├── AppIcon.png │ │ │ │ ├── Contents.json │ │ │ │ └── transparent.png │ │ │ └── Contents.json │ │ ├── CaseStudiesApp.swift │ │ ├── FactClient.swift │ │ ├── Info.plist │ │ └── Internal │ │ │ ├── AboutView.swift │ │ │ ├── CircularProgressView.swift │ │ │ ├── ResignFirstResponder.swift │ │ │ ├── TemplateText.swift │ │ │ └── UIViewRepresented.swift │ ├── SwiftUICaseStudiesTests │ │ ├── 01-GettingStarted-AlertsAndConfirmationDialogsTests.swift │ │ ├── 01-GettingStarted-AnimationsTests.swift │ │ ├── 01-GettingStarted-BindingBasicsTests.swift │ │ ├── 02-GettingStarted-SharedStateFileStorageTests.swift │ │ ├── 02-GettingStarted-SharedStateInMemoryTests.swift │ │ ├── 02-GettingStarted-SharedStateUserDefaultsTests.swift │ │ ├── 03-Effects-BasicsTests.swift │ │ ├── 03-Effects-CancellationTests.swift │ │ ├── 03-Effects-LongLivingTests.swift │ │ ├── 03-Effects-RefreshableTests.swift │ │ ├── 03-Effects-TimersTests.swift │ │ ├── 03-Effects-WebSocketTests.swift │ │ ├── 05-HigherOrderReducers-RecursionTests.swift │ │ ├── 05-HigherOrderReducers-ReusableFavoritingTests.swift │ │ └── 05-HigherOrderReducers-ReusableOfflineDownloadsTests.swift │ ├── UIKitCaseStudies │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-60@2x.png │ │ │ │ ├── AppIcon-76@2x.png │ │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ │ ├── AppIcon.png │ │ │ │ ├── Contents.json │ │ │ │ └── transparent.png │ │ │ └── Contents.json │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ ├── CounterViewController.swift │ │ ├── Info.plist │ │ ├── Internal │ │ │ ├── ActivityIndicatorViewController.swift │ │ │ └── IfLetStoreController.swift │ │ ├── ListsOfState.swift │ │ ├── LoadThenNavigate.swift │ │ ├── NavigateAndLoad.swift │ │ ├── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ │ └── Contents.json │ │ ├── RootViewController.swift │ │ └── SceneDelegate.swift │ ├── UIKitCaseStudiesTests │ │ ├── Info.plist │ │ └── UIKitCaseStudiesTests.swift │ ├── tvOSCaseStudies │ │ ├── AppDelegate.swift │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon.png │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Core.swift │ │ ├── FocusView.swift │ │ ├── Info.plist │ │ └── RootView.swift │ └── tvOSCaseStudiesTests │ │ └── FocusTests.swift ├── Integration │ ├── Integration.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ │ └── swiftpm │ │ │ │ └── Package.resolved │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Integration.xcscheme │ ├── Integration │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── IntegrationApp.swift │ │ ├── Legacy │ │ │ ├── BindingLocalTestCase.swift │ │ │ ├── BindingsAnimationsTestBench.swift │ │ │ ├── EscapedWithViewStoreTestCase.swift │ │ │ ├── ForEachBindingTestCase.swift │ │ │ ├── IfLetStoreTestCase.swift │ │ │ ├── LegacyPresentationTestCase.swift │ │ │ ├── NavigationStackTestCase.swift │ │ │ ├── PresentationItemTestCase.swift │ │ │ └── SwitchStoreTestCase.swift │ │ ├── Preview Content │ │ │ └── Preview Assets.xcassets │ │ │ │ └── Contents.json │ │ ├── Test Cases │ │ │ └── MultipleAlertsTestCase.swift │ │ ├── iOS 16+17 │ │ │ ├── NewContainsOldTestCase.swift │ │ │ ├── NewOldSiblingsTestCase.swift │ │ │ ├── NewPresentsOldTestCase.swift │ │ │ ├── OldContainsNewTestCase.swift │ │ │ └── OldPresentsNewTestCase.swift │ │ ├── iOS 16 │ │ │ ├── BasicsTestCase.swift │ │ │ ├── EnumTestCase.swift │ │ │ ├── IdentifiedListTestCase.swift │ │ │ ├── NavigationTestCase.swift │ │ │ ├── OptionalTestCase.swift │ │ │ ├── PresentationTestCase.swift │ │ │ └── SiblingTestCase.swift │ │ └── iOS 17 │ │ │ ├── ObservableBasicsTestCase.swift │ │ │ ├── ObservableBindingLocalTest.swift │ │ │ ├── ObservableEnumTestCase.swift │ │ │ ├── ObservableIdentifiedListTestCase.swift │ │ │ ├── ObservableNavigationTestCase.swift │ │ │ ├── ObservableOptionalTestCase.swift │ │ │ ├── ObservablePresentationTestCase.swift │ │ │ ├── ObservableSharedStateTestCase.swift │ │ │ └── ObservableSiblingTestCase.swift │ ├── IntegrationUITests │ │ ├── EnumTests.swift │ │ ├── Internal │ │ │ ├── BaseIntegrationTests.swift │ │ │ └── TestHelpers.swift │ │ ├── Legacy │ │ │ ├── BindingLocalTests.swift │ │ │ ├── EscapedWithViewStoreTests.swift │ │ │ ├── ForEachBindingTests.swift │ │ │ ├── IfLetStoreTests.swift │ │ │ ├── LegacyNavigationTests.swift │ │ │ ├── LegacyPresentationTests.swift │ │ │ └── SwitchStoreTests.swift │ │ ├── Test Cases │ │ │ └── MultipleAlertsTests.swift │ │ ├── iOS 16+17 │ │ │ ├── NewContainsOldTests.swift │ │ │ ├── NewOldSiblingsTests.swift │ │ │ ├── NewPresentsOldTests.swift │ │ │ ├── OldContainsNewTests.swift │ │ │ └── OldPresentsNewTests.swift │ │ ├── iOS 16 │ │ │ ├── BasicsTests.swift │ │ │ ├── EnumTests.swift │ │ │ ├── IdentifiedListTests.swift │ │ │ ├── NavigationTests.swift │ │ │ ├── OptionalTests.swift │ │ │ ├── PresentationTests.swift │ │ │ └── SiblingTests.swift │ │ └── iOS 17 │ │ │ ├── ObservableBasicsTests.swift │ │ │ ├── ObservableBindingLocalTests.swift │ │ │ ├── ObservableEnumTests.swift │ │ │ ├── ObservableIdentifiedListTests.swift │ │ │ ├── ObservableNavigationTests.swift │ │ │ ├── ObservableOptionalTests.swift │ │ │ ├── ObservablePresentationTests.swift │ │ │ ├── ObservableSharedStateTests.swift │ │ │ └── ObservableSiblingTests.swift │ └── TestCases │ │ └── TestCase.swift ├── Package.swift ├── README.md ├── Search │ ├── README.md │ ├── Search.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Search.xcscheme │ ├── Search │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-60@2x.png │ │ │ │ ├── AppIcon-76@2x.png │ │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ │ ├── AppIcon.png │ │ │ │ ├── Contents.json │ │ │ │ └── transparent.png │ │ │ └── Contents.json │ │ ├── SearchApp.swift │ │ ├── SearchView.swift │ │ └── WeatherClient.swift │ └── SearchTests │ │ └── SearchTests.swift ├── SpeechRecognition │ ├── README.md │ ├── SpeechRecognition.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── SpeechRecognition.xcscheme │ ├── SpeechRecognition │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-60@2x.png │ │ │ │ ├── AppIcon-76@2x.png │ │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ │ ├── AppIcon.png │ │ │ │ ├── Contents.json │ │ │ │ └── transparent.png │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── SpeechClient │ │ │ ├── Client.swift │ │ │ ├── Live.swift │ │ │ └── Models.swift │ │ ├── SpeechRecognition.swift │ │ └── SpeechRecognitionApp.swift │ └── SpeechRecognitionTests │ │ └── SpeechRecognitionTests.swift ├── SyncUps │ ├── README.md │ ├── SyncUps.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── SyncUps.xcscheme │ ├── SyncUps.xctestplan │ ├── SyncUps │ │ ├── App.swift │ │ ├── AppFeature.swift │ │ ├── Assets.xcassets │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── Themes │ │ │ │ ├── Contents.json │ │ │ │ ├── bubblegum.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── buttercup.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── indigo.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── lavender.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── magenta.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── navy.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── orange.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── oxblood.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── periwinkle.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── poppy.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── purple.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── seafoam.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── sky.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── tan.colorset │ │ │ │ └── Contents.json │ │ │ │ ├── teal.colorset │ │ │ │ └── Contents.json │ │ │ │ └── yellow.colorset │ │ │ │ └── Contents.json │ │ ├── Dependencies │ │ │ ├── OpenSettings.swift │ │ │ └── SpeechRecognizer.swift │ │ ├── Meeting.swift │ │ ├── Models.swift │ │ ├── RecordMeeting.swift │ │ ├── Resources │ │ │ └── ding.wav │ │ ├── SyncUpDetail.swift │ │ ├── SyncUpForm.swift │ │ └── SyncUpsList.swift │ ├── SyncUpsTests │ │ ├── AppFeatureTests.swift │ │ ├── RecordMeetingTests.swift │ │ ├── SyncUpDetailTests.swift │ │ ├── SyncUpFormTests.swift │ │ └── SyncUpsListTests.swift │ └── SyncUpsUITests │ │ └── SyncUpsUITests.swift ├── TicTacToe │ ├── App │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-60@2x.png │ │ │ │ ├── AppIcon-76@2x.png │ │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ │ ├── AppIcon.png │ │ │ │ ├── Contents.json │ │ │ │ └── transparent.png │ │ │ └── Contents.json │ │ ├── RootView.swift │ │ └── TicTacToeApp.swift │ ├── README.md │ ├── TicTacToe.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── TicTacToe.xcscheme │ └── tic-tac-toe │ │ ├── .gitignore │ │ ├── Package.swift │ │ ├── Sources │ │ ├── AppCore │ │ │ └── AppCore.swift │ │ ├── AppSwiftUI │ │ │ └── AppView.swift │ │ ├── AppUIKit │ │ │ └── AppViewController.swift │ │ ├── AuthenticationClient │ │ │ └── AuthenticationClient.swift │ │ ├── AuthenticationClientLive │ │ │ └── LiveAuthenticationClient.swift │ │ ├── GameCore │ │ │ ├── GameCore.swift │ │ │ └── Three.swift │ │ ├── GameSwiftUI │ │ │ └── GameView.swift │ │ ├── GameUIKit │ │ │ └── GameViewController.swift │ │ ├── LoginCore │ │ │ └── LoginCore.swift │ │ ├── LoginSwiftUI │ │ │ └── LoginView.swift │ │ ├── LoginUIKit │ │ │ └── LoginViewController.swift │ │ ├── NewGameCore │ │ │ └── NewGameCore.swift │ │ ├── NewGameSwiftUI │ │ │ └── NewGameView.swift │ │ ├── NewGameUIKit │ │ │ └── NewGameViewController.swift │ │ ├── TwoFactorCore │ │ │ └── TwoFactorCore.swift │ │ ├── TwoFactorSwiftUI │ │ │ └── TwoFactorView.swift │ │ └── TwoFactorUIKit │ │ │ └── TwoFactorViewController.swift │ │ └── Tests │ │ ├── AppCoreTests │ │ └── AppCoreTests.swift │ │ ├── GameCoreTests │ │ └── GameCoreTests.swift │ │ ├── LoginCoreTests │ │ └── LoginCoreTests.swift │ │ ├── NewGameCoreTests │ │ └── NewGameCoreTests.swift │ │ └── TwoFactorCoreTests │ │ └── TwoFactorCoreTests.swift ├── Todos │ ├── README.md │ ├── Todos.xcodeproj │ │ ├── project.pbxproj │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── IDEWorkspaceChecks.plist │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Todos.xcscheme │ ├── Todos │ │ ├── Assets.xcassets │ │ │ ├── AppIcon.appiconset │ │ │ │ ├── AppIcon-60@2x.png │ │ │ │ ├── AppIcon-76@2x.png │ │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ │ ├── AppIcon.png │ │ │ │ ├── Contents.json │ │ │ │ └── transparent.png │ │ │ └── Contents.json │ │ ├── Todo.swift │ │ ├── Todos.swift │ │ └── TodosApp.swift │ └── TodosTests │ │ └── TodosTests.swift └── VoiceMemos │ ├── README.md │ ├── VoiceMemos.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcshareddata │ │ └── xcschemes │ │ └── VoiceMemos.xcscheme │ ├── VoiceMemos │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ ├── AppIcon-60@2x.png │ │ │ ├── AppIcon-76@2x.png │ │ │ ├── AppIcon-iPadPro@2x.png │ │ │ ├── AppIcon.png │ │ │ ├── Contents.json │ │ │ └── transparent.png │ │ └── Contents.json │ ├── AudioPlayerClient │ │ ├── AudioPlayerClient.swift │ │ └── LiveAudioPlayerClient.swift │ ├── AudioRecorderClient │ │ ├── AudioRecorderClient.swift │ │ └── LiveAudioRecorderClient.swift │ ├── Dependencies.swift │ ├── Helpers.swift │ ├── Info.plist │ ├── RecordingMemo.swift │ ├── VoiceMemo.swift │ ├── VoiceMemos.swift │ └── VoiceMemosApp.swift │ └── VoiceMemosTests │ └── VoiceMemosTests.swift ├── LICENSE ├── Makefile ├── Package.resolved ├── Package.swift ├── Package@swift-6.0.swift ├── README.md ├── Sources ├── ComposableArchitecture │ ├── CaseReducer.swift │ ├── Core.swift │ ├── Dependencies │ │ ├── Dismiss.swift │ │ └── IsPresented.swift │ ├── Documentation.docc │ │ ├── Articles │ │ │ ├── Bindings.md │ │ │ ├── DependencyManagement.md │ │ │ ├── FAQ.md │ │ │ ├── GettingStarted.md │ │ │ ├── MigrationGuides.md │ │ │ ├── MigrationGuides │ │ │ │ ├── MigratingTo1.10.md │ │ │ │ ├── MigratingTo1.11.md │ │ │ │ ├── MigratingTo1.12.md │ │ │ │ ├── MigratingTo1.13.md │ │ │ │ ├── MigratingTo1.14.md │ │ │ │ ├── MigratingTo1.15.md │ │ │ │ ├── MigratingTo1.16.md │ │ │ │ ├── MigratingTo1.17.1.md │ │ │ │ ├── MigratingTo1.17.md │ │ │ │ ├── MigratingTo1.18.md │ │ │ │ ├── MigratingTo1.19.md │ │ │ │ ├── MigratingTo1.4.md │ │ │ │ ├── MigratingTo1.5.md │ │ │ │ ├── MigratingTo1.6.md │ │ │ │ ├── MigratingTo1.7.md │ │ │ │ ├── MigratingTo1.8.md │ │ │ │ └── MigratingTo1.9.md │ │ │ ├── Navigation.md │ │ │ ├── ObservationBackport.md │ │ │ ├── Performance.md │ │ │ ├── SharingState.md │ │ │ ├── StackBasedNavigation.md │ │ │ ├── SwiftConcurrency.md │ │ │ ├── TestingTCA.md │ │ │ ├── TreeBasedNavigation.md │ │ │ └── WhatIsNavigation.md │ │ ├── ComposableArchitecture.md │ │ ├── Extensions │ │ │ ├── Action.md │ │ │ ├── Deprecations │ │ │ │ ├── ReducerDeprecations.md │ │ │ │ ├── ScopeDeprecations.md │ │ │ │ ├── StoreDeprecations.md │ │ │ │ ├── SwiftUIDeprecations.md │ │ │ │ └── TestStoreDeprecations.md │ │ │ ├── Effect.md │ │ │ ├── EffectRun.md │ │ │ ├── EffectSend.md │ │ │ ├── IdentifiedAction.md │ │ │ ├── NavigationLinkState.md │ │ │ ├── ObservableState.md │ │ │ ├── Presents.md │ │ │ ├── Reduce.md │ │ │ ├── Reducer.md │ │ │ ├── ReducerBody.md │ │ │ ├── ReducerBuilder.md │ │ │ ├── ReducerForEach.md │ │ │ ├── ReducerMacro.md │ │ │ ├── ReducerlIfLet.md │ │ │ ├── ReducerlIfLetPresentation.md │ │ │ ├── Scope.md │ │ │ ├── State.md │ │ │ ├── Store.md │ │ │ ├── StoreDynamicMemberLookup.md │ │ │ ├── StoreState.md │ │ │ ├── SwiftUIBinding.md │ │ │ ├── SwiftUIBindingScopeForEach.md │ │ │ ├── SwiftUIBindingScopeIfLet.md │ │ │ ├── SwiftUIBindingSubscript.md │ │ │ ├── SwiftUIIntegration.md │ │ │ ├── SwitchStore.md │ │ │ ├── TaskResult.md │ │ │ ├── TestStore.md │ │ │ ├── TestStoreDependencies.md │ │ │ ├── TestStoreExhaustivity.md │ │ │ ├── UIKit.md │ │ │ ├── ViewStore.md │ │ │ ├── ViewStoreBinding.md │ │ │ ├── WithViewStore.md │ │ │ └── WithViewStoreInit.md │ │ ├── Resources │ │ │ ├── 01-02-image-0003.png │ │ │ ├── 01-02-video-0005.mp4 │ │ │ ├── 01-02-video-0006.mp4 │ │ │ ├── 01-03-image-0005.jpg │ │ │ ├── 01-homepage.png │ │ │ ├── 02-01-image-0001.png │ │ │ ├── 02-02-video-0005.mov │ │ │ ├── 02-homepage.png │ │ │ ├── 03-03-video-0006.mp4 │ │ │ ├── ch02-sub01-sec01-image-0001.png │ │ │ ├── ch02-sub01-sec01-image-0002.png │ │ │ ├── ch02-sub01-sec03-image-0000.mov │ │ │ ├── ch02-sub02-sec01-0000.mov │ │ │ ├── ch02-sub04-sec01-image-0000.png │ │ │ ├── ch02-sub04-sec01-video-0000.mov │ │ │ └── ch02-sub04-sec03-video-0000.mp4 │ │ └── Tutorials │ │ │ ├── BuildingSyncUps │ │ │ ├── 01-WhatIsSyncUps │ │ │ │ ├── CreateProject-0001-image.png │ │ │ │ ├── CreateProject-0002-image.png │ │ │ │ ├── CreateProject-0003-image.png │ │ │ │ ├── CreateProject-0004-image.png │ │ │ │ ├── TourOfSyncUps-0003-image.png │ │ │ │ ├── TourOfSyncUps-0004-image.png │ │ │ │ ├── TourOfSyncUps-0005-image.png │ │ │ │ ├── TourOfSyncUps-0006-image.png │ │ │ │ ├── TourOfSyncUps-0007-image.png │ │ │ │ ├── TourOfSyncUps-0008-image.png │ │ │ │ ├── TourOfSyncUps-0009-image.png │ │ │ │ ├── TourOfSyncUps-0010-image.png │ │ │ │ ├── TourOfSyncUps-0011-image.png │ │ │ │ ├── TourOfSyncUps-0012-image.png │ │ │ │ ├── TourOfSyncUps-0013-image.png │ │ │ │ ├── TourOfSyncUps-0014-image.png │ │ │ │ └── WhatIsSyncUps.tutorial │ │ │ ├── 02-ListsOfSyncUps │ │ │ │ ├── ListsOfSyncUps-01-code-0001.swift │ │ │ │ ├── ListsOfSyncUps-01-code-0002.swift │ │ │ │ ├── ListsOfSyncUps-01-code-0003.swift │ │ │ │ ├── ListsOfSyncUps-01-code-0004.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0001.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0002.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0003.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0004.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0005.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0006-previous.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0006.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0007.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0008.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0009.swift │ │ │ │ ├── ListsOfSyncUps-02-code-0010.mp4 │ │ │ │ ├── ListsOfSyncUps-03-code-0001-previous.swift │ │ │ │ ├── ListsOfSyncUps-03-code-0001.swift │ │ │ │ ├── ListsOfSyncUps-03-code-0002.diff │ │ │ │ ├── ListsOfSyncUps-cover.png │ │ │ │ ├── ListsOfSyncUps.tutorial │ │ │ │ ├── TestingListOfSyncUps-01-code-0001.swift │ │ │ │ ├── TestingListOfSyncUps-01-code-0002.swift │ │ │ │ ├── TestingListOfSyncUps-01-code-0003.swift │ │ │ │ ├── TestingListOfSyncUps-01-code-0004.swift │ │ │ │ └── TestingListOfSyncUps.tutorial │ │ │ ├── 03-SyncUpForm │ │ │ │ ├── SyncUpForm-01-code-0001.swift │ │ │ │ ├── SyncUpForm-01-code-0002.swift │ │ │ │ ├── SyncUpForm-01-code-0003.swift │ │ │ │ ├── SyncUpForm-01-code-0004.swift │ │ │ │ ├── SyncUpForm-01-code-0005.swift │ │ │ │ ├── SyncUpForm-01-code-0006.swift │ │ │ │ ├── SyncUpForm-01-code-0007.swift │ │ │ │ ├── SyncUpForm-01-code-0008.swift │ │ │ │ ├── SyncUpForm-01-code-0009.swift │ │ │ │ ├── SyncUpForm-02-code-0001-previous.swift │ │ │ │ ├── SyncUpForm-02-code-0001.swift │ │ │ │ ├── SyncUpForm-02-code-0002.swift │ │ │ │ ├── SyncUpForm-02-code-0003.swift │ │ │ │ ├── SyncUpForm-02-code-0004.swift │ │ │ │ ├── SyncUpForm-02-code-0005.swift │ │ │ │ ├── SyncUpForm-02-code-0006.swift │ │ │ │ ├── SyncUpForm-02-video-0007.mp4 │ │ │ │ ├── SyncUpForm-03-code-0001-previous.swift │ │ │ │ ├── SyncUpForm-03-code-0001.swift │ │ │ │ ├── SyncUpForm-03-code-0002.swift │ │ │ │ ├── SyncUpForm-03-code-0003.swift │ │ │ │ ├── SyncUpForm-03-code-0004-previous.swift │ │ │ │ ├── SyncUpForm-03-code-0004.swift │ │ │ │ ├── SyncUpForm-03-code-0005.swift │ │ │ │ ├── SyncUpForm.tutorial │ │ │ │ ├── SyncUpFormBasics-01-0000.png │ │ │ │ ├── TestingSyncUpForm-01-code-0001.swift │ │ │ │ ├── TestingSyncUpForm-01-code-0002.swift │ │ │ │ ├── TestingSyncUpForm-01-code-0003.swift │ │ │ │ ├── TestingSyncUpForm-01-code-0004-previous.swift │ │ │ │ ├── TestingSyncUpForm-01-code-0004.swift │ │ │ │ ├── TestingSyncUpForm-01-code-0005.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0001-previous.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0001.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0002.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0003.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0004-previous.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0004.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0005.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0006-previous.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0006.swift │ │ │ │ ├── TestingSyncUpForm-02-code-0007.swift │ │ │ │ └── TestingSyncUpForm.tutorial │ │ │ ├── 04-PresentingSyncUpForm │ │ │ │ ├── PresentingSyncUpForm-01-code-0001-previous.swift │ │ │ │ ├── PresentingSyncUpForm-01-code-0001.swift │ │ │ │ ├── PresentingSyncUpForm-01-code-0002.swift │ │ │ │ ├── PresentingSyncUpForm-01-code-0003.swift │ │ │ │ ├── PresentingSyncUpForm-01-code-0004.swift │ │ │ │ ├── PresentingSyncUpForm-01-code-0005.swift │ │ │ │ ├── PresentingSyncUpForm-02-code-0001-previous.swift │ │ │ │ ├── PresentingSyncUpForm-02-code-0001.swift │ │ │ │ ├── PresentingSyncUpForm-02-code-0002.swift │ │ │ │ ├── PresentingSyncUpForm-02-code-0003.swift │ │ │ │ ├── PresentingSyncUpForm-02-video-0004.mov │ │ │ │ ├── PresentingSyncUpForm-03-code-0001-previous.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0001.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0002.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0003-previous.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0003.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0004.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0005.swift │ │ │ │ ├── PresentingSyncUpForm-03-code-0006.mov │ │ │ │ ├── PresentingSyncUpForm.tutorial │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0001-previous.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0001.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0002.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0003.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0004.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0005-previous.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0005.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0006.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0007-previous.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0007.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0008.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0009.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0010.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0011.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0012.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0013.swift │ │ │ │ ├── TestingSyncUpFormPresentation-01-code-0014.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0001-previous.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0001.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0002.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0003.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0004.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0005.swift │ │ │ │ ├── TestingSyncUpFormPresentation-02-code-0006.swift │ │ │ │ └── TestingSyncUpFormPresentation.tutorial │ │ │ ├── 05-PersistingSyncUps │ │ │ │ ├── PersistingSyncUps-01-code-0001-previous.swift │ │ │ │ ├── PersistingSyncUps-01-code-0001.swift │ │ │ │ ├── PersistingSyncUps-01-code-0002.swift │ │ │ │ ├── PersistingSyncUps-01-code-0003.swift │ │ │ │ ├── PersistingSyncUps-01-code-0004.swift │ │ │ │ ├── PersistingSyncUps-01-code-0005.swift │ │ │ │ ├── PersistingSyncUps-01-code-0006-previous.swift │ │ │ │ ├── PersistingSyncUps-01-code-0006.swift │ │ │ │ ├── PersistingSyncUps-01-code-0007.swift │ │ │ │ ├── PersistingSyncUps-01-video-0008.mov │ │ │ │ ├── PersistingSyncUps-02-code-0001-previous.swift │ │ │ │ ├── PersistingSyncUps-02-code-0001.swift │ │ │ │ ├── PersistingSyncUps-02-code-0002.swift │ │ │ │ ├── PersistingSyncUps-02-code-0003.swift │ │ │ │ └── PersistingSyncUps.tutorial │ │ │ ├── 06-SyncUpDetail │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0001-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0001.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0002.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0003.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0004.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0005-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0005.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0006.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0007.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0008.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0009-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0009.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0010.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-code-0011.swift │ │ │ │ ├── EditingAndDeletingSyncUp-01-cover-480p.mov │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0001-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0001.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0002.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0003.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0004.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0005.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0006.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0007.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0008.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0009.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0010.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0011.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0012.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0013.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0014-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-code-0014.swift │ │ │ │ ├── EditingAndDeletingSyncUp-02-cover-480p.mov │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0001-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0001.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0002.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0003-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0003.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0004.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0005.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0006.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0007.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0008.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0009.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0010.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0011.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0012.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0013-previous.swift │ │ │ │ ├── EditingAndDeletingSyncUp-03-code-0013.swift │ │ │ │ ├── EditingAndDeletingSyncUp.tutorial │ │ │ │ ├── SyncUpDetail-01-code-0001.swift │ │ │ │ ├── SyncUpDetail-01-code-0002.swift │ │ │ │ ├── SyncUpDetail-01-code-0003.swift │ │ │ │ ├── SyncUpDetail-01-code-0004.swift │ │ │ │ ├── SyncUpDetail-01-code-0005.swift │ │ │ │ ├── SyncUpDetail-01-code-0006.swift │ │ │ │ ├── SyncUpDetail-01-code-0007.swift │ │ │ │ ├── SyncUpDetail-01-image-0007.png │ │ │ │ ├── SyncUpDetail-cover.png │ │ │ │ ├── SyncUpDetail.tutorial │ │ │ │ ├── TestingSyncUpDetail-01-code-0001.swift │ │ │ │ ├── TestingSyncUpDetail-01-code-0002.swift │ │ │ │ ├── TestingSyncUpDetail-01-code-0003.swift │ │ │ │ ├── TestingSyncUpDetail-01-code-0004.swift │ │ │ │ ├── TestingSyncUpDetail-01-code-0005.swift │ │ │ │ ├── TestingSyncUpDetail-01-code-0006.swift │ │ │ │ └── TestingSyncUpDetail.tutorial │ │ │ ├── 07-SyncUpDetailNavigation │ │ │ │ ├── MeetingNavigation-01-code-0001.swift │ │ │ │ ├── MeetingNavigation-01-code-0002.swift │ │ │ │ ├── MeetingNavigation-01-code-0003.swift │ │ │ │ ├── MeetingNavigation-01-cover.png │ │ │ │ ├── MeetingNavigation-02-code-0001.swift │ │ │ │ ├── MeetingNavigation-02-code-0002.swift │ │ │ │ ├── MeetingNavigation-02-code-0003-previous.swift │ │ │ │ ├── MeetingNavigation-02-code-0003.swift │ │ │ │ ├── MeetingNavigation-02-code-0004-previous.swift │ │ │ │ ├── MeetingNavigation-02-code-0004.swift │ │ │ │ ├── MeetingNavigation.tutorial │ │ │ │ ├── SyncUpDetailNavigation-01-code-0001.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0002.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0003.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0004.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0005.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0006.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0007.swift │ │ │ │ ├── SyncUpDetailNavigation-01-code-0008.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0001-previous.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0001.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0002.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0003.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0004.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0005.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0006.swift │ │ │ │ ├── SyncUpDetailNavigation-02-code-0007.swift │ │ │ │ ├── SyncUpDetailNavigation-03-code-0001-previous.swift │ │ │ │ ├── SyncUpDetailNavigation-03-code-0001.swift │ │ │ │ ├── SyncUpDetailNavigation-03-code-0002.swift │ │ │ │ ├── SyncUpDetailNavigation-03-code-0003.swift │ │ │ │ ├── SyncUpDetailNavigation-03-code-0004.swift │ │ │ │ ├── SyncUpDetailNavigation-03-video-0005.mov │ │ │ │ ├── SyncUpDetailNavigation-03-video-0006.mov │ │ │ │ ├── SyncUpDetailNavigation.tutorial │ │ │ │ ├── TestingNavigation-01-code-0001.swift │ │ │ │ ├── TestingNavigation-01-code-0002.swift │ │ │ │ ├── TestingNavigation-01-code-0003.swift │ │ │ │ ├── TestingNavigation-01-code-0004.swift │ │ │ │ ├── TestingNavigation-01-code-0005.swift │ │ │ │ ├── TestingNavigation-01-code-0006.swift │ │ │ │ ├── TestingNavigation-01-code-0007.swift │ │ │ │ ├── TestingNavigation-01-code-0008.swift │ │ │ │ └── TestingNavigation.tutorial │ │ │ ├── 08-RecordMeeting │ │ │ │ ├── ImplementingSpeechRecognizer.tutorial │ │ │ │ ├── ImplementingTimer-01-code-0001-previous.swift │ │ │ │ ├── ImplementingTimer-01-code-0001.swift │ │ │ │ ├── ImplementingTimer-01-code-0002.swift │ │ │ │ ├── ImplementingTimer-01-code-0003.swift │ │ │ │ ├── ImplementingTimer-01-code-0004.swift │ │ │ │ ├── ImplementingTimer-01-code-0005.swift │ │ │ │ ├── ImplementingTimer-01-code-0006.swift │ │ │ │ ├── ImplementingTimer-01-code-0007.swift │ │ │ │ ├── ImplementingTimer-01-code-0008.swift │ │ │ │ ├── ImplementingTimer-01-code-0009.swift │ │ │ │ ├── ImplementingTimer-01-code-0010.swift │ │ │ │ ├── ImplementingTimer-01-code-0011-previous.swift │ │ │ │ ├── ImplementingTimer-01-code-0011.swift │ │ │ │ ├── ImplementingTimer-01-video-0012.mov │ │ │ │ ├── ImplementingTimer-02-code-0001-previous.swift │ │ │ │ ├── ImplementingTimer-02-code-0001.swift │ │ │ │ ├── ImplementingTimer-02-code-0002.swift │ │ │ │ ├── ImplementingTimer-02-code-0003.swift │ │ │ │ ├── ImplementingTimer-02-code-0004.swift │ │ │ │ ├── ImplementingTimer-03-code-0001-previous.swift │ │ │ │ ├── ImplementingTimer-03-code-0001.swift │ │ │ │ ├── ImplementingTimer-03-code-0002.swift │ │ │ │ ├── ImplementingTimer-03-code-0003.swift │ │ │ │ ├── ImplementingTimer-03-code-0004.swift │ │ │ │ ├── ImplementingTimer-03-code-0005.swift │ │ │ │ ├── ImplementingTimer-03-code-0006.swift │ │ │ │ ├── ImplementingTimer-03-code-0007.swift │ │ │ │ ├── ImplementingTimer-03-code-0008.swift │ │ │ │ ├── ImplementingTimer-03-video-0009.mov │ │ │ │ ├── ImplementingTimer-04-code-0001.swift │ │ │ │ ├── ImplementingTimer-04-code-0002.swift │ │ │ │ ├── ImplementingTimer-04-code-0003.swift │ │ │ │ ├── ImplementingTimer-04-code-0004.swift │ │ │ │ ├── ImplementingTimer-04-code-0005.swift │ │ │ │ ├── ImplementingTimer-04-code-0006.swift │ │ │ │ ├── ImplementingTimer-04-code-0007.swift │ │ │ │ ├── ImplementingTimer-04-code-0008.swift │ │ │ │ ├── ImplementingTimer-04-code-0009.swift │ │ │ │ ├── ImplementingTimer-04-code-0010.swift │ │ │ │ ├── ImplementingTimer-04-code-0011.swift │ │ │ │ ├── ImplementingTimer-04-code-0012.swift │ │ │ │ ├── ImplementingTimer-04-code-0013.swift │ │ │ │ ├── ImplementingTimer-04-code-0014.swift │ │ │ │ ├── ImplementingTimer-04-code-0015.swift │ │ │ │ ├── ImplementingTimer-04-code-0016.swift │ │ │ │ ├── ImplementingTimer-04-code-0017.swift │ │ │ │ ├── ImplementingTimer.tutorial │ │ │ │ ├── RecordMeetingFeature-01-code-0001.swift │ │ │ │ ├── RecordMeetingFeature-01-code-0002.swift │ │ │ │ ├── RecordMeetingFeature-01-code-0003.swift │ │ │ │ ├── RecordMeetingFeature-01-image-0004.jpg │ │ │ │ ├── RecordMeetingFeature-02-code-0001-previous.swift │ │ │ │ ├── RecordMeetingFeature-02-code-0001.swift │ │ │ │ ├── RecordMeetingFeature-02-code-0002-previous.swift │ │ │ │ ├── RecordMeetingFeature-02-code-0002.swift │ │ │ │ ├── RecordMeetingFeature-02-code-0003-previous.swift │ │ │ │ ├── RecordMeetingFeature-02-code-0003.swift │ │ │ │ ├── RecordMeetingFeature-02-video-0004.mov │ │ │ │ └── RecordMeetingFeature.tutorial │ │ │ └── BuildingSyncUps.tutorial │ │ │ └── MeetTheComposableArchitecture │ │ │ ├── 01-Essentials │ │ │ ├── 01-YourFirstFeature │ │ │ │ ├── 01-01-01-code-0001.swift │ │ │ │ ├── 01-01-01-code-0002.swift │ │ │ │ ├── 01-01-01-code-0003.swift │ │ │ │ ├── 01-01-01-code-0004.swift │ │ │ │ ├── 01-01-01-code-0005.swift │ │ │ │ ├── 01-01-01-code-0006.swift │ │ │ │ ├── 01-01-02-code-0001.swift │ │ │ │ ├── 01-01-02-code-0002.swift │ │ │ │ ├── 01-01-02-code-0003.swift │ │ │ │ ├── 01-01-02-code-0004.swift │ │ │ │ ├── 01-01-02-code-0005.swift │ │ │ │ ├── 01-01-02-code-0006.swift │ │ │ │ ├── 01-01-02-code-0007.swift │ │ │ │ ├── 01-01-03-code-0001.swift │ │ │ │ ├── 01-01-03-code-0002.swift │ │ │ │ ├── 01-01-03-code-0003.swift │ │ │ │ ├── 01-01-03-code-0004.swift │ │ │ │ └── 01-01-YourFirstFeature.tutorial │ │ │ ├── 02-AddingSideEffects │ │ │ │ ├── 01-02-01-code-0001-previous.swift │ │ │ │ ├── 01-02-01-code-0001.swift │ │ │ │ ├── 01-02-01-code-0002.swift │ │ │ │ ├── 01-02-01-code-0003.swift │ │ │ │ ├── 01-02-01-code-0004.swift │ │ │ │ ├── 01-02-01-code-0005.swift │ │ │ │ ├── 01-02-02-code-0001.swift │ │ │ │ ├── 01-02-02-code-0002.swift │ │ │ │ ├── 01-02-02-code-0003.swift │ │ │ │ ├── 01-02-02-code-0004.swift │ │ │ │ ├── 01-02-02-code-0005.swift │ │ │ │ ├── 01-02-03-code-0001.swift │ │ │ │ ├── 01-02-03-code-0002.swift │ │ │ │ ├── 01-02-03-code-0003.swift │ │ │ │ ├── 01-02-03-code-0004.swift │ │ │ │ ├── 01-02-03-code-0005.swift │ │ │ │ ├── 01-02-03-code-0006.swift │ │ │ │ └── 01-02-AddingSideEffects.tutorial │ │ │ ├── 03-TestingYourFeatures │ │ │ │ ├── 01-03-01-code-0001.swift │ │ │ │ ├── 01-03-01-code-0002.swift │ │ │ │ ├── 01-03-01-code-0003-previous.swift │ │ │ │ ├── 01-03-01-code-0003.swift │ │ │ │ ├── 01-03-01-code-0004.swift │ │ │ │ ├── 01-03-01-code-0005.swift │ │ │ │ ├── 01-03-01-code-0006.swift │ │ │ │ ├── 01-03-02-code-0001-previous.swift │ │ │ │ ├── 01-03-02-code-0001.swift │ │ │ │ ├── 01-03-02-code-0002.swift │ │ │ │ ├── 01-03-02-code-0003.swift │ │ │ │ ├── 01-03-02-code-0004.swift │ │ │ │ ├── 01-03-02-code-0005.swift │ │ │ │ ├── 01-03-02-code-0006.swift │ │ │ │ ├── 01-03-02-code-0007.swift │ │ │ │ ├── 01-03-02-code-0008.swift │ │ │ │ ├── 01-03-02-code-0009.swift │ │ │ │ ├── 01-03-02-code-0010.swift │ │ │ │ ├── 01-03-03-code-0001-previous.swift │ │ │ │ ├── 01-03-03-code-0001.swift │ │ │ │ ├── 01-03-03-code-0002.swift │ │ │ │ ├── 01-03-03-code-0003.swift │ │ │ │ ├── 01-03-03-code-0004.swift │ │ │ │ ├── 01-03-03-code-0005.swift │ │ │ │ ├── 01-03-04-code-0001.swift │ │ │ │ ├── 01-03-04-code-0002.swift │ │ │ │ ├── 01-03-04-code-0003.swift │ │ │ │ ├── 01-03-04-code-0004.swift │ │ │ │ ├── 01-03-04-code-0005.swift │ │ │ │ ├── 01-03-04-code-0006-previous.swift │ │ │ │ ├── 01-03-04-code-0006.swift │ │ │ │ ├── 01-03-04-code-0007.swift │ │ │ │ ├── 01-03-04-code-0008.swift │ │ │ │ └── 01-03-TestingYourFeature.tutorial │ │ │ └── 04-ComposingFeatures │ │ │ │ ├── 01-04-01-code-0001.swift │ │ │ │ ├── 01-04-01-code-0002.swift │ │ │ │ ├── 01-04-01-code-0003.swift │ │ │ │ ├── 01-04-02-code-0001.swift │ │ │ │ ├── 01-04-02-code-0002.swift │ │ │ │ ├── 01-04-02-code-0003.swift │ │ │ │ ├── 01-04-02-code-0004.swift │ │ │ │ ├── 01-04-02-code-0005.swift │ │ │ │ ├── 01-04-02-code-0006.swift │ │ │ │ ├── 01-04-02-code-0007.swift │ │ │ │ ├── 01-04-02-code-0008.swift │ │ │ │ ├── 01-04-03-code-0001-previous.swift │ │ │ │ ├── 01-04-03-code-0001.swift │ │ │ │ ├── 01-04-03-code-0002.swift │ │ │ │ ├── 01-04-03-code-0003.swift │ │ │ │ ├── 01-04-03-code-0004.swift │ │ │ │ ├── 01-04-03-code-0005-previous.swift │ │ │ │ ├── 01-04-03-code-0005.swift │ │ │ │ └── 01-04-ComposingFeatures.tutorial │ │ │ ├── 02-Navigation │ │ │ ├── 01-YourFirstPresentation │ │ │ │ ├── 02-01-01-code-0000.swift │ │ │ │ ├── 02-01-01-code-0001.swift │ │ │ │ ├── 02-01-01-code-0002.swift │ │ │ │ ├── 02-01-01-code-0003.swift │ │ │ │ ├── 02-01-01-code-0004.swift │ │ │ │ ├── 02-01-01-code-0005.swift │ │ │ │ ├── 02-01-01-code-0006.swift │ │ │ │ ├── 02-01-01-code-0007.swift │ │ │ │ ├── 02-01-02-code-0000.swift │ │ │ │ ├── 02-01-02-code-0001.swift │ │ │ │ ├── 02-01-02-code-0002.swift │ │ │ │ ├── 02-01-02-code-0003.swift │ │ │ │ ├── 02-01-02-code-0004.swift │ │ │ │ ├── 02-01-02-code-0005.swift │ │ │ │ ├── 02-01-02-code-0006.swift │ │ │ │ ├── 02-01-02-code-0007.swift │ │ │ │ ├── 02-01-02-code-0008.swift │ │ │ │ ├── 02-01-02-code-0009.swift │ │ │ │ ├── 02-01-04-code-0000-previous.swift │ │ │ │ ├── 02-01-04-code-0000.swift │ │ │ │ ├── 02-01-04-code-0001.swift │ │ │ │ ├── 02-01-04-code-0002.swift │ │ │ │ ├── 02-01-04-code-0003-previous.swift │ │ │ │ ├── 02-01-04-code-0003.swift │ │ │ │ ├── 02-01-04-code-0004-previous.swift │ │ │ │ ├── 02-01-04-code-0004.swift │ │ │ │ ├── 02-01-04-code-0005.swift │ │ │ │ ├── 02-01-04-code-0006.swift │ │ │ │ ├── 02-01-04-code-0007-previous.swift │ │ │ │ ├── 02-01-04-code-0007.swift │ │ │ │ └── 02-01-YourFirstPresentation.tutorial │ │ │ ├── 02-MultipleDestinations │ │ │ │ ├── 02-02-01-code-0000-previous.swift │ │ │ │ ├── 02-02-01-code-0000.swift │ │ │ │ ├── 02-02-01-code-0001.swift │ │ │ │ ├── 02-02-01-code-0002.swift │ │ │ │ ├── 02-02-01-code-0003.swift │ │ │ │ ├── 02-02-01-code-0004.swift │ │ │ │ ├── 02-02-01-code-0005.swift │ │ │ │ ├── 02-02-01-code-0006-previous.swift │ │ │ │ ├── 02-02-01-code-0006.swift │ │ │ │ ├── 02-02-01-code-0007.swift │ │ │ │ ├── 02-02-02-code-0000.swift │ │ │ │ ├── 02-02-02-code-0001.swift │ │ │ │ ├── 02-02-02-code-0002.swift │ │ │ │ ├── 02-02-02-code-0003-previous.swift │ │ │ │ ├── 02-02-02-code-0003.swift │ │ │ │ ├── 02-02-02-code-0004-previous.swift │ │ │ │ ├── 02-02-02-code-0004.swift │ │ │ │ ├── 02-02-02-code-0005-previous.swift │ │ │ │ ├── 02-02-02-code-0005.swift │ │ │ │ ├── 02-02-02-code-0006.swift │ │ │ │ ├── 02-02-02-code-0007.swift │ │ │ │ ├── 02-02-02-code-0008.swift │ │ │ │ ├── 02-02-02-code-0009.swift │ │ │ │ ├── 02-02-02-code-0010.swift │ │ │ │ ├── 02-02-02-code-0011.swift │ │ │ │ ├── 02-02-02-code-0012-previous.swift │ │ │ │ ├── 02-02-02-code-0012.swift │ │ │ │ ├── 02-02-02-code-0013.swift │ │ │ │ └── 02-02-MultipleDestinations.tutorial │ │ │ ├── 03-TestingPresentation │ │ │ │ ├── 02-03-01-code-0000.swift │ │ │ │ ├── 02-03-01-code-0001.swift │ │ │ │ ├── 02-03-01-code-0002.swift │ │ │ │ ├── 02-03-01-code-0003.swift │ │ │ │ ├── 02-03-01-code-0004.swift │ │ │ │ ├── 02-03-01-code-0005.swift │ │ │ │ ├── 02-03-01-code-0006-previous.swift │ │ │ │ ├── 02-03-01-code-0006.swift │ │ │ │ ├── 02-03-01-code-0007.swift │ │ │ │ ├── 02-03-01-code-0008-previous.swift │ │ │ │ ├── 02-03-01-code-0008.swift │ │ │ │ ├── 02-03-01-code-0009.swift │ │ │ │ ├── 02-03-01-code-0010.swift │ │ │ │ ├── 02-03-01-code-0011.swift │ │ │ │ ├── 02-03-01-code-0012.swift │ │ │ │ ├── 02-03-01-code-0013.swift │ │ │ │ ├── 02-03-01-code-0014.swift │ │ │ │ ├── 02-03-01-code-0015-previous.swift │ │ │ │ ├── 02-03-01-code-0015.swift │ │ │ │ ├── 02-03-01-code-0016.swift │ │ │ │ ├── 02-03-01-code-0017.swift │ │ │ │ ├── 02-03-02-code-0000.swift │ │ │ │ ├── 02-03-02-code-0001.swift │ │ │ │ ├── 02-03-02-code-0002.swift │ │ │ │ ├── 02-03-02-code-0003.swift │ │ │ │ ├── 02-03-02-code-0004.swift │ │ │ │ ├── 02-03-02-code-0005.swift │ │ │ │ ├── 02-03-02-code-0006.swift │ │ │ │ ├── 02-03-03-code-0000.swift │ │ │ │ ├── 02-03-03-code-0001.swift │ │ │ │ ├── 02-03-03-code-0002.swift │ │ │ │ ├── 02-03-03-code-0003.swift │ │ │ │ ├── 02-03-03-code-0004.swift │ │ │ │ ├── 02-03-03-code-0005.swift │ │ │ │ ├── 02-03-03-code-0006.swift │ │ │ │ ├── 02-03-03-code-0007-previous.swift │ │ │ │ ├── 02-03-03-code-0007.swift │ │ │ │ ├── 02-03-03-code-0008-previous.swift │ │ │ │ ├── 02-03-03-code-0008.swift │ │ │ │ ├── 02-03-03-code-0009.swift │ │ │ │ ├── 02-03-03-code-0010.swift │ │ │ │ └── 02-03-TestingPresentation.tutorial │ │ │ └── 04-NavigationStacks │ │ │ │ ├── 02-04-01-code-0000.swift │ │ │ │ ├── 02-04-01-code-0001.swift │ │ │ │ ├── 02-04-01-code-0002.swift │ │ │ │ ├── 02-04-01-code-0003.swift │ │ │ │ ├── 02-04-01-code-0004.swift │ │ │ │ ├── 02-04-01-code-0005.swift │ │ │ │ ├── 02-04-01-code-0006.swift │ │ │ │ ├── 02-04-01-code-0007.swift │ │ │ │ ├── 02-04-02-code-0000-previous.swift │ │ │ │ ├── 02-04-02-code-0000.swift │ │ │ │ ├── 02-04-02-code-0001.swift │ │ │ │ ├── 02-04-02-code-0002.swift │ │ │ │ ├── 02-04-02-code-0003-previous.swift │ │ │ │ ├── 02-04-02-code-0003.swift │ │ │ │ ├── 02-04-02-code-0004.swift │ │ │ │ ├── 02-04-02-code-0005-previous.swift │ │ │ │ ├── 02-04-02-code-0005.swift │ │ │ │ ├── 02-04-02-code-0006-previous.swift │ │ │ │ ├── 02-04-02-code-0006.swift │ │ │ │ ├── 02-04-03-code-0000-previous.swift │ │ │ │ ├── 02-04-03-code-0000.swift │ │ │ │ ├── 02-04-03-code-0001.swift │ │ │ │ ├── 02-04-03-code-0002.swift │ │ │ │ ├── 02-04-03-code-0003-previous.swift │ │ │ │ ├── 02-04-03-code-0003.swift │ │ │ │ ├── 02-04-03-code-0004-previous.swift │ │ │ │ ├── 02-04-03-code-0004.swift │ │ │ │ └── 02-04-NavigationStacks.tutorial │ │ │ ├── MeetComposableArchitecture.tutorial │ │ │ ├── chapter1.png │ │ │ ├── chapter2.png │ │ │ ├── chapter3.png │ │ │ ├── chapter4.png │ │ │ ├── chapter5.png │ │ │ ├── chapter6.png │ │ │ ├── chapter7.png │ │ │ └── chapter8.png │ ├── Effect.swift │ ├── Effects │ │ ├── Animation.swift │ │ ├── Cancellation.swift │ │ ├── Debounce.swift │ │ ├── Publisher.swift │ │ ├── TaskResult.swift │ │ └── Throttle.swift │ ├── Internal │ │ ├── AreOrderedSetsDuplicates.swift │ │ ├── AssumeIsolated.swift │ │ ├── Box.swift │ │ ├── Create.swift │ │ ├── CurrentValueRelay.swift │ │ ├── Debug.swift │ │ ├── DefaultSubscript.swift │ │ ├── Deprecations.swift │ │ ├── DispatchQueue.swift │ │ ├── EffectActions.swift │ │ ├── EphemeralState.swift │ │ ├── Exports.swift │ │ ├── HashableStaticString.swift │ │ ├── KeyPath+Sendable.swift │ │ ├── Locking.swift │ │ ├── Logger.swift │ │ ├── NavigationID.swift │ │ ├── NotificationName.swift │ │ ├── OpenExistential.swift │ │ ├── PresentationID.swift │ │ ├── ReturningLastNonNilValue.swift │ │ ├── RuntimeWarnings.swift │ │ └── StackIDGenerator.swift │ ├── Macros.swift │ ├── Observation │ │ ├── Alert+Observation.swift │ │ ├── Binding+Observation.swift │ │ ├── IdentifiedArray+Observation.swift │ │ ├── NavigationStack+Observation.swift │ │ ├── ObservableState.swift │ │ ├── ObservationStateRegistrar.swift │ │ ├── Store+Observation.swift │ │ └── ViewAction.swift │ ├── Reducer.swift │ ├── Reducer │ │ ├── ReducerBuilder.swift │ │ └── Reducers │ │ │ ├── BindingReducer.swift │ │ │ ├── CombineReducers.swift │ │ │ ├── DebugReducer.swift │ │ │ ├── DependencyKeyWritingReducer.swift │ │ │ ├── EmptyReducer.swift │ │ │ ├── ForEachReducer.swift │ │ │ ├── IfCaseLetReducer.swift │ │ │ ├── IfLetReducer.swift │ │ │ ├── OnChange.swift │ │ │ ├── Optional.swift │ │ │ ├── PresentationReducer.swift │ │ │ ├── Reduce.swift │ │ │ ├── Scope.swift │ │ │ ├── SignpostReducer.swift │ │ │ └── StackReducer.swift │ ├── Resources │ │ └── PrivacyInfo.xcprivacy │ ├── Sharing │ │ └── AppStorageKeyPathKey.swift │ ├── Store.swift │ ├── SwiftUI │ │ ├── Alert.swift │ │ ├── Binding.swift │ │ ├── ConfirmationDialog.swift │ │ ├── Deprecated │ │ │ ├── ActionSheet.swift │ │ │ ├── LegacyAlert.swift │ │ │ └── NavigationLinkStore.swift │ │ ├── ForEachStore.swift │ │ ├── FullScreenCover.swift │ │ ├── IfLetStore.swift │ │ ├── NavigationDestination.swift │ │ ├── NavigationStackStore.swift │ │ ├── Popover.swift │ │ ├── PresentationModifier.swift │ │ ├── Sheet.swift │ │ ├── SwitchStore.swift │ │ └── WithViewStore.swift │ ├── TestStore.swift │ ├── UIKit │ │ ├── AlertStateUIKit.swift │ │ ├── IfLetUIKit.swift │ │ └── NavigationStackControllerUIKit.swift │ └── ViewStore.swift └── ComposableArchitectureMacros │ ├── Availability.swift │ ├── Extensions.swift │ ├── ObservableStateMacro.swift │ ├── Plugins.swift │ ├── PresentsMacro.swift │ ├── ReducerMacro.swift │ └── ViewActionMacro.swift └── Tests ├── ComposableArchitectureMacrosTests ├── MacroBaseTestCase.swift ├── ObservableStateMacroTests.swift ├── PresentsMacroTests.swift ├── ReducerMacroTests.swift └── ViewActionMacroTests.swift └── ComposableArchitectureTests ├── BindableStoreTests.swift ├── BindingLocalTests.swift ├── CompatibilityTests.swift ├── ComposableArchitectureTests.swift ├── CurrentValueRelayTests.swift ├── DebugTests.swift ├── DependencyKeyWritingReducerTests.swift ├── EffectCancellationIsolationTests.swift ├── EffectCancellationTests.swift ├── EffectDebounceTests.swift ├── EffectFailureTests.swift ├── EffectOperationTests.swift ├── EffectRunTests.swift ├── EffectTests.swift ├── EnumReducerMacroTests.swift ├── Internal ├── BaseTCATestCase.swift └── TestHelpers.swift ├── MacroConformanceTests.swift ├── MacroTests.swift ├── MemoryManagementTests.swift ├── ObservableStateEnumMacroTests.swift ├── ObservableTests.swift ├── ReducerBuilderTests.swift ├── ReducerTests.swift ├── Reducers ├── BindingReducerTests.swift ├── ForEachReducerTests.swift ├── IfCaseLetReducerTests.swift ├── IfLetReducerTests.swift ├── OnChangeReducerTests.swift ├── PresentationReducerTests.swift └── StackReducerTests.swift ├── RuntimeWarningTests.swift ├── ScopeCacheTests.swift ├── ScopeLoggerTests.swift ├── ScopeTests.swift ├── StoreLifetimeTests.swift ├── StorePerceptionTests.swift ├── StoreTests.swift ├── TaskCancellationTests.swift ├── TaskResultTests.swift ├── TestStoreFailureTests.swift ├── TestStoreNonExhaustiveTests.swift ├── TestStoreTests.swift ├── ThrottleTests.swift └── ViewStoreTests.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/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | 3 | contact_links: 4 | - name: Project Discussion 5 | url: https://github.com/pointfreeco/swift-composable-architecture/discussions 6 | about: Composable Architecture Q&A, ideas, and more 7 | - name: Documentation 8 | url: https://pointfreeco.github.io/swift-composable-architecture/main/documentation/composablearchitecture/ 9 | about: Read the Composable Architecture's documentation 10 | - name: Videos 11 | url: https://www.pointfree.co/collections/composable-architecture 12 | about: Watch videos to get a behind-the-scenes look at how the Composable Architecture was motivated and built 13 | - name: Slack 14 | url: https://www.pointfree.co/slack-invite 15 | about: Community chat 16 | -------------------------------------------------------------------------------- /.github/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.github/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.github/workflows/format.yml: -------------------------------------------------------------------------------- 1 | name: Format 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | concurrency: 9 | group: format-${{ github.ref }} 10 | cancel-in-progress: true 11 | 12 | jobs: 13 | swift_format: 14 | name: swift-format 15 | runs-on: macos-15 16 | permissions: 17 | contents: write 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Select Xcode 16.2 21 | run: sudo xcode-select -s /Applications/Xcode_16.2.app 22 | - name: Format 23 | run: make format 24 | - uses: stefanzweifel/git-auto-commit-action@v5 25 | with: 26 | commit_message: Run swift-format 27 | branch: 'main' 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .build 3 | .swiftpm 4 | /Packages 5 | /*.swiftinterface 6 | /*.xcodeproj 7 | xcuserdata/ 8 | .docc-build/ -------------------------------------------------------------------------------- /.spi.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | builder: 3 | configs: 4 | - platform: ios 5 | scheme: ComposableArchitecture 6 | - platform: macos-xcodebuild 7 | scheme: ComposableArchitecture 8 | - platform: tvos 9 | scheme: ComposableArchitecture 10 | - platform: watchos 11 | scheme: ComposableArchitecture 12 | - documentation_targets: [ComposableArchitecture] 13 | -------------------------------------------------------------------------------- /ComposableArchitecture.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ComposableArchitecture.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/CaseStudies/CaseStudies.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/CaseStudies/CaseStudies.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/CaseStudies/README.md: -------------------------------------------------------------------------------- 1 | # Composable Architecture Case Studies 2 | 3 | This project includes a number of digestible examples of how to solve common problems using the Composable Architecture. 4 | -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/CaseStudiesApp.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct CaseStudiesApp: App { 6 | var body: some Scene { 7 | WindowGroup { 8 | RootView() 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Internal/AboutView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct AboutView: View { 4 | let readMe: String 5 | 6 | var body: some View { 7 | DisclosureGroup("About this case study") { 8 | Text(template: self.readMe) 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Internal/CircularProgressView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct CircularProgressView: View { 4 | private let value: Double 5 | 6 | init(value: Double) { 7 | self.value = value 8 | } 9 | 10 | var body: some View { 11 | Circle() 12 | .trim(from: 0, to: CGFloat(self.value)) 13 | .stroke(style: StrokeStyle(lineWidth: 2, lineCap: .round)) 14 | .rotationEffect(.degrees(-90)) 15 | .animation(.easeIn, value: self.value) 16 | } 17 | } 18 | 19 | #Preview { 20 | CircularProgressView(value: 0.3).frame(width: 44, height: 44) 21 | } 22 | -------------------------------------------------------------------------------- /Examples/CaseStudies/SwiftUICaseStudies/Internal/UIViewRepresented.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct UIViewRepresented: UIViewRepresentable { 4 | let makeUIView: (Context) -> UIViewType 5 | let updateUIView: (UIViewType, Context) -> Void = { _, _ in } 6 | 7 | func makeUIView(context: Context) -> UIViewType { 8 | self.makeUIView(context) 9 | } 10 | 11 | func updateUIView(_ uiView: UIViewType, context: Context) { 12 | self.updateUIView(uiView, context) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Internal/ActivityIndicatorViewController.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | final class ActivityIndicatorViewController: UIViewController { 4 | override func viewDidLoad() { 5 | super.viewDidLoad() 6 | 7 | self.view.backgroundColor = .systemBackground 8 | 9 | let activityIndicator = UIActivityIndicatorView() 10 | activityIndicator.startAnimating() 11 | activityIndicator.translatesAutoresizingMaskIntoConstraints = false 12 | self.view.addSubview(activityIndicator) 13 | 14 | NSLayoutConstraint.activate([ 15 | activityIndicator.centerXAnchor.constraint( 16 | equalTo: self.view.safeAreaLayoutGuide.centerXAnchor), 17 | activityIndicator.centerYAnchor.constraint( 18 | equalTo: self.view.safeAreaLayoutGuide.centerYAnchor), 19 | ]) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Examples/CaseStudies/UIKitCaseStudies/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/CaseStudies/tvOSCaseStudies/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | import UIKit 4 | 5 | @main 6 | final class AppDelegate: UIResponder, UIApplicationDelegate { 7 | var window: UIWindow? 8 | 9 | func application( 10 | _ application: UIApplication, 11 | didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? 12 | ) -> Bool { 13 | let contentView = RootView( 14 | store: Store(initialState: Root.State()) { 15 | Root() 16 | } 17 | ) 18 | 19 | let window = UIWindow(frame: UIScreen.main.bounds) 20 | window.rootViewController = UIHostingController(rootView: contentView) 21 | self.window = window 22 | window.makeKeyAndVisible() 23 | return true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Examples/CaseStudies/tvOSCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/CaseStudies/tvOSCaseStudies/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/CaseStudies/tvOSCaseStudies/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/CaseStudies/tvOSCaseStudies/Core.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct Root { 5 | struct State { 6 | var focus = Focus.State() 7 | } 8 | 9 | enum Action { 10 | case focus(Focus.Action) 11 | } 12 | 13 | var body: some Reducer { 14 | Scope(state: \.focus, action: \.focus) { 15 | Focus() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Examples/CaseStudies/tvOSCaseStudies/RootView.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct RootView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | NavigationView { 9 | Form { 10 | Section { 11 | FocusView( 12 | store: store.scope(state: \.focus, action: \.focus) 13 | ) 14 | } 15 | } 16 | } 17 | } 18 | } 19 | 20 | #Preview { 21 | NavigationStack { 22 | RootView( 23 | store: Store(initialState: Root.State()) { 24 | Root() 25 | } 26 | ) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Examples/Integration/Integration.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/Integration/Integration.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Integration/Integration/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/Integration/Integration/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Examples/Integration/Integration/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/Integration/Integration/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleURLTypes 6 | 7 | 8 | CFBundleTypeRole 9 | Editor 10 | CFBundleURLIconFile 11 | 12 | CFBundleURLName 13 | 14 | CFBundleURLSchemes 15 | 16 | integration 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /Examples/Integration/Integration/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/Integration/IntegrationUITests/Internal/TestHelpers.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | @available( 4 | *, 5 | deprecated, 6 | message: "This is a test that currently fails but should not in the future." 7 | ) 8 | func XCTTODO(_ message: String) { 9 | XCTExpectFailure(message) 10 | } 11 | 12 | extension XCUIElement { 13 | func find( 14 | timeout: TimeInterval = 0.3, 15 | filePath: StaticString = #filePath, 16 | line: UInt = #line 17 | ) -> XCUIElement { 18 | if !self.waitForExistence(timeout: timeout) { 19 | XCTFail("Failed to find \(self).", file: filePath, line: line) 20 | } 21 | return self 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/Integration/IntegrationUITests/Test Cases/MultipleAlertsTests.swift: -------------------------------------------------------------------------------- 1 | import TestCases 2 | import XCTest 3 | 4 | final class MultipleAlertsTests: BaseIntegrationTests { 5 | @MainActor 6 | override func setUpWithError() throws { 7 | try XCTSkipIf(ProcessInfo.processInfo.environment["CI"] != nil) 8 | try super.setUpWithError() 9 | self.app.buttons["Test cases"].tap() 10 | app.collectionViews.buttons[TestCase.Cases.multipleAlerts.rawValue].tap() 11 | } 12 | 13 | @MainActor 14 | func testMultipleAlerts() { 15 | app.buttons["Show alert"].tap() 16 | 17 | app.buttons["Another!"].tap() 18 | 19 | app.buttons["I'm done"].tap() 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Examples/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.2 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Examples", 7 | products: [], 8 | targets: [] 9 | ) 10 | -------------------------------------------------------------------------------- /Examples/Search/Search.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/Search/Search.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Search/Search/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/Search/Search/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/Search/Search/SearchApp.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct SearchApp: App { 6 | static let store = Store(initialState: Search.State()) { 7 | Search() 8 | ._printChanges() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | SearchView(store: Self.store) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Examples/SpeechRecognition/README.md: -------------------------------------------------------------------------------- 1 | # Speech Recognition 2 | 3 | This application demonstrates how to work with a complex dependency in the Composable Architecture. It uses the `SFSpeechRecognizer` API from the `Speech` framework to listen to audio on the device and live-transcribe it to the UI. 4 | 5 | The `SFSpeechRecognizer` class is a complex dependency, and if we used it freely in our application we wouldn't be able to test any of that code. So, instead, we wrap the API in a `SpeechClient` type that exposes asynchronous endpoints for accessing the underlying `SFSpeechRecognizer` class. Then we can use it in the reducer in an understandable way, _and_ we can write tests for the reducer. 6 | -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/SpeechRecognition/SpeechRecognition/SpeechRecognitionApp.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct SpeechRecognitionApp: App { 6 | static let store = Store(initialState: SpeechRecognition.State()) { 7 | SpeechRecognition() 8 | ._printChanges() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | SpeechRecognitionView(store: Self.store) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Examples/SyncUps/SyncUps/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/SyncUps/SyncUps/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "platform" : "ios", 6 | "size" : "1024x1024" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Examples/SyncUps/SyncUps/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/SyncUps/SyncUps/Assets.xcassets/Themes/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/SyncUps/SyncUps/Dependencies/OpenSettings.swift: -------------------------------------------------------------------------------- 1 | import Dependencies 2 | import UIKit 3 | 4 | extension DependencyValues { 5 | var openSettings: @Sendable () async -> Void { 6 | get { self[OpenSettingsKey.self] } 7 | set { self[OpenSettingsKey.self] = newValue } 8 | } 9 | 10 | private enum OpenSettingsKey: DependencyKey { 11 | typealias Value = @Sendable () async -> Void 12 | 13 | static let liveValue: @Sendable () async -> Void = { 14 | await MainActor.run { 15 | UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!) 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Examples/SyncUps/SyncUps/Meeting.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct MeetingView: View { 4 | let meeting: Meeting 5 | let syncUp: SyncUp 6 | 7 | var body: some View { 8 | Form { 9 | Section { 10 | ForEach(syncUp.attendees) { attendee in 11 | Text(attendee.name) 12 | } 13 | } header: { 14 | Text("Attendees") 15 | } 16 | Section { 17 | Text(meeting.transcript) 18 | } header: { 19 | Text("Transcript") 20 | } 21 | } 22 | .navigationTitle(Text(meeting.date, style: .date)) 23 | } 24 | } 25 | 26 | #Preview { 27 | MeetingView(meeting: SyncUp.mock.meetings[0], syncUp: .mock) 28 | } 29 | -------------------------------------------------------------------------------- /Examples/SyncUps/SyncUps/Resources/ding.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/SyncUps/SyncUps/Resources/ding.wav -------------------------------------------------------------------------------- /Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/TicTacToe/App/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/TicTacToe/App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/TicTacToe/App/TicTacToeApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct TicTacToeApp: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | RootView() 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Examples/TicTacToe/TicTacToe.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/TicTacToe/TicTacToe.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/TicTacToe/tic-tac-toe/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | -------------------------------------------------------------------------------- /Examples/TicTacToe/tic-tac-toe/Sources/AppSwiftUI/AppView.swift: -------------------------------------------------------------------------------- 1 | import AppCore 2 | import ComposableArchitecture 3 | import LoginSwiftUI 4 | import NewGameSwiftUI 5 | import SwiftUI 6 | 7 | public struct AppView: View { 8 | let store: StoreOf 9 | 10 | public init(store: StoreOf) { 11 | self.store = store 12 | } 13 | 14 | public var body: some View { 15 | switch store.case { 16 | case let .login(store): 17 | NavigationStack { 18 | LoginView(store: store) 19 | } 20 | case let .newGame(store): 21 | NavigationStack { 22 | NewGameView(store: store) 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Examples/Todos/README.md: -------------------------------------------------------------------------------- 1 | # Todos 2 | 3 | This simple todo application built with the Composable Architecture includes a few bells and whistles: 4 | 5 | * Filtering and rearranging todo items. 6 | * Automatically sort completed todos to the bottom of the list. 7 | * Debouncing the sort action to allow multiple todo items to be toggled before being sorted. 8 | * A comprehensive test suite. 9 | -------------------------------------------------------------------------------- /Examples/Todos/Todos.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/Todos/Todos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/Todos/Todos/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/Todos/Todos/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/Todos/Todos/TodosApp.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct TodosApp: App { 6 | static let store = Store(initialState: Todos.State()) { 7 | Todos() 8 | ._printChanges() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | AppView(store: Self.store) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/README.md: -------------------------------------------------------------------------------- 1 | # Voice Memos 2 | 3 | This application demonstrates how to work with multiple dependencies and manage a complex state machine driven off of timers in the Composable Architecture. Some functionality includes: 4 | 5 | * Requesting the user’s permission to record audio. 6 | * Prompting the user if insufficient permission is provided. 7 | * Audio recording and playback. 8 | * Handling errors that may occur during recording or playback. 9 | * Stubbing dependencies to work with SwiftUI previews. 10 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon-60@2x.png -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon-76@2x.png -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon-iPadPro@2x.png -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/AppIcon.png -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Examples/VoiceMemos/VoiceMemos/Assets.xcassets/AppIcon.appiconset/transparent.png -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/AudioPlayerClient/AudioPlayerClient.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | 4 | @DependencyClient 5 | struct AudioPlayerClient { 6 | var play: @Sendable (_ url: URL) async throws -> Bool 7 | } 8 | 9 | extension AudioPlayerClient: TestDependencyKey { 10 | static let previewValue = Self( 11 | play: { _ in 12 | try await Task.sleep(for: .seconds(5)) 13 | return true 14 | } 15 | ) 16 | 17 | static let testValue = Self() 18 | } 19 | 20 | extension DependencyValues { 21 | var audioPlayer: AudioPlayerClient { 22 | get { self[AudioPlayerClient.self] } 23 | set { self[AudioPlayerClient.self] = newValue } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/Helpers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | let dateComponentsFormatter: DateComponentsFormatter = { 4 | let formatter = DateComponentsFormatter() 5 | formatter.allowedUnits = [.minute, .second] 6 | formatter.zeroFormattingBehavior = .pad 7 | return formatter 8 | }() 9 | -------------------------------------------------------------------------------- /Examples/VoiceMemos/VoiceMemos/VoiceMemosApp.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct VoiceMemosApp: App { 6 | static let store = Store(initialState: VoiceMemos.State()) { 7 | VoiceMemos() 8 | ._printChanges() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | VoiceMemosView(store: Self.store) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Dependencies/IsPresented.swift: -------------------------------------------------------------------------------- 1 | extension DependencyValues { 2 | /// A Boolean value that indicates whether the current feature is being presented from a parent 3 | /// feature. 4 | /// 5 | /// This value is set to true on reducers that are run from within 6 | /// ``Reducer/ifLet(_:action:destination:fileID:filePath:line:column:)-4ub6q`` and 7 | /// ``Reducer/forEach(_:action:destination:fileID:filePath:line:column:)-9svqb``. 8 | /// 9 | /// See ``DismissEffect`` for more information on how child features can easily dismiss themselves 10 | /// without communicating to the parent. 11 | public var isPresented: Bool { 12 | self.dismiss.dismiss != nil 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/Action.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer/Action`` 2 | 3 | ## Topics 4 | 5 | ### View actions 6 | 7 | - ``ViewAction`` 8 | - ``ViewAction(for:)`` 9 | - ``ViewActionSending`` 10 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/Deprecations/ScopeDeprecations.md: -------------------------------------------------------------------------------- 1 | # Deprecations 2 | 3 | Review unsupported reducer APIs and their replacements. 4 | 5 | ## Overview 6 | 7 | Avoid using deprecated APIs in your app. Select a method to see the replacement that you should use 8 | instead. 9 | 10 | ## Topics 11 | 12 | ### Case path deprecations 13 | 14 | - ``Scope/init(state:action:child:)-2srhu`` 15 | - ``Scope/init(state:action:child:fileID:filePath:line:column:)-8j92g`` 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/Deprecations/StoreDeprecations.md: -------------------------------------------------------------------------------- 1 | # Deprecations 2 | 3 | Review unsupported store APIs and their replacements. 4 | 5 | ## Overview 6 | 7 | Avoid using deprecated APIs in your app. Select a method to see the replacement that you should use 8 | instead. 9 | 10 | ## Topics 11 | 12 | ### Scoping stores 13 | 14 | - ``Store/scope(state:action:)-9iai9`` 15 | 16 | ### UIKit integration 17 | 18 | - ``Store/ifLet(then:else:)`` 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/EffectRun.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Effect/run(priority:operation:catch:fileID:filePath:line:column:)`` 2 | 3 | ## Topics 4 | 5 | ### Sending actions 6 | 7 | - ``Send`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/EffectSend.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Effect/send(_:)`` 2 | 3 | ## Topics 4 | 5 | ### Animating actions 6 | 7 | - ``Effect/send(_:animation:)`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/IdentifiedAction.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/IdentifiedAction`` 2 | 3 | ## Topics 4 | 5 | ### Supporting types 6 | 7 | - ``IdentifiedActionOf`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/NavigationLinkState.md: -------------------------------------------------------------------------------- 1 | # ``SwiftUI/NavigationLink/init(state:label:fileID:filePath:line:column:)`` 2 | 3 | ## Topics 4 | 5 | ### Overloads 6 | 7 | - ``SwiftUI/NavigationLink/init(_:state:fileID:line:)-1fmz8`` 8 | - ``SwiftUI/NavigationLink/init(_:state:fileID:line:)-3xjq3`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ObservableState.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/ObservableState()`` 2 | 3 | ## Topics 4 | 5 | ### Conformance 6 | 7 | - ``ObservableState`` 8 | 9 | ### Change tracking 10 | 11 | - ``ObservableStateID`` 12 | - ``ObservationStateRegistrar`` 13 | 14 | ### Supporting macros 15 | 16 | - ``ObservationStateTracked()`` 17 | - ``ObservationStateIgnored()`` 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/Presents.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Presents()`` 2 | 3 | ## Topics 4 | 5 | ### Property wrapper 6 | 7 | - ``PresentationState`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/Reduce.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reduce`` 2 | 3 | ## Topics 4 | 5 | ### Creating a reducer 6 | 7 | - ``init(_:)-6xl6k`` 8 | 9 | ### Type erased reducers 10 | 11 | - ``init(_:)-9kwa6`` 12 | 13 | ### Reduce conformance 14 | 15 | - ``Reducer/body-20w8t`` 16 | - ``Reducer/reduce(into:action:)-1t2ri`` 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ReducerBody.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer/body-swift.property`` 2 | 3 | ## Topics 4 | 5 | ### Associated type 6 | 7 | - ``Body`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ReducerBuilder.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/ReducerBuilder`` 2 | 3 | ## Topics 4 | 5 | ### Building reducers 6 | 7 | - ``buildExpression(_:)-cp3q`` 8 | - ``buildExpression(_:)-9uxku`` 9 | - ``buildBlock(_:)`` 10 | - ``buildBlock()`` 11 | - ``buildPartialBlock(first:)`` 12 | - ``buildPartialBlock(accumulated:next:)`` 13 | - ``buildOptional(_:)`` 14 | - ``buildEither(first:)`` 15 | - ``buildEither(second:)`` 16 | - ``buildArray(_:)`` 17 | - ``buildLimitedAvailability(_:)`` 18 | - ``buildFinalResult(_:)`` 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ReducerForEach.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer/forEach(_:action:element:fileID:filePath:line:column:)-6zye8`` 2 | 3 | ## Topics 4 | 5 | ### Identifying actions 6 | 7 | - ``IdentifiedAction`` 8 | 9 | ### Navigation stacks 10 | 11 | - ``StackState`` 12 | - ``StackAction`` 13 | - ``StackActionOf`` 14 | - ``Reducer/forEach(_:action:destination:fileID:filePath:line:column:)-9svqb`` 15 | - ``Reducer/forEach(_:action:)`` 16 | - ``DismissEffect`` 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ReducerMacro.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer()`` 2 | 3 | ## Topics 4 | 5 | ### Enum reducers 6 | 7 | - ``Reducer(state:action:)`` 8 | - ``ReducerCaseEphemeral()`` 9 | - ``ReducerCaseIgnored()`` 10 | - ``CaseReducer`` 11 | - ``CaseReducerState`` 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ReducerlIfLet.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer/ifLet(_:action:then:fileID:filePath:line:column:)-2r2pn`` 2 | 3 | ## Topics 4 | 5 | ### Enum state 6 | 7 | - ``Reducer/ifLet(_:action:)`` 8 | 9 | ### Ephemeral state 10 | 11 | - ``Reducer/ifLet(_:action:fileID:filePath:line:column:)-5bebx`` 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ReducerlIfLetPresentation.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer/ifLet(_:action:destination:fileID:filePath:line:column:)-4ub6q`` 2 | 3 | ## Topics 4 | 5 | ### Ephemeral state 6 | 7 | - ``Reducer/ifLet(_:action:fileID:filePath:line:column:)-3ux09`` 8 | 9 | ### Presentation 10 | 11 | - ``PresentationState`` 12 | - ``PresentationAction`` 13 | - ``DismissEffect`` 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/Scope.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Scope`` 2 | 3 | ## Topics 4 | 5 | ### Struct state 6 | 7 | - ``init(state:action:child:)-88vdx`` 8 | 9 | ### Enum state 10 | 11 | - ``init(state:action:child:fileID:filePath:line:column:)-9g44g`` 12 | 13 | ### Deprecations 14 | 15 | - 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/State.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Reducer/State`` 2 | 3 | ## Topics 4 | 5 | ### Observing state 6 | 7 | - ``ObservableState()`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/StoreDynamicMemberLookup.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Store/subscript(dynamicMember:)-655ef`` 2 | 3 | ## Topics 4 | 5 | ### Writable, bindable state 6 | 7 | - ``Store/subscript(dynamicMember:)-6ilk2`` 8 | - ``Store/subscript(dynamicMember:)-85nex`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/StoreState.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/Store/state-1qxwl`` 2 | 3 | ## Topics 4 | 5 | ### Writable, bindable state 6 | 7 | - ``Store/state-20w4g`` 8 | - ``Store/state-2wgiw`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/SwiftUIBinding.md: -------------------------------------------------------------------------------- 1 | # ``SwiftUI/Binding`` 2 | 3 | Learn how SwiftUI's `Binding` type has been extended for the Composable Architecture 4 | 5 | ## Overview 6 | 7 | A binding to a ``Store``is extended with several unique scoping operations that can be used to power 8 | controls and drive navigation. 9 | 10 | ## Topics 11 | 12 | ### Control bindings 13 | 14 | - ``SwiftUI/Binding/subscript(dynamicMember:)`` 15 | 16 | ### Navigation bindings 17 | 18 | - ``SwiftUI/Binding/scope(state:action:fileID:filePath:line:column:)`` 19 | - ``SwiftUI/Binding/scope(state:action:)-35r82`` 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/SwiftUIBindingScopeForEach.md: -------------------------------------------------------------------------------- 1 | # ``SwiftUI/Binding/scope(state:action:)-35r82`` 2 | 3 | ## Topics 4 | 5 | ### Bindable 6 | 7 | - ``SwiftUI/Bindable/scope(state:action:)`` 8 | - ``Perception/Bindable/scope(state:action:)`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/SwiftUIBindingScopeIfLet.md: -------------------------------------------------------------------------------- 1 | # ``SwiftUI/Binding/scope(state:action:fileID:filePath:line:column:)`` 2 | 3 | ## Topics 4 | 5 | ### Bindable 6 | 7 | - ``SwiftUI/Bindable/scope(state:action:fileID:line:)`` 8 | - ``Perception/Bindable/scope(state:action:fileID:line:)`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/SwiftUIBindingSubscript.md: -------------------------------------------------------------------------------- 1 | # ``SwiftUI/Binding/subscript(dynamicMember:)`` 2 | 3 | ## Topics 4 | 5 | ### Bindable 6 | 7 | - ``SwiftUI/Bindable/subscript(dynamicMember:)`` 8 | - ``Perception/Bindable/subscript(dynamicMember:)`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/SwitchStore.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/SwitchStore`` 2 | 3 | ## Topics 4 | 5 | ### Building Content 6 | 7 | - ``CaseLet`` 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/TaskResult.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/TaskResult`` 2 | 3 | ## Topics 4 | 5 | ### Representing a task result 6 | 7 | - ``success(_:)`` 8 | - ``failure(_:)`` 9 | 10 | ### Converting a throwing expression 11 | 12 | - ``init(catching:)`` 13 | 14 | ### Accessing a result's value 15 | 16 | - ``value`` 17 | 18 | ### Transforming results 19 | 20 | - ``map(_:)`` 21 | - ``flatMap(_:)`` 22 | - ``init(_:)`` 23 | - ``Swift/Result/init(_:)`` 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/TestStoreDependencies.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/TestStore/dependencies`` 2 | 3 | ## Topics 4 | 5 | ### Configuring exhaustivity 6 | 7 | - ``withDependencies(_:operation:)-988rh`` 8 | - ``withDependencies(_:operation:)-61in2`` 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/TestStoreExhaustivity.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/TestStore/exhaustivity`` 2 | 3 | ## Topics 4 | 5 | ### Configuring exhaustivity 6 | 7 | - ``Exhaustivity`` 8 | - ``withExhaustivity(_:operation:)-3fqeg`` 9 | - ``withExhaustivity(_:operation:)-1mhu4`` 10 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/ViewStoreBinding.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/ViewStore/binding(get:send:)-65xes`` 2 | 3 | ## Topics 4 | 5 | ### Overloads 6 | 7 | - ``binding(get:send:)-l66r`` 8 | - ``binding(send:)-7nwak`` 9 | - ``binding(send:)-705m7`` 10 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/WithViewStore.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/WithViewStore`` 2 | 3 | ## Overview 4 | 5 | ## Topics 6 | 7 | ### Creating a view 8 | 9 | - ``init(_:observe:content:file:line:)-8g15l`` 10 | 11 | ### Debugging view updates 12 | 13 | - ``_printChanges(_:)`` 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Extensions/WithViewStoreInit.md: -------------------------------------------------------------------------------- 1 | # ``ComposableArchitecture/WithViewStore/init(_:observe:content:file:line:)-8g15l`` 2 | 3 | ## Topics 4 | 5 | ### Overloads 6 | 7 | - ``WithViewStore/init(_:observe:removeDuplicates:content:file:line:)-7y5bp`` 8 | - ``WithViewStore/init(_:observe:send:content:file:line:)-5d0z5`` 9 | - ``WithViewStore/init(_:observe:send:removeDuplicates:content:file:line:)-dheh`` 10 | 11 | ### Bindings 12 | 13 | - ``WithViewStore/init(_:observe:content:file:line:)-4gpoj`` 14 | - ``WithViewStore/init(_:observe:removeDuplicates:content:file:line:)-1zbzi`` 15 | - ``WithViewStore/init(_:observe:send:content:file:line:)-3r7aq`` 16 | - ``WithViewStore/init(_:observe:send:removeDuplicates:content:file:line:)-4izbr`` 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/01-02-image-0003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/01-02-image-0003.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/01-02-video-0005.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/01-02-video-0005.mp4 -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/01-02-video-0006.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/01-02-video-0006.mp4 -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/01-03-image-0005.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/01-03-image-0005.jpg -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/01-homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/01-homepage.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/02-01-image-0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/02-01-image-0001.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/02-02-video-0005.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/02-02-video-0005.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/02-homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/02-homepage.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/03-03-video-0006.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/03-03-video-0006.mp4 -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub01-sec01-image-0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub01-sec01-image-0001.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub01-sec01-image-0002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub01-sec01-image-0002.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub01-sec03-image-0000.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub01-sec03-image-0000.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub02-sec01-0000.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub02-sec01-0000.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub04-sec01-image-0000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub04-sec01-image-0000.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub04-sec01-video-0000.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub04-sec01-video-0000.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub04-sec03-video-0000.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Resources/ch02-sub04-sec03-video-0000.mp4 -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0001-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0001-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0002-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0002-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0003-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0003-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0004-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/CreateProject-0004-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0003-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0003-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0004-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0004-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0005-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0005-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0006-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0006-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0007-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0007-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0008-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0008-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0009-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0009-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0010-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0010-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0011-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0011-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0012-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0012-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0013-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0013-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0014-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/01-WhatIsSyncUps/TourOfSyncUps-0014-image.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpsList { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpsList { 6 | @ObservableState 7 | struct State: Equatable { 8 | var syncUps: IdentifiedArrayOf = [] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpsList { 6 | @ObservableState 7 | struct State: Equatable { 8 | var syncUps: IdentifiedArrayOf = [] 9 | } 10 | enum Action { 11 | case addSyncUpButtonTapped 12 | case onDelete(IndexSet) 13 | case syncUpTapped(id: SyncUp.ID) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0006-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpsList { 6 | // ... 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0010.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-02-code-0010.mp4 -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/ListsOfSyncUps-cover.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/TestingListOfSyncUps-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func deletion() async { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/TestingListOfSyncUps-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func deletion() async { 10 | let store = TestStore( 11 | initialState: SyncUpsList.State( 12 | syncUps: [ 13 | SyncUp( 14 | id: SyncUp.ID(), 15 | title: "Point-Free Morning Sync" 16 | ) 17 | ] 18 | ) 19 | ) { 20 | SyncUpsList() 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/TestingListOfSyncUps-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func deletion() async { 10 | let store = TestStore( 11 | initialState: SyncUpsList.State( 12 | syncUps: [ 13 | SyncUp( 14 | id: SyncUp.ID(), 15 | title: "Point-Free Morning Sync" 16 | ) 17 | ] 18 | ) 19 | ) { 20 | SyncUpsList() 21 | } 22 | 23 | await store.send(.onDelete([0])) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/02-ListsOfSyncUps/TestingListOfSyncUps-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func deletion() async { 10 | let store = TestStore( 11 | initialState: SyncUpsList.State( 12 | syncUps: [ 13 | SyncUp( 14 | id: SyncUp.ID(), 15 | title: "Point-Free Morning Sync" 16 | ) 17 | ] 18 | ) 19 | ) { 20 | SyncUpsList() 21 | } 22 | 23 | await store.send(.onDelete([0])) { 24 | $0.syncUps = [] 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpForm { 6 | @ObservableState 7 | struct State: Equatable { 8 | } 9 | 10 | enum Action { 11 | } 12 | 13 | var body: some ReducerOf { 14 | Reduce { state, action in 15 | switch action { 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpForm { 6 | @ObservableState 7 | struct State: Equatable { 8 | var syncUp: SyncUp 9 | } 10 | 11 | enum Action { 12 | } 13 | 14 | var body: some ReducerOf { 15 | Reduce { state, action in 16 | switch action { 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpForm { 6 | @ObservableState 7 | struct State: Equatable { 8 | var syncUp: SyncUp 9 | } 10 | 11 | enum Action: BindableAction { 12 | case binding(BindingAction) 13 | } 14 | 15 | var body: some ReducerOf { 16 | Reduce { state, action in 17 | switch action { 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpForm { 6 | @ObservableState 7 | struct State: Equatable { 8 | var syncUp: SyncUp 9 | } 10 | 11 | enum Action: BindableAction { 12 | case binding(BindingAction) 13 | } 14 | 15 | var body: some ReducerOf { 16 | BindingReducer() 17 | 18 | Reduce { state, action in 19 | switch action { 20 | case .binding: 21 | return .none 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-01-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpForm { 6 | // ... 7 | } 8 | 9 | struct SyncUpFormView: View { 10 | var body: some View { 11 | Form { 12 | 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-01-code-0008.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpForm { 6 | // ... 7 | } 8 | 9 | struct SyncUpFormView: View { 10 | @Bindable var store: StoreOf 11 | 12 | var body: some View { 13 | Form { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-02-video-0007.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpForm-02-video-0007.mp4 -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpFormBasics-01-0000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/SyncUpFormBasics-01-0000.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func removeAttendee() async { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func removeAttendee() async { 10 | let store = TestStore( 11 | initialState: SyncUpForm.State( 12 | syncUp: SyncUp( 13 | id: SyncUp.ID(), 14 | attendees: [ 15 | Attendee(id: Attendee.ID()), 16 | Attendee(id: Attendee.ID()) 17 | ] 18 | ) 19 | ) 20 | ) { 21 | SyncUpForm() 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func removeAttendee() async { 10 | let store = TestStore( 11 | initialState: SyncUpForm.State( 12 | syncUp: SyncUp( 13 | id: SyncUp.ID(), 14 | attendees: [ 15 | Attendee(id: Attendee.ID()), 16 | Attendee(id: Attendee.ID()) 17 | ] 18 | ) 19 | ) 20 | ) { 21 | SyncUpForm() 22 | } 23 | 24 | await store.send(.onDeleteAttendees([0])) { 25 | $0.syncUp.attendees.removeFirst() 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-01-code-0004-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func removeAttendee() async { 10 | // ... 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func removeFocusedAttendee() async { 10 | let attendee1 = Attendee(id: Attendee.ID()) 11 | let attendee2 = Attendee(id: Attendee.ID()) 12 | let store = TestStore( 13 | initialState: SyncUpForm.State( 14 | focus: .attendee(attendee1.id), 15 | syncUp: SyncUp( 16 | id: SyncUp.ID(), 17 | attendees: [attendee1, attendee2] 18 | ) 19 | ) 20 | ) { 21 | SyncUpForm() 22 | } 23 | } 24 | 25 | @Test 26 | func removeAttendee() async { 27 | // ... 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-02-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func removeFocusedAttendee() async { 10 | // ... 11 | } 12 | 13 | @Test 14 | func removeAttendee() async { 15 | // ... 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/03-SyncUpForm/TestingSyncUpForm-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpFormTests { 8 | @Test 9 | func addAttendee() async { 10 | let store = TestStore( 11 | initialState: SyncUpForm.State( 12 | syncUp: SyncUp(id: SyncUp.ID()) 13 | ) 14 | ) { 15 | SyncUpForm() 16 | } 17 | } 18 | 19 | @Test 20 | func removeFocusedAttendee() async { 21 | // ... 22 | } 23 | 24 | @Test 25 | func removeAttendee() async { 26 | // ... 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/PresentingSyncUpForm-02-video-0004.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/PresentingSyncUpForm-02-video-0004.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/PresentingSyncUpForm-03-code-0006.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/PresentingSyncUpForm-03-code-0006.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func deletion() async { 10 | // ... 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | 11 | } 12 | 13 | @Test 14 | func deletion() async { 15 | // ... 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } 13 | } 14 | 15 | @Test 16 | func deletion() async { 17 | // ... 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } 13 | 14 | await store.send(.addSyncUpButtonTapped) { 15 | $0.addSyncUp = SyncUpForm.State(syncUp: SyncUp(id: SyncUp.ID())) 16 | } 17 | } 18 | 19 | @Test 20 | func deletion() async { 21 | // ... 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0007-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } 13 | 14 | await store.send(.addSyncUpButtonTapped) { 15 | $0.addSyncUp = SyncUpForm.State(syncUp: SyncUp(id: SyncUp.ID())) 16 | } 17 | } 18 | 19 | @Test 20 | func deletion() async { 21 | // ... 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | 16 | await store.send(.addSyncUpButtonTapped) { 17 | $0.addSyncUp = SyncUpForm.State(syncUp: SyncUp(id: SyncUp.ID())) 18 | } 19 | } 20 | 21 | @Test 22 | func deletion() async { 23 | // ... 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0008.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | 16 | await store.send(.addSyncUpButtonTapped) { 17 | $0.addSyncUp = SyncUpForm.State( 18 | syncUp: SyncUp(id: SyncUp.ID(0)) 19 | ) 20 | } 21 | } 22 | 23 | @Test 24 | func deletion() async { 25 | // ... 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0009.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | 16 | await store.send(.addSyncUpButtonTapped) { 17 | $0.addSyncUp = SyncUpForm.State( 18 | syncUp: SyncUp(id: SyncUp.ID(0)) 19 | ) 20 | } 21 | 22 | await store.send(\.addSyncUp…) 23 | } 24 | 25 | @Test 26 | func deletion() async { 27 | // ... 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-01-code-0010.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | 16 | await store.send(.addSyncUpButtonTapped) { 17 | $0.addSyncUp = SyncUpForm.State( 18 | syncUp: SyncUp(id: SyncUp.ID(0)) 19 | ) 20 | } 21 | 22 | await store.send(\.addSyncUp.binding…) 23 | } 24 | 25 | @Test 26 | func deletion() async { 27 | // ... 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-02-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUp() async { 10 | // ... 11 | } 12 | 13 | @Test 14 | func deletion() async { 15 | // ... 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUpNonExhaustive() async { 10 | 11 | } 12 | 13 | @Test 14 | func addSyncUp() async { 15 | // ... 16 | } 17 | 18 | @Test 19 | func deletion() async { 20 | // ... 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUpNonExhaustive() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | store.exhaustivity = .off 16 | } 17 | 18 | @Test 19 | func addSyncUp() async { 20 | // ... 21 | } 22 | 23 | @Test 24 | func deletion() async { 25 | // ... 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/04-PresentingSyncUpForm/TestingSyncUpFormPresentation-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpsListTests { 8 | @Test 9 | func addSyncUpNonExhaustive() async { 10 | let store = TestStore(initialState: SyncUpsList.State()) { 11 | SyncUpsList() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | store.exhaustivity = .off 16 | 17 | await store.send(.addSyncUpButtonTapped) 18 | } 19 | 20 | @Test 21 | func addSyncUp() async { 22 | // ... 23 | } 24 | 25 | @Test 26 | func deletion() async { 27 | // ... 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/05-PersistingSyncUps/PersistingSyncUps-01-code-0006-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpsList { 6 | // ... 7 | } 8 | 9 | struct SyncUpsListView: View { 10 | // ... 11 | } 12 | 13 | #Preview { 14 | NavigationStack { 15 | SyncUpsListView( 16 | store: Store( 17 | initialState: SyncUpsList.State( 18 | syncUps: [.mock] 19 | ) 20 | ) { 21 | SyncUpsList() 22 | ._printChanges() 23 | } 24 | ) 25 | } 26 | } -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/05-PersistingSyncUps/PersistingSyncUps-01-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpsList { 6 | // ... 7 | } 8 | 9 | struct SyncUpsListView: View { 10 | // ... 11 | } 12 | 13 | #Preview { 14 | @Shared(.syncUps) var syncUps = [.mock] 15 | NavigationStack { 16 | SyncUpsListView( 17 | store: Store( 18 | initialState: SyncUpsList.State() 19 | ) { 20 | SyncUpsList() 21 | ._printChanges() 22 | } 23 | ) 24 | } 25 | } -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/05-PersistingSyncUps/PersistingSyncUps-01-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct SyncUpsApp: App { 6 | @MainActor 7 | static let store = Store(initialState: SyncUpsList.State()) { 8 | SyncUpsList() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | NavigationStack { 14 | SyncUpsListView(store: Self.store) 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/05-PersistingSyncUps/PersistingSyncUps-01-video-0008.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/05-PersistingSyncUps/PersistingSyncUps-01-video-0008.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-01-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @ObservableState 7 | struct State: Equatable { 8 | @Shared var syncUp: SyncUp 9 | } 10 | 11 | enum Action { 12 | case deleteButtonTapped 13 | case editButtonTapped 14 | } 15 | 16 | var body: some ReducerOf { 17 | Reduce { state, action in 18 | switch action { 19 | case .deleteButtonTapped: 20 | return .none 21 | 22 | case .editButtonTapped: 23 | return .none 24 | } 25 | } 26 | } 27 | } 28 | 29 | struct SyncUpDetailView: View { 30 | // ... 31 | } 32 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @ObservableState 7 | struct State: Equatable { 8 | @Presents var editSyncUp: SyncUpForm.State? 9 | @Shared var syncUp: SyncUp 10 | } 11 | 12 | enum Action { 13 | case deleteButtonTapped 14 | case editButtonTapped 15 | } 16 | 17 | var body: some ReducerOf { 18 | Reduce { state, action in 19 | switch action { 20 | case .deleteButtonTapped: 21 | return .none 22 | 23 | case .editButtonTapped: 24 | return .none 25 | } 26 | } 27 | } 28 | } 29 | 30 | struct SyncUpDetailView: View { 31 | // ... 32 | } 33 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-01-cover-480p.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-01-cover-480p.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-02-cover-480p.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-02-cover-480p.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-03-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | // ... 7 | } 8 | 9 | struct SyncUpDetailView: View { 10 | // ... 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-03-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @Reducer 7 | enum Destination { 8 | } 9 | // ... 10 | } 11 | extension SyncUpDetail.Destination.State: Equatable {} 12 | 13 | struct SyncUpDetailView: View { 14 | // ... 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/EditingAndDeletingSyncUp-03-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @Reducer 7 | enum Destination { 8 | case alert(AlertState) 9 | case edit(SyncUpForm) 10 | @CasePathable 11 | enum Alert { 12 | case confirmButtonTapped 13 | } 14 | } 15 | // ... 16 | } 17 | extension SyncUpDetail.Destination.State: Equatable {} 18 | 19 | struct SyncUpDetailView: View { 20 | // ... 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @ObservableState 7 | struct State: Equatable { 8 | } 9 | 10 | enum Action { 11 | } 12 | 13 | var body: some ReducerOf { 14 | Reduce { state, action in 15 | switch action { 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @ObservableState 7 | struct State: Equatable { 8 | @Shared var syncUp: SyncUp 9 | } 10 | 11 | enum Action { 12 | } 13 | 14 | var body: some ReducerOf { 15 | Reduce { state, action in 16 | switch action { 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @ObservableState 7 | struct State: Equatable { 8 | @Shared var syncUp: SyncUp 9 | } 10 | 11 | enum Action { 12 | case deleteButtonTapped 13 | case editButtonTapped 14 | } 15 | 16 | var body: some ReducerOf { 17 | Reduce { state, action in 18 | switch action { 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | @ObservableState 7 | struct State: Equatable { 8 | @Shared var syncUp: SyncUp 9 | } 10 | 11 | enum Action { 12 | case deleteButtonTapped 13 | case editButtonTapped 14 | } 15 | 16 | var body: some ReducerOf { 17 | Reduce { state, action in 18 | switch action { 19 | case .deleteButtonTapped: 20 | return .none 21 | 22 | case .editButtonTapped: 23 | return .none 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct SyncUpDetail { 6 | // ... 7 | } 8 | 9 | struct SyncUpDetailView: View { 10 | let store: StoreOf 11 | 12 | var body: some View { 13 | Form { 14 | 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-image-0007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-01-image-0007.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/SyncUpDetail-cover.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/TestingSyncUpDetail-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpDetailTests { 8 | @Test 9 | func edit() async { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/TestingSyncUpDetail-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpDetailTests { 8 | @Test 9 | func edit() async { 10 | let syncUp = SyncUp( 11 | id: SyncUp.ID(), 12 | title: "Point-Free Morning Sync" 13 | ) 14 | let store = TestStore(initialState: SyncUpDetail.State(syncUp: Shared(value: syncUp))) { 15 | SyncUpDetail() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/06-SyncUpDetail/TestingSyncUpDetail-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct SyncUpDetailTests { 8 | @Test 9 | func edit() async { 10 | let syncUp = SyncUp( 11 | id: SyncUp.ID(), 12 | title: "Point-Free Morning Sync" 13 | ) 14 | let store = TestStore(initialState: SyncUpDetail.State(syncUp: Shared(value: syncUp))) { 15 | SyncUpDetail() 16 | } 17 | 18 | await store.send(.editButtonTapped) { 19 | $0.destination = .edit(SyncUpForm.State(syncUp: syncUp)) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct MeetingView: View { 4 | let meeting: Meeting 5 | let syncUp: SyncUp 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct MeetingView: View { 4 | let meeting: Meeting 5 | let syncUp: SyncUp 6 | 7 | var body: some View { 8 | Form { 9 | Section { 10 | ForEach(syncUp.attendees) { attendee in 11 | Text(attendee.name) 12 | } 13 | } header: { 14 | Text("Attendees") 15 | } 16 | Section { 17 | Text(meeting.transcript) 18 | } header: { 19 | Text("Transcript") 20 | } 21 | } 22 | .navigationTitle(Text(meeting.date, style: .date)) 23 | } 24 | } 25 | 26 | #Preview { 27 | MeetingView(meeting: SyncUp.mock.meetings[0], syncUp: .mock) 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-01-cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-01-cover.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct App { 6 | @Reducer 7 | enum Path { 8 | case detail(SyncUpDetail) 9 | } 10 | // ... 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/MeetingNavigation-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct App { 6 | @Reducer 7 | enum Path { 8 | case detail(SyncUpDetail) 9 | case meeting(Meeting, syncUp: SyncUp) 10 | } 11 | // ... 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | @ObservableState 7 | struct State: Equatable { 8 | } 9 | enum Action { 10 | } 11 | var body: some ReducerOf { 12 | Reduce { state, action in 13 | switch action { 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | @ObservableState 7 | struct State: Equatable { 8 | var syncUpsList = SyncUpsList.State() 9 | } 10 | enum Action { 11 | case syncUpsList(SyncUpsList.Action) 12 | } 13 | var body: some ReducerOf { 14 | Scope(state: \.syncUpsList, action: \.syncUpsList) { 15 | SyncUpsList() 16 | } 17 | Reduce { state, action in 18 | switch action { 19 | case .syncUpsList: 20 | return .none 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | @ObservableState 7 | struct State: Equatable { 8 | var path = StackState() 9 | var syncUpsList = SyncUpsList.State() 10 | } 11 | enum Action { 12 | case syncUpsList(SyncUpsList.Action) 13 | } 14 | var body: some ReducerOf { 15 | Scope(state: \.syncUpsList, action: \.syncUpsList) { 16 | SyncUpsList() 17 | } 18 | Reduce { state, action in 19 | switch action { 20 | case .syncUpsList: 21 | return .none 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | @Reducer 7 | enum Path { 8 | } 9 | @ObservableState 10 | struct State: Equatable { 11 | var path = StackState() 12 | var syncUpsList = SyncUpsList.State() 13 | } 14 | enum Action { 15 | case syncUpsList(SyncUpsList.Action) 16 | } 17 | var body: some ReducerOf { 18 | Scope(state: \.syncUpsList, action: \.syncUpsList) { 19 | SyncUpsList() 20 | } 21 | Reduce { state, action in 22 | switch action { 23 | case .syncUpsList: 24 | return .none 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | } 11 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | @Bindable var store: StoreOf 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | @Bindable var store: StoreOf 11 | 12 | var body: some View { 13 | NavigationStack( 14 | path: $store.scope(state: \.path, action: \.path) 15 | ) { 16 | 17 | } destination: { store in 18 | 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | @Bindable var store: StoreOf 11 | 12 | var body: some View { 13 | NavigationStack( 14 | path: $store.scope(state: \.path, action: \.path) 15 | ) { 16 | SyncUpsListView( 17 | store: store.scope(state: \.syncUpsList, action: \.syncUpsList) 18 | ) 19 | } destination: { store in 20 | 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | @Bindable var store: StoreOf 11 | 12 | var body: some View { 13 | NavigationStack( 14 | path: $store.scope(state: \.path, action: \.path) 15 | ) { 16 | SyncUpsListView( 17 | store: store.scope(state: \.syncUpsList, action: \.syncUpsList) 18 | ) 19 | } destination: { store in 20 | switch store.case { 21 | case let .detail(detailStore): 22 | 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-02-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct AppFeature { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | @Bindable var store: StoreOf 11 | 12 | var body: some View { 13 | NavigationStack( 14 | path: $store.scope(state: \.path, action: \.path) 15 | ) { 16 | SyncUpsListView( 17 | store: store.scope(state: \.syncUpsList, action: \.syncUpsList) 18 | ) 19 | } destination: { store in 20 | switch store.case { 21 | case let .detail(detailStore): 22 | SyncUpDetailView(store: detailStore) 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-03-video-0005.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-03-video-0005.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-03-video-0006.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/SyncUpDetailNavigation-03-video-0006.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/TestingNavigation-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func delete() async throws { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/TestingNavigation-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func delete() async throws { 10 | let syncUp = SyncUp.mock 11 | @Shared(.syncUps) var syncUps = [syncUp] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/TestingNavigation-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func delete() async throws { 10 | let syncUp = SyncUp.mock 11 | @Shared(.syncUps) var syncUps = [syncUp] 12 | 13 | let store = TestStore(initialState: AppFeature.State()) { 14 | AppFeature() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/TestingNavigation-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func delete() async throws { 10 | let syncUp = SyncUp.mock 11 | @Shared(.syncUps) var syncUps = [syncUp] 12 | 13 | let store = TestStore(initialState: AppFeature.State()) { 14 | AppFeature() 15 | } 16 | 17 | await store.send(\.path.push, (id: 0, .detail(SyncUpDetail.State(syncUp: ???)))) { 18 | 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/07-SyncUpDetailNavigation/TestingNavigation-01-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func delete() async throws { 10 | let syncUp = SyncUp.mock 11 | @Shared(.syncUps) var syncUps = [syncUp] 12 | 13 | let store = TestStore(initialState: AppFeature.State()) { 14 | AppFeature() 15 | } 16 | 17 | let sharedSyncUp = try #require(Shared($syncUps[id: syncUp.id])) 18 | 19 | await store.send(\.path.push, (id: 0, .detail(SyncUpDetail.State(syncUp: sharedSyncUp)))) { 20 | $0.path[id: 0] = .detail(SyncUpDetail.State(syncUp: sharedSyncUp)) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-01-code-0011-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct App { 6 | // ... 7 | } 8 | 9 | struct AppView: View { 10 | // ... 11 | } 12 | 13 | #Preview { 14 | AppView( 15 | store: Store( 16 | initialState: App.State( 17 | syncUpsList: SyncUpsList.State() 18 | ) 19 | ) { 20 | App() 21 | } 22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-01-video-0012.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-01-video-0012.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-03-video-0009.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-03-video-0009.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-04-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct RecordMeetingTests { 8 | @Test 9 | func timerFinishes() async { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-04-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct RecordMeetingTests { 8 | @Test 9 | func timerFinishes() async { 10 | let syncUp = SyncUp( 11 | id: SyncUp.ID(), 12 | attendees: [ 13 | Attendee(id: Attendee.ID(), name: "Blob"), 14 | Attendee(id: Attendee.ID(), name: "Blob Jr"), 15 | ], 16 | duration: .seconds(4), 17 | title: "Morning Sync" 18 | ) 19 | let store = TestStore( 20 | initialState: RecordMeeting.State(syncUp: Shared(value: syncUp)) 21 | ) { 22 | RecordMeeting() 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/ImplementingTimer-04-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import SyncUps 5 | 6 | @MainActor 7 | struct RecordMeetingTests { 8 | @Test 9 | func timerFinishes() async { 10 | let syncUp = SyncUp( 11 | id: SyncUp.ID(), 12 | attendees: [ 13 | Attendee(id: Attendee.ID(), name: "Blob"), 14 | Attendee(id: Attendee.ID(), name: "Blob Jr"), 15 | ], 16 | duration: .seconds(4), 17 | title: "Morning Sync" 18 | ) 19 | let store = TestStore( 20 | initialState: RecordMeeting.State(syncUp: Shared(value: syncUp)) 21 | ) { 22 | RecordMeeting() 23 | } 24 | 25 | await store.send(.onAppear) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct RecordMeeting { 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct RecordMeeting { 5 | @ObservableState 6 | struct State: Equatable { 7 | var secondsElapsed = 0 8 | var speakerIndex = 0 9 | @Shared var syncUp: SyncUp 10 | var transcript = "" 11 | 12 | var durationRemaining: Duration { 13 | syncUp.duration - .seconds(secondsElapsed) 14 | } 15 | } 16 | 17 | enum Action { 18 | case endMeetingButtonTapped 19 | case nextButtonTapped 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-01-image-0004.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-01-image-0004.jpg -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-02-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct App { 6 | // ... 7 | } 8 | 9 | extension App { 10 | @Reducer 11 | enum Path { 12 | case detail(SyncUpDetail) 13 | case meeting(Meeting, syncUp: SyncUp) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @Reducer 5 | struct App { 6 | // ... 7 | } 8 | 9 | extension App { 10 | @Reducer 11 | enum Path { 12 | case detail(SyncUpDetail) 13 | case meeting(Meeting, syncUp: SyncUp) 14 | case record(RecordMeeting) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-02-video-0004.mov: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/BuildingSyncUps/08-RecordMeeting/RecordMeetingFeature-02-video-0004.mov -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct CounterFeature { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct CounterFeature { 5 | @ObservableState 6 | struct State { 7 | 8 | } 9 | 10 | enum Action { 11 | 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct CounterFeature { 5 | @ObservableState 6 | struct State { 7 | var count = 0 8 | } 9 | 10 | enum Action { 11 | case decrementButtonTapped 12 | case incrementButtonTapped 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-01-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct CounterFeature { 5 | @ObservableState 6 | struct State { 7 | var count = 0 8 | } 9 | 10 | enum Action { 11 | case decrementButtonTapped 12 | case incrementButtonTapped 13 | } 14 | 15 | var body: some ReducerOf { 16 | Reduce { state, action in 17 | switch action { 18 | case .decrementButtonTapped: 19 | 20 | case .incrementButtonTapped: 21 | 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-01-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct CounterFeature { 5 | @ObservableState 6 | struct State { 7 | var count = 0 8 | } 9 | 10 | enum Action { 11 | case decrementButtonTapped 12 | case incrementButtonTapped 13 | } 14 | 15 | var body: some ReducerOf { 16 | Reduce { state, action in 17 | switch action { 18 | case .decrementButtonTapped: 19 | state.count -= 1 20 | return .none 21 | 22 | case .incrementButtonTapped: 23 | state.count += 1 24 | return .none 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct CounterView: View { 5 | var body: some View { 6 | EmptyView() 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | struct CounterView: View { 2 | let store: StoreOf 3 | 4 | var body: some View { 5 | EmptyView() 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-02-code-0005.swift: -------------------------------------------------------------------------------- 1 | #Preview { 2 | CounterView( 3 | store: Store(initialState: CounterFeature.State()) { 4 | CounterFeature() 5 | } 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-02-code-0006.swift: -------------------------------------------------------------------------------- 1 | #Preview { 2 | CounterView( 3 | store: Store(initialState: CounterFeature.State()) { 4 | // CounterFeature() 5 | } 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-02-code-0007.swift: -------------------------------------------------------------------------------- 1 | #Preview { 2 | CounterView( 3 | store: Store(initialState: CounterFeature.State()) { 4 | CounterFeature() 5 | } 6 | ) 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-03-code-0001.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct MyApp: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | ContentView() 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-03-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct MyApp: App { 6 | var body: some Scene { 7 | WindowGroup { 8 | CounterView( 9 | store: Store(initialState: CounterFeature.State()) { 10 | CounterFeature() 11 | } 12 | ) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-03-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct MyApp: App { 6 | static let store = Store(initialState: CounterFeature.State()) { 7 | CounterFeature() 8 | } 9 | 10 | var body: some Scene { 11 | WindowGroup { 12 | CounterView(store: MyApp.store) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/01-YourFirstFeature/01-01-03-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct MyApp: App { 6 | static let store = Store(initialState: CounterFeature.State()) { 7 | CounterFeature() 8 | ._printChanges() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | CounterView(store: MyApp.store) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/02-AddingSideEffects/01-02-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct CounterFeature { 5 | @ObservableState 6 | struct State { 7 | var count = 0 8 | } 9 | 10 | enum Action { 11 | case decrementButtonTapped 12 | case incrementButtonTapped 13 | } 14 | 15 | var body: some ReducerOf { 16 | Reduce { state, action in 17 | switch action { 18 | case .decrementButtonTapped: 19 | state.count -= 1 20 | return .none 21 | 22 | case .incrementButtonTapped: 23 | state.count += 1 24 | return .none 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func basics() async { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func basics() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func basics() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.incrementButtonTapped) 15 | await store.send(.decrementButtonTapped) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-01-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func basics() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.incrementButtonTapped) { 15 | $0.count = 1 16 | } 17 | await store.send(.decrementButtonTapped) { 18 | $0.count = 0 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | } 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func basics() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func timer() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.toggleTimerButtonTapped) { 15 | $0.isTimerRunning = true 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func timer() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.toggleTimerButtonTapped) { 15 | $0.isTimerRunning = true 16 | } 17 | // ❌ An effect returned for this action is still running. 18 | // It must complete before the end of the test. … 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func timer() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.toggleTimerButtonTapped) { 15 | $0.isTimerRunning = true 16 | } 17 | await store.send(.toggleTimerButtonTapped) { 18 | $0.isTimerRunning = false 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func timer() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.toggleTimerButtonTapped) { 15 | $0.isTimerRunning = true 16 | } 17 | await store.receive(\.timerTick) { 18 | $0.count = 1 19 | } 20 | await store.send(.toggleTimerButtonTapped) { 21 | $0.isTimerRunning = false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func timer() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.toggleTimerButtonTapped) { 15 | $0.isTimerRunning = true 16 | } 17 | await store.receive(\.timerTick, timeout: .seconds(2)) { 18 | $0.count = 1 19 | } 20 | await store.send(.toggleTimerButtonTapped) { 21 | $0.isTimerRunning = false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-02-code-0009.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func timer() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.toggleTimerButtonTapped) { 15 | $0.isTimerRunning = true 16 | } 17 | await store.receive(\.timerTick, timeout: .seconds(2)) { 18 | $0.count = 1 19 | } 20 | await store.send(.toggleTimerButtonTapped) { 21 | $0.isTimerRunning = false 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-03-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | } 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-03-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-03-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.factButtonTapped) { 15 | $0.isLoading = true 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-03-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.factButtonTapped) { 15 | $0.isLoading = true 16 | } 17 | // ❌ An effect returned for this action is still running. 18 | // It must complete before the end of the test. … 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-03-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.factButtonTapped) { 15 | $0.isLoading = true 16 | } 17 | await store.receive(\.factResponse, timeout: .seconds(1)) { 18 | $0.isLoading = false 19 | $0.fact = "???" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | struct NumberFactClient { 4 | var fetch: (Int) async throws -> String 5 | } 6 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | 4 | struct NumberFactClient { 5 | var fetch: (Int) async throws -> String 6 | } 7 | 8 | extension NumberFactClient: DependencyKey { 9 | static let liveValue = Self( 10 | fetch: { number in 11 | let (data, _) = try await URLSession.shared 12 | .data(from: URL(string: "http://numbersapi.com/\(number)")!) 13 | return String(decoding: data, as: UTF8.self) 14 | } 15 | ) 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | 4 | struct NumberFactClient { 5 | var fetch: (Int) async throws -> String 6 | } 7 | 8 | extension NumberFactClient: DependencyKey { 9 | static let liveValue = Self( 10 | fetch: { number in 11 | let (data, _) = try await URLSession.shared 12 | .data(from: URL(string: "http://numbersapi.com/\(number)")!) 13 | return String(decoding: data, as: UTF8.self) 14 | } 15 | ) 16 | } 17 | 18 | extension DependencyValues { 19 | var numberFact: NumberFactClient { 20 | get { self[NumberFactClient.self] } 21 | set { self[NumberFactClient.self] = newValue } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0006-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } 13 | 14 | await store.send(.factButtonTapped) { 15 | $0.isLoading = true 16 | } 17 | await store.receive(\.factResponse, timeout: .seconds(1)) { 18 | $0.isLoading = false 19 | $0.fact = "???" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } withDependencies: { 13 | $0.numberFact.fetch = { "\($0) is a good number." } 14 | } 15 | 16 | await store.send(.factButtonTapped) { 17 | $0.isLoading = true 18 | } 19 | await store.receive(\.factResponse, timeout: .seconds(1)) { 20 | $0.isLoading = false 21 | $0.fact = "???" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/03-TestingYourFeatures/01-03-04-code-0008.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct CounterFeatureTests { 8 | @Test 9 | func numberFact() async { 10 | let store = TestStore(initialState: CounterFeature.State()) { 11 | CounterFeature() 12 | } withDependencies: { 13 | $0.numberFact.fetch = { "\($0) is a good number." } 14 | } 15 | 16 | await store.send(.factButtonTapped) { 17 | $0.isLoading = true 18 | } 19 | await store.receive(\.factResponse) { 20 | $0.isLoading = false 21 | $0.fact = "0 is a good number." 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct AppView: View { 4 | var body: some View { 5 | TabView { 6 | 7 | } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct AppView: View { 4 | var body: some View { 5 | TabView { 6 | CounterView(store: ???) 7 | .tabItem { 8 | Text("Counter 1") 9 | } 10 | 11 | CounterView(store: ???) 12 | .tabItem { 13 | Text("Counter 2") 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct AppView: View { 5 | let store1: StoreOf 6 | let store2: StoreOf 7 | 8 | var body: some View { 9 | TabView { 10 | CounterView(store: store1) 11 | .tabItem { 12 | Text("Counter 1") 13 | } 14 | 15 | CounterView(store: store2) 16 | .tabItem { 17 | Text("Counter 2") 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct AppFeature { 5 | 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct AppFeature { 5 | struct State: Equatable { 6 | var tab1 = CounterFeature.State() 7 | var tab2 = CounterFeature.State() 8 | } 9 | enum Action { 10 | case tab1(CounterFeature.Action) 11 | case tab2(CounterFeature.Action) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct AppFeature { 5 | struct State: Equatable { 6 | var tab1 = CounterFeature.State() 7 | var tab2 = CounterFeature.State() 8 | } 9 | enum Action { 10 | case tab1(CounterFeature.Action) 11 | case tab2(CounterFeature.Action) 12 | } 13 | var body: some ReducerOf { 14 | Reduce { state, action in 15 | // Core logic of the app feature 16 | return .none 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct AppFeature { 5 | struct State: Equatable { 6 | var tab1 = CounterFeature.State() 7 | var tab2 = CounterFeature.State() 8 | } 9 | enum Action { 10 | case tab1(CounterFeature.Action) 11 | case tab2(CounterFeature.Action) 12 | } 13 | var body: some ReducerOf { 14 | Scope(state: \.tab1, action: \.tab1) { 15 | CounterFeature() 16 | } 17 | Scope(state: \.tab2, action: \.tab2) { 18 | CounterFeature() 19 | } 20 | Reduce { state, action in 21 | // Core logic of the app feature 22 | return .none 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func incrementInFirstTab() async { 10 | 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func incrementInFirstTab() async { 10 | let store = TestStore(initialState: AppFeature.State()) { 11 | AppFeature() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func incrementInFirstTab() async { 10 | let store = TestStore(initialState: AppFeature.State()) { 11 | AppFeature() 12 | } 13 | 14 | await store.send(\.tab1.incrementButtonTapped) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-02-code-0008.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import CounterApp 5 | 6 | @MainActor 7 | struct AppFeatureTests { 8 | @Test 9 | func incrementInFirstTab() async { 10 | let store = TestStore(initialState: AppFeature.State()) { 11 | AppFeature() 12 | } 13 | 14 | await store.send(\.tab1.incrementButtonTapped) { 15 | $0.tab1.count = 1 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0001-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct AppView: View { 5 | // let store1: StoreOf 6 | // let store2: StoreOf 7 | 8 | var body: some View { 9 | TabView { 10 | CounterView(store: store1) 11 | .tabItem { 12 | Text("Counter 1") 13 | } 14 | 15 | CounterView(store: store2) 16 | .tabItem { 17 | Text("Counter 2") 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct AppView: View { 5 | // let store1: StoreOf 6 | // let store2: StoreOf 7 | let store: StoreOf 8 | 9 | var body: some View { 10 | TabView { 11 | CounterView(store: store1) 12 | .tabItem { 13 | Text("Counter 1") 14 | } 15 | 16 | CounterView(store: store2) 17 | .tabItem { 18 | Text("Counter 2") 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct AppView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | TabView { 9 | CounterView(store: store.scope(state: \.tab1, action: \.tab1)) 10 | .tabItem { 11 | Text("Counter 1") 12 | } 13 | 14 | CounterView(store: store2) 15 | .tabItem { 16 | Text("Counter 2") 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct AppView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | TabView { 9 | CounterView(store: store.scope(state: \.tab1, action: \.tab1)) 10 | .tabItem { 11 | Text("Counter 1") 12 | } 13 | 14 | CounterView(store: store.scope(state: \.tab2, action: \.tab2)) 15 | .tabItem { 16 | Text("Counter 2") 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct AppView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | TabView { 9 | CounterView(store: store.scope(state: \.tab1, action: \.tab1)) 10 | .tabItem { 11 | Text("Counter 1") 12 | } 13 | 14 | CounterView(store: store.scope(state: \.tab2, action: \.tab2)) 15 | .tabItem { 16 | Text("Counter 2") 17 | } 18 | } 19 | } 20 | } 21 | 22 | #Preview { 23 | AppView( 24 | store: Store(initialState: AppFeature.State()) { 25 | AppFeature() 26 | } 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0005-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct MyApp: App { 6 | static let store = Store(initialState: CounterFeature.State()) { 7 | CounterFeature() 8 | ._printChanges() 9 | } 10 | 11 | var body: some Scene { 12 | WindowGroup { 13 | CounterView(store: MyApp.store) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/01-Essentials/04-ComposingFeatures/01-04-03-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | @main 5 | struct MyApp: App { 6 | static let store = Store(initialState: AppFeature.State()) { 7 | AppFeature() 8 | } 9 | 10 | var body: some Scene { 11 | WindowGroup { 12 | AppView(store: MyApp.store) 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0000.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import ComposableArchitecture 3 | 4 | struct Contact: Equatable, Identifiable { 5 | let id: UUID 6 | var name: String 7 | } 8 | 9 | @Reducer 10 | struct ContactsFeature { 11 | @ObservableState 12 | struct State: Equatable { 13 | var contacts: IdentifiedArrayOf = [] 14 | } 15 | enum Action { 16 | case addButtonTapped 17 | } 18 | var body: some ReducerOf { 19 | Reduce { state, action in 20 | switch action { 21 | case .addButtonTapped: 22 | // TODO: Handle action 23 | return .none 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ContactsView: View { 4 | let store: StoreOf 5 | 6 | var body: some View { 7 | NavigationStack { 8 | List { 9 | ForEach(store.contacts) { contact in 10 | Text(contact.name) 11 | } 12 | } 13 | .navigationTitle("Contacts") 14 | .toolbar { 15 | ToolbarItem { 16 | Button { 17 | store.send(.addButtonTapped) 18 | } label: { 19 | Image(systemName: "plus") 20 | } 21 | } 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | #Preview { 2 | ContactsView( 3 | store: Store( 4 | initialState: ContactsFeature.State( 5 | contacts: [ 6 | Contact(id: UUID(), name: "Blob"), 7 | Contact(id: UUID(), name: "Blob Jr"), 8 | Contact(id: UUID(), name: "Blob Sr"), 9 | ] 10 | ) 11 | ) { 12 | ContactsFeature() 13 | } 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct AddContactFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | var contact: Contact 8 | } 9 | enum Action { 10 | case cancelButtonTapped 11 | case saveButtonTapped 12 | case setName(String) 13 | } 14 | var body: some ReducerOf { 15 | Reduce { state, action in 16 | switch action { 17 | case .cancelButtonTapped: 18 | return .none 19 | 20 | case .saveButtonTapped: 21 | return .none 22 | 23 | case let .setName(name): 24 | state.contact.name = name 25 | return .none 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct AddContactView: View { 4 | @Bindable var store: StoreOf 5 | } 6 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0005.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct AddContactView: View { 4 | @Bindable var store: StoreOf 5 | 6 | var body: some View { 7 | Form { 8 | TextField("Name", text: $store.contact.name.sending(\.setName)) 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0006.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct AddContactView: View { 4 | @Bindable var store: StoreOf 5 | 6 | var body: some View { 7 | Form { 8 | TextField("Name", text: $store.contact.name.sending(\.setName)) 9 | Button("Save") { 10 | store.send(.saveButtonTapped) 11 | } 12 | } 13 | .toolbar { 14 | ToolbarItem { 15 | Button("Cancel") { 16 | store.send(.cancelButtonTapped) 17 | } 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-01-code-0007.swift: -------------------------------------------------------------------------------- 1 | #Preview { 2 | NavigationStack { 3 | AddContactView( 4 | store: Store( 5 | initialState: AddContactFeature.State( 6 | contact: Contact( 7 | id: UUID(), 8 | name: "Blob" 9 | ) 10 | ) 11 | ) { 12 | AddContactFeature() 13 | } 14 | ) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-02-code-0000.swift: -------------------------------------------------------------------------------- 1 | @Reducer 2 | struct ContactsFeature { 3 | @ObservableState 4 | struct State: Equatable { 5 | var contacts: IdentifiedArrayOf = [] 6 | } 7 | enum Action { 8 | case addButtonTapped 9 | } 10 | var body: some ReducerOf { 11 | Reduce { state, action in 12 | switch action { 13 | case .addButtonTapped: 14 | // TODO: Handle action 15 | return .none 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | @Reducer 2 | struct ContactsFeature { 3 | @ObservableState 4 | struct State: Equatable { 5 | @Presents var addContact: AddContactFeature.State? 6 | var contacts: IdentifiedArrayOf = [] 7 | } 8 | enum Action { 9 | case addButtonTapped 10 | } 11 | var body: some ReducerOf { 12 | Reduce { state, action in 13 | switch action { 14 | case .addButtonTapped: 15 | // TODO: Handle action 16 | return .none 17 | } 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | @Reducer 2 | struct ContactsFeature { 3 | @ObservableState 4 | struct State: Equatable { 5 | @Presents var addContact: AddContactFeature.State? 6 | var contacts: IdentifiedArrayOf = [] 7 | } 8 | enum Action { 9 | case addButtonTapped 10 | case addContact(PresentationAction) 11 | } 12 | var body: some ReducerOf { 13 | Reduce { state, action in 14 | switch action { 15 | case .addButtonTapped: 16 | // TODO: Handle action 17 | return .none 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | @Reducer 2 | struct ContactsFeature { 3 | @ObservableState 4 | struct State: Equatable { 5 | @Presents var addContact: AddContactFeature.State? 6 | var contacts: IdentifiedArrayOf = [] 7 | } 8 | enum Action { 9 | case addButtonTapped 10 | case addContact(PresentationAction) 11 | } 12 | var body: some ReducerOf { 13 | Reduce { state, action in 14 | switch action { 15 | case .addButtonTapped: 16 | // TODO: Handle action 17 | return .none 18 | 19 | case .addContact: 20 | return .none 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/01-YourFirstPresentation/02-01-02-code-0008.swift: -------------------------------------------------------------------------------- 1 | struct ContactsView: View { 2 | let store: StoreOf 3 | 4 | var body: some View { 5 | NavigationStack { 6 | List { 7 | ForEach(store.contacts) { contact in 8 | Text(contact.name) 9 | } 10 | } 11 | .navigationTitle("Contacts") 12 | .toolbar { 13 | ToolbarItem { 14 | Button { 15 | store.send(.addButtonTapped) 16 | } label: { 17 | Image(systemName: "plus") 18 | } 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0000.swift: -------------------------------------------------------------------------------- 1 | extension ContactsFeature { 2 | @Reducer 3 | enum Destination { 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | extension ContactsFeature { 2 | @Reducer 3 | enum Destination { 4 | case addContact(AddContactFeature) 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | extension ContactsFeature { 2 | @Reducer 3 | enum Destination { 4 | case addContact(AddContactFeature) 5 | case alert(AlertState) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0004-previous.swift: -------------------------------------------------------------------------------- 1 | extension ContactsFeature { 2 | @Reducer 3 | enum Destination { 4 | case addContact(AddContactFeature) 5 | case alert(AlertState) 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/02-MultipleDestinations/02-02-02-code-0004.swift: -------------------------------------------------------------------------------- 1 | extension ContactsFeature { 2 | @Reducer 3 | enum Destination { 4 | case addContact(AddContactFeature) 5 | case alert(AlertState) 6 | } 7 | } 8 | extension ContactsFeature.Destination.State: Equatable {} 9 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0000.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | 14 | await store.send(.addButtonTapped) { 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | 14 | await store.send(.addButtonTapped) { 15 | $0.destination = .addContact( 16 | ) 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | 14 | await store.send(.addButtonTapped) { 15 | $0.destination = .addContact( 16 | AddContactFeature.State( 17 | ) 18 | ) 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | 14 | await store.send(.addButtonTapped) { 15 | $0.destination = .addContact( 16 | AddContactFeature.State( 17 | contact: Contact(id: ???, name: "") 18 | ) 19 | ) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0008-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | 14 | await store.send(.addButtonTapped) { 15 | $0.destination = .addContact( 16 | AddContactFeature.State( 17 | contact: Contact(id: ???, name: "") 18 | ) 19 | ) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0008.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func addFlow() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } withDependencies: { 13 | $0.uuid = .incrementing 14 | } 15 | 16 | await store.send(.addButtonTapped) { 17 | $0.destination = .addContact( 18 | AddContactFeature.State( 19 | contact: Contact(id: ???, name: "") 20 | ) 21 | ) 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-01-code-0009.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlow() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | 17 | await store.send(.addButtonTapped) { 18 | $0.destination = .addContact( 19 | AddContactFeature.State( 20 | contact: Contact(id: UUID(0), name: "") 21 | ) 22 | ) 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-02-code-0000.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlowNonExhaustive() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-02-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlowNonExhaustive() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | store.exhaustivity = .off 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-02-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlowNonExhaustive() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | store.exhaustivity = .off 17 | 18 | await store.send(.addButtonTapped) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-02-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlowNonExhaustive() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | store.exhaustivity = .off 17 | 18 | await store.send(.addButtonTapped) 19 | await store.send(\.destination.addContact.setName, "Blob Jr.") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-02-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlowNonExhaustive() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | store.exhaustivity = .off 17 | 18 | await store.send(.addButtonTapped) 19 | await store.send(\.destination.addContact.setName, "Blob Jr.") 20 | await store.send(\.destination.addContact.saveButtonTapped) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-02-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func addFlowNonExhaustive() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | ContactsFeature() 13 | } withDependencies: { 14 | $0.uuid = .incrementing 15 | } 16 | store.exhaustivity = .off 17 | 18 | await store.send(.addButtonTapped) 19 | await store.send(\.destination.addContact.setName, "Blob Jr.") 20 | await store.send(\.destination.addContact.saveButtonTapped) 21 | await store.skipReceivedActions() 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0000.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func deleteContact() async { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Testing 3 | 4 | @testable import ContactsApp 5 | 6 | @MainActor 7 | struct ContactsFeatureTests { 8 | @Test 9 | func deleteContact() async { 10 | let store = TestStore(initialState: ContactsFeature.State()) { 11 | ContactsFeature() 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func deleteContact() async { 11 | let store = TestStore(initialState: ContactsFeature.State()) { 12 | initialState: ContactsFeature.State( 13 | contacts: [ 14 | Contact(id: UUID(0), name: "Blob"), 15 | Contact(id: UUID(1), name: "Blob Jr."), 16 | ] 17 | ) 18 | ) { 19 | ContactsFeature() 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func deleteContact() async { 11 | let store = TestStore( 12 | initialState: ContactsFeature.State( 13 | contacts: [ 14 | Contact(id: UUID(0), name: "Blob"), 15 | Contact(id: UUID(1), name: "Blob Jr."), 16 | ] 17 | ) 18 | ) { 19 | ContactsFeature() 20 | } 21 | 22 | await store.send(.deleteButtonTapped(id: UUID(1))) { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0004.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func deleteContact() async { 11 | let store = TestStore( 12 | initialState: ContactsFeature.State( 13 | contacts: [ 14 | Contact(id: UUID(0), name: "Blob"), 15 | Contact(id: UUID(1), name: "Blob Jr."), 16 | ] 17 | ) 18 | ) { 19 | ContactsFeature() 20 | } 21 | 22 | await store.send(.deleteButtonTapped(id: UUID(1))) { 23 | $0.destination = .alert( 24 | ) 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | extension AlertState where Action == ContactsFeature.Action.Alert { 4 | static func deleteConfirmation(id: UUID) -> Self { 5 | Self { 6 | TextState("Are you sure?") 7 | } actions: { 8 | ButtonState(role: .destructive, action: .confirmDeletion(id: id)) { 9 | TextState("Delete") 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/03-TestingPresentation/02-03-03-code-0008.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import Foundation 3 | import Testing 4 | 5 | @testable import ContactsApp 6 | 7 | @MainActor 8 | struct ContactsFeatureTests { 9 | @Test 10 | func deleteContact() async { 11 | let store = TestStore( 12 | initialState: ContactsFeature.State( 13 | contacts: [ 14 | Contact(id: UUID(0), name: "Blob"), 15 | Contact(id: UUID(1), name: "Blob Jr."), 16 | ] 17 | ) 18 | ) { 19 | ContactsFeature() 20 | } 21 | 22 | await store.send(.deleteButtonTapped(id: UUID(1))) { 23 | $0.destination = .alert(.deleteConfirmation(id: UUID(1))) 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0000.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | } 6 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | let contact: Contact 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0002.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | let contact: Contact 8 | } 9 | enum Action { 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0003.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | let contact: Contact 8 | } 9 | enum Action { 10 | } 11 | var body: some ReducerOf { 12 | Reduce { state, action in 13 | switch action { 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0004.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ContactDetailView: View { 4 | var body: some View { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0005.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct ContactDetailView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0006.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct ContactDetailView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | Form { 9 | } 10 | .navigationTitle(Text(store.contact.name)) 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-01-code-0007.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct ContactDetailView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | Form { 9 | } 10 | .navigationTitle(Text(store.contact.name)) 11 | } 12 | } 13 | 14 | #Preview { 15 | NavigationStack { 16 | ContactDetailView( 17 | store: Store( 18 | initialState: ContactDetailFeature.State( 19 | contact: Contact(id: UUID(), name: "Blob") 20 | ) 21 | ) { 22 | ContactDetailFeature() 23 | } 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-03-code-0000-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | let contact: Contact 8 | } 9 | enum Action { 10 | } 11 | var body: some ReducerOf { 12 | Reduce { state, action in 13 | switch action { 14 | } 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-03-code-0000.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | @Presents var alert: AlertState? 8 | let contact: Contact 9 | } 10 | enum Action { 11 | } 12 | var body: some ReducerOf { 13 | Reduce { state, action in 14 | switch action { 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-03-code-0001.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | @Reducer 4 | struct ContactDetailFeature { 5 | @ObservableState 6 | struct State: Equatable { 7 | @Presents var alert: AlertState? 8 | let contact: Contact 9 | } 10 | enum Action { 11 | case alert(PresentationAction) 12 | case delegate(Delegate) 13 | case deleteButtonTapped 14 | enum Alert { 15 | case confirmDeletion 16 | } 17 | enum Delegate { 18 | case confirmDeletion 19 | } 20 | } 21 | var body: some ReducerOf { 22 | Reduce { state, action in 23 | switch action { 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/02-Navigation/04-NavigationStacks/02-04-03-code-0003-previous.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | import SwiftUI 3 | 4 | struct ContactDetailView: View { 5 | let store: StoreOf 6 | 7 | var body: some View { 8 | Form { 9 | } 10 | .navigationTitle(Text(store.contact.name)) 11 | } 12 | } 13 | 14 | #Preview { 15 | NavigationStack { 16 | ContactDetailView( 17 | store: Store( 18 | initialState: ContactDetailFeature.State( 19 | contact: Contact(id: UUID(), name: "Blob") 20 | ) 21 | ) { 22 | ContactDetailFeature() 23 | } 24 | ) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter1.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter2.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter3.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter4.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter5.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter6.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter7.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pointfreeco/swift-composable-architecture/49f03230076ca964e0c6a4a676e38b6d3ea64c3a/Sources/ComposableArchitecture/Documentation.docc/Tutorials/MeetTheComposableArchitecture/chapter8.png -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/AreOrderedSetsDuplicates.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import OrderedCollections 3 | 4 | @inlinable 5 | func areOrderedSetsDuplicates(_ lhs: OrderedSet, _ rhs: OrderedSet) -> Bool { 6 | guard lhs.count == rhs.count 7 | else { return false } 8 | 9 | return withUnsafePointer(to: lhs) { lhsPointer in 10 | withUnsafePointer(to: rhs) { rhsPointer in 11 | memcmp(lhsPointer, rhsPointer, MemoryLayout>.size) == 0 || lhs == rhs 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/Box.swift: -------------------------------------------------------------------------------- 1 | final class Box { 2 | var wrappedValue: Wrapped 3 | 4 | init(wrappedValue: Wrapped) { 5 | self.wrappedValue = wrappedValue 6 | } 7 | 8 | var boxedValue: Wrapped { 9 | _read { yield self.wrappedValue } 10 | _modify { yield &self.wrappedValue } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/Debug.swift: -------------------------------------------------------------------------------- 1 | import CustomDump 2 | import Foundation 3 | 4 | extension String { 5 | @usableFromInline 6 | func indent(by indent: Int) -> String { 7 | let indentation = String(repeating: " ", count: indent) 8 | return indentation + self.replacingOccurrences(of: "\n", with: "\n\(indentation)") 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/Exports.swift: -------------------------------------------------------------------------------- 1 | @_exported import CasePaths 2 | @_exported import Clocks 3 | @_exported import CombineSchedulers 4 | @_exported import ConcurrencyExtras 5 | @_exported import CustomDump 6 | @_exported import Dependencies 7 | @_exported import DependenciesMacros 8 | @_exported import IdentifiedCollections 9 | @_exported import Observation 10 | @_exported import Perception 11 | @_exported import Sharing 12 | @_exported import SwiftUINavigation 13 | @_exported import UIKitNavigation 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/Locking.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | extension UnsafeMutablePointer { 4 | @inlinable @discardableResult 5 | func sync(_ work: () -> R) -> R { 6 | os_unfair_lock_lock(self) 7 | defer { os_unfair_lock_unlock(self) } 8 | return work() 9 | } 10 | 11 | func lock() { 12 | os_unfair_lock_lock(self) 13 | } 14 | 15 | func unlock() { 16 | os_unfair_lock_unlock(self) 17 | } 18 | } 19 | 20 | extension NSRecursiveLock { 21 | @inlinable @discardableResult 22 | @_spi(Internals) public func sync(work: () -> R) -> R { 23 | self.lock() 24 | defer { self.unlock() } 25 | return work() 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/OpenExistential.swift: -------------------------------------------------------------------------------- 1 | // MARK: Equatable 2 | 3 | func _isEqual(_ lhs: Any, _ rhs: Any) -> Bool? { 4 | (lhs as? any Equatable)?.isEqual(other: rhs) 5 | } 6 | 7 | extension Equatable { 8 | fileprivate func isEqual(other: Any) -> Bool { 9 | self == other as? Self 10 | } 11 | } 12 | 13 | // MARK: Identifiable 14 | 15 | func _identifiableID(_ value: Any) -> AnyHashable? { 16 | func open(_ value: some Identifiable) -> AnyHashable { 17 | value.id 18 | } 19 | guard let value = value as? any Identifiable else { return nil } 20 | return open(value) 21 | } 22 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/ReturningLastNonNilValue.swift: -------------------------------------------------------------------------------- 1 | // Creates a memoized cache that always returns the last non-`nil` value. 2 | // 3 | // Useful for preserving a presented UI during the programmatic dismissal of sheets and other forms 4 | // of navigation, where setting state to `nil` drives dismissal. 5 | func returningLastNonNilValue(_ f: @escaping (A) -> B?) -> (A) -> B? { 6 | var lastWrapped: B? 7 | return { wrapped in 8 | lastWrapped = f(wrapped) ?? lastWrapped 9 | return lastWrapped 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Internal/RuntimeWarnings.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import IssueReporting 3 | 4 | extension Notification.Name { 5 | @_documentation(visibility: private) 6 | @available(*, deprecated, renamed: "_runtimeWarning") 7 | public static let runtimeWarning = Self("ComposableArchitecture.runtimeWarning") 8 | 9 | /// A notification that is posted when a runtime warning is emitted. 10 | public static let _runtimeWarning = Self("ComposableArchitecture.runtimeWarning") 11 | } 12 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Reducer/Reducers/EmptyReducer.swift: -------------------------------------------------------------------------------- 1 | /// A reducer that does nothing. 2 | /// 3 | /// While not very useful on its own, `EmptyReducer` can be used as a placeholder in APIs that hold 4 | /// reducers. 5 | public struct EmptyReducer: Reducer { 6 | /// Initializes a reducer that does nothing. 7 | @inlinable 8 | public init() { 9 | self.init(internal: ()) 10 | } 11 | 12 | @usableFromInline 13 | init(internal: Void) {} 14 | 15 | @inlinable 16 | public func reduce(into _: inout State, action _: Action) -> Effect { 17 | .none 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Reducer/Reducers/Optional.swift: -------------------------------------------------------------------------------- 1 | extension Optional: Reducer where Wrapped: Reducer { 2 | @inlinable 3 | public func reduce( 4 | into state: inout Wrapped.State, action: Wrapped.Action 5 | ) -> Effect { 6 | switch self { 7 | case let .some(wrapped): 8 | return wrapped.reduce(into: &state, action: action) 9 | case .none: 10 | return .none 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Sources/ComposableArchitecture/Resources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyCollectedDataTypes 6 | 7 | NSPrivacyAccessedAPITypes 8 | 9 | 10 | NSPrivacyAccessedAPIType 11 | NSPrivacyAccessedAPICategoryUserDefaults 12 | NSPrivacyAccessedAPITypeReasons 13 | 14 | C56D.1 15 | 16 | 17 | 18 | NSPrivacyTrackingDomains 19 | 20 | NSPrivacyTracking 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /Sources/ComposableArchitectureMacros/Plugins.swift: -------------------------------------------------------------------------------- 1 | import SwiftCompilerPlugin 2 | import SwiftSyntaxMacros 3 | 4 | @main 5 | struct MacrosPlugin: CompilerPlugin { 6 | let providingMacros: [any Macro.Type] = [ 7 | ObservableStateMacro.self, 8 | ObservationStateTrackedMacro.self, 9 | ObservationStateIgnoredMacro.self, 10 | PresentsMacro.self, 11 | ReducerMacro.self, 12 | ReducerCaseEphemeralMacro.self, 13 | ReducerCaseIgnoredMacro.self, 14 | ViewActionMacro.self, 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Tests/ComposableArchitectureMacrosTests/MacroBaseTestCase.swift: -------------------------------------------------------------------------------- 1 | #if canImport(ComposableArchitectureMacros) 2 | import ComposableArchitectureMacros 3 | import MacroTesting 4 | import SwiftSyntaxMacros 5 | import SwiftSyntaxMacrosTestSupport 6 | import XCTest 7 | 8 | class MacroBaseTestCase: XCTestCase { 9 | override func invokeTest() { 10 | MacroTesting.withMacroTesting( 11 | //isRecording: true, 12 | macros: [ 13 | ObservableStateMacro.self, 14 | ObservationStateTrackedMacro.self, 15 | ObservationStateIgnoredMacro.self, 16 | PresentsMacro.self, 17 | ViewActionMacro.self, 18 | ] 19 | ) { 20 | super.invokeTest() 21 | } 22 | } 23 | } 24 | #endif 25 | -------------------------------------------------------------------------------- /Tests/ComposableArchitectureTests/Internal/BaseTCATestCase.swift: -------------------------------------------------------------------------------- 1 | @_spi(Internals) @_spi(Logging) import ComposableArchitecture 2 | import XCTest 3 | 4 | class BaseTCATestCase: XCTestCase { 5 | override func tearDown() async throws { 6 | try await super.tearDown() 7 | let description = "\(self)" 8 | _cancellationCancellables.withValue { 9 | XCTAssertEqual($0.count, 0, description) 10 | $0.removeAll() 11 | } 12 | await MainActor.run { 13 | Logger.shared.isEnabled = false 14 | Logger.shared.clear() 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Tests/ComposableArchitectureTests/Internal/TestHelpers.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | @_transparent 4 | @available( 5 | *, 6 | deprecated, 7 | message: "This is a test that currently fails but should not in the future." 8 | ) 9 | func XCTTODO(_ message: String) { 10 | XCTExpectFailure(message) 11 | } 12 | -------------------------------------------------------------------------------- /Tests/ComposableArchitectureTests/ObservableStateEnumMacroTests.swift: -------------------------------------------------------------------------------- 1 | import ComposableArchitecture 2 | 3 | private enum TestObservableEnum_CompilerDirective { 4 | @Reducer 5 | struct ChildFeature {} 6 | @ObservableState 7 | public enum State { 8 | case child(ChildFeature.State) 9 | #if os(macOS) 10 | case mac(ChildFeature.State) 11 | #elseif os(tvOS) 12 | case tv(ChildFeature.State) 13 | #endif 14 | #if DEBUG 15 | #if INNER 16 | case inner(ChildFeature.State) 17 | #endif 18 | #endif 19 | } 20 | } 21 | --------------------------------------------------------------------------------