mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Current artwork and notifications
This commit is contained in:
parent
63afa3ffce
commit
d2d4705e87
@ -100,6 +100,10 @@
|
||||
E4B11BB02274F71A0075461B /* EnumEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BAF2274F71A0075461B /* EnumEquatable.swift */; };
|
||||
E4B11BB22274F9520075461B /* ResetAlbumListArt.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BB12274F9520075461B /* ResetAlbumListArt.swift */; };
|
||||
E4B11BB42275002D0075461B /* UpdateMPDDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BB32275002D0075461B /* UpdateMPDDatabase.swift */; };
|
||||
E4B11BB62275374B0075461B /* UserNotificationsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BB52275374B0075461B /* UserNotificationsController.swift */; };
|
||||
E4B11BB8227538FA0075461B /* CurrentArtView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BB7227538FA0075461B /* CurrentArtView.swift */; };
|
||||
E4B11BBA22753BF10075461B /* UpdateCurrentSong.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BB922753BF10075461B /* UpdateCurrentSong.swift */; };
|
||||
E4B11BBC227541C40075461B /* UpdateCurrentArtwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BBB227541C40075461B /* UpdateCurrentArtwork.swift */; };
|
||||
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
|
||||
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* MPDIdle.swift */; };
|
||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
|
||||
@ -291,6 +295,10 @@
|
||||
E4B11BAF2274F71A0075461B /* EnumEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumEquatable.swift; sourceTree = "<group>"; };
|
||||
E4B11BB12274F9520075461B /* ResetAlbumListArt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetAlbumListArt.swift; sourceTree = "<group>"; };
|
||||
E4B11BB32275002D0075461B /* UpdateMPDDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateMPDDatabase.swift; sourceTree = "<group>"; };
|
||||
E4B11BB52275374B0075461B /* UserNotificationsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationsController.swift; sourceTree = "<group>"; };
|
||||
E4B11BB7227538FA0075461B /* CurrentArtView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentArtView.swift; sourceTree = "<group>"; };
|
||||
E4B11BB922753BF10075461B /* UpdateCurrentSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCurrentSong.swift; sourceTree = "<group>"; };
|
||||
E4B11BBB227541C40075461B /* UpdateCurrentArtwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCurrentArtwork.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>"; };
|
||||
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
|
||||
@ -444,6 +452,7 @@
|
||||
children = (
|
||||
E47E2FD62220720300F747E6 /* AlbumItemView.swift */,
|
||||
E47E2FD222205D2500F747E6 /* MainWindow.swift */,
|
||||
E4B11BB7227538FA0075461B /* CurrentArtView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -622,6 +631,8 @@
|
||||
E4B11BAC2274F2E80075461B /* UpdateAlbumArt.swift */,
|
||||
E4B11BB12274F9520075461B /* ResetAlbumListArt.swift */,
|
||||
E4B11BB32275002D0075461B /* UpdateMPDDatabase.swift */,
|
||||
E4B11BB922753BF10075461B /* UpdateCurrentSong.swift */,
|
||||
E4B11BBB227541C40075461B /* UpdateCurrentArtwork.swift */,
|
||||
);
|
||||
path = Actions;
|
||||
sourceTree = "<group>";
|
||||
@ -664,6 +675,7 @@
|
||||
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
||||
E465049921E94DF500A70F4C /* WindowController.swift */,
|
||||
E4B11BB52275374B0075461B /* UserNotificationsController.swift */,
|
||||
);
|
||||
path = Controllers;
|
||||
sourceTree = "<group>";
|
||||
@ -883,6 +895,7 @@
|
||||
E4B11BA92274EDE30075461B /* Loading.swift in Sources */,
|
||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
||||
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
|
||||
E4B11BB62275374B0075461B /* UserNotificationsController.swift in Sources */,
|
||||
E4B11B7B226D34F80075461B /* UpdateAlbumListAction.swift in Sources */,
|
||||
E4B11B6D226A5B180075461B /* UpdateQueueAction.swift in Sources */,
|
||||
E4B11B68226A4FA00075461B /* QueueState.swift in Sources */,
|
||||
@ -913,6 +926,7 @@
|
||||
E4A83BF12221FAA00098FED6 /* PreferencesViewController.swift in Sources */,
|
||||
E4B11B61226A4C000075461B /* PlayerReducer.swift in Sources */,
|
||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||
E4B11BBA22753BF10075461B /* UpdateCurrentSong.swift in Sources */,
|
||||
E4B11B71226A64E60075461B /* UpdateElapsedTimeAction.swift in Sources */,
|
||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||
E40F41F3221EDE27004B6CB8 /* Preferences.swift in Sources */,
|
||||
@ -929,6 +943,7 @@
|
||||
E41E52FF223BF95E00173814 /* MPDClient+Transport.swift in Sources */,
|
||||
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */,
|
||||
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */,
|
||||
E4B11BB8227538FA0075461B /* CurrentArtView.swift in Sources */,
|
||||
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */,
|
||||
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */,
|
||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
||||
@ -948,6 +963,7 @@
|
||||
E4B11B6A226A4FBC0075461B /* AlbumListState.swift in Sources */,
|
||||
E41E5305223BFB0700173814 /* MPDClient+Error.swift in Sources */,
|
||||
E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */,
|
||||
E4B11BBC227541C40075461B /* UpdateCurrentArtwork.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
14
Persephone/Actions/UpdateCurrentArtwork.swift
Normal file
14
Persephone/Actions/UpdateCurrentArtwork.swift
Normal file
@ -0,0 +1,14 @@
|
||||
//
|
||||
// UpdateCurrentArtwork.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/4/27.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import ReSwift
|
||||
|
||||
struct UpdateCurrentArtwork: Action {
|
||||
var coverArt: NSImage?
|
||||
}
|
||||
13
Persephone/Actions/UpdateCurrentSong.swift
Normal file
13
Persephone/Actions/UpdateCurrentSong.swift
Normal file
@ -0,0 +1,13 @@
|
||||
//
|
||||
// UpdateCurrentSong.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/4/27.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import ReSwift
|
||||
|
||||
struct UpdateCurrentSong: Action {
|
||||
var currentSong: Song
|
||||
}
|
||||
@ -16,6 +16,7 @@ class AppDelegate: NSObject,
|
||||
MediaKeyTapDelegate {
|
||||
var preferences = Preferences()
|
||||
var mediaKeyTap: MediaKeyTap?
|
||||
var userNotificationsController: UserNotificationsController?
|
||||
|
||||
static let mpdClient = MPDClient(
|
||||
withDelegate: NotificationsController()
|
||||
@ -35,10 +36,10 @@ class AppDelegate: NSObject,
|
||||
mediaKeyTap?.start()
|
||||
|
||||
AppDelegate.store.subscribe(self) {
|
||||
(subscription: Subscription<AppState>) -> Subscription<PlayerState> in
|
||||
|
||||
subscription.select { state in state.playerState }
|
||||
$0.select { $0.playerState }
|
||||
}
|
||||
|
||||
userNotificationsController = UserNotificationsController()
|
||||
}
|
||||
|
||||
func applicationWillTerminate(_ aNotification: Notification) {
|
||||
|
||||
@ -24,9 +24,7 @@ class AlbumViewController: NSViewController,
|
||||
super.viewDidLoad()
|
||||
|
||||
AppDelegate.store.subscribe(self) {
|
||||
(subscription: Subscription<AppState>) -> Subscription<AlbumListState> in
|
||||
|
||||
subscription.select { state -> AlbumListState in state.albumListState }
|
||||
$0.select { $0.albumListState }
|
||||
}
|
||||
|
||||
albumScrollView.postsBoundsChangedNotifications = true
|
||||
|
||||
@ -34,7 +34,7 @@ class AlbumViewItem: NSCollectionViewItem {
|
||||
|
||||
switch album.coverArt {
|
||||
case .loaded(let coverArt):
|
||||
albumCoverView.image = coverArt
|
||||
albumCoverView.image = coverArt ?? .defaultCoverArt
|
||||
default:
|
||||
albumCoverView.image = .defaultCoverArt
|
||||
}
|
||||
|
||||
@ -20,9 +20,7 @@ class QueueViewController: NSViewController,
|
||||
super.viewDidLoad()
|
||||
|
||||
AppDelegate.store.subscribe(self) {
|
||||
(subscription: Subscription<AppState>) -> Subscription<QueueState> in
|
||||
|
||||
subscription.select { state in state.queueState }
|
||||
$0.select { $0.queueState }
|
||||
}
|
||||
|
||||
queueView.dataSource = dataSource
|
||||
@ -52,38 +50,6 @@ class QueueViewController: NSViewController,
|
||||
}
|
||||
}
|
||||
|
||||
func notifyTrack(_ state: QueueState) {
|
||||
guard let currentSong = state.currentSong,
|
||||
let status = AppDelegate.mpdClient.status,
|
||||
status.state == .playing
|
||||
else { return }
|
||||
|
||||
SongNotifierService(song: currentSong, image: queueAlbumArtImage.image)
|
||||
.deliver()
|
||||
}
|
||||
|
||||
func updateAlbumArt(_ state: QueueState) {
|
||||
if let playingQueueItem = state.queue.first(
|
||||
where: { $0.isPlaying }
|
||||
) {
|
||||
let albumArtService = AlbumArtService(song: playingQueueItem.song)
|
||||
|
||||
albumArtService.fetchBigAlbumArt()
|
||||
.done() {
|
||||
if let image = $0 {
|
||||
self.queueAlbumArtImage.image = image
|
||||
} else {
|
||||
self.queueAlbumArtImage.image = NSImage.defaultCoverArt
|
||||
}
|
||||
|
||||
self.notifyTrack(state)
|
||||
}
|
||||
.cauterize()
|
||||
} else {
|
||||
queueAlbumArtImage.image = NSImage.defaultCoverArt
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(
|
||||
_ outlineView: NSOutlineView,
|
||||
selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet
|
||||
@ -164,6 +130,5 @@ extension QueueViewController: StoreSubscriber {
|
||||
func newState(state: StoreSubscriberStateType) {
|
||||
dataSource.setQueueIcon()
|
||||
queueView.reloadData()
|
||||
updateAlbumArt(state)
|
||||
}
|
||||
}
|
||||
|
||||
42
Persephone/Controllers/UserNotificationsController.swift
Normal file
42
Persephone/Controllers/UserNotificationsController.swift
Normal file
@ -0,0 +1,42 @@
|
||||
//
|
||||
// UserNotificationsController.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/4/27.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ReSwift
|
||||
|
||||
class UserNotificationsController {
|
||||
init() {
|
||||
AppDelegate.store.subscribe(self) {
|
||||
$0.select { $0.playerState.currentSong }
|
||||
}
|
||||
}
|
||||
|
||||
func notifyTrack(_ state: Song?) {
|
||||
guard let currentSong = state,
|
||||
let status = AppDelegate.mpdClient.status,
|
||||
status.state == .playing
|
||||
else { return }
|
||||
|
||||
let albumArtService = AlbumArtService(song: currentSong)
|
||||
|
||||
albumArtService.fetchBigAlbumArt()
|
||||
.done() {
|
||||
SongNotifierService(song: currentSong, image: $0)
|
||||
.deliver()
|
||||
}
|
||||
.cauterize()
|
||||
}
|
||||
}
|
||||
|
||||
extension UserNotificationsController: StoreSubscriber {
|
||||
typealias StoreSubscriberStateType = Song?
|
||||
|
||||
func newState(state: Song?) {
|
||||
notifyTrack(state)
|
||||
}
|
||||
}
|
||||
@ -22,9 +22,7 @@ class WindowController: NSWindowController {
|
||||
window?.titleVisibility = .hidden
|
||||
|
||||
AppDelegate.store.subscribe(self) {
|
||||
(subscription: Subscription<AppState>) -> Subscription<PlayerState> in
|
||||
|
||||
subscription.select { state in state.playerState }
|
||||
$0.select { $0.playerState }
|
||||
}
|
||||
|
||||
trackProgress.font = .timerFont
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.11.2-alpha</string>
|
||||
<string>0.12.0-pre-alpha</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
|
||||
@ -25,6 +25,32 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
|
||||
AppDelegate.trackTimer.stop(elapsedTimeMs: state.elapsedTimeMs)
|
||||
}
|
||||
|
||||
case let action as UpdateCurrentSong:
|
||||
state.currentSong = action.currentSong
|
||||
|
||||
if let currentSong = state.currentSong {
|
||||
let albumArtService = AlbumArtService(song: currentSong)
|
||||
|
||||
albumArtService.fetchBigAlbumArt()
|
||||
.done() { image in
|
||||
DispatchQueue.main.async {
|
||||
if let image = image {
|
||||
AppDelegate.store.dispatch(UpdateCurrentArtwork(coverArt: image))
|
||||
} else {
|
||||
AppDelegate.store.dispatch(UpdateCurrentArtwork(coverArt: .defaultCoverArt))
|
||||
}
|
||||
}
|
||||
}
|
||||
.cauterize()
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
AppDelegate.store.dispatch(UpdateCurrentArtwork(coverArt: .defaultCoverArt))
|
||||
}
|
||||
}
|
||||
|
||||
case let action as UpdateCurrentArtwork:
|
||||
state.currentArtwork = action.coverArt
|
||||
|
||||
case let action as UpdateElapsedTimeAction:
|
||||
state.elapsedTimeMs = action.elapsedTimeMs
|
||||
|
||||
@ -40,13 +66,3 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
|
||||
|
||||
return state
|
||||
}
|
||||
|
||||
func updateElapsedTime(_ timer: Timer) {
|
||||
guard let userInfo = timer.userInfo as? Dictionary<String, Any>,
|
||||
let elapsedTimeMs = userInfo["elapsedTimeMs"] as? UInt
|
||||
else { return }
|
||||
|
||||
AppDelegate.store.dispatch(
|
||||
UpdateElapsedTimeAction(elapsedTimeMs: elapsedTimeMs)
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import ReSwift
|
||||
|
||||
func queueReducer(action: Action, state: QueueState?) -> QueueState {
|
||||
@ -37,6 +38,12 @@ func queueReducer(action: Action, state: QueueState?) -> QueueState {
|
||||
state.queue[newSongRowPos].isPlaying = true
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
AppDelegate.store.dispatch(
|
||||
UpdateCurrentSong(currentSong: state.queue[newSongRowPos].song)
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@ -635,7 +635,7 @@
|
||||
<rect key="frame" x="0.0" y="220" width="328" height="328"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Dw3-M5-tWY">
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" horizontalCompressionResistancePriority="250" verticalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="Dw3-M5-tWY" customClass="CurrentArtView" customModule="Persephone" customModuleProvider="target">
|
||||
<rect key="frame" x="0.0" y="0.0" width="328" height="328"/>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="blankAlbum" id="IoN-3N-TCb"/>
|
||||
</imageView>
|
||||
|
||||
@ -11,6 +11,8 @@ import ReSwift
|
||||
|
||||
struct PlayerState: StateType {
|
||||
var status: MPDClient.MPDStatus?
|
||||
var currentSong: Song?
|
||||
var currentArtwork: NSImage?
|
||||
|
||||
var state: MPDClient.MPDStatus.State?
|
||||
|
||||
|
||||
32
Persephone/Views/CurrentArtView.swift
Normal file
32
Persephone/Views/CurrentArtView.swift
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// CurrentArtView.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/4/27.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
import ReSwift
|
||||
|
||||
class CurrentArtView: NSImageView {
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
|
||||
AppDelegate.store.subscribe(self) {
|
||||
$0.select { $0.playerState.currentArtwork }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension CurrentArtView: StoreSubscriber {
|
||||
typealias StoreSubscriberStateType = NSImage?
|
||||
|
||||
func newState(state: NSImage?) {
|
||||
if let coverArt = state {
|
||||
image = coverArt
|
||||
} else {
|
||||
image = .defaultCoverArt
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user