From f687e89f9dce7280c32ae180165fcc6f0778b8b3 Mon Sep 17 00:00:00 2001 From: Daniel Barber Date: Fri, 21 Jun 2019 14:18:41 -0400 Subject: [PATCH] Drag songs with custom drag image --- Persephone.xcodeproj/project.pbxproj | 32 +++++++-- .../Controllers/QueueViewController.swift | 27 +------ .../DataSources/AlbumTracksDataSource.swift | 40 ++++++++++- Persephone/DataSources/QueueDataSource.swift | 72 +++++++++++++------ Persephone/Extensions/NSView.swift | 17 +++++ Persephone/Models/DraggedSong.swift | 13 ++++ Persephone/Models/DraggedSongType.swift | 50 +++++++++++++ .../Resources/Base.lproj/Main.storyboard | 5 +- Persephone/Resources/DraggedSongView.xib | 52 ++++++++++++++ Persephone/Views/DraggedSongView.swift | 31 ++++++++ 10 files changed, 282 insertions(+), 57 deletions(-) create mode 100644 Persephone/Extensions/NSView.swift create mode 100644 Persephone/Models/DraggedSong.swift create mode 100644 Persephone/Models/DraggedSongType.swift create mode 100644 Persephone/Resources/DraggedSongView.xib create mode 100644 Persephone/Views/DraggedSongView.swift diff --git a/Persephone.xcodeproj/project.pbxproj b/Persephone.xcodeproj/project.pbxproj index 829a9f2..9dcaa2b 100644 --- a/Persephone.xcodeproj/project.pbxproj +++ b/Persephone.xcodeproj/project.pbxproj @@ -57,6 +57,8 @@ 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 */; }; @@ -72,6 +74,9 @@ 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 */; }; @@ -277,6 +282,8 @@ E450AD9E2229B9BC0091BED3 /* PersephoneBridgingHeader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PersephoneBridgingHeader.h; sourceTree = ""; }; E450AD9F2229E7C90091BED3 /* PMKFoundation.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PMKFoundation.framework.dSYM; path = Carthage/Build/Mac/PMKFoundation.framework.dSYM; sourceTree = ""; }; E450ADA02229E7C90091BED3 /* PMKFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PMKFoundation.framework; path = Carthage/Build/Mac/PMKFoundation.framework; sourceTree = ""; }; + E451E36A22BD214D008BE9B2 /* DraggedSongType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggedSongType.swift; sourceTree = ""; }; + E451E36C22BD23DB008BE9B2 /* DraggedSong.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggedSong.swift; sourceTree = ""; }; E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDetailSongRowView.swift; sourceTree = ""; }; E45962C52241A78500FC1A1E /* MPDCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDCommand.swift; sourceTree = ""; }; E45E4FD722515D87004B537F /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = SOURCE_ROOT; }; @@ -293,6 +300,9 @@ E47E2FDC2220A6D100F747E6 /* Time.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Time.swift; sourceTree = ""; }; E47E2FE42220AA0700F747E6 /* AlbumViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlbumViewLayout.swift; sourceTree = ""; }; E489E39822B85D0400CA8CBD /* NSPasteboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSPasteboard.swift; sourceTree = ""; }; + E489E39C22B9CF0000CA8CBD /* NSView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSView.swift; sourceTree = ""; }; + E489E3A222B9D31800CA8CBD /* DraggedSongView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DraggedSongView.swift; sourceTree = ""; }; + E489E3A322B9D31800CA8CBD /* DraggedSongView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DraggedSongView.xib; sourceTree = ""; }; E4928E0A2218D62A001D4BEA /* CGColor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CGColor.swift; sourceTree = ""; }; E4A3A6A022A457B600EA2C40 /* AlbumDetailSongListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumDetailSongListView.swift; sourceTree = ""; }; E4A642D922090CBE00067D21 /* MPDStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPDStatus.swift; sourceTree = ""; }; @@ -449,6 +459,7 @@ E435E3E3221CD75D00184CFC /* NSImage.swift */, E408D3B8220DE98F0006D9BE /* NSUserInterfaceItemIdentifier.swift */, E489E39822B85D0400CA8CBD /* NSPasteboard.swift */, + E489E39C22B9CF0000CA8CBD /* NSView.swift */, ); path = Extensions; sourceTree = ""; @@ -473,12 +484,13 @@ E408D3C3220E138B0006D9BE /* Views */ = { isa = PBXGroup; children = ( - E47E2FD62220720300F747E6 /* AlbumItemView.swift */, - E47E2FD222205D2500F747E6 /* MainWindow.swift */, - E4B11BB7227538FA0075461B /* CurrentCoverArtView.swift */, - E423563F228623D2001216D6 /* QueueSongTitleView.swift */, - E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */, E4A3A6A022A457B600EA2C40 /* AlbumDetailSongListView.swift */, + E45878372296173C00586A1C /* AlbumDetailSongRowView.swift */, + E47E2FD62220720300F747E6 /* AlbumItemView.swift */, + E4B11BB7227538FA0075461B /* CurrentCoverArtView.swift */, + E489E3A222B9D31800CA8CBD /* DraggedSongView.swift */, + E47E2FD222205D2500F747E6 /* MainWindow.swift */, + E423563F228623D2001216D6 /* QueueSongTitleView.swift */, E4120D6B22AD8139004CB1F8 /* QueueView.swift */, ); path = Views; @@ -709,9 +721,10 @@ E4D1B598220BA3C90026F233 /* Resources */ = { isa = PBXGroup; children = ( - E40786212110CE70006887B1 /* Main.storyboard */, E43B67A922909793007DCF55 /* AlbumDetailView.xib */, E408D3C9220E341D0006D9BE /* AlbumViewItem.xib */, + E489E3A322B9D31800CA8CBD /* DraggedSongView.xib */, + E40786212110CE70006887B1 /* Main.storyboard */, ); path = Resources; sourceTree = ""; @@ -736,6 +749,8 @@ E419E2862249B96600216A8C /* Song.swift */, E47E2FDC2220A6D100F747E6 /* Time.swift */, E4B11B72226A6C770075461B /* TrackTimer.swift */, + E451E36A22BD214D008BE9B2 /* DraggedSongType.swift */, + E451E36C22BD23DB008BE9B2 /* DraggedSong.swift */, ); path = Models; sourceTree = ""; @@ -865,6 +880,7 @@ 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 */, @@ -940,6 +956,7 @@ 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 */, @@ -951,6 +968,7 @@ 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 */, @@ -965,6 +983,7 @@ 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 */, @@ -1004,6 +1023,7 @@ E4B11B6A226A4FBC0075461B /* AlbumListState.swift in Sources */, E41E5305223BFB0700173814 /* MPDClient+Error.swift in Sources */, E435E3E2221CD4E200184CFC /* NSFont.swift in Sources */, + E489E39D22B9CF0000CA8CBD /* NSView.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Persephone/Controllers/QueueViewController.swift b/Persephone/Controllers/QueueViewController.swift index 502832d..21e4572 100644 --- a/Persephone/Controllers/QueueViewController.swift +++ b/Persephone/Controllers/QueueViewController.swift @@ -22,6 +22,7 @@ class QueueViewController: NSViewController { $0.select { $0.queueState } } + queueView.dataSource = dataSource queueView.columnAutoresizingStyle = .sequentialColumnAutoresizingStyle queueView.registerForDraggedTypes([.songPasteboardType]) queueView.draggingDestinationFeedbackStyle = .regular @@ -66,32 +67,6 @@ class QueueViewController: NSViewController { } } -extension QueueViewController: NSOutlineViewDataSource { - func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { - return dataSource.outlineView(outlineView, numberOfChildrenOfItem: item) - } - - func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { - return dataSource.outlineView(outlineView, isItemExpandable: item) - } - - func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { - return dataSource.outlineView(outlineView, child: index, ofItem: item) - } - - func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? { - return dataSource.outlineView(outlineView, pasteboardWriterForItem: item) - } - - func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation { - return dataSource.outlineView(outlineView, validateDrop: info, proposedItem: item, proposedChildIndex: index) - } - - func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool { - return dataSource.outlineView(outlineView, acceptDrop: info, item: item, childIndex: index) - } -} - extension QueueViewController: StoreSubscriber { typealias StoreSubscriberStateType = QueueState diff --git a/Persephone/DataSources/AlbumTracksDataSource.swift b/Persephone/DataSources/AlbumTracksDataSource.swift index 3dd9dc7..d751653 100644 --- a/Persephone/DataSources/AlbumTracksDataSource.swift +++ b/Persephone/DataSources/AlbumTracksDataSource.swift @@ -40,11 +40,23 @@ class AlbumTracksDataSource: NSObject, NSTableViewDataSource { } func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> NSPasteboardWriting? { - let item = albumSongs[row] + let albumSongItem = albumSongs[row] + + guard let song = albumSongItem.song + else { return nil } let pasteboardItem = NSPasteboardItem() - pasteboardItem.setPropertyList(["songUri": item.song?.mpdSong.uriString], forType: .songPasteboardType) + let draggedSong = DraggedSong( + type: .albumSongItem(song.mpdSong.uriString), + title: song.title, + artist: song.artist + ) + + let encoder = PropertyListEncoder() + let data = try! encoder.encode(draggedSong) + + pasteboardItem.setData(data, forType: .songPasteboardType) return pasteboardItem } @@ -52,4 +64,28 @@ class AlbumTracksDataSource: NSObject, NSTableViewDataSource { 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 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) + + component.contents = draggedSongView.view.image() + component.frame = NSRect(origin: CGPoint(), size: draggedSongView.view.image().size) + return [component] + } + } + } } diff --git a/Persephone/DataSources/QueueDataSource.swift b/Persephone/DataSources/QueueDataSource.swift index 506df4a..1156240 100644 --- a/Persephone/DataSources/QueueDataSource.swift +++ b/Persephone/DataSources/QueueDataSource.swift @@ -45,7 +45,16 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource { let pasteboardItem = NSPasteboardItem() - pasteboardItem.setPropertyList(["queuePos": queueItem.queuePos], forType: .songPasteboardType) + let draggedSong = DraggedSong( + type: .queueItem(queueItem.queuePos), + title: queueItem.song.title, + artist: queueItem.song.artist + ) + + let encoder = PropertyListEncoder() + let data = try! encoder.encode(draggedSong) + + pasteboardItem.setData(data, forType: .songPasteboardType) return pasteboardItem } @@ -53,51 +62,74 @@ class QueueDataSource: NSObject, NSOutlineViewDataSource { func outlineView(_ outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation { var newQueuePos = index - 1 - guard let draggingTypes = info.draggingPasteboard.types, - draggingTypes.contains(.songPasteboardType) + guard newQueuePos >= 0, + 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 [] } - if let payload = info.draggingPasteboard.propertyList(forType: .songPasteboardType) as? [String: Int], - let queuePos = payload["queuePos"], - newQueuePos >= 0 { - + switch draggedSong.type { + case let .queueItem(queuePos): if newQueuePos > queuePos { newQueuePos -= 1 } guard queuePos != newQueuePos else { return [] } return .move - } else if let payload = info.draggingPasteboard.propertyList(forType: .songPasteboardType) as? [String: String], - let _ = payload["songUri"], - newQueuePos >= 0 { + case .albumSongItem: return .copy } - - return [] } func outlineView(_ outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool { var newQueuePos = index - 1 - if let payload = info.draggingPasteboard.propertyList(forType: .songPasteboardType) as? [String: Int], - let queuePos = payload["queuePos"] { + 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 - } else if let payload = info.draggingPasteboard.propertyList(forType: .songPasteboardType) as? [String: String], - let songUri = payload["songUri"] { - - App.store.dispatch(MPDAddSongToQueue(songUri: songUri, queuePos: newQueuePos)) - + case let .albumSongItem(uri): + App.store.dispatch(MPDAddSongToQueue(songUri: uri, queuePos: newQueuePos)) return true } return false } + + 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) + + component.contents = draggedSongView.view.image() + component.frame = NSRect(origin: CGPoint(), size: draggedSongView.view.image().size) + return [component] + } + } + } + } diff --git a/Persephone/Extensions/NSView.swift b/Persephone/Extensions/NSView.swift new file mode 100644 index 0000000..5a0bfa4 --- /dev/null +++ b/Persephone/Extensions/NSView.swift @@ -0,0 +1,17 @@ +// +// 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 { + let imageRepresentation = bitmapImageRepForCachingDisplay(in: bounds)! + cacheDisplay(in: bounds, to: imageRepresentation) + return NSImage(cgImage: imageRepresentation.cgImage!, size: bounds.size) + } +} diff --git a/Persephone/Models/DraggedSong.swift b/Persephone/Models/DraggedSong.swift new file mode 100644 index 0000000..251d3b5 --- /dev/null +++ b/Persephone/Models/DraggedSong.swift @@ -0,0 +1,13 @@ +// +// 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? +} diff --git a/Persephone/Models/DraggedSongType.swift b/Persephone/Models/DraggedSongType.swift new file mode 100644 index 0000000..3f81fdd --- /dev/null +++ b/Persephone/Models/DraggedSongType.swift @@ -0,0 +1,50 @@ +// +// 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) + } + + } +} diff --git a/Persephone/Resources/Base.lproj/Main.storyboard b/Persephone/Resources/Base.lproj/Main.storyboard index 3263598..0604ec7 100644 --- a/Persephone/Resources/Base.lproj/Main.storyboard +++ b/Persephone/Resources/Base.lproj/Main.storyboard @@ -578,14 +578,14 @@ - + - + @@ -713,7 +713,6 @@ - diff --git a/Persephone/Resources/DraggedSongView.xib b/Persephone/Resources/DraggedSongView.xib new file mode 100644 index 0000000..5b10e05 --- /dev/null +++ b/Persephone/Resources/DraggedSongView.xib @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Persephone/Views/DraggedSongView.swift b/Persephone/Views/DraggedSongView.swift new file mode 100644 index 0000000..e1c24de --- /dev/null +++ b/Persephone/Views/DraggedSongView.swift @@ -0,0 +1,31 @@ +// +// 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! + + 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 + } +}