From 5a5cc8a62f36bb858a35bae076069d4420861444 Mon Sep 17 00:00:00 2001 From: John Ryan Date: Tue, 7 Apr 2020 09:12:25 -0700 Subject: [PATCH] remove navigation rail, update adaptive scaffold (#404) --- experimental/web_dashboard/lib/src/app.dart | 40 +- .../experimental/adaptive_scaffold_demo.dart | 35 - .../third_party/adaptive_scaffold.dart | 6 +- .../widgets/third_party/navigation_rail.dart | 754 ------------------ .../third_party/navigation_rail_theme.dart | 215 ----- experimental/web_dashboard/pubspec.lock | 12 +- 6 files changed, 45 insertions(+), 1017 deletions(-) delete mode 100644 experimental/web_dashboard/lib/src/experimental/adaptive_scaffold_demo.dart delete mode 100644 experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail.dart delete mode 100644 experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail_theme.dart diff --git a/experimental/web_dashboard/lib/src/app.dart b/experimental/web_dashboard/lib/src/app.dart index 9c69353f9..0ca1deee2 100644 --- a/experimental/web_dashboard/lib/src/app.dart +++ b/experimental/web_dashboard/lib/src/app.dart @@ -5,12 +5,20 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'pages/home.dart'; import 'api/api.dart'; import 'api/mock.dart'; +import 'pages/home.dart'; +import 'widgets/third_party/adaptive_scaffold.dart'; /// An app that shows a responsive dashboard. -class DashboardApp extends StatelessWidget { +class DashboardApp extends StatefulWidget { + @override + _DashboardAppState createState() => _DashboardAppState(); +} + +class _DashboardAppState extends State { + int _pageIndex = 0; + @override Widget build(BuildContext context) { return MultiProvider( @@ -18,8 +26,34 @@ class DashboardApp extends StatelessWidget { Provider(create: (_) => MockDashboardApi()), ], child: MaterialApp( - home: HomePage(), + home: AdaptiveScaffold( + currentIndex: _pageIndex, + destinations: [ + AdaptiveScaffoldDestination(title: 'Home', icon: Icons.home), + AdaptiveScaffoldDestination(title: 'Entries', icon: Icons.list), + AdaptiveScaffoldDestination( + title: 'Settings', icon: Icons.settings), + ], + body: _pageAtIndex(_pageIndex), + onNavigationIndexChange: (newIndex) { + setState(() { + _pageIndex = newIndex; + }); + }, + ), ), ); } + + static Widget _pageAtIndex(int index) { + switch (index) { + case 1: + return Center(child: Text('page 2')); + case 2: + return Center(child: Text('page 3')); + case 0: + default: + return HomePage(); + } + } } diff --git a/experimental/web_dashboard/lib/src/experimental/adaptive_scaffold_demo.dart b/experimental/web_dashboard/lib/src/experimental/adaptive_scaffold_demo.dart deleted file mode 100644 index c44386c23..000000000 --- a/experimental/web_dashboard/lib/src/experimental/adaptive_scaffold_demo.dart +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2020, the Flutter project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. - -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:web_dashboard/src/widgets/third_party/adaptive_scaffold.dart'; - -void main() { - runApp(DashboardWithoutRoutes()); -} - -class DashboardWithoutRoutes extends StatefulWidget { - @override - _DashboardWithoutRoutesState createState() => _DashboardWithoutRoutesState(); -} - -class _DashboardWithoutRoutesState extends State { - @override - Widget build(BuildContext context) { - return MaterialApp( - home: AdaptiveScaffold( - currentIndex: 0, - destinations: [ - AdaptiveScaffoldDestination(title: 'Home', icon: Icons.home), - AdaptiveScaffoldDestination(title: 'Metrics', icon: Icons.show_chart), - AdaptiveScaffoldDestination(title: 'Settings', icon: Icons.settings), - ], - body: Center( - child: Text('Hello, World!'), - ), - ), - ); - } -} diff --git a/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart b/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart index 3e2e3e5be..c5308ee41 100644 --- a/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart +++ b/experimental/web_dashboard/lib/src/widgets/third_party/adaptive_scaffold.dart @@ -4,8 +4,6 @@ import 'package:flutter/material.dart'; -import 'navigation_rail.dart'; - bool _isLargeScreen(BuildContext context) { return MediaQuery.of(context).size.width > 960.0; } @@ -109,8 +107,8 @@ class _AdaptiveScaffoldState extends State { ), ), ], - currentIndex: widget.currentIndex, - onDestinationSelected: widget.onNavigationIndexChange, + selectedIndex: widget.currentIndex, + onDestinationSelected: widget.onNavigationIndexChange ?? (_) {}, ), VerticalDivider( width: 1, diff --git a/experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail.dart b/experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail.dart deleted file mode 100644 index 2e82eb192..000000000 --- a/experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail.dart +++ /dev/null @@ -1,754 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:ui'; - -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; - -import 'navigation_rail_theme.dart'; - -/// A material widget that is meant to be displayed at the left or right of an -/// app to navigate between a small number of views, typically between three and -/// five. -/// -/// A navigation rail is usually used inside a [Row] of a [Scaffold] body. -/// -/// The navigation rail is meant for layouts with wide viewports, such as a -/// desktop web or tablet landscape layout. For smaller layouts, like mobile -/// portrait, a [BottomNavigationBar] should be used instead. Adaptive layouts -/// can build different instances of the [Scaffold] in order to have a -/// navigation rail for more horizontal layouts and a bottom navigation bar -/// for more vertical layouts. -/// -/// {@tool dartpad --template=stateful_widget_material} -/// -/// This example shows a [NavigationRail] used within a Scaffold with 3 -/// [NavigationRailDestination]s. The main content is separated by a divider -/// (although elevation on the navigation rail can be used instead). The -/// `_currentIndex` updates according to the `onDestinationSelected` callback. -/// -/// ```dart -/// int _currentIndex = 0; -/// -/// @override -/// Widget build(BuildContext context) { -/// return Scaffold( -/// body: Row( -/// children: [ -/// NavigationRail( -/// currentIndex: _currentIndex, -/// labelType: NavigationRailLabelType.selected, -/// destinations: [ -/// NavigationRailDestination( -/// icon: Icon(Icons.favorite_border), -/// activeIcon: Icon(Icons.favorite), -/// label: Text('First'), -/// ), -/// NavigationRailDestination( -/// icon: Icon(Icons.bookmark_border), -/// activeIcon: Icon(Icons.book), -/// label: Text('Second'), -/// ), -/// NavigationRailDestination( -/// icon: Icon(Icons.star_border), -/// activeIcon: Icon(Icons.star), -/// label: Text('Third'), -/// ), -/// ], -/// onDestinationSelected: (int index) { -/// setState(() { -/// _currentIndex = index; -/// }); -/// }, -/// ), -/// VerticalDivider(thickness: 1, width: 1), -/// Expanded( -/// child: Center( -/// child: Text('currentIndex: $_currentIndex'), -/// ), -/// ) -/// ], -/// ), -/// ); -/// } -/// ``` -/// {@end-tool} -/// -/// See also: -/// -/// * [Scaffold], which can display the navigation rail within a [Row] of the -/// [Scaffold.body] slot. -/// * [NavigationRailDestination], which is used as a model to create tappable -/// destinations in the navigation rail. -/// * [BottomNavigationBar], which is used as a horizontal alternative for -/// the same style of navigation as the navigation rail. -class NavigationRail extends StatefulWidget { - /// Creates a material design navigation rail. - /// - /// The argument [destinations] must not be null. Additionally, it must be - /// non-empty. - /// - /// If [elevation] is specified, it must be non-negative. - /// - /// If [preferredWidth] is specified, it must be non-negative, and if - /// [extendedWidth is specified, it must be non-negative and greater than - /// [preferredWidth]. - /// - /// The argument [extended] must not be null. [extended] can only be set to - /// true when when the [labelType] is null or [NavigationRailLabelType.none]. - /// - /// If [backgroundColor], [elevation], [groupAlignment], [labelType], - /// [unselectedLabelTextStyle], [unselectedLabelTextStyle], - /// [unselectedIconTheme], or [selectedIconTheme] are null, then their - /// [NavigationRailThemeData] values will be used. If the corresponding - /// [NavigationRailThemeData] property is null, then the navigation rail - /// defaults are used. - /// - /// Typically used within a [Row] of the [Scaffold.body] property. - NavigationRail({ - this.backgroundColor, - this.extended = false, - this.leading, - this.trailing, - @required this.destinations, - this.currentIndex = 0, - this.onDestinationSelected, - this.elevation, - this.groupAlignment, - this.labelType, - this.unselectedLabelTextStyle, - this.selectedLabelTextStyle, - this.unselectedIconTheme, - this.selectedIconTheme, - this.preferredWidth = _railWidth, - this.extendedWidth = _extendedRailWidth, - }) : assert(destinations != null && destinations.isNotEmpty), - assert(0 <= currentIndex && currentIndex < destinations.length), - assert(elevation == null || elevation > 0), - assert(preferredWidth == null || preferredWidth > 0), - assert(extendedWidth == null || extendedWidth > 0), - assert((preferredWidth == null || extendedWidth == null) || extendedWidth >= preferredWidth), - assert(extended != null), - assert(!extended || (labelType == null || labelType == NavigationRailLabelType.none)); - - /// Sets the color of the Container that holds all of the [NavigationRail]'s - /// contents. - final Color backgroundColor; - - /// Indicates of the [NavigationRail] should be in the extended state. - /// - /// The rail will implicitly animate between the extended and normal state. - /// - /// If the rail is going to be in the extended state, then the [labelType] - /// should be set to [NavigationRailLabelType.none]. - final bool extended; - - /// The leading widget in the rail that is placed above the destinations. - /// - /// This is commonly a [FloatingActionButton], but may also be a non-button, - /// such as a logo. - final Widget leading; - - /// The trailing widget in the rail that is placed below the destinations. - /// - /// This is commonly a list of additional options or destinations that is - /// usually only rendered when [extended] is true. - final Widget trailing; - - /// Defines the appearance of the button items that are arrayed within the - /// navigation rail. - final List destinations; - - /// The index into [destinations] for the current active - /// [NavigationRailDestination]. - final int currentIndex; - - /// Called when one of the [destinations] is selected. - /// - /// The stateful widget that creates the navigation rail needs to keep - /// track of the index of the selected [NavigationRailDestination] and call - /// `setState` to rebuild the navigation rail with the new [currentIndex]. - final ValueChanged onDestinationSelected; - - /// The elevation for the inner side of the rail. - /// - /// The shadow only shows on the inner side of the rail. - /// - /// In LTR configurations, the inner side is the right side, and in RTL - /// configurations, it is the left side. - final double elevation; - - /// The alignment for the [NavigationRailDestination]s as they are positioned - /// within the [NavigationRail]. - /// - /// Navigation rail destinations can be aligned as a group to the [top], - /// [bottom], or [center] of a layout. - final NavigationRailGroupAlignment groupAlignment; - - /// Defines the layout and behavior of the labels for the default, unextended - /// [NavigationRail]. - /// - /// When the navigation rail is extended, the labels are always shown. - /// - /// See also: - /// - /// * [NavigationRailLabelType] for information on the meaning of different - /// types. - final NavigationRailLabelType labelType; - - /// The [TextStyle] of the unselected [NavigationRailDestination] labels. - /// - /// When the [NavigationRailDestination] is selected, the - /// [selectedLabelTextStyle] will be used instead. - final TextStyle unselectedLabelTextStyle; - - /// The [TextStyle] of the [NavigationRailDestination] labels when they are - /// selected. - /// - /// When the [NavigationRailDestination] is not selected, - /// [unselectedLabelTextStyle] will be used. - final TextStyle selectedLabelTextStyle; - - /// The default size, opacity, and color of the icon in the - /// [NavigationRailDestination]. - /// - /// If this field is not provided, or provided with any null properties, then - /// a copy of the [IconThemeData.fallback] with a custom [NavigationRail] - /// specific color will be used. - final IconThemeData unselectedIconTheme; - - /// The size, opacity, and color of the icon in the selected - /// [NavigationRailDestination]. - /// - /// When the [NavigationRailDestination] is not selected, - /// [unselectedIconTheme] will be used. - final IconThemeData selectedIconTheme; - - /// The smallest possible width for the rail regardless of the destination - /// content size. - /// - /// The default is 72. - /// - /// This value also defines the min width and min height of the destination - /// boxes. - /// - /// To make a compact rail, set this to 56 and use - /// [NavigationRailLabelType.none]. - final double preferredWidth; - - /// The final width when the animation is complete for setting [extended] to - /// true. - /// - /// This is only used when [extended] is set to true. - /// - /// The default value is 256. - final double extendedWidth; - - /// Returns the animation that controls the [NavigationRail.extended] state. - /// - /// This can be used to synchronize animations in the [leading] or [trailing] - /// widget, such as an animated menu or a [FloatingActionButton] animation. - static Animation extendedAnimation(BuildContext context) { - return context.dependOnInheritedWidgetOfExactType<_ExtendedNavigationRailAnimation>().animation; - } - - @override - _NavigationRailState createState() => _NavigationRailState(); -} - -class _NavigationRailState extends State with TickerProviderStateMixin { - List _destinationControllers = []; - List> _destinationAnimations; - AnimationController _extendedController; - Animation _extendedAnimation; - - @override - void initState() { - super.initState(); - _initControllers(); - } - - @override - void dispose() { - _disposeControllers(); - super.dispose(); - } - - @override - void didUpdateWidget(NavigationRail oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget.extended != oldWidget.extended) { - if (widget.extended) { - _extendedController.forward(); - } else { - _extendedController.reverse(); - } - } - - // No animated segue if the length of the items list changes. - if (widget.destinations.length != oldWidget.destinations.length) { - _resetState(); - return; - } - - if (widget.currentIndex != oldWidget.currentIndex) { - _destinationControllers[oldWidget.currentIndex].reverse(); - _destinationControllers[widget.currentIndex].forward(); - return; - } - } - - @override - Widget build(BuildContext context) { - final ThemeData theme = Theme.of(context); - final NavigationRailThemeData navigationRailTheme = NavigationRailTheme.of(context); - final MaterialLocalizations localizations = MaterialLocalizations.of(context); - - final Color backgroundColor = widget.backgroundColor ?? navigationRailTheme.backgroundColor ?? theme.colorScheme.surface; - final double elevation = widget.elevation ?? navigationRailTheme.elevation ?? 0; - final Color baseSelectedColor = theme.colorScheme.primary; - final Color baseColor = theme.colorScheme.onSurface.withOpacity(0.64); - final IconThemeData unselectedIconTheme = theme.iconTheme.copyWith(color: baseColor).merge(widget.unselectedIconTheme ?? navigationRailTheme.unselectedIconTheme); - final IconThemeData selectedIconTheme = theme.iconTheme.copyWith(color: baseSelectedColor).merge(widget.selectedIconTheme ?? navigationRailTheme.selectedIconTheme); - final TextStyle unselectedLabelTextStyle = theme.textTheme.bodyText1.copyWith(color: baseColor).merge(widget.unselectedLabelTextStyle ?? navigationRailTheme.unselectedLabelTextStyle); - final TextStyle selectedLabelTextStyle = theme.textTheme.bodyText1.copyWith(color: baseSelectedColor).merge(widget.selectedLabelTextStyle ?? navigationRailTheme.selectedLabelTextStyle); - final NavigationRailGroupAlignment groupAlignment = widget.groupAlignment ?? navigationRailTheme.groupAlignment ?? NavigationRailGroupAlignment.top; - final NavigationRailLabelType labelType = widget.labelType ?? navigationRailTheme.labelType ?? NavigationRailLabelType.none; - final MainAxisAlignment destinationsAlignment = _resolveGroupAlignment(groupAlignment); - - return _ExtendedNavigationRailAnimation( - animation: _extendedAnimation, - child: Semantics( - explicitChildNodes: true, - child: Material( - elevation: elevation, - color: backgroundColor, - child: Column( - children: [ - _verticalSpacer, - if (widget.leading != null) - ...[ - if (_extendedAnimation.value > 0) - SizedBox( - width: lerpDouble(widget.preferredWidth, widget.extendedWidth, _extendedAnimation.value), - child: widget.leading, - ) - else - widget.leading, - _verticalSpacer, - ], - Expanded( - child: Column( - mainAxisAlignment: destinationsAlignment, - children: [ - for (int i = 0; i < widget.destinations.length; i++) - _RailDestinationBox( - width: widget.preferredWidth, - extendedWidth: widget.extendedWidth, - extendedTransitionAnimation: _extendedAnimation, - selected: widget.currentIndex == i, - icon: widget.currentIndex == i ? widget.destinations[i].activeIcon : widget.destinations[i].icon, - label: widget.destinations[i].label, - destinationAnimation: _destinationAnimations[i], - labelType: labelType, - iconTheme: widget.currentIndex == i ? selectedIconTheme : unselectedIconTheme, - labelTextStyle: widget.currentIndex == i ? selectedLabelTextStyle : unselectedLabelTextStyle, - onTap: () { - widget.onDestinationSelected(i); - }, - indexLabel: localizations.tabLabel( - tabIndex: i + 1, - tabCount: widget.destinations.length, - ), - ), - ], - ), - ), - if (widget.trailing != null) - if (_extendedAnimation.value > 0) - SizedBox( - width: lerpDouble(widget.preferredWidth, widget.extendedWidth, _extendedAnimation.value), - child: widget.trailing, - ) - else - widget.trailing, - ], - ), - ), - ), - ); - } - - MainAxisAlignment _resolveGroupAlignment(NavigationRailGroupAlignment groupAlignment) { - switch (groupAlignment) { - case NavigationRailGroupAlignment.top: - return MainAxisAlignment.start; - case NavigationRailGroupAlignment.center: - return MainAxisAlignment.center; - case NavigationRailGroupAlignment.bottom: - return MainAxisAlignment.end; - } - return MainAxisAlignment.start; - } - - void _disposeControllers() { - for (final AnimationController controller in _destinationControllers) { - controller.dispose(); - } - _extendedController.dispose(); - } - - void _initControllers() { - _destinationControllers = List.generate(widget.destinations.length, (int index) { - return AnimationController( - duration: kThemeAnimationDuration, - vsync: this, - )..addListener(_rebuild); - }); - _destinationAnimations = _destinationControllers.map((AnimationController controller) => controller.view).toList(); - _destinationControllers[widget.currentIndex].value = 1.0; - _extendedController = AnimationController( - duration: kThemeAnimationDuration, - vsync: this, - value: widget.extended ? 1.0 : 0.0, - ); - _extendedAnimation = CurvedAnimation( - parent: _extendedController, - curve: Curves.easeInOut, - ); - _extendedController.addListener(() { - _rebuild(); - }); - } - - void _resetState() { - _disposeControllers(); - _initControllers(); - } - - void _rebuild() { - setState(() { - // Rebuilding when any of the controllers tick, i.e. when the items are - // animated. - }); - } -} - -class _RailDestinationBox extends StatelessWidget { - _RailDestinationBox({ - @required this.width, - this.extendedWidth, - @required this.icon, - @required this.label, - @required this.destinationAnimation, - @required this.extendedTransitionAnimation, - @required this.labelType, - @required this.selected, - @required this.iconTheme, - @required this.labelTextStyle, - @required this.onTap, - this.indexLabel, - }) : assert(width != null), - assert(icon != null), - assert(label != null), - assert(destinationAnimation != null), - assert(extendedTransitionAnimation != null), - assert(labelType != null), - assert(selected != null), - assert(iconTheme != null), - assert(labelTextStyle != null), - assert(onTap != null), - _positionAnimation = CurvedAnimation( - parent: ReverseAnimation(destinationAnimation), - curve: Curves.easeInOut, - reverseCurve: Curves.easeInOut.flipped, - ); - - final double width; - final double extendedWidth; - final Widget icon; - final Widget label; - final Animation destinationAnimation; - final NavigationRailLabelType labelType; - final bool selected; - final Animation extendedTransitionAnimation; - final IconThemeData iconTheme; - final TextStyle labelTextStyle; - final VoidCallback onTap; - final String indexLabel; - - final Animation _positionAnimation; - - @override - Widget build(BuildContext context) { - final Widget themedIcon = IconTheme( - data: iconTheme, - child: icon, - ); - final Widget styledLabel = DefaultTextStyle.merge( - style: labelTextStyle, - child: label, - ); - Widget content; - switch (labelType) { - case NavigationRailLabelType.none: - if (extendedTransitionAnimation.value == 0) { - content = Stack( - children: [ - SizedBox( - width: width, - height: width, - child: themedIcon, - ), - // For semantics when label is not showing, - SizedBox( - width: 0, - height: 0, - child: Opacity( - alwaysIncludeSemantics: true, - opacity: 0.0, - child: label, - ), - ), - ] - ); - } else { - final TextDirection textDirection = Directionality.of(context); - content = SizedBox( - width: lerpDouble(width, extendedWidth, extendedTransitionAnimation.value), - child: Stack( - children: [ - Positioned( - child: SizedBox( - width: width, - height: width, - child: themedIcon, - ), - ), - Positioned.directional( - textDirection: textDirection, - start: width, - height: width, - child: Opacity( - alwaysIncludeSemantics: true, - opacity: _extendedLabelFadeValue(), - child: Align( - alignment: AlignmentDirectional.centerStart, - child: styledLabel, - ), - ), - ), - ], - ), - ); - } - break; - case NavigationRailLabelType.selected: - final double appearingAnimationValue = 1 - _positionAnimation.value; - final double lerpedPadding = lerpDouble(_verticalDestinationPaddingNoLabel, _verticalDestinationPaddingWithLabel, appearingAnimationValue); - content = Container( - constraints: BoxConstraints( - minWidth: width, - minHeight: width, - ), - padding: const EdgeInsets.symmetric(horizontal: _horizontalDestinationPadding), - child: ClipRect( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - SizedBox(height: lerpedPadding), - themedIcon, - Align( - alignment: Alignment.topCenter, - heightFactor: appearingAnimationValue, - widthFactor: 1.0, - child: Opacity( - alwaysIncludeSemantics: true, - opacity: selected ? _normalLabelFadeInValue() : _normalLabelFadeOutValue(), - child: styledLabel, - ), - ), - SizedBox(height: lerpedPadding), - ], - ), - ), - ); - break; - case NavigationRailLabelType.all: - content = Container( - constraints: BoxConstraints( - minWidth: width, - minHeight: width, - ), - padding: const EdgeInsets.symmetric(horizontal: _horizontalDestinationPadding), - child: Column( - children: [ - const SizedBox(height: _verticalDestinationPaddingWithLabel), - themedIcon, - styledLabel, - const SizedBox(height: _verticalDestinationPaddingWithLabel), - ], - ), - ); - break; - } - - final ColorScheme colors = Theme.of(context).colorScheme; - return Semantics( - container: true, - selected: selected, - child: Stack( - children: [ - Material( - type: MaterialType.transparency, - clipBehavior: Clip.none, - child: InkResponse( - onTap: onTap, - onHover: (_) {}, - highlightShape: BoxShape.rectangle, - borderRadius: BorderRadius.all(Radius.circular(width / 2.0)), - containedInkWell: true, - splashColor: colors.primary.withOpacity(0.12), - hoverColor: colors.primary.withOpacity(0.04), - child: content, - ), - ), - Semantics( - label: indexLabel, - ), - ] - ), - ); - } - - double _normalLabelFadeInValue() { - if (destinationAnimation.value < 0.25) { - return 0; - } else if (destinationAnimation.value < 0.75) { - return (destinationAnimation.value - 0.25) * 2; - } else { - return 1; - } - } - - double _normalLabelFadeOutValue() { - if (destinationAnimation.value > 0.75) { - return (destinationAnimation.value - 0.75) * 4.0; - } else { - return 0; - } - } - - double _extendedLabelFadeValue() { - return extendedTransitionAnimation.value < 0.25 ? extendedTransitionAnimation.value * 4.0 : 1.0; - } -} - -/// Defines the behavior of the labels of a [NavigationRail]. -/// -/// See also: -/// -/// * [NavigationRail] -enum NavigationRailLabelType { - /// Only the icons of a navigation rail item are shown. - none, - - /// Only the selected navigation rail item will show its label. - /// - /// The label will animate in and out as new items are selected. - selected, - - /// All navigation rail items will show their label. - all, -} - -/// Defines the alignment for the group of [NavigationRailDestination]s within -/// a [NavigationRail]. -/// -/// Navigation rail destinations can be aligned as a group to the [top], -/// [bottom], or [center] of a layout. -enum NavigationRailGroupAlignment { - /// Place the [NavigationRailDestination]s at the top of the rail. - top, - - /// Place the [NavigationRailDestination]s in the center of the rail. - center, - - /// Place the [NavigationRailDestination]s at the bottom of the rail. - bottom, -} - -/// A description for an interactive button within a [NavigationRail]. -/// -/// See also: -/// -/// * [NavigationRail] -class NavigationRailDestination { - /// Creates a destination that is used with [NavigationRail.destinations]. - /// - /// [icon] should not be null and [label] should not be null when this - /// destination is used in the [NavigationRail]. - const NavigationRailDestination({ - @required this.icon, - Widget activeIcon, - this.label, - }) : activeIcon = activeIcon ?? icon, - assert(icon != null); - - /// The icon of the destination. - /// - /// Typically the icon is an [Icon] or an [ImageIcon] widget. If another type - /// of widget is provided then it should configure itself to match the current - /// [IconTheme] size and color. - /// - /// If [activeIcon] is provided, this will only be displayed when the - /// destination is not selected. - /// - /// To make the [NavigationRail] more accessible, consider choosing an - /// icon with a stroked and filled version, such as [Icons.cloud] and - /// [Icons.cloud_queue]. [icon] should be set to the stroked version and - /// [activeIcon] to the filled version. - final Widget icon; - - /// An alternative icon displayed when this destination is selected. - /// - /// If this icon is not provided, the [NavigationRail] will display [icon] in - /// either state. - /// - /// See also: - /// - /// * [NavigationRailDestination.icon], for a description of how to pair - /// icons. - final Widget activeIcon; - - /// The label for the destination. - /// - /// The label should be provided when used with the [NavigationRail]. When - /// the labelType is [NavigationRailLabelType.none] and the rail is not - /// extended, then it can be null, but should be used for semantics. - final Widget label; -} - -class _ExtendedNavigationRailAnimation extends InheritedWidget { - const _ExtendedNavigationRailAnimation({ - Key key, - @required this.animation, - @required Widget child, - }) : assert(child != null), - super(key: key, child: child); - - final Animation animation; - - @override - bool updateShouldNotify(_ExtendedNavigationRailAnimation old) => animation != old.animation; -} - -const double _railWidth = 72.0; -const double _extendedRailWidth = 256.0; -const double _horizontalDestinationPadding = 8.0; -const double _verticalDestinationPaddingNoLabel = 24.0; -const double _verticalDestinationPaddingWithLabel = 16.0; -const Widget _verticalSpacer = SizedBox(height: 8.0); \ No newline at end of file diff --git a/experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail_theme.dart b/experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail_theme.dart deleted file mode 100644 index a7ec83d91..000000000 --- a/experimental/web_dashboard/lib/src/widgets/third_party/navigation_rail_theme.dart +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:ui' show lerpDouble; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart'; - -import 'navigation_rail.dart'; - -/// Defines default property values for descendant [NavigationRail] -/// widgets. -/// -/// Descendant widgets obtain the current [NavigationRailThemeData] object -/// using `NavigationRailTheme.of(context)`. Instances of -/// [NavigationRailThemeData] can be customized with -/// [NavigationRailThemeData.copyWith]. -/// -/// Typically a [NavigationRailThemeData] is specified as part of the -/// overall [Theme] with [ThemeData.navigationRailTheme]. -/// -/// All [NavigationRailThemeData] properties are `null` by default. -/// When null, the [NavigationRail] will use the values from [ThemeData] -/// if they exist, otherwise it will provide its own defaults. -/// -/// See also: -/// -/// * [ThemeData], which describes the overall theme information for the -/// application. -class NavigationRailThemeData extends Diagnosticable { - /// Creates a theme that can be used for [ThemeData.navigationRailTheme]. - const NavigationRailThemeData({ - this.backgroundColor, - this.elevation, - this.unselectedLabelTextStyle, - this.selectedLabelTextStyle, - this.unselectedIconTheme, - this.selectedIconTheme, - this.groupAlignment, - this.labelType, - }); - - /// Color to be used for the unselected, enabled [NavigationRail]'s - /// background. - final Color backgroundColor; - - /// The z-coordinate to be used for the unselected, enabled - /// [NavigationRail]'s elevation foreground. - final double elevation; - - /// The style on which to base the destination label, when the destination - /// is not selected. - final TextStyle unselectedLabelTextStyle; - - /// The style on which to base the destination label, when the destination - /// is selected. - final TextStyle selectedLabelTextStyle; - - /// The theme on which to base the destination icon, when the destination - /// is not selected. - final IconThemeData unselectedIconTheme; - - /// The theme on which to base the destination icon, when the destination - /// is selected. - final IconThemeData selectedIconTheme; - - /// The alignment for the [NavigationRailDestination]s as they are positioned - /// within the [NavigationRail]. - final NavigationRailGroupAlignment groupAlignment; - - /// The type that defines the layout and behavior of the labels in the - /// [NavigationRail]. - final NavigationRailLabelType labelType; - - /// Creates a copy of this object with the given fields replaced with the - /// new values. - NavigationRailThemeData copyWith({ - Color backgroundColor, - double elevation, - TextStyle unselectedLabelTextStyle, - TextStyle selectedLabelTextStyle, - IconThemeData unselectedIconTheme, - IconThemeData selectedIconTheme, - NavigationRailGroupAlignment groupAlignment, - NavigationRailLabelType labelType, - }) { - return NavigationRailThemeData( - backgroundColor: backgroundColor ?? this.backgroundColor, - elevation: elevation ?? this.elevation, - unselectedLabelTextStyle: unselectedLabelTextStyle ?? this.unselectedLabelTextStyle, - selectedLabelTextStyle: selectedLabelTextStyle ?? this.selectedLabelTextStyle, - unselectedIconTheme: unselectedIconTheme ?? this.unselectedIconTheme, - selectedIconTheme: selectedIconTheme ?? this.selectedIconTheme, - groupAlignment: groupAlignment ?? this.groupAlignment, - labelType: labelType ?? this.labelType, - ); - } - - /// Linearly interpolate between two navigation rail themes. - /// - /// If both arguments are null then null is returned. - /// - /// {@macro dart.ui.shadow.lerp} - static NavigationRailThemeData lerp(NavigationRailThemeData a, NavigationRailThemeData b, double t) { - assert(t != null); - if (a == null && b == null) - return null; - return NavigationRailThemeData( - backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), - elevation: lerpDouble(a?.elevation, b?.elevation, t), - unselectedLabelTextStyle: TextStyle.lerp(a?.unselectedLabelTextStyle, b?.unselectedLabelTextStyle, t), - selectedLabelTextStyle: TextStyle.lerp(a?.selectedLabelTextStyle, b?.selectedLabelTextStyle, t), - unselectedIconTheme: IconThemeData.lerp(a?.unselectedIconTheme, b?.unselectedIconTheme, t), - selectedIconTheme: IconThemeData.lerp(a?.selectedIconTheme, b?.selectedIconTheme, t), - groupAlignment: t < 0.5 ? a.groupAlignment : b.groupAlignment, - labelType: t < 0.5 ? a.labelType : b.labelType, - ); - } - - @override - int get hashCode { - return hashValues( - backgroundColor, - elevation, - unselectedLabelTextStyle, - selectedLabelTextStyle, - unselectedIconTheme, - selectedIconTheme, - groupAlignment, - labelType, - ); - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) - return true; - if (other.runtimeType != runtimeType) - return false; - return other is NavigationRailThemeData - && other.backgroundColor == backgroundColor - && other.elevation == elevation - && other.unselectedLabelTextStyle == unselectedLabelTextStyle - && other.selectedLabelTextStyle == selectedLabelTextStyle - && other.unselectedIconTheme == unselectedIconTheme - && other.selectedIconTheme == selectedIconTheme - && other.groupAlignment == groupAlignment - && other.labelType == labelType; - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - const NavigationRailThemeData defaultData = NavigationRailThemeData(); - - properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: defaultData.backgroundColor)); - properties.add(DoubleProperty('elevation', elevation, defaultValue: defaultData.elevation)); - properties.add(DiagnosticsProperty('unselectedLabelTextStyle', unselectedLabelTextStyle, defaultValue: defaultData.unselectedLabelTextStyle)); - properties.add(DiagnosticsProperty('selectedLabelTextStyle', selectedLabelTextStyle, defaultValue: defaultData.selectedLabelTextStyle)); - properties.add(DiagnosticsProperty('unselectedIconTheme', unselectedIconTheme, defaultValue: defaultData.unselectedIconTheme)); - properties.add(DiagnosticsProperty('selectedIconTheme', selectedIconTheme, defaultValue: defaultData.selectedIconTheme)); - properties.add(DiagnosticsProperty('groupAlignment', groupAlignment, defaultValue: defaultData.groupAlignment)); - properties.add(DiagnosticsProperty('labelType', labelType, defaultValue: defaultData.labelType)); - } -} - -/// An inherited widget that defines background color, elevation, label text -/// style, icon theme, group alignment, and label type parameters for -/// [NavigationRail]s in this widget's subtree. -/// -/// Values specified here are used for [NavigationRail] properties that are not -/// given an explicit non-null value. -class NavigationRailTheme extends InheritedTheme { - /// Creates a navigation rail theme that controls the - /// [NavigationRailThemeData] properties for a [NavigationRail]. - /// - /// The data argument must not be null. - const NavigationRailTheme({ - Key key, - @required this.data, - Widget child, - }) : assert(data != null), super(key: key, child: child); - - /// Specifies the background color, elevation, label text style, icon theme, - /// group alignment, and label type and border values for descendant - /// [NavigationRail] widgets. - final NavigationRailThemeData data; - - /// The closest instance of this class that encloses the given context. - /// - /// If there is no enclosing [NavigationRailTheme] widget, then - /// [ThemeData.navigationRailTheme] is used. - /// - /// Typical usage is as follows: - /// - /// ```dart - /// NavigationRailTheme theme = NavigationRailTheme.of(context); - /// ``` - static NavigationRailThemeData of(BuildContext context) { - final NavigationRailTheme navigationRailTheme = context.dependOnInheritedWidgetOfExactType(); - return navigationRailTheme?.data ?? NavigationRailThemeData(); // ?? Theme.of(context).navigationRailTheme; - } - - @override - Widget wrap(BuildContext context, Widget child) { - final NavigationRailTheme ancestorTheme = context.findAncestorWidgetOfExactType(); - return identical(this, ancestorTheme) ? child : NavigationRailTheme(data: data, child: child); - } - - @override - bool updateShouldNotify(NavigationRailTheme oldWidget) => data != oldWidget.data; -} \ No newline at end of file diff --git a/experimental/web_dashboard/pubspec.lock b/experimental/web_dashboard/pubspec.lock index a30968b95..878a5384e 100644 --- a/experimental/web_dashboard/pubspec.lock +++ b/experimental/web_dashboard/pubspec.lock @@ -227,7 +227,7 @@ packages: name: package_config url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.9.3" package_resolver: dependency: transitive description: @@ -323,7 +323,7 @@ packages: name: source_map_stack_trace url: "https://pub.dartlang.org" source: hosted - version: "1.1.5" + version: "2.0.0" source_maps: dependency: transitive description: @@ -372,21 +372,21 @@ packages: name: test url: "https://pub.dartlang.org" source: hosted - version: "1.12.0" + version: "1.14.2" test_api: dependency: transitive description: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.2.14" + version: "0.2.15" test_core: dependency: transitive description: name: test_core url: "https://pub.dartlang.org" source: hosted - version: "0.3.0" + version: "0.3.3" typed_data: dependency: transitive description: @@ -451,5 +451,5 @@ packages: source: hosted version: "2.2.0" sdks: - dart: ">=2.6.0 <3.0.0" + dart: ">=2.7.0 <3.0.0" flutter: ">=1.12.1"