mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Mostly working, albumlist is not showing album art
This commit is contained in:
parent
bb5a7c2c5c
commit
2e6c903d74
@ -88,6 +88,10 @@
|
|||||||
E4B11B6F226A5C7A0075461B /* UpdateStatusAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */; };
|
E4B11B6F226A5C7A0075461B /* UpdateStatusAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */; };
|
||||||
E4B11B71226A64E60075461B /* UpdateElapsedTimeAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B70226A64E60075461B /* UpdateElapsedTimeAction.swift */; };
|
E4B11B71226A64E60075461B /* UpdateElapsedTimeAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B70226A64E60075461B /* UpdateElapsedTimeAction.swift */; };
|
||||||
E4B11B73226A6C770075461B /* TrackTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B72226A6C770075461B /* TrackTimer.swift */; };
|
E4B11B73226A6C770075461B /* TrackTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B72226A6C770075461B /* TrackTimer.swift */; };
|
||||||
|
E4B11B75226CC4D30075461B /* QueueReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B74226CC4D30075461B /* QueueReducer.swift */; };
|
||||||
|
E4B11B77226CC6BE0075461B /* UpdateQueuePosAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B76226CC6BE0075461B /* UpdateQueuePosAction.swift */; };
|
||||||
|
E4B11B79226D346B0075461B /* AlbumListReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B78226D346B0075461B /* AlbumListReducer.swift */; };
|
||||||
|
E4B11B7B226D34F80075461B /* UpdateAlbumListAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B7A226D34F80075461B /* UpdateAlbumListAction.swift */; };
|
||||||
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
|
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
|
||||||
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* MPDIdle.swift */; };
|
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* MPDIdle.swift */; };
|
||||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
|
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
|
||||||
@ -267,6 +271,10 @@
|
|||||||
E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateStatusAction.swift; sourceTree = "<group>"; };
|
E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateStatusAction.swift; sourceTree = "<group>"; };
|
||||||
E4B11B70226A64E60075461B /* UpdateElapsedTimeAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateElapsedTimeAction.swift; sourceTree = "<group>"; };
|
E4B11B70226A64E60075461B /* UpdateElapsedTimeAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateElapsedTimeAction.swift; sourceTree = "<group>"; };
|
||||||
E4B11B72226A6C770075461B /* TrackTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTimer.swift; sourceTree = "<group>"; };
|
E4B11B72226A6C770075461B /* TrackTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackTimer.swift; sourceTree = "<group>"; };
|
||||||
|
E4B11B74226CC4D30075461B /* QueueReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueReducer.swift; sourceTree = "<group>"; };
|
||||||
|
E4B11B76226CC6BE0075461B /* UpdateQueuePosAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateQueuePosAction.swift; sourceTree = "<group>"; };
|
||||||
|
E4B11B78226D346B0075461B /* AlbumListReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListReducer.swift; sourceTree = "<group>"; };
|
||||||
|
E4B11B7A226D34F80075461B /* UpdateAlbumListAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateAlbumListAction.swift; sourceTree = "<group>"; };
|
||||||
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.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>"; };
|
E4C8B53D22349002009A20F3 /* MPDIdle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDIdle.swift; sourceTree = "<group>"; };
|
||||||
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
|
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
|
||||||
@ -566,6 +574,8 @@
|
|||||||
children = (
|
children = (
|
||||||
E4B11B60226A4BFF0075461B /* PlayerReducer.swift */,
|
E4B11B60226A4BFF0075461B /* PlayerReducer.swift */,
|
||||||
E4B11B62226A4C510075461B /* AppReducer.swift */,
|
E4B11B62226A4C510075461B /* AppReducer.swift */,
|
||||||
|
E4B11B74226CC4D30075461B /* QueueReducer.swift */,
|
||||||
|
E4B11B78226D346B0075461B /* AlbumListReducer.swift */,
|
||||||
);
|
);
|
||||||
path = Reducers;
|
path = Reducers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -584,9 +594,11 @@
|
|||||||
E4B11B6B226A5AF50075461B /* Actions */ = {
|
E4B11B6B226A5AF50075461B /* Actions */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E4B11B6C226A5B180075461B /* UpdateQueueAction.swift */,
|
E4B11B7A226D34F80075461B /* UpdateAlbumListAction.swift */,
|
||||||
E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */,
|
|
||||||
E4B11B70226A64E60075461B /* UpdateElapsedTimeAction.swift */,
|
E4B11B70226A64E60075461B /* UpdateElapsedTimeAction.swift */,
|
||||||
|
E4B11B6C226A5B180075461B /* UpdateQueueAction.swift */,
|
||||||
|
E4B11B76226CC6BE0075461B /* UpdateQueuePosAction.swift */,
|
||||||
|
E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */,
|
||||||
);
|
);
|
||||||
path = Actions;
|
path = Actions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -837,6 +849,7 @@
|
|||||||
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */,
|
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */,
|
||||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
||||||
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
|
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
|
||||||
|
E4B11B7B226D34F80075461B /* UpdateAlbumListAction.swift in Sources */,
|
||||||
E4B11B6D226A5B180075461B /* UpdateQueueAction.swift in Sources */,
|
E4B11B6D226A5B180075461B /* UpdateQueueAction.swift in Sources */,
|
||||||
E4B11B68226A4FA00075461B /* QueueState.swift in Sources */,
|
E4B11B68226A4FA00075461B /* QueueState.swift in Sources */,
|
||||||
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
|
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
|
||||||
@ -848,6 +861,7 @@
|
|||||||
E41E5307223C019100173814 /* MPDClient+Status.swift in Sources */,
|
E41E5307223C019100173814 /* MPDClient+Status.swift in Sources */,
|
||||||
E41E5310223EF6CE00173814 /* AlbumArtService+Remote.swift in Sources */,
|
E41E5310223EF6CE00173814 /* AlbumArtService+Remote.swift in Sources */,
|
||||||
E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */,
|
E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */,
|
||||||
|
E4B11B77226CC6BE0075461B /* UpdateQueuePosAction.swift in Sources */,
|
||||||
E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */,
|
E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */,
|
||||||
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */,
|
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */,
|
||||||
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */,
|
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */,
|
||||||
@ -870,8 +884,10 @@
|
|||||||
E419E2872249B96600216A8C /* Song.swift in Sources */,
|
E419E2872249B96600216A8C /* Song.swift in Sources */,
|
||||||
E439109822640213002982E9 /* SongNotifierService.swift in Sources */,
|
E439109822640213002982E9 /* SongNotifierService.swift in Sources */,
|
||||||
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
||||||
|
E4B11B75226CC4D30075461B /* QueueReducer.swift in Sources */,
|
||||||
E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */,
|
E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */,
|
||||||
E4B11B73226A6C770075461B /* TrackTimer.swift in Sources */,
|
E4B11B73226A6C770075461B /* TrackTimer.swift in Sources */,
|
||||||
|
E4B11B79226D346B0075461B /* AlbumListReducer.swift in Sources */,
|
||||||
E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */,
|
E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */,
|
||||||
E41E52FF223BF95E00173814 /* MPDClient+Transport.swift in Sources */,
|
E41E52FF223BF95E00173814 /* MPDClient+Transport.swift in Sources */,
|
||||||
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */,
|
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */,
|
||||||
|
|||||||
13
Persephone/Actions/UpdateAlbumListAction.swift
Normal file
13
Persephone/Actions/UpdateAlbumListAction.swift
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// UpdateAlbumListAction.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/4/21.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
struct UpdateAlbumListAction: Action {
|
||||||
|
var albums: [MPDClient.MPDAlbum]
|
||||||
|
}
|
||||||
13
Persephone/Actions/UpdateQueuePosAction.swift
Normal file
13
Persephone/Actions/UpdateQueuePosAction.swift
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// UpdateQueuePosAction.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/4/21.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
struct UpdateQueuePosAction: Action {
|
||||||
|
var queuePos: Int
|
||||||
|
}
|
||||||
@ -21,7 +21,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate {
|
|||||||
|
|
||||||
static let trackTimer = TrackTimer()
|
static let trackTimer = TrackTimer()
|
||||||
|
|
||||||
static let store = Store(reducer: appReducer, state: nil)
|
static let store = Store<AppState>(reducer: appReducer, state: nil)
|
||||||
|
|
||||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||||
connect()
|
connect()
|
||||||
|
|||||||
@ -7,10 +7,14 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
class AlbumViewController: NSViewController,
|
class AlbumViewController: NSViewController,
|
||||||
NSCollectionViewDelegate,
|
NSCollectionViewDelegate,
|
||||||
NSCollectionViewDelegateFlowLayout {
|
NSCollectionViewDelegateFlowLayout,
|
||||||
|
StoreSubscriber {
|
||||||
|
typealias StoreSubscriberStateType = AlbumListState
|
||||||
|
|
||||||
var preferences = Preferences()
|
var preferences = Preferences()
|
||||||
|
|
||||||
let paddingWidth: CGFloat = 40
|
let paddingWidth: CGFloat = 40
|
||||||
@ -21,22 +25,14 @@ class AlbumViewController: NSViewController,
|
|||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
AppDelegate.store.subscribe(self) {
|
||||||
|
(subscription: Subscription<AppState>) -> Subscription<AlbumListState> in
|
||||||
|
|
||||||
|
subscription.select { state -> AlbumListState in state.albumListState }
|
||||||
|
}
|
||||||
|
|
||||||
albumScrollView.postsBoundsChangedNotifications = true
|
albumScrollView.postsBoundsChangedNotifications = true
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(updateAlbums(_:)),
|
|
||||||
name: Notification.loadedAlbums,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(clearAlbums(_:)),
|
|
||||||
name: Notification.willDisconnect,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
|
|
||||||
albumCollectionView.dataSource = dataSource
|
albumCollectionView.dataSource = dataSource
|
||||||
|
|
||||||
preferences.addObserver(self, forKeyPath: "mpdLibraryDir")
|
preferences.addObserver(self, forKeyPath: "mpdLibraryDir")
|
||||||
@ -72,24 +68,15 @@ class AlbumViewController: NSViewController,
|
|||||||
case "mpdLibraryDir":
|
case "mpdLibraryDir":
|
||||||
albumCollectionView.reloadData()
|
albumCollectionView.reloadData()
|
||||||
case "fetchMissingArtworkFromInternet":
|
case "fetchMissingArtworkFromInternet":
|
||||||
dataSource.resetCoverArt()
|
// dataSource.resetCoverArt()
|
||||||
albumCollectionView.reloadData()
|
albumCollectionView.reloadData()
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func updateAlbums(_ notification: Notification) {
|
func newState(state: StoreSubscriberStateType) {
|
||||||
guard let albums = notification.userInfo?[Notification.albumsKey] as? [MPDClient.MPDAlbum]
|
print("New album list state")
|
||||||
else { return }
|
|
||||||
|
|
||||||
dataSource.albums = albums.map { Album(mpdAlbum: $0) }
|
|
||||||
albumCollectionView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func clearAlbums(_ notification: Notification) {
|
|
||||||
dataSource.albums = []
|
|
||||||
|
|
||||||
albumCollectionView.reloadData()
|
albumCollectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -16,26 +16,16 @@ class NotificationsController: MPDClientDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func willDisconnect(mpdClient: MPDClient) {
|
func willDisconnect(mpdClient: MPDClient) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
AppDelegate.store.dispatch(UpdateAlbumListAction(albums: []))
|
||||||
|
}
|
||||||
sendNotification(name: Notification.willDisconnect)
|
sendNotification(name: Notification.willDisconnect)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus) {
|
func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus) {
|
||||||
AppDelegate.store.dispatch(UpdateStatusAction(status: status))
|
DispatchQueue.main.async {
|
||||||
sendNotification(
|
AppDelegate.store.dispatch(UpdateStatusAction(status: status))
|
||||||
name: Notification.stateChanged,
|
}
|
||||||
userInfo: [Notification.stateKey: status.state]
|
|
||||||
)
|
|
||||||
sendNotification(
|
|
||||||
name: Notification.timeChanged,
|
|
||||||
userInfo: [
|
|
||||||
Notification.totalTimeKey: status.totalTime,
|
|
||||||
Notification.elapsedTimeMsKey: status.elapsedTimeMs
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func didUpdateTime(mpdClient: MPDClient, total: UInt, elapsedMs: UInt) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func willStartDatabaseUpdate(mpdClient: MPDClient) {
|
func willStartDatabaseUpdate(mpdClient: MPDClient) {
|
||||||
@ -47,21 +37,22 @@ class NotificationsController: MPDClientDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.MPDSong]) {
|
func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.MPDSong]) {
|
||||||
//AppDelegate.store.dispatch(UpdateQueueAction(queue: queue))
|
DispatchQueue.main.async {
|
||||||
sendNotification(
|
AppDelegate.store.dispatch(UpdateQueueAction(queue: queue))
|
||||||
name: Notification.queueChanged,
|
}
|
||||||
userInfo: [Notification.queueKey: queue]
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func didUpdateQueuePos(mpdClient: MPDClient, song: Int) {
|
func didUpdateQueuePos(mpdClient: MPDClient, song: Int) {
|
||||||
sendNotification(
|
DispatchQueue.main.async {
|
||||||
name: Notification.queuePosChanged,
|
AppDelegate.store.dispatch(UpdateQueuePosAction(queuePos: song))
|
||||||
userInfo: [Notification.queuePosKey: song]
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.MPDAlbum]) {
|
func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.MPDAlbum]) {
|
||||||
|
print("Albums")
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
AppDelegate.store.dispatch(UpdateAlbumListAction(albums: albums))
|
||||||
|
}
|
||||||
sendNotification(
|
sendNotification(
|
||||||
name: Notification.loadedAlbums,
|
name: Notification.loadedAlbums,
|
||||||
userInfo: [Notification.albumsKey: albums]
|
userInfo: [Notification.albumsKey: albums]
|
||||||
|
|||||||
@ -7,10 +7,13 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
import PromiseKit
|
import ReSwift
|
||||||
|
|
||||||
class QueueViewController: NSViewController,
|
class QueueViewController: NSViewController,
|
||||||
NSOutlineViewDelegate {
|
NSOutlineViewDelegate,
|
||||||
|
StoreSubscriber {
|
||||||
|
typealias StoreSubscriberStateType = QueueState
|
||||||
|
|
||||||
var dataSource = QueueDataSource()
|
var dataSource = QueueDataSource()
|
||||||
|
|
||||||
@IBOutlet var queueView: NSOutlineView!
|
@IBOutlet var queueView: NSOutlineView!
|
||||||
@ -19,11 +22,22 @@ class QueueViewController: NSViewController,
|
|||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
setupNotificationObservers()
|
AppDelegate.store.subscribe(self) {
|
||||||
|
(subscription: Subscription<AppState>) -> Subscription<QueueState> in
|
||||||
|
|
||||||
|
subscription.select { state in state.queueState }
|
||||||
|
}
|
||||||
|
|
||||||
queueView.dataSource = dataSource
|
queueView.dataSource = dataSource
|
||||||
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newState(state: StoreSubscriberStateType) {
|
||||||
|
print("New queue state")
|
||||||
|
dataSource.setQueueIcon()
|
||||||
|
queueView.reloadData()
|
||||||
|
updateAlbumArt(state)
|
||||||
|
}
|
||||||
|
|
||||||
override func keyDown(with event: NSEvent) {
|
override func keyDown(with event: NSEvent) {
|
||||||
switch event.keyCode {
|
switch event.keyCode {
|
||||||
@ -42,15 +56,8 @@ class QueueViewController: NSViewController,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func stateChanged(_ notification: Notification) {
|
func notifyTrack(_ state: QueueState) {
|
||||||
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.MPDStatus.State
|
guard let currentSong = state.currentSong,
|
||||||
else { return }
|
|
||||||
|
|
||||||
dataSource.setQueueIcon(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
func notifyTrack() {
|
|
||||||
guard let currentSong = dataSource.currentSong,
|
|
||||||
let status = AppDelegate.mpdClient.status,
|
let status = AppDelegate.mpdClient.status,
|
||||||
status.state == .playing
|
status.state == .playing
|
||||||
else { return }
|
else { return }
|
||||||
@ -59,25 +66,10 @@ class QueueViewController: NSViewController,
|
|||||||
.deliver()
|
.deliver()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func queueChanged(_ notification: Notification) {
|
func updateAlbumArt(_ state: QueueState) {
|
||||||
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.MPDSong]
|
if let playingQueueItem = state.queue.first(
|
||||||
else { return }
|
where: { $0.isPlaying }
|
||||||
|
) {
|
||||||
dataSource.updateQueue(queue)
|
|
||||||
queueView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func queuePosChanged(_ notification: Notification) {
|
|
||||||
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
dataSource.setQueuePos(queuePos)
|
|
||||||
queueView.reloadData()
|
|
||||||
updateAlbumArt()
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateAlbumArt() {
|
|
||||||
if let playingQueueItem = dataSource.queue.first(where: { $0.isPlaying }) {
|
|
||||||
let albumArtService = AlbumArtService(song: playingQueueItem.song)
|
let albumArtService = AlbumArtService(song: playingQueueItem.song)
|
||||||
|
|
||||||
albumArtService.fetchBigAlbumArt()
|
albumArtService.fetchBigAlbumArt()
|
||||||
@ -88,7 +80,7 @@ class QueueViewController: NSViewController,
|
|||||||
self.queueAlbumArtImage.image = NSImage.defaultCoverArt
|
self.queueAlbumArtImage.image = NSImage.defaultCoverArt
|
||||||
}
|
}
|
||||||
|
|
||||||
self.notifyTrack()
|
self.notifyTrack(state)
|
||||||
}
|
}
|
||||||
.cauterize()
|
.cauterize()
|
||||||
} else {
|
} else {
|
||||||
@ -168,27 +160,4 @@ func cellForSongTitle(_ outlineView: NSOutlineView, with queueItem: QueueItem) -
|
|||||||
|
|
||||||
return cellView
|
return cellView
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupNotificationObservers() {
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(stateChanged(_:)),
|
|
||||||
name: Notification.stateChanged,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(queueChanged(_:)),
|
|
||||||
name: Notification.queueChanged,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(queuePosChanged(_:)),
|
|
||||||
name: Notification.queuePosChanged,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import Cocoa
|
|||||||
import ReSwift
|
import ReSwift
|
||||||
|
|
||||||
class WindowController: NSWindowController, StoreSubscriber {
|
class WindowController: NSWindowController, StoreSubscriber {
|
||||||
typealias StoreSubscriberStateType = AppState
|
typealias StoreSubscriberStateType = PlayerState
|
||||||
|
|
||||||
enum TransportAction: Int {
|
enum TransportAction: Int {
|
||||||
case prevTrack, playPause, stop, nextTrack
|
case prevTrack, playPause, stop, nextTrack
|
||||||
@ -23,8 +23,11 @@ class WindowController: NSWindowController, StoreSubscriber {
|
|||||||
super.windowDidLoad()
|
super.windowDidLoad()
|
||||||
window?.titleVisibility = .hidden
|
window?.titleVisibility = .hidden
|
||||||
|
|
||||||
// TODO: We will want to filter this subscribe later
|
AppDelegate.store.subscribe(self) {
|
||||||
AppDelegate.store.subscribe(self)
|
(subscription: Subscription<AppState>) -> Subscription<PlayerState> in
|
||||||
|
|
||||||
|
subscription.select { state in state.playerState }
|
||||||
|
}
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver(
|
||||||
self,
|
self,
|
||||||
@ -44,12 +47,13 @@ class WindowController: NSWindowController, StoreSubscriber {
|
|||||||
trackRemaining.font = .timerFont
|
trackRemaining.font = .timerFont
|
||||||
}
|
}
|
||||||
|
|
||||||
func newState(state: WindowController.StoreSubscriberStateType) {
|
func newState(state: StoreSubscriberStateType) {
|
||||||
self.state = state.playerState.state
|
print("New player state")
|
||||||
|
self.state = state.state
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.setTransportControlState(state.playerState)
|
self.setTransportControlState(state)
|
||||||
self.setTrackProgressControls(state.playerState)
|
self.setTrackProgressControls(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,45 +10,44 @@ import Cocoa
|
|||||||
import PromiseKit
|
import PromiseKit
|
||||||
|
|
||||||
class AlbumDataSource: NSObject, NSCollectionViewDataSource {
|
class AlbumDataSource: NSObject, NSCollectionViewDataSource {
|
||||||
var albums: [Album] = []
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
return albums.count
|
return AppDelegate.store.state.albumListState.albums.count
|
||||||
}
|
|
||||||
|
|
||||||
func resetCoverArt() {
|
|
||||||
albums = albums.map {
|
|
||||||
var album = $0
|
|
||||||
album.coverArtFetched = false
|
|
||||||
return album
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
// func resetCoverArt() {
|
||||||
|
// albums = AppDelegate.store.state.albumListState.albums.map {
|
||||||
|
// var album = $0
|
||||||
|
// album.coverArtFetched = false
|
||||||
|
// return album
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
||||||
|
let albums = AppDelegate.store.state.albumListState.albums
|
||||||
let item = collectionView.makeItem(withIdentifier: .albumViewItem, for: indexPath)
|
let item = collectionView.makeItem(withIdentifier: .albumViewItem, for: indexPath)
|
||||||
guard let albumViewItem = item as? AlbumViewItem else { return item }
|
guard let albumViewItem = item as? AlbumViewItem else { return item }
|
||||||
|
|
||||||
albumViewItem.view.wantsLayer = true
|
albumViewItem.view.wantsLayer = true
|
||||||
albumViewItem.setAlbum(albums[indexPath.item])
|
albumViewItem.setAlbum(albums[indexPath.item])
|
||||||
|
|
||||||
if albums[indexPath.item].coverArt == nil &&
|
// if albums[indexPath.item].coverArt == nil &&
|
||||||
!albums[indexPath.item].coverArtFetched {
|
// !albums[indexPath.item].coverArtFetched {
|
||||||
|
//
|
||||||
AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) {
|
// AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) {
|
||||||
guard let song = $0 else { return }
|
// guard let song = $0 else { return }
|
||||||
|
//
|
||||||
AlbumArtService(song: Song(mpdSong: song))
|
// AlbumArtService(song: Song(mpdSong: song))
|
||||||
.fetchAlbumArt()
|
// .fetchAlbumArt()
|
||||||
.done { image in
|
// .done { image in
|
||||||
self.albums[indexPath.item].coverArt = image
|
// self.albums[indexPath.item].coverArt = image
|
||||||
self.albums[indexPath.item].coverArtFetched = true
|
// self.albums[indexPath.item].coverArtFetched = true
|
||||||
|
//
|
||||||
DispatchQueue.main.async {
|
// DispatchQueue.main.async {
|
||||||
collectionView.reloadItems(at: [indexPath])
|
// collectionView.reloadItems(at: [indexPath])
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return albumViewItem
|
return albumViewItem
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,46 +9,13 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
||||||
var queue: [QueueItem] = []
|
|
||||||
var queuePos: Int = -1
|
|
||||||
var currentSong: Song?
|
|
||||||
|
|
||||||
var queueIcon: NSImage? = nil
|
var queueIcon: NSImage? = nil
|
||||||
|
|
||||||
func updateQueue(_ queue: [MPDClient.MPDSong]) {
|
func setQueueIcon() {
|
||||||
queuePos = -1
|
switch AppDelegate.store.state.playerState.state {
|
||||||
|
case .playing?:
|
||||||
self.queue = queue.enumerated().map { index, mpdSong in
|
|
||||||
let song = Song(mpdSong: mpdSong)
|
|
||||||
return QueueItem(
|
|
||||||
song: song,
|
|
||||||
queuePos: index,
|
|
||||||
isPlaying: index == queuePos
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setQueuePos(_ queuePos: Int) {
|
|
||||||
let oldSongRowPos = self.queuePos
|
|
||||||
let newSongRowPos = queuePos
|
|
||||||
self.queuePos = queuePos
|
|
||||||
|
|
||||||
if oldSongRowPos >= 0 {
|
|
||||||
queue[oldSongRowPos].isPlaying = false
|
|
||||||
}
|
|
||||||
if newSongRowPos >= 0 {
|
|
||||||
queue[newSongRowPos].isPlaying = true
|
|
||||||
currentSong = queue[newSongRowPos].song
|
|
||||||
} else {
|
|
||||||
currentSong = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setQueueIcon(_ state: MPDClient.MPDStatus.State) {
|
|
||||||
switch state {
|
|
||||||
case .playing:
|
|
||||||
queueIcon = .playIcon
|
queueIcon = .playIcon
|
||||||
case .paused:
|
case .paused?:
|
||||||
queueIcon = .pauseIcon
|
queueIcon = .pauseIcon
|
||||||
default:
|
default:
|
||||||
queueIcon = nil
|
queueIcon = nil
|
||||||
@ -56,7 +23,7 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
||||||
return queue.count + 1
|
return AppDelegate.store.state.queueState.queue.count + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
||||||
@ -65,7 +32,7 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
|||||||
|
|
||||||
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 queue[index - 1]
|
return AppDelegate.store.state.queueState.queue[index - 1]
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,3 +30,10 @@ struct Album {
|
|||||||
return "\(title) - \(artist)".sha1()
|
return "\(title) - \(artist)".sha1()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Album: Equatable {
|
||||||
|
static func == (lhs: Album, rhs: Album) -> Bool {
|
||||||
|
return (lhs.artist == rhs.artist) &&
|
||||||
|
(lhs.title == rhs.title)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -13,3 +13,11 @@ struct QueueItem {
|
|||||||
var queuePos: Int
|
var queuePos: Int
|
||||||
var isPlaying: Bool
|
var isPlaying: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension QueueItem: Equatable {
|
||||||
|
static func == (lhs: QueueItem, rhs: QueueItem) -> Bool {
|
||||||
|
return (lhs.song == rhs.song) &&
|
||||||
|
(lhs.queuePos == rhs.queuePos) &&
|
||||||
|
(lhs.isPlaying == rhs.isPlaying)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -23,3 +23,11 @@ struct Song {
|
|||||||
return Album(mpdAlbum: mpdSong.album)
|
return Album(mpdAlbum: mpdSong.album)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension Song: Equatable {
|
||||||
|
static func == (lhs: Song, rhs: Song) -> Bool {
|
||||||
|
return (lhs.title == rhs.title) &&
|
||||||
|
(lhs.artist == rhs.artist) &&
|
||||||
|
(lhs.album == rhs.album)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ class TrackTimer: NSObject {
|
|||||||
startTime = CACurrentMediaTime()
|
startTime = CACurrentMediaTime()
|
||||||
startElapsed = Double(elapsedTimeMs) / 1000
|
startElapsed = Double(elapsedTimeMs) / 1000
|
||||||
|
|
||||||
DispatchQueue.main.sync {
|
DispatchQueue.main.async {
|
||||||
self.timer = Timer.scheduledTimer(
|
self.timer = Timer.scheduledTimer(
|
||||||
withTimeInterval: 0.25,
|
withTimeInterval: 0.25,
|
||||||
repeats: true
|
repeats: true
|
||||||
|
|||||||
22
Persephone/Reducers/AlbumListReducer.swift
Normal file
22
Persephone/Reducers/AlbumListReducer.swift
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// AlbumListReducer.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/4/21.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
func albumListReducer(action: Action, state: AlbumListState?) -> AlbumListState {
|
||||||
|
var state = state ?? AlbumListState()
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case let action as UpdateAlbumListAction:
|
||||||
|
state.albums = action.albums.map { Album(mpdAlbum: $0) }
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
@ -6,11 +6,13 @@
|
|||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import ReSwift
|
import ReSwift
|
||||||
|
|
||||||
func appReducer(action: Action, state: AppState?) -> AppState {
|
func appReducer(action: Action, state: AppState?) -> AppState {
|
||||||
|
print(action)
|
||||||
return AppState(
|
return AppState(
|
||||||
playerState: playerReducer(action: action, state: state?.playerState)
|
playerState: playerReducer(action: action, state: state?.playerState),
|
||||||
|
queueState: queueReducer(action: action, state: state?.queueState),
|
||||||
|
albumListState: albumListReducer(action: action, state: state?.albumListState)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
45
Persephone/Reducers/QueueReducer.swift
Normal file
45
Persephone/Reducers/QueueReducer.swift
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// QueueReducer.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/4/21.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
func queueReducer(action: Action, state: QueueState?) -> QueueState {
|
||||||
|
var state = state ?? QueueState()
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case let action as UpdateQueueAction:
|
||||||
|
state.queuePos = -1
|
||||||
|
|
||||||
|
state.queue = action.queue.enumerated().map { index, mpdSong in
|
||||||
|
let song = Song(mpdSong: mpdSong)
|
||||||
|
|
||||||
|
return QueueItem(
|
||||||
|
song: song,
|
||||||
|
queuePos: index,
|
||||||
|
isPlaying: index == state.queuePos
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
case let action as UpdateQueuePosAction:
|
||||||
|
let oldSongRowPos = state.queuePos
|
||||||
|
let newSongRowPos = action.queuePos
|
||||||
|
state.queuePos = action.queuePos
|
||||||
|
|
||||||
|
if oldSongRowPos >= 0 {
|
||||||
|
state.queue[oldSongRowPos].isPlaying = false
|
||||||
|
}
|
||||||
|
if newSongRowPos >= 0 {
|
||||||
|
state.queue[newSongRowPos].isPlaying = true
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
@ -10,4 +10,11 @@ import ReSwift
|
|||||||
|
|
||||||
struct AlbumListState: StateType {
|
struct AlbumListState: StateType {
|
||||||
var albums: [Album] = []
|
var albums: [Album] = []
|
||||||
|
var albumsWithUpdates: [Int]
|
||||||
|
}
|
||||||
|
|
||||||
|
extension AlbumListState: Equatable {
|
||||||
|
static func == (lhs: AlbumListState, rhs: AlbumListState) -> Bool {
|
||||||
|
return lhs.albums == rhs.albums
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,6 @@ import ReSwift
|
|||||||
|
|
||||||
struct AppState: StateType {
|
struct AppState: StateType {
|
||||||
var playerState = PlayerState()
|
var playerState = PlayerState()
|
||||||
// var queueState = QueueState()
|
var queueState = QueueState()
|
||||||
// var albumListState = AlbumListState()
|
var albumListState = AlbumListState()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,3 +17,11 @@ struct PlayerState: StateType {
|
|||||||
var totalTime: UInt?
|
var totalTime: UInt?
|
||||||
var elapsedTimeMs: UInt?
|
var elapsedTimeMs: UInt?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension PlayerState: Equatable {
|
||||||
|
static func == (lhs: PlayerState, rhs: PlayerState) -> Bool {
|
||||||
|
return (lhs.state == rhs.state) &&
|
||||||
|
(lhs.totalTime == rhs.totalTime) &&
|
||||||
|
(lhs.elapsedTimeMs == rhs.elapsedTimeMs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -12,3 +12,10 @@ struct QueueState: StateType {
|
|||||||
var queue: [QueueItem] = []
|
var queue: [QueueItem] = []
|
||||||
var queuePos: Int = -1
|
var queuePos: Int = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension QueueState: Equatable {
|
||||||
|
static func == (lhs: QueueState, rhs: QueueState) -> Bool {
|
||||||
|
return (lhs.queue == rhs.queue) &&
|
||||||
|
(lhs.queuePos == rhs.queuePos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user