diff --git a/lib/screens/now_playing_screen.dart b/lib/screens/now_playing_screen.dart index 9ead75ae..bcaa0ff4 100644 --- a/lib/screens/now_playing_screen.dart +++ b/lib/screens/now_playing_screen.dart @@ -1802,13 +1802,30 @@ class _NowPlayingScreenState extends ConsumerState { setState(() => _lyricsOptionsOpen = true); try { final anchor = mornyeMenuAnchor(buttonContext); + var menuWidth = 240.0; + for (final (_, label, _) in actions) { + final painter = TextPainter( + text: TextSpan( + text: label, + style: Theme.of( + context, + ).textTheme.bodyLarge?.copyWith(fontSize: 15), + ), + textDirection: Directionality.of(context), + textScaler: MediaQuery.textScalerOf(context), + )..layout(); + if (painter.width + 80 > menuWidth) menuWidth = painter.width + 80; + painter.dispose(); + } final action = context.isMornye ? await showMornyeContextMenu( context: buttonContext, anchor: anchor, preferAbove: true, + maxWidth: menuWidth, builder: (menuContext) => MornyeContextMenu( dense: true, + liquidGlass: true, groups: [ [ for (final (value, label, icon) in actions) diff --git a/lib/widgets/mornye_chrome.dart b/lib/widgets/mornye_chrome.dart index a3fc8839..8962e17d 100644 --- a/lib/widgets/mornye_chrome.dart +++ b/lib/widgets/mornye_chrome.dart @@ -127,6 +127,7 @@ class MornyeGlassPanel extends ConsumerWidget { this.lastInGroup = true, this.strongTint = false, this.tintOpacity, + this.liquidGlass = false, }); /// Shared glass material for confirmation dialogs and floating sheets. @@ -137,6 +138,7 @@ class MornyeGlassPanel extends ConsumerWidget { this.firstInGroup = true, this.lastInGroup = true, this.tintOpacity = 0.78, + this.liquidGlass = false, }) : strongTint = false; final Widget child; @@ -145,25 +147,37 @@ class MornyeGlassPanel extends ConsumerWidget { final bool lastInGroup; final bool strongTint; final double? tintOpacity; + final bool liquidGlass; @override - Widget build(BuildContext context, WidgetRef ref) => MornyeGlass.navigation( - radius: radius, - firstInGroup: firstInGroup, - lastInGroup: lastInGroup, - strongTint: strongTint, - tintOpacity: tintOpacity, - blurEnabled: + Widget build(BuildContext context, WidgetRef ref) { + final blur = !MediaQuery.highContrastOf(context) && (!ref.watch(lowEndDeviceProvider) || - ref.watch(backdropBlurEnabledProvider)), - child: Material( - color: strongTint - ? Theme.of(context).colorScheme.surface.withValues(alpha: 0.60) - : Colors.transparent, - child: child, - ), - ); + ref.watch(backdropBlurEnabledProvider)); + if (liquidGlass) { + return MornyeGlass( + radius: radius, + tintOpacity: tintOpacity, + blurEnabled: blur, + child: Material(color: Colors.transparent, child: child), + ); + } + return MornyeGlass.navigation( + radius: radius, + firstInGroup: firstInGroup, + lastInGroup: lastInGroup, + strongTint: strongTint, + tintOpacity: tintOpacity, + blurEnabled: blur, + child: Material( + color: strongTint + ? Theme.of(context).colorScheme.surface.withValues(alpha: 0.60) + : Colors.transparent, + child: child, + ), + ); + } } class MornyeGlass extends StatelessWidget { diff --git a/lib/widgets/mornye_context_menu.dart b/lib/widgets/mornye_context_menu.dart index 3d842a59..38039a5d 100644 --- a/lib/widgets/mornye_context_menu.dart +++ b/lib/widgets/mornye_context_menu.dart @@ -18,6 +18,7 @@ Future showMornyeContextMenu({ required WidgetBuilder builder, Rect? anchor, bool preferAbove = false, + double maxWidth = 320, }) { final navigator = Navigator.of(context, rootNavigator: true); final themes = InheritedTheme.capture(from: context, to: navigator.context); @@ -42,6 +43,7 @@ Future showMornyeContextMenu({ delegate: _MenuLayout( anchor: target, preferAbove: preferAbove, + maxWidth: maxWidth, padding: media.padding.copyWith( bottom: math.max(media.padding.bottom, media.viewInsets.bottom), ), @@ -63,17 +65,19 @@ class _MenuLayout extends SingleChildLayoutDelegate { required this.anchor, required this.padding, required this.preferAbove, + required this.maxWidth, }); final Rect? anchor; final EdgeInsets padding; final bool preferAbove; + final double maxWidth; static const double _margin = 16; @override BoxConstraints getConstraintsForChild(BoxConstraints constraints) { final width = math.min( - 320.0, + maxWidth, math.max(0.0, constraints.maxWidth - padding.horizontal - _margin * 2), ); var height = math.max( @@ -125,6 +129,7 @@ class _MenuLayout extends SingleChildLayoutDelegate { bool shouldRelayout(_MenuLayout oldDelegate) => anchor != oldDelegate.anchor || padding != oldDelegate.padding || + maxWidth != oldDelegate.maxWidth || preferAbove != oldDelegate.preferAbove; } @@ -154,12 +159,14 @@ class MornyeContextMenu extends StatelessWidget { required this.groups, this.inheritSurface = false, this.dense = false, + this.liquidGlass = false, }); final List quickActions; final List> groups; final bool inheritSurface; final bool dense; + final bool liquidGlass; @override Widget build(BuildContext context) { @@ -204,6 +211,8 @@ class MornyeContextMenu extends StatelessWidget { data: theme, child: MornyeGlassPanel.overlay( radius: 28, + liquidGlass: liquidGlass, + tintOpacity: liquidGlass ? 0.24 : 0.78, child: LayoutBuilder( builder: (context, constraints) { // Let the entire menu scroll when pinning the shortcuts would diff --git a/test/now_playing_lyrics_transition_test.dart b/test/now_playing_lyrics_transition_test.dart index 26cfa076..63d33d72 100644 --- a/test/now_playing_lyrics_transition_test.dart +++ b/test/now_playing_lyrics_transition_test.dart @@ -1696,6 +1696,11 @@ void main() { } else { await tester.tap(options); await tester.pumpAndSettle(); + final glass = tester.widget( + find.byType(MornyeGlassPanel).last, + ); + expect(glass.liquidGlass, isTrue); + expect(glass.tintOpacity, lessThan(0.5)); expect( find.text('Hide Pronunciation'), supplement == 'pronunciation' ? findsOneWidget : findsNothing,