mirror of
https://github.com/danbee/persephone
synced 2025-03-04 08:39:11 +00:00
Compare commits
9 Commits
41120dd16c
...
34f941017f
| Author | SHA1 | Date | |
|---|---|---|---|
| 34f941017f | |||
| 225d511543 | |||
| 47c273c7ad | |||
| 98e741d9fe | |||
| c0da221074 | |||
| 6ccaef91a1 | |||
| c4e5f7408a | |||
| b46cbf229f | |||
| 063b8da202 |
@ -101,6 +101,7 @@
|
|||||||
E4B11BC02275EE150075461B /* QueueActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BBF2275EE150075461B /* QueueActions.swift */; };
|
E4B11BC02275EE150075461B /* QueueActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BBF2275EE150075461B /* QueueActions.swift */; };
|
||||||
E4B11BC22275EE410075461B /* AlbumListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BC12275EE410075461B /* AlbumListActions.swift */; };
|
E4B11BC22275EE410075461B /* AlbumListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B11BC12275EE410075461B /* AlbumListActions.swift */; };
|
||||||
E4B3DF6523D66A4400728F6B /* QueueSongCoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */; };
|
E4B3DF6523D66A4400728F6B /* QueueSongCoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */; };
|
||||||
|
E4B46F8F2402E89800152157 /* MPDError.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B46F8E2402E89800152157 /* MPDError.swift */; };
|
||||||
E4B5AE7E22F4C49600CCEC65 /* MPDServerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B5AE7D22F4C49600CCEC65 /* MPDServerDelegate.swift */; };
|
E4B5AE7E22F4C49600CCEC65 /* MPDServerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4B5AE7D22F4C49600CCEC65 /* MPDServerDelegate.swift */; };
|
||||||
E4BB7F8F23E5E7BC00906E2F /* MPDAlbumArtImageDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BB7F8E23E5E7BC00906E2F /* MPDAlbumArtImageDataProvider.swift */; };
|
E4BB7F8F23E5E7BC00906E2F /* MPDAlbumArtImageDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BB7F8E23E5E7BC00906E2F /* MPDAlbumArtImageDataProvider.swift */; };
|
||||||
E4BB7F9323E9150A00906E2F /* CoverArtService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BB7F9223E9150A00906E2F /* CoverArtService.swift */; };
|
E4BB7F9323E9150A00906E2F /* CoverArtService.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4BB7F9223E9150A00906E2F /* CoverArtService.swift */; };
|
||||||
@ -120,6 +121,9 @@
|
|||||||
E4F26F7723411AE300D45FF9 /* ArtistListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F26F7623411AE300D45FF9 /* ArtistListActions.swift */; };
|
E4F26F7723411AE300D45FF9 /* ArtistListActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F26F7623411AE300D45FF9 /* ArtistListActions.swift */; };
|
||||||
E4F26F7923411B1500D45FF9 /* ArtistReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F26F7823411B1500D45FF9 /* ArtistReducer.swift */; };
|
E4F26F7923411B1500D45FF9 /* ArtistReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F26F7823411B1500D45FF9 /* ArtistReducer.swift */; };
|
||||||
E4F26F7B23411D5400D45FF9 /* MPDClient+Artist.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F26F7A23411D5400D45FF9 /* MPDClient+Artist.swift */; };
|
E4F26F7B23411D5400D45FF9 /* MPDClient+Artist.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F26F7A23411D5400D45FF9 /* MPDClient+Artist.swift */; };
|
||||||
|
E4F2EFEE24076A2700198159 /* ServerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F2EFED24076A2700198159 /* ServerState.swift */; };
|
||||||
|
E4F2EFF024076B0900198159 /* ServerActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F2EFEF24076B0900198159 /* ServerActions.swift */; };
|
||||||
|
E4F2EFF224076B5E00198159 /* ServerReducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F2EFF124076B5E00198159 /* ServerReducer.swift */; };
|
||||||
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */; };
|
E4F6B460221E119B00ACF42A /* QueueDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */; };
|
||||||
E4F6B463221E125900ACF42A /* QueueItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B462221E125900ACF42A /* QueueItem.swift */; };
|
E4F6B463221E125900ACF42A /* QueueItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B462221E125900ACF42A /* QueueItem.swift */; };
|
||||||
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B466221E233200ACF42A /* AlbumDataSource.swift */; };
|
E4F6B467221E233200ACF42A /* AlbumDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F6B466221E233200ACF42A /* AlbumDataSource.swift */; };
|
||||||
@ -300,6 +304,7 @@
|
|||||||
E4B11BBF2275EE150075461B /* QueueActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueActions.swift; sourceTree = "<group>"; };
|
E4B11BBF2275EE150075461B /* QueueActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueActions.swift; sourceTree = "<group>"; };
|
||||||
E4B11BC12275EE410075461B /* AlbumListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListActions.swift; sourceTree = "<group>"; };
|
E4B11BC12275EE410075461B /* AlbumListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumListActions.swift; sourceTree = "<group>"; };
|
||||||
E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueSongCoverView.swift; sourceTree = "<group>"; };
|
E4B3DF6423D66A4400728F6B /* QueueSongCoverView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueSongCoverView.swift; sourceTree = "<group>"; };
|
||||||
|
E4B46F8E2402E89800152157 /* MPDError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDError.swift; sourceTree = "<group>"; };
|
||||||
E4B5AE7D22F4C49600CCEC65 /* MPDServerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDServerDelegate.swift; sourceTree = "<group>"; };
|
E4B5AE7D22F4C49600CCEC65 /* MPDServerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDServerDelegate.swift; sourceTree = "<group>"; };
|
||||||
E4BB7F8E23E5E7BC00906E2F /* MPDAlbumArtImageDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDAlbumArtImageDataProvider.swift; sourceTree = "<group>"; };
|
E4BB7F8E23E5E7BC00906E2F /* MPDAlbumArtImageDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDAlbumArtImageDataProvider.swift; sourceTree = "<group>"; };
|
||||||
E4BB7F9223E9150A00906E2F /* CoverArtService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoverArtService.swift; sourceTree = "<group>"; };
|
E4BB7F9223E9150A00906E2F /* CoverArtService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoverArtService.swift; sourceTree = "<group>"; };
|
||||||
@ -320,6 +325,9 @@
|
|||||||
E4F26F7623411AE300D45FF9 /* ArtistListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArtistListActions.swift; sourceTree = "<group>"; };
|
E4F26F7623411AE300D45FF9 /* ArtistListActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArtistListActions.swift; sourceTree = "<group>"; };
|
||||||
E4F26F7823411B1500D45FF9 /* ArtistReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArtistReducer.swift; sourceTree = "<group>"; };
|
E4F26F7823411B1500D45FF9 /* ArtistReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArtistReducer.swift; sourceTree = "<group>"; };
|
||||||
E4F26F7A23411D5400D45FF9 /* MPDClient+Artist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Artist.swift"; sourceTree = "<group>"; };
|
E4F26F7A23411D5400D45FF9 /* MPDClient+Artist.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MPDClient+Artist.swift"; sourceTree = "<group>"; };
|
||||||
|
E4F2EFED24076A2700198159 /* ServerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerState.swift; sourceTree = "<group>"; };
|
||||||
|
E4F2EFEF24076B0900198159 /* ServerActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerActions.swift; sourceTree = "<group>"; };
|
||||||
|
E4F2EFF124076B5E00198159 /* ServerReducer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerReducer.swift; sourceTree = "<group>"; };
|
||||||
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueDataSource.swift; sourceTree = "<group>"; };
|
E4F6B45F221E119B00ACF42A /* QueueDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueDataSource.swift; sourceTree = "<group>"; };
|
||||||
E4F6B462221E125900ACF42A /* QueueItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueItem.swift; sourceTree = "<group>"; };
|
E4F6B462221E125900ACF42A /* QueueItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueItem.swift; sourceTree = "<group>"; };
|
||||||
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDataSource.swift; sourceTree = "<group>"; };
|
E4F6B466221E233200ACF42A /* AlbumDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDataSource.swift; sourceTree = "<group>"; };
|
||||||
@ -660,6 +668,7 @@
|
|||||||
E4B11B60226A4BFF0075461B /* PlayerReducer.swift */,
|
E4B11B60226A4BFF0075461B /* PlayerReducer.swift */,
|
||||||
E4FF718F227601B400D4C412 /* PreferencesReducer.swift */,
|
E4FF718F227601B400D4C412 /* PreferencesReducer.swift */,
|
||||||
E4B11B74226CC4D30075461B /* QueueReducer.swift */,
|
E4B11B74226CC4D30075461B /* QueueReducer.swift */,
|
||||||
|
E4F2EFF124076B5E00198159 /* ServerReducer.swift */,
|
||||||
E440519D227BB0720090CD6F /* UIReducer.swift */,
|
E440519D227BB0720090CD6F /* UIReducer.swift */,
|
||||||
);
|
);
|
||||||
path = Reducers;
|
path = Reducers;
|
||||||
@ -676,6 +685,7 @@
|
|||||||
E4B11B65226A4F830075461B /* PlayerState.swift */,
|
E4B11B65226A4F830075461B /* PlayerState.swift */,
|
||||||
E4FF718D2276010E00D4C412 /* PreferencesState.swift */,
|
E4FF718D2276010E00D4C412 /* PreferencesState.swift */,
|
||||||
E4B11B67226A4FA00075461B /* QueueState.swift */,
|
E4B11B67226A4FA00075461B /* QueueState.swift */,
|
||||||
|
E4F2EFED24076A2700198159 /* ServerState.swift */,
|
||||||
E440519F227BB0AB0090CD6F /* UIState.swift */,
|
E440519F227BB0AB0090CD6F /* UIState.swift */,
|
||||||
);
|
);
|
||||||
path = State;
|
path = State;
|
||||||
@ -689,6 +699,7 @@
|
|||||||
E4B11BBD2275EDAA0075461B /* PlayerActions.swift */,
|
E4B11BBD2275EDAA0075461B /* PlayerActions.swift */,
|
||||||
E4FF71912276029000D4C412 /* PreferencesActions.swift */,
|
E4FF71912276029000D4C412 /* PreferencesActions.swift */,
|
||||||
E4B11BBF2275EE150075461B /* QueueActions.swift */,
|
E4B11BBF2275EE150075461B /* QueueActions.swift */,
|
||||||
|
E4F2EFEF24076B0900198159 /* ServerActions.swift */,
|
||||||
E440519B227BAF2E0090CD6F /* UIActions.swift */,
|
E440519B227BAF2E0090CD6F /* UIActions.swift */,
|
||||||
);
|
);
|
||||||
path = Actions;
|
path = Actions;
|
||||||
@ -707,6 +718,7 @@
|
|||||||
children = (
|
children = (
|
||||||
E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */,
|
E4EB237A220F7CF1008C70C0 /* MPDAlbum.swift */,
|
||||||
E45962C52241A78500FC1A1E /* MPDCommand.swift */,
|
E45962C52241A78500FC1A1E /* MPDCommand.swift */,
|
||||||
|
E4B46F8E2402E89800152157 /* MPDError.swift */,
|
||||||
E4C8B53D22349002009A20F3 /* MPDIdle.swift */,
|
E4C8B53D22349002009A20F3 /* MPDIdle.swift */,
|
||||||
E4EB2378220F10B8008C70C0 /* MPDPair.swift */,
|
E4EB2378220F10B8008C70C0 /* MPDPair.swift */,
|
||||||
E4E8CC9922075D370024217A /* MPDSong.swift */,
|
E4E8CC9922075D370024217A /* MPDSong.swift */,
|
||||||
@ -974,6 +986,8 @@
|
|||||||
E450AD7E222620A10091BED3 /* Album.swift in Sources */,
|
E450AD7E222620A10091BED3 /* Album.swift in Sources */,
|
||||||
E4DA820623D6236200C1EE58 /* NSSize.swift in Sources */,
|
E4DA820623D6236200C1EE58 /* NSSize.swift in Sources */,
|
||||||
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
E408D3B6220DD8970006D9BE /* Notification.swift in Sources */,
|
||||||
|
E4F2EFEE24076A2700198159 /* ServerState.swift in Sources */,
|
||||||
|
E4B46F8F2402E89800152157 /* MPDError.swift in Sources */,
|
||||||
E43AC1F822C7065A001E483C /* AlbumCoverButton.swift in Sources */,
|
E43AC1F822C7065A001E483C /* AlbumCoverButton.swift in Sources */,
|
||||||
E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */,
|
E45962C62241A78500FC1A1E /* MPDCommand.swift in Sources */,
|
||||||
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
E408D3B9220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift in Sources */,
|
||||||
@ -991,6 +1005,7 @@
|
|||||||
E4FF71922276029000D4C412 /* PreferencesActions.swift in Sources */,
|
E4FF71922276029000D4C412 /* PreferencesActions.swift in Sources */,
|
||||||
E489E39922B85D0400CA8CBD /* NSPasteboard.swift in Sources */,
|
E489E39922B85D0400CA8CBD /* NSPasteboard.swift in Sources */,
|
||||||
E43AC1F122C68E6A001E483C /* NSPasteboardItem.swift in Sources */,
|
E43AC1F122C68E6A001E483C /* NSPasteboardItem.swift in Sources */,
|
||||||
|
E4F2EFF224076B5E00198159 /* ServerReducer.swift in Sources */,
|
||||||
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
E465049A21E94DF500A70F4C /* WindowController.swift in Sources */,
|
||||||
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
E41B22C621FB932700D544F6 /* MPDClient.swift in Sources */,
|
||||||
E47E2FDD2220A6D100F747E6 /* Time.swift in Sources */,
|
E47E2FDD2220A6D100F747E6 /* Time.swift in Sources */,
|
||||||
@ -1021,6 +1036,7 @@
|
|||||||
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */,
|
E41EA46C221636AF0068EF46 /* GeneralPrefsViewController.swift in Sources */,
|
||||||
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
E4E8CC902204EC7F0024217A /* Delegate.swift in Sources */,
|
||||||
E47E2FD5222071FD00F747E6 /* AlbumViewItem.swift in Sources */,
|
E47E2FD5222071FD00F747E6 /* AlbumViewItem.swift in Sources */,
|
||||||
|
E4F2EFF024076B0900198159 /* ServerActions.swift in Sources */,
|
||||||
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
E408D3BE220E03EE0006D9BE /* RawRepresentable.swift in Sources */,
|
||||||
E4B11B66226A4F830075461B /* PlayerState.swift in Sources */,
|
E4B11B66226A4F830075461B /* PlayerState.swift in Sources */,
|
||||||
E4B11BBE2275EDAA0075461B /* PlayerActions.swift in Sources */,
|
E4B11BBE2275EDAA0075461B /* PlayerActions.swift in Sources */,
|
||||||
@ -1179,7 +1195,7 @@
|
|||||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
ENABLE_NS_ASSERTIONS = NO;
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
@ -1221,7 +1237,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/libmpdclient/output",
|
"$(PROJECT_DIR)/libmpdclient/output",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = "0.16.1-alpha";
|
MARKETING_VERSION = "0.17.0-alpha";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = me.danbarber.Persephone;
|
PRODUCT_BUNDLE_IDENTIFIER = me.danbarber.Persephone;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -1238,7 +1254,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = 54DPC63K8R;
|
DEVELOPMENT_TEAM = 54DPC63K8R;
|
||||||
@ -1253,7 +1269,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/libmpdclient/output",
|
"$(PROJECT_DIR)/libmpdclient/output",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = "0.16.1-alpha";
|
MARKETING_VERSION = "0.17.0-alpha";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = me.danbarber.Persephone;
|
PRODUCT_BUNDLE_IDENTIFIER = me.danbarber.Persephone;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@ -1298,7 +1314,7 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = 54DPC63K8R;
|
DEVELOPMENT_TEAM = 54DPC63K8R;
|
||||||
@ -1348,7 +1364,7 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
|
||||||
CODE_SIGN_IDENTITY = "3rd Party Mac Developer Application";
|
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = 54DPC63K8R;
|
DEVELOPMENT_TEAM = 54DPC63K8R;
|
||||||
|
|||||||
@ -16,6 +16,8 @@ class AppDelegate: NSObject,
|
|||||||
MediaKeyTapDelegate {
|
MediaKeyTapDelegate {
|
||||||
var mediaKeyTap: MediaKeyTap?
|
var mediaKeyTap: MediaKeyTap?
|
||||||
|
|
||||||
|
@IBOutlet weak var connectMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet weak var disconnectMenuItem: NSMenuItem!
|
||||||
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
|
@IBOutlet weak var mainWindowMenuItem: NSMenuItem!
|
||||||
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
|
@IBOutlet weak var updateDatabaseMenuItem: NSMenuItem!
|
||||||
@IBOutlet weak var playSelectedSongMenuItem: NSMenuItem!
|
@IBOutlet weak var playSelectedSongMenuItem: NSMenuItem!
|
||||||
@ -28,13 +30,13 @@ class AppDelegate: NSObject,
|
|||||||
|
|
||||||
App.store.subscribe(self) {
|
App.store.subscribe(self) {
|
||||||
$0.select {
|
$0.select {
|
||||||
$0.uiState
|
($0.serverState, $0.uiState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ = App.userNotificationsController
|
_ = App.userNotificationsController
|
||||||
|
|
||||||
App.mpdServerController.connect()
|
_ = App.mpdServerController
|
||||||
}
|
}
|
||||||
|
|
||||||
func applicationWillTerminate(_ aNotification: Notification) {
|
func applicationWillTerminate(_ aNotification: Notification) {
|
||||||
@ -105,6 +107,11 @@ class AppDelegate: NSObject,
|
|||||||
playSelectedSongNextMenuItem.isEnabled = selectedSong != nil
|
playSelectedSongNextMenuItem.isEnabled = selectedSong != nil
|
||||||
addSelectedSongToQueueMenuItem.isEnabled = selectedSong != nil
|
addSelectedSongToQueueMenuItem.isEnabled = selectedSong != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setConnectMenuItemsState(connected: Bool) {
|
||||||
|
connectMenuItem.isEnabled = !connected
|
||||||
|
disconnectMenuItem.isEnabled = connected
|
||||||
|
}
|
||||||
|
|
||||||
func handle(mediaKey: MediaKey, event: KeyEvent) {
|
func handle(mediaKey: MediaKey, event: KeyEvent) {
|
||||||
switch mediaKey {
|
switch mediaKey {
|
||||||
@ -117,6 +124,13 @@ class AppDelegate: NSObject,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IBAction func connectMenuAction(_ sender: NSMenuItem) {
|
||||||
|
App.mpdServerController.connect()
|
||||||
|
}
|
||||||
|
@IBAction func disconnectMenuAction(_ sender: NSMenuItem) {
|
||||||
|
App.mpdServerController.disconnect()
|
||||||
|
}
|
||||||
|
|
||||||
@IBAction func updateDatabase(_ sender: NSMenuItem) {
|
@IBAction func updateDatabase(_ sender: NSMenuItem) {
|
||||||
App.mpdClient.updateDatabase()
|
App.mpdClient.updateDatabase()
|
||||||
}
|
}
|
||||||
@ -182,11 +196,14 @@ class AppDelegate: NSObject,
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension AppDelegate: StoreSubscriber {
|
extension AppDelegate: StoreSubscriber {
|
||||||
typealias StoreSubscriberStateType = UIState
|
typealias StoreSubscriberStateType = (
|
||||||
|
serverState: ServerState, uiState: UIState
|
||||||
|
)
|
||||||
|
|
||||||
func newState(state: UIState) {
|
func newState(state: StoreSubscriberStateType) {
|
||||||
updateDatabaseMenuItem.isEnabled = !state.databaseUpdating
|
updateDatabaseMenuItem.isEnabled = !state.uiState.databaseUpdating
|
||||||
setMainWindowStateMenuItem(state: state.mainWindowState)
|
setMainWindowStateMenuItem(state: state.uiState.mainWindowState)
|
||||||
setSongMenuItemsState(selectedSong: state.selectedSong)
|
setSongMenuItemsState(selectedSong: state.uiState.selectedSong)
|
||||||
|
setConnectMenuItemsState(connected: state.serverState.connected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,4 +12,5 @@ extension Notification.Name {
|
|||||||
static let didConnect = Notification.Name("MPDClientDidConnect")
|
static let didConnect = Notification.Name("MPDClientDidConnect")
|
||||||
static let willDisconnect = Notification.Name("MPDClientWillDisconnect")
|
static let willDisconnect = Notification.Name("MPDClientWillDisconnect")
|
||||||
static let didReloadAlbumArt = Notification.Name("MPDDidReloadAlbumArt")
|
static let didReloadAlbumArt = Notification.Name("MPDDidReloadAlbumArt")
|
||||||
|
static let didRaiseError = Notification.Name("MPDDidRaiseError")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,15 +6,28 @@
|
|||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import AppKit
|
||||||
|
|
||||||
class MPDServerDelegate: MPDClientDelegate {
|
class MPDServerDelegate: MPDClientDelegate {
|
||||||
func didConnect(mpdClient: MPDClient) {
|
func didConnect(mpdClient: MPDClient) {
|
||||||
NotificationCenter.default.post(name: .didConnect, object: nil)
|
NotificationCenter.default.post(name: .didConnect, object: nil)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
App.store.dispatch(UpdateConnectedState(connected: true))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func willDisconnect(mpdClient: MPDClient) {
|
func willDisconnect(mpdClient: MPDClient) {
|
||||||
NotificationCenter.default.post(name: .willDisconnect, object: nil)
|
NotificationCenter.default.post(name: .willDisconnect, object: nil)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
App.store.dispatch(UpdateConnectedState(connected: false))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func didRaiseError(
|
||||||
|
mpdClient: MPDClient,
|
||||||
|
error: MPDClient.MPDError
|
||||||
|
) {
|
||||||
|
NotificationCenter.default.post(name: .didRaiseError, object: error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus) {
|
func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus) {
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<items>
|
<items>
|
||||||
<menuItem title="Persephone" id="1Xt-HY-uBw">
|
<menuItem title="Persephone" id="1Xt-HY-uBw">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Persephone" systemMenu="apple" id="uQy-DD-JDr">
|
<menu key="submenu" title="Persephone" systemMenu="apple" autoenablesItems="NO" id="uQy-DD-JDr">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="About Persephone" id="5kV-Vb-QxS">
|
<menuItem title="About Persephone" id="5kV-Vb-QxS">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
@ -29,7 +29,19 @@
|
|||||||
<segue destination="xYu-7w-E5x" kind="show" identifier="Preferences" id="OTW-56-v9E"/>
|
<segue destination="xYu-7w-E5x" kind="show" identifier="Preferences" id="OTW-56-v9E"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="wFC-TO-SCJ"/>
|
<menuItem title="Connect" keyEquivalent="c" id="VlA-Re-OZs">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="connectMenuAction:" target="Voe-Tx-rLC" id="Psl-MI-Dbx"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Disconnect" enabled="NO" keyEquivalent="d" id="yjK-qU-C6d">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask" control="YES" option="YES" command="YES"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="disconnectMenuAction:" target="Voe-Tx-rLC" id="smu-DN-Ubp"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="vcx-U6-vzu"/>
|
||||||
<menuItem title="Services" id="NMo-om-nkz">
|
<menuItem title="Services" id="NMo-om-nkz">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
|
||||||
@ -61,6 +73,50 @@
|
|||||||
</items>
|
</items>
|
||||||
</menu>
|
</menu>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
|
<menuItem title="Edit" id="vqD-eY-QGd">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<menu key="submenu" title="Edit" id="TuB-7j-hDK">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Undo" keyEquivalent="z" id="Qfn-k5-qMJ">
|
||||||
|
<connections>
|
||||||
|
<action selector="undo:" target="Ady-hI-5gd" id="eEs-gZ-3LG"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Redo" keyEquivalent="Z" id="jTO-Fc-mMc">
|
||||||
|
<connections>
|
||||||
|
<action selector="redo:" target="Ady-hI-5gd" id="VB9-9R-Kbp"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem isSeparatorItem="YES" id="iGg-SA-H7J"/>
|
||||||
|
<menuItem title="Cut" keyEquivalent="x" id="wMs-2i-IFp">
|
||||||
|
<connections>
|
||||||
|
<action selector="cut:" target="Ady-hI-5gd" id="kNV-s2-6rJ"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Copy" keyEquivalent="c" id="6Xf-49-5o2">
|
||||||
|
<connections>
|
||||||
|
<action selector="copy:" target="Ady-hI-5gd" id="QzD-pM-sbg"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Paste" keyEquivalent="v" id="FPx-H8-gor">
|
||||||
|
<connections>
|
||||||
|
<action selector="paste:" target="Ady-hI-5gd" id="zK6-ON-cCD"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Delete" id="42c-Ut-F4e">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="delete:" target="Ady-hI-5gd" id="XbT-8a-cop"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Select All" keyEquivalent="a" id="oF5-zh-KZt">
|
||||||
|
<connections>
|
||||||
|
<action selector="selectAll:" target="Ady-hI-5gd" id="3gW-FK-DJV"/>
|
||||||
|
</connections>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</menuItem>
|
||||||
<menuItem title="Database" id="usv-UH-vkC">
|
<menuItem title="Database" id="usv-UH-vkC">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<menu key="submenu" title="Database" autoenablesItems="NO" id="rFP-zL-1X4">
|
<menu key="submenu" title="Database" autoenablesItems="NO" id="rFP-zL-1X4">
|
||||||
@ -178,6 +234,8 @@
|
|||||||
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Persephone" customModuleProvider="target">
|
<customObject id="Voe-Tx-rLC" customClass="AppDelegate" customModule="Persephone" customModuleProvider="target">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="addSelectedSongToQueueMenuItem" destination="JFH-jT-sBp" id="9dy-sJ-XYS"/>
|
<outlet property="addSelectedSongToQueueMenuItem" destination="JFH-jT-sBp" id="9dy-sJ-XYS"/>
|
||||||
|
<outlet property="connectMenuItem" destination="VlA-Re-OZs" id="Zzt-yq-mtp"/>
|
||||||
|
<outlet property="disconnectMenuItem" destination="yjK-qU-C6d" id="qel-dM-Gbl"/>
|
||||||
<outlet property="mainWindowMenuItem" destination="1Sq-L7-znT" id="dC6-yY-6Ss"/>
|
<outlet property="mainWindowMenuItem" destination="1Sq-L7-znT" id="dC6-yY-6Ss"/>
|
||||||
<outlet property="playSelectedSongMenuItem" destination="dyT-9E-DRY" id="UY2-SN-YMF"/>
|
<outlet property="playSelectedSongMenuItem" destination="dyT-9E-DRY" id="UY2-SN-YMF"/>
|
||||||
<outlet property="playSelectedSongNextMenuItem" destination="Q8j-jr-IOp" id="Jqh-ia-sMK"/>
|
<outlet property="playSelectedSongNextMenuItem" destination="Q8j-jr-IOp" id="Jqh-ia-sMK"/>
|
||||||
@ -375,7 +433,7 @@
|
|||||||
<splitViewController id="fnD-7K-pHK" customClass="MainSplitViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
<splitViewController id="fnD-7K-pHK" customClass="MainSplitViewController" customModule="Persephone" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<splitViewItems>
|
<splitViewItems>
|
||||||
<splitViewItem holdingPriority="255" behavior="contentList" id="CWo-v7-gd2"/>
|
<splitViewItem holdingPriority="255" behavior="contentList" id="CWo-v7-gd2"/>
|
||||||
<splitViewItem id="Mdr-U0-Vci"/>
|
<splitViewItem id="bAy-ec-iQI"/>
|
||||||
</splitViewItems>
|
</splitViewItems>
|
||||||
<splitView key="splitView" dividerStyle="thin" vertical="YES" id="g34-ef-XN0">
|
<splitView key="splitView" dividerStyle="thin" vertical="YES" id="g34-ef-XN0">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
<rect key="frame" x="0.0" y="0.0" width="450" height="300"/>
|
||||||
@ -387,7 +445,7 @@
|
|||||||
<connections>
|
<connections>
|
||||||
<outlet property="splitView" destination="g34-ef-XN0" id="YEc-LL-DoS"/>
|
<outlet property="splitView" destination="g34-ef-XN0" id="YEc-LL-DoS"/>
|
||||||
<segue destination="KIP-rq-4dM" kind="relationship" relationship="splitItems" id="Vmb-hY-d12"/>
|
<segue destination="KIP-rq-4dM" kind="relationship" relationship="splitItems" id="Vmb-hY-d12"/>
|
||||||
<segue destination="SjO-VS-1bb" kind="relationship" relationship="splitItems" id="peC-gL-WJ1"/>
|
<segue destination="gPn-fP-LFc" kind="relationship" relationship="splitItems" id="eC9-b4-YWt"/>
|
||||||
</connections>
|
</connections>
|
||||||
</splitViewController>
|
</splitViewController>
|
||||||
<customObject id="Dag-kO-ps3" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
<customObject id="Dag-kO-ps3" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
||||||
@ -501,53 +559,6 @@
|
|||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="1411" y="-420"/>
|
<point key="canvasLocation" x="1411" y="-420"/>
|
||||||
</scene>
|
</scene>
|
||||||
<!--View Controller-->
|
|
||||||
<scene sceneID="VvW-vT-alQ">
|
|
||||||
<objects>
|
|
||||||
<customObject id="MSG-y7-cKU" userLabel="First Responder" customClass="NSResponder" sceneMemberID="firstResponder"/>
|
|
||||||
<viewController id="SjO-VS-1bb" sceneMemberID="viewController">
|
|
||||||
<view key="view" id="BRY-0R-F3u">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="558"/>
|
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
|
||||||
<subviews>
|
|
||||||
<tabView type="noTabsNoBorder" initialItem="XgS-cX-SDH" translatesAutoresizingMaskIntoConstraints="NO" id="ARv-cj-xlz">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="558"/>
|
|
||||||
<font key="font" metaFont="system"/>
|
|
||||||
<tabViewItems>
|
|
||||||
<tabViewItem label="Albums" identifier="" id="XgS-cX-SDH">
|
|
||||||
<view key="view" id="hB7-hN-SbB">
|
|
||||||
<rect key="frame" x="0.0" y="0.0" width="478" height="558"/>
|
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
||||||
<subviews>
|
|
||||||
<containerView translatesAutoresizingMaskIntoConstraints="NO" id="moE-bb-Zvg">
|
|
||||||
<rect key="frame" x="-3" y="-3" width="481" height="561"/>
|
|
||||||
<connections>
|
|
||||||
<segue destination="gPn-fP-LFc" kind="embed" id="2iB-9y-I9h"/>
|
|
||||||
</connections>
|
|
||||||
</containerView>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstItem="moE-bb-Zvg" firstAttribute="top" secondItem="hB7-hN-SbB" secondAttribute="top" id="DUI-jy-8D7"/>
|
|
||||||
<constraint firstItem="moE-bb-Zvg" firstAttribute="leading" secondItem="hB7-hN-SbB" secondAttribute="leading" constant="-3" id="dCS-Kx-2UP"/>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="moE-bb-Zvg" secondAttribute="trailing" id="qey-4e-xfu"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="moE-bb-Zvg" secondAttribute="bottom" constant="-3" id="ziA-Xh-dlz"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
</tabViewItem>
|
|
||||||
</tabViewItems>
|
|
||||||
</tabView>
|
|
||||||
</subviews>
|
|
||||||
<constraints>
|
|
||||||
<constraint firstAttribute="trailing" secondItem="ARv-cj-xlz" secondAttribute="trailing" id="nXk-bi-ua4"/>
|
|
||||||
<constraint firstAttribute="bottom" secondItem="ARv-cj-xlz" secondAttribute="bottom" id="nzf-Jw-Bpk"/>
|
|
||||||
<constraint firstItem="ARv-cj-xlz" firstAttribute="top" secondItem="BRY-0R-F3u" secondAttribute="top" id="v6W-0L-kQ1"/>
|
|
||||||
<constraint firstItem="ARv-cj-xlz" firstAttribute="leading" secondItem="BRY-0R-F3u" secondAttribute="leading" id="w2Z-xv-Fwz"/>
|
|
||||||
</constraints>
|
|
||||||
</view>
|
|
||||||
</viewController>
|
|
||||||
</objects>
|
|
||||||
<point key="canvasLocation" x="1436" y="238"/>
|
|
||||||
</scene>
|
|
||||||
<!--General-->
|
<!--General-->
|
||||||
<scene sceneID="xTC-Y5-Agk">
|
<scene sceneID="xTC-Y5-Agk">
|
||||||
<objects>
|
<objects>
|
||||||
@ -912,7 +923,7 @@
|
|||||||
</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"/>
|
||||||
</objects>
|
</objects>
|
||||||
<point key="canvasLocation" x="2038" y="87"/>
|
<point key="canvasLocation" x="1485" y="182"/>
|
||||||
</scene>
|
</scene>
|
||||||
</scenes>
|
</scenes>
|
||||||
<resources>
|
<resources>
|
||||||
|
|||||||
@ -38,13 +38,14 @@ class WindowController: NSWindowController {
|
|||||||
|
|
||||||
App.store.subscribe(self) {
|
App.store.subscribe(self) {
|
||||||
$0.select {
|
$0.select {
|
||||||
($0.playerState, $0.uiState)
|
($0.serverState, $0.playerState, $0.uiState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
App.store.dispatch(MainWindowDidOpenAction())
|
App.store.dispatch(MainWindowDidOpenAction())
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self, selector: #selector(willDisconnect), name: .willDisconnect, object: nil)
|
NotificationCenter.default.addObserver(self, selector: #selector(willDisconnect), name: .willDisconnect, object: nil)
|
||||||
|
NotificationCenter.default.addObserver(self, selector: #selector(reportError), name: .didRaiseError, object: nil)
|
||||||
|
|
||||||
trackProgress.font = .timerFont
|
trackProgress.font = .timerFont
|
||||||
trackRemaining.font = .timerFont
|
trackRemaining.font = .timerFont
|
||||||
@ -76,9 +77,18 @@ class WindowController: NSWindowController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setShuffleRepeatState(_ state: PlayerState) {
|
func setShuffleRepeatState(
|
||||||
shuffleState.state = state.shuffleState ? .on : .off
|
_ serverState: ServerState,
|
||||||
repeatState.state = state.repeatState ? .on : .off
|
_ playerState: PlayerState
|
||||||
|
) {
|
||||||
|
shuffleState.isEnabled = serverState.connected
|
||||||
|
repeatState.isEnabled = serverState.connected
|
||||||
|
shuffleState.state = playerState.shuffleState ? .on : .off
|
||||||
|
repeatState.state = playerState.repeatState ? .on : .off
|
||||||
|
}
|
||||||
|
|
||||||
|
func setSearchState(_ serverState: ServerState) {
|
||||||
|
searchQuery.isEnabled = serverState.connected
|
||||||
}
|
}
|
||||||
|
|
||||||
func setTrackProgressControls(_ playerState: PlayerState) {
|
func setTrackProgressControls(_ playerState: PlayerState) {
|
||||||
@ -144,10 +154,56 @@ class WindowController: NSWindowController {
|
|||||||
|
|
||||||
@objc func willDisconnect() {
|
@objc func willDisconnect() {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
App.store.dispatch(SetSearchQuery(searchQuery: ""))
|
App.store.dispatch(ResetStatusAction())
|
||||||
self.searchQuery.stringValue = ""
|
self.searchQuery.stringValue = ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc func reportError(_ notification: NSNotification) {
|
||||||
|
guard let error = notification.object as? MPDClient.MPDError
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
guard let window = NSApplication.shared.mainWindow ?? self.window
|
||||||
|
else { return }
|
||||||
|
|
||||||
|
let alert = NSAlert(error: error)
|
||||||
|
alert.messageText = error.message
|
||||||
|
|
||||||
|
alert.alertStyle = error.recovered ? .warning : .critical
|
||||||
|
|
||||||
|
print(error.mpdError)
|
||||||
|
|
||||||
|
switch error.mpdError {
|
||||||
|
case MPD_ERROR_MALFORMED,
|
||||||
|
MPD_ERROR_ARGUMENT:
|
||||||
|
alert.informativeText = "Please check the mpd log for more details."
|
||||||
|
case MPD_ERROR_SYSTEM,
|
||||||
|
MPD_ERROR_TIMEOUT:
|
||||||
|
alert.informativeText = "Is the mpd server running?"
|
||||||
|
case MPD_ERROR_RESOLVER:
|
||||||
|
alert.informativeText = "Check your network connection."
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !error.recovered {
|
||||||
|
alert.addButton(withTitle: "Reconnect")
|
||||||
|
alert.addButton(withTitle: "Dismiss")
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.beginSheetModal(for: window) { response in
|
||||||
|
switch response {
|
||||||
|
case .alertFirstButtonReturn:
|
||||||
|
if !error.recovered {
|
||||||
|
App.mpdServerController.connect()
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Refactor this using a gesture recognizer
|
// TODO: Refactor this using a gesture recognizer
|
||||||
@IBAction func changeTrackProgress(_ sender: NSSlider) {
|
@IBAction func changeTrackProgress(_ sender: NSSlider) {
|
||||||
@ -224,12 +280,15 @@ extension WindowController: NSWindowDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extension WindowController: StoreSubscriber {
|
extension WindowController: StoreSubscriber {
|
||||||
typealias StoreSubscriberStateType = (playerState: PlayerState, uiState: UIState)
|
typealias StoreSubscriberStateType = (
|
||||||
|
serverState: ServerState, playerState: PlayerState, uiState: UIState
|
||||||
|
)
|
||||||
|
|
||||||
func newState(state: StoreSubscriberStateType) {
|
func newState(state: StoreSubscriberStateType) {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.setTransportControlState(state.playerState)
|
self.setTransportControlState(state.playerState)
|
||||||
self.setShuffleRepeatState(state.playerState)
|
self.setShuffleRepeatState(state.serverState, state.playerState)
|
||||||
|
self.setSearchState(state.serverState)
|
||||||
self.setTrackProgressControls(state.playerState)
|
self.setTrackProgressControls(state.playerState)
|
||||||
self.setDatabaseUpdatingIndicator(state.uiState)
|
self.setDatabaseUpdatingIndicator(state.uiState)
|
||||||
self.setVolumeControlIcon(state.playerState)
|
self.setVolumeControlIcon(state.playerState)
|
||||||
|
|||||||
@ -13,6 +13,8 @@ extension MPDClient {
|
|||||||
command: MPDCommand,
|
command: MPDCommand,
|
||||||
userData: Dictionary<String, Any> = [:]
|
userData: Dictionary<String, Any> = [:]
|
||||||
) {
|
) {
|
||||||
|
guard command == .connect || isConnected else { return }
|
||||||
|
|
||||||
switch command {
|
switch command {
|
||||||
|
|
||||||
case .connect:
|
case .connect:
|
||||||
@ -157,7 +159,9 @@ extension MPDClient {
|
|||||||
let commandOperation = BlockOperation() { [unowned self] in
|
let commandOperation = BlockOperation() { [unowned self] in
|
||||||
self.sendCommand(command: command, userData: userData)
|
self.sendCommand(command: command, userData: userData)
|
||||||
|
|
||||||
self.idle(forceIdle)
|
if self.checkError() {
|
||||||
|
self.idle(forceIdle)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandOperation.queuePriority = priority
|
commandOperation.queuePriority = priority
|
||||||
|
|||||||
@ -11,16 +11,19 @@ import mpdclient
|
|||||||
|
|
||||||
extension MPDClient {
|
extension MPDClient {
|
||||||
func createConnection(host: String, port: Int) {
|
func createConnection(host: String, port: Int) {
|
||||||
guard let connection = mpd_connection_new(host, UInt32(port), 10000),
|
connection = mpd_connection_new(host, UInt32(port), 10000)
|
||||||
mpd_connection_get_error(connection) == MPD_ERROR_SUCCESS
|
let error = mpd_connection_get_error(connection)
|
||||||
else { return }
|
|
||||||
|
guard error == MPD_ERROR_SUCCESS else {
|
||||||
|
_ = handleError(mpdError: error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
self.isConnected = true
|
self.isConnected = true
|
||||||
|
|
||||||
guard let status = mpd_run_status(connection)
|
guard let status = mpd_run_status(connection)
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
self.connection = connection
|
|
||||||
self.status = MPDStatus(status)
|
self.status = MPDStatus(status)
|
||||||
|
|
||||||
delegate?.didConnect(mpdClient: self)
|
delegate?.didConnect(mpdClient: self)
|
||||||
@ -50,4 +53,10 @@ extension MPDClient {
|
|||||||
func disconnect() {
|
func disconnect() {
|
||||||
enqueueCommand(command: .disconnect)
|
enqueueCommand(command: .disconnect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resetConnection() {
|
||||||
|
delegate?.willDisconnect(mpdClient: self)
|
||||||
|
mpd_connection_free(connection)
|
||||||
|
self.isConnected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,38 @@ import Foundation
|
|||||||
import mpdclient
|
import mpdclient
|
||||||
|
|
||||||
extension MPDClient {
|
extension MPDClient {
|
||||||
|
func checkError() -> Bool {
|
||||||
|
let error = mpd_connection_get_error(connection)
|
||||||
|
|
||||||
|
if error != MPD_ERROR_SUCCESS {
|
||||||
|
return handleError(mpdError: error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleError(mpdError: mpd_error) -> Bool {
|
||||||
|
guard let errorMessage = mpd_connection_get_error_message(connection)
|
||||||
|
else { return true }
|
||||||
|
|
||||||
|
let message = String(cString: errorMessage)
|
||||||
|
|
||||||
|
let recovered = mpd_connection_clear_error(connection)
|
||||||
|
|
||||||
|
let error = MPDError(
|
||||||
|
mpdError: mpdError,
|
||||||
|
recovered: recovered,
|
||||||
|
message: message
|
||||||
|
)
|
||||||
|
delegate?.didRaiseError(mpdClient: self, error: error)
|
||||||
|
|
||||||
|
if !recovered {
|
||||||
|
resetConnection()
|
||||||
|
}
|
||||||
|
|
||||||
|
return recovered
|
||||||
|
}
|
||||||
|
|
||||||
func getLastErrorMessage() -> String? {
|
func getLastErrorMessage() -> String? {
|
||||||
if mpd_connection_get_error(connection) == MPD_ERROR_SUCCESS {
|
if mpd_connection_get_error(connection) == MPD_ERROR_SUCCESS {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import mpdclient
|
|||||||
|
|
||||||
extension MPDClient {
|
extension MPDClient {
|
||||||
func noIdle() {
|
func noIdle() {
|
||||||
|
guard isConnected else { return }
|
||||||
|
|
||||||
do {
|
do {
|
||||||
idleLock.lock()
|
idleLock.lock()
|
||||||
defer { idleLock.unlock() }
|
defer { idleLock.unlock() }
|
||||||
@ -22,6 +24,8 @@ extension MPDClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func idle(_ force: Bool = false) {
|
func idle(_ force: Bool = false) {
|
||||||
|
guard isConnected else { return }
|
||||||
|
|
||||||
let shouldIdle: Bool
|
let shouldIdle: Bool
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -50,8 +54,8 @@ extension MPDClient {
|
|||||||
wasIdle = isIdle
|
wasIdle = isIdle
|
||||||
isIdle = false
|
isIdle = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if wasIdle {
|
if checkError() && wasIdle {
|
||||||
if mpdIdle.contains(.database) {
|
if mpdIdle.contains(.database) {
|
||||||
self.fetchAllAlbums()
|
self.fetchAllAlbums()
|
||||||
}
|
}
|
||||||
|
|||||||
18
Persephone/MPDClient/Models/MPDError.swift
Normal file
18
Persephone/MPDClient/Models/MPDError.swift
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
//
|
||||||
|
// MPDError.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2/23/20.
|
||||||
|
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import mpdclient
|
||||||
|
|
||||||
|
extension MPDClient {
|
||||||
|
struct MPDError: Error {
|
||||||
|
let mpdError: mpd_error
|
||||||
|
let recovered: Bool
|
||||||
|
let message: String
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,8 @@ import Foundation
|
|||||||
protocol MPDClientDelegate {
|
protocol MPDClientDelegate {
|
||||||
func didConnect(mpdClient: MPDClient)
|
func didConnect(mpdClient: MPDClient)
|
||||||
func willDisconnect(mpdClient: MPDClient)
|
func willDisconnect(mpdClient: MPDClient)
|
||||||
|
|
||||||
|
func didRaiseError(mpdClient: MPDClient, error: MPDClient.MPDError)
|
||||||
|
|
||||||
func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus)
|
func didUpdateStatus(mpdClient: MPDClient, status: MPDClient.MPDStatus)
|
||||||
|
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import AppKit
|
|
||||||
import ReSwift
|
import ReSwift
|
||||||
|
|
||||||
struct UpdateCurrentSongAction: Action {
|
struct UpdateCurrentSongAction: Action {
|
||||||
@ -17,6 +16,8 @@ struct UpdateElapsedTimeAction: Action {
|
|||||||
var elapsedTimeMs: UInt = 0
|
var elapsedTimeMs: UInt = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ResetStatusAction: Action {}
|
||||||
|
|
||||||
struct UpdateStatusAction: Action {
|
struct UpdateStatusAction: Action {
|
||||||
var status: MPDClient.MPDStatus
|
var status: MPDClient.MPDStatus
|
||||||
}
|
}
|
||||||
|
|||||||
13
Persephone/State/Actions/ServerActions.swift
Normal file
13
Persephone/State/Actions/ServerActions.swift
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// ServerActions.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2/26/20.
|
||||||
|
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
struct UpdateConnectedState: Action {
|
||||||
|
var connected: Bool
|
||||||
|
}
|
||||||
@ -9,6 +9,7 @@
|
|||||||
import ReSwift
|
import ReSwift
|
||||||
|
|
||||||
struct AppState: StateType {
|
struct AppState: StateType {
|
||||||
|
var serverState = ServerState()
|
||||||
var playerState = PlayerState()
|
var playerState = PlayerState()
|
||||||
var queueState = QueueState()
|
var queueState = QueueState()
|
||||||
var albumListState = AlbumListState()
|
var albumListState = AlbumListState()
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
// Copyright © 2019 Dan Barber. All rights reserved.
|
// Copyright © 2019 Dan Barber. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
import AppKit
|
|
||||||
import ReSwift
|
import ReSwift
|
||||||
|
|
||||||
struct PlayerState: StateType {
|
struct PlayerState: StateType {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import ReSwift
|
|||||||
|
|
||||||
func appReducer(action: Action, state: AppState?) -> AppState {
|
func appReducer(action: Action, state: AppState?) -> AppState {
|
||||||
return AppState(
|
return AppState(
|
||||||
|
serverState: serverReducer(action: action, state: state?.serverState),
|
||||||
playerState: playerReducer(action: action, state: state?.playerState),
|
playerState: playerReducer(action: action, state: state?.playerState),
|
||||||
queueState: queueReducer(action: action, state: state?.queueState),
|
queueState: queueReducer(action: action, state: state?.queueState),
|
||||||
albumListState: albumListReducer(action: action, state: state?.albumListState),
|
albumListState: albumListReducer(action: action, state: state?.albumListState),
|
||||||
|
|||||||
@ -13,6 +13,14 @@ func playerReducer(action: Action, state: PlayerState?) -> PlayerState {
|
|||||||
var state = state ?? PlayerState()
|
var state = state ?? PlayerState()
|
||||||
|
|
||||||
switch action {
|
switch action {
|
||||||
|
case is ResetStatusAction:
|
||||||
|
state.state = .unknown
|
||||||
|
state.totalTime = 0
|
||||||
|
state.elapsedTimeMs = 0
|
||||||
|
state.shuffleState = false
|
||||||
|
state.repeatState = false
|
||||||
|
state.volume = -1
|
||||||
|
|
||||||
case let action as UpdateStatusAction:
|
case let action as UpdateStatusAction:
|
||||||
state.status = action.status
|
state.status = action.status
|
||||||
state.state = action.status.state
|
state.state = action.status.state
|
||||||
|
|||||||
23
Persephone/State/Reducers/ServerReducer.swift
Normal file
23
Persephone/State/Reducers/ServerReducer.swift
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
//
|
||||||
|
// ServerReducer.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2/26/20.
|
||||||
|
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
func serverReducer(action: Action, state: ServerState?) -> ServerState {
|
||||||
|
var state = state ?? ServerState()
|
||||||
|
|
||||||
|
switch action {
|
||||||
|
case let action as UpdateConnectedState:
|
||||||
|
state.connected = action.connected
|
||||||
|
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return state
|
||||||
|
}
|
||||||
13
Persephone/State/ServerState.swift
Normal file
13
Persephone/State/ServerState.swift
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
//
|
||||||
|
// ServerState.swift
|
||||||
|
// Persephone
|
||||||
|
//
|
||||||
|
// Created by Daniel Barber on 2/26/20.
|
||||||
|
// Copyright © 2020 Dan Barber. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import ReSwift
|
||||||
|
|
||||||
|
struct ServerState: StateType {
|
||||||
|
var connected: Bool = false
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user