| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665 |
- // Copyright 2021 The Flutter team. 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/material.dart';
- import 'color_palettes_screen.dart';
- import 'component_screen.dart';
- import 'constants.dart';
- import 'elevation_screen.dart';
- import 'typography_screen.dart';
- class Home extends StatefulWidget {
- const Home({
- super.key,
- required this.useLightMode,
- required this.useMaterial3,
- required this.colorSelected,
- required this.handleBrightnessChange,
- required this.handleMaterialVersionChange,
- required this.handleColorSelect,
- });
- final bool useLightMode;
- final bool useMaterial3;
- final ColorSeed colorSelected;
- final void Function(bool useLightMode) handleBrightnessChange;
- final void Function() handleMaterialVersionChange;
- final void Function(int value) handleColorSelect;
- @override
- State<Home> createState() => _HomeState();
- }
- class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
- final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
- late final AnimationController controller;
- late final CurvedAnimation railAnimation;
- bool controllerInitialized = false;
- bool showMediumSizeLayout = false;
- bool showLargeSizeLayout = false;
- int screenIndex = ScreenSelected.component.value;
- @override
- initState() {
- super.initState();
- controller = AnimationController(
- duration: Duration(milliseconds: transitionLength.toInt() * 2),
- value: 0,
- vsync: this,
- );
- railAnimation = CurvedAnimation(
- parent: controller,
- curve: const Interval(0.5, 1.0),
- );
- }
- @override
- void dispose() {
- controller.dispose();
- super.dispose();
- }
- @override
- void didChangeDependencies() {
- super.didChangeDependencies();
- final double width = MediaQuery.of(context).size.width;
- final AnimationStatus status = controller.status;
- if (width > mediumWidthBreakpoint) {
- if (width > largeWidthBreakpoint) {
- showMediumSizeLayout = false;
- showLargeSizeLayout = true;
- } else {
- showMediumSizeLayout = true;
- showLargeSizeLayout = false;
- }
- if (status != AnimationStatus.forward &&
- status != AnimationStatus.completed) {
- controller.forward();
- }
- } else {
- showMediumSizeLayout = false;
- showLargeSizeLayout = false;
- if (status != AnimationStatus.reverse &&
- status != AnimationStatus.dismissed) {
- controller.reverse();
- }
- }
- if (!controllerInitialized) {
- controllerInitialized = true;
- controller.value = width > mediumWidthBreakpoint ? 1 : 0;
- }
- }
- void handleScreenChanged(int screenSelected) {
- setState(() {
- screenIndex = screenSelected;
- });
- }
- Widget createScreenFor(
- ScreenSelected screenSelected, bool showNavBarExample) {
- switch (screenSelected) {
- case ScreenSelected.component:
- return Expanded(
- child: OneTwoTransition(
- animation: railAnimation,
- one: FirstComponentList(
- showNavBottomBar: showNavBarExample,
- scaffoldKey: scaffoldKey,
- showSecondList: showMediumSizeLayout || showLargeSizeLayout),
- two: SecondComponentList(
- scaffoldKey: scaffoldKey,
- ),
- ),
- );
- case ScreenSelected.color:
- return const ColorPalettesScreen();
- case ScreenSelected.typography:
- return const TypographyScreen();
- case ScreenSelected.elevation:
- return const ElevationScreen();
- default:
- return FirstComponentList(
- showNavBottomBar: showNavBarExample,
- scaffoldKey: scaffoldKey,
- showSecondList: showMediumSizeLayout || showLargeSizeLayout);
- }
- }
- PreferredSizeWidget createAppBar() {
- return AppBar(
- title: widget.useMaterial3
- ? const Text('Material 3')
- : const Text('Material 2'),
- actions: !showMediumSizeLayout && !showLargeSizeLayout
- ? [
- _BrightnessButton(
- handleBrightnessChange: widget.handleBrightnessChange,
- ),
- _Material3Button(
- handleMaterialVersionChange: widget.handleMaterialVersionChange,
- ),
- _ColorSeedButton(
- handleColorSelect: widget.handleColorSelect,
- colorSelected: widget.colorSelected,
- ),
- ]
- : [Container()],
- );
- }
- Widget _expandedTrailingActions() => Container(
- constraints: const BoxConstraints.tightFor(width: 250),
- padding: const EdgeInsets.symmetric(horizontal: 30),
- child: Column(
- mainAxisAlignment: MainAxisAlignment.end,
- crossAxisAlignment: CrossAxisAlignment.stretch,
- children: [
- Row(
- children: [
- const Text('Brightness'),
- Expanded(child: Container()),
- Switch(
- value: widget.useLightMode,
- onChanged: (value) {
- widget.handleBrightnessChange(value);
- })
- ],
- ),
- Row(
- children: [
- widget.useMaterial3
- ? const Text('Material 3')
- : const Text('Material 2'),
- Expanded(child: Container()),
- Switch(
- value: widget.useMaterial3,
- onChanged: (_) {
- widget.handleMaterialVersionChange();
- })
- ],
- ),
- const Divider(),
- ConstrainedBox(
- constraints: const BoxConstraints(maxHeight: 200.0),
- child: GridView.count(
- crossAxisCount: 3,
- children: List.generate(
- ColorSeed.values.length,
- (i) => IconButton(
- icon: const Icon(Icons.radio_button_unchecked),
- color: ColorSeed.values[i].color,
- isSelected: widget.colorSelected.color ==
- ColorSeed.values[i].color,
- selectedIcon: const Icon(Icons.circle),
- onPressed: () {
- widget.handleColorSelect(i);
- },
- )),
- ),
- ),
- ],
- ),
- );
- Widget _trailingActions() => Column(
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- Flexible(
- child: _BrightnessButton(
- handleBrightnessChange: widget.handleBrightnessChange,
- showTooltipBelow: false,
- ),
- ),
- Flexible(
- child: _Material3Button(
- handleMaterialVersionChange: widget.handleMaterialVersionChange,
- showTooltipBelow: false,
- ),
- ),
- Flexible(
- child: _ColorSeedButton(
- handleColorSelect: widget.handleColorSelect,
- colorSelected: widget.colorSelected,
- ),
- ),
- ],
- );
- @override
- Widget build(BuildContext context) {
- return AnimatedBuilder(
- animation: controller,
- builder: (context, child) {
- return NavigationTransition(
- scaffoldKey: scaffoldKey,
- animationController: controller,
- railAnimation: railAnimation,
- appBar: createAppBar(),
- body: createScreenFor(
- ScreenSelected.values[screenIndex], controller.value == 1),
- navigationRail: NavigationRail(
- extended: showLargeSizeLayout,
- destinations: navRailDestinations,
- selectedIndex: screenIndex,
- onDestinationSelected: (index) {
- setState(() {
- screenIndex = index;
- handleScreenChanged(screenIndex);
- });
- },
- trailing: Expanded(
- child: Padding(
- padding: const EdgeInsets.only(bottom: 20),
- child: showLargeSizeLayout
- ? _expandedTrailingActions()
- : _trailingActions(),
- ),
- ),
- ),
- navigationBar: NavigationBars(
- onSelectItem: (index) {
- setState(() {
- screenIndex = index;
- handleScreenChanged(screenIndex);
- });
- },
- selectedIndex: screenIndex,
- isExampleBar: false,
- ),
- );
- },
- );
- }
- }
- class _BrightnessButton extends StatelessWidget {
- const _BrightnessButton({
- required this.handleBrightnessChange,
- this.showTooltipBelow = true,
- });
- final Function handleBrightnessChange;
- final bool showTooltipBelow;
- @override
- Widget build(BuildContext context) {
- final isBright = Theme.of(context).brightness == Brightness.light;
- return Tooltip(
- preferBelow: showTooltipBelow,
- message: 'Toggle brightness',
- child: IconButton(
- icon: isBright
- ? const Icon(Icons.dark_mode_outlined)
- : const Icon(Icons.light_mode_outlined),
- onPressed: () => handleBrightnessChange(!isBright),
- ),
- );
- }
- }
- class _Material3Button extends StatelessWidget {
- const _Material3Button({
- required this.handleMaterialVersionChange,
- this.showTooltipBelow = true,
- });
- final void Function() handleMaterialVersionChange;
- final bool showTooltipBelow;
- @override
- Widget build(BuildContext context) {
- final useMaterial3 = Theme.of(context).useMaterial3;
- return Tooltip(
- preferBelow: showTooltipBelow,
- message: 'Switch to Material ${useMaterial3 ? 2 : 3}',
- child: IconButton(
- icon: useMaterial3
- ? const Icon(Icons.filter_2)
- : const Icon(Icons.filter_3),
- onPressed: handleMaterialVersionChange,
- ),
- );
- }
- }
- class _ColorSeedButton extends StatelessWidget {
- const _ColorSeedButton({
- required this.handleColorSelect,
- required this.colorSelected,
- });
- final void Function(int) handleColorSelect;
- final ColorSeed colorSelected;
- @override
- Widget build(BuildContext context) {
- return PopupMenuButton(
- icon: Icon(
- Icons.palette_outlined,
- color: Theme.of(context).colorScheme.onSurfaceVariant,
- ),
- tooltip: 'Select a seed color',
- shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
- itemBuilder: (context) {
- return List.generate(ColorSeed.values.length, (index) {
- ColorSeed currentColor = ColorSeed.values[index];
- return PopupMenuItem(
- value: index,
- enabled: currentColor != colorSelected,
- child: Wrap(
- children: [
- Padding(
- padding: const EdgeInsets.only(left: 10),
- child: Icon(
- currentColor == colorSelected
- ? Icons.color_lens
- : Icons.color_lens_outlined,
- color: currentColor.color,
- ),
- ),
- Padding(
- padding: const EdgeInsets.only(left: 20),
- child: Text(currentColor.label),
- ),
- ],
- ),
- );
- });
- },
- onSelected: handleColorSelect,
- );
- }
- }
- class NavigationTransition extends StatefulWidget {
- const NavigationTransition(
- {super.key,
- required this.scaffoldKey,
- required this.animationController,
- required this.railAnimation,
- required this.navigationRail,
- required this.navigationBar,
- required this.appBar,
- required this.body});
- final GlobalKey<ScaffoldState> scaffoldKey;
- final AnimationController animationController;
- final CurvedAnimation railAnimation;
- final Widget navigationRail;
- final Widget navigationBar;
- final PreferredSizeWidget appBar;
- final Widget body;
- @override
- State<NavigationTransition> createState() => _NavigationTransitionState();
- }
- class _NavigationTransitionState extends State<NavigationTransition> {
- late final AnimationController controller;
- late final CurvedAnimation railAnimation;
- late final ReverseAnimation barAnimation;
- bool controllerInitialized = false;
- bool showDivider = false;
- @override
- void initState() {
- super.initState();
- controller = widget.animationController;
- railAnimation = widget.railAnimation;
- barAnimation = ReverseAnimation(
- CurvedAnimation(
- parent: controller,
- curve: const Interval(0.0, 0.5),
- ),
- );
- }
- @override
- Widget build(BuildContext context) {
- final ColorScheme colorScheme = Theme.of(context).colorScheme;
- return Scaffold(
- key: widget.scaffoldKey,
- appBar: widget.appBar,
- body: Row(
- children: <Widget>[
- RailTransition(
- animation: railAnimation,
- backgroundColor: colorScheme.surface,
- child: widget.navigationRail,
- ),
- widget.body,
- ],
- ),
- bottomNavigationBar: BarTransition(
- animation: barAnimation,
- backgroundColor: colorScheme.surface,
- child: widget.navigationBar,
- ),
- endDrawer: const NavigationDrawerSection(),
- );
- }
- }
- final List<NavigationRailDestination> navRailDestinations = appBarDestinations
- .map(
- (destination) => NavigationRailDestination(
- icon: Tooltip(
- message: destination.label,
- child: destination.icon,
- ),
- selectedIcon: Tooltip(
- message: destination.label,
- child: destination.selectedIcon,
- ),
- label: Text(destination.label),
- ),
- )
- .toList();
- class SizeAnimation extends CurvedAnimation {
- SizeAnimation(Animation<double> parent)
- : super(
- parent: parent,
- curve: const Interval(
- 0.2,
- 0.8,
- curve: Curves.easeInOutCubicEmphasized,
- ),
- reverseCurve: Interval(
- 0,
- 0.2,
- curve: Curves.easeInOutCubicEmphasized.flipped,
- ),
- );
- }
- class OffsetAnimation extends CurvedAnimation {
- OffsetAnimation(Animation<double> parent)
- : super(
- parent: parent,
- curve: const Interval(
- 0.4,
- 1.0,
- curve: Curves.easeInOutCubicEmphasized,
- ),
- reverseCurve: Interval(
- 0,
- 0.2,
- curve: Curves.easeInOutCubicEmphasized.flipped,
- ),
- );
- }
- class RailTransition extends StatefulWidget {
- const RailTransition(
- {super.key,
- required this.animation,
- required this.backgroundColor,
- required this.child});
- final Animation<double> animation;
- final Widget child;
- final Color backgroundColor;
- @override
- State<RailTransition> createState() => _RailTransition();
- }
- class _RailTransition extends State<RailTransition> {
- late Animation<Offset> offsetAnimation;
- late Animation<double> widthAnimation;
- @override
- void didChangeDependencies() {
- super.didChangeDependencies();
- // The animations are only rebuilt by this method when the text
- // direction changes because this widget only depends on Directionality.
- final bool ltr = Directionality.of(context) == TextDirection.ltr;
- widthAnimation = Tween<double>(
- begin: 0,
- end: 1,
- ).animate(SizeAnimation(widget.animation));
- offsetAnimation = Tween<Offset>(
- begin: ltr ? const Offset(-1, 0) : const Offset(1, 0),
- end: Offset.zero,
- ).animate(OffsetAnimation(widget.animation));
- }
- @override
- Widget build(BuildContext context) {
- return ClipRect(
- child: DecoratedBox(
- decoration: BoxDecoration(color: widget.backgroundColor),
- child: Align(
- alignment: Alignment.topLeft,
- widthFactor: widthAnimation.value,
- child: FractionalTranslation(
- translation: offsetAnimation.value,
- child: widget.child,
- ),
- ),
- ),
- );
- }
- }
- class BarTransition extends StatefulWidget {
- const BarTransition(
- {super.key,
- required this.animation,
- required this.backgroundColor,
- required this.child});
- final Animation<double> animation;
- final Color backgroundColor;
- final Widget child;
- @override
- State<BarTransition> createState() => _BarTransition();
- }
- class _BarTransition extends State<BarTransition> {
- late final Animation<Offset> offsetAnimation;
- late final Animation<double> heightAnimation;
- @override
- void initState() {
- super.initState();
- offsetAnimation = Tween<Offset>(
- begin: const Offset(0, 1),
- end: Offset.zero,
- ).animate(OffsetAnimation(widget.animation));
- heightAnimation = Tween<double>(
- begin: 0,
- end: 1,
- ).animate(SizeAnimation(widget.animation));
- }
- @override
- Widget build(BuildContext context) {
- return ClipRect(
- child: DecoratedBox(
- decoration: BoxDecoration(color: widget.backgroundColor),
- child: Align(
- alignment: Alignment.topLeft,
- heightFactor: heightAnimation.value,
- child: FractionalTranslation(
- translation: offsetAnimation.value,
- child: widget.child,
- ),
- ),
- ),
- );
- }
- }
- class OneTwoTransition extends StatefulWidget {
- const OneTwoTransition({
- super.key,
- required this.animation,
- required this.one,
- required this.two,
- });
- final Animation<double> animation;
- final Widget one;
- final Widget two;
- @override
- State<OneTwoTransition> createState() => _OneTwoTransitionState();
- }
- class _OneTwoTransitionState extends State<OneTwoTransition> {
- late final Animation<Offset> offsetAnimation;
- late final Animation<double> widthAnimation;
- @override
- void initState() {
- super.initState();
- offsetAnimation = Tween<Offset>(
- begin: const Offset(1, 0),
- end: Offset.zero,
- ).animate(OffsetAnimation(widget.animation));
- widthAnimation = Tween<double>(
- begin: 0,
- end: mediumWidthBreakpoint,
- ).animate(SizeAnimation(widget.animation));
- }
- @override
- Widget build(BuildContext context) {
- return Row(
- children: <Widget>[
- Flexible(
- flex: mediumWidthBreakpoint.toInt(),
- child: widget.one,
- ),
- if (widthAnimation.value.toInt() > 0) ...[
- Flexible(
- flex: widthAnimation.value.toInt(),
- child: FractionalTranslation(
- translation: offsetAnimation.value,
- child: widget.two,
- ),
- )
- ],
- ],
- );
- }
- }
|