├── .gitignore ├── Configuration ├── Assets.xcassets │ ├── AccentColor.colorset │ │ └── Contents.json │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Disambiguator.xcconfig ├── SwiftUIWeeklyLayoutChallengeApp.swift ├── macOS.entitlements └── watchOS.plist ├── LICENSE ├── README.md ├── SwiftUIWeeklyLayoutChallenge.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist └── SwiftUIWeeklyLayoutChallenge ├── .gitignore ├── ContentView.swift ├── Documentation.docc ├── Regulations │ └── RegulationsV1.md ├── Resources │ ├── Topic001_iOS.png │ ├── Topic001_macOS.png │ ├── Topic001_tvOS.png │ ├── Topic001_watchOS.png │ ├── Topic002_iOS.png │ ├── Topic002_tvOS.png │ ├── Topic002_watchOS.png │ ├── Topic003_iOS.png │ ├── Topic003_macOS.png │ ├── Topic003_tvOS.png │ ├── Topic003_watchOS.png │ ├── Topic004_iOS.png │ ├── Topic004_macOS.png │ ├── Topic004_tvOS.png │ ├── Topic004_watchOS.png │ ├── Topic005_iOS-Dark.png │ ├── Topic005_iOS-Light.png │ ├── Topic005_macOS-Dark.png │ ├── Topic005_macOS-Light.png │ ├── Topic006_iPadmini6thGen.png │ ├── Topic006_iPhone13mini.png │ ├── Topic006_iPhoneSE3rdGen.png │ ├── Topic007_iPhone13mini_1.png │ ├── Topic007_iPhone13mini_2.png │ ├── Topic007_iPhone13mini_3.png │ ├── Topic007_iPhone13mini_4.png │ ├── Topic008_iPhone14Pro_1.png │ ├── Topic008_iPhone14Pro_2.png │ ├── Topic008_iPhone14Pro_3.png │ ├── Topic008_iPhone14Pro_4.png │ ├── Topic009_iPhone14Pro.mp4 │ ├── Topic009_iPhone14Pro_1.png │ ├── Topic009_iPhone14Pro_2.png │ ├── Topic009_iPhone14Pro_3.png │ └── Topic009_iPhone14Pro_4.png ├── SwiftUIWeeklyLayoutChallenge.md └── Topics │ ├── Topic001.md │ ├── Topic002.md │ ├── Topic003.md │ ├── Topic004.md │ ├── Topic005.md │ ├── Topic006.md │ ├── Topic007.md │ ├── Topic008.md │ └── Topic009.md ├── Package.swift ├── Topic001.swift ├── Topic002.swift ├── Topic003.swift ├── Topic004.swift ├── Topic005.swift ├── Topic006.swift ├── Topic007.swift ├── Topic008.swift ├── Topic009.swift └── TopicXXX.swift /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | *.xcscmblueprint 6 | *.xccheckout 7 | build/ 8 | DerivedData/ 9 | *.moved-aside 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | *.hmap 19 | *.ipa 20 | *.dSYM.zip 21 | *.dSYM 22 | timeline.xctimeline 23 | playground.xcworkspace 24 | .swiftpm/config/registries.json 25 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 26 | .netrc 27 | -------------------------------------------------------------------------------- /Configuration/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 | -------------------------------------------------------------------------------- /Configuration/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | }, 93 | { 94 | "idiom" : "mac", 95 | "scale" : "1x", 96 | "size" : "16x16" 97 | }, 98 | { 99 | "idiom" : "mac", 100 | "scale" : "2x", 101 | "size" : "16x16" 102 | }, 103 | { 104 | "idiom" : "mac", 105 | "scale" : "1x", 106 | "size" : "32x32" 107 | }, 108 | { 109 | "idiom" : "mac", 110 | "scale" : "2x", 111 | "size" : "32x32" 112 | }, 113 | { 114 | "idiom" : "mac", 115 | "scale" : "1x", 116 | "size" : "128x128" 117 | }, 118 | { 119 | "idiom" : "mac", 120 | "scale" : "2x", 121 | "size" : "128x128" 122 | }, 123 | { 124 | "idiom" : "mac", 125 | "scale" : "1x", 126 | "size" : "256x256" 127 | }, 128 | { 129 | "idiom" : "mac", 130 | "scale" : "2x", 131 | "size" : "256x256" 132 | }, 133 | { 134 | "idiom" : "mac", 135 | "scale" : "1x", 136 | "size" : "512x512" 137 | }, 138 | { 139 | "idiom" : "mac", 140 | "scale" : "2x", 141 | "size" : "512x512" 142 | } 143 | ], 144 | "info" : { 145 | "author" : "xcode", 146 | "version" : 1 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Configuration/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Configuration/Disambiguator.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Disambiguator.xcconfig 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/07/13. 6 | // 7 | 8 | DISAMBIGUATOR=${DEVELOPMENT_TEAM} 9 | -------------------------------------------------------------------------------- /Configuration/SwiftUIWeeklyLayoutChallengeApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftUIWeeklyLayoutChallengeApp.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/07/13. 6 | // 7 | 8 | import SwiftUI 9 | import SwiftUIWeeklyLayoutChallenge 10 | 11 | @main 12 | struct SwiftUIWeeklyLayoutChallengeApp: App { 13 | var body: some Scene { 14 | WindowGroup { 15 | ContentView() 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Configuration/macOS.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | com.apple.security.files.user-selected.read-only 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Configuration/watchOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | WKAppBundleIdentifier 10 | com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}.watchkitapp 11 | 12 | NSExtensionPointIdentifier 13 | com.apple.watchkit 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 treastrain / Tanaka Ryoga 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) - SwiftUIWeeklyLayoutChallenge 2 | 3 | [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) は、「お題」として Twitter に投稿されたスクリーンショットをもとに、その UI レイアウトを各々が SwiftUI で構成、それをインターネット上で共有し合うイベントです。 4 | 5 | ## イベントの意図 6 | 1つの UI レイアウトを SwiftUI によって実現するとき、さまざまな表現方法があると思っています。求められる要件などによって最適と思われるコーディングを行うことは、デベロッパの腕の見せどころです。 7 | 8 | 原則、1枚のスクリーンショットによって示されたお題に対して、多くの人が「自分なら SwiftUI でどう UI レイアウトを組むか?」について共有し合うことで、SwiftUI による UI レイアウトの理解を深めることを目的としています。 9 | 10 | [ハッシュタグに「勝負」という単語が含まれていますが、「最も優れたコード・優勝者」を決めることはしません。](https://twitter.com/treastrain/status/1547115218664574976) 11 | 12 | また、お題の「1枚のスクリーンショット」と非常に限定的なテキストによる補足情報のみから UI レイアウトを組むことになるため、それ以外で必要とされる情報については各自で補完する必要があります。そのため、各お題の「絶対的な正解」は存在せず、よって各お題の締め切りも設定しません。 13 | 14 | ## 取り組み方 15 | [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) のハッシュタグがついた、お題のツイートが定期的に [@treastrain](https://twitter.com/treastrain) より行われます。そのツイートのリプライにある、お題に対して適用されるレギュレーションを守りながら、SwiftUI による UI レイアウトコーディングを行なってください。 16 | 17 | ## 本リポジトリについて 18 | 本リポジトリには、[#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) に取り組む際に便利なテンプレートが含まれています。 19 | 20 | 1. Local Swift Package である `SwiftUIWeeklyLayoutChallenge` ディレクトリ下にある `TopicXXX.swift` を複製し、`TopicXXX` を適当な名前に変更する(`Topic001` など)。 21 | 1. `ContentView.swift` の中身を前ステップで変更した名前にあわせて変更する。 22 | ```diff 23 | - typealias ContentView = TopicXXXView 24 | + typealias ContentView = Topic001View 25 | ``` 26 | 1. 前々ステップで複製した Swift ファイルを使ってコーディングを行う。 27 | 28 | iOS・macOS・tvOS・watchOS でそれぞれの App としてビルド・実行するための Xcode Project も同梱しています。 29 | 30 | また、レギュレーションやお題についての Markdown ファイル、お題のスクリーンショットを生成するために使用した SwiftUI によるコードも含まれています(そのコードがお題に対する絶対的な正解とは限りません)(お題のスクリーンショットを生成するために使用した SwiftUI によるコードは、お題ツイート日時より日をあけて公開されます)。 31 | 32 | 本リポジトリは、過去のお題をまとめたカタログ App となることは意図されていません。 33 | 34 | ## きっかけ 35 | https://twitter.com/treastrain/status/1546884462738571265 36 | 37 | [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) に取り組んだ際には、ぜひ Twitter、Zenn、Qiita やブログ記事などであなたが書いた SwiftUI のコードを共有してください!個人による取り組みだけでなく、企業・団体の勉強会などでも自由にお使いいただけます。 38 | 39 | ## お題の提供 40 | [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) で取り上げたいお題についても募集しています。お題ができた方はぜひ [@treastrain](https://twitter.com/treastrain) に Twitter DM で連絡してください(すべて採用される保証はありませんのでご了承ください)。お題作成者の Twitter ID は、お題ツイートのリプライに記載されます([第001回の例](https://twitter.com/treastrain/status/1547154248475234304))。 41 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 55; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | CB0D88A2288279C800E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */ = {isa = PBXBuildFile; productRef = CB0D88A1288279C800E61609 /* SwiftUIWeeklyLayoutChallenge */; }; 11 | CB0D88A4288279D200E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */ = {isa = PBXBuildFile; productRef = CB0D88A3288279D200E61609 /* SwiftUIWeeklyLayoutChallenge */; }; 12 | CB0D88A6288279D900E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */ = {isa = PBXBuildFile; productRef = CB0D88A5288279D900E61609 /* SwiftUIWeeklyLayoutChallenge */; }; 13 | CB0D88A8288279E200E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */ = {isa = PBXBuildFile; productRef = CB0D88A7288279E200E61609 /* SwiftUIWeeklyLayoutChallenge */; }; 14 | CB5D435A2881DADD001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB5D43592881DAD1001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift */; }; 15 | CB5D435B2881DADD001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB5D43592881DAD1001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift */; }; 16 | CB5D435C2881DADE001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB5D43592881DAD1001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift */; }; 17 | CB5D435D2881DADF001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB5D43592881DAD1001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift */; }; 18 | CB5D435E2881DAE8001B5EA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB5D43562881DAD1001B5EA1 /* Assets.xcassets */; }; 19 | CB5D435F2881DAE9001B5EA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB5D43562881DAD1001B5EA1 /* Assets.xcassets */; }; 20 | CB5D43602881DAE9001B5EA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB5D43562881DAD1001B5EA1 /* Assets.xcassets */; }; 21 | CB5D43612881DAEA001B5EA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB5D43562881DAD1001B5EA1 /* Assets.xcassets */; }; 22 | CB5D43622881DAEA001B5EA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB5D43562881DAD1001B5EA1 /* Assets.xcassets */; }; 23 | CB5D43632881DAEB001B5EA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB5D43562881DAD1001B5EA1 /* Assets.xcassets */; }; 24 | CB7F7B13287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp WatchKit App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = CB7F7B12287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp WatchKit App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 25 | CB7F7B1E287DEEF800E789D3 /* watchOS WatchKit Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CB7F7B1D287DEEF800E789D3 /* watchOS WatchKit Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | CB7F7B14287DEEF700E789D3 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = CB7F7AEA287DEEC500E789D3 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = CB7F7B11287DEEF700E789D3; 34 | remoteInfo = "SwiftUIWeeklyLayoutChallenge (watchOS) WatchKit App"; 35 | }; 36 | CB7F7B1F287DEEF800E789D3 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = CB7F7AEA287DEEC500E789D3 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = CB7F7B1C287DEEF800E789D3; 41 | remoteInfo = "SwiftUIWeeklyLayoutChallenge (watchOS) WatchKit Extension"; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXCopyFilesBuildPhase section */ 46 | CB7F7B31287DEEF900E789D3 /* Embed App Extensions */ = { 47 | isa = PBXCopyFilesBuildPhase; 48 | buildActionMask = 2147483647; 49 | dstPath = ""; 50 | dstSubfolderSpec = 13; 51 | files = ( 52 | CB7F7B1E287DEEF800E789D3 /* watchOS WatchKit Extension.appex in Embed App Extensions */, 53 | ); 54 | name = "Embed App Extensions"; 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | CB7F7B35287DEEF900E789D3 /* Embed Watch Content */ = { 58 | isa = PBXCopyFilesBuildPhase; 59 | buildActionMask = 2147483647; 60 | dstPath = "$(CONTENTS_FOLDER_PATH)/Watch"; 61 | dstSubfolderSpec = 16; 62 | files = ( 63 | CB7F7B13287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp WatchKit App.app in Embed Watch Content */, 64 | ); 65 | name = "Embed Watch Content"; 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXCopyFilesBuildPhase section */ 69 | 70 | /* Begin PBXFileReference section */ 71 | CB5D43372881C744001B5EA1 /* SwiftUIWeeklyLayoutChallenge */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = SwiftUIWeeklyLayoutChallenge; sourceTree = ""; }; 72 | CB5D434C2881D4DB001B5EA1 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; 73 | CB5D43552881DAD1001B5EA1 /* watchOS.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = watchOS.plist; sourceTree = ""; }; 74 | CB5D43562881DAD1001B5EA1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 75 | CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Disambiguator.xcconfig; sourceTree = ""; }; 76 | CB5D43582881DAD1001B5EA1 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 77 | CB5D43592881DAD1001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftUIWeeklyLayoutChallengeApp.swift; sourceTree = ""; }; 78 | CB7F7AF6287DEEC600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIWeeklyLayoutChallengeApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 79 | CB7F7AFC287DEEC600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIWeeklyLayoutChallengeApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | CB7F7B0F287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIWeeklyLayoutChallengeApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | CB7F7B12287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp WatchKit App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SwiftUIWeeklyLayoutChallengeApp WatchKit App.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | CB7F7B1D287DEEF800E789D3 /* watchOS WatchKit Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "watchOS WatchKit Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | CB7F7B41287DF16600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftUIWeeklyLayoutChallengeApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 84 | /* End PBXFileReference section */ 85 | 86 | /* Begin PBXFrameworksBuildPhase section */ 87 | CB7F7AF3287DEEC600E789D3 /* Frameworks */ = { 88 | isa = PBXFrameworksBuildPhase; 89 | buildActionMask = 2147483647; 90 | files = ( 91 | CB0D88A2288279C800E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | CB7F7AF9287DEEC600E789D3 /* Frameworks */ = { 96 | isa = PBXFrameworksBuildPhase; 97 | buildActionMask = 2147483647; 98 | files = ( 99 | CB0D88A4288279D200E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */, 100 | ); 101 | runOnlyForDeploymentPostprocessing = 0; 102 | }; 103 | CB7F7B1A287DEEF800E789D3 /* Frameworks */ = { 104 | isa = PBXFrameworksBuildPhase; 105 | buildActionMask = 2147483647; 106 | files = ( 107 | CB0D88A8288279E200E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */, 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | CB7F7B3E287DF16600E789D3 /* Frameworks */ = { 112 | isa = PBXFrameworksBuildPhase; 113 | buildActionMask = 2147483647; 114 | files = ( 115 | CB0D88A6288279D900E61609 /* SwiftUIWeeklyLayoutChallenge in Frameworks */, 116 | ); 117 | runOnlyForDeploymentPostprocessing = 0; 118 | }; 119 | /* End PBXFrameworksBuildPhase section */ 120 | 121 | /* Begin PBXGroup section */ 122 | CB5D43392881CE88001B5EA1 /* Frameworks */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | ); 126 | name = Frameworks; 127 | sourceTree = ""; 128 | }; 129 | CB5D43542881DAD1001B5EA1 /* Configuration */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | CB5D43592881DAD1001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift */, 133 | CB5D43562881DAD1001B5EA1 /* Assets.xcassets */, 134 | CB5D43582881DAD1001B5EA1 /* macOS.entitlements */, 135 | CB5D43552881DAD1001B5EA1 /* watchOS.plist */, 136 | CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */, 137 | ); 138 | path = Configuration; 139 | sourceTree = ""; 140 | }; 141 | CB7F7AE9287DEEC500E789D3 = { 142 | isa = PBXGroup; 143 | children = ( 144 | CB5D434C2881D4DB001B5EA1 /* README.md */, 145 | CB5D43372881C744001B5EA1 /* SwiftUIWeeklyLayoutChallenge */, 146 | CB5D43542881DAD1001B5EA1 /* Configuration */, 147 | CB7F7AF7287DEEC600E789D3 /* Products */, 148 | CB5D43392881CE88001B5EA1 /* Frameworks */, 149 | ); 150 | sourceTree = ""; 151 | }; 152 | CB7F7AF7287DEEC600E789D3 /* Products */ = { 153 | isa = PBXGroup; 154 | children = ( 155 | CB7F7AF6287DEEC600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */, 156 | CB7F7AFC287DEEC600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */, 157 | CB7F7B0F287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */, 158 | CB7F7B12287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp WatchKit App.app */, 159 | CB7F7B1D287DEEF800E789D3 /* watchOS WatchKit Extension.appex */, 160 | CB7F7B41287DF16600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */, 161 | ); 162 | name = Products; 163 | sourceTree = ""; 164 | }; 165 | /* End PBXGroup section */ 166 | 167 | /* Begin PBXNativeTarget section */ 168 | CB7F7AF5287DEEC600E789D3 /* iOS App */ = { 169 | isa = PBXNativeTarget; 170 | buildConfigurationList = CB7F7B07287DEEC600E789D3 /* Build configuration list for PBXNativeTarget "iOS App" */; 171 | buildPhases = ( 172 | CB7F7AF2287DEEC600E789D3 /* Sources */, 173 | CB7F7AF3287DEEC600E789D3 /* Frameworks */, 174 | CB7F7AF4287DEEC600E789D3 /* Resources */, 175 | ); 176 | buildRules = ( 177 | ); 178 | dependencies = ( 179 | ); 180 | name = "iOS App"; 181 | packageProductDependencies = ( 182 | CB0D88A1288279C800E61609 /* SwiftUIWeeklyLayoutChallenge */, 183 | ); 184 | productName = "SwiftUIWeeklyLayoutChallenge (iOS)"; 185 | productReference = CB7F7AF6287DEEC600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */; 186 | productType = "com.apple.product-type.application"; 187 | }; 188 | CB7F7AFB287DEEC600E789D3 /* macOS App */ = { 189 | isa = PBXNativeTarget; 190 | buildConfigurationList = CB7F7B0A287DEEC600E789D3 /* Build configuration list for PBXNativeTarget "macOS App" */; 191 | buildPhases = ( 192 | CB7F7AF8287DEEC600E789D3 /* Sources */, 193 | CB7F7AF9287DEEC600E789D3 /* Frameworks */, 194 | CB7F7AFA287DEEC600E789D3 /* Resources */, 195 | ); 196 | buildRules = ( 197 | ); 198 | dependencies = ( 199 | ); 200 | name = "macOS App"; 201 | packageProductDependencies = ( 202 | CB0D88A3288279D200E61609 /* SwiftUIWeeklyLayoutChallenge */, 203 | ); 204 | productName = "SwiftUIWeeklyLayoutChallenge (macOS)"; 205 | productReference = CB7F7AFC287DEEC600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */; 206 | productType = "com.apple.product-type.application"; 207 | }; 208 | CB7F7B0E287DEEF700E789D3 /* watchOS App */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = CB7F7B36287DEEF900E789D3 /* Build configuration list for PBXNativeTarget "watchOS App" */; 211 | buildPhases = ( 212 | CB7F7B0D287DEEF700E789D3 /* Resources */, 213 | CB7F7B35287DEEF900E789D3 /* Embed Watch Content */, 214 | ); 215 | buildRules = ( 216 | ); 217 | dependencies = ( 218 | CB7F7B15287DEEF700E789D3 /* PBXTargetDependency */, 219 | ); 220 | name = "watchOS App"; 221 | productName = "SwiftUIWeeklyLayoutChallenge (watchOS)"; 222 | productReference = CB7F7B0F287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */; 223 | productType = "com.apple.product-type.application.watchapp2-container"; 224 | }; 225 | CB7F7B11287DEEF700E789D3 /* watchOS WatchKit App */ = { 226 | isa = PBXNativeTarget; 227 | buildConfigurationList = CB7F7B32287DEEF900E789D3 /* Build configuration list for PBXNativeTarget "watchOS WatchKit App" */; 228 | buildPhases = ( 229 | CB7F7B10287DEEF700E789D3 /* Resources */, 230 | CB7F7B31287DEEF900E789D3 /* Embed App Extensions */, 231 | ); 232 | buildRules = ( 233 | ); 234 | dependencies = ( 235 | CB7F7B20287DEEF800E789D3 /* PBXTargetDependency */, 236 | ); 237 | name = "watchOS WatchKit App"; 238 | productName = "SwiftUIWeeklyLayoutChallenge (watchOS) WatchKit App"; 239 | productReference = CB7F7B12287DEEF700E789D3 /* SwiftUIWeeklyLayoutChallengeApp WatchKit App.app */; 240 | productType = "com.apple.product-type.application.watchapp2"; 241 | }; 242 | CB7F7B1C287DEEF800E789D3 /* watchOS WatchKit Extension */ = { 243 | isa = PBXNativeTarget; 244 | buildConfigurationList = CB7F7B2E287DEEF900E789D3 /* Build configuration list for PBXNativeTarget "watchOS WatchKit Extension" */; 245 | buildPhases = ( 246 | CB7F7B19287DEEF800E789D3 /* Sources */, 247 | CB7F7B1A287DEEF800E789D3 /* Frameworks */, 248 | CB7F7B1B287DEEF800E789D3 /* Resources */, 249 | ); 250 | buildRules = ( 251 | ); 252 | dependencies = ( 253 | ); 254 | name = "watchOS WatchKit Extension"; 255 | packageProductDependencies = ( 256 | CB0D88A7288279E200E61609 /* SwiftUIWeeklyLayoutChallenge */, 257 | ); 258 | productName = "SwiftUIWeeklyLayoutChallenge (watchOS) WatchKit Extension"; 259 | productReference = CB7F7B1D287DEEF800E789D3 /* watchOS WatchKit Extension.appex */; 260 | productType = "com.apple.product-type.watchkit2-extension"; 261 | }; 262 | CB7F7B40287DF16600E789D3 /* tvOS App */ = { 263 | isa = PBXNativeTarget; 264 | buildConfigurationList = CB7F7B4C287DF16700E789D3 /* Build configuration list for PBXNativeTarget "tvOS App" */; 265 | buildPhases = ( 266 | CB7F7B3D287DF16600E789D3 /* Sources */, 267 | CB7F7B3E287DF16600E789D3 /* Frameworks */, 268 | CB7F7B3F287DF16600E789D3 /* Resources */, 269 | ); 270 | buildRules = ( 271 | ); 272 | dependencies = ( 273 | ); 274 | name = "tvOS App"; 275 | packageProductDependencies = ( 276 | CB0D88A5288279D900E61609 /* SwiftUIWeeklyLayoutChallenge */, 277 | ); 278 | productName = "SwiftUIWeeklyLayoutChallenge (tvOS)"; 279 | productReference = CB7F7B41287DF16600E789D3 /* SwiftUIWeeklyLayoutChallengeApp.app */; 280 | productType = "com.apple.product-type.application"; 281 | }; 282 | /* End PBXNativeTarget section */ 283 | 284 | /* Begin PBXProject section */ 285 | CB7F7AEA287DEEC500E789D3 /* Project object */ = { 286 | isa = PBXProject; 287 | attributes = { 288 | BuildIndependentTargetsInParallel = 1; 289 | LastSwiftUpdateCheck = 1340; 290 | LastUpgradeCheck = 1340; 291 | TargetAttributes = { 292 | CB7F7AF5287DEEC600E789D3 = { 293 | CreatedOnToolsVersion = 13.4.1; 294 | }; 295 | CB7F7AFB287DEEC600E789D3 = { 296 | CreatedOnToolsVersion = 13.4.1; 297 | }; 298 | CB7F7B0E287DEEF700E789D3 = { 299 | CreatedOnToolsVersion = 13.4.1; 300 | }; 301 | CB7F7B11287DEEF700E789D3 = { 302 | CreatedOnToolsVersion = 13.4.1; 303 | }; 304 | CB7F7B1C287DEEF800E789D3 = { 305 | CreatedOnToolsVersion = 13.4.1; 306 | }; 307 | CB7F7B40287DF16600E789D3 = { 308 | CreatedOnToolsVersion = 13.4.1; 309 | }; 310 | }; 311 | }; 312 | buildConfigurationList = CB7F7AED287DEEC500E789D3 /* Build configuration list for PBXProject "SwiftUIWeeklyLayoutChallenge" */; 313 | compatibilityVersion = "Xcode 13.0"; 314 | developmentRegion = ja; 315 | hasScannedForEncodings = 0; 316 | knownRegions = ( 317 | ja, 318 | Base, 319 | ); 320 | mainGroup = CB7F7AE9287DEEC500E789D3; 321 | productRefGroup = CB7F7AF7287DEEC600E789D3 /* Products */; 322 | projectDirPath = ""; 323 | projectRoot = ""; 324 | targets = ( 325 | CB7F7AF5287DEEC600E789D3 /* iOS App */, 326 | CB7F7AFB287DEEC600E789D3 /* macOS App */, 327 | CB7F7B40287DF16600E789D3 /* tvOS App */, 328 | CB7F7B0E287DEEF700E789D3 /* watchOS App */, 329 | CB7F7B11287DEEF700E789D3 /* watchOS WatchKit App */, 330 | CB7F7B1C287DEEF800E789D3 /* watchOS WatchKit Extension */, 331 | ); 332 | }; 333 | /* End PBXProject section */ 334 | 335 | /* Begin PBXResourcesBuildPhase section */ 336 | CB7F7AF4287DEEC600E789D3 /* Resources */ = { 337 | isa = PBXResourcesBuildPhase; 338 | buildActionMask = 2147483647; 339 | files = ( 340 | CB5D435E2881DAE8001B5EA1 /* Assets.xcassets in Resources */, 341 | ); 342 | runOnlyForDeploymentPostprocessing = 0; 343 | }; 344 | CB7F7AFA287DEEC600E789D3 /* Resources */ = { 345 | isa = PBXResourcesBuildPhase; 346 | buildActionMask = 2147483647; 347 | files = ( 348 | CB5D435F2881DAE9001B5EA1 /* Assets.xcassets in Resources */, 349 | ); 350 | runOnlyForDeploymentPostprocessing = 0; 351 | }; 352 | CB7F7B0D287DEEF700E789D3 /* Resources */ = { 353 | isa = PBXResourcesBuildPhase; 354 | buildActionMask = 2147483647; 355 | files = ( 356 | CB5D43612881DAEA001B5EA1 /* Assets.xcassets in Resources */, 357 | ); 358 | runOnlyForDeploymentPostprocessing = 0; 359 | }; 360 | CB7F7B10287DEEF700E789D3 /* Resources */ = { 361 | isa = PBXResourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | CB5D43622881DAEA001B5EA1 /* Assets.xcassets in Resources */, 365 | ); 366 | runOnlyForDeploymentPostprocessing = 0; 367 | }; 368 | CB7F7B1B287DEEF800E789D3 /* Resources */ = { 369 | isa = PBXResourcesBuildPhase; 370 | buildActionMask = 2147483647; 371 | files = ( 372 | CB5D43632881DAEB001B5EA1 /* Assets.xcassets in Resources */, 373 | ); 374 | runOnlyForDeploymentPostprocessing = 0; 375 | }; 376 | CB7F7B3F287DF16600E789D3 /* Resources */ = { 377 | isa = PBXResourcesBuildPhase; 378 | buildActionMask = 2147483647; 379 | files = ( 380 | CB5D43602881DAE9001B5EA1 /* Assets.xcassets in Resources */, 381 | ); 382 | runOnlyForDeploymentPostprocessing = 0; 383 | }; 384 | /* End PBXResourcesBuildPhase section */ 385 | 386 | /* Begin PBXSourcesBuildPhase section */ 387 | CB7F7AF2287DEEC600E789D3 /* Sources */ = { 388 | isa = PBXSourcesBuildPhase; 389 | buildActionMask = 2147483647; 390 | files = ( 391 | CB5D435A2881DADD001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */, 392 | ); 393 | runOnlyForDeploymentPostprocessing = 0; 394 | }; 395 | CB7F7AF8287DEEC600E789D3 /* Sources */ = { 396 | isa = PBXSourcesBuildPhase; 397 | buildActionMask = 2147483647; 398 | files = ( 399 | CB5D435B2881DADD001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */, 400 | ); 401 | runOnlyForDeploymentPostprocessing = 0; 402 | }; 403 | CB7F7B19287DEEF800E789D3 /* Sources */ = { 404 | isa = PBXSourcesBuildPhase; 405 | buildActionMask = 2147483647; 406 | files = ( 407 | CB5D435D2881DADF001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */, 408 | ); 409 | runOnlyForDeploymentPostprocessing = 0; 410 | }; 411 | CB7F7B3D287DF16600E789D3 /* Sources */ = { 412 | isa = PBXSourcesBuildPhase; 413 | buildActionMask = 2147483647; 414 | files = ( 415 | CB5D435C2881DADE001B5EA1 /* SwiftUIWeeklyLayoutChallengeApp.swift in Sources */, 416 | ); 417 | runOnlyForDeploymentPostprocessing = 0; 418 | }; 419 | /* End PBXSourcesBuildPhase section */ 420 | 421 | /* Begin PBXTargetDependency section */ 422 | CB7F7B15287DEEF700E789D3 /* PBXTargetDependency */ = { 423 | isa = PBXTargetDependency; 424 | target = CB7F7B11287DEEF700E789D3 /* watchOS WatchKit App */; 425 | targetProxy = CB7F7B14287DEEF700E789D3 /* PBXContainerItemProxy */; 426 | }; 427 | CB7F7B20287DEEF800E789D3 /* PBXTargetDependency */ = { 428 | isa = PBXTargetDependency; 429 | target = CB7F7B1C287DEEF800E789D3 /* watchOS WatchKit Extension */; 430 | targetProxy = CB7F7B1F287DEEF800E789D3 /* PBXContainerItemProxy */; 431 | }; 432 | /* End PBXTargetDependency section */ 433 | 434 | /* Begin XCBuildConfiguration section */ 435 | CB7F7B05287DEEC600E789D3 /* Debug */ = { 436 | isa = XCBuildConfiguration; 437 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 438 | buildSettings = { 439 | ALWAYS_SEARCH_USER_PATHS = NO; 440 | CLANG_ANALYZER_NONNULL = YES; 441 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 442 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 443 | CLANG_ENABLE_MODULES = YES; 444 | CLANG_ENABLE_OBJC_ARC = YES; 445 | CLANG_ENABLE_OBJC_WEAK = YES; 446 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 447 | CLANG_WARN_BOOL_CONVERSION = YES; 448 | CLANG_WARN_COMMA = YES; 449 | CLANG_WARN_CONSTANT_CONVERSION = YES; 450 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 451 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 452 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 453 | CLANG_WARN_EMPTY_BODY = YES; 454 | CLANG_WARN_ENUM_CONVERSION = YES; 455 | CLANG_WARN_INFINITE_RECURSION = YES; 456 | CLANG_WARN_INT_CONVERSION = YES; 457 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 458 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 459 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 460 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 461 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 462 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 463 | CLANG_WARN_STRICT_PROTOTYPES = YES; 464 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 465 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 466 | CLANG_WARN_UNREACHABLE_CODE = YES; 467 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 468 | COPY_PHASE_STRIP = NO; 469 | DEBUG_INFORMATION_FORMAT = dwarf; 470 | ENABLE_STRICT_OBJC_MSGSEND = YES; 471 | ENABLE_TESTABILITY = YES; 472 | GCC_C_LANGUAGE_STANDARD = gnu11; 473 | GCC_DYNAMIC_NO_PIC = NO; 474 | GCC_NO_COMMON_BLOCKS = YES; 475 | GCC_OPTIMIZATION_LEVEL = 0; 476 | GCC_PREPROCESSOR_DEFINITIONS = ( 477 | "DEBUG=1", 478 | "$(inherited)", 479 | ); 480 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 481 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 482 | GCC_WARN_UNDECLARED_SELECTOR = YES; 483 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 484 | GCC_WARN_UNUSED_FUNCTION = YES; 485 | GCC_WARN_UNUSED_VARIABLE = YES; 486 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 487 | MTL_FAST_MATH = YES; 488 | ONLY_ACTIVE_ARCH = YES; 489 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 490 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 491 | }; 492 | name = Debug; 493 | }; 494 | CB7F7B06287DEEC600E789D3 /* Release */ = { 495 | isa = XCBuildConfiguration; 496 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 497 | buildSettings = { 498 | ALWAYS_SEARCH_USER_PATHS = NO; 499 | CLANG_ANALYZER_NONNULL = YES; 500 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 501 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; 502 | CLANG_ENABLE_MODULES = YES; 503 | CLANG_ENABLE_OBJC_ARC = YES; 504 | CLANG_ENABLE_OBJC_WEAK = YES; 505 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 506 | CLANG_WARN_BOOL_CONVERSION = YES; 507 | CLANG_WARN_COMMA = YES; 508 | CLANG_WARN_CONSTANT_CONVERSION = YES; 509 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 510 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 511 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 512 | CLANG_WARN_EMPTY_BODY = YES; 513 | CLANG_WARN_ENUM_CONVERSION = YES; 514 | CLANG_WARN_INFINITE_RECURSION = YES; 515 | CLANG_WARN_INT_CONVERSION = YES; 516 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 517 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 518 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 519 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 520 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 521 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 522 | CLANG_WARN_STRICT_PROTOTYPES = YES; 523 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 524 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 525 | CLANG_WARN_UNREACHABLE_CODE = YES; 526 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 527 | COPY_PHASE_STRIP = NO; 528 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 529 | ENABLE_NS_ASSERTIONS = NO; 530 | ENABLE_STRICT_OBJC_MSGSEND = YES; 531 | GCC_C_LANGUAGE_STANDARD = gnu11; 532 | GCC_NO_COMMON_BLOCKS = YES; 533 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 534 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 535 | GCC_WARN_UNDECLARED_SELECTOR = YES; 536 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 537 | GCC_WARN_UNUSED_FUNCTION = YES; 538 | GCC_WARN_UNUSED_VARIABLE = YES; 539 | MTL_ENABLE_DEBUG_INFO = NO; 540 | MTL_FAST_MATH = YES; 541 | SWIFT_COMPILATION_MODE = wholemodule; 542 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 543 | }; 544 | name = Release; 545 | }; 546 | CB7F7B08287DEEC600E789D3 /* Debug */ = { 547 | isa = XCBuildConfiguration; 548 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 549 | buildSettings = { 550 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 551 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 552 | CODE_SIGN_IDENTITY = "Apple Development"; 553 | CODE_SIGN_STYLE = Automatic; 554 | CURRENT_PROJECT_VERSION = 1; 555 | DEVELOPMENT_TEAM = ""; 556 | ENABLE_PREVIEWS = YES; 557 | GENERATE_INFOPLIST_FILE = YES; 558 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 559 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 560 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 561 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 562 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 563 | IPHONEOS_DEPLOYMENT_TARGET = 15.5; 564 | LD_RUNPATH_SEARCH_PATHS = ( 565 | "$(inherited)", 566 | "@executable_path/Frameworks", 567 | ); 568 | MARKETING_VERSION = 1.0; 569 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 570 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 571 | PROVISIONING_PROFILE_SPECIFIER = ""; 572 | SDKROOT = iphoneos; 573 | SWIFT_EMIT_LOC_STRINGS = YES; 574 | SWIFT_VERSION = 5.0; 575 | TARGETED_DEVICE_FAMILY = "1,2"; 576 | }; 577 | name = Debug; 578 | }; 579 | CB7F7B09287DEEC600E789D3 /* Release */ = { 580 | isa = XCBuildConfiguration; 581 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 582 | buildSettings = { 583 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 584 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 585 | CODE_SIGN_IDENTITY = "Apple Development"; 586 | CODE_SIGN_STYLE = Automatic; 587 | CURRENT_PROJECT_VERSION = 1; 588 | DEVELOPMENT_TEAM = ""; 589 | ENABLE_PREVIEWS = YES; 590 | GENERATE_INFOPLIST_FILE = YES; 591 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; 592 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; 593 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 594 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 595 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; 596 | IPHONEOS_DEPLOYMENT_TARGET = 15.5; 597 | LD_RUNPATH_SEARCH_PATHS = ( 598 | "$(inherited)", 599 | "@executable_path/Frameworks", 600 | ); 601 | MARKETING_VERSION = 1.0; 602 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 603 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 604 | PROVISIONING_PROFILE_SPECIFIER = ""; 605 | SDKROOT = iphoneos; 606 | SWIFT_EMIT_LOC_STRINGS = YES; 607 | SWIFT_VERSION = 5.0; 608 | TARGETED_DEVICE_FAMILY = "1,2"; 609 | VALIDATE_PRODUCT = YES; 610 | }; 611 | name = Release; 612 | }; 613 | CB7F7B0B287DEEC600E789D3 /* Debug */ = { 614 | isa = XCBuildConfiguration; 615 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 616 | buildSettings = { 617 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 618 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 619 | CODE_SIGN_ENTITLEMENTS = Configuration/macOS.entitlements; 620 | CODE_SIGN_STYLE = Automatic; 621 | COMBINE_HIDPI_IMAGES = YES; 622 | CURRENT_PROJECT_VERSION = 1; 623 | DEVELOPMENT_TEAM = ""; 624 | ENABLE_HARDENED_RUNTIME = YES; 625 | ENABLE_PREVIEWS = YES; 626 | GENERATE_INFOPLIST_FILE = YES; 627 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 628 | LD_RUNPATH_SEARCH_PATHS = ( 629 | "$(inherited)", 630 | "@executable_path/../Frameworks", 631 | ); 632 | MACOSX_DEPLOYMENT_TARGET = 12.3; 633 | MARKETING_VERSION = 1.0; 634 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 635 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 636 | SDKROOT = macosx; 637 | SWIFT_EMIT_LOC_STRINGS = YES; 638 | SWIFT_VERSION = 5.0; 639 | }; 640 | name = Debug; 641 | }; 642 | CB7F7B0C287DEEC600E789D3 /* Release */ = { 643 | isa = XCBuildConfiguration; 644 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 645 | buildSettings = { 646 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 647 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 648 | CODE_SIGN_ENTITLEMENTS = Configuration/macOS.entitlements; 649 | CODE_SIGN_STYLE = Automatic; 650 | COMBINE_HIDPI_IMAGES = YES; 651 | CURRENT_PROJECT_VERSION = 1; 652 | DEVELOPMENT_TEAM = ""; 653 | ENABLE_HARDENED_RUNTIME = YES; 654 | ENABLE_PREVIEWS = YES; 655 | GENERATE_INFOPLIST_FILE = YES; 656 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 657 | LD_RUNPATH_SEARCH_PATHS = ( 658 | "$(inherited)", 659 | "@executable_path/../Frameworks", 660 | ); 661 | MACOSX_DEPLOYMENT_TARGET = 12.3; 662 | MARKETING_VERSION = 1.0; 663 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 664 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 665 | SDKROOT = macosx; 666 | SWIFT_EMIT_LOC_STRINGS = YES; 667 | SWIFT_VERSION = 5.0; 668 | }; 669 | name = Release; 670 | }; 671 | CB7F7B2F287DEEF900E789D3 /* Debug */ = { 672 | isa = XCBuildConfiguration; 673 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 674 | buildSettings = { 675 | CODE_SIGN_STYLE = Automatic; 676 | CURRENT_PROJECT_VERSION = 1; 677 | DEVELOPMENT_ASSET_PATHS = ""; 678 | DEVELOPMENT_TEAM = ""; 679 | ENABLE_PREVIEWS = YES; 680 | GENERATE_INFOPLIST_FILE = YES; 681 | INFOPLIST_FILE = Configuration/watchOS.plist; 682 | INFOPLIST_KEY_CFBundleDisplayName = "SwiftUIWeeklyLayoutChallengeApp WatchKit Extension"; 683 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 684 | INFOPLIST_KEY_WKWatchOnly = YES; 685 | LD_RUNPATH_SEARCH_PATHS = ( 686 | "$(inherited)", 687 | "@executable_path/Frameworks", 688 | "@executable_path/../../Frameworks", 689 | ); 690 | MARKETING_VERSION = 1.0; 691 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}.watchkitapp.watchkitextension"; 692 | PRODUCT_NAME = "${TARGET_NAME}"; 693 | SDKROOT = watchos; 694 | SKIP_INSTALL = YES; 695 | SWIFT_EMIT_LOC_STRINGS = YES; 696 | SWIFT_VERSION = 5.0; 697 | TARGETED_DEVICE_FAMILY = 4; 698 | WATCHOS_DEPLOYMENT_TARGET = 8.5; 699 | }; 700 | name = Debug; 701 | }; 702 | CB7F7B30287DEEF900E789D3 /* Release */ = { 703 | isa = XCBuildConfiguration; 704 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 705 | buildSettings = { 706 | CODE_SIGN_STYLE = Automatic; 707 | CURRENT_PROJECT_VERSION = 1; 708 | DEVELOPMENT_ASSET_PATHS = ""; 709 | DEVELOPMENT_TEAM = ""; 710 | ENABLE_PREVIEWS = YES; 711 | GENERATE_INFOPLIST_FILE = YES; 712 | INFOPLIST_FILE = Configuration/watchOS.plist; 713 | INFOPLIST_KEY_CFBundleDisplayName = "SwiftUIWeeklyLayoutChallengeApp WatchKit Extension"; 714 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 715 | INFOPLIST_KEY_WKWatchOnly = YES; 716 | LD_RUNPATH_SEARCH_PATHS = ( 717 | "$(inherited)", 718 | "@executable_path/Frameworks", 719 | "@executable_path/../../Frameworks", 720 | ); 721 | MARKETING_VERSION = 1.0; 722 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}.watchkitapp.watchkitextension"; 723 | PRODUCT_NAME = "${TARGET_NAME}"; 724 | SDKROOT = watchos; 725 | SKIP_INSTALL = YES; 726 | SWIFT_EMIT_LOC_STRINGS = YES; 727 | SWIFT_VERSION = 5.0; 728 | TARGETED_DEVICE_FAMILY = 4; 729 | VALIDATE_PRODUCT = YES; 730 | WATCHOS_DEPLOYMENT_TARGET = 8.5; 731 | }; 732 | name = Release; 733 | }; 734 | CB7F7B33287DEEF900E789D3 /* Debug */ = { 735 | isa = XCBuildConfiguration; 736 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 737 | buildSettings = { 738 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 739 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 740 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 741 | CODE_SIGN_STYLE = Automatic; 742 | CURRENT_PROJECT_VERSION = 1; 743 | DEVELOPMENT_TEAM = ""; 744 | GENERATE_INFOPLIST_FILE = YES; 745 | IBSC_MODULE = SwiftUIWeeklyLayoutChallenge__watchOS__WatchKit_Extension; 746 | INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; 747 | MARKETING_VERSION = 1.0; 748 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}.watchkitapp"; 749 | PRODUCT_NAME = "SwiftUIWeeklyLayoutChallengeApp WatchKit App"; 750 | SDKROOT = watchos; 751 | SKIP_INSTALL = YES; 752 | SWIFT_EMIT_LOC_STRINGS = YES; 753 | SWIFT_VERSION = 5.0; 754 | TARGETED_DEVICE_FAMILY = 4; 755 | WATCHOS_DEPLOYMENT_TARGET = 8.5; 756 | }; 757 | name = Debug; 758 | }; 759 | CB7F7B34287DEEF900E789D3 /* Release */ = { 760 | isa = XCBuildConfiguration; 761 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 762 | buildSettings = { 763 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 764 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 765 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 766 | CODE_SIGN_STYLE = Automatic; 767 | CURRENT_PROJECT_VERSION = 1; 768 | DEVELOPMENT_TEAM = ""; 769 | GENERATE_INFOPLIST_FILE = YES; 770 | IBSC_MODULE = SwiftUIWeeklyLayoutChallenge__watchOS__WatchKit_Extension; 771 | INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown"; 772 | MARKETING_VERSION = 1.0; 773 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}.watchkitapp"; 774 | PRODUCT_NAME = "SwiftUIWeeklyLayoutChallengeApp WatchKit App"; 775 | SDKROOT = watchos; 776 | SKIP_INSTALL = YES; 777 | SWIFT_EMIT_LOC_STRINGS = YES; 778 | SWIFT_VERSION = 5.0; 779 | TARGETED_DEVICE_FAMILY = 4; 780 | VALIDATE_PRODUCT = YES; 781 | WATCHOS_DEPLOYMENT_TARGET = 8.5; 782 | }; 783 | name = Release; 784 | }; 785 | CB7F7B37287DEEF900E789D3 /* Debug */ = { 786 | isa = XCBuildConfiguration; 787 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 788 | buildSettings = { 789 | CODE_SIGN_STYLE = Automatic; 790 | CURRENT_PROJECT_VERSION = 1; 791 | DEVELOPMENT_TEAM = ""; 792 | MARKETING_VERSION = 1.0; 793 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 794 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 795 | SDKROOT = iphoneos; 796 | SWIFT_VERSION = 5.0; 797 | }; 798 | name = Debug; 799 | }; 800 | CB7F7B38287DEEF900E789D3 /* Release */ = { 801 | isa = XCBuildConfiguration; 802 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 803 | buildSettings = { 804 | CODE_SIGN_STYLE = Automatic; 805 | CURRENT_PROJECT_VERSION = 1; 806 | DEVELOPMENT_TEAM = ""; 807 | MARKETING_VERSION = 1.0; 808 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 809 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 810 | SDKROOT = iphoneos; 811 | SWIFT_VERSION = 5.0; 812 | VALIDATE_PRODUCT = YES; 813 | }; 814 | name = Release; 815 | }; 816 | CB7F7B4D287DF16700E789D3 /* Debug */ = { 817 | isa = XCBuildConfiguration; 818 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 819 | buildSettings = { 820 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 821 | CODE_SIGN_STYLE = Automatic; 822 | CURRENT_PROJECT_VERSION = 1; 823 | DEVELOPMENT_ASSET_PATHS = ""; 824 | DEVELOPMENT_TEAM = ""; 825 | ENABLE_PREVIEWS = YES; 826 | GENERATE_INFOPLIST_FILE = YES; 827 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 828 | INFOPLIST_KEY_UIUserInterfaceStyle = Automatic; 829 | LD_RUNPATH_SEARCH_PATHS = ( 830 | "$(inherited)", 831 | "@executable_path/Frameworks", 832 | ); 833 | MARKETING_VERSION = 1.0; 834 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 835 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 836 | SDKROOT = appletvos; 837 | SWIFT_EMIT_LOC_STRINGS = YES; 838 | SWIFT_VERSION = 5.0; 839 | TARGETED_DEVICE_FAMILY = 3; 840 | TVOS_DEPLOYMENT_TARGET = 15.4; 841 | }; 842 | name = Debug; 843 | }; 844 | CB7F7B4E287DF16700E789D3 /* Release */ = { 845 | isa = XCBuildConfiguration; 846 | baseConfigurationReference = CB5D43572881DAD1001B5EA1 /* Disambiguator.xcconfig */; 847 | buildSettings = { 848 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; 849 | CODE_SIGN_STYLE = Automatic; 850 | CURRENT_PROJECT_VERSION = 1; 851 | DEVELOPMENT_ASSET_PATHS = ""; 852 | DEVELOPMENT_TEAM = ""; 853 | ENABLE_PREVIEWS = YES; 854 | GENERATE_INFOPLIST_FILE = YES; 855 | INFOPLIST_KEY_UILaunchScreen_Generation = YES; 856 | INFOPLIST_KEY_UIUserInterfaceStyle = Automatic; 857 | LD_RUNPATH_SEARCH_PATHS = ( 858 | "$(inherited)", 859 | "@executable_path/Frameworks", 860 | ); 861 | MARKETING_VERSION = 1.0; 862 | PRODUCT_BUNDLE_IDENTIFIER = "com.example.jp.tret.SwiftUIWeeklyLayoutChallengeApp${DISAMBIGUATOR}"; 863 | PRODUCT_NAME = SwiftUIWeeklyLayoutChallengeApp; 864 | SDKROOT = appletvos; 865 | SWIFT_EMIT_LOC_STRINGS = YES; 866 | SWIFT_VERSION = 5.0; 867 | TARGETED_DEVICE_FAMILY = 3; 868 | TVOS_DEPLOYMENT_TARGET = 15.4; 869 | VALIDATE_PRODUCT = YES; 870 | }; 871 | name = Release; 872 | }; 873 | /* End XCBuildConfiguration section */ 874 | 875 | /* Begin XCConfigurationList section */ 876 | CB7F7AED287DEEC500E789D3 /* Build configuration list for PBXProject "SwiftUIWeeklyLayoutChallenge" */ = { 877 | isa = XCConfigurationList; 878 | buildConfigurations = ( 879 | CB7F7B05287DEEC600E789D3 /* Debug */, 880 | CB7F7B06287DEEC600E789D3 /* Release */, 881 | ); 882 | defaultConfigurationIsVisible = 0; 883 | defaultConfigurationName = Release; 884 | }; 885 | CB7F7B07287DEEC600E789D3 /* Build configuration list for PBXNativeTarget "iOS App" */ = { 886 | isa = XCConfigurationList; 887 | buildConfigurations = ( 888 | CB7F7B08287DEEC600E789D3 /* Debug */, 889 | CB7F7B09287DEEC600E789D3 /* Release */, 890 | ); 891 | defaultConfigurationIsVisible = 0; 892 | defaultConfigurationName = Release; 893 | }; 894 | CB7F7B0A287DEEC600E789D3 /* Build configuration list for PBXNativeTarget "macOS App" */ = { 895 | isa = XCConfigurationList; 896 | buildConfigurations = ( 897 | CB7F7B0B287DEEC600E789D3 /* Debug */, 898 | CB7F7B0C287DEEC600E789D3 /* Release */, 899 | ); 900 | defaultConfigurationIsVisible = 0; 901 | defaultConfigurationName = Release; 902 | }; 903 | CB7F7B2E287DEEF900E789D3 /* Build configuration list for PBXNativeTarget "watchOS WatchKit Extension" */ = { 904 | isa = XCConfigurationList; 905 | buildConfigurations = ( 906 | CB7F7B2F287DEEF900E789D3 /* Debug */, 907 | CB7F7B30287DEEF900E789D3 /* Release */, 908 | ); 909 | defaultConfigurationIsVisible = 0; 910 | defaultConfigurationName = Release; 911 | }; 912 | CB7F7B32287DEEF900E789D3 /* Build configuration list for PBXNativeTarget "watchOS WatchKit App" */ = { 913 | isa = XCConfigurationList; 914 | buildConfigurations = ( 915 | CB7F7B33287DEEF900E789D3 /* Debug */, 916 | CB7F7B34287DEEF900E789D3 /* Release */, 917 | ); 918 | defaultConfigurationIsVisible = 0; 919 | defaultConfigurationName = Release; 920 | }; 921 | CB7F7B36287DEEF900E789D3 /* Build configuration list for PBXNativeTarget "watchOS App" */ = { 922 | isa = XCConfigurationList; 923 | buildConfigurations = ( 924 | CB7F7B37287DEEF900E789D3 /* Debug */, 925 | CB7F7B38287DEEF900E789D3 /* Release */, 926 | ); 927 | defaultConfigurationIsVisible = 0; 928 | defaultConfigurationName = Release; 929 | }; 930 | CB7F7B4C287DF16700E789D3 /* Build configuration list for PBXNativeTarget "tvOS App" */ = { 931 | isa = XCConfigurationList; 932 | buildConfigurations = ( 933 | CB7F7B4D287DF16700E789D3 /* Debug */, 934 | CB7F7B4E287DF16700E789D3 /* Release */, 935 | ); 936 | defaultConfigurationIsVisible = 0; 937 | defaultConfigurationName = Release; 938 | }; 939 | /* End XCConfigurationList section */ 940 | 941 | /* Begin XCSwiftPackageProductDependency section */ 942 | CB0D88A1288279C800E61609 /* SwiftUIWeeklyLayoutChallenge */ = { 943 | isa = XCSwiftPackageProductDependency; 944 | productName = SwiftUIWeeklyLayoutChallenge; 945 | }; 946 | CB0D88A3288279D200E61609 /* SwiftUIWeeklyLayoutChallenge */ = { 947 | isa = XCSwiftPackageProductDependency; 948 | productName = SwiftUIWeeklyLayoutChallenge; 949 | }; 950 | CB0D88A5288279D900E61609 /* SwiftUIWeeklyLayoutChallenge */ = { 951 | isa = XCSwiftPackageProductDependency; 952 | productName = SwiftUIWeeklyLayoutChallenge; 953 | }; 954 | CB0D88A7288279E200E61609 /* SwiftUIWeeklyLayoutChallenge */ = { 955 | isa = XCSwiftPackageProductDependency; 956 | productName = SwiftUIWeeklyLayoutChallenge; 957 | }; 958 | /* End XCSwiftPackageProductDependency section */ 959 | }; 960 | rootObject = CB7F7AEA287DEEC500E789D3 /* Project object */; 961 | } 962 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | /*.xcodeproj 5 | xcuserdata/ 6 | DerivedData/ 7 | .swiftpm/config/registries.json 8 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 9 | .netrc 10 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/07/13. 6 | // 7 | 8 | import SwiftUI 9 | 10 | public typealias ContentView = TopicXXXView 11 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Regulations/RegulationsV1.md: -------------------------------------------------------------------------------- 1 | # SwiftUIレイアウト一本勝負 レギュレーション v1 2 | 3 | \#SwiftUIレイアウト一本勝負 レギュレーション v1 4 | 5 | 1. お題のスクリーンショットを SwiftUI でトレース、レイアウトを組んでください。 6 | 1. 特別な指定がない場合、サポートするデバイスや OS、そのバージョンは各自で決めてください。 7 | 1. 特別な指定がない場合、コーディング時に便利なデータのサンプルや各種数値の明示はありませんので、お題のスクリーンショットとの差分が限りなく無い状態を目指してください。 8 | 1. 完成したら SwiftUI のコードを [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) をつけてツイートしてください。 9 | 1. 上記ツイート時、書いたコードはツイート本文に書くでも、エディタ等のスクリーンショットを追加してもよいですし、Gist や Zenn、Qiita などに書いてそこへのリンクを併記する方法を取っても構いません。 10 | 11 | [https://twitter.com/treastrain/status/1547151607938560000](https://twitter.com/treastrain/status/1547151607938560000) 12 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_iOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_macOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_macOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_tvOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_tvOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_watchOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic001_watchOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic002_iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic002_iOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic002_tvOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic002_tvOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic002_watchOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic002_watchOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_iOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_macOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_macOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_tvOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_tvOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_watchOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic003_watchOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_iOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_iOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_macOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_macOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_tvOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_tvOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_watchOS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic004_watchOS.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_iOS-Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_iOS-Dark.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_iOS-Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_iOS-Light.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_macOS-Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_macOS-Dark.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_macOS-Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic005_macOS-Light.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic006_iPadmini6thGen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic006_iPadmini6thGen.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic006_iPhone13mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic006_iPhone13mini.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic006_iPhoneSE3rdGen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic006_iPhoneSE3rdGen.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_1.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_2.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_3.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic007_iPhone13mini_4.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_1.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_2.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_3.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic008_iPhone14Pro_4.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro.mp4 -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_1.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_2.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_3.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/treastrain/SwiftUIWeeklyLayoutChallenge/bdf801d46022a29e96f3c42f73fad433cfb39deb/SwiftUIWeeklyLayoutChallenge/Documentation.docc/Resources/Topic009_iPhone14Pro_4.png -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/SwiftUIWeeklyLayoutChallenge.md: -------------------------------------------------------------------------------- 1 | # ``SwiftUIWeeklyLayoutChallenge`` 2 | 3 | SwiftUIレイアウト一本勝負 4 | 5 | ## Overview 6 | [#SwiftUIレイアウト一本勝負](https://twitter.com/search?q=%23SwiftUI%E3%83%AC%E3%82%A4%E3%82%A2%E3%82%A6%E3%83%88%E4%B8%80%E6%9C%AC%E5%8B%9D%E8%B2%A0) は、「お題」として Twitter に投稿されたスクリーンショットをもとに、その UI レイアウトを各々が SwiftUI で構成、それをインターネット上で共有し合うイベントです。 7 | 8 | 詳しくは GitHub の [treastrain/SwiftUIWeeklyLayoutChallenge](https://github.com/treastrain/SwiftUIWeeklyLayoutChallenge) をご覧ください。 9 | 10 | ## Topics 11 | ### レギュレーション 12 | - 13 | 14 | ### お題 15 | - 16 | - 17 | - 18 | - 19 | - 20 | - 21 | - 22 | - 23 | - 24 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic001.md: -------------------------------------------------------------------------------- 1 | # お題 001 2 | 3 | サイコロの「5」の目状にテキストを配置 4 | 5 | - サイコロの「5」の目のように「Hello, world!」を配置してください 6 | - 画面サイズが小さいデバイスの場合は、上前端(top & leading)と下後端(bottom & trailing)の位置に来るテキストを優先して(=可能な限り改行させないで)表示してください 7 | 8 | |iOS|macOS|tvOS|watchOS| 9 | |:-:|:-:|:-:|:-:| 10 | |![](Topic001_iOS)|![](Topic001_macOS)|![](Topic001_tvOS)|![](Topic001_watchOS)| 11 | 12 | ## お題作成者 13 | treastrain ([@treastrain](https://twitter.com/treastrain)) 14 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic002.md: -------------------------------------------------------------------------------- 1 | # お題 002 2 | 3 | ナビゲーション構造のリスト 4 | 5 | - ナビゲーション階層による画面遷移を前提としてください(NavigationLink を用いてください) 6 | - macOS App は考慮しなくてよいこととします 7 | - エンティティ・サンプルデータ の提供があります(`Topic002View.swift` を参照、利用は必須ではありません) 8 | 9 | |iOS|tvOS|watchOS| 10 | |:-:|:-:|:-:| 11 | |![](Topic002_iOS)|![](Topic002_tvOS)|![](Topic002_watchOS)| 12 | 13 | ## お題作成者 14 | treastrain ([@treastrain](https://twitter.com/treastrain)) 15 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic003.md: -------------------------------------------------------------------------------- 1 | # お題 003 2 | 3 | 出発信号機 4 | 5 | - Picker を用いて色を選択可能にしてください 6 | - 色のパターンが一致した場合、指差喚呼用の文字を表示してください 7 | - iOS 14.0+、macOS 11.0+、tvOS 14.0+、watchOS 7.0+ を前提とします 8 | - コードの一部提供があります(利用は必須ではありません) 9 | - [Bonus] 指差喚呼用の文字(出発進行 など)の部分をタップして選択肢を表示させて、そこでも色を変えられるようにしてください 10 | - (iOS App の動作イメージ)[https://twitter.com/treastrain/status/1552168376113729536](https://twitter.com/treastrain/status/1552168376113729536) 11 | 12 | |iOS|macOS|tvOS|watchOS| 13 | |:-:|:-:|:-:|:-:| 14 | |![](Topic003_iOS)|![](Topic003_macOS)|![](Topic003_tvOS)|![](Topic003_watchOS)| 15 | 16 | ## コード提供 17 | ```swift 18 | import SwiftUI 19 | 20 | /// 21 | public struct Topic003View: View { 22 | public init() {} 23 | 24 | public var body: some View { 25 | if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { 26 | #if os(macOS) 27 | DepartureSignal() 28 | .padding() 29 | #else 30 | if #available(watchOS 7.0, *) { 31 | NavigationView { 32 | DepartureSignal() 33 | } 34 | } else { 35 | DepartureSignal() 36 | } 37 | #endif 38 | } else { 39 | Text("Support for this platform is not considered.") 40 | } 41 | } 42 | } 43 | 44 | @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) 45 | struct DepartureSignal: View { 46 | enum Signal: String, CaseIterable, Identifiable { 47 | /// 上の灯火から順に 消・消・緑・消 で進行信号を現示。 48 | case 出発進行 49 | /// 上の灯火から順に 黄・消・消・緑 で減速信号を現示。 50 | case 出発減速 51 | /// 上の灯火から順に 消・消・消・黄 で注意信号を現示。 52 | case 出発注意 53 | /// 上の灯火から順に 黄・消・消・黄 で警戒信号を現示。 54 | case 出発警戒 55 | /// 上の灯火から順に 消・赤・消・消 で停止信号を現示。 56 | case 出発停止 57 | 58 | var id: String { rawValue } 59 | } 60 | 61 | var body: some View { 62 | Text("Code your layout here!") 63 | } 64 | 65 | var light: some View { 66 | Image(systemName: "circle.fill") 67 | .font(.largeTitle) 68 | } 69 | } 70 | ``` 71 | 72 | ## お題作成者 73 | treastrain ([@treastrain](https://twitter.com/treastrain)) 74 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic004.md: -------------------------------------------------------------------------------- 1 | # お題 004 2 | 3 | 角の丸い2つのボタン 4 | 5 | - 2から100までの数字をランダムに表示してください 6 | - その数字が素数か合成数かを、ユーザーがボタンで回答できるようにします 7 | - ボタンをタップしたときの挙動などの明示はありません 8 | - iOS 15.0+、macOS 12.0+、tvOS 15.0+、watchOS 8.0+ を前提とします 9 | 10 | |iOS|macOS|tvOS|watchOS| 11 | |:-:|:-:|:-:|:-:| 12 | |![](Topic004_iOS)|![](Topic004_macOS)|![](Topic004_tvOS)|![](Topic004_watchOS)| 13 | 14 | ## コード提供 15 | ```swift 16 | import SwiftUI 17 | 18 | /// 19 | public struct Topic004View: View { 20 | public init() {} 21 | 22 | public var body: some View { 23 | if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { 24 | content 25 | } else { 26 | Text("Support for this platform is not considered.") 27 | } 28 | } 29 | 30 | @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) 31 | private var content: some View { 32 | Text("Code your layout here!") 33 | } 34 | } 35 | ``` 36 | 37 | ## お題作成者 38 | treastrain ([@treastrain](https://twitter.com/treastrain)) 39 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic005.md: -------------------------------------------------------------------------------- 1 | # お題 005 2 | 3 | グループ構造を示すスタイル 4 | 5 | - 表示可能領域が不足する場合に備えてスクロール可能にします 6 | - iOS 15.0+、macOS 12.0+ を前提とします 7 | - [Bonus] 最上部の「#SwiftUIレイアウト一本勝負」の文字色を虹色にしてください 8 | 9 | |iOS (Light)|iOS (Dark)|macOS (Light)|macOS (Dark)| 10 | |:-:|:-:|:-:|:-:| 11 | |![](Topic005_iOS-Light)|![](Topic005_iOS-Dark)|![](Topic005_macOS-Light)|![](Topic005_macOS-Dark)| 12 | 13 | ## コード提供 14 | ```swift 15 | import SwiftUI 16 | 17 | /// 18 | public struct Topic005View: View { 19 | public init() {} 20 | 21 | public var body: some View { 22 | #if os(iOS) || os(macOS) 23 | if #available(iOS 15.0, macOS 12.0, *) { 24 | Topic005ContentView() 25 | } else { 26 | Text("Support for this platform is not considered.") 27 | } 28 | #else 29 | Text("Support for this platform is not considered.") 30 | #endif 31 | } 32 | } 33 | 34 | #if os(iOS) || os(macOS) 35 | @available(iOS 15.0, macOS 12.0, *) 36 | fileprivate struct Topic005ContentView: View { 37 | var body: some View { 38 | Text("Code your layout here!") 39 | } 40 | } 41 | #endif 42 | ``` 43 | 44 | ## お題作成者 45 | treastrain ([@treastrain](https://twitter.com/treastrain)) 46 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic006.md: -------------------------------------------------------------------------------- 1 | # お題 006 2 | 3 | ユーザーが自由に配置できるビュー 4 | 5 | - タップするとアラートが表示されるビューを、下後端からそれぞれ16の位置に配置してください 6 | - そのビューは長押しをすることで別な選択肢が表示され、ドラッグで表示位置を変更できます 7 | - iOS 15.0+ を前提とし、描画サイズの変化(端末の回転など)は考慮しません 8 | - (App の動作イメージ)[https://twitter.com/treastrain/status/1559742341636030464](https://twitter.com/treastrain/status/1559742341636030464) 9 | 10 | |iPhone 13 mini|iPhone SE (3rd generation)|iPad mini (6th generation)| 11 | |:-:|:-:|:-:| 12 | |![](Topic006_iPhone13mini)|![](Topic006_iPhoneSE3rdGen)|![](Topic006_iPadmini6thGen)| 13 | 14 | ## コード提供 15 | ```swift 16 | import SwiftUI 17 | 18 | /// 19 | public struct Topic006View: View { 20 | public init() {} 21 | 22 | public var body: some View { 23 | #if os(iOS) 24 | if #available(iOS 15.0, *) { 25 | Topic006ContentView() 26 | } else { 27 | Text("Support for this platform is not considered.") 28 | } 29 | #else 30 | Text("Support for this platform is not considered.") 31 | #endif 32 | } 33 | } 34 | 35 | #if os(iOS) 36 | @available(iOS 15.0, *) 37 | fileprivate struct Topic006ContentView: View { 38 | private let paddingLength: CGFloat = 16 39 | 40 | var body: some View { 41 | Text("Code your layout here!") 42 | } 43 | } 44 | #endif 45 | ``` 46 | 47 | ## お題作成者 48 | treastrain ([@treastrain](https://twitter.com/treastrain)) 49 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic007.md: -------------------------------------------------------------------------------- 1 | # お題 007 2 | 3 | ナンバーパッド 4 | 5 | - 数字、\*、# をタップすると、順に画面上部にそれらが表示されます 6 | - 画面下後端のボタンをタップすると、上記の入力内容を1つ削除します 7 | - 画面上部の表示を長押しすると、コピー等のためのメニューを表示します 8 | - iOS 15.0+ の iPhone(Portrait)のみを考慮します 9 | 10 | |動作プレビュー1|動作プレビュー2|動作プレビュー3|動作プレビュー4| 11 | |:-:|:-:|:-:|:-:| 12 | |![](Topic007_iPhone13mini_1)|![](Topic007_iPhone13mini_2)|![](Topic007_iPhone13mini_3)|![](Topic007_iPhone13mini_4)| 13 | 14 | ## コード提供 15 | ```swift 16 | import SwiftUI 17 | 18 | /// 19 | public struct Topic007View: View { 20 | public init() {} 21 | 22 | public var body: some View { 23 | #if os(iOS) 24 | if #available(iOS 15.0, *) { 25 | Topic007ContentView() 26 | } else { 27 | Text("Support for this platform is not considered.") 28 | } 29 | #else 30 | Text("Support for this platform is not considered.") 31 | #endif 32 | } 33 | } 34 | 35 | #if os(iOS) 36 | @available(iOS 15.0, *) 37 | fileprivate struct Topic007ContentView: View { 38 | public var body: some View { 39 | Text("Code your layout here!") 40 | } 41 | } 42 | #endif 43 | ``` 44 | 45 | ## お題作成者 46 | treastrain ([@treastrain](https://twitter.com/treastrain)) 47 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic008.md: -------------------------------------------------------------------------------- 1 | # お題 008 2 | 3 | アプリ一覧 - その1 4 | 5 | - App アイコン(を模したイメージ)、App の名前、サブタイトル、「入手」ボタンを配置してください 6 | - 要素と要素の間に限り、水平線を表示してください 7 | - タップの反応領域は「入手」ボタンのみです 8 | - iOS 15.0+ の iPhone のみを考慮します 9 | 10 | |動作プレビュー1|動作プレビュー2|動作プレビュー3|動作プレビュー4| 11 | |:-:|:-:|:-:|:-:| 12 | |![](Topic008_iPhone14Pro_1)|![](Topic008_iPhone14Pro_2)|![](Topic008_iPhone14Pro_3)|![](Topic008_iPhone14Pro_4)| 13 | 14 | ## コード提供 15 | ```swift 16 | import SwiftUI 17 | 18 | /// 19 | public struct Topic008View: View { 20 | public init() {} 21 | 22 | public var body: some View { 23 | #if os(iOS) 24 | if #available(iOS 15.0, *) { 25 | NavigationView { 26 | NavigationContentView() 27 | } 28 | } else { 29 | Text("Support for this platform is not considered.") 30 | } 31 | #else 32 | Text("Support for this platform is not considered.") 33 | #endif 34 | } 35 | } 36 | 37 | #if os(iOS) 38 | fileprivate struct AppInfo: Identifiable, Equatable { 39 | let id = UUID() 40 | let color: Color 41 | let name: String 42 | let subtitle: String 43 | 44 | static func == (lhs: Self, rhs: Self) -> Bool { 45 | return lhs.id == rhs.id 46 | } 47 | } 48 | 49 | @available(iOS 15.0, *) 50 | fileprivate struct NavigationContentView: View { 51 | private let appInfo: [AppInfo] = [ 52 | .init(color: .orange, name: "App Name 1", subtitle: "Subtitle 1"), 53 | .init(color: .yellow, name: "アプリ名 2", subtitle: "サブタイトル 2"), 54 | .init(color: .green, name: "Long App Name 3 - Long App Name 3", subtitle: "Subtitle 3"), 55 | .init(color: .mint, name: "長い長いアプリ名 4 - 長い長いアプリ名 4 - 長い長いアプリ名 4", subtitle: "サブタイトル 4"), 56 | .init(color: .teal, name: "Long App Name 5 - Long App Name 5", subtitle: "Long Subtitle 5 - Long Subtitle 5"), 57 | .init(color: .cyan, name: "長い長いアプリ名 6 - 長い長いアプリ名 6 - 長い長いアプリ名 6", subtitle: "長い長いサブタイトル 6 - 長い長いサブタイトル 6"), 58 | .init(color: .blue, name: "App Name 7", subtitle: "Subtitle 7"), 59 | .init(color: .indigo, name: "アプリ名 8", subtitle: "サブタイトル 8"), 60 | .init(color: .purple, name: "App Name 9", subtitle: "Subtitle 9"), 61 | .init(color: .pink, name: "アプリ名 10", subtitle: "Subtitle 10"), 62 | ] 63 | 64 | var body: some View { 65 | Text("Code your layout here!") 66 | } 67 | } 68 | #endif 69 | ``` 70 | 71 | ## お題作成者 72 | treastrain ([@treastrain](https://twitter.com/treastrain)) 73 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Documentation.docc/Topics/Topic009.md: -------------------------------------------------------------------------------- 1 | # お題 009 2 | 3 | アプリ一覧 - その2 4 | 5 | - のように、App アイコン、App の名前、サブタイトル、唯一タップ可能な「入手」ボタン、水平線を配置してください 6 | - 各 App の情報は垂直方向に3つずつ表示し、それ以降は水平方向のスクロールで表示します 7 | - iOS 15.0+ の iPhone のみを考慮します 8 | - (App の動作イメージ)[https://twitter.com/treastrain/status/1577672247195541535](https://twitter.com/treastrain/status/1577672247195541535) 9 | 10 | |動作プレビュー1|動作プレビュー2|動作プレビュー3|動作プレビュー4| 11 | |:-:|:-:|:-:|:-:| 12 | |![](Topic009_iPhone14Pro_1)|![](Topic009_iPhone14Pro_2)|![](Topic009_iPhone14Pro_3)|![](Topic009_iPhone14Pro_4)| 13 | 14 | ## コード提供 15 | ```swift 16 | import SwiftUI 17 | 18 | /// 19 | public struct Topic009View: View { 20 | public init() {} 21 | 22 | public var body: some View { 23 | #if os(iOS) 24 | if #available(iOS 15.0, *) { 25 | NavigationView { 26 | NavigationContentView() 27 | } 28 | } else { 29 | Text("Support for this platform is not considered.") 30 | } 31 | #else 32 | Text("Support for this platform is not considered.") 33 | #endif 34 | } 35 | } 36 | 37 | #if os(iOS) 38 | fileprivate struct AppInfo: Identifiable, Equatable { 39 | let id = UUID() 40 | let color: Color 41 | let name: String 42 | let subtitle: String 43 | 44 | static func == (lhs: Self, rhs: Self) -> Bool { 45 | return lhs.id == rhs.id 46 | } 47 | } 48 | 49 | @available(iOS 15.0, *) 50 | fileprivate struct NavigationContentView: View { 51 | private let appInfo: [AppInfo] = [ 52 | .init(color: .orange, name: "App Name 1", subtitle: "Subtitle 1"), 53 | .init(color: .yellow, name: "アプリ名 2", subtitle: "サブタイトル 2"), 54 | .init(color: .green, name: "Long App Name 3 - Long App Name 3", subtitle: "Subtitle 3"), 55 | .init(color: .mint, name: "長い長いアプリ名 4 - 長い長いアプリ名 4 - 長い長いアプリ名 4", subtitle: "サブタイトル 4"), 56 | .init(color: .teal, name: "Long App Name 5 - Long App Name 5", subtitle: "Long Subtitle 5 - Long Subtitle 5"), 57 | .init(color: .cyan, name: "長い長いアプリ名 6 - 長い長いアプリ名 6 - 長い長いアプリ名 6", subtitle: "長い長いサブタイトル 6 - 長い長いサブタイトル 6"), 58 | .init(color: .blue, name: "App Name 7", subtitle: "Subtitle 7"), 59 | .init(color: .indigo, name: "アプリ名 8", subtitle: "サブタイトル 8"), 60 | .init(color: .purple, name: "App Name 9", subtitle: "Subtitle 9"), 61 | ] 62 | 63 | var body: some View { 64 | Text("Code your layout here!") 65 | } 66 | } 67 | 68 | @available(iOS 15.0, *) 69 | /// より 70 | fileprivate struct AppView: View { 71 | static let horizontalSpacing: CGFloat = 8 72 | static let appIconSize: CGFloat = 64 73 | 74 | let info: AppInfo 75 | 76 | var body: some View { 77 | HStack(spacing: Self.horizontalSpacing) { 78 | Image(systemName: "app.fill") 79 | .resizable() 80 | .foregroundColor(info.color) 81 | .frame(width: Self.appIconSize, height: Self.appIconSize) 82 | VStack(alignment: .leading, spacing: 5) { 83 | Text(info.name) 84 | .lineLimit(2) 85 | Text(info.subtitle) 86 | .lineLimit(1) 87 | .font(.footnote) 88 | .foregroundColor(.secondary) 89 | } 90 | .frame(maxWidth: .infinity, alignment: .leading) 91 | Button { 92 | print(#function) 93 | } label: { 94 | Text("入手") 95 | .font(.headline) 96 | .padding(.horizontal, 8) 97 | } 98 | .buttonStyle(.bordered) 99 | .buttonBorderShape(.capsule) 100 | } 101 | .frame(maxWidth: .infinity) 102 | } 103 | } 104 | #endif 105 | ``` 106 | 107 | ## お題作成者 108 | treastrain ([@treastrain](https://twitter.com/treastrain)) 109 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.5 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "SwiftUIWeeklyLayoutChallenge", 7 | defaultLocalization: "ja", 8 | platforms: [.iOS(.v13), .macOS(.v10_15), .macCatalyst(.v13), .tvOS(.v13), .watchOS(.v6)], 9 | products: [ 10 | .library( 11 | name: "SwiftUIWeeklyLayoutChallenge", 12 | targets: ["SwiftUIWeeklyLayoutChallenge"]), 13 | ], 14 | targets: [ 15 | .target( 16 | name: "SwiftUIWeeklyLayoutChallenge", 17 | path: "."), 18 | ] 19 | ) 20 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic001.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic001.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/07/13. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic001View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | VStack { 16 | HStack { 17 | Text("Hello, world!") 18 | .layoutPriority(1) 19 | Spacer() 20 | Text("Hello, world!") 21 | } 22 | Spacer() 23 | Text("Hello, world!") 24 | Spacer() 25 | HStack { 26 | Text("Hello, world!") 27 | Spacer() 28 | Text("Hello, world!") 29 | .layoutPriority(1) 30 | } 31 | } 32 | .padding() 33 | } 34 | } 35 | 36 | struct Topic001View_Previews: PreviewProvider { 37 | static var previews: some View { 38 | Topic001View() 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic002.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic002View.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/07/20. 6 | // 7 | 8 | import SwiftUI 9 | 10 | // MARK: - Entities 11 | fileprivate struct Vital: Identifiable { 12 | let id = UUID() 13 | let title: LocalizedStringKey 14 | let value: Value 15 | let date: Date 16 | let iconSystemName: String 17 | let color: Color 18 | 19 | enum Value { 20 | case number(value: Double, style: NumberFormatter.Style, customUnit: String? = nil) 21 | case dateComponents(_ dateComponents: DateComponents) 22 | case measurement(value: Double, unit: Dimension, formattedUnit: Dimension? = nil) 23 | } 24 | } 25 | 26 | // MARK: - Sample Data 27 | fileprivate let vitalData: [Vital] = [ 28 | .init(title: "取り込まれた酸素のレベル", value: .number(value: 0.99, style: .percent), date: Date(timeIntervalSinceNow: -300), iconSystemName: "o.circle.fill", color: .blue), 29 | .init(title: "心拍数", value: .number(value: 61, style: .decimal, customUnit: "拍/分"), date: Date(timeIntervalSinceNow: -5400), iconSystemName: "heart.fill", color: .red), 30 | .init(title: "睡眠", value: .dateComponents(.init(minute: 451)), date: Date(timeIntervalSinceNow: -87000), iconSystemName: "bed.double.fill", color: .green), 31 | .init(title: "体温", value: .measurement(value: 36.4, unit: UnitTemperature.celsius), date: Date(timeIntervalSinceNow: -172800), iconSystemName: "thermometer", color: .red), 32 | ] 33 | 34 | // MARK: - Views 35 | #if !os(macOS) 36 | /// 37 | public struct Topic002View: View { 38 | public init() {} 39 | 40 | public var body: some View { 41 | #if os(watchOS) 42 | if #available(watchOS 7.0, *) { 43 | NavigationView { 44 | VitalList() 45 | } 46 | } else { 47 | VitalList() 48 | } 49 | #else 50 | NavigationView { 51 | VitalList() 52 | } 53 | #endif 54 | } 55 | } 56 | 57 | struct VitalList: View { 58 | var body: some View { 59 | if #available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *) { 60 | list() 61 | .navigationTitle("バイタルデータ") 62 | } else { 63 | list() 64 | .navigationBarTitle("バイタルデータ") 65 | } 66 | } 67 | 68 | private func list() -> some View { 69 | List(vitalData) { vital in 70 | VitalNavigationLink( 71 | destination: { Text(vital.title) }, 72 | vital: vital 73 | ) 74 | } 75 | } 76 | } 77 | 78 | fileprivate struct VitalNavigationLink : View where Destination : View { 79 | init(@ViewBuilder destination: @escaping () -> Destination, vital: Vital) { 80 | self.destination = destination 81 | self.vital = vital 82 | } 83 | 84 | @ViewBuilder 85 | private let destination: () -> Destination 86 | private let vital: Vital 87 | 88 | var body: some View { 89 | #if os(iOS) 90 | ZStack(alignment: .leading) { 91 | NavigationLink(destination: destination) { 92 | EmptyView() 93 | } 94 | .opacity(0) 95 | 96 | VitalLabel(vital: vital) 97 | } 98 | #else 99 | NavigationLink(destination: destination) { 100 | VitalLabel(vital: vital) 101 | } 102 | #endif 103 | } 104 | } 105 | 106 | fileprivate struct VitalLabel: View { 107 | init(vital: Vital) { 108 | self.vital = vital 109 | } 110 | 111 | private let vital: Vital 112 | 113 | #if os(watchOS) 114 | private let vStackSpacing: CGFloat? = nil 115 | #else 116 | private let vStackSpacing: CGFloat? = 18 117 | #endif 118 | 119 | var body: some View { 120 | VStack(alignment: .leading, spacing: vStackSpacing) { 121 | HStack { 122 | Group { 123 | if #available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *) { 124 | Label { 125 | Text(vital.title) 126 | .bold() 127 | .font(.subheadline) 128 | } icon: { 129 | Image(systemName: vital.iconSystemName) 130 | } 131 | } else { 132 | HStack(alignment: .top) { 133 | Image(systemName: vital.iconSystemName) 134 | Text(vital.title) 135 | .bold() 136 | .font(.subheadline) 137 | } 138 | } 139 | } 140 | .foregroundColor(vital.color) 141 | Spacer() 142 | Text(vital.relativeDateTimeString) 143 | .font(.footnote) 144 | .foregroundColor(.secondary) 145 | #if os(iOS) 146 | DisclosureIndicator() 147 | #endif 148 | } 149 | 150 | vital.value.localizedString 151 | .map { 152 | $0.isNumber || [".", ",", " "].contains($0) 153 | ? Text(String($0)) 154 | .font(.system(.title, design: .rounded).weight(.medium)) 155 | .foregroundColor(.primary) 156 | : Text(String($0)) 157 | .font(.callout.weight(.medium)) 158 | .foregroundColor(.secondary) 159 | } 160 | .reduce(Text("")) { $0 + $1 } 161 | } 162 | .foregroundColor(.primary) 163 | .padding(.vertical, 6) 164 | } 165 | } 166 | 167 | #if os(iOS) 168 | struct ChevronForwardIcon: View { 169 | var body: some View { 170 | if #available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *) { 171 | Image(systemName: "chevron.forward") 172 | .font(.footnote.weight(.bold)) 173 | .foregroundColor(.init(.tertiaryLabel)) 174 | } else { 175 | Image(systemName: "chevron.right") 176 | .flipsForRightToLeftLayoutDirection(true) 177 | .font(.footnote.weight(.bold)) 178 | .foregroundColor(.init(.tertiaryLabel)) 179 | } 180 | } 181 | } 182 | 183 | typealias DisclosureIndicator = ChevronForwardIcon 184 | #endif 185 | #else 186 | /// 187 | public struct Topic002View: View { 188 | public init() {} 189 | 190 | public var body: some View { 191 | Text("Support for this platform is not considered.") 192 | } 193 | } 194 | #endif 195 | 196 | extension Vital { 197 | var relativeDateTimeString: String { 198 | if #available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) { 199 | return date.formatted(.relative(presentation: .named)) 200 | } else { 201 | let formatter = RelativeDateTimeFormatter() 202 | formatter.dateTimeStyle = .named 203 | return formatter.localizedString(for: date, relativeTo: Date()) 204 | } 205 | } 206 | } 207 | 208 | extension Vital.Value { 209 | var localizedString: String { 210 | switch self { 211 | case .number(let value, let style, let customUnit): 212 | if #available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) { 213 | return { 214 | switch style { 215 | case .percent: 216 | return value.formatted(.percent) 217 | case .decimal: 218 | return value.formatted(.number) 219 | default: 220 | preconditionFailure("The implementation was omitted.") 221 | } 222 | }() + (customUnit ?? "") 223 | } else { 224 | let formatter = NumberFormatter() 225 | formatter.numberStyle = style 226 | return (formatter.string(from: .init(value: value)) ?? "\(value)") + (customUnit ?? "") 227 | } 228 | case .dateComponents(let dateComponents): 229 | let formatter = DateComponentsFormatter() 230 | formatter.unitsStyle = .brief 231 | formatter.allowedUnits = [.hour, .minute] 232 | return formatter.string(from: dateComponents) ?? "\(dateComponents)" 233 | case .measurement(let value, let unit, let formattedUnit): 234 | var measurement = Measurement(value: value, unit: unit) 235 | measurement.convert(to: formattedUnit ?? unit) 236 | if #available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, watchOS 8.0, *) { 237 | return measurement.formatted(.measurement(width: .abbreviated, usage: .asProvided)) 238 | } else { 239 | let formatter = MeasurementFormatter() 240 | formatter.unitOptions = .providedUnit 241 | return formatter.string(from: measurement) 242 | } 243 | } 244 | } 245 | } 246 | 247 | struct ContentView_Previews: PreviewProvider { 248 | static var previews: some View { 249 | Topic002View() 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic003.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic003.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/07/27. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic003View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | if #available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) { 16 | #if os(macOS) 17 | DepartureSignal() 18 | .padding() 19 | #else 20 | NavigationView { 21 | DepartureSignal() 22 | } 23 | #endif 24 | } else { 25 | Text("Support for this platform is not considered.") 26 | } 27 | } 28 | } 29 | 30 | // MARK: - Protocols 31 | protocol Light: CustomStringConvertible, Identifiable, CaseIterable { 32 | var color: Color { get } 33 | } 34 | 35 | protocol LightReferenceMappable { 36 | var reference: Lights { get } 37 | } 38 | 39 | extension LightReferenceMappable where Self: Light { 40 | var color: Color { reference.color } 41 | var description: String { reference.description } 42 | var id: Lights.ID { reference.id } 43 | } 44 | 45 | // MARK: - Enums 46 | enum Lights: Light { 47 | case red 48 | case green 49 | case yellow 50 | case off 51 | 52 | var color: Color { 53 | switch self { 54 | case .red: 55 | return .red 56 | case .green: 57 | return .green 58 | case .yellow: 59 | return .yellow 60 | case .off: 61 | return .black 62 | } 63 | } 64 | 65 | var description: String { 66 | switch self { 67 | case .red: 68 | return "赤" 69 | case .green: 70 | return "緑" 71 | case .yellow: 72 | return "黄" 73 | case .off: 74 | return "消" 75 | } 76 | } 77 | 78 | var id: String { description } 79 | } 80 | 81 | // MARK: - Views 82 | @available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *) 83 | struct DepartureSignal: View { 84 | enum Light1: Light, LightReferenceMappable { 85 | case yellow 86 | case off 87 | 88 | var reference: Lights { 89 | switch self { 90 | case .yellow: 91 | return .yellow 92 | case .off: 93 | return .off 94 | } 95 | } 96 | } 97 | 98 | enum Light2: Light, LightReferenceMappable { 99 | case red 100 | case off 101 | 102 | var reference: Lights { 103 | switch self { 104 | case .red: 105 | return .red 106 | case .off: 107 | return .off 108 | } 109 | } 110 | } 111 | 112 | enum Light3: Light, LightReferenceMappable { 113 | case green 114 | case off 115 | 116 | var reference: Lights { 117 | switch self { 118 | case .green: 119 | return .green 120 | case .off: 121 | return .off 122 | } 123 | } 124 | } 125 | 126 | enum Light4: Light, LightReferenceMappable { 127 | case green 128 | case yellow 129 | case off 130 | 131 | var reference: Lights { 132 | switch self { 133 | case .green: 134 | return .green 135 | case .yellow: 136 | return .yellow 137 | case .off: 138 | return .off 139 | } 140 | } 141 | } 142 | 143 | enum Signal: String, CaseIterable, Identifiable { 144 | /// 上の灯火から順に 消・消・緑・消 で進行信号を現示。 145 | case 出発進行 146 | /// 上の灯火から順に 黄・消・消・緑 で減速信号を現示。 147 | case 出発減速 148 | /// 上の灯火から順に 消・消・消・黄 で注意信号を現示。 149 | case 出発注意 150 | /// 上の灯火から順に 黄・消・消・黄 で警戒信号を現示。 151 | case 出発警戒 152 | /// 上の灯火から順に 消・赤・消・消 で停止信号を現示。 153 | case 出発停止 154 | 155 | var pattern: (Light1, Light2, Light3, Light4) { 156 | switch self { 157 | case .出発進行: 158 | return (.off, .off, .green, .off) 159 | case .出発減速: 160 | return (.yellow, .off, .off, .green) 161 | case .出発注意: 162 | return (.off, .off, .off, .yellow) 163 | case .出発警戒: 164 | return (.yellow, .off, .off, .yellow) 165 | case .出発停止: 166 | return (.off, .red, .off, .off) 167 | } 168 | } 169 | 170 | var id: String { rawValue } 171 | } 172 | 173 | @State private var light1: Light1 = .off 174 | @State private var light2: Light2 = .off 175 | @State private var light3: Light3 = .off 176 | @State private var light4: Light4 = .off 177 | @State private var signal: Signal? = nil 178 | 179 | var body: some View { 180 | form 181 | .navigationTitle("出発信号機") 182 | } 183 | 184 | var light: some View { 185 | Image(systemName: "circle.fill") 186 | .font(.largeTitle) 187 | } 188 | 189 | var form: some View { 190 | Form { 191 | Section { 192 | VStack { 193 | light 194 | .foregroundColor(light1.color) 195 | light 196 | .foregroundColor(light2.color) 197 | light 198 | .foregroundColor(light3.color) 199 | light 200 | .foregroundColor(light4.color) 201 | } 202 | .frame(maxWidth: .infinity) 203 | .padding() 204 | } 205 | 206 | Section { 207 | #if os(iOS) 208 | Menu { 209 | ForEach(Signal.allCases) { signal in 210 | Button(LocalizedStringKey(signal.rawValue)) { 211 | self.signal = signal 212 | } 213 | } 214 | } label: { 215 | Text(signal?.rawValue ?? "--------") 216 | .font(.largeTitle) 217 | .bold() 218 | .frame(maxWidth: .infinity) 219 | } 220 | .foregroundColor(.primary) 221 | #else 222 | Picker("指差呼称", selection: $signal) { 223 | ForEach(Signal.allCases) { 224 | Text(LocalizedStringKey($0.rawValue)) 225 | .tag(Signal?.some($0)) 226 | } 227 | } 228 | #endif 229 | } 230 | 231 | Section { 232 | SegmentedPicker("灯1", selection: $light1) 233 | SegmentedPicker("灯2", selection: $light2) 234 | SegmentedPicker("灯3", selection: $light3) 235 | SegmentedPicker("灯4", selection: $light4) 236 | } 237 | } 238 | .onChange(of: signal) { updateLights(by: $0) } 239 | .onChange(of: light1) { updateSignal(by: $0, light2, light3, light4) } 240 | .onChange(of: light2) { updateSignal(by: light1, $0, light3, light4) } 241 | .onChange(of: light3) { updateSignal(by: light1, light2, $0, light4) } 242 | .onChange(of: light4) { updateSignal(by: light1, light2, light3, $0) } 243 | } 244 | 245 | private func updateLights(by signal: Signal?) { 246 | guard let pattern = signal?.pattern else { return } 247 | (light1, light2, light3, light4) = pattern 248 | } 249 | 250 | private func updateSignal(by light1: Light1, _ light2: Light2, _ light3: Light3, _ light4: Light4) { 251 | signal = Signal.allCases.first(where: { $0.pattern == (light1, light2, light3, light4) }) 252 | } 253 | } 254 | 255 | struct SegmentedPicker : View where SelectionValue : Hashable & Identifiable & CaseIterable & CustomStringConvertible, 256 | SelectionValue.AllCases : RandomAccessCollection { 257 | init(_ titleKey: LocalizedStringKey, selection: Binding) { 258 | self.titleKey = titleKey 259 | self.selection = selection 260 | } 261 | 262 | private let titleKey: LocalizedStringKey 263 | private let selection: Binding 264 | 265 | var body: some View { 266 | HStack { 267 | #if !os(watchOS) 268 | Text(titleKey) 269 | Spacer() 270 | #endif 271 | Picker(titleKey, selection: selection) { 272 | ForEach(SelectionValue.allCases) { 273 | Text(LocalizedStringKey($0.description)) 274 | .tag($0) 275 | } 276 | } 277 | #if os(iOS) || os(tvOS) 278 | .pickerStyle(.segmented) 279 | #else 280 | .pickerStyle(.automatic) 281 | .labelsHidden() 282 | #endif 283 | .fixedSize() 284 | } 285 | } 286 | } 287 | 288 | struct Topic003View_Previews: PreviewProvider { 289 | static var previews: some View { 290 | Topic003View() 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic004.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic004.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/08/03. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic004View: View { 12 | public init() {} 13 | 14 | @State private var number = Int.random(in: 2...100) 15 | 16 | public var body: some View { 17 | if #available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) { 18 | content 19 | } else { 20 | Text("Support for this platform is not considered.") 21 | } 22 | } 23 | 24 | @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) 25 | private var content: some View { 26 | VStack(spacing: 30) { 27 | Text(number.formatted()) 28 | .font(.system(.largeTitle, design: .monospaced)) 29 | .fontWeight(.black) 30 | .scaleEffect(2) 31 | HStack { 32 | Button { 33 | print("action: prime") 34 | } label: { 35 | #if os(watchOS) 36 | Text("P") 37 | .lineLimit(1) 38 | #else 39 | Text("Prime") 40 | .lineLimit(1) 41 | .minimumScaleFactor(0.1) 42 | .padding(5) 43 | #endif 44 | } 45 | #if os(watchOS) 46 | Text("/") 47 | #else 48 | Text("or") 49 | #endif 50 | Button { 51 | print("action: composite") 52 | } label: { 53 | #if os(watchOS) 54 | Text("C") 55 | .lineLimit(1) 56 | #else 57 | Text("Composite") 58 | .lineLimit(1) 59 | .minimumScaleFactor(0.1) 60 | .padding(5) 61 | #endif 62 | } 63 | } 64 | #if !os(watchOS) 65 | .fixedSize() 66 | #endif 67 | #if os(iOS) 68 | .buttonStyle(.borderedProminent) 69 | #elseif os(macOS) 70 | .buttonStyle(.link) 71 | #elseif os(tvOS) || os(watchOS) 72 | .buttonStyle(.bordered) 73 | #endif 74 | .cornerRadius(.infinity) 75 | } 76 | .font(.system(.title, design: .rounded).weight(.black)) 77 | .padding() 78 | } 79 | } 80 | 81 | struct Topic004View_Previews: PreviewProvider { 82 | static var previews: some View { 83 | Topic004View() 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic005.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic005.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/08/10. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic005View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | #if os(iOS) || os(macOS) 16 | if #available(iOS 15.0, macOS 12.0, *) { 17 | Topic005ContentView() 18 | } else { 19 | Text("Support for this platform is not considered.") 20 | } 21 | #else 22 | Text("Support for this platform is not considered.") 23 | #endif 24 | } 25 | } 26 | 27 | #if os(iOS) || os(macOS) 28 | @available(iOS 15.0, macOS 12.0, *) 29 | fileprivate struct Topic005ContentView: View { 30 | var body: some View { 31 | ScrollView { 32 | GroupBox { 33 | Group { 34 | GroupBox("001") { 35 | BulletListRow { Text("Stacksと") + Text("layoutPriority(_:)").font(.code) + Text("を使ってみる") } 36 | } 37 | GroupBox("002") { 38 | BulletListRow { Text("NavigationLink").font(.code) + Text("を使ってみる") } 39 | BulletListRow { Text("List").font(.code) + Text("を使ってみる") } 40 | } 41 | GroupBox("003") { 42 | BulletListRow { Text("Form").font(.code) + Text("を使ってみる") } 43 | BulletListRow { Text("Picker").font(.code) + Text("と") + Text("pickerStyle(_:)").font(.code) + Text("を使ってみる") } 44 | BulletListRow { Text("fixedSize(horizontal:vertical:)").font(.code) + Text("を使ってみる") } 45 | } 46 | GroupBox("004") { 47 | BulletListRow { Text("PrimitiveButtonStyle").font(.code) + Text("を使ってみる") } 48 | } 49 | } 50 | } label: { 51 | VStack { 52 | Text("#SwiftUIレイアウト一本勝負") 53 | .font(.system(.largeTitle, design: .monospaced)) 54 | .fontWeight(.black) 55 | .lineLimit(1) 56 | .minimumScaleFactor(0.1) 57 | .foregroundStyle( 58 | .linearGradient( 59 | colors: [.purple, .red, .orange, .green, .blue, .indigo, .purple], 60 | startPoint: .leading, 61 | endPoint: .trailing 62 | ) 63 | ) 64 | Text("主なテーマ") 65 | } 66 | } 67 | .padding() 68 | } 69 | } 70 | } 71 | #endif 72 | 73 | @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) 74 | fileprivate struct BulletListRow: View where Content : View { 75 | init(@ViewBuilder content: @escaping () -> Content) { 76 | self.content = content 77 | } 78 | 79 | @ViewBuilder 80 | private let content: () -> Content 81 | 82 | var body: some View { 83 | Label { 84 | content() 85 | .frame(maxWidth: .infinity, alignment: .leading) 86 | } icon: { 87 | Text("•") 88 | } 89 | } 90 | } 91 | 92 | extension Font { 93 | @available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *) 94 | fileprivate static let code: Font = .body.monospaced() 95 | } 96 | 97 | struct Topic005View_Previews: PreviewProvider { 98 | static var previews: some View { 99 | Topic005View() 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic006.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic006.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/08/17. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic006View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | #if os(iOS) 16 | if #available(iOS 15.0, *) { 17 | Topic006ContentView() 18 | } else { 19 | Text("Support for this platform is not considered.") 20 | } 21 | #else 22 | Text("Support for this platform is not considered.") 23 | #endif 24 | } 25 | } 26 | 27 | #if os(iOS) 28 | @available(iOS 15.0, *) 29 | fileprivate struct Topic006ContentView: View { 30 | private let coordinateSpaceName = "stacks" 31 | private var coordinateSpace: CoordinateSpace { .named(coordinateSpaceName) } 32 | private let paddingLength: CGFloat = 16 33 | 34 | @State private var selectedTitle = "" 35 | @State private var isPresented = false 36 | @State private var position: CGPoint? = nil 37 | 38 | var drag: some Gesture { 39 | DragGesture(coordinateSpace: coordinateSpace) 40 | .onChanged { position = $0.location } 41 | } 42 | 43 | var body: some View { 44 | ZStack { 45 | Text("後ろに位置する View") 46 | 47 | VStack(alignment: .trailing) { 48 | Spacer() 49 | 50 | HStack(alignment: .bottom) { 51 | Spacer() 52 | 53 | Menu( 54 | content: { 55 | Button(action: compose) { 56 | Label("新規作成", systemImage: "square.and.pencil") 57 | } 58 | Button(action: addImage) { 59 | Label("画像を追加", systemImage: "photo") 60 | } 61 | Button(action: addAudio) { 62 | Label("音声を追加", systemImage: "mic.badge.plus") 63 | } 64 | }, 65 | label: { 66 | Image(systemName: "plus") 67 | .imageScale(.large) 68 | .frame(width: 50, height: 50) 69 | .foregroundColor(.white) 70 | .background(Color.accentColor) 71 | .clipShape(Circle()) 72 | }, 73 | primaryAction: compose 74 | ) 75 | .padding(paddingLength) 76 | .ifLet(position) { view, position in 77 | view.position(position) 78 | } 79 | .gesture(drag) 80 | .background( 81 | GeometryReader { geometryProxy in 82 | Color.clear 83 | .onAppear { 84 | if position == nil { 85 | let frame = geometryProxy.frame(in: coordinateSpace) 86 | position = .init( 87 | x: frame.midX - (paddingLength / 2), 88 | y: frame.midY - (paddingLength / 2) 89 | ) 90 | } 91 | } 92 | } 93 | ) 94 | } 95 | } 96 | .coordinateSpace(name: coordinateSpaceName) 97 | } 98 | .alert(selectedTitle, isPresented: $isPresented) { 99 | Button("閉じる") { isPresented = false } 100 | } 101 | } 102 | 103 | private func compose() { 104 | selectedTitle = "新規作成" 105 | isPresented = true 106 | } 107 | 108 | private func addImage() { 109 | selectedTitle = "画像を追加" 110 | isPresented = true 111 | } 112 | 113 | private func addAudio() { 114 | selectedTitle = "音声を追加" 115 | isPresented = true 116 | } 117 | } 118 | 119 | extension View { 120 | @ViewBuilder 121 | fileprivate func `ifLet`(_ value: Optional, transform: (Self, Wrapped) -> Content) -> some View { 122 | if let value = value { 123 | transform(self, value) 124 | } else { 125 | self 126 | } 127 | } 128 | } 129 | #endif 130 | 131 | struct Topic006View_Previews: PreviewProvider { 132 | static var previews: some View { 133 | Topic006View() 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic007.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic007.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/08/31. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic007View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | #if os(iOS) 16 | if #available(iOS 15.0, *) { 17 | Topic007ContentView() 18 | } else { 19 | Text("Support for this platform is not considered.") 20 | } 21 | #else 22 | Text("Support for this platform is not considered.") 23 | #endif 24 | } 25 | } 26 | 27 | #if os(iOS) 28 | @available(iOS 15.0, *) 29 | fileprivate struct Topic007ContentView: View { 30 | @State var number = "" 31 | 32 | public var body: some View { 33 | VStack { 34 | Text(number.isEmpty ? " " : number) 35 | .font(.largeTitle) 36 | .enableTextSelection(!number.isEmpty) 37 | VStack(spacing: 20) { 38 | HStack(spacing: 20) { 39 | RoundButton(phoneNumber: .one, action: append(number:)) 40 | RoundButton(phoneNumber: .two, action: append(number:)) 41 | RoundButton(phoneNumber: .three, action: append(number:)) 42 | } 43 | HStack(spacing: 20) { 44 | RoundButton(phoneNumber: .four, action: append(number:)) 45 | RoundButton(phoneNumber: .five, action: append(number:)) 46 | RoundButton(phoneNumber: .six, action: append(number:)) 47 | } 48 | HStack(spacing: 20) { 49 | RoundButton(phoneNumber: .seven, action: append(number:)) 50 | RoundButton(phoneNumber: .eight, action: append(number:)) 51 | RoundButton(phoneNumber: .nine, action: append(number:)) 52 | } 53 | HStack(spacing: 20) { 54 | RoundButton(phoneNumber: .star, action: append(number:)) 55 | RoundButton(phoneNumber: .zero, action: append(number:)) 56 | RoundButton(phoneNumber: .numberSign, action: append(number:)) 57 | } 58 | HStack(spacing: 20) { 59 | RoundButton("") { _ in } 60 | RoundButton("📞") { _ in } 61 | RoundButton("🆑") { _ in 62 | guard !number.isEmpty else { return } 63 | number.removeLast() 64 | } 65 | } 66 | } 67 | } 68 | .padding(.horizontal, 50) 69 | } 70 | 71 | private func append(number: String) { 72 | self.number.append(number) 73 | } 74 | } 75 | 76 | @available(iOS 15.0, *) 77 | extension View { 78 | @ViewBuilder 79 | fileprivate func enableTextSelection(_ enabled: Bool) -> some View { 80 | if enabled { 81 | textSelection(.enabled) 82 | } else { 83 | textSelection(.disabled) 84 | } 85 | } 86 | } 87 | 88 | @available(iOS 15.0, *) 89 | fileprivate struct RoundButton: View { 90 | private let number: String 91 | private let caption: String? 92 | private let action: (String) -> Void 93 | 94 | init(_ number: String, caption: String? = nil, action: @escaping (String) -> Void) { 95 | self.number = number 96 | self.caption = caption 97 | self.action = action 98 | } 99 | 100 | init(phoneNumber: PhoneNumber, action: @escaping (String) -> Void) { 101 | self.init(phoneNumber.number, caption: phoneNumber.caption, action: action) 102 | } 103 | 104 | var body: some View { 105 | Button { 106 | action(number) 107 | } label: { 108 | VStack { 109 | switch number { 110 | case PhoneNumber.star.number: 111 | Image(systemName: "staroflife.fill") 112 | case PhoneNumber.numberSign.number: 113 | Image(systemName: "number") 114 | case "📞": 115 | Image(systemName: "phone.fill") 116 | .font(.title) 117 | case "🆑": 118 | Image(systemName: "delete.backward") 119 | default: 120 | if number.isEmpty { 121 | EmptyView() 122 | } else { 123 | Text(number) 124 | .font(.title) 125 | } 126 | } 127 | if let caption = caption { 128 | Text(caption) 129 | .font(.caption2) 130 | } 131 | } 132 | .frame(width: 60, height: 60) 133 | } 134 | .buttonStyle(.bordered) 135 | .foregroundColor(number == "📞" ? .white : .primary) 136 | .background(number == "📞" ? .green : .clear) 137 | .clipShape(Circle()) 138 | .opacity(number.isEmpty ? 0 : 1) 139 | } 140 | } 141 | 142 | fileprivate enum PhoneNumber { 143 | case one 144 | case two 145 | case three 146 | case four 147 | case five 148 | case six 149 | case seven 150 | case eight 151 | case nine 152 | case zero 153 | case star 154 | case numberSign 155 | 156 | var number: String { 157 | switch self { 158 | case .one: 159 | return "1" 160 | case .two: 161 | return "2" 162 | case .three: 163 | return "3" 164 | case .four: 165 | return "4" 166 | case .five: 167 | return "5" 168 | case .six: 169 | return "6" 170 | case .seven: 171 | return "7" 172 | case .eight: 173 | return "8" 174 | case .nine: 175 | return "9" 176 | case .zero: 177 | return "0" 178 | case .star: 179 | return "*" 180 | case .numberSign: 181 | return "#" 182 | } 183 | } 184 | 185 | var caption: String? { 186 | switch self { 187 | case .one: 188 | return "" 189 | case .two: 190 | return "ABC" 191 | case .three: 192 | return "DEF" 193 | case .four: 194 | return "GHI" 195 | case .five: 196 | return "JKL" 197 | case .six: 198 | return "MNO" 199 | case .seven: 200 | return "PQRS" 201 | case .eight: 202 | return "TUV" 203 | case .nine: 204 | return "WXYZ" 205 | case .zero: 206 | return "+" 207 | case .star: 208 | return nil 209 | case .numberSign: 210 | return nil 211 | } 212 | } 213 | } 214 | #endif 215 | 216 | struct Topic007View_Previews: PreviewProvider { 217 | static var previews: some View { 218 | Topic007View() 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic008.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic008.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/09/21. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic008View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | #if os(iOS) 16 | if #available(iOS 15.0, *) { 17 | NavigationView { 18 | NavigationContentView() 19 | } 20 | } else { 21 | Text("Support for this platform is not considered.") 22 | } 23 | #else 24 | Text("Support for this platform is not considered.") 25 | #endif 26 | } 27 | } 28 | 29 | #if os(iOS) 30 | fileprivate struct AppInfo: Identifiable, Equatable { 31 | let id = UUID() 32 | let color: Color 33 | let name: String 34 | let subtitle: String 35 | 36 | static func == (lhs: Self, rhs: Self) -> Bool { 37 | return lhs.id == rhs.id 38 | } 39 | } 40 | 41 | @available(iOS 15.0, *) 42 | fileprivate struct NavigationContentView: View { 43 | private let appInfo: [AppInfo] = [ 44 | .init(color: .orange, name: "App Name 1", subtitle: "Subtitle 1"), 45 | .init(color: .yellow, name: "アプリ名 2", subtitle: "サブタイトル 2"), 46 | .init(color: .green, name: "Long App Name 3 - Long App Name 3", subtitle: "Subtitle 3"), 47 | .init(color: .mint, name: "長い長いアプリ名 4 - 長い長いアプリ名 4 - 長い長いアプリ名 4", subtitle: "サブタイトル 4"), 48 | .init(color: .teal, name: "Long App Name 5 - Long App Name 5", subtitle: "Long Subtitle 5 - Long Subtitle 5"), 49 | .init(color: .cyan, name: "長い長いアプリ名 6 - 長い長いアプリ名 6 - 長い長いアプリ名 6", subtitle: "長い長いサブタイトル 6 - 長い長いサブタイトル 6"), 50 | .init(color: .blue, name: "App Name 7", subtitle: "Subtitle 7"), 51 | .init(color: .indigo, name: "アプリ名 8", subtitle: "サブタイトル 8"), 52 | .init(color: .purple, name: "App Name 9", subtitle: "Subtitle 9"), 53 | .init(color: .pink, name: "アプリ名 10", subtitle: "Subtitle 10"), 54 | ] 55 | 56 | var body: some View { 57 | ScrollView { 58 | ForEach(appInfo) { info in /// `List` で書くとどのようになるでしょうか 59 | AppView(info: info) 60 | if appInfo.last != info { 61 | Divider() 62 | .padding(.leading, AppView.appIconSize + AppView.horizontalSpacing) 63 | } 64 | } 65 | .frame(maxWidth: .infinity) 66 | .padding() 67 | } 68 | .navigationTitle("App") 69 | } 70 | } 71 | 72 | @available(iOS 15.0, *) 73 | fileprivate struct AppView: View { 74 | static let horizontalSpacing: CGFloat = 8 75 | static let appIconSize: CGFloat = 64 76 | 77 | let info: AppInfo 78 | 79 | var body: some View { 80 | HStack(spacing: Self.horizontalSpacing) { 81 | Image(systemName: "app.fill") 82 | .resizable() 83 | .foregroundColor(info.color) 84 | .frame(width: Self.appIconSize, height: Self.appIconSize) 85 | VStack(alignment: .leading, spacing: 5) { 86 | Text(info.name) 87 | .lineLimit(2) 88 | Text(info.subtitle) 89 | .lineLimit(1) 90 | .font(.footnote) 91 | .foregroundColor(.secondary) 92 | } 93 | .frame(maxWidth: .infinity, alignment: .leading) 94 | Button { 95 | print(#function) 96 | } label: { 97 | Text("入手") 98 | .font(.headline) 99 | .padding(.horizontal, 8) 100 | } 101 | .buttonStyle(.bordered) 102 | .buttonBorderShape(.capsule) 103 | } 104 | .frame(maxWidth: .infinity) 105 | } 106 | } 107 | #endif 108 | 109 | struct Topic008View_Previews: PreviewProvider { 110 | static var previews: some View { 111 | Topic008View() 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/Topic009.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Topic009.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by treastrain on 2022/10/05. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// 11 | public struct Topic009View: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | #if os(iOS) 16 | if #available(iOS 15.0, *) { 17 | NavigationView { 18 | NavigationContentView() 19 | } 20 | } else { 21 | Text("Support for this platform is not considered.") 22 | } 23 | #else 24 | Text("Support for this platform is not considered.") 25 | #endif 26 | } 27 | } 28 | 29 | #if os(iOS) 30 | /// より 31 | fileprivate struct AppInfo: Identifiable, Equatable { 32 | let id = UUID() 33 | let color: Color 34 | let name: String 35 | let subtitle: String 36 | 37 | static func == (lhs: Self, rhs: Self) -> Bool { 38 | return lhs.id == rhs.id 39 | } 40 | } 41 | 42 | @available(iOS 15.0, *) 43 | fileprivate struct NavigationContentView: View { 44 | private let appInfo: [AppInfo] = [ 45 | .init(color: .orange, name: "App Name 1", subtitle: "Subtitle 1"), 46 | .init(color: .yellow, name: "アプリ名 2", subtitle: "サブタイトル 2"), 47 | .init(color: .green, name: "Long App Name 3 - Long App Name 3", subtitle: "Subtitle 3"), 48 | .init(color: .mint, name: "長い長いアプリ名 4 - 長い長いアプリ名 4 - 長い長いアプリ名 4", subtitle: "サブタイトル 4"), 49 | .init(color: .teal, name: "Long App Name 5 - Long App Name 5", subtitle: "Long Subtitle 5 - Long Subtitle 5"), 50 | .init(color: .cyan, name: "長い長いアプリ名 6 - 長い長いアプリ名 6 - 長い長いアプリ名 6", subtitle: "長い長いサブタイトル 6 - 長い長いサブタイトル 6"), 51 | .init(color: .blue, name: "App Name 7", subtitle: "Subtitle 7"), 52 | .init(color: .indigo, name: "アプリ名 8", subtitle: "サブタイトル 8"), 53 | .init(color: .purple, name: "App Name 9", subtitle: "Subtitle 9"), 54 | ] 55 | 56 | var body: some View { 57 | ScrollView { 58 | VStack { 59 | Divider() 60 | .padding(.horizontal) 61 | GeometryReader { geometryProxy in 62 | TabView { 63 | ForEach(Array(stride(from: 0, to: appInfo.count, by: 3)), id: \.self) { index in 64 | VStack { 65 | AppView(info: appInfo[index]) 66 | if index + 1 < appInfo.count { 67 | Divider() 68 | AppView(info: appInfo[index + 1]) 69 | } 70 | if index + 2 < appInfo.count { 71 | Divider() 72 | AppView(info: appInfo[index + 2]) 73 | } 74 | } 75 | .padding(.horizontal) 76 | } 77 | } 78 | .frame(width: geometryProxy.size.width, alignment: .center) 79 | .tabViewStyle(.page(indexDisplayMode: .never)) 80 | } 81 | .frame(height: 230) 82 | } 83 | } 84 | .navigationTitle("App") 85 | } 86 | } 87 | 88 | @available(iOS 15.0, *) 89 | fileprivate struct AppView: View { 90 | static let horizontalSpacing: CGFloat = 8 91 | static let appIconSize: CGFloat = 64 92 | 93 | let info: AppInfo 94 | 95 | var body: some View { 96 | HStack(spacing: Self.horizontalSpacing) { 97 | Image(systemName: "app.fill") 98 | .resizable() 99 | .foregroundColor(info.color) 100 | .frame(width: Self.appIconSize, height: Self.appIconSize) 101 | VStack(alignment: .leading, spacing: 5) { 102 | Text(info.name) 103 | .lineLimit(2) 104 | Text(info.subtitle) 105 | .lineLimit(1) 106 | .font(.footnote) 107 | .foregroundColor(.secondary) 108 | } 109 | .frame(maxWidth: .infinity, alignment: .leading) 110 | Button { 111 | print(#function) 112 | } label: { 113 | Text("入手") 114 | .font(.headline) 115 | .padding(.horizontal, 8) 116 | } 117 | .buttonStyle(.bordered) 118 | .buttonBorderShape(.capsule) 119 | } 120 | .frame(maxWidth: .infinity) 121 | } 122 | } 123 | #endif 124 | 125 | struct Topic009View_Previews: PreviewProvider { 126 | static var previews: some View { 127 | Topic009View() 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /SwiftUIWeeklyLayoutChallenge/TopicXXX.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopicXXX.swift 3 | // SwiftUIWeeklyLayoutChallenge 4 | // 5 | // Created by ___USERNAME___ on ___DATE___. 6 | // 7 | 8 | import SwiftUI 9 | 10 | /// お題 XXX 11 | public struct TopicXXXView: View { 12 | public init() {} 13 | 14 | public var body: some View { 15 | Text("Code your layout here!") 16 | } 17 | } 18 | 19 | struct TopicXXXView_Previews: PreviewProvider { 20 | static var previews: some View { 21 | TopicXXXView() 22 | } 23 | } 24 | 25 | --------------------------------------------------------------------------------