LCOV - code coverage report
Current view: top level - src/widgets - bottom_navigation_builder.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 2 81 2.5 %
Date: 2023-03-02 15:31:08 Functions: 0 0 -

          Line data    Source code
       1             : import 'package:flutter/material.dart';
       2             : 
       3             : import '../destination.dart';
       4             : import '../navigation_controller.dart';
       5             : import 'index.dart';
       6             : 
       7             : /// A [NavigatorBuilder] that allows to switch between destinations using
       8             : /// [BottomNavigationBar].
       9             : ///
      10             : /// It builds a wrapper widget, which is a [Scaffold] with a [Scaffold.body] set
      11             : /// to the current destination's content, and [Scaffold.bottomNavigationBar]
      12             : /// specified.
      13             : ///
      14             : /// The [bottomNavigationItems] must correspond to the navigator's destinations.
      15             : ///
      16             : /// The bottom navigation bar can be customized using [parameters], which includes
      17             : /// all parameters supported by the [BottomNavigationBar] widget.
      18             : ///
      19             : /// See also:
      20             : /// - [NavigatorBuilder]
      21             : /// - [BottomNavigationBarParameters]
      22             : /// - [NavigationController]
      23             : /// - [BottomNavigationBar]
      24             : ///
      25             : class BottomNavigationBuilder extends NavigatorBuilder {
      26             :   /// Creates a [BottomNavigationBuilder] instance.
      27             :   ///
      28           0 :   const BottomNavigationBuilder({
      29             :     this.bottomNavigationItems = const <BottomNavigationBarItem>[],
      30             :     this.parameters = const BottomNavigationBarParameters(),
      31             :     this.navigationBarItems = const <NavigationDestination>[],
      32             :     this.navigationBarParameters = const NavigationBarParameters(),
      33             :     bool? material3,
      34             :   }) : _material3 = material3 ?? false,
      35           0 :         super();
      36             : 
      37             :   /// Creates a [BottomNavigationBuilder] instance that uses Material 3 [NavigationBar]
      38             :   /// widget.
      39             :   ///
      40           0 :   factory BottomNavigationBuilder.navigationBar({
      41             :     required List<NavigationDestination> navigationBarItems,
      42             :     NavigationBarParameters? navigationBarParameters,
      43             :   }) =>
      44           0 :       BottomNavigationBuilder(
      45             :         navigationBarItems: navigationBarItems,
      46             :         navigationBarParameters:
      47             :             navigationBarParameters ?? const NavigationBarParameters(),
      48             :         material3: true,
      49             :       );
      50             : 
      51             :   /// A list of [BottomNavigationBarItems], that corresponds to the navigator's
      52             :   /// destination list.
      53             :   ///
      54             :   /// The list must contain the same number of bottom navigation bar items,
      55             :   /// following with the same order as a destination list specified for the navigator.
      56             :   ///
      57             :   final List<BottomNavigationBarItem> bottomNavigationItems;
      58             : 
      59             :   /// A set of [BottomNavigationBar] parameters.
      60             :   ///
      61             :   /// Contains all supported parameters to customize [BottomNavigationBar] widget.
      62             :   /// Doesn't include 'items', 'onTap' and 'currentIndex', which are managed by
      63             :   /// [BottomNavigationBuilder].
      64             :   ///
      65             :   final BottomNavigationBarParameters parameters;
      66             : 
      67             :   /// A list of [NavigationDestination] widgets, that corresponds to the navigator's
      68             :   /// destination list.
      69             :   ///
      70             :   /// The list must contain the same number of items, following with the same order
      71             :   /// as a destination list specified in the navigator.
      72             :   ///
      73             :   final List<NavigationDestination> navigationBarItems;
      74             : 
      75             :   /// A set of [NavigationBar] parameters.
      76             :   ///
      77             :   /// Contains all supported parameters to customize [NavigationBar] widget.
      78             :   /// Doesn't include 'items', 'onTap' and 'currentIndex', which are managed by
      79             :   /// [BottomNavigationBuilder].
      80             :   ///
      81             :   final NavigationBarParameters navigationBarParameters;
      82             : 
      83             :   final bool _material3;
      84             : 
      85           0 :   @override
      86             :   Widget build(BuildContext context, NavigationController navigator) {
      87           0 :     final currentDestination = navigator.currentDestination;
      88           0 :     return _BottomNavigationWrapper(
      89             :       destination: currentDestination,
      90           0 :       onSelectBottomTab: (index) =>
      91           0 :           navigator.goTo(navigator.destinations[index]),
      92           0 :       selectedIndex: navigator.destinations.indexOf(currentDestination),
      93           0 :       items: bottomNavigationItems,
      94           0 :       parameters: parameters,
      95           0 :       navigationBarItems: navigationBarItems,
      96           0 :       navigationBarParameters: navigationBarParameters,
      97           0 :       material3: _material3,
      98             :     );
      99             :   }
     100             : }
     101             : 
     102             : class _BottomNavigationWrapper extends StatefulWidget {
     103           0 :   const _BottomNavigationWrapper({
     104             :     Key? key,
     105             :     required this.destination,
     106             :     required this.onSelectBottomTab,
     107             :     required this.selectedIndex,
     108             :     this.items = const <BottomNavigationBarItem>[],
     109             :     this.parameters = const BottomNavigationBarParameters(),
     110             :     this.navigationBarItems = const <NavigationDestination>[],
     111             :     this.navigationBarParameters = const NavigationBarParameters(),
     112             :     this.material3 = false,
     113           0 :   }) : super(key: key);
     114             : 
     115             :   final Destination destination;
     116             : 
     117             :   final List<BottomNavigationBarItem> items;
     118             : 
     119             :   final void Function(int) onSelectBottomTab;
     120             : 
     121             :   final int selectedIndex;
     122             : 
     123             :   final BottomNavigationBarParameters parameters;
     124             : 
     125             :   final List<NavigationDestination> navigationBarItems;
     126             : 
     127             :   final NavigationBarParameters navigationBarParameters;
     128             : 
     129             :   final bool material3;
     130             : 
     131           0 :   @override
     132             :   _BottomNavigationWrapperState createState() =>
     133           0 :       _BottomNavigationWrapperState();
     134             : }
     135             : 
     136             : class _BottomNavigationWrapperState extends State<_BottomNavigationWrapper> {
     137             :   final _content = <Destination, Widget>{};
     138             : 
     139             :   final _indexes = <Destination, int>{};
     140             : 
     141             :   late final OverlayEntry _mainOverlay;
     142             : 
     143           0 :   @override
     144             :   void initState() {
     145           0 :     super.initState();
     146           0 :     _content[widget.destination] = widget.destination.build(context);
     147           0 :     _indexes[widget.destination] = widget.selectedIndex;
     148           0 :     _mainOverlay = OverlayEntry(
     149           0 :       builder: (context) => Scaffold(
     150           0 :         body: Stack(
     151           0 :           children: [
     152           0 :             ..._content.entries
     153           0 :                 .map((entry) => Offstage(
     154           0 :                       offstage: _indexes[entry.key] != widget.selectedIndex,
     155           0 :                       child: entry.value,
     156             :                     ))
     157           0 :                 .toList(),
     158             :           ],
     159             :         ),
     160           0 :         bottomNavigationBar: widget.material3
     161           0 :             ? NavigationBar(
     162             :                 animationDuration:
     163           0 :                     widget.navigationBarParameters.animationDuration,
     164           0 :                 selectedIndex: widget.selectedIndex,
     165           0 :                 destinations: widget.navigationBarItems,
     166           0 :                 onDestinationSelected: widget.onSelectBottomTab,
     167           0 :                 backgroundColor: widget.navigationBarParameters.backgroundColor,
     168           0 :                 elevation: widget.navigationBarParameters.elevation,
     169           0 :                 height: widget.navigationBarParameters.height,
     170           0 :                 labelBehavior: widget.navigationBarParameters.labelBehavior,
     171             :               )
     172           0 :             : BottomNavigationBar(
     173           0 :                 items: widget.items,
     174           0 :                 currentIndex: widget.selectedIndex,
     175           0 :                 onTap: widget.onSelectBottomTab,
     176           0 :                 elevation: widget.parameters.elevation,
     177           0 :                 type: widget.parameters.type,
     178           0 :                 fixedColor: widget.parameters.fixedColor,
     179           0 :                 backgroundColor: widget.parameters.backgroundColor,
     180           0 :                 iconSize: widget.parameters.iconSize,
     181           0 :                 selectedItemColor: widget.parameters.selectedItemColor,
     182           0 :                 unselectedItemColor: widget.parameters.unselectedItemColor,
     183           0 :                 selectedIconTheme: widget.parameters.selectedIconTheme,
     184           0 :                 unselectedIconTheme: widget.parameters.unselectedIconTheme,
     185           0 :                 selectedFontSize: widget.parameters.selectedFontSize,
     186           0 :                 unselectedFontSize: widget.parameters.unselectedFontSize,
     187           0 :                 selectedLabelStyle: widget.parameters.selectedLabelStyle,
     188           0 :                 unselectedLabelStyle: widget.parameters.unselectedLabelStyle,
     189           0 :                 showSelectedLabels: widget.parameters.showSelectedLabels,
     190           0 :                 showUnselectedLabels: widget.parameters.showUnselectedLabels,
     191           0 :                 mouseCursor: widget.parameters.mouseCursor,
     192           0 :                 enableFeedback: widget.parameters.enableFeedback,
     193           0 :                 landscapeLayout: widget.parameters.landscapeLayout,
     194             :               ),
     195             :       ),
     196             :     );
     197             :   }
     198             : 
     199           0 :   @override
     200             :   void didUpdateWidget(_BottomNavigationWrapper oldWidget) {
     201           0 :     super.didUpdateWidget(oldWidget);
     202             :     bool needsRebuild = false;
     203           0 :     if (widget.material3 != oldWidget.material3) {
     204             :       needsRebuild = true;
     205             :     }
     206           0 :     if (!widget.destination.isFinalDestination) {
     207             :       needsRebuild = true;
     208           0 :       _content[widget.destination] = widget.destination.build(context);
     209           0 :       _indexes[widget.destination] = widget.selectedIndex;
     210           0 :     } else if (oldWidget.selectedIndex != widget.selectedIndex &&
     211           0 :         !_content.containsKey(widget.destination)) {
     212             :       needsRebuild = true;
     213           0 :       _content[widget.destination] = widget.destination.build(context);
     214           0 :       _indexes[widget.destination] = widget.selectedIndex;
     215             :     }
     216             :     if (needsRebuild) {
     217           0 :       _mainOverlay.markNeedsBuild();
     218             :     }
     219             :   }
     220             : 
     221           0 :   @override
     222             :   Widget build(BuildContext context) {
     223           0 :     return Overlay(
     224           0 :       initialEntries: [
     225           0 :         _mainOverlay,
     226             :       ],
     227             :     );
     228             :   }
     229             : }
     230             : 
     231             : /// Contains parameters to customize the [BottomNavigationBar].
     232             : ///
     233             : /// It includes all the same arguments as the [BottomNavigationBar()], excepting
     234             : /// the 'items', 'onTap' and 'currentIndex', which are managed by the [BottomNavigationBuilder].
     235             : ///
     236             : /// See also:
     237             : /// - [BottomNavigationBuilder]
     238             : /// - [BottomNavigationBar]
     239             : ///
     240             : class BottomNavigationBarParameters {
     241             :   /// Create a [BottomNavigationBarParameters] instance.
     242             :   ///
     243          11 :   const BottomNavigationBarParameters({
     244             :     this.elevation,
     245             :     this.type,
     246             :     this.fixedColor,
     247             :     this.backgroundColor,
     248             :     this.iconSize = 24.0,
     249             :     this.selectedItemColor,
     250             :     this.unselectedItemColor,
     251             :     this.selectedIconTheme,
     252             :     this.unselectedIconTheme,
     253             :     this.selectedFontSize = 14.0,
     254             :     this.unselectedFontSize = 12.0,
     255             :     this.selectedLabelStyle,
     256             :     this.unselectedLabelStyle,
     257             :     this.showSelectedLabels,
     258             :     this.showUnselectedLabels,
     259             :     this.mouseCursor,
     260             :     this.enableFeedback,
     261             :     this.landscapeLayout,
     262             :   });
     263             : 
     264             :   /// [BottomNavigationBar.elevation]
     265             :   ///
     266             :   final double? elevation;
     267             : 
     268             :   /// [BottomNavigationBar.type]
     269             :   ///
     270             :   final BottomNavigationBarType? type;
     271             : 
     272             :   /// [BottomNavigationBar.fixedColor]
     273             :   ///
     274             :   final Color? fixedColor;
     275             : 
     276             :   /// [BottomNavigationBar.backgroundColor]
     277             :   ///
     278             :   final Color? backgroundColor;
     279             : 
     280             :   /// [BottomNavigationBar.iconSize]
     281             :   ///
     282             :   final double iconSize;
     283             : 
     284             :   /// [BottomNavigationBar.selectedItemColor]
     285             :   ///
     286             :   final Color? selectedItemColor;
     287             : 
     288             :   /// [BottomNavigationBar.unselectedItemColor]
     289             :   ///
     290             :   final Color? unselectedItemColor;
     291             : 
     292             :   /// [BottomNavigationBar.selectedIconTheme]
     293             :   ///
     294             :   final IconThemeData? selectedIconTheme;
     295             : 
     296             :   /// [BottomNavigationBar.unselectedIconTheme]
     297             :   ///
     298             :   final IconThemeData? unselectedIconTheme;
     299             : 
     300             :   /// [BottomNavigationBar.selectedLabelStyle]
     301             :   ///
     302             :   final TextStyle? selectedLabelStyle;
     303             : 
     304             :   /// [BottomNavigationBar.unselectedLabelStyle]
     305             :   ///
     306             :   final TextStyle? unselectedLabelStyle;
     307             : 
     308             :   /// [BottomNavigationBar.selectedFontSize]
     309             :   ///
     310             :   final double selectedFontSize;
     311             : 
     312             :   /// [BottomNavigationBar.unselectedFontSize]
     313             :   ///
     314             :   final double unselectedFontSize;
     315             : 
     316             :   /// [BottomNavigationBar.showUnselectedLabels]
     317             :   ///
     318             :   final bool? showUnselectedLabels;
     319             : 
     320             :   /// [BottomNavigationBar.showSelectedLabels]
     321             :   ///
     322             :   final bool? showSelectedLabels;
     323             : 
     324             :   /// [BottomNavigationBar.mouseCursor]
     325             :   ///
     326             :   final MouseCursor? mouseCursor;
     327             : 
     328             :   /// [BottomNavigationBar.enableFeedback]
     329             :   ///
     330             :   final bool? enableFeedback;
     331             : 
     332             :   /// [BottomNavigationBar.landscapeLayout]
     333             :   ///
     334             :   final BottomNavigationBarLandscapeLayout? landscapeLayout;
     335             : }
     336             : 
     337             : /// Contains parameters to customize the [NavigationBar].
     338             : ///
     339             : /// It includes all the same arguments as the [NavigationBar()], excepting
     340             : /// the 'items', 'onTap' and 'currentIndex', which are managed by the [BottomNavigationBuilder].
     341             : ///
     342             : /// See also:
     343             : /// - [BottomNavigationBuilder]
     344             : /// - [NavigationBar]
     345             : ///
     346             : class NavigationBarParameters {
     347             :   /// Create a [NavigationBarParameters] instance.
     348             :   ///
     349          11 :   const NavigationBarParameters({
     350             :     this.animationDuration,
     351             :     this.backgroundColor,
     352             :     this.elevation,
     353             :     this.height,
     354             :     this.labelBehavior,
     355             :   });
     356             : 
     357             :   /// [NavigationBar.animationDuration]
     358             :   ///
     359             :   final Duration? animationDuration;
     360             : 
     361             :   /// [NavigationBar.backgroundColor]
     362             :   ///
     363             :   final Color? backgroundColor;
     364             : 
     365             :   /// [NavigationBar.elevation]
     366             :   ///
     367             :   final double? elevation;
     368             : 
     369             :   /// [NavigationBar.height]
     370             :   ///
     371             :   final double? height;
     372             : 
     373             :   /// [NavigationBar.labelBehavior]
     374             :   ///
     375             :   final NavigationDestinationLabelBehavior? labelBehavior;
     376             : }

Generated by: LCOV version