├── .DS_Store ├── FlowCoordinators-iOS16.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── WorkspaceSettings.xcsettings │ └── xcuserdata │ │ └── michzio.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── xcuserdata │ └── michzio.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── FlowCoordinators-iOS16 ├── .DS_Store ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Extensions │ └── NavigationLink.swift ├── FlowCoordinatorsApp.swift ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json └── Views │ ├── .DS_Store │ ├── Content │ ├── ContentFlowCoordinator.swift │ ├── ContentLink.swift │ ├── ContentView.swift │ └── ContentViewModel.swift │ ├── Cover │ ├── CoverFlowCoordinator.swift │ ├── CoverLink.swift │ ├── CoverView.swift │ └── CoverViewModel.swift │ ├── First │ ├── FirstFlowCoordinator.swift │ ├── FirstLink.swift │ ├── FirstView.swift │ └── FirstViewModel.swift │ ├── Second │ ├── SecondFlowCoordinator.swift │ ├── SecondLink.swift │ ├── SecondView.swift │ └── SecondViewModel.swift │ ├── Sheet │ ├── SheetFlowCoordinator.swift │ ├── SheetLink.swift │ ├── SheetView.swift │ └── SheetViewModel.swift │ └── Third │ ├── ThirdFlowCoordinator.swift │ ├── ThirdLink.swift │ ├── ThirdView.swift │ └── ThirdViewModel.swift ├── README.md └── navigation-image.gif /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michzio/FlowCoordinators-SwiftUI-iOS16/cfc2c66f78d5bd1a1180a2cea39ad4a0bf146de6/.DS_Store -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 84D3E012291E91C00024F9A3 /* FlowCoordinatorsApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E011291E91C00024F9A3 /* FlowCoordinatorsApp.swift */; }; 11 | 84D3E014291E91C00024F9A3 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E013291E91C00024F9A3 /* ContentView.swift */; }; 12 | 84D3E016291E91D90024F9A3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84D3E015291E91D90024F9A3 /* Assets.xcassets */; }; 13 | 84D3E019291E91D90024F9A3 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 84D3E018291E91D90024F9A3 /* Preview Assets.xcassets */; }; 14 | 84D3E022291E92470024F9A3 /* ContentViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E021291E92470024F9A3 /* ContentViewModel.swift */; }; 15 | 84D3E024291E92E50024F9A3 /* ContentFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E023291E92E50024F9A3 /* ContentFlowCoordinator.swift */; }; 16 | 84D3E02A291E936C0024F9A3 /* SheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E029291E936C0024F9A3 /* SheetView.swift */; }; 17 | 84D3E02C291E939B0024F9A3 /* SheetFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E02B291E939B0024F9A3 /* SheetFlowCoordinator.swift */; }; 18 | 84D3E02E291E93C00024F9A3 /* SheetViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E02D291E93C00024F9A3 /* SheetViewModel.swift */; }; 19 | 84D3E032291E93FB0024F9A3 /* FirstView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E02F291E93FB0024F9A3 /* FirstView.swift */; }; 20 | 84D3E033291E93FB0024F9A3 /* FirstViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E030291E93FB0024F9A3 /* FirstViewModel.swift */; }; 21 | 84D3E034291E93FB0024F9A3 /* FirstFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E031291E93FB0024F9A3 /* FirstFlowCoordinator.swift */; }; 22 | 84D3E038291E94030024F9A3 /* SecondFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E035291E94030024F9A3 /* SecondFlowCoordinator.swift */; }; 23 | 84D3E039291E94030024F9A3 /* SecondViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E036291E94030024F9A3 /* SecondViewModel.swift */; }; 24 | 84D3E03A291E94030024F9A3 /* SecondView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E037291E94030024F9A3 /* SecondView.swift */; }; 25 | 84D3E03E291E940C0024F9A3 /* ThirdView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E03B291E940C0024F9A3 /* ThirdView.swift */; }; 26 | 84D3E03F291E940C0024F9A3 /* ThirdViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E03C291E940C0024F9A3 /* ThirdViewModel.swift */; }; 27 | 84D3E040291E940C0024F9A3 /* ThirdFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E03D291E940C0024F9A3 /* ThirdFlowCoordinator.swift */; }; 28 | 84D3E042291E97B10024F9A3 /* ContentLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E041291E97B10024F9A3 /* ContentLink.swift */; }; 29 | 84D3E044291E9D880024F9A3 /* FirstLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E043291E9D880024F9A3 /* FirstLink.swift */; }; 30 | 84D3E046291E9E230024F9A3 /* ThirdLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E045291E9E230024F9A3 /* ThirdLink.swift */; }; 31 | 84D3E048291E9EC40024F9A3 /* SecondLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E047291E9EC40024F9A3 /* SecondLink.swift */; }; 32 | 84D3E04A291EA0050024F9A3 /* SheetLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E049291EA0050024F9A3 /* SheetLink.swift */; }; 33 | 84D3E04D291EA1840024F9A3 /* CoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E04C291EA1840024F9A3 /* CoverView.swift */; }; 34 | 84D3E04F291EA1BF0024F9A3 /* CoverFlowCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E04E291EA1BF0024F9A3 /* CoverFlowCoordinator.swift */; }; 35 | 84D3E051291EA2030024F9A3 /* CoverViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E050291EA2030024F9A3 /* CoverViewModel.swift */; }; 36 | 84D3E053291EA22E0024F9A3 /* CoverLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E052291EA22E0024F9A3 /* CoverLink.swift */; }; 37 | 84D3E056291EAF2A0024F9A3 /* NavigationLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84D3E055291EAF2A0024F9A3 /* NavigationLink.swift */; }; 38 | /* End PBXBuildFile section */ 39 | 40 | /* Begin PBXFileReference section */ 41 | 84D3E00E291E91C00024F9A3 /* FlowCoordinators-iOS16.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "FlowCoordinators-iOS16.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | 84D3E011291E91C00024F9A3 /* FlowCoordinatorsApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FlowCoordinatorsApp.swift; sourceTree = ""; }; 43 | 84D3E013291E91C00024F9A3 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 44 | 84D3E015291E91D90024F9A3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 45 | 84D3E018291E91D90024F9A3 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 46 | 84D3E021291E92470024F9A3 /* ContentViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentViewModel.swift; sourceTree = ""; }; 47 | 84D3E023291E92E50024F9A3 /* ContentFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentFlowCoordinator.swift; sourceTree = ""; }; 48 | 84D3E029291E936C0024F9A3 /* SheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetView.swift; sourceTree = ""; }; 49 | 84D3E02B291E939B0024F9A3 /* SheetFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetFlowCoordinator.swift; sourceTree = ""; }; 50 | 84D3E02D291E93C00024F9A3 /* SheetViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetViewModel.swift; sourceTree = ""; }; 51 | 84D3E02F291E93FB0024F9A3 /* FirstView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstView.swift; sourceTree = ""; }; 52 | 84D3E030291E93FB0024F9A3 /* FirstViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstViewModel.swift; sourceTree = ""; }; 53 | 84D3E031291E93FB0024F9A3 /* FirstFlowCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FirstFlowCoordinator.swift; sourceTree = ""; }; 54 | 84D3E035291E94030024F9A3 /* SecondFlowCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondFlowCoordinator.swift; sourceTree = ""; }; 55 | 84D3E036291E94030024F9A3 /* SecondViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondViewModel.swift; sourceTree = ""; }; 56 | 84D3E037291E94030024F9A3 /* SecondView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecondView.swift; sourceTree = ""; }; 57 | 84D3E03B291E940C0024F9A3 /* ThirdView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdView.swift; sourceTree = ""; }; 58 | 84D3E03C291E940C0024F9A3 /* ThirdViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdViewModel.swift; sourceTree = ""; }; 59 | 84D3E03D291E940C0024F9A3 /* ThirdFlowCoordinator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThirdFlowCoordinator.swift; sourceTree = ""; }; 60 | 84D3E041291E97B10024F9A3 /* ContentLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentLink.swift; sourceTree = ""; }; 61 | 84D3E043291E9D880024F9A3 /* FirstLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FirstLink.swift; sourceTree = ""; }; 62 | 84D3E045291E9E230024F9A3 /* ThirdLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdLink.swift; sourceTree = ""; }; 63 | 84D3E047291E9EC40024F9A3 /* SecondLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecondLink.swift; sourceTree = ""; }; 64 | 84D3E049291EA0050024F9A3 /* SheetLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SheetLink.swift; sourceTree = ""; }; 65 | 84D3E04C291EA1840024F9A3 /* CoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoverView.swift; sourceTree = ""; }; 66 | 84D3E04E291EA1BF0024F9A3 /* CoverFlowCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoverFlowCoordinator.swift; sourceTree = ""; }; 67 | 84D3E050291EA2030024F9A3 /* CoverViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoverViewModel.swift; sourceTree = ""; }; 68 | 84D3E052291EA22E0024F9A3 /* CoverLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoverLink.swift; sourceTree = ""; }; 69 | 84D3E055291EAF2A0024F9A3 /* NavigationLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationLink.swift; sourceTree = ""; }; 70 | /* End PBXFileReference section */ 71 | 72 | /* Begin PBXFrameworksBuildPhase section */ 73 | 84D3E00B291E91C00024F9A3 /* Frameworks */ = { 74 | isa = PBXFrameworksBuildPhase; 75 | buildActionMask = 2147483647; 76 | files = ( 77 | ); 78 | runOnlyForDeploymentPostprocessing = 0; 79 | }; 80 | /* End PBXFrameworksBuildPhase section */ 81 | 82 | /* Begin PBXGroup section */ 83 | 84D3E005291E91C00024F9A3 = { 84 | isa = PBXGroup; 85 | children = ( 86 | 84D3E010291E91C00024F9A3 /* FlowCoordinators-iOS16 */, 87 | 84D3E00F291E91C00024F9A3 /* Products */, 88 | ); 89 | sourceTree = ""; 90 | }; 91 | 84D3E00F291E91C00024F9A3 /* Products */ = { 92 | isa = PBXGroup; 93 | children = ( 94 | 84D3E00E291E91C00024F9A3 /* FlowCoordinators-iOS16.app */, 95 | ); 96 | name = Products; 97 | sourceTree = ""; 98 | }; 99 | 84D3E010291E91C00024F9A3 /* FlowCoordinators-iOS16 */ = { 100 | isa = PBXGroup; 101 | children = ( 102 | 84D3E054291EAF140024F9A3 /* Extensions */, 103 | 84D3E01F291E92250024F9A3 /* Views */, 104 | 84D3E011291E91C00024F9A3 /* FlowCoordinatorsApp.swift */, 105 | 84D3E015291E91D90024F9A3 /* Assets.xcassets */, 106 | 84D3E017291E91D90024F9A3 /* Preview Content */, 107 | ); 108 | path = "FlowCoordinators-iOS16"; 109 | sourceTree = ""; 110 | }; 111 | 84D3E017291E91D90024F9A3 /* Preview Content */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 84D3E018291E91D90024F9A3 /* Preview Assets.xcassets */, 115 | ); 116 | path = "Preview Content"; 117 | sourceTree = ""; 118 | }; 119 | 84D3E01F291E92250024F9A3 /* Views */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 84D3E04B291EA1650024F9A3 /* Cover */, 123 | 84D3E028291E934D0024F9A3 /* Sheet */, 124 | 84D3E027291E93470024F9A3 /* Third */, 125 | 84D3E026291E93420024F9A3 /* Second */, 126 | 84D3E025291E933D0024F9A3 /* First */, 127 | 84D3E020291E922B0024F9A3 /* Content */, 128 | ); 129 | path = Views; 130 | sourceTree = ""; 131 | }; 132 | 84D3E020291E922B0024F9A3 /* Content */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 84D3E013291E91C00024F9A3 /* ContentView.swift */, 136 | 84D3E021291E92470024F9A3 /* ContentViewModel.swift */, 137 | 84D3E023291E92E50024F9A3 /* ContentFlowCoordinator.swift */, 138 | 84D3E041291E97B10024F9A3 /* ContentLink.swift */, 139 | ); 140 | path = Content; 141 | sourceTree = ""; 142 | }; 143 | 84D3E025291E933D0024F9A3 /* First */ = { 144 | isa = PBXGroup; 145 | children = ( 146 | 84D3E031291E93FB0024F9A3 /* FirstFlowCoordinator.swift */, 147 | 84D3E02F291E93FB0024F9A3 /* FirstView.swift */, 148 | 84D3E030291E93FB0024F9A3 /* FirstViewModel.swift */, 149 | 84D3E043291E9D880024F9A3 /* FirstLink.swift */, 150 | ); 151 | path = First; 152 | sourceTree = ""; 153 | }; 154 | 84D3E026291E93420024F9A3 /* Second */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 84D3E035291E94030024F9A3 /* SecondFlowCoordinator.swift */, 158 | 84D3E037291E94030024F9A3 /* SecondView.swift */, 159 | 84D3E036291E94030024F9A3 /* SecondViewModel.swift */, 160 | 84D3E047291E9EC40024F9A3 /* SecondLink.swift */, 161 | ); 162 | path = Second; 163 | sourceTree = ""; 164 | }; 165 | 84D3E027291E93470024F9A3 /* Third */ = { 166 | isa = PBXGroup; 167 | children = ( 168 | 84D3E03D291E940C0024F9A3 /* ThirdFlowCoordinator.swift */, 169 | 84D3E03B291E940C0024F9A3 /* ThirdView.swift */, 170 | 84D3E03C291E940C0024F9A3 /* ThirdViewModel.swift */, 171 | 84D3E045291E9E230024F9A3 /* ThirdLink.swift */, 172 | ); 173 | path = Third; 174 | sourceTree = ""; 175 | }; 176 | 84D3E028291E934D0024F9A3 /* Sheet */ = { 177 | isa = PBXGroup; 178 | children = ( 179 | 84D3E029291E936C0024F9A3 /* SheetView.swift */, 180 | 84D3E02B291E939B0024F9A3 /* SheetFlowCoordinator.swift */, 181 | 84D3E02D291E93C00024F9A3 /* SheetViewModel.swift */, 182 | 84D3E049291EA0050024F9A3 /* SheetLink.swift */, 183 | ); 184 | path = Sheet; 185 | sourceTree = ""; 186 | }; 187 | 84D3E04B291EA1650024F9A3 /* Cover */ = { 188 | isa = PBXGroup; 189 | children = ( 190 | 84D3E04C291EA1840024F9A3 /* CoverView.swift */, 191 | 84D3E04E291EA1BF0024F9A3 /* CoverFlowCoordinator.swift */, 192 | 84D3E050291EA2030024F9A3 /* CoverViewModel.swift */, 193 | 84D3E052291EA22E0024F9A3 /* CoverLink.swift */, 194 | ); 195 | path = Cover; 196 | sourceTree = ""; 197 | }; 198 | 84D3E054291EAF140024F9A3 /* Extensions */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | 84D3E055291EAF2A0024F9A3 /* NavigationLink.swift */, 202 | ); 203 | path = Extensions; 204 | sourceTree = ""; 205 | }; 206 | /* End PBXGroup section */ 207 | 208 | /* Begin PBXNativeTarget section */ 209 | 84D3E00D291E91C00024F9A3 /* FlowCoordinators-iOS16 */ = { 210 | isa = PBXNativeTarget; 211 | buildConfigurationList = 84D3E01C291E91D90024F9A3 /* Build configuration list for PBXNativeTarget "FlowCoordinators-iOS16" */; 212 | buildPhases = ( 213 | 84D3E00A291E91C00024F9A3 /* Sources */, 214 | 84D3E00B291E91C00024F9A3 /* Frameworks */, 215 | 84D3E00C291E91C00024F9A3 /* Resources */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | ); 221 | name = "FlowCoordinators-iOS16"; 222 | productName = "FlowCoordinators-iOS16"; 223 | productReference = 84D3E00E291E91C00024F9A3 /* FlowCoordinators-iOS16.app */; 224 | productType = "com.apple.product-type.application"; 225 | }; 226 | /* End PBXNativeTarget section */ 227 | 228 | /* Begin PBXProject section */ 229 | 84D3E006291E91C00024F9A3 /* Project object */ = { 230 | isa = PBXProject; 231 | attributes = { 232 | BuildIndependentTargetsInParallel = 1; 233 | LastSwiftUpdateCheck = 1400; 234 | LastUpgradeCheck = 1400; 235 | TargetAttributes = { 236 | 84D3E00D291E91C00024F9A3 = { 237 | CreatedOnToolsVersion = 14.0; 238 | }; 239 | }; 240 | }; 241 | buildConfigurationList = 84D3E009291E91C00024F9A3 /* Build configuration list for PBXProject "FlowCoordinators-iOS16" */; 242 | compatibilityVersion = "Xcode 14.0"; 243 | developmentRegion = en; 244 | hasScannedForEncodings = 0; 245 | knownRegions = ( 246 | en, 247 | Base, 248 | ); 249 | mainGroup = 84D3E005291E91C00024F9A3; 250 | productRefGroup = 84D3E00F291E91C00024F9A3 /* Products */; 251 | projectDirPath = ""; 252 | projectRoot = ""; 253 | targets = ( 254 | 84D3E00D291E91C00024F9A3 /* FlowCoordinators-iOS16 */, 255 | ); 256 | }; 257 | /* End PBXProject section */ 258 | 259 | /* Begin PBXResourcesBuildPhase section */ 260 | 84D3E00C291E91C00024F9A3 /* Resources */ = { 261 | isa = PBXResourcesBuildPhase; 262 | buildActionMask = 2147483647; 263 | files = ( 264 | 84D3E019291E91D90024F9A3 /* Preview Assets.xcassets in Resources */, 265 | 84D3E016291E91D90024F9A3 /* Assets.xcassets in Resources */, 266 | ); 267 | runOnlyForDeploymentPostprocessing = 0; 268 | }; 269 | /* End PBXResourcesBuildPhase section */ 270 | 271 | /* Begin PBXSourcesBuildPhase section */ 272 | 84D3E00A291E91C00024F9A3 /* Sources */ = { 273 | isa = PBXSourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 84D3E044291E9D880024F9A3 /* FirstLink.swift in Sources */, 277 | 84D3E053291EA22E0024F9A3 /* CoverLink.swift in Sources */, 278 | 84D3E03E291E940C0024F9A3 /* ThirdView.swift in Sources */, 279 | 84D3E046291E9E230024F9A3 /* ThirdLink.swift in Sources */, 280 | 84D3E02C291E939B0024F9A3 /* SheetFlowCoordinator.swift in Sources */, 281 | 84D3E014291E91C00024F9A3 /* ContentView.swift in Sources */, 282 | 84D3E048291E9EC40024F9A3 /* SecondLink.swift in Sources */, 283 | 84D3E04A291EA0050024F9A3 /* SheetLink.swift in Sources */, 284 | 84D3E042291E97B10024F9A3 /* ContentLink.swift in Sources */, 285 | 84D3E012291E91C00024F9A3 /* FlowCoordinatorsApp.swift in Sources */, 286 | 84D3E02A291E936C0024F9A3 /* SheetView.swift in Sources */, 287 | 84D3E051291EA2030024F9A3 /* CoverViewModel.swift in Sources */, 288 | 84D3E04D291EA1840024F9A3 /* CoverView.swift in Sources */, 289 | 84D3E039291E94030024F9A3 /* SecondViewModel.swift in Sources */, 290 | 84D3E03F291E940C0024F9A3 /* ThirdViewModel.swift in Sources */, 291 | 84D3E024291E92E50024F9A3 /* ContentFlowCoordinator.swift in Sources */, 292 | 84D3E032291E93FB0024F9A3 /* FirstView.swift in Sources */, 293 | 84D3E022291E92470024F9A3 /* ContentViewModel.swift in Sources */, 294 | 84D3E038291E94030024F9A3 /* SecondFlowCoordinator.swift in Sources */, 295 | 84D3E033291E93FB0024F9A3 /* FirstViewModel.swift in Sources */, 296 | 84D3E040291E940C0024F9A3 /* ThirdFlowCoordinator.swift in Sources */, 297 | 84D3E03A291E94030024F9A3 /* SecondView.swift in Sources */, 298 | 84D3E02E291E93C00024F9A3 /* SheetViewModel.swift in Sources */, 299 | 84D3E056291EAF2A0024F9A3 /* NavigationLink.swift in Sources */, 300 | 84D3E034291E93FB0024F9A3 /* FirstFlowCoordinator.swift in Sources */, 301 | 84D3E04F291EA1BF0024F9A3 /* CoverFlowCoordinator.swift in Sources */, 302 | ); 303 | runOnlyForDeploymentPostprocessing = 0; 304 | }; 305 | /* End PBXSourcesBuildPhase section */ 306 | 307 | /* Begin XCBuildConfiguration section */ 308 | 84D3E01A291E91D90024F9A3 /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ALWAYS_SEARCH_USER_PATHS = NO; 312 | CLANG_ANALYZER_NONNULL = YES; 313 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 314 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 315 | CLANG_ENABLE_MODULES = YES; 316 | CLANG_ENABLE_OBJC_ARC = YES; 317 | CLANG_ENABLE_OBJC_WEAK = YES; 318 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 319 | CLANG_WARN_BOOL_CONVERSION = YES; 320 | CLANG_WARN_COMMA = YES; 321 | CLANG_WARN_CONSTANT_CONVERSION = YES; 322 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 323 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 324 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN_ENUM_CONVERSION = YES; 327 | CLANG_WARN_INFINITE_RECURSION = YES; 328 | CLANG_WARN_INT_CONVERSION = YES; 329 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 330 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 331 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 332 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 333 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 334 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 335 | CLANG_WARN_STRICT_PROTOTYPES = YES; 336 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 337 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 338 | CLANG_WARN_UNREACHABLE_CODE = YES; 339 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 340 | COPY_PHASE_STRIP = NO; 341 | DEBUG_INFORMATION_FORMAT = dwarf; 342 | ENABLE_STRICT_OBJC_MSGSEND = YES; 343 | ENABLE_TESTABILITY = YES; 344 | GCC_C_LANGUAGE_STANDARD = gnu11; 345 | GCC_DYNAMIC_NO_PIC = NO; 346 | GCC_NO_COMMON_BLOCKS = YES; 347 | GCC_OPTIMIZATION_LEVEL = 0; 348 | GCC_PREPROCESSOR_DEFINITIONS = ( 349 | "DEBUG=1", 350 | "$(inherited)", 351 | ); 352 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 353 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 354 | GCC_WARN_UNDECLARED_SELECTOR = YES; 355 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 356 | GCC_WARN_UNUSED_FUNCTION = YES; 357 | GCC_WARN_UNUSED_VARIABLE = YES; 358 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 359 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 360 | MTL_FAST_MATH = YES; 361 | ONLY_ACTIVE_ARCH = YES; 362 | SDKROOT = iphoneos; 363 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 364 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 365 | }; 366 | name = Debug; 367 | }; 368 | 84D3E01B291E91D90024F9A3 /* Release */ = { 369 | isa = XCBuildConfiguration; 370 | buildSettings = { 371 | ALWAYS_SEARCH_USER_PATHS = NO; 372 | CLANG_ANALYZER_NONNULL = YES; 373 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 374 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 375 | CLANG_ENABLE_MODULES = YES; 376 | CLANG_ENABLE_OBJC_ARC = YES; 377 | CLANG_ENABLE_OBJC_WEAK = YES; 378 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 379 | CLANG_WARN_BOOL_CONVERSION = YES; 380 | CLANG_WARN_COMMA = YES; 381 | CLANG_WARN_CONSTANT_CONVERSION = YES; 382 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 383 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 384 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 385 | CLANG_WARN_EMPTY_BODY = YES; 386 | CLANG_WARN_ENUM_CONVERSION = YES; 387 | CLANG_WARN_INFINITE_RECURSION = YES; 388 | CLANG_WARN_INT_CONVERSION = YES; 389 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 390 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 391 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 392 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 393 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 394 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 395 | CLANG_WARN_STRICT_PROTOTYPES = YES; 396 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 397 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 398 | CLANG_WARN_UNREACHABLE_CODE = YES; 399 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 400 | COPY_PHASE_STRIP = NO; 401 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 402 | ENABLE_NS_ASSERTIONS = NO; 403 | ENABLE_STRICT_OBJC_MSGSEND = YES; 404 | GCC_C_LANGUAGE_STANDARD = gnu11; 405 | GCC_NO_COMMON_BLOCKS = YES; 406 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 407 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 408 | GCC_WARN_UNDECLARED_SELECTOR = YES; 409 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 410 | GCC_WARN_UNUSED_FUNCTION = YES; 411 | GCC_WARN_UNUSED_VARIABLE = YES; 412 | IPHONEOS_DEPLOYMENT_TARGET = 16.0; 413 | MTL_ENABLE_DEBUG_INFO = NO; 414 | MTL_FAST_MATH = YES; 415 | SDKROOT = iphoneos; 416 | SWIFT_COMPILATION_MODE = wholemodule; 417 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 418 | VALIDATE_PRODUCT = YES; 419 | }; 420 | name = Release; 421 | }; 422 | 84D3E01D291E91D90024F9A3 /* Debug */ = { 423 | isa = XCBuildConfiguration; 424 | buildSettings = { 425 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 426 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 427 | CODE_SIGN_STYLE = Automatic; 428 | CURRENT_PROJECT_VERSION = 1; 429 | DEVELOPMENT_ASSET_PATHS = "\"FlowCoordinators-iOS16/Preview Content\""; 430 | ENABLE_PREVIEWS = YES; 431 | GENERATE_INFOPLIST_FILE = YES; 432 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 433 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 434 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 435 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 436 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 437 | LD_RUNPATH_SEARCH_PATHS = ( 438 | "$(inherited)", 439 | "@executable_path/Frameworks", 440 | ); 441 | MARKETING_VERSION = 1.0; 442 | PRODUCT_BUNDLE_IDENTIFIER = "pl.elector.FlowCoordinators-iOS16"; 443 | PRODUCT_NAME = "$(TARGET_NAME)"; 444 | SWIFT_EMIT_LOC_STRINGS = YES; 445 | SWIFT_VERSION = 5.0; 446 | TARGETED_DEVICE_FAMILY = "1,2"; 447 | }; 448 | name = Debug; 449 | }; 450 | 84D3E01E291E91D90024F9A3 /* Release */ = { 451 | isa = XCBuildConfiguration; 452 | buildSettings = { 453 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 454 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 455 | CODE_SIGN_STYLE = Automatic; 456 | CURRENT_PROJECT_VERSION = 1; 457 | DEVELOPMENT_ASSET_PATHS = "\"FlowCoordinators-iOS16/Preview Content\""; 458 | ENABLE_PREVIEWS = YES; 459 | GENERATE_INFOPLIST_FILE = YES; 460 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 461 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 462 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 463 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 464 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 465 | LD_RUNPATH_SEARCH_PATHS = ( 466 | "$(inherited)", 467 | "@executable_path/Frameworks", 468 | ); 469 | MARKETING_VERSION = 1.0; 470 | PRODUCT_BUNDLE_IDENTIFIER = "pl.elector.FlowCoordinators-iOS16"; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | SWIFT_EMIT_LOC_STRINGS = YES; 473 | SWIFT_VERSION = 5.0; 474 | TARGETED_DEVICE_FAMILY = "1,2"; 475 | }; 476 | name = Release; 477 | }; 478 | /* End XCBuildConfiguration section */ 479 | 480 | /* Begin XCConfigurationList section */ 481 | 84D3E009291E91C00024F9A3 /* Build configuration list for PBXProject "FlowCoordinators-iOS16" */ = { 482 | isa = XCConfigurationList; 483 | buildConfigurations = ( 484 | 84D3E01A291E91D90024F9A3 /* Debug */, 485 | 84D3E01B291E91D90024F9A3 /* Release */, 486 | ); 487 | defaultConfigurationIsVisible = 0; 488 | defaultConfigurationName = Release; 489 | }; 490 | 84D3E01C291E91D90024F9A3 /* Build configuration list for PBXNativeTarget "FlowCoordinators-iOS16" */ = { 491 | isa = XCConfigurationList; 492 | buildConfigurations = ( 493 | 84D3E01D291E91D90024F9A3 /* Debug */, 494 | 84D3E01E291E91D90024F9A3 /* Release */, 495 | ); 496 | defaultConfigurationIsVisible = 0; 497 | defaultConfigurationName = Release; 498 | }; 499 | /* End XCConfigurationList section */ 500 | }; 501 | rootObject = 84D3E006291E91C00024F9A3 /* Project object */; 502 | } 503 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/project.xcworkspace/xcuserdata/michzio.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michzio/FlowCoordinators-SwiftUI-iOS16/cfc2c66f78d5bd1a1180a2cea39ad4a0bf146de6/FlowCoordinators-iOS16.xcodeproj/project.xcworkspace/xcuserdata/michzio.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/project.xcworkspace/xcuserdata/michzio.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | UseAppPreferences 7 | CustomBuildLocationType 8 | RelativeToDerivedData 9 | DerivedDataLocationStyle 10 | Default 11 | ShowSharedSchemesAutomaticallyEnabled 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/xcuserdata/michzio.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 21 | 22 | 23 | 25 | 37 | 38 | 39 | 41 | 53 | 54 | 55 | 57 | 69 | 70 | 71 | 73 | 85 | 86 | 100 | 101 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16.xcodeproj/xcuserdata/michzio.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FlowCoordinators-iOS16.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michzio/FlowCoordinators-SwiftUI-iOS16/cfc2c66f78d5bd1a1180a2cea39ad4a0bf146de6/FlowCoordinators-iOS16/.DS_Store -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/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 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/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 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Extensions/NavigationLink.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | public extension NavigationLink { 4 | init( 5 | destination: @escaping (T) -> ItemDestination, 6 | item: Binding, 7 | label: () -> Label 8 | ) where Destination == AnyView { 9 | let isActive = Binding( 10 | get: { 11 | item.wrappedValue != nil 12 | }, 13 | set: { active in 14 | guard !active else { return } 15 | item.wrappedValue = nil 16 | } 17 | ) 18 | 19 | let itemDestination = { 20 | AnyView(Unwrap(item.wrappedValue, content: destination)) 21 | } 22 | 23 | self.init(isActive: isActive, destination: itemDestination, label: label) 24 | } 25 | } 26 | 27 | public struct Unwrap: View { 28 | private let t: T? 29 | private let content: (T) -> V 30 | 31 | public init(_ t: T?, @ViewBuilder content: @escaping (T) -> V) { 32 | self.t = t 33 | self.content = content 34 | } 35 | 36 | public var body: some View { 37 | if let t = t { 38 | content(t) 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/FlowCoordinatorsApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct FlowCoordinators: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | ContentView(viewModel: ContentViewModel()) 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michzio/FlowCoordinators-SwiftUI-iOS16/cfc2c66f78d5bd1a1180a2cea39ad4a0bf146de6/FlowCoordinators-iOS16/Views/.DS_Store -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Content/ContentFlowCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | open class ContentFlowState: ObservableObject { 4 | @Published var path = NavigationPath() 5 | @Published var presentedItem: ContentLink? 6 | @Published var coverItem: ContentLink? 7 | @Published var selectedLink: ContentLink? // old style 8 | } 9 | 10 | struct ContentFlowCoordinator: View { 11 | 12 | @ObservedObject var state: ContentFlowState 13 | let content: () -> Content 14 | 15 | var body: some View { 16 | NavigationStack(path: $state.path) { 17 | ZStack { 18 | content() 19 | .sheet(item: $state.presentedItem, content: sheetContent) 20 | .fullScreenCover(item: $state.coverItem, content: coverContent) 21 | 22 | navigationLinks 23 | } 24 | .navigationDestination(for: ContentLink.self, destination: linkDestination) 25 | .navigationDestination(for: String.self, destination: customDestination) 26 | } 27 | } 28 | 29 | private var navigationLinks: some View { 30 | /// to make this link work you need to replace NavigationStack with NavigationView! 31 | NavigationLink(destination: linkDestination, item: $state.selectedLink) { EmptyView() } 32 | } 33 | 34 | @ViewBuilder private func linkDestination(link: ContentLink) -> some View { 35 | switch link { 36 | case let .firstLink(text): 37 | firstDestination(text) 38 | case let .secondLink(number): 39 | secondDestination(number) 40 | case .thirdLink: 41 | thirdDestination() 42 | default: 43 | EmptyView() 44 | } 45 | } 46 | 47 | @ViewBuilder private func sheetContent(item: ContentLink) -> some View { 48 | switch item { 49 | case let .sheetLink(text): 50 | SheetView(viewModel: SheetViewModel(text: text)) 51 | default: 52 | EmptyView() 53 | } 54 | } 55 | 56 | @ViewBuilder private func coverContent(item: ContentLink) -> some View { 57 | switch item { 58 | case let .coverLink(text): 59 | CoverView(viewModel: CoverViewModel(text: text)) 60 | default: 61 | EmptyView() 62 | } 63 | } 64 | 65 | private func customDestination(text: String) -> some View { 66 | Text(text) 67 | } 68 | 69 | private func firstDestination(_ text: String?) -> some View { 70 | let viewModel = FirstViewModel(path: $state.path, text: text) 71 | let view = FirstView(viewModel: viewModel) 72 | return view 73 | } 74 | 75 | private func secondDestination(_ number: Int?) -> some View { 76 | let viewModel = SecondViewModel(path: $state.path, number: number) 77 | let view = SecondView(viewModel: viewModel) 78 | return view 79 | } 80 | 81 | private func thirdDestination() -> some View { 82 | let viewModel = ThirdViewModel(path: $state.path) 83 | let view = ThirdView(viewModel: viewModel) 84 | return view 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Content/ContentLink.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum ContentLink: Hashable, Identifiable { 4 | case firstLink(text: String?) 5 | case secondLink(number: Int?) 6 | case thirdLink 7 | case sheetLink(item: String) 8 | case coverLink(item: String) 9 | 10 | var id: String { 11 | String(describing: self) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Content/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ContentView: View { 4 | 5 | @StateObject var viewModel: ContentViewModel 6 | 7 | var body: some View { 8 | ContentFlowCoordinator(state: viewModel, content: content) 9 | } 10 | 11 | @ViewBuilder private func content() -> some View { 12 | ZStack { 13 | Color.white.ignoresSafeArea() 14 | 15 | VStack { 16 | Text(viewModel.text) 17 | 18 | Text("Buttons") 19 | 20 | Group { 21 | Button("First view >", action: viewModel.firstAction) 22 | Button("Second view >", action: viewModel.secondAction) 23 | Button("Third view >", action: viewModel.thirdAction) 24 | Button("Custom view >", action: viewModel.customAction) 25 | 26 | Button("Select link (old) >", action: viewModel.selectLinkAction) 27 | 28 | Text("Presentation") 29 | Button("Sheet view", action: viewModel.sheetAction) 30 | Button("Cover view", action: viewModel.coverAction) 31 | } 32 | 33 | 34 | Text("Links") 35 | 36 | NavigationLink(value: ContentLink.firstLink(text: "Link param")) { 37 | Text("First link >") 38 | } 39 | NavigationLink(value: ContentLink.secondLink(number: 200)) { 40 | Text("Second link >") 41 | } 42 | 43 | NavigationLink(value: ContentLink.thirdLink) { 44 | Text("Third link >") 45 | } 46 | 47 | NavigationLink(value: "Custom link") { 48 | Text("Custom link >") 49 | } 50 | } 51 | } 52 | .navigationBarTitle("Title", displayMode: .inline) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Content/ContentViewModel.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | final class ContentViewModel: ContentFlowState { 4 | 5 | let text: String = "Content View" 6 | 7 | func firstAction() { 8 | path.append(ContentLink.firstLink(text: "Some param")) 9 | } 10 | 11 | func secondAction() { 12 | path.append(ContentLink.secondLink(number: 2)) 13 | } 14 | 15 | func thirdAction() { 16 | path.append(ContentLink.thirdLink) 17 | } 18 | 19 | func customAction() { 20 | path.append("Custom action") 21 | } 22 | 23 | func sheetAction() { 24 | presentedItem = .sheetLink(item: "Sheet param") 25 | } 26 | 27 | func selectLinkAction() { 28 | selectedLink = .firstLink(text: "Selected link action") 29 | } 30 | 31 | func coverAction() { 32 | coverItem = .coverLink(item: "Cover param") 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Cover/CoverFlowCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | open class CoverFlowState: ObservableObject { 4 | @Published var coverPath = NavigationPath() 5 | @Published var presentedItem: CoverLink? 6 | } 7 | 8 | struct CoverFlowCoordinator: View { 9 | 10 | @ObservedObject var state: CoverFlowState 11 | let content: () -> Content 12 | 13 | var body: some View { 14 | NavigationStack(path: $state.coverPath) { 15 | content() 16 | .sheet(item: $state.presentedItem, content: sheetContent) 17 | .navigationDestination(for: CoverLink.self, destination: linkDestination) 18 | } 19 | } 20 | 21 | @ViewBuilder private func linkDestination(link: CoverLink) -> some View { 22 | EmptyView() 23 | } 24 | 25 | @ViewBuilder private func sheetContent(item: CoverLink) -> some View { 26 | EmptyView() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Cover/CoverLink.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum CoverLink: Hashable, Identifiable { 4 | case link 5 | 6 | var id: String { 7 | String(describing: self) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Cover/CoverView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct CoverView: View { 4 | 5 | @Environment(\.dismiss) private var dismiss 6 | 7 | @StateObject var viewModel: CoverViewModel 8 | 9 | var body: some View { 10 | CoverFlowCoordinator(state: viewModel, content: content) 11 | } 12 | 13 | @ViewBuilder private func content() -> some View { 14 | ZStack { 15 | Color.yellow.ignoresSafeArea() 16 | VStack { 17 | Text(viewModel.text) 18 | 19 | Button("Close", action: { dismiss() }) 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Cover/CoverViewModel.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | final class CoverViewModel: CoverFlowState { 4 | 5 | let text: String 6 | 7 | init(text: String) { 8 | self.text = "Cover view with \(text)" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/First/FirstFlowCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | open class FirstFlowState: ObservableObject { 4 | 5 | @Published var presentedItem: FirstLink? 6 | 7 | @Binding var path: NavigationPath 8 | 9 | init(path: Binding) { 10 | _path = path 11 | } 12 | } 13 | 14 | struct FirstFlowCoordinator: View { 15 | 16 | @ObservedObject var state: FirstFlowState 17 | let content: () -> Content 18 | 19 | var body: some View { 20 | content() 21 | .sheet(item: $state.presentedItem, content: sheetContent) 22 | .navigationDestination(for: FirstLink.self, destination: linkDestination) 23 | } 24 | 25 | @ViewBuilder private func linkDestination(link: FirstLink) -> some View { 26 | EmptyView() 27 | } 28 | 29 | @ViewBuilder private func sheetContent(item: FirstLink) -> some View { 30 | EmptyView() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/First/FirstLink.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum FirstLink: Hashable, Identifiable { 4 | case link 5 | 6 | var id: String { 7 | String(describing: self) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/First/FirstView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct FirstView: View { 4 | 5 | @StateObject var viewModel: FirstViewModel 6 | 7 | var body: some View { 8 | FirstFlowCoordinator(state: viewModel, content: content) 9 | } 10 | 11 | @ViewBuilder private func content() -> some View { 12 | ZStack { 13 | Color.red.ignoresSafeArea() 14 | Text(viewModel.text) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/First/FirstViewModel.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | final class FirstViewModel: FirstFlowState { 4 | 5 | @Published var text: String 6 | 7 | init(path: Binding, text: String?) { 8 | if let text = text { 9 | self.text = "First View with text: \(text)" 10 | } else { 11 | self.text = "Default First View" 12 | } 13 | 14 | super.init(path: path) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Second/SecondFlowCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | open class SecondFlowState: ObservableObject { 4 | @Published var presentedItem: SecondLink? 5 | 6 | @Binding var path: NavigationPath 7 | 8 | init(path: Binding) { 9 | _path = path 10 | } 11 | } 12 | 13 | struct SecondFlowCoordinator: View { 14 | 15 | @ObservedObject var state: SecondFlowState 16 | let content: () -> Content 17 | 18 | var body: some View { 19 | content() 20 | .sheet(item: $state.presentedItem, content: sheetContent) 21 | .navigationDestination(for: SecondLink.self, destination: linkDestination) 22 | } 23 | 24 | @ViewBuilder private func linkDestination(link: SecondLink) -> some View { 25 | switch link { 26 | case .link: 27 | thirdView() 28 | } 29 | } 30 | 31 | @ViewBuilder private func sheetContent(item: SecondLink) -> some View { 32 | EmptyView() 33 | } 34 | 35 | private func thirdView() -> some View { 36 | let viewModel = ThirdViewModel(path: $state.path) 37 | return ThirdView(viewModel: viewModel) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Second/SecondLink.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum SecondLink: Hashable, Identifiable { 4 | case link 5 | 6 | var id: String { 7 | String(describing: self) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Second/SecondView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct SecondView: View { 4 | 5 | @StateObject var viewModel: SecondViewModel 6 | 7 | var body: some View { 8 | SecondFlowCoordinator(state: viewModel, content: content) 9 | } 10 | 11 | @ViewBuilder private func content() -> some View { 12 | ZStack { 13 | Color.green.ignoresSafeArea() 14 | VStack { 15 | Text(viewModel.text) 16 | 17 | Button("Next screen button") { 18 | viewModel.nextLink() 19 | } 20 | 21 | NavigationLink("Next screen link", value: SecondLink.link) 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Second/SecondViewModel.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | final class SecondViewModel: SecondFlowState { 4 | 5 | @Published var text: String 6 | 7 | init(path: Binding, number: Int?) { 8 | if let number = number { 9 | self.text = "Second View with number: \(number)" 10 | } else { 11 | self.text = "Default Second View" 12 | } 13 | 14 | super.init(path: path) 15 | } 16 | 17 | func nextLink() { 18 | path.append(SecondLink.link) 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Sheet/SheetFlowCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | open class SheetFlowState: ObservableObject { 4 | @Published var sheetPath = NavigationPath() 5 | @Published var presentedItem: SheetLink? 6 | } 7 | 8 | struct SheetFlowCoordinator: View { 9 | 10 | @ObservedObject var state: SheetFlowState 11 | let content: () -> Content 12 | 13 | var body: some View { 14 | NavigationStack(path: $state.sheetPath) { 15 | content() 16 | .sheet(item: $state.presentedItem, content: sheetContent) 17 | .navigationDestination(for: SheetLink.self, destination: linkDestination) 18 | } 19 | } 20 | 21 | @ViewBuilder private func linkDestination(link: SheetLink) -> some View { 22 | EmptyView() 23 | } 24 | 25 | @ViewBuilder private func sheetContent(item: SheetLink) -> some View { 26 | EmptyView() 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Sheet/SheetLink.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum SheetLink: Hashable, Identifiable { 4 | case link 5 | 6 | var id: String { 7 | String(describing: self) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Sheet/SheetView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct SheetView: View { 4 | 5 | @StateObject var viewModel: SheetViewModel 6 | 7 | var body: some View { 8 | SheetFlowCoordinator(state: viewModel, content: content) 9 | } 10 | 11 | @ViewBuilder private func content() -> some View { 12 | ZStack { 13 | Color.yellow.ignoresSafeArea() 14 | Text(viewModel.text) 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Sheet/SheetViewModel.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | final class SheetViewModel: SheetFlowState { 4 | 5 | let text: String 6 | 7 | init(text: String) { 8 | self.text = "Sheet view with \(text)" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Third/ThirdFlowCoordinator.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | open class ThridFlowState: ObservableObject { 4 | 5 | @Published var presentedItem: ThirdLink? 6 | 7 | @Binding var path: NavigationPath 8 | 9 | init(path: Binding) { 10 | _path = path 11 | } 12 | } 13 | 14 | struct ThirdFlowCoordinator: View { 15 | 16 | @ObservedObject var state: ThridFlowState 17 | let content: () -> Content 18 | 19 | var body: some View { 20 | content() 21 | .sheet(item: $state.presentedItem, content: sheetContent) 22 | .navigationDestination(for: ThirdLink.self, destination: linkDestination) 23 | } 24 | 25 | @ViewBuilder private func linkDestination(link: ThirdLink) -> some View { 26 | EmptyView() 27 | } 28 | 29 | @ViewBuilder private func sheetContent(item: ThirdLink) -> some View { 30 | EmptyView() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Third/ThirdLink.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | enum ThirdLink: Hashable, Identifiable { 4 | case link 5 | 6 | var id: String { 7 | String(describing: self) 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Third/ThirdView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | struct ThirdView: View { 4 | 5 | @StateObject var viewModel: ThirdViewModel 6 | 7 | var body: some View { 8 | ThirdFlowCoordinator(state: viewModel, content: content) 9 | } 10 | 11 | @ViewBuilder private func content() -> some View { 12 | ZStack { 13 | Color.mint.ignoresSafeArea() 14 | VStack { 15 | Text(viewModel.text) 16 | 17 | Button("Pop to root view") { 18 | viewModel.popToRootAction() 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /FlowCoordinators-iOS16/Views/Third/ThirdViewModel.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | final class ThirdViewModel: ThridFlowState { 4 | 5 | let text = "Default Third View" 6 | 7 | func popToRootAction() { 8 | path = .init() 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FlowCoordinators-SwiftUI-iOS16 2 | 3 | Project demonstrates how to add Coordinator to separate navigation from view content 4 | 5 | ![image info](./navigation-image.gif) 6 | -------------------------------------------------------------------------------- /navigation-image.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/michzio/FlowCoordinators-SwiftUI-iOS16/cfc2c66f78d5bd1a1180a2cea39ad4a0bf146de6/navigation-image.gif --------------------------------------------------------------------------------