From 40ae6909cd7e23b40f91703f1aabc5b23c65fb7f Mon Sep 17 00:00:00 2001 From: Daniel Barber Date: Sat, 27 Apr 2019 16:49:36 -0400 Subject: [PATCH] Album images load! --- Cartfile | 1 + Cartfile.resolved | 1 + Persephone.xcodeproj/project.pbxproj | 108 +++++++++++------- Persephone/Actions/EnumEquatable.swift | 11 ++ Persephone/Actions/UpdateAlbumArt.swift | 15 +++ .../Controllers/AlbumViewController.swift | 19 ++- Persephone/Controllers/AlbumViewItem.swift | 7 +- .../Controllers/QueueViewController.swift | 6 + Persephone/DataSources/AlbumDataSource.swift | 42 +++---- Persephone/Models/Album.swift | 6 +- Persephone/Models/Loading.swift | 30 +++++ Persephone/Reducers/AlbumListReducer.swift | 2 + Persephone/Reducers/AppReducer.swift | 1 - Persephone/State/AlbumListState.swift | 1 - 14 files changed, 182 insertions(+), 68 deletions(-) create mode 100644 Persephone/Actions/EnumEquatable.swift create mode 100644 Persephone/Actions/UpdateAlbumArt.swift create mode 100644 Persephone/Models/Loading.swift diff --git a/Cartfile b/Cartfile index ef29de1..65c902d 100644 --- a/Cartfile +++ b/Cartfile @@ -3,3 +3,4 @@ github "PromiseKit/Foundation" ~> 3.0 github "nhurden/MediaKeyTap" github "krzyzanowskim/CryptoSwift" github "ReSwift/ReSwift" "mjarvis/swift-5.0" +github "tonyarnold/Differ" diff --git a/Cartfile.resolved b/Cartfile.resolved index 79f86bd..035ec4b 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -4,3 +4,4 @@ github "SwiftyJSON/SwiftyJSON" "4.3.0" github "krzyzanowskim/CryptoSwift" "1.0.0" github "mxcl/PromiseKit" "6.8.4" github "nhurden/MediaKeyTap" "2.2.1" +github "tonyarnold/Differ" "1.4.2" diff --git a/Persephone.xcodeproj/project.pbxproj b/Persephone.xcodeproj/project.pbxproj index 2ef5e93..8df768f 100644 --- a/Persephone.xcodeproj/project.pbxproj +++ b/Persephone.xcodeproj/project.pbxproj @@ -20,8 +20,6 @@ E40F41F3221EDE27004B6CB8 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40F41F2221EDE27004B6CB8 /* Preferences.swift */; }; E40FE71B221B904300A4223F /* NSEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE71A221B904300A4223F /* NSEvent.swift */; }; E419E2872249B96600216A8C /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E419E2862249B96600216A8C /* Song.swift */; }; - E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; }; - E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; }; E41E52FD223BF87300173814 /* MPDClient+Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E52FC223BF87300173814 /* MPDClient+Connection.swift */; }; E41E52FF223BF95E00173814 /* MPDClient+Transport.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E52FE223BF95E00173814 /* MPDClient+Transport.swift */; }; @@ -35,8 +33,6 @@ E41E5310223EF6CE00173814 /* AlbumArtService+Remote.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E530F223EF6CE00173814 /* AlbumArtService+Remote.swift */; }; E41E5312223EF74A00173814 /* AlbumArtService+Filesystem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E5311223EF74A00173814 /* AlbumArtService+Filesystem.swift */; }; 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 */; }; @@ -44,24 +40,16 @@ E435E3E4221CD75D00184CFC /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E3221CD75D00184CFC /* NSImage.swift */; }; E439109822640213002982E9 /* SongNotifierService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E439109722640213002982E9 /* SongNotifierService.swift */; }; E450AD7E222620A10091BED3 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E450AD7D222620A10091BED3 /* Album.swift */; }; - E450AD8622262AE60091BED3 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8522262AE60091BED3 /* SwiftyJSON.framework */; }; - E450AD8822262AEC0091BED3 /* SwiftyJSON.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E450AD8522262AE60091BED3 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 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 */; }; - E450AD9222262C970091BED3 /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8C22262C590091BED3 /* PromiseKit.framework */; }; - E450AD9322262C970091BED3 /* PromiseKit.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E450AD8C22262C590091BED3 /* PromiseKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E450AD9522262DF10091BED3 /* AlbumArtQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = E450AD9422262DF10091BED3 /* AlbumArtQueue.swift */; }; E450AD98222633920091BED3 /* Alamofire.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E450AD96222633920091BED3 /* Alamofire.framework.dSYM */; }; E450ADA12229E7C90091BED3 /* PMKFoundation.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E450AD9F2229E7C90091BED3 /* PMKFoundation.framework.dSYM */; }; - E450ADA32229E7E00091BED3 /* PMKFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450ADA02229E7C90091BED3 /* PMKFoundation.framework */; }; - E450ADA42229E7E00091BED3 /* PMKFoundation.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E450ADA02229E7C90091BED3 /* PMKFoundation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E45962C52241A78500FC1A1E /* MPDCommand.swift */; }; E45E4FDA22515D87004B537F /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = E45E4FD722515D87004B537F /* CHANGELOG.md */; }; E45E4FDB22515D87004B537F /* Brewfile in Resources */ = {isa = PBXBuildFile; fileRef = E45E4FD822515D87004B537F /* Brewfile */; }; E45E4FDC22515D87004B537F /* Cartfile in Resources */ = {isa = PBXBuildFile; fileRef = E45E4FD922515D87004B537F /* Cartfile */; }; E45E4FDF225168DA004B537F /* CryptoSwift.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E45E4FDD225168DA004B537F /* CryptoSwift.framework.dSYM */; }; - E45E4FE122516953004B537F /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E45E4FDE225168DA004B537F /* CryptoSwift.framework */; }; - E45E4FE222516953004B537F /* CryptoSwift.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E45E4FDE225168DA004B537F /* CryptoSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E465049A21E94DF500A70F4C /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E465049921E94DF500A70F4C /* WindowController.swift */; }; E47E2FCC2220573500F747E6 /* MediaKeyTap.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E47E2FCB2220573500F747E6 /* MediaKeyTap.framework.dSYM */; }; E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */; }; @@ -77,8 +65,6 @@ E4A83BF4222207D50098FED6 /* AlbumArtService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A83BF3222207D50098FED6 /* AlbumArtService.swift */; }; E4B11B53226928F20075461B /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B52226928F20075461B /* AppState.swift */; }; E4B11B5A2269296C0075461B /* ReSwift.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E4B11B582269296C0075461B /* ReSwift.framework.dSYM */; }; - E4B11B5B226929730075461B /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4B11B572269296C0075461B /* ReSwift.framework */; }; - E4B11B5C226929730075461B /* ReSwift.framework in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E4B11B572269296C0075461B /* ReSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E4B11B61226A4C000075461B /* PlayerReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B60226A4BFF0075461B /* PlayerReducer.swift */; }; E4B11B63226A4C510075461B /* AppReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B62226A4C510075461B /* AppReducer.swift */; }; E4B11B66226A4F830075461B /* PlayerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11B65226A4F830075461B /* PlayerState.swift */; }; @@ -92,6 +78,26 @@ 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 */; }; + E4B11B7E2274E36D0075461B /* Differ.framework.dSYM in Resources */ = {isa = PBXBuildFile; fileRef = E4B11B7C2274E36D0075461B /* Differ.framework.dSYM */; }; + E4B11B962274E43B0075461B /* Differ.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4B11B7D2274E36D0075461B /* Differ.framework */; }; + E4B11B972274E43B0075461B /* Differ.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E4B11B7D2274E36D0075461B /* Differ.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11B982274E43B0075461B /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4B11B572269296C0075461B /* ReSwift.framework */; }; + E4B11B992274E43B0075461B /* ReSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E4B11B572269296C0075461B /* ReSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11B9A2274E43B0075461B /* CryptoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E45E4FDE225168DA004B537F /* CryptoSwift.framework */; }; + E4B11B9B2274E43B0075461B /* CryptoSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E45E4FDE225168DA004B537F /* CryptoSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11B9C2274E43B0075461B /* PMKFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450ADA02229E7C90091BED3 /* PMKFoundation.framework */; }; + E4B11B9D2274E43B0075461B /* PMKFoundation.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E450ADA02229E7C90091BED3 /* PMKFoundation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11B9E2274E43B0075461B /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8C22262C590091BED3 /* PromiseKit.framework */; }; + E4B11B9F2274E43B0075461B /* PromiseKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8C22262C590091BED3 /* PromiseKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11BA02274E43B0075461B /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8522262AE60091BED3 /* SwiftyJSON.framework */; }; + E4B11BA12274E43B0075461B /* SwiftyJSON.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E450AD8522262AE60091BED3 /* SwiftyJSON.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11BA22274E43B0075461B /* MediaKeyTap.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E421ACA1221F73B8008B2449 /* MediaKeyTap.framework */; }; + E4B11BA32274E43B0075461B /* MediaKeyTap.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E421ACA1221F73B8008B2449 /* MediaKeyTap.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E4B11BA62274E44A0075461B /* libmpdclient.2.dylib in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + E4B11BA72274E4500075461B /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; }; + E4B11BA92274EDE30075461B /* Loading.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BA82274EDE30075461B /* Loading.swift */; }; + E4B11BAD2274F2E80075461B /* UpdateAlbumArt.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BAC2274F2E80075461B /* UpdateAlbumArt.swift */; }; + E4B11BB02274F71A0075461B /* EnumEquatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BAF2274F71A0075461B /* EnumEquatable.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 */; }; @@ -123,23 +129,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - E41B22C221FB6C3300D544F6 /* Embed Libraries */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - E4B11B5C226929730075461B /* ReSwift.framework in Embed Libraries */, - E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */, - E450ADA42229E7E00091BED3 /* PMKFoundation.framework in Embed Libraries */, - E421ACA4221F73C4008B2449 /* MediaKeyTap.framework in Embed Libraries */, - E45E4FE222516953004B537F /* CryptoSwift.framework in Embed Libraries */, - E450AD8822262AEC0091BED3 /* SwiftyJSON.framework in Embed Libraries */, - E450AD9322262C970091BED3 /* PromiseKit.framework in Embed Libraries */, - ); - name = "Embed Libraries"; - runOnlyForDeploymentPostprocessing = 0; - }; E421AC9B221F7319008B2449 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -149,6 +138,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + E4B11BA52274E43B0075461B /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + E4B11B9B2274E43B0075461B /* CryptoSwift.framework in Embed Frameworks */, + E4B11B972274E43B0075461B /* Differ.framework in Embed Frameworks */, + E4B11BA12274E43B0075461B /* SwiftyJSON.framework in Embed Frameworks */, + E4B11B9F2274E43B0075461B /* PromiseKit.framework in Embed Frameworks */, + E4B11B9D2274E43B0075461B /* PMKFoundation.framework in Embed Frameworks */, + E4B11BA62274E44A0075461B /* libmpdclient.2.dylib in Embed Frameworks */, + E4B11BA32274E43B0075461B /* MediaKeyTap.framework in Embed Frameworks */, + E4B11B992274E43B0075461B /* ReSwift.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ @@ -275,6 +282,11 @@ E4B11B76226CC6BE0075461B /* UpdateQueuePosAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateQueuePosAction.swift; sourceTree = ""; }; E4B11B78226D346B0075461B /* AlbumListReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListReducer.swift; sourceTree = ""; }; E4B11B7A226D34F80075461B /* UpdateAlbumListAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateAlbumListAction.swift; sourceTree = ""; }; + E4B11B7C2274E36D0075461B /* Differ.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = Differ.framework.dSYM; path = Carthage/Build/Mac/Differ.framework.dSYM; sourceTree = ""; }; + E4B11B7D2274E36D0075461B /* Differ.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Differ.framework; path = Carthage/Build/Mac/Differ.framework; sourceTree = ""; }; + E4B11BA82274EDE30075461B /* Loading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Loading.swift; sourceTree = ""; }; + E4B11BAC2274F2E80075461B /* UpdateAlbumArt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateAlbumArt.swift; sourceTree = ""; }; + E4B11BAF2274F71A0075461B /* EnumEquatable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumEquatable.swift; sourceTree = ""; }; E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = ""; }; E4C8B53D22349002009A20F3 /* MPDIdle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDIdle.swift; sourceTree = ""; }; E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = ""; }; @@ -293,13 +305,14 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - E4B11B5B226929730075461B /* ReSwift.framework in Frameworks */, - E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */, - E450ADA32229E7E00091BED3 /* PMKFoundation.framework in Frameworks */, - E421ACA3221F73C4008B2449 /* MediaKeyTap.framework in Frameworks */, - E45E4FE122516953004B537F /* CryptoSwift.framework in Frameworks */, - E450AD8622262AE60091BED3 /* SwiftyJSON.framework in Frameworks */, - E450AD9222262C970091BED3 /* PromiseKit.framework in Frameworks */, + E4B11BA72274E4500075461B /* libmpdclient.2.dylib in Frameworks */, + E4B11B9A2274E43B0075461B /* CryptoSwift.framework in Frameworks */, + E4B11B962274E43B0075461B /* Differ.framework in Frameworks */, + E4B11BA02274E43B0075461B /* SwiftyJSON.framework in Frameworks */, + E4B11B9E2274E43B0075461B /* PromiseKit.framework in Frameworks */, + E4B11B9C2274E43B0075461B /* PMKFoundation.framework in Frameworks */, + E4B11BA22274E43B0075461B /* MediaKeyTap.framework in Frameworks */, + E4B11B982274E43B0075461B /* ReSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -349,6 +362,7 @@ E407861A2110CE6E006887B1 /* Persephone */ = { isa = PBXGroup; children = ( + E4B11BAE2274F7030075461B /* Protocols */, E4B11B6B226A5AF50075461B /* Actions */, E407861B2110CE6E006887B1 /* AppDelegate.swift */, E407861F2110CE70006887B1 /* Assets.xcassets */, @@ -433,6 +447,8 @@ E41B22BE21FB6B3300D544F6 /* Frameworks */ = { isa = PBXGroup; children = ( + E4B11B7D2274E36D0075461B /* Differ.framework */, + E4B11B7C2274E36D0075461B /* Differ.framework.dSYM */, E4B11B572269296C0075461B /* ReSwift.framework */, E4B11B582269296C0075461B /* ReSwift.framework.dSYM */, E45E4FDE225168DA004B537F /* CryptoSwift.framework */, @@ -599,10 +615,19 @@ E4B11B6C226A5B180075461B /* UpdateQueueAction.swift */, E4B11B76226CC6BE0075461B /* UpdateQueuePosAction.swift */, E4B11B6E226A5C7A0075461B /* UpdateStatusAction.swift */, + E4B11BAC2274F2E80075461B /* UpdateAlbumArt.swift */, + E4B11BAF2274F71A0075461B /* EnumEquatable.swift */, ); path = Actions; sourceTree = ""; }; + E4B11BAE2274F7030075461B /* Protocols */ = { + isa = PBXGroup; + children = ( + ); + path = Protocols; + sourceTree = ""; + }; E4D1B594220BA2490026F233 /* Models */ = { isa = PBXGroup; children = ( @@ -659,6 +684,7 @@ isa = PBXGroup; children = ( E450AD7D222620A10091BED3 /* Album.swift */, + E4B11BA82274EDE30075461B /* Loading.swift */, E40F41F2221EDE27004B6CB8 /* Preferences.swift */, E4F6B462221E125900ACF42A /* QueueItem.swift */, E419E2862249B96600216A8C /* Song.swift */, @@ -679,8 +705,8 @@ E40786152110CE6E006887B1 /* Frameworks */, E40786162110CE6E006887B1 /* Resources */, E42A98F122430936004D8180 /* ShellScript */, - E41B22C221FB6C3300D544F6 /* Embed Libraries */, E421AC9B221F7319008B2449 /* CopyFiles */, + E4B11BA52274E43B0075461B /* Embed Frameworks */, ); buildRules = ( ); @@ -798,6 +824,7 @@ E450AD8F22262C620091BED3 /* PromiseKit.framework.dSYM in Resources */, E408D3CB220E341D0006D9BE /* AlbumViewItem.xib in Resources */, E4B11B5A2269296C0075461B /* ReSwift.framework.dSYM in Resources */, + E4B11B7E2274E36D0075461B /* Differ.framework.dSYM in Resources */, E40786232110CE70006887B1 /* Main.storyboard in Resources */, E450ADA12229E7C90091BED3 /* PMKFoundation.framework.dSYM in Resources */, E47E2FCC2220573500F747E6 /* MediaKeyTap.framework.dSYM in Resources */, @@ -847,6 +874,7 @@ files = ( E4A83BEF2221F8CF0098FED6 /* AlbumArtPrefsController.swift in Sources */, E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */, + E4B11BA92274EDE30075461B /* Loading.swift in Sources */, E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */, E40FE71B221B904300A4223F /* NSEvent.swift in Sources */, E4B11B7B226D34F80075461B /* UpdateAlbumListAction.swift in Sources */, @@ -854,6 +882,7 @@ E4B11B68226A4FA00075461B /* QueueState.swift in Sources */, E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */, E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */, + E4B11BAD2274F2E80075461B /* UpdateAlbumArt.swift in Sources */, E4B11B6F226A5C7A0075461B /* UpdateStatusAction.swift in Sources */, E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */, E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */, @@ -886,6 +915,7 @@ E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */, E4B11B75226CC4D30075461B /* QueueReducer.swift in Sources */, E41E5309223C020400173814 /* MPDClient+Command.swift in Sources */, + E4B11BB02274F71A0075461B /* EnumEquatable.swift in Sources */, E4B11B73226A6C770075461B /* TrackTimer.swift in Sources */, E4B11B79226D346B0075461B /* AlbumListReducer.swift in Sources */, E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */, diff --git a/Persephone/Actions/EnumEquatable.swift b/Persephone/Actions/EnumEquatable.swift new file mode 100644 index 0000000..1295f8f --- /dev/null +++ b/Persephone/Actions/EnumEquatable.swift @@ -0,0 +1,11 @@ +// +// EnumEquatable.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/27. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +protocol EnumEquatable { + static func ~=(lhs: Self, rhs: Self) -> Bool +} diff --git a/Persephone/Actions/UpdateAlbumArt.swift b/Persephone/Actions/UpdateAlbumArt.swift new file mode 100644 index 0000000..58423f0 --- /dev/null +++ b/Persephone/Actions/UpdateAlbumArt.swift @@ -0,0 +1,15 @@ +// +// UpdateAlbumArt.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/27. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import Cocoa +import ReSwift + +struct UpdateAlbumArt: Action { + var coverArt: NSImage? + var albumIndex: Int +} diff --git a/Persephone/Controllers/AlbumViewController.swift b/Persephone/Controllers/AlbumViewController.swift index 0629e0b..d5cd9d8 100644 --- a/Persephone/Controllers/AlbumViewController.swift +++ b/Persephone/Controllers/AlbumViewController.swift @@ -8,6 +8,7 @@ import Cocoa import ReSwift +import Differ class AlbumViewController: NSViewController, NSCollectionViewDelegate, @@ -39,6 +40,12 @@ class AlbumViewController: NSViewController, preferences.addObserver(self, forKeyPath: "fetchMissingArtworkFromInternet") } + override func viewWillDisappear() { + super.viewWillDisappear() + + AppDelegate.store.unsubscribe(self) + } + override func viewWillLayout() { super.viewWillLayout() @@ -77,7 +84,17 @@ class AlbumViewController: NSViewController, func newState(state: StoreSubscriberStateType) { print("New album list state") - albumCollectionView.reloadData() + if dataSource.albums == [] { + dataSource.albums = state.albums + albumCollectionView.reloadData() + } else { + let oldAlbums = dataSource.albums + dataSource.albums = state.albums + albumCollectionView.animateItemChanges( + oldData: oldAlbums, + newData: dataSource.albums + ) + } } @IBOutlet var albumScrollView: NSScrollView! diff --git a/Persephone/Controllers/AlbumViewItem.swift b/Persephone/Controllers/AlbumViewItem.swift index e43aa04..30b7609 100644 --- a/Persephone/Controllers/AlbumViewItem.swift +++ b/Persephone/Controllers/AlbumViewItem.swift @@ -31,10 +31,11 @@ class AlbumViewItem: NSCollectionViewItem { self.album = album albumTitle.stringValue = album.title albumArtist.stringValue = album.artist - - if let coverArt = album.coverArt { + + switch album.coverArt { + case .loaded(let coverArt): albumCoverView.image = coverArt - } else { + default: albumCoverView.image = .defaultCoverArt } } diff --git a/Persephone/Controllers/QueueViewController.swift b/Persephone/Controllers/QueueViewController.swift index 4197f31..1b3a349 100644 --- a/Persephone/Controllers/QueueViewController.swift +++ b/Persephone/Controllers/QueueViewController.swift @@ -32,6 +32,12 @@ class QueueViewController: NSViewController, queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle } + override func viewWillDisappear() { + super.viewWillDisappear() + + AppDelegate.store.unsubscribe(self) + } + func newState(state: StoreSubscriberStateType) { print("New queue state") dataSource.setQueueIcon() diff --git a/Persephone/DataSources/AlbumDataSource.swift b/Persephone/DataSources/AlbumDataSource.swift index 0aee886..fc27270 100644 --- a/Persephone/DataSources/AlbumDataSource.swift +++ b/Persephone/DataSources/AlbumDataSource.swift @@ -10,8 +10,10 @@ import Cocoa import PromiseKit class AlbumDataSource: NSObject, NSCollectionViewDataSource { + var albums: [Album] = [] + func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int { - return AppDelegate.store.state.albumListState.albums.count + return albums.count } // // func resetCoverArt() { @@ -23,31 +25,31 @@ class AlbumDataSource: NSObject, NSCollectionViewDataSource { // } func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem { - let albums = AppDelegate.store.state.albumListState.albums let item = collectionView.makeItem(withIdentifier: .albumViewItem, for: indexPath) guard let albumViewItem = item as? AlbumViewItem else { return item } albumViewItem.view.wantsLayer = true albumViewItem.setAlbum(albums[indexPath.item]) -// if albums[indexPath.item].coverArt == nil && -// !albums[indexPath.item].coverArtFetched { -// -// AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) { -// guard let song = $0 else { return } -// -// AlbumArtService(song: Song(mpdSong: song)) -// .fetchAlbumArt() -// .done { image in -// self.albums[indexPath.item].coverArt = image -// self.albums[indexPath.item].coverArtFetched = true -// -// DispatchQueue.main.async { -// collectionView.reloadItems(at: [indexPath]) -// } -// } -// } -// } + switch albums[indexPath.item].coverArt { + case .notAsked: + AppDelegate.mpdClient.getAlbumFirstSong(for: albums[indexPath.item].mpdAlbum) { + guard let song = $0 else { return } + + AlbumArtService(song: Song(mpdSong: song)) + .fetchAlbumArt() + .done { image in + DispatchQueue.main.async { + AppDelegate.store.dispatch( + UpdateAlbumArt(coverArt: image, albumIndex: indexPath.item) + ) + //collectionView.reloadItems(at: [indexPath]) + } + } + } + default: + break + } return albumViewItem } diff --git a/Persephone/Models/Album.swift b/Persephone/Models/Album.swift index b82d95c..1042f32 100644 --- a/Persephone/Models/Album.swift +++ b/Persephone/Models/Album.swift @@ -11,8 +11,7 @@ import CryptoSwift struct Album { var mpdAlbum: MPDClient.MPDAlbum - var coverArt: NSImage? - var coverArtFetched: Bool = false + var coverArt: Loading = .notAsked init(mpdAlbum: MPDClient.MPDAlbum) { self.mpdAlbum = mpdAlbum @@ -34,6 +33,7 @@ struct Album { extension Album: Equatable { static func == (lhs: Album, rhs: Album) -> Bool { return (lhs.artist == rhs.artist) && - (lhs.title == rhs.title) + (lhs.title == rhs.title) && + (lhs.coverArt ~= rhs.coverArt) } } diff --git a/Persephone/Models/Loading.swift b/Persephone/Models/Loading.swift new file mode 100644 index 0000000..3c8a57e --- /dev/null +++ b/Persephone/Models/Loading.swift @@ -0,0 +1,30 @@ +// +// Loading.swift +// Persephone +// +// Created by Daniel Barber on 2019/4/27. +// Copyright © 2019 Dan Barber. All rights reserved. +// + +import Foundation + +enum Loading { + case notAsked + case loading + case loaded(T) + case error(Error) +} + +extension Loading: EnumEquatable { + static func ~= (lhs: Loading, rhs: Loading) -> Bool { + switch (lhs, rhs) { + case (.notAsked, .notAsked), + (.loading, .loading), + (.loaded, .loaded), + (.error, .error): + return true + default: + return false + } + } +} diff --git a/Persephone/Reducers/AlbumListReducer.swift b/Persephone/Reducers/AlbumListReducer.swift index 92ddcd1..fcaf1c6 100644 --- a/Persephone/Reducers/AlbumListReducer.swift +++ b/Persephone/Reducers/AlbumListReducer.swift @@ -14,6 +14,8 @@ func albumListReducer(action: Action, state: AlbumListState?) -> AlbumListState switch action { case let action as UpdateAlbumListAction: state.albums = action.albums.map { Album(mpdAlbum: $0) } + case let action as UpdateAlbumArt: + state.albums[action.albumIndex].coverArt = .loaded(action.coverArt) default: break } diff --git a/Persephone/Reducers/AppReducer.swift b/Persephone/Reducers/AppReducer.swift index bce611a..07c62c2 100644 --- a/Persephone/Reducers/AppReducer.swift +++ b/Persephone/Reducers/AppReducer.swift @@ -9,7 +9,6 @@ import ReSwift func appReducer(action: Action, state: AppState?) -> AppState { - print(action) return AppState( playerState: playerReducer(action: action, state: state?.playerState), queueState: queueReducer(action: action, state: state?.queueState), diff --git a/Persephone/State/AlbumListState.swift b/Persephone/State/AlbumListState.swift index a38af70..bf00dac 100644 --- a/Persephone/State/AlbumListState.swift +++ b/Persephone/State/AlbumListState.swift @@ -10,7 +10,6 @@ import ReSwift struct AlbumListState: StateType { var albums: [Album] = [] - var albumsWithUpdates: [Int] } extension AlbumListState: Equatable {