├── .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 | |||||
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 | ||||
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 | |||||
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 | |||||
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 | |||||
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 | ||||
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 | |||||
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 | |||||
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 | |||||
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 |
--------------------------------------------------------------------------------