import 'dart:io'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotiflac_android/providers/music_player_provider.dart'; import 'package:spotiflac_android/screens/now_playing_screen.dart'; import 'package:spotiflac_android/services/cover_cache_manager.dart'; import 'package:spotiflac_android/widgets/settings_group.dart'; class MiniPlayer extends ConsumerWidget { const MiniPlayer({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final mediaItem = ref.watch(currentMediaItemProvider).value; if (mediaItem == null) return const SizedBox.shrink(); final playback = ref.watch(playbackStateProvider).value; final isPlaying = playback?.playing ?? false; final controller = ref.read(musicPlayerControllerProvider); final colorScheme = Theme.of(context).colorScheme; final duration = mediaItem.duration?.inMilliseconds ?? 0; final position = playback?.position.inMilliseconds ?? 0; final progress = duration > 0 ? (position / duration).clamp(0.0, 1.0) : 0.0; return DecoratedBox( position: DecorationPosition.foreground, decoration: BoxDecoration( border: Border( top: BorderSide( color: colorScheme.outlineVariant.withValues(alpha: 0.5), ), ), ), child: Material( color: settingsGroupColor(context).withValues(alpha: 0.72), child: InkWell( onTap: () { Navigator.of(context, rootNavigator: true).push( MaterialPageRoute( builder: (_) => const NowPlayingScreen(), fullscreenDialog: true, ), ); }, child: Column( mainAxisSize: MainAxisSize.min, children: [ LinearProgressIndicator( value: progress, minHeight: 2, backgroundColor: colorScheme.surfaceContainerHighest, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), child: Row( children: [ ClipRRect( borderRadius: BorderRadius.circular(6), child: SizedBox( width: 44, height: 44, child: _MiniArt( artUri: mediaItem.artUri?.toString(), colorScheme: colorScheme, ), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( mediaItem.title, style: Theme.of(context).textTheme.titleSmall ?.copyWith(fontWeight: FontWeight.w600), maxLines: 1, overflow: TextOverflow.ellipsis, ), Text( mediaItem.artist ?? '', style: Theme.of(context).textTheme.bodySmall ?.copyWith(color: colorScheme.onSurfaceVariant), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), IconButton( icon: Icon(isPlaying ? Icons.pause : Icons.play_arrow), onPressed: () => controller.togglePlayPause(isPlaying), ), IconButton( icon: const Icon(Icons.skip_next), onPressed: controller.next, ), ], ), ), ], ), ), ), ); } } class _MiniArt extends StatelessWidget { final String? artUri; final ColorScheme colorScheme; const _MiniArt({required this.artUri, required this.colorScheme}); @override Widget build(BuildContext context) { final placeholder = Container( color: colorScheme.surfaceContainerHighest, child: Icon( Icons.music_note, size: 22, color: colorScheme.onSurfaceVariant, ), ); final uri = artUri; if (uri == null || uri.isEmpty) return placeholder; if (uri.startsWith('http')) { return CachedNetworkImage( imageUrl: uri, fit: BoxFit.cover, cacheManager: CoverCacheManager.instance, memCacheWidth: 132, fadeInDuration: const Duration(milliseconds: 150), fadeOutDuration: const Duration(milliseconds: 0), placeholder: (_, _) => placeholder, errorWidget: (_, _, _) => placeholder, ); } if (uri.startsWith('file://')) { return Image.file( File(Uri.parse(uri).toFilePath()), fit: BoxFit.cover, cacheWidth: 132, errorBuilder: (_, _, _) => placeholder, ); } return placeholder; } }