mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Hitting the play button on an album plays the album
Had to refactor the QueueView somewhat as there was a bug that only surfaced on clearing and refilling the playlist. The bug was due to the way NSOutlineView reuses subviews.
This commit is contained in:
parent
d9d5edd364
commit
0e6b34513a
25
Persephone/Assets.xcassets/playButtonLarge.imageset/Contents.json
vendored
Normal file
25
Persephone/Assets.xcassets/playButtonLarge.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "playButtonLarge.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "playButtonLarge@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"template-rendering-intent" : "template"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge.png
vendored
Normal file
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 B |
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge@2x.png
vendored
Normal file
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 516 B |
@ -10,6 +10,7 @@ import Cocoa
|
|||||||
|
|
||||||
class AlbumItem: NSCollectionViewItem {
|
class AlbumItem: NSCollectionViewItem {
|
||||||
var observer: NSKeyValueObservation?
|
var observer: NSKeyValueObservation?
|
||||||
|
var album: MPDClient.Album?
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
@ -27,6 +28,7 @@ class AlbumItem: NSCollectionViewItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setAlbum(_ album: MPDClient.Album) {
|
func setAlbum(_ album: MPDClient.Album) {
|
||||||
|
self.album = album
|
||||||
albumTitle.stringValue = album.title
|
albumTitle.stringValue = album.title
|
||||||
albumArtist.stringValue = album.artist
|
albumArtist.stringValue = album.artist
|
||||||
}
|
}
|
||||||
@ -42,6 +44,12 @@ class AlbumItem: NSCollectionViewItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction func playAlbum(_ sender: Any) {
|
||||||
|
guard let album = album else { return }
|
||||||
|
|
||||||
|
AppDelegate.mpdClient.playAlbum(album)
|
||||||
|
}
|
||||||
|
|
||||||
@IBOutlet var albumCoverView: NSImageView!
|
@IBOutlet var albumCoverView: NSImageView!
|
||||||
@IBOutlet var albumTitle: NSTextField!
|
@IBOutlet var albumTitle: NSTextField!
|
||||||
@IBOutlet var albumArtist: NSTextField!
|
@IBOutlet var albumArtist: NSTextField!
|
||||||
|
|||||||
@ -9,7 +9,13 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
|
class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
|
||||||
var queue: [MPDClient.Song] = []
|
struct SongItem {
|
||||||
|
var song: MPDClient.Song
|
||||||
|
var queuePos: Int
|
||||||
|
var isPlaying: Bool
|
||||||
|
}
|
||||||
|
|
||||||
|
var queue: [SongItem] = []
|
||||||
var queuePos: Int = -1
|
var queuePos: Int = -1
|
||||||
|
|
||||||
var queueIcon: NSImage? = nil
|
var queueIcon: NSImage? = nil
|
||||||
@ -20,11 +26,6 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
let playIcon = NSImage(named: "playButton")
|
let playIcon = NSImage(named: "playButton")
|
||||||
let pauseIcon = NSImage(named: "pauseButton")
|
let pauseIcon = NSImage(named: "pauseButton")
|
||||||
|
|
||||||
struct SongItem {
|
|
||||||
var song: MPDClient.Song
|
|
||||||
var queuePos: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
@ -74,8 +75,14 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
|
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
self.queue = queue
|
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()
|
queueView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,16 +90,13 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
let oldSongRowPos = self.queuePos + 1
|
let oldSongRowPos = self.queuePos
|
||||||
let newSongRowPos = queuePos + 1
|
let newSongRowPos = queuePos
|
||||||
self.queuePos = queuePos
|
self.queuePos = queuePos
|
||||||
|
|
||||||
setQueuePos(oldSongRowPos: oldSongRowPos, newSongRowPos: newSongRowPos)
|
setQueuePos(oldSongRowPos: oldSongRowPos, newSongRowPos: newSongRowPos)
|
||||||
|
|
||||||
queueView.reloadData(
|
queueView.reloadData()
|
||||||
forRowIndexes: [oldSongRowPos, newSongRowPos],
|
|
||||||
columnIndexes: [0, 1]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setQueueIcon(_ state: MPDClient.Status.State) {
|
func setQueueIcon(_ state: MPDClient.Status.State) {
|
||||||
@ -107,30 +111,11 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setQueuePos(oldSongRowPos: Int, newSongRowPos: Int) {
|
func setQueuePos(oldSongRowPos: Int, newSongRowPos: Int) {
|
||||||
if oldSongRowPos > 0 {
|
if oldSongRowPos >= 0 {
|
||||||
guard let oldSongRow = queueView.rowView(atRow: oldSongRowPos, makeIfNecessary: true),
|
queue[oldSongRowPos].isPlaying = false
|
||||||
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),
|
queue[newSongRowPos].isPlaying = true
|
||||||
let newSongTitleCell = songRow.view(atColumn: 0) as? NSTableCellView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
setRowFont(rowView: songRow, font: systemFontBold)
|
|
||||||
newSongTitleCell.imageView?.image = self.queueIcon
|
|
||||||
}
|
|
||||||
|
|
||||||
func setRowFont(rowView: NSTableRowView, font: NSFont) {
|
|
||||||
guard let songTitleCell = rowView.view(atColumn: 0) as? NSTableCellView,
|
|
||||||
let songArtistCell = rowView.view(atColumn: 1) as? NSTableCellView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
songTitleCell.textField?.font = font
|
|
||||||
songArtistCell.textField?.font = font
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
||||||
@ -143,7 +128,7 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
||||||
if index > 0 {
|
if index > 0 {
|
||||||
return SongItem(song: queue[index - 1], queuePos: index - 1)
|
return queue[index - 1]
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -159,6 +144,13 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
) as! NSTableCellView
|
) as! NSTableCellView
|
||||||
|
|
||||||
cellView.textField?.stringValue = songItem.song.getTag(.title)
|
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
|
return cellView
|
||||||
case "songArtistColumn":
|
case "songArtistColumn":
|
||||||
@ -168,6 +160,11 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
) as! NSTableCellView
|
) as! NSTableCellView
|
||||||
|
|
||||||
cellView.textField?.stringValue = songItem.song.getTag(.artist)
|
cellView.textField?.stringValue = songItem.song.getTag(.artist)
|
||||||
|
if songItem.isPlaying {
|
||||||
|
cellView.textField?.font = systemFontBold
|
||||||
|
} else {
|
||||||
|
cellView.textField?.font = systemFontRegular
|
||||||
|
}
|
||||||
|
|
||||||
return cellView
|
return cellView
|
||||||
default:
|
default:
|
||||||
|
|||||||
@ -109,6 +109,27 @@ class MPDClient {
|
|||||||
idle()
|
idle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func playAlbum(_ album: Album) {
|
||||||
|
noIdle()
|
||||||
|
commandQueue.async { [unowned self] in
|
||||||
|
var songs: [Song] = []
|
||||||
|
|
||||||
|
mpd_run_clear(self.connection)
|
||||||
|
mpd_search_db_songs(self.connection, true)
|
||||||
|
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album.title)
|
||||||
|
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM_ARTIST, album.artist)
|
||||||
|
mpd_search_commit(self.connection)
|
||||||
|
while let mpdSong = mpd_recv_song(self.connection) {
|
||||||
|
songs.append(Song(mpdSong))
|
||||||
|
}
|
||||||
|
for song in songs {
|
||||||
|
mpd_run_add(self.connection, song.uri)
|
||||||
|
}
|
||||||
|
mpd_run_play_pos(self.connection, 0)
|
||||||
|
}
|
||||||
|
idle()
|
||||||
|
}
|
||||||
|
|
||||||
func queueCommand(command: Command) {
|
func queueCommand(command: Command) {
|
||||||
noIdle()
|
noIdle()
|
||||||
commandQueue.async { [unowned self] in
|
commandQueue.async { [unowned self] in
|
||||||
|
|||||||
@ -41,6 +41,10 @@ extension MPDClient {
|
|||||||
mpd_song_free(mpdSong)
|
mpd_song_free(mpdSong)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uri: UnsafePointer<Int8> {
|
||||||
|
return mpd_song_get_uri(mpdSong)
|
||||||
|
}
|
||||||
|
|
||||||
func getTag(_ tagType: TagType) -> String {
|
func getTag(_ tagType: TagType) -> String {
|
||||||
let mpdTagType = mpd_tag_type(rawValue: Int32(tagType.rawValue))
|
let mpdTagType = mpd_tag_type(rawValue: Int32(tagType.rawValue))
|
||||||
|
|
||||||
|
|||||||
@ -47,10 +47,13 @@
|
|||||||
<constraint firstAttribute="height" constant="42" id="XXC-YE-Ego"/>
|
<constraint firstAttribute="height" constant="42" id="XXC-YE-Ego"/>
|
||||||
<constraint firstAttribute="width" constant="42" id="zcR-GT-zym"/>
|
<constraint firstAttribute="width" constant="42" id="zcR-GT-zym"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
<buttonCell key="cell" type="inline" bezelStyle="inline" image="playButton" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="T1p-LZ-RpJ">
|
<buttonCell key="cell" type="inline" bezelStyle="inline" image="playButtonLarge" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="T1p-LZ-RpJ">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="smallSystemBold"/>
|
<font key="font" metaFont="smallSystemBold"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="playAlbum:" target="-2" id="gNt-Rn-kte"/>
|
||||||
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
@ -77,6 +80,6 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="blankAlbum" width="128" height="128"/>
|
<image name="blankAlbum" width="128" height="128"/>
|
||||||
<image name="playButton" width="17" height="17"/>
|
<image name="playButtonLarge" width="22" height="22"/>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
BIN
Resources/export/playButtonLarge.pdf
Normal file
BIN
Resources/export/playButtonLarge.pdf
Normal file
Binary file not shown.
BIN
Resources/export/playButtonLarge.png
Normal file
BIN
Resources/export/playButtonLarge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 B |
BIN
Resources/export/playButtonLarge@2x.png
Normal file
BIN
Resources/export/playButtonLarge@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 516 B |
Binary file not shown.
Loading…
Reference in New Issue
Block a user