diff --git a/flutter_client/lib/player/now_playing_screen.dart b/flutter_client/lib/player/now_playing_screen.dart new file mode 100644 index 00000000..7c192a5b --- /dev/null +++ b/flutter_client/lib/player/now_playing_screen.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../theme/theme_extension.dart'; +import 'player_provider.dart'; + +class NowPlayingScreen extends ConsumerWidget { + const NowPlayingScreen({super.key}); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final fs = Theme.of(context).extension()!; + final media = ref.watch(mediaItemProvider).valueOrNull; + final playback = ref.watch(playbackStateProvider).valueOrNull; + + if (media == null) { + return const Scaffold(body: Center(child: Text('Nothing playing.'))); + } + + final pos = playback?.updatePosition ?? Duration.zero; + final dur = media.duration ?? Duration.zero; + + return Scaffold( + backgroundColor: fs.obsidian, + appBar: AppBar( + backgroundColor: fs.obsidian, + leading: IconButton( + icon: Icon(Icons.expand_more, color: fs.parchment), + onPressed: () => Navigator.of(context).pop(), + ), + ), + body: SafeArea( + child: Padding( + padding: const EdgeInsets.all(24), + child: Column(children: [ + const Spacer(), + Container( + width: 280, height: 280, color: fs.slate, + ), + const SizedBox(height: 24), + Text(media.title, style: TextStyle(color: fs.parchment, fontSize: 22)), + Text(media.artist ?? '', style: TextStyle(color: fs.ash, fontSize: 14)), + const SizedBox(height: 16), + Slider( + activeColor: fs.accent, + min: 0, + max: dur.inMilliseconds.toDouble().clamp(1, double.infinity), + value: pos.inMilliseconds.toDouble().clamp(0, dur.inMilliseconds.toDouble()), + onChanged: (v) => ref.read(audioHandlerProvider).seek(Duration(milliseconds: v.toInt())), + ), + Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ + IconButton( + icon: Icon(Icons.skip_previous, color: fs.parchment, size: 32), + onPressed: () => ref.read(audioHandlerProvider).skipToPrevious(), + ), + IconButton( + iconSize: 56, + icon: Icon(playback?.playing == true ? Icons.pause_circle_filled : Icons.play_circle_filled, color: fs.accent), + onPressed: () { + final h = ref.read(audioHandlerProvider); + if (playback?.playing == true) { h.pause(); } else { h.play(); } + }, + ), + IconButton( + icon: Icon(Icons.skip_next, color: fs.parchment, size: 32), + onPressed: () => ref.read(audioHandlerProvider).skipToNext(), + ), + ]), + const Spacer(), + ]), + ), + ), + ); + } +} diff --git a/flutter_client/lib/shared/routing.dart b/flutter_client/lib/shared/routing.dart index b376aa5c..df417199 100644 --- a/flutter_client/lib/shared/routing.dart +++ b/flutter_client/lib/shared/routing.dart @@ -8,6 +8,7 @@ import '../auth/server_url_screen.dart'; import '../library/album_detail_screen.dart'; import '../library/artist_detail_screen.dart'; import '../library/home_screen.dart'; +import '../player/now_playing_screen.dart'; import '../player/player_bar.dart'; import 'widgets/version_gate.dart'; @@ -43,6 +44,7 @@ GoRouter buildRouter(Ref ref) { path: '/albums/:id', builder: (_, s) => AlbumDetailScreen(id: s.pathParameters['id']!), ), + GoRoute(path: '/now-playing', builder: (_, __) => const NowPlayingScreen()), ], ), ],