From 8bab7c2bf556a4d4bb16f825b7760a302c978443 Mon Sep 17 00:00:00 2001 From: Daniel Barber Date: Tue, 30 Apr 2019 09:11:50 -0400 Subject: [PATCH] Refactor more of the things! 1. Move all the mpdClient actions into a reducer. 2. Move global stuff into their own global struct --- Persephone.xcodeproj/project.pbxproj | 16 +++++++ Persephone/App.swift | 18 ++++++++ Persephone/AppDelegate.swift | 24 +++------- .../Controllers/AlbumViewController.swift | 4 +- Persephone/Controllers/AlbumViewItem.swift | 4 +- .../Controllers/MPDServerController.swift | 12 +++-- .../Controllers/NotificationsController.swift | 16 +++---- .../Controllers/QueueViewController.swift | 4 +- .../UserNotificationsController.swift | 4 +- Persephone/Controllers/WindowController.swift | 16 +++---- Persephone/DataSources/AlbumDataSource.swift | 4 +- Persephone/Models/TrackTimer.swift | 4 +- .../Controllers/CoverArtPrefsController.swift | 8 ++-- .../GeneralPrefsViewController.swift | 8 ++-- .../PreferencesWindowController.swift | 2 +- .../CoverArtService+Filesystem.swift | 4 +- .../Extensions/CoverArtService+Remote.swift | 2 +- Persephone/State/Actions/MPDActions.swift | 34 ++++++++++++++ Persephone/State/AppState.swift | 1 + Persephone/State/MPDState.swift | 11 +++++ .../State/Reducers/AlbumListReducer.swift | 2 +- Persephone/State/Reducers/AppReducer.swift | 3 +- Persephone/State/Reducers/MPDReducer.swift | 46 +++++++++++++++++++ Persephone/State/Reducers/PlayerReducer.swift | 12 ++--- Persephone/State/Reducers/QueueReducer.swift | 2 +- Persephone/Views/CurrentCoverArtView.swift | 2 +- 26 files changed, 191 insertions(+), 72 deletions(-) create mode 100644 Persephone/App.swift create mode 100644 Persephone/State/Actions/MPDActions.swift create mode 100644 Persephone/State/MPDState.swift create mode 100644 Persephone/State/Reducers/MPDReducer.swift diff --git a/Persephone.xcodeproj/project.pbxproj b/Persephone.xcodeproj/project.pbxproj index c00912a..b742579 100644 --- a/Persephone.xcodeproj/project.pbxproj +++ b/Persephone.xcodeproj/project.pbxproj @@ -39,6 +39,10 @@ E435E3E4221CD75D00184CFC /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E3221CD75D00184CFC /* NSImage.swift */; }; E439109822640213002982E9 /* SongNotifierService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E439109722640213002982E9 /* SongNotifierService.swift */; }; E4405192227644340090CD6F /* MPDServerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4405191227644340090CD6F /* MPDServerController.swift */; }; + E44051942278765A0090CD6F /* App.swift in Sources */ = {isa = PBXBuildFile; fileRef = E44051932278765A0090CD6F /* App.swift */; }; + E4405196227879960090CD6F /* MPDActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4405195227879960090CD6F /* MPDActions.swift */; }; + E440519822787CB40090CD6F /* MPDState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E440519722787CB40090CD6F /* MPDState.swift */; }; + E440519A22787CF60090CD6F /* MPDReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E440519922787CF60090CD6F /* MPDReducer.swift */; }; E450AD7E222620A10091BED3 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E450AD7D222620A10091BED3 /* Album.swift */; }; E450AD8F22262C620091BED3 /* PromiseKit.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E450AD8E22262C620091BED3 /* PromiseKit.framework.dSYM */; }; E450AD9122262C780091BED3 /* SwiftyJSON.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E450AD9022262C780091BED3 /* SwiftyJSON.framework.dSYM */; }; @@ -239,6 +243,10 @@ E435E3E3221CD75D00184CFC /* NSImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = ""; }; E439109722640213002982E9 /* SongNotifierService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongNotifierService.swift; sourceTree = ""; }; E4405191227644340090CD6F /* MPDServerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDServerController.swift; sourceTree = ""; }; + E44051932278765A0090CD6F /* App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = App.swift; sourceTree = ""; }; + E4405195227879960090CD6F /* MPDActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDActions.swift; sourceTree = ""; }; + E440519722787CB40090CD6F /* MPDState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDState.swift; sourceTree = ""; }; + E440519922787CF60090CD6F /* MPDReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDReducer.swift; sourceTree = ""; }; E450AD7D222620A10091BED3 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = ""; }; E450AD8522262AE60091BED3 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/Mac/SwiftyJSON.framework; sourceTree = ""; }; E450AD8C22262C590091BED3 /* PromiseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PromiseKit.framework; path = Carthage/Build/Mac/PromiseKit.framework; sourceTree = ""; }; @@ -370,6 +378,7 @@ children = ( E4B11BAE2274F7030075461B /* Protocols */, E407861B2110CE6E006887B1 /* AppDelegate.swift */, + E44051932278765A0090CD6F /* App.swift */, E407861F2110CE70006887B1 /* Assets.xcassets */, E4D1B597220BA3A20026F233 /* Controllers */, E4F6B45E221E117600ACF42A /* DataSources */, @@ -598,6 +607,7 @@ E4B11B74226CC4D30075461B /* QueueReducer.swift */, E4B11B78226D346B0075461B /* AlbumListReducer.swift */, E4FF718F227601B400D4C412 /* PreferencesReducer.swift */, + E440519922787CF60090CD6F /* MPDReducer.swift */, ); path = Reducers; sourceTree = ""; @@ -612,6 +622,7 @@ E4B11B67226A4FA00075461B /* QueueState.swift */, E4B11B69226A4FBC0075461B /* AlbumListState.swift */, E4FF718D2276010E00D4C412 /* PreferencesState.swift */, + E440519722787CB40090CD6F /* MPDState.swift */, ); path = State; sourceTree = ""; @@ -623,6 +634,7 @@ E4B11BBD2275EDAA0075461B /* PlayerActions.swift */, E4B11BBF2275EE150075461B /* QueueActions.swift */, E4FF71912276029000D4C412 /* PreferencesActions.swift */, + E4405195227879960090CD6F /* MPDActions.swift */, ); path = Actions; sourceTree = ""; @@ -889,6 +901,7 @@ E4B11BB62275374B0075461B /* UserNotificationsController.swift in Sources */, E4B11B68226A4FA00075461B /* QueueState.swift in Sources */, E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */, + E4405196227879960090CD6F /* MPDActions.swift in Sources */, E4405192227644340090CD6F /* MPDServerController.swift in Sources */, E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */, E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */, @@ -897,6 +910,7 @@ E41E5307223C019100173814 /* MPDClient+Status.swift in Sources */, E41E5310223EF6CE00173814 /* CoverArtService+Remote.swift in Sources */, E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */, + E440519822787CB40090CD6F /* MPDState.swift in Sources */, E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */, E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */, E4B11BC02275EE150075461B /* QueueActions.swift in Sources */, @@ -926,6 +940,7 @@ E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */, E4B11BB02274F71A0075461B /* EnumEquatable.swift in Sources */, E4B11B73226A6C770075461B /* TrackTimer.swift in Sources */, + E44051942278765A0090CD6F /* App.swift in Sources */, E4B11B79226D346B0075461B /* AlbumListReducer.swift in Sources */, E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */, E41E52FF223BF95E00173814 /* MPDClient+Transport.swift in Sources */, @@ -949,6 +964,7 @@ E41E5303223BF9C300173814 /* MPDClient+Idle.swift in Sources */, E4B11B53226928F20075461B /* AppState.swift in Sources */, E435E3E4221CD75D00184CFC /* NSImage.swift in Sources */, + E440519A22787CF60090CD6F /* MPDReducer.swift in Sources */, E4B11B6A226A4FBC0075461B /* AlbumListState.swift in Sources */, E41E5305223BFB0700173814 /* MPDClient+Error.swift in Sources */, E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */, diff --git a/Persephone/App.swift b/Persephone/App.swift new file mode 100644 index 0000000..0383eb7 --- /dev/null +++ b/Persephone/App.swift @@ -0,0 +1,18 @@ +// +// App.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/30. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import Foundation +import ReSwift + +struct App { + static let userNotificationsController = UserNotificationsController() + static let mpdServerController = MPDServerController() + static let mpdClient = MPDClient(withDelegate: NotificationsController()) + static let trackTimer = TrackTimer() + static let store = Store(reducer: appReducer, state: nil) +} diff --git a/Persephone/AppDelegate.swift b/Persephone/AppDelegate.swift index d929792..337e923 100644 --- a/Persephone/AppDelegate.swift +++ b/Persephone/AppDelegate.swift @@ -15,45 +15,35 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate { var mediaKeyTap: MediaKeyTap? - var userNotificationsController = UserNotificationsController() - var mpdServerController = MPDServerController() - - static let mpdClient = MPDClient( - withDelegate: NotificationsController() - ) - - static let trackTimer = TrackTimer() - - static let store = Store(reducer: appReducer, state: nil) func applicationDidFinishLaunching(_ aNotification: Notification) { - mpdServerController.connect() + App.mpdServerController.connect() mediaKeyTap = MediaKeyTap(delegate: self) mediaKeyTap?.start() - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.playerState.databaseUpdating } } } func applicationWillTerminate(_ aNotification: Notification) { - mpdServerController.disconnect() + App.mpdServerController.disconnect() } func handle(mediaKey: MediaKey, event: KeyEvent) { switch mediaKey { case .playPause: - AppDelegate.mpdClient.playPause() + App.store.dispatch(MPDPlayPauseAction()) case .next, .fastForward: - AppDelegate.mpdClient.nextTrack() + App.store.dispatch(MPDNextTrackAction()) case .previous, .rewind: - AppDelegate.mpdClient.prevTrack() + App.store.dispatch(MPDPrevTrackAction()) } } @IBAction func updateDatabase(_ sender: NSMenuItem) { - AppDelegate.mpdClient.updateDatabase() + App.store.dispatch(MPDUpdateDatabaseAction()) } @IBOutlet weak var updateDatabaseMenuItem: NSMenuItem! diff --git a/Persephone/Controllers/AlbumViewController.swift b/Persephone/Controllers/AlbumViewController.swift index 5c96de0..2993996 100644 --- a/Persephone/Controllers/AlbumViewController.swift +++ b/Persephone/Controllers/AlbumViewController.swift @@ -21,7 +21,7 @@ class AlbumViewController: NSViewController, override func viewDidLoad() { super.viewDidLoad() - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.albumListState } } @@ -59,7 +59,7 @@ class AlbumViewController: NSViewController, case "mpdLibraryDir": albumCollectionView.reloadData() case "fetchMissingArtworkFromInternet": - AppDelegate.store.dispatch(ResetAlbumListCoverArtAction()) + App.store.dispatch(ResetAlbumListCoverArtAction()) default: break } diff --git a/Persephone/Controllers/AlbumViewItem.swift b/Persephone/Controllers/AlbumViewItem.swift index 2e8e667..5728c38 100644 --- a/Persephone/Controllers/AlbumViewItem.swift +++ b/Persephone/Controllers/AlbumViewItem.swift @@ -53,8 +53,8 @@ class AlbumViewItem: NSCollectionViewItem { @IBAction func playAlbum(_ sender: Any) { guard let album = album else { return } - - AppDelegate.mpdClient.playAlbum(album.mpdAlbum) + + App.store.dispatch(MPDPlayAlbum(album: album.mpdAlbum)) } @IBOutlet var albumCoverView: NSImageView! diff --git a/Persephone/Controllers/MPDServerController.swift b/Persephone/Controllers/MPDServerController.swift index 6e8868c..8810d08 100644 --- a/Persephone/Controllers/MPDServerController.swift +++ b/Persephone/Controllers/MPDServerController.swift @@ -11,20 +11,22 @@ import ReSwift class MPDServerController { init() { - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.preferencesState.mpdServer } } } func connect() { - AppDelegate.mpdClient.connect( - host: AppDelegate.store.state.preferencesState.mpdServer.hostOrDefault, - port: AppDelegate.store.state.preferencesState.mpdServer.portOrDefault + App.store.dispatch( + MPDConnectAction( + host: App.store.state.preferencesState.mpdServer.hostOrDefault, + port: App.store.state.preferencesState.mpdServer.portOrDefault + ) ) } func disconnect() { - AppDelegate.mpdClient.disconnect() + App.store.dispatch(MPDDisconnectAction()) } } diff --git a/Persephone/Controllers/NotificationsController.swift b/Persephone/Controllers/NotificationsController.swift index 98e6c5a..ce5a8fe 100644 --- a/Persephone/Controllers/NotificationsController.swift +++ b/Persephone/Controllers/NotificationsController.swift @@ -17,44 +17,44 @@ class NotificationsController: MPDClientDelegate { func willDisconnect(mpdClient: MPDClient) { DispatchQueue.main.async { - AppDelegate.store.dispatch(UpdateAlbumListAction(albums: [])) + App.store.dispatch(UpdateAlbumListAction(albums: [])) } sendNotification(name: Notification.willDisconnect) } func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus) { DispatchQueue.main.async { - AppDelegate.store.dispatch(UpdateStatusAction(status: status)) + App.store.dispatch(UpdateStatusAction(status: status)) } } func willStartDatabaseUpdate(mpdClient: MPDClient) { DispatchQueue.main.async { - AppDelegate.store.dispatch(StartedDatabaseUpdateAction()) + App.store.dispatch(StartedDatabaseUpdateAction()) } } func didFinishDatabaseUpdate(mpdClient: MPDClient) { DispatchQueue.main.async { - AppDelegate.store.dispatch(FinishedDatabaseUpdateAction()) + App.store.dispatch(FinishedDatabaseUpdateAction()) } } func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.MPDSong]) { DispatchQueue.main.async { - AppDelegate.store.dispatch(UpdateQueueAction(queue: queue)) + App.store.dispatch(UpdateQueueAction(queue: queue)) } } func didUpdateQueuePos(mpdClient: MPDClient, song: Int) { DispatchQueue.main.async { - AppDelegate.store.dispatch(UpdateQueuePosAction(queuePos: song)) + App.store.dispatch(UpdateQueuePosAction(queuePos: song)) } } func didLoadAlbums(mpdClient: MPDClient, albums: [MPDClient.MPDAlbum]) { DispatchQueue.main.async { - AppDelegate.store.dispatch(UpdateAlbumListAction(albums: albums)) + App.store.dispatch(UpdateAlbumListAction(albums: albums)) } } @@ -62,7 +62,7 @@ class NotificationsController: MPDClientDelegate { self.notificationQueue.async { NotificationCenter.default.post( name: name, - object: AppDelegate.mpdClient, + object: App.mpdClient, userInfo: userInfo ) } diff --git a/Persephone/Controllers/QueueViewController.swift b/Persephone/Controllers/QueueViewController.swift index dbaef73..7da4dde 100644 --- a/Persephone/Controllers/QueueViewController.swift +++ b/Persephone/Controllers/QueueViewController.swift @@ -19,7 +19,7 @@ class QueueViewController: NSViewController, override func viewDidLoad() { super.viewDidLoad() - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.queueState } } @@ -40,7 +40,7 @@ class QueueViewController: NSViewController, let newQueuePos = queueView.selectedRow - 1 if newQueuePos >= 0 { - AppDelegate.mpdClient.playTrack(at: newQueuePos) + App.store.dispatch(MPDPlayTrack(queuePos: newQueuePos)) } } diff --git a/Persephone/Controllers/UserNotificationsController.swift b/Persephone/Controllers/UserNotificationsController.swift index 7ded587..486fe2d 100644 --- a/Persephone/Controllers/UserNotificationsController.swift +++ b/Persephone/Controllers/UserNotificationsController.swift @@ -11,14 +11,14 @@ import ReSwift class UserNotificationsController { init() { - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.playerState.currentSong } } } func notifyTrack(_ state: Song?) { guard let currentSong = state, - let status = AppDelegate.mpdClient.status, + let status = App.mpdClient.status, status.state == .playing else { return } diff --git a/Persephone/Controllers/WindowController.swift b/Persephone/Controllers/WindowController.swift index 2c14f6d..2315a58 100644 --- a/Persephone/Controllers/WindowController.swift +++ b/Persephone/Controllers/WindowController.swift @@ -21,7 +21,7 @@ class WindowController: NSWindowController { super.windowDidLoad() window?.titleVisibility = .hidden - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.playerState } } @@ -32,7 +32,7 @@ class WindowController: NSWindowController { override func keyDown(with event: NSEvent) { switch event.keyCode { case NSEvent.keyCodeSpace: - AppDelegate.mpdClient.playPause() + App.store.dispatch(MPDPlayPauseAction()) default: nextResponder?.keyDown(with: event) } @@ -112,13 +112,13 @@ class WindowController: NSWindowController { case .leftMouseDown: trackTimer?.invalidate() case .leftMouseDragged: - AppDelegate.store.dispatch( + App.store.dispatch( UpdateElapsedTimeAction(elapsedTimeMs: UInt(sender.integerValue)) ) case .leftMouseUp: let seekTime = Float(sender.integerValue) / 1000 - AppDelegate.mpdClient.seekCurrentSong(timeInSeconds: seekTime) + App.store.dispatch(MPDSeekCurrentSong(timeInSeconds: seekTime)) default: break } @@ -130,13 +130,13 @@ class WindowController: NSWindowController { switch transportAction { case .prevTrack: - AppDelegate.mpdClient.prevTrack() + App.store.dispatch(MPDPrevTrackAction()) case .playPause: - AppDelegate.mpdClient.playPause() + App.store.dispatch(MPDPlayPauseAction()) case .stop: - AppDelegate.mpdClient.stop() + App.store.dispatch(MPDStopAction()) case .nextTrack: - AppDelegate.mpdClient.nextTrack() + App.store.dispatch(MPDNextTrackAction()) } } diff --git a/Persephone/DataSources/AlbumDataSource.swift b/Persephone/DataSources/AlbumDataSource.swift index d0aa6d3..5d70cac 100644 --- a/Persephone/DataSources/AlbumDataSource.swift +++ b/Persephone/DataSources/AlbumDataSource.swift @@ -25,14 +25,14 @@ class AlbumDataSource: NSObject, NSCollectionViewDataSource { switch albums[indexPath.item].coverArt { case .notLoaded: - AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) { + App.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) { guard let song = $0 else { return } CoverArtService(song: Song(mpdSong: song)) .fetchCoverArt() .done { image in DispatchQueue.main.async { - AppDelegate.store.dispatch( + App.store.dispatch( UpdateCoverArtAction(coverArt: image, albumIndex: indexPath.item) ) } diff --git a/Persephone/Models/TrackTimer.swift b/Persephone/Models/TrackTimer.swift index ccbd93d..577696a 100644 --- a/Persephone/Models/TrackTimer.swift +++ b/Persephone/Models/TrackTimer.swift @@ -31,7 +31,7 @@ class TrackTimer: NSObject { let timeDiff = currentTime - self.startTime let newElapsedTimeMs = UInt((self.startElapsed + timeDiff) * 1000) - AppDelegate.store.dispatch( + App.store.dispatch( UpdateElapsedTimeAction(elapsedTimeMs: newElapsedTimeMs) ) } @@ -44,7 +44,7 @@ class TrackTimer: NSObject { DispatchQueue.main.async { self.timer?.invalidate() - AppDelegate.store.dispatch( + App.store.dispatch( UpdateElapsedTimeAction(elapsedTimeMs: elapsedTimeMs) ) } diff --git a/Persephone/Preferences/Controllers/CoverArtPrefsController.swift b/Persephone/Preferences/Controllers/CoverArtPrefsController.swift index 24bbe41..b8aad25 100644 --- a/Persephone/Preferences/Controllers/CoverArtPrefsController.swift +++ b/Persephone/Preferences/Controllers/CoverArtPrefsController.swift @@ -12,11 +12,11 @@ class CoverArtPrefsController: NSViewController { override func viewDidLoad() { super.viewDidLoad() - if let mpdLibraryDir = AppDelegate.store.state.preferencesState.mpdLibraryDir { + if let mpdLibraryDir = App.store.state.preferencesState.mpdLibraryDir { mpdLibraryDirField.stringValue = mpdLibraryDir } - if AppDelegate.store.state.preferencesState.fetchMissingArtworkFromInternet { + if App.store.state.preferencesState.fetchMissingArtworkFromInternet { fetchMissingArtworkFromInternet.state = .on } else { fetchMissingArtworkFromInternet.state = .off @@ -34,13 +34,13 @@ class CoverArtPrefsController: NSViewController { } @IBAction func updateMpdLibraryDir(_ sender: NSTextField) { - AppDelegate.store.dispatch(UpdateMPDLibraryDir(mpdLibraryDir: sender.stringValue)) + App.store.dispatch(UpdateMPDLibraryDir(mpdLibraryDir: sender.stringValue)) } @IBOutlet var mpdLibraryDirField: NSTextField! @IBAction func updateFetchMissingArtworkFromInternet(_ sender: NSButton) { - AppDelegate.store.dispatch( + App.store.dispatch( UpdateFetchMissingArtworkFromInternet( fetchMissingArtworkFromInternet: sender.state == .on ) diff --git a/Persephone/Preferences/Controllers/GeneralPrefsViewController.swift b/Persephone/Preferences/Controllers/GeneralPrefsViewController.swift index 0662736..91959d4 100644 --- a/Persephone/Preferences/Controllers/GeneralPrefsViewController.swift +++ b/Persephone/Preferences/Controllers/GeneralPrefsViewController.swift @@ -13,11 +13,11 @@ class GeneralPrefsViewController: NSViewController { override func viewDidLoad() { super.viewDidLoad() - if let mpdHost = AppDelegate.store.state.preferencesState.mpdServer.host { + if let mpdHost = App.store.state.preferencesState.mpdServer.host { mpdHostField.stringValue = mpdHost } - if let mpdPort = AppDelegate.store.state.preferencesState.mpdServer.port { + if let mpdPort = App.store.state.preferencesState.mpdServer.port { print(mpdPort) mpdPortField.stringValue = "\(mpdPort)" } @@ -34,11 +34,11 @@ class GeneralPrefsViewController: NSViewController { } @IBAction func updateMpdHost(_ sender: NSTextField) { - AppDelegate.store.dispatch(UpdateServerHost(host: sender.stringValue)) + App.store.dispatch(UpdateServerHost(host: sender.stringValue)) } @IBAction func updateMpdPort(_ sender: NSTextField) { - AppDelegate.store.dispatch(UpdateServerPort(port: sender.integerValue)) + App.store.dispatch(UpdateServerPort(port: sender.integerValue)) } @IBOutlet var mpdHostField: NSTextField! diff --git a/Persephone/Preferences/Controllers/PreferencesWindowController.swift b/Persephone/Preferences/Controllers/PreferencesWindowController.swift index 4c0b7ea..bc96209 100644 --- a/Persephone/Preferences/Controllers/PreferencesWindowController.swift +++ b/Persephone/Preferences/Controllers/PreferencesWindowController.swift @@ -14,7 +14,7 @@ class PreferencesWindowController: NSWindowController, NSWindowDelegate { } func windowShouldClose(_ sender: NSWindow) -> Bool { - AppDelegate.store.dispatch(SavePreferences()) + App.store.dispatch(SavePreferences()) self.window?.orderOut(sender) return false } diff --git a/Persephone/Services/Extensions/CoverArtService+Filesystem.swift b/Persephone/Services/Extensions/CoverArtService+Filesystem.swift index 1a061fb..36f794b 100644 --- a/Persephone/Services/Extensions/CoverArtService+Filesystem.swift +++ b/Persephone/Services/Extensions/CoverArtService+Filesystem.swift @@ -19,7 +19,7 @@ extension CoverArtService { } var musicDir: String { - return AppDelegate.store.state.preferencesState.expandedMpdLibraryDir + return App.store.state.preferencesState.expandedMpdLibraryDir } func getArtworkFromFilesystem() -> Promise { @@ -48,7 +48,7 @@ extension CoverArtService { } func fileSystemArtworkFilePath() -> String? { - let musicDir = AppDelegate.store.state.preferencesState.expandedMpdLibraryDir + let musicDir = App.store.state.preferencesState.expandedMpdLibraryDir return self.coverArtFilenames .lazy diff --git a/Persephone/Services/Extensions/CoverArtService+Remote.swift b/Persephone/Services/Extensions/CoverArtService+Remote.swift index 44ddcef..bf0a05d 100644 --- a/Persephone/Services/Extensions/CoverArtService+Remote.swift +++ b/Persephone/Services/Extensions/CoverArtService+Remote.swift @@ -19,7 +19,7 @@ extension CoverArtService { func getRemoteArtwork() -> Promise { return Promise { seal in - if AppDelegate.store.state.preferencesState .fetchMissingArtworkFromInternet { + if App.store.state.preferencesState .fetchMissingArtworkFromInternet { coverArtQueue.async { let coverArtWorkItem = DispatchWorkItem { self.getArtworkFromMusicBrainz().map(Optional.some).pipe(to: seal.resolve) diff --git a/Persephone/State/Actions/MPDActions.swift b/Persephone/State/Actions/MPDActions.swift new file mode 100644 index 0000000..7691a91 --- /dev/null +++ b/Persephone/State/Actions/MPDActions.swift @@ -0,0 +1,34 @@ +// +// MPDActions.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/30. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import ReSwift + +struct MPDConnectAction: Action { + let host: String + let port: Int +} +struct MPDDisconnectAction: Action {} + +struct MPDPlayPauseAction: Action {} +struct MPDStopAction: Action {} +struct MPDNextTrackAction: Action {} +struct MPDPrevTrackAction: Action {} + +struct MPDPlayTrack: Action { + let queuePos: Int +} + +struct MPDPlayAlbum: Action { + let album: MPDClient.MPDAlbum +} + +struct MPDSeekCurrentSong: Action { + let timeInSeconds: Float +} + +struct MPDUpdateDatabaseAction: Action {} diff --git a/Persephone/State/AppState.swift b/Persephone/State/AppState.swift index 03975b6..27bf287 100644 --- a/Persephone/State/AppState.swift +++ b/Persephone/State/AppState.swift @@ -13,4 +13,5 @@ struct AppState: StateType { var queueState = QueueState() var albumListState = AlbumListState() var preferencesState = PreferencesState() + var mpdState = MPDState() } diff --git a/Persephone/State/MPDState.swift b/Persephone/State/MPDState.swift new file mode 100644 index 0000000..30cbfd1 --- /dev/null +++ b/Persephone/State/MPDState.swift @@ -0,0 +1,11 @@ +// +// MPDState.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/30. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import ReSwift + +struct MPDState: StateType {} diff --git a/Persephone/State/Reducers/AlbumListReducer.swift b/Persephone/State/Reducers/AlbumListReducer.swift index 33f5a1d..fff826c 100644 --- a/Persephone/State/Reducers/AlbumListReducer.swift +++ b/Persephone/State/Reducers/AlbumListReducer.swift @@ -19,7 +19,7 @@ func albumListReducer(action: Action, state: AlbumListState?) -> AlbumListState state.albums[action.albumIndex].coverArt = .loaded(action.coverArt) case is ResetAlbumListCoverArtAction: - state.albums = AppDelegate.store.state.albumListState.albums.map { + state.albums = App.store.state.albumListState.albums.map { var album = $0 switch album.coverArt { case .loaded(let coverArt): diff --git a/Persephone/State/Reducers/AppReducer.swift b/Persephone/State/Reducers/AppReducer.swift index c7e9722..4743748 100644 --- a/Persephone/State/Reducers/AppReducer.swift +++ b/Persephone/State/Reducers/AppReducer.swift @@ -13,6 +13,7 @@ func appReducer(action: Action, state: AppState?) -> AppState { playerState: playerReducer(action: action, state: state?.playerState), queueState: queueReducer(action: action, state: state?.queueState), albumListState: albumListReducer(action: action, state: state?.albumListState), - preferencesState: preferencesReducer(action: action, state: state?.preferencesState) + preferencesState: preferencesReducer(action: action, state: state?.preferencesState), + mpdState: mpdReducer(action: action, state: state?.mpdState) ) } diff --git a/Persephone/State/Reducers/MPDReducer.swift b/Persephone/State/Reducers/MPDReducer.swift new file mode 100644 index 0000000..c41f021 --- /dev/null +++ b/Persephone/State/Reducers/MPDReducer.swift @@ -0,0 +1,46 @@ +// +// MPDReducer.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/30. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import ReSwift + +func mpdReducer(action: Action, state: MPDState?) -> MPDState { + let state = state ?? MPDState() + + switch action { + case let action as MPDConnectAction: + App.mpdClient.connect(host: action.host, port: action.port) + case is MPDDisconnectAction: + App.mpdClient.disconnect() + + case is MPDPlayPauseAction: + App.mpdClient.playPause() + case is MPDStopAction: + App.mpdClient.stop() + case is MPDNextTrackAction: + App.mpdClient.nextTrack() + case is MPDPrevTrackAction: + App.mpdClient.prevTrack() + + case let action as MPDPlayTrack: + App.mpdClient.playTrack(at: action.queuePos) + + case let action as MPDPlayAlbum: + App.mpdClient.playAlbum(action.album) + + case let action as MPDSeekCurrentSong: + App.mpdClient.seekCurrentSong(timeInSeconds: action.timeInSeconds) + + case is MPDUpdateDatabaseAction: + App.mpdClient.updateDatabase() + + default: + break + } + + return state +} diff --git a/Persephone/State/Reducers/PlayerReducer.swift b/Persephone/State/Reducers/PlayerReducer.swift index 14ef026..1808ac1 100644 --- a/Persephone/State/Reducers/PlayerReducer.swift +++ b/Persephone/State/Reducers/PlayerReducer.swift @@ -20,13 +20,13 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState { state.elapsedTimeMs = action.status.elapsedTimeMs if state.state == .playing { - AppDelegate.trackTimer.start(elapsedTimeMs: state.elapsedTimeMs) + App.trackTimer.start(elapsedTimeMs: state.elapsedTimeMs) } else { - AppDelegate.trackTimer.stop(elapsedTimeMs: state.elapsedTimeMs) + App.trackTimer.stop(elapsedTimeMs: state.elapsedTimeMs) } DispatchQueue.main.async { - AppDelegate.store.dispatch( + App.store.dispatch( UpdateQueuePlayerStateAction(state: state.state) ) } @@ -41,16 +41,16 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState { .done() { image in DispatchQueue.main.async { if let image = image { - AppDelegate.store.dispatch(UpdateCurrentCoverArtAction(coverArt: image)) + App.store.dispatch(UpdateCurrentCoverArtAction(coverArt: image)) } else { - AppDelegate.store.dispatch(UpdateCurrentCoverArtAction(coverArt: .defaultCoverArt)) + App.store.dispatch(UpdateCurrentCoverArtAction(coverArt: .defaultCoverArt)) } } } .cauterize() } else { DispatchQueue.main.async { - AppDelegate.store.dispatch(UpdateCurrentCoverArtAction(coverArt: .defaultCoverArt)) + App.store.dispatch(UpdateCurrentCoverArtAction(coverArt: .defaultCoverArt)) } } diff --git a/Persephone/State/Reducers/QueueReducer.swift b/Persephone/State/Reducers/QueueReducer.swift index d0281c1..2ea900d 100644 --- a/Persephone/State/Reducers/QueueReducer.swift +++ b/Persephone/State/Reducers/QueueReducer.swift @@ -39,7 +39,7 @@ func queueReducer(action: Action, state: QueueState?) -> QueueState { } DispatchQueue.main.async { - AppDelegate.store.dispatch( + App.store.dispatch( UpdateCurrentSongAction(currentSong: state.queue[newSongRowPos].song) ) } diff --git a/Persephone/Views/CurrentCoverArtView.swift b/Persephone/Views/CurrentCoverArtView.swift index dc51e27..b06bfa3 100644 --- a/Persephone/Views/CurrentCoverArtView.swift +++ b/Persephone/Views/CurrentCoverArtView.swift @@ -13,7 +13,7 @@ class CurrentCoverArtView: NSImageView { required init?(coder: NSCoder) { super.init(coder: coder) - AppDelegate.store.subscribe(self) { + App.store.subscribe(self) { $0.select { $0.playerState.currentArtwork } } }