├── .gitignore
├── Gemfile
├── Gemfile.lock
├── LICENSE
├── Makefile
├── Podfile
├── Podfile.lock
├── README.md
├── UIKitForMacPlayground.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── xcuserdata
│ └── noahgilmore.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
├── UIKitForMacPlayground.xcworkspace
├── contents.xcworkspacedata
└── xcshareddata
│ ├── IDEWorkspaceChecks.plist
│ └── WorkspaceSettings.xcsettings
├── UIKitForMacPlayground
├── AppDelegate.swift
├── AppKitBridge.swift
├── AppKitBundleLoader.h
├── AppKitBundleLoader.m
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
├── Base.lproj
│ └── LaunchScreen.storyboard
├── ColorView.swift
├── ContextMenuViewController.swift
├── CursorsViewController.swift
├── DetailType.swift
├── DragAndDropViewController.swift
├── DragExampleView.swift
├── DropExampleView.swift
├── ExamplesViewController.swift
├── HashableIdGenerator.swift
├── HeaderView.swift
├── HoverExampleView.swift
├── HoverViewController.swift
├── Info.plist
├── ListViewController.swift
├── NotificationsViewController.swift
├── OpenFileViewController.swift
├── SceneDelegate.swift
├── SquareSceneDelegate.swift
├── SwiftUIView.swift
├── TouchBarViewController.swift
├── UIKitForMacPlayground-Bridging-Header.h
├── UIKitForMacPlayground.entitlements
├── UserActivities.swift
├── ViewController.swift
└── WindowsViewController.swift
└── UIKitForMacPlaygroundSupportingBundle
├── AppKitPrincipal.swift
├── Info.plist
└── UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 | vendor/
5 | .bundle/
6 | Pods/
7 | xcuserdata/
8 |
9 | ## Build generated
10 | build/
11 | DerivedData/
12 |
13 | ## Various settings
14 | *.pbxuser
15 | !default.pbxuser
16 | *.mode1v3
17 | !default.mode1v3
18 | *.mode2v3
19 | !default.mode2v3
20 | *.perspectivev3
21 | !default.perspectivev3
22 | xcuserdata/
23 |
24 | ## Other
25 | *.moved-aside
26 | *.xccheckout
27 | *.xcscmblueprint
28 |
29 | ## Obj-C/Swift specific
30 | *.hmap
31 | *.ipa
32 | *.dSYM.zip
33 | *.dSYM
34 |
35 | ## Playgrounds
36 | timeline.xctimeline
37 | playground.xcworkspace
38 |
39 | # Swift Package Manager
40 | #
41 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
42 | # Packages/
43 | # Package.pins
44 | # Package.resolved
45 | .build/
46 |
47 | # CocoaPods
48 | #
49 | # We recommend against adding the Pods directory to your .gitignore. However
50 | # you should judge for yourself, the pros and cons are mentioned at:
51 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
52 | #
53 | # Pods/
54 |
55 | # Carthage
56 | #
57 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
58 | # Carthage/Checkouts
59 |
60 | Carthage/Build
61 |
62 | # fastlane
63 | #
64 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
65 | # screenshots whenever they are needed.
66 | # For more information about the recommended setup visit:
67 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
68 |
69 | fastlane/report.xml
70 | fastlane/Preview.html
71 | fastlane/screenshots/**/*.png
72 | fastlane/test_output
73 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'cocoapods', '~> 1.7'
4 |
--------------------------------------------------------------------------------
/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | CFPropertyList (3.0.0)
5 | activesupport (4.2.11.1)
6 | i18n (~> 0.7)
7 | minitest (~> 5.1)
8 | thread_safe (~> 0.3, >= 0.3.4)
9 | tzinfo (~> 1.1)
10 | atomos (0.1.3)
11 | claide (1.0.2)
12 | cocoapods (1.7.3)
13 | activesupport (>= 4.0.2, < 5)
14 | claide (>= 1.0.2, < 2.0)
15 | cocoapods-core (= 1.7.3)
16 | cocoapods-deintegrate (>= 1.0.3, < 2.0)
17 | cocoapods-downloader (>= 1.2.2, < 2.0)
18 | cocoapods-plugins (>= 1.0.0, < 2.0)
19 | cocoapods-search (>= 1.0.0, < 2.0)
20 | cocoapods-stats (>= 1.0.0, < 2.0)
21 | cocoapods-trunk (>= 1.3.1, < 2.0)
22 | cocoapods-try (>= 1.1.0, < 2.0)
23 | colored2 (~> 3.1)
24 | escape (~> 0.0.4)
25 | fourflusher (>= 2.3.0, < 3.0)
26 | gh_inspector (~> 1.0)
27 | molinillo (~> 0.6.6)
28 | nap (~> 1.0)
29 | ruby-macho (~> 1.4)
30 | xcodeproj (>= 1.10.0, < 2.0)
31 | cocoapods-core (1.7.3)
32 | activesupport (>= 4.0.2, < 6)
33 | fuzzy_match (~> 2.0.4)
34 | nap (~> 1.0)
35 | cocoapods-deintegrate (1.0.4)
36 | cocoapods-downloader (1.2.2)
37 | cocoapods-plugins (1.0.0)
38 | nap
39 | cocoapods-search (1.0.0)
40 | cocoapods-stats (1.1.0)
41 | cocoapods-trunk (1.3.1)
42 | nap (>= 0.8, < 2.0)
43 | netrc (~> 0.11)
44 | cocoapods-try (1.1.0)
45 | colored2 (3.1.2)
46 | concurrent-ruby (1.1.5)
47 | escape (0.0.4)
48 | fourflusher (2.3.1)
49 | fuzzy_match (2.0.4)
50 | gh_inspector (1.1.3)
51 | i18n (0.9.5)
52 | concurrent-ruby (~> 1.0)
53 | minitest (5.11.3)
54 | molinillo (0.6.6)
55 | nanaimo (0.2.6)
56 | nap (1.1.0)
57 | netrc (0.11.0)
58 | ruby-macho (1.4.0)
59 | thread_safe (0.3.6)
60 | tzinfo (1.2.5)
61 | thread_safe (~> 0.1)
62 | xcodeproj (1.10.0)
63 | CFPropertyList (>= 2.3.3, < 4.0)
64 | atomos (~> 0.1.3)
65 | claide (>= 1.0.2, < 2.0)
66 | colored2 (~> 3.1)
67 | nanaimo (~> 0.2.6)
68 |
69 | PLATFORMS
70 | ruby
71 |
72 | DEPENDENCIES
73 | cocoapods (~> 1.7)
74 |
75 | BUNDLED WITH
76 | 1.15.1
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Noah Gilmore
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 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .PHONY: bundle
2 | bundle:
3 | bundle install --path vendor/bundle
4 |
5 | .PHONY: pods
6 | pods: bundle
7 | bundle exec pod install
8 |
9 | .PHONY: pods-update
10 | pods-update:
11 | bundle exec pod install --repo-update
12 |
13 | .PHONY: clean
14 | clean:
15 | rm -rf Pods
16 |
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | # Uncomment the next line to define a global platform for your project
2 | # platform :ios, '9.0'
3 |
4 | target 'UIKitForMacPlayground' do
5 | # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
6 | use_frameworks!
7 | end
8 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODFILE CHECKSUM: e62e42da1da543cf83b59d8b7d84ce443aaa52dc
2 |
3 | COCOAPODS: 1.7.3
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Catalyst Playground
2 | An example project demonstrating Mac Catalyst features
3 |
4 |
5 |
6 | ## Running
7 | To run the project, clone and cd into the repo, then:
8 |
9 | ```
10 | bundle install --path vendor/bundle
11 | bundle exec pod install
12 | xed .
13 | ```
14 |
15 | Then click the run button!
16 |
17 | (Note that the project compiles on Mac and on iPad, but some features like the toolbar and appkit bundle bridging are not available on iPad)
18 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 50;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 78646C4D22E87D2200B29FE7 /* (null) in Sources */ = {isa = PBXBuildFile; };
11 | 78646C4E22E87D2200B29FE7 /* (null) in Sources */ = {isa = PBXBuildFile; };
12 | A1147A2322F030C8003DC870 /* UIKitForMacPlaygroundSupportingBundle.bundle in Embed PlugIns */ = {isa = PBXBuildFile; fileRef = A1D887B122DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
13 | A1147A2522F03713003DC870 /* NotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1147A2422F03713003DC870 /* NotificationsViewController.swift */; };
14 | A1147A2922F0386B003DC870 /* CursorsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1147A2722F0386B003DC870 /* CursorsViewController.swift */; };
15 | A1147A2D22F08F6D003DC870 /* SwiftUIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1147A2C22F08F6C003DC870 /* SwiftUIView.swift */; };
16 | A116117322D003B000251B87 /* WindowsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A116117222D003B000251B87 /* WindowsViewController.swift */; };
17 | A116368B22C520AD0020072C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A116368A22C520AD0020072C /* AppDelegate.swift */; };
18 | A116368F22C520AD0020072C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A116368E22C520AD0020072C /* ViewController.swift */; };
19 | A116369422C520AF0020072C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A116369322C520AF0020072C /* Assets.xcassets */; };
20 | A116369722C520AF0020072C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A116369522C520AF0020072C /* LaunchScreen.storyboard */; };
21 | A1A1A69322CB0D97003B81A7 /* ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A1A69222CB0D97003B81A7 /* ListViewController.swift */; };
22 | A1A568FC22DFD4900045DF86 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A116368C22C520AD0020072C /* SceneDelegate.swift */; };
23 | A1CDC1E222E98C7700B72002 /* OpenFileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1CDC1E122E98C7700B72002 /* OpenFileViewController.swift */; };
24 | A1D8877722DC3D3B007C73ED /* SquareSceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D8877622DC3D3B007C73ED /* SquareSceneDelegate.swift */; };
25 | A1D8879A22DCA178007C73ED /* HashableIdGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D8879922DCA178007C73ED /* HashableIdGenerator.swift */; };
26 | A1D8879C22DCA1AA007C73ED /* ExamplesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D8879B22DCA1AA007C73ED /* ExamplesViewController.swift */; };
27 | A1D8879E22DCA1F6007C73ED /* HeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D8879D22DCA1F6007C73ED /* HeaderView.swift */; };
28 | A1D887A022DCA20B007C73ED /* UserActivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D8879F22DCA20B007C73ED /* UserActivities.swift */; };
29 | A1D887A222DCA24E007C73ED /* HoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887A122DCA24E007C73ED /* HoverViewController.swift */; };
30 | A1D887A422DCA275007C73ED /* HoverExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887A322DCA275007C73ED /* HoverExampleView.swift */; };
31 | A1D887A622DCA299007C73ED /* ColorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887A522DCA299007C73ED /* ColorView.swift */; };
32 | A1D887A822DCB108007C73ED /* DragAndDropViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887A722DCB108007C73ED /* DragAndDropViewController.swift */; };
33 | A1D887AA22DCB167007C73ED /* DragExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887A922DCB167007C73ED /* DragExampleView.swift */; };
34 | A1D887AC22DCB27F007C73ED /* DropExampleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887AB22DCB27F007C73ED /* DropExampleView.swift */; };
35 | A1D887B922DCC9F3007C73ED /* AppKitPrincipal.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887B822DCC9F3007C73ED /* AppKitPrincipal.swift */; };
36 | A1D887C522DD308C007C73ED /* AppKitBundleLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = A1D887C422DD308C007C73ED /* AppKitBundleLoader.m */; };
37 | A1D887C722DE06EF007C73ED /* TouchBarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887C622DE06EF007C73ED /* TouchBarViewController.swift */; };
38 | A1D887C922DE0D78007C73ED /* ContextMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887C822DE0D78007C73ED /* ContextMenuViewController.swift */; };
39 | A1D887CB22DE3670007C73ED /* DetailType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887CA22DE3670007C73ED /* DetailType.swift */; };
40 | A1D887CC22DE367E007C73ED /* DetailType.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1D887CA22DE3670007C73ED /* DetailType.swift */; };
41 | B96C579B73CBD88DAF015B1D /* Pods_UIKitForMacPlayground.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 67B3C60BFC993E73C93CC8E0 /* Pods_UIKitForMacPlayground.framework */; };
42 | /* End PBXBuildFile section */
43 |
44 | /* Begin PBXContainerItemProxy section */
45 | A1A568FE22DFD7020045DF86 /* PBXContainerItemProxy */ = {
46 | isa = PBXContainerItemProxy;
47 | containerPortal = A116367F22C520AD0020072C /* Project object */;
48 | proxyType = 1;
49 | remoteGlobalIDString = A1D887B022DCC874007C73ED;
50 | remoteInfo = UIKitForMacPlaygroundSupportingBundle;
51 | };
52 | /* End PBXContainerItemProxy section */
53 |
54 | /* Begin PBXCopyFilesBuildPhase section */
55 | A1A5690022DFD7030045DF86 /* Embed PlugIns */ = {
56 | isa = PBXCopyFilesBuildPhase;
57 | buildActionMask = 12;
58 | dstPath = "";
59 | dstSubfolderSpec = 13;
60 | files = (
61 | A1147A2322F030C8003DC870 /* UIKitForMacPlaygroundSupportingBundle.bundle in Embed PlugIns */,
62 | );
63 | name = "Embed PlugIns";
64 | runOnlyForDeploymentPostprocessing = 0;
65 | };
66 | /* End PBXCopyFilesBuildPhase section */
67 |
68 | /* Begin PBXFileReference section */
69 | 417486A30CE1D0BCFC3EB3F4 /* Pods-UIKitForMacPlayground.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UIKitForMacPlayground.release.xcconfig"; path = "Target Support Files/Pods-UIKitForMacPlayground/Pods-UIKitForMacPlayground.release.xcconfig"; sourceTree = ""; };
70 | 67B3C60BFC993E73C93CC8E0 /* Pods_UIKitForMacPlayground.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_UIKitForMacPlayground.framework; sourceTree = BUILT_PRODUCTS_DIR; };
71 | A1147A2422F03713003DC870 /* NotificationsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationsViewController.swift; sourceTree = ""; };
72 | A1147A2722F0386B003DC870 /* CursorsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CursorsViewController.swift; sourceTree = ""; };
73 | A1147A2C22F08F6C003DC870 /* SwiftUIView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftUIView.swift; sourceTree = ""; };
74 | A116117222D003B000251B87 /* WindowsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowsViewController.swift; sourceTree = ""; };
75 | A116368722C520AD0020072C /* UIKitForMacPlayground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UIKitForMacPlayground.app; sourceTree = BUILT_PRODUCTS_DIR; };
76 | A116368A22C520AD0020072C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
77 | A116368C22C520AD0020072C /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; };
78 | A116368E22C520AD0020072C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
79 | A116369322C520AF0020072C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
80 | A116369622C520AF0020072C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
81 | A116369822C520AF0020072C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
82 | A116369E22C520E00020072C /* UIKitForMacPlayground.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = UIKitForMacPlayground.entitlements; sourceTree = ""; };
83 | A1A1A69222CB0D97003B81A7 /* ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListViewController.swift; sourceTree = ""; };
84 | A1CDC1E122E98C7700B72002 /* OpenFileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenFileViewController.swift; sourceTree = ""; };
85 | A1D8877622DC3D3B007C73ED /* SquareSceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SquareSceneDelegate.swift; sourceTree = ""; };
86 | A1D8879922DCA178007C73ED /* HashableIdGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashableIdGenerator.swift; sourceTree = ""; };
87 | A1D8879B22DCA1AA007C73ED /* ExamplesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExamplesViewController.swift; sourceTree = ""; };
88 | A1D8879D22DCA1F6007C73ED /* HeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderView.swift; sourceTree = ""; };
89 | A1D8879F22DCA20B007C73ED /* UserActivities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserActivities.swift; sourceTree = ""; };
90 | A1D887A122DCA24E007C73ED /* HoverViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverViewController.swift; sourceTree = ""; };
91 | A1D887A322DCA275007C73ED /* HoverExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HoverExampleView.swift; sourceTree = ""; };
92 | A1D887A522DCA299007C73ED /* ColorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorView.swift; sourceTree = ""; };
93 | A1D887A722DCB108007C73ED /* DragAndDropViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DragAndDropViewController.swift; sourceTree = ""; };
94 | A1D887A922DCB167007C73ED /* DragExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DragExampleView.swift; sourceTree = ""; };
95 | A1D887AB22DCB27F007C73ED /* DropExampleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropExampleView.swift; sourceTree = ""; };
96 | A1D887B122DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UIKitForMacPlaygroundSupportingBundle.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
97 | A1D887B322DCC874007C73ED /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
98 | A1D887B722DCC9F3007C73ED /* UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h"; sourceTree = ""; };
99 | A1D887B822DCC9F3007C73ED /* AppKitPrincipal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppKitPrincipal.swift; sourceTree = ""; };
100 | A1D887C222DD308C007C73ED /* UIKitForMacPlayground-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIKitForMacPlayground-Bridging-Header.h"; sourceTree = ""; };
101 | A1D887C322DD308C007C73ED /* AppKitBundleLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppKitBundleLoader.h; sourceTree = ""; };
102 | A1D887C422DD308C007C73ED /* AppKitBundleLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppKitBundleLoader.m; sourceTree = ""; };
103 | A1D887C622DE06EF007C73ED /* TouchBarViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TouchBarViewController.swift; sourceTree = ""; };
104 | A1D887C822DE0D78007C73ED /* ContextMenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContextMenuViewController.swift; sourceTree = ""; };
105 | A1D887CA22DE3670007C73ED /* DetailType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailType.swift; sourceTree = ""; };
106 | A793676ECB32AE0CCFB9C6EA /* Pods-UIKitForMacPlayground.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UIKitForMacPlayground.debug.xcconfig"; path = "Target Support Files/Pods-UIKitForMacPlayground/Pods-UIKitForMacPlayground.debug.xcconfig"; sourceTree = ""; };
107 | /* End PBXFileReference section */
108 |
109 | /* Begin PBXFrameworksBuildPhase section */
110 | A116368422C520AD0020072C /* Frameworks */ = {
111 | isa = PBXFrameworksBuildPhase;
112 | buildActionMask = 2147483647;
113 | files = (
114 | B96C579B73CBD88DAF015B1D /* Pods_UIKitForMacPlayground.framework in Frameworks */,
115 | );
116 | runOnlyForDeploymentPostprocessing = 0;
117 | };
118 | A1D887AE22DCC874007C73ED /* Frameworks */ = {
119 | isa = PBXFrameworksBuildPhase;
120 | buildActionMask = 2147483647;
121 | files = (
122 | );
123 | runOnlyForDeploymentPostprocessing = 0;
124 | };
125 | /* End PBXFrameworksBuildPhase section */
126 |
127 | /* Begin PBXGroup section */
128 | 12C4E70C679440A52759DFC1 /* Frameworks */ = {
129 | isa = PBXGroup;
130 | children = (
131 | 67B3C60BFC993E73C93CC8E0 /* Pods_UIKitForMacPlayground.framework */,
132 | );
133 | name = Frameworks;
134 | sourceTree = "";
135 | };
136 | 27FF9F9969858C90A708E2B4 /* Pods */ = {
137 | isa = PBXGroup;
138 | children = (
139 | A793676ECB32AE0CCFB9C6EA /* Pods-UIKitForMacPlayground.debug.xcconfig */,
140 | 417486A30CE1D0BCFC3EB3F4 /* Pods-UIKitForMacPlayground.release.xcconfig */,
141 | );
142 | path = Pods;
143 | sourceTree = "";
144 | };
145 | A116367E22C520AD0020072C = {
146 | isa = PBXGroup;
147 | children = (
148 | A116368922C520AD0020072C /* UIKitForMacPlayground */,
149 | A1D887B222DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle */,
150 | A116368822C520AD0020072C /* Products */,
151 | 27FF9F9969858C90A708E2B4 /* Pods */,
152 | 12C4E70C679440A52759DFC1 /* Frameworks */,
153 | );
154 | sourceTree = "";
155 | };
156 | A116368822C520AD0020072C /* Products */ = {
157 | isa = PBXGroup;
158 | children = (
159 | A116368722C520AD0020072C /* UIKitForMacPlayground.app */,
160 | A1D887B122DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle.bundle */,
161 | );
162 | name = Products;
163 | sourceTree = "";
164 | };
165 | A116368922C520AD0020072C /* UIKitForMacPlayground */ = {
166 | isa = PBXGroup;
167 | children = (
168 | A1147A2C22F08F6C003DC870 /* SwiftUIView.swift */,
169 | A1147A2722F0386B003DC870 /* CursorsViewController.swift */,
170 | A116369E22C520E00020072C /* UIKitForMacPlayground.entitlements */,
171 | A116368A22C520AD0020072C /* AppDelegate.swift */,
172 | A116368C22C520AD0020072C /* SceneDelegate.swift */,
173 | A116368E22C520AD0020072C /* ViewController.swift */,
174 | A116369322C520AF0020072C /* Assets.xcassets */,
175 | A116369522C520AF0020072C /* LaunchScreen.storyboard */,
176 | A116369822C520AF0020072C /* Info.plist */,
177 | A1A1A69222CB0D97003B81A7 /* ListViewController.swift */,
178 | A116117222D003B000251B87 /* WindowsViewController.swift */,
179 | A1D8877622DC3D3B007C73ED /* SquareSceneDelegate.swift */,
180 | A1D8879922DCA178007C73ED /* HashableIdGenerator.swift */,
181 | A1D8879B22DCA1AA007C73ED /* ExamplesViewController.swift */,
182 | A1D8879D22DCA1F6007C73ED /* HeaderView.swift */,
183 | A1D8879F22DCA20B007C73ED /* UserActivities.swift */,
184 | A1D887A122DCA24E007C73ED /* HoverViewController.swift */,
185 | A1D887A322DCA275007C73ED /* HoverExampleView.swift */,
186 | A1D887A522DCA299007C73ED /* ColorView.swift */,
187 | A1D887A722DCB108007C73ED /* DragAndDropViewController.swift */,
188 | A1D887A922DCB167007C73ED /* DragExampleView.swift */,
189 | A1D887AB22DCB27F007C73ED /* DropExampleView.swift */,
190 | A1D887C322DD308C007C73ED /* AppKitBundleLoader.h */,
191 | A1D887C422DD308C007C73ED /* AppKitBundleLoader.m */,
192 | A1D887C222DD308C007C73ED /* UIKitForMacPlayground-Bridging-Header.h */,
193 | A1D887C622DE06EF007C73ED /* TouchBarViewController.swift */,
194 | A1D887C822DE0D78007C73ED /* ContextMenuViewController.swift */,
195 | A1D887CA22DE3670007C73ED /* DetailType.swift */,
196 | A1CDC1E122E98C7700B72002 /* OpenFileViewController.swift */,
197 | A1147A2422F03713003DC870 /* NotificationsViewController.swift */,
198 | );
199 | path = UIKitForMacPlayground;
200 | sourceTree = "";
201 | };
202 | A1D887B222DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle */ = {
203 | isa = PBXGroup;
204 | children = (
205 | A1D887B322DCC874007C73ED /* Info.plist */,
206 | A1D887B822DCC9F3007C73ED /* AppKitPrincipal.swift */,
207 | A1D887B722DCC9F3007C73ED /* UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h */,
208 | );
209 | path = UIKitForMacPlaygroundSupportingBundle;
210 | sourceTree = "";
211 | };
212 | /* End PBXGroup section */
213 |
214 | /* Begin PBXNativeTarget section */
215 | A116368622C520AD0020072C /* UIKitForMacPlayground */ = {
216 | isa = PBXNativeTarget;
217 | buildConfigurationList = A116369B22C520AF0020072C /* Build configuration list for PBXNativeTarget "UIKitForMacPlayground" */;
218 | buildPhases = (
219 | 214D85965551D10ACF6D83E5 /* [CP] Check Pods Manifest.lock */,
220 | A116368322C520AD0020072C /* Sources */,
221 | A116368422C520AD0020072C /* Frameworks */,
222 | A116368522C520AD0020072C /* Resources */,
223 | A1A5690022DFD7030045DF86 /* Embed PlugIns */,
224 | );
225 | buildRules = (
226 | );
227 | dependencies = (
228 | A1A568FF22DFD7020045DF86 /* PBXTargetDependency */,
229 | );
230 | name = UIKitForMacPlayground;
231 | productName = UIKitForMacPlayground;
232 | productReference = A116368722C520AD0020072C /* UIKitForMacPlayground.app */;
233 | productType = "com.apple.product-type.application";
234 | };
235 | A1D887B022DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle */ = {
236 | isa = PBXNativeTarget;
237 | buildConfigurationList = A1D887B422DCC874007C73ED /* Build configuration list for PBXNativeTarget "UIKitForMacPlaygroundSupportingBundle" */;
238 | buildPhases = (
239 | A1D887AD22DCC874007C73ED /* Sources */,
240 | A1D887AE22DCC874007C73ED /* Frameworks */,
241 | A1D887AF22DCC874007C73ED /* Resources */,
242 | );
243 | buildRules = (
244 | );
245 | dependencies = (
246 | );
247 | name = UIKitForMacPlaygroundSupportingBundle;
248 | productName = UIKitForMacPlaygroundSupportingBundle;
249 | productReference = A1D887B122DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle.bundle */;
250 | productType = "com.apple.product-type.bundle";
251 | };
252 | /* End PBXNativeTarget section */
253 |
254 | /* Begin PBXProject section */
255 | A116367F22C520AD0020072C /* Project object */ = {
256 | isa = PBXProject;
257 | attributes = {
258 | LastSwiftUpdateCheck = 1100;
259 | LastUpgradeCheck = 1100;
260 | ORGANIZATIONNAME = "Noah Gilmore";
261 | TargetAttributes = {
262 | A116368622C520AD0020072C = {
263 | CreatedOnToolsVersion = 11.0;
264 | LastSwiftMigration = 1100;
265 | };
266 | A1D887B022DCC874007C73ED = {
267 | CreatedOnToolsVersion = 11.0;
268 | LastSwiftMigration = 1100;
269 | };
270 | };
271 | };
272 | buildConfigurationList = A116368222C520AD0020072C /* Build configuration list for PBXProject "UIKitForMacPlayground" */;
273 | compatibilityVersion = "Xcode 9.3";
274 | developmentRegion = en;
275 | hasScannedForEncodings = 0;
276 | knownRegions = (
277 | en,
278 | Base,
279 | );
280 | mainGroup = A116367E22C520AD0020072C;
281 | productRefGroup = A116368822C520AD0020072C /* Products */;
282 | projectDirPath = "";
283 | projectRoot = "";
284 | targets = (
285 | A116368622C520AD0020072C /* UIKitForMacPlayground */,
286 | A1D887B022DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle */,
287 | );
288 | };
289 | /* End PBXProject section */
290 |
291 | /* Begin PBXResourcesBuildPhase section */
292 | A116368522C520AD0020072C /* Resources */ = {
293 | isa = PBXResourcesBuildPhase;
294 | buildActionMask = 2147483647;
295 | files = (
296 | A116369722C520AF0020072C /* LaunchScreen.storyboard in Resources */,
297 | A116369422C520AF0020072C /* Assets.xcassets in Resources */,
298 | );
299 | runOnlyForDeploymentPostprocessing = 0;
300 | };
301 | A1D887AF22DCC874007C73ED /* Resources */ = {
302 | isa = PBXResourcesBuildPhase;
303 | buildActionMask = 2147483647;
304 | files = (
305 | );
306 | runOnlyForDeploymentPostprocessing = 0;
307 | };
308 | /* End PBXResourcesBuildPhase section */
309 |
310 | /* Begin PBXShellScriptBuildPhase section */
311 | 214D85965551D10ACF6D83E5 /* [CP] Check Pods Manifest.lock */ = {
312 | isa = PBXShellScriptBuildPhase;
313 | buildActionMask = 2147483647;
314 | files = (
315 | );
316 | inputFileListPaths = (
317 | );
318 | inputPaths = (
319 | "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
320 | "${PODS_ROOT}/Manifest.lock",
321 | );
322 | name = "[CP] Check Pods Manifest.lock";
323 | outputFileListPaths = (
324 | );
325 | outputPaths = (
326 | "$(DERIVED_FILE_DIR)/Pods-UIKitForMacPlayground-checkManifestLockResult.txt",
327 | );
328 | runOnlyForDeploymentPostprocessing = 0;
329 | shellPath = /bin/sh;
330 | shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
331 | showEnvVarsInLog = 0;
332 | };
333 | /* End PBXShellScriptBuildPhase section */
334 |
335 | /* Begin PBXSourcesBuildPhase section */
336 | A116368322C520AD0020072C /* Sources */ = {
337 | isa = PBXSourcesBuildPhase;
338 | buildActionMask = 2147483647;
339 | files = (
340 | A1D887A422DCA275007C73ED /* HoverExampleView.swift in Sources */,
341 | A1D887A822DCB108007C73ED /* DragAndDropViewController.swift in Sources */,
342 | 78646C4E22E87D2200B29FE7 /* (null) in Sources */,
343 | A116368F22C520AD0020072C /* ViewController.swift in Sources */,
344 | A1D887C722DE06EF007C73ED /* TouchBarViewController.swift in Sources */,
345 | A1147A2522F03713003DC870 /* NotificationsViewController.swift in Sources */,
346 | A1D8879E22DCA1F6007C73ED /* HeaderView.swift in Sources */,
347 | A1D887A622DCA299007C73ED /* ColorView.swift in Sources */,
348 | A1147A2922F0386B003DC870 /* CursorsViewController.swift in Sources */,
349 | A116368B22C520AD0020072C /* AppDelegate.swift in Sources */,
350 | A1147A2D22F08F6D003DC870 /* SwiftUIView.swift in Sources */,
351 | A1D887A022DCA20B007C73ED /* UserActivities.swift in Sources */,
352 | A1A568FC22DFD4900045DF86 /* SceneDelegate.swift in Sources */,
353 | A1A1A69322CB0D97003B81A7 /* ListViewController.swift in Sources */,
354 | A1D887C522DD308C007C73ED /* AppKitBundleLoader.m in Sources */,
355 | A116117322D003B000251B87 /* WindowsViewController.swift in Sources */,
356 | A1D8877722DC3D3B007C73ED /* SquareSceneDelegate.swift in Sources */,
357 | A1D887A222DCA24E007C73ED /* HoverViewController.swift in Sources */,
358 | A1D8879C22DCA1AA007C73ED /* ExamplesViewController.swift in Sources */,
359 | A1D887C922DE0D78007C73ED /* ContextMenuViewController.swift in Sources */,
360 | A1D887AC22DCB27F007C73ED /* DropExampleView.swift in Sources */,
361 | A1D887CB22DE3670007C73ED /* DetailType.swift in Sources */,
362 | A1D887AA22DCB167007C73ED /* DragExampleView.swift in Sources */,
363 | 78646C4D22E87D2200B29FE7 /* (null) in Sources */,
364 | A1D8879A22DCA178007C73ED /* HashableIdGenerator.swift in Sources */,
365 | A1CDC1E222E98C7700B72002 /* OpenFileViewController.swift in Sources */,
366 | );
367 | runOnlyForDeploymentPostprocessing = 0;
368 | };
369 | A1D887AD22DCC874007C73ED /* Sources */ = {
370 | isa = PBXSourcesBuildPhase;
371 | buildActionMask = 2147483647;
372 | files = (
373 | A1D887CC22DE367E007C73ED /* DetailType.swift in Sources */,
374 | A1D887B922DCC9F3007C73ED /* AppKitPrincipal.swift in Sources */,
375 | );
376 | runOnlyForDeploymentPostprocessing = 0;
377 | };
378 | /* End PBXSourcesBuildPhase section */
379 |
380 | /* Begin PBXTargetDependency section */
381 | A1A568FF22DFD7020045DF86 /* PBXTargetDependency */ = {
382 | isa = PBXTargetDependency;
383 | target = A1D887B022DCC874007C73ED /* UIKitForMacPlaygroundSupportingBundle */;
384 | targetProxy = A1A568FE22DFD7020045DF86 /* PBXContainerItemProxy */;
385 | };
386 | /* End PBXTargetDependency section */
387 |
388 | /* Begin PBXVariantGroup section */
389 | A116369522C520AF0020072C /* LaunchScreen.storyboard */ = {
390 | isa = PBXVariantGroup;
391 | children = (
392 | A116369622C520AF0020072C /* Base */,
393 | );
394 | name = LaunchScreen.storyboard;
395 | sourceTree = "";
396 | };
397 | /* End PBXVariantGroup section */
398 |
399 | /* Begin XCBuildConfiguration section */
400 | A116369922C520AF0020072C /* Debug */ = {
401 | isa = XCBuildConfiguration;
402 | buildSettings = {
403 | ALWAYS_SEARCH_USER_PATHS = NO;
404 | CLANG_ANALYZER_NONNULL = YES;
405 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
406 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
407 | CLANG_CXX_LIBRARY = "libc++";
408 | CLANG_ENABLE_MODULES = YES;
409 | CLANG_ENABLE_OBJC_ARC = YES;
410 | CLANG_ENABLE_OBJC_WEAK = YES;
411 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
412 | CLANG_WARN_BOOL_CONVERSION = YES;
413 | CLANG_WARN_COMMA = YES;
414 | CLANG_WARN_CONSTANT_CONVERSION = YES;
415 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
416 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
417 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
418 | CLANG_WARN_EMPTY_BODY = YES;
419 | CLANG_WARN_ENUM_CONVERSION = YES;
420 | CLANG_WARN_INFINITE_RECURSION = YES;
421 | CLANG_WARN_INT_CONVERSION = YES;
422 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
423 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
424 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
425 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
426 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
427 | CLANG_WARN_STRICT_PROTOTYPES = YES;
428 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
429 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
430 | CLANG_WARN_UNREACHABLE_CODE = YES;
431 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
432 | COPY_PHASE_STRIP = NO;
433 | DEBUG_INFORMATION_FORMAT = dwarf;
434 | ENABLE_STRICT_OBJC_MSGSEND = YES;
435 | ENABLE_TESTABILITY = YES;
436 | GCC_C_LANGUAGE_STANDARD = gnu11;
437 | GCC_DYNAMIC_NO_PIC = NO;
438 | GCC_NO_COMMON_BLOCKS = YES;
439 | GCC_OPTIMIZATION_LEVEL = 0;
440 | GCC_PREPROCESSOR_DEFINITIONS = (
441 | "DEBUG=1",
442 | "$(inherited)",
443 | );
444 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
445 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
446 | GCC_WARN_UNDECLARED_SELECTOR = YES;
447 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
448 | GCC_WARN_UNUSED_FUNCTION = YES;
449 | GCC_WARN_UNUSED_VARIABLE = YES;
450 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
451 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
452 | MTL_FAST_MATH = YES;
453 | ONLY_ACTIVE_ARCH = YES;
454 | SDKROOT = iphoneos;
455 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
456 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
457 | };
458 | name = Debug;
459 | };
460 | A116369A22C520AF0020072C /* Release */ = {
461 | isa = XCBuildConfiguration;
462 | buildSettings = {
463 | ALWAYS_SEARCH_USER_PATHS = NO;
464 | CLANG_ANALYZER_NONNULL = YES;
465 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
466 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
467 | CLANG_CXX_LIBRARY = "libc++";
468 | CLANG_ENABLE_MODULES = YES;
469 | CLANG_ENABLE_OBJC_ARC = YES;
470 | CLANG_ENABLE_OBJC_WEAK = YES;
471 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
472 | CLANG_WARN_BOOL_CONVERSION = YES;
473 | CLANG_WARN_COMMA = YES;
474 | CLANG_WARN_CONSTANT_CONVERSION = YES;
475 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
476 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
477 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
478 | CLANG_WARN_EMPTY_BODY = YES;
479 | CLANG_WARN_ENUM_CONVERSION = YES;
480 | CLANG_WARN_INFINITE_RECURSION = YES;
481 | CLANG_WARN_INT_CONVERSION = YES;
482 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
483 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
484 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
485 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
486 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
487 | CLANG_WARN_STRICT_PROTOTYPES = YES;
488 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
489 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
490 | CLANG_WARN_UNREACHABLE_CODE = YES;
491 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
492 | COPY_PHASE_STRIP = NO;
493 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
494 | ENABLE_NS_ASSERTIONS = NO;
495 | ENABLE_STRICT_OBJC_MSGSEND = YES;
496 | GCC_C_LANGUAGE_STANDARD = gnu11;
497 | GCC_NO_COMMON_BLOCKS = YES;
498 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
499 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
500 | GCC_WARN_UNDECLARED_SELECTOR = YES;
501 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
502 | GCC_WARN_UNUSED_FUNCTION = YES;
503 | GCC_WARN_UNUSED_VARIABLE = YES;
504 | IPHONEOS_DEPLOYMENT_TARGET = 13.0;
505 | MTL_ENABLE_DEBUG_INFO = NO;
506 | MTL_FAST_MATH = YES;
507 | SDKROOT = iphoneos;
508 | SWIFT_COMPILATION_MODE = wholemodule;
509 | SWIFT_OPTIMIZATION_LEVEL = "-O";
510 | VALIDATE_PRODUCT = YES;
511 | };
512 | name = Release;
513 | };
514 | A116369C22C520AF0020072C /* Debug */ = {
515 | isa = XCBuildConfiguration;
516 | baseConfigurationReference = A793676ECB32AE0CCFB9C6EA /* Pods-UIKitForMacPlayground.debug.xcconfig */;
517 | buildSettings = {
518 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
519 | CLANG_ENABLE_MODULES = YES;
520 | CODE_SIGN_ENTITLEMENTS = UIKitForMacPlayground/UIKitForMacPlayground.entitlements;
521 | CODE_SIGN_IDENTITY = "Apple Development";
522 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
523 | CODE_SIGN_STYLE = Automatic;
524 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
525 | DERIVE_UIKITFORMAC_PRODUCT_BUNDLE_IDENTIFIER = YES;
526 | DEVELOPMENT_TEAM = 29P3YRFLV5;
527 | INFOPLIST_FILE = UIKitForMacPlayground/Info.plist;
528 | LD_RUNPATH_SEARCH_PATHS = (
529 | "$(inherited)",
530 | "@executable_path/Frameworks",
531 | );
532 | PRODUCT_BUNDLE_IDENTIFIER = com.noahgilmore.UIKitForMacPlayground;
533 | PRODUCT_NAME = "$(TARGET_NAME)";
534 | PROVISIONING_PROFILE_SPECIFIER = "";
535 | "PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]" = "";
536 | SUPPORTS_MACCATALYST = YES;
537 | SUPPORTS_UIKITFORMAC = YES;
538 | SWIFT_OBJC_BRIDGING_HEADER = "UIKitForMacPlayground/UIKitForMacPlayground-Bridging-Header.h";
539 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
540 | SWIFT_VERSION = 5.0;
541 | TARGETED_DEVICE_FAMILY = "1,2";
542 | };
543 | name = Debug;
544 | };
545 | A116369D22C520AF0020072C /* Release */ = {
546 | isa = XCBuildConfiguration;
547 | baseConfigurationReference = 417486A30CE1D0BCFC3EB3F4 /* Pods-UIKitForMacPlayground.release.xcconfig */;
548 | buildSettings = {
549 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
550 | CLANG_ENABLE_MODULES = YES;
551 | CODE_SIGN_ENTITLEMENTS = UIKitForMacPlayground/UIKitForMacPlayground.entitlements;
552 | CODE_SIGN_STYLE = Automatic;
553 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = YES;
554 | DERIVE_UIKITFORMAC_PRODUCT_BUNDLE_IDENTIFIER = YES;
555 | DEVELOPMENT_TEAM = 29P3YRFLV5;
556 | INFOPLIST_FILE = UIKitForMacPlayground/Info.plist;
557 | LD_RUNPATH_SEARCH_PATHS = (
558 | "$(inherited)",
559 | "@executable_path/Frameworks",
560 | );
561 | PRODUCT_BUNDLE_IDENTIFIER = com.noahgilmore.UIKitForMacPlayground;
562 | PRODUCT_NAME = "$(TARGET_NAME)";
563 | SUPPORTS_MACCATALYST = YES;
564 | SUPPORTS_UIKITFORMAC = YES;
565 | SWIFT_OBJC_BRIDGING_HEADER = "UIKitForMacPlayground/UIKitForMacPlayground-Bridging-Header.h";
566 | SWIFT_VERSION = 5.0;
567 | TARGETED_DEVICE_FAMILY = "1,2";
568 | };
569 | name = Release;
570 | };
571 | A1D887B522DCC874007C73ED /* Debug */ = {
572 | isa = XCBuildConfiguration;
573 | buildSettings = {
574 | CLANG_ENABLE_MODULES = YES;
575 | CODE_SIGN_STYLE = Automatic;
576 | COMBINE_HIDPI_IMAGES = YES;
577 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = NO;
578 | DEVELOPMENT_TEAM = 29P3YRFLV5;
579 | GCC_PREPROCESSOR_DEFINITIONS = (
580 | "DEBUG=1",
581 | "IS_APPKIT_BUNDLE=1",
582 | );
583 | INFOPLIST_FILE = UIKitForMacPlaygroundSupportingBundle/Info.plist;
584 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
585 | LD_RUNPATH_SEARCH_PATHS = (
586 | "$(inherited)",
587 | "@executable_path/../Frameworks",
588 | "@loader_path/../Frameworks",
589 | );
590 | MACOSX_DEPLOYMENT_TARGET = 10.15;
591 | PRODUCT_BUNDLE_IDENTIFIER = com.noahgilmore.UIKitForMacPlaygroundSupportingBundle;
592 | PRODUCT_NAME = "$(TARGET_NAME)";
593 | SDKROOT = macosx;
594 | SKIP_INSTALL = YES;
595 | SUPPORTS_MACCATALYST = NO;
596 | SWIFT_OBJC_BRIDGING_HEADER = "UIKitForMacPlaygroundSupportingBundle/UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h";
597 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
598 | SWIFT_VERSION = 5.0;
599 | WRAPPER_EXTENSION = bundle;
600 | };
601 | name = Debug;
602 | };
603 | A1D887B622DCC874007C73ED /* Release */ = {
604 | isa = XCBuildConfiguration;
605 | buildSettings = {
606 | CLANG_ENABLE_MODULES = YES;
607 | CODE_SIGN_STYLE = Automatic;
608 | COMBINE_HIDPI_IMAGES = YES;
609 | DERIVE_MACCATALYST_PRODUCT_BUNDLE_IDENTIFIER = NO;
610 | DEVELOPMENT_TEAM = Y5PE65HELJ;
611 | GCC_PREPROCESSOR_DEFINITIONS = "IS_APPKIT_BUNDLE=1";
612 | INFOPLIST_FILE = UIKitForMacPlaygroundSupportingBundle/Info.plist;
613 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles";
614 | LD_RUNPATH_SEARCH_PATHS = (
615 | "$(inherited)",
616 | "@executable_path/../Frameworks",
617 | "@loader_path/../Frameworks",
618 | );
619 | MACOSX_DEPLOYMENT_TARGET = 10.15;
620 | PRODUCT_BUNDLE_IDENTIFIER = com.noahgilmore.UIKitForMacPlaygroundSupportingBundle;
621 | PRODUCT_NAME = "$(TARGET_NAME)";
622 | SDKROOT = macosx;
623 | SKIP_INSTALL = YES;
624 | SUPPORTS_MACCATALYST = NO;
625 | SWIFT_OBJC_BRIDGING_HEADER = "UIKitForMacPlaygroundSupportingBundle/UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h";
626 | SWIFT_VERSION = 5.0;
627 | WRAPPER_EXTENSION = bundle;
628 | };
629 | name = Release;
630 | };
631 | /* End XCBuildConfiguration section */
632 |
633 | /* Begin XCConfigurationList section */
634 | A116368222C520AD0020072C /* Build configuration list for PBXProject "UIKitForMacPlayground" */ = {
635 | isa = XCConfigurationList;
636 | buildConfigurations = (
637 | A116369922C520AF0020072C /* Debug */,
638 | A116369A22C520AF0020072C /* Release */,
639 | );
640 | defaultConfigurationIsVisible = 0;
641 | defaultConfigurationName = Release;
642 | };
643 | A116369B22C520AF0020072C /* Build configuration list for PBXNativeTarget "UIKitForMacPlayground" */ = {
644 | isa = XCConfigurationList;
645 | buildConfigurations = (
646 | A116369C22C520AF0020072C /* Debug */,
647 | A116369D22C520AF0020072C /* Release */,
648 | );
649 | defaultConfigurationIsVisible = 0;
650 | defaultConfigurationName = Release;
651 | };
652 | A1D887B422DCC874007C73ED /* Build configuration list for PBXNativeTarget "UIKitForMacPlaygroundSupportingBundle" */ = {
653 | isa = XCConfigurationList;
654 | buildConfigurations = (
655 | A1D887B522DCC874007C73ED /* Debug */,
656 | A1D887B622DCC874007C73ED /* Release */,
657 | );
658 | defaultConfigurationIsVisible = 0;
659 | defaultConfigurationName = Release;
660 | };
661 | /* End XCConfigurationList section */
662 | };
663 | rootObject = A116367F22C520AD0020072C /* Project object */;
664 | }
665 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcodeproj/xcuserdata/noahgilmore.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | UIKitForMacPlayground.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 1
11 |
12 | UIKitForMacPlaygroundSupportingBundle.xcscheme_^#shared#^_
13 |
14 | orderHint
15 | 2
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 6/27/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import UserNotifications
11 |
12 | @UIApplicationMain
13 | class AppDelegate: UIResponder, UIApplicationDelegate {
14 | var bridge: AppKitObjcBridge? = nil
15 |
16 | static var shared: AppDelegate {
17 | return UIApplication.shared.delegate as! AppDelegate
18 | }
19 |
20 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
21 | // Override point for customization after application launch.
22 | let pluginPath = Bundle.main.builtInPlugInsPath!.appending("/UIKitForMacPlaygroundSupportingBundle.bundle")
23 | let bundle = Bundle(path: pluginPath)!
24 | let loader = AppKitBundleLoader()
25 | bridge = loader.load(bundle)
26 | bridge?.setUIKit(self)
27 |
28 | UNUserNotificationCenter.current().delegate = self
29 |
30 | return true
31 | }
32 |
33 | func applicationWillTerminate(_ application: UIApplication) {
34 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
35 | }
36 |
37 | // MARK: UISceneSession Lifecycle
38 |
39 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
40 |
41 | if let activity = options.userActivities.first {
42 | if activity.activityType == UserActivities.square.rawValue {
43 | let configuration = UISceneConfiguration(name: nil, sessionRole: connectingSceneSession.role)
44 | configuration.delegateClass = SquareSceneDelegate.self
45 | return configuration
46 | }
47 | }
48 |
49 | let configuration = UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
50 | configuration.delegateClass = SceneDelegate.self
51 | return configuration
52 | }
53 |
54 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {
55 | // Called when the user discards a scene session.
56 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
57 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
58 | }
59 |
60 | override func buildMenu(with builder: UIMenuBuilder) {
61 | super.buildMenu(with: builder)
62 |
63 | let command = UIKeyCommand(
64 | input: "J",
65 | modifierFlags: [.command],
66 | action: #selector(self.jumpSelected(_:))
67 | )
68 | command.title = "Jump to Windows"
69 |
70 | let noShortcutCommand = UICommand(
71 | title: "No shortcut",
72 | image: nil,
73 | action: #selector(self.noShortcutSelected),
74 | propertyList: nil
75 | )
76 |
77 | builder.insertChild(UIMenu(
78 | title: "Jump",
79 | image: nil,
80 | identifier: UIMenu.Identifier(rawValue: "com.noahgilmore.uikitformacplaygroud.jump"),
81 | options: [],
82 | children: [command, noShortcutCommand]
83 | ), atEndOfMenu: .view)
84 | }
85 |
86 | @objc private func jumpSelected(_ sender: AppDelegate) {
87 | guard let delegate = UIApplication.shared.connectedScenes.compactMap({
88 | ($0 as? UIWindowScene)
89 | }).filter({ $0.activationState == .foregroundActive })
90 | .first?.delegate else { return }
91 | guard let sceneDelegate = delegate as? SceneDelegate else { return }
92 | sceneDelegate.handleDetailType(.windows)
93 | }
94 |
95 | @objc private func noShortcutSelected(_ sender: AppDelegate) {
96 | guard let delegate = UIApplication.shared.connectedScenes.compactMap({
97 | ($0 as? UIWindowScene)
98 | }).filter({ $0.activationState == .foregroundActive })
99 | .first?.delegate else { return }
100 | guard let sceneDelegate = delegate as? SceneDelegate else { return }
101 | sceneDelegate.handleDetailType(.keyboardShortcuts)
102 | }
103 | }
104 |
105 | extension AppDelegate: UIKitBridge {
106 | func didSelectDetailType(_ detailTypeString: String) {
107 | guard let detailType = DetailType(rawValue: detailTypeString) else { return }
108 | print(detailType)
109 | guard let scene = UIResponder.currentWindowScene() else { return }
110 | print(scene)
111 | guard let delegate = scene.delegate as? SceneDelegate else { return }
112 | print(delegate)
113 | delegate.handleDetailType(detailType)
114 | }
115 | }
116 |
117 | private weak var currentFirstResponder: UIResponder?
118 | extension UIResponder {
119 | var containingScene: UIWindowScene? {
120 | var currentResponder: UIResponder = self
121 | while let responder = currentResponder.next {
122 | if let windowScene = responder as? UIWindowScene {
123 | return windowScene
124 | }
125 | currentResponder = responder
126 | }
127 | return nil
128 | }
129 |
130 | @objc func findFirstResponder(sender: AnyObject) {
131 | currentFirstResponder = self
132 | }
133 |
134 | static func firstResponder() -> UIResponder? {
135 | currentFirstResponder = nil
136 | UIApplication.shared.sendAction(#selector(findFirstResponder(sender:)), to: nil, from: nil, for: nil)
137 | return currentFirstResponder
138 | }
139 |
140 | static func currentWindowScene() -> UIWindowScene? {
141 | return firstResponder()?.containingScene
142 | }
143 | }
144 |
145 | extension AppDelegate: UNUserNotificationCenterDelegate {
146 | func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
147 | // Allows displaying rich notifications even while the app is in the foreground
148 | completionHandler([.alert, .badge, .sound])
149 | }
150 | }
151 |
152 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/AppKitBridge.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppKitBridge.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | protocol AppKitBridge: NSObjectProtocol {
12 | func ping()
13 | }
14 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/AppKitBundleLoader.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppKitBundleLoader.h
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #if TARGET_OS_MACCATALYST || IS_APPKIT_BUNDLE
12 | #import
13 | #endif
14 |
15 | @protocol UIKitBridge;
16 |
17 | NS_ASSUME_NONNULL_BEGIN
18 |
19 | @protocol AppKitObjcBridge
20 |
21 | - (void)moveWindowRight;
22 | #if TARGET_OS_MACCATALYST || IS_APPKIT_BUNDLE
23 | - (NSToolbarItem *)customToolbarItemWithIdentifier:(NSString *)identifier callback:(void (^)(NSString *))callback NS_SWIFT_NAME(customToolbarItem(identifier:callback:));
24 | #endif
25 | - (void)setUIKitBridge:(id)bridge;
26 | - (void)setPointerCursor;
27 | - (void)setDefaultCursor;
28 | - (void)sceneBecameActiveWithIdentifier:(NSString *)string NS_SWIFT_NAME(sceneBecameActive(identifier:));
29 |
30 | @end
31 |
32 | @interface AppKitBundleLoader : NSObject
33 |
34 | - (id)loadBundle:(NSBundle *)bundle;
35 |
36 | @end
37 |
38 | NS_ASSUME_NONNULL_END
39 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/AppKitBundleLoader.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppKitBundleLoader.m
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | #import "AppKitBundleLoader.h"
10 |
11 | @implementation AppKitBundleLoader
12 |
13 | - (id)loadBundle:(NSBundle *)bundle {
14 | id bridge = [[[bundle principalClass] alloc] init];
15 | return bridge;
16 | }
17 |
18 | @end
19 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "20x20",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "20x20",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "29x29",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "29x29",
61 | "scale" : "2x"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "size" : "40x40",
66 | "scale" : "1x"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "size" : "40x40",
71 | "scale" : "2x"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "size" : "76x76",
76 | "scale" : "1x"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "size" : "76x76",
81 | "scale" : "2x"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "size" : "83.5x83.5",
86 | "scale" : "2x"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "size" : "1024x1024",
91 | "scale" : "1x"
92 | }
93 | ],
94 | "info" : {
95 | "version" : 1,
96 | "author" : "xcode"
97 | }
98 | }
--------------------------------------------------------------------------------
/UIKitForMacPlayground/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/UIKitForMacPlayground/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/ColorView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ColorView.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class ColorView: UIView {
12 | var color: UIColor {
13 | didSet {
14 | self.backgroundColor = color
15 | }
16 | }
17 |
18 | init(color: UIColor, dimension: CGFloat? = nil) {
19 | self.color = color
20 | super.init(frame: .zero)
21 |
22 | self.backgroundColor = color
23 |
24 | if let dimension = dimension {
25 | self.widthAnchor.constraint(equalToConstant: dimension).isActive = true
26 | self.heightAnchor.constraint(equalToConstant: dimension).isActive = true
27 | }
28 | }
29 |
30 | required init?(coder aDecoder: NSCoder) {
31 | fatalError("init(coder:) has not been implemented")
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/ContextMenuViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContextMenuViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/16/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | final class ContextMenuViewController: ExamplesViewController {
13 | let colorView = ColorView(color: .systemTeal, dimension: 100)
14 |
15 | override func viewDidLoad() {
16 | self.views = [
17 | .paragraph(text: "This square has a context menu (right click to trigger)"),
18 | .view(view: colorView)
19 | ]
20 | super.viewDidLoad()
21 |
22 | colorView.addInteraction(UIContextMenuInteraction(delegate: self))
23 | }
24 | }
25 |
26 | extension ContextMenuViewController: UIContextMenuInteractionDelegate {
27 | func contextMenuInteraction(_ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint) -> UIContextMenuConfiguration? {
28 | return UIContextMenuConfiguration(identifier: nil, previewProvider: nil, actionProvider: { suggestedActions in
29 | return UIMenu(title: "Menu", image: nil, identifier: nil, children: [
30 | UIAction(title: "Change to random color", image: UIImage(systemName: "square.and.arrow.up"), identifier: UIAction.Identifier(rawValue: "open"), handler: { action in
31 | self.colorView.color = generateRandomColor()
32 | }),
33 | UIMenu(title: "Predefined colors", image: nil, identifier: nil, children: [
34 | (string: "Red", color: UIColor.systemRed),
35 | (string: "Blue", color: UIColor.systemBlue),
36 | (string: "Green", color: UIColor.systemGreen)
37 | ].map { config in
38 | UIAction(title: config.string, image: nil, identifier: UIAction.Identifier(rawValue: "open-\(config.string)"), handler: { action in
39 | self.colorView.color = config.color
40 | })
41 | })
42 | ])
43 | })
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/CursorsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // CursorsViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/17/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | final class CursorPointerGestureRegocnizerTarget {
13 | @objc func handleHover(_ sender: UIHoverGestureRecognizer) {
14 | switch sender.state {
15 | case .began, .changed:
16 | AppDelegate.shared.bridge?.setPointerCursor()
17 | case .ended:
18 | AppDelegate.shared.bridge?.setDefaultCursor()
19 | default:
20 | break
21 | }
22 | }
23 | }
24 |
25 | final class CursorPointerGestureRecognizer: UIHoverGestureRecognizer {
26 | private let target: CursorPointerGestureRegocnizerTarget
27 | init() {
28 | let target = CursorPointerGestureRegocnizerTarget()
29 | self.target = target
30 | super.init(target: target, action: #selector(CursorPointerGestureRegocnizerTarget.handleHover(_:)))
31 | }
32 | }
33 |
34 | final class CursorsViewController: ExamplesViewController {
35 | let colorView = ColorView(color: .systemPink, dimension: 100)
36 | weak var bridge: AppKitObjcBridge? = nil
37 |
38 | override func viewDidLoad() {
39 | bridge = AppDelegate.shared.bridge
40 | if bridge != nil {
41 | self.views = [
42 | .paragraph(text: "This square changes the cursor when hovering over it."),
43 | .paragraph(text: "Also, all the buttons in this app change the cursor to a pointer when they're hovered over."),
44 | .view(view: colorView)
45 | ]
46 | } else {
47 | self.views = [
48 | .paragraph(text: "Cursors are not supported in non-AppKit runtime contexts."),
49 | .view(view: colorView)
50 | ]
51 | }
52 | super.viewDidLoad()
53 |
54 | colorView.addGestureRecognizer(UIHoverGestureRecognizer(target: self, action: #selector(handleHover(_:))))
55 | }
56 |
57 | @objc private func handleHover(_ sender: UIHoverGestureRecognizer) {
58 | switch sender.state {
59 | case .began, .changed:
60 | AppDelegate.shared.bridge?.setPointerCursor()
61 | case .ended:
62 | AppDelegate.shared.bridge?.setDefaultCursor()
63 | default:
64 | break
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/DetailType.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DetailType.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/16/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | enum DetailType: String, CaseIterable {
12 | case keyboardShortcuts = "Keyboard Shortcuts"
13 | case windows = "Windows"
14 | case hover = "Hover"
15 | case dragAndDrop = "Drag and drop"
16 | case touchBar = "Touch bar"
17 | case contextMenus = "Context menus"
18 | case cursors = "Cursors"
19 | case swiftUI = "SwiftUI"
20 | case openFile = "Opening files"
21 | case notifications = "Notifications"
22 | }
23 |
24 | @objc protocol UIKitBridge {
25 | func didSelectDetailType(_ detailTypeString: String)
26 | }
27 |
28 | extension Notification.Name {
29 | static let didChangeDetailType = Notification.Name("didChangeDetailType")
30 | }
31 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/DragAndDropViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DragAndDropViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class DragAndDropViewController: ExamplesViewController {
13 | override func viewDidLoad() {
14 | self.views = [
15 | .paragraph(text: "These squares are drag targets: drag them into the drop targets to set color (even across windows)."),
16 | .view(view: DragExampleView()),
17 | .paragraph(text: "These squares are drop targets: drag a drag target onto them to set their color (even across windows)"),
18 | .view(view: DropExampleView()),
19 | ]
20 |
21 | super.viewDidLoad()
22 | }
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/DragExampleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DragExampleView.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | final class DragColorView: ColorView {
13 | init(color: UIColor) {
14 | super.init(color: color, dimension: 70)
15 | let interaction = UIDragInteraction(delegate: self)
16 | self.addInteraction(interaction)
17 | }
18 |
19 | required init?(coder aDecoder: NSCoder) {
20 | fatalError("init(coder:) has not been implemented")
21 | }
22 | }
23 |
24 | extension DragColorView: UIDragInteractionDelegate {
25 | func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
26 | return [UIDragItem(itemProvider: NSItemProvider(object: self.color))]
27 | }
28 | }
29 |
30 | final class DragExampleView: UIView {
31 | private let stackView: UIStackView = {
32 | let view = UIStackView()
33 | view.axis = .horizontal
34 | view.spacing = 40
35 | return view
36 | }()
37 |
38 | init() {
39 | super.init(frame: .zero)
40 |
41 | self.addSubview(stackView)
42 | for color in [UIColor.red, UIColor.blue, UIColor.green] {
43 | let colorView = DragColorView(color: color)
44 | stackView.addArrangedSubview(colorView)
45 | }
46 | stackView.translatesAutoresizingMaskIntoConstraints = false
47 | stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
48 | stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
49 | stackView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
50 | stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
51 |
52 | // let view = DragColorView(color: UIColor.purple)
53 | // self.addSubview(view)
54 | // view.translatesAutoresizingMaskIntoConstraints = false
55 | // view.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
56 | // view.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
57 | // view.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
58 | // view.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
59 | }
60 |
61 | required init?(coder aDecoder: NSCoder) {
62 | fatalError("init(coder:) has not been implemented")
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/DropExampleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DropExampleView.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | final class DropColorView: ColorView {
13 | init(color: UIColor) {
14 | super.init(color: color, dimension: 100)
15 | let interaction = UIDropInteraction(delegate: self)
16 | self.addInteraction(interaction)
17 | }
18 |
19 | required init?(coder aDecoder: NSCoder) {
20 | fatalError("init(coder:) has not been implemented")
21 | }
22 | }
23 |
24 | extension DropColorView: UIDropInteractionDelegate {
25 | func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
26 | return session.canLoadObjects(ofClass: UIColor.self)
27 | }
28 |
29 | func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
30 | session.loadObjects(ofClass: UIColor.self) { colors in
31 | let color = colors.first as! UIColor
32 | self.color = color
33 | }
34 | }
35 |
36 | func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
37 | return UIDropProposal(operation: .copy)
38 | }
39 | }
40 |
41 | final class DropExampleView: UIView {
42 | private let stackView: UIStackView = {
43 | let view = UIStackView()
44 | view.axis = .horizontal
45 | view.spacing = 40
46 | return view
47 | }()
48 |
49 | init() {
50 | super.init(frame: .zero)
51 |
52 | self.addSubview(stackView)
53 |
54 | for color in [UIColor.red, UIColor.blue, UIColor.green] {
55 | let colorView = DropColorView(color: color)
56 | stackView.addArrangedSubview(colorView)
57 | }
58 |
59 | stackView.translatesAutoresizingMaskIntoConstraints = false
60 | stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
61 | stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
62 | stackView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
63 | stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
64 |
65 | // let view = DropColorView(color: UIColor.systemPink)
66 | // self.addSubview(view)
67 | // view.translatesAutoresizingMaskIntoConstraints = false
68 | // view.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
69 | // view.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
70 | // view.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
71 | // view.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
72 | }
73 |
74 | required init?(coder aDecoder: NSCoder) {
75 | fatalError("init(coder:) has not been implemented")
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/ExamplesViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ExamplesViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class AppKitWindowReportingViewController: UIViewController {
13 | var identifier: String? = nil
14 |
15 | override func viewDidAppear(_ animated: Bool) {
16 | super.viewDidAppear(animated)
17 |
18 | if let identifier = self.identifier {
19 | if self.view.window?.rootViewController == self {
20 | AppDelegate.shared.bridge?.sceneBecameActive(identifier: identifier)
21 | }
22 | }
23 | }
24 | }
25 |
26 | /// Subclasses extend this controller to provide standard components in a list (ViewType instances)
27 | class ExamplesViewController: AppKitWindowReportingViewController {
28 | typealias ButtonHandler = (ExamplesViewController) -> Void
29 | enum ViewType {
30 | case header(text: String)
31 | case paragraph(text: String)
32 | case button(text: String, color: UIColor, didTap: ButtonHandler)
33 | case view(view: UIView)
34 | }
35 |
36 | var views: [ViewType] = []
37 |
38 | private let stackView: UIStackView = {
39 | let view = UIStackView()
40 | view.axis = .vertical
41 | view.spacing = 20
42 | view.alignment = .leading
43 | return view
44 | }()
45 |
46 | private var buttonUUIDHashValuesToActions: [Int: ButtonHandler] = [:]
47 |
48 | override func viewDidLoad() {
49 | super.viewDidLoad()
50 |
51 | self.view.backgroundColor = UIColor.systemBackground
52 |
53 | for view in views {
54 | switch view {
55 | case let .header(text):
56 | stackView.addArrangedSubview(HeaderView(text: text))
57 | case let .paragraph(text):
58 | let label = UILabel()
59 | label.textColor = .label
60 | label.text = text
61 | label.numberOfLines = 0
62 | stackView.addArrangedSubview(label)
63 | case let .button(text, color, didTap):
64 | let button = UIButton()
65 | let uid = HashableIdGenerator.next()
66 | button.setTitle(text, for: .normal)
67 | button.tag = uid
68 | button.addTarget(self, action: #selector(didTapButton(_:)), for: .touchUpInside)
69 | button.setTitleColor(color, for: .normal)
70 | button.addGestureRecognizer(CursorPointerGestureRecognizer())
71 | buttonUUIDHashValuesToActions[uid] = didTap
72 | stackView.addArrangedSubview(button)
73 | case let .view(view):
74 | stackView.addArrangedSubview(view)
75 | }
76 | }
77 |
78 | self.view.addSubview(stackView)
79 | stackView.translatesAutoresizingMaskIntoConstraints = false
80 | stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 50).isActive = true
81 | let trailingConstraint = stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -50)
82 | trailingConstraint.priority = .defaultHigh
83 | trailingConstraint.isActive = true
84 | stackView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
85 | }
86 |
87 | @objc private func didTapButton(_ sender: UIButton) {
88 | let hashValue = sender.tag
89 | guard let handler = buttonUUIDHashValuesToActions[hashValue] else {
90 | return
91 | }
92 | handler(self)
93 | }
94 |
95 | override var canBecomeFirstResponder: Bool {
96 | return true
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/HashableIdGenerator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HashableIdGenerator.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// Generates a process-unique stream of ints. Used for buttonn identification in ExamplesViewController.
12 | enum HashableIdGenerator {
13 | private static var nextId = 0
14 |
15 | static func next() -> Int {
16 | nextId += 1
17 | return nextId
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/HeaderView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HeaderView.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | final class HeaderView: UIView {
13 | init(text: String) {
14 | super.init(frame: .zero)
15 |
16 | let label = UILabel()
17 | label.textColor = .label
18 | label.text = text
19 | label.font = UIFont.preferredFont(forTextStyle: .largeTitle)
20 | label.translatesAutoresizingMaskIntoConstraints = false
21 | addSubview(label)
22 | label.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
23 | label.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
24 | label.topAnchor.constraint(equalTo: self.topAnchor, constant: 30).isActive = true
25 | label.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
26 | }
27 |
28 | required init?(coder aDecoder: NSCoder) {
29 | fatalError("init(coder:) has not been implemented")
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/HoverExampleView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HoverExampleView.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | final class HoverColorView: ColorView {
13 | let hoverColor: UIColor
14 | let originalColor: UIColor
15 |
16 | init(color: UIColor, hoverColor: UIColor) {
17 | self.hoverColor = hoverColor
18 | self.originalColor = color
19 |
20 | super.init(color: color, dimension: 70)
21 | let recognizer = UIHoverGestureRecognizer(target: self, action: #selector(handleHover(_:)))
22 | self.addGestureRecognizer(recognizer)
23 | }
24 |
25 | required init?(coder aDecoder: NSCoder) {
26 | fatalError("init(coder:) has not been implemented")
27 | }
28 |
29 | @objc private func handleHover(_ sender: UIHoverGestureRecognizer) {
30 | switch sender.state {
31 | case .began, .changed:
32 | self.color = self.hoverColor
33 | case .ended:
34 | self.color = self.originalColor
35 | default:
36 | break
37 | }
38 | }
39 | }
40 |
41 | final class HoverExampleView: UIView {
42 | private let stackView: UIStackView = {
43 | let view = UIStackView()
44 | view.axis = .horizontal
45 | view.spacing = 40
46 | return view
47 | }()
48 |
49 | init() {
50 | super.init(frame: .zero)
51 |
52 | self.addSubview(stackView)
53 |
54 | for (color, hoverColor) in [(UIColor.red, UIColor.blue), (UIColor.blue, UIColor.green), (UIColor.green, UIColor.red)] {
55 | let colorView = HoverColorView(color: color, hoverColor: hoverColor)
56 | stackView.addArrangedSubview(colorView)
57 | }
58 |
59 | stackView.translatesAutoresizingMaskIntoConstraints = false
60 | stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor).isActive = true
61 | stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor).isActive = true
62 | stackView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
63 | stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
64 | }
65 |
66 | required init?(coder aDecoder: NSCoder) {
67 | fatalError("init(coder:) has not been implemented")
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/HoverViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HoverViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class HoverViewController: ExamplesViewController {
13 | override func viewDidLoad() {
14 | self.views = [
15 | .paragraph(text: "The following squares change color when you hover over them."),
16 | .view(view: HoverExampleView())
17 | ]
18 |
19 | super.viewDidLoad()
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleDisplayName
8 | CatalystPlayground
9 | CFBundleExecutable
10 | $(EXECUTABLE_NAME)
11 | CFBundleIdentifier
12 | $(PRODUCT_BUNDLE_IDENTIFIER)
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | $(PRODUCT_NAME)
17 | CFBundlePackageType
18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSUserActivityTypes
26 |
27 | com.noahgilmore.uikitformacplayground.square
28 |
29 | UIApplicationSceneManifest
30 |
31 | UIApplicationSupportsMultipleScenes
32 |
33 |
34 | UILaunchStoryboardName
35 | LaunchScreen
36 | UIRequiredDeviceCapabilities
37 |
38 | armv7
39 |
40 | UISupportedInterfaceOrientations
41 |
42 | UIInterfaceOrientationPortrait
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 | UISupportedInterfaceOrientations~ipad
47 |
48 | UIInterfaceOrientationPortrait
49 | UIInterfaceOrientationPortraitUpsideDown
50 | UIInterfaceOrientationLandscapeLeft
51 | UIInterfaceOrientationLandscapeRight
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/ListViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ListViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/1/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | enum Section {
13 | case main
14 | }
15 |
16 | final class ListViewController: UITableViewController {
17 | let didSelectDetailType: (DetailType) -> Void
18 | private var dataSource: UITableViewDiffableDataSource!
19 |
20 | private static var reuseIdentifier = "cell"
21 |
22 | init(didSelectDetailType: @escaping (DetailType) -> Void) {
23 | self.didSelectDetailType = didSelectDetailType
24 | super.init(style: .plain)
25 | self.title = "Examples"
26 |
27 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: Self.reuseIdentifier)
28 |
29 | dataSource = UITableViewDiffableDataSource(tableView: self.tableView) { tableView, indexPath, detailType in
30 | let cell = tableView.dequeueReusableCell(withIdentifier: Self.reuseIdentifier)!
31 | cell.textLabel?.text = detailType.rawValue
32 | return cell
33 | }
34 |
35 | var snapshot = NSDiffableDataSourceSnapshot()
36 | snapshot.appendSections([.main])
37 | snapshot.appendItems(DetailType.allCases)
38 | dataSource.apply(snapshot)
39 | self.tableView.delegate = self
40 | }
41 |
42 | required init?(coder aDecoder: NSCoder) {
43 | fatalError("init(coder:) has not been implemented")
44 | }
45 |
46 | override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
47 | tableView.deselectRow(at: indexPath, animated: true)
48 | guard let detailType = dataSource.itemIdentifier(for: indexPath) else { return }
49 | self.didSelectDetailType(detailType)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/NotificationsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NotificationsViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/30/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import UserNotifications
12 |
13 | class NotificationsViewController: ExamplesViewController {
14 | override func viewDidLoad() {
15 | self.views = [
16 | .paragraph(text: "This button shows a local notification."),
17 | .button(text: "Show notification", color: .systemBlue, didTap: { _ in
18 | self.requestAndTriggerNotification()
19 | }
20 | )
21 | ]
22 |
23 | super.viewDidLoad()
24 | }
25 |
26 | func requestAndTriggerNotification() {
27 | let center = UNUserNotificationCenter.current()
28 | // Request permission to display alerts and play sounds.
29 | // Note: if the app is in the foreground, this will trigger the AppDelegate's
30 | // UNUserNotificationCenterDelegate method, which will call the completionHandler
31 | // to display the default notification UI. If the app is in the background, the
32 | // default notification UI will be displayed without calling the AppDelegate
33 | center.requestAuthorization(options: [.badge, .sound, .alert]) { (granted, error) in
34 | if granted {
35 | self.triggerNotification()
36 | }
37 | }
38 | }
39 |
40 | func triggerNotification() {
41 | let content = UNMutableNotificationContent()
42 | content.title = "This is a notification"
43 | content.body = "This is the notification body"
44 | let uuidString = UUID().uuidString
45 | let request = UNNotificationRequest(identifier: uuidString,
46 | content: content, trigger: nil)
47 |
48 | // Schedule the request with the system.
49 | let notificationCenter = UNUserNotificationCenter.current()
50 | notificationCenter.add(request) { (error) in
51 | if let error = error {
52 | print("User notification error: \(error)")
53 | }
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/OpenFileViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OpenFileViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/25/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 | import MobileCoreServices
12 |
13 | class OpenFileViewController: ExamplesViewController {
14 | private lazy var imageView: UIImageView = {
15 | let view = UIImageView()
16 | view.contentMode = .scaleAspectFit
17 | view.widthAnchor.constraint(lessThanOrEqualToConstant: 300).isActive = true
18 | return view
19 | }()
20 |
21 | override func viewDidLoad() {
22 | self.views = [
23 | .paragraph(text: "This button launches a file open panel for images. The chosen image will be displayed in an image view."),
24 | .button(text: "Open file", color: .systemBlue, didTap: { vc in
25 | let controller = UIDocumentPickerViewController(documentTypes: [(kUTTypeImage as String)], in: .import)
26 | controller.delegate = self
27 | vc.present(controller, animated: true, completion: nil)
28 | }),
29 | .view(view: imageView)
30 | ]
31 |
32 | super.viewDidLoad()
33 | }
34 | }
35 |
36 | extension OpenFileViewController: UIDocumentPickerDelegate {
37 | func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
38 | guard let url = urls.first else { return }
39 | guard let image = UIImage(contentsOfFile: url.path) else { return }
40 | imageView.image = image
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SceneDelegate.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 6/27/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | #if targetEnvironment(macCatalyst)
11 | import AppKit
12 | #endif
13 | import SwiftUI
14 |
15 | // Hacky stuff as per https://stackoverflow.com/questions/27243158/hiding-the-master-view-controller-with-uisplitviewcontroller-in-ios8
16 | extension UISplitViewController {
17 | func toggleMasterView() {
18 | let barButtonItem = self.displayModeButtonItem
19 | UIApplication.shared.sendAction(barButtonItem.action!, to: barButtonItem.target, from: nil, for: nil)
20 | }
21 | }
22 |
23 | class ReportingSplitViewController: UISplitViewController {
24 | override func viewDidAppear(_ animated: Bool) {
25 | super.viewDidAppear(animated)
26 | AppDelegate.shared.bridge?.sceneBecameActive(identifier: "normal")
27 | }
28 | }
29 |
30 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
31 | var window: UIWindow?
32 |
33 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
34 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
35 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
36 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
37 | guard let scene = (scene as? UIWindowScene) else { return }
38 |
39 | let splitViewController = ReportingSplitViewController()
40 | let listViewController = ListViewController(didSelectDetailType: { type in
41 | let viewController = self.viewController(forDetailType: type)
42 | viewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
43 | viewController.navigationItem.leftItemsSupplementBackButton = true
44 | viewController.navigationItem.largeTitleDisplayMode = .never
45 | let detailNavController = UINavigationController(rootViewController: viewController)
46 | splitViewController.showDetailViewController(detailNavController, sender: self)
47 | if viewController.canBecomeFirstResponder {
48 | viewController.becomeFirstResponder()
49 | }
50 | guard let identifier = self.window?.windowScene?.session.persistentIdentifier else { return }
51 | NotificationCenter.default.post(name: .didChangeDetailType, object: nil, userInfo: ["detailType": type.rawValue, "identifier": identifier])
52 | })
53 | let navController = UINavigationController(rootViewController: listViewController)
54 | navController.navigationBar.prefersLargeTitles = true
55 | let viewController = ViewController()
56 | viewController.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
57 | viewController.navigationItem.leftItemsSupplementBackButton = true
58 | viewController.navigationItem.largeTitleDisplayMode = .never
59 | let detailNavController = UINavigationController(rootViewController: viewController)
60 | splitViewController.viewControllers = [navController, detailNavController]
61 | splitViewController.delegate = self
62 | splitViewController.primaryBackgroundStyle = .sidebar
63 |
64 | window = UIWindow(windowScene: scene)
65 | window?.rootViewController = splitViewController
66 | window?.makeKeyAndVisible()
67 |
68 | #if targetEnvironment(macCatalyst)
69 | if let titlebar = scene.titlebar {
70 | let toolbar = NSToolbar(identifier: "toolbar")
71 | toolbar.delegate = self
72 |
73 | titlebar.toolbar = toolbar
74 | titlebar.titleVisibility = .hidden
75 | }
76 | #endif
77 | }
78 |
79 | func handleDetailType(_ detailType: DetailType) {
80 | guard let splitViewController = window?.rootViewController as? UISplitViewController else { return }
81 | guard let navigationController = splitViewController.viewControllers.first as? UINavigationController else { return }
82 | guard let listViewController = navigationController.topViewController as? ListViewController else { return }
83 | listViewController.didSelectDetailType(detailType)
84 | }
85 |
86 | func viewController(forDetailType type: DetailType) -> UIViewController {
87 | switch type {
88 | case .windows:
89 | return WindowsViewController()
90 | case .hover:
91 | return HoverViewController()
92 | case .dragAndDrop:
93 | return DragAndDropViewController()
94 | case .touchBar:
95 | return TouchBarViewController()
96 | case .contextMenus:
97 | return ContextMenuViewController()
98 | case .cursors:
99 | return CursorsViewController()
100 | case .swiftUI:
101 | return UIHostingController(rootView: SwiftUIView())
102 | case .openFile:
103 | return OpenFileViewController()
104 | case .notifications:
105 | return NotificationsViewController()
106 | default:
107 | return ViewController()
108 | }
109 | }
110 |
111 | func sceneDidDisconnect(_ scene: UIScene) {
112 | // Called as the scene is being released by the system.
113 | // This occurs shortly after the scene enters the background, or when its session is discarded.
114 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
115 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
116 | }
117 |
118 | func sceneDidBecomeActive(_ scene: UIScene) {
119 | // Called when the scene has moved from an inactive state to an active state.
120 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
121 | }
122 |
123 | func sceneWillResignActive(_ scene: UIScene) {
124 | // Called when the scene will move from an active state to an inactive state.
125 | // This may occur due to temporary interruptions (ex. an incoming phone call).
126 | }
127 |
128 | func sceneWillEnterForeground(_ scene: UIScene) {
129 | // Called as the scene transitions from the background to the foreground.
130 | // Use this method to undo the changes made on entering the background.
131 | }
132 |
133 | func sceneDidEnterBackground(_ scene: UIScene) {
134 | // Called as the scene transitions from the foreground to the background.
135 | // Use this method to save data, release shared resources, and store enough scene-specific state information
136 | // to restore the scene back to its current state.
137 | }
138 |
139 | func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {
140 | print("Old: \(previousCoordinateSpace.bounds), new: \(windowScene.coordinateSpace.bounds)")
141 | }
142 | }
143 |
144 | extension SceneDelegate: UISplitViewControllerDelegate {
145 | func splitViewController(_ splitViewController: UISplitViewController, collapseSecondary secondaryViewController: UIViewController, onto primaryViewController: UIViewController) -> Bool {
146 | return true
147 | }
148 | }
149 |
150 | #if targetEnvironment(macCatalyst)
151 | extension SceneDelegate: NSToolbarDelegate {
152 | var identifiers: [NSToolbarItem.Identifier] {
153 | return [NSToolbarItem.Identifier(rawValue: "test"), .flexibleSpace, NSToolbarItem.Identifier(rawValue: "other")]
154 | }
155 |
156 | func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
157 | return self.identifiers
158 | }
159 |
160 | func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
161 | return self.identifiers
162 | }
163 |
164 | func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
165 | guard let identifier = self.window?.windowScene?.session.persistentIdentifier else { return nil }
166 | switch itemIdentifier.rawValue {
167 | case "test":
168 | let item = NSToolbarItem(itemIdentifier: itemIdentifier, barButtonItem: UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(didTapAddButton)))
169 | item.title = "New window"
170 | return item
171 | case "other":
172 | let item = AppDelegate.shared.bridge!.customToolbarItem(identifier: identifier) { string in
173 | guard let detailType = DetailType(rawValue: string) else { return }
174 | self.handleDetailType(detailType)
175 | }
176 | return item
177 | default:
178 | return nil
179 | }
180 | }
181 |
182 | @objc private func didTapAddButton(_ sender: NSToolbarItem) {
183 | UIApplication.shared.requestSceneSessionActivation(nil, userActivity: nil, options: nil, errorHandler: nil)
184 | }
185 |
186 | @objc private func didTapOtherButton(_ sender: NSToolbarItem) {
187 | UIApplication.shared.requestSceneSessionActivation(nil, userActivity: nil, options: nil, errorHandler: nil)
188 | }
189 | }
190 | #endif
191 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/SquareSceneDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SquareSceneDelegate.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/14/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class SquareSceneDelegate: UIResponder, UIWindowSceneDelegate {
13 | var window: UIWindow?
14 |
15 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
16 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
17 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
18 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
19 | guard let scene = (scene as? UIWindowScene) else { return }
20 |
21 | window = UIWindow(windowScene: scene)
22 | let vc = ViewController()
23 | if let vc = vc as? AppKitWindowReportingViewController {
24 | vc.identifier = "square"
25 | }
26 | window?.rootViewController = vc
27 | window?.makeKeyAndVisible()
28 | }
29 |
30 | func sceneDidDisconnect(_ scene: UIScene) {
31 | // Called as the scene is being released by the system.
32 | // This occurs shortly after the scene enters the background, or when its session is discarded.
33 | // Release any resources associated with this scene that can be re-created the next time the scene connects.
34 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
35 | }
36 |
37 | func sceneDidBecomeActive(_ scene: UIScene) {
38 | // Called when the scene has moved from an inactive state to an active state.
39 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
40 | }
41 |
42 | func sceneWillResignActive(_ scene: UIScene) {
43 | // Called when the scene will move from an active state to an inactive state.
44 | // This may occur due to temporary interruptions (ex. an incoming phone call).
45 | }
46 |
47 | func sceneWillEnterForeground(_ scene: UIScene) {
48 | // Called as the scene transitions from the background to the foreground.
49 | // Use this method to undo the changes made on entering the background.
50 | }
51 |
52 | func sceneDidEnterBackground(_ scene: UIScene) {
53 | // Called as the scene transitions from the foreground to the background.
54 | // Use this method to save data, release shared resources, and store enough scene-specific state information
55 | // to restore the scene back to its current state.
56 | }
57 |
58 | func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {
59 | print("Old: \(previousCoordinateSpace), new: \(windowScene.coordinateSpace)")
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/SwiftUIView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // SwiftUIView.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/17/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 |
11 | struct SwiftUIView: View {
12 | var body: some View {
13 | Text("This view is defined in SwiftUI.")
14 | .frame(width: 300, height: 300)
15 | .background(Color.pink)
16 | }
17 | }
18 |
19 | #if DEBUG
20 | struct SwiftUIView_Previews: PreviewProvider {
21 | static var previews: some View {
22 | SwiftUIView()
23 | }
24 | }
25 | #endif
26 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/TouchBarViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TouchBarViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/16/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | #if targetEnvironment(macCatalyst)
12 | import AppKit
13 | #endif
14 |
15 | final class TouchBarViewController: ExamplesViewController {
16 | let colorView = ColorView(color: .red, dimension: 100)
17 |
18 | override func viewDidLoad() {
19 | self.views = [
20 | .paragraph(text: "This view controller provides touch bar items. Use them to modify the color of this square."),
21 | .view(view: colorView)
22 | ]
23 | super.viewDidLoad()
24 | }
25 |
26 | #if targetEnvironment(macCatalyst)
27 | override func makeTouchBar() -> NSTouchBar? {
28 | let bar = NSTouchBar()
29 | let buttonIdentifier = NSTouchBarItem.Identifier(rawValue: "clickme")
30 | let colorIdentifier = NSTouchBarItem.Identifier(rawValue: "color")
31 | bar.defaultItemIdentifiers = [
32 | buttonIdentifier,
33 | colorIdentifier
34 | ]
35 | let colorPicker = NSColorPickerTouchBarItem.strokeColorPicker(withIdentifier: colorIdentifier)
36 | colorPicker.target = self
37 | colorPicker.action = #selector(didPickColor)
38 | bar.templateItems = [
39 | NSButtonTouchBarItem(
40 | identifier: buttonIdentifier,
41 | title: "Random color",
42 | target: self,
43 | action: #selector(didTapRandomColor)
44 | ),
45 | colorPicker
46 | ]
47 | return bar
48 | }
49 |
50 | @objc private func didTapRandomColor(_ sender: NSTouchBarItem) {
51 | self.colorView.color = generateRandomColor()
52 | }
53 |
54 | @objc private func didPickColor(_ sender: NSColorPickerTouchBarItem) {
55 | self.colorView.color = sender.color
56 | }
57 | #endif
58 | }
59 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/UIKitForMacPlayground-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "AppKitBundleLoader.h"
6 | #import
7 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/UIKitForMacPlayground.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-write
8 |
9 | com.apple.security.network.client
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/UserActivities.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UserActivities.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 |
11 | /// NSUserActivity types supported by this app
12 | enum UserActivities: String {
13 | case square = "com.noahgilmore.uikitformacplayground.square"
14 | }
15 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 6/27/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | #if targetEnvironment(macCatalyst)
12 | import AppKit
13 | #endif
14 |
15 | func generateRandomColor() -> UIColor {
16 | let hue : CGFloat = CGFloat(arc4random() % 256) / 256 // use 256 to get full range from 0.0 to 1.0
17 | let saturation : CGFloat = CGFloat(arc4random() % 128) / 256 + 0.5 // from 0.5 to 1.0 to stay away from white
18 | let brightness : CGFloat = CGFloat(arc4random() % 128) / 256 + 0.5 // from 0.5 to 1.0 to stay away from black
19 |
20 | return UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: 1)
21 | }
22 |
23 | class ViewController: ExamplesViewController {
24 | override func viewDidLoad() {
25 | self.views = [
26 | .paragraph(text: "Press Cmd-R to change the color of this view")
27 | ]
28 | super.viewDidLoad()
29 | // Do any additional setup after loading the view.
30 | self.view.backgroundColor = generateRandomColor()
31 | }
32 |
33 | override func viewDidAppear(_ animated: Bool) {
34 | super.viewDidAppear(animated)
35 | UIMenuSystem.main.setNeedsRebuild()
36 | }
37 |
38 | override var keyCommands: [UIKeyCommand]? {
39 | return [
40 | UIKeyCommand(
41 | input: "R",
42 | modifierFlags: [.command],
43 | action: #selector(ViewController.testSelected(_:))
44 | )
45 | ]
46 | }
47 |
48 | override var canBecomeFirstResponder: Bool {
49 | return true
50 | }
51 |
52 | @objc private func testSelected(_ sender: AppDelegate) {
53 | self.view.backgroundColor = generateRandomColor()
54 | }
55 |
56 | override func buildMenu(with builder: UIMenuBuilder) {
57 | super.buildMenu(with: builder)
58 |
59 | let command = UIKeyCommand(
60 | input: "Y",
61 | modifierFlags: [.command],
62 | action: #selector(self.testSelected(_:))
63 | )
64 | command.title = "Change colors"
65 |
66 | let noShortcutCommand = UICommand(
67 | title: "No shortcut",
68 | image: nil,
69 | action: #selector(self.testSelected),
70 | propertyList: nil
71 | )
72 |
73 | builder.insertChild(UIMenu(
74 | title: "Jump",
75 | image: nil,
76 | identifier: UIMenu.Identifier(rawValue: "com.noahgilmore.uikitformacplaygroud.changecolor"),
77 | options: [],
78 | children: [command, noShortcutCommand]
79 | ), atEndOfMenu: .file)
80 | }
81 |
82 | #if targetEnvironment(macCatalyst)
83 | override func makeTouchBar() -> NSTouchBar? {
84 | let bar = NSTouchBar()
85 | let identifier = NSTouchBarItem.Identifier(rawValue: "clickme")
86 | bar.defaultItemIdentifiers = [identifier]
87 | bar.templateItems = [
88 | NSButtonTouchBarItem(
89 | identifier: identifier,
90 | title: "😥",
91 | target: self,
92 | action: #selector(didTapClickMe(_:))
93 | )
94 | ]
95 | return bar
96 | }
97 |
98 | @objc private func didTapClickMe(_ sender: NSTouchBarItem) {
99 | print("Click me!!!")
100 | }
101 | #endif
102 | }
103 |
--------------------------------------------------------------------------------
/UIKitForMacPlayground/WindowsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // WindowsViewCotroller.swift
3 | // UIKitForMacPlayground
4 | //
5 | // Created by Noah Gilmore on 7/5/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import UIKit
11 |
12 | class WindowsViewController: ExamplesViewController {
13 | override func viewDidLoad() {
14 | self.views = [
15 | .paragraph(text: "You can jump to this page at any time using Command J or selecting Jump To -> Windows from the menu bar."),
16 | .header(text: "Creation/deletion"),
17 | .button(text: "Launch new window (Cmd-N equivalent)", color: .systemBlue, didTap: { _ in
18 | UIApplication.shared.requestSceneSessionActivation(nil, userActivity: nil, options: nil, errorHandler: nil)
19 | }),
20 | .button(text: "Close current window (Cmd-W equivalent)", color: .systemRed, didTap: { _ in
21 | guard let containingScene = self.view.window?.windowScene else {
22 | return
23 | }
24 | UIApplication.shared.requestSceneSessionDestruction(
25 | containingScene.session,
26 | options: nil,
27 | errorHandler: nil
28 | )
29 | }),
30 | .header(text: "Different window types"),
31 | .button(text: "Launch a new single-color, 200x200, non-resizable window", color: .systemBlue, didTap: { _ in
32 | let activity = NSUserActivity(activityType: UserActivities.square.rawValue)
33 | UIApplication.shared.requestSceneSessionActivation(nil, userActivity: activity, options: nil, errorHandler: nil)
34 | })
35 | ]
36 |
37 | if let bridge = AppDelegate.shared.bridge {
38 | self.views.append(contentsOf: [
39 | .header(text: "Window management"),
40 | .button(text: "Move this window 50pt to the right", color: .systemBlue, didTap: { _ in
41 | bridge.moveWindowRight()
42 | })
43 | ])
44 | }
45 |
46 | super.viewDidLoad()
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/UIKitForMacPlaygroundSupportingBundle/AppKitPrincipal.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppKitPrincipal.swift
3 | // UIKitForMacPlaygroundSupportingBundle
4 | //
5 | // Created by Noah Gilmore on 7/15/19.
6 | // Copyright © 2019 Noah Gilmore. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import AppKit
11 |
12 | class AppKitPrincipal: NSObject, AppKitObjcBridge {
13 | private var bridge: UIKitBridge! = nil
14 | private let windowManager = WindowManager()
15 |
16 | func moveWindowRight() {
17 | let firstWindow = NSApplication.shared.windows.first!
18 | let currentFrame = firstWindow.frame
19 | let newFrame = currentFrame.offsetBy(dx: 50, dy: 0)
20 | firstWindow.setFrame(newFrame, display: false, animate: true)
21 | }
22 |
23 | func customToolbarItem(identifier: String, callback: @escaping (String) -> Void) -> NSToolbarItem {
24 | let item = DetailTypeToolbarItem(itemIdentifier: NSToolbarItem.Identifier(rawValue: identifier), handler: callback)
25 | return item
26 | }
27 |
28 | func setUIKit(_ bridge: UIKitBridge) {
29 | self.bridge = bridge
30 | }
31 |
32 | @objc private func didSelectFromPopup(_ sender: NSPopUpButton) {
33 | self.bridge.didSelectDetailType(sender.titleOfSelectedItem ?? "")
34 | }
35 |
36 | func setDefaultCursor() {
37 | NSCursor.arrow.set()
38 | }
39 |
40 | func setPointerCursor() {
41 | NSCursor.pointingHand.set()
42 | }
43 |
44 | func sceneBecameActive(identifier: String) {
45 | self.windowManager.sceneBecameActive(identifier: identifier)
46 | }
47 | }
48 |
49 | class DetailTypeToolbarItem: NSToolbarItem {
50 | private let handler: (String) -> Void
51 |
52 | init(itemIdentifier: NSToolbarItem.Identifier, handler: @escaping (String) -> Void) {
53 | self.handler = handler
54 | super.init(itemIdentifier: itemIdentifier)
55 | let button = NSPopUpButton()
56 | for type in DetailType.allCases {
57 | button.addItem(withTitle: type.rawValue)
58 | }
59 | button.target = self
60 | button.action = #selector(didSelectFromPopup)
61 | self.view = button
62 |
63 | NotificationCenter.default.addObserver(forName: Notification.Name.didChangeDetailType, object: nil, queue: nil, using: { notification in
64 | guard let detailTypeString = notification.userInfo?["detailType"] as? String else {
65 | return
66 | }
67 | guard let identifier = notification.userInfo?["identifier"] as? String else {
68 | return
69 | }
70 | guard identifier == self.itemIdentifier.rawValue else { return }
71 | guard let detailType = DetailType(rawValue: detailTypeString) else { return }
72 | self.setSelected(detailType)
73 | })
74 | }
75 |
76 | func setSelected(_ detailType: DetailType) {
77 | guard let button = self.view as? NSPopUpButton else {
78 | return
79 | }
80 | button.selectItem(withTitle: detailType.rawValue)
81 | }
82 |
83 | @objc private func didSelectFromPopup(_ sender: NSPopUpButton) {
84 | guard let selectedTitle = sender.titleOfSelectedItem else { return }
85 | self.handler(selectedTitle)
86 | }
87 | }
88 |
89 | class RedView: NSView {
90 | override func draw(_ dirtyRect: NSRect) {
91 | super.draw(dirtyRect)
92 | NSColor.systemRed.setFill()
93 | dirtyRect.fill()
94 | }
95 | }
96 |
97 | /// TODO: This is a hacky way to track and get references to windows between UIKit and AppKit. There's probably a much better way.
98 | class WindowManager {
99 | private var windows: [Int: NSWindow] = [:]
100 |
101 | func sceneBecameActive(identifier: String) {
102 | var newWindows: [Int: NSWindow] = [:]
103 | for window in NSApplication.shared.windows {
104 | if !windows.keys.contains(window.windowNumber) {
105 | print("BECOMING ACTIVE: \(window.windowNumber), \(identifier)")
106 | self.handleWindowAppearance(identifier: identifier, window: window)
107 | }
108 | newWindows[window.windowNumber] = window
109 | }
110 | windows = newWindows
111 | }
112 |
113 | func handleWindowAppearance(identifier: String, window: NSWindow) {
114 | if identifier == "square" {
115 | window.setContentSize(NSSize(width: 200, height: 200))
116 | window.styleMask.remove(.resizable)
117 | }
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/UIKitForMacPlaygroundSupportingBundle/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 | NSHumanReadableCopyright
22 | Copyright © 2019 Noah Gilmore. All rights reserved.
23 | NSPrincipalClass
24 | AppKitPrincipal
25 |
26 |
27 |
--------------------------------------------------------------------------------
/UIKitForMacPlaygroundSupportingBundle/UIKitForMacPlaygroundSupportingBundle-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 | #import "AppKitBundleLoader.h"
6 |
7 |
--------------------------------------------------------------------------------