mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
281 lines
9.0 KiB
Dart
281 lines
9.0 KiB
Dart
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:shadcn_flutter/shadcn_flutter.dart';
|
|
|
|
import 'package:shadcn_flutter/shadcn_flutter_extension.dart';
|
|
import 'package:spotube/collections/assets.gen.dart';
|
|
import 'package:spotube/collections/spotube_icons.dart';
|
|
import 'package:spotube/components/ui/button_tile.dart';
|
|
import 'package:spotube/extensions/constrains.dart';
|
|
import 'package:spotube/extensions/context.dart';
|
|
import 'package:spotube/models/metadata/metadata.dart';
|
|
import 'package:spotube/provider/track_options/track_options_provider.dart';
|
|
|
|
/// [track] must be a [SpotubeFullTrackObject] or [SpotubeLocalTrackObject]
|
|
class TrackOptions extends HookConsumerWidget {
|
|
final SpotubeTrackObject track;
|
|
final bool userPlaylist;
|
|
final String? playlistId;
|
|
final Widget? icon;
|
|
const TrackOptions({
|
|
super.key,
|
|
required this.track,
|
|
this.userPlaylist = false,
|
|
this.playlistId,
|
|
this.icon,
|
|
}) : assert(
|
|
track is SpotubeFullTrackObject || track is SpotubeLocalTrackObject,
|
|
"Track must be a SpotubeFullTrackObject, SpotubeLocalTrackObject",
|
|
);
|
|
|
|
@override
|
|
Widget build(BuildContext context, ref) {
|
|
final mediaQuery = MediaQuery.of(context);
|
|
final ThemeData(:colorScheme) = Theme.of(context);
|
|
|
|
final trackOptionActions = ref.watch(trackOptionActionsProvider(track));
|
|
final (
|
|
:isBlacklisted,
|
|
:isInDownloadQueue,
|
|
:isInQueue,
|
|
:isActiveTrack,
|
|
:isAuthenticated,
|
|
:isLiked,
|
|
:progressNotifier
|
|
) = ref.watch(trackOptionsStateProvider(track));
|
|
final isLocalTrack = track is SpotubeLocalTrackObject;
|
|
|
|
return Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
spacing: 8,
|
|
children: [
|
|
if (isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.delete,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.trash),
|
|
title: Text(context.l10n.delete),
|
|
),
|
|
if (mediaQuery.smAndDown && !isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.album,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.album),
|
|
title: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(context.l10n.go_to_album),
|
|
Text(
|
|
track.album.name,
|
|
style: context.theme.typography.xSmall,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
if (!isInQueue) ...[
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.addToQueue,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.queueAdd),
|
|
title: Text(context.l10n.add_to_queue),
|
|
),
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.playNext,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.lightning),
|
|
title: Text(context.l10n.play_next),
|
|
),
|
|
] else
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.removeFromQueue,
|
|
playlistId,
|
|
);
|
|
},
|
|
enabled: !isActiveTrack,
|
|
leading: const Icon(SpotubeIcons.queueRemove),
|
|
title: Text(context.l10n.remove_from_queue),
|
|
),
|
|
if (isAuthenticated && !isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.favorite,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: isLiked
|
|
? const Icon(
|
|
SpotubeIcons.heartFilled,
|
|
color: Colors.pink,
|
|
)
|
|
: const Icon(SpotubeIcons.heart),
|
|
title: Text(
|
|
isLiked
|
|
? context.l10n.remove_from_favorites
|
|
: context.l10n.save_as_favorite,
|
|
),
|
|
),
|
|
if (isAuthenticated && !isLocalTrack) ...[
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.startRadio,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.radio),
|
|
title: Text(context.l10n.start_a_radio),
|
|
),
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.addToPlaylist,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.playlistAdd),
|
|
title: Text(context.l10n.add_to_playlist),
|
|
),
|
|
],
|
|
if (userPlaylist && isAuthenticated && !isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.removeFromPlaylist,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.removeFilled),
|
|
title: Text(context.l10n.remove_from_playlist),
|
|
),
|
|
if (!isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.download,
|
|
playlistId,
|
|
);
|
|
},
|
|
enabled: !isInDownloadQueue,
|
|
leading: isInDownloadQueue
|
|
? HookBuilder(builder: (context) {
|
|
final progress = useListenable(progressNotifier);
|
|
return CircularProgressIndicator(
|
|
value: progress?.value,
|
|
);
|
|
})
|
|
: const Icon(SpotubeIcons.download),
|
|
title: Text(context.l10n.download_track),
|
|
),
|
|
if (!isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.blacklist,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: Icon(
|
|
SpotubeIcons.playlistRemove,
|
|
color: isBlacklisted != true ? Colors.red[400] : null,
|
|
),
|
|
title: Text(
|
|
isBlacklisted == true
|
|
? context.l10n.remove_from_blacklist
|
|
: context.l10n.add_to_blacklist,
|
|
style: TextStyle(
|
|
color: isBlacklisted != true ? Colors.red[400] : null,
|
|
),
|
|
),
|
|
),
|
|
if (!isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.share,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.share),
|
|
title: Text(context.l10n.share),
|
|
),
|
|
if (!isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.songlink,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: Assets.logos.songlinkTransparent.image(
|
|
width: 22,
|
|
height: 22,
|
|
color: colorScheme.foreground.withValues(alpha: 0.5),
|
|
),
|
|
title: Text(context.l10n.song_link),
|
|
),
|
|
if (!isLocalTrack)
|
|
ButtonTile(
|
|
style: ButtonVariance.menu,
|
|
onPressed: () async {
|
|
await trackOptionActions.action(
|
|
context,
|
|
TrackOptionValue.details,
|
|
playlistId,
|
|
);
|
|
},
|
|
leading: const Icon(SpotubeIcons.info),
|
|
title: Text(context.l10n.details),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|