part of 'queue_tab.dart'; class _QueueItemSliverRow extends ConsumerWidget { final String itemId; final ColorScheme colorScheme; final Widget Function(BuildContext, DownloadItem, ColorScheme) itemBuilder; const _QueueItemSliverRow({ super.key, required this.itemId, required this.colorScheme, required this.itemBuilder, }); @override Widget build(BuildContext context, WidgetRef ref) { final item = ref.watch( downloadQueueLookupProvider.select((lookup) => lookup.byItemId[itemId]), ); if (item == null) { return const SizedBox.shrink(); } return RepaintBoundary(child: itemBuilder(context, item, colorScheme)); } } enum _CollectionEntryType { wishlist, loved, favoriteArtists, playlist } class _CollectionEntry { final _CollectionEntryType type; final int playlistIndex; const _CollectionEntry._(this.type, [this.playlistIndex = -1]); static const wishlist = _CollectionEntry._(_CollectionEntryType.wishlist); static const loved = _CollectionEntry._(_CollectionEntryType.loved); static const favoriteArtists = _CollectionEntry._( _CollectionEntryType.favoriteArtists, ); static _CollectionEntry playlist(int index) => _CollectionEntry._(_CollectionEntryType.playlist, index); } class _FilterChip extends StatelessWidget { final String label; final int count; final bool isSelected; final VoidCallback onTap; const _FilterChip({ required this.label, required this.count, required this.isSelected, required this.onTap, }); @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return FilterChip( label: Row( mainAxisSize: MainAxisSize.min, children: [ Text(label), const SizedBox(width: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: isSelected ? colorScheme.primary.withValues(alpha: 0.2) : colorScheme.outline.withValues(alpha: 0.2), borderRadius: BorderRadius.circular(10), ), child: Text( count.toString(), style: TextStyle( fontSize: 11, color: isSelected ? colorScheme.onPrimaryContainer : colorScheme.onSurfaceVariant, fontWeight: FontWeight.w500, ), ), ), ], ), selected: isSelected, onSelected: (_) => onTap(), showCheckmark: false, ); } } class _SelectionActionButton extends StatelessWidget { final IconData icon; final String label; final VoidCallback? onPressed; final ColorScheme colorScheme; const _SelectionActionButton({ required this.icon, required this.label, required this.onPressed, required this.colorScheme, }); @override Widget build(BuildContext context) { final isDisabled = onPressed == null; return Material( color: isDisabled ? colorScheme.surfaceContainerHighest.withValues(alpha: 0.5) : colorScheme.secondaryContainer, borderRadius: BorderRadius.circular(14), child: InkWell( onTap: onPressed, borderRadius: BorderRadius.circular(14), child: Padding( padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 12), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 18, color: isDisabled ? colorScheme.onSurfaceVariant.withValues(alpha: 0.5) : colorScheme.onSecondaryContainer, ), const SizedBox(width: 6), Flexible( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 13, fontWeight: FontWeight.w600, color: isDisabled ? colorScheme.onSurfaceVariant.withValues(alpha: 0.5) : colorScheme.onSecondaryContainer, ), ), ), ], ), ), ), ); } } class _AnimatedOverlayBottomBar extends StatefulWidget { final Widget child; const _AnimatedOverlayBottomBar({required this.child}); @override State<_AnimatedOverlayBottomBar> createState() => _AnimatedOverlayBottomBarState(); } class _AnimatedOverlayBottomBarState extends State<_AnimatedOverlayBottomBar> with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Animation _slideAnimation; late final Animation _fadeAnimation; @override void initState() { super.initState(); _controller = AnimationController( vsync: this, duration: const Duration(milliseconds: 240), ); final curve = CurvedAnimation( parent: _controller, curve: Curves.easeOutCubic, ); _slideAnimation = Tween( begin: const Offset(0, 0.08), end: Offset.zero, ).animate(curve); _fadeAnimation = Tween(begin: 0, end: 1).animate(curve); _controller.forward(); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return FadeTransition( opacity: _fadeAnimation, child: SlideTransition(position: _slideAnimation, child: widget.child), ); } }