1
1
mirror of https://github.com/danbee/persephone synced 2025-03-04 08:39:11 +00:00

Bunch of changes based on PR feedback

This commit is contained in:
Daniel Barber 2019-02-08 12:02:10 -05:00
parent 2c06d24276
commit 58dcab754f
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
9 changed files with 141 additions and 78 deletions

View File

@ -12,6 +12,8 @@
E40786232110CE70006887B1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E40786212110CE70006887B1 /* Main.storyboard */; };
E407862F2110CE70006887B1 /* PersephoneTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E407862E2110CE70006887B1 /* PersephoneTests.swift */; };
E407863A2110CE70006887B1 /* PersephoneUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40786392110CE70006887B1 /* PersephoneUITests.swift */; };
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B5220DD8970006D9BE /* Notification.swift */; };
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */; };
E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
@ -67,6 +69,8 @@
E40786352110CE70006887B1 /* PersephoneUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PersephoneUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E40786392110CE70006887B1 /* PersephoneUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersephoneUITests.swift; sourceTree = "<group>"; };
E407863B2110CE70006887B1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E408D3B5220DD8970006D9BE /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSUserInterfaceItemIdentifier.swift; sourceTree = "<group>"; };
E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = "<group>"; };
E41B22C421FB715A00D544F6 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
E41B22C521FB932700D544F6 /* MPDClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDClient.swift; sourceTree = "<group>"; };
@ -163,6 +167,7 @@
E407861A2110CE6E006887B1 /* Persephone */ = {
isa = PBXGroup;
children = (
E408D3B7220DE8CC0006D9BE /* Extensions */,
E4D1B598220BA3C90026F233 /* Resources */,
E4D1B597220BA3A20026F233 /* Controllers */,
E41B22C721FB966C00D544F6 /* include */,
@ -192,6 +197,15 @@
path = PersephoneUITests;
sourceTree = "<group>";
};
E408D3B7220DE8CC0006D9BE /* Extensions */ = {
isa = PBXGroup;
children = (
E408D3B5220DD8970006D9BE /* Notification.swift */,
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */,
);
path = Extensions;
sourceTree = "<group>";
};
E41B22BE21FB6B3300D544F6 /* Frameworks */ = {
isa = PBXGroup;
children = (
@ -435,6 +449,8 @@
files = (
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,

View File

@ -12,24 +12,24 @@ import mpdclient
class NotificationsController: MPDClientDelegate {
let notificationQueue = DispatchQueue.main
func didUpdateState(mpdClient: MPDClient, state: mpd_state) {
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State) {
sendNotification(
name: MPDClient.stateChanged,
userInfo: [MPDClient.stateKey: state]
name: Notification.stateChanged,
userInfo: [Notification.stateKey: state]
)
}
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song]) {
sendNotification(
name: MPDClient.queueChanged,
userInfo: [MPDClient.queueKey: queue]
name: Notification.queueChanged,
userInfo: [Notification.queueKey: queue]
)
}
func didUpdateQueuePos(mpdClient: MPDClient, song: Int32) {
func didUpdateQueuePos(mpdClient: MPDClient, song: Int) {
sendNotification(
name: MPDClient.queuePosChanged,
userInfo: [MPDClient.queuePosKey: song]
name: Notification.queuePosChanged,
userInfo: [Notification.queuePosKey: song]
)
}

View File

@ -11,13 +11,16 @@ import mpdclient
class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
var queue: [MPDClient.Song] = []
var queuePos: Int32 = -1
var queuePos: Int = -1
var queueIcon: NSImage? = nil
let systemFontRegular = NSFont.systemFont(ofSize: 13, weight: .regular)
let systemFontBold = NSFont.systemFont(ofSize: 13, weight: .bold)
let playIcon = NSImage(named: NSImage.Name("playButton"))
let pauseIcon = NSImage(named: NSImage.Name("pauseButton"))
struct SongItem {
var song: MPDClient.Song
var queuePos: Int
@ -31,34 +34,34 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
NotificationCenter.default.addObserver(
self,
selector: #selector(stateChanged(_:)),
name: MPDClient.stateChanged,
name: Notification.stateChanged,
object: AppDelegate.mpdClient
)
NotificationCenter.default.addObserver(
self,
selector: #selector(queueChanged(_:)),
name: MPDClient.queueChanged,
name: Notification.queueChanged,
object: AppDelegate.mpdClient
)
NotificationCenter.default.addObserver(
self,
selector: #selector(queuePosChanged(_:)),
name: MPDClient.queuePosChanged,
name: Notification.queuePosChanged,
object: AppDelegate.mpdClient
)
}
@objc func stateChanged(_ notification: Notification) {
guard let state = notification.userInfo?[MPDClient.stateKey] as? mpd_state
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
else { return }
setQueueIcon(state)
}
@objc func queueChanged(_ notification: Notification) {
guard let queue = notification.userInfo?[MPDClient.queueKey] as? [MPDClient.Song]
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
else { return }
self.queue = queue
@ -67,11 +70,13 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
}
@objc func queuePosChanged(_ notification: Notification) {
guard let queuePos = notification.userInfo?[MPDClient.queuePosKey] as? Int32
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
else { return }
let oldSongRowPos = Int(self.queuePos + 1)
let newSongRowPos = Int(queuePos + 1)
print(queuePos)
let oldSongRowPos = self.queuePos + 1
let newSongRowPos = queuePos + 1
self.queuePos = queuePos
setQueuePos(oldSongRowPos: oldSongRowPos, newSongRowPos: newSongRowPos)
@ -82,12 +87,12 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
)
}
func setQueueIcon(_ state: mpd_state) {
func setQueueIcon(_ state: MPDClient.Status.State) {
switch state {
case MPD_STATE_PLAY:
self.queueIcon = NSImage(named: NSImage.Name("playButton"))
case MPD_STATE_PAUSE:
self.queueIcon = NSImage(named: NSImage.Name("pauseButton"))
case .playing:
self.queueIcon = playIcon
case .paused:
self.queueIcon = pauseIcon
default:
self.queueIcon = nil
}
@ -95,18 +100,16 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
func setQueuePos(oldSongRowPos: Int, newSongRowPos: Int) {
if oldSongRowPos > 0 {
guard let oldSongRow = queueView.rowView(atRow: oldSongRowPos, makeIfNecessary: true)
else { return }
guard let oldSongTitleCell = oldSongRow.view(atColumn: 0) as? NSTableCellView
guard let oldSongRow = queueView.rowView(atRow: oldSongRowPos, makeIfNecessary: true),
let oldSongTitleCell = oldSongRow.view(atColumn: 0) as? NSTableCellView
else { return }
setRowFont(rowView: oldSongRow, font: systemFontRegular)
oldSongTitleCell.imageView?.image = nil
}
guard let songRow = queueView.rowView(atRow: newSongRowPos, makeIfNecessary: true)
else { return }
guard let newSongTitleCell = songRow.view(atColumn: 0) as? NSTableCellView
guard let songRow = queueView.rowView(atRow: newSongRowPos, makeIfNecessary: true),
let newSongTitleCell = songRow.view(atColumn: 0) as? NSTableCellView
else { return }
setRowFont(rowView: songRow, font: systemFontBold)
@ -114,9 +117,8 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
}
func setRowFont(rowView: NSTableRowView, font: NSFont) {
guard let songTitleCell = rowView.view(atColumn: 0) as? NSTableCellView
else { return }
guard let songArtistCell = rowView.view(atColumn: 1) as? NSTableCellView
guard let songTitleCell = rowView.view(atColumn: 0) as? NSTableCellView,
let songArtistCell = rowView.view(atColumn: 1) as? NSTableCellView
else { return }
songTitleCell.textField?.font = font
@ -144,7 +146,7 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
switch tableColumn?.identifier.rawValue {
case "songTitleColumn":
let cellView = outlineView.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("songTitleCell"),
withIdentifier: .queueSongTitle,
owner: self
) as! NSTableCellView
@ -153,7 +155,7 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
return cellView
case "songArtistColumn":
let cellView = outlineView.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("songArtistCell"),
withIdentifier: .queueSongArtist,
owner: self
) as! NSTableCellView
@ -166,7 +168,7 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
} else {
if tableColumn?.identifier.rawValue == "songTitleColumn" {
let cellView = outlineView.makeView(
withIdentifier: NSUserInterfaceItemIdentifier("queueHeadingCell"),
withIdentifier: .queueHeading,
owner: self
) as! NSTableCellView

View File

@ -7,7 +7,6 @@
//
import Cocoa
import mpdclient
class WindowController: NSWindowController {
enum TransportAction: Int {
@ -17,6 +16,9 @@ class WindowController: NSWindowController {
case nextTrack = 3
}
let playIcon = NSImage(named: NSImage.Name("playButton"))
let pauseIcon = NSImage(named: NSImage.Name("pauseButton"))
override func windowDidLoad() {
super.windowDidLoad()
window?.titleVisibility = .hidden
@ -24,28 +26,28 @@ class WindowController: NSWindowController {
NotificationCenter.default.addObserver(
self,
selector: #selector(stateChanged(_:)),
name: MPDClient.stateChanged,
name: Notification.stateChanged,
object: AppDelegate.mpdClient
)
}
@objc func stateChanged(_ notification: Notification) {
guard let state = notification.userInfo?[MPDClient.stateKey] as? mpd_state
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
else { return }
setTransportControlState(state)
}
func setTransportControlState(_ state: mpd_state) {
transportControls.setEnabled([MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(state), forSegment: 0)
transportControls.setEnabled([MPD_STATE_PLAY, MPD_STATE_PAUSE, MPD_STATE_STOP].contains(state), forSegment: 1)
transportControls.setEnabled([MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(state), forSegment: 2)
transportControls.setEnabled([MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(state), forSegment: 3)
func setTransportControlState(_ state: MPDClient.Status.State) {
transportControls.setEnabled(state.isOneOf([.playing, .paused]), forSegment: 0)
transportControls.setEnabled(state.isOneOf([.playing, .paused, .stopped]), forSegment: 1)
transportControls.setEnabled(state.isOneOf([.playing, .paused]), forSegment: 2)
transportControls.setEnabled(state.isOneOf([.playing, .paused]), forSegment: 3)
if [MPD_STATE_PAUSE, MPD_STATE_STOP, MPD_STATE_UNKNOWN].contains(state) {
transportControls.setImage(NSImage(named: NSImage.Name("playButton")), forSegment: 1)
if state.isOneOf([.paused, .stopped, .unknown]) {
transportControls.setImage(playIcon, forSegment: 1)
} else {
transportControls.setImage(NSImage(named: NSImage.Name("pauseButton")), forSegment: 1)
transportControls.setImage(pauseIcon, forSegment: 1)
}
}

View File

@ -0,0 +1,18 @@
//
// NSUserInterfaceItemIdentifier.swift
// Persephone
//
// Created by Daniel Barber on 2019/2/08.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Cocoa
extension NSUserInterfaceItemIdentifier {
static let queueSongTitleColumn = NSUserInterfaceItemIdentifier("songTitleColumn")
static let queueSongArtistColumn = NSUserInterfaceItemIdentifier("songArtistColumn")
static let queueHeading = NSUserInterfaceItemIdentifier("queueHeadingCell")
static let queueSongArtist = NSUserInterfaceItemIdentifier("songArtistCell")
static let queueSongTitle = NSUserInterfaceItemIdentifier("songTitleCell")
}

View File

@ -0,0 +1,19 @@
//
// Notification.swift
// Persephone
//
// Created by Daniel Barber on 2019/2/08.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Foundation
extension Notification {
static let stateChanged = Notification.Name("MPDClientStateChanged")
static let queueChanged = Notification.Name("MPDClientQueueChanged")
static let queuePosChanged = Notification.Name("MPDClientQueuePosChanged")
static let stateKey = "state"
static let queueKey = "queue"
static let queuePosKey = "song"
}

View File

@ -11,19 +11,12 @@ import mpdclient
class MPDClient {
var delegate: MPDClientDelegate?
static let stateChanged = Notification.Name("MPDClientStateChanged")
static let queueChanged = Notification.Name("MPDClientQueueChanged")
static let queuePosChanged = Notification.Name("MPDClientQueuePosChanged")
static let stateKey = "state"
static let queueKey = "queue"
static let queuePosKey = "song"
let HOST = "localhost"
let PORT: UInt32 = 6600
private var connection: OpaquePointer?
var status: Status?
private var status: Status?
private var queue: [Song] = []
private let commandQueue = DispatchQueue(label: "commandQueue")
@ -32,13 +25,6 @@ class MPDClient {
case prevTrack, nextTrack, playPause, stop, fetchStatus, fetchQueue
}
enum State: UInt32 {
case unknown = 0
case stopped = 1
case playing = 2
case paused = 3
}
struct Idle: OptionSet {
let rawValue: UInt32
@ -71,9 +57,9 @@ class MPDClient {
fetchQueue()
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state())
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state)
self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue)
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song())
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
idle()
}
@ -145,15 +131,19 @@ class MPDClient {
}
func sendNextTrack() {
if [MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(status?.state()) {
mpd_run_next(connection)
}
guard let state = status?.state,
state.isOneOf([.playing, .paused])
else { return }
mpd_run_next(connection)
}
func sendPreviousTrack() {
if [MPD_STATE_PLAY, MPD_STATE_PAUSE].contains(status?.state()) {
mpd_run_previous(connection)
}
guard let state = status?.state,
state.isOneOf([.playing, .paused])
else { return }
mpd_run_previous(connection)
}
func sendStop() {
@ -161,7 +151,7 @@ class MPDClient {
}
func sendPlay() {
if status?.state() == MPD_STATE_STOP {
if status?.state == .stopped {
mpd_run_play(connection)
} else {
mpd_run_toggle_pause(connection)
@ -190,8 +180,8 @@ class MPDClient {
}
if mpdIdle.contains(.player) {
self.fetchStatus()
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state())
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song())
self.delegate?.didUpdateState(mpdClient: self, state: self.status!.state)
self.delegate?.didUpdateQueuePos(mpdClient: self, song: self.status!.song)
}
if !mpdIdle.isEmpty {
self.idle()

View File

@ -9,9 +9,22 @@
import Foundation
import mpdclient
extension RawRepresentable where Self: Equatable {
func isOneOf<Options: Sequence>(_ options: Options) -> Bool where Options.Element == Self {
return options.contains(self)
}
}
extension MPDClient {
class Status {
let mpdStatus: OpaquePointer
private let mpdStatus: OpaquePointer
enum State: UInt {
case unknown = 0
case stopped = 1
case playing = 2
case paused = 3
}
init(_ mpdStatus: OpaquePointer) {
self.mpdStatus = mpdStatus
@ -21,12 +34,15 @@ extension MPDClient {
mpd_status_free(mpdStatus)
}
func state() -> mpd_state {
return mpd_status_get_state(mpdStatus)
var state: State {
let mpdState = mpd_status_get_state(mpdStatus)
return State(rawValue: UInt(mpdState.rawValue))!
}
func song() -> Int32 {
return mpd_status_get_song_pos(mpdStatus)
var song: Int {
return Int(mpd_status_get_song_pos(mpdStatus))
}
}
}

View File

@ -10,7 +10,7 @@ import Foundation
import mpdclient
protocol MPDClientDelegate {
func didUpdateState(mpdClient: MPDClient, state: mpd_state)
func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State)
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song])
func didUpdateQueuePos(mpdClient: MPDClient, song: Int32)
func didUpdateQueuePos(mpdClient: MPDClient, song: Int)
}