fix(ui): present the library switcher and profile menu as bottom sheets on mobile

Both anchored popups were small tap targets on phones. AppMenuButton
gains an opt-in adaptiveSheet flag that routes through
showAdaptiveAppMenu: full-width, untitled sheet rows on touch platforms
(phones plus Android TV / tvOS), the same anchored popup on desktop.
This commit is contained in:
edde746
2026-08-23 10:12:26 +02:00
parent aa9118a799
commit c4b043cba9
3 changed files with 24 additions and 7 deletions
+1
View File
@@ -664,6 +664,7 @@ class _DiscoverScreenState extends State<DiscoverScreen>
? ProfileAvatar(profile: active, size: 32, avatarUrl: activeProvider.avatarUrlFor(active.id))
: const AppIcon(Symbols.account_circle_rounded, fill: 1, size: 32, color: Colors.white),
tooltip: t.profiles.sectionTitle,
adaptiveSheet: true,
anchorAlignment: AppMenuAnchorAlignment.end,
onSelected: (value) => unawaited(_handleUserMenuAction(context, value)),
entriesBuilder: (context) =>
@@ -634,6 +634,7 @@ class _LibrariesScreenState extends State<LibrariesScreen>
return AppMenuButton<String>(
key: _libraryDropdownKey,
tooltip: t.libraries.selectLibrary,
adaptiveSheet: true,
onSelected: (libraryGlobalKey) {
_loadLibraryContent(libraryGlobalKey);
},
+22 -7
View File
@@ -160,6 +160,12 @@ class AppMenuButton<T> extends StatefulWidget {
final Widget? icon;
final Widget? child;
final String? tooltip;
/// When true, iOS/Android (phones plus Android TV / tvOS) present the menu
/// as an untitled bottom sheet — just the drag handle and rows — via
/// [showAdaptiveAppMenu]; desktop keeps the anchored popup. False keeps the
/// anchored popup on every platform.
final bool adaptiveSheet;
final bool enabled;
final AppMenuEntryBuilder<T> entriesBuilder;
final ValueChanged<T>? onSelected;
@@ -170,6 +176,7 @@ class AppMenuButton<T> extends StatefulWidget {
this.icon,
this.child,
this.tooltip,
this.adaptiveSheet = false,
this.enabled = true,
required this.entriesBuilder,
this.onSelected,
@@ -189,13 +196,21 @@ class AppMenuButtonState<T> extends State<AppMenuButton<T>> {
final topLeft = renderBox.localToGlobal(Offset.zero);
final anchorRect = Rect.fromLTWH(topLeft.dx, topLeft.dy, renderBox.size.width, renderBox.size.height);
final selected = await showAppMenu<T>(
context,
entries: widget.entriesBuilder(context),
anchorRect: anchorRect,
anchorAlignment: widget.anchorAlignment,
focusFirstItem: focusFirstItem,
);
final selected = widget.adaptiveSheet
? await showAdaptiveAppMenu<T>(
context,
entries: widget.entriesBuilder(context),
anchorRect: anchorRect,
anchorAlignment: widget.anchorAlignment,
focusFirstItem: focusFirstItem,
)
: await showAppMenu<T>(
context,
entries: widget.entriesBuilder(context),
anchorRect: anchorRect,
anchorAlignment: widget.anchorAlignment,
focusFirstItem: focusFirstItem,
);
if (!mounted || selected == null) return selected;
widget.onSelected?.call(selected);
return selected;