import 'package:flutter/foundation.dart'; import '../../../core/contracts/library.dart'; import '../session/playback_target.dart'; import 'playlist.dart'; @immutable class CrossServerPlaylistEntry { const CrossServerPlaylistEntry({ required this.serverId, required this.serverName, required this.serverUrl, required this.token, required this.userId, required this.itemId, this.label = '', this.preloadedItem, }); final String serverId; final String serverName; final String serverUrl; final String token; final String userId; final String itemId; final String label; final EmbyRawItem? preloadedItem; PlaybackServerIdentity toIdentity() => PlaybackServerIdentity( serverId: serverId, baseUrl: serverUrl, token: token, userId: userId, serverName: serverName, ); @override bool operator ==(Object other) => other is CrossServerPlaylistEntry && other.serverId == serverId && other.serverName == serverName && other.serverUrl == serverUrl && other.token == token && other.userId == userId && other.itemId == itemId && other.label == label && other.preloadedItem == preloadedItem; @override int get hashCode => Object.hash( serverId, serverName, serverUrl, token, userId, itemId, label, preloadedItem, ); } class CrossServerPlaylist implements Playlist { CrossServerPlaylist({ required List sequence, required int initialIndex, bool initialPlayFromStart = false, }) : assert(sequence.isNotEmpty, 'cross-server sequence cannot be empty'), assert(initialIndex >= 0 && initialIndex < sequence.length), _entries = List.unmodifiable(sequence), _currentIndex = ValueNotifier(initialIndex), _current = ValueNotifier( _toItem(sequence[initialIndex], playFromStart: initialPlayFromStart), ); final List _entries; final ValueNotifier _current; final ValueNotifier _currentIndex; bool _disposed = false; @override ValueListenable get current => _current; @override ValueListenable get currentIndex => _currentIndex; @override int get length => _entries.length; @override bool get hasNext => _currentIndex.value < _entries.length - 1; @override bool get hasPrev => _currentIndex.value > 0; @override Future next() => goTo(_currentIndex.value + 1); @override Future prev() => goTo(_currentIndex.value - 1); @override Future goTo(int index) async { if (_disposed) return; if (index < 0 || index >= _entries.length) return; if (index == _currentIndex.value) return; final target = _entries[index]; _currentIndex.value = index; _current.value = _toItem(target); } @override Future goToItemId(String itemId) async { final idx = _entries.indexWhere((e) => e.itemId == itemId); if (idx < 0) return; await goTo(idx); } static PlaylistItem _toItem( CrossServerPlaylistEntry e, { bool playFromStart = false, }) => PlaylistItem( itemId: e.itemId, serverId: e.serverId, serverIdentity: e.toIdentity(), displayLabel: e.label, playFromStart: playFromStart, preloadedItem: e.preloadedItem, ); @override void dispose() { _disposed = true; _current.dispose(); _currentIndex.dispose(); } }