├── .gitignore
├── README.md
├── TestSidebar
├── App.swift
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Info.plist
├── Preview Content
│ └── Preview Assets.xcassets
│ │ └── Contents.json
└── TestSidebar.entitlements
├── TribleTroubleiPad
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Info.plist
└── Preview Content
│ └── Preview Assets.xcassets
│ └── Contents.json
└── TripleTrouble.xcodeproj
├── project.pbxproj
└── project.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
└── IDEWorkspaceChecks.plist
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Triple Trouble
2 |
3 | A minimal example of three-column navigation for iPad and macOS using SwiftUI.
4 |
5 | See [the post](https://kean.blog/post/triple-trouble) for more info.
6 |
7 | > **WARNING**: This solution requires Big Sur.
8 |
9 | ## Code
10 |
11 | ```swift
12 | import SwiftUI
13 |
14 | @main
15 | struct TestSidebarApp: App {
16 | var body: some Scene {
17 | WindowGroup {
18 | ContentView()
19 | }
20 | // Uncomment to hide title
21 | // .windowToolbarStyle(UnifiedWindowToolbarStyle(showsTitle: false))
22 | .commands {
23 | SidebarCommands()
24 | }
25 | }
26 | }
27 |
28 | struct ContentView: View {
29 |
30 | var body: some View {
31 | NavigationView {
32 | SidebarView()
33 | Text("No Sidebar Selection")
34 | Text("No Message Selection")
35 | }
36 | }
37 | }
38 |
39 | struct SidebarView: View {
40 | @State private var isDefaultItemActive = true
41 |
42 | var body: some View {
43 | let list = List {
44 | Text("Favorites")
45 | .font(.caption)
46 | .foregroundColor(.secondary)
47 | NavigationLink(destination: IndoxView(), isActive: $isDefaultItemActive) {
48 | Label("Inbox", systemImage: "tray.2")
49 | }
50 | NavigationLink(destination: SentView()) {
51 | Label("Sent", systemImage: "paperplane")
52 | }
53 | }
54 | .listStyle(SidebarListStyle())
55 |
56 | #if os(macOS)
57 | list.toolbar {
58 | Button(action: toggleSidebar) {
59 | Image(systemName: "sidebar.left")
60 | }
61 | }
62 | #else
63 | list
64 | #endif
65 | }
66 | }
67 |
68 | #if os(macOS)
69 | private func toggleSidebar() {
70 | NSApp.keyWindow?.firstResponder?
71 | .tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
72 | }
73 | #endif
74 |
75 | struct IndoxView: View {
76 | var body: some View {
77 | List(Array(0...100).map(String.init), id: \.self) { message in
78 | NavigationLink(destination: MessageDetailsView(message: message)) {
79 | Text(message)
80 | }
81 | }
82 | .navigationTitle("Inbox")
83 | .toolbar {
84 | Button(action: { /* Open filters */ }) {
85 | Image(systemName: "line.horizontal.3.decrease.circle")
86 | }
87 | }
88 | }
89 | }
90 |
91 | struct SentView: View {
92 | var body: some View {
93 | Text("No Sent Messages")
94 | .navigationTitle("Sent")
95 | .toolbar {
96 | Button(action: {}) {
97 | Image(systemName: "line.horizontal.3.decrease.circle")
98 | }
99 | }
100 | }
101 | }
102 |
103 | struct MessageDetailsView: View {
104 | let message: String
105 |
106 | var body: some View {
107 | Text("Details for \(message)")
108 | .toolbar {
109 | Button(action: {}) {
110 | Image(systemName: "square.and.arrow.up")
111 | }
112 | }
113 | }
114 | }
115 | ```
116 |
117 | ## Screenshot
118 |
119 |
120 |
121 | 
122 |
123 |
124 |
125 | 
126 |
--------------------------------------------------------------------------------
/TestSidebar/App.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestSidebarApp.swift
3 | // TestSidebar
4 | //
5 | // Created by Alexander Grebenyuk on 15.02.2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | #if canImport(UIKit)
11 | import UIKit
12 | #endif
13 |
14 | @main
15 | struct TestSidebarApp: App {
16 | var body: some Scene {
17 | WindowGroup {
18 | ContentView()
19 | }
20 | // Uncomment to hide title
21 | // .windowToolbarStyle(UnifiedWindowToolbarStyle(showsTitle: false))
22 | .commands {
23 | SidebarCommands()
24 | }
25 | }
26 | }
27 |
28 | struct ContentView: View {
29 |
30 | var body: some View {
31 | NavigationView {
32 | Sidebar()
33 | Text("No Sidebar Selection")
34 | Text("No Message Selection")
35 | }
36 | .onAppear {
37 | #if canImport(UIKit)
38 | // Setting up iPad layout to match macOS behaviour
39 | UIApplication.shared.setFirstSplitViewPreferredDisplayMode(.twoBesideSecondary)
40 | #endif
41 | }
42 | }
43 | }
44 |
45 | struct Sidebar: View {
46 | @State private var isDefaultItemActive = true
47 |
48 | var body: some View {
49 | let list = List {
50 | Text("Favorites")
51 | .font(.caption)
52 | .foregroundColor(.secondary)
53 | NavigationLink(destination: IndoxView(), isActive: $isDefaultItemActive) {
54 | Label("Inbox", systemImage: "tray.2")
55 | }
56 | NavigationLink(destination: SentView()) {
57 | Label("Sent", systemImage: "paperplane")
58 | }
59 | }
60 | .listStyle(SidebarListStyle())
61 |
62 | #if os(macOS)
63 | list.toolbar {
64 | Button(action: toggleSidebar) {
65 | Image(systemName: "sidebar.left")
66 | }
67 | }
68 | #else
69 | list
70 | #endif
71 | }
72 | }
73 |
74 | #if os(macOS)
75 | private func toggleSidebar() {
76 | NSApp.keyWindow?.firstResponder?
77 | .tryToPerform(#selector(NSSplitViewController.toggleSidebar(_:)), with: nil)
78 | }
79 | #endif
80 |
81 | struct IndoxView: View {
82 | var body: some View {
83 | List(Array(0...100).map(String.init), id: \.self) { message in
84 | NavigationLink(destination: MessageDetailsView(message: message)) {
85 | Text(message)
86 | }
87 | }
88 | .navigationTitle("Inbox")
89 | .toolbar {
90 | Button(action: { /* Open filters */ }) {
91 | Image(systemName: "line.horizontal.3.decrease.circle")
92 | }
93 | }
94 | }
95 | }
96 |
97 | struct SentView: View {
98 | var body: some View {
99 | Text("No Sent Messages")
100 | .navigationTitle("Sent")
101 | .toolbar {
102 | Button(action: {}) {
103 | Image(systemName: "line.horizontal.3.decrease.circle")
104 | }
105 | }
106 | }
107 | }
108 |
109 | struct MessageDetailsView: View {
110 | let message: String
111 |
112 | var body: some View {
113 | Text("Details for \(message)")
114 | .toolbar {
115 | Button(action: {}) {
116 | Image(systemName: "square.and.arrow.up")
117 | }
118 | }
119 | }
120 | }
121 |
122 | struct ContentView_Previews: PreviewProvider {
123 | static var previews: some View {
124 | ContentView()
125 | }
126 | }
127 |
128 | // MARK: - Consistency with iPad
129 |
130 | #if canImport(UIKit)
131 | private extension UIApplication {
132 | func setFirstSplitViewPreferredDisplayMode(_ preferredDisplayMode: UISplitViewController.DisplayMode) {
133 | var splitViewController: UISplitViewController? {
134 | UIApplication.shared.firstSplitViewController
135 | }
136 |
137 | // Sometimes split view is not available instantly
138 | if let splitViewController = splitViewController {
139 | splitViewController.preferredDisplayMode = preferredDisplayMode
140 | } else {
141 | DispatchQueue.main.async {
142 | splitViewController?.preferredDisplayMode = preferredDisplayMode
143 | }
144 | }
145 | }
146 |
147 | private var firstSplitViewController: UISplitViewController? {
148 | windows.first { $0.isKeyWindow }?
149 | .rootViewController?.firstSplitViewController
150 | }
151 | }
152 |
153 | private extension UIViewController {
154 | var firstSplitViewController: UISplitViewController? {
155 | self as? UISplitViewController
156 | ?? children.lazy.compactMap { $0.firstSplitViewController }.first
157 | }
158 | }
159 | #endif
160 |
--------------------------------------------------------------------------------
/TestSidebar/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 |
--------------------------------------------------------------------------------
/TestSidebar/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/TestSidebar/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TestSidebar/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSMinimumSystemVersion
22 | $(MACOSX_DEPLOYMENT_TARGET)
23 |
24 |
25 |
--------------------------------------------------------------------------------
/TestSidebar/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TestSidebar/TestSidebar.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 |
--------------------------------------------------------------------------------
/TribleTroubleiPad/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 |
--------------------------------------------------------------------------------
/TribleTroubleiPad/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 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/TribleTroubleiPad/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TribleTroubleiPad/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UIApplicationSceneManifest
24 |
25 | UIApplicationSupportsMultipleScenes
26 |
27 |
28 | UIApplicationSupportsIndirectInputEvents
29 |
30 | UILaunchScreen
31 |
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/TribleTroubleiPad/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/TripleTrouble.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0C2464BA25DAE3F10057A577 /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2464B925DAE3F10057A577 /* App.swift */; };
11 | 0C2464BE25DAE3F30057A577 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C2464BD25DAE3F30057A577 /* Assets.xcassets */; };
12 | 0C2464C125DAE3F30057A577 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0C2464C025DAE3F30057A577 /* Preview Assets.xcassets */; };
13 | 0CC7AC1D25DB023200D1B24E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CC7AC1C25DB023200D1B24E /* Assets.xcassets */; };
14 | 0CC7AC2025DB023200D1B24E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0CC7AC1F25DB023200D1B24E /* Preview Assets.xcassets */; };
15 | 0CC7AC2925DB024500D1B24E /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0C2464B925DAE3F10057A577 /* App.swift */; };
16 | /* End PBXBuildFile section */
17 |
18 | /* Begin PBXFileReference section */
19 | 0C2464B625DAE3F10057A577 /* TripleTrouble.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TripleTrouble.app; sourceTree = BUILT_PRODUCTS_DIR; };
20 | 0C2464B925DAE3F10057A577 /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; };
21 | 0C2464BD25DAE3F30057A577 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
22 | 0C2464C025DAE3F30057A577 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
23 | 0C2464C225DAE3F30057A577 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
24 | 0C2464C325DAE3F30057A577 /* TestSidebar.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TestSidebar.entitlements; sourceTree = ""; };
25 | 0CC7AC1625DB023000D1B24E /* TribleTroubleiPad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TribleTroubleiPad.app; sourceTree = BUILT_PRODUCTS_DIR; };
26 | 0CC7AC1C25DB023200D1B24E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
27 | 0CC7AC1F25DB023200D1B24E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
28 | 0CC7AC2125DB023200D1B24E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 0C2464B325DAE3F10057A577 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | 0CC7AC1325DB023000D1B24E /* Frameworks */ = {
40 | isa = PBXFrameworksBuildPhase;
41 | buildActionMask = 2147483647;
42 | files = (
43 | );
44 | runOnlyForDeploymentPostprocessing = 0;
45 | };
46 | /* End PBXFrameworksBuildPhase section */
47 |
48 | /* Begin PBXGroup section */
49 | 0C2464AD25DAE3F10057A577 = {
50 | isa = PBXGroup;
51 | children = (
52 | 0C2464B825DAE3F10057A577 /* TestSidebar */,
53 | 0CC7AC1725DB023000D1B24E /* TribleTroubleiPad */,
54 | 0C2464B725DAE3F10057A577 /* Products */,
55 | );
56 | sourceTree = "";
57 | };
58 | 0C2464B725DAE3F10057A577 /* Products */ = {
59 | isa = PBXGroup;
60 | children = (
61 | 0C2464B625DAE3F10057A577 /* TripleTrouble.app */,
62 | 0CC7AC1625DB023000D1B24E /* TribleTroubleiPad.app */,
63 | );
64 | name = Products;
65 | sourceTree = "";
66 | };
67 | 0C2464B825DAE3F10057A577 /* TestSidebar */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 0C2464B925DAE3F10057A577 /* App.swift */,
71 | 0C2464BD25DAE3F30057A577 /* Assets.xcassets */,
72 | 0C2464C225DAE3F30057A577 /* Info.plist */,
73 | 0C2464C325DAE3F30057A577 /* TestSidebar.entitlements */,
74 | 0C2464BF25DAE3F30057A577 /* Preview Content */,
75 | );
76 | path = TestSidebar;
77 | sourceTree = "";
78 | };
79 | 0C2464BF25DAE3F30057A577 /* Preview Content */ = {
80 | isa = PBXGroup;
81 | children = (
82 | 0C2464C025DAE3F30057A577 /* Preview Assets.xcassets */,
83 | );
84 | path = "Preview Content";
85 | sourceTree = "";
86 | };
87 | 0CC7AC1725DB023000D1B24E /* TribleTroubleiPad */ = {
88 | isa = PBXGroup;
89 | children = (
90 | 0CC7AC1C25DB023200D1B24E /* Assets.xcassets */,
91 | 0CC7AC2125DB023200D1B24E /* Info.plist */,
92 | 0CC7AC1E25DB023200D1B24E /* Preview Content */,
93 | );
94 | path = TribleTroubleiPad;
95 | sourceTree = "";
96 | };
97 | 0CC7AC1E25DB023200D1B24E /* Preview Content */ = {
98 | isa = PBXGroup;
99 | children = (
100 | 0CC7AC1F25DB023200D1B24E /* Preview Assets.xcassets */,
101 | );
102 | path = "Preview Content";
103 | sourceTree = "";
104 | };
105 | /* End PBXGroup section */
106 |
107 | /* Begin PBXNativeTarget section */
108 | 0C2464B525DAE3F10057A577 /* TripleTrouble */ = {
109 | isa = PBXNativeTarget;
110 | buildConfigurationList = 0C2464C625DAE3F30057A577 /* Build configuration list for PBXNativeTarget "TripleTrouble" */;
111 | buildPhases = (
112 | 0C2464B225DAE3F10057A577 /* Sources */,
113 | 0C2464B325DAE3F10057A577 /* Frameworks */,
114 | 0C2464B425DAE3F10057A577 /* Resources */,
115 | );
116 | buildRules = (
117 | );
118 | dependencies = (
119 | );
120 | name = TripleTrouble;
121 | productName = TestSidebar;
122 | productReference = 0C2464B625DAE3F10057A577 /* TripleTrouble.app */;
123 | productType = "com.apple.product-type.application";
124 | };
125 | 0CC7AC1525DB023000D1B24E /* TribleTroubleiPad */ = {
126 | isa = PBXNativeTarget;
127 | buildConfigurationList = 0CC7AC2225DB023200D1B24E /* Build configuration list for PBXNativeTarget "TribleTroubleiPad" */;
128 | buildPhases = (
129 | 0CC7AC1225DB023000D1B24E /* Sources */,
130 | 0CC7AC1325DB023000D1B24E /* Frameworks */,
131 | 0CC7AC1425DB023000D1B24E /* Resources */,
132 | );
133 | buildRules = (
134 | );
135 | dependencies = (
136 | );
137 | name = TribleTroubleiPad;
138 | productName = TribleTroubleiPad;
139 | productReference = 0CC7AC1625DB023000D1B24E /* TribleTroubleiPad.app */;
140 | productType = "com.apple.product-type.application";
141 | };
142 | /* End PBXNativeTarget section */
143 |
144 | /* Begin PBXProject section */
145 | 0C2464AE25DAE3F10057A577 /* Project object */ = {
146 | isa = PBXProject;
147 | attributes = {
148 | LastSwiftUpdateCheck = 1240;
149 | LastUpgradeCheck = 1240;
150 | TargetAttributes = {
151 | 0C2464B525DAE3F10057A577 = {
152 | CreatedOnToolsVersion = 12.4;
153 | };
154 | 0CC7AC1525DB023000D1B24E = {
155 | CreatedOnToolsVersion = 12.4;
156 | };
157 | };
158 | };
159 | buildConfigurationList = 0C2464B125DAE3F10057A577 /* Build configuration list for PBXProject "TripleTrouble" */;
160 | compatibilityVersion = "Xcode 9.3";
161 | developmentRegion = en;
162 | hasScannedForEncodings = 0;
163 | knownRegions = (
164 | en,
165 | Base,
166 | );
167 | mainGroup = 0C2464AD25DAE3F10057A577;
168 | productRefGroup = 0C2464B725DAE3F10057A577 /* Products */;
169 | projectDirPath = "";
170 | projectRoot = "";
171 | targets = (
172 | 0C2464B525DAE3F10057A577 /* TripleTrouble */,
173 | 0CC7AC1525DB023000D1B24E /* TribleTroubleiPad */,
174 | );
175 | };
176 | /* End PBXProject section */
177 |
178 | /* Begin PBXResourcesBuildPhase section */
179 | 0C2464B425DAE3F10057A577 /* Resources */ = {
180 | isa = PBXResourcesBuildPhase;
181 | buildActionMask = 2147483647;
182 | files = (
183 | 0C2464C125DAE3F30057A577 /* Preview Assets.xcassets in Resources */,
184 | 0C2464BE25DAE3F30057A577 /* Assets.xcassets in Resources */,
185 | );
186 | runOnlyForDeploymentPostprocessing = 0;
187 | };
188 | 0CC7AC1425DB023000D1B24E /* Resources */ = {
189 | isa = PBXResourcesBuildPhase;
190 | buildActionMask = 2147483647;
191 | files = (
192 | 0CC7AC2025DB023200D1B24E /* Preview Assets.xcassets in Resources */,
193 | 0CC7AC1D25DB023200D1B24E /* Assets.xcassets in Resources */,
194 | );
195 | runOnlyForDeploymentPostprocessing = 0;
196 | };
197 | /* End PBXResourcesBuildPhase section */
198 |
199 | /* Begin PBXSourcesBuildPhase section */
200 | 0C2464B225DAE3F10057A577 /* Sources */ = {
201 | isa = PBXSourcesBuildPhase;
202 | buildActionMask = 2147483647;
203 | files = (
204 | 0C2464BA25DAE3F10057A577 /* App.swift in Sources */,
205 | );
206 | runOnlyForDeploymentPostprocessing = 0;
207 | };
208 | 0CC7AC1225DB023000D1B24E /* Sources */ = {
209 | isa = PBXSourcesBuildPhase;
210 | buildActionMask = 2147483647;
211 | files = (
212 | 0CC7AC2925DB024500D1B24E /* App.swift in Sources */,
213 | );
214 | runOnlyForDeploymentPostprocessing = 0;
215 | };
216 | /* End PBXSourcesBuildPhase section */
217 |
218 | /* Begin XCBuildConfiguration section */
219 | 0C2464C425DAE3F30057A577 /* Debug */ = {
220 | isa = XCBuildConfiguration;
221 | buildSettings = {
222 | ALWAYS_SEARCH_USER_PATHS = NO;
223 | CLANG_ANALYZER_NONNULL = YES;
224 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
225 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
226 | CLANG_CXX_LIBRARY = "libc++";
227 | CLANG_ENABLE_MODULES = YES;
228 | CLANG_ENABLE_OBJC_ARC = YES;
229 | CLANG_ENABLE_OBJC_WEAK = YES;
230 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
231 | CLANG_WARN_BOOL_CONVERSION = YES;
232 | CLANG_WARN_COMMA = YES;
233 | CLANG_WARN_CONSTANT_CONVERSION = YES;
234 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
236 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
237 | CLANG_WARN_EMPTY_BODY = YES;
238 | CLANG_WARN_ENUM_CONVERSION = YES;
239 | CLANG_WARN_INFINITE_RECURSION = YES;
240 | CLANG_WARN_INT_CONVERSION = YES;
241 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
242 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
243 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
245 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
246 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
247 | CLANG_WARN_STRICT_PROTOTYPES = YES;
248 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
249 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
250 | CLANG_WARN_UNREACHABLE_CODE = YES;
251 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
252 | COPY_PHASE_STRIP = NO;
253 | DEBUG_INFORMATION_FORMAT = dwarf;
254 | ENABLE_STRICT_OBJC_MSGSEND = YES;
255 | ENABLE_TESTABILITY = YES;
256 | GCC_C_LANGUAGE_STANDARD = gnu11;
257 | GCC_DYNAMIC_NO_PIC = NO;
258 | GCC_NO_COMMON_BLOCKS = YES;
259 | GCC_OPTIMIZATION_LEVEL = 0;
260 | GCC_PREPROCESSOR_DEFINITIONS = (
261 | "DEBUG=1",
262 | "$(inherited)",
263 | );
264 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
265 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
266 | GCC_WARN_UNDECLARED_SELECTOR = YES;
267 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
268 | GCC_WARN_UNUSED_FUNCTION = YES;
269 | GCC_WARN_UNUSED_VARIABLE = YES;
270 | MACOSX_DEPLOYMENT_TARGET = 11.1;
271 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
272 | MTL_FAST_MATH = YES;
273 | ONLY_ACTIVE_ARCH = YES;
274 | SDKROOT = macosx;
275 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
276 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
277 | };
278 | name = Debug;
279 | };
280 | 0C2464C525DAE3F30057A577 /* Release */ = {
281 | isa = XCBuildConfiguration;
282 | buildSettings = {
283 | ALWAYS_SEARCH_USER_PATHS = NO;
284 | CLANG_ANALYZER_NONNULL = YES;
285 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
286 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
287 | CLANG_CXX_LIBRARY = "libc++";
288 | CLANG_ENABLE_MODULES = YES;
289 | CLANG_ENABLE_OBJC_ARC = YES;
290 | CLANG_ENABLE_OBJC_WEAK = YES;
291 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
292 | CLANG_WARN_BOOL_CONVERSION = YES;
293 | CLANG_WARN_COMMA = YES;
294 | CLANG_WARN_CONSTANT_CONVERSION = YES;
295 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
296 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
297 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
298 | CLANG_WARN_EMPTY_BODY = YES;
299 | CLANG_WARN_ENUM_CONVERSION = YES;
300 | CLANG_WARN_INFINITE_RECURSION = YES;
301 | CLANG_WARN_INT_CONVERSION = YES;
302 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
303 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
304 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
305 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
306 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
307 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
308 | CLANG_WARN_STRICT_PROTOTYPES = YES;
309 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
310 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
311 | CLANG_WARN_UNREACHABLE_CODE = YES;
312 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
313 | COPY_PHASE_STRIP = NO;
314 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
315 | ENABLE_NS_ASSERTIONS = NO;
316 | ENABLE_STRICT_OBJC_MSGSEND = YES;
317 | GCC_C_LANGUAGE_STANDARD = gnu11;
318 | GCC_NO_COMMON_BLOCKS = YES;
319 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
320 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
321 | GCC_WARN_UNDECLARED_SELECTOR = YES;
322 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
323 | GCC_WARN_UNUSED_FUNCTION = YES;
324 | GCC_WARN_UNUSED_VARIABLE = YES;
325 | MACOSX_DEPLOYMENT_TARGET = 11.1;
326 | MTL_ENABLE_DEBUG_INFO = NO;
327 | MTL_FAST_MATH = YES;
328 | SDKROOT = macosx;
329 | SWIFT_COMPILATION_MODE = wholemodule;
330 | SWIFT_OPTIMIZATION_LEVEL = "-O";
331 | };
332 | name = Release;
333 | };
334 | 0C2464C725DAE3F30057A577 /* Debug */ = {
335 | isa = XCBuildConfiguration;
336 | buildSettings = {
337 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
338 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
339 | CODE_SIGN_ENTITLEMENTS = TestSidebar/TestSidebar.entitlements;
340 | CODE_SIGN_STYLE = Automatic;
341 | COMBINE_HIDPI_IMAGES = YES;
342 | DEVELOPMENT_ASSET_PATHS = "\"TestSidebar/Preview Content\"";
343 | ENABLE_PREVIEWS = YES;
344 | INFOPLIST_FILE = TestSidebar/Info.plist;
345 | LD_RUNPATH_SEARCH_PATHS = (
346 | "$(inherited)",
347 | "@executable_path/../Frameworks",
348 | );
349 | MACOSX_DEPLOYMENT_TARGET = 11.0;
350 | PRODUCT_BUNDLE_IDENTIFIER = com.github.kean.TestSidebar;
351 | PRODUCT_NAME = "$(TARGET_NAME)";
352 | SWIFT_VERSION = 5.0;
353 | };
354 | name = Debug;
355 | };
356 | 0C2464C825DAE3F30057A577 /* Release */ = {
357 | isa = XCBuildConfiguration;
358 | buildSettings = {
359 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
360 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
361 | CODE_SIGN_ENTITLEMENTS = TestSidebar/TestSidebar.entitlements;
362 | CODE_SIGN_STYLE = Automatic;
363 | COMBINE_HIDPI_IMAGES = YES;
364 | DEVELOPMENT_ASSET_PATHS = "\"TestSidebar/Preview Content\"";
365 | ENABLE_PREVIEWS = YES;
366 | INFOPLIST_FILE = TestSidebar/Info.plist;
367 | LD_RUNPATH_SEARCH_PATHS = (
368 | "$(inherited)",
369 | "@executable_path/../Frameworks",
370 | );
371 | MACOSX_DEPLOYMENT_TARGET = 11.0;
372 | PRODUCT_BUNDLE_IDENTIFIER = com.github.kean.TestSidebar;
373 | PRODUCT_NAME = "$(TARGET_NAME)";
374 | SWIFT_VERSION = 5.0;
375 | };
376 | name = Release;
377 | };
378 | 0CC7AC2325DB023200D1B24E /* Debug */ = {
379 | isa = XCBuildConfiguration;
380 | buildSettings = {
381 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
382 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
383 | CODE_SIGN_STYLE = Automatic;
384 | DEVELOPMENT_ASSET_PATHS = "\"TribleTroubleiPad/Preview Content\"";
385 | ENABLE_PREVIEWS = YES;
386 | INFOPLIST_FILE = TribleTroubleiPad/Info.plist;
387 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
388 | LD_RUNPATH_SEARCH_PATHS = (
389 | "$(inherited)",
390 | "@executable_path/Frameworks",
391 | );
392 | PRODUCT_BUNDLE_IDENTIFIER = com.github.kean.TribleTroubleiPad;
393 | PRODUCT_NAME = "$(TARGET_NAME)";
394 | SDKROOT = iphoneos;
395 | SWIFT_VERSION = 5.0;
396 | TARGETED_DEVICE_FAMILY = "1,2";
397 | };
398 | name = Debug;
399 | };
400 | 0CC7AC2425DB023200D1B24E /* Release */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
404 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
405 | CODE_SIGN_STYLE = Automatic;
406 | DEVELOPMENT_ASSET_PATHS = "\"TribleTroubleiPad/Preview Content\"";
407 | ENABLE_PREVIEWS = YES;
408 | INFOPLIST_FILE = TribleTroubleiPad/Info.plist;
409 | IPHONEOS_DEPLOYMENT_TARGET = 14.4;
410 | LD_RUNPATH_SEARCH_PATHS = (
411 | "$(inherited)",
412 | "@executable_path/Frameworks",
413 | );
414 | PRODUCT_BUNDLE_IDENTIFIER = com.github.kean.TribleTroubleiPad;
415 | PRODUCT_NAME = "$(TARGET_NAME)";
416 | SDKROOT = iphoneos;
417 | SWIFT_VERSION = 5.0;
418 | TARGETED_DEVICE_FAMILY = "1,2";
419 | VALIDATE_PRODUCT = YES;
420 | };
421 | name = Release;
422 | };
423 | /* End XCBuildConfiguration section */
424 |
425 | /* Begin XCConfigurationList section */
426 | 0C2464B125DAE3F10057A577 /* Build configuration list for PBXProject "TripleTrouble" */ = {
427 | isa = XCConfigurationList;
428 | buildConfigurations = (
429 | 0C2464C425DAE3F30057A577 /* Debug */,
430 | 0C2464C525DAE3F30057A577 /* Release */,
431 | );
432 | defaultConfigurationIsVisible = 0;
433 | defaultConfigurationName = Release;
434 | };
435 | 0C2464C625DAE3F30057A577 /* Build configuration list for PBXNativeTarget "TripleTrouble" */ = {
436 | isa = XCConfigurationList;
437 | buildConfigurations = (
438 | 0C2464C725DAE3F30057A577 /* Debug */,
439 | 0C2464C825DAE3F30057A577 /* Release */,
440 | );
441 | defaultConfigurationIsVisible = 0;
442 | defaultConfigurationName = Release;
443 | };
444 | 0CC7AC2225DB023200D1B24E /* Build configuration list for PBXNativeTarget "TribleTroubleiPad" */ = {
445 | isa = XCConfigurationList;
446 | buildConfigurations = (
447 | 0CC7AC2325DB023200D1B24E /* Debug */,
448 | 0CC7AC2425DB023200D1B24E /* Release */,
449 | );
450 | defaultConfigurationIsVisible = 0;
451 | defaultConfigurationName = Release;
452 | };
453 | /* End XCConfigurationList section */
454 | };
455 | rootObject = 0C2464AE25DAE3F10057A577 /* Project object */;
456 | }
457 |
--------------------------------------------------------------------------------
/TripleTrouble.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TripleTrouble.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------