From a05a279508e7ccc6716361427a6fe3db40f8e27d Mon Sep 17 00:00:00 2001 From: Bryan Van Deusen Date: Mon, 11 May 2026 07:52:45 -0400 Subject: [PATCH] fix(flutter): strip duplicate status-bar inset when update banner shows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit You correctly diagnosed the symptom: the AppBar gets taller when the banner is present. Why: the shell is [Banner, Expanded(child), PlayerBar] and the banner uses SafeArea(bottom:false) to clear the status bar. But MediaQuery.padding is screen-relative — the child's Scaffold/AppBar reads MediaQuery.padding.top and applies its own status-bar inset on top of the banner, doubling the gap. Watch shouldShowUpdateBannerProvider in the shell. When it returns non-null (banner visible), wrap the child in MediaQuery.removePadding removeTop: true so the AppBar mounts directly under the banner. When the banner is hidden, child gets its normal top inset. --- flutter_client/lib/shared/routing.dart | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/flutter_client/lib/shared/routing.dart b/flutter_client/lib/shared/routing.dart index 9d99b5df..781fd8ce 100644 --- a/flutter_client/lib/shared/routing.dart +++ b/flutter_client/lib/shared/routing.dart @@ -18,6 +18,7 @@ import '../playlists/playlists_list_screen.dart'; import '../requests/requests_screen.dart'; import '../search/search_screen.dart'; import '../settings/settings_screen.dart'; +import '../update/client_update_provider.dart'; import '../update/update_banner.dart'; import '../admin/admin_landing_screen.dart'; import '../admin/admin_requests_screen.dart'; @@ -88,15 +89,30 @@ GoRouter buildRouter(Ref ref) { ); } -class _ShellWithPlayerBar extends StatelessWidget { +class _ShellWithPlayerBar extends ConsumerWidget { const _ShellWithPlayerBar({required this.child}); final Widget child; @override - Widget build(BuildContext context) { + Widget build(BuildContext context, WidgetRef ref) { + // The banner sits above the routed child and uses SafeArea to clear + // the system status bar. MediaQuery.padding is screen-relative + // though, so the child's Scaffold/AppBar would still apply its own + // top status-bar inset on top of the banner — doubling the gap. + // When the banner is showing, strip that inset from the child so + // its AppBar lands directly under the banner. + final hasBanner = ref.watch(shouldShowUpdateBannerProvider) != null; return Column( children: [ const UpdateBanner(), - Expanded(child: child), + Expanded( + child: hasBanner + ? MediaQuery.removePadding( + context: context, + removeTop: true, + child: child, + ) + : child, + ), const PlayerBar(), ], );