import 'package:collection/collection.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/track.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; class ProxyPlaylist { final Set tracks; final Set collections; final int? active; ProxyPlaylist(this.tracks, [this.active, this.collections = const {}]); factory ProxyPlaylist.fromJson( Map json, ) { return ProxyPlaylist( List.castFrom>( json['tracks'] ?? >[], ).map((t) => _makeAppropriateTrack(t)).toSet(), json['active'] as int?, json['collections'] == null ? {} : (json['collections'] as List).toSet().cast(), ); } factory ProxyPlaylist.fromJsonRaw(Map json) => ProxyPlaylist( json['tracks'] == null ? {} : (json['tracks'] as List).map((t) => Track.fromJson(t)).toSet(), json['active'] as int?, json['collections'] == null ? {} : (json['collections'] as List).toSet().cast(), ); Track? get activeTrack => active == null || active == -1 ? null : tracks.elementAtOrNull(active!); bool get isFetching => activeTrack == null && tracks.isNotEmpty; bool containsCollection(String collection) { return collections.contains(collection); } bool containsTrack(TrackSimple track) { return tracks.firstWhereOrNull((element) { if (element is LocalTrack && track is LocalTrack) { return element.path == track.path; } return element.id == track.id; }) != null; } bool containsTracks(Iterable tracks) { if (tracks.isEmpty) return false; return tracks.every(containsTrack); } static Track _makeAppropriateTrack(Map track) { if (track.containsKey("path")) { return LocalTrack.fromJson(track); } else { return Track.fromJson(track); } } /// To make sure proper instance method is used for JSON serialization /// Otherwise default super.toJson() is used static Map _makeAppropriateTrackJson(Track track) { return switch (track.runtimeType) { LocalTrack() => (track as LocalTrack).toJson(), SourcedTrack() => (track as SourcedTrack).toJson(), _ => track.toJson(), }; } Map toJson() { return { 'tracks': tracks.map(_makeAppropriateTrackJson).toList(), 'active': active, 'collections': collections.toList(), }; } ProxyPlaylist copyWith({ Set? tracks, int? active, Set? collections, }) { return ProxyPlaylist( tracks ?? this.tracks, active ?? this.active, collections ?? this.collections, ); } }