import 'package:audio_service/audio_service.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../shared/cover.dart'; import '../shared/theme.dart'; import 'audio_handler.dart'; /// Vollbild-Wiedergabe: Cover, Titel, Fortschritt, Transport-Controls. class NowPlayingScreen extends StatelessWidget { const NowPlayingScreen({super.key}); @override Widget build(BuildContext context) { final handler = context.read(); return Scaffold( appBar: AppBar( backgroundColor: Colors.transparent, leading: IconButton( icon: const Icon(Icons.keyboard_arrow_down), onPressed: () => Navigator.of(context).maybePop(), ), ), body: SafeArea( child: StreamBuilder( stream: handler.mediaItem, builder: (context, snapshot) { final item = snapshot.data; if (item == null) { return const Center(child: Text('Nichts in Wiedergabe')); } return Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Column( children: [ Expanded(child: Center(child: _Cover(item: item))), const SizedBox(height: 24), Text( item.title, style: Theme.of(context).textTheme.headlineSmall, maxLines: 2, overflow: TextOverflow.ellipsis, textAlign: TextAlign.center, ), const SizedBox(height: 8), Text( item.artist ?? 'Unbekannt', style: const TextStyle(color: Colors.white54), ), const SizedBox(height: 24), _ProgressBar(handler: handler), const _Controls(), const SizedBox(height: 16), ], ), ); }, ), ), ); } } class _Cover extends StatelessWidget { const _Cover({required this.item}); final MediaItem item; @override Widget build(BuildContext context) { return AspectRatio( aspectRatio: 1, child: CoverImage(artUri: item.artUri, radius: 16), ); } } class _ProgressBar extends StatelessWidget { const _ProgressBar({required this.handler}); final MeloAudioHandler handler; @override Widget build(BuildContext context) { return StreamBuilder( stream: handler.durationStream, builder: (context, dSnap) { final total = dSnap.data ?? Duration.zero; return StreamBuilder( stream: handler.positionStream, builder: (context, pSnap) { var position = pSnap.data ?? Duration.zero; final hasDuration = total > Duration.zero; if (hasDuration && position > total) position = total; final maxMs = hasDuration ? total.inMilliseconds.toDouble() : 1.0; final valueMs = position.inMilliseconds.toDouble().clamp(0.0, maxMs).toDouble(); return Column( children: [ Slider( value: valueMs, max: maxMs, onChanged: hasDuration ? (v) => handler.seek(Duration(milliseconds: v.round())) : null, ), Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text(_fmt(position), style: const TextStyle(color: Colors.white54)), Text(_fmt(total), style: const TextStyle(color: Colors.white54)), ], ), ), ], ); }, ); }, ); } static String _fmt(Duration d) { final m = d.inMinutes.remainder(60).toString().padLeft(2, '0'); final s = d.inSeconds.remainder(60).toString().padLeft(2, '0'); return '$m:$s'; } } class _Controls extends StatelessWidget { const _Controls(); @override Widget build(BuildContext context) { final handler = context.read(); return StreamBuilder( stream: handler.playbackState, builder: (context, snapshot) { final state = snapshot.data; final playing = state?.playing ?? false; final shuffle = state?.shuffleMode == AudioServiceShuffleMode.all; final repeat = state?.repeatMode ?? AudioServiceRepeatMode.none; return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ IconButton( icon: Icon(Icons.shuffle, color: shuffle ? MeloTheme.red : Colors.white54), onPressed: () => handler.setShuffleMode(shuffle ? AudioServiceShuffleMode.none : AudioServiceShuffleMode.all), ), IconButton( iconSize: 40, icon: const Icon(Icons.skip_previous), onPressed: handler.skipToPrevious, ), IconButton( iconSize: 64, icon: Icon(playing ? Icons.pause_circle : Icons.play_circle, color: MeloTheme.red), onPressed: playing ? handler.pause : handler.play, ), IconButton( iconSize: 40, icon: const Icon(Icons.skip_next), onPressed: handler.skipToNext, ), IconButton( icon: Icon( repeat == AudioServiceRepeatMode.one ? Icons.repeat_one : Icons.repeat, color: repeat == AudioServiceRepeatMode.none ? Colors.white54 : MeloTheme.red, ), onPressed: () => handler.setRepeatMode(switch (repeat) { AudioServiceRepeatMode.none => AudioServiceRepeatMode.all, AudioServiceRepeatMode.all => AudioServiceRepeatMode.one, _ => AudioServiceRepeatMode.none, }), ), ], ); }, ); } }