mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Add dynamic dock menu with "Now Playing" section
Inspired pretty heavily by iTunes.
This commit is contained in:
parent
8e6396dbe9
commit
e6bbe4f35d
@ -661,10 +661,11 @@
|
|||||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
||||||
E47E2FD4222071FD00F747E6 /* AlbumViewItem.swift */,
|
E47E2FD4222071FD00F747E6 /* AlbumViewItem.swift */,
|
||||||
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */,
|
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */,
|
||||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
|
||||||
E465049921E94DF500A70F4C /* WindowController.swift */,
|
|
||||||
E4B11BB52275374B0075461B /* UserNotificationsController.swift */,
|
|
||||||
E4405191227644340090CD6F /* MPDServerController.swift */,
|
E4405191227644340090CD6F /* MPDServerController.swift */,
|
||||||
|
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
||||||
|
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
||||||
|
E4B11BB52275374B0075461B /* UserNotificationsController.swift */,
|
||||||
|
E465049921E94DF500A70F4C /* WindowController.swift */,
|
||||||
);
|
);
|
||||||
path = Controllers;
|
path = Controllers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
|||||||
@ -32,6 +32,57 @@ class AppDelegate: NSObject,
|
|||||||
App.mpdServerController.disconnect()
|
App.mpdServerController.disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applicationDockMenu(_ sender: NSApplication) -> NSMenu? {
|
||||||
|
let dockMenu = NSMenu()
|
||||||
|
dockMenu.autoenablesItems = false
|
||||||
|
|
||||||
|
guard let state = App.store.state.playerState.state else { return nil }
|
||||||
|
|
||||||
|
if let currentSong = App.store.state.playerState.currentSong,
|
||||||
|
state.isOneOf([.playing, .paused]) {
|
||||||
|
|
||||||
|
let nowPlayingItem = NSMenuItem(title: "Now Playing", action: nil, keyEquivalent: "")
|
||||||
|
let songItem = NSMenuItem(title: currentSong.title, action: nil, keyEquivalent: "")
|
||||||
|
let albumItem = NSMenuItem(
|
||||||
|
title: "\(currentSong.artist) — \(currentSong.album.title)",
|
||||||
|
action: nil,
|
||||||
|
keyEquivalent: ""
|
||||||
|
)
|
||||||
|
|
||||||
|
nowPlayingItem.isEnabled = false
|
||||||
|
songItem.indentationLevel = 1
|
||||||
|
songItem.isEnabled = false
|
||||||
|
albumItem.indentationLevel = 1
|
||||||
|
albumItem.isEnabled = false
|
||||||
|
|
||||||
|
dockMenu.addItem(nowPlayingItem)
|
||||||
|
dockMenu.addItem(songItem)
|
||||||
|
dockMenu.addItem(albumItem)
|
||||||
|
dockMenu.addItem(NSMenuItem.separator())
|
||||||
|
}
|
||||||
|
|
||||||
|
let playPauseMenuItem = NSMenuItem(
|
||||||
|
title: state == .playing ? "Pause" : "Play",
|
||||||
|
action: #selector(playPauseMenuAction),
|
||||||
|
keyEquivalent: ""
|
||||||
|
)
|
||||||
|
let stopMenuItem = NSMenuItem(title: "Stop", action: #selector(stopMenuAction), keyEquivalent: "")
|
||||||
|
let nextTrackMenuItem = NSMenuItem(title: "Next", action: #selector(nextTrackMenuAction), keyEquivalent: "")
|
||||||
|
let prevTrackMenuItem = NSMenuItem(title: "Previous", action: #selector(prevTrackMenuAction), keyEquivalent: "")
|
||||||
|
|
||||||
|
playPauseMenuItem.isEnabled = state.isOneOf([.playing, .paused, .stopped])
|
||||||
|
stopMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
||||||
|
nextTrackMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
||||||
|
prevTrackMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
||||||
|
|
||||||
|
dockMenu.addItem(playPauseMenuItem)
|
||||||
|
dockMenu.addItem(stopMenuItem)
|
||||||
|
dockMenu.addItem(nextTrackMenuItem)
|
||||||
|
dockMenu.addItem(prevTrackMenuItem)
|
||||||
|
|
||||||
|
return dockMenu
|
||||||
|
}
|
||||||
|
|
||||||
func handle(mediaKey: MediaKey, event: KeyEvent) {
|
func handle(mediaKey: MediaKey, event: KeyEvent) {
|
||||||
switch mediaKey {
|
switch mediaKey {
|
||||||
case .playPause:
|
case .playPause:
|
||||||
@ -43,46 +94,24 @@ class AppDelegate: NSObject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setDockTransportControlState(_ state: MPDClient.MPDStatus.State) {
|
|
||||||
playPauseMenuItem.isEnabled = state.isOneOf([.playing, .paused, .stopped])
|
|
||||||
stopMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
|
||||||
nextTrackMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
|
||||||
prevTrackMenuItem.isEnabled = state.isOneOf([.playing, .paused])
|
|
||||||
|
|
||||||
if state.isOneOf([.paused, .stopped, .unknown]) {
|
|
||||||
playPauseMenuItem.title = "Play"
|
|
||||||
} else {
|
|
||||||
playPauseMenuItem.title = "Pause"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func enableUpdateDatabaseMenuItem() {
|
|
||||||
updateDatabaseMenuItem?.isEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func updateDatabase(_ sender: NSMenuItem) {
|
@IBAction func updateDatabase(_ sender: NSMenuItem) {
|
||||||
App.store.dispatch(MPDUpdateDatabaseAction())
|
App.store.dispatch(MPDUpdateDatabaseAction())
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBAction func playPauseMenuAction(_ sender: NSMenuItem) {
|
@IBAction func playPauseMenuAction(_ sender: NSMenuItem) {
|
||||||
AppDelegate.mpdClient.playPause()
|
App.store.dispatch(MPDPlayPauseAction())
|
||||||
}
|
}
|
||||||
@IBAction func stopMenuAction(_ sender: NSMenuItem) {
|
@IBAction func stopMenuAction(_ sender: NSMenuItem) {
|
||||||
AppDelegate.mpdClient.stop()
|
App.store.dispatch(MPDStopAction())
|
||||||
}
|
}
|
||||||
@IBAction func nextTrackMenuAction(_ sender: NSMenuItem) {
|
@IBAction func nextTrackMenuAction(_ sender: NSMenuItem) {
|
||||||
AppDelegate.mpdClient.nextTrack()
|
App.store.dispatch(MPDNextTrackAction())
|
||||||
}
|
}
|
||||||
@IBAction func prevTrackMenuAction(_ sender: Any) {
|
@IBAction func prevTrackMenuAction(_ sender: Any) {
|
||||||
AppDelegate.mpdClient.prevTrack()
|
App.store.dispatch(MPDPrevTrackAction())
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
|
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
|
||||||
|
|
||||||
@IBOutlet weak var playPauseMenuItem: NSMenuItem!
|
|
||||||
@IBOutlet weak var stopMenuItem: NSMenuItem!
|
|
||||||
@IBOutlet weak var nextTrackMenuItem: NSMenuItem!
|
|
||||||
@IBOutlet weak var prevTrackMenuItem: NSMenuItem!
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AppDelegate: StoreSubscriber {
|
extension AppDelegate: StoreSubscriber {
|
||||||
|
|||||||
@ -20,6 +20,7 @@ class WindowController: NSWindowController {
|
|||||||
override func windowDidLoad() {
|
override func windowDidLoad() {
|
||||||
super.windowDidLoad()
|
super.windowDidLoad()
|
||||||
window?.titleVisibility = .hidden
|
window?.titleVisibility = .hidden
|
||||||
|
window?.isExcludedFromWindowsMenu = true
|
||||||
|
|
||||||
App.store.subscribe(self) {
|
App.store.subscribe(self) {
|
||||||
$0.select { $0.playerState }
|
$0.select { $0.playerState }
|
||||||
@ -53,12 +54,6 @@ class WindowController: NSWindowController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setWindowTitle() {
|
|
||||||
guard let status = AppDelegate.mpdClient.status else { return }
|
|
||||||
|
|
||||||
self.window?.title = status.
|
|
||||||
}
|
|
||||||
|
|
||||||
func setTrackProgressControls(_ playerState: PlayerState) {
|
func setTrackProgressControls(_ playerState: PlayerState) {
|
||||||
guard let state = playerState.state,
|
guard let state = playerState.state,
|
||||||
let totalTime = playerState.totalTime,
|
let totalTime = playerState.totalTime,
|
||||||
|
|||||||
@ -90,6 +90,8 @@
|
|||||||
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
|
<action selector="performZoom:" target="Ady-hI-5gd" id="DIl-cC-cCs"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="QhP-iz-rRa"/>
|
||||||
|
<menuItem title="Persephone" state="on" keyEquivalent="0" id="1Sq-L7-znT"/>
|
||||||
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
<menuItem isSeparatorItem="YES" id="eu3-7i-yIM"/>
|
||||||
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
<menuItem title="Bring All to Front" id="LE2-aR-0XJ">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
@ -116,49 +118,15 @@
|
|||||||
</menu>
|
</menu>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
<outlet property="delegate" destination="Voe-Tx-rLC" id="PrD-fu-P6m"/>
|
||||||
<outlet property="dockMenu" destination="HMZ-6U-dkI" id="z8r-8r-l9q"/>
|
|
||||||
</connections>
|
</connections>
|
||||||
</application>
|
</application>
|
||||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Persephone" customModuleProvider="target">
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Persephone" customModuleProvider="target">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="nextTrackMenuItem" destination="InD-dy-4Xk" id="vTQ-Gf-E8k"/>
|
|
||||||
<outlet property="playPauseMenu" destination="Ldt-58-fDl" id="p2r-nI-tf4"/>
|
|
||||||
<outlet property="playPauseMenuItem" destination="Ldt-58-fDl" id="KGN-OQ-uHK"/>
|
|
||||||
<outlet property="prevTrackMenuItem" destination="90s-qF-dI2" id="Zba-8D-UEg"/>
|
|
||||||
<outlet property="stopMenuItem" destination="F1T-fC-2rX" id="doK-EU-w6M"/>
|
|
||||||
<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>
|
||||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="Ady-hI-5gd" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
<menu autoenablesItems="NO" id="HMZ-6U-dkI">
|
|
||||||
<items>
|
|
||||||
<menuItem title="Play" enabled="NO" id="Ldt-58-fDl">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="playPauseMenuAction:" target="Voe-Tx-rLC" id="J7X-Fe-jyM"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Stop" enabled="NO" id="F1T-fC-2rX">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="stopMenuAction:" target="Voe-Tx-rLC" id="CnR-Hf-mDH"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Next" enabled="NO" id="InD-dy-4Xk">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="nextMenuAction:" target="Voe-Tx-rLC" id="7QQ-ce-PyS"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
<menuItem title="Previous" enabled="NO" id="90s-qF-dI2">
|
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
|
||||||
<connections>
|
|
||||||
<action selector="prevMenuAction:" target="Voe-Tx-rLC" id="iw3-oE-E2Y"/>
|
|
||||||
</connections>
|
|
||||||
</menuItem>
|
|
||||||
</items>
|
|
||||||
</menu>
|
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="81" y="-332"/>
|
<point key="canvasLocation" x="81" y="-332"/>
|
||||||
</scene>
|
</scene>
|
||||||
@ -166,7 +134,7 @@
|
|||||||
<scene sceneID="R2V-B0-nI4">
|
<scene sceneID="R2V-B0-nI4">
|
||||||
<objects>
|
<objects>
|
||||||
<windowController id="B8D-0N-5wS" customClass="WindowController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
<windowController id="B8D-0N-5wS" customClass="WindowController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<window key="window" title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA" customClass="MainWindow" customModule="Persephone" customModuleProvider="target">
|
<window key="window" title="Persephone" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="IQv-IB-iLA" customClass="MainWindow" customModule="Persephone" customModuleProvider="target">
|
||||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||||
<rect key="contentRect" x="207" y="570" width="960" height="560"/>
|
<rect key="contentRect" x="207" y="570" width="960" height="560"/>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user