mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-12-08 16:27:31 +00:00
feat: implement recently played section
This commit is contained in:
parent
db209ac449
commit
ddadb0edc5
@ -2,4 +2,9 @@ targets:
|
||||
$default:
|
||||
sources:
|
||||
exclude:
|
||||
- bin/*.dart
|
||||
- bin/*.dart
|
||||
builders:
|
||||
json_serializable:
|
||||
options:
|
||||
any_map: true
|
||||
explicit_to_json: true
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/extensions/track.dart';
|
||||
import 'package:spotube/models/spotify/home_feed.dart';
|
||||
import 'package:spotube/models/spotify_friends.dart';
|
||||
|
||||
|
||||
@ -81,9 +81,9 @@ class AlbumCard extends HookConsumerWidget {
|
||||
if (isRemoteDevice) {
|
||||
final remotePlayback = ref.read(connectProvider.notifier);
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
WebSocketLoadEventData.album(
|
||||
tracks: fetchedTracks,
|
||||
collectionId: album.id!,
|
||||
collection: album,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
|
||||
32
lib/components/home/sections/recent.dart
Normal file
32
lib/components/home/sections/recent.dart
Normal file
@ -0,0 +1,32 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart';
|
||||
import 'package:spotube/provider/history/recent.dart';
|
||||
import 'package:spotube/provider/history/state.dart';
|
||||
|
||||
class HomeRecentlyPlayedSection extends HookConsumerWidget {
|
||||
const HomeRecentlyPlayedSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, ref) {
|
||||
final history = ref.watch(recentlyPlayedItems);
|
||||
|
||||
if (history.isEmpty) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
return HorizontalPlaybuttonCardView(
|
||||
title: const Text('Recently Played'),
|
||||
items: [
|
||||
for (final item in history)
|
||||
if (item is PlaybackHistoryPlaylist)
|
||||
item.playlist
|
||||
else if (item is PlaybackHistoryAlbum)
|
||||
item.album
|
||||
],
|
||||
hasNextPage: false,
|
||||
isLoadingNextPage: false,
|
||||
onFetchMore: () {},
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -81,9 +81,9 @@ class PlaylistCard extends HookConsumerWidget {
|
||||
if (isRemoteDevice) {
|
||||
final remotePlayback = ref.read(connectProvider.notifier);
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
WebSocketLoadEventData.playlist(
|
||||
tracks: fetchedTracks,
|
||||
collectionId: playlist.id!,
|
||||
collection: playlist,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
|
||||
@ -96,7 +96,7 @@ class HorizontalPlaybuttonCardView<T> extends HookWidget {
|
||||
return switch (item) {
|
||||
PlaylistSimple() =>
|
||||
PlaylistCard(item as PlaylistSimple),
|
||||
AlbumSimple() => AlbumCard(item as Album),
|
||||
AlbumSimple() => AlbumCard(item as AlbumSimple),
|
||||
Artist() => Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12.0),
|
||||
|
||||
@ -17,6 +17,7 @@ import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
|
||||
import 'package:spotube/components/shared/tracks_view/track_view_provider.dart';
|
||||
import 'package:spotube/models/connect/connect.dart';
|
||||
import 'package:spotube/provider/connect/connect.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/utils/service_utils.dart';
|
||||
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
|
||||
@ -28,6 +29,7 @@ class TrackViewBodySection extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, ref) {
|
||||
final playlist = ref.watch(proxyPlaylistProvider);
|
||||
final playlistNotifier = ref.watch(proxyPlaylistProvider.notifier);
|
||||
final historyNotifier = ref.watch(playbackHistoryProvider.notifier);
|
||||
final props = InheritedTrackView.of(context);
|
||||
final trackViewState = ref.watch(trackViewProvider(props.tracks));
|
||||
|
||||
@ -146,11 +148,17 @@ class TrackViewBodySection extends HookConsumerWidget {
|
||||
} else {
|
||||
final tracks = await props.pagination.onFetchAll();
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
tracks: tracks,
|
||||
collectionId: props.collectionId,
|
||||
initialIndex: index,
|
||||
),
|
||||
props.collection is AlbumSimple
|
||||
? WebSocketLoadEventData.album(
|
||||
tracks: tracks,
|
||||
collection: props.collection as AlbumSimple,
|
||||
initialIndex: index,
|
||||
)
|
||||
: WebSocketLoadEventData.playlist(
|
||||
tracks: tracks,
|
||||
collection: props.collection as PlaylistSimple,
|
||||
initialIndex: index,
|
||||
),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
@ -164,6 +172,13 @@ class TrackViewBodySection extends HookConsumerWidget {
|
||||
autoPlay: true,
|
||||
);
|
||||
playlistNotifier.addCollection(props.collectionId);
|
||||
if (props.collection is AlbumSimple) {
|
||||
historyNotifier
|
||||
.addAlbums([props.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier
|
||||
.addPlaylists([props.collection as PlaylistSimple]);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart';
|
||||
import 'package:spotube/components/shared/dialogs/confirm_download_dialog.dart';
|
||||
@ -8,6 +9,7 @@ import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
|
||||
import 'package:spotube/components/shared/tracks_view/track_view_provider.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/provider/download_manager_provider.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
||||
@ -23,6 +25,7 @@ class TrackViewBodyOptions extends HookConsumerWidget {
|
||||
ref.watch(downloadManagerProvider);
|
||||
final downloader = ref.watch(downloadManagerProvider.notifier);
|
||||
final playlistNotifier = ref.watch(proxyPlaylistProvider.notifier);
|
||||
final historyNotifier = ref.watch(playbackHistoryProvider.notifier);
|
||||
final audioSource =
|
||||
ref.watch(userPreferencesProvider.select((s) => s.audioSource));
|
||||
|
||||
@ -72,6 +75,12 @@ class TrackViewBodyOptions extends HookConsumerWidget {
|
||||
{
|
||||
playlistNotifier.addTracksAtFirst(selectedTracks);
|
||||
playlistNotifier.addCollection(props.collectionId);
|
||||
if (props.collection is AlbumSimple) {
|
||||
historyNotifier.addAlbums([props.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier
|
||||
.addPlaylists([props.collection as PlaylistSimple]);
|
||||
}
|
||||
trackViewState.deselectAll();
|
||||
break;
|
||||
}
|
||||
@ -79,6 +88,12 @@ class TrackViewBodyOptions extends HookConsumerWidget {
|
||||
{
|
||||
playlistNotifier.addTracks(selectedTracks);
|
||||
playlistNotifier.addCollection(props.collectionId);
|
||||
if (props.collection is AlbumSimple) {
|
||||
historyNotifier.addAlbums([props.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier
|
||||
.addPlaylists([props.collection as PlaylistSimple]);
|
||||
}
|
||||
trackViewState.deselectAll();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/playlist/playlist_create_dialog.dart';
|
||||
import 'package:spotube/components/shared/heart_button.dart';
|
||||
@ -9,6 +10,7 @@ import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_
|
||||
import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/provider/authentication_provider.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
|
||||
class TrackViewHeaderActions extends HookConsumerWidget {
|
||||
@ -20,6 +22,7 @@ class TrackViewHeaderActions extends HookConsumerWidget {
|
||||
|
||||
final playlist = ref.watch(proxyPlaylistProvider);
|
||||
final playlistNotifier = ref.watch(proxyPlaylistProvider.notifier);
|
||||
final historyNotifier = ref.watch(playbackHistoryProvider.notifier);
|
||||
|
||||
final isActive = playlist.collections.contains(props.collectionId);
|
||||
|
||||
@ -61,6 +64,13 @@ class TrackViewHeaderActions extends HookConsumerWidget {
|
||||
final tracks = await props.pagination.onFetchAll();
|
||||
await playlistNotifier.addTracks(tracks);
|
||||
playlistNotifier.addCollection(props.collectionId);
|
||||
if (props.collection is AlbumSimple) {
|
||||
historyNotifier
|
||||
.addAlbums([props.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier
|
||||
.addPlaylists([props.collection as PlaylistSimple]);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (props.onHeart != null && auth != null)
|
||||
|
||||
@ -5,12 +5,14 @@ import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:palette_generator/palette_generator.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/shared/dialogs/select_device_dialog.dart';
|
||||
import 'package:spotube/components/shared/tracks_view/track_view_props.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/models/connect/connect.dart';
|
||||
import 'package:spotube/provider/connect/connect.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
|
||||
@ -28,6 +30,7 @@ class TrackViewHeaderButtons extends HookConsumerWidget {
|
||||
final props = InheritedTrackView.of(context);
|
||||
final playlist = ref.watch(proxyPlaylistProvider);
|
||||
final playlistNotifier = ref.watch(proxyPlaylistProvider.notifier);
|
||||
final historyNotifier = ref.watch(playbackHistoryProvider.notifier);
|
||||
|
||||
final isActive = playlist.collections.contains(props.collectionId);
|
||||
|
||||
@ -52,10 +55,16 @@ class TrackViewHeaderButtons extends HookConsumerWidget {
|
||||
if (isRemoteDevice) {
|
||||
final remotePlayback = ref.read(connectProvider.notifier);
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
tracks: allTracks,
|
||||
collectionId: props.collectionId,
|
||||
initialIndex: Random().nextInt(allTracks.length)),
|
||||
props.collection is AlbumSimple
|
||||
? WebSocketLoadEventData.album(
|
||||
tracks: allTracks,
|
||||
collection: props.collection as AlbumSimple,
|
||||
initialIndex: Random().nextInt(allTracks.length))
|
||||
: WebSocketLoadEventData.playlist(
|
||||
tracks: allTracks,
|
||||
collection: props.collection as PlaylistSimple,
|
||||
initialIndex: Random().nextInt(allTracks.length),
|
||||
),
|
||||
);
|
||||
await remotePlayback.setShuffle(true);
|
||||
} else {
|
||||
@ -66,6 +75,11 @@ class TrackViewHeaderButtons extends HookConsumerWidget {
|
||||
);
|
||||
await audioPlayer.setShuffle(true);
|
||||
playlistNotifier.addCollection(props.collectionId);
|
||||
if (props.collection is AlbumSimple) {
|
||||
historyNotifier.addAlbums([props.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier.addPlaylists([props.collection as PlaylistSimple]);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
@ -84,14 +98,24 @@ class TrackViewHeaderButtons extends HookConsumerWidget {
|
||||
if (isRemoteDevice) {
|
||||
final remotePlayback = ref.read(connectProvider.notifier);
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
tracks: allTracks,
|
||||
collectionId: props.collectionId,
|
||||
),
|
||||
props.collection is AlbumSimple
|
||||
? WebSocketLoadEventData.album(
|
||||
tracks: allTracks,
|
||||
collection: props.collection as AlbumSimple,
|
||||
)
|
||||
: WebSocketLoadEventData.playlist(
|
||||
tracks: allTracks,
|
||||
collection: props.collection as PlaylistSimple,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
await playlistNotifier.load(allTracks, autoPlay: true);
|
||||
playlistNotifier.addCollection(props.collectionId);
|
||||
if (props.collection is AlbumSimple) {
|
||||
historyNotifier.addAlbums([props.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier.addPlaylists([props.collection as PlaylistSimple]);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false;
|
||||
|
||||
@ -39,7 +39,7 @@ class PaginationProps {
|
||||
}
|
||||
|
||||
class InheritedTrackView extends InheritedWidget {
|
||||
final String collectionId;
|
||||
final Object collection;
|
||||
final String title;
|
||||
final String? description;
|
||||
final String image;
|
||||
@ -55,7 +55,7 @@ class InheritedTrackView extends InheritedWidget {
|
||||
const InheritedTrackView({
|
||||
super.key,
|
||||
required super.child,
|
||||
required this.collectionId,
|
||||
required this.collection,
|
||||
required this.title,
|
||||
this.description,
|
||||
required this.image,
|
||||
@ -65,7 +65,11 @@ class InheritedTrackView extends InheritedWidget {
|
||||
required this.shareUrl,
|
||||
this.isLiked = false,
|
||||
this.onHeart,
|
||||
});
|
||||
}) : assert(collection is AlbumSimple || collection is PlaylistSimple);
|
||||
|
||||
String get collectionId => collection is AlbumSimple
|
||||
? (collection as AlbumSimple).id!
|
||||
: (collection as PlaylistSimple).id!;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(InheritedTrackView oldWidget) {
|
||||
@ -78,7 +82,7 @@ class InheritedTrackView extends InheritedWidget {
|
||||
oldWidget.onHeart != onHeart ||
|
||||
oldWidget.shareUrl != shareUrl ||
|
||||
oldWidget.routePath != routePath ||
|
||||
oldWidget.collectionId != collectionId ||
|
||||
oldWidget.collection != collection ||
|
||||
oldWidget.child != child;
|
||||
}
|
||||
|
||||
|
||||
@ -16,16 +16,89 @@ final _privateConstructorUsedError = UnsupportedError(
|
||||
|
||||
WebSocketLoadEventData _$WebSocketLoadEventDataFromJson(
|
||||
Map<String, dynamic> json) {
|
||||
return _WebSocketLoadEventData.fromJson(json);
|
||||
switch (json['runtimeType']) {
|
||||
case 'playlist':
|
||||
return WebSocketLoadEventDataPlaylist.fromJson(json);
|
||||
case 'album':
|
||||
return WebSocketLoadEventDataAlbum.fromJson(json);
|
||||
|
||||
default:
|
||||
throw CheckedFromJsonException(
|
||||
json,
|
||||
'runtimeType',
|
||||
'WebSocketLoadEventData',
|
||||
'Invalid union type "${json['runtimeType']}"!');
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$WebSocketLoadEventData {
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
List<Track> get tracks => throw _privateConstructorUsedError;
|
||||
String? get collectionId => throw _privateConstructorUsedError;
|
||||
Object? get collection => throw _privateConstructorUsedError;
|
||||
int? get initialIndex => throw _privateConstructorUsedError;
|
||||
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)
|
||||
playlist,
|
||||
required TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)
|
||||
album,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)?
|
||||
playlist,
|
||||
TResult? Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)?
|
||||
album,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)?
|
||||
playlist,
|
||||
TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)?
|
||||
album,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(WebSocketLoadEventDataPlaylist value) playlist,
|
||||
required TResult Function(WebSocketLoadEventDataAlbum value) album,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(WebSocketLoadEventDataPlaylist value)? playlist,
|
||||
TResult? Function(WebSocketLoadEventDataAlbum value)? album,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(WebSocketLoadEventDataPlaylist value)? playlist,
|
||||
TResult Function(WebSocketLoadEventDataAlbum value)? album,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$WebSocketLoadEventDataCopyWith<WebSocketLoadEventData> get copyWith =>
|
||||
@ -40,7 +113,6 @@ abstract class $WebSocketLoadEventDataCopyWith<$Res> {
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
String? collectionId,
|
||||
int? initialIndex});
|
||||
}
|
||||
|
||||
@ -59,7 +131,6 @@ class _$WebSocketLoadEventDataCopyWithImpl<$Res,
|
||||
@override
|
||||
$Res call({
|
||||
Object? tracks = null,
|
||||
Object? collectionId = freezed,
|
||||
Object? initialIndex = freezed,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
@ -67,10 +138,6 @@ class _$WebSocketLoadEventDataCopyWithImpl<$Res,
|
||||
? _value.tracks
|
||||
: tracks // ignore: cast_nullable_to_non_nullable
|
||||
as List<Track>,
|
||||
collectionId: freezed == collectionId
|
||||
? _value.collectionId
|
||||
: collectionId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
initialIndex: freezed == initialIndex
|
||||
? _value.initialIndex
|
||||
: initialIndex // ignore: cast_nullable_to_non_nullable
|
||||
@ -80,46 +147,46 @@ class _$WebSocketLoadEventDataCopyWithImpl<$Res,
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$WebSocketLoadEventDataImplCopyWith<$Res>
|
||||
abstract class _$$WebSocketLoadEventDataPlaylistImplCopyWith<$Res>
|
||||
implements $WebSocketLoadEventDataCopyWith<$Res> {
|
||||
factory _$$WebSocketLoadEventDataImplCopyWith(
|
||||
_$WebSocketLoadEventDataImpl value,
|
||||
$Res Function(_$WebSocketLoadEventDataImpl) then) =
|
||||
__$$WebSocketLoadEventDataImplCopyWithImpl<$Res>;
|
||||
factory _$$WebSocketLoadEventDataPlaylistImplCopyWith(
|
||||
_$WebSocketLoadEventDataPlaylistImpl value,
|
||||
$Res Function(_$WebSocketLoadEventDataPlaylistImpl) then) =
|
||||
__$$WebSocketLoadEventDataPlaylistImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
String? collectionId,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$WebSocketLoadEventDataImplCopyWithImpl<$Res>
|
||||
class __$$WebSocketLoadEventDataPlaylistImplCopyWithImpl<$Res>
|
||||
extends _$WebSocketLoadEventDataCopyWithImpl<$Res,
|
||||
_$WebSocketLoadEventDataImpl>
|
||||
implements _$$WebSocketLoadEventDataImplCopyWith<$Res> {
|
||||
__$$WebSocketLoadEventDataImplCopyWithImpl(
|
||||
_$WebSocketLoadEventDataImpl _value,
|
||||
$Res Function(_$WebSocketLoadEventDataImpl) _then)
|
||||
_$WebSocketLoadEventDataPlaylistImpl>
|
||||
implements _$$WebSocketLoadEventDataPlaylistImplCopyWith<$Res> {
|
||||
__$$WebSocketLoadEventDataPlaylistImplCopyWithImpl(
|
||||
_$WebSocketLoadEventDataPlaylistImpl _value,
|
||||
$Res Function(_$WebSocketLoadEventDataPlaylistImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? tracks = null,
|
||||
Object? collectionId = freezed,
|
||||
Object? collection = freezed,
|
||||
Object? initialIndex = freezed,
|
||||
}) {
|
||||
return _then(_$WebSocketLoadEventDataImpl(
|
||||
return _then(_$WebSocketLoadEventDataPlaylistImpl(
|
||||
tracks: null == tracks
|
||||
? _value._tracks
|
||||
: tracks // ignore: cast_nullable_to_non_nullable
|
||||
as List<Track>,
|
||||
collectionId: freezed == collectionId
|
||||
? _value.collectionId
|
||||
: collectionId // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
collection: freezed == collection
|
||||
? _value.collection
|
||||
: collection // ignore: cast_nullable_to_non_nullable
|
||||
as PlaylistSimple?,
|
||||
initialIndex: freezed == initialIndex
|
||||
? _value.initialIndex
|
||||
: initialIndex // ignore: cast_nullable_to_non_nullable
|
||||
@ -130,16 +197,21 @@ class __$$WebSocketLoadEventDataImplCopyWithImpl<$Res>
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$WebSocketLoadEventDataImpl implements _WebSocketLoadEventData {
|
||||
_$WebSocketLoadEventDataImpl(
|
||||
class _$WebSocketLoadEventDataPlaylistImpl
|
||||
extends WebSocketLoadEventDataPlaylist {
|
||||
_$WebSocketLoadEventDataPlaylistImpl(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
required final List<Track> tracks,
|
||||
this.collectionId,
|
||||
this.initialIndex})
|
||||
: _tracks = tracks;
|
||||
this.collection,
|
||||
this.initialIndex,
|
||||
final String? $type})
|
||||
: _tracks = tracks,
|
||||
$type = $type ?? 'playlist',
|
||||
super._();
|
||||
|
||||
factory _$WebSocketLoadEventDataImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$WebSocketLoadEventDataImplFromJson(json);
|
||||
factory _$WebSocketLoadEventDataPlaylistImpl.fromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$$WebSocketLoadEventDataPlaylistImplFromJson(json);
|
||||
|
||||
final List<Track> _tracks;
|
||||
@override
|
||||
@ -151,23 +223,26 @@ class _$WebSocketLoadEventDataImpl implements _WebSocketLoadEventData {
|
||||
}
|
||||
|
||||
@override
|
||||
final String? collectionId;
|
||||
final PlaylistSimple? collection;
|
||||
@override
|
||||
final int? initialIndex;
|
||||
|
||||
@JsonKey(name: 'runtimeType')
|
||||
final String $type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WebSocketLoadEventData(tracks: $tracks, collectionId: $collectionId, initialIndex: $initialIndex)';
|
||||
return 'WebSocketLoadEventData.playlist(tracks: $tracks, collection: $collection, initialIndex: $initialIndex)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$WebSocketLoadEventDataImpl &&
|
||||
other is _$WebSocketLoadEventDataPlaylistImpl &&
|
||||
const DeepCollectionEquality().equals(other._tracks, _tracks) &&
|
||||
(identical(other.collectionId, collectionId) ||
|
||||
other.collectionId == collectionId) &&
|
||||
(identical(other.collection, collection) ||
|
||||
other.collection == collection) &&
|
||||
(identical(other.initialIndex, initialIndex) ||
|
||||
other.initialIndex == initialIndex));
|
||||
}
|
||||
@ -175,42 +250,361 @@ class _$WebSocketLoadEventDataImpl implements _WebSocketLoadEventData {
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,
|
||||
const DeepCollectionEquality().hash(_tracks), collectionId, initialIndex);
|
||||
const DeepCollectionEquality().hash(_tracks), collection, initialIndex);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$WebSocketLoadEventDataImplCopyWith<_$WebSocketLoadEventDataImpl>
|
||||
get copyWith => __$$WebSocketLoadEventDataImplCopyWithImpl<
|
||||
_$WebSocketLoadEventDataImpl>(this, _$identity);
|
||||
_$$WebSocketLoadEventDataPlaylistImplCopyWith<
|
||||
_$WebSocketLoadEventDataPlaylistImpl>
|
||||
get copyWith => __$$WebSocketLoadEventDataPlaylistImplCopyWithImpl<
|
||||
_$WebSocketLoadEventDataPlaylistImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)
|
||||
playlist,
|
||||
required TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)
|
||||
album,
|
||||
}) {
|
||||
return playlist(tracks, collection, initialIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)?
|
||||
playlist,
|
||||
TResult? Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)?
|
||||
album,
|
||||
}) {
|
||||
return playlist?.call(tracks, collection, initialIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)?
|
||||
playlist,
|
||||
TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)?
|
||||
album,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (playlist != null) {
|
||||
return playlist(tracks, collection, initialIndex);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(WebSocketLoadEventDataPlaylist value) playlist,
|
||||
required TResult Function(WebSocketLoadEventDataAlbum value) album,
|
||||
}) {
|
||||
return playlist(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(WebSocketLoadEventDataPlaylist value)? playlist,
|
||||
TResult? Function(WebSocketLoadEventDataAlbum value)? album,
|
||||
}) {
|
||||
return playlist?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(WebSocketLoadEventDataPlaylist value)? playlist,
|
||||
TResult Function(WebSocketLoadEventDataAlbum value)? album,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (playlist != null) {
|
||||
return playlist(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$WebSocketLoadEventDataImplToJson(
|
||||
return _$$WebSocketLoadEventDataPlaylistImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _WebSocketLoadEventData implements WebSocketLoadEventData {
|
||||
factory _WebSocketLoadEventData(
|
||||
abstract class WebSocketLoadEventDataPlaylist extends WebSocketLoadEventData {
|
||||
factory WebSocketLoadEventDataPlaylist(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
required final List<Track> tracks,
|
||||
final String? collectionId,
|
||||
final int? initialIndex}) = _$WebSocketLoadEventDataImpl;
|
||||
final PlaylistSimple? collection,
|
||||
final int? initialIndex}) = _$WebSocketLoadEventDataPlaylistImpl;
|
||||
WebSocketLoadEventDataPlaylist._() : super._();
|
||||
|
||||
factory _WebSocketLoadEventData.fromJson(Map<String, dynamic> json) =
|
||||
_$WebSocketLoadEventDataImpl.fromJson;
|
||||
factory WebSocketLoadEventDataPlaylist.fromJson(Map<String, dynamic> json) =
|
||||
_$WebSocketLoadEventDataPlaylistImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
List<Track> get tracks;
|
||||
@override
|
||||
String? get collectionId;
|
||||
PlaylistSimple? get collection;
|
||||
@override
|
||||
int? get initialIndex;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$WebSocketLoadEventDataImplCopyWith<_$WebSocketLoadEventDataImpl>
|
||||
_$$WebSocketLoadEventDataPlaylistImplCopyWith<
|
||||
_$WebSocketLoadEventDataPlaylistImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$WebSocketLoadEventDataAlbumImplCopyWith<$Res>
|
||||
implements $WebSocketLoadEventDataCopyWith<$Res> {
|
||||
factory _$$WebSocketLoadEventDataAlbumImplCopyWith(
|
||||
_$WebSocketLoadEventDataAlbumImpl value,
|
||||
$Res Function(_$WebSocketLoadEventDataAlbumImpl) then) =
|
||||
__$$WebSocketLoadEventDataAlbumImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$WebSocketLoadEventDataAlbumImplCopyWithImpl<$Res>
|
||||
extends _$WebSocketLoadEventDataCopyWithImpl<$Res,
|
||||
_$WebSocketLoadEventDataAlbumImpl>
|
||||
implements _$$WebSocketLoadEventDataAlbumImplCopyWith<$Res> {
|
||||
__$$WebSocketLoadEventDataAlbumImplCopyWithImpl(
|
||||
_$WebSocketLoadEventDataAlbumImpl _value,
|
||||
$Res Function(_$WebSocketLoadEventDataAlbumImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? tracks = null,
|
||||
Object? collection = freezed,
|
||||
Object? initialIndex = freezed,
|
||||
}) {
|
||||
return _then(_$WebSocketLoadEventDataAlbumImpl(
|
||||
tracks: null == tracks
|
||||
? _value._tracks
|
||||
: tracks // ignore: cast_nullable_to_non_nullable
|
||||
as List<Track>,
|
||||
collection: freezed == collection
|
||||
? _value.collection
|
||||
: collection // ignore: cast_nullable_to_non_nullable
|
||||
as AlbumSimple?,
|
||||
initialIndex: freezed == initialIndex
|
||||
? _value.initialIndex
|
||||
: initialIndex // ignore: cast_nullable_to_non_nullable
|
||||
as int?,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$WebSocketLoadEventDataAlbumImpl extends WebSocketLoadEventDataAlbum {
|
||||
_$WebSocketLoadEventDataAlbumImpl(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
required final List<Track> tracks,
|
||||
this.collection,
|
||||
this.initialIndex,
|
||||
final String? $type})
|
||||
: _tracks = tracks,
|
||||
$type = $type ?? 'album',
|
||||
super._();
|
||||
|
||||
factory _$WebSocketLoadEventDataAlbumImpl.fromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$$WebSocketLoadEventDataAlbumImplFromJson(json);
|
||||
|
||||
final List<Track> _tracks;
|
||||
@override
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
List<Track> get tracks {
|
||||
if (_tracks is EqualUnmodifiableListView) return _tracks;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_tracks);
|
||||
}
|
||||
|
||||
@override
|
||||
final AlbumSimple? collection;
|
||||
@override
|
||||
final int? initialIndex;
|
||||
|
||||
@JsonKey(name: 'runtimeType')
|
||||
final String $type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'WebSocketLoadEventData.album(tracks: $tracks, collection: $collection, initialIndex: $initialIndex)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$WebSocketLoadEventDataAlbumImpl &&
|
||||
const DeepCollectionEquality().equals(other._tracks, _tracks) &&
|
||||
(identical(other.collection, collection) ||
|
||||
other.collection == collection) &&
|
||||
(identical(other.initialIndex, initialIndex) ||
|
||||
other.initialIndex == initialIndex));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType,
|
||||
const DeepCollectionEquality().hash(_tracks), collection, initialIndex);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$WebSocketLoadEventDataAlbumImplCopyWith<_$WebSocketLoadEventDataAlbumImpl>
|
||||
get copyWith => __$$WebSocketLoadEventDataAlbumImplCopyWithImpl<
|
||||
_$WebSocketLoadEventDataAlbumImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)
|
||||
playlist,
|
||||
required TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)
|
||||
album,
|
||||
}) {
|
||||
return album(tracks, collection, initialIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)?
|
||||
playlist,
|
||||
TResult? Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)?
|
||||
album,
|
||||
}) {
|
||||
return album?.call(tracks, collection, initialIndex);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex)?
|
||||
playlist,
|
||||
TResult Function(
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex)?
|
||||
album,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (album != null) {
|
||||
return album(tracks, collection, initialIndex);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(WebSocketLoadEventDataPlaylist value) playlist,
|
||||
required TResult Function(WebSocketLoadEventDataAlbum value) album,
|
||||
}) {
|
||||
return album(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(WebSocketLoadEventDataPlaylist value)? playlist,
|
||||
TResult? Function(WebSocketLoadEventDataAlbum value)? album,
|
||||
}) {
|
||||
return album?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(WebSocketLoadEventDataPlaylist value)? playlist,
|
||||
TResult Function(WebSocketLoadEventDataAlbum value)? album,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (album != null) {
|
||||
return album(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$WebSocketLoadEventDataAlbumImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WebSocketLoadEventDataAlbum extends WebSocketLoadEventData {
|
||||
factory WebSocketLoadEventDataAlbum(
|
||||
{@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
required final List<Track> tracks,
|
||||
final AlbumSimple? collection,
|
||||
final int? initialIndex}) = _$WebSocketLoadEventDataAlbumImpl;
|
||||
WebSocketLoadEventDataAlbum._() : super._();
|
||||
|
||||
factory WebSocketLoadEventDataAlbum.fromJson(Map<String, dynamic> json) =
|
||||
_$WebSocketLoadEventDataAlbumImpl.fromJson;
|
||||
|
||||
@override
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson)
|
||||
List<Track> get tracks;
|
||||
@override
|
||||
AlbumSimple? get collection;
|
||||
@override
|
||||
int? get initialIndex;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$WebSocketLoadEventDataAlbumImplCopyWith<_$WebSocketLoadEventDataAlbumImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
@ -6,20 +6,48 @@ part of 'connect.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$WebSocketLoadEventDataImpl _$$WebSocketLoadEventDataImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$WebSocketLoadEventDataImpl(
|
||||
tracks: (json['tracks'] as List<dynamic>)
|
||||
.map((e) => Track.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
collectionId: json['collectionId'] as String?,
|
||||
initialIndex: json['initialIndex'] as int?,
|
||||
);
|
||||
_$WebSocketLoadEventDataPlaylistImpl
|
||||
_$$WebSocketLoadEventDataPlaylistImplFromJson(Map json) =>
|
||||
_$WebSocketLoadEventDataPlaylistImpl(
|
||||
tracks: (json['tracks'] as List<dynamic>)
|
||||
.map((e) => Track.fromJson(Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
collection: json['collection'] == null
|
||||
? null
|
||||
: PlaylistSimple.fromJson(
|
||||
Map<String, dynamic>.from(json['collection'] as Map)),
|
||||
initialIndex: json['initialIndex'] as int?,
|
||||
$type: json['runtimeType'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$WebSocketLoadEventDataImplToJson(
|
||||
_$WebSocketLoadEventDataImpl instance) =>
|
||||
Map<String, dynamic> _$$WebSocketLoadEventDataPlaylistImplToJson(
|
||||
_$WebSocketLoadEventDataPlaylistImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'tracks': _tracksJson(instance.tracks),
|
||||
'collectionId': instance.collectionId,
|
||||
'collection': instance.collection?.toJson(),
|
||||
'initialIndex': instance.initialIndex,
|
||||
'runtimeType': instance.$type,
|
||||
};
|
||||
|
||||
_$WebSocketLoadEventDataAlbumImpl _$$WebSocketLoadEventDataAlbumImplFromJson(
|
||||
Map json) =>
|
||||
_$WebSocketLoadEventDataAlbumImpl(
|
||||
tracks: (json['tracks'] as List<dynamic>)
|
||||
.map((e) => Track.fromJson(Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
collection: json['collection'] == null
|
||||
? null
|
||||
: AlbumSimple.fromJson(
|
||||
Map<String, dynamic>.from(json['collection'] as Map)),
|
||||
initialIndex: json['initialIndex'] as int?,
|
||||
$type: json['runtimeType'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$WebSocketLoadEventDataAlbumImplToJson(
|
||||
_$WebSocketLoadEventDataAlbumImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'tracks': _tracksJson(instance.tracks),
|
||||
'collection': instance.collection?.toJson(),
|
||||
'initialIndex': instance.initialIndex,
|
||||
'runtimeType': instance.$type,
|
||||
};
|
||||
|
||||
@ -6,14 +6,27 @@ List<Map<String, dynamic>> _tracksJson(List<Track> tracks) {
|
||||
|
||||
@freezed
|
||||
class WebSocketLoadEventData with _$WebSocketLoadEventData {
|
||||
factory WebSocketLoadEventData({
|
||||
const WebSocketLoadEventData._();
|
||||
|
||||
factory WebSocketLoadEventData.playlist({
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) required List<Track> tracks,
|
||||
String? collectionId,
|
||||
PlaylistSimple? collection,
|
||||
int? initialIndex,
|
||||
}) = _WebSocketLoadEventData;
|
||||
}) = WebSocketLoadEventDataPlaylist;
|
||||
|
||||
factory WebSocketLoadEventData.album({
|
||||
@JsonKey(name: 'tracks', toJson: _tracksJson) required List<Track> tracks,
|
||||
AlbumSimple? collection,
|
||||
int? initialIndex,
|
||||
}) = WebSocketLoadEventDataAlbum;
|
||||
|
||||
factory WebSocketLoadEventData.fromJson(Map<String, dynamic> json) =>
|
||||
_$WebSocketLoadEventDataFromJson(json);
|
||||
|
||||
String? get collectionId => when(
|
||||
playlist: (tracks, collection, _) => collection?.id,
|
||||
album: (tracks, collection, _) => collection?.id,
|
||||
);
|
||||
}
|
||||
|
||||
class WebSocketLoadEvent extends WebSocketEvent<WebSocketLoadEventData> {
|
||||
|
||||
@ -97,7 +97,7 @@ class SourceTypeAdapter extends TypeAdapter<SourceType> {
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
SourceMatch _$SourceMatchFromJson(Map<String, dynamic> json) => SourceMatch(
|
||||
SourceMatch _$SourceMatchFromJson(Map json) => SourceMatch(
|
||||
id: json['id'] as String,
|
||||
sourceId: json['sourceId'] as String,
|
||||
sourceType: $enumDecode(_$SourceTypeEnumMap, json['sourceType']),
|
||||
|
||||
@ -6,14 +6,13 @@ part of 'home_feed.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$SpotifySectionPlaylistImpl _$$SpotifySectionPlaylistImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SpotifySectionPlaylistImpl _$$SpotifySectionPlaylistImplFromJson(Map json) =>
|
||||
_$SpotifySectionPlaylistImpl(
|
||||
description: json['description'] as String,
|
||||
format: json['format'] as String,
|
||||
images: (json['images'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
SpotifySectionItemImage.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifySectionItemImage.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
name: json['name'] as String,
|
||||
owner: json['owner'] as String,
|
||||
@ -25,20 +24,19 @@ Map<String, dynamic> _$$SpotifySectionPlaylistImplToJson(
|
||||
<String, dynamic>{
|
||||
'description': instance.description,
|
||||
'format': instance.format,
|
||||
'images': instance.images,
|
||||
'images': instance.images.map((e) => e.toJson()).toList(),
|
||||
'name': instance.name,
|
||||
'owner': instance.owner,
|
||||
'uri': instance.uri,
|
||||
};
|
||||
|
||||
_$SpotifySectionArtistImpl _$$SpotifySectionArtistImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SpotifySectionArtistImpl _$$SpotifySectionArtistImplFromJson(Map json) =>
|
||||
_$SpotifySectionArtistImpl(
|
||||
name: json['name'] as String,
|
||||
uri: json['uri'] as String,
|
||||
images: (json['images'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
SpotifySectionItemImage.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifySectionItemImage.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
@ -47,19 +45,18 @@ Map<String, dynamic> _$$SpotifySectionArtistImplToJson(
|
||||
<String, dynamic>{
|
||||
'name': instance.name,
|
||||
'uri': instance.uri,
|
||||
'images': instance.images,
|
||||
'images': instance.images.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
_$SpotifySectionAlbumImpl _$$SpotifySectionAlbumImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SpotifySectionAlbumImpl _$$SpotifySectionAlbumImplFromJson(Map json) =>
|
||||
_$SpotifySectionAlbumImpl(
|
||||
artists: (json['artists'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
SpotifySectionAlbumArtist.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifySectionAlbumArtist.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
images: (json['images'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
SpotifySectionItemImage.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifySectionItemImage.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
name: json['name'] as String,
|
||||
uri: json['uri'] as String,
|
||||
@ -68,14 +65,14 @@ _$SpotifySectionAlbumImpl _$$SpotifySectionAlbumImplFromJson(
|
||||
Map<String, dynamic> _$$SpotifySectionAlbumImplToJson(
|
||||
_$SpotifySectionAlbumImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'artists': instance.artists,
|
||||
'images': instance.images,
|
||||
'artists': instance.artists.map((e) => e.toJson()).toList(),
|
||||
'images': instance.images.map((e) => e.toJson()).toList(),
|
||||
'name': instance.name,
|
||||
'uri': instance.uri,
|
||||
};
|
||||
|
||||
_$SpotifySectionAlbumArtistImpl _$$SpotifySectionAlbumArtistImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
Map json) =>
|
||||
_$SpotifySectionAlbumArtistImpl(
|
||||
name: json['name'] as String,
|
||||
uri: json['uri'] as String,
|
||||
@ -89,7 +86,7 @@ Map<String, dynamic> _$$SpotifySectionAlbumArtistImplToJson(
|
||||
};
|
||||
|
||||
_$SpotifySectionItemImageImpl _$$SpotifySectionItemImageImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
Map json) =>
|
||||
_$SpotifySectionItemImageImpl(
|
||||
height: json['height'] as num?,
|
||||
url: json['url'] as String,
|
||||
@ -105,40 +102,40 @@ Map<String, dynamic> _$$SpotifySectionItemImageImplToJson(
|
||||
};
|
||||
|
||||
_$SpotifyHomeFeedSectionItemImpl _$$SpotifyHomeFeedSectionItemImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
Map json) =>
|
||||
_$SpotifyHomeFeedSectionItemImpl(
|
||||
typename: json['typename'] as String,
|
||||
playlist: json['playlist'] == null
|
||||
? null
|
||||
: SpotifySectionPlaylist.fromJson(
|
||||
json['playlist'] as Map<String, dynamic>),
|
||||
Map<String, dynamic>.from(json['playlist'] as Map)),
|
||||
artist: json['artist'] == null
|
||||
? null
|
||||
: SpotifySectionArtist.fromJson(
|
||||
json['artist'] as Map<String, dynamic>),
|
||||
Map<String, dynamic>.from(json['artist'] as Map)),
|
||||
album: json['album'] == null
|
||||
? null
|
||||
: SpotifySectionAlbum.fromJson(json['album'] as Map<String, dynamic>),
|
||||
: SpotifySectionAlbum.fromJson(
|
||||
Map<String, dynamic>.from(json['album'] as Map)),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$$SpotifyHomeFeedSectionItemImplToJson(
|
||||
_$SpotifyHomeFeedSectionItemImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'typename': instance.typename,
|
||||
'playlist': instance.playlist,
|
||||
'artist': instance.artist,
|
||||
'album': instance.album,
|
||||
'playlist': instance.playlist?.toJson(),
|
||||
'artist': instance.artist?.toJson(),
|
||||
'album': instance.album?.toJson(),
|
||||
};
|
||||
|
||||
_$SpotifyHomeFeedSectionImpl _$$SpotifyHomeFeedSectionImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SpotifyHomeFeedSectionImpl _$$SpotifyHomeFeedSectionImplFromJson(Map json) =>
|
||||
_$SpotifyHomeFeedSectionImpl(
|
||||
typename: json['typename'] as String,
|
||||
title: json['title'] as String?,
|
||||
uri: json['uri'] as String,
|
||||
items: (json['items'] as List<dynamic>)
|
||||
.map((e) =>
|
||||
SpotifyHomeFeedSectionItem.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifyHomeFeedSectionItem.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
@ -148,16 +145,15 @@ Map<String, dynamic> _$$SpotifyHomeFeedSectionImplToJson(
|
||||
'typename': instance.typename,
|
||||
'title': instance.title,
|
||||
'uri': instance.uri,
|
||||
'items': instance.items,
|
||||
'items': instance.items.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
_$SpotifyHomeFeedImpl _$$SpotifyHomeFeedImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$SpotifyHomeFeedImpl _$$SpotifyHomeFeedImplFromJson(Map json) =>
|
||||
_$SpotifyHomeFeedImpl(
|
||||
greeting: json['greeting'] as String,
|
||||
sections: (json['sections'] as List<dynamic>)
|
||||
.map(
|
||||
(e) => SpotifyHomeFeedSection.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifyHomeFeedSection.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
@ -165,5 +161,5 @@ Map<String, dynamic> _$$SpotifyHomeFeedImplToJson(
|
||||
_$SpotifyHomeFeedImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'greeting': instance.greeting,
|
||||
'sections': instance.sections,
|
||||
'sections': instance.sections.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
@ -6,8 +6,7 @@ part of 'recommendation_seeds.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$RecommendationSeedsImpl _$$RecommendationSeedsImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$RecommendationSeedsImpl _$$RecommendationSeedsImplFromJson(Map json) =>
|
||||
_$RecommendationSeedsImpl(
|
||||
acousticness: json['acousticness'] as num?,
|
||||
danceability: json['danceability'] as num?,
|
||||
|
||||
@ -6,60 +6,55 @@ part of 'spotify_friends.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
SpotifyFriend _$SpotifyFriendFromJson(Map<String, dynamic> json) =>
|
||||
SpotifyFriend(
|
||||
SpotifyFriend _$SpotifyFriendFromJson(Map json) => SpotifyFriend(
|
||||
uri: json['uri'] as String,
|
||||
name: json['name'] as String,
|
||||
imageUrl: json['imageUrl'] as String,
|
||||
);
|
||||
|
||||
SpotifyActivityArtist _$SpotifyActivityArtistFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
SpotifyActivityArtist _$SpotifyActivityArtistFromJson(Map json) =>
|
||||
SpotifyActivityArtist(
|
||||
uri: json['uri'] as String,
|
||||
name: json['name'] as String,
|
||||
);
|
||||
|
||||
SpotifyActivityAlbum _$SpotifyActivityAlbumFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
SpotifyActivityAlbum _$SpotifyActivityAlbumFromJson(Map json) =>
|
||||
SpotifyActivityAlbum(
|
||||
uri: json['uri'] as String,
|
||||
name: json['name'] as String,
|
||||
);
|
||||
|
||||
SpotifyActivityContext _$SpotifyActivityContextFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
SpotifyActivityContext _$SpotifyActivityContextFromJson(Map json) =>
|
||||
SpotifyActivityContext(
|
||||
uri: json['uri'] as String,
|
||||
name: json['name'] as String,
|
||||
index: json['index'] as num,
|
||||
);
|
||||
|
||||
SpotifyActivityTrack _$SpotifyActivityTrackFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
SpotifyActivityTrack _$SpotifyActivityTrackFromJson(Map json) =>
|
||||
SpotifyActivityTrack(
|
||||
uri: json['uri'] as String,
|
||||
name: json['name'] as String,
|
||||
imageUrl: json['imageUrl'] as String,
|
||||
artist: SpotifyActivityArtist.fromJson(
|
||||
json['artist'] as Map<String, dynamic>),
|
||||
album:
|
||||
SpotifyActivityAlbum.fromJson(json['album'] as Map<String, dynamic>),
|
||||
Map<String, dynamic>.from(json['artist'] as Map)),
|
||||
album: SpotifyActivityAlbum.fromJson(
|
||||
Map<String, dynamic>.from(json['album'] as Map)),
|
||||
context: SpotifyActivityContext.fromJson(
|
||||
json['context'] as Map<String, dynamic>),
|
||||
Map<String, dynamic>.from(json['context'] as Map)),
|
||||
);
|
||||
|
||||
SpotifyFriendActivity _$SpotifyFriendActivityFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
SpotifyFriendActivity _$SpotifyFriendActivityFromJson(Map json) =>
|
||||
SpotifyFriendActivity(
|
||||
user: SpotifyFriend.fromJson(json['user'] as Map<String, dynamic>),
|
||||
track:
|
||||
SpotifyActivityTrack.fromJson(json['track'] as Map<String, dynamic>),
|
||||
user: SpotifyFriend.fromJson(
|
||||
Map<String, dynamic>.from(json['user'] as Map)),
|
||||
track: SpotifyActivityTrack.fromJson(
|
||||
Map<String, dynamic>.from(json['track'] as Map)),
|
||||
);
|
||||
|
||||
SpotifyFriends _$SpotifyFriendsFromJson(Map<String, dynamic> json) =>
|
||||
SpotifyFriends(
|
||||
SpotifyFriends _$SpotifyFriendsFromJson(Map json) => SpotifyFriends(
|
||||
friends: (json['friends'] as List<dynamic>)
|
||||
.map((e) => SpotifyFriendActivity.fromJson(e as Map<String, dynamic>))
|
||||
.map((e) => SpotifyFriendActivity.fromJson(
|
||||
Map<String, dynamic>.from(e as Map)))
|
||||
.toList(),
|
||||
);
|
||||
|
||||
@ -22,7 +22,7 @@ class AlbumPage extends HookConsumerWidget {
|
||||
final isSavedAlbum = ref.watch(albumsIsSavedProvider(album.id!));
|
||||
|
||||
return InheritedTrackView(
|
||||
collectionId: album.id!,
|
||||
collection: album,
|
||||
image: album.images.asUrlString(
|
||||
placeholder: ImagePlaceholder.albumArt,
|
||||
),
|
||||
|
||||
@ -52,8 +52,9 @@ class ArtistPageTopTracks extends HookConsumerWidget {
|
||||
|
||||
if (!isPlaylistPlaying) {
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
WebSocketLoadEventData.playlist(
|
||||
tracks: tracks,
|
||||
collection: null,
|
||||
initialIndex: tracks.indexWhere((s) => s.id == currentTrack?.id),
|
||||
),
|
||||
);
|
||||
|
||||
@ -10,6 +10,7 @@ import 'package:spotube/components/home/sections/friends.dart';
|
||||
import 'package:spotube/components/home/sections/genres.dart';
|
||||
import 'package:spotube/components/home/sections/made_for_user.dart';
|
||||
import 'package:spotube/components/home/sections/new_releases.dart';
|
||||
import 'package:spotube/components/home/sections/recent.dart';
|
||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||
import 'package:spotube/components/shared/page_window_title_bar.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
@ -72,6 +73,8 @@ class HomePage extends HookConsumerWidget {
|
||||
else if (kIsMacOS)
|
||||
const SliverGap(10),
|
||||
const HomeGenresSection(),
|
||||
const SliverGap(10),
|
||||
const SliverToBoxAdapter(child: HomeRecentlyPlayedSection()),
|
||||
const SliverToBoxAdapter(child: HomeFeaturedSection()),
|
||||
const HomePageFriendsSection(),
|
||||
const SliverToBoxAdapter(child: HomeNewReleasesSection()),
|
||||
|
||||
@ -18,7 +18,7 @@ class LikedPlaylistPage extends HookConsumerWidget {
|
||||
final tracks = likedTracks.asData?.value ?? <Track>[];
|
||||
|
||||
return InheritedTrackView(
|
||||
collectionId: playlist.id!,
|
||||
collection: playlist,
|
||||
image: "assets/liked-tracks.jpg",
|
||||
pagination: PaginationProps(
|
||||
hasNextPage: false,
|
||||
|
||||
@ -29,7 +29,7 @@ class PlaylistPage extends HookConsumerWidget {
|
||||
final isUserPlaylist = useIsUserPlaylist(ref, playlist.id!);
|
||||
|
||||
return InheritedTrackView(
|
||||
collectionId: playlist.id!,
|
||||
collection: playlist,
|
||||
image: playlist.images.asUrlString(
|
||||
placeholder: ImagePlaceholder.collection,
|
||||
),
|
||||
|
||||
@ -76,7 +76,7 @@ class SearchTracksSection extends HookConsumerWidget {
|
||||
|
||||
if (shouldPlay) {
|
||||
await remotePlayback.load(
|
||||
WebSocketLoadEventData(
|
||||
WebSocketLoadEventData.playlist(
|
||||
tracks: [track],
|
||||
),
|
||||
);
|
||||
|
||||
@ -9,9 +9,11 @@ import 'package:shelf/shelf_io.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:shelf_router/shelf_router.dart';
|
||||
import 'package:shelf_web_socket/shelf_web_socket.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/models/connect/connect.dart';
|
||||
import 'package:spotube/models/logger.dart';
|
||||
import 'package:spotube/provider/connect/clients.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_provider.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
@ -32,6 +34,7 @@ final connectServerProvider = FutureProvider((ref) async {
|
||||
final resolvedService = await ref
|
||||
.watch(connectClientsProvider.selectAsync((s) => s.resolvedService));
|
||||
final playbackNotifier = ref.read(proxyPlaylistProvider.notifier);
|
||||
final historyNotifier = ref.read(playbackHistoryProvider.notifier);
|
||||
|
||||
if (!enabled || resolvedService != null) {
|
||||
return null;
|
||||
@ -146,8 +149,14 @@ final connectServerProvider = FutureProvider((ref) async {
|
||||
initialIndex: event.data.initialIndex ?? 0,
|
||||
);
|
||||
|
||||
if (event.data.collectionId != null) {
|
||||
playbackNotifier.addCollection(event.data.collectionId!);
|
||||
if (event.data.collectionId == null) return;
|
||||
playbackNotifier.addCollection(event.data.collectionId!);
|
||||
if (event.data.collection is AlbumSimple) {
|
||||
historyNotifier
|
||||
.addAlbums([event.data.collection as AlbumSimple]);
|
||||
} else {
|
||||
historyNotifier.addPlaylists(
|
||||
[event.data.collection as PlaylistSimple]);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -6,13 +6,19 @@ import 'package:spotube/provider/history/state.dart';
|
||||
import 'package:spotube/utils/persisted_state_notifier.dart';
|
||||
|
||||
class PlaybackHistoryState {
|
||||
final List<PlaybackHistoryBase> items;
|
||||
final List<PlaybackHistoryItem> items;
|
||||
const PlaybackHistoryState({this.items = const []});
|
||||
|
||||
factory PlaybackHistoryState.fromJson(Map<String, dynamic> json) {
|
||||
return PlaybackHistoryState(
|
||||
items:
|
||||
json["items"]?.map((json) => PlaybackHistoryBase.fromJson(json)));
|
||||
items: json["items"]
|
||||
?.map(
|
||||
(json) => PlaybackHistoryItem.fromJson(json),
|
||||
)
|
||||
.toList()
|
||||
.cast<PlaybackHistoryItem>() ??
|
||||
<PlaybackHistoryItem>[],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
@ -22,7 +28,7 @@ class PlaybackHistoryState {
|
||||
}
|
||||
|
||||
PlaybackHistoryState copyWith({
|
||||
List<PlaybackHistoryBase>? items,
|
||||
List<PlaybackHistoryItem>? items,
|
||||
}) {
|
||||
return PlaybackHistoryState(items: items ?? this.items);
|
||||
}
|
||||
@ -47,7 +53,8 @@ class PlaybackHistoryNotifier
|
||||
items: [
|
||||
...state.items,
|
||||
for (final playlist in playlists)
|
||||
PlaybackHistoryPlaylist(date: DateTime.now(), playlist: playlist),
|
||||
PlaybackHistoryItem.playlist(
|
||||
date: DateTime.now(), playlist: playlist),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -57,7 +64,7 @@ class PlaybackHistoryNotifier
|
||||
items: [
|
||||
...state.items,
|
||||
for (final album in albums)
|
||||
PlaybackHistoryAlbum(date: DateTime.now(), album: album),
|
||||
PlaybackHistoryItem.album(date: DateTime.now(), album: album),
|
||||
],
|
||||
);
|
||||
}
|
||||
@ -67,7 +74,7 @@ class PlaybackHistoryNotifier
|
||||
items: [
|
||||
...state.items,
|
||||
for (final track in tracks)
|
||||
PlaybackHistoryTrack(date: DateTime.now(), track: track),
|
||||
PlaybackHistoryItem.track(date: DateTime.now(), track: track),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
40
lib/provider/history/recent.dart
Normal file
40
lib/provider/history/recent.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/history/state.dart';
|
||||
|
||||
final recentlyPlayedItems = Provider((ref) {
|
||||
return ref.watch(
|
||||
playbackHistoryProvider.select(
|
||||
(s) => s.items
|
||||
.toSet()
|
||||
// unique items
|
||||
.whereIndexed(
|
||||
(index, item) =>
|
||||
index ==
|
||||
s.items.lastIndexWhere(
|
||||
(e) => switch ((e, item)) {
|
||||
(
|
||||
PlaybackHistoryPlaylist(:final playlist),
|
||||
PlaybackHistoryPlaylist(playlist: final playlist2)
|
||||
) =>
|
||||
playlist.id == playlist2.id,
|
||||
(
|
||||
PlaybackHistoryAlbum(:final album),
|
||||
PlaybackHistoryAlbum(album: final album2)
|
||||
) =>
|
||||
album.id == album2.id,
|
||||
_ => false,
|
||||
},
|
||||
),
|
||||
)
|
||||
.where(
|
||||
(s) => s is PlaybackHistoryPlaylist || s is PlaybackHistoryAlbum,
|
||||
)
|
||||
.take(10)
|
||||
.sortedBy((s) => s.date)
|
||||
.reversed
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
});
|
||||
@ -1,70 +1,26 @@
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
|
||||
part 'state.freezed.dart';
|
||||
part 'state.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class PlaybackHistoryBase {
|
||||
final DateTime date;
|
||||
@freezed
|
||||
class PlaybackHistoryItem with _$PlaybackHistoryItem {
|
||||
factory PlaybackHistoryItem.playlist({
|
||||
required DateTime date,
|
||||
required PlaylistSimple playlist,
|
||||
}) = PlaybackHistoryPlaylist;
|
||||
|
||||
const PlaybackHistoryBase({required this.date});
|
||||
factory PlaybackHistoryItem.album({
|
||||
required DateTime date,
|
||||
required AlbumSimple album,
|
||||
}) = PlaybackHistoryAlbum;
|
||||
|
||||
factory PlaybackHistoryBase.fromJson(Map<String, dynamic> json) {
|
||||
if (json.containsKey("playlist")) {
|
||||
return PlaybackHistoryPlaylist.fromJson(json);
|
||||
} else if (json.containsKey("album")) {
|
||||
return PlaybackHistoryAlbum.fromJson(json);
|
||||
} else if (json.containsKey("track")) {
|
||||
return PlaybackHistoryTrack.fromJson(json);
|
||||
}
|
||||
factory PlaybackHistoryItem.track({
|
||||
required DateTime date,
|
||||
required TrackSimple track,
|
||||
}) = PlaybackHistoryTrack;
|
||||
|
||||
return _$PlaybackHistoryBaseFromJson(json);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() => _$PlaybackHistoryBaseToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class PlaybackHistoryPlaylist extends PlaybackHistoryBase {
|
||||
final PlaylistSimple playlist;
|
||||
PlaybackHistoryPlaylist({
|
||||
required super.date,
|
||||
required this.playlist,
|
||||
});
|
||||
|
||||
factory PlaybackHistoryPlaylist.fromJson(Map<String, dynamic> json) =>
|
||||
_$PlaybackHistoryPlaylistFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PlaybackHistoryPlaylistToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class PlaybackHistoryAlbum extends PlaybackHistoryBase {
|
||||
final AlbumSimple album;
|
||||
PlaybackHistoryAlbum({
|
||||
required super.date,
|
||||
required this.album,
|
||||
});
|
||||
|
||||
factory PlaybackHistoryAlbum.fromJson(Map<String, dynamic> json) =>
|
||||
_$PlaybackHistoryAlbumFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PlaybackHistoryAlbumToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class PlaybackHistoryTrack extends PlaybackHistoryBase {
|
||||
final TrackSimple track;
|
||||
PlaybackHistoryTrack({
|
||||
required super.date,
|
||||
required this.track,
|
||||
});
|
||||
|
||||
factory PlaybackHistoryTrack.fromJson(Map<String, dynamic> json) =>
|
||||
_$PlaybackHistoryTrackFromJson(json);
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PlaybackHistoryTrackToJson(this);
|
||||
factory PlaybackHistoryItem.fromJson(Map<String, dynamic> json) =>
|
||||
_$PlaybackHistoryItemFromJson(json);
|
||||
}
|
||||
|
||||
644
lib/provider/history/state.freezed.dart
Normal file
644
lib/provider/history/state.freezed.dart
Normal file
@ -0,0 +1,644 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||
|
||||
part of 'state.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models');
|
||||
|
||||
PlaybackHistoryItem _$PlaybackHistoryItemFromJson(Map<String, dynamic> json) {
|
||||
switch (json['runtimeType']) {
|
||||
case 'playlist':
|
||||
return PlaybackHistoryPlaylist.fromJson(json);
|
||||
case 'album':
|
||||
return PlaybackHistoryAlbum.fromJson(json);
|
||||
case 'track':
|
||||
return PlaybackHistoryTrack.fromJson(json);
|
||||
|
||||
default:
|
||||
throw CheckedFromJsonException(json, 'runtimeType', 'PlaybackHistoryItem',
|
||||
'Invalid union type "${json['runtimeType']}"!');
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PlaybackHistoryItem {
|
||||
DateTime get date => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(DateTime date, PlaylistSimple playlist) playlist,
|
||||
required TResult Function(DateTime date, AlbumSimple album) album,
|
||||
required TResult Function(DateTime date, TrackSimple track) track,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult? Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult? Function(DateTime date, TrackSimple track)? track,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult Function(DateTime date, TrackSimple track)? track,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(PlaybackHistoryPlaylist value) playlist,
|
||||
required TResult Function(PlaybackHistoryAlbum value) album,
|
||||
required TResult Function(PlaybackHistoryTrack value) track,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult? Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult? Function(PlaybackHistoryTrack value)? track,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult Function(PlaybackHistoryTrack value)? track,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$PlaybackHistoryItemCopyWith<PlaybackHistoryItem> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $PlaybackHistoryItemCopyWith<$Res> {
|
||||
factory $PlaybackHistoryItemCopyWith(
|
||||
PlaybackHistoryItem value, $Res Function(PlaybackHistoryItem) then) =
|
||||
_$PlaybackHistoryItemCopyWithImpl<$Res, PlaybackHistoryItem>;
|
||||
@useResult
|
||||
$Res call({DateTime date});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$PlaybackHistoryItemCopyWithImpl<$Res, $Val extends PlaybackHistoryItem>
|
||||
implements $PlaybackHistoryItemCopyWith<$Res> {
|
||||
_$PlaybackHistoryItemCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? date = null,
|
||||
}) {
|
||||
return _then(_value.copyWith(
|
||||
date: null == date
|
||||
? _value.date
|
||||
: date // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
) as $Val);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$PlaybackHistoryPlaylistImplCopyWith<$Res>
|
||||
implements $PlaybackHistoryItemCopyWith<$Res> {
|
||||
factory _$$PlaybackHistoryPlaylistImplCopyWith(
|
||||
_$PlaybackHistoryPlaylistImpl value,
|
||||
$Res Function(_$PlaybackHistoryPlaylistImpl) then) =
|
||||
__$$PlaybackHistoryPlaylistImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({DateTime date, PlaylistSimple playlist});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$PlaybackHistoryPlaylistImplCopyWithImpl<$Res>
|
||||
extends _$PlaybackHistoryItemCopyWithImpl<$Res,
|
||||
_$PlaybackHistoryPlaylistImpl>
|
||||
implements _$$PlaybackHistoryPlaylistImplCopyWith<$Res> {
|
||||
__$$PlaybackHistoryPlaylistImplCopyWithImpl(
|
||||
_$PlaybackHistoryPlaylistImpl _value,
|
||||
$Res Function(_$PlaybackHistoryPlaylistImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? date = null,
|
||||
Object? playlist = null,
|
||||
}) {
|
||||
return _then(_$PlaybackHistoryPlaylistImpl(
|
||||
date: null == date
|
||||
? _value.date
|
||||
: date // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
playlist: null == playlist
|
||||
? _value.playlist
|
||||
: playlist // ignore: cast_nullable_to_non_nullable
|
||||
as PlaylistSimple,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$PlaybackHistoryPlaylistImpl implements PlaybackHistoryPlaylist {
|
||||
_$PlaybackHistoryPlaylistImpl(
|
||||
{required this.date, required this.playlist, final String? $type})
|
||||
: $type = $type ?? 'playlist';
|
||||
|
||||
factory _$PlaybackHistoryPlaylistImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PlaybackHistoryPlaylistImplFromJson(json);
|
||||
|
||||
@override
|
||||
final DateTime date;
|
||||
@override
|
||||
final PlaylistSimple playlist;
|
||||
|
||||
@JsonKey(name: 'runtimeType')
|
||||
final String $type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PlaybackHistoryItem.playlist(date: $date, playlist: $playlist)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PlaybackHistoryPlaylistImpl &&
|
||||
(identical(other.date, date) || other.date == date) &&
|
||||
(identical(other.playlist, playlist) ||
|
||||
other.playlist == playlist));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, date, playlist);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl>
|
||||
get copyWith => __$$PlaybackHistoryPlaylistImplCopyWithImpl<
|
||||
_$PlaybackHistoryPlaylistImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(DateTime date, PlaylistSimple playlist) playlist,
|
||||
required TResult Function(DateTime date, AlbumSimple album) album,
|
||||
required TResult Function(DateTime date, TrackSimple track) track,
|
||||
}) {
|
||||
return playlist(date, this.playlist);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult? Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult? Function(DateTime date, TrackSimple track)? track,
|
||||
}) {
|
||||
return playlist?.call(date, this.playlist);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult Function(DateTime date, TrackSimple track)? track,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (playlist != null) {
|
||||
return playlist(date, this.playlist);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(PlaybackHistoryPlaylist value) playlist,
|
||||
required TResult Function(PlaybackHistoryAlbum value) album,
|
||||
required TResult Function(PlaybackHistoryTrack value) track,
|
||||
}) {
|
||||
return playlist(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult? Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult? Function(PlaybackHistoryTrack value)? track,
|
||||
}) {
|
||||
return playlist?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult Function(PlaybackHistoryTrack value)? track,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (playlist != null) {
|
||||
return playlist(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$PlaybackHistoryPlaylistImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PlaybackHistoryPlaylist implements PlaybackHistoryItem {
|
||||
factory PlaybackHistoryPlaylist(
|
||||
{required final DateTime date,
|
||||
required final PlaylistSimple playlist}) = _$PlaybackHistoryPlaylistImpl;
|
||||
|
||||
factory PlaybackHistoryPlaylist.fromJson(Map<String, dynamic> json) =
|
||||
_$PlaybackHistoryPlaylistImpl.fromJson;
|
||||
|
||||
@override
|
||||
DateTime get date;
|
||||
PlaylistSimple get playlist;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$PlaybackHistoryPlaylistImplCopyWith<_$PlaybackHistoryPlaylistImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$PlaybackHistoryAlbumImplCopyWith<$Res>
|
||||
implements $PlaybackHistoryItemCopyWith<$Res> {
|
||||
factory _$$PlaybackHistoryAlbumImplCopyWith(_$PlaybackHistoryAlbumImpl value,
|
||||
$Res Function(_$PlaybackHistoryAlbumImpl) then) =
|
||||
__$$PlaybackHistoryAlbumImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({DateTime date, AlbumSimple album});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$PlaybackHistoryAlbumImplCopyWithImpl<$Res>
|
||||
extends _$PlaybackHistoryItemCopyWithImpl<$Res, _$PlaybackHistoryAlbumImpl>
|
||||
implements _$$PlaybackHistoryAlbumImplCopyWith<$Res> {
|
||||
__$$PlaybackHistoryAlbumImplCopyWithImpl(_$PlaybackHistoryAlbumImpl _value,
|
||||
$Res Function(_$PlaybackHistoryAlbumImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? date = null,
|
||||
Object? album = null,
|
||||
}) {
|
||||
return _then(_$PlaybackHistoryAlbumImpl(
|
||||
date: null == date
|
||||
? _value.date
|
||||
: date // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
album: null == album
|
||||
? _value.album
|
||||
: album // ignore: cast_nullable_to_non_nullable
|
||||
as AlbumSimple,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$PlaybackHistoryAlbumImpl implements PlaybackHistoryAlbum {
|
||||
_$PlaybackHistoryAlbumImpl(
|
||||
{required this.date, required this.album, final String? $type})
|
||||
: $type = $type ?? 'album';
|
||||
|
||||
factory _$PlaybackHistoryAlbumImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PlaybackHistoryAlbumImplFromJson(json);
|
||||
|
||||
@override
|
||||
final DateTime date;
|
||||
@override
|
||||
final AlbumSimple album;
|
||||
|
||||
@JsonKey(name: 'runtimeType')
|
||||
final String $type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PlaybackHistoryItem.album(date: $date, album: $album)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PlaybackHistoryAlbumImpl &&
|
||||
(identical(other.date, date) || other.date == date) &&
|
||||
(identical(other.album, album) || other.album == album));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, date, album);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl>
|
||||
get copyWith =>
|
||||
__$$PlaybackHistoryAlbumImplCopyWithImpl<_$PlaybackHistoryAlbumImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(DateTime date, PlaylistSimple playlist) playlist,
|
||||
required TResult Function(DateTime date, AlbumSimple album) album,
|
||||
required TResult Function(DateTime date, TrackSimple track) track,
|
||||
}) {
|
||||
return album(date, this.album);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult? Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult? Function(DateTime date, TrackSimple track)? track,
|
||||
}) {
|
||||
return album?.call(date, this.album);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult Function(DateTime date, TrackSimple track)? track,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (album != null) {
|
||||
return album(date, this.album);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(PlaybackHistoryPlaylist value) playlist,
|
||||
required TResult Function(PlaybackHistoryAlbum value) album,
|
||||
required TResult Function(PlaybackHistoryTrack value) track,
|
||||
}) {
|
||||
return album(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult? Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult? Function(PlaybackHistoryTrack value)? track,
|
||||
}) {
|
||||
return album?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult Function(PlaybackHistoryTrack value)? track,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (album != null) {
|
||||
return album(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$PlaybackHistoryAlbumImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PlaybackHistoryAlbum implements PlaybackHistoryItem {
|
||||
factory PlaybackHistoryAlbum(
|
||||
{required final DateTime date,
|
||||
required final AlbumSimple album}) = _$PlaybackHistoryAlbumImpl;
|
||||
|
||||
factory PlaybackHistoryAlbum.fromJson(Map<String, dynamic> json) =
|
||||
_$PlaybackHistoryAlbumImpl.fromJson;
|
||||
|
||||
@override
|
||||
DateTime get date;
|
||||
AlbumSimple get album;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$PlaybackHistoryAlbumImplCopyWith<_$PlaybackHistoryAlbumImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$PlaybackHistoryTrackImplCopyWith<$Res>
|
||||
implements $PlaybackHistoryItemCopyWith<$Res> {
|
||||
factory _$$PlaybackHistoryTrackImplCopyWith(_$PlaybackHistoryTrackImpl value,
|
||||
$Res Function(_$PlaybackHistoryTrackImpl) then) =
|
||||
__$$PlaybackHistoryTrackImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({DateTime date, TrackSimple track});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$PlaybackHistoryTrackImplCopyWithImpl<$Res>
|
||||
extends _$PlaybackHistoryItemCopyWithImpl<$Res, _$PlaybackHistoryTrackImpl>
|
||||
implements _$$PlaybackHistoryTrackImplCopyWith<$Res> {
|
||||
__$$PlaybackHistoryTrackImplCopyWithImpl(_$PlaybackHistoryTrackImpl _value,
|
||||
$Res Function(_$PlaybackHistoryTrackImpl) _then)
|
||||
: super(_value, _then);
|
||||
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? date = null,
|
||||
Object? track = null,
|
||||
}) {
|
||||
return _then(_$PlaybackHistoryTrackImpl(
|
||||
date: null == date
|
||||
? _value.date
|
||||
: date // ignore: cast_nullable_to_non_nullable
|
||||
as DateTime,
|
||||
track: null == track
|
||||
? _value.track
|
||||
: track // ignore: cast_nullable_to_non_nullable
|
||||
as TrackSimple,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@JsonSerializable()
|
||||
class _$PlaybackHistoryTrackImpl implements PlaybackHistoryTrack {
|
||||
_$PlaybackHistoryTrackImpl(
|
||||
{required this.date, required this.track, final String? $type})
|
||||
: $type = $type ?? 'track';
|
||||
|
||||
factory _$PlaybackHistoryTrackImpl.fromJson(Map<String, dynamic> json) =>
|
||||
_$$PlaybackHistoryTrackImplFromJson(json);
|
||||
|
||||
@override
|
||||
final DateTime date;
|
||||
@override
|
||||
final TrackSimple track;
|
||||
|
||||
@JsonKey(name: 'runtimeType')
|
||||
final String $type;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PlaybackHistoryItem.track(date: $date, track: $track)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PlaybackHistoryTrackImpl &&
|
||||
(identical(other.date, date) || other.date == date) &&
|
||||
(identical(other.track, track) || other.track == track));
|
||||
}
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, date, track);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl>
|
||||
get copyWith =>
|
||||
__$$PlaybackHistoryTrackImplCopyWithImpl<_$PlaybackHistoryTrackImpl>(
|
||||
this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(DateTime date, PlaylistSimple playlist) playlist,
|
||||
required TResult Function(DateTime date, AlbumSimple album) album,
|
||||
required TResult Function(DateTime date, TrackSimple track) track,
|
||||
}) {
|
||||
return track(date, this.track);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult? Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult? Function(DateTime date, TrackSimple track)? track,
|
||||
}) {
|
||||
return track?.call(date, this.track);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(DateTime date, PlaylistSimple playlist)? playlist,
|
||||
TResult Function(DateTime date, AlbumSimple album)? album,
|
||||
TResult Function(DateTime date, TrackSimple track)? track,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (track != null) {
|
||||
return track(date, this.track);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(PlaybackHistoryPlaylist value) playlist,
|
||||
required TResult Function(PlaybackHistoryAlbum value) album,
|
||||
required TResult Function(PlaybackHistoryTrack value) track,
|
||||
}) {
|
||||
return track(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult? Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult? Function(PlaybackHistoryTrack value)? track,
|
||||
}) {
|
||||
return track?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(PlaybackHistoryPlaylist value)? playlist,
|
||||
TResult Function(PlaybackHistoryAlbum value)? album,
|
||||
TResult Function(PlaybackHistoryTrack value)? track,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (track != null) {
|
||||
return track(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return _$$PlaybackHistoryTrackImplToJson(
|
||||
this,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class PlaybackHistoryTrack implements PlaybackHistoryItem {
|
||||
factory PlaybackHistoryTrack(
|
||||
{required final DateTime date,
|
||||
required final TrackSimple track}) = _$PlaybackHistoryTrackImpl;
|
||||
|
||||
factory PlaybackHistoryTrack.fromJson(Map<String, dynamic> json) =
|
||||
_$PlaybackHistoryTrackImpl.fromJson;
|
||||
|
||||
@override
|
||||
DateTime get date;
|
||||
TrackSimple get track;
|
||||
@override
|
||||
@JsonKey(ignore: true)
|
||||
_$$PlaybackHistoryTrackImplCopyWith<_$PlaybackHistoryTrackImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@ -6,56 +6,51 @@ part of 'state.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
PlaybackHistoryBase _$PlaybackHistoryBaseFromJson(Map<String, dynamic> json) =>
|
||||
PlaybackHistoryBase(
|
||||
_$PlaybackHistoryPlaylistImpl _$$PlaybackHistoryPlaylistImplFromJson(
|
||||
Map json) =>
|
||||
_$PlaybackHistoryPlaylistImpl(
|
||||
date: DateTime.parse(json['date'] as String),
|
||||
playlist: PlaylistSimple.fromJson(
|
||||
Map<String, dynamic>.from(json['playlist'] as Map)),
|
||||
$type: json['runtimeType'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PlaybackHistoryBaseToJson(
|
||||
PlaybackHistoryBase instance) =>
|
||||
Map<String, dynamic> _$$PlaybackHistoryPlaylistImplToJson(
|
||||
_$PlaybackHistoryPlaylistImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'date': instance.date.toIso8601String(),
|
||||
'playlist': instance.playlist.toJson(),
|
||||
'runtimeType': instance.$type,
|
||||
};
|
||||
|
||||
PlaybackHistoryPlaylist _$PlaybackHistoryPlaylistFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
PlaybackHistoryPlaylist(
|
||||
_$PlaybackHistoryAlbumImpl _$$PlaybackHistoryAlbumImplFromJson(Map json) =>
|
||||
_$PlaybackHistoryAlbumImpl(
|
||||
date: DateTime.parse(json['date'] as String),
|
||||
playlist:
|
||||
PlaylistSimple.fromJson(json['playlist'] as Map<String, dynamic>),
|
||||
album:
|
||||
AlbumSimple.fromJson(Map<String, dynamic>.from(json['album'] as Map)),
|
||||
$type: json['runtimeType'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PlaybackHistoryPlaylistToJson(
|
||||
PlaybackHistoryPlaylist instance) =>
|
||||
Map<String, dynamic> _$$PlaybackHistoryAlbumImplToJson(
|
||||
_$PlaybackHistoryAlbumImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'date': instance.date.toIso8601String(),
|
||||
'playlist': instance.playlist,
|
||||
'album': instance.album.toJson(),
|
||||
'runtimeType': instance.$type,
|
||||
};
|
||||
|
||||
PlaybackHistoryAlbum _$PlaybackHistoryAlbumFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
PlaybackHistoryAlbum(
|
||||
_$PlaybackHistoryTrackImpl _$$PlaybackHistoryTrackImplFromJson(Map json) =>
|
||||
_$PlaybackHistoryTrackImpl(
|
||||
date: DateTime.parse(json['date'] as String),
|
||||
album: AlbumSimple.fromJson(json['album'] as Map<String, dynamic>),
|
||||
track:
|
||||
TrackSimple.fromJson(Map<String, dynamic>.from(json['track'] as Map)),
|
||||
$type: json['runtimeType'] as String?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PlaybackHistoryAlbumToJson(
|
||||
PlaybackHistoryAlbum instance) =>
|
||||
Map<String, dynamic> _$$PlaybackHistoryTrackImplToJson(
|
||||
_$PlaybackHistoryTrackImpl instance) =>
|
||||
<String, dynamic>{
|
||||
'date': instance.date.toIso8601String(),
|
||||
'album': instance.album,
|
||||
};
|
||||
|
||||
PlaybackHistoryTrack _$PlaybackHistoryTrackFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
PlaybackHistoryTrack(
|
||||
date: DateTime.parse(json['date'] as String),
|
||||
track: TrackSimple.fromJson(json['track'] as Map<String, dynamic>),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$PlaybackHistoryTrackToJson(
|
||||
PlaybackHistoryTrack instance) =>
|
||||
<String, dynamic>{
|
||||
'date': instance.date.toIso8601String(),
|
||||
'track': instance.track,
|
||||
'track': instance.track.toJson(),
|
||||
'runtimeType': instance.$type,
|
||||
};
|
||||
|
||||
@ -3,24 +3,50 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:catcher_2/catcher_2.dart';
|
||||
import 'package:palette_generator/palette_generator.dart';
|
||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/palette_provider.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/skip_segments.dart';
|
||||
import 'package:spotube/provider/server/sourced_track.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
|
||||
extension ProxyPlaylistListeners on ProxyPlaylistNotifier {
|
||||
Future<void> updatePalette() async {
|
||||
final palette = ref.read(paletteProvider);
|
||||
if (!preferences.albumColorSync) {
|
||||
if (palette != null) ref.read(paletteProvider.notifier).state = null;
|
||||
return;
|
||||
}
|
||||
return Future.microtask(() async {
|
||||
if (playlist.activeTrack == null) return;
|
||||
|
||||
final palette = await PaletteGenerator.fromImageProvider(
|
||||
UniversalImage.imageProvider(
|
||||
(playlist.activeTrack?.album?.images).asUrlString(
|
||||
placeholder: ImagePlaceholder.albumArt,
|
||||
),
|
||||
height: 50,
|
||||
width: 50,
|
||||
),
|
||||
);
|
||||
ref.read(paletteProvider.notifier).state = palette;
|
||||
});
|
||||
}
|
||||
|
||||
StreamSubscription subscribeToPlaylist() {
|
||||
return audioPlayer.playlistStream.listen((playlist) {
|
||||
state = state.copyWith(
|
||||
tracks: playlist.medias
|
||||
return audioPlayer.playlistStream.listen((mpvPlaylist) {
|
||||
state = playlist.copyWith(
|
||||
tracks: mpvPlaylist.medias
|
||||
.map((media) => SpotubeMedia.fromMedia(media).track)
|
||||
.toSet(),
|
||||
active: playlist.index,
|
||||
active: mpvPlaylist.index,
|
||||
);
|
||||
|
||||
notificationService.addTrack(state.activeTrack!);
|
||||
discord.updatePresence(state.activeTrack!);
|
||||
notificationService.addTrack(playlist.activeTrack!);
|
||||
discord.updatePresence(playlist.activeTrack!);
|
||||
updatePalette();
|
||||
});
|
||||
}
|
||||
@ -46,17 +72,18 @@ extension ProxyPlaylistListeners on ProxyPlaylistNotifier {
|
||||
String? lastScrobbled;
|
||||
return audioPlayer.positionStream.listen((position) {
|
||||
try {
|
||||
final uid = state.activeTrack is LocalTrack
|
||||
? (state.activeTrack as LocalTrack).path
|
||||
: state.activeTrack?.id;
|
||||
final uid = playlist.activeTrack is LocalTrack
|
||||
? (playlist.activeTrack as LocalTrack).path
|
||||
: playlist.activeTrack?.id;
|
||||
|
||||
if (state.activeTrack == null ||
|
||||
if (playlist.activeTrack == null ||
|
||||
lastScrobbled == uid ||
|
||||
position.inSeconds < 30) {
|
||||
return;
|
||||
}
|
||||
|
||||
scrobbler.scrobble(state.activeTrack!);
|
||||
scrobbler.scrobble(playlist.activeTrack!);
|
||||
history.addTracks([playlist.activeTrack!]);
|
||||
lastScrobbled = uid;
|
||||
} catch (e, stack) {
|
||||
Catcher2.reportCheckedError(e, stack);
|
||||
@ -68,9 +95,9 @@ extension ProxyPlaylistListeners on ProxyPlaylistNotifier {
|
||||
String lastTrack = ""; // used to prevent multiple calls to the same track
|
||||
return audioPlayer.positionStream.listen((event) async {
|
||||
if (event < const Duration(seconds: 3) ||
|
||||
state.active == null ||
|
||||
state.active == state.tracks.length - 1) return;
|
||||
final nextTrack = state.tracks.elementAt(state.active! + 1);
|
||||
playlist.active == null ||
|
||||
playlist.active == playlist.tracks.length - 1) return;
|
||||
final nextTrack = playlist.tracks.elementAt(playlist.active! + 1);
|
||||
|
||||
if (lastTrack == nextTrack.id || nextTrack is LocalTrack) return;
|
||||
|
||||
|
||||
@ -2,14 +2,12 @@ import 'dart:async';
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:palette_generator/palette_generator.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/image.dart';
|
||||
import 'package:spotube/extensions/track.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/history/history.dart';
|
||||
import 'package:spotube/provider/palette_provider.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/player_listeners.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart';
|
||||
@ -32,6 +30,8 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist> {
|
||||
ProxyPlaylist get playlist => state;
|
||||
BlackListNotifier get blacklist => ref.read(blacklistProvider.notifier);
|
||||
Discord get discord => ref.read(discordProvider);
|
||||
PlaybackHistoryNotifier get history =>
|
||||
ref.read(playbackHistoryProvider.notifier);
|
||||
|
||||
List<StreamSubscription> _subscriptions = [];
|
||||
|
||||
@ -167,28 +167,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier<ProxyPlaylist> {
|
||||
discord.clear();
|
||||
}
|
||||
|
||||
Future<void> updatePalette() async {
|
||||
final palette = ref.read(paletteProvider);
|
||||
if (!preferences.albumColorSync) {
|
||||
if (palette != null) ref.read(paletteProvider.notifier).state = null;
|
||||
return;
|
||||
}
|
||||
return Future.microtask(() async {
|
||||
if (state.activeTrack == null) return;
|
||||
|
||||
final palette = await PaletteGenerator.fromImageProvider(
|
||||
UniversalImage.imageProvider(
|
||||
(state.activeTrack?.album?.images).asUrlString(
|
||||
placeholder: ImagePlaceholder.albumArt,
|
||||
),
|
||||
height: 50,
|
||||
width: 50,
|
||||
),
|
||||
);
|
||||
ref.read(paletteProvider.notifier).state = palette;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
set state(state) {
|
||||
super.state = state;
|
||||
|
||||
@ -6,6 +6,7 @@ import 'package:path_provider/path_provider.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/components/settings/color_scheme_picker_dialog.dart';
|
||||
import 'package:spotube/provider/palette_provider.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/player_listeners.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/provider/user_preferences/user_preferences_state.dart';
|
||||
import 'package:spotube/services/audio_player/audio_player.dart';
|
||||
|
||||
@ -6,8 +6,7 @@ part of 'user_preferences_state.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$UserPreferencesImpl _$$UserPreferencesImplFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
_$UserPreferencesImpl _$$UserPreferencesImplFromJson(Map json) =>
|
||||
_$UserPreferencesImpl(
|
||||
audioQuality:
|
||||
$enumDecodeNullable(_$SourceQualitiesEnumMap, json['audioQuality']) ??
|
||||
|
||||
@ -3,7 +3,6 @@ import 'dart:io';
|
||||
import 'package:catcher_2/catcher_2.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/extensions/track.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/server/server.dart';
|
||||
import 'package:spotube/services/audio_player/custom_player.dart';
|
||||
|
||||
@ -6,8 +6,7 @@ part of 'song_link.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
_$SongLinkImpl _$$SongLinkImplFromJson(Map<String, dynamic> json) =>
|
||||
_$SongLinkImpl(
|
||||
_$SongLinkImpl _$$SongLinkImplFromJson(Map json) => _$SongLinkImpl(
|
||||
displayName: json['displayName'] as String,
|
||||
linkId: json['linkId'] as String,
|
||||
platform: json['platform'] as String,
|
||||
|
||||
@ -6,7 +6,7 @@ part of 'source_info.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
SourceInfo _$SourceInfoFromJson(Map<String, dynamic> json) => SourceInfo(
|
||||
SourceInfo _$SourceInfoFromJson(Map json) => SourceInfo(
|
||||
id: json['id'] as String,
|
||||
title: json['title'] as String,
|
||||
artist: json['artist'] as String,
|
||||
|
||||
@ -6,8 +6,7 @@ part of 'source_map.dart';
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
SourceQualityMap _$SourceQualityMapFromJson(Map<String, dynamic> json) =>
|
||||
SourceQualityMap(
|
||||
SourceQualityMap _$SourceQualityMapFromJson(Map json) => SourceQualityMap(
|
||||
high: json['high'] as String,
|
||||
medium: json['medium'] as String,
|
||||
low: json['low'] as String,
|
||||
@ -20,16 +19,18 @@ Map<String, dynamic> _$SourceQualityMapToJson(SourceQualityMap instance) =>
|
||||
'low': instance.low,
|
||||
};
|
||||
|
||||
SourceMap _$SourceMapFromJson(Map<String, dynamic> json) => SourceMap(
|
||||
SourceMap _$SourceMapFromJson(Map json) => SourceMap(
|
||||
weba: json['weba'] == null
|
||||
? null
|
||||
: SourceQualityMap.fromJson(json['weba'] as Map<String, dynamic>),
|
||||
: SourceQualityMap.fromJson(
|
||||
Map<String, dynamic>.from(json['weba'] as Map)),
|
||||
m4a: json['m4a'] == null
|
||||
? null
|
||||
: SourceQualityMap.fromJson(json['m4a'] as Map<String, dynamic>),
|
||||
: SourceQualityMap.fromJson(
|
||||
Map<String, dynamic>.from(json['m4a'] as Map)),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$SourceMapToJson(SourceMap instance) => <String, dynamic>{
|
||||
'weba': instance.weba,
|
||||
'm4a': instance.m4a,
|
||||
'weba': instance.weba?.toJson(),
|
||||
'm4a': instance.m4a?.toJson(),
|
||||
};
|
||||
|
||||
14
pubspec.lock
14
pubspec.lock
@ -2048,11 +2048,19 @@ packages:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
path: "."
|
||||
ref: "feat/to-json"
|
||||
resolved-ref: "05ace91cdfe64db23d8c62077069e7c25b3645cb"
|
||||
ref: "fix/explicit-to-json"
|
||||
resolved-ref: c4b37c599413ac7bfd78993e416a56105c62b634
|
||||
url: "https://github.com/KRTirtho/spotify-dart.git"
|
||||
source: git
|
||||
version: "0.13.5"
|
||||
version: "0.13.6"
|
||||
sprintf:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: sprintf
|
||||
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
sqflite:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@ -118,7 +118,7 @@ dependencies:
|
||||
spotify:
|
||||
git:
|
||||
url: https://github.com/KRTirtho/spotify-dart.git
|
||||
ref: feat/to-json
|
||||
ref: fix/explicit-to-json
|
||||
bonsoir: ^5.1.9
|
||||
shelf: ^1.4.1
|
||||
shelf_router: ^1.1.4
|
||||
|
||||
Loading…
Reference in New Issue
Block a user