Drag and drop that does not break playback

Reordering a playlist while it is playing is where most software breaks. Getting it right means the playing row can move without the audio noticing.

Dragging a song into a playlist is easy. Dragging one into a playlist that is currently on the air is where implementations fall apart.

Seeing where it will land

Two visual aids run during a drag. A preview adorner renders a semi-transparent image of what you are dragging, following the cursor. A drop insertion caret — a 3-pixel accent line — marks the exact row boundary where the item will land.

Drop on a row and it inserts above that row. Drop on empty space and it appends. There is no ambiguity about where a drop will go, which matters when the cost of guessing wrong is audible.

The playing-row problem

Here is the case that separates careful software from the rest.

Insert a track above the currently playing row and every index below shifts by one. Naively, the "now playing" pointer now indicates a different file — so auto-advance queues the wrong next track and the row highlight lands on the wrong line.

PlayOnRadio increments the internal now-playing index on that insert, so the cursor keeps pointing at the same physical file. Playback continues, the highlight stays put, and the crossfade still queues the correct next item.

The playing row itself can also be dragged and reordered. Playback is not restarted; the internal cursor follows the same file to its new position.

A small interaction fix

One detail worth calling out because it is invisible when done right. When the context menu is open and you click on the playlist to dismiss it, that click should close the menu — not start a drag.

So the app defers arming drag-and-drop until the left mouse button is released. Clicking away to dismiss behaves like pressing Escape. Once the button is up, dragging works normally again.

Saving without stalling

Routine edits schedule a save three seconds after the last change, so a burst of reordering writes once rather than twenty times. Duplicate states are skipped using a content fingerprint, and the write runs on a background thread.

On exit — or before any discard or replace — the save is flushed synchronously. Debouncing must never mean losing the last edit.

Related reading

Ready to hear it on your own station?

Tell us about your setup and we'll send you a personalised quote.

Request a Quote