Skip to content

Commit

Permalink
Remove legacy pasteboard writer for tracklist
Browse files Browse the repository at this point in the history
Also refactoring:

- You're now able to drop between tracklist and playlist. They now use
  very similar logic for determining if it's reordering or inserting.
- Fix the drag image handler for table views without headers.
- Remove the tracklist indices pasteboard type.

Unfortunately there's some very similar code in both controllers,
because move does not return an IndexSet. This should be refactored.
  • Loading branch information
NattyNarwhal committed Jun 21, 2024
1 parent 7f828e1 commit 4b705f8
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 36 deletions.
2 changes: 0 additions & 2 deletions Submariner/PasteboardType+Submariner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ extension NSPasteboard.PasteboardType {
///
/// Usually multiple of these will exist on a pasteboard.
static let libraryItem = NSPasteboard.PasteboardType(rawValue: "com.submarinerapp.item-url-string")
/// Tracks from the tracklist, represented as an index set.
static let tracklistIndices = NSPasteboard.PasteboardType(rawValue: "com.submarinerapp.tracklist-indices")
/// The index of a row, as a raw integer in a Data wrapper.
static let rowIndex = NSPasteboard.PasteboardType(rawValue: "com.submarinerapp.row-index")
}
5 changes: 5 additions & 0 deletions Submariner/SBPlaylist.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ public class SBPlaylist: SBResource {
trackIDs?.append(contentsOf: additionalIDs)
}

func add(tracks: [SBTrack], at row: Int) {
let additionalIDs = tracks.map { $0.objectID.uriRepresentation() }
trackIDs?.insert(contentsOf: additionalIDs, at: row)
}

func remove(indices: IndexSet) {
trackIDs?.remove(atOffsets: indices)
}
Expand Down
40 changes: 29 additions & 11 deletions Submariner/SBPlaylistController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -142,27 +142,45 @@ import Cocoa
}

func tableView(_ tableView: NSTableView, validateDrop info: any NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
// internal drop track
if row != -1 && dropOperation == .above && info.draggingPasteboard.libraryItems() != nil {
return .move
guard row != -1 && dropOperation == .above else {
return []
}

if let sourceTable = info.draggingSource as? SBTableView, sourceTable == tracksTableView {
return .move
} else if info.draggingPasteboard.libraryItems() != nil {
return .copy
}
return []
}

func tableView(_ tableView: NSTableView, acceptDrop info: any NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
if info.draggingSourceOperationMask.contains(.move) {
// XXX: For some reason, draggingSourceOperationMask has all bits set?
if let sourceTable = info.draggingSource as? SBTableView, sourceTable == tracksTableView {
let indices = info.draggingPasteboard.rowIndices()

playlist.moveTracks(fromOffsets: indices, toOffset: row)

tracksController.rearrangeObjects()
tracksTableView.reloadData()

// submit changes to server, this uses createPlaylist behind the scenes since we can reorder with it
if let server = playlist.server, let playlistID = playlist.itemId {
server.updatePlaylist(ID: playlistID, tracks: tracks)
// change selection to match new indices, since Array.move doesn't return them
var newRow = row
for index in indices {
if index < newRow {
newRow -= 1
}
}
let lastRow = newRow + indices.count - 1
let newRange = newRow...lastRow
let newIndexSet = IndexSet(integersIn: newRange)
tracksTableView.selectRowIndexes(newIndexSet, byExtendingSelection: false)
} else if let tracks = info.draggingPasteboard.libraryItems(managedObjectContext: self.managedObjectContext) {
playlist.add(tracks: tracks, at: row)
}

tracksController.rearrangeObjects()
tracksTableView.reloadData()

// submit changes to server, this uses createPlaylist behind the scenes since we can reorder with it
if let server = playlist.server, let playlistID = playlist.itemId {
server.updatePlaylist(ID: playlistID, tracks: tracks)
}
return true
}
Expand Down
4 changes: 3 additions & 1 deletion Submariner/SBTableView+DragImage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ extension SBTableView {
func setDragImage(of item: NSDraggingItem, for row: Int, at screenPoint: NSPoint) {
// Find the left edge of the row by converting the header view origin to
// the table view coordinate
var headerOrigin = convert(headerView?.frame.origin ?? NSZeroPoint, fromDescendant: headerView)
// If the header view doesn't exist (i.e. tracklist), let's use our superview,
// since we can't use ourself.
var headerOrigin = convert(headerView?.frame.origin ?? NSZeroPoint, fromDescendant: headerView ?? self.superview)

// Generate the drag image from the current row with all the columns
var p: NSPoint = .zero
Expand Down
35 changes: 13 additions & 22 deletions Submariner/SBTracklistController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import Cocoa

title = "Tracklist"

playlistTableView.registerForDraggedTypes([.libraryItems, .libraryItem, .tracklistIndices])
playlistTableView.registerForDraggedTypes([.libraryItems, .libraryItem])

notificationObserver = NotificationCenter.default.addObserver(forName: .SBPlayerPlaylistUpdated,
object: nil,
Expand Down Expand Up @@ -126,42 +126,33 @@ import Cocoa

// #MARK: - NSTableView Delegate

// FIXME: Replace with tableView:pasteboardWriterForRow:?
func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) -> Bool {
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: rowIndexes, requiringSecureCoding: true)

pboard.declareTypes([.tracklistIndices], owner: self)
pboard.setData(data, forType: .tracklistIndices)

return true
} catch {
return false
func tableView(_ tableView: NSTableView, pasteboardWriterForRow row: Int) -> (any NSPasteboardWriting)? {
if tableView == playlistTableView {
let track = SBPlayer.sharedInstance().playlist[row]
return SBLibraryItemPasteboardWriter(item: track, index: row)
}
return nil
}

func tableView(_ tableView: NSTableView, validateDrop info: NSDraggingInfo, proposedRow row: Int, proposedDropOperation dropOperation: NSTableView.DropOperation) -> NSDragOperation {
guard row != -1 && dropOperation == .above else {
return []
}

if let types = info.draggingPasteboard.types {
if types.contains(.tracklistIndices) {
return .move
} else if types.contains(.libraryItems) || types.contains(.libraryItem) { // for cursor
return .copy
}
if let sourceTable = info.draggingSource as? SBTableView, sourceTable == playlistTableView {
return .move
} else if info.draggingPasteboard.libraryItems() != nil {
return .copy
}

return []
}

static let allowedClasses = [NSIndexSet.self, NSArray.self, NSURL.self]

func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableView.DropOperation) -> Bool {
if let data = info.draggingPasteboard.data(forType: .tracklistIndices),
let rowIndexes = try? NSKeyedUnarchiver.unarchivedObject(ofClasses: SBTracklistController.allowedClasses,
from: data) as? IndexSet {
// XXX: For some reason, draggingSourceOperationMask has all bits set?
if let sourceTable = info.draggingSource as? SBTableView, sourceTable == playlistTableView {
let rowIndexes = info.draggingPasteboard.rowIndices()
SBPlayer.sharedInstance().move(trackIndexSet: rowIndexes, index: row)

// change selection to match new indices, since Array.move doesn't return them
Expand Down

0 comments on commit 4b705f8

Please sign in to comment.