fix(nav): hide active sidebar background during focus

This commit is contained in:
edde746
2026-05-22 02:21:06 +02:00
parent afc94a50fc
commit 487c7b87f6
2 changed files with 80 additions and 4 deletions
+9 -4
View File
@@ -60,6 +60,7 @@ class NavigationRailItem extends StatelessWidget {
final BorderRadius borderRadius;
final double iconSize;
final double horizontalPadding;
final bool suppressSelectedBackground;
/// Called when RIGHT arrow is pressed to navigate to content area.
final VoidCallback? onNavigateRight;
@@ -79,12 +80,14 @@ class NavigationRailItem extends StatelessWidget {
this.borderRadius = const BorderRadius.all(Radius.circular(12)),
this.iconSize = 22,
this.horizontalPadding = 17,
this.suppressSelectedBackground = false,
this.onNavigateRight,
});
@override
Widget build(BuildContext context) {
final t = tokens(context);
final showSelectedBackground = isSelected && !suppressSelectedBackground;
return Focus(
focusNode: focusNode,
@@ -111,9 +114,8 @@ class NavigationRailItem extends StatelessWidget {
decoration: BoxDecoration(
color: () {
if (isCollapsed) return isFocused ? t.text.withValues(alpha: 0.12) : null;
if (isSelected && isFocused) return t.text.withValues(alpha: 0.15);
if (isSelected) return t.text.withValues(alpha: 0.1);
if (isFocused) return t.text.withValues(alpha: 0.12);
if (isFocused) return t.text.withValues(alpha: showSelectedBackground ? 0.15 : 0.12);
if (showSelectedBackground) return t.text.withValues(alpha: 0.1);
return null;
}(),
borderRadius: borderRadius,
@@ -792,6 +794,7 @@ class SideNavigationRailState extends State<SideNavigationRail> with MountedSetS
focusNode: focusNode,
autofocus: autofocus,
horizontalPadding: itemHorizontalPadding,
suppressSelectedBackground: widget.isSidebarFocused,
onNavigateRight: widget.onNavigateToContent,
);
}
@@ -858,6 +861,7 @@ class SideNavigationRailState extends State<SideNavigationRail> with MountedSetS
final isLoading = librariesProvider.isLoading;
final isLibrariesSelected = widget.selectedTab == NavigationTabId.libraries && widget.selectedLibraryKey == null;
final isLibrariesFocused = _focusTracker.isFocused(_kLibraries);
final showLibrariesSelectedBackground = isLibrariesSelected && !widget.isSidebarFocused;
final allEmpty = visibleRows.isEmpty && hiddenLibraryCount == 0;
return Column(
@@ -894,7 +898,7 @@ class SideNavigationRailState extends State<SideNavigationRail> with MountedSetS
decoration: BoxDecoration(
color: () {
if (isCollapsed) return isLibrariesFocused ? t.text.withValues(alpha: 0.08) : null;
if (isLibrariesSelected) return t.text.withValues(alpha: 0.1);
if (showLibrariesSelectedBackground) return t.text.withValues(alpha: 0.1);
if (isLibrariesFocused) return t.text.withValues(alpha: 0.08);
return null;
}(),
@@ -1190,6 +1194,7 @@ class SideNavigationRailState extends State<SideNavigationRail> with MountedSetS
focusNode: focusNode,
borderRadius: BorderRadius.circular(tokens(context).radiusSm),
iconSize: 18,
suppressSelectedBackground: widget.isSidebarFocused,
onNavigateRight: widget.onNavigateToContent,
),
);
@@ -58,6 +58,58 @@ Future<void> _press(WidgetTester tester, LogicalKeyboardKey key) async {
await tester.pumpAndSettle();
}
BoxDecoration? _railItemDecoration(WidgetTester tester, Finder item) {
return tester.widget<Container>(find.descendant(of: item, matching: find.byType(Container)).first).decoration
as BoxDecoration?;
}
Future<void> _pumpBasicRail(
WidgetTester tester, {
GlobalKey<SideNavigationRailState>? sideNavKey,
bool isSidebarFocused = false,
bool alwaysExpanded = false,
}) async {
await SettingsService.getInstance();
final librariesProvider = LibrariesProvider();
addTearDown(librariesProvider.dispose);
final hiddenLibrariesProvider = HiddenLibrariesProvider();
await hiddenLibrariesProvider.ensureInitialized();
addTearDown(hiddenLibrariesProvider.dispose);
final manager = MultiServerManager();
final aggregation = DataAggregationService(manager);
final multiServerProvider = MultiServerProvider(manager, aggregation);
addTearDown(multiServerProvider.dispose);
await tester.pumpWidget(
TranslationProvider(
child: MultiProvider(
providers: [
ChangeNotifierProvider<LibrariesProvider>.value(value: librariesProvider),
ChangeNotifierProvider<HiddenLibrariesProvider>.value(value: hiddenLibrariesProvider),
ChangeNotifierProvider<MultiServerProvider>.value(value: multiServerProvider),
],
child: MaterialApp(
theme: ThemeData(extensions: const [_testTokens]),
home: Scaffold(
body: SideNavigationRail(
key: sideNavKey,
selectedTab: NavigationTabId.discover,
isSidebarFocused: isSidebarFocused,
alwaysExpanded: alwaysExpanded,
onDestinationSelected: (_) {},
onLibrarySelected: (_) {},
),
),
),
),
),
);
await tester.pumpAndSettle();
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
@@ -177,6 +229,25 @@ void main() {
expect(surfaceOpacity.opacity, 0.0);
});
testWidgets('expanded rail keeps selected background outside sidebar keyboard focus', (tester) async {
await _pumpBasicRail(tester, alwaysExpanded: true);
final selectedItem = find.byType(NavigationRailItem).first;
expect(_railItemDecoration(tester, selectedItem)?.color, _testTokens.text.withValues(alpha: 0.1));
});
testWidgets('D-pad sidebar focus hides selected item background after focus moves', (tester) async {
final sideNavKey = GlobalKey<SideNavigationRailState>();
await _pumpBasicRail(tester, sideNavKey: sideNavKey, isSidebarFocused: true, alwaysExpanded: true);
sideNavKey.currentState!.focusActiveItem();
await tester.pumpAndSettle();
await _press(tester, LogicalKeyboardKey.arrowDown);
final selectedItem = find.byType(NavigationRailItem).first;
expect(_railItemDecoration(tester, selectedItem)?.color, isNull);
});
testWidgets('reports interaction expansion for shell content push', (tester) async {
await SettingsService.getInstance();