diff --git a/Persephone.xcodeproj/project.pbxproj b/Persephone.xcodeproj/project.pbxproj index 166e474..1cbb508 100644 --- a/Persephone.xcodeproj/project.pbxproj +++ b/Persephone.xcodeproj/project.pbxproj @@ -36,6 +36,7 @@ E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41EA46B221636AF0068EF46 /* GeneralPrefsViewController.swift */; }; E421ACA3221F73C4008B2449 /* MediaKeyTap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E421ACA1221F73B8008B2449 /* MediaKeyTap.framework */; }; E421ACA4221F73C4008B2449 /* MediaKeyTap.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E421ACA1221F73B8008B2449 /* MediaKeyTap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = E42410B52241B956005ED6DF /* MPDClient+Database.swift */; }; E42A8F3B22176D6400A13ED9 /* LICENSE.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3922176D6400A13ED9 /* LICENSE.md */; }; E42A8F3C22176D6400A13ED9 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3A22176D6400A13ED9 /* README.md */; }; E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E1221CD4E200184CFC /* NSFont.swift */; }; @@ -195,6 +196,7 @@ E41E5311223EF74A00173814 /* AlbumArtService+Filesystem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlbumArtService+Filesystem.swift"; sourceTree = ""; }; E41EA46B221636AF0068EF46 /* GeneralPrefsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralPrefsViewController.swift; sourceTree = ""; }; E421ACA1221F73B8008B2449 /* MediaKeyTap.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MediaKeyTap.framework; path = Carthage/Build/Mac/MediaKeyTap.framework; sourceTree = ""; }; + E42410B52241B956005ED6DF /* MPDClient+Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Database.swift"; sourceTree = ""; }; E42A8F3922176D6400A13ED9 /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = ""; }; E42A8F3A22176D6400A13ED9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; E435E3E1221CD4E200184CFC /* NSFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSFont.swift; sourceTree = ""; }; @@ -351,6 +353,7 @@ isa = PBXGroup; children = ( E41E52FC223BF87300173814 /* MPDClient+Connection.swift */, + E42410B52241B956005ED6DF /* MPDClient+Database.swift */, E41E52FE223BF95E00173814 /* MPDClient+Transport.swift */, E41E5300223BF99300173814 /* MPDClient+Queue.swift */, E41E5302223BF9C300173814 /* MPDClient+Idle.swift */, @@ -749,6 +752,7 @@ E41E5307223C019100173814 /* MPDClient+Status.swift in Sources */, E41E5310223EF6CE00173814 /* AlbumArtService+Remote.swift in Sources */, E41E530B223C033700173814 /* MPDClient+Album.swift in Sources */, + E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */, E4A642DA22090CBE00067D21 /* Status.swift in Sources */, E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */, E450AD9522262DF10091BED3 /* AlbumArtQueue.swift in Sources */, diff --git a/Persephone/AppDelegate.swift b/Persephone/AppDelegate.swift index 6f6f249..ef4a5f4 100644 --- a/Persephone/AppDelegate.swift +++ b/Persephone/AppDelegate.swift @@ -68,4 +68,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, MediaKeyTapDelegate { func disconnect() { AppDelegate.mpdClient.disconnect() } + + @IBAction func updateDatabase(_ sender: NSMenuItem) { + AppDelegate.mpdClient.updateDatabase() + } } diff --git a/Persephone/Controllers/NotificationsController.swift b/Persephone/Controllers/NotificationsController.swift index 2b1b4ab..882b4fe 100644 --- a/Persephone/Controllers/NotificationsController.swift +++ b/Persephone/Controllers/NotificationsController.swift @@ -36,6 +36,14 @@ class NotificationsController: MPDClientDelegate { ) } + func willUpdateDatabase(mpdClient: MPDClient) { + sendNotification(name: Notification.databaseUpdateStarted) + } + + func didUpdateDatabase(mpdClient: MPDClient) { + sendNotification(name: Notification.databaseUpdated) + } + func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song]) { sendNotification( name: Notification.queueChanged, diff --git a/Persephone/Controllers/WindowController.swift b/Persephone/Controllers/WindowController.swift index 1c6bab8..60f558a 100644 --- a/Persephone/Controllers/WindowController.swift +++ b/Persephone/Controllers/WindowController.swift @@ -36,6 +36,20 @@ class WindowController: NSWindowController { object: AppDelegate.mpdClient ) + NotificationCenter.default.addObserver( + self, + selector: #selector(startDatabaseUpdatingIndicator), + name: Notification.databaseUpdateStarted, + object: AppDelegate.mpdClient + ) + + NotificationCenter.default.addObserver( + self, + selector: #selector(stopDatabaseUpdatingIndicator), + name: Notification.databaseUpdated, + object: AppDelegate.mpdClient + ) + trackProgress.font = .timerFont trackRemaining.font = .timerFont } @@ -132,6 +146,14 @@ class WindowController: NSWindowController { setTimeRemaining() } + @objc func startDatabaseUpdatingIndicator() { + databaseUpdatingIndicator.startAnimation(self) + } + + @objc func stopDatabaseUpdatingIndicator() { + databaseUpdatingIndicator.stopAnimation(self) + } + func setTimeElapsed() { guard let elapsedTimeMs = elapsedTimeMs else { return } @@ -194,4 +216,5 @@ class WindowController: NSWindowController { @IBOutlet var trackProgress: NSTextField! @IBOutlet var trackProgressBar: NSSlider! @IBOutlet var trackRemaining: NSTextField! + @IBOutlet var databaseUpdatingIndicator: NSProgressIndicator! } diff --git a/Persephone/Extensions/Notification.swift b/Persephone/Extensions/Notification.swift index 6a8f5b4..45315a1 100644 --- a/Persephone/Extensions/Notification.swift +++ b/Persephone/Extensions/Notification.swift @@ -14,6 +14,8 @@ extension Notification { static let stateChanged = Name("MPDClientStateChanged") static let timeChanged = Name("MPDClientTimeChanged") + static let databaseUpdateStarted = Name("MPDClientDatabaseUpdateStarted") + static let databaseUpdated = Name("MPDClientDatabaseUpdated") static let queueChanged = Name("MPDClientQueueChanged") static let queuePosChanged = Name("MPDClientQueuePosChanged") static let loadedAlbums = Name("MPDClientLoadedAlbums") diff --git a/Persephone/MPDClient/Extensions/MPDClient+Command.swift b/Persephone/MPDClient/Extensions/MPDClient+Command.swift index e34a62e..aac1940 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Command.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Command.swift @@ -29,6 +29,10 @@ extension MPDClient { else { return } sendSeekCurrentSong(timeInSeconds: timeInSeconds) + // Database commands + case .updateDatabase: + sendUpdateDatabase() + // Status commands case .fetchStatus: sendRunStatus() diff --git a/Persephone/MPDClient/Extensions/MPDClient+Database.swift b/Persephone/MPDClient/Extensions/MPDClient+Database.swift new file mode 100644 index 0000000..5a05643 --- /dev/null +++ b/Persephone/MPDClient/Extensions/MPDClient+Database.swift @@ -0,0 +1,20 @@ +// +// MPDClient+Database.swift +// Persephone +// +// Created by Daniel Barber on 2019/3/19. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import Foundation +import mpdclient + +extension MPDClient { + func updateDatabase() { + enqueueCommand(command: .updateDatabase) + } + + func sendUpdateDatabase() { + mpd_run_update(connection, nil) + } +} diff --git a/Persephone/MPDClient/Extensions/MPDClient+Idle.swift b/Persephone/MPDClient/Extensions/MPDClient+Idle.swift index c30ac2b..003dd48 100644 --- a/Persephone/MPDClient/Extensions/MPDClient+Idle.swift +++ b/Persephone/MPDClient/Extensions/MPDClient+Idle.swift @@ -32,6 +32,9 @@ extension MPDClient { let mpdIdle = Idle(rawValue: result.rawValue) + if mpdIdle.contains(.database) { + self.fetchAllAlbums() + } if mpdIdle.contains(.queue) { self.fetchQueue() self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue) @@ -45,6 +48,15 @@ extension MPDClient { self.delegate?.didUpdateQueuePos(mpdClient: self, song: status.song) } } + if mpdIdle.contains(.update) { + self.fetchStatus() + + if self.status?.updating ?? false { + self.delegate?.willUpdateDatabase(mpdClient: self) + } else { + self.delegate?.didUpdateDatabase(mpdClient: self) + } + } if !mpdIdle.isEmpty { self.idle() } diff --git a/Persephone/MPDClient/Models/Command.swift b/Persephone/MPDClient/Models/Command.swift index 3bdc11a..a035729 100644 --- a/Persephone/MPDClient/Models/Command.swift +++ b/Persephone/MPDClient/Models/Command.swift @@ -17,6 +17,9 @@ extension MPDClient { case stop case seekCurrentSong + // Database commands + case updateDatabase + // Status commands case fetchStatus diff --git a/Persephone/MPDClient/Models/Status.swift b/Persephone/MPDClient/Models/Status.swift index e43d140..dc0f913 100644 --- a/Persephone/MPDClient/Models/Status.swift +++ b/Persephone/MPDClient/Models/Status.swift @@ -49,5 +49,11 @@ extension MPDClient { var song: Int { return Int(mpd_status_get_song_pos(mpdStatus)) } + + var updating: Bool { + let updating = mpd_status_get_update_id(mpdStatus) + + return updating > 0 + } } } diff --git a/Persephone/MPDClient/Protocols/Delegate.swift b/Persephone/MPDClient/Protocols/Delegate.swift index 25de673..67e24ce 100644 --- a/Persephone/MPDClient/Protocols/Delegate.swift +++ b/Persephone/MPDClient/Protocols/Delegate.swift @@ -15,6 +15,9 @@ protocol MPDClientDelegate { func didUpdateState(mpdClient: MPDClient, state: MPDClient.Status.State) func didUpdateTime(mpdClient: MPDClient, total: UInt, elapsedMs: UInt) + func willUpdateDatabase(mpdClient: MPDClient) + func didUpdateDatabase(mpdClient: MPDClient) + func didUpdateQueue(mpdClient: MPDClient, queue: [MPDClient.Song]) func didUpdateQueuePos(mpdClient: MPDClient, song: Int) diff --git a/Persephone/Resources/Base.lproj/Main.storyboard b/Persephone/Resources/Base.lproj/Main.storyboard index b717309..30ed0cd 100644 --- a/Persephone/Resources/Base.lproj/Main.storyboard +++ b/Persephone/Resources/Base.lproj/Main.storyboard @@ -66,8 +66,11 @@ - + + + + @@ -195,9 +198,17 @@ + + + + + + + + @@ -210,6 +221,7 @@ +