mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-12 23:45:18 +00:00
197 lines
6.4 KiB
Dart
197 lines
6.4 KiB
Dart
import 'package:auto_route/auto_route.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shadcn_flutter/shadcn_flutter.dart' hide Consumer;
|
|
import 'package:spotube/collections/routes.gr.dart';
|
|
import 'package:spotube/components/dialogs/select_device_dialog.dart';
|
|
import 'package:spotube/components/playbutton_view/playbutton_card.dart';
|
|
import 'package:spotube/components/playbutton_view/playbutton_tile.dart';
|
|
import 'package:spotube/extensions/context.dart';
|
|
import 'package:spotube/models/connect/connect.dart';
|
|
import 'package:spotube/models/metadata/metadata.dart';
|
|
import 'package:spotube/provider/audio_player/querying_track_info.dart';
|
|
import 'package:spotube/provider/connect/connect.dart';
|
|
import 'package:spotube/provider/history/history.dart';
|
|
import 'package:spotube/provider/audio_player/audio_player.dart';
|
|
import 'package:spotube/provider/metadata_plugin/library/tracks.dart';
|
|
import 'package:spotube/provider/metadata_plugin/tracks/playlist.dart';
|
|
import 'package:spotube/provider/metadata_plugin/user.dart';
|
|
import 'package:spotube/services/audio_player/audio_player.dart';
|
|
|
|
class PlaylistCard extends HookConsumerWidget {
|
|
final SpotubeSimplePlaylistObject playlist;
|
|
final bool _isTile;
|
|
|
|
const PlaylistCard(
|
|
this.playlist, {
|
|
super.key,
|
|
}) : _isTile = false;
|
|
|
|
const PlaylistCard.tile(
|
|
this.playlist, {
|
|
super.key,
|
|
}) : _isTile = true;
|
|
|
|
@override
|
|
Widget build(BuildContext context, ref) {
|
|
final playlistQueue = ref.watch(audioPlayerProvider);
|
|
final playlistNotifier = ref.watch(audioPlayerProvider.notifier);
|
|
final isFetchingActiveTrack = ref.watch(queryingTrackInfoProvider);
|
|
final historyNotifier = ref.read(playbackHistoryActionsProvider);
|
|
|
|
final playing =
|
|
useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying;
|
|
bool isPlaylistPlaying = useMemoized(
|
|
() => playlistQueue.containsCollection(playlist.id),
|
|
[playlistQueue, playlist.id],
|
|
);
|
|
|
|
final updating = useState(false);
|
|
final me = ref.watch(metadataPluginUserProvider);
|
|
|
|
Future<List<SpotubeTrackObject>> fetchInitialTracks() async {
|
|
if (playlist.id == 'user-liked-tracks') {
|
|
final tracks = await ref.read(metadataPluginSavedTracksProvider.future);
|
|
return tracks.items;
|
|
}
|
|
|
|
final result = await ref
|
|
.read(metadataPluginPlaylistTracksProvider(playlist.id).future);
|
|
|
|
return result.items;
|
|
}
|
|
|
|
Future<List<SpotubeTrackObject>> fetchAllTracks() async {
|
|
await fetchInitialTracks();
|
|
|
|
if (playlist.id == 'user-liked-tracks') {
|
|
return ref.read(metadataPluginSavedTracksProvider.notifier).fetchAll();
|
|
}
|
|
|
|
return ref
|
|
.read(metadataPluginPlaylistTracksProvider(playlist.id).notifier)
|
|
.fetchAll();
|
|
}
|
|
|
|
void onTap() {
|
|
context.navigateTo(PlaylistRoute(id: playlist.id, playlist: playlist));
|
|
}
|
|
|
|
void onPlaybuttonPressed() async {
|
|
try {
|
|
updating.value = true;
|
|
if (isPlaylistPlaying && playing) {
|
|
return audioPlayer.pause();
|
|
} else if (isPlaylistPlaying && !playing) {
|
|
return audioPlayer.resume();
|
|
}
|
|
|
|
final fetchedInitialTracks = await fetchInitialTracks();
|
|
|
|
if (fetchedInitialTracks.isEmpty || !context.mounted) return;
|
|
|
|
final isRemoteDevice = await showSelectDeviceDialog(context, ref);
|
|
if (isRemoteDevice == null) return;
|
|
if (isRemoteDevice) {
|
|
final remotePlayback = ref.read(connectProvider.notifier);
|
|
final allTracks = await fetchAllTracks();
|
|
await remotePlayback.load(
|
|
WebSocketLoadEventData.playlist(
|
|
tracks: allTracks as List<SpotubeFullTrackObject>,
|
|
collection: playlist,
|
|
),
|
|
);
|
|
} else {
|
|
await playlistNotifier.load(fetchedInitialTracks, autoPlay: true);
|
|
playlistNotifier.addCollection(playlist.id);
|
|
historyNotifier.addPlaylists([playlist]);
|
|
|
|
final allTracks = await fetchAllTracks();
|
|
|
|
await playlistNotifier
|
|
.addTracks(allTracks.sublist(fetchedInitialTracks.length));
|
|
}
|
|
} finally {
|
|
if (context.mounted) {
|
|
updating.value = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void onAddToQueuePressed() async {
|
|
updating.value = true;
|
|
try {
|
|
if (isPlaylistPlaying) return;
|
|
|
|
final fetchedInitialTracks = await fetchAllTracks();
|
|
|
|
if (fetchedInitialTracks.isEmpty) return;
|
|
|
|
playlistNotifier.addTracks(fetchedInitialTracks);
|
|
playlistNotifier.addCollection(playlist.id);
|
|
historyNotifier.addPlaylists([playlist]);
|
|
if (context.mounted) {
|
|
showToast(
|
|
context: context,
|
|
builder: (context, overlay) {
|
|
return SurfaceCard(
|
|
child: Basic(
|
|
content: Text(
|
|
context.l10n
|
|
.added_num_tracks_to_queue(fetchedInitialTracks.length),
|
|
),
|
|
trailing: Button.outline(
|
|
child: Text(context.l10n.undo),
|
|
onPressed: () {
|
|
playlistNotifier
|
|
.removeTracks(fetchedInitialTracks.map((e) => e.id));
|
|
},
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
} finally {
|
|
updating.value = false;
|
|
}
|
|
}
|
|
|
|
final imageUrl = playlist.images.asUrlString(
|
|
placeholder: ImagePlaceholder.collection,
|
|
);
|
|
final isLoading =
|
|
(isPlaylistPlaying && isFetchingActiveTrack) || updating.value;
|
|
final isOwner = playlist.owner.id == me.asData?.value?.id &&
|
|
me.asData?.value?.id != null;
|
|
|
|
if (_isTile) {
|
|
return PlaybuttonTile(
|
|
title: playlist.name,
|
|
description: playlist.description,
|
|
image: null,
|
|
imageUrl: imageUrl,
|
|
isPlaying: isPlaylistPlaying,
|
|
isLoading: isLoading,
|
|
isOwner: isOwner,
|
|
onTap: onTap,
|
|
onPlaybuttonPressed: onPlaybuttonPressed,
|
|
onAddToQueuePressed: onAddToQueuePressed,
|
|
);
|
|
}
|
|
|
|
return PlaybuttonCard(
|
|
title: playlist.name,
|
|
description: playlist.description,
|
|
image: null,
|
|
imageUrl: imageUrl,
|
|
isPlaying: isPlaylistPlaying,
|
|
isLoading: isLoading,
|
|
isOwner: isOwner,
|
|
onTap: onTap,
|
|
onPlaybuttonPressed: onPlaybuttonPressed,
|
|
onAddToQueuePressed: onAddToQueuePressed,
|
|
);
|
|
}
|
|
}
|