├── airslide ├── Assets.xcassets │ ├── Contents.json │ └── AppIcon.appiconset │ │ ├── 1024-128.png │ │ ├── 1024-16.png │ │ ├── 1024-256.png │ │ ├── 1024-32.png │ │ ├── 1024-512.png │ │ ├── 1024-64.png │ │ ├── 1024-1024.png │ │ └── Contents.json ├── nologin.sh ├── login.sh ├── Info.plist ├── airslide.entitlements ├── Credits.rtf ├── PreferenceViewController.swift ├── Base.lproj │ └── Main.storyboard └── AppDelegate.swift ├── AirSlide.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── lucas.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ ├── WorkspaceSettings.xcsettings │ │ └── IDEWorkspaceChecks.plist ├── xcuserdata │ └── lucas.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── xcschememanagement.plist ├── xcshareddata │ └── xcschemes │ │ └── AirSlide.xcscheme └── project.pbxproj ├── airslideUITests ├── airslideUITestsLaunchTests.swift └── airslideUITests.swift ├── README.md └── airslideTests └── airslideTests.swift /airslide/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /airslide/nologin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | osascript -e 'tell application "System Events" to delete login item "Airslide"' 3 | 4 | 5 | -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-128.png -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-16.png -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-256.png -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-32.png -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-512.png -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-64.png -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/1024-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/airslide/Assets.xcassets/AppIcon.appiconset/1024-1024.png -------------------------------------------------------------------------------- /airslide/login.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | osascript -e 'tell application "System Events" to make login item at end with properties {path:"/Applications/Airslide.app", hidden:false}' 3 | -------------------------------------------------------------------------------- /AirSlide.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /airslide/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /AirSlide.xcodeproj/project.xcworkspace/xcuserdata/lucas.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmmago/airslide/HEAD/AirSlide.xcodeproj/project.xcworkspace/xcuserdata/lucas.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /AirSlide.xcodeproj/xcuserdata/lucas.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /airslide/airslide.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.automation.apple-events 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AirSlide.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreviewsEnabled 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /AirSlide.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /airslide/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf2639 2 | \cocoatextscaling0\cocoaplatform0{\fonttbl\f0\fswiss\fcharset0 Helvetica;} 3 | {\colortbl;\red255\green255\blue255;} 4 | {\*\expandedcolortbl;;} 5 | \paperw11900\paperh16840\margl1440\margr1440\vieww11520\viewh8400\viewkind0 6 | \pard\tx566\tx1133\tx1700\tx2267\tqr\tx2623\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc\partightenfactor0 7 | 8 | \f0\fs24 \cf0 Copyright \'a9 2023 mago. All rights reserved.} -------------------------------------------------------------------------------- /AirSlide.xcodeproj/project.xcworkspace/xcuserdata/lucas.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildLocationStyle 6 | UseAppPreferences 7 | CustomBuildLocationType 8 | RelativeToDerivedData 9 | DerivedDataLocationStyle 10 | Default 11 | ShowSharedSchemesAutomaticallyEnabled 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /airslideUITests/airslideUITestsLaunchTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // airslideUITestsLaunchTests.swift 3 | // airslideUITests 4 | // 5 | // Created by Lucas on 26/01/2023. 6 | // 7 | 8 | import XCTest 9 | 10 | final class airslideUITestsLaunchTests: XCTestCase { 11 | 12 | override class var runsForEachTargetApplicationUIConfiguration: Bool { 13 | true 14 | } 15 | 16 | override func setUpWithError() throws { 17 | continueAfterFailure = false 18 | } 19 | 20 | func testLaunch() throws { 21 | let app = XCUIApplication() 22 | app.launch() 23 | 24 | // Insert steps here to perform after app launch but before taking a screenshot, 25 | // such as logging into a test account or navigating somewhere in the app 26 | 27 | let attachment = XCTAttachment(screenshot: app.screenshot()) 28 | attachment.name = "Launch Screen" 29 | attachment.lifetime = .keepAlways 30 | add(attachment) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AirSlide.xcodeproj/xcuserdata/lucas.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AirSlide.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | airslide.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | SuppressBuildableAutocreation 19 | 20 | A0EFF9F329833873002FF9B5 21 | 22 | primary 23 | 24 | 25 | A0EFFA0429833873002FF9B5 26 | 27 | primary 28 | 29 | 30 | A0EFFA0E29833873002FF9B5 31 | 32 | primary 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # airslide AirSlide 4 | 5 | 6 | 7 | 8 | Quick notch action to airdrop items. Free and open source alternative to [TopDrop](https://apps.apple.com/us/app/topdrop/id1630456052?mt=12). 9 | 10 | 11 | ![ezgif-4-3f45fad8cd](https://user-images.githubusercontent.com/76073612/215779627-fdb727ee-4214-424a-bcc4-cc46742d613a.gif) 12 | 13 | App will ask for access to automations and accessibility settings, please allow both. 14 | 15 | ## Work in progress 16 | 17 | 🟩 14" MBP 18 | 19 | 🟧 16" MBP and MacBook Air M2 (13" and 15") compatibility (need feedbacks !). I don't have acess to these machines so it's pretty much trial and error. 20 | 21 | User experience on any other mac without notch may vary, might implement a solution later on. 22 | 23 | # Useful Tools 24 | 25 | - [ChatGPT](https://chat.openai.com/chat/) 26 | 27 |

Buy Me A Coffee

28 | 29 | -------------------------------------------------------------------------------- /airslideTests/airslideTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // airslideTests.swift 3 | // airslideTests 4 | // 5 | // Created by Lucas on 26/01/2023. 6 | // 7 | 8 | import XCTest 9 | @testable import airslide 10 | 11 | final class airslideTests: XCTestCase { 12 | 13 | override func setUpWithError() throws { 14 | // Put setup code here. This method is called before the invocation of each test method in the class. 15 | } 16 | 17 | override func tearDownWithError() throws { 18 | // Put teardown code here. This method is called after the invocation of each test method in the class. 19 | } 20 | 21 | func testExample() throws { 22 | // This is an example of a functional test case. 23 | // Use XCTAssert and related functions to verify your tests produce the correct results. 24 | // Any test you write for XCTest can be annotated as throws and async. 25 | // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. 26 | // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. 27 | } 28 | 29 | func testPerformanceExample() throws { 30 | // This is an example of a performance test case. 31 | self.measure { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /airslideUITests/airslideUITests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // airslideUITests.swift 3 | // airslideUITests 4 | // 5 | // Created by Lucas on 26/01/2023. 6 | // 7 | 8 | import XCTest 9 | 10 | final class airslideUITests: XCTestCase { 11 | 12 | override func setUpWithError() throws { 13 | // Put setup code here. This method is called before the invocation of each test method in the class. 14 | 15 | // In UI tests it is usually best to stop immediately when a failure occurs. 16 | continueAfterFailure = false 17 | 18 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 19 | } 20 | 21 | override func tearDownWithError() throws { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | } 24 | 25 | func testExample() throws { 26 | // UI tests must launch the application that they test. 27 | let app = XCUIApplication() 28 | app.launch() 29 | 30 | // Use XCTAssert and related functions to verify your tests produce the correct results. 31 | } 32 | 33 | func testLaunchPerformance() throws { 34 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 7.0, *) { 35 | // This measures how long it takes to launch your application. 36 | measure(metrics: [XCTApplicationLaunchMetric()]) { 37 | XCUIApplication().launch() 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /airslide/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "1024-16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "1024-32.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "1024-32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "1024-64.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "1024-128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "1024-256.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "1024-256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "1024-512.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "1024-512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "1024-1024.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /AirSlide.xcodeproj/xcshareddata/xcschemes/AirSlide.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 34 | 40 | 41 | 42 | 45 | 51 | 52 | 53 | 54 | 55 | 65 | 67 | 73 | 74 | 75 | 76 | 82 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /airslide/PreferenceViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // airslide 4 | // 5 | // Created by Lucas on 26/01/2023. 6 | // 7 | 8 | import Cocoa 9 | 10 | 11 | let userDefaults = UserDefaults.standard 12 | 13 | 14 | class PreferenceViewController: NSViewController { 15 | 16 | @IBOutlet weak var openatlogin: NSButton! 17 | @IBOutlet weak var hideicon: NSButton! 18 | @IBOutlet weak var soundlist: NSComboBoxCell! 19 | @IBOutlet weak var support: NSButton! 20 | @IBOutlet weak var quitapp: NSButton! 21 | 22 | @IBAction func openatlogin(_ sender: Any) { 23 | 24 | if openatlogin.state == .on { 25 | 26 | if Bundle.main.bundlePath == "/Applications/AirSlide.app"{ 27 | UserDefaults.standard.set(true, forKey: "openatlogin") 28 | UserDefaults.standard.set(false, forKey: "openprefatlaunch") 29 | let task = Process() 30 | task.launchPath = "/bin/bash" 31 | task.arguments = ["-c", "sh \(Bundle.main.resourcePath!)/login.sh"] 32 | task.launch() 33 | task.waitUntilExit() 34 | 35 | } 36 | else { 37 | openatlogin.state = .off 38 | UserDefaults.standard.set(false, forKey: "openatlogin") 39 | UserDefaults.standard.set(true, forKey: "openprefatlaunch") 40 | let alert = NSAlert() 41 | alert.messageText = "Warning" 42 | alert.informativeText = "Please put app in your Applications folder first !" 43 | alert.alertStyle = .warning 44 | alert.addButton(withTitle: "OK") 45 | alert.runModal() 46 | } 47 | 48 | } 49 | else if openatlogin.state == .off{ 50 | UserDefaults.standard.set(false, forKey: "openatlogin") 51 | UserDefaults.standard.set(true, forKey: "openprefatlaunch") 52 | let task = Process() 53 | task.launchPath = "/bin/bash" 54 | task.arguments = ["-c", "sh \(Bundle.main.resourcePath!)/nologin.sh"] 55 | task.launch() 56 | task.waitUntilExit() 57 | 58 | } 59 | } 60 | 61 | @IBAction func hideicon(_ sender: Any) { 62 | 63 | if hideicon.state == .on { 64 | 65 | if let appDelegate = NSApplication.shared.delegate as? AppDelegate { 66 | appDelegate.statusItem?.isVisible = false 67 | } 68 | 69 | UserDefaults.standard.set(true, forKey: "hideicon") 70 | 71 | 72 | 73 | 74 | 75 | 76 | } else { 77 | 78 | let appDelegate = NSApplication.shared.delegate as! AppDelegate 79 | appDelegate.statusItem?.isVisible = true 80 | 81 | UserDefaults.standard.set(false, forKey: "hideicon") 82 | 83 | 84 | 85 | 86 | 87 | } 88 | } 89 | 90 | 91 | @IBAction func soundlist(_ sender: Any) { 92 | 93 | 94 | UserDefaults.standard.set(soundlist.title, forKey: "actualsound") 95 | 96 | //preview sound 97 | let sound = NSSound(named: UserDefaults.standard.value(forKey: "actualsound") as! NSSound.Name) 98 | sound?.play() 99 | 100 | } 101 | 102 | 103 | @IBAction func quitapp(_ sender: Any) { 104 | if let window = NSApplication.shared.keyWindow { 105 | 106 | window.close() 107 | 108 | } 109 | } 110 | 111 | @IBAction func support(_ sender: Any) { 112 | guard let url = URL(string: "https://www.paypal.com/donate/?hosted_button_id=TUH8ECY3KP4BW") else { return } 113 | NSWorkspace.shared.open(url) 114 | } 115 | 116 | 117 | override func viewDidLoad() { 118 | super.viewDidLoad() 119 | 120 | print(UserDefaults.standard.bool(forKey: "hideicon")) 121 | print(UserDefaults.standard.bool(forKey: "actualsound")) 122 | print(UserDefaults.standard.bool(forKey: "openatlogin")) 123 | 124 | let soundOptions = ["Basso", "Blow", "Bottle", "Frog", "Funk", "Glass", "Hero", "Morse", "Ping", "Pop", "Purr", "Sosumi", "Submarine", "Tink"] 125 | 126 | soundlist.addItems(withObjectValues: soundOptions) 127 | 128 | //set default sound to "Puur" cuz it's nice 129 | if UserDefaults.standard.string(forKey: "actualsound") == nil { 130 | soundlist.title = "Purr" 131 | UserDefaults.standard.set("Purr", forKey: "actualsound") 132 | } 133 | else { 134 | soundlist.title = UserDefaults.standard.string(forKey: "actualsound")! 135 | } 136 | 137 | 138 | if UserDefaults.standard.value(forKey: "openatlogin") == nil { 139 | openatlogin.state = .off 140 | UserDefaults.standard.set(false, forKey: "openatlogin") 141 | } 142 | else if UserDefaults.standard.value(forKey: "openatlogin") as! Int == 1{ 143 | openatlogin.state = .on 144 | } 145 | else if UserDefaults.standard.value(forKey: "openatlogin") as! Int == 0{ 146 | openatlogin.state = .off 147 | } 148 | 149 | 150 | 151 | if UserDefaults.standard.value(forKey: "hideicon") == nil{ 152 | hideicon.state = .off 153 | UserDefaults.standard.set(false, forKey: "hideicon") 154 | } 155 | else if UserDefaults.standard.value(forKey: "hideicon") as! Int == 1{ 156 | hideicon.state = .on 157 | 158 | } 159 | else if UserDefaults.standard.value(forKey: "hideicon") as! Int == 0{ 160 | hideicon.state = .off 161 | 162 | } 163 | } 164 | 165 | override var representedObject: Any? { 166 | didSet { 167 | // Update the view, if already loaded. 168 | } 169 | } 170 | 171 | 172 | } 173 | 174 | -------------------------------------------------------------------------------- /airslide/Base.lproj/Main.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 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 100 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 159 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /AirSlide.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 56; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A0427C27298BEC4600538691 /* login.sh in Resources */ = {isa = PBXBuildFile; fileRef = A0427C25298BEC4600538691 /* login.sh */; }; 11 | A0427C28298BEC4600538691 /* nologin.sh in Resources */ = {isa = PBXBuildFile; fileRef = A0427C26298BEC4600538691 /* nologin.sh */; }; 12 | A050ADF829893E7200C295A3 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = A050ADF729893E7200C295A3 /* Credits.rtf */; }; 13 | A0EFF9F829833873002FF9B5 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0EFF9F729833873002FF9B5 /* AppDelegate.swift */; }; 14 | A0EFF9FA29833873002FF9B5 /* PreferenceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0EFF9F929833873002FF9B5 /* PreferenceViewController.swift */; }; 15 | A0EFF9FC29833873002FF9B5 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A0EFF9FB29833873002FF9B5 /* Assets.xcassets */; }; 16 | A0EFF9FF29833873002FF9B5 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A0EFF9FD29833873002FF9B5 /* Main.storyboard */; }; 17 | /* End PBXBuildFile section */ 18 | 19 | /* Begin PBXCopyFilesBuildPhase section */ 20 | A006CA1D2985607500D434B4 /* Embed ExtensionKit Extensions */ = { 21 | isa = PBXCopyFilesBuildPhase; 22 | buildActionMask = 2147483647; 23 | dstPath = "$(EXTENSIONS_FOLDER_PATH)"; 24 | dstSubfolderSpec = 16; 25 | files = ( 26 | ); 27 | name = "Embed ExtensionKit Extensions"; 28 | runOnlyForDeploymentPostprocessing = 0; 29 | }; 30 | A0EC59BD2986D6E600E23C60 /* Embed Frameworks */ = { 31 | isa = PBXCopyFilesBuildPhase; 32 | buildActionMask = 2147483647; 33 | dstPath = ""; 34 | dstSubfolderSpec = 10; 35 | files = ( 36 | ); 37 | name = "Embed Frameworks"; 38 | runOnlyForDeploymentPostprocessing = 0; 39 | }; 40 | A0EE52812988004A00CC6884 /* CopyFiles */ = { 41 | isa = PBXCopyFilesBuildPhase; 42 | buildActionMask = 2147483647; 43 | dstPath = ""; 44 | dstSubfolderSpec = 16; 45 | files = ( 46 | ); 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXCopyFilesBuildPhase section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | A006CA0C29855D9D00D434B4 /* ServiceManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ServiceManagement.framework; path = System/Library/Frameworks/ServiceManagement.framework; sourceTree = SDKROOT; }; 53 | A0427C25298BEC4600538691 /* login.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = login.sh; path = airslide/login.sh; sourceTree = ""; }; 54 | A0427C26298BEC4600538691 /* nologin.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = nologin.sh; path = airslide/nologin.sh; sourceTree = ""; }; 55 | A050ADF729893E7200C295A3 /* Credits.rtf */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.rtf; name = Credits.rtf; path = airslide/Credits.rtf; sourceTree = ""; }; 56 | A0EFF9F429833873002FF9B5 /* AirSlide.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AirSlide.app; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | A0EFF9F729833873002FF9B5 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 58 | A0EFF9F929833873002FF9B5 /* PreferenceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferenceViewController.swift; sourceTree = ""; }; 59 | A0EFF9FB29833873002FF9B5 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 60 | A0EFF9FE29833873002FF9B5 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 61 | A0EFFA0029833873002FF9B5 /* airslide.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = airslide.entitlements; sourceTree = ""; }; 62 | A0EFFA0929833873002FF9B5 /* airslideTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = airslideTests.swift; sourceTree = ""; }; 63 | A0EFFA1329833873002FF9B5 /* airslideUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = airslideUITests.swift; sourceTree = ""; }; 64 | A0EFFA1529833873002FF9B5 /* airslideUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = airslideUITestsLaunchTests.swift; sourceTree = ""; }; 65 | /* End PBXFileReference section */ 66 | 67 | /* Begin PBXFrameworksBuildPhase section */ 68 | A0EFF9F129833873002FF9B5 /* Frameworks */ = { 69 | isa = PBXFrameworksBuildPhase; 70 | buildActionMask = 2147483647; 71 | files = ( 72 | ); 73 | runOnlyForDeploymentPostprocessing = 0; 74 | }; 75 | /* End PBXFrameworksBuildPhase section */ 76 | 77 | /* Begin PBXGroup section */ 78 | A006CA0B29855D9D00D434B4 /* Frameworks */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | A006CA0C29855D9D00D434B4 /* ServiceManagement.framework */, 82 | ); 83 | name = Frameworks; 84 | sourceTree = ""; 85 | }; 86 | A0EFF9EB29833873002FF9B5 = { 87 | isa = PBXGroup; 88 | children = ( 89 | A0427C25298BEC4600538691 /* login.sh */, 90 | A0427C26298BEC4600538691 /* nologin.sh */, 91 | A050ADF729893E7200C295A3 /* Credits.rtf */, 92 | A0EFF9F629833873002FF9B5 /* airslide */, 93 | A0EFFA0829833873002FF9B5 /* airslideTests */, 94 | A0EFFA1229833873002FF9B5 /* airslideUITests */, 95 | A0EFF9F529833873002FF9B5 /* Products */, 96 | A006CA0B29855D9D00D434B4 /* Frameworks */, 97 | ); 98 | sourceTree = ""; 99 | }; 100 | A0EFF9F529833873002FF9B5 /* Products */ = { 101 | isa = PBXGroup; 102 | children = ( 103 | A0EFF9F429833873002FF9B5 /* AirSlide.app */, 104 | ); 105 | name = Products; 106 | sourceTree = ""; 107 | }; 108 | A0EFF9F629833873002FF9B5 /* airslide */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | A0EFF9F729833873002FF9B5 /* AppDelegate.swift */, 112 | A0EFF9F929833873002FF9B5 /* PreferenceViewController.swift */, 113 | A0EFF9FB29833873002FF9B5 /* Assets.xcassets */, 114 | A0EFF9FD29833873002FF9B5 /* Main.storyboard */, 115 | A0EFFA0029833873002FF9B5 /* airslide.entitlements */, 116 | ); 117 | path = airslide; 118 | sourceTree = ""; 119 | }; 120 | A0EFFA0829833873002FF9B5 /* airslideTests */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | A0EFFA0929833873002FF9B5 /* airslideTests.swift */, 124 | ); 125 | path = airslideTests; 126 | sourceTree = ""; 127 | }; 128 | A0EFFA1229833873002FF9B5 /* airslideUITests */ = { 129 | isa = PBXGroup; 130 | children = ( 131 | A0EFFA1329833873002FF9B5 /* airslideUITests.swift */, 132 | A0EFFA1529833873002FF9B5 /* airslideUITestsLaunchTests.swift */, 133 | ); 134 | path = airslideUITests; 135 | sourceTree = ""; 136 | }; 137 | /* End PBXGroup section */ 138 | 139 | /* Begin PBXNativeTarget section */ 140 | A0EFF9F329833873002FF9B5 /* AirSlide */ = { 141 | isa = PBXNativeTarget; 142 | buildConfigurationList = A0EFFA1929833873002FF9B5 /* Build configuration list for PBXNativeTarget "AirSlide" */; 143 | buildPhases = ( 144 | A0EFF9F029833873002FF9B5 /* Sources */, 145 | A0EFF9F129833873002FF9B5 /* Frameworks */, 146 | A0EFF9F229833873002FF9B5 /* Resources */, 147 | A006CA1D2985607500D434B4 /* Embed ExtensionKit Extensions */, 148 | A0EC59BD2986D6E600E23C60 /* Embed Frameworks */, 149 | A0EE52812988004A00CC6884 /* CopyFiles */, 150 | ); 151 | buildRules = ( 152 | ); 153 | dependencies = ( 154 | ); 155 | name = AirSlide; 156 | packageProductDependencies = ( 157 | ); 158 | productName = airslide; 159 | productReference = A0EFF9F429833873002FF9B5 /* AirSlide.app */; 160 | productType = "com.apple.product-type.application"; 161 | }; 162 | /* End PBXNativeTarget section */ 163 | 164 | /* Begin PBXProject section */ 165 | A0EFF9EC29833873002FF9B5 /* Project object */ = { 166 | isa = PBXProject; 167 | attributes = { 168 | BuildIndependentTargetsInParallel = 1; 169 | LastSwiftUpdateCheck = 1420; 170 | LastUpgradeCheck = 1420; 171 | TargetAttributes = { 172 | A0EFF9F329833873002FF9B5 = { 173 | CreatedOnToolsVersion = 14.2; 174 | }; 175 | }; 176 | }; 177 | buildConfigurationList = A0EFF9EF29833873002FF9B5 /* Build configuration list for PBXProject "AirSlide" */; 178 | compatibilityVersion = "Xcode 14.0"; 179 | developmentRegion = en; 180 | hasScannedForEncodings = 0; 181 | knownRegions = ( 182 | en, 183 | Base, 184 | ); 185 | mainGroup = A0EFF9EB29833873002FF9B5; 186 | packageReferences = ( 187 | ); 188 | productRefGroup = A0EFF9F529833873002FF9B5 /* Products */; 189 | projectDirPath = ""; 190 | projectRoot = ""; 191 | targets = ( 192 | A0EFF9F329833873002FF9B5 /* AirSlide */, 193 | ); 194 | }; 195 | /* End PBXProject section */ 196 | 197 | /* Begin PBXResourcesBuildPhase section */ 198 | A0EFF9F229833873002FF9B5 /* Resources */ = { 199 | isa = PBXResourcesBuildPhase; 200 | buildActionMask = 2147483647; 201 | files = ( 202 | A0EFF9FC29833873002FF9B5 /* Assets.xcassets in Resources */, 203 | A0EFF9FF29833873002FF9B5 /* Main.storyboard in Resources */, 204 | A0427C28298BEC4600538691 /* nologin.sh in Resources */, 205 | A0427C27298BEC4600538691 /* login.sh in Resources */, 206 | A050ADF829893E7200C295A3 /* Credits.rtf in Resources */, 207 | ); 208 | runOnlyForDeploymentPostprocessing = 0; 209 | }; 210 | /* End PBXResourcesBuildPhase section */ 211 | 212 | /* Begin PBXSourcesBuildPhase section */ 213 | A0EFF9F029833873002FF9B5 /* Sources */ = { 214 | isa = PBXSourcesBuildPhase; 215 | buildActionMask = 2147483647; 216 | files = ( 217 | A0EFF9FA29833873002FF9B5 /* PreferenceViewController.swift in Sources */, 218 | A0EFF9F829833873002FF9B5 /* AppDelegate.swift in Sources */, 219 | ); 220 | runOnlyForDeploymentPostprocessing = 0; 221 | }; 222 | /* End PBXSourcesBuildPhase section */ 223 | 224 | /* Begin PBXVariantGroup section */ 225 | A0EFF9FD29833873002FF9B5 /* Main.storyboard */ = { 226 | isa = PBXVariantGroup; 227 | children = ( 228 | A0EFF9FE29833873002FF9B5 /* Base */, 229 | ); 230 | name = Main.storyboard; 231 | sourceTree = ""; 232 | }; 233 | /* End PBXVariantGroup section */ 234 | 235 | /* Begin XCBuildConfiguration section */ 236 | A0EFFA1729833873002FF9B5 /* Debug */ = { 237 | isa = XCBuildConfiguration; 238 | buildSettings = { 239 | ALWAYS_SEARCH_USER_PATHS = NO; 240 | CLANG_ANALYZER_NONNULL = YES; 241 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 242 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 243 | CLANG_ENABLE_MODULES = YES; 244 | CLANG_ENABLE_OBJC_ARC = YES; 245 | CLANG_ENABLE_OBJC_WEAK = YES; 246 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 247 | CLANG_WARN_BOOL_CONVERSION = YES; 248 | CLANG_WARN_COMMA = YES; 249 | CLANG_WARN_CONSTANT_CONVERSION = YES; 250 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 251 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 252 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 253 | CLANG_WARN_EMPTY_BODY = YES; 254 | CLANG_WARN_ENUM_CONVERSION = YES; 255 | CLANG_WARN_INFINITE_RECURSION = YES; 256 | CLANG_WARN_INT_CONVERSION = YES; 257 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 258 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 259 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 260 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 261 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 262 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 263 | CLANG_WARN_STRICT_PROTOTYPES = YES; 264 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 265 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 266 | CLANG_WARN_UNREACHABLE_CODE = YES; 267 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 268 | COPY_PHASE_STRIP = NO; 269 | DEBUG_INFORMATION_FORMAT = dwarf; 270 | ENABLE_STRICT_OBJC_MSGSEND = YES; 271 | ENABLE_TESTABILITY = YES; 272 | GCC_C_LANGUAGE_STANDARD = gnu11; 273 | GCC_DYNAMIC_NO_PIC = NO; 274 | GCC_NO_COMMON_BLOCKS = YES; 275 | GCC_OPTIMIZATION_LEVEL = 0; 276 | GCC_PREPROCESSOR_DEFINITIONS = ( 277 | "DEBUG=1", 278 | "$(inherited)", 279 | ); 280 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 281 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 282 | GCC_WARN_UNDECLARED_SELECTOR = YES; 283 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 284 | GCC_WARN_UNUSED_FUNCTION = YES; 285 | GCC_WARN_UNUSED_VARIABLE = YES; 286 | INFOPLIST_KEY_LSUIElement = YES; 287 | INFOPLIST_KEY_NSAppleEventsUsageDescription = ""; 288 | MACOSX_DEPLOYMENT_TARGET = 12.6; 289 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 290 | MTL_FAST_MATH = YES; 291 | ONLY_ACTIVE_ARCH = YES; 292 | SDKROOT = macosx; 293 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 294 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 295 | }; 296 | name = Debug; 297 | }; 298 | A0EFFA1829833873002FF9B5 /* Release */ = { 299 | isa = XCBuildConfiguration; 300 | buildSettings = { 301 | ALWAYS_SEARCH_USER_PATHS = NO; 302 | CLANG_ANALYZER_NONNULL = YES; 303 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 304 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; 305 | CLANG_ENABLE_MODULES = YES; 306 | CLANG_ENABLE_OBJC_ARC = YES; 307 | CLANG_ENABLE_OBJC_WEAK = YES; 308 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 309 | CLANG_WARN_BOOL_CONVERSION = YES; 310 | CLANG_WARN_COMMA = YES; 311 | CLANG_WARN_CONSTANT_CONVERSION = YES; 312 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 313 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 314 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 315 | CLANG_WARN_EMPTY_BODY = YES; 316 | CLANG_WARN_ENUM_CONVERSION = YES; 317 | CLANG_WARN_INFINITE_RECURSION = YES; 318 | CLANG_WARN_INT_CONVERSION = YES; 319 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 320 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 321 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 322 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 323 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 324 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 325 | CLANG_WARN_STRICT_PROTOTYPES = YES; 326 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 327 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 328 | CLANG_WARN_UNREACHABLE_CODE = YES; 329 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 330 | COPY_PHASE_STRIP = NO; 331 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 332 | ENABLE_NS_ASSERTIONS = NO; 333 | ENABLE_STRICT_OBJC_MSGSEND = YES; 334 | GCC_C_LANGUAGE_STANDARD = gnu11; 335 | GCC_NO_COMMON_BLOCKS = YES; 336 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 338 | GCC_WARN_UNDECLARED_SELECTOR = YES; 339 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 340 | GCC_WARN_UNUSED_FUNCTION = YES; 341 | GCC_WARN_UNUSED_VARIABLE = YES; 342 | INFOPLIST_KEY_LSUIElement = YES; 343 | INFOPLIST_KEY_NSAppleEventsUsageDescription = ""; 344 | MACOSX_DEPLOYMENT_TARGET = 12.6; 345 | MTL_ENABLE_DEBUG_INFO = NO; 346 | MTL_FAST_MATH = YES; 347 | SDKROOT = macosx; 348 | SWIFT_COMPILATION_MODE = wholemodule; 349 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 350 | }; 351 | name = Release; 352 | }; 353 | A0EFFA1A29833873002FF9B5 /* Debug */ = { 354 | isa = XCBuildConfiguration; 355 | buildSettings = { 356 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 357 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; 358 | CODE_SIGN_ENTITLEMENTS = airslide/airslide.entitlements; 359 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; 360 | CODE_SIGN_STYLE = Automatic; 361 | COMBINE_HIDPI_IMAGES = YES; 362 | DEVELOPMENT_TEAM = 5T9BF883B2; 363 | ENABLE_HARDENED_RUNTIME = YES; 364 | GENERATE_INFOPLIST_FILE = YES; 365 | INFOPLIST_FILE = airslide/Info.plist; 366 | INFOPLIST_KEY_CFBundleDisplayName = AirSlide; 367 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; 368 | INFOPLIST_KEY_LSUIElement = YES; 369 | INFOPLIST_KEY_NSAppleEventsUsageDescription = ""; 370 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 371 | INFOPLIST_KEY_NSMainStoryboardFile = Main; 372 | INFOPLIST_KEY_NSPrincipalClass = NSApplication; 373 | LD_RUNPATH_SEARCH_PATHS = ( 374 | "$(inherited)", 375 | "@executable_path/../Frameworks", 376 | ); 377 | MACOSX_DEPLOYMENT_TARGET = 12.0; 378 | MARKETING_VERSION = 1.2.2; 379 | PRODUCT_BUNDLE_IDENTIFIER = mago.airslide; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | SWIFT_EMIT_LOC_STRINGS = YES; 382 | SWIFT_VERSION = 5.0; 383 | }; 384 | name = Debug; 385 | }; 386 | A0EFFA1B29833873002FF9B5 /* Release */ = { 387 | isa = XCBuildConfiguration; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; 391 | CODE_SIGN_ENTITLEMENTS = airslide/airslide.entitlements; 392 | "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; 393 | CODE_SIGN_STYLE = Automatic; 394 | COMBINE_HIDPI_IMAGES = YES; 395 | DEVELOPMENT_TEAM = 5T9BF883B2; 396 | ENABLE_HARDENED_RUNTIME = YES; 397 | GENERATE_INFOPLIST_FILE = YES; 398 | INFOPLIST_FILE = airslide/Info.plist; 399 | INFOPLIST_KEY_CFBundleDisplayName = AirSlide; 400 | INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; 401 | INFOPLIST_KEY_LSUIElement = YES; 402 | INFOPLIST_KEY_NSAppleEventsUsageDescription = ""; 403 | INFOPLIST_KEY_NSHumanReadableCopyright = ""; 404 | INFOPLIST_KEY_NSMainStoryboardFile = Main; 405 | INFOPLIST_KEY_NSPrincipalClass = NSApplication; 406 | LD_RUNPATH_SEARCH_PATHS = ( 407 | "$(inherited)", 408 | "@executable_path/../Frameworks", 409 | ); 410 | MACOSX_DEPLOYMENT_TARGET = 12.0; 411 | MARKETING_VERSION = 1.2.2; 412 | PRODUCT_BUNDLE_IDENTIFIER = mago.airslide; 413 | PRODUCT_NAME = "$(TARGET_NAME)"; 414 | SWIFT_EMIT_LOC_STRINGS = YES; 415 | SWIFT_VERSION = 5.0; 416 | }; 417 | name = Release; 418 | }; 419 | /* End XCBuildConfiguration section */ 420 | 421 | /* Begin XCConfigurationList section */ 422 | A0EFF9EF29833873002FF9B5 /* Build configuration list for PBXProject "AirSlide" */ = { 423 | isa = XCConfigurationList; 424 | buildConfigurations = ( 425 | A0EFFA1729833873002FF9B5 /* Debug */, 426 | A0EFFA1829833873002FF9B5 /* Release */, 427 | ); 428 | defaultConfigurationIsVisible = 0; 429 | defaultConfigurationName = Release; 430 | }; 431 | A0EFFA1929833873002FF9B5 /* Build configuration list for PBXNativeTarget "AirSlide" */ = { 432 | isa = XCConfigurationList; 433 | buildConfigurations = ( 434 | A0EFFA1A29833873002FF9B5 /* Debug */, 435 | A0EFFA1B29833873002FF9B5 /* Release */, 436 | ); 437 | defaultConfigurationIsVisible = 0; 438 | defaultConfigurationName = Release; 439 | }; 440 | /* End XCConfigurationList section */ 441 | }; 442 | rootObject = A0EFF9EC29833873002FF9B5 /* Project object */; 443 | } 444 | -------------------------------------------------------------------------------- /airslide/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | 2 | import Cocoa 3 | import AppKit 4 | import Foundation 5 | 6 | 7 | 8 | @NSApplicationMain 9 | class AppDelegate: NSObject, NSApplicationDelegate, NSSharingServiceDelegate { 10 | 11 | var hasExecuted = false //allow view trigger to show and be fired only once 12 | var hasExecuted2 = false //allow airdrop trigger do be fired only once 13 | 14 | var filepath = "" 15 | 16 | @IBOutlet weak var menu: NSMenu? 17 | @IBOutlet weak var firstMenuItem: NSMenuItem? 18 | 19 | var statusBar: NSStatusBar! 20 | var statusItem: NSStatusItem? 21 | let mainScreen = NSScreen.main! 22 | 23 | func applicationDidFinishLaunching(_ notification: Notification) { 24 | 25 | if UserDefaults.standard.bool(forKey: "openprefatlaunch") == true{ 26 | let storyboard = NSStoryboard(name: "Main", bundle: nil) 27 | let preferencesVC = storyboard.instantiateController(withIdentifier: "PreferencesViewController") as? NSViewController 28 | preferencesVC?.presentAsModalWindow(preferencesVC!) 29 | } 30 | 31 | //Setting status item 32 | statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength) 33 | statusItem?.button?.image = NSImage(systemSymbolName: "paperplane.fill", accessibilityDescription: nil) 34 | 35 | if let menu = menu { 36 | statusItem?.menu = menu 37 | } 38 | 39 | //Defining each device screen size 40 | let MBP14 = (NSScreen.main?.frame.height)! == 982 41 | let MBP16 = (NSScreen.main?.frame.height)! > 1000 //to be sure 42 | let MBAM2 = (NSScreen.main?.frame.height)! < 980 //to be sure 43 | 44 | if MBP14{ 45 | startMBP14() 46 | } 47 | if MBP16{ 48 | startMBP16() 49 | } 50 | if MBAM2 { 51 | startMBAM2() 52 | } 53 | 54 | 55 | //First check for highlited files path 56 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDown) { event in 57 | 58 | let frontmostApp = NSWorkspace.shared.frontmostApplication 59 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 60 | 61 | 62 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide"){ 63 | let script = """ 64 | tell application "Finder" 65 | set theSelection to selection as alias list 66 | set thePaths to {} 67 | repeat with anItem in theSelection 68 | set end of thePaths to POSIX path of anItem 69 | end repeat 70 | return thePaths 71 | end tell 72 | """ 73 | let appleScript = NSAppleScript(source: script) 74 | var error: NSDictionary? 75 | if let result = appleScript?.executeAndReturnError(&error) { 76 | let count = result.numberOfItems 77 | self.filepath = "" 78 | if result.numberOfItems != 0{ 79 | for index in 1...count { 80 | if index == 1 { 81 | self.filepath += (result.atIndex(index)?.stringValue)! 82 | } else { 83 | self.filepath += ", " + (result.atIndex(index)?.stringValue)! 84 | } 85 | } 86 | } 87 | } else if (error != nil) { 88 | print("error: \(error!)") 89 | } 90 | } 91 | 92 | } 93 | 94 | 95 | if MBP14{ 96 | //Create notch view 97 | let window = NSWindow(contentRect: NSMakeRect(635, 880, 250, 100), styleMask: .borderless, backing: .buffered, defer: false) 98 | window.level = .screenSaver 99 | window.isOpaque = false 100 | window.backgroundColor = .clear 101 | 102 | let blueView = NSView(frame: CGRect(x: 29, y: window.contentView!.frame.midY + 20 , width: window.contentView!.frame.width - 66, height: window.contentView!.frame.height - 5)) 103 | blueView.wantsLayer = true 104 | blueView.layer?.backgroundColor = NSColor(red: 0, green: 123/255, blue: 254/255, alpha: 1).cgColor 105 | blueView.layer?.cornerRadius = 10 106 | blueView.isHidden = true 107 | 108 | let borderLayer = CALayer() 109 | borderLayer.frame = blueView.bounds 110 | borderLayer.cornerRadius = blueView.layer!.cornerRadius 111 | borderLayer.borderColor = NSColor.white.cgColor 112 | borderLayer.borderWidth = 6.0 113 | blueView.layer?.addSublayer(borderLayer) 114 | 115 | let animation = CABasicAnimation(keyPath: "borderColor") 116 | animation.fromValue = NSColor.clear.cgColor 117 | animation.toValue = NSColor.white.cgColor 118 | animation.duration = 1.618 119 | animation.autoreverses = true 120 | animation.repeatCount = Float.infinity 121 | borderLayer.add(animation, forKey: "borderColor") 122 | 123 | window.contentView?.addSubview(blueView) 124 | window.makeKeyAndOrderFront(nil) 125 | 126 | 127 | //Bring down view when mouse dragging enter top screen zone 128 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { event in 129 | 130 | if !self.hasExecuted { 131 | 132 | let mousePoint = event.locationInWindow 133 | let frontmostApp = NSWorkspace.shared.frontmostApplication 134 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 135 | 136 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") && mousePoint.y > 840 { 137 | 138 | self.hasExecuted = true 139 | 140 | blueView.isHidden = false 141 | 142 | //down view animation 143 | //print(blueView.frame.midY) 144 | NSAnimationContext.runAnimationGroup({ (context) in 145 | context.duration = 0.7 146 | blueView.animator().frame.origin.y -= 6 147 | }, completionHandler: { 148 | blueView.frame.origin.y -= 0 149 | }) 150 | } 151 | } 152 | } 153 | 154 | //Bring it back down if mouse drag quit top screen zone 155 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { event in 156 | 157 | 158 | let mousePoint = event.locationInWindow 159 | 160 | if mousePoint.y < 840 { 161 | if blueView.frame.midY == 111.5{ 162 | self.hasExecuted = false 163 | NSAnimationContext.runAnimationGroup({ (context) in 164 | context.duration = 0.7 165 | blueView.animator().frame.origin.y -= -6 166 | }, completionHandler: { 167 | blueView.frame.origin.y -= 0 168 | }) 169 | } 170 | } 171 | } 172 | 173 | 174 | //Bring animation back up if mouse up 175 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseUp) { event in 176 | 177 | self.hasExecuted = false 178 | self.hasExecuted2 = false 179 | 180 | 181 | let frontmostApp = NSWorkspace.shared.frontmostApplication 182 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 183 | 184 | 185 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") { 186 | 187 | //back up animation 188 | if blueView.frame.midY == 111.5{ 189 | NSAnimationContext.runAnimationGroup({ (context) in 190 | context.duration = 0.7 191 | blueView.animator().frame.origin.y -= -6 192 | }, completionHandler: { 193 | blueView.frame.origin.y -= 0 194 | }) 195 | } 196 | } 197 | 198 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { 199 | 200 | //hide only if in start position 201 | if blueView.frame.midY == 117.5{ 202 | blueView.isHidden = true 203 | } 204 | 205 | 206 | } 207 | 208 | 209 | } 210 | 211 | } 212 | 213 | //Same for 16" 214 | else if MBP16{ 215 | 216 | let window = NSWindow(contentRect: NSMakeRect(725, 1001, 285.71, 113.74), styleMask: .borderless, backing: .buffered, defer: false) //THEORICAL VALUES 217 | window.level = .screenSaver 218 | window.isOpaque = false 219 | window.backgroundColor = .clear 220 | 221 | let blueView = NSView(frame: CGRect(x: 29, y: window.contentView!.frame.midY + 20 , width: window.contentView!.frame.width - 66, height: window.contentView!.frame.height - 5)) 222 | blueView.wantsLayer = true 223 | blueView.layer?.backgroundColor = NSColor(red: 0, green: 123/255, blue: 254/255, alpha: 1).cgColor 224 | blueView.layer?.cornerRadius = 10 225 | blueView.isHidden = true 226 | 227 | let borderLayer = CALayer() 228 | borderLayer.frame = blueView.bounds 229 | borderLayer.cornerRadius = blueView.layer!.cornerRadius 230 | borderLayer.borderColor = NSColor.white.cgColor 231 | borderLayer.borderWidth = 6.0 232 | blueView.layer?.addSublayer(borderLayer) 233 | 234 | let animation = CABasicAnimation(keyPath: "borderColor") 235 | animation.fromValue = NSColor.clear.cgColor 236 | animation.toValue = NSColor.white.cgColor 237 | animation.duration = 1.618 238 | animation.autoreverses = true 239 | animation.repeatCount = Float.infinity 240 | borderLayer.add(animation, forKey: "borderColor") 241 | 242 | window.contentView?.addSubview(blueView) 243 | window.makeKeyAndOrderFront(nil) 244 | 245 | //Show view when dragging mouse reach top of screen 246 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { event in 247 | 248 | if !self.hasExecuted { 249 | 250 | let mousePoint = event.locationInWindow 251 | let frontmostApp = NSWorkspace.shared.frontmostApplication 252 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 253 | 254 | 255 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") && mousePoint.y > 950 { 256 | 257 | self.hasExecuted = true 258 | 259 | blueView.isHidden = false 260 | 261 | //down view animation 262 | NSAnimationContext.runAnimationGroup({ (context) in 263 | context.duration = 0.7 264 | blueView.animator().frame.origin.y -= 6 265 | }, completionHandler: { 266 | blueView.frame.origin.y -= 0 267 | }) 268 | } 269 | } 270 | } 271 | 272 | //Bring it back down if mouse drag quit top screen zone 273 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { event in 274 | 275 | 276 | let mousePoint = event.locationInWindow 277 | 278 | if mousePoint.y < 950 { 279 | if blueView.frame.midY == 125.5{ 280 | self.hasExecuted = false 281 | NSAnimationContext.runAnimationGroup({ (context) in 282 | context.duration = 0.7 283 | blueView.animator().frame.origin.y -= -6 284 | }, completionHandler: { 285 | blueView.frame.origin.y -= 0 286 | }) 287 | } 288 | } 289 | } 290 | 291 | //Hide view when mouse release 292 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseUp) { event in 293 | 294 | self.hasExecuted = false 295 | self.hasExecuted2 = false 296 | 297 | let frontmostApp = NSWorkspace.shared.frontmostApplication 298 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 299 | 300 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") { 301 | 302 | //back up animation 303 | if blueView.frame.midY == 125.5{ 304 | NSAnimationContext.runAnimationGroup({ (context) in 305 | context.duration = 0.7 306 | blueView.animator().frame.origin.y -= -6 307 | }, completionHandler: { 308 | blueView.frame.origin.y -= 0 309 | }) 310 | } 311 | } 312 | 313 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { 314 | //hide only if in start position 315 | if blueView.frame.midY == 131.5{ 316 | blueView.isHidden = true 317 | } 318 | 319 | } 320 | 321 | 322 | } 323 | 324 | } 325 | 326 | //Same for MBAir 327 | else if MBAM2 { 328 | 329 | let window = NSWindow(contentRect: NSMakeRect(617.36, 856.70, 243.05, 97.35), styleMask: .borderless, backing: .buffered, defer: false) //THEORICAL VALUES 330 | window.level = .screenSaver 331 | window.isOpaque = false 332 | window.backgroundColor = .clear 333 | 334 | let blueView = NSView(frame: CGRect(x: 29, y: window.contentView!.frame.midY + 20 , width: window.contentView!.frame.width - 66, height: window.contentView!.frame.height - 5)) 335 | blueView.wantsLayer = true 336 | blueView.layer?.backgroundColor = NSColor(red: 0, green: 123/255, blue: 254/255, alpha: 1).cgColor 337 | blueView.layer?.cornerRadius = 10 338 | blueView.isHidden = true 339 | 340 | let borderLayer = CALayer() 341 | borderLayer.frame = blueView.bounds 342 | borderLayer.cornerRadius = blueView.layer!.cornerRadius 343 | borderLayer.borderColor = NSColor.white.cgColor 344 | borderLayer.borderWidth = 6.0 345 | blueView.layer?.addSublayer(borderLayer) 346 | 347 | let animation = CABasicAnimation(keyPath: "borderColor") 348 | animation.fromValue = NSColor.clear.cgColor 349 | animation.toValue = NSColor.white.cgColor 350 | animation.duration = 1.618 351 | animation.autoreverses = true 352 | animation.repeatCount = Float.infinity 353 | borderLayer.add(animation, forKey: "borderColor") 354 | 355 | window.contentView?.addSubview(blueView) 356 | window.makeKeyAndOrderFront(nil) 357 | 358 | //Show view when dragging mouse reach top of screen 359 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { event in 360 | 361 | if !self.hasExecuted { 362 | 363 | let mousePoint = event.locationInWindow 364 | let frontmostApp = NSWorkspace.shared.frontmostApplication 365 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 366 | 367 | 368 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") && mousePoint.y > 827.87 { 369 | 370 | self.hasExecuted = true 371 | 372 | blueView.isHidden = false 373 | 374 | //down view animation 375 | NSAnimationContext.runAnimationGroup({ (context) in 376 | context.duration = 0.7 377 | blueView.animator().frame.origin.y -= 6 378 | }, completionHandler: { 379 | blueView.frame.origin.y -= 0 380 | }) 381 | } 382 | } 383 | } 384 | 385 | //Bring it back down if mouse drag quit top screen zone 386 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { event in 387 | 388 | //print(blueView.frame.midY) 389 | let mousePoint = event.locationInWindow 390 | 391 | if mousePoint.y < 827.87 { 392 | if blueView.frame.midY == 109.5{ 393 | self.hasExecuted = false 394 | NSAnimationContext.runAnimationGroup({ (context) in 395 | context.duration = 0.7 396 | blueView.animator().frame.origin.y -= -6 397 | }, completionHandler: { 398 | blueView.frame.origin.y -= 0 399 | }) 400 | } 401 | } 402 | } 403 | 404 | //Hide view when mouse release 405 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseUp) { event in 406 | 407 | self.hasExecuted = false 408 | self.hasExecuted2 = false 409 | 410 | let frontmostApp = NSWorkspace.shared.frontmostApplication 411 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 412 | 413 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") { 414 | 415 | //back up animation 416 | if blueView.frame.midY == 109.5{ 417 | NSAnimationContext.runAnimationGroup({ (context) in 418 | context.duration = 0.7 419 | blueView.animator().frame.origin.y -= -6 420 | }, completionHandler: { 421 | blueView.frame.origin.y -= 0 422 | }) 423 | } 424 | } 425 | 426 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.8) { 427 | //hide only if in start position 428 | if blueView.frame.midY == 115.5{ 429 | blueView.isHidden = true 430 | } 431 | 432 | } 433 | 434 | 435 | } 436 | 437 | } 438 | 439 | 440 | 441 | 442 | 443 | //Show pref pane when clicking notch 444 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDown) { event in 445 | 446 | let mousePoint = event.locationInWindow 447 | 448 | //Focus app on main screen 449 | if self.mainScreen.frame.contains(mousePoint) == true { 450 | 451 | let statusBarHeight = NSStatusBar.system.thickness 452 | let screenHeight = NSScreen.main?.frame.height 453 | let mouseY = event.locationInWindow.y 454 | let mouseX = event.locationInWindow.x 455 | let frontmostApp = NSWorkspace.shared.frontmostApplication 456 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 457 | 458 | if MBP14 { 459 | 460 | if mouseY >= (screenHeight! - statusBarHeight) - 12 && mouseX > 665 && mouseX < 850 { 461 | 462 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") { 463 | 464 | let storyboard = NSStoryboard(name: "Main", bundle: nil) 465 | let preferencesVC = storyboard.instantiateController(withIdentifier: "PreferencesViewController") as? NSViewController 466 | preferencesVC?.presentAsModalWindow(preferencesVC!) 467 | 468 | 469 | 470 | } 471 | } 472 | } 473 | else if MBP16 { 474 | 475 | if mouseY >= (screenHeight! - statusBarHeight) - 12 && mouseX > 756.42 && mouseX < 941.42 { 476 | 477 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") { 478 | 479 | let storyboard = NSStoryboard(name: "Main", bundle: nil) 480 | let preferencesVC = storyboard.instantiateController(withIdentifier: "PreferencesViewController") as? NSViewController 481 | preferencesVC?.presentAsModalWindow(preferencesVC!) 482 | 483 | } 484 | 485 | } 486 | 487 | } 488 | else if MBAM2 { 489 | 490 | if mouseY >= (screenHeight! - statusBarHeight) - 12 && mouseX > 646.52 && mouseX < 827.49 { 491 | 492 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") { 493 | 494 | let storyboard = NSStoryboard(name: "Main", bundle: nil) 495 | let preferencesVC = storyboard.instantiateController(withIdentifier: "PreferencesViewController") as? NSViewController 496 | preferencesVC?.presentAsModalWindow(preferencesVC!) 497 | 498 | } 499 | 500 | } 501 | 502 | } 503 | } 504 | 505 | } 506 | 507 | var mouseDraggedinNotch = false 508 | 509 | //Drag on notch event 510 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseDragged) { [self] event in 511 | 512 | let mousePoint = event.locationInWindow 513 | 514 | //Focus app on main screen 515 | if self.mainScreen.frame.contains(mousePoint) == true { 516 | 517 | let statusBarHeight = NSStatusBar.system.thickness 518 | let screenHeight = NSScreen.main?.frame.height 519 | let mouseY = event.locationInWindow.y 520 | let mouseX = event.locationInWindow.x 521 | let frontmostApp = NSWorkspace.shared.frontmostApplication 522 | let frontmostAppBundleIdentifier = frontmostApp?.bundleIdentifier 523 | 524 | if MBP14 { 525 | 526 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") && self.filepath != "" { //So app only works on finder 527 | 528 | if mouseY >= (screenHeight! - statusBarHeight) - 12 && mouseX > 665 && mouseX < 850 { 529 | 530 | if mouseDraggedinNotch == false{ 531 | mouseDraggedinNotch = true 532 | } 533 | 534 | } 535 | else { 536 | if mouseDraggedinNotch == true { 537 | mouseDraggedinNotch = false 538 | } 539 | 540 | } 541 | } 542 | 543 | } 544 | 545 | else if MBP16 { 546 | 547 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") && self.filepath != "" { 548 | 549 | if mouseY >= (screenHeight! - statusBarHeight) - 12 && mouseX > 756.42 && mouseX < 941.42 { 550 | 551 | if mouseDraggedinNotch == false{ 552 | mouseDraggedinNotch = true 553 | } 554 | 555 | } 556 | else { 557 | if mouseDraggedinNotch == true { 558 | mouseDraggedinNotch = false 559 | } 560 | } 561 | 562 | } 563 | 564 | } 565 | else if MBAM2 { 566 | 567 | if (frontmostAppBundleIdentifier! == "com.apple.finder" || frontmostAppBundleIdentifier! == "mago.airslide") && self.filepath != "" { 568 | 569 | if mouseY >= (screenHeight! - statusBarHeight) - 12 && mouseX > 646.52 && mouseX < 827.49 { 570 | 571 | if mouseDraggedinNotch == false{ 572 | mouseDraggedinNotch = true 573 | } 574 | 575 | } 576 | else { 577 | if mouseDraggedinNotch == true { 578 | mouseDraggedinNotch = false 579 | } 580 | } 581 | 582 | } 583 | 584 | } 585 | 586 | 587 | } 588 | 589 | } 590 | 591 | 592 | //This allow the main function to fire only if mouse is in notch area and not on second screen. 593 | AppKit.NSEvent.addGlobalMonitorForEvents(matching: .leftMouseUp) { event in 594 | 595 | let mousePoint = event.locationInWindow 596 | 597 | if mouseDraggedinNotch == true && self.mainScreen.frame.contains(mousePoint) == true { 598 | 599 | self.dotherightthing() 600 | 601 | mouseDraggedinNotch = false 602 | } 603 | else { 604 | mouseDraggedinNotch = false 605 | } 606 | 607 | } 608 | 609 | } 610 | 611 | //Airdrop trigger function 612 | func dotherightthing(){ 613 | 614 | if !self.hasExecuted2 { 615 | 616 | self.hasExecuted2 = true 617 | 618 | let sound = NSSound(named: UserDefaults.standard.value(forKey: "actualsound") as! NSSound.Name) 619 | sound?.play() 620 | 621 | //press "esc" 622 | let source = CGEventSource(stateID: .combinedSessionState) 623 | let keyDown = CGEvent(keyboardEventSource: source, virtualKey: 53, keyDown: true) 624 | keyDown?.post(tap: .cghidEventTap) 625 | 626 | FileManager.default.fileExists(atPath: self.filepath) 627 | 628 | let fileURL = URL(fileURLWithPath: self.filepath) 629 | 630 | //if multiple files 631 | if self.filepath.contains(","){ 632 | 633 | let separatedElements = self.filepath.components(separatedBy: ",") 634 | let trimmedElements = separatedElements.map { $0.trimmingCharacters(in: .whitespaces) } 635 | var fileURLs = [URL]() 636 | for element in trimmedElements { 637 | let fileURL = URL(fileURLWithPath: element) 638 | fileURLs.append(fileURL) 639 | } 640 | let sharingService = NSSharingService(named: NSSharingService.Name.sendViaAirDrop) 641 | sharingService?.delegate = self 642 | sharingService?.perform(withItems: fileURLs) 643 | } 644 | 645 | //if only one file 646 | else{ 647 | let sharingService = NSSharingService(named: NSSharingService.Name.sendViaAirDrop) 648 | sharingService?.delegate = self 649 | sharingService?.perform(withItems: [fileURL]) 650 | 651 | 652 | } 653 | 654 | } 655 | } 656 | 657 | //vvv ONLY FOR APP START INDICATOR PURPOSE vvv 658 | 659 | func startMBP14(){ 660 | let window = NSWindow(contentRect: NSMakeRect(635, 880, 250, 100), styleMask: .borderless, backing: .buffered, defer: false) 661 | window.level = .screenSaver 662 | window.isOpaque = false 663 | window.backgroundColor = .clear 664 | 665 | let blueView = NSView(frame: CGRect(x: 29, y: window.contentView!.frame.midY + 20 , width: window.contentView!.frame.width - 66, height: window.contentView!.frame.height - 5)) 666 | blueView.wantsLayer = true 667 | blueView.layer?.backgroundColor = NSColor(red: 0, green: 123/255, blue: 254/255, alpha: 1).cgColor 668 | blueView.layer?.cornerRadius = 10 669 | blueView.isHidden = false 670 | 671 | let borderLayer = CALayer() 672 | borderLayer.frame = blueView.bounds 673 | borderLayer.cornerRadius = blueView.layer!.cornerRadius 674 | borderLayer.borderColor = NSColor.white.cgColor 675 | borderLayer.borderWidth = 6.0 676 | blueView.layer?.addSublayer(borderLayer) 677 | 678 | let animation = CABasicAnimation(keyPath: "borderColor") 679 | animation.fromValue = NSColor.clear.cgColor 680 | animation.toValue = NSColor.white.cgColor 681 | animation.duration = 1.618 682 | animation.autoreverses = true 683 | animation.repeatCount = Float.infinity 684 | borderLayer.add(animation, forKey: "borderColor") 685 | 686 | window.contentView?.addSubview(blueView) 687 | window.makeKeyAndOrderFront(nil) 688 | 689 | 690 | NSAnimationContext.runAnimationGroup({ (context) in 691 | context.duration = 1 692 | blueView.animator().frame.origin.y -= 6 693 | }, completionHandler: { 694 | blueView.frame.origin.y -= 0 695 | }) 696 | 697 | 698 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { 699 | NSAnimationContext.runAnimationGroup({ (context) in 700 | context.duration = 1 701 | blueView.animator().frame.origin.y -= -6 702 | }, completionHandler: { 703 | blueView.frame.origin.y -= 0 704 | }) 705 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) { 706 | blueView.isHidden = true 707 | } 708 | } 709 | } 710 | 711 | func startMBP16(){ 712 | let window = NSWindow(contentRect: NSMakeRect(725, 1001, 285.71, 113.74), styleMask: .borderless, backing: .buffered, defer: false) 713 | window.level = .screenSaver 714 | window.isOpaque = false 715 | window.backgroundColor = .clear 716 | 717 | let blueView = NSView(frame: CGRect(x: 29, y: window.contentView!.frame.midY + 20 , width: window.contentView!.frame.width - 66, height: window.contentView!.frame.height - 5)) 718 | blueView.wantsLayer = true 719 | blueView.layer?.backgroundColor = NSColor(red: 0, green: 123/255, blue: 254/255, alpha: 1).cgColor 720 | blueView.layer?.cornerRadius = 10 721 | blueView.isHidden = false 722 | 723 | let borderLayer = CALayer() 724 | borderLayer.frame = blueView.bounds 725 | borderLayer.cornerRadius = blueView.layer!.cornerRadius 726 | borderLayer.borderColor = NSColor.white.cgColor 727 | borderLayer.borderWidth = 6.0 728 | blueView.layer?.addSublayer(borderLayer) 729 | 730 | let animation = CABasicAnimation(keyPath: "borderColor") 731 | animation.fromValue = NSColor.clear.cgColor 732 | animation.toValue = NSColor.white.cgColor 733 | animation.duration = 1.618 734 | animation.autoreverses = true 735 | animation.repeatCount = Float.infinity 736 | borderLayer.add(animation, forKey: "borderColor") 737 | 738 | window.contentView?.addSubview(blueView) 739 | window.makeKeyAndOrderFront(nil) 740 | 741 | 742 | NSAnimationContext.runAnimationGroup({ (context) in 743 | context.duration = 1 744 | blueView.animator().frame.origin.y -= 6 745 | }, completionHandler: { 746 | blueView.frame.origin.y -= 0 747 | }) 748 | 749 | 750 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { 751 | NSAnimationContext.runAnimationGroup({ (context) in 752 | context.duration = 1 753 | blueView.animator().frame.origin.y -= -6 754 | }, completionHandler: { 755 | blueView.frame.origin.y -= 0 756 | }) 757 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) { 758 | blueView.isHidden = true 759 | } 760 | } 761 | } 762 | 763 | func startMBAM2(){ 764 | let window = NSWindow(contentRect: NSMakeRect(617.36, 856.70, 243.05, 97.35), styleMask: .borderless, backing: .buffered, defer: false) 765 | window.level = .screenSaver 766 | window.isOpaque = false 767 | window.backgroundColor = .clear 768 | 769 | let blueView = NSView(frame: CGRect(x: 29, y: window.contentView!.frame.midY + 20 , width: window.contentView!.frame.width - 66, height: window.contentView!.frame.height - 5)) 770 | blueView.wantsLayer = true 771 | blueView.layer?.backgroundColor = NSColor(red: 0, green: 123/255, blue: 254/255, alpha: 1).cgColor 772 | blueView.layer?.cornerRadius = 10 773 | blueView.isHidden = false 774 | 775 | let borderLayer = CALayer() 776 | borderLayer.frame = blueView.bounds 777 | borderLayer.cornerRadius = blueView.layer!.cornerRadius 778 | borderLayer.borderColor = NSColor.white.cgColor 779 | borderLayer.borderWidth = 6.0 780 | blueView.layer?.addSublayer(borderLayer) 781 | 782 | let animation = CABasicAnimation(keyPath: "borderColor") 783 | animation.fromValue = NSColor.clear.cgColor 784 | animation.toValue = NSColor.white.cgColor 785 | animation.duration = 1.618 786 | animation.autoreverses = true 787 | animation.repeatCount = Float.infinity 788 | borderLayer.add(animation, forKey: "borderColor") 789 | 790 | window.contentView?.addSubview(blueView) 791 | window.makeKeyAndOrderFront(nil) 792 | 793 | 794 | NSAnimationContext.runAnimationGroup({ (context) in 795 | context.duration = 1 796 | blueView.animator().frame.origin.y -= 6 797 | }, completionHandler: { 798 | blueView.frame.origin.y -= 0 799 | }) 800 | 801 | 802 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) { 803 | NSAnimationContext.runAnimationGroup({ (context) in 804 | context.duration = 1 805 | blueView.animator().frame.origin.y -= -6 806 | }, completionHandler: { 807 | blueView.frame.origin.y -= 0 808 | }) 809 | DispatchQueue.main.asyncAfter(deadline: .now() + 1.4) { 810 | blueView.isHidden = true 811 | } 812 | } 813 | } 814 | 815 | } 816 | 817 | --------------------------------------------------------------------------------