From 476e2d516677c90df211ed5e9a1a39e14329309f Mon Sep 17 00:00:00 2001 From: Taha Tesser Date: Tue, 11 Jul 2023 12:30:05 +0300 Subject: [PATCH] Add `Badge` widget to `NavigationBar` and `NavigationRail` examples (#129834) fixes [Showcase `Badge` widget in `NavigationBar` and `NavigationRail` examples ](https://github.com/flutter/flutter/issues/129832) | Preview | Preview | Preview | | --------------- | --------------- | --------------- | | | | | --- .../navigation_bar/navigation_bar.0.dart | 105 ++++++++++++++---- .../navigation_rail/navigation_rail.1.dart | 16 ++- .../navigation_bar/navigation_bar.0_test.dart | 34 ++++-- .../navigation_rail.1_test.dart | 20 ++++ 4 files changed, 142 insertions(+), 33 deletions(-) diff --git a/examples/api/lib/material/navigation_bar/navigation_bar.0.dart b/examples/api/lib/material/navigation_bar/navigation_bar.0.dart index b5ff01d313..5c38b8c161 100644 --- a/examples/api/lib/material/navigation_bar/navigation_bar.0.dart +++ b/examples/api/lib/material/navigation_bar/navigation_bar.0.dart @@ -13,7 +13,10 @@ class NavigationBarApp extends StatelessWidget { @override Widget build(BuildContext context) { - return const MaterialApp(home: NavigationExample()); + return MaterialApp( + theme: ThemeData(useMaterial3: true), + home: const NavigationExample(), + ); } } @@ -29,6 +32,7 @@ class _NavigationExampleState extends State { @override Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); return Scaffold( bottomNavigationBar: NavigationBar( onDestinationSelected: (int index) { @@ -36,7 +40,7 @@ class _NavigationExampleState extends State { currentPageIndex = index; }); }, - indicatorColor: Colors.amber[800], + indicatorColor: Colors.amber, selectedIndex: currentPageIndex, destinations: const [ NavigationDestination( @@ -45,31 +49,94 @@ class _NavigationExampleState extends State { label: 'Home', ), NavigationDestination( - icon: Icon(Icons.business), - label: 'Business', + icon: Badge(child: Icon(Icons.notifications_sharp)), + label: 'Notifications', ), NavigationDestination( - selectedIcon: Icon(Icons.school), - icon: Icon(Icons.school_outlined), - label: 'School', + icon: Badge( + label: Text('2'), + child: Icon(Icons.messenger_sharp), + ), + label: 'Messages', ), ], ), body: [ - Container( - color: Colors.red, - alignment: Alignment.center, - child: const Text('Page 1'), + /// Home page + Card( + shadowColor: Colors.transparent, + margin: const EdgeInsets.all(8.0), + child: SizedBox.expand( + child: Center( + child: Text( + 'Home page', + style: theme.textTheme.titleLarge, + ), + ), + ), ), - Container( - color: Colors.green, - alignment: Alignment.center, - child: const Text('Page 2'), + /// Notifications page + const Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Card( + child: ListTile( + leading: Icon(Icons.notifications_sharp), + title: Text('Notification 1'), + subtitle: Text('This is a notification'), + ), + ), + Card( + child: ListTile( + leading: Icon(Icons.notifications_sharp), + title: Text('Notification 2'), + subtitle: Text('This is a notification'), + ), + ), + ], + ), ), - Container( - color: Colors.blue, - alignment: Alignment.center, - child: const Text('Page 3'), + /// Messages page + ListView.builder( + reverse: true, + itemCount: 2, + itemBuilder: (BuildContext context, int index) { + if (index == 0) { + return Align( + alignment: Alignment.centerRight, + child: Container( + margin: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(8.0), + ), + child: Text( + 'Hello', + style: theme.textTheme.bodyLarge! + .copyWith(color: theme.colorScheme.onPrimary), + ), + ), + ); + } + return Align( + alignment: Alignment.centerLeft, + child: Container( + margin: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8.0), + decoration: BoxDecoration( + color: theme.colorScheme.primary, + borderRadius: BorderRadius.circular(8.0), + ), + child: Text( + 'Hi!', + style: theme.textTheme.bodyLarge! + .copyWith(color: theme.colorScheme.onPrimary), + ), + ), + ); + }, ), ][currentPageIndex], ); diff --git a/examples/api/lib/material/navigation_rail/navigation_rail.1.dart b/examples/api/lib/material/navigation_rail/navigation_rail.1.dart index 812f3341b6..f3e943736e 100644 --- a/examples/api/lib/material/navigation_rail/navigation_rail.1.dart +++ b/examples/api/lib/material/navigation_rail/navigation_rail.1.dart @@ -14,7 +14,7 @@ class NavigationRailExampleApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( - theme: ThemeData(colorSchemeSeed: const Color(0xff6750a4), useMaterial3: true), + theme: ThemeData(useMaterial3: true), home: const NavRailExample(), ); } @@ -73,13 +73,19 @@ class _NavRailExampleState extends State { label: Text('First'), ), NavigationRailDestination( - icon: Icon(Icons.bookmark_border), - selectedIcon: Icon(Icons.book), + icon: Badge(child: Icon(Icons.bookmark_border)), + selectedIcon: Badge(child: Icon(Icons.book)), label: Text('Second'), ), NavigationRailDestination( - icon: Icon(Icons.star_border), - selectedIcon: Icon(Icons.star), + icon: Badge( + label: Text('4'), + child: Icon(Icons.star_border), + ), + selectedIcon: Badge( + label: Text('4'), + child: Icon(Icons.star), + ), label: Text('Third'), ), ], diff --git a/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart b/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart index f18598a397..d89d8db5a2 100644 --- a/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart +++ b/examples/api/test/material/navigation_bar/navigation_bar.0_test.dart @@ -17,20 +17,36 @@ void main() { /// NavigationDestinations must be rendered expect(find.text('Home'), findsOneWidget); - expect(find.text('Business'), findsOneWidget); - expect(find.text('School'), findsOneWidget); + expect(find.text('Notifications'), findsOneWidget); + expect(find.text('Messages'), findsOneWidget); - /// initial index must be zero + /// Test notification badge. + final Badge notificationBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.notifications_sharp), + matching: find.byType(Badge), + )); + expect(notificationBadge.label, null); + + /// Test messages badge. + final Badge messagesBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.messenger_sharp), + matching: find.byType(Badge), + )); + expect(messagesBadge.label, isNotNull); + + /// Initial index must be zero expect(navigationBarWidget.selectedIndex, 0); + expect(find.text('Home page'), findsOneWidget); - /// switch to second tab - await tester.tap(find.text('Business')); + /// Switch to second tab + await tester.tap(find.text('Notifications')); await tester.pumpAndSettle(); - expect(find.text('Page 2'), findsOneWidget); + expect(find.text('This is a notification'), findsNWidgets(2)); - /// switch to third tab - await tester.tap(find.text('School')); + /// Switch to third tab + await tester.tap(find.text('Messages')); await tester.pumpAndSettle(); - expect(find.text('Page 3'), findsOneWidget); + expect(find.text('Hi!'), findsOneWidget); + expect(find.text('Hello'), findsOneWidget); }); } diff --git a/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart b/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart index 1c3eee1482..d3526d4adc 100644 --- a/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart +++ b/examples/api/test/material/navigation_rail/navigation_rail.1_test.dart @@ -94,4 +94,24 @@ void main() { expect(find.byType(FloatingActionButton), findsOneWidget); expect(find.byType(IconButton), findsOneWidget); }); + + testWidgets('Destinations have badge', (WidgetTester tester) async { + await tester.pumpWidget( + const example.NavigationRailExampleApp(), + ); + + // Test badge wthout label. + final Badge notificationBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.bookmark_border), + matching: find.byType(Badge), + )); + expect(notificationBadge.label, null); + + // Test badge with label. + final Badge messagesBadge = tester.firstWidget(find.ancestor( + of: find.byIcon(Icons.star_border), + matching: find.byType(Badge), + )); + expect(messagesBadge.label, isNotNull); + }); }