From f4595d5f64afbe0e3fe63ca27fdaaf0a44ddb7e1 Mon Sep 17 00:00:00 2001 From: LOSSES Don <1384036+Losses@users.noreply.github.com> Date: Sun, 20 Oct 2024 22:13:46 +0800 Subject: [PATCH] feat: Implement playback controller buttons for the Zune view --- .../widgets/small_screen_playing_track.dart | 183 +++++++++++++----- .../controller_buttons.dart | 2 +- pubspec.lock | 4 +- pubspec.yaml | 2 +- 4 files changed, 136 insertions(+), 55 deletions(-) diff --git a/lib/screens/cover_wall/widgets/small_screen_playing_track.dart b/lib/screens/cover_wall/widgets/small_screen_playing_track.dart index e5e273586..926796d0a 100644 --- a/lib/screens/cover_wall/widgets/small_screen_playing_track.dart +++ b/lib/screens/cover_wall/widgets/small_screen_playing_track.dart @@ -1,5 +1,9 @@ +import 'package:material_symbols_icons/symbols.dart'; import 'package:provider/provider.dart'; import 'package:fluent_ui/fluent_ui.dart'; +import 'package:rune/providers/playback_controller.dart'; +import 'package:rune/providers/volume.dart'; +import 'package:rune/widgets/playback_controller/constants/controller_items.dart'; import '../../../utils/ax_shadow.dart'; import '../../../utils/format_time.dart'; @@ -27,14 +31,17 @@ class SmallScreenPlayingTrack extends StatelessWidget { final width = MediaQuery.of(context).size.width; + Provider.of(context); + return Selector( + (String?, String?, String?, String?, double?, String?)>( selector: (context, playbackStatusProvider) => ( playbackStatusProvider.playbackStatus?.coverArtPath, playbackStatusProvider.playbackStatus?.artist, playbackStatusProvider.playbackStatus?.album, playbackStatusProvider.playbackStatus?.title, playbackStatusProvider.playbackStatus?.duration, + playbackStatusProvider.playbackStatus?.state, ), builder: (context, p, child) { if (p.$1 == null) return Container(); @@ -50,68 +57,142 @@ class SmallScreenPlayingTrack extends StatelessWidget { playbackControllerHeight + 12, ), constraints: const BoxConstraints(maxWidth: 240), - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SmallerOrEqualTo( - breakpoint: DeviceType.zune, - builder: (context, isSmaller) { - if (isSmaller) return Container(); - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10), - child: Container( - decoration: BoxDecoration( - border: Border.all(color: Colors.white, width: 4), - boxShadow: axShadow(9), - ), - child: AspectRatio( - aspectRatio: 1, - child: CoverArt( - hint: ( - p.$3 ?? "", - p.$2 ?? "", - 'Total Time ${formatTime(p.$5 ?? 0)}' + child: SmallerOrEqualTo( + breakpoint: DeviceType.zune, + builder: (context, isZune) { + return Column( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (!isZune) + Container( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Container( + decoration: BoxDecoration( + border: Border.all(color: Colors.white, width: 4), + boxShadow: axShadow(9), + ), + child: AspectRatio( + aspectRatio: 1, + child: CoverArt( + hint: ( + p.$3 ?? "", + p.$2 ?? "", + 'Total Time ${formatTime(p.$5 ?? 0)}' + ), + key: p.$1 != null ? Key(p.$1.toString()) : null, + path: p.$1, + size: (width - 20).clamp(0, 240), ), - key: p.$1 != null ? Key(p.$1.toString()) : null, - path: p.$1, - size: (width - 20).clamp(0, 240), ), ), ), - ); - }, - ), - SmallerOrEqualTo( - breakpoint: DeviceType.zune, - builder: (context, isSmaller) { - if (isSmaller) return Container(); - - return Transform.translate( + if (!isZune) + Transform.translate( offset: const Offset(0, -16), child: SizedBox( height: 80, child: CoverArtPageProgressBar(shadows: shadows), ), - ); - }), - const SizedBox(height: 8), - Text( - p.$4 ?? "Unknown Track", - style: typography.subtitle?.apply(shadows: shadows), - textAlign: TextAlign.center, - ), - const SizedBox(height: 12), - Text( - '$artist · $album', - style: - typography.body?.apply(shadows: shadows, heightFactor: 2), - textAlign: TextAlign.center, - ), - ], + ), + const SizedBox(height: 8), + Text( + p.$4 ?? "Unknown Track", + style: typography.subtitle?.apply(shadows: shadows), + textAlign: TextAlign.center, + ), + const SizedBox(height: 12), + Text( + '$artist · $album', + style: typography.body + ?.apply(shadows: shadows, heightFactor: 2), + textAlign: TextAlign.center, + ), + if (isZune) const SizedBox(height: 12), + if (isZune) + Selector, List)>( + selector: (context, controllerProvider) { + final entries = controllerProvider.entries; + final hiddenIndex = + entries.indexWhere((entry) => entry.id == 'hidden'); + final List visibleEntries = + hiddenIndex != -1 + ? entries.sublist(0, hiddenIndex) + : entries; + final List hiddenEntries = + hiddenIndex != -1 + ? entries.sublist(hiddenIndex + 1) + : []; + + return (visibleEntries, hiddenEntries); + }, + builder: (context, entries, child) { + return CommandBar( + isCompact: true, + overflowMenuItemBuilder: (context, entry) { + if (entry is PrimaryCommandBarItem) { + return entry.entry.flyoutEntryBuilder(context); + } + + throw "Unacceptable entry type"; + }, + overflowItemBuilder: (onPressed) { + return OverflowCommandBarItem( + key: const ValueKey("Overflow Item"), + onPressed: onPressed, + ); + }, + primaryItems: entries.$1 + .map( + (x) => PrimaryCommandBarItem( + key: ValueKey(x.id), + entry: x, + ), + ) + .toList(), + secondaryItems: entries.$2 + .map( + (x) => PrimaryCommandBarItem( + key: ValueKey(x.id), + entry: x, + ), + ) + .toList(), + ); + }, + ) + ], + ); + }, ), ); }, ); } } + +class PrimaryCommandBarItem extends CommandBarItem { + PrimaryCommandBarItem({required super.key, required this.entry}); + + final ControllerEntry entry; + + @override + Widget build(BuildContext context, CommandBarItemDisplayMode displayMode) { + return entry.controllerButtonBuilder(context); + } +} + +class OverflowCommandBarItem extends CommandBarItem { + OverflowCommandBarItem({required super.key, required this.onPressed}); + + final VoidCallback onPressed; + + @override + Widget build(BuildContext context, CommandBarItemDisplayMode displayMode) { + return IconButton( + icon: const Icon(Symbols.more_vert), + onPressed: onPressed, + ); + } +} diff --git a/lib/widgets/playback_controller/controller_buttons.dart b/lib/widgets/playback_controller/controller_buttons.dart index f910b9ca3..9b502e151 100644 --- a/lib/widgets/playback_controller/controller_buttons.dart +++ b/lib/widgets/playback_controller/controller_buttons.dart @@ -2,9 +2,9 @@ import 'package:provider/provider.dart'; import 'package:go_router/go_router.dart'; import 'package:fluent_ui/fluent_ui.dart'; import 'package:material_symbols_icons/symbols.dart'; -import 'package:rune/providers/status.dart'; import '../../widgets/playback_controller/constants/controller_items.dart'; +import '../../providers/status.dart'; import '../../providers/playback_controller.dart'; import '../../providers/responsive_providers.dart'; diff --git a/pubspec.lock b/pubspec.lock index 0e77f1bc0..abfb42bc2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -338,8 +338,8 @@ packages: dependency: "direct main" description: path: "." - ref: "6f3e1695a43ceb5b7d9c14e7563a0d1eaf303814" - resolved-ref: "6f3e1695a43ceb5b7d9c14e7563a0d1eaf303814" + ref: "2186f815de5d6b461775938eb2484d9a3f4162ee" + resolved-ref: "2186f815de5d6b461775938eb2484d9a3f4162ee" url: "https://github.com/Losses/fluent_ui.git" source: git version: "4.9.1" diff --git a/pubspec.yaml b/pubspec.yaml index dc324c682..30be9d079 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -39,7 +39,7 @@ dependencies: fluent_ui: git: url: https://github.com/Losses/fluent_ui.git - ref: 6f3e1695a43ceb5b7d9c14e7563a0d1eaf303814 + ref: 2186f815de5d6b461775938eb2484d9a3f4162ee flutter_acrylic: ^1.1.4 system_theme: ^3.0.0 go_router: ^14.2.1