anchor.diff:  class _QueuePageState extends State<QueuePage> with SingleTickerProviderStateMixin {
     // Keep a local copy of the queue so we can re-order without waiting for communication with background service
     // Directly reflecting AudioService.queueStream in the UI leads to flicker when finishing a drag and drop
  -  List<MediaItem> queue;
  +  QueueState localState;
   
     @override
     void initState() {
       super.initState();
  -    AudioService.queueStream.listen((newQueue) {
  +    _queueStateStream.listen((newState) {
         setState(() {
  -        queue = newQueue;
  +        localState = newState;
         });
       });
  -    queue = AudioService.queue;
  +    localState = QueueState(AudioService.queue, AudioService.currentMediaItem);
  +    // TODO autoscroll to current song?
     }
   
     @override
  
positive.code:   }
  }
  
  Widget _songWidget(MediaItem mediaItem) {
    final dto.Song song = mediaItem.toSong();
    return ListTile(
      key: Key(mediaItem.id),
      leading: ListThumbnail(song.artwork),
      title: Text(song.formatTitle(), overflow: TextOverflow.ellipsis),
      subtitle: Text(song.formatArtist(), overflow: TextOverflow.ellipsis),
      trailing: Icon(Icons.more_vert),
      dense: true,
    );
  
negative.code:       body: StreamBuilder<List<MediaItem>>(
            stream: AudioService.queueStream,
            builder: (context, snapshot) {
              return ReorderableListView(
                children: localState.queue
                    .map((mediaItem) => _songWidget(context, mediaItem, mediaItem.id == localState.mediaItem.id))
                    .toList(),
                onReorder: (int oldIndex, int newIndex) {
                  final int insertIndex = oldIndex > newIndex ? newIndex : newIndex - 1;
                  localState.queue.insert(insertIndex, localState.queue.removeAt(oldIndex));
                  setState(() {});
                  AudioService.customAction(customActionMoveQueueItem, [oldIndex, newIndex]);
                },
  