1
1
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:
Daniel Barber 2019-02-17 17:43:19 -05:00
parent d9d5edd364
commit 0e6b34513a
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
12 changed files with 96 additions and 38 deletions

View 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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

View File

@ -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!

View File

@ -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:

View File

@ -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

View File

@ -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))

View File

@ -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>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 516 B

Binary file not shown.