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

Implement top level song menu

This commit is contained in:
Daniel Barber 2019-06-07 11:19:26 -04:00
parent e05698e766
commit cd094c3a64
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
8 changed files with 163 additions and 83 deletions

View File

@ -111,6 +111,7 @@
E4B11BC22275EE410075461B /* AlbumListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BC12275EE410075461B /* AlbumListActions.swift */; };
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* MPDIdle.swift */; };
E4E7A6AD22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E7A6AC22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift */; };
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueViewController.swift */; };
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* MPDSong.swift */; };
@ -314,6 +315,7 @@
E4B11BC12275EE410075461B /* AlbumListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListActions.swift; sourceTree = "<group>"; };
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
E4C8B53D22349002009A20F3 /* MPDIdle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDIdle.swift; sourceTree = "<group>"; };
E4E7A6AC22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlbumDetailView+NSTableViewDelegate.swift"; sourceTree = "<group>"; };
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
E4E8CC912204F4B80024217A /* QueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueViewController.swift; sourceTree = "<group>"; };
E4E8CC9922075D370024217A /* MPDSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDSong.swift; sourceTree = "<group>"; };
@ -683,6 +685,7 @@
isa = PBXGroup;
children = (
E43B67A822909793007DCF55 /* AlbumDetailView.swift */,
E4E7A6AC22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift */,
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
E47E2FD4222071FD00F747E6 /* AlbumViewItem.swift */,
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */,
@ -940,6 +943,7 @@
E4EB2379220F10B8008C70C0 /* MPDPair.swift in Sources */,
E440519E227BB0720090CD6F /* UIReducer.swift in Sources */,
E43B67AA22909793007DCF55 /* AlbumDetailView.swift in Sources */,
E4E7A6AD22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift in Sources */,
E4FF7190227601B400D4C412 /* PreferencesReducer.swift in Sources */,
E4F6B463221E125900ACF42A /* QueueItem.swift in Sources */,
E4A83BF12221FAA00098FED6 /* PreferencesViewController.swift in Sources */,

View File

@ -16,6 +16,11 @@ class AppDelegate: NSObject,
MediaKeyTapDelegate {
var mediaKeyTap: MediaKeyTap?
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
@IBOutlet weak var playSelectedSongMenuItem: NSMenuItem!
@IBOutlet weak var addSelectedSongToQueueMenuItem: NSMenuItem!
func applicationDidFinishLaunching(_ aNotification: Notification) {
App.mpdServerController.connect()
instantiateUserNotificationsController()
@ -97,6 +102,11 @@ class AppDelegate: NSObject,
}
}
func setSongMenuItemsState(selectedSong: Song?) {
playSelectedSongMenuItem.isEnabled = selectedSong != nil
addSelectedSongToQueueMenuItem.isEnabled = selectedSong != nil
}
func handle(mediaKey: MediaKey, event: KeyEvent) {
switch mediaKey {
case .playPause:
@ -125,8 +135,20 @@ class AppDelegate: NSObject,
App.store.dispatch(MPDPrevTrackAction())
}
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
@IBAction func playSelectedSongAction(_ sender: NSMenuItem) {
guard let song = App.store.state.uiState.selectedSong
else { return }
let queueLength = App.store.state.queueState.queue.count
App.store.dispatch(MPDAppendTrack(song: song.mpdSong))
App.store.dispatch(MPDPlayTrack(queuePos: queueLength))
}
@IBAction func addSelectedSongToQueueAction(_ sender: NSMenuItem) {
guard let song = App.store.state.uiState.selectedSong
else { return }
App.store.dispatch(MPDAppendTrack(song: song.mpdSong))
}
}
extension AppDelegate: StoreSubscriber {
@ -135,5 +157,6 @@ extension AppDelegate: StoreSubscriber {
func newState(state: UIState) {
updateDatabaseMenuItem.isEnabled = !state.databaseUpdating
setMainWindowStateMenuItem(state: state.mainWindowState)
setSongMenuItemsState(selectedSong: state.selectedSong)
}
}

View File

@ -0,0 +1,102 @@
//
// AlbumDetailView+NSTableViewDelegate.swift
// Persephone
//
// Created by Daniel Barber on 2019/6/07.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import AppKit
extension AlbumDetailView: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let song = dataSource.albumSongs[row].song {
switch tableColumn?.identifier.rawValue {
case "trackNumberColumn":
return cellForTrackNumber(tableView, with: song)
case "trackTitleColumn":
return cellForSongTitle(tableView, with: song)
case "trackDurationColumn":
return cellForSongDuration(tableView, with: song)
default:
return nil
}
} else if let disc = dataSource.albumSongs[row].disc {
return cellForDiscNumber(tableView, with: disc)
}
return nil
}
func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
return dataSource.albumSongs[row].disc != nil
}
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
let view = AlbumDetailSongRowView()
return view
}
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
return dataSource.albumSongs[row].disc == nil
}
func tableViewSelectionDidChange(_ notification: Notification) {
guard let tableView = notification.object as? NSTableView
else { return }
if tableView.selectedRow >= 0 {
let song = dataSource.albumSongs[tableView.selectedRow].song
App.store.dispatch(SetSelectedSong(selectedSong: song))
} else {
App.store.dispatch(SetSelectedSong(selectedSong: nil))
}
}
func cellForDiscNumber(_ tableView: NSTableView, with disc: String) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .discNumber,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = "Disc \(disc)"
return cellView
}
func cellForTrackNumber(_ tableView: NSTableView, with song: Song) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .trackNumber,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = "\(song.trackNumber)."
return cellView
}
func cellForSongTitle(_ tableView: NSTableView, with song: Song) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .songTitle,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = song.title
return cellView
}
func cellForSongDuration(_ tableView: NSTableView, with song: Song) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .songDuration,
owner: self
) as! NSTableCellView
cellView.textField?.font = .timerFont
cellView.textField?.stringValue = song.duration.formattedTime
return cellView
}
}

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved.
//
import Cocoa
import AppKit
class AlbumDetailView: NSViewController {
var album: Album?
@ -60,6 +60,8 @@ class AlbumDetailView: NSViewController {
albumTitle.stringValue = ""
albumArtist.stringValue = ""
albumCoverView.image = .defaultCoverArt
App.store.dispatch(SetSelectedSong(selectedSong: nil))
}
@IBAction func playAlbum(_ sender: NSButton) {
@ -140,83 +142,3 @@ class AlbumDetailView: NSViewController {
self.album = album
}
}
extension AlbumDetailView: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
if let song = dataSource.albumSongs[row].song {
switch tableColumn?.identifier.rawValue {
case "trackNumberColumn":
return cellForTrackNumber(tableView, with: song)
case "trackTitleColumn":
return cellForSongTitle(tableView, with: song)
case "trackDurationColumn":
return cellForSongDuration(tableView, with: song)
default:
return nil
}
} else if let disc = dataSource.albumSongs[row].disc {
return cellForDiscNumber(tableView, with: disc)
}
return nil
}
func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
return dataSource.albumSongs[row].disc != nil
}
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
let view = AlbumDetailSongRowView()
return view
}
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
return dataSource.albumSongs[row].disc == nil
}
func cellForDiscNumber(_ tableView: NSTableView, with disc: String) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .discNumber,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = "Disc \(disc)"
return cellView
}
func cellForTrackNumber(_ tableView: NSTableView, with song: Song) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .trackNumber,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = "\(song.trackNumber)."
return cellView
}
func cellForSongTitle(_ tableView: NSTableView, with song: Song) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .songTitle,
owner: self
) as! NSTableCellView
cellView.textField?.stringValue = song.title
return cellView
}
func cellForSongDuration(_ tableView: NSTableView, with song: Song) -> NSView {
let cellView = tableView.makeView(
withIdentifier: .songDuration,
owner: self
) as! NSTableCellView
cellView.textField?.font = .timerFont
cellView.textField?.stringValue = song.duration.formattedTime
return cellView
}
}

View File

@ -75,6 +75,24 @@
</items>
</menu>
</menuItem>
<menuItem title="Song" id="elk-xW-VXb">
<menu key="submenu" title="Song" autoenablesItems="NO" id="RuT-kk-xTu">
<items>
<menuItem title="Play selected song" enabled="NO" id="dyT-9E-DRY">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="playSelectedSongAction:" target="Voe-Tx-rLC" id="jIo-ux-Mhr"/>
</connections>
</menuItem>
<menuItem title="Add selected song to queue" enabled="NO" id="JFH-jT-sBp">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="addSelectedSongToQueueAction:" target="Voe-Tx-rLC" id="9j9-Xd-g0D"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="aUF-d1-5bR">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
@ -132,7 +150,9 @@
</application>
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Persephone" customModuleProvider="target">
<connections>
<outlet property="addSelectedSongToQueueMenuItem" destination="JFH-jT-sBp" id="9dy-sJ-XYS"/>
<outlet property="mainWindowMenuItem" destination="1Sq-L7-znT" id="dC6-yY-6Ss"/>
<outlet property="playSelectedSongMenuItem" destination="dyT-9E-DRY" id="UY2-SN-YMF"/>
<outlet property="updateDatabaseMenuItem" destination="EJg-93-1F6" id="gMf-SQ-lyI"/>
</connections>
</customObject>

View File

@ -17,3 +17,7 @@ struct MainWindowDidMinimizeAction: Action {}
struct DatabaseUpdateStartedAction: Action {}
struct DatabaseUpdateFinishedAction: Action {}
struct SetSelectedSong: Action {
let selectedSong: Song?
}

View File

@ -27,6 +27,9 @@ func uiReducer(action: Action, state: UIState?) -> UIState {
case is DatabaseUpdateFinishedAction:
state.databaseUpdating = false
case let action as SetSelectedSong:
state.selectedSong = action.selectedSong
default:
break
}

View File

@ -18,4 +18,6 @@ struct UIState: StateType {
var mainWindowState: MainWindowState = .closed
var databaseUpdating: Bool = false
var selectedSong: Song?
}