mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Move queue datasource and refactor view controller
This commit is contained in:
parent
4ca8fdbe1a
commit
b709d6c98c
@ -36,6 +36,8 @@
|
||||
E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; };
|
||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB2378220F10B8008C70C0 /* Pair.swift */; };
|
||||
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB237A220F7CF1008C70C0 /* Album.swift */; };
|
||||
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */; };
|
||||
E4F6B463221E125900ACF42A /* SongItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B462221E125900ACF42A /* SongItem.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@ -141,6 +143,8 @@
|
||||
E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
|
||||
E4EB2378220F10B8008C70C0 /* Pair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pair.swift; sourceTree = "<group>"; };
|
||||
E4EB237A220F7CF1008C70C0 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
|
||||
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueDataSource.swift; sourceTree = "<group>"; };
|
||||
E4F6B462221E125900ACF42A /* SongItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongItem.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -196,7 +200,8 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E40FE717221B48CE00A4223F /* Layouts */,
|
||||
E41EA46D221715820068EF46 /* Models */,
|
||||
E4F6B461221E124700ACF42A /* Models */,
|
||||
E4F6B45E221E117600ACF42A /* DataSources */,
|
||||
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
||||
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
||||
E4D1B598220BA3C90026F233 /* Resources */,
|
||||
@ -382,6 +387,22 @@
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E4F6B45E221E117600ACF42A /* DataSources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */,
|
||||
);
|
||||
path = DataSources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E4F6B461221E124700ACF42A /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E4F6B462221E125900ACF42A /* SongItem.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -526,6 +547,7 @@
|
||||
files = (
|
||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
||||
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
|
||||
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */,
|
||||
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
|
||||
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
|
||||
E40FE719221B48E300A4223F /* AlbumViewLayout.swift in Sources */,
|
||||
@ -533,6 +555,7 @@
|
||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */,
|
||||
E41EA46F221715910068EF46 /* Preferences.swift in Sources */,
|
||||
E4F6B463221E125900ACF42A /* SongItem.swift in Sources */,
|
||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
||||
|
||||
@ -8,29 +8,131 @@
|
||||
|
||||
import Cocoa
|
||||
|
||||
class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
|
||||
struct SongItem {
|
||||
var song: MPDClient.Song
|
||||
var queuePos: Int
|
||||
var isPlaying: Bool
|
||||
}
|
||||
|
||||
var queue: [SongItem] = []
|
||||
var queuePos: Int = -1
|
||||
|
||||
var queueIcon: NSImage? = nil
|
||||
class QueueViewController: NSViewController,
|
||||
NSOutlineViewDelegate {
|
||||
var dataSource = QueueDataSource()
|
||||
|
||||
let systemFontRegular = NSFont.systemFont(ofSize: 13, weight: .regular)
|
||||
let systemFontBold = NSFont.systemFont(ofSize: 13, weight: .bold)
|
||||
|
||||
|
||||
let playIcon = NSImage(named: "playButton")
|
||||
let pauseIcon = NSImage(named: "pauseButton")
|
||||
|
||||
@IBOutlet var queueView: NSOutlineView!
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
||||
setupNotificationObservers()
|
||||
|
||||
queueView.dataSource = dataSource
|
||||
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
||||
}
|
||||
|
||||
@IBAction func playTrack(_ sender: Any) {
|
||||
if dataSource.queuePos >= 0 {
|
||||
AppDelegate.mpdClient.playTrack(queuePos: dataSource.queuePos)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func stateChanged(_ notification: Notification) {
|
||||
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
|
||||
else { return }
|
||||
|
||||
dataSource.setQueueIcon(state)
|
||||
}
|
||||
|
||||
@objc func queueChanged(_ notification: Notification) {
|
||||
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
|
||||
else { return }
|
||||
|
||||
dataSource.updateQueue(queue)
|
||||
queueView.reloadData()
|
||||
}
|
||||
|
||||
@objc func queuePosChanged(_ notification: Notification) {
|
||||
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
||||
else { return }
|
||||
|
||||
dataSource.setQueuePos(queuePos)
|
||||
|
||||
queueView.reloadData()
|
||||
}
|
||||
|
||||
func outlineView(
|
||||
_ outlineView: NSOutlineView,
|
||||
selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet
|
||||
) -> IndexSet {
|
||||
if proposedSelectionIndexes.contains(0) {
|
||||
return IndexSet()
|
||||
} else {
|
||||
return proposedSelectionIndexes
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
||||
if let songItem = item as? SongItem {
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "songTitleColumn":
|
||||
return cellForSongTitle(outlineView, with: songItem)
|
||||
case "songArtistColumn":
|
||||
return cellForSongArtist(outlineView, with: songItem)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} else if tableColumn?.identifier.rawValue == "songTitleColumn" {
|
||||
return cellForQueueHeading(outlineView)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func cellForSongTitle(_ outlineView: NSOutlineView, with songItem: SongItem) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongTitle,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = songItem.song.getTag(.title)
|
||||
if songItem.isPlaying {
|
||||
cellView.textField?.font = systemFontBold
|
||||
cellView.imageView?.image = dataSource.queueIcon
|
||||
} else {
|
||||
cellView.textField?.font = systemFontRegular
|
||||
cellView.imageView?.image = nil
|
||||
}
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongArtist(_ outlineView: NSOutlineView, with songItem: SongItem) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongArtist,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = songItem.song.getTag(.artist)
|
||||
if songItem.isPlaying {
|
||||
cellView.textField?.font = systemFontBold
|
||||
} else {
|
||||
cellView.textField?.font = systemFontRegular
|
||||
}
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForQueueHeading(_ outlineView: NSOutlineView) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueHeading,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = "QUEUE"
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func setupNotificationObservers() {
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(stateChanged(_:)),
|
||||
@ -51,165 +153,5 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
||||
name: Notification.queuePosChanged,
|
||||
object: AppDelegate.mpdClient
|
||||
)
|
||||
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(clearQueue(_:)),
|
||||
name: Notification.willDisconnect,
|
||||
object: AppDelegate.mpdClient
|
||||
)
|
||||
}
|
||||
|
||||
@IBAction func playTrack(_ sender: Any) {
|
||||
guard let view = sender as? NSOutlineView
|
||||
else { return }
|
||||
|
||||
let queuePos = view.selectedRow - 1
|
||||
|
||||
if queuePos >= 0 {
|
||||
AppDelegate.mpdClient.playTrack(queuePos: queuePos)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func stateChanged(_ notification: Notification) {
|
||||
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?[Notification.queueKey] as? [MPDClient.Song]
|
||||
else { return }
|
||||
|
||||
var newQueue: [SongItem] = []
|
||||
|
||||
for (index, mpdSong) in queue.enumerated() {
|
||||
let songItem = SongItem(song: mpdSong, queuePos: index, isPlaying: index == queuePos)
|
||||
newQueue.append(songItem)
|
||||
}
|
||||
|
||||
self.queue = newQueue
|
||||
queueView.reloadData()
|
||||
}
|
||||
|
||||
@objc func queuePosChanged(_ notification: Notification) {
|
||||
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
||||
else { return }
|
||||
|
||||
let oldSongRowPos = self.queuePos
|
||||
let newSongRowPos = queuePos
|
||||
self.queuePos = queuePos
|
||||
|
||||
setQueuePos(oldSongRowPos: oldSongRowPos, newSongRowPos: newSongRowPos)
|
||||
|
||||
queueView.reloadData()
|
||||
}
|
||||
|
||||
@objc func clearQueue(_ notification: Notification) {
|
||||
self.queue = []
|
||||
|
||||
queueView.reloadData()
|
||||
}
|
||||
|
||||
func setQueueIcon(_ state: MPDClient.Status.State) {
|
||||
switch state {
|
||||
case .playing:
|
||||
self.queueIcon = playIcon
|
||||
case .paused:
|
||||
self.queueIcon = pauseIcon
|
||||
default:
|
||||
self.queueIcon = nil
|
||||
}
|
||||
}
|
||||
|
||||
func setQueuePos(oldSongRowPos: Int, newSongRowPos: Int) {
|
||||
if oldSongRowPos >= 0 {
|
||||
queue[oldSongRowPos].isPlaying = false
|
||||
}
|
||||
if newSongRowPos >= 0 {
|
||||
queue[newSongRowPos].isPlaying = true
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
||||
return queue.count + 1
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
||||
if index > 0 {
|
||||
return queue[index - 1]
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
||||
if let songItem = item as? SongItem {
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "songTitleColumn":
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongTitle,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = songItem.song.getTag(.title)
|
||||
if songItem.isPlaying {
|
||||
cellView.textField?.font = systemFontBold
|
||||
cellView.imageView?.image = self.queueIcon
|
||||
} else {
|
||||
cellView.textField?.font = systemFontRegular
|
||||
cellView.imageView?.image = nil
|
||||
}
|
||||
|
||||
return cellView
|
||||
case "songArtistColumn":
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongArtist,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = songItem.song.getTag(.artist)
|
||||
if songItem.isPlaying {
|
||||
cellView.textField?.font = systemFontBold
|
||||
} else {
|
||||
cellView.textField?.font = systemFontRegular
|
||||
}
|
||||
|
||||
return cellView
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
if tableColumn?.identifier.rawValue == "songTitleColumn" {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueHeading,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = "QUEUE"
|
||||
|
||||
return cellView
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(
|
||||
_ outlineView: NSOutlineView,
|
||||
selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet
|
||||
) -> IndexSet {
|
||||
if proposedSelectionIndexes.contains(0) {
|
||||
return IndexSet()
|
||||
} else {
|
||||
return proposedSelectionIndexes
|
||||
}
|
||||
}
|
||||
|
||||
@IBOutlet var queueView: NSOutlineView!
|
||||
}
|
||||
|
||||
70
Persephone/DataSources/QueueDataSource.swift
Normal file
70
Persephone/DataSources/QueueDataSource.swift
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// QueueDataSource.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/2/20.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
||||
var queue: [SongItem] = []
|
||||
var queuePos: Int = -1
|
||||
|
||||
var queueIcon: NSImage? = nil
|
||||
|
||||
let playIcon = NSImage(named: "playButton")
|
||||
let pauseIcon = NSImage(named: "pauseButton")
|
||||
|
||||
func updateQueue(_ queue: [MPDClient.Song]) {
|
||||
var newQueue: [SongItem] = []
|
||||
|
||||
for (index, mpdSong) in queue.enumerated() {
|
||||
let songItem = SongItem(song: mpdSong, queuePos: index, isPlaying: index == queuePos)
|
||||
newQueue.append(songItem)
|
||||
}
|
||||
|
||||
self.queue = newQueue
|
||||
}
|
||||
|
||||
func setQueuePos(_ queuePos: Int) {
|
||||
let oldSongRowPos = self.queuePos
|
||||
let newSongRowPos = queuePos
|
||||
self.queuePos = queuePos
|
||||
|
||||
if oldSongRowPos >= 0 {
|
||||
queue[oldSongRowPos].isPlaying = false
|
||||
}
|
||||
if newSongRowPos >= 0 {
|
||||
queue[newSongRowPos].isPlaying = true
|
||||
}
|
||||
}
|
||||
|
||||
func setQueueIcon(_ state: MPDClient.Status.State) {
|
||||
switch state {
|
||||
case .playing:
|
||||
queueIcon = playIcon
|
||||
case .paused:
|
||||
queueIcon = pauseIcon
|
||||
default:
|
||||
queueIcon = nil
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
||||
return queue.count + 1
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
||||
if index > 0 {
|
||||
return queue[index - 1]
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
15
Persephone/Models/SongItem.swift
Normal file
15
Persephone/Models/SongItem.swift
Normal file
@ -0,0 +1,15 @@
|
||||
//
|
||||
// SongItem.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/2/20.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
struct SongItem {
|
||||
var song: MPDClient.Song
|
||||
var queuePos: Int
|
||||
var isPlaying: Bool
|
||||
}
|
||||
@ -972,7 +972,6 @@
|
||||
</tableColumns>
|
||||
<connections>
|
||||
<action trigger="doubleAction" selector="playTrack:" target="KIP-rq-4dM" id="opa-6G-OW0"/>
|
||||
<outlet property="dataSource" destination="KIP-rq-4dM" id="K1Q-7o-xXW"/>
|
||||
<outlet property="delegate" destination="KIP-rq-4dM" id="60F-6x-bUE"/>
|
||||
</connections>
|
||||
</outlineView>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user