mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Shuffle/repeat buttons change server state
This commit is contained in:
parent
d211651e16
commit
ad04250760
@ -18,7 +18,7 @@ class AppDelegate: NSObject,
|
|||||||
|
|
||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
App.mpdServerController.connect()
|
App.mpdServerController.connect()
|
||||||
_ = App.userNotificationsController
|
instantiateUserNotificationsController()
|
||||||
|
|
||||||
mediaKeyTap = MediaKeyTap(delegate: self)
|
mediaKeyTap = MediaKeyTap(delegate: self)
|
||||||
mediaKeyTap?.start()
|
mediaKeyTap?.start()
|
||||||
@ -30,6 +30,10 @@ class AppDelegate: NSObject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func instantiateUserNotificationsController() {
|
||||||
|
_ = App.userNotificationsController
|
||||||
|
}
|
||||||
|
|
||||||
func applicationWillTerminate(_ aNotification: Notification) {
|
func applicationWillTerminate(_ aNotification: Notification) {
|
||||||
App.mpdServerController.disconnect()
|
App.mpdServerController.disconnect()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,16 @@ class WindowController: NSWindowController {
|
|||||||
var state: MPDClient.MPDStatus.State?
|
var state: MPDClient.MPDStatus.State?
|
||||||
var trackTimer: Timer?
|
var trackTimer: Timer?
|
||||||
|
|
||||||
|
@IBOutlet var transportControls: NSSegmentedCell!
|
||||||
|
|
||||||
|
@IBOutlet var trackProgress: NSTextField!
|
||||||
|
@IBOutlet var trackProgressBar: NSSlider!
|
||||||
|
@IBOutlet var trackRemaining: NSTextField!
|
||||||
|
@IBOutlet var databaseUpdatingIndicator: NSProgressIndicator!
|
||||||
|
|
||||||
|
@IBOutlet var shuffleState: NSButton!
|
||||||
|
@IBOutlet var repeatState: NSButton!
|
||||||
|
|
||||||
override func windowDidLoad() {
|
override func windowDidLoad() {
|
||||||
super.windowDidLoad()
|
super.windowDidLoad()
|
||||||
window?.titleVisibility = .hidden
|
window?.titleVisibility = .hidden
|
||||||
@ -137,12 +147,14 @@ class WindowController: NSWindowController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@IBOutlet var transportControls: NSSegmentedCell!
|
@IBAction func handleShuffleButton(_ sender: NSButton) {
|
||||||
|
App.store.dispatch(MPDSetShuffleAction(shuffleState: sender.state == .on))
|
||||||
@IBOutlet var trackProgress: NSTextField!
|
}
|
||||||
@IBOutlet var trackProgressBar: NSSlider!
|
|
||||||
@IBOutlet var trackRemaining: NSTextField!
|
@IBAction func handleRepeatButton(_ sender: NSButton) {
|
||||||
@IBOutlet var databaseUpdatingIndicator: NSProgressIndicator!
|
App.store.dispatch(MPDSetRepeatAction(repeatState: sender.state == .on))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension WindowController: NSWindowDelegate {
|
extension WindowController: NSWindowDelegate {
|
||||||
|
|||||||
@ -29,6 +29,16 @@ extension MPDClient {
|
|||||||
else { return }
|
else { return }
|
||||||
sendSeekCurrentSong(timeInSeconds: timeInSeconds)
|
sendSeekCurrentSong(timeInSeconds: timeInSeconds)
|
||||||
|
|
||||||
|
case .setShuffleState:
|
||||||
|
guard let shuffleState = userData["shuffleState"] as? Bool
|
||||||
|
else { return }
|
||||||
|
sendShuffleState(shuffleState: shuffleState)
|
||||||
|
|
||||||
|
case .setRepeatState:
|
||||||
|
guard let repeatState = userData["repeatState"] as? Bool
|
||||||
|
else { return }
|
||||||
|
sendRepeatState(repeatState: repeatState)
|
||||||
|
|
||||||
// Database commands
|
// Database commands
|
||||||
case .updateDatabase:
|
case .updateDatabase:
|
||||||
sendUpdateDatabase()
|
sendUpdateDatabase()
|
||||||
|
|||||||
@ -33,6 +33,20 @@ extension MPDClient {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setShuffleState(shuffleState: Bool) {
|
||||||
|
enqueueCommand(
|
||||||
|
command: .setShuffleState,
|
||||||
|
userData: ["shuffleState": shuffleState]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setRepeatState(repeatState: Bool) {
|
||||||
|
enqueueCommand(
|
||||||
|
command: .setRepeatState,
|
||||||
|
userData: ["repeatState": repeatState]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func sendNextTrack() {
|
func sendNextTrack() {
|
||||||
guard let state = status?.state,
|
guard let state = status?.state,
|
||||||
state.isOneOf([.playing, .paused])
|
state.isOneOf([.playing, .paused])
|
||||||
@ -64,4 +78,12 @@ extension MPDClient {
|
|||||||
func sendSeekCurrentSong(timeInSeconds: Float) {
|
func sendSeekCurrentSong(timeInSeconds: Float) {
|
||||||
mpd_run_seek_current(self.connection, timeInSeconds, false)
|
mpd_run_seek_current(self.connection, timeInSeconds, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sendShuffleState(shuffleState: Bool) {
|
||||||
|
mpd_run_random(self.connection, shuffleState)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendRepeatState(repeatState: Bool) {
|
||||||
|
mpd_run_repeat(self.connection, repeatState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,9 @@ extension MPDClient {
|
|||||||
case stop
|
case stop
|
||||||
case seekCurrentSong
|
case seekCurrentSong
|
||||||
|
|
||||||
|
case setShuffleState
|
||||||
|
case setRepeatState
|
||||||
|
|
||||||
// Database commands
|
// Database commands
|
||||||
case updateDatabase
|
case updateDatabase
|
||||||
|
|
||||||
|
|||||||
@ -222,9 +222,44 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
</progressIndicator>
|
</progressIndicator>
|
||||||
</toolbarItem>
|
</toolbarItem>
|
||||||
|
<toolbarItem implicitItemIdentifier="A07933B6-4770-4B28-856B-B98DB5C6EB55" label="" paletteLabel="Shuffle" image="shuffleButton" selectable="YES" id="gF4-mh-Nzd">
|
||||||
|
<nil key="toolTip"/>
|
||||||
|
<size key="minSize" width="42" height="24"/>
|
||||||
|
<size key="maxSize" width="42" height="24"/>
|
||||||
|
<button key="view" verticalHuggingPriority="750" id="E8L-uK-XT0">
|
||||||
|
<rect key="frame" x="2" y="14" width="42" height="24"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="shuffleButton" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" inset="2" id="YNb-hd-ax8">
|
||||||
|
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="handleShuffleButton:" target="B8D-0N-5wS" id="THd-0g-fmb"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</toolbarItem>
|
||||||
|
<toolbarItem implicitItemIdentifier="4B55BD96-797D-4F30-B582-2D917823879F" label="" paletteLabel="Repeat" image="repeatButton" id="MwO-i4-shF">
|
||||||
|
<nil key="toolTip"/>
|
||||||
|
<size key="minSize" width="42" height="25"/>
|
||||||
|
<size key="maxSize" width="42" height="25"/>
|
||||||
|
<button key="view" verticalHuggingPriority="750" id="OqH-lV-sAg">
|
||||||
|
<rect key="frame" x="1" y="14" width="42" height="25"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="roundTextured" bezelStyle="texturedRounded" image="repeatButton" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" borderStyle="border" inset="2" id="1bu-vK-3Hb">
|
||||||
|
<behavior key="behavior" pushIn="YES" changeContents="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="handleRepeatButton:" target="B8D-0N-5wS" id="EN2-u4-DNl"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</toolbarItem>
|
||||||
</allowedToolbarItems>
|
</allowedToolbarItems>
|
||||||
<defaultToolbarItems>
|
<defaultToolbarItems>
|
||||||
<toolbarItem reference="p3r-ty-Pxf"/>
|
<toolbarItem reference="p3r-ty-Pxf"/>
|
||||||
|
<toolbarItem reference="mhg-16-CNM"/>
|
||||||
|
<toolbarItem reference="gF4-mh-Nzd"/>
|
||||||
|
<toolbarItem reference="MwO-i4-shF"/>
|
||||||
<toolbarItem reference="fw4-Lp-bWJ"/>
|
<toolbarItem reference="fw4-Lp-bWJ"/>
|
||||||
<toolbarItem reference="9ol-aR-mzv"/>
|
<toolbarItem reference="9ol-aR-mzv"/>
|
||||||
<toolbarItem reference="n52-8S-6kR"/>
|
<toolbarItem reference="n52-8S-6kR"/>
|
||||||
@ -239,6 +274,8 @@
|
|||||||
</window>
|
</window>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="databaseUpdatingIndicator" destination="LpV-iM-o6t" id="y0T-eR-ygY"/>
|
<outlet property="databaseUpdatingIndicator" destination="LpV-iM-o6t" id="y0T-eR-ygY"/>
|
||||||
|
<outlet property="repeatState" destination="OqH-lV-sAg" id="DPC-Ff-Srr"/>
|
||||||
|
<outlet property="shuffleState" destination="E8L-uK-XT0" id="dCF-hm-dBs"/>
|
||||||
<outlet property="trackProgress" destination="kx6-xm-TAN" id="XDv-Th-Agj"/>
|
<outlet property="trackProgress" destination="kx6-xm-TAN" id="XDv-Th-Agj"/>
|
||||||
<outlet property="trackProgressBar" destination="KMy-xf-rmN" id="a67-JU-cyQ"/>
|
<outlet property="trackProgressBar" destination="KMy-xf-rmN" id="a67-JU-cyQ"/>
|
||||||
<outlet property="trackRemaining" destination="9WZ-ij-lrb" id="0pH-d7-wvD"/>
|
<outlet property="trackRemaining" destination="9WZ-ij-lrb" id="0pH-d7-wvD"/>
|
||||||
@ -749,6 +786,8 @@
|
|||||||
<image name="nextTrackButton" width="17" height="17"/>
|
<image name="nextTrackButton" width="17" height="17"/>
|
||||||
<image name="playButton" width="17" height="17"/>
|
<image name="playButton" width="17" height="17"/>
|
||||||
<image name="prevTrackButton" width="17" height="17"/>
|
<image name="prevTrackButton" width="17" height="17"/>
|
||||||
|
<image name="repeatButton" width="17" height="17"/>
|
||||||
|
<image name="shuffleButton" width="17" height="17"/>
|
||||||
<image name="stopButton" width="17" height="17"/>
|
<image name="stopButton" width="17" height="17"/>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@ -29,3 +29,11 @@ struct MPDSeekCurrentSong: Action {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct MPDUpdateDatabaseAction: Action {}
|
struct MPDUpdateDatabaseAction: Action {}
|
||||||
|
|
||||||
|
struct MPDSetShuffleAction: Action {
|
||||||
|
let shuffleState: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MPDSetRepeatAction: Action {
|
||||||
|
let repeatState: Bool
|
||||||
|
}
|
||||||
|
|||||||
@ -24,3 +24,11 @@ struct UpdateElapsedTimeAction: Action {
|
|||||||
struct UpdateStatusAction: Action {
|
struct UpdateStatusAction: Action {
|
||||||
var status: MPDClient.MPDStatus
|
var status: MPDClient.MPDStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct UpdateShuffleAction: Action {
|
||||||
|
var shuffleState: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UpdateRepeatAction: Action {
|
||||||
|
var repeatState: Bool
|
||||||
|
}
|
||||||
|
|||||||
@ -15,6 +15,8 @@ struct PlayerState: StateType {
|
|||||||
var currentArtwork: NSImage?
|
var currentArtwork: NSImage?
|
||||||
|
|
||||||
var state: MPDClient.MPDStatus.State?
|
var state: MPDClient.MPDStatus.State?
|
||||||
|
var shuffleState: Bool = false
|
||||||
|
var repeatState: Bool = false
|
||||||
|
|
||||||
var totalTime: UInt?
|
var totalTime: UInt?
|
||||||
var elapsedTimeMs: UInt?
|
var elapsedTimeMs: UInt?
|
||||||
@ -24,6 +26,8 @@ extension PlayerState: Equatable {
|
|||||||
static func == (lhs: PlayerState, rhs: PlayerState) -> Bool {
|
static func == (lhs: PlayerState, rhs: PlayerState) -> Bool {
|
||||||
return (lhs.state == rhs.state) &&
|
return (lhs.state == rhs.state) &&
|
||||||
(lhs.totalTime == rhs.totalTime) &&
|
(lhs.totalTime == rhs.totalTime) &&
|
||||||
(lhs.elapsedTimeMs == rhs.elapsedTimeMs)
|
(lhs.elapsedTimeMs == rhs.elapsedTimeMs) &&
|
||||||
|
(lhs.shuffleState == rhs.shuffleState) &&
|
||||||
|
(lhs.repeatState == rhs.repeatState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,6 +39,12 @@ func mpdReducer(action: Action, state: MPDState?) -> MPDState {
|
|||||||
case let action as MPDSeekCurrentSong:
|
case let action as MPDSeekCurrentSong:
|
||||||
App.mpdClient.seekCurrentSong(timeInSeconds: action.timeInSeconds)
|
App.mpdClient.seekCurrentSong(timeInSeconds: action.timeInSeconds)
|
||||||
|
|
||||||
|
case let action as MPDSetShuffleAction:
|
||||||
|
App.mpdClient.setShuffleState(shuffleState: action.shuffleState)
|
||||||
|
|
||||||
|
case let action as MPDSetRepeatAction:
|
||||||
|
App.mpdClient.setRepeatState(repeatState: action.repeatState)
|
||||||
|
|
||||||
case is MPDUpdateDatabaseAction:
|
case is MPDUpdateDatabaseAction:
|
||||||
App.mpdClient.updateDatabase()
|
App.mpdClient.updateDatabase()
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,12 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
|
|||||||
case let action as UpdateElapsedTimeAction:
|
case let action as UpdateElapsedTimeAction:
|
||||||
state.elapsedTimeMs = action.elapsedTimeMs
|
state.elapsedTimeMs = action.elapsedTimeMs
|
||||||
|
|
||||||
|
case let action as UpdateShuffleAction:
|
||||||
|
state.shuffleState = action.shuffleState
|
||||||
|
|
||||||
|
case let action as UpdateRepeatAction:
|
||||||
|
state.repeatState = action.repeatState
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Resources/export/repeatButton.pdf
Normal file
BIN
Resources/export/repeatButton.pdf
Normal file
Binary file not shown.
BIN
Resources/export/repeatButton.png
Normal file
BIN
Resources/export/repeatButton.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 299 B |
BIN
Resources/export/repeatButton1.pdf
Normal file
BIN
Resources/export/repeatButton1.pdf
Normal file
Binary file not shown.
BIN
Resources/export/repeatButton1.png
Normal file
BIN
Resources/export/repeatButton1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 344 B |
BIN
Resources/export/repeatButton1@2x.png
Normal file
BIN
Resources/export/repeatButton1@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
Resources/export/repeatButton@2x.png
Normal file
BIN
Resources/export/repeatButton@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Resources/export/shuffleButton.pdf
Normal file
BIN
Resources/export/shuffleButton.pdf
Normal file
Binary file not shown.
BIN
Resources/export/shuffleButton.png
Normal file
BIN
Resources/export/shuffleButton.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 353 B |
BIN
Resources/export/shuffleButton@2x.png
Normal file
BIN
Resources/export/shuffleButton@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
Loading…
Reference in New Issue
Block a user