mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Compare commits
No commits in common. "dc600492433db345606e1c9ab724a3d03505a5cd" and "e05698e7666b1b5368b1837328cb6cf7b49dedb9" have entirely different histories.
dc60049243
...
e05698e766
@ -18,7 +18,6 @@
|
||||
E408D3C2220E134F0006D9BE /* AlbumViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E408D3C1220E134F0006D9BE /* AlbumViewController.swift */; };
|
||||
E408D3CB220E341D0006D9BE /* AlbumViewItem.xib in Resources */ = {isa = PBXBuildFile; fileRef = E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */; };
|
||||
E40FE71B221B904300A4223F /* NSEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40FE71A221B904300A4223F /* NSEvent.swift */; };
|
||||
E4120D6C22AD8139004CB1F8 /* QueueView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4120D6B22AD8139004CB1F8 /* QueueView.swift */; };
|
||||
E419E2872249B96600216A8C /* Song.swift in Sources */ = {isa = PBXBuildFile; fileRef = E419E2862249B96600216A8C /* Song.swift */; };
|
||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41B22C521FB932700D544F6 /* MPDClient.swift */; };
|
||||
E41E52FD223BF87300173814 /* MPDClient+Connection.swift in Sources */ = {isa = PBXBuildFile; fileRef = E41E52FC223BF87300173814 /* MPDClient+Connection.swift */; };
|
||||
@ -40,7 +39,6 @@
|
||||
E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E1221CD4E200184CFC /* NSFont.swift */; };
|
||||
E435E3E4221CD75D00184CFC /* NSImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = E435E3E3221CD75D00184CFC /* NSImage.swift */; };
|
||||
E439109822640213002982E9 /* SongNotifierService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E439109722640213002982E9 /* SongNotifierService.swift */; };
|
||||
E43AC1F122C68E6A001E483C /* NSPasteboardItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43AC1F022C68E6A001E483C /* NSPasteboardItem.swift */; };
|
||||
E43B67AA22909793007DCF55 /* AlbumDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43B67A822909793007DCF55 /* AlbumDetailView.swift */; };
|
||||
E43B67AB22909793007DCF55 /* AlbumDetailView.xib in Resources */ = {isa = PBXBuildFile; fileRef = E43B67A922909793007DCF55 /* AlbumDetailView.xib */; };
|
||||
E43B67AD229194CD007DCF55 /* AlbumTracksDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E43B67AC229194CD007DCF55 /* AlbumTracksDataSource.swift */; };
|
||||
@ -58,8 +56,6 @@
|
||||
E450AD9522262DF10091BED3 /* CoverArtQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = E450AD9422262DF10091BED3 /* CoverArtQueue.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 */; };
|
||||
E451E36B22BD214D008BE9B2 /* DraggedSongType.swift in Sources */ = {isa = PBXBuildFile; fileRef = E451E36A22BD214D008BE9B2 /* DraggedSongType.swift */; };
|
||||
E451E36E22BD2501008BE9B2 /* DraggedSong.swift in Sources */ = {isa = PBXBuildFile; fileRef = E451E36C22BD23DB008BE9B2 /* DraggedSong.swift */; };
|
||||
E45878382296173C00586A1C /* AlbumDetailSongRowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */; };
|
||||
E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = E45962C52241A78500FC1A1E /* MPDCommand.swift */; };
|
||||
E45E4FDA22515D87004B537F /* CHANGELOG.md in Resources */ = {isa = PBXBuildFile; fileRef = E45E4FD722515D87004B537F /* CHANGELOG.md */; };
|
||||
@ -74,10 +70,6 @@
|
||||
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FD62220720300F747E6 /* AlbumItemView.swift */; };
|
||||
E47E2FDD2220A6D100F747E6 /* Time.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FDC2220A6D100F747E6 /* Time.swift */; };
|
||||
E47E2FE52220AA0700F747E6 /* AlbumViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = E47E2FE42220AA0700F747E6 /* AlbumViewLayout.swift */; };
|
||||
E489E39922B85D0400CA8CBD /* NSPasteboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = E489E39822B85D0400CA8CBD /* NSPasteboard.swift */; };
|
||||
E489E39D22B9CF0000CA8CBD /* NSView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E489E39C22B9CF0000CA8CBD /* NSView.swift */; };
|
||||
E489E3A422B9D31800CA8CBD /* DraggedSongView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E489E3A222B9D31800CA8CBD /* DraggedSongView.swift */; };
|
||||
E489E3A522B9D31800CA8CBD /* DraggedSongView.xib in Resources */ = {isa = PBXBuildFile; fileRef = E489E3A322B9D31800CA8CBD /* DraggedSongView.xib */; };
|
||||
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4928E0A2218D62A001D4BEA /* CGColor.swift */; };
|
||||
E4A3A6A122A457B600EA2C40 /* AlbumDetailSongListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A3A6A022A457B600EA2C40 /* AlbumDetailSongListView.swift */; };
|
||||
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4A642D922090CBE00067D21 /* MPDStatus.swift */; };
|
||||
@ -119,8 +111,6 @@
|
||||
E4B11BC22275EE410075461B /* AlbumListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BC12275EE410075461B /* AlbumListActions.swift */; };
|
||||
E4C8B53C22342005009A20F3 /* PreferencesWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */; };
|
||||
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4C8B53D22349002009A20F3 /* MPDIdle.swift */; };
|
||||
E4D3BFA622B419C000C56F48 /* QueueViewController+NSOutlineViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D3BFA522B419C000C56F48 /* QueueViewController+NSOutlineViewDelegate.swift */; };
|
||||
E4E7A6AD22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E7A6AC22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift */; };
|
||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC8F2204EC7F0024217A /* Delegate.swift */; };
|
||||
E4E8CC922204F4B80024217A /* QueueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC912204F4B80024217A /* QueueViewController.swift */; };
|
||||
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4E8CC9922075D370024217A /* MPDSong.swift */; };
|
||||
@ -201,7 +191,6 @@
|
||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumViewController.swift; sourceTree = "<group>"; };
|
||||
E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumViewItem.xib; sourceTree = "<group>"; };
|
||||
E40FE71A221B904300A4223F /* NSEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEvent.swift; sourceTree = "<group>"; };
|
||||
E4120D6B22AD8139004CB1F8 /* QueueView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueView.swift; sourceTree = "<group>"; };
|
||||
E419E2862249B96600216A8C /* Song.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Song.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>"; };
|
||||
E41B22C421FB715A00D544F6 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
|
||||
@ -261,7 +250,6 @@
|
||||
E435E3E1221CD4E200184CFC /* NSFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSFont.swift; sourceTree = "<group>"; };
|
||||
E435E3E3221CD75D00184CFC /* NSImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSImage.swift; sourceTree = "<group>"; };
|
||||
E439109722640213002982E9 /* SongNotifierService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SongNotifierService.swift; sourceTree = "<group>"; };
|
||||
E43AC1F022C68E6A001E483C /* NSPasteboardItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSPasteboardItem.swift; sourceTree = "<group>"; };
|
||||
E43B67A822909793007DCF55 /* AlbumDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDetailView.swift; sourceTree = "<group>"; };
|
||||
E43B67A922909793007DCF55 /* AlbumDetailView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AlbumDetailView.xib; sourceTree = "<group>"; };
|
||||
E43B67AC229194CD007DCF55 /* AlbumTracksDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumTracksDataSource.swift; sourceTree = "<group>"; };
|
||||
@ -284,8 +272,6 @@
|
||||
E450AD9E2229B9BC0091BED3 /* PersephoneBridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PersephoneBridgingHeader.h; sourceTree = "<group>"; };
|
||||
E450AD9F2229E7C90091BED3 /* PMKFoundation.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PMKFoundation.framework.dSYM; path = Carthage/Build/Mac/PMKFoundation.framework.dSYM; sourceTree = "<group>"; };
|
||||
E450ADA02229E7C90091BED3 /* PMKFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PMKFoundation.framework; path = Carthage/Build/Mac/PMKFoundation.framework; sourceTree = "<group>"; };
|
||||
E451E36A22BD214D008BE9B2 /* DraggedSongType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggedSongType.swift; sourceTree = "<group>"; };
|
||||
E451E36C22BD23DB008BE9B2 /* DraggedSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggedSong.swift; sourceTree = "<group>"; };
|
||||
E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDetailSongRowView.swift; sourceTree = "<group>"; };
|
||||
E45962C52241A78500FC1A1E /* MPDCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDCommand.swift; sourceTree = "<group>"; };
|
||||
E45E4FD722515D87004B537F /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = SOURCE_ROOT; };
|
||||
@ -301,10 +287,6 @@
|
||||
E47E2FD62220720300F747E6 /* AlbumItemView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumItemView.swift; sourceTree = "<group>"; };
|
||||
E47E2FDC2220A6D100F747E6 /* Time.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Time.swift; sourceTree = "<group>"; };
|
||||
E47E2FE42220AA0700F747E6 /* AlbumViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumViewLayout.swift; sourceTree = "<group>"; };
|
||||
E489E39822B85D0400CA8CBD /* NSPasteboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSPasteboard.swift; sourceTree = "<group>"; };
|
||||
E489E39C22B9CF0000CA8CBD /* NSView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSView.swift; sourceTree = "<group>"; };
|
||||
E489E3A222B9D31800CA8CBD /* DraggedSongView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggedSongView.swift; sourceTree = "<group>"; };
|
||||
E489E3A322B9D31800CA8CBD /* DraggedSongView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraggedSongView.xib; sourceTree = "<group>"; };
|
||||
E4928E0A2218D62A001D4BEA /* CGColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGColor.swift; sourceTree = "<group>"; };
|
||||
E4A3A6A022A457B600EA2C40 /* AlbumDetailSongListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDetailSongListView.swift; sourceTree = "<group>"; };
|
||||
E4A642D922090CBE00067D21 /* MPDStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDStatus.swift; sourceTree = "<group>"; };
|
||||
@ -332,8 +314,6 @@
|
||||
E4B11BC12275EE410075461B /* AlbumListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListActions.swift; sourceTree = "<group>"; };
|
||||
E4C8B53B22342005009A20F3 /* PreferencesWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindowController.swift; sourceTree = "<group>"; };
|
||||
E4C8B53D22349002009A20F3 /* MPDIdle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDIdle.swift; sourceTree = "<group>"; };
|
||||
E4D3BFA522B419C000C56F48 /* QueueViewController+NSOutlineViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "QueueViewController+NSOutlineViewDelegate.swift"; sourceTree = "<group>"; };
|
||||
E4E7A6AC22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AlbumDetailView+NSTableViewDelegate.swift"; sourceTree = "<group>"; };
|
||||
E4E8CC8F2204EC7F0024217A /* Delegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Delegate.swift; sourceTree = "<group>"; };
|
||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueViewController.swift; sourceTree = "<group>"; };
|
||||
E4E8CC9922075D370024217A /* MPDSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDSong.swift; sourceTree = "<group>"; };
|
||||
@ -460,9 +440,6 @@
|
||||
E435E3E1221CD4E200184CFC /* NSFont.swift */,
|
||||
E435E3E3221CD75D00184CFC /* NSImage.swift */,
|
||||
E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */,
|
||||
E489E39822B85D0400CA8CBD /* NSPasteboard.swift */,
|
||||
E489E39C22B9CF0000CA8CBD /* NSView.swift */,
|
||||
E43AC1F022C68E6A001E483C /* NSPasteboardItem.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -487,14 +464,12 @@
|
||||
E408D3C3220E138B0006D9BE /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E4A3A6A022A457B600EA2C40 /* AlbumDetailSongListView.swift */,
|
||||
E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */,
|
||||
E47E2FD62220720300F747E6 /* AlbumItemView.swift */,
|
||||
E4B11BB7227538FA0075461B /* CurrentCoverArtView.swift */,
|
||||
E489E3A222B9D31800CA8CBD /* DraggedSongView.swift */,
|
||||
E47E2FD222205D2500F747E6 /* MainWindow.swift */,
|
||||
E4B11BB7227538FA0075461B /* CurrentCoverArtView.swift */,
|
||||
E423563F228623D2001216D6 /* QueueSongTitleView.swift */,
|
||||
E4120D6B22AD8139004CB1F8 /* QueueView.swift */,
|
||||
E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */,
|
||||
E4A3A6A022A457B600EA2C40 /* AlbumDetailSongListView.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -708,13 +683,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E43B67A822909793007DCF55 /* AlbumDetailView.swift */,
|
||||
E4E7A6AC22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift */,
|
||||
E408D3C1220E134F0006D9BE /* AlbumViewController.swift */,
|
||||
E47E2FD4222071FD00F747E6 /* AlbumViewItem.swift */,
|
||||
E47E2FD022205C4600F747E6 /* MainSplitViewController.swift */,
|
||||
E4405191227644340090CD6F /* MPDServerController.swift */,
|
||||
E4E8CC912204F4B80024217A /* QueueViewController.swift */,
|
||||
E4D3BFA522B419C000C56F48 /* QueueViewController+NSOutlineViewDelegate.swift */,
|
||||
E4B11BB52275374B0075461B /* UserNotificationsController.swift */,
|
||||
E465049921E94DF500A70F4C /* WindowController.swift */,
|
||||
);
|
||||
@ -724,10 +697,9 @@
|
||||
E4D1B598220BA3C90026F233 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E40786212110CE70006887B1 /* Main.storyboard */,
|
||||
E43B67A922909793007DCF55 /* AlbumDetailView.xib */,
|
||||
E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */,
|
||||
E489E3A322B9D31800CA8CBD /* DraggedSongView.xib */,
|
||||
E40786212110CE70006887B1 /* Main.storyboard */,
|
||||
);
|
||||
path = Resources;
|
||||
sourceTree = "<group>";
|
||||
@ -752,8 +724,6 @@
|
||||
E419E2862249B96600216A8C /* Song.swift */,
|
||||
E47E2FDC2220A6D100F747E6 /* Time.swift */,
|
||||
E4B11B72226A6C770075461B /* TrackTimer.swift */,
|
||||
E451E36A22BD214D008BE9B2 /* DraggedSongType.swift */,
|
||||
E451E36C22BD23DB008BE9B2 /* DraggedSong.swift */,
|
||||
);
|
||||
path = Models;
|
||||
sourceTree = "<group>";
|
||||
@ -883,7 +853,6 @@
|
||||
E43B67AB22909793007DCF55 /* AlbumDetailView.xib in Resources */,
|
||||
E45E4FDC22515D87004B537F /* Cartfile in Resources */,
|
||||
E450AD98222633920091BED3 /* Alamofire.framework.dSYM in Resources */,
|
||||
E489E3A522B9D31800CA8CBD /* DraggedSongView.xib in Resources */,
|
||||
E40786202110CE70006887B1 /* Assets.xcassets in Resources */,
|
||||
E45E4FDF225168DA004B537F /* CryptoSwift.framework.dSYM in Resources */,
|
||||
E42A8F3C22176D6400A13ED9 /* README.md in Resources */,
|
||||
@ -946,7 +915,6 @@
|
||||
E4B11BB62275374B0075461B /* UserNotificationsController.swift in Sources */,
|
||||
E4B11B68226A4FA00075461B /* QueueState.swift in Sources */,
|
||||
E4928E0B2218D62A001D4BEA /* CGColor.swift in Sources */,
|
||||
E4D3BFA622B419C000C56F48 /* QueueViewController+NSOutlineViewDelegate.swift in Sources */,
|
||||
E4405196227879960090CD6F /* MPDActions.swift in Sources */,
|
||||
E4405192227644340090CD6F /* MPDServerController.swift in Sources */,
|
||||
E4C8B53E22349002009A20F3 /* MPDIdle.swift in Sources */,
|
||||
@ -959,7 +927,6 @@
|
||||
E440519822787CB40090CD6F /* MPDState.swift in Sources */,
|
||||
E42410B62241B956005ED6DF /* MPDClient+Database.swift in Sources */,
|
||||
E4235640228623D2001216D6 /* QueueSongTitleView.swift in Sources */,
|
||||
E451E36E22BD2501008BE9B2 /* DraggedSong.swift in Sources */,
|
||||
E4A642DA22090CBE00067D21 /* MPDStatus.swift in Sources */,
|
||||
E4B11BC02275EE150075461B /* QueueActions.swift in Sources */,
|
||||
E47E2FD72220720300F747E6 /* AlbumItemView.swift in Sources */,
|
||||
@ -971,23 +938,18 @@
|
||||
E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */,
|
||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
||||
E4EB2379220F10B8008C70C0 /* MPDPair.swift in Sources */,
|
||||
E489E3A422B9D31800CA8CBD /* DraggedSongView.swift in Sources */,
|
||||
E440519E227BB0720090CD6F /* UIReducer.swift in Sources */,
|
||||
E43B67AA22909793007DCF55 /* AlbumDetailView.swift in Sources */,
|
||||
E4E7A6AD22AAAF98006D566C /* AlbumDetailView+NSTableViewDelegate.swift in Sources */,
|
||||
E4FF7190227601B400D4C412 /* PreferencesReducer.swift in Sources */,
|
||||
E4F6B463221E125900ACF42A /* QueueItem.swift in Sources */,
|
||||
E4A83BF12221FAA00098FED6 /* PreferencesViewController.swift in Sources */,
|
||||
E4B11BC22275EE410075461B /* AlbumListActions.swift in Sources */,
|
||||
E4B11B61226A4C000075461B /* PlayerReducer.swift in Sources */,
|
||||
E4FF71922276029000D4C412 /* PreferencesActions.swift in Sources */,
|
||||
E489E39922B85D0400CA8CBD /* NSPasteboard.swift in Sources */,
|
||||
E43AC1F122C68E6A001E483C /* NSPasteboardItem.swift in Sources */,
|
||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||
E47E2FDD2220A6D100F747E6 /* Time.swift in Sources */,
|
||||
E419E2872249B96600216A8C /* Song.swift in Sources */,
|
||||
E451E36B22BD214D008BE9B2 /* DraggedSongType.swift in Sources */,
|
||||
E44051A0227BB0AB0090CD6F /* UIState.swift in Sources */,
|
||||
E4FF718E2276010E00D4C412 /* PreferencesState.swift in Sources */,
|
||||
E439109822640213002982E9 /* SongNotifierService.swift in Sources */,
|
||||
@ -1003,7 +965,6 @@
|
||||
E47E2FD122205C4600F747E6 /* MainSplitViewController.swift in Sources */,
|
||||
E4B11BB8227538FA0075461B /* CurrentCoverArtView.swift in Sources */,
|
||||
E4E8CC9A22075D370024217A /* MPDSong.swift in Sources */,
|
||||
E4120D6C22AD8139004CB1F8 /* QueueView.swift in Sources */,
|
||||
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */,
|
||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
||||
E4A83BF4222207D50098FED6 /* CoverArtService.swift in Sources */,
|
||||
@ -1027,7 +988,6 @@
|
||||
E4B11B6A226A4FBC0075461B /* AlbumListState.swift in Sources */,
|
||||
E41E5305223BFB0700173814 /* MPDClient+Error.swift in Sources */,
|
||||
E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */,
|
||||
E489E39D22B9CF0000CA8CBD /* NSView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@ -16,12 +16,6 @@ class AppDelegate: NSObject,
|
||||
MediaKeyTapDelegate {
|
||||
var mediaKeyTap: MediaKeyTap?
|
||||
|
||||
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
|
||||
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
|
||||
@IBOutlet weak var playSelectedSongMenuItem: NSMenuItem!
|
||||
@IBOutlet weak var playSelectedSongNextMenuItem: NSMenuItem!
|
||||
@IBOutlet weak var addSelectedSongToQueueMenuItem: NSMenuItem!
|
||||
|
||||
func applicationDidFinishLaunching(_ aNotification: Notification) {
|
||||
App.mpdServerController.connect()
|
||||
instantiateUserNotificationsController()
|
||||
@ -103,12 +97,6 @@ class AppDelegate: NSObject,
|
||||
}
|
||||
}
|
||||
|
||||
func setSongMenuItemsState(selectedSong: Song?) {
|
||||
playSelectedSongMenuItem.isEnabled = selectedSong != nil
|
||||
playSelectedSongNextMenuItem.isEnabled = selectedSong != nil
|
||||
addSelectedSongToQueueMenuItem.isEnabled = selectedSong != nil
|
||||
}
|
||||
|
||||
func handle(mediaKey: MediaKey, event: KeyEvent) {
|
||||
switch mediaKey {
|
||||
case .playPause:
|
||||
@ -137,53 +125,8 @@ class AppDelegate: NSObject,
|
||||
App.store.dispatch(MPDPrevTrackAction())
|
||||
}
|
||||
|
||||
@IBAction func removeQueueSongMenuAction(_ sender: NSMenuItem) {
|
||||
guard let queueItem = App.store.state.uiState.selectedQueueItem
|
||||
else { return }
|
||||
|
||||
App.store.dispatch(MPDRemoveTrack(queuePos: queueItem.queuePos))
|
||||
App.store.dispatch(SetSelectedQueueItem(selectedQueueItem: nil))
|
||||
}
|
||||
@IBAction func clearQueueMenuAction(_ sender: NSMenuItem) {
|
||||
let alert = NSAlert()
|
||||
alert.alertStyle = .warning
|
||||
alert.messageText = "Are you sure you want to clear the queue?"
|
||||
alert.informativeText = "You can’t undo this action."
|
||||
alert.addButton(withTitle: "Clear Queue")
|
||||
alert.addButton(withTitle: "Cancel")
|
||||
|
||||
let result = alert.runModal()
|
||||
|
||||
if result == .alertFirstButtonReturn {
|
||||
App.store.dispatch(MPDClearQueue())
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func playSelectedSongAction(_ sender: NSMenuItem) {
|
||||
guard let song = App.store.state.uiState.selectedSong
|
||||
else { return }
|
||||
|
||||
let queueLength = App.store.state.queueState.queue.count
|
||||
App.store.dispatch(MPDAppendTrack(song: song.mpdSong))
|
||||
App.store.dispatch(MPDPlayTrack(queuePos: queueLength))
|
||||
}
|
||||
@IBAction func playSelectedSongNextAction(_ sender: NSMenuItem) {
|
||||
let queuePos = App.store.state.queueState.queuePos
|
||||
|
||||
guard let song = App.store.state.uiState.selectedSong,
|
||||
queuePos > -1
|
||||
else { return }
|
||||
|
||||
App.store.dispatch(
|
||||
MPDAddSongToQueue(songUri: song.mpdSong.uriString, queuePos: queuePos + 1)
|
||||
)
|
||||
}
|
||||
@IBAction func addSelectedSongToQueueAction(_ sender: NSMenuItem) {
|
||||
guard let song = App.store.state.uiState.selectedSong
|
||||
else { return }
|
||||
|
||||
App.store.dispatch(MPDAppendTrack(song: song.mpdSong))
|
||||
}
|
||||
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
|
||||
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
|
||||
}
|
||||
|
||||
extension AppDelegate: StoreSubscriber {
|
||||
@ -192,6 +135,5 @@ extension AppDelegate: StoreSubscriber {
|
||||
func newState(state: UIState) {
|
||||
updateDatabaseMenuItem.isEnabled = !state.databaseUpdating
|
||||
setMainWindowStateMenuItem(state: state.mainWindowState)
|
||||
setSongMenuItemsState(selectedSong: state.selectedSong)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "songIcon.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "songIcon@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 309 B |
Binary file not shown.
|
Before Width: | Height: | Size: 547 B |
@ -1,102 +0,0 @@
|
||||
//
|
||||
// AlbumDetailView+NSTableViewDelegate.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/07.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
extension AlbumDetailView: NSTableViewDelegate {
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
if let song = dataSource.albumSongs[row].song {
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "trackNumberColumn":
|
||||
return cellForTrackNumber(tableView, with: song)
|
||||
case "trackTitleColumn":
|
||||
return cellForSongTitle(tableView, with: song)
|
||||
case "trackDurationColumn":
|
||||
return cellForSongDuration(tableView, with: song)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} else if let disc = dataSource.albumSongs[row].disc {
|
||||
return cellForDiscNumber(tableView, with: disc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
|
||||
return dataSource.albumSongs[row].disc != nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
|
||||
let view = AlbumDetailSongRowView()
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
|
||||
return dataSource.albumSongs[row].disc == nil
|
||||
}
|
||||
|
||||
func tableViewSelectionDidChange(_ notification: Notification) {
|
||||
guard let tableView = notification.object as? NSTableView
|
||||
else { return }
|
||||
|
||||
if tableView.selectedRow >= 0 {
|
||||
let song = dataSource.albumSongs[tableView.selectedRow].song
|
||||
|
||||
App.store.dispatch(SetSelectedSong(selectedSong: song))
|
||||
} else {
|
||||
App.store.dispatch(SetSelectedSong(selectedSong: nil))
|
||||
}
|
||||
}
|
||||
|
||||
func cellForDiscNumber(_ tableView: NSTableView, with disc: String) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .discNumber,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = "Disc \(disc)"
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForTrackNumber(_ tableView: NSTableView, with song: Song) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .trackNumber,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = "\(song.trackNumber)."
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongTitle(_ tableView: NSTableView, with song: Song) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .songTitle,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = song.title
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongDuration(_ tableView: NSTableView, with song: Song) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .songDuration,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.font = .timerFont
|
||||
cellView.textField?.stringValue = song.duration.formattedTime
|
||||
|
||||
return cellView
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Cocoa
|
||||
|
||||
class AlbumDetailView: NSViewController {
|
||||
var album: Album?
|
||||
@ -60,8 +60,6 @@ class AlbumDetailView: NSViewController {
|
||||
albumTitle.stringValue = ""
|
||||
albumArtist.stringValue = ""
|
||||
albumCoverView.image = .defaultCoverArt
|
||||
|
||||
App.store.dispatch(SetSelectedSong(selectedSong: nil))
|
||||
}
|
||||
|
||||
@IBAction func playAlbum(_ sender: NSButton) {
|
||||
@ -88,17 +86,6 @@ class AlbumDetailView: NSViewController {
|
||||
App.store.dispatch(MPDPlayTrack(queuePos: queueLength))
|
||||
}
|
||||
|
||||
@IBAction func menuActionPlayNext(_ sender: Any) {
|
||||
guard let song = dataSource.albumSongs[albumTracksView.clickedRow].song
|
||||
else { return }
|
||||
|
||||
let queuePos = App.store.state.queueState.queuePos
|
||||
|
||||
if queuePos > -1 {
|
||||
App.store.dispatch(MPDAddSongToQueue(songUri: song.mpdSong.uriString, queuePos: queuePos + 1))
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func menuActionAppendSong(_ sender: NSMenuItem) {
|
||||
guard let song = dataSource.albumSongs[albumTracksView.clickedRow].song
|
||||
else { return }
|
||||
@ -153,3 +140,83 @@ class AlbumDetailView: NSViewController {
|
||||
self.album = album
|
||||
}
|
||||
}
|
||||
|
||||
extension AlbumDetailView: NSTableViewDelegate {
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
if let song = dataSource.albumSongs[row].song {
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "trackNumberColumn":
|
||||
return cellForTrackNumber(tableView, with: song)
|
||||
case "trackTitleColumn":
|
||||
return cellForSongTitle(tableView, with: song)
|
||||
case "trackDurationColumn":
|
||||
return cellForSongDuration(tableView, with: song)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} else if let disc = dataSource.albumSongs[row].disc {
|
||||
return cellForDiscNumber(tableView, with: disc)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, isGroupRow row: Int) -> Bool {
|
||||
return dataSource.albumSongs[row].disc != nil
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
|
||||
let view = AlbumDetailSongRowView()
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, shouldSelectRow row: Int) -> Bool {
|
||||
return dataSource.albumSongs[row].disc == nil
|
||||
}
|
||||
|
||||
func cellForDiscNumber(_ tableView: NSTableView, with disc: String) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .discNumber,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = "Disc \(disc)"
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForTrackNumber(_ tableView: NSTableView, with song: Song) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .trackNumber,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = "\(song.trackNumber)."
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongTitle(_ tableView: NSTableView, with song: Song) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .songTitle,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = song.title
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongDuration(_ tableView: NSTableView, with song: Song) -> NSView {
|
||||
let cellView = tableView.makeView(
|
||||
withIdentifier: .songDuration,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.font = .timerFont
|
||||
cellView.textField?.stringValue = song.duration.formattedTime
|
||||
|
||||
return cellView
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,87 +0,0 @@
|
||||
//
|
||||
// QueueViewController+NSOutlineViewDelegate.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/14.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
extension QueueViewController: NSOutlineViewDelegate {
|
||||
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 queueItem = item as? QueueItem {
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "songTitleColumn":
|
||||
return cellForSongTitle(outlineView, with: queueItem)
|
||||
case "songArtistColumn":
|
||||
return cellForSongArtist(outlineView, with: queueItem)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} else if tableColumn?.identifier.rawValue == "songTitleColumn" {
|
||||
return cellForQueueHeading(outlineView)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func outlineViewSelectionDidChange(_ notification: Notification) {
|
||||
if queueView.selectedRow >= 1 {
|
||||
let queueItem = dataSource.queue[queueView.selectedRow - 1]
|
||||
|
||||
App.store.dispatch(SetSelectedQueueItem(selectedQueueItem: queueItem))
|
||||
} else {
|
||||
App.store.dispatch(SetSelectedQueueItem(selectedQueueItem: nil))
|
||||
}
|
||||
}
|
||||
|
||||
func cellForSongTitle(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongTitle,
|
||||
owner: self
|
||||
) as! QueueSongTitleView
|
||||
|
||||
cellView.setQueueSong(queueItem, queueIcon: dataSource.queueIcon)
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongArtist(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongArtist,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = queueItem.song.artist
|
||||
if queueItem.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
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,8 @@
|
||||
import AppKit
|
||||
import ReSwift
|
||||
|
||||
class QueueViewController: NSViewController {
|
||||
class QueueViewController: NSViewController,
|
||||
NSOutlineViewDelegate {
|
||||
var dataSource = QueueDataSource()
|
||||
|
||||
@IBOutlet var queueView: NSOutlineView!
|
||||
@ -24,47 +25,90 @@ class QueueViewController: NSViewController {
|
||||
|
||||
queueView.dataSource = dataSource
|
||||
queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle
|
||||
queueView.registerForDraggedTypes([.songPasteboardType])
|
||||
queueView.draggingDestinationFeedbackStyle = .regular
|
||||
}
|
||||
|
||||
override func keyDown(with event: NSEvent) {
|
||||
switch event.keyCode {
|
||||
case NSEvent.keyCodeSpace:
|
||||
nextResponder?.keyDown(with: event)
|
||||
case NSEvent.keyCodeBS:
|
||||
let queuePos = queueView.selectedRow - 1
|
||||
|
||||
if queuePos >= 0 {
|
||||
App.store.dispatch(MPDRemoveTrack(queuePos: queuePos))
|
||||
}
|
||||
default:
|
||||
super.keyDown(with: event)
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func playTrack(_ sender: Any) {
|
||||
let queuePos = queueView.selectedRow - 1
|
||||
let newQueuePos = queueView.selectedRow - 1
|
||||
|
||||
if queuePos >= 0 {
|
||||
App.store.dispatch(MPDPlayTrack(queuePos: queuePos))
|
||||
if newQueuePos >= 0 {
|
||||
App.store.dispatch(MPDPlayTrack(queuePos: newQueuePos))
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func playSongMenuAction(_ sender: NSMenuItem) {
|
||||
let queuePos = queueView.clickedRow - 1
|
||||
|
||||
if queuePos >= 0 {
|
||||
App.store.dispatch(MPDPlayTrack(queuePos: queuePos))
|
||||
func outlineView(
|
||||
_ outlineView: NSOutlineView,
|
||||
selectionIndexesForProposedSelection proposedSelectionIndexes: IndexSet
|
||||
) -> IndexSet {
|
||||
if proposedSelectionIndexes.contains(0) {
|
||||
return IndexSet()
|
||||
} else {
|
||||
return proposedSelectionIndexes
|
||||
}
|
||||
}
|
||||
@IBAction func removeSongMenuAction(_ sender: NSMenuItem) {
|
||||
let queuePos = queueView.clickedRow - 1
|
||||
|
||||
if queuePos >= 0 {
|
||||
App.store.dispatch(MPDRemoveTrack(queuePos: queuePos))
|
||||
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
|
||||
if let queueItem = item as? QueueItem {
|
||||
switch tableColumn?.identifier.rawValue {
|
||||
case "songTitleColumn":
|
||||
return cellForSongTitle(outlineView, with: queueItem)
|
||||
case "songArtistColumn":
|
||||
return cellForSongArtist(outlineView, with: queueItem)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
} else if tableColumn?.identifier.rawValue == "songTitleColumn" {
|
||||
return cellForQueueHeading(outlineView)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func cellForSongTitle(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongTitle,
|
||||
owner: self
|
||||
) as! QueueSongTitleView
|
||||
|
||||
cellView.setQueueSong(queueItem, queueIcon: dataSource.queueIcon)
|
||||
|
||||
return cellView
|
||||
}
|
||||
|
||||
func cellForSongArtist(_ outlineView: NSOutlineView, with queueItem: QueueItem) -> NSView {
|
||||
let cellView = outlineView.makeView(
|
||||
withIdentifier: .queueSongArtist,
|
||||
owner: self
|
||||
) as! NSTableCellView
|
||||
|
||||
cellView.textField?.stringValue = queueItem.song.artist
|
||||
if queueItem.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
|
||||
}
|
||||
}
|
||||
|
||||
extension QueueViewController: StoreSubscriber {
|
||||
|
||||
@ -39,46 +39,7 @@ class AlbumTracksDataSource: NSObject, NSTableViewDataSource {
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? {
|
||||
let albumSongItem = albumSongs[row]
|
||||
|
||||
guard let song = albumSongItem.song
|
||||
else { return nil }
|
||||
|
||||
return NSPasteboardItem(
|
||||
draggedSong: DraggedSong(
|
||||
type: .albumSongItem(song.mpdSong.uriString),
|
||||
title: song.title,
|
||||
artist: song.artist
|
||||
),
|
||||
ofType: .songPasteboardType
|
||||
)
|
||||
}
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return albumSongs.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forRowIndexes rowIndexes: IndexSet) {
|
||||
session.enumerateDraggingItems(
|
||||
options: [],
|
||||
for: tableView,
|
||||
classes: [NSPasteboardItem.self],
|
||||
searchOptions: [:]
|
||||
) { draggingItem, index, stop in
|
||||
guard let item = draggingItem.item as? NSPasteboardItem,
|
||||
let draggedSong = item.draggedSong(forType: .songPasteboardType),
|
||||
case let (title?, artist?) = (draggedSong.title, draggedSong.artist)
|
||||
else { return }
|
||||
|
||||
draggingItem.imageComponentsProvider = {
|
||||
let component = NSDraggingImageComponent(key: NSDraggingItem.ImageComponentKey.icon)
|
||||
let draggedSongView = DraggedSongView(title: title, artist: artist)
|
||||
|
||||
component.contents = draggedSongView.view.image()
|
||||
component.frame = NSRect(origin: CGPoint(), size: draggedSongView.view.image().size)
|
||||
return [component]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,95 +35,7 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource {
|
||||
if index > 0 {
|
||||
return queue[index - 1]
|
||||
} else {
|
||||
return ""
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? {
|
||||
guard let queueItem = item as? QueueItem
|
||||
else { return nil }
|
||||
|
||||
return NSPasteboardItem(
|
||||
draggedSong: DraggedSong(
|
||||
type: .queueItem(queueItem.queuePos),
|
||||
title: queueItem.song.title,
|
||||
artist: queueItem.song.artist
|
||||
),
|
||||
ofType: .songPasteboardType
|
||||
)
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
|
||||
var newQueuePos = index - 1
|
||||
|
||||
guard newQueuePos >= 0,
|
||||
let draggingTypes = info.draggingPasteboard.types,
|
||||
draggingTypes.contains(.songPasteboardType),
|
||||
let pasteboardItem = info.draggingPasteboard.pasteboardItems?.first,
|
||||
let draggedSong = pasteboardItem.draggedSong(forType: .songPasteboardType)
|
||||
else { return [] }
|
||||
|
||||
switch draggedSong.type {
|
||||
case let .queueItem(queuePos):
|
||||
if newQueuePos > queuePos { newQueuePos -= 1 }
|
||||
|
||||
guard queuePos != newQueuePos
|
||||
else { return [] }
|
||||
|
||||
return .move
|
||||
case .albumSongItem:
|
||||
return .copy
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
|
||||
var newQueuePos = index - 1
|
||||
|
||||
guard let draggingTypes = info.draggingPasteboard.types,
|
||||
draggingTypes.contains(.songPasteboardType),
|
||||
let data = info.draggingPasteboard.data(forType: .songPasteboardType),
|
||||
let draggedSong = try? PropertyListDecoder().decode(DraggedSong.self, from: data)
|
||||
else { return false }
|
||||
|
||||
switch draggedSong.type {
|
||||
case let .queueItem(queuePos):
|
||||
if newQueuePos > queuePos { newQueuePos -= 1 }
|
||||
|
||||
guard queuePos != newQueuePos
|
||||
else { return false }
|
||||
|
||||
App.store.dispatch(MPDMoveSongInQueue(oldQueuePos: queuePos, newQueuePos: newQueuePos))
|
||||
return true
|
||||
case let .albumSongItem(uri):
|
||||
App.store.dispatch(MPDAddSongToQueue(songUri: uri, queuePos: newQueuePos))
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
func outlineView(_ outlineView: NSOutlineView, draggingSession session: NSDraggingSession, willBeginAt screenPoint: NSPoint, forItems draggedItems: [Any]) {
|
||||
session.enumerateDraggingItems(
|
||||
options: [],
|
||||
for: outlineView,
|
||||
classes: [NSPasteboardItem.self],
|
||||
searchOptions: [:]
|
||||
) { draggingItem, index, stop in
|
||||
guard let item = draggingItem.item as? NSPasteboardItem,
|
||||
let data = item.data(forType: .songPasteboardType),
|
||||
let draggedSong = try? PropertyListDecoder().decode(DraggedSong.self, from: data),
|
||||
case let (title?, artist?) = (draggedSong.title, draggedSong.artist)
|
||||
else { return }
|
||||
|
||||
draggingItem.imageComponentsProvider = {
|
||||
let component = NSDraggingImageComponent(key: NSDraggingItem.ImageComponentKey.icon)
|
||||
let draggedSongView = DraggedSongView(title: title, artist: artist)
|
||||
|
||||
let view = draggedSongView.view
|
||||
let image = view.image()
|
||||
component.contents = image
|
||||
component.frame = NSRect(origin: CGPoint(), size: view.frame.size)
|
||||
return [component]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -10,5 +10,4 @@ import AppKit
|
||||
|
||||
extension NSEvent {
|
||||
static let keyCodeSpace: UInt16 = 49
|
||||
static let keyCodeBS: UInt16 = 51
|
||||
}
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
//
|
||||
// NSPasteboard.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/17.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
extension NSPasteboard.PasteboardType {
|
||||
static let songPasteboardType = NSPasteboard.PasteboardType("me.danbarber.persephone")
|
||||
}
|
||||
@ -1,29 +0,0 @@
|
||||
//
|
||||
// NSPasteboardItem.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/28.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
extension NSPasteboardItem {
|
||||
convenience init(draggedSong: DraggedSong, ofType type: NSPasteboard.PasteboardType) {
|
||||
self.init()
|
||||
self.setDraggedSong(draggedSong, forType: type)
|
||||
}
|
||||
|
||||
func setDraggedSong(_ draggedSong: DraggedSong, forType type: NSPasteboard.PasteboardType) {
|
||||
let data = try! PropertyListEncoder().encode(draggedSong)
|
||||
|
||||
setData(data, forType: type)
|
||||
}
|
||||
|
||||
func draggedSong(forType type: NSPasteboard.PasteboardType) -> DraggedSong? {
|
||||
guard let itemData = data(forType: type)
|
||||
else { return nil }
|
||||
|
||||
return try? PropertyListDecoder().decode(DraggedSong.self, from: itemData)
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
//
|
||||
// NSView.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/18.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
extension NSView {
|
||||
func image() -> NSImage {
|
||||
layoutSubtreeIfNeeded()
|
||||
let imageRepresentation = bitmapImageRepForCachingDisplay(in: frame)!
|
||||
cacheDisplay(in: frame, to: imageRepresentation)
|
||||
return NSImage(cgImage: imageRepresentation.cgImage!, size: frame.size)
|
||||
}
|
||||
}
|
||||
@ -54,8 +54,6 @@ extension MPDClient {
|
||||
guard let queuePos = userData["queuePos"] as? Int
|
||||
else { return }
|
||||
sendPlayTrack(at: queuePos)
|
||||
case .clearQueue:
|
||||
sendClearQueue()
|
||||
case .replaceQueue:
|
||||
guard let songs = userData["songs"] as? [MPDSong]
|
||||
else { return }
|
||||
@ -64,22 +62,6 @@ extension MPDClient {
|
||||
guard let song = userData["song"] as? MPDSong
|
||||
else { return }
|
||||
sendAppendSong(song)
|
||||
case .removeSong:
|
||||
guard let queuePos = userData["queuePos"] as? Int
|
||||
else { return }
|
||||
sendRemoveSong(at: queuePos)
|
||||
|
||||
case .moveSongInQueue:
|
||||
guard let oldQueuePos = userData["oldQueuePos"] as? Int,
|
||||
let newQueuePos = userData["newQueuePos"] as? Int
|
||||
else { return }
|
||||
sendMoveSongInQueue(at: oldQueuePos, to: newQueuePos)
|
||||
|
||||
case .addSongToQueue:
|
||||
guard let songUri = userData["uri"] as? String,
|
||||
let queuePos = userData["queuePos"] as? Int
|
||||
else { return }
|
||||
sendAddSongToQueue(uri: songUri, at: queuePos)
|
||||
|
||||
// Album commands
|
||||
case .fetchAllAlbums:
|
||||
|
||||
@ -37,12 +37,7 @@ extension MPDClient {
|
||||
}
|
||||
if mpdIdle.contains(.queue) {
|
||||
self.fetchQueue()
|
||||
self.fetchStatus()
|
||||
|
||||
self.delegate?.didUpdateQueue(mpdClient: self, queue: self.queue)
|
||||
if let status = self.status {
|
||||
self.delegate?.didUpdateQueuePos(mpdClient: self, song: status.song)
|
||||
}
|
||||
}
|
||||
if mpdIdle.contains(.player) || mpdIdle.contains(.options) {
|
||||
self.fetchStatus()
|
||||
|
||||
@ -14,10 +14,6 @@ extension MPDClient {
|
||||
sendCommand(command: .fetchQueue)
|
||||
}
|
||||
|
||||
func clearQueue() {
|
||||
enqueueCommand(command: .clearQueue)
|
||||
}
|
||||
|
||||
func playTrack(at queuePos: Int) {
|
||||
enqueueCommand(command: .playTrack, userData: ["queuePos": queuePos])
|
||||
}
|
||||
@ -26,18 +22,6 @@ extension MPDClient {
|
||||
enqueueCommand(command: .appendSong, userData: ["song": song])
|
||||
}
|
||||
|
||||
func removeSong(at queuePos: Int) {
|
||||
enqueueCommand(command: .removeSong, userData: ["queuePos": queuePos])
|
||||
}
|
||||
|
||||
func moveSongInQueue(at queuePos: Int, to newQueuePos: Int) {
|
||||
enqueueCommand(command: .moveSongInQueue, userData: ["oldQueuePos": queuePos, "newQueuePos": newQueuePos])
|
||||
}
|
||||
|
||||
func addSongToQueue(songUri: String, at queuePos: Int) {
|
||||
enqueueCommand(command: .addSongToQueue, userData: ["uri": songUri, "queuePos": queuePos])
|
||||
}
|
||||
|
||||
func sendPlayTrack(at queuePos: Int) {
|
||||
mpd_run_play_pos(self.connection, UInt32(queuePos))
|
||||
}
|
||||
@ -52,10 +36,6 @@ extension MPDClient {
|
||||
}
|
||||
}
|
||||
|
||||
func sendClearQueue() {
|
||||
mpd_run_clear(self.connection)
|
||||
}
|
||||
|
||||
func sendReplaceQueue(_ songs: [MPDSong]) {
|
||||
mpd_run_clear(self.connection)
|
||||
|
||||
@ -68,16 +48,4 @@ extension MPDClient {
|
||||
func sendAppendSong(_ song: MPDSong) {
|
||||
mpd_run_add(self.connection, song.uri)
|
||||
}
|
||||
|
||||
func sendRemoveSong(at queuePos: Int) {
|
||||
mpd_run_delete(self.connection, UInt32(queuePos))
|
||||
}
|
||||
|
||||
func sendMoveSongInQueue(at oldQueuePos: Int, to newQueuePos: Int) {
|
||||
mpd_run_move(self.connection, UInt32(oldQueuePos), UInt32(newQueuePos))
|
||||
}
|
||||
|
||||
func sendAddSongToQueue(uri: String, at queuePos: Int) {
|
||||
mpd_run_add_id_to(self.connection, uri, UInt32(queuePos))
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,12 +29,8 @@ extension MPDClient {
|
||||
// Queue commands
|
||||
case fetchQueue
|
||||
case playTrack
|
||||
case clearQueue
|
||||
case replaceQueue
|
||||
case appendSong
|
||||
case removeSong
|
||||
case moveSongInQueue
|
||||
case addSongToQueue
|
||||
|
||||
// Album commands
|
||||
case fetchAllAlbums
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
//
|
||||
// DraggedSong.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/21.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
struct DraggedSong: Codable {
|
||||
var type: DraggedSongType
|
||||
var title: String?
|
||||
var artist: String?
|
||||
}
|
||||
@ -1,50 +0,0 @@
|
||||
//
|
||||
// DraggedSongType.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/21.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
enum DraggedSongType {
|
||||
case queueItem(Int)
|
||||
case albumSongItem(String)
|
||||
}
|
||||
|
||||
private enum Discriminator: Int, Codable {
|
||||
case queueItem
|
||||
case albumSongItem
|
||||
}
|
||||
|
||||
extension DraggedSongType: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
case value
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
switch self {
|
||||
case let .queueItem(queuePos):
|
||||
try container.encode(Discriminator.queueItem, forKey: .type)
|
||||
try container.encode(queuePos, forKey: .value)
|
||||
case let .albumSongItem(uri):
|
||||
try container.encode(Discriminator.albumSongItem, forKey: .type)
|
||||
try container.encode(uri, forKey: .value)
|
||||
}
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let type = try container.decode(Discriminator.self, forKey: .type)
|
||||
switch type {
|
||||
case .queueItem:
|
||||
let queuePos = try container.decode(Int.self, forKey: .value)
|
||||
self = .queueItem(queuePos)
|
||||
case .albumSongItem:
|
||||
let uri = try container.decode(String.self, forKey: .value)
|
||||
self = .albumSongItem(uri)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -6,9 +6,9 @@
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
import Foundation
|
||||
|
||||
struct QueueItem: Hashable {
|
||||
struct QueueItem: Equatable {
|
||||
var song: Song
|
||||
var queuePos: Int
|
||||
var isPlaying: Bool
|
||||
|
||||
@ -43,14 +43,3 @@ extension Song: Equatable {
|
||||
(lhs.album == rhs.album)
|
||||
}
|
||||
}
|
||||
|
||||
extension Song: Hashable {
|
||||
func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(mpdSong.uriString)
|
||||
hasher.combine(disc)
|
||||
hasher.combine(trackNumber)
|
||||
hasher.combine(title)
|
||||
hasher.combine(artist)
|
||||
hasher.combine(album.title)
|
||||
}
|
||||
}
|
||||
|
||||
@ -250,19 +250,12 @@
|
||||
</customView>
|
||||
<menu id="qbK-4f-3fG">
|
||||
<items>
|
||||
<menuItem title="Play Now" id="poo-OI-Kwi">
|
||||
<menuItem title="Play Song" id="poo-OI-Kwi">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="menuActionPlaySong:" target="-2" id="ZB9-dq-reF"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Play Next" id="78G-Sy-J8P">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="menuActionPlayNext:" target="-2" id="hMo-gT-IcI"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="Hk6-In-qd2"/>
|
||||
<menuItem title="Add Song to Queue" id="PdP-4s-xfR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
|
||||
@ -75,51 +75,6 @@
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Queue" id="zZL-2K-acp">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Queue" id="CWM-rf-Ozu">
|
||||
<items>
|
||||
<menuItem title="Remove Song" id="x9q-fx-zaQ">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="removeQueueSongMenuAction:" target="Voe-Tx-rLC" id="stm-VC-mfp"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="MG8-dW-RM9"/>
|
||||
<menuItem title="Clear…" id="x6w-87-3xV">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="clearQueueMenuAction:" target="Voe-Tx-rLC" id="q00-ts-Swv"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Song" id="elk-xW-VXb">
|
||||
<menu key="submenu" title="Song" autoenablesItems="NO" id="RuT-kk-xTu">
|
||||
<items>
|
||||
<menuItem title="Play Now" enabled="NO" id="dyT-9E-DRY">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="playSelectedSongAction:" target="Voe-Tx-rLC" id="jIo-ux-Mhr"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Play Next" id="Q8j-jr-IOp">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="playSelectedSongNextAction:" target="Voe-Tx-rLC" id="HQR-6p-8g7"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="ml8-jV-bZq"/>
|
||||
<menuItem title="Add to Queue" enabled="NO" id="JFH-jT-sBp">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="addSelectedSongToQueueAction:" target="Voe-Tx-rLC" id="9j9-Xd-g0D"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem title="Window" id="aUF-d1-5bR">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<menu key="submenu" title="Window" systemMenu="window" id="Td7-aD-5lo">
|
||||
@ -177,10 +132,7 @@
|
||||
</application>
|
||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Persephone" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="addSelectedSongToQueueMenuItem" destination="JFH-jT-sBp" id="9dy-sJ-XYS"/>
|
||||
<outlet property="mainWindowMenuItem" destination="1Sq-L7-znT" id="dC6-yY-6Ss"/>
|
||||
<outlet property="playSelectedSongMenuItem" destination="dyT-9E-DRY" id="UY2-SN-YMF"/>
|
||||
<outlet property="playSelectedSongNextMenuItem" destination="Q8j-jr-IOp" id="Jqh-ia-sMK"/>
|
||||
<outlet property="updateDatabaseMenuItem" destination="EJg-93-1F6" id="gMf-SQ-lyI"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
@ -582,21 +534,21 @@
|
||||
<scene sceneID="QcX-dC-cTZ">
|
||||
<objects>
|
||||
<viewController id="KIP-rq-4dM" customClass="QueueViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
||||
<splitView key="view" dividerStyle="thin" id="84I-w3-Mxl">
|
||||
<splitView key="view" wantsLayer="YES" dividerStyle="thin" id="84I-w3-Mxl">
|
||||
<rect key="frame" x="0.0" y="0.0" width="328" height="548"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="17" horizontalPageScroll="10" verticalLineScroll="17" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="S3o-nF-NN7">
|
||||
<scrollView borderType="none" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="S3o-nF-NN7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<clipView key="contentView" drawsBackground="NO" id="WI8-Pw-03L">
|
||||
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="14" outlineTableColumn="0Co-uF-CCB" id="jEJ-jg-fll" customClass="QueueView" customModule="Persephone" customModuleProvider="target">
|
||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" selectionHighlightStyle="sourceList" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" viewBased="YES" indentationPerLevel="16" outlineTableColumn="0Co-uF-CCB" id="jEJ-jg-fll">
|
||||
<rect key="frame" x="0.0" y="0.0" width="328" height="219"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<size key="intercellSpacing" width="3" height="0.0"/>
|
||||
<size key="intercellSpacing" width="3" height="2"/>
|
||||
<color key="backgroundColor" name="_sourceListBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||
<tableColumns>
|
||||
@ -614,7 +566,7 @@
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView identifier="queueHeadingCell" id="GOd-cg-juD">
|
||||
<rect key="frame" x="1" y="0.0" width="200" height="17"/>
|
||||
<rect key="frame" x="1" y="1" width="200" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="xgd-Cz-np3">
|
||||
@ -635,7 +587,7 @@
|
||||
</constraints>
|
||||
</tableCellView>
|
||||
<tableCellView identifier="songTitleCell" id="5rR-Gz-AcP" customClass="QueueSongTitleView" customModule="Persephone" customModuleProvider="target">
|
||||
<rect key="frame" x="1" y="17" width="200" height="17"/>
|
||||
<rect key="frame" x="1" y="20" width="200" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<imageView identifier="queuePlayerState" translatesAutoresizingMaskIntoConstraints="NO" id="o8i-cz-hIP" userLabel="Player State View">
|
||||
@ -695,7 +647,7 @@
|
||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
||||
<prototypeCellViews>
|
||||
<tableCellView identifier="songArtistCell" id="JSk-Vc-Y7e">
|
||||
<rect key="frame" x="204" y="0.0" width="122" height="17"/>
|
||||
<rect key="frame" x="204" y="1" width="122" height="17"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="tBe-Q9-3Rw">
|
||||
@ -722,7 +674,6 @@
|
||||
<connections>
|
||||
<action trigger="doubleAction" selector="playTrack:" target="KIP-rq-4dM" id="opa-6G-OW0"/>
|
||||
<outlet property="delegate" destination="KIP-rq-4dM" id="60F-6x-bUE"/>
|
||||
<outlet property="menu" destination="dYA-Jm-eOa" id="9s2-7K-tVx"/>
|
||||
</connections>
|
||||
</outlineView>
|
||||
</subviews>
|
||||
@ -773,24 +724,8 @@
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="du4-e9-TfX" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
<menu identifier="queueViewMenu" id="dYA-Jm-eOa">
|
||||
<items>
|
||||
<menuItem title="Play" id="kp1-XJ-9CL">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="playSongMenuAction:" target="KIP-rq-4dM" id="1nO-8z-LT2"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem title="Remove" id="GaJ-qk-Cg4">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
<connections>
|
||||
<action selector="removeSongMenuAction:" target="KIP-rq-4dM" id="0Oc-Z3-4OD"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="796" y="848"/>
|
||||
<point key="canvasLocation" x="820" y="749"/>
|
||||
</scene>
|
||||
<!--Album View Controller-->
|
||||
<scene sceneID="7Ua-Hj-zWt">
|
||||
@ -813,7 +748,6 @@
|
||||
<color key="primaryBackgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
<connections>
|
||||
<outlet property="delegate" destination="gPn-fP-LFc" id="LQ2-Vl-r08"/>
|
||||
<outlet property="menu" destination="Rif-KP-4xb" id="f7w-Ot-TKf"/>
|
||||
</connections>
|
||||
</collectionView>
|
||||
</subviews>
|
||||
@ -841,18 +775,8 @@
|
||||
</connections>
|
||||
</viewController>
|
||||
<customObject id="uex-Ws-5X4" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||
<menu id="Rif-KP-4xb">
|
||||
<items>
|
||||
<menuItem title="Play album" id="Cuu-eF-cPb">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
<menuItem title="Add album to queue" id="pUA-0C-zhs">
|
||||
<modifierMask key="keyEquivalentModifierMask"/>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="329" y="1370"/>
|
||||
<point key="canvasLocation" x="531" y="1358"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.70"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="DraggedSongView" customModule="Persephone" customModuleProvider="target">
|
||||
<connections>
|
||||
<outlet property="artistLabel" destination="egC-YO-gnV" id="g0f-FI-cGF"/>
|
||||
<outlet property="titleLabel" destination="tsD-ub-h7I" id="EVO-Z7-tZY"/>
|
||||
<outlet property="view" destination="Hz6-mo-xeY" id="Wf9-hm-E7M"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||
<customView id="Hz6-mo-xeY">
|
||||
<rect key="frame" x="0.0" y="0.0" width="129" height="22"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<subviews>
|
||||
<box boxType="custom" borderType="line" cornerRadius="4" translatesAutoresizingMaskIntoConstraints="NO" id="G2x-p5-RM6">
|
||||
<rect key="frame" x="0.0" y="0.0" width="129" height="22"/>
|
||||
<view key="contentView" id="qbG-wn-N4h">
|
||||
<rect key="frame" x="1" y="1" width="127" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<stackView distribution="fillProportionally" orientation="horizontal" alignment="centerY" spacing="12" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rlT-HP-okZ">
|
||||
<rect key="frame" x="0.0" y="0.0" width="127" height="20"/>
|
||||
<subviews>
|
||||
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Go5-Lk-qgA">
|
||||
<rect key="frame" x="8" y="2" width="17" height="17"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="height" constant="17" id="DKw-m3-Lne"/>
|
||||
<constraint firstAttribute="width" constant="17" id="k19-kI-PmI"/>
|
||||
</constraints>
|
||||
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="songIcon" id="KDX-a9-N4B"/>
|
||||
</imageView>
|
||||
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="tsD-ub-h7I">
|
||||
<rect key="frame" x="35" y="2" width="32" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" title="Title" usesSingleLineMode="YES" id="rMn-D0-PG7">
|
||||
<font key="font" metaFont="systemMedium" size="13"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField horizontalHuggingPriority="1000" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="egC-YO-gnV">
|
||||
<rect key="frame" x="75" y="2" width="38" height="17"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" alignment="left" title="Artist" usesSingleLineMode="YES" id="m15-pn-bdW">
|
||||
<font key="font" metaFont="system"/>
|
||||
<color key="textColor" name="secondaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<edgeInsets key="edgeInsets" left="8" right="16" top="0.0" bottom="0.0"/>
|
||||
<visibilityPriorities>
|
||||
<real value="1000"/>
|
||||
<integer value="1000"/>
|
||||
<integer value="1000"/>
|
||||
</visibilityPriorities>
|
||||
<customSpacing>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
<real value="3.4028234663852886e+38"/>
|
||||
</customSpacing>
|
||||
</stackView>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="rlT-HP-okZ" secondAttribute="trailing" id="3dK-4q-G3z"/>
|
||||
<constraint firstAttribute="bottom" secondItem="rlT-HP-okZ" secondAttribute="bottom" id="6bV-EI-Qk5"/>
|
||||
<constraint firstItem="rlT-HP-okZ" firstAttribute="leading" secondItem="qbG-wn-N4h" secondAttribute="leading" id="d0B-7v-cmT"/>
|
||||
<constraint firstItem="rlT-HP-okZ" firstAttribute="top" secondItem="qbG-wn-N4h" secondAttribute="top" id="mvZ-UP-tHf"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<color key="borderColor" name="tertiaryLabelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="fillColor" red="0.27450980392156865" green="0.27450980392156865" blue="0.27450980392156865" alpha="0.65297645246478875" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
</box>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstItem="G2x-p5-RM6" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" id="A72-wi-zNE"/>
|
||||
<constraint firstItem="G2x-p5-RM6" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" id="ENp-3t-AXT"/>
|
||||
<constraint firstAttribute="trailing" secondItem="G2x-p5-RM6" secondAttribute="trailing" id="MbJ-MP-4HG"/>
|
||||
<constraint firstAttribute="bottom" secondItem="G2x-p5-RM6" secondAttribute="bottom" id="Nzd-OC-f1V"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="53.5" y="14"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
<image name="songIcon" width="17" height="17"/>
|
||||
</resources>
|
||||
</document>
|
||||
@ -16,26 +16,10 @@ struct MPDStopAction: Action {}
|
||||
struct MPDNextTrackAction: Action {}
|
||||
struct MPDPrevTrackAction: Action {}
|
||||
|
||||
struct MPDClearQueue: Action {}
|
||||
|
||||
struct MPDMoveSongInQueue: Action {
|
||||
let oldQueuePos: Int
|
||||
let newQueuePos: Int
|
||||
}
|
||||
|
||||
struct MPDAddSongToQueue: Action {
|
||||
let songUri: String
|
||||
let queuePos: Int
|
||||
}
|
||||
|
||||
struct MPDAppendTrack: Action {
|
||||
let song: MPDClient.MPDSong
|
||||
}
|
||||
|
||||
struct MPDRemoveTrack: Action {
|
||||
let queuePos: Int
|
||||
}
|
||||
|
||||
struct MPDPlayTrack: Action {
|
||||
let queuePos: Int
|
||||
}
|
||||
|
||||
@ -17,11 +17,3 @@ struct MainWindowDidMinimizeAction: Action {}
|
||||
struct DatabaseUpdateStartedAction: Action {}
|
||||
|
||||
struct DatabaseUpdateFinishedAction: Action {}
|
||||
|
||||
struct SetSelectedQueueItem: Action {
|
||||
let selectedQueueItem: QueueItem?
|
||||
}
|
||||
|
||||
struct SetSelectedSong: Action {
|
||||
let selectedSong: Song?
|
||||
}
|
||||
|
||||
@ -30,21 +30,9 @@ func mpdReducer(action: Action, state: MPDState?) -> MPDState {
|
||||
case is MPDPrevTrackAction:
|
||||
App.mpdClient.prevTrack()
|
||||
|
||||
case is MPDClearQueue:
|
||||
App.mpdClient.clearQueue()
|
||||
|
||||
case let action as MPDMoveSongInQueue:
|
||||
App.mpdClient.moveSongInQueue(at: action.oldQueuePos, to: action.newQueuePos)
|
||||
|
||||
case let action as MPDAddSongToQueue:
|
||||
App.mpdClient.addSongToQueue(songUri: action.songUri, at: action.queuePos)
|
||||
|
||||
case let action as MPDAppendTrack:
|
||||
App.mpdClient.appendSong(action.song)
|
||||
|
||||
case let action as MPDRemoveTrack:
|
||||
App.mpdClient.removeSong(at: action.queuePos)
|
||||
|
||||
case let action as MPDPlayTrack:
|
||||
App.mpdClient.playTrack(at: action.queuePos)
|
||||
|
||||
|
||||
@ -14,9 +14,7 @@ func queueReducer(action: Action, state: QueueState?) -> QueueState {
|
||||
|
||||
switch action {
|
||||
case let action as UpdateQueueAction:
|
||||
if state.queuePos >= action.queue.count {
|
||||
state.queuePos = -1
|
||||
}
|
||||
state.queuePos = -1
|
||||
|
||||
state.queue = action.queue.enumerated().map { index, mpdSong in
|
||||
let song = Song(mpdSong: mpdSong)
|
||||
|
||||
@ -27,12 +27,6 @@ func uiReducer(action: Action, state: UIState?) -> UIState {
|
||||
case is DatabaseUpdateFinishedAction:
|
||||
state.databaseUpdating = false
|
||||
|
||||
case let action as SetSelectedSong:
|
||||
state.selectedSong = action.selectedSong
|
||||
|
||||
case let action as SetSelectedQueueItem:
|
||||
state.selectedQueueItem = action.selectedQueueItem
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
@ -18,8 +18,4 @@ struct UIState: StateType {
|
||||
var mainWindowState: MainWindowState = .closed
|
||||
|
||||
var databaseUpdating: Bool = false
|
||||
|
||||
var selectedSong: Song?
|
||||
|
||||
var selectedQueueItem: QueueItem?
|
||||
}
|
||||
|
||||
@ -1,33 +0,0 @@
|
||||
//
|
||||
// DraggedSong.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/18.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class DraggedSongView: NSViewController {
|
||||
@IBOutlet var titleLabel: NSTextField!
|
||||
@IBOutlet var artistLabel: NSTextField!
|
||||
|
||||
private let songTitle: String
|
||||
private let songArtist: String
|
||||
|
||||
init(title: String, artist: String) {
|
||||
songTitle = title
|
||||
songArtist = artist
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
titleLabel.stringValue = songTitle
|
||||
artistLabel.stringValue = songArtist
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
//
|
||||
// QueueView.swift
|
||||
// Persephone
|
||||
//
|
||||
// Created by Daniel Barber on 2019/6/09.
|
||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||
//
|
||||
|
||||
import AppKit
|
||||
|
||||
class QueueView: NSOutlineView {
|
||||
override func menu(for event: NSEvent) -> NSMenu? {
|
||||
let point = convert(event.locationInWindow, from: nil)
|
||||
|
||||
let currentRow = row(at: point)
|
||||
|
||||
if currentRow > 0 {
|
||||
return super.menu(for: event)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 309 B |
Binary file not shown.
|
Before Width: | Height: | Size: 547 B |
Binary file not shown.
Loading…
Reference in New Issue
Block a user