fix(nav): hide active sidebar background during focus
This commit is contained in:
@@ -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();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user