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

Redesign queue view

* Add cover art for each track
* Stack song title and artist
* Add song duration
* Redesign the dragged image view to match
This commit is contained in:
Daniel Barber 2020-01-22 22:23:59 -05:00
parent 6458b7402b
commit a8987029f5
Signed by: danbarber
GPG Key ID: 931D8112E0103DD8
33 changed files with 512 additions and 266 deletions

View File

@ -18,7 +18,6 @@
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C1220E134F0006D9BE /* AlbumViewController.swift */; };
E408D3CB220E341D0006D9BE /* AlbumViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */; };
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE71A221B904300A4223F /* NSEvent.swift */; };
E4120D6C22AD8139004CB1F8 /* QueueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4120D6B22AD8139004CB1F8 /* QueueView.swift */; };
E419E2872249B96600216A8C /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E419E2862249B96600216A8C /* Song.swift */; };
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
E41E52FD223BF87300173814 /* MPDClient+Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E52FC223BF87300173814 /* MPDClient+Connection.swift */; };
@ -30,7 +29,7 @@
E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E5308223C020400173814 /* MPDClient+Command.swift */; };
E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E530A223C033700173814 /* MPDClient+Album.swift */; };
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41EA46B221636AF0068EF46 /* GeneralPrefsViewController.swift */; };
E4235640228623D2001216D6 /* QueueSongTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E423563F228623D2001216D6 /* QueueSongTitleView.swift */; };
E4235640228623D2001216D6 /* QueueSongInfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E423563F228623D2001216D6 /* QueueSongInfoView.swift */; };
E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = E42410B52241B956005ED6DF /* MPDClient+Database.swift */; };
E42A4D4F22E20D7D001C6CAD /* MPDTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = E42A4D4E22E20D7D001C6CAD /* MPDTag.swift */; };
E42A4D5122E2167E001C6CAD /* MPDClient+Songs.swift in Sources */ = {isa = PBXBuildFile; fileRef = E42A4D5022E2167E001C6CAD /* MPDClient+Songs.swift */; };
@ -99,6 +98,7 @@
E4B11BBE2275EDAA0075461B /* PlayerActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BBD2275EDAA0075461B /* PlayerActions.swift */; };
E4B11BC02275EE150075461B /* QueueActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BBF2275EE150075461B /* QueueActions.swift */; };
E4B11BC22275EE410075461B /* AlbumListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BC12275EE410075461B /* AlbumListActions.swift */; };
E4B3DF6523D66A4400728F6B /* QueueSongCoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */; };
E4B5AE7E22F4C49600CCEC65 /* MPDServerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B5AE7D22F4C49600CCEC65 /* MPDServerDelegate.swift */; };
E4BBD2F323357C0700702C16 /* ArtistListState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BBD2F223357C0700702C16 /* ArtistListState.swift */; };
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
@ -183,7 +183,6 @@
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewController.swift; sourceTree = "<group>"; };
E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumViewItem.xib; sourceTree = "<group>"; };
E40FE71A221B904300A4223F /* NSEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEvent.swift; sourceTree = "<group>"; };
E4120D6B22AD8139004CB1F8 /* QueueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueView.swift; sourceTree = "<group>"; };
E419E2862249B96600216A8C /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.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>"; };
@ -232,7 +231,7 @@
E41E5308223C020400173814 /* MPDClient+Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Command.swift"; sourceTree = "<group>"; };
E41E530A223C033700173814 /* MPDClient+Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Album.swift"; sourceTree = "<group>"; };
E41EA46B221636AF0068EF46 /* GeneralPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPrefsViewController.swift; sourceTree = "<group>"; };
E423563F228623D2001216D6 /* QueueSongTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueSongTitleView.swift; sourceTree = "<group>"; };
E423563F228623D2001216D6 /* QueueSongInfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueSongInfoView.swift; sourceTree = "<group>"; };
E42410B52241B956005ED6DF /* MPDClient+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Database.swift"; sourceTree = "<group>"; };
E42A4D4E22E20D7D001C6CAD /* MPDTag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDTag.swift; sourceTree = "<group>"; };
E42A4D5022E2167E001C6CAD /* MPDClient+Songs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Songs.swift"; sourceTree = "<group>"; };
@ -293,6 +292,7 @@
E4B11BBD2275EDAA0075461B /* PlayerActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerActions.swift; sourceTree = "<group>"; };
E4B11BBF2275EE150075461B /* QueueActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueActions.swift; sourceTree = "<group>"; };
E4B11BC12275EE410075461B /* AlbumListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListActions.swift; sourceTree = "<group>"; };
E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueSongCoverView.swift; sourceTree = "<group>"; };
E4B5AE7D22F4C49600CCEC65 /* MPDServerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDServerDelegate.swift; sourceTree = "<group>"; };
E4BBD2F223357C0700702C16 /* ArtistListState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArtistListState.swift; sourceTree = "<group>"; };
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
@ -537,8 +537,8 @@
children = (
E4B11BB7227538FA0075461B /* CurrentCoverArtView.swift */,
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */,
E423563F228623D2001216D6 /* QueueSongTitleView.swift */,
E4120D6B22AD8139004CB1F8 /* QueueView.swift */,
E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */,
E423563F228623D2001216D6 /* QueueSongInfoView.swift */,
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
E4D3BFA522B419C000C56F48 /* QueueViewController+NSOutlineViewDelegate.swift */,
);
@ -935,7 +935,7 @@
E442CCCD2347E73C00004E0C /* Artist.swift in Sources */,
E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */,
E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */,
E4235640228623D2001216D6 /* QueueSongTitleView.swift in Sources */,
E4235640228623D2001216D6 /* QueueSongInfoView.swift in Sources */,
E451E36E22BD2501008BE9B2 /* DraggedSong.swift in Sources */,
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */,
E4B11BC02275EE150075461B /* QueueActions.swift in Sources */,
@ -971,6 +971,7 @@
E44051A0227BB0AB0090CD6F /* UIState.swift in Sources */,
E4FF718E2276010E00D4C412 /* PreferencesState.swift in Sources */,
E439109822640213002982E9 /* SongNotifierService.swift in Sources */,
E4B3DF6523D66A4400728F6B /* QueueSongCoverView.swift in Sources */,
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
E4B11B75226CC4D30075461B /* QueueReducer.swift in Sources */,
E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */,
@ -985,7 +986,6 @@
E4B5AE7E22F4C49600CCEC65 /* MPDServerDelegate.swift in Sources */,
E4B11BB8227538FA0075461B /* CurrentCoverArtView.swift in Sources */,
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */,
E4120D6C22AD8139004CB1F8 /* QueueView.swift in Sources */,
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */,
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
E47E2FD5222071FD00F747E6 /* AlbumViewItem.swift in Sources */,

View File

@ -0,0 +1,54 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "pauseButton.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "pauseButtonWhite.png",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "pauseButton@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "pauseButtonWhite@2x.png",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
},
{
"idiom" : "universal",
"scale" : "3x",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
]
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

View File

@ -0,0 +1,54 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "playButton.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "playButtonWhite.png",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "playButton@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "playButtonWhite@2x.png",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
},
{
"idiom" : "universal",
"scale" : "3x",
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
]
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

View File

@ -145,6 +145,18 @@ class AlbumDetailView: NSViewController {
.scaleFactor(2),
]
)
cacheSmallCover(provider: provider)
}
func cacheSmallCover(provider: ImageDataProvider) {
_ = KingfisherManager.shared.retrieveImage(
with: .provider(provider),
options: [
.processor(DownsamplingImageProcessor(size: .queueSongCoverSize)),
.scaleFactor(2),
]
) { result in }
}
func setAppearance() {

View File

@ -49,7 +49,8 @@ class AlbumTracksDataSource: NSObject, NSTableViewDataSource {
draggedSong: DraggedSong(
type: .albumSongItem(song.mpdSong.uriString),
title: song.title,
artist: song.artist
artist: song.artist,
cover: song.album.coverArtFilePath
),
ofType: .songPasteboardType
)
@ -68,12 +69,20 @@ class AlbumTracksDataSource: NSObject, NSTableViewDataSource {
) { draggingItem, index, stop in
guard let item = draggingItem.item as? NSPasteboardItem,
let draggedSong = item.draggedSong(forType: .songPasteboardType),
case let (title?, artist?) = (draggedSong.title, draggedSong.artist)
case let (title?, artist?, cover?) = (
draggedSong.title,
draggedSong.artist,
draggedSong.cover
)
else { return }
draggingItem.imageComponentsProvider = {
let component = NSDraggingImageComponent(key: NSDraggingItem.ImageComponentKey.icon)
let draggedSongView = DraggedSongView(title: title, artist: artist)
let draggedSongView = DraggedSongView(
title: title,
artist: artist,
cover: cover
)
component.contents = draggedSongView.view.image()
component.frame = NSRect(origin: CGPoint(), size: draggedSongView.view.image().size)

View File

@ -15,16 +15,16 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
func setQueueIcon(_ state: QueueState) {
switch state.state {
case .playing?:
queueIcon = .playIcon
queueIcon = .queuePlayIcon
case .paused?:
queueIcon = .pauseIcon
queueIcon = .queuePauseIcon
default:
queueIcon = nil
}
}
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
return queue.count + 1
return queue.count
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
@ -32,11 +32,7 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
if index > 0 {
return queue[index - 1]
} else {
return ""
}
return queue[index]
}
func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? {
@ -47,14 +43,15 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
draggedSong: DraggedSong(
type: .queueItem(queueItem.queuePos),
title: queueItem.song.title,
artist: queueItem.song.artist
artist: queueItem.song.artist,
cover: queueItem.song.album.coverArtFilePath
),
ofType: .songPasteboardType
)
}
func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
var newQueuePos = index - 1
var newQueuePos = index
guard newQueuePos >= 0,
let draggingTypes = info.draggingPasteboard.types
@ -84,7 +81,7 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
}
func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
var newQueuePos = index - 1
var newQueuePos = index
guard let draggingTypes = info.draggingPasteboard.types
else { return false }
@ -131,12 +128,20 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
guard let item = draggingItem.item as? NSPasteboardItem,
let data = item.data(forType: .songPasteboardType),
let draggedSong = try? PropertyListDecoder().decode(DraggedSong.self, from: data),
case let (title?, artist?) = (draggedSong.title, draggedSong.artist)
case let (title?, artist?, cover?) = (
draggedSong.title,
draggedSong.artist,
draggedSong.cover
)
else { return }
draggingItem.imageComponentsProvider = {
let component = NSDraggingImageComponent(key: NSDraggingItem.ImageComponentKey.icon)
let draggedSongView = DraggedSongView(title: title, artist: artist)
let draggedSongView = DraggedSongView(
title: title,
artist: artist,
cover: cover
)
let view = draggedSongView.view
let image = view.image()

View File

@ -0,0 +1,86 @@
//
// QueueSongCoverView.swift
// Persephone
//
// Created by Daniel Barber on 1/20/20.
// Copyright © 2020 Dan Barber. All rights reserved.
//
import AppKit
import Kingfisher
class QueueSongCoverView: NSTableCellView {
@IBOutlet var queueSongCover: NSImageView!
@IBOutlet var queueSongButton: NSButton!
let playingFilters = [
CIFilter(name: "CIExposureAdjust", parameters: ["inputEV": -2])!
]
var isPlaying: Bool = false
override func viewDidMoveToSuperview() {
super.viewDidMoveToSuperview()
queueSongCover.wantsLayer = true
queueSongCover.layer?.backgroundColor = CGColor.black
queueSongCover.layer?.cornerRadius = 2
queueSongCover.layer?.borderWidth = 1
queueSongCover.layer?.masksToBounds = true
queueSongButton.wantsLayer = true
setAppearance()
if isPlaying {
queueSongCover.layer?.filters = playingFilters
} else {
queueSongCover.layer?.filters = nil
}
}
override func prepareForReuse() {
super.prepareForReuse()
queueSongCover.image = .defaultCoverArt
}
func setAppearance() {
guard let viewLayer = queueSongCover.layer
else { return }
if #available(OSX 10.14, *) {
let darkMode = NSApp.effectiveAppearance.bestMatch(from:
[.darkAqua, .aqua]) == .darkAqua
viewLayer.borderColor = darkMode ? .albumBorderColorDark : .albumBorderColorLight
} else {
viewLayer.borderColor = .albumBorderColorLight
}
}
func setSong(_ queueItem: QueueItem, queueIcon: NSImage?) {
guard let imagePath = queueItem.song.album.coverArtFilePath
else { return }
isPlaying = queueItem.isPlaying
let imageURL = URL(fileURLWithPath: imagePath)
let provider = LocalFileImageDataProvider(fileURL: imageURL)
queueSongCover.kf.setImage(
with: .provider(provider),
placeholder: NSImage.defaultCoverArt,
options: [
.processor(DownsamplingImageProcessor(size: .queueSongCoverSize)),
.scaleFactor(2),
]
)
if isPlaying && queueIcon != nil {
queueSongCover.layer?.filters = playingFilters
queueSongButton.image = queueIcon
} else {
queueSongCover.layer?.filters = nil
queueSongButton.image = nil
}
}
}

View File

@ -8,23 +8,18 @@
import AppKit
class QueueSongTitleView: NSTableCellView {
@IBOutlet var queuePlayerStateImage: NSImageView!
@IBOutlet var queuePosition: NSTextField!
class QueueSongInfoView: NSTableCellView {
@IBOutlet var queueSongTitle: NSTextField!
@IBOutlet var queueSongArtist: NSTextField!
func setQueueSong(_ queueItem: QueueItem, queueIcon: NSImage?) {
queuePosition?.font = .timerFont
func setSong(_ queueItem: QueueItem, queueIcon: NSImage?) {
queueSongTitle?.stringValue = queueItem.song.title
queueSongArtist?.stringValue = queueItem.song.artist
if queueItem.isPlaying && queueIcon != nil {
queueSongTitle?.font = .systemFontBold
queuePlayerStateImage?.image = queueIcon
queuePosition?.stringValue = ""
} else {
queueSongTitle?.font = .systemFontRegular
queuePlayerStateImage?.image = nil
queuePosition?.stringValue = "\(queueItem.queuePos + 1)."
}
}
}

View File

@ -1,23 +0,0 @@
//
// QueueView.swift
// Persephone
//
// Created by Daniel Barber on 2019/6/09.
// Copyright © 2019 Dan Barber. All rights reserved.
//
import AppKit
class QueueView: NSOutlineView {
override func menu(for event: NSEvent) -> NSMenu? {
let point = convert(event.locationInWindow, from: nil)
let currentRow = row(at: point)
if currentRow > 0 {
return super.menu(for: event)
} else {
return nil
}
}
}

View File

@ -9,78 +9,59 @@
import AppKit
extension QueueViewController: NSOutlineViewDelegate {
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 queueItem = item as? QueueItem {
switch tableColumn?.identifier.rawValue {
case "songTitleColumn":
return cellForSongTitle(outlineView, with: queueItem)
case "songArtistColumn":
return cellForSongArtist(outlineView, with: queueItem)
case "songCoverColumn":
return cellForSongCover(outlineView, with: queueItem)
case "songInfoColumn":
return cellForSongInfo(outlineView, with: queueItem)
case "songDurationColumn":
return cellForSongDuration(outlineView, with: queueItem)
default:
return nil
}
} else if tableColumn?.identifier.rawValue == "songTitleColumn" {
return cellForQueueHeading(outlineView)
} else {
return nil
}
}
func outlineViewSelectionDidChange(_ notification: Notification) {
if queueView.selectedRow >= 1 {
let queueItem = dataSource.queue[queueView.selectedRow - 1]
let queueItem = dataSource.queue[queueView.selectedRow]
App.store.dispatch(SetSelectedQueueItem(selectedQueueItem: queueItem))
} else {
App.store.dispatch(SetSelectedQueueItem(selectedQueueItem: nil))
}
App.store.dispatch(SetSelectedQueueItem(selectedQueueItem: queueItem))
}
func cellForSongTitle(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
let cellView = outlineView.makeView(
withIdentifier: .queueSongTitle,
func cellForSongCover(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
let cellView = outlineView.makeView(
withIdentifier: .queueSongCover,
owner: self
) as! QueueSongTitleView
) as! QueueSongCoverView
cellView.setQueueSong(queueItem, queueIcon: dataSource.queueIcon)
cellView.setSong(queueItem, queueIcon: dataSource.queueIcon)
return cellView
}
func cellForSongArtist(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
func cellForSongInfo(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
let cellView = outlineView.makeView(
withIdentifier: .queueSongArtist,
withIdentifier: .queueSongInfo,
owner: self
) as! NSTableCellView
) as! QueueSongInfoView
cellView.textField?.stringValue = queueItem.song.artist
if queueItem.isPlaying {
cellView.textField?.font = .systemFontBold
} else {
cellView.textField?.font = .systemFontRegular
}
cellView.setSong(queueItem, queueIcon: dataSource.queueIcon)
return cellView
}
func cellForQueueHeading(_ outlineView: NSOutlineView) -> NSView {
func cellForSongDuration(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
let cellView = outlineView.makeView(
withIdentifier: .queueHeading,
withIdentifier: .queueSongDuration,
owner: self
) as! NSTableCellView
) as! NSTableCellView
cellView.textField?.stringValue = "QUEUE"
cellView.textField?.font = .timerFont
cellView.textField?.stringValue = queueItem.song.duration.formattedTime
return cellView
}

View File

@ -40,11 +40,9 @@ class QueueViewController: NSViewController {
case NSEvent.keyCodeSpace:
nextResponder?.keyDown(with: event)
case NSEvent.keyCodeBS:
let queuePos = queueView.selectedRow - 1
let queuePos = queueView.selectedRow
if queuePos >= 0 {
App.mpdClient.removeSong(at: queuePos)
}
App.mpdClient.removeSong(at: queuePos)
default:
super.keyDown(with: event)
}
@ -62,26 +60,20 @@ class QueueViewController: NSViewController {
}
@IBAction func playTrack(_ sender: Any) {
let queuePos = queueView.selectedRow - 1
let queuePos = queueView.selectedRow
if queuePos >= 0 {
App.mpdClient.playTrack(at: queuePos)
}
App.mpdClient.playTrack(at: queuePos)
}
@IBAction func playSongMenuAction(_ sender: NSMenuItem) {
let queuePos = queueView.clickedRow - 1
let queuePos = queueView.clickedRow
if queuePos >= 0 {
App.mpdClient.playTrack(at: queuePos)
}
App.mpdClient.playTrack(at: queuePos)
}
@IBAction func removeSongMenuAction(_ sender: NSMenuItem) {
let queuePos = queueView.clickedRow - 1
let queuePos = queueView.clickedRow
if queuePos >= 0 {
App.mpdClient.removeSong(at: queuePos)
}
App.mpdClient.removeSong(at: queuePos)
}
}

View File

@ -7,17 +7,22 @@
//
import Cocoa
import Kingfisher
class DraggedSongView: NSViewController {
@IBOutlet var titleLabel: NSTextField!
@IBOutlet var artistLabel: NSTextField!
@IBOutlet var coverImage: NSImageView!
private let songTitle: String
private let songArtist: String
private let songCover: String?
init(title: String, artist: String) {
init(title: String, artist: String, cover: String? = nil) {
songTitle = title
songArtist = artist
songCover = cover
super.init(nibName: nil, bundle: nil)
}
@ -27,7 +32,44 @@ class DraggedSongView: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
coverImage.wantsLayer = true
coverImage.layer?.backgroundColor = CGColor.black
coverImage.layer?.cornerRadius = 2
coverImage.layer?.borderWidth = 1
coverImage.layer?.masksToBounds = true
setAppearance()
titleLabel.stringValue = songTitle
artistLabel.stringValue = songArtist
setCoverArt()
}
func setAppearance() {
if #available(OSX 10.14, *) {
let darkMode = NSApp.effectiveAppearance.bestMatch(from:
[.darkAqua, .aqua]) == .darkAqua
coverImage.layer?.borderColor = darkMode ? .albumBorderColorDark : .albumBorderColorLight
} else {
coverImage.layer?.borderColor = .albumBorderColorLight
}
}
func setCoverArt() {
guard let imagePath = songCover else { return }
let imageURL = URL(fileURLWithPath: imagePath)
let provider = LocalFileImageDataProvider(fileURL: imageURL)
coverImage.kf.setImage(
with: .provider(provider),
placeholder: NSImage.defaultCoverArt,
options: [
.processor(DownsamplingImageProcessor(size: .queueSongCoverSize)),
.scaleFactor(2),
]
)
}
}

View File

@ -1,14 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="DraggedSongView" customModule="Persephone" customModuleProvider="target">
<connections>
<outlet property="artistLabel" destination="egC-YO-gnV" id="g0f-FI-cGF"/>
<outlet property="coverImage" destination="Go5-Lk-qgA" id="M4D-rz-VvO"/>
<outlet property="titleLabel" destination="tsD-ub-h7I" id="EVO-Z7-tZY"/>
<outlet property="view" destination="Hz6-mo-xeY" id="Wf9-hm-E7M"/>
</connections>
@ -16,53 +17,64 @@
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="129" height="22"/>
<rect key="frame" x="0.0" y="0.0" width="110" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<box boxType="custom" borderType="line" cornerRadius="4" translatesAutoresizingMaskIntoConstraints="NO" id="G2x-p5-RM6">
<rect key="frame" x="0.0" y="0.0" width="129" height="22"/>
<rect key="frame" x="0.0" y="0.0" width="110" height="44"/>
<view key="contentView" id="qbG-wn-N4h">
<rect key="frame" x="1" y="1" width="127" height="20"/>
<rect key="frame" x="1" y="1" width="108" height="42"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView distribution="fillProportionally" orientation="horizontal" alignment="centerY" spacing="12" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rlT-HP-okZ">
<rect key="frame" x="0.0" y="0.0" width="127" height="20"/>
<stackView distribution="fillProportionally" orientation="horizontal" alignment="centerY" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rlT-HP-okZ">
<rect key="frame" x="0.0" y="0.0" width="108" height="42"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Go5-Lk-qgA">
<rect key="frame" x="8" y="2" width="17" height="17"/>
<rect key="frame" x="8" y="5" width="32" height="32"/>
<constraints>
<constraint firstAttribute="height" constant="17" id="DKw-m3-Lne"/>
<constraint firstAttribute="width" constant="17" id="k19-kI-PmI"/>
<constraint firstAttribute="height" constant="32" id="DKw-m3-Lne"/>
<constraint firstAttribute="width" constant="32" id="k19-kI-PmI"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="songIcon" id="KDX-a9-N4B"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="defaultCoverArt" id="KDX-a9-N4B"/>
</imageView>
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tsD-ub-h7I">
<rect key="frame" x="35" y="2" width="32" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" title="Title" usesSingleLineMode="YES" id="rMn-D0-PG7">
<font key="font" metaFont="systemMedium" size="13"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="egC-YO-gnV">
<rect key="frame" x="75" y="2" width="38" height="17"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" alignment="left" title="Artist" usesSingleLineMode="YES" id="m15-pn-bdW">
<font key="font" metaFont="system"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="0.0" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="H9H-r5-zq3">
<rect key="frame" x="48" y="6" width="44" height="31"/>
<subviews>
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tsD-ub-h7I">
<rect key="frame" x="-2" y="15" width="31" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" title="Title" usesSingleLineMode="YES" id="rMn-D0-PG7">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="egC-YO-gnV">
<rect key="frame" x="-2" y="0.0" width="35" height="15"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" alignment="left" title="Artist" usesSingleLineMode="YES" id="m15-pn-bdW">
<font key="font" metaFont="system" size="12"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<visibilityPriorities>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
<edgeInsets key="edgeInsets" left="8" right="16" top="0.0" bottom="0.0"/>
<visibilityPriorities>
<real value="1000"/>
<integer value="1000"/>
<integer value="1000"/>
</visibilityPriorities>
<customSpacing>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
<real value="3.4028234663852886e+38"/>
</customSpacing>
</stackView>
</subviews>
@ -74,7 +86,7 @@
</constraints>
</view>
<color key="borderColor" name="tertiaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="fillColor" red="0.27450980392156865" green="0.27450980392156865" blue="0.27450980392156865" alpha="0.65297645246478875" colorSpace="custom" customColorSpace="sRGB"/>
<color key="fillColor" name="windowBackgroundColor" catalog="System" colorSpace="catalog"/>
</box>
</subviews>
<constraints>
@ -83,10 +95,10 @@
<constraint firstAttribute="trailing" secondItem="G2x-p5-RM6" secondAttribute="trailing" id="MbJ-MP-4HG"/>
<constraint firstAttribute="bottom" secondItem="G2x-p5-RM6" secondAttribute="bottom" id="Nzd-OC-f1V"/>
</constraints>
<point key="canvasLocation" x="53.5" y="14"/>
<point key="canvasLocation" x="-30" y="129"/>
</customView>
</objects>
<resources>
<image name="songIcon" width="17" height="17"/>
<image name="defaultCoverArt" width="128" height="128"/>
</resources>
</document>

View File

@ -11,6 +11,8 @@ import AppKit
extension NSImage {
static let playIcon = NSImage(named: "playButton")
static let pauseIcon = NSImage(named: "pauseButton")
static let queuePlayIcon = NSImage(named: "queuePlayButton")
static let queuePauseIcon = NSImage(named: "queuePauseButton")
static let defaultCoverArt = NSImage(named: "defaultCoverArt")

View File

@ -9,6 +9,7 @@
import AppKit
extension NSSize {
static let queueSongCoverSize = NSSize(width: 32, height: 32)
static let albumListCoverSize = NSSize(width: 180, height: 180)
static let albumDetailCoverSize = NSSize(width: 500, height: 500)
static let currentlyPlayingCoverSize = albumDetailCoverSize

View File

@ -9,15 +9,13 @@
import AppKit
extension NSUserInterfaceItemIdentifier {
static let queueSongTitleColumn = NSUserInterfaceItemIdentifier("songTitleColumn")
static let queueSongArtistColumn = NSUserInterfaceItemIdentifier("songArtistColumn")
static let queueSongInfoColumn = NSUserInterfaceItemIdentifier("songInfoColumn")
static let queueHeading = NSUserInterfaceItemIdentifier("queueHeadingCell")
static let queueSongArtist = NSUserInterfaceItemIdentifier("songArtistCell")
static let queueSongTitle = NSUserInterfaceItemIdentifier("songTitleCell")
static let queueSongCover = NSUserInterfaceItemIdentifier("songCoverCell")
static let queueSongInfo = NSUserInterfaceItemIdentifier("songInfoCell")
static let queueSongDuration = NSUserInterfaceItemIdentifier("songDurationCell")
static let albumViewItem = NSUserInterfaceItemIdentifier("AlbumViewItem")
static let artistViewItem = NSUserInterfaceItemIdentifier("ArtistViewItem")
static let discNumber = NSUserInterfaceItemIdentifier("discNumberCell")
static let trackNumber = NSUserInterfaceItemIdentifier("trackNumberCell")

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<document type="com.apple.InterfaceBuilder3.Cocoa.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" initialViewController="B8D-0N-5wS">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15705"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -646,27 +646,27 @@
<scene sceneID="QcX-dC-cTZ">
<objects>
<viewController id="KIP-rq-4dM" customClass="QueueViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
<splitView key="view" dividerStyle="thin" id="84I-w3-Mxl">
<rect key="frame" x="0.0" y="0.0" width="328" height="547"/>
<splitView key="view" misplaced="YES" dividerStyle="thin" id="84I-w3-Mxl">
<rect key="frame" x="0.0" y="0.0" width="329" height="543"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<scrollView misplaced="YES" borderType="none" autohidesScrollers="YES" horizontalLineScroll="17" horizontalPageScroll="10" verticalLineScroll="17" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="S3o-nF-NN7">
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="42" horizontalPageScroll="10" verticalLineScroll="42" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="S3o-nF-NN7">
<rect key="frame" x="0.0" y="0.0" width="329" height="217"/>
<autoresizingMask key="autoresizingMask" flexibleMaxY="YES"/>
<clipView key="contentView" drawsBackground="NO" id="WI8-Pw-03L">
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
<rect key="frame" x="0.0" y="0.0" width="329" height="217"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="14" outlineTableColumn="0Co-uF-CCB" id="jEJ-jg-fll" customClass="QueueView" customModule="Persephone" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowHeight="42" rowSizeStyle="automatic" viewBased="YES" indentationMarkerFollowsCell="NO" outlineTableColumn="0Co-uF-CCB" id="jEJ-jg-fll">
<rect key="frame" x="0.0" y="0.0" width="329" height="217"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<size key="intercellSpacing" width="3" height="0.0"/>
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="songTitleColumn" width="200" minWidth="128" maxWidth="1000" id="0Co-uF-CCB">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Title">
<font key="font" metaFont="message" size="11"/>
<tableColumn identifier="songCoverColumn" width="43" minWidth="42" maxWidth="1000" id="0Co-uF-CCB" userLabel="Position">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
@ -677,107 +677,131 @@
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView identifier="queueHeadingCell" id="GOd-cg-juD">
<rect key="frame" x="1" y="0.0" width="200" height="17"/>
<tableCellView identifier="songCoverCell" id="5rR-Gz-AcP" userLabel="Song Cover View" customClass="QueueSongCoverView" customModule="Persephone" customModuleProvider="target">
<rect key="frame" x="1" y="0.0" width="43" height="42"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xgd-Cz-np3">
<rect key="frame" x="0.0" y="2" width="322" height="14"/>
<imageView identifier="songCoverView" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="7Yi-vi-Frs" userLabel="Song Cover View">
<rect key="frame" x="9" y="5" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="443" id="mkA-ng-q8a"/>
<constraint firstAttribute="width" constant="32" id="hhe-Vq-2aS"/>
<constraint firstAttribute="height" constant="32" id="iz9-3T-uWZ"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="QUEUE" id="Mqf-uh-ibl">
<font key="font" metaFont="smallSystemBold"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="kingfisher-1" id="KfD-57-Whk"/>
<color key="contentTintColor" name="quaternaryLabelColor" catalog="System" colorSpace="catalog"/>
</imageView>
<button wantsLayer="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wOh-Rs-R2S" userLabel="Song Play Button">
<rect key="frame" x="9" y="5" width="32" height="32"/>
<constraints>
<constraint firstAttribute="width" constant="32" id="cDu-pP-YAh"/>
<constraint firstAttribute="height" constant="32" id="j6D-Zt-d1I"/>
</constraints>
<buttonCell key="cell" type="square" bezelStyle="shadowlessSquare" imagePosition="only" alignment="center" transparent="YES" inset="2" id="eWw-vk-jay">
<behavior key="behavior" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<color key="contentTintColor" name="labelColor" catalog="System" colorSpace="catalog"/>
</button>
</subviews>
<constraints>
<constraint firstItem="wOh-Rs-R2S" firstAttribute="centerY" secondItem="5rR-Gz-AcP" secondAttribute="centerY" id="5pe-ht-AvV"/>
<constraint firstAttribute="trailing" secondItem="wOh-Rs-R2S" secondAttribute="trailing" constant="2" id="6b6-jo-ek2"/>
<constraint firstAttribute="trailing" secondItem="7Yi-vi-Frs" secondAttribute="trailing" constant="2" id="mdH-6E-1hS"/>
<constraint firstItem="7Yi-vi-Frs" firstAttribute="centerY" secondItem="5rR-Gz-AcP" secondAttribute="centerY" id="uga-Kx-ogd"/>
</constraints>
<connections>
<outlet property="queueSongButton" destination="wOh-Rs-R2S" id="tkf-l4-qKj"/>
<outlet property="queueSongCover" destination="7Yi-vi-Frs" id="fna-Ad-H3N"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="songInfoColumn" width="213" minWidth="10" maxWidth="3.4028234663852886e+38" id="HP0-ty-PFY" userLabel="Song Info">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="zb2-QK-DhK">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="songInfoCell" id="GuF-NF-B1t" userLabel="Song Info View" customClass="QueueSongInfoView" customModule="Persephone" customModuleProvider="target">
<rect key="frame" x="47" y="0.0" width="213" height="42"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tBe-Q9-3Rw" userLabel="Song Artist View">
<rect key="frame" x="1" y="7" width="219" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Song Artist" id="Ceb-ec-ydU">
<font key="font" metaFont="system" size="12"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="i0h-bn-auJ" userLabel="Song Title View">
<rect key="frame" x="1" y="23" width="211" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Song Title" id="ei8-1e-ErK">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="tBe-Q9-3Rw" secondAttribute="trailing" constant="-5" id="33u-Xt-7zG"/>
<constraint firstItem="i0h-bn-auJ" firstAttribute="leading" secondItem="GuF-NF-B1t" secondAttribute="leading" constant="3" id="Mqo-x9-boa"/>
<constraint firstAttribute="trailing" secondItem="i0h-bn-auJ" secondAttribute="trailing" constant="3" id="Qf6-8z-3ei"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="top" secondItem="i0h-bn-auJ" secondAttribute="bottom" id="ZRx-0N-kaR"/>
<constraint firstItem="i0h-bn-auJ" firstAttribute="top" secondItem="GuF-NF-B1t" secondAttribute="top" constant="3" id="baQ-VK-KP0"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="leading" secondItem="i0h-bn-auJ" secondAttribute="leading" id="uIN-3Y-iOI"/>
</constraints>
<connections>
<outlet property="queueSongArtist" destination="tBe-Q9-3Rw" id="uzL-Uq-EEl"/>
<outlet property="queueSongTitle" destination="i0h-bn-auJ" id="fQ1-z3-Jxs"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="songDurationColumn" width="64" minWidth="64" maxWidth="64" id="8O6-ox-kx2" userLabel="Duration">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
<font key="font" metaFont="menu" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="JOa-Mc-ceQ">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="songDurationCell" misplaced="YES" id="9Nz-Yf-SN1" userLabel="Song Duration View">
<rect key="frame" x="263" y="0.0" width="64" height="42"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ukg-c0-XVS">
<rect key="frame" x="8" y="13" width="41" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="42" id="HmU-DM-ORZ"/>
<constraint firstAttribute="height" constant="17" id="grB-CG-1vJ"/>
</constraints>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="right" title="88:88" id="JnJ-sF-vCP">
<font key="font" metaFont="system"/>
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="xgd-Cz-np3" firstAttribute="leading" secondItem="GOd-cg-juD" secondAttribute="leading" constant="2" id="iOU-E2-K47"/>
<constraint firstItem="xgd-Cz-np3" firstAttribute="centerY" secondItem="GOd-cg-juD" secondAttribute="centerY" id="uxd-zs-s33"/>
</constraints>
</tableCellView>
<tableCellView identifier="songTitleCell" id="5rR-Gz-AcP" customClass="QueueSongTitleView" customModule="Persephone" customModuleProvider="target">
<rect key="frame" x="1" y="17" width="200" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView identifier="queuePlayerState" translatesAutoresizingMaskIntoConstraints="NO" id="o8i-cz-hIP" userLabel="Player State View">
<rect key="frame" x="3" y="-1" width="17" height="17"/>
<constraints>
<constraint firstAttribute="width" constant="17" id="00Z-Tq-MFp"/>
</constraints>
<imageCell key="cell" refusesFirstResponder="YES" imageScaling="proportionallyDown" image="playButton" id="ckK-gW-Vhx"/>
</imageView>
<textField identifier="queuePosition" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="mc4-Xr-oUl" userLabel="Queue Position View">
<rect key="frame" x="4" y="1" width="33" height="16"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="888." id="wpZ-1t-Do7">
<font key="font" metaFont="system"/>
<color key="textColor" name="tertiaryLabelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="i0h-bn-auJ" userLabel="Song Title View">
<rect key="frame" x="40" y="1" width="160" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="ei8-1e-ErK">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstItem="i0h-bn-auJ" firstAttribute="leading" secondItem="o8i-cz-hIP" secondAttribute="trailing" constant="22" id="68y-un-94T"/>
<constraint firstItem="mc4-Xr-oUl" firstAttribute="centerY" secondItem="5rR-Gz-AcP" secondAttribute="centerY" id="ELP-WE-eIm"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="leading" secondItem="5rR-Gz-AcP" secondAttribute="leading" constant="3" id="SkK-PE-YOL"/>
<constraint firstAttribute="trailing" secondItem="i0h-bn-auJ" secondAttribute="trailing" constant="2" id="XQG-u9-wiY"/>
<constraint firstItem="mc4-Xr-oUl" firstAttribute="baseline" secondItem="i0h-bn-auJ" secondAttribute="baseline" id="YMz-iR-hUI"/>
<constraint firstItem="mc4-Xr-oUl" firstAttribute="leading" secondItem="5rR-Gz-AcP" secondAttribute="leading" constant="6" id="s8m-Sb-8up"/>
<constraint firstItem="o8i-cz-hIP" firstAttribute="top" secondItem="5rR-Gz-AcP" secondAttribute="top" constant="1" id="srE-Dv-Ie5"/>
<constraint firstAttribute="trailing" secondItem="ukg-c0-XVS" secondAttribute="trailing" constant="10" id="jLU-Py-Sw9"/>
<constraint firstItem="ukg-c0-XVS" firstAttribute="centerY" secondItem="9Nz-Yf-SN1" secondAttribute="centerY" id="jkF-3G-jYj"/>
<constraint firstItem="ukg-c0-XVS" firstAttribute="centerX" secondItem="9Nz-Yf-SN1" secondAttribute="centerX" constant="2" id="v3t-6q-KV4"/>
</constraints>
<connections>
<outlet property="imageView" destination="o8i-cz-hIP" id="4In-Lr-QcL"/>
<outlet property="queuePlayerStateImage" destination="o8i-cz-hIP" id="lUU-N4-jtd"/>
<outlet property="queuePosition" destination="mc4-Xr-oUl" id="aBD-Tg-cDt"/>
<outlet property="queueSongTitle" destination="i0h-bn-auJ" id="25v-lw-ypc"/>
<outlet property="textField" destination="i0h-bn-auJ" id="5YB-JL-2wJ"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="songArtistColumn" width="122" minWidth="64" maxWidth="1000" id="SPM-QP-DX8">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Artist">
<font key="font" metaFont="message" size="11"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="alT-Kq-P4B">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView identifier="songArtistCell" id="JSk-Vc-Y7e">
<rect key="frame" x="204" y="0.0" width="122" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tBe-Q9-3Rw">
<rect key="frame" x="0.0" y="1" width="127" height="16"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Ceb-ec-ydU">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="tBe-Q9-3Rw" secondAttribute="trailing" constant="-3" id="E6a-sY-dne"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="leading" secondItem="JSk-Vc-Y7e" secondAttribute="leading" constant="2" id="Gm4-l1-WRz"/>
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="centerY" secondItem="JSk-Vc-Y7e" secondAttribute="centerY" id="KhJ-nn-rh5"/>
</constraints>
<connections>
<outlet property="textField" destination="tBe-Q9-3Rw" id="2e6-zi-tKj"/>
<outlet property="textField" destination="ukg-c0-XVS" id="FyU-zm-ijP"/>
</connections>
</tableCellView>
</prototypeCellViews>
@ -797,7 +821,7 @@
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="500" id="zuT-k9-w8d"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="7mx-v9-DSr">
<rect key="frame" x="0.0" y="237" width="328" height="16"/>
<rect key="frame" x="0.0" y="201" width="329" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="p5z-C0-FUJ">
@ -806,11 +830,11 @@
</scroller>
</scrollView>
<customView misplaced="YES" id="iUb-eV-Qws">
<rect key="frame" x="0.0" y="220" width="328" height="327"/>
<rect key="frame" x="0.0" y="218" width="329" height="325"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Dw3-M5-tWY" customClass="CurrentCoverArtView" customModule="Persephone" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="328" height="328"/>
<rect key="frame" x="0.0" y="0.0" width="329" height="329"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="defaultCoverArt" id="IoN-3N-TCb"/>
</imageView>
</subviews>
@ -851,7 +875,7 @@
</items>
</menu>
</objects>
<point key="canvasLocation" x="825" y="746"/>
<point key="canvasLocation" x="824.5" y="745.5"/>
</scene>
<!--Album View Controller-->
<scene sceneID="7Ua-Hj-zWt">
@ -920,6 +944,7 @@
<image name="NSPreferencesGeneral" width="32" height="32"/>
<image name="coverArtPreferencesIcon" width="32" height="32"/>
<image name="defaultCoverArt" width="128" height="128"/>
<image name="kingfisher-1" width="250" height="250"/>
<image name="nextTrackButton" width="17" height="17"/>
<image name="playButton" width="17" height="17"/>
<image name="prevTrackButton" width="17" height="17"/>

View File

@ -10,4 +10,5 @@ struct DraggedSong: Codable {
var type: DraggedSongType
var title: String?
var artist: String?
var cover: String?
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 307 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.