mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Add a button to albums that plays the album
This works by clearing the queue, adding all the tracks from the album to the queue and playing the first track. Fix bug where resize might leave a play button visible Had to refactor the QueueView somewhat as there was a bug that only surfaced on clearing and refilling the playlist. The bug was due to the way NSOutlineView reuses subviews. Add screenshot with album play button Move queue datasource and refactor view controller Move album datasource out of the view controller
This commit is contained in:
parent
5d0e1c4719
commit
2d6aa478a7
@ -16,20 +16,21 @@
|
|||||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */; };
|
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */; };
|
||||||
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */; };
|
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */; };
|
||||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C1220E134F0006D9BE /* AlbumViewController.swift */; };
|
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C1220E134F0006D9BE /* AlbumViewController.swift */; };
|
||||||
E408D3CA220E341D0006D9BE /* AlbumItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C8220E341D0006D9BE /* AlbumItem.swift */; };
|
|
||||||
E408D3CB220E341D0006D9BE /* AlbumItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E408D3C9220E341D0006D9BE /* AlbumItem.xib */; };
|
E408D3CB220E341D0006D9BE /* AlbumItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E408D3C9220E341D0006D9BE /* AlbumItem.xib */; };
|
||||||
|
E40F41F3221EDE27004B6CB8 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40F41F2221EDE27004B6CB8 /* Preferences.swift */; };
|
||||||
E40FE719221B48E300A4223F /* AlbumViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE718221B48E300A4223F /* AlbumViewLayout.swift */; };
|
E40FE719221B48E300A4223F /* AlbumViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE718221B48E300A4223F /* AlbumViewLayout.swift */; };
|
||||||
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE71A221B904300A4223F /* NSEvent.swift */; };
|
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE71A221B904300A4223F /* NSEvent.swift */; };
|
||||||
E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
E41B22C021FB6BBA00D544F6 /* libmpdclient.2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (Required, ); }; };
|
||||||
E41B22C121FB6C3300D544F6 /* libmpdclient.2.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
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 */; };
|
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
|
||||||
E41EA46C221636AF0068EF46 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41EA46B221636AF0068EF46 /* PreferencesViewController.swift */; };
|
E41EA46C221636AF0068EF46 /* PreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41EA46B221636AF0068EF46 /* PreferencesViewController.swift */; };
|
||||||
E41EA46F221715910068EF46 /* Preferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41EA46E221715910068EF46 /* Preferences.swift */; };
|
|
||||||
E42A8F3B22176D6400A13ED9 /* LICENSE.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3922176D6400A13ED9 /* LICENSE.md */; };
|
E42A8F3B22176D6400A13ED9 /* LICENSE.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3922176D6400A13ED9 /* LICENSE.md */; };
|
||||||
E42A8F3C22176D6400A13ED9 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3A22176D6400A13ED9 /* README.md */; };
|
E42A8F3C22176D6400A13ED9 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = E42A8F3A22176D6400A13ED9 /* README.md */; };
|
||||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E465049921E94DF500A70F4C /* WindowController.swift */; };
|
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E465049921E94DF500A70F4C /* WindowController.swift */; };
|
||||||
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */; };
|
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */; };
|
||||||
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD222205D2500F747E6 /* MainWindow.swift */; };
|
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD222205D2500F747E6 /* MainWindow.swift */; };
|
||||||
|
E47E2FD5222071FD00F747E6 /* AlbumItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD4222071FD00F747E6 /* AlbumItem.swift */; };
|
||||||
|
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD62220720300F747E6 /* AlbumItemView.swift */; };
|
||||||
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4928E0A2218D62A001D4BEA /* CGColor.swift */; };
|
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4928E0A2218D62A001D4BEA /* CGColor.swift */; };
|
||||||
E4A642DA22090CBE00067D21 /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A642D922090CBE00067D21 /* Status.swift */; };
|
E4A642DA22090CBE00067D21 /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A642D922090CBE00067D21 /* Status.swift */; };
|
||||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
|
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
|
||||||
@ -38,6 +39,9 @@
|
|||||||
E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; };
|
E4E8CC9A22075D370024217A /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* Song.swift */; };
|
||||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB2378220F10B8008C70C0 /* Pair.swift */; };
|
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB2378220F10B8008C70C0 /* Pair.swift */; };
|
||||||
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB237A220F7CF1008C70C0 /* Album.swift */; };
|
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4EB237A220F7CF1008C70C0 /* Album.swift */; };
|
||||||
|
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */; };
|
||||||
|
E4F6B463221E125900ACF42A /* SongItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B462221E125900ACF42A /* SongItem.swift */; };
|
||||||
|
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B466221E233200ACF42A /* AlbumDataSource.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -88,8 +92,8 @@
|
|||||||
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSUserInterfaceItemIdentifier.swift; sourceTree = "<group>"; };
|
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSUserInterfaceItemIdentifier.swift; sourceTree = "<group>"; };
|
||||||
E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
|
E408D3BD220E03EE0006D9BE /* RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RawRepresentable.swift; sourceTree = "<group>"; };
|
||||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewController.swift; sourceTree = "<group>"; };
|
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewController.swift; sourceTree = "<group>"; };
|
||||||
E408D3C8220E341D0006D9BE /* AlbumItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumItem.swift; sourceTree = "<group>"; };
|
|
||||||
E408D3C9220E341D0006D9BE /* AlbumItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumItem.xib; sourceTree = "<group>"; };
|
E408D3C9220E341D0006D9BE /* AlbumItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumItem.xib; sourceTree = "<group>"; };
|
||||||
|
E40F41F2221EDE27004B6CB8 /* Preferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
||||||
E40FE718221B48E300A4223F /* AlbumViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewLayout.swift; sourceTree = "<group>"; };
|
E40FE718221B48E300A4223F /* AlbumViewLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewLayout.swift; sourceTree = "<group>"; };
|
||||||
E40FE71A221B904300A4223F /* NSEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEvent.swift; sourceTree = "<group>"; };
|
E40FE71A221B904300A4223F /* NSEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEvent.swift; sourceTree = "<group>"; };
|
||||||
E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = "<group>"; };
|
E41B22BF21FB6BBA00D544F6 /* libmpdclient.2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libmpdclient.2.dylib; path = libmpdclient/output/libmpdclient.2.dylib; sourceTree = "<group>"; };
|
||||||
@ -131,12 +135,13 @@
|
|||||||
E41B22EA21FB966C00D544F6 /* queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = queue.h; sourceTree = "<group>"; };
|
E41B22EA21FB966C00D544F6 /* queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = queue.h; sourceTree = "<group>"; };
|
||||||
E41B22EB21FB966C00D544F6 /* playlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = playlist.h; sourceTree = "<group>"; };
|
E41B22EB21FB966C00D544F6 /* playlist.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = playlist.h; sourceTree = "<group>"; };
|
||||||
E41EA46B221636AF0068EF46 /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = "<group>"; };
|
E41EA46B221636AF0068EF46 /* PreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesViewController.swift; sourceTree = "<group>"; };
|
||||||
E41EA46E221715910068EF46 /* Preferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Preferences.swift; sourceTree = "<group>"; };
|
|
||||||
E42A8F3922176D6400A13ED9 /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = "<group>"; };
|
E42A8F3922176D6400A13ED9 /* LICENSE.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = LICENSE.md; sourceTree = "<group>"; };
|
||||||
E42A8F3A22176D6400A13ED9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
E42A8F3A22176D6400A13ED9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||||
E465049921E94DF500A70F4C /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = "<group>"; };
|
E465049921E94DF500A70F4C /* WindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowController.swift; sourceTree = "<group>"; };
|
||||||
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = "<group>"; };
|
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = "<group>"; };
|
||||||
E47E2FD222205D2500F747E6 /* MainWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindow.swift; sourceTree = "<group>"; };
|
E47E2FD222205D2500F747E6 /* MainWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainWindow.swift; sourceTree = "<group>"; };
|
||||||
|
E47E2FD4222071FD00F747E6 /* AlbumItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumItem.swift; sourceTree = "<group>"; };
|
||||||
|
E47E2FD62220720300F747E6 /* AlbumItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumItemView.swift; sourceTree = "<group>"; };
|
||||||
E4928E0A2218D62A001D4BEA /* CGColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGColor.swift; sourceTree = "<group>"; };
|
E4928E0A2218D62A001D4BEA /* CGColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGColor.swift; sourceTree = "<group>"; };
|
||||||
E4A642D922090CBE00067D21 /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
|
E4A642D922090CBE00067D21 /* Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Status.swift; sourceTree = "<group>"; };
|
||||||
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
|
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
|
||||||
@ -145,6 +150,9 @@
|
|||||||
E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
|
E4E8CC9922075D370024217A /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.swift; sourceTree = "<group>"; };
|
||||||
E4EB2378220F10B8008C70C0 /* Pair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pair.swift; sourceTree = "<group>"; };
|
E4EB2378220F10B8008C70C0 /* Pair.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pair.swift; sourceTree = "<group>"; };
|
||||||
E4EB237A220F7CF1008C70C0 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
|
E4EB237A220F7CF1008C70C0 /* Album.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Album.swift; sourceTree = "<group>"; };
|
||||||
|
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueDataSource.swift; sourceTree = "<group>"; };
|
||||||
|
E4F6B462221E125900ACF42A /* SongItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongItem.swift; sourceTree = "<group>"; };
|
||||||
|
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDataSource.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -200,7 +208,8 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E40FE717221B48CE00A4223F /* Layouts */,
|
E40FE717221B48CE00A4223F /* Layouts */,
|
||||||
E41EA46D221715820068EF46 /* Models */,
|
E4F6B461221E124700ACF42A /* Models */,
|
||||||
|
E4F6B45E221E117600ACF42A /* DataSources */,
|
||||||
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
E407861F2110CE70006887B1 /* Assets.xcassets */,
|
||||||
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
E408D3B7220DE8CC0006D9BE /* Extensions */,
|
||||||
E4D1B598220BA3C90026F233 /* Resources */,
|
E4D1B598220BA3C90026F233 /* Resources */,
|
||||||
@ -255,7 +264,7 @@
|
|||||||
E408D3C3220E138B0006D9BE /* Views */ = {
|
E408D3C3220E138B0006D9BE /* Views */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
E408D3C8220E341D0006D9BE /* AlbumItem.swift */,
|
E47E2FD62220720300F747E6 /* AlbumItemView.swift */,
|
||||||
E47E2FD222205D2500F747E6 /* MainWindow.swift */,
|
E47E2FD222205D2500F747E6 /* MainWindow.swift */,
|
||||||
);
|
);
|
||||||
path = Views;
|
path = Views;
|
||||||
@ -328,14 +337,6 @@
|
|||||||
path = mpd;
|
path = mpd;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
E41EA46D221715820068EF46 /* Models */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
E41EA46E221715910068EF46 /* Preferences.swift */,
|
|
||||||
);
|
|
||||||
path = Models;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
E4A642DB220912FA00067D21 /* MPDClient */ = {
|
E4A642DB220912FA00067D21 /* MPDClient */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -369,6 +370,7 @@
|
|||||||
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
E4D1B597220BA3A20026F233 /* Controllers */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
E47E2FD4222071FD00F747E6 /* AlbumItem.swift */,
|
||||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
||||||
E41EA46B221636AF0068EF46 /* PreferencesViewController.swift */,
|
E41EA46B221636AF0068EF46 /* PreferencesViewController.swift */,
|
||||||
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
E4E8CC932206097F0024217A /* NotificationsController.swift */,
|
||||||
@ -388,6 +390,24 @@
|
|||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
E4F6B45E221E117600ACF42A /* DataSources */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */,
|
||||||
|
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */,
|
||||||
|
);
|
||||||
|
path = DataSources;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
E4F6B461221E124700ACF42A /* Models */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
E40F41F2221EDE27004B6CB8 /* Preferences.swift */,
|
||||||
|
E4F6B462221E125900ACF42A /* SongItem.swift */,
|
||||||
|
);
|
||||||
|
path = Models;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -530,25 +550,29 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */,
|
||||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */,
|
||||||
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
|
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */,
|
||||||
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
|
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
|
||||||
|
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */,
|
||||||
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
|
E4A642DA22090CBE00067D21 /* Status.swift in Sources */,
|
||||||
|
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */,
|
||||||
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
|
E4E8CC942206097F0024217A /* NotificationsController.swift in Sources */,
|
||||||
E40FE719221B48E300A4223F /* AlbumViewLayout.swift in Sources */,
|
E40FE719221B48E300A4223F /* AlbumViewLayout.swift in Sources */,
|
||||||
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
||||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
||||||
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */,
|
E4EB2379220F10B8008C70C0 /* Pair.swift in Sources */,
|
||||||
E41EA46F221715910068EF46 /* Preferences.swift in Sources */,
|
E4F6B463221E125900ACF42A /* SongItem.swift in Sources */,
|
||||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||||
|
E40F41F3221EDE27004B6CB8 /* Preferences.swift in Sources */,
|
||||||
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
E407861C2110CE6E006887B1 /* AppDelegate.swift in Sources */,
|
||||||
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */,
|
E47E2FD322205D2500F747E6 /* MainWindow.swift in Sources */,
|
||||||
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */,
|
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */,
|
||||||
E4E8CC9A22075D370024217A /* Song.swift in Sources */,
|
E4E8CC9A22075D370024217A /* Song.swift in Sources */,
|
||||||
E408D3CA220E341D0006D9BE /* AlbumItem.swift in Sources */,
|
|
||||||
E41EA46C221636AF0068EF46 /* PreferencesViewController.swift in Sources */,
|
E41EA46C221636AF0068EF46 /* PreferencesViewController.swift in Sources */,
|
||||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
||||||
|
E47E2FD5222071FD00F747E6 /* AlbumItem.swift in Sources */,
|
||||||
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
||||||
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */,
|
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */,
|
||||||
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */,
|
E4EB237B220F7CF1008C70C0 /* Album.swift in Sources */,
|
||||||
|
|||||||
25
Persephone/Assets.xcassets/playButtonLarge.imageset/Contents.json
vendored
Normal file
25
Persephone/Assets.xcassets/playButtonLarge.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "playButtonLarge.png",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"filename" : "playButtonLarge@2x.png",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"template-rendering-intent" : "template"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge.png
vendored
Normal file
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 B |
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge@2x.png
vendored
Normal file
BIN
Persephone/Assets.xcassets/playButtonLarge.imageset/playButtonLarge@2x.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 516 B |
@ -10,6 +10,7 @@ import Cocoa
|
|||||||
|
|
||||||
class AlbumItem: NSCollectionViewItem {
|
class AlbumItem: NSCollectionViewItem {
|
||||||
var observer: NSKeyValueObservation?
|
var observer: NSKeyValueObservation?
|
||||||
|
var album: MPDClient.Album?
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
@ -27,6 +28,7 @@ class AlbumItem: NSCollectionViewItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setAlbum(_ album: MPDClient.Album) {
|
func setAlbum(_ album: MPDClient.Album) {
|
||||||
|
self.album = album
|
||||||
albumTitle.stringValue = album.title
|
albumTitle.stringValue = album.title
|
||||||
albumArtist.stringValue = album.artist
|
albumArtist.stringValue = album.artist
|
||||||
}
|
}
|
||||||
@ -42,6 +44,12 @@ class AlbumItem: NSCollectionViewItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction func playAlbum(_ sender: Any) {
|
||||||
|
guard let album = album else { return }
|
||||||
|
|
||||||
|
AppDelegate.mpdClient.playAlbum(album)
|
||||||
|
}
|
||||||
|
|
||||||
@IBOutlet var albumCoverView: NSImageView!
|
@IBOutlet var albumCoverView: NSImageView!
|
||||||
@IBOutlet var albumTitle: NSTextField!
|
@IBOutlet var albumTitle: NSTextField!
|
||||||
@IBOutlet var albumArtist: NSTextField!
|
@IBOutlet var albumArtist: NSTextField!
|
||||||
@ -9,16 +9,18 @@
|
|||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class AlbumViewController: NSViewController,
|
class AlbumViewController: NSViewController,
|
||||||
NSCollectionViewDataSource,
|
|
||||||
NSCollectionViewDelegate,
|
NSCollectionViewDelegate,
|
||||||
NSCollectionViewDelegateFlowLayout {
|
NSCollectionViewDelegateFlowLayout {
|
||||||
var albums: [MPDClient.Album] = []
|
|
||||||
let paddingWidth: CGFloat = 40
|
let paddingWidth: CGFloat = 40
|
||||||
let gutterWidth: CGFloat = 20
|
let gutterWidth: CGFloat = 20
|
||||||
|
|
||||||
|
var dataSource = AlbumDataSource()
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
|
albumScrollView.postsBoundsChangedNotifications = true
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver(
|
||||||
self,
|
self,
|
||||||
selector: #selector(updateAlbums(_:)),
|
selector: #selector(updateAlbums(_:)),
|
||||||
@ -32,6 +34,8 @@ class AlbumViewController: NSViewController,
|
|||||||
name: Notification.willDisconnect,
|
name: Notification.willDisconnect,
|
||||||
object: AppDelegate.mpdClient
|
object: AppDelegate.mpdClient
|
||||||
)
|
)
|
||||||
|
|
||||||
|
albumCollectionView.dataSource = dataSource
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillLayout() {
|
override func viewWillLayout() {
|
||||||
@ -44,30 +48,16 @@ class AlbumViewController: NSViewController,
|
|||||||
guard let albums = notification.userInfo?[Notification.albumsKey] as? [MPDClient.Album]
|
guard let albums = notification.userInfo?[Notification.albumsKey] as? [MPDClient.Album]
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
self.albums = albums
|
dataSource.albums = albums
|
||||||
|
|
||||||
albumCollectionView.reloadData()
|
albumCollectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func clearAlbums(_ notification: Notification) {
|
@objc func clearAlbums(_ notification: Notification) {
|
||||||
self.albums = []
|
dataSource.albums = []
|
||||||
|
|
||||||
albumCollectionView.reloadData()
|
albumCollectionView.reloadData()
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
@IBOutlet var albumScrollView: NSScrollView!
|
||||||
return albums.count
|
|
||||||
}
|
|
||||||
|
|
||||||
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
|
||||||
let item = collectionView.makeItem(withIdentifier: .albumItem, for: indexPath)
|
|
||||||
guard let albumItem = item as? AlbumItem else { return item }
|
|
||||||
|
|
||||||
albumItem.view.wantsLayer = true
|
|
||||||
albumItem.setAlbum(albums[indexPath.item])
|
|
||||||
|
|
||||||
return albumItem
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBOutlet var albumCollectionView: NSCollectionView!
|
@IBOutlet var albumCollectionView: NSCollectionView!
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,11 +8,9 @@
|
|||||||
|
|
||||||
import Cocoa
|
import Cocoa
|
||||||
|
|
||||||
class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineViewDelegate {
|
class QueueViewController: NSViewController,
|
||||||
var queue: [MPDClient.Song] = []
|
NSOutlineViewDelegate {
|
||||||
var queuePos: Int = -1
|
var dataSource = QueueDataSource()
|
||||||
|
|
||||||
var queueIcon: NSImage? = nil
|
|
||||||
|
|
||||||
let systemFontRegular = NSFont.systemFont(ofSize: 13, weight: .regular)
|
let systemFontRegular = NSFont.systemFont(ofSize: 13, weight: .regular)
|
||||||
let systemFontBold = NSFont.systemFont(ofSize: 13, weight: .bold)
|
let systemFontBold = NSFont.systemFont(ofSize: 13, weight: .bold)
|
||||||
@ -20,16 +18,130 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
let playIcon = NSImage(named: "playButton")
|
let playIcon = NSImage(named: "playButton")
|
||||||
let pauseIcon = NSImage(named: "pauseButton")
|
let pauseIcon = NSImage(named: "pauseButton")
|
||||||
|
|
||||||
struct SongItem {
|
@IBOutlet var queueView: NSOutlineView!
|
||||||
var song: MPDClient.Song
|
|
||||||
var queuePos: Int
|
|
||||||
}
|
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
setupNotificationObservers()
|
||||||
|
|
||||||
|
queueView.dataSource = dataSource
|
||||||
|
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
||||||
|
}
|
||||||
|
|
||||||
|
override func keyDown(with event: NSEvent) {
|
||||||
|
switch event.keyCode {
|
||||||
|
case NSEvent.keyCodeSpace:
|
||||||
|
nextResponder?.keyDown(with: event)
|
||||||
|
default:
|
||||||
|
super.keyDown(with: event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func playTrack(_ sender: Any) {
|
||||||
|
if dataSource.queuePos >= 0 {
|
||||||
|
AppDelegate.mpdClient.playTrack(queuePos: dataSource.queuePos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func stateChanged(_ notification: Notification) {
|
||||||
|
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
dataSource.setQueueIcon(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func queueChanged(_ notification: Notification) {
|
||||||
|
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
dataSource.updateQueue(queue)
|
||||||
|
queueView.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func queuePosChanged(_ notification: Notification) {
|
||||||
|
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
dataSource.setQueuePos(queuePos)
|
||||||
|
|
||||||
|
queueView.reloadData()
|
||||||
|
}
|
||||||
|
|
||||||
|
func outlineView(
|
||||||
|
_ outlineView: NSOutlineView,
|
||||||
|
selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet
|
||||||
|
) -> IndexSet {
|
||||||
|
if proposedSelectionIndexes.contains(0) {
|
||||||
|
return IndexSet()
|
||||||
|
} else {
|
||||||
|
return proposedSelectionIndexes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
||||||
|
if let songItem = item as? SongItem {
|
||||||
|
switch tableColumn?.identifier.rawValue {
|
||||||
|
case "songTitleColumn":
|
||||||
|
return cellForSongTitle(outlineView, with: songItem)
|
||||||
|
case "songArtistColumn":
|
||||||
|
return cellForSongArtist(outlineView, with: songItem)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
} else if tableColumn?.identifier.rawValue == "songTitleColumn" {
|
||||||
|
return cellForQueueHeading(outlineView)
|
||||||
|
} else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cellForSongTitle(_ outlineView: NSOutlineView, with songItem: SongItem) -> NSView {
|
||||||
|
let cellView = outlineView.makeView(
|
||||||
|
withIdentifier: .queueSongTitle,
|
||||||
|
owner: self
|
||||||
|
) as! NSTableCellView
|
||||||
|
|
||||||
|
cellView.textField?.stringValue = songItem.song.getTag(.title)
|
||||||
|
if songItem.isPlaying {
|
||||||
|
cellView.textField?.font = systemFontBold
|
||||||
|
cellView.imageView?.image = dataSource.queueIcon
|
||||||
|
} else {
|
||||||
|
cellView.textField?.font = systemFontRegular
|
||||||
|
cellView.imageView?.image = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return cellView
|
||||||
|
}
|
||||||
|
|
||||||
|
func cellForSongArtist(_ outlineView: NSOutlineView, with songItem: SongItem) -> NSView {
|
||||||
|
let cellView = outlineView.makeView(
|
||||||
|
withIdentifier: .queueSongArtist,
|
||||||
|
owner: self
|
||||||
|
) as! NSTableCellView
|
||||||
|
|
||||||
|
cellView.textField?.stringValue = songItem.song.getTag(.artist)
|
||||||
|
if songItem.isPlaying {
|
||||||
|
cellView.textField?.font = systemFontBold
|
||||||
|
} else {
|
||||||
|
cellView.textField?.font = systemFontRegular
|
||||||
|
}
|
||||||
|
|
||||||
|
return cellView
|
||||||
|
}
|
||||||
|
|
||||||
|
func cellForQueueHeading(_ outlineView: NSOutlineView) -> NSView {
|
||||||
|
let cellView = outlineView.makeView(
|
||||||
|
withIdentifier: .queueHeading,
|
||||||
|
owner: self
|
||||||
|
) as! NSTableCellView
|
||||||
|
|
||||||
|
cellView.textField?.stringValue = "QUEUE"
|
||||||
|
|
||||||
|
return cellView
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupNotificationObservers() {
|
||||||
NotificationCenter.default.addObserver(
|
NotificationCenter.default.addObserver(
|
||||||
self,
|
self,
|
||||||
selector: #selector(stateChanged(_:)),
|
selector: #selector(stateChanged(_:)),
|
||||||
@ -50,177 +162,5 @@ class QueueViewController: NSViewController, NSOutlineViewDataSource, NSOutlineV
|
|||||||
name: Notification.queuePosChanged,
|
name: Notification.queuePosChanged,
|
||||||
object: AppDelegate.mpdClient
|
object: AppDelegate.mpdClient
|
||||||
)
|
)
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(
|
|
||||||
self,
|
|
||||||
selector: #selector(clearQueue(_:)),
|
|
||||||
name: Notification.willDisconnect,
|
|
||||||
object: AppDelegate.mpdClient
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func keyDown(with event: NSEvent) {
|
|
||||||
switch event.keyCode {
|
|
||||||
case NSEvent.keyCodeSpace:
|
|
||||||
nextResponder?.keyDown(with: event)
|
|
||||||
default:
|
|
||||||
super.keyDown(with: event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBAction func playTrack(_ sender: Any) {
|
|
||||||
guard let view = sender as? NSOutlineView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
let queuePos = view.selectedRow - 1
|
|
||||||
|
|
||||||
if queuePos >= 0 {
|
|
||||||
AppDelegate.mpdClient.playTrack(queuePos: queuePos)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func stateChanged(_ notification: Notification) {
|
|
||||||
guard let state = notification.userInfo?[Notification.stateKey] as? MPDClient.Status.State
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
setQueueIcon(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func queueChanged(_ notification: Notification) {
|
|
||||||
guard let queue = notification.userInfo?[Notification.queueKey] as? [MPDClient.Song]
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
self.queue = queue
|
|
||||||
|
|
||||||
queueView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func queuePosChanged(_ notification: Notification) {
|
|
||||||
guard let queuePos = notification.userInfo?[Notification.queuePosKey] as? Int
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
let oldSongRowPos = self.queuePos + 1
|
|
||||||
let newSongRowPos = queuePos + 1
|
|
||||||
self.queuePos = queuePos
|
|
||||||
|
|
||||||
setQueuePos(oldSongRowPos: oldSongRowPos, newSongRowPos: newSongRowPos)
|
|
||||||
|
|
||||||
queueView.reloadData(
|
|
||||||
forRowIndexes: [oldSongRowPos, newSongRowPos],
|
|
||||||
columnIndexes: [0, 1]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func clearQueue(_ notification: Notification) {
|
|
||||||
self.queue = []
|
|
||||||
|
|
||||||
queueView.reloadData()
|
|
||||||
}
|
|
||||||
|
|
||||||
func setQueueIcon(_ state: MPDClient.Status.State) {
|
|
||||||
switch state {
|
|
||||||
case .playing:
|
|
||||||
self.queueIcon = playIcon
|
|
||||||
case .paused:
|
|
||||||
self.queueIcon = pauseIcon
|
|
||||||
default:
|
|
||||||
self.queueIcon = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func setQueuePos(oldSongRowPos: Int, newSongRowPos: Int) {
|
|
||||||
if oldSongRowPos > 0 {
|
|
||||||
guard let oldSongRow = queueView.rowView(atRow: oldSongRowPos, makeIfNecessary: true),
|
|
||||||
let oldSongTitleCell = oldSongRow.view(atColumn: 0) as? NSTableCellView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
setRowFont(rowView: oldSongRow, font: systemFontRegular)
|
|
||||||
oldSongTitleCell.imageView?.image = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let songRow = queueView.rowView(atRow: newSongRowPos, makeIfNecessary: true),
|
|
||||||
let newSongTitleCell = songRow.view(atColumn: 0) as? NSTableCellView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
setRowFont(rowView: songRow, font: systemFontBold)
|
|
||||||
newSongTitleCell.imageView?.image = self.queueIcon
|
|
||||||
}
|
|
||||||
|
|
||||||
func setRowFont(rowView: NSTableRowView, font: NSFont) {
|
|
||||||
guard let songTitleCell = rowView.view(atColumn: 0) as? NSTableCellView,
|
|
||||||
let songArtistCell = rowView.view(atColumn: 1) as? NSTableCellView
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
songTitleCell.textField?.font = font
|
|
||||||
songArtistCell.textField?.font = font
|
|
||||||
}
|
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
|
||||||
return queue.count + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
|
||||||
if index > 0 {
|
|
||||||
return SongItem(song: queue[index - 1], queuePos: index - 1)
|
|
||||||
} else {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
|
||||||
if let songItem = item as? SongItem {
|
|
||||||
switch tableColumn?.identifier.rawValue {
|
|
||||||
case "songTitleColumn":
|
|
||||||
let cellView = outlineView.makeView(
|
|
||||||
withIdentifier: .queueSongTitle,
|
|
||||||
owner: self
|
|
||||||
) as! NSTableCellView
|
|
||||||
|
|
||||||
cellView.textField?.stringValue = songItem.song.getTag(.title)
|
|
||||||
|
|
||||||
return cellView
|
|
||||||
case "songArtistColumn":
|
|
||||||
let cellView = outlineView.makeView(
|
|
||||||
withIdentifier: .queueSongArtist,
|
|
||||||
owner: self
|
|
||||||
) as! NSTableCellView
|
|
||||||
|
|
||||||
cellView.textField?.stringValue = songItem.song.getTag(.artist)
|
|
||||||
|
|
||||||
return cellView
|
|
||||||
default:
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if tableColumn?.identifier.rawValue == "songTitleColumn" {
|
|
||||||
let cellView = outlineView.makeView(
|
|
||||||
withIdentifier: .queueHeading,
|
|
||||||
owner: self
|
|
||||||
) as! NSTableCellView
|
|
||||||
|
|
||||||
cellView.textField?.stringValue = "QUEUE"
|
|
||||||
|
|
||||||
return cellView
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func outlineView(
|
|
||||||
_ outlineView: NSOutlineView,
|
|
||||||
selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet
|
|
||||||
) -> IndexSet {
|
|
||||||
if proposedSelectionIndexes.contains(0) {
|
|
||||||
return IndexSet()
|
|
||||||
} else {
|
|
||||||
return proposedSelectionIndexes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@IBOutlet var queueView: NSOutlineView!
|
|
||||||
}
|
}
|
||||||
|
|||||||
27
Persephone/DataSources/AlbumDataSource.swift
Normal file
27
Persephone/DataSources/AlbumDataSource.swift
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
//
|
||||||
|
// AlbumDataSource.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/2/20.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class AlbumDataSource: NSObject, NSCollectionViewDataSource {
|
||||||
|
var albums: [MPDClient.Album] = []
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: NSCollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||||
|
return albums.count
|
||||||
|
}
|
||||||
|
|
||||||
|
func collectionView(_ collectionView: NSCollectionView, itemForRepresentedObjectAt indexPath: IndexPath) -> NSCollectionViewItem {
|
||||||
|
let item = collectionView.makeItem(withIdentifier: .albumItem, for: indexPath)
|
||||||
|
guard let albumItem = item as? AlbumItem else { return item }
|
||||||
|
|
||||||
|
albumItem.view.wantsLayer = true
|
||||||
|
albumItem.setAlbum(albums[indexPath.item])
|
||||||
|
|
||||||
|
return albumItem
|
||||||
|
}
|
||||||
|
}
|
||||||
65
Persephone/DataSources/QueueDataSource.swift
Normal file
65
Persephone/DataSources/QueueDataSource.swift
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
//
|
||||||
|
// QueueDataSource.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/2/20.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
||||||
|
var queue: [SongItem] = []
|
||||||
|
var queuePos: Int = -1
|
||||||
|
|
||||||
|
var queueIcon: NSImage? = nil
|
||||||
|
|
||||||
|
let playIcon = NSImage(named: "playButton")
|
||||||
|
let pauseIcon = NSImage(named: "pauseButton")
|
||||||
|
|
||||||
|
func updateQueue(_ queue: [MPDClient.Song]) {
|
||||||
|
self.queue = queue.enumerated().map { index, song in
|
||||||
|
SongItem(song: song, queuePos: index, isPlaying: index == queuePos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setQueuePos(_ queuePos: Int) {
|
||||||
|
let oldSongRowPos = self.queuePos
|
||||||
|
let newSongRowPos = queuePos
|
||||||
|
self.queuePos = queuePos
|
||||||
|
|
||||||
|
if oldSongRowPos >= 0 {
|
||||||
|
queue[oldSongRowPos].isPlaying = false
|
||||||
|
}
|
||||||
|
if newSongRowPos >= 0 {
|
||||||
|
queue[newSongRowPos].isPlaying = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setQueueIcon(_ state: MPDClient.Status.State) {
|
||||||
|
switch state {
|
||||||
|
case .playing:
|
||||||
|
queueIcon = playIcon
|
||||||
|
case .paused:
|
||||||
|
queueIcon = pauseIcon
|
||||||
|
default:
|
||||||
|
queueIcon = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
||||||
|
return queue.count + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
||||||
|
if index > 0 {
|
||||||
|
return queue[index - 1]
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -119,6 +119,27 @@ class MPDClient {
|
|||||||
idle()
|
idle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func playAlbum(_ album: Album) {
|
||||||
|
noIdle()
|
||||||
|
commandQueue.async { [unowned self] in
|
||||||
|
var songs: [Song] = []
|
||||||
|
|
||||||
|
mpd_run_clear(self.connection)
|
||||||
|
mpd_search_db_songs(self.connection, true)
|
||||||
|
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM, album.title)
|
||||||
|
mpd_search_add_tag_constraint(self.connection, MPD_OPERATOR_DEFAULT, MPD_TAG_ALBUM_ARTIST, album.artist)
|
||||||
|
mpd_search_commit(self.connection)
|
||||||
|
while let mpdSong = mpd_recv_song(self.connection) {
|
||||||
|
songs.append(Song(mpdSong))
|
||||||
|
}
|
||||||
|
for song in songs {
|
||||||
|
mpd_run_add(self.connection, song.uri)
|
||||||
|
}
|
||||||
|
mpd_run_play_pos(self.connection, 0)
|
||||||
|
}
|
||||||
|
idle()
|
||||||
|
}
|
||||||
|
|
||||||
func queueCommand(command: Command) {
|
func queueCommand(command: Command) {
|
||||||
guard isConnected else { return }
|
guard isConnected else { return }
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,10 @@ extension MPDClient {
|
|||||||
mpd_song_free(mpdSong)
|
mpd_song_free(mpdSong)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var uri: UnsafePointer<Int8> {
|
||||||
|
return mpd_song_get_uri(mpdSong)
|
||||||
|
}
|
||||||
|
|
||||||
func getTag(_ tagType: TagType) -> String {
|
func getTag(_ tagType: TagType) -> String {
|
||||||
let mpdTagType = mpd_tag_type(rawValue: Int32(tagType.rawValue))
|
let mpdTagType = mpd_tag_type(rawValue: Int32(tagType.rawValue))
|
||||||
|
|
||||||
|
|||||||
15
Persephone/Models/SongItem.swift
Normal file
15
Persephone/Models/SongItem.swift
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
//
|
||||||
|
// SongItem.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/2/20.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
struct SongItem {
|
||||||
|
var song: MPDClient.Song
|
||||||
|
var queuePos: Int
|
||||||
|
var isPlaying: Bool
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@
|
|||||||
<customObject id="-2" userLabel="File's Owner" customClass="AlbumItem" customModule="Persephone" customModuleProvider="target">
|
<customObject id="-2" userLabel="File's Owner" customClass="AlbumItem" customModule="Persephone" customModuleProvider="target">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="albumArtist" destination="5Uu-j1-qyT" id="2Et-tX-InT"/>
|
<outlet property="albumArtist" destination="5Uu-j1-qyT" id="2Et-tX-InT"/>
|
||||||
<outlet property="albumCoverView" destination="Kfb-8f-ean" id="ZAL-jD-lHj"/>
|
<outlet property="albumCoverView" destination="Kfb-8f-ean" id="CXx-gB-gz8"/>
|
||||||
<outlet property="albumTitle" destination="KEh-NL-c2W" id="SI3-hm-H2B"/>
|
<outlet property="albumTitle" destination="KEh-NL-c2W" id="SI3-hm-H2B"/>
|
||||||
<outlet property="imageView" destination="Kfb-8f-ean" id="Ur0-hX-wJm"/>
|
<outlet property="imageView" destination="Kfb-8f-ean" id="Ur0-hX-wJm"/>
|
||||||
<outlet property="view" destination="Hz6-mo-xeY" id="v7W-XA-Emc"/>
|
<outlet property="view" destination="Hz6-mo-xeY" id="v7W-XA-Emc"/>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
</customObject>
|
</customObject>
|
||||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
<customView id="Hz6-mo-xeY">
|
<customView id="Hz6-mo-xeY" customClass="AlbumItemView" customModule="Persephone" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="128" height="167"/>
|
<rect key="frame" x="0.0" y="0.0" width="128" height="167"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
@ -41,24 +41,45 @@
|
|||||||
<rect key="frame" x="0.0" y="39" width="128" height="128"/>
|
<rect key="frame" x="0.0" y="39" width="128" height="128"/>
|
||||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="blankAlbum" id="FsA-JX-BFh"/>
|
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="blankAlbum" id="FsA-JX-BFh"/>
|
||||||
</imageView>
|
</imageView>
|
||||||
|
<button hidden="YES" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="n8W-do-HyG">
|
||||||
|
<rect key="frame" x="43" y="81" width="42" height="43"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="height" constant="42" id="XXC-YE-Ego"/>
|
||||||
|
<constraint firstAttribute="width" constant="42" id="zcR-GT-zym"/>
|
||||||
|
</constraints>
|
||||||
|
<buttonCell key="cell" type="inline" bezelStyle="inline" image="playButtonLarge" imagePosition="only" alignment="center" lineBreakMode="truncatingTail" state="on" borderStyle="border" inset="2" id="T1p-LZ-RpJ">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="smallSystemBold"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="playAlbum:" target="-2" id="gNt-Rn-kte"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
</subviews>
|
</subviews>
|
||||||
<constraints>
|
<constraints>
|
||||||
<constraint firstItem="5Uu-j1-qyT" firstAttribute="trailing" secondItem="KEh-NL-c2W" secondAttribute="trailing" id="64z-uz-4nY"/>
|
<constraint firstItem="5Uu-j1-qyT" firstAttribute="trailing" secondItem="KEh-NL-c2W" secondAttribute="trailing" id="64z-uz-4nY"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="KEh-NL-c2W" secondAttribute="bottom" constant="18" id="8Kg-1r-wNp"/>
|
<constraint firstAttribute="bottom" secondItem="KEh-NL-c2W" secondAttribute="bottom" constant="18" id="8Kg-1r-wNp"/>
|
||||||
<constraint firstItem="Kfb-8f-ean" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="JMi-4i-dgs"/>
|
<constraint firstItem="Kfb-8f-ean" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="JMi-4i-dgs"/>
|
||||||
<constraint firstAttribute="trailing" secondItem="Kfb-8f-ean" secondAttribute="trailing" id="KQC-Wz-Bsg"/>
|
<constraint firstAttribute="trailing" secondItem="Kfb-8f-ean" secondAttribute="trailing" id="KQC-Wz-Bsg"/>
|
||||||
|
<constraint firstItem="n8W-do-HyG" firstAttribute="centerX" secondItem="KEh-NL-c2W" secondAttribute="centerX" id="Kf1-ws-d4q"/>
|
||||||
<constraint firstItem="5Uu-j1-qyT" firstAttribute="leading" secondItem="KEh-NL-c2W" secondAttribute="leading" id="MUo-0i-fX9"/>
|
<constraint firstItem="5Uu-j1-qyT" firstAttribute="leading" secondItem="KEh-NL-c2W" secondAttribute="leading" id="MUo-0i-fX9"/>
|
||||||
<constraint firstItem="Kfb-8f-ean" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="Qbk-jx-zAi"/>
|
<constraint firstItem="Kfb-8f-ean" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="Qbk-jx-zAi"/>
|
||||||
<constraint firstItem="KEh-NL-c2W" firstAttribute="trailing" secondItem="Kfb-8f-ean" secondAttribute="trailing" id="U0w-G4-ggX"/>
|
<constraint firstItem="KEh-NL-c2W" firstAttribute="trailing" secondItem="Kfb-8f-ean" secondAttribute="trailing" id="U0w-G4-ggX"/>
|
||||||
<constraint firstItem="KEh-NL-c2W" firstAttribute="leading" secondItem="Kfb-8f-ean" secondAttribute="leading" id="V8r-Rc-Dx7"/>
|
<constraint firstItem="KEh-NL-c2W" firstAttribute="leading" secondItem="Kfb-8f-ean" secondAttribute="leading" id="V8r-Rc-Dx7"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="5Uu-j1-qyT" secondAttribute="bottom" id="gci-4h-pDZ"/>
|
<constraint firstAttribute="bottom" secondItem="5Uu-j1-qyT" secondAttribute="bottom" id="gci-4h-pDZ"/>
|
||||||
|
<constraint firstItem="n8W-do-HyG" firstAttribute="centerY" secondItem="Kfb-8f-ean" secondAttribute="centerY" id="pgP-oA-Nxa"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="Kfb-8f-ean" secondAttribute="bottom" constant="39" id="sid-zJ-YMA"/>
|
<constraint firstAttribute="bottom" secondItem="Kfb-8f-ean" secondAttribute="bottom" constant="39" id="sid-zJ-YMA"/>
|
||||||
</constraints>
|
</constraints>
|
||||||
|
<connections>
|
||||||
|
<outlet property="imageView" destination="Kfb-8f-ean" id="T7Z-En-dU3"/>
|
||||||
|
<outlet property="playButton" destination="n8W-do-HyG" id="Xw0-iI-svx"/>
|
||||||
|
</connections>
|
||||||
<point key="canvasLocation" x="-22" y="125.5"/>
|
<point key="canvasLocation" x="-22" y="125.5"/>
|
||||||
</customView>
|
</customView>
|
||||||
<collectionViewItem id="Qgu-aI-55A" customClass="AlbumItem" customModule="Persephone" customModuleProvider="target"/>
|
<collectionViewItem id="Qgu-aI-55A" customClass="AlbumItem" customModule="Persephone" customModuleProvider="target"/>
|
||||||
</objects>
|
</objects>
|
||||||
<resources>
|
<resources>
|
||||||
<image name="blankAlbum" width="128" height="128"/>
|
<image name="blankAlbum" width="128" height="128"/>
|
||||||
|
<image name="playButtonLarge" width="22" height="22"/>
|
||||||
</resources>
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
|
|||||||
@ -932,7 +932,7 @@
|
|||||||
</tableCellView>
|
</tableCellView>
|
||||||
</prototypeCellViews>
|
</prototypeCellViews>
|
||||||
</tableColumn>
|
</tableColumn>
|
||||||
<tableColumn identifier="songArtistColumn" width="144" minWidth="128" maxWidth="1000" id="SPM-QP-DX8">
|
<tableColumn identifier="songArtistColumn" width="144" minWidth="64" maxWidth="1000" id="SPM-QP-DX8">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Artist">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Artist">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
@ -949,9 +949,8 @@
|
|||||||
<rect key="frame" x="204" y="1" width="144" height="17"/>
|
<rect key="frame" x="204" y="1" width="144" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="tBe-Q9-3Rw">
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tBe-Q9-3Rw">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="222" height="17"/>
|
<rect key="frame" x="0.0" y="0.0" width="149" height="17"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Ceb-ec-ydU">
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Ceb-ec-ydU">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
@ -959,6 +958,11 @@
|
|||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="centerY" secondItem="JSk-Vc-Y7e" secondAttribute="centerY" id="Tkg-cb-Bg6"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="tBe-Q9-3Rw" secondAttribute="trailing" constant="-3" id="VhZ-ua-QQX"/>
|
||||||
|
<constraint firstItem="tBe-Q9-3Rw" firstAttribute="leading" secondItem="JSk-Vc-Y7e" secondAttribute="leading" constant="2" id="cTy-tR-Grg"/>
|
||||||
|
</constraints>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="textField" destination="tBe-Q9-3Rw" id="2e6-zi-tKj"/>
|
<outlet property="textField" destination="tBe-Q9-3Rw" id="2e6-zi-tKj"/>
|
||||||
</connections>
|
</connections>
|
||||||
@ -968,7 +972,6 @@
|
|||||||
</tableColumns>
|
</tableColumns>
|
||||||
<connections>
|
<connections>
|
||||||
<action trigger="doubleAction" selector="playTrack:" target="KIP-rq-4dM" id="opa-6G-OW0"/>
|
<action trigger="doubleAction" selector="playTrack:" target="KIP-rq-4dM" id="opa-6G-OW0"/>
|
||||||
<outlet property="dataSource" destination="KIP-rq-4dM" id="K1Q-7o-xXW"/>
|
|
||||||
<outlet property="delegate" destination="KIP-rq-4dM" id="60F-6x-bUE"/>
|
<outlet property="delegate" destination="KIP-rq-4dM" id="60F-6x-bUE"/>
|
||||||
</connections>
|
</connections>
|
||||||
</outlineView>
|
</outlineView>
|
||||||
@ -1024,7 +1027,6 @@
|
|||||||
<collectionViewLayout key="collectionViewLayout" id="YE8-sD-l5P" customClass="AlbumViewLayout" customModule="Persephone" customModuleProvider="target"/>
|
<collectionViewLayout key="collectionViewLayout" id="YE8-sD-l5P" customClass="AlbumViewLayout" customModule="Persephone" customModuleProvider="target"/>
|
||||||
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="gPn-fP-LFc" id="2VB-5V-ltv"/>
|
|
||||||
<outlet property="delegate" destination="gPn-fP-LFc" id="LQ2-Vl-r08"/>
|
<outlet property="delegate" destination="gPn-fP-LFc" id="LQ2-Vl-r08"/>
|
||||||
</connections>
|
</connections>
|
||||||
</collectionView>
|
</collectionView>
|
||||||
@ -1049,6 +1051,7 @@
|
|||||||
</view>
|
</view>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="albumCollectionView" destination="lfq-AB-epE" id="p69-Fs-hCN"/>
|
<outlet property="albumCollectionView" destination="lfq-AB-epE" id="p69-Fs-hCN"/>
|
||||||
|
<outlet property="albumScrollView" destination="i5f-35-7x8" id="jmd-Sa-Bxt"/>
|
||||||
</connections>
|
</connections>
|
||||||
</viewController>
|
</viewController>
|
||||||
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
|
|||||||
71
Persephone/Views/AlbumItemView.swift
Normal file
71
Persephone/Views/AlbumItemView.swift
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
//
|
||||||
|
// AlbumItemView.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2019/2/17.
|
||||||
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
class AlbumItemView: NSView {
|
||||||
|
var trackingArea: NSTrackingArea?
|
||||||
|
|
||||||
|
override func updateTrackingAreas() {
|
||||||
|
super.updateTrackingAreas()
|
||||||
|
|
||||||
|
guard let albumImageView = imageView else { return }
|
||||||
|
|
||||||
|
if let trackingArea = self.trackingArea {
|
||||||
|
self.removeTrackingArea(trackingArea)
|
||||||
|
}
|
||||||
|
|
||||||
|
let trackingArea = NSTrackingArea(
|
||||||
|
rect: albumImageView.frame,
|
||||||
|
options: [.mouseEnteredAndExited, .activeAlways],
|
||||||
|
owner: self,
|
||||||
|
userInfo: nil
|
||||||
|
)
|
||||||
|
|
||||||
|
self.trackingArea = trackingArea
|
||||||
|
addTrackingArea(trackingArea)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder decoder: NSCoder) {
|
||||||
|
super.init(coder: decoder)
|
||||||
|
|
||||||
|
NotificationCenter.default.addObserver(
|
||||||
|
self,
|
||||||
|
selector: #selector(viewWillScroll(_:)),
|
||||||
|
name: NSScrollView.willStartLiveScrollNotification,
|
||||||
|
object: nil
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func viewWillScroll(_ notification: Notification) {
|
||||||
|
hidePlayButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func resize(withOldSuperviewSize oldSize: NSSize) {
|
||||||
|
hidePlayButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func mouseEntered(with event: NSEvent) {
|
||||||
|
showPlayButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
override func mouseExited(with event: NSEvent) {
|
||||||
|
hidePlayButton()
|
||||||
|
}
|
||||||
|
|
||||||
|
func showPlayButton() {
|
||||||
|
playButton.isHidden = false
|
||||||
|
}
|
||||||
|
|
||||||
|
func hidePlayButton() {
|
||||||
|
playButton.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBOutlet var imageView: NSImageView!
|
||||||
|
@IBOutlet var playButton: NSButton!
|
||||||
|
}
|
||||||
BIN
Resources/export/playButtonLarge.pdf
Normal file
BIN
Resources/export/playButtonLarge.pdf
Normal file
Binary file not shown.
BIN
Resources/export/playButtonLarge.png
Normal file
BIN
Resources/export/playButtonLarge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 295 B |
BIN
Resources/export/playButtonLarge@2x.png
Normal file
BIN
Resources/export/playButtonLarge@2x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 516 B |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 179 KiB |
Loading…
Reference in New Issue
Block a user