├── README.md ├── SwiftUI-Mac-11.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcuserdata │ └── sarah.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── SwiftUI-Mac-11 ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ ├── Contents.json │ │ ├── icon_128.png │ │ ├── icon_128@2x.png │ │ ├── icon_16.png │ │ ├── icon_16@2x.png │ │ ├── icon_256.png │ │ ├── icon_256@2x.png │ │ ├── icon_32.png │ │ ├── icon_32@2x.png │ │ ├── icon_512.png │ │ └── icon_512@2x.png │ └── Contents.json ├── Data │ ├── Helper.swift │ ├── HttpStatus.swift │ └── httpcodes.json ├── Info.plist ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── SwiftUI_Mac_11.entitlements ├── SwiftUI_Mac_11App.swift └── Views │ ├── ContentView.swift │ ├── DetailView.swift │ ├── DialogsView.swift │ ├── FormSamplesView.swift │ ├── PickerSamplesView.swift │ ├── SamplesView.swift │ ├── SettingsView.swift │ └── SwitchSamplesView.swift └── assets └── swiftui-mac-11-toolbar.png /README.md: -------------------------------------------------------------------------------- 1 | # SwiftUI for Mac Big Sur 2 | 3 | An Xcode project for use with https://troz.net/post/2020/swiftui_mac_big_sur/ 4 | 5 | Demonstrating using SwiftUI to create a Mac app on macOS 11 Big Sur with Xcode 12. 6 | 7 | ![App UI](assets/swiftui-mac-11-toolbar.png) 8 | 9 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2611466424AF2F4000C5CFFF /* DialogsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2611466324AF2F4000C5CFFF /* DialogsView.swift */; }; 11 | 265E6C5F24AF275B00FDC676 /* SamplesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265E6C5E24AF275B00FDC676 /* SamplesView.swift */; }; 12 | 265E6C6324AF2B7A00FDC676 /* PickerSamplesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265E6C6024AF2B7A00FDC676 /* PickerSamplesView.swift */; }; 13 | 265E6C6424AF2B7A00FDC676 /* SwitchSamplesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265E6C6124AF2B7A00FDC676 /* SwitchSamplesView.swift */; }; 14 | 265E6C6524AF2B7A00FDC676 /* FormSamplesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 265E6C6224AF2B7A00FDC676 /* FormSamplesView.swift */; }; 15 | 26ADC44624AEEC550042ED8A /* SwiftUI_Mac_11App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26ADC44524AEEC550042ED8A /* SwiftUI_Mac_11App.swift */; }; 16 | 26ADC44824AEEC550042ED8A /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26ADC44724AEEC550042ED8A /* ContentView.swift */; }; 17 | 26ADC44A24AEEC560042ED8A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 26ADC44924AEEC560042ED8A /* Assets.xcassets */; }; 18 | 26ADC44D24AEEC560042ED8A /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 26ADC44C24AEEC560042ED8A /* Preview Assets.xcassets */; }; 19 | 26D1053E24AEF8F300897038 /* httpcodes.json in Resources */ = {isa = PBXBuildFile; fileRef = 26D1053B24AEF8F300897038 /* httpcodes.json */; }; 20 | 26D1053F24AEF8F300897038 /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D1053C24AEF8F300897038 /* Helper.swift */; }; 21 | 26D1054024AEF8F300897038 /* HttpStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D1053D24AEF8F300897038 /* HttpStatus.swift */; }; 22 | 26D1054224AEF93200897038 /* DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D1054124AEF93200897038 /* DetailView.swift */; }; 23 | 26D1054624AF028F00897038 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26D1054524AF028F00897038 /* SettingsView.swift */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | 2611466324AF2F4000C5CFFF /* DialogsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DialogsView.swift; sourceTree = ""; }; 28 | 265E6C5E24AF275B00FDC676 /* SamplesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SamplesView.swift; sourceTree = ""; }; 29 | 265E6C6024AF2B7A00FDC676 /* PickerSamplesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PickerSamplesView.swift; sourceTree = ""; }; 30 | 265E6C6124AF2B7A00FDC676 /* SwitchSamplesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwitchSamplesView.swift; sourceTree = ""; }; 31 | 265E6C6224AF2B7A00FDC676 /* FormSamplesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSamplesView.swift; sourceTree = ""; }; 32 | 26ADC44224AEEC550042ED8A /* SwiftUI-Mac-11.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SwiftUI-Mac-11.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | 26ADC44524AEEC550042ED8A /* SwiftUI_Mac_11App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUI_Mac_11App.swift; sourceTree = ""; }; 34 | 26ADC44724AEEC550042ED8A /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 35 | 26ADC44924AEEC560042ED8A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 36 | 26ADC44C24AEEC560042ED8A /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 37 | 26ADC44E24AEEC560042ED8A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 38 | 26ADC44F24AEEC560042ED8A /* SwiftUI_Mac_11.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftUI_Mac_11.entitlements; sourceTree = ""; }; 39 | 26D1053B24AEF8F300897038 /* httpcodes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = httpcodes.json; sourceTree = ""; }; 40 | 26D1053C24AEF8F300897038 /* Helper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = ""; }; 41 | 26D1053D24AEF8F300897038 /* HttpStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HttpStatus.swift; sourceTree = ""; }; 42 | 26D1054124AEF93200897038 /* DetailView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailView.swift; sourceTree = ""; }; 43 | 26D1054524AF028F00897038 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = ""; }; 44 | /* End PBXFileReference section */ 45 | 46 | /* Begin PBXFrameworksBuildPhase section */ 47 | 26ADC43F24AEEC550042ED8A /* Frameworks */ = { 48 | isa = PBXFrameworksBuildPhase; 49 | buildActionMask = 2147483647; 50 | files = ( 51 | ); 52 | runOnlyForDeploymentPostprocessing = 0; 53 | }; 54 | /* End PBXFrameworksBuildPhase section */ 55 | 56 | /* Begin PBXGroup section */ 57 | 26ADC43924AEEC550042ED8A = { 58 | isa = PBXGroup; 59 | children = ( 60 | 26ADC44424AEEC550042ED8A /* SwiftUI-Mac-11 */, 61 | 26ADC44324AEEC550042ED8A /* Products */, 62 | ); 63 | sourceTree = ""; 64 | }; 65 | 26ADC44324AEEC550042ED8A /* Products */ = { 66 | isa = PBXGroup; 67 | children = ( 68 | 26ADC44224AEEC550042ED8A /* SwiftUI-Mac-11.app */, 69 | ); 70 | name = Products; 71 | sourceTree = ""; 72 | }; 73 | 26ADC44424AEEC550042ED8A /* SwiftUI-Mac-11 */ = { 74 | isa = PBXGroup; 75 | children = ( 76 | 26ADC44524AEEC550042ED8A /* SwiftUI_Mac_11App.swift */, 77 | 26D1054424AEFADC00897038 /* Views */, 78 | 26D1054324AEFAD400897038 /* Data */, 79 | 26ADC44924AEEC560042ED8A /* Assets.xcassets */, 80 | 26ADC44E24AEEC560042ED8A /* Info.plist */, 81 | 26ADC44F24AEEC560042ED8A /* SwiftUI_Mac_11.entitlements */, 82 | 26ADC44B24AEEC560042ED8A /* Preview Content */, 83 | ); 84 | path = "SwiftUI-Mac-11"; 85 | sourceTree = ""; 86 | }; 87 | 26ADC44B24AEEC560042ED8A /* Preview Content */ = { 88 | isa = PBXGroup; 89 | children = ( 90 | 26ADC44C24AEEC560042ED8A /* Preview Assets.xcassets */, 91 | ); 92 | path = "Preview Content"; 93 | sourceTree = ""; 94 | }; 95 | 26D1054324AEFAD400897038 /* Data */ = { 96 | isa = PBXGroup; 97 | children = ( 98 | 26D1053B24AEF8F300897038 /* httpcodes.json */, 99 | 26D1053D24AEF8F300897038 /* HttpStatus.swift */, 100 | 26D1053C24AEF8F300897038 /* Helper.swift */, 101 | ); 102 | path = Data; 103 | sourceTree = ""; 104 | }; 105 | 26D1054424AEFADC00897038 /* Views */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 26ADC44724AEEC550042ED8A /* ContentView.swift */, 109 | 26D1054124AEF93200897038 /* DetailView.swift */, 110 | 26D1054524AF028F00897038 /* SettingsView.swift */, 111 | 265E6C5E24AF275B00FDC676 /* SamplesView.swift */, 112 | 265E6C6024AF2B7A00FDC676 /* PickerSamplesView.swift */, 113 | 265E6C6124AF2B7A00FDC676 /* SwitchSamplesView.swift */, 114 | 265E6C6224AF2B7A00FDC676 /* FormSamplesView.swift */, 115 | 2611466324AF2F4000C5CFFF /* DialogsView.swift */, 116 | ); 117 | path = Views; 118 | sourceTree = ""; 119 | }; 120 | /* End PBXGroup section */ 121 | 122 | /* Begin PBXNativeTarget section */ 123 | 26ADC44124AEEC550042ED8A /* SwiftUI-Mac-11 */ = { 124 | isa = PBXNativeTarget; 125 | buildConfigurationList = 26ADC45224AEEC560042ED8A /* Build configuration list for PBXNativeTarget "SwiftUI-Mac-11" */; 126 | buildPhases = ( 127 | 26ADC43E24AEEC550042ED8A /* Sources */, 128 | 26ADC43F24AEEC550042ED8A /* Frameworks */, 129 | 26ADC44024AEEC550042ED8A /* Resources */, 130 | ); 131 | buildRules = ( 132 | ); 133 | dependencies = ( 134 | ); 135 | name = "SwiftUI-Mac-11"; 136 | productName = "SwiftUI-Mac-11"; 137 | productReference = 26ADC44224AEEC550042ED8A /* SwiftUI-Mac-11.app */; 138 | productType = "com.apple.product-type.application"; 139 | }; 140 | /* End PBXNativeTarget section */ 141 | 142 | /* Begin PBXProject section */ 143 | 26ADC43A24AEEC550042ED8A /* Project object */ = { 144 | isa = PBXProject; 145 | attributes = { 146 | LastSwiftUpdateCheck = 1200; 147 | LastUpgradeCheck = 1200; 148 | TargetAttributes = { 149 | 26ADC44124AEEC550042ED8A = { 150 | CreatedOnToolsVersion = 12.0; 151 | }; 152 | }; 153 | }; 154 | buildConfigurationList = 26ADC43D24AEEC550042ED8A /* Build configuration list for PBXProject "SwiftUI-Mac-11" */; 155 | compatibilityVersion = "Xcode 9.3"; 156 | developmentRegion = en; 157 | hasScannedForEncodings = 0; 158 | knownRegions = ( 159 | en, 160 | Base, 161 | ); 162 | mainGroup = 26ADC43924AEEC550042ED8A; 163 | productRefGroup = 26ADC44324AEEC550042ED8A /* Products */; 164 | projectDirPath = ""; 165 | projectRoot = ""; 166 | targets = ( 167 | 26ADC44124AEEC550042ED8A /* SwiftUI-Mac-11 */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXResourcesBuildPhase section */ 173 | 26ADC44024AEEC550042ED8A /* Resources */ = { 174 | isa = PBXResourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | 26ADC44D24AEEC560042ED8A /* Preview Assets.xcassets in Resources */, 178 | 26D1053E24AEF8F300897038 /* httpcodes.json in Resources */, 179 | 26ADC44A24AEEC560042ED8A /* Assets.xcassets in Resources */, 180 | ); 181 | runOnlyForDeploymentPostprocessing = 0; 182 | }; 183 | /* End PBXResourcesBuildPhase section */ 184 | 185 | /* Begin PBXSourcesBuildPhase section */ 186 | 26ADC43E24AEEC550042ED8A /* Sources */ = { 187 | isa = PBXSourcesBuildPhase; 188 | buildActionMask = 2147483647; 189 | files = ( 190 | 265E6C6524AF2B7A00FDC676 /* FormSamplesView.swift in Sources */, 191 | 265E6C6324AF2B7A00FDC676 /* PickerSamplesView.swift in Sources */, 192 | 265E6C5F24AF275B00FDC676 /* SamplesView.swift in Sources */, 193 | 26D1054624AF028F00897038 /* SettingsView.swift in Sources */, 194 | 26ADC44824AEEC550042ED8A /* ContentView.swift in Sources */, 195 | 2611466424AF2F4000C5CFFF /* DialogsView.swift in Sources */, 196 | 265E6C6424AF2B7A00FDC676 /* SwitchSamplesView.swift in Sources */, 197 | 26ADC44624AEEC550042ED8A /* SwiftUI_Mac_11App.swift in Sources */, 198 | 26D1053F24AEF8F300897038 /* Helper.swift in Sources */, 199 | 26D1054224AEF93200897038 /* DetailView.swift in Sources */, 200 | 26D1054024AEF8F300897038 /* HttpStatus.swift in Sources */, 201 | ); 202 | runOnlyForDeploymentPostprocessing = 0; 203 | }; 204 | /* End PBXSourcesBuildPhase section */ 205 | 206 | /* Begin XCBuildConfiguration section */ 207 | 26ADC45024AEEC560042ED8A /* Debug */ = { 208 | isa = XCBuildConfiguration; 209 | buildSettings = { 210 | ALWAYS_SEARCH_USER_PATHS = NO; 211 | CLANG_ANALYZER_NONNULL = YES; 212 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 213 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 214 | CLANG_CXX_LIBRARY = "libc++"; 215 | CLANG_ENABLE_MODULES = YES; 216 | CLANG_ENABLE_OBJC_ARC = YES; 217 | CLANG_ENABLE_OBJC_WEAK = YES; 218 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 219 | CLANG_WARN_BOOL_CONVERSION = YES; 220 | CLANG_WARN_COMMA = YES; 221 | CLANG_WARN_CONSTANT_CONVERSION = YES; 222 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 223 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 224 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 225 | CLANG_WARN_EMPTY_BODY = YES; 226 | CLANG_WARN_ENUM_CONVERSION = YES; 227 | CLANG_WARN_INFINITE_RECURSION = YES; 228 | CLANG_WARN_INT_CONVERSION = YES; 229 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 230 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 231 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 232 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 233 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 234 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 235 | CLANG_WARN_STRICT_PROTOTYPES = YES; 236 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 237 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 238 | CLANG_WARN_UNREACHABLE_CODE = YES; 239 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 240 | COPY_PHASE_STRIP = NO; 241 | DEBUG_INFORMATION_FORMAT = dwarf; 242 | ENABLE_STRICT_OBJC_MSGSEND = YES; 243 | ENABLE_TESTABILITY = YES; 244 | GCC_C_LANGUAGE_STANDARD = gnu11; 245 | GCC_DYNAMIC_NO_PIC = NO; 246 | GCC_NO_COMMON_BLOCKS = YES; 247 | GCC_OPTIMIZATION_LEVEL = 0; 248 | GCC_PREPROCESSOR_DEFINITIONS = ( 249 | "DEBUG=1", 250 | "$(inherited)", 251 | ); 252 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 253 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 254 | GCC_WARN_UNDECLARED_SELECTOR = YES; 255 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 256 | GCC_WARN_UNUSED_FUNCTION = YES; 257 | GCC_WARN_UNUSED_VARIABLE = YES; 258 | MACOSX_DEPLOYMENT_TARGET = 11.0; 259 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 260 | MTL_FAST_MATH = YES; 261 | ONLY_ACTIVE_ARCH = YES; 262 | SDKROOT = macosx; 263 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 264 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 265 | }; 266 | name = Debug; 267 | }; 268 | 26ADC45124AEEC560042ED8A /* Release */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ALWAYS_SEARCH_USER_PATHS = NO; 272 | CLANG_ANALYZER_NONNULL = YES; 273 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 274 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 275 | CLANG_CXX_LIBRARY = "libc++"; 276 | CLANG_ENABLE_MODULES = YES; 277 | CLANG_ENABLE_OBJC_ARC = YES; 278 | CLANG_ENABLE_OBJC_WEAK = YES; 279 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 280 | CLANG_WARN_BOOL_CONVERSION = YES; 281 | CLANG_WARN_COMMA = YES; 282 | CLANG_WARN_CONSTANT_CONVERSION = YES; 283 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 284 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 285 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 286 | CLANG_WARN_EMPTY_BODY = YES; 287 | CLANG_WARN_ENUM_CONVERSION = YES; 288 | CLANG_WARN_INFINITE_RECURSION = YES; 289 | CLANG_WARN_INT_CONVERSION = YES; 290 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 291 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 292 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 293 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 294 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 295 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 296 | CLANG_WARN_STRICT_PROTOTYPES = YES; 297 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 298 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 299 | CLANG_WARN_UNREACHABLE_CODE = YES; 300 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 301 | COPY_PHASE_STRIP = NO; 302 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 303 | ENABLE_NS_ASSERTIONS = NO; 304 | ENABLE_STRICT_OBJC_MSGSEND = YES; 305 | GCC_C_LANGUAGE_STANDARD = gnu11; 306 | GCC_NO_COMMON_BLOCKS = YES; 307 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 308 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 309 | GCC_WARN_UNDECLARED_SELECTOR = YES; 310 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 311 | GCC_WARN_UNUSED_FUNCTION = YES; 312 | GCC_WARN_UNUSED_VARIABLE = YES; 313 | MACOSX_DEPLOYMENT_TARGET = 11.0; 314 | MTL_ENABLE_DEBUG_INFO = NO; 315 | MTL_FAST_MATH = YES; 316 | SDKROOT = macosx; 317 | SWIFT_COMPILATION_MODE = wholemodule; 318 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 319 | }; 320 | name = Release; 321 | }; 322 | 26ADC45324AEEC560042ED8A /* Debug */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 326 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 327 | CODE_SIGN_ENTITLEMENTS = "SwiftUI-Mac-11/SwiftUI_Mac_11.entitlements"; 328 | CODE_SIGN_STYLE = Automatic; 329 | COMBINE_HIDPI_IMAGES = YES; 330 | DEVELOPMENT_ASSET_PATHS = "\"SwiftUI-Mac-11/Preview Content\""; 331 | DEVELOPMENT_TEAM = TC28MCLCFA; 332 | ENABLE_PREVIEWS = YES; 333 | INFOPLIST_FILE = "SwiftUI-Mac-11/Info.plist"; 334 | LD_RUNPATH_SEARCH_PATHS = ( 335 | "$(inherited)", 336 | "@executable_path/../Frameworks", 337 | ); 338 | MACOSX_DEPLOYMENT_TARGET = 11.0; 339 | PRODUCT_BUNDLE_IDENTIFIER = "net.troz.SwiftUI-Mac-11"; 340 | PRODUCT_NAME = "$(TARGET_NAME)"; 341 | SWIFT_VERSION = 5.0; 342 | }; 343 | name = Debug; 344 | }; 345 | 26ADC45424AEEC560042ED8A /* Release */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 349 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 350 | CODE_SIGN_ENTITLEMENTS = "SwiftUI-Mac-11/SwiftUI_Mac_11.entitlements"; 351 | CODE_SIGN_STYLE = Automatic; 352 | COMBINE_HIDPI_IMAGES = YES; 353 | DEVELOPMENT_ASSET_PATHS = "\"SwiftUI-Mac-11/Preview Content\""; 354 | DEVELOPMENT_TEAM = TC28MCLCFA; 355 | ENABLE_PREVIEWS = YES; 356 | INFOPLIST_FILE = "SwiftUI-Mac-11/Info.plist"; 357 | LD_RUNPATH_SEARCH_PATHS = ( 358 | "$(inherited)", 359 | "@executable_path/../Frameworks", 360 | ); 361 | MACOSX_DEPLOYMENT_TARGET = 11.0; 362 | PRODUCT_BUNDLE_IDENTIFIER = "net.troz.SwiftUI-Mac-11"; 363 | PRODUCT_NAME = "$(TARGET_NAME)"; 364 | SWIFT_VERSION = 5.0; 365 | }; 366 | name = Release; 367 | }; 368 | /* End XCBuildConfiguration section */ 369 | 370 | /* Begin XCConfigurationList section */ 371 | 26ADC43D24AEEC550042ED8A /* Build configuration list for PBXProject "SwiftUI-Mac-11" */ = { 372 | isa = XCConfigurationList; 373 | buildConfigurations = ( 374 | 26ADC45024AEEC560042ED8A /* Debug */, 375 | 26ADC45124AEEC560042ED8A /* Release */, 376 | ); 377 | defaultConfigurationIsVisible = 0; 378 | defaultConfigurationName = Release; 379 | }; 380 | 26ADC45224AEEC560042ED8A /* Build configuration list for PBXNativeTarget "SwiftUI-Mac-11" */ = { 381 | isa = XCConfigurationList; 382 | buildConfigurations = ( 383 | 26ADC45324AEEC560042ED8A /* Debug */, 384 | 26ADC45424AEEC560042ED8A /* Release */, 385 | ); 386 | defaultConfigurationIsVisible = 0; 387 | defaultConfigurationName = Release; 388 | }; 389 | /* End XCConfigurationList section */ 390 | }; 391 | rootObject = 26ADC43A24AEEC550042ED8A /* Project object */; 392 | } 393 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11.xcodeproj/xcuserdata/sarah.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11.xcodeproj/xcuserdata/sarah.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SwiftUI-Mac-11.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/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 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon_16.png", 5 | "idiom" : "mac", 6 | "scale" : "1x", 7 | "size" : "16x16" 8 | }, 9 | { 10 | "filename" : "icon_16@2x.png", 11 | "idiom" : "mac", 12 | "scale" : "2x", 13 | "size" : "16x16" 14 | }, 15 | { 16 | "filename" : "icon_32.png", 17 | "idiom" : "mac", 18 | "scale" : "1x", 19 | "size" : "32x32" 20 | }, 21 | { 22 | "filename" : "icon_32@2x.png", 23 | "idiom" : "mac", 24 | "scale" : "2x", 25 | "size" : "32x32" 26 | }, 27 | { 28 | "filename" : "icon_128.png", 29 | "idiom" : "mac", 30 | "scale" : "1x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "filename" : "icon_128@2x.png", 35 | "idiom" : "mac", 36 | "scale" : "2x", 37 | "size" : "128x128" 38 | }, 39 | { 40 | "filename" : "icon_256.png", 41 | "idiom" : "mac", 42 | "scale" : "1x", 43 | "size" : "256x256" 44 | }, 45 | { 46 | "filename" : "icon_256@2x.png", 47 | "idiom" : "mac", 48 | "scale" : "2x", 49 | "size" : "256x256" 50 | }, 51 | { 52 | "filename" : "icon_512.png", 53 | "idiom" : "mac", 54 | "scale" : "1x", 55 | "size" : "512x512" 56 | }, 57 | { 58 | "filename" : "icon_512@2x.png", 59 | "idiom" : "mac", 60 | "scale" : "2x", 61 | "size" : "512x512" 62 | } 63 | ], 64 | "info" : { 65 | "author" : "xcode", 66 | "version" : 1 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_128.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_128@2x.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_16.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_16@2x.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_256.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_256@2x.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_32.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_32@2x.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_512.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/SwiftUI-Mac-11/Assets.xcassets/AppIcon.appiconset/icon_512@2x.png -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Data/Helper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Helper.swift 3 | // A small collection of quick helpers to avoid repeating the same old code. 4 | // 5 | // Created by Paul Hudson on 23/06/2019. 6 | // Copyright © 2019 Hacking with Swift. All rights reserved. 7 | // 8 | 9 | import Cocoa 10 | 11 | extension Bundle { 12 | func decode(_ type: T.Type, from file: String) -> T { 13 | guard let url = self.url(forResource: file, withExtension: nil) else { 14 | fatalError("Failed to locate \(file) in bundle.") 15 | } 16 | 17 | guard let data = try? Data(contentsOf: url) else { 18 | fatalError("Failed to load \(file) from bundle.") 19 | } 20 | 21 | let decoder = JSONDecoder() 22 | 23 | guard let loaded = try? decoder.decode(T.self, from: data) else { 24 | fatalError("Failed to decode \(file) from bundle.") 25 | } 26 | 27 | return loaded 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Data/HttpStatus.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HttpStatus.swift 3 | // SwiftUI-Mac 4 | // 5 | // Created by Sarah Reichelt on 6/11/19. 6 | // Copyright © 2019 Sarah Reichelt. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct HttpStatus: Identifiable, Decodable { 12 | let id = UUID() 13 | let code: String 14 | let title: String 15 | 16 | var imageUrl: URL { 17 | let address = "https://http.cat/\(code).jpg" 18 | return URL(string: address)! 19 | } 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case code 23 | case title 24 | } 25 | } 26 | 27 | struct HttpSection: Identifiable, Decodable { 28 | let id = UUID() 29 | let headerCode: String 30 | let headerText: String 31 | let statuses: [HttpStatus] 32 | 33 | enum CodingKeys: String, CodingKey { 34 | case headerCode 35 | case headerText 36 | case statuses 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Data/httpcodes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "headerCode": "1xx", 4 | "headerText": "Informational", 5 | "statuses": [ 6 | { 7 | "code": "100", 8 | "title": "Continue" 9 | }, 10 | { 11 | "code": "101", 12 | "title": "Switching Protocols" 13 | } 14 | ] 15 | }, 16 | { 17 | "headerCode": "2xx", 18 | "headerText": "Success", 19 | "statuses": [ 20 | { 21 | "code": "200", 22 | "title": "OK" 23 | }, 24 | { 25 | "code": "201", 26 | "title": "Created" 27 | }, 28 | { 29 | "code": "202", 30 | "title": "Accepted" 31 | }, 32 | { 33 | "code": "204", 34 | "title": "No Content" 35 | }, 36 | { 37 | "code": "206", 38 | "title": "Partial Content" 39 | }, 40 | { 41 | "code": "207", 42 | "title": "Multi-Status" 43 | } 44 | ] 45 | }, 46 | { 47 | "headerCode": "3xx", 48 | "headerText": "Redirection", 49 | "statuses": [ 50 | { 51 | "code": "300", 52 | "title": "Multiple Choices" 53 | }, 54 | { 55 | "code": "301", 56 | "title": "Moved Permanently" 57 | }, 58 | { 59 | "code": "302", 60 | "title": "Found" 61 | }, 62 | { 63 | "code": "303", 64 | "title": "See Other" 65 | }, 66 | { 67 | "code": "304", 68 | "title": "Not Modified" 69 | }, 70 | { 71 | "code": "305", 72 | "title": "Use Proxy" 73 | }, 74 | { 75 | "code": "307", 76 | "title": "Temporary Redirect" 77 | } 78 | ] 79 | }, 80 | { 81 | "headerCode": "4xx", 82 | "headerText": "Client Error", 83 | "statuses": [ 84 | { 85 | "code": "400", 86 | "title": "Bad Request" 87 | }, 88 | { 89 | "code": "401", 90 | "title": "Unauthorized" 91 | }, 92 | { 93 | "code": "402", 94 | "title": "Payment Required" 95 | }, 96 | { 97 | "code": "403", 98 | "title": "Forbidden" 99 | }, 100 | { 101 | "code": "404", 102 | "title": "Not Found" 103 | }, 104 | { 105 | "code": "405", 106 | "title": "Method Not Allowed" 107 | }, 108 | { 109 | "code": "406", 110 | "title": "Not Acceptable" 111 | }, 112 | { 113 | "code": "408", 114 | "title": "Request Timeout" 115 | }, 116 | { 117 | "code": "409", 118 | "title": "Conflict" 119 | }, 120 | { 121 | "code": "410", 122 | "title": "Gone" 123 | }, 124 | { 125 | "code": "411", 126 | "title": "Length Required" 127 | }, 128 | { 129 | "code": "412", 130 | "title": "Precondition Failed" 131 | }, 132 | { 133 | "code": "413", 134 | "title": "Payload Too Large" 135 | }, 136 | { 137 | "code": "414", 138 | "title": "Request-URI Too Long" 139 | }, 140 | { 141 | "code": "415", 142 | "title": "Unsupported Media Type" 143 | }, 144 | { 145 | "code": "416", 146 | "title": "Requested Range Not Satisfiable" 147 | }, 148 | { 149 | "code": "417", 150 | "title": "Expectation Failed" 151 | }, 152 | { 153 | "code": "418", 154 | "title": "I'm a teapot" 155 | }, 156 | { 157 | "code": "421", 158 | "title": "Misdirected Request" 159 | }, 160 | { 161 | "code": "422", 162 | "title": "Unprocessable Entity" 163 | }, 164 | { 165 | "code": "423", 166 | "title": "Locked" 167 | }, 168 | { 169 | "code": "424", 170 | "title": "Failed Dependency" 171 | }, 172 | { 173 | "code": "425", 174 | "title": "Unordered Collection" 175 | }, 176 | { 177 | "code": "426", 178 | "title": "Upgrade Required" 179 | }, 180 | { 181 | "code": "429", 182 | "title": "Too Many Requests" 183 | }, 184 | { 185 | "code": "431", 186 | "title": "Request Header Fields Too Large" 187 | }, 188 | { 189 | "code": "444", 190 | "title": "Connection Closed Without Response" 191 | }, 192 | { 193 | "code": "451", 194 | "title": "Unavailable For Legal Reasons" 195 | } 196 | ] 197 | }, 198 | { 199 | "headerCode": "5xx", 200 | "headerText": "Server Error", 201 | "statuses": [ 202 | { 203 | "code": "500", 204 | "title": "Internal Server Error" 205 | }, 206 | { 207 | "code": "501", 208 | "title": "Not Implemented" 209 | }, 210 | { 211 | "code": "502", 212 | "title": "Bad Gateway" 213 | }, 214 | { 215 | "code": "503", 216 | "title": "Service Unavailable" 217 | }, 218 | { 219 | "code": "504", 220 | "title": "Gateway Timeout" 221 | }, 222 | { 223 | "code": "506", 224 | "title": "Variant Also Negotiates" 225 | }, 226 | { 227 | "code": "507", 228 | "title": "Insufficient Storage" 229 | }, 230 | { 231 | "code": "508", 232 | "title": "Loop Detected" 233 | }, 234 | { 235 | "code": "509", 236 | "title": "Bandwidth Limit Exceeded" 237 | }, 238 | { 239 | "code": "510", 240 | "title": "Not Extended" 241 | }, 242 | { 243 | "code": "511", 244 | "title": "Network Authentication Required" 245 | }, 246 | { 247 | "code": "599", 248 | "title": "Network Connect Timeout Error" 249 | } 250 | ] 251 | } 252 | ] 253 | 254 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSMinimumSystemVersion 22 | $(MACOSX_DEPLOYMENT_TARGET) 23 | 24 | 25 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/SwiftUI_Mac_11.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-write 8 | 9 | com.apple.security.network.client 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/SwiftUI_Mac_11App.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftUI_Mac_11App.swift 3 | // SwiftUI-Mac-11 4 | // 5 | // Created by Sarah Reichelt on 3/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | @main 11 | struct SwiftUI_Mac_11App: App { 12 | @AppStorage("appTheme") var appTheme: String = "system" 13 | 14 | @SceneBuilder var body: some Scene { 15 | WindowGroup { 16 | ContentView() 17 | } 18 | .commands { 19 | CommandGroup(after: .windowArrangement) { 20 | Button(action: { 21 | NSApp.appearance = NSAppearance(named: .darkAqua) 22 | appTheme = "dark" 23 | }) { 24 | Text("Dark mode").fontWeight(.medium) 25 | }.modifier(MenuButtonStyling()) 26 | 27 | Button(action: { 28 | NSApp.appearance = NSAppearance(named: .aqua) 29 | appTheme = "light" 30 | }) { 31 | Text("Light mode").fontWeight(.medium) 32 | }.modifier(MenuButtonStyling()) 33 | 34 | Button(action: { 35 | NSApp.appearance = nil 36 | appTheme = "system" 37 | }) { 38 | Text("System mode").fontWeight(.medium) 39 | }.modifier(MenuButtonStyling()) 40 | } 41 | 42 | CommandMenu("Utilities") { 43 | Button(action: { 44 | NotificationCenter.default.post(name: .flipImage, object: nil) 45 | }) { 46 | Text("Flip Image").fontWeight(.medium) 47 | }.modifier(MenuButtonStyling()) 48 | .keyboardShortcut("i") 49 | 50 | Button(action: { 51 | NotificationCenter.default.post(name: .showSamples, object: nil) 52 | }) { 53 | Text("Toggle UI Samples Window").fontWeight(.medium) 54 | }.modifier(MenuButtonStyling()) 55 | .keyboardShortcut("u") 56 | } 57 | } 58 | 59 | Settings { 60 | SettingsView() 61 | } 62 | } 63 | 64 | } 65 | 66 | extension Notification.Name { 67 | static let flipImage = Notification.Name("flip_image") 68 | static let saveImage = Notification.Name("save_image") 69 | static let showSamples = Notification.Name("show_samples") 70 | } 71 | 72 | struct MenuButtonStyling: ViewModifier { 73 | func body(content: Content) -> some View { 74 | content 75 | .foregroundColor(.primary) 76 | .padding(.bottom, 2) 77 | .padding(.top, 1) 78 | } 79 | } 80 | 81 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // SwiftUI-Mac-11 4 | // 5 | // Created by Sarah Reichelt on 3/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ContentView: View { 11 | @State private var httpSections: [HttpSection] = [] 12 | @State private var showSamplesSheet = false 13 | 14 | @AppStorage("appTheme") var appTheme: String = "system" 15 | 16 | private let openSamplesMenuItemSelected = NotificationCenter.default 17 | .publisher(for: .showSamples) 18 | .receive(on: RunLoop.main) 19 | 20 | var body: some View { 21 | NavigationView { 22 | List() { 23 | ForEach(httpSections) { section in 24 | NavigationLink(destination: StatusList(title: section.headerText, 25 | statuses: section.statuses)) { 26 | ListRowView(code: section.headerCode, title: section.headerText) 27 | } 28 | } 29 | } 30 | .listStyle(InsetListStyle()) 31 | .frame(minWidth: 150, idealWidth: 150, maxWidth: 250, 32 | minHeight: 400, maxHeight: .infinity) 33 | 34 | StatusList(title: "", statuses: []) 35 | } 36 | .sheet(isPresented: $showSamplesSheet) { 37 | SamplesView(isVisible: $showSamplesSheet) 38 | } 39 | .onAppear { 40 | readCodes() 41 | checkTheme() 42 | } 43 | .onReceive(openSamplesMenuItemSelected) { _ in 44 | showSamplesSheet.toggle() 45 | } 46 | .navigationTitle("HTTP Status Codes") 47 | .modifier(ToolbarModifier()) 48 | } 49 | 50 | func readCodes() { 51 | httpSections = Bundle.main.decode([HttpSection].self, from: "httpcodes.json") 52 | } 53 | 54 | func checkTheme() { 55 | switch appTheme { 56 | case "dark": 57 | NSApp.appearance = NSAppearance(named: .darkAqua) 58 | case "light": 59 | NSApp.appearance = NSAppearance(named: .aqua) 60 | default: 61 | NSApp.appearance = nil 62 | } 63 | } 64 | } 65 | 66 | struct ContentView_Previews: PreviewProvider { 67 | static var previews: some View { 68 | ContentView() 69 | } 70 | } 71 | 72 | struct StatusList: View { 73 | var title: String 74 | var statuses: [HttpStatus] 75 | 76 | var body: some View { 77 | NavigationView { 78 | List { 79 | ForEach(statuses) { status in 80 | NavigationLink(destination: DetailView(sectionTitle: title, httpStatus: status)) { 81 | ListRowView(code: status.code, title: status.title) 82 | } 83 | } 84 | } 85 | .listStyle(InsetListStyle()) 86 | .frame(minWidth: 200, idealWidth: 200, maxWidth: 350, maxHeight: .infinity) 87 | 88 | Text(statuses.isEmpty ? "Select a category." : "Select an HTTP status.") 89 | .frame(maxWidth: .infinity, maxHeight: .infinity) 90 | } 91 | .navigationTitle(title) 92 | } 93 | } 94 | 95 | struct ListRowView: View { 96 | let code: String 97 | let title: String 98 | 99 | var body: some View { 100 | VStack(alignment: .leading) { 101 | Text(code) 102 | .font(.largeTitle) 103 | .foregroundColor(.primary) 104 | 105 | Text(title) 106 | .font(.title2) 107 | .truncationMode(.tail) 108 | } 109 | .padding(.vertical) 110 | } 111 | } 112 | 113 | struct ToolbarModifier: ViewModifier { 114 | func body(content: Content) -> some View { 115 | content 116 | .toolbar { 117 | ToolbarItem { 118 | Button(action: { 119 | NotificationCenter.default.post(name: .flipImage, object: nil) 120 | } ) { 121 | Image(systemName: "arrow.left.and.right.righttriangle.left.righttriangle.right") 122 | } 123 | } 124 | 125 | ToolbarItem { 126 | Button(action: { 127 | NotificationCenter.default.post(name: .showSamples, object: nil) 128 | } ) { 129 | Image(systemName: "uiwindow.split.2x1") 130 | } 131 | } 132 | } 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/DetailView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DetailView.swift 3 | // SwiftUI-Mac 4 | // 5 | // Created by Sarah Reichelt on 6/11/19. 6 | // Copyright © 2019 Sarah Reichelt. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct DetailView: View { 12 | let sectionTitle: String 13 | let httpStatus: HttpStatus 14 | 15 | @State private var catImage: NSImage? 16 | @State private var imageIsFlipped = false 17 | 18 | private let flipImageMenuItemSelected = NotificationCenter.default 19 | .publisher(for: .flipImage) 20 | .receive(on: RunLoop.main) 21 | 22 | private let saveImageUrlSelected = NotificationCenter.default 23 | .publisher(for: .saveImage) 24 | 25 | var body: some View { 26 | VStack { 27 | Text("HTTP Status Code: \(httpStatus.code)") 28 | .font(.headline) 29 | .padding() 30 | Text(httpStatus.title) 31 | .font(.title) 32 | 33 | if let catImage = catImage{ 34 | CatImageView(catImage: catImage, imageIsFlipped: imageIsFlipped) 35 | } else { 36 | Spacer() 37 | ProgressView() 38 | } 39 | Spacer() 40 | DialogsView() 41 | } 42 | .frame(maxWidth: .infinity, maxHeight: .infinity) 43 | .onAppear { 44 | getCatImage() 45 | } 46 | .navigationTitle("\(sectionTitle) - \(httpStatus.title)") 47 | .onReceive(flipImageMenuItemSelected) { _ in 48 | imageIsFlipped.toggle() 49 | } 50 | .onReceive(saveImageUrlSelected) { publisher in 51 | if let saveUrl = publisher.object as? URL, 52 | let imageData = catImage?.tiffRepresentation { 53 | if let imageRep = NSBitmapImageRep(data: imageData) { 54 | if let saveData = imageRep.representation(using: .jpeg, properties: [:]) { 55 | try? saveData.write(to: saveUrl) 56 | } 57 | } 58 | } 59 | } 60 | } 61 | 62 | func getCatImage() { 63 | let url = httpStatus.imageUrl 64 | let task = URLSession.shared.dataTask(with: url) { (data, response, error) in 65 | if let error = error { 66 | print(error) 67 | } else if let data = data { 68 | DispatchQueue.main.async { 69 | catImage = NSImage(data: data) 70 | } 71 | } 72 | } 73 | task.resume() 74 | } 75 | 76 | } 77 | 78 | struct DetailView_Previews: PreviewProvider { 79 | static var previews: some View { 80 | DetailView(sectionTitle: "4xx", httpStatus: HttpStatus(code: "404", title: "Not Found")) 81 | } 82 | } 83 | 84 | struct CatImageView: View { 85 | @AppStorage("showCopyright") var showCopyright: Bool = false 86 | 87 | let catImage: NSImage 88 | let imageIsFlipped: Bool 89 | 90 | var body: some View { 91 | Image(nsImage: catImage) 92 | .resizable() 93 | .aspectRatio(contentMode: .fit) 94 | .rotation3DEffect(Angle(degrees: imageIsFlipped ? 180 : 0), 95 | axis: (x: 0, y: 1, z: 0)) 96 | .animation(.default) 97 | .overlay( 98 | Text(showCopyright ? "Copyright © https://http.cat" : "") 99 | .padding(6) 100 | .font(.caption) 101 | .foregroundColor(.white) 102 | .shadow(radius: 5) 103 | ,alignment: .bottomTrailing) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/DialogsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DialogsView.swift 3 | // SwiftUI-Mac 4 | // 5 | // Created by Sarah Reichelt on 13/11/19. 6 | // Copyright © 2019 Sarah Reichelt. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct DialogsView: View { 12 | @State private var alertIsShowing = false 13 | @State private var dialogResult = "Click the buttons above to test the dialogs." 14 | 15 | var body: some View { 16 | VStack(spacing: 6) { 17 | HStack { 18 | Button("Alert") { 19 | dialogResult = "Showing Alert" 20 | alertIsShowing.toggle() 21 | } 22 | 23 | Spacer() 24 | 25 | Button("File") { 26 | dialogResult = "Select where to save the cat image." 27 | saveImage() 28 | } 29 | } 30 | .padding(.horizontal) 31 | .padding(.top, 6) 32 | 33 | Text(dialogResult) 34 | .font(.caption) 35 | .frame(height: 20) 36 | } 37 | .alert(isPresented: $alertIsShowing) { 38 | Alert(title: Text("Alert"), 39 | message: Text("This is an alert with two buttons!"), 40 | primaryButton: .default(Text("OK"), action: { 41 | dialogResult = "OK clicked in Alert" 42 | }), secondaryButton: .cancel({ 43 | dialogResult = "Cancel clicked in Alert" 44 | })) 45 | } 46 | } 47 | 48 | func saveImage() { 49 | let panel = NSSavePanel() 50 | panel.nameFieldLabel = "Save cat image as:" 51 | panel.nameFieldStringValue = "cat.jpg" 52 | panel.canCreateDirectories = true 53 | panel.begin { response in 54 | if response == NSApplication.ModalResponse.OK, let fileUrl = panel.url { 55 | dialogResult = "Saving to \(fileUrl.path)" 56 | NotificationCenter.default.post(name: .saveImage, object: fileUrl) 57 | } else { 58 | dialogResult = "Cancel clicked in Save dialog" 59 | } 60 | } 61 | } 62 | } 63 | 64 | struct DialogsView_Previews: PreviewProvider { 65 | static var previews: some View { 66 | DialogsView() 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/FormSamplesView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FormSamplesView.swift 3 | // SwiftUI-Mac 4 | // 5 | // Created by Sarah Reichelt on 10/11/19. 6 | // Copyright © 2019 Sarah Reichelt. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct FormSamplesView: View { 12 | @State private var email = "" 13 | @State private var password = "" 14 | @State private var selectedDate = Date() 15 | @State private var selectedTime = Date() 16 | @State private var selectedColor = Color.blue 17 | 18 | // TODO: Focus in text field 19 | 20 | var body: some View { 21 | VStack(spacing: 30) { 22 | TextField("Enter your email address", text: $email) 23 | 24 | SecureField("Enter your password", text: $password) 25 | 26 | DatePicker(selection: $selectedDate, displayedComponents: [ .date ]) { 27 | Text("Pick a date:") 28 | } 29 | 30 | DatePicker(selection: $selectedTime, displayedComponents: [ .hourAndMinute ]) { 31 | Text("Pick a time:") 32 | } 33 | 34 | ColorPicker(selection: $selectedColor, supportsOpacity: true) { 35 | Text("Choose a color:").padding() 36 | } 37 | .frame(height: 50) 38 | .background(selectedColor) 39 | } 40 | .padding() 41 | } 42 | } 43 | 44 | struct FormSamplesView_Previews: PreviewProvider { 45 | static var previews: some View { 46 | FormSamplesView() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/PickerSamplesView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PickerSamplesView.swift 3 | // SwiftUI-Mac 4 | // 5 | // Created by Sarah Reichelt on 10/11/19. 6 | // Copyright © 2019 Sarah Reichelt. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct PickerSamplesView: View { 12 | @State private var menuSelected = 0 13 | @State private var radioSelected = 0 14 | @State private var segmentSelected = 0 15 | 16 | var body: some View { 17 | VStack { 18 | Text("This picker uses the default style.") 19 | .modifier(ExplanatoryText()) 20 | 21 | Picker(selection: $menuSelected, label: Text("Select an option:")) { 22 | Text("Option 1").tag(1) 23 | Text("Option 2").tag(2) 24 | Text("Option 3").tag(3) 25 | Text("Option 4").tag(4) 26 | Text("Option 5").tag(5) 27 | } 28 | .frame(width: 300) 29 | 30 | Divider().padding(.vertical) 31 | 32 | Text("This picker uses the RadioGroupPickerStyle.") 33 | .modifier(ExplanatoryText()) 34 | 35 | GroupBox { 36 | Picker(selection: $radioSelected, label: Text("Place your vote:")) { 37 | Text("Yes").tag(0) 38 | Text("No").tag(1) 39 | Text("Maybe").tag(2) 40 | } 41 | .pickerStyle(RadioGroupPickerStyle()) 42 | } 43 | 44 | Divider().padding(.vertical) 45 | 46 | Text("This picker uses the SegmentedPickerStyle.") 47 | .modifier(ExplanatoryText()) 48 | 49 | Picker(selection: $segmentSelected, label: Text("Select a color:")) { 50 | Text("Red").tag(0) 51 | Text("Green").tag(1) 52 | Text("Blue").tag(2) 53 | } 54 | .pickerStyle(SegmentedPickerStyle()) 55 | .padding() 56 | } 57 | .padding() 58 | } 59 | } 60 | 61 | struct PickerSamplesView_Previews: PreviewProvider { 62 | static var previews: some View { 63 | PickerSamplesView() 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/SamplesView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Samplesview.swift 3 | // SwiftUI-Mac-11 4 | // 5 | // Created by Sarah Reichelt on 3/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SamplesView: View { 11 | @Binding var isVisible: Bool 12 | @State private var selectedTab = 0 13 | 14 | var body: some View { 15 | VStack { 16 | TabView(selection: $selectedTab) { 17 | PickerSamplesView().tabItem { Text("Pickers") }.tag(0) 18 | SwitchSamplesView().tabItem { Text("Switches") }.tag(1) 19 | FormSamplesView().tabItem { Text("Form") }.tag(2) 20 | } 21 | 22 | Spacer() 23 | 24 | Button(action: { 25 | isVisible = false 26 | }) { 27 | Text("Close") 28 | } 29 | .keyboardShortcut(.defaultAction) 30 | .padding(.top, 10) 31 | } 32 | .padding() 33 | .frame(minWidth: 400, idealWidth: 400, maxWidth: .infinity, minHeight: 420, idealHeight: 420, maxHeight: .infinity) 34 | } 35 | } 36 | 37 | struct Samplesview_Previews: PreviewProvider { 38 | static var previews: some View { 39 | SamplesView(isVisible: .constant(true)) 40 | } 41 | } 42 | 43 | struct ExplanatoryText: ViewModifier { 44 | func body(content: Content) -> some View { 45 | content 46 | .font(.caption) 47 | .foregroundColor(.secondary) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/SettingsView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Settings.swift 3 | // SwiftUI-Mac-11 4 | // 5 | // Created by Sarah Reichelt on 3/7/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct SettingsView: View { 11 | @AppStorage("showCopyright") var showCopyright: Bool = false 12 | 13 | var body: some View { 14 | Toggle(isOn: $showCopyright) { 15 | Text("Show Copyright Notice") 16 | } 17 | .frame(width: 220, height: 80) 18 | } 19 | } 20 | 21 | struct Settings_Previews: PreviewProvider { 22 | static var previews: some View { 23 | SettingsView() 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SwiftUI-Mac-11/Views/SwitchSamplesView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwitchSamplesView.swift 3 | // SwiftUI-Mac 4 | // 5 | // Created by Sarah Reichelt on 10/11/19. 6 | // Copyright © 2019 Sarah Reichelt. All rights reserved. 7 | // 8 | 9 | import SwiftUI 10 | 11 | struct SwitchSamplesView: View { 12 | @State private var toggleValue = true 13 | @State private var stepperValue = 0 14 | @State private var sliderValue = 0.0 15 | 16 | var body: some View { 17 | VStack { 18 | Text("Use a Toggle to get a check box.") 19 | .modifier(ExplanatoryText()) 20 | 21 | Toggle(isOn: $toggleValue) { 22 | Text("Toggle switch") 23 | } 24 | 25 | Divider().padding(.vertical) 26 | 27 | Text("Steppers and sliders are much the same.") 28 | .modifier(ExplanatoryText()) 29 | 30 | Stepper(value: $stepperValue, in: 0 ... 100) { 31 | Text("Select a number:") 32 | } 33 | 34 | Slider(value: $sliderValue, 35 | in: 0 ... 10, 36 | minimumValueLabel: Text("Slow"), 37 | maximumValueLabel: Text("Fast")) { 38 | Text("Speed:") 39 | } 40 | .padding() 41 | 42 | Divider().padding(.vertical) 43 | 44 | Group { 45 | Text("Toggle value = \(toggleValue ? "ON" : "OFF")") 46 | Text("Stepper value = \(stepperValue)") 47 | Text("Slider value = \(sliderValue, specifier: "%.2f")") 48 | } 49 | .modifier(ExplanatoryText()) 50 | } 51 | 52 | .padding() 53 | } 54 | } 55 | 56 | struct SwitchSamplesView_Previews: PreviewProvider { 57 | static var previews: some View { 58 | SwitchSamplesView() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /assets/swiftui-mac-11-toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/trozware/swiftui-mac-11/8ed16576f796530949c1ccf079974f7cbb2e3406/assets/swiftui-mac-11-toolbar.png --------------------------------------------------------------------------------