mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Better keyboard shortcuts
* Override `window.sendEvent` to implement global [space] play/pause * Add Controls menu to implement stop, prev, next as ⌘., ⌘← and ⌘→
This commit is contained in:
parent
34f941017f
commit
46dcd60ed1
@ -16,6 +16,11 @@ class AppDelegate: NSObject,
|
|||||||
MediaKeyTapDelegate {
|
MediaKeyTapDelegate {
|
||||||
var mediaKeyTap: MediaKeyTap?
|
var mediaKeyTap: MediaKeyTap?
|
||||||
|
|
||||||
|
@IBOutlet weak var playPauseMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet weak var stopMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet weak var nextSongMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet weak var previousSongMenuItem: NSMenuItem!
|
||||||
|
|
||||||
@IBOutlet weak var connectMenuItem: NSMenuItem!
|
@IBOutlet weak var connectMenuItem: NSMenuItem!
|
||||||
@IBOutlet weak var disconnectMenuItem: NSMenuItem!
|
@IBOutlet weak var disconnectMenuItem: NSMenuItem!
|
||||||
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
|
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
|
||||||
@ -30,7 +35,7 @@ class AppDelegate: NSObject,
|
|||||||
|
|
||||||
App.store.subscribe(self) {
|
App.store.subscribe(self) {
|
||||||
$0.select {
|
$0.select {
|
||||||
($0.serverState, $0.uiState)
|
($0.serverState, $0.playerState, $0.uiState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -52,7 +57,11 @@ class AppDelegate: NSObject,
|
|||||||
if let currentSong = App.store.state.playerState.currentSong,
|
if let currentSong = App.store.state.playerState.currentSong,
|
||||||
state.isOneOf([.playing, .paused]) {
|
state.isOneOf([.playing, .paused]) {
|
||||||
|
|
||||||
let nowPlayingItem = NSMenuItem(title: "Now Playing", action: nil, keyEquivalent: "")
|
let nowPlayingItem = NSMenuItem(
|
||||||
|
title: state == .playing ? "Now Playing" : "Paused",
|
||||||
|
action: nil,
|
||||||
|
keyEquivalent: ""
|
||||||
|
)
|
||||||
let songItem = NSMenuItem(title: currentSong.title, action: nil, keyEquivalent: "")
|
let songItem = NSMenuItem(title: currentSong.title, action: nil, keyEquivalent: "")
|
||||||
let albumItem = NSMenuItem(
|
let albumItem = NSMenuItem(
|
||||||
title: "\(currentSong.artist) — \(currentSong.album.title)",
|
title: "\(currentSong.artist) — \(currentSong.album.title)",
|
||||||
@ -108,6 +117,21 @@ class AppDelegate: NSObject,
|
|||||||
addSelectedSongToQueueMenuItem.isEnabled = selectedSong != nil
|
addSelectedSongToQueueMenuItem.isEnabled = selectedSong != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setControlsMenuItemsState(state: PlayerState) {
|
||||||
|
guard let state = state.state else { return }
|
||||||
|
|
||||||
|
playPauseMenuItem.isEnabled = state.isOneOf([.playing, .paused, .stopped])
|
||||||
|
stopMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
||||||
|
nextSongMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
||||||
|
previousSongMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
||||||
|
|
||||||
|
if state.isOneOf([.paused, .stopped, .unknown]) {
|
||||||
|
playPauseMenuItem.title = "Play"
|
||||||
|
} else {
|
||||||
|
playPauseMenuItem.title = "Pause"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setConnectMenuItemsState(connected: Bool) {
|
func setConnectMenuItemsState(connected: Bool) {
|
||||||
connectMenuItem.isEnabled = !connected
|
connectMenuItem.isEnabled = !connected
|
||||||
disconnectMenuItem.isEnabled = connected
|
disconnectMenuItem.isEnabled = connected
|
||||||
@ -197,13 +221,14 @@ class AppDelegate: NSObject,
|
|||||||
|
|
||||||
extension AppDelegate: StoreSubscriber {
|
extension AppDelegate: StoreSubscriber {
|
||||||
typealias StoreSubscriberStateType = (
|
typealias StoreSubscriberStateType = (
|
||||||
serverState: ServerState, uiState: UIState
|
serverState: ServerState, playerState: PlayerState, uiState: UIState
|
||||||
)
|
)
|
||||||
|
|
||||||
func newState(state: StoreSubscriberStateType) {
|
func newState(state: StoreSubscriberStateType) {
|
||||||
updateDatabaseMenuItem.isEnabled = !state.uiState.databaseUpdating
|
updateDatabaseMenuItem.isEnabled = !state.uiState.databaseUpdating
|
||||||
setMainWindowStateMenuItem(state: state.uiState.mainWindowState)
|
setMainWindowStateMenuItem(state: state.uiState.mainWindowState)
|
||||||
setSongMenuItemsState(selectedSong: state.uiState.selectedSong)
|
setSongMenuItemsState(selectedSong: state.uiState.selectedSong)
|
||||||
|
setControlsMenuItemsState(state: state.playerState)
|
||||||
setConnectMenuItemsState(connected: state.serverState.connected)
|
setConnectMenuItemsState(connected: state.serverState.connected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,18 +39,6 @@ class QueueViewController: NSViewController {
|
|||||||
App.store.unsubscribe(self)
|
App.store.unsubscribe(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
override func keyDown(with event: NSEvent) {
|
|
||||||
switch event.keyCode {
|
|
||||||
case NSEvent.keyCodeSpace:
|
|
||||||
nextResponder?.keyDown(with: event)
|
|
||||||
case NSEvent.keyCodeBS:
|
|
||||||
let queuePos = queueView.selectedRow
|
|
||||||
|
|
||||||
App.mpdClient.removeSong(at: queuePos)
|
|
||||||
default:
|
|
||||||
super.keyDown(with: event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func didConnect() {
|
@objc func didConnect() {
|
||||||
App.mpdClient.fetchQueue()
|
App.mpdClient.fetchQueue()
|
||||||
|
|||||||
@ -176,6 +176,34 @@
|
|||||||
</items>
|
</items>
|
||||||
</menu>
|
</menu>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Controls" id="hB8-hX-gD5">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Controls" autoenablesItems="NO" id="61K-cL-XWL">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Play" keyEquivalent=" " id="xXJ-ld-Y8C">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="playPauseMenuAction:" target="Voe-Tx-rLC" id="Rld-sw-gZY"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Stop" keyEquivalent="." id="gWV-jG-Mxw">
|
||||||
|
<connections>
|
||||||
|
<action selector="stopMenuAction:" target="Voe-Tx-rLC" id="Bz3-r5-4bf"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Next song" keyEquivalent="" id="NXq-Bk-4E0">
|
||||||
|
<connections>
|
||||||
|
<action selector="nextTrackMenuAction:" target="Voe-Tx-rLC" id="uhI-Rf-2WT"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Previous song" keyEquivalent="" id="Ziz-Ge-r1Q">
|
||||||
|
<connections>
|
||||||
|
<action selector="prevTrackMenuAction:" target="Voe-Tx-rLC" id="05d-gm-3bo"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
<menuItem title="Window" id="aUF-d1-5bR">
|
<menuItem title="Window" id="aUF-d1-5bR">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||||
@ -237,8 +265,12 @@
|
|||||||
<outlet property="connectMenuItem" destination="VlA-Re-OZs" id="Zzt-yq-mtp"/>
|
<outlet property="connectMenuItem" destination="VlA-Re-OZs" id="Zzt-yq-mtp"/>
|
||||||
<outlet property="disconnectMenuItem" destination="yjK-qU-C6d" id="qel-dM-Gbl"/>
|
<outlet property="disconnectMenuItem" destination="yjK-qU-C6d" id="qel-dM-Gbl"/>
|
||||||
<outlet property="mainWindowMenuItem" destination="1Sq-L7-znT" id="dC6-yY-6Ss"/>
|
<outlet property="mainWindowMenuItem" destination="1Sq-L7-znT" id="dC6-yY-6Ss"/>
|
||||||
|
<outlet property="nextSongMenuItem" destination="NXq-Bk-4E0" id="QEA-iy-BPE"/>
|
||||||
|
<outlet property="playPauseMenuItem" destination="xXJ-ld-Y8C" id="aeQ-wi-en7"/>
|
||||||
<outlet property="playSelectedSongMenuItem" destination="dyT-9E-DRY" id="UY2-SN-YMF"/>
|
<outlet property="playSelectedSongMenuItem" destination="dyT-9E-DRY" id="UY2-SN-YMF"/>
|
||||||
<outlet property="playSelectedSongNextMenuItem" destination="Q8j-jr-IOp" id="Jqh-ia-sMK"/>
|
<outlet property="playSelectedSongNextMenuItem" destination="Q8j-jr-IOp" id="Jqh-ia-sMK"/>
|
||||||
|
<outlet property="previousSongMenuItem" destination="Ziz-Ge-r1Q" id="Ufe-w4-alG"/>
|
||||||
|
<outlet property="stopMenuItem" destination="gWV-jG-Mxw" id="AkD-66-iWe"/>
|
||||||
<outlet property="updateDatabaseMenuItem" destination="EJg-93-1F6" id="gMf-SQ-lyI"/>
|
<outlet property="updateDatabaseMenuItem" destination="EJg-93-1F6" id="gMf-SQ-lyI"/>
|
||||||
</connections>
|
</connections>
|
||||||
</customObject>
|
</customObject>
|
||||||
|
|||||||
@ -9,12 +9,4 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class MainSplitViewController: NSSplitViewController {
|
class MainSplitViewController: NSSplitViewController {
|
||||||
override func keyDown(with event: NSEvent) {
|
|
||||||
switch event.keyCode {
|
|
||||||
case NSEvent.keyCodeSpace:
|
|
||||||
nextResponder?.keyDown(with: event)
|
|
||||||
default:
|
|
||||||
super.keyDown(with: event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,12 +9,25 @@
|
|||||||
import AppKit
|
import AppKit
|
||||||
|
|
||||||
class MainWindow: NSWindow {
|
class MainWindow: NSWindow {
|
||||||
override func keyDown(with event: NSEvent) {
|
override func sendEvent(_ event: NSEvent) {
|
||||||
switch event.keyCode {
|
guard let responder = firstResponder else { return }
|
||||||
case NSEvent.keyCodeSpace:
|
|
||||||
nextResponder?.keyDown(with: event)
|
if event.type == .keyDown &&
|
||||||
default:
|
doesNotRequireSpace(responder) {
|
||||||
super.keyDown(with: event)
|
|
||||||
|
switch event.keyCode {
|
||||||
|
case NSEvent.keyCodeSpace:
|
||||||
|
App.mpdClient.playPause()
|
||||||
|
default:
|
||||||
|
super.sendEvent(event)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
super.sendEvent(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func doesNotRequireSpace(_ responder: NSResponder) -> Bool {
|
||||||
|
return !responder.isKind(of: NSText.self) &&
|
||||||
|
!responder.isKind(of: NSButton.self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,7 +30,7 @@ class WindowController: NSWindowController {
|
|||||||
@IBOutlet var volumeState: NSButton!
|
@IBOutlet var volumeState: NSButton!
|
||||||
|
|
||||||
@IBOutlet weak var searchQuery: NSSearchField!
|
@IBOutlet weak var searchQuery: NSSearchField!
|
||||||
|
|
||||||
override func windowDidLoad() {
|
override func windowDidLoad() {
|
||||||
super.windowDidLoad()
|
super.windowDidLoad()
|
||||||
window?.titleVisibility = .hidden
|
window?.titleVisibility = .hidden
|
||||||
@ -51,17 +51,6 @@ class WindowController: NSWindowController {
|
|||||||
trackRemaining.font = .timerFont
|
trackRemaining.font = .timerFont
|
||||||
}
|
}
|
||||||
|
|
||||||
override func keyDown(with event: NSEvent) {
|
|
||||||
switch event.keyCode {
|
|
||||||
case NSEvent.keyCodeSpace:
|
|
||||||
if !event.isARepeat {
|
|
||||||
App.mpdClient.playPause()
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
nextResponder?.keyDown(with: event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTransportControlState(_ state: PlayerState) {
|
func setTransportControlState(_ state: PlayerState) {
|
||||||
guard let state = state.state else { return }
|
guard let state = state.state else { return }
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user