mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-12 18:39:58 +00:00
Improve optional checking in native selector
This commit is contained in:
@@ -2,47 +2,30 @@ import Cocoa
|
|||||||
|
|
||||||
|
|
||||||
class AppDelegate : NSObject, NSApplicationDelegate {
|
class AppDelegate : NSObject, NSApplicationDelegate {
|
||||||
var initData: InitData!
|
|
||||||
|
|
||||||
var mainWindow: NSWindow?
|
var mainWindow: NSWindow?
|
||||||
var mainWindowController: NSWindowController?
|
var mainWindowController: NSWindowController?
|
||||||
var mainWindowViewController: ViewController?
|
var mainWindowViewController: ViewController?
|
||||||
|
|
||||||
|
|
||||||
func applicationDidFinishLaunching (_ aNotification: Notification) {
|
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(
|
let window = NSWindow(
|
||||||
contentRect: NSZeroRect
|
contentRect: NSZeroRect
|
||||||
, styleMask: [ .titled, .closable ]
|
, styleMask: [ .titled, .closable ]
|
||||||
, backing: .buffered
|
, backing: .buffered
|
||||||
, defer: false)
|
, defer: false)
|
||||||
|
|
||||||
let screenHeight = NSScreen.main!.frame.height
|
|
||||||
|
|
||||||
window.titleVisibility = .hidden
|
window.titleVisibility = .hidden
|
||||||
window.isMovableByWindowBackground = true
|
window.isMovableByWindowBackground = true
|
||||||
window.orderFrontRegardless()
|
window.orderFrontRegardless()
|
||||||
window.setFrameTopLeftPoint(NSPoint(
|
|
||||||
x: self.initData.windowPositionX
|
if let screen = NSScreen.main {
|
||||||
, y: Int(screenHeight - CGFloat(self.initData.windowPositionY))))
|
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)
|
let windowController = NSWindowController(window: window)
|
||||||
windowController.showWindow(window)
|
windowController.showWindow(window)
|
||||||
@@ -59,7 +42,7 @@ class AppDelegate : NSObject, NSApplicationDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func applicationDidResignActive (_ aNotification: Notification) {
|
func applicationDidResignActive (_ aNotification: Notification) {
|
||||||
if self.initData.closeIfFocusLost {
|
if InitDataProvider.shared.data.closeIfFocusLost {
|
||||||
self.mainWindow?.performClose(aNotification)
|
self.mainWindow?.performClose(aNotification)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
20
app/NativeMacReceiverSelector/InitDataProvider.swift
Normal file
20
app/NativeMacReceiverSelector/InitDataProvider.swift
Normal file
@@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -32,7 +32,7 @@ class ReceiverView : NSStackView {
|
|||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
}
|
}
|
||||||
|
|
||||||
init (receiver: Receiver, initData: InitData) {
|
init (receiver: Receiver) {
|
||||||
super.init(frame: NSZeroRect)
|
super.init(frame: NSZeroRect)
|
||||||
|
|
||||||
self.receiver = receiver
|
self.receiver = receiver
|
||||||
@@ -63,7 +63,7 @@ class ReceiverView : NSStackView {
|
|||||||
|
|
||||||
|
|
||||||
self.castButton = NSButton(
|
self.castButton = NSButton(
|
||||||
title: initData.i18n_castButtonTitle
|
title: InitDataProvider.shared.data.i18n_castButtonTitle
|
||||||
, target: self
|
, target: self
|
||||||
, action: #selector(ReceiverView.onCast))
|
, action: #selector(ReceiverView.onCast))
|
||||||
|
|
||||||
@@ -89,12 +89,14 @@ class ReceiverView : NSStackView {
|
|||||||
if !constraintsSet {
|
if !constraintsSet {
|
||||||
self.translatesAutoresizingMaskIntoConstraints = false
|
self.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
|
||||||
|
if let superview = self.superview {
|
||||||
self.leadingAnchor.constraint(
|
self.leadingAnchor.constraint(
|
||||||
equalTo: superview!.leadingAnchor
|
equalTo: superview.leadingAnchor
|
||||||
, constant: 8).isActive = true
|
, constant: 8).isActive = true
|
||||||
self.trailingAnchor.constraint(
|
self.trailingAnchor.constraint(
|
||||||
equalTo: superview!.trailingAnchor
|
equalTo: superview.trailingAnchor
|
||||||
, constant: -8).isActive = true
|
, constant: -8).isActive = true
|
||||||
|
}
|
||||||
|
|
||||||
constraintsSet = true
|
constraintsSet = true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import Cocoa
|
|||||||
|
|
||||||
|
|
||||||
class ViewController : NSViewController {
|
class ViewController : NSViewController {
|
||||||
var initData: InitData!
|
|
||||||
|
|
||||||
var mediaTypePopUpButton: NSPopUpButton!
|
var mediaTypePopUpButton: NSPopUpButton!
|
||||||
var receiverViews = [ReceiverView]()
|
var receiverViews = [ReceiverView]()
|
||||||
|
|
||||||
@@ -21,7 +19,7 @@ class ViewController : NSViewController {
|
|||||||
override func viewDidLoad () {
|
override func viewDidLoad () {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
self.initData = (NSApplication.shared.delegate as! AppDelegate).initData
|
let initData = InitDataProvider.shared.data
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View Hierarchy
|
* View Hierarchy
|
||||||
@@ -59,27 +57,27 @@ class ViewController : NSViewController {
|
|||||||
, initData.i18n_mediaTypeFile
|
, initData.i18n_mediaTypeFile
|
||||||
])
|
])
|
||||||
|
|
||||||
let mediaTypePopUpButtonMenu = self.mediaTypePopUpButton.menu!
|
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) {
|
||||||
|
|
||||||
|
if let mediaTypePopUpButtonMenu = self.mediaTypePopUpButton.menu {
|
||||||
mediaTypePopUpButtonMenu.delegate = self
|
mediaTypePopUpButtonMenu.delegate = self
|
||||||
|
mediaTypePopUpButtonMenu.insertItem(NSMenuItem.separator()
|
||||||
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)!
|
|
||||||
|
|
||||||
mediaTypePopUpButtonMenu
|
|
||||||
.insertItem(NSMenuItem.separator()
|
|
||||||
, at: mediaTypePopUpButtonMenu.index(of: fileItem))
|
, at: mediaTypePopUpButtonMenu.index(of: fileItem))
|
||||||
|
}
|
||||||
|
|
||||||
// Set tags to enum value
|
// Set tags to enum value
|
||||||
appItem.tag = MediaType.app.rawValue
|
appItem.tag = MediaType.app.rawValue
|
||||||
tabItem.tag = MediaType.tab.rawValue
|
tabItem.tag = MediaType.tab.rawValue
|
||||||
screenItem.tag = MediaType.screen.rawValue
|
screenItem.tag = MediaType.screen.rawValue
|
||||||
fileItem.tag = MediaType.file.rawValue
|
fileItem.tag = MediaType.file.rawValue
|
||||||
|
}
|
||||||
|
|
||||||
for item in self.mediaTypePopUpButton.itemArray {
|
for item in self.mediaTypePopUpButton.itemArray {
|
||||||
if (initData.availableMediaTypes & item.tag) == 0 {
|
if (initData.availableMediaTypes & item.tag) == 0 {
|
||||||
@@ -121,15 +119,12 @@ class ViewController : NSViewController {
|
|||||||
let receiverSeparator = NSBox()
|
let receiverSeparator = NSBox()
|
||||||
receiverSeparator.boxType = .separator
|
receiverSeparator.boxType = .separator
|
||||||
|
|
||||||
let receiverView = ReceiverView(
|
let receiverView = ReceiverView(receiver: receiver)
|
||||||
receiver: receiver
|
|
||||||
, initData: self.initData)
|
|
||||||
|
|
||||||
receiverView.receiverViewDelegate = self
|
receiverView.receiverViewDelegate = self
|
||||||
|
|
||||||
if UInt(initData!.availableMediaTypes) == 0
|
if UInt(initData.availableMediaTypes) == 0
|
||||||
|| (initData!.availableMediaTypes
|
|| (initData.availableMediaTypes
|
||||||
& initData!.defaultMediaType.rawValue) == 0 {
|
& initData.defaultMediaType.rawValue) == 0 {
|
||||||
receiverView.isEnabled = false
|
receiverView.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,26 +144,33 @@ class ViewController : NSViewController {
|
|||||||
|
|
||||||
override func viewDidAppear () {
|
override func viewDidAppear () {
|
||||||
// Set window title and update visibility
|
// Set window title and update visibility
|
||||||
let window = self.view.window!
|
if let window = self.view.window {
|
||||||
window.title = initData.i18n_extensionName
|
window.title = InitDataProvider.shared.data.i18n_extensionName
|
||||||
window.titleVisibility = .visible
|
window.titleVisibility = .visible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension ViewController : NSMenuDelegate {
|
extension ViewController : NSMenuDelegate {
|
||||||
func menuDidClose (_ menu: NSMenu) {
|
func menuDidClose (_ menu: NSMenu) {
|
||||||
let mediaType = MediaType(
|
let initData = InitDataProvider.shared.data
|
||||||
rawValue: self.mediaTypePopUpButton.selectedItem!.tag)!
|
|
||||||
|
|
||||||
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 {
|
for receiverView in self.receiverViews {
|
||||||
receiverView.isEnabled = true
|
receiverView.isEnabled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let fileItem = self.mediaTypePopUpButton
|
guard let fileItem = self.mediaTypePopUpButton
|
||||||
.item(at: self.mediaTypePopUpButton.indexOfItem(
|
.item(at: self.mediaTypePopUpButton.indexOfItem(
|
||||||
withTag: MediaType.file.rawValue))!
|
withTag: MediaType.file.rawValue)) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (mediaType == .file) {
|
if (mediaType == .file) {
|
||||||
let panel = NSOpenPanel()
|
let panel = NSOpenPanel()
|
||||||
@@ -178,7 +180,9 @@ extension ViewController : NSMenuDelegate {
|
|||||||
panel.canCreateDirectories = false
|
panel.canCreateDirectories = false
|
||||||
panel.canChooseFiles = true
|
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) {
|
if (result == .OK) {
|
||||||
let url = panel.urls[0]
|
let url = panel.urls[0]
|
||||||
let fileName = url.lastPathComponent
|
let fileName = url.lastPathComponent
|
||||||
@@ -194,14 +198,21 @@ extension ViewController : NSMenuDelegate {
|
|||||||
} else {
|
} else {
|
||||||
// Re-select the default media type item
|
// Re-select the default media type item
|
||||||
self.mediaTypePopUpButton.selectItem(
|
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
|
// Reset file item
|
||||||
fileItem.title = self.initData.i18n_mediaTypeFile
|
fileItem.title = initData.i18n_mediaTypeFile
|
||||||
self.filePath = nil
|
self.filePath = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,23 +228,23 @@ extension ViewController : ReceiverViewDelegate {
|
|||||||
receiverView.isEnabled = false
|
receiverView.isEnabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
|
||||||
let mediaType = MediaType(
|
guard let selectedItem = self.mediaTypePopUpButton.selectedItem
|
||||||
rawValue: self.mediaTypePopUpButton.selectedItem!.tag)!
|
, let mediaType = MediaType(rawValue: selectedItem.tag) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let selection = ReceiverSelection(
|
let selection = ReceiverSelection(
|
||||||
receiver: receiver
|
receiver: receiver
|
||||||
, mediaType: mediaType
|
, mediaType: mediaType
|
||||||
, filePath: self.filePath ?? nil)
|
, filePath: self.filePath ?? nil)
|
||||||
|
|
||||||
let jsonData = try JSONEncoder().encode(selection)
|
if let jsonData = try? JSONEncoder().encode(selection)
|
||||||
let jsonString = String(data: jsonData, encoding: .utf8)
|
, let jsonString = String(data: jsonData, encoding: .utf8) {
|
||||||
|
print(jsonString)
|
||||||
print(jsonString!)
|
|
||||||
fflush(stdout)
|
fflush(stdout)
|
||||||
} catch {
|
} else {
|
||||||
fputs("Error: Failed to encode output data", stderr)
|
fatalError("Error: Failed to encode output data")
|
||||||
exit(1)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user