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

Compare commits

..

No commits in common. "4d2a8087ed50c54e748fb5ab63a5c36082988cf7" and "22bb7efef2d38f448b512e2551ae3e868898f18e" have entirely different histories.

38 changed files with 90 additions and 88 deletions

View File

@ -6,7 +6,7 @@
// Copyright © 2018 Dan Barber. All rights reserved. // Copyright © 2018 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
import MediaKeyTap import MediaKeyTap

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
import Differ import Differ
@ -28,6 +28,15 @@ class AlbumViewController: NSViewController,
albumScrollView.postsBoundsChangedNotifications = true albumScrollView.postsBoundsChangedNotifications = true
albumCollectionView.dataSource = dataSource albumCollectionView.dataSource = dataSource
// preferences.addObserver(self, forKeyPath: "mpdLibraryDir")
// preferences.addObserver(self, forKeyPath: "fetchMissingArtworkFromInternet")
}
override func viewWillDisappear() {
super.viewWillDisappear()
AppDelegate.store.unsubscribe(self)
} }
override func viewWillLayout() { override func viewWillLayout() {
@ -59,7 +68,7 @@ class AlbumViewController: NSViewController,
case "mpdLibraryDir": case "mpdLibraryDir":
albumCollectionView.reloadData() albumCollectionView.reloadData()
case "fetchMissingArtworkFromInternet": case "fetchMissingArtworkFromInternet":
AppDelegate.store.dispatch(ResetAlbumListCoverArtAction()) AppDelegate.store.dispatch(ResetAlbumListCoverArt())
default: default:
break break
} }
@ -73,11 +82,16 @@ extension AlbumViewController: StoreSubscriber {
typealias StoreSubscriberStateType = AlbumListState typealias StoreSubscriberStateType = AlbumListState
func newState(state: StoreSubscriberStateType) { func newState(state: StoreSubscriberStateType) {
let oldAlbums = dataSource.albums if dataSource.albums == [] {
dataSource.albums = state.albums dataSource.albums = state.albums
albumCollectionView.animateItemChanges( albumCollectionView.reloadData()
oldData: oldAlbums, } else {
newData: dataSource.albums let oldAlbums = dataSource.albums
) dataSource.albums = state.albums
albumCollectionView.animateItemChanges(
oldData: oldAlbums,
newData: dataSource.albums
)
}
} }
} }

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class AlbumViewItem: NSCollectionViewItem { class AlbumViewItem: NSCollectionViewItem {
var observer: NSKeyValueObservation? var observer: NSKeyValueObservation?

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class MainSplitViewController: NSSplitViewController { class MainSplitViewController: NSSplitViewController {
override func keyDown(with event: NSEvent) { override func keyDown(with event: NSEvent) {

View File

@ -30,13 +30,13 @@ class NotificationsController: MPDClientDelegate {
func willStartDatabaseUpdate(mpdClient: MPDClient) { func willStartDatabaseUpdate(mpdClient: MPDClient) {
DispatchQueue.main.async { DispatchQueue.main.async {
AppDelegate.store.dispatch(StartedDatabaseUpdateAction()) AppDelegate.store.dispatch(StartedDatabaseUpdate())
} }
} }
func didFinishDatabaseUpdate(mpdClient: MPDClient) { func didFinishDatabaseUpdate(mpdClient: MPDClient) {
DispatchQueue.main.async { DispatchQueue.main.async {
AppDelegate.store.dispatch(FinishedDatabaseUpdateAction()) AppDelegate.store.dispatch(FinishedDatabaseUpdate())
} }
} }

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
class QueueViewController: NSViewController, class QueueViewController: NSViewController,
@ -27,6 +27,12 @@ class QueueViewController: NSViewController,
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
} }
override func viewWillDisappear() {
super.viewWillDisappear()
AppDelegate.store.unsubscribe(self)
}
override func keyDown(with event: NSEvent) { override func keyDown(with event: NSEvent) {
switch event.keyCode { switch event.keyCode {
case NSEvent.keyCodeSpace: case NSEvent.keyCodeSpace:
@ -122,8 +128,7 @@ extension QueueViewController: StoreSubscriber {
typealias StoreSubscriberStateType = QueueState typealias StoreSubscriberStateType = QueueState
func newState(state: StoreSubscriberStateType) { func newState(state: StoreSubscriberStateType) {
dataSource.queue = state.queue dataSource.setQueueIcon()
dataSource.setQueueIcon(state)
queueView.reloadData() queueView.reloadData()
} }
} }

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
class WindowController: NSWindowController { class WindowController: NSWindowController {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import PromiseKit import PromiseKit
class AlbumDataSource: NSObject, NSCollectionViewDataSource { class AlbumDataSource: NSObject, NSCollectionViewDataSource {
@ -33,7 +33,7 @@ class AlbumDataSource: NSObject, NSCollectionViewDataSource {
.done { image in .done { image in
DispatchQueue.main.async { DispatchQueue.main.async {
AppDelegate.store.dispatch( AppDelegate.store.dispatch(
UpdateCoverArtAction(coverArt: image, albumIndex: indexPath.item) UpdateCoverArt(coverArt: image, albumIndex: indexPath.item)
) )
} }
} }

View File

@ -6,14 +6,13 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class QueueDataSource: NSObject, NSOutlineViewDataSource { class QueueDataSource: NSObject, NSOutlineViewDataSource {
var queue: [QueueItem] = []
var queueIcon: NSImage? = nil var queueIcon: NSImage? = nil
func setQueueIcon(_ state: QueueState) { func setQueueIcon() {
switch state.state { switch AppDelegate.store.state.playerState.state {
case .playing?: case .playing?:
queueIcon = .playIcon queueIcon = .playIcon
case .paused?: case .paused?:
@ -24,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 {
@ -33,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
} }

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
extension CGColor { extension CGColor {
static let albumBorderColorLight = NSColor.black.withAlphaComponent(0.15).cgColor static let albumBorderColorLight = NSColor.black.withAlphaComponent(0.15).cgColor

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
extension NSEvent { extension NSEvent {
static let keyCodeSpace: UInt16 = 49 static let keyCodeSpace: UInt16 = 49

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
extension NSFont { extension NSFont {
static let systemFontRegular = systemFont(ofSize: 13, weight: .regular) static let systemFontRegular = systemFont(ofSize: 13, weight: .regular)

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
extension NSImage { extension NSImage {
static let playIcon = NSImage(named: "playButton") static let playIcon = NSImage(named: "playButton")

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
extension NSUserInterfaceItemIdentifier { extension NSUserInterfaceItemIdentifier {
static let queueSongTitleColumn = NSUserInterfaceItemIdentifier("songTitleColumn") static let queueSongTitleColumn = NSUserInterfaceItemIdentifier("songTitleColumn")

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class AlbumViewLayout: NSCollectionViewFlowLayout { class AlbumViewLayout: NSCollectionViewFlowLayout {
let maxItemWidth: CGFloat = 180 let maxItemWidth: CGFloat = 180

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import CryptoSwift import CryptoSwift
struct Album { struct Album {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class TrackTimer: NSObject { class TrackTimer: NSObject {
var timer: Timer? var timer: Timer?
@ -16,12 +16,12 @@ class TrackTimer: NSObject {
func start(elapsedTimeMs: UInt?) { func start(elapsedTimeMs: UInt?) {
guard let elapsedTimeMs = elapsedTimeMs else { return } guard let elapsedTimeMs = elapsedTimeMs else { return }
timer?.invalidate()
startTime = CACurrentMediaTime() startTime = CACurrentMediaTime()
startElapsed = Double(elapsedTimeMs) / 1000 startElapsed = Double(elapsedTimeMs) / 1000
DispatchQueue.main.async { DispatchQueue.main.async {
self.timer?.invalidate()
self.timer = Timer.scheduledTimer( self.timer = Timer.scheduledTimer(
withTimeInterval: 0.25, withTimeInterval: 0.25,
repeats: true repeats: true
@ -41,9 +41,9 @@ class TrackTimer: NSObject {
func stop(elapsedTimeMs: UInt?) { func stop(elapsedTimeMs: UInt?) {
guard let elapsedTimeMs = elapsedTimeMs else { return } guard let elapsedTimeMs = elapsedTimeMs else { return }
DispatchQueue.main.async { timer?.invalidate()
self.timer?.invalidate()
DispatchQueue.main.async {
AppDelegate.store.dispatch( AppDelegate.store.dispatch(
UpdateElapsedTimeAction(elapsedTimeMs: elapsedTimeMs) UpdateElapsedTimeAction(elapsedTimeMs: elapsedTimeMs)
) )

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class CoverArtQueue { class CoverArtQueue {
static let shared = CoverArtQueue() static let shared = CoverArtQueue()

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class CoverArtPrefsController: NSViewController { class CoverArtPrefsController: NSViewController {
override func viewDidLoad() { override func viewDidLoad() {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
class GeneralPrefsViewController: NSViewController { class GeneralPrefsViewController: NSViewController {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class PreferencesViewController: NSTabViewController { class PreferencesViewController: NSTabViewController {
private lazy var tabViewSizes: [String : NSSize] = [:] private lazy var tabViewSizes: [String : NSSize] = [:]

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class PreferencesWindowController: NSWindowController, NSWindowDelegate { class PreferencesWindowController: NSWindowController, NSWindowDelegate {
override func windowDidLoad() { override func windowDidLoad() {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import PromiseKit import PromiseKit
class CoverArtService { class CoverArtService {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import PromiseKit import PromiseKit
extension CoverArtService { extension CoverArtService {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import PromiseKit import PromiseKit
extension CoverArtService { extension CoverArtService {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import SwiftyJSON import SwiftyJSON
import PromiseKit import PromiseKit
import PMKFoundation import PMKFoundation

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
struct SongNotifierService { struct SongNotifierService {
let song: Song let song: Song

View File

@ -6,12 +6,12 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
struct ResetAlbumListCoverArtAction: Action {} struct ResetAlbumListCoverArt: Action {}
struct UpdateCoverArtAction: Action { struct UpdateCoverArt: Action {
var coverArt: NSImage? var coverArt: NSImage?
var albumIndex: Int var albumIndex: Int
} }

View File

@ -6,14 +6,14 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
struct UpdateCurrentCoverArtAction: Action { struct UpdateCurrentCoverArt: Action {
var coverArt: NSImage? var coverArt: NSImage?
} }
struct UpdateCurrentSongAction: Action { struct UpdateCurrentSong: Action {
var currentSong: Song var currentSong: Song
} }
@ -25,6 +25,6 @@ struct UpdateStatusAction: Action {
var status: MPDClient.MPDStatus var status: MPDClient.MPDStatus
} }
struct StartedDatabaseUpdateAction: Action {} struct StartedDatabaseUpdate: Action {}
struct FinishedDatabaseUpdateAction: Action {} struct FinishedDatabaseUpdate: Action {}

View File

@ -15,7 +15,3 @@ struct UpdateQueueAction: Action {
struct UpdateQueuePosAction: Action { struct UpdateQueuePosAction: Action {
var queuePos: Int var queuePos: Int
} }
struct UpdateQueuePlayerStateAction: Action {
var state: MPDClient.MPDStatus.State?
}

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
struct PlayerState: StateType { struct PlayerState: StateType {

View File

@ -11,14 +11,11 @@ import ReSwift
struct QueueState: StateType { struct QueueState: StateType {
var queue: [QueueItem] = [] var queue: [QueueItem] = []
var queuePos: Int = -1 var queuePos: Int = -1
var state: MPDClient.MPDStatus.State?
} }
extension QueueState: Equatable { extension QueueState: Equatable {
static func == (lhs: QueueState, rhs: QueueState) -> Bool { static func == (lhs: QueueState, rhs: QueueState) -> Bool {
return (lhs.queue == rhs.queue) && return (lhs.queue == rhs.queue) &&
(lhs.queuePos == rhs.queuePos) && (lhs.queuePos == rhs.queuePos)
(lhs.state == rhs.state)
} }
} }

View File

@ -15,10 +15,10 @@ func albumListReducer(action: Action, state: AlbumListState?) -> AlbumListState
case let action as UpdateAlbumListAction: case let action as UpdateAlbumListAction:
state.albums = action.albums.map { Album(mpdAlbum: $0) } state.albums = action.albums.map { Album(mpdAlbum: $0) }
case let action as UpdateCoverArtAction: case let action as UpdateCoverArt:
state.albums[action.albumIndex].coverArt = .loaded(action.coverArt) state.albums[action.albumIndex].coverArt = .loaded(action.coverArt)
case is ResetAlbumListCoverArtAction: case is ResetAlbumListCoverArt:
state.albums = AppDelegate.store.state.albumListState.albums.map { state.albums = AppDelegate.store.state.albumListState.albums.map {
var album = $0 var album = $0
switch album.coverArt { switch album.coverArt {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
func playerReducer(action: Action, state: PlayerState?) -> PlayerState { func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
@ -25,13 +25,7 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
AppDelegate.trackTimer.stop(elapsedTimeMs: state.elapsedTimeMs) AppDelegate.trackTimer.stop(elapsedTimeMs: state.elapsedTimeMs)
} }
DispatchQueue.main.async { case let action as UpdateCurrentSong:
AppDelegate.store.dispatch(
UpdateQueuePlayerStateAction(state: state.state)
)
}
case let action as UpdateCurrentSongAction:
state.currentSong = action.currentSong state.currentSong = action.currentSong
if let currentSong = state.currentSong { if let currentSong = state.currentSong {
@ -41,29 +35,29 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
.done() { image in .done() { image in
DispatchQueue.main.async { DispatchQueue.main.async {
if let image = image { if let image = image {
AppDelegate.store.dispatch(UpdateCurrentCoverArtAction(coverArt: image)) AppDelegate.store.dispatch(UpdateCurrentCoverArt(coverArt: image))
} else { } else {
AppDelegate.store.dispatch(UpdateCurrentCoverArtAction(coverArt: .defaultCoverArt)) AppDelegate.store.dispatch(UpdateCurrentCoverArt(coverArt: .defaultCoverArt))
} }
} }
} }
.cauterize() .cauterize()
} else { } else {
DispatchQueue.main.async { DispatchQueue.main.async {
AppDelegate.store.dispatch(UpdateCurrentCoverArtAction(coverArt: .defaultCoverArt)) AppDelegate.store.dispatch(UpdateCurrentCoverArt(coverArt: .defaultCoverArt))
} }
} }
case let action as UpdateCurrentCoverArtAction: case let action as UpdateCurrentCoverArt:
state.currentArtwork = action.coverArt state.currentArtwork = action.coverArt
case let action as UpdateElapsedTimeAction: case let action as UpdateElapsedTimeAction:
state.elapsedTimeMs = action.elapsedTimeMs state.elapsedTimeMs = action.elapsedTimeMs
case is StartedDatabaseUpdateAction: case is StartedDatabaseUpdate:
state.databaseUpdating = true state.databaseUpdating = true
case is FinishedDatabaseUpdateAction: case is FinishedDatabaseUpdate:
state.databaseUpdating = false state.databaseUpdating = false
default: default:

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
func queueReducer(action: Action, state: QueueState?) -> QueueState { func queueReducer(action: Action, state: QueueState?) -> QueueState {
@ -40,12 +40,9 @@ func queueReducer(action: Action, state: QueueState?) -> QueueState {
DispatchQueue.main.async { DispatchQueue.main.async {
AppDelegate.store.dispatch( AppDelegate.store.dispatch(
UpdateCurrentSongAction(currentSong: state.queue[newSongRowPos].song) UpdateCurrentSong(currentSong: state.queue[newSongRowPos].song)
) )
} }
case let action as UpdateQueuePlayerStateAction:
state.state = action.state
default: default:
break break

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class AlbumItemView: NSView { class AlbumItemView: NSView {
var trackingArea: NSTrackingArea? var trackingArea: NSTrackingArea?

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
import ReSwift import ReSwift
class CurrentCoverArtView: NSImageView { class CurrentCoverArtView: NSImageView {

View File

@ -6,7 +6,7 @@
// Copyright © 2019 Dan Barber. All rights reserved. // Copyright © 2019 Dan Barber. All rights reserved.
// //
import AppKit import Cocoa
class MainWindow: NSWindow { class MainWindow: NSWindow {
override func keyDown(with event: NSEvent) { override func keyDown(with event: NSEvent) {