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