mirror of
https://github.com/KRTirtho/spotube.git
synced 2025-09-13 07:55:18 +00:00
refactor: replace PopupMenuButton widgets with AdaptivePopSheetList
This commit is contained in:
parent
ddc1c5f373
commit
3b56c78d5c
@ -42,7 +42,7 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
||||
this.borderRadius = const BorderRadius.all(Radius.circular(999)),
|
||||
this.tooltip,
|
||||
}) : assert(
|
||||
icon != null || child != null,
|
||||
!(icon != null && child != null),
|
||||
'Either icon or child must be provided',
|
||||
);
|
||||
|
||||
@ -55,21 +55,14 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
||||
return PopupMenuButton(
|
||||
icon: icon,
|
||||
tooltip: tooltip,
|
||||
child: IgnorePointer(child: child),
|
||||
child: child == null ? null : IgnorePointer(child: child),
|
||||
itemBuilder: (context) => children
|
||||
.map(
|
||||
(item) => PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: ListTile(
|
||||
enabled: item.enabled,
|
||||
onTap: () {
|
||||
item.onTap?.call();
|
||||
Navigator.pop(context);
|
||||
if (item.value != null) {
|
||||
onSelected?.call(item.value as T);
|
||||
}
|
||||
},
|
||||
title: item.child,
|
||||
child: _AdaptivePopSheetListItem(
|
||||
item: item,
|
||||
onSelected: onSelected,
|
||||
),
|
||||
),
|
||||
)
|
||||
@ -90,7 +83,17 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (headings != null) ...[
|
||||
Container(
|
||||
width: 180,
|
||||
height: 6,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primary,
|
||||
borderRadius: BorderRadius.circular(999),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
...headings!,
|
||||
const SizedBox(height: 8),
|
||||
Divider(
|
||||
color: theme.colorScheme.primary,
|
||||
thickness: 0.3,
|
||||
@ -99,16 +102,9 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
...children.map(
|
||||
(item) => ListTile(
|
||||
onTap: () {
|
||||
item.onTap?.call();
|
||||
Navigator.pop(context);
|
||||
if (item.value != null) {
|
||||
onSelected?.call(item.value as T);
|
||||
}
|
||||
},
|
||||
enabled: item.enabled,
|
||||
title: item.child,
|
||||
(item) => _AdaptivePopSheetListItem(
|
||||
item: item,
|
||||
onSelected: onSelected,
|
||||
),
|
||||
)
|
||||
],
|
||||
@ -144,3 +140,41 @@ class AdaptivePopSheetList<T> extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AdaptivePopSheetListItem<T> extends StatelessWidget {
|
||||
final PopSheetEntry<T> item;
|
||||
final ValueChanged<T>? onSelected;
|
||||
const _AdaptivePopSheetListItem({
|
||||
super.key,
|
||||
required this.item,
|
||||
this.onSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return InkWell(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
onTap: !item.enabled
|
||||
? null
|
||||
: () {
|
||||
item.onTap?.call();
|
||||
Navigator.pop(context);
|
||||
if (item.value != null) {
|
||||
onSelected?.call(item.value as T);
|
||||
}
|
||||
},
|
||||
child: DefaultTextStyle(
|
||||
style: TextStyle(
|
||||
color: item.enabled
|
||||
? theme.textTheme.bodyMedium!.color
|
||||
: theme.textTheme.bodyMedium!.color!.withOpacity(0.5),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8),
|
||||
child: item.child,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -25,32 +25,50 @@ class SortTracksDropdown extends StatelessWidget {
|
||||
PopSheetEntry(
|
||||
value: SortBy.none,
|
||||
enabled: value != SortBy.none,
|
||||
child: Text(context.l10n.none),
|
||||
child: ListTile(
|
||||
enabled: value != SortBy.none,
|
||||
title: Text(context.l10n.none),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: SortBy.ascending,
|
||||
enabled: value != SortBy.ascending,
|
||||
child: Text(context.l10n.sort_a_z),
|
||||
child: ListTile(
|
||||
enabled: value != SortBy.ascending,
|
||||
title: Text(context.l10n.sort_a_z),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: SortBy.descending,
|
||||
enabled: value != SortBy.descending,
|
||||
child: Text(context.l10n.sort_z_a),
|
||||
child: ListTile(
|
||||
enabled: value != SortBy.descending,
|
||||
title: Text(context.l10n.sort_z_a),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: SortBy.dateAdded,
|
||||
enabled: value != SortBy.dateAdded,
|
||||
child: Text(context.l10n.sort_date),
|
||||
child: ListTile(
|
||||
enabled: value != SortBy.dateAdded,
|
||||
title: Text(context.l10n.sort_date),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: SortBy.artist,
|
||||
enabled: value != SortBy.artist,
|
||||
child: Text(context.l10n.sort_artist),
|
||||
child: ListTile(
|
||||
enabled: value != SortBy.artist,
|
||||
title: Text(context.l10n.sort_artist),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: SortBy.album,
|
||||
enabled: value != SortBy.album,
|
||||
child: Text(context.l10n.sort_album),
|
||||
child: ListTile(
|
||||
enabled: value != SortBy.album,
|
||||
title: Text(context.l10n.sort_album),
|
||||
),
|
||||
),
|
||||
],
|
||||
headings: [
|
||||
|
@ -7,15 +7,29 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/library/user_local_tracks.dart';
|
||||
import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart';
|
||||
import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart';
|
||||
import 'package:spotube/components/shared/heart_button.dart';
|
||||
import 'package:spotube/extensions/constrains.dart';
|
||||
import 'package:spotube/components/shared/image/universal_image.dart';
|
||||
import 'package:spotube/extensions/context.dart';
|
||||
import 'package:spotube/models/local_track.dart';
|
||||
import 'package:spotube/provider/authentication_provider.dart';
|
||||
import 'package:spotube/provider/blacklist_provider.dart';
|
||||
import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart';
|
||||
import 'package:spotube/services/mutations/mutations.dart';
|
||||
import 'package:spotube/utils/type_conversion_utils.dart';
|
||||
|
||||
enum TrackOptionValue {
|
||||
share,
|
||||
addToPlaylist,
|
||||
addToQueue,
|
||||
removeFromPlaylist,
|
||||
removeFromQueue,
|
||||
blacklist,
|
||||
delete,
|
||||
playNext,
|
||||
favorite,
|
||||
}
|
||||
|
||||
class TrackOptions extends HookConsumerWidget {
|
||||
final Track track;
|
||||
@ -80,151 +94,62 @@ class TrackOptions extends HookConsumerWidget {
|
||||
playlistId ?? "",
|
||||
);
|
||||
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
|
||||
final createItems = useCallback(
|
||||
(BuildContext context) {
|
||||
if (track is LocalTrack) {
|
||||
return [
|
||||
if (mediaQuery.isSm) ...[
|
||||
Text(
|
||||
track.name!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
thickness: 0.2,
|
||||
indent: 16,
|
||||
endIndent: 16,
|
||||
),
|
||||
],
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
await File((track as LocalTrack).path).delete();
|
||||
ref.refresh(localTracksProvider);
|
||||
if (context.mounted) Navigator.pop(context);
|
||||
},
|
||||
leading: const Icon(SpotubeIcons.trash),
|
||||
title: Text(context.l10n.delete),
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
if (mediaQuery.isSm) ...[
|
||||
Text(
|
||||
track.name!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
Divider(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
thickness: 0.2,
|
||||
indent: 16,
|
||||
endIndent: 16,
|
||||
),
|
||||
],
|
||||
if (!playlist.containsTrack(track)) ...[
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
await playback.addTrack(track);
|
||||
if (context.mounted) {
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
context.l10n.added_track_to_queue(track.name!),
|
||||
),
|
||||
),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
leading: const Icon(SpotubeIcons.queueAdd),
|
||||
title: Text(context.l10n.add_to_queue),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
playback.addTracksAtFirst([track]);
|
||||
return ListTileTheme(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: AdaptivePopSheetList<TrackOptionValue>(
|
||||
onSelected: (value) async {
|
||||
switch (value) {
|
||||
case TrackOptionValue.delete:
|
||||
await File((track as LocalTrack).path).delete();
|
||||
ref.refresh(localTracksProvider);
|
||||
break;
|
||||
case TrackOptionValue.addToQueue:
|
||||
await playback.addTrack(track);
|
||||
if (context.mounted) {
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
context.l10n.track_will_play_next(track.name!),
|
||||
context.l10n.added_track_to_queue(track.name!),
|
||||
),
|
||||
),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
leading: const Icon(SpotubeIcons.lightning),
|
||||
title: Text(context.l10n.play_next),
|
||||
),
|
||||
] else
|
||||
ListTile(
|
||||
onTap: playlist.activeTrack?.id == track.id
|
||||
? null
|
||||
: () {
|
||||
playback.removeTrack(track.id!);
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
context.l10n.removed_track_from_queue(
|
||||
track.name!,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
enabled: playlist.activeTrack?.id != track.id,
|
||||
leading: const Icon(SpotubeIcons.queueRemove),
|
||||
title: Text(context.l10n.remove_from_queue),
|
||||
),
|
||||
if (favorites.me.hasData)
|
||||
ListTile(
|
||||
onTap: () {
|
||||
favorites.toggleTrackLike.mutate(favorites.isLiked);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
leading: favorites.isLiked
|
||||
? const Icon(
|
||||
SpotubeIcons.heartFilled,
|
||||
color: Colors.pink,
|
||||
)
|
||||
: const Icon(SpotubeIcons.heart),
|
||||
title: Text(
|
||||
favorites.isLiked
|
||||
? context.l10n.remove_from_favorites
|
||||
: context.l10n.save_as_favorite,
|
||||
),
|
||||
),
|
||||
if (auth != null)
|
||||
ListTile(
|
||||
onTap: () {
|
||||
actionAddToPlaylist(context, track);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
leading: const Icon(SpotubeIcons.playlistAdd),
|
||||
title: Text(context.l10n.add_to_playlist),
|
||||
),
|
||||
if (userPlaylist && auth != null)
|
||||
ListTile(
|
||||
onTap: () {
|
||||
removingTrack.value = track.uri;
|
||||
removeTrack.mutate(track.uri!);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
leading: (removeTrack.isMutating || !removeTrack.hasData) &&
|
||||
removingTrack.value == track.uri
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: const Icon(SpotubeIcons.removeFilled),
|
||||
title: Text(context.l10n.remove_from_playlist),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
}
|
||||
break;
|
||||
case TrackOptionValue.playNext:
|
||||
playback.addTracksAtFirst([track]);
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
context.l10n.track_will_play_next(track.name!),
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case TrackOptionValue.removeFromQueue:
|
||||
playback.removeTrack(track.id!);
|
||||
scaffoldMessenger.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
context.l10n.removed_track_from_queue(
|
||||
track.name!,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case TrackOptionValue.favorite:
|
||||
favorites.toggleTrackLike.mutate(favorites.isLiked);
|
||||
break;
|
||||
case TrackOptionValue.addToPlaylist:
|
||||
actionAddToPlaylist(context, track);
|
||||
break;
|
||||
case TrackOptionValue.removeFromPlaylist:
|
||||
removingTrack.value = track.uri;
|
||||
removeTrack.mutate(track.uri!);
|
||||
break;
|
||||
case TrackOptionValue.blacklist:
|
||||
if (isBlackListed) {
|
||||
ref.read(BlackListNotifier.provider.notifier).remove(
|
||||
BlacklistedElement.track(track.id!, track.name!),
|
||||
@ -234,69 +159,139 @@ class TrackOptions extends HookConsumerWidget {
|
||||
BlacklistedElement.track(track.id!, track.name!),
|
||||
);
|
||||
}
|
||||
Navigator.pop(context);
|
||||
},
|
||||
leading: const Icon(SpotubeIcons.playlistRemove),
|
||||
iconColor: !isBlackListed ? Colors.red[400] : null,
|
||||
textColor: !isBlackListed ? Colors.red[400] : null,
|
||||
break;
|
||||
case TrackOptionValue.share:
|
||||
actionShare(context, track);
|
||||
break;
|
||||
}
|
||||
},
|
||||
icon: const Icon(SpotubeIcons.moreHorizontal),
|
||||
headings: [
|
||||
ListTile(
|
||||
dense: true,
|
||||
leading: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: UniversalImage(
|
||||
path: TypeConversionUtils.image_X_UrlString(
|
||||
track.album!.images,
|
||||
placeholder: ImagePlaceholder.albumArt),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
isBlackListed
|
||||
? context.l10n.remove_from_blacklist
|
||||
: context.l10n.add_to_blacklist,
|
||||
track.name!,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
subtitle: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: TypeConversionUtils.artists_X_ClickableArtists(
|
||||
track.artists!,
|
||||
),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () {
|
||||
actionShare(context, track);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
leading: const Icon(SpotubeIcons.share),
|
||||
title: Text(context.l10n.share),
|
||||
)
|
||||
];
|
||||
},
|
||||
[track, playlist, favorites, auth, isBlackListed, mediaQuery],
|
||||
);
|
||||
|
||||
if (mediaQuery.isSm) {
|
||||
return IconButton(
|
||||
icon: const Icon(SpotubeIcons.moreHorizontal),
|
||||
onPressed: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
builder: (context) => Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: ListTileTheme(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
],
|
||||
children: switch (track.runtimeType) {
|
||||
LocalTrack => [
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.delete,
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.trash),
|
||||
title: Text(context.l10n.delete),
|
||||
),
|
||||
horizontalTitleGap: 5,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: createItems(context),
|
||||
)
|
||||
],
|
||||
_ => [
|
||||
if (!playlist.containsTrack(track)) ...[
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.addToQueue,
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.queueAdd),
|
||||
title: Text(context.l10n.add_to_queue),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.playNext,
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.lightning),
|
||||
title: Text(context.l10n.play_next),
|
||||
),
|
||||
),
|
||||
] else
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.removeFromQueue,
|
||||
enabled: playlist.activeTrack?.id != track.id,
|
||||
child: ListTile(
|
||||
enabled: playlist.activeTrack?.id != track.id,
|
||||
leading: const Icon(SpotubeIcons.queueRemove),
|
||||
title: Text(context.l10n.remove_from_queue),
|
||||
),
|
||||
),
|
||||
if (favorites.me.hasData)
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.favorite,
|
||||
child: ListTile(
|
||||
leading: favorites.isLiked
|
||||
? const Icon(
|
||||
SpotubeIcons.heartFilled,
|
||||
color: Colors.pink,
|
||||
)
|
||||
: const Icon(SpotubeIcons.heart),
|
||||
title: Text(
|
||||
favorites.isLiked
|
||||
? context.l10n.remove_from_favorites
|
||||
: context.l10n.save_as_favorite,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (auth != null)
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.addToPlaylist,
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.playlistAdd),
|
||||
title: Text(context.l10n.add_to_playlist),
|
||||
),
|
||||
),
|
||||
if (userPlaylist && auth != null)
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.removeFromPlaylist,
|
||||
child: ListTile(
|
||||
leading: (removeTrack.isMutating || !removeTrack.hasData) &&
|
||||
removingTrack.value == track.uri
|
||||
? const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
)
|
||||
: const Icon(SpotubeIcons.removeFilled),
|
||||
title: Text(context.l10n.remove_from_playlist),
|
||||
),
|
||||
),
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.blacklist,
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.playlistRemove),
|
||||
iconColor: !isBlackListed ? Colors.red[400] : null,
|
||||
textColor: !isBlackListed ? Colors.red[400] : null,
|
||||
title: Text(
|
||||
isBlackListed
|
||||
? context.l10n.remove_from_blacklist
|
||||
: context.l10n.add_to_blacklist,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
useRootNavigator: true,
|
||||
);
|
||||
PopSheetEntry(
|
||||
value: TrackOptionValue.share,
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.share),
|
||||
title: Text(context.l10n.share),
|
||||
),
|
||||
)
|
||||
]
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return PopupMenuButton(
|
||||
icon: const Icon(SpotubeIcons.moreHorizontal),
|
||||
position: PopupMenuPosition.under,
|
||||
tooltip: context.l10n.more_actions,
|
||||
itemBuilder: (context) {
|
||||
return createItems(context)
|
||||
.map(
|
||||
(e) => PopupMenuItem(
|
||||
padding: EdgeInsets.zero,
|
||||
child: e,
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
|
||||
import 'package:spotify/spotify.dart';
|
||||
import 'package:spotube/collections/spotube_icons.dart';
|
||||
import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart';
|
||||
import 'package:spotube/components/shared/dialogs/confirm_download_dialog.dart';
|
||||
import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart';
|
||||
import 'package:spotube/components/shared/fallbacks/not_found.dart';
|
||||
@ -138,70 +139,63 @@ class TracksTableView extends HookConsumerWidget {
|
||||
.state = value;
|
||||
},
|
||||
),
|
||||
PopupMenuButton(
|
||||
AdaptivePopSheetList(
|
||||
tooltip: context.l10n.more_actions,
|
||||
itemBuilder: (context) {
|
||||
return [
|
||||
PopupMenuItem(
|
||||
headings: [
|
||||
Text(
|
||||
context.l10n.more_actions,
|
||||
style: tableHeadStyle,
|
||||
),
|
||||
],
|
||||
children: [
|
||||
PopSheetEntry(
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "download",
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.download),
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "download",
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(SpotubeIcons.download),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
context.l10n
|
||||
.download_count(selectedTracks.length),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
context.l10n.download_count(selectedTracks.length),
|
||||
),
|
||||
),
|
||||
if (!userPlaylist)
|
||||
PopupMenuItem(
|
||||
),
|
||||
if (!userPlaylist)
|
||||
PopSheetEntry(
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "add-to-playlist",
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.playlistAdd),
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "add-to-playlist",
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(SpotubeIcons.playlistAdd),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
context.l10n.add_count_to_playlist(
|
||||
selectedTracks.length,
|
||||
),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
context.l10n
|
||||
.add_count_to_playlist(selectedTracks.length),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
),
|
||||
PopSheetEntry(
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "add-to-queue",
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.queueAdd),
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "add-to-queue",
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(SpotubeIcons.queueAdd),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
context.l10n
|
||||
.add_count_to_queue(selectedTracks.length),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
context.l10n
|
||||
.add_count_to_queue(selectedTracks.length),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
),
|
||||
PopSheetEntry(
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "play-next",
|
||||
child: ListTile(
|
||||
leading: const Icon(SpotubeIcons.lightning),
|
||||
enabled: selectedTracks.isNotEmpty,
|
||||
value: "play-next",
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(SpotubeIcons.lightning),
|
||||
const SizedBox(width: 5),
|
||||
Text(
|
||||
context.l10n
|
||||
.play_count_next(selectedTracks.length),
|
||||
),
|
||||
],
|
||||
title: Text(
|
||||
context.l10n.play_count_next(selectedTracks.length),
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
],
|
||||
onSelected: (action) async {
|
||||
switch (action) {
|
||||
case "download":
|
||||
|
Loading…
Reference in New Issue
Block a user