From 12a94fcba79bc67a6b7f1fc34cdcc6e86ec89c3b Mon Sep 17 00:00:00 2001 From: edde746 <86283021+edde746@users.noreply.github.com> Date: Wed, 28 Jan 2026 23:07:09 +0100 Subject: [PATCH] fix: android tv bottom sheet back button --- lib/focus/dpad_navigator.dart | 21 +++++++++++++++++++++ lib/focus/key_event_utils.dart | 2 ++ lib/theme/mono_theme.dart | 4 ++-- lib/widgets/focusable_bottom_sheet.dart | 10 ++++++---- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/focus/dpad_navigator.dart b/lib/focus/dpad_navigator.dart index 66b1916b..1271e5bd 100644 --- a/lib/focus/dpad_navigator.dart +++ b/lib/focus/dpad_navigator.dart @@ -84,11 +84,32 @@ class SelectKeyUpSuppressor { /// the BACK key-up from propagating to the underlying screen. class BackKeyUpSuppressor { static bool _suppressBackUntilKeyUp = false; + static bool _closedViaBackKey = false; + /// Mark that a modal is being closed via back key press. + /// Call this before Navigator.pop() in back key handlers. + static void markClosedViaBackKey() { + _closedViaBackKey = true; + } + + /// Request suppression of back key-up events. + /// Suppression is skipped if the modal was closed via back key + /// (since the key-up already triggered the close). static void suppressBackUntilKeyUp() { + if (_closedViaBackKey) { + _closedViaBackKey = false; + return; + } _suppressBackUntilKeyUp = true; } + /// Clear any pending suppression. Call when opening a new modal + /// to ensure stale suppression from previous closes doesn't affect it. + static void clearSuppression() { + _suppressBackUntilKeyUp = false; + _closedViaBackKey = false; + } + static bool consumeIfSuppressed(KeyEvent event) { if (!_suppressBackUntilKeyUp) return false; if (event.logicalKey.isBackKey) { diff --git a/lib/focus/key_event_utils.dart b/lib/focus/key_event_utils.dart index 21ba8a56..70b808e9 100644 --- a/lib/focus/key_event_utils.dart +++ b/lib/focus/key_event_utils.dart @@ -66,6 +66,8 @@ KeyEventResult handleBackKeyAction(KeyEvent event, VoidCallback onBack) { if (event is KeyUpEvent) { BackKeyCoordinator.markHandled(); + // Mark that we're closing via back key so suppressBackUntilKeyUp() knows to skip + BackKeyUpSuppressor.markClosedViaBackKey(); onBack(); return KeyEventResult.handled; } diff --git a/lib/theme/mono_theme.dart b/lib/theme/mono_theme.dart index 419f0de8..6b34287d 100644 --- a/lib/theme/mono_theme.dart +++ b/lib/theme/mono_theme.dart @@ -27,6 +27,8 @@ ThemeData monoTheme({required bool dark, bool oled = false}) { textMuted: const Color(0x99111111), ); + final isDark = dark || oled; + final buttonStyle = ButtonStyle( padding: const WidgetStatePropertyAll(EdgeInsets.symmetric(horizontal: 18, vertical: 14)), elevation: const WidgetStatePropertyAll(0), @@ -35,8 +37,6 @@ ThemeData monoTheme({required bool dark, bool oled = false}) { shape: const WidgetStatePropertyAll(StadiumBorder()), ); - final isDark = dark || oled; - final base = ThemeData( useMaterial3: true, brightness: isDark ? Brightness.dark : Brightness.light, diff --git a/lib/widgets/focusable_bottom_sheet.dart b/lib/widgets/focusable_bottom_sheet.dart index bcf9e1dd..27270c57 100644 --- a/lib/widgets/focusable_bottom_sheet.dart +++ b/lib/widgets/focusable_bottom_sheet.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import '../focus/input_mode_tracker.dart'; import '../focus/dpad_navigator.dart'; +import '../focus/key_event_utils.dart'; /// A wrapper widget that provides autofocus functionality for bottom sheets. /// @@ -29,6 +30,8 @@ class _FocusableBottomSheetState extends State { @override void initState() { super.initState(); + // Clear any stale back key suppression from previous sheet closes + BackKeyUpSuppressor.clearSuppression(); _requestInitialFocus(); } @@ -61,13 +64,12 @@ class _FocusableBottomSheetState extends State { canRequestFocus: false, skipTraversal: true, onKeyEvent: (node, event) { + // Handle select key suppression (for when sheet was opened via select key) if (SelectKeyUpSuppressor.consumeIfSuppressed(event)) { return KeyEventResult.handled; } - if (BackKeyUpSuppressor.consumeIfSuppressed(event)) { - return KeyEventResult.handled; - } - return KeyEventResult.ignored; + // Handle back key to close the bottom sheet + return handleBackKeyNavigation(context, event); }, child: widget.child, );