diff --git a/app/NativeMacReceiverSelector/AppDelegate.swift b/app/NativeMacReceiverSelector/AppDelegate.swift index 0fccf1d..3334a13 100644 --- a/app/NativeMacReceiverSelector/AppDelegate.swift +++ b/app/NativeMacReceiverSelector/AppDelegate.swift @@ -2,47 +2,30 @@ import Cocoa class AppDelegate : NSObject, NSApplicationDelegate { - var initData: InitData! - var mainWindow: NSWindow? var mainWindowController: NSWindowController? var mainWindowViewController: ViewController? func applicationDidFinishLaunching (_ aNotification: Notification) { - if CommandLine.argc < 2 { - fputs("Error: Not enough args\n", stderr) - exit(1) - } - - guard let data = CommandLine.arguments[1].data(using: .utf8) else { - fputs("Error: Failed to convert input to data\n", stderr) - exit(1) - } - - do { - // Decode and store initialization JSON data - self.initData = try JSONDecoder().decode(InitData.self, from: data) - } catch { - fputs("Error: Failed to parse input data\n (\(error))", stderr) - exit(1) - } - - let window = NSWindow( contentRect: NSZeroRect , styleMask: [ .titled, .closable ] , backing: .buffered , defer: false) - let screenHeight = NSScreen.main!.frame.height - window.titleVisibility = .hidden window.isMovableByWindowBackground = true window.orderFrontRegardless() - window.setFrameTopLeftPoint(NSPoint( - x: self.initData.windowPositionX - , y: Int(screenHeight - CGFloat(self.initData.windowPositionY)))) + + if let screen = NSScreen.main { + let windowX = InitDataProvider.shared.data.windowPositionX + let windowY = Int(screen.frame.height - CGFloat( + InitDataProvider.shared.data.windowPositionY)) + + window.setFrameTopLeftPoint(NSPoint(x: windowX, y: windowY)) + } + let windowController = NSWindowController(window: window) windowController.showWindow(window) @@ -59,7 +42,7 @@ class AppDelegate : NSObject, NSApplicationDelegate { } func applicationDidResignActive (_ aNotification: Notification) { - if self.initData.closeIfFocusLost { + if InitDataProvider.shared.data.closeIfFocusLost { self.mainWindow?.performClose(aNotification) } } diff --git a/app/NativeMacReceiverSelector/InitDataProvider.swift b/app/NativeMacReceiverSelector/InitDataProvider.swift new file mode 100644 index 0000000..4034edf --- /dev/null +++ b/app/NativeMacReceiverSelector/InitDataProvider.swift @@ -0,0 +1,20 @@ +import Cocoa + +class InitDataProvider { + static let shared = InitDataProvider() + + let data: InitData + + private init() { + if CommandLine.argc < 2 { + fatalError("Missing init data") + } + + if let input = CommandLine.arguments[1].data(using: .utf8) + , let parsed = try? JSONDecoder().decode(InitData.self, from: input) { + self.data = parsed + } else { + fatalError("Failed to convert and parse init data") + } + } +} diff --git a/app/NativeMacReceiverSelector/ReceiverView.swift b/app/NativeMacReceiverSelector/ReceiverView.swift index 1739f76..dcc1e50 100644 --- a/app/NativeMacReceiverSelector/ReceiverView.swift +++ b/app/NativeMacReceiverSelector/ReceiverView.swift @@ -32,7 +32,7 @@ class ReceiverView : NSStackView { super.init(coder: coder) } - init (receiver: Receiver, initData: InitData) { + init (receiver: Receiver) { super.init(frame: NSZeroRect) self.receiver = receiver @@ -63,7 +63,7 @@ class ReceiverView : NSStackView { self.castButton = NSButton( - title: initData.i18n_castButtonTitle + title: InitDataProvider.shared.data.i18n_castButtonTitle , target: self , action: #selector(ReceiverView.onCast)) @@ -89,12 +89,14 @@ class ReceiverView : NSStackView { if !constraintsSet { self.translatesAutoresizingMaskIntoConstraints = false - self.leadingAnchor.constraint( - equalTo: superview!.leadingAnchor - , constant: 8).isActive = true - self.trailingAnchor.constraint( - equalTo: superview!.trailingAnchor - , constant: -8).isActive = true + if let superview = self.superview { + self.leadingAnchor.constraint( + equalTo: superview.leadingAnchor + , constant: 8).isActive = true + self.trailingAnchor.constraint( + equalTo: superview.trailingAnchor + , constant: -8).isActive = true + } constraintsSet = true } diff --git a/app/NativeMacReceiverSelector/ViewController.swift b/app/NativeMacReceiverSelector/ViewController.swift index 4fc8057..8d470d9 100644 --- a/app/NativeMacReceiverSelector/ViewController.swift +++ b/app/NativeMacReceiverSelector/ViewController.swift @@ -2,8 +2,6 @@ import Cocoa class ViewController : NSViewController { - var initData: InitData! - var mediaTypePopUpButton: NSPopUpButton! var receiverViews = [ReceiverView]() @@ -21,7 +19,7 @@ class ViewController : NSViewController { override func viewDidLoad () { super.viewDidLoad() - self.initData = (NSApplication.shared.delegate as! AppDelegate).initData + let initData = InitDataProvider.shared.data /** * View Hierarchy @@ -59,27 +57,27 @@ class ViewController : NSViewController { , initData.i18n_mediaTypeFile ]) - let mediaTypePopUpButtonMenu = self.mediaTypePopUpButton.menu! - mediaTypePopUpButtonMenu.delegate = self + if let appItem = self.mediaTypePopUpButton + .item(withTitle: initData.i18n_mediaTypeApp) + , let tabItem = self.mediaTypePopUpButton + .item(withTitle: initData.i18n_mediaTypeTab) + , let screenItem = self.mediaTypePopUpButton + .item(withTitle: initData.i18n_mediaTypeScreen) + , let fileItem = self.mediaTypePopUpButton + .item(withTitle: initData.i18n_mediaTypeFile) { - let appItem = self.mediaTypePopUpButton - .item(withTitle: initData.i18n_mediaTypeApp)! - let tabItem = self.mediaTypePopUpButton - .item(withTitle: initData.i18n_mediaTypeTab)! - let screenItem = self.mediaTypePopUpButton - .item(withTitle: initData.i18n_mediaTypeScreen)! - let fileItem = self.mediaTypePopUpButton - .item(withTitle: initData.i18n_mediaTypeFile)! + if let mediaTypePopUpButtonMenu = self.mediaTypePopUpButton.menu { + mediaTypePopUpButtonMenu.delegate = self + mediaTypePopUpButtonMenu.insertItem(NSMenuItem.separator() + , at: mediaTypePopUpButtonMenu.index(of: fileItem)) + } - mediaTypePopUpButtonMenu - .insertItem(NSMenuItem.separator() - , at: mediaTypePopUpButtonMenu.index(of: fileItem)) - - // Set tags to enum value - appItem.tag = MediaType.app.rawValue - tabItem.tag = MediaType.tab.rawValue - screenItem.tag = MediaType.screen.rawValue - fileItem.tag = MediaType.file.rawValue + // Set tags to enum value + appItem.tag = MediaType.app.rawValue + tabItem.tag = MediaType.tab.rawValue + screenItem.tag = MediaType.screen.rawValue + fileItem.tag = MediaType.file.rawValue + } for item in self.mediaTypePopUpButton.itemArray { if (initData.availableMediaTypes & item.tag) == 0 { @@ -121,15 +119,12 @@ class ViewController : NSViewController { let receiverSeparator = NSBox() receiverSeparator.boxType = .separator - let receiverView = ReceiverView( - receiver: receiver - , initData: self.initData) - + let receiverView = ReceiverView(receiver: receiver) receiverView.receiverViewDelegate = self - if UInt(initData!.availableMediaTypes) == 0 - || (initData!.availableMediaTypes - & initData!.defaultMediaType.rawValue) == 0 { + if UInt(initData.availableMediaTypes) == 0 + || (initData.availableMediaTypes + & initData.defaultMediaType.rawValue) == 0 { receiverView.isEnabled = false } @@ -149,26 +144,33 @@ class ViewController : NSViewController { override func viewDidAppear () { // Set window title and update visibility - let window = self.view.window! - window.title = initData.i18n_extensionName - window.titleVisibility = .visible + if let window = self.view.window { + window.title = InitDataProvider.shared.data.i18n_extensionName + window.titleVisibility = .visible + } } } extension ViewController : NSMenuDelegate { func menuDidClose (_ menu: NSMenu) { - let mediaType = MediaType( - rawValue: self.mediaTypePopUpButton.selectedItem!.tag)! + let initData = InitDataProvider.shared.data - if self.initData.availableMediaTypes & mediaType.rawValue != 0 { + guard let selectedItem = self.mediaTypePopUpButton.selectedItem + , let mediaType = MediaType(rawValue: selectedItem.tag) else { + return + } + + if initData.availableMediaTypes & mediaType.rawValue != 0 { for receiverView in self.receiverViews { receiverView.isEnabled = true } } - let fileItem = self.mediaTypePopUpButton + guard let fileItem = self.mediaTypePopUpButton .item(at: self.mediaTypePopUpButton.indexOfItem( - withTag: MediaType.file.rawValue))! + withTag: MediaType.file.rawValue)) else { + return + } if (mediaType == .file) { let panel = NSOpenPanel() @@ -178,7 +180,9 @@ extension ViewController : NSMenuDelegate { panel.canCreateDirectories = false panel.canChooseFiles = true - panel.beginSheetModal(for: self.view.window!) { (result) in + guard let window = self.view.window else { return } + + panel.beginSheetModal(for: window) { (result) in if (result == .OK) { let url = panel.urls[0] let fileName = url.lastPathComponent @@ -194,14 +198,21 @@ extension ViewController : NSMenuDelegate { } else { // Re-select the default media type item self.mediaTypePopUpButton.selectItem( - withTag: self.initData.defaultMediaType.rawValue) + withTag: initData.defaultMediaType.rawValue) + + let defaultMediaTypeAvailable = initData.availableMediaTypes + & initData.defaultMediaType.rawValue != 0 + + for receiverView in self.receiverViews { + receiverView.isEnabled = defaultMediaTypeAvailable + } } } } // Reset file item - fileItem.title = self.initData.i18n_mediaTypeFile + fileItem.title = initData.i18n_mediaTypeFile self.filePath = nil } } @@ -217,23 +228,23 @@ extension ViewController : ReceiverViewDelegate { receiverView.isEnabled = false } - do { - let mediaType = MediaType( - rawValue: self.mediaTypePopUpButton.selectedItem!.tag)! - let selection = ReceiverSelection( - receiver: receiver - , mediaType: mediaType - , filePath: self.filePath ?? nil) + guard let selectedItem = self.mediaTypePopUpButton.selectedItem + , let mediaType = MediaType(rawValue: selectedItem.tag) else { + return + } - let jsonData = try JSONEncoder().encode(selection) - let jsonString = String(data: jsonData, encoding: .utf8) + let selection = ReceiverSelection( + receiver: receiver + , mediaType: mediaType + , filePath: self.filePath ?? nil) - print(jsonString!) + if let jsonData = try? JSONEncoder().encode(selection) + , let jsonString = String(data: jsonData, encoding: .utf8) { + print(jsonString) fflush(stdout) - } catch { - fputs("Error: Failed to encode output data", stderr) - exit(1) + } else { + fatalError("Error: Failed to encode output data") } } }