diff --git a/CHANGELOG.md b/CHANGELOG.md index ec373a8..31478fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to the **ThemeDemo** application are documented here. +## 0.9.9 + +**July 20, 2023** + +* Chore: Bump all dependencies, now using FlexColorScheme 7.2.0 +* Chore: Fix deprecated Flutter SDK APIs. +* Chore: Bump MaterialShowcase to the same version as the one used by Themes Playground in FlexColorScheme 7.2.0. + ## 0.9.8 **May 17, 2023** diff --git a/lib/bottomsheet/views/bottom_sheet_settings.dart b/lib/bottomsheet/views/bottom_sheet_settings.dart index 312ad39..e9e7535 100644 --- a/lib/bottomsheet/views/bottom_sheet_settings.dart +++ b/lib/bottomsheet/views/bottom_sheet_settings.dart @@ -62,8 +62,8 @@ class BottomSheetSettings extends ConsumerWidget { // Hide the extra dark mode controls in light theme mode. AnimatedHide( hide: isLight, - child: Column( - children: const [ + child: const Column( + children: [ DarkIsTrueBlackSwitch(), DarkComputeThemeSwitch(), DarkLevelSlider(), diff --git a/lib/core/constants/app_const.dart b/lib/core/constants/app_const.dart index 42c1ba9..d1e8f12 100644 --- a/lib/core/constants/app_const.dart +++ b/lib/core/constants/app_const.dart @@ -8,13 +8,13 @@ class AppConst { static const String appName = 'ThemeDemo'; /// Current app version. - static const String version = '0.9.8'; + static const String version = '0.9.9'; /// Used version of FlexColorScheme package. - static const String packageVersion = '7.1.2'; + static const String packageVersion = '7.2.0'; /// Build with Flutter version. - static const String flutterVersion = 'Channel stable v3.10.0'; + static const String flutterVersion = 'Channel stable v3.10.6'; /// Copyright years notice. static const String copyright = '© 2021-2023'; diff --git a/lib/core/utils/drawer_width.dart b/lib/core/utils/drawer_width.dart index 2f23a33..1578a9b 100644 --- a/lib/core/utils/drawer_width.dart +++ b/lib/core/utils/drawer_width.dart @@ -8,8 +8,11 @@ import 'package:flutter/material.dart'; /// * Is never less than 244 dp wide. /// * Will fill max width if screen is less than 244 dp wide. double drawerWidth() { - final double screenWidth = - MediaQueryData.fromWindow(WidgetsBinding.instance.window).size.width; + final double physicalWidth = + WidgetsBinding.instance.platformDispatcher.views.first.physicalSize.width; + final double devicePixelRatio = + WidgetsBinding.instance.platformDispatcher.views.first.devicePixelRatio; + final double screenWidth = physicalWidth / devicePixelRatio; /// Drawer, minimum none covered space when screen width is > 300 dp . const double minNotUsedSpace = 56; // This is spec in M2. diff --git a/lib/core/views/widgets/universal/colored_text.dart b/lib/core/views/widgets/universal/colored_text.dart index 4c12d8f..1dd1337 100644 --- a/lib/core/views/widgets/universal/colored_text.dart +++ b/lib/core/views/widgets/universal/colored_text.dart @@ -288,7 +288,7 @@ class ColoredText extends StatelessWidget { color: color ?? Theme.of(context).colorScheme.primary, ), ); - if (MediaQuery.boldTextOverride(context)) { + if (MediaQuery.boldTextOf(context)) { effectiveTextStyle = effectiveTextStyle .merge(const TextStyle(fontWeight: FontWeight.bold)); } diff --git a/lib/home/views/pages/home_page.dart b/lib/home/views/pages/home_page.dart index 14a8093..def6179 100644 --- a/lib/home/views/pages/home_page.dart +++ b/lib/home/views/pages/home_page.dart @@ -74,6 +74,13 @@ class _MyHomePageState extends ConsumerState { actions: const [AboutIconButton()], ), drawer: const AppDrawer(), + bottomNavigationBar: NavigationBar( + destinations: const [ + NavigationDestination( + icon: Icon(Icons.access_alarm_outlined), label: 'Alarm'), + NavigationDestination(icon: Icon(Icons.settings), label: 'Settings') + ], + ), // This annotated region will change the Android system navigation bar to // a theme color, matching active theme mode and FlexColorScheme theme. body: AnnotatedRegion( diff --git a/lib/home/views/widgets/theme_settings.dart b/lib/home/views/widgets/theme_settings.dart index 46384ac..8fcfdbe 100644 --- a/lib/home/views/widgets/theme_settings.dart +++ b/lib/home/views/widgets/theme_settings.dart @@ -66,8 +66,8 @@ class ThemeSettings extends ConsumerWidget { ), AnimatedHide( hide: !useSubThemes, - child: Column( - children: const [ + child: const Column( + children: [ ListTile( title: Text('Global border radius on components'), subtitle: Text( diff --git a/lib/settings/views/widgets/surface_mode_widgets.dart b/lib/settings/views/widgets/surface_mode_widgets.dart index f13e368..467eae7 100644 --- a/lib/settings/views/widgets/surface_mode_widgets.dart +++ b/lib/settings/views/widgets/surface_mode_widgets.dart @@ -235,11 +235,11 @@ List _getModeWidget(ColorScheme scheme, [bool allModes = true]) => message: 'High surface\nlow scaffold', child: Icon(Icons.layers), ), - Tooltip( + const Tooltip( message: 'High scaffold\nlow surface', child: Stack( alignment: Alignment.center, - children: const [ + children: [ Padding( padding: EdgeInsets.only(top: 10), child: Icon(Icons.layers_outlined), diff --git a/lib/theme/views/widgets/showcase_material.dart b/lib/theme/views/widgets/showcase_material.dart index bda53b0..30fa654 100644 --- a/lib/theme/views/widgets/showcase_material.dart +++ b/lib/theme/views/widgets/showcase_material.dart @@ -1,3 +1,6 @@ +import 'dart:async'; + +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -21,17 +24,16 @@ class ShowcaseMaterial extends StatelessWidget { @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); + const TextStyle headerStyle = TextStyle(fontSize: 16); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ + // + // Buttons + // + const Text('Material Buttons', style: headerStyle), const SizedBox(height: 8), - const TextInputField(), - const SizedBox(height: 8), - const DropDownButtonFormField(), - const SizedBox(height: 8), - const DropDownMenuShowcase(), - const Divider(), const ElevatedButtonShowcase(), const SizedBox(height: 8), const FilledButtonShowcase(), @@ -41,97 +43,202 @@ class ShowcaseMaterial extends StatelessWidget { const OutlinedButtonShowcase(), const SizedBox(height: 8), const TextButtonShowcase(), + const SizedBox(height: 16), + // + // ToggleButtons and SegmentedButton + // + const Text('ToggleButtons and SegmentedButton', style: headerStyle), const SizedBox(height: 8), const ToggleButtonsShowcase(), const SizedBox(height: 8), - const SegmentedButtonShowcase(), - const Divider(), + const SegmentedButtonShowcase(showOutlinedButton: false), + const SizedBox(height: 16), + // + // FloatingActionButton and Chip + // + const Text('FloatingActionButton and Chip', style: headerStyle), + const SizedBox(height: 8), const FabShowcase(), const SizedBox(height: 16), const ChipShowcase(), - const Divider(), - const SizedBox(height: 8), - const PopupMenuButtonsShowcase(), - const SizedBox(height: 8), - const Divider(), - const DropDownMenuShowcase(explainUsage: true), - const MenuBarShowcase(), - const MenuAnchorShowcase(), + const SizedBox(height: 16), + // + // Switch, CheckBox and Radio + // + const Text('Switch, Checkbox and Radio', style: headerStyle), const SizedBox(height: 8), - const Divider(), + const SwitchShowcase(showCupertinoSwitches: false), + const CheckboxShowcase(), + const RadioShowcase(), const SizedBox(height: 8), - const TooltipShowcase(), + // + // Icon + // + const Text('Icon', style: headerStyle), const SizedBox(height: 16), - const IconButtonCircleAvatarDropdownShowcase(), + const IconShowcase(), + const SizedBox(height: 16), + // + // IconButton + // + const Text('IconButton', style: headerStyle), const SizedBox(height: 16), const IconButtonShowcase(), const SizedBox(height: 16), + const IconButtonVariantsShowcase(), + const SizedBox(height: 16), + // + // CircleAvatar + // + const Text('CircleAvatar', style: headerStyle), + const SizedBox(height: 16), + const CircleAvatarShowcase(), + const SizedBox(height: 16), + // + // Tooltip + // + const Text('Tooltip', style: headerStyle), + const SizedBox(height: 8), + const TooltipShowcase(), + const SizedBox(height: 16), + // + // ProgressIndicator + // + const Text('ProgressIndicator', style: headerStyle), + const SizedBox(height: 8), const ProgressIndicatorShowcase(), - const Divider(), - const SwitchShowcase(), - const CheckboxShowcase(), - const RadioShowcase(), + const SizedBox(height: 16), + // + // Slider and RangeSlider + // + const Text('Slider and RangeSlider', style: headerStyle), const SizedBox(height: 8), - const Divider(), const SliderShowcase(), - const SizedBox(height: 8), + const Divider(), const RangeSliderShowcase(), const SizedBox(height: 8), - const Divider(), - const ListTileAllShowcase(), - const Divider(), - const ExpansionTileShowcase(), - const Divider(), - const ExpansionPanelListShowcase(), - const Divider(), - const AppBarShowcase(), - const Divider(), - const BottomAppBarShowcase(), - const Divider(), - const TabBarForAppBarShowcase(), + // + // TextField + // + const Text('TextField with InputDecorator', style: headerStyle), const SizedBox(height: 8), - const Divider(), - const TabBarForBackgroundShowcase(), + const TextFieldShowcase(), + const SizedBox(height: 16), + // + // PopupMenuButton, DropdownButtonFormField, DropDownButton + // + const Text('PopupMenuButton and DropdownButtons', style: headerStyle), + const PopupMenuButtonsShowcase(explain: true), const SizedBox(height: 8), - const Divider(), - const BottomNavigationBarShowcase(), + const DropdownButtonFormFieldShowcase(explain: true), const SizedBox(height: 8), - const NavigationBarShowcase(), + const DropDownButtonShowcase(explain: true), const SizedBox(height: 8), - const Divider(), - const NavigationRailShowcase(), + // + // DropdownMenu, MenuBar, MenuAnchor + // + const Text('Dropdown Menus and MenuBar', style: headerStyle), + const DropDownMenuShowcase(explain: true), + const MenuAnchorShowcase(explain: true), + const MenuBarShowcase(explain: true), + const SizedBox(height: 16), + // + // AppBars and TabBar + // + const Text('AppBar and TabBar', style: headerStyle), const SizedBox(height: 8), - const NavigationDrawerShowcase(), - const DrawerShowcase(), + const AppBarShowcase(), const SizedBox(height: 8), - const Divider(), + const TabBarForAppBarShowcase(explain: true), + const SizedBox(height: 8), + const TabBarForBackgroundShowcase(explain: true), + const SizedBox(height: 16), + // + // BottomAppBar and SearchBar + // + const Text('BottomAppBar and SearchBar', style: headerStyle), + const BottomAppBarShowcase(explain: true), + const SearchBarShowcase(explain: true), + const SizedBox(height: 16), + // + // BottomNavigationBar (M2), NavigationBar (M3) + // NavigationRail, NavigationDrawer + // + const Text('Navigation Components', style: headerStyle), + const BottomNavigationBarShowcase(explain: true), + const SizedBox(height: 8), + const NavigationBarShowcase(explain: true), + const SizedBox(height: 8), + const NavigationRailShowcase(explain: true), + const SizedBox(height: 8), + const NavigationDrawerShowcase(explain: true), + const DrawerShowcase(explain: true), + const SizedBox(height: 16), + // + // AlertDialog, TimePickerDialog, DatePickerDialog + // + const Text('Dialogs', style: headerStyle), const AlertDialogShowcase(), const TimePickerDialogShowcase(), const DatePickerDialogShowcase(), const SizedBox(height: 8), - const Divider(), + // + // BottomSheet + // + const Text('BottomSheet', style: headerStyle), const SizedBox(height: 16), const BottomSheetShowcase(), const SizedBox(height: 16), const BottomSheetModalShowcase(), - const SizedBox(height: 32), + const SizedBox(height: 16), + // + // SnackBar and MaterialBanner + // + const Text('SnackBar and MaterialBanner', style: headerStyle), + const SizedBox(height: 8), const MaterialBannerSnackBarShowcase(), - const Divider(height: 32), - const MaterialShowcase(), - const Divider(height: 32), - const CardShowcase(), + // + // Card + // + const Text('Card', style: headerStyle), const SizedBox(height: 8), + const CardShowcase(explain: true), + const SizedBox(height: 16), + // + // Material + // + const Text('Material', style: headerStyle), + const MaterialShowcase(explain: true), + const SizedBox(height: 16), + // + // LisTile, SwitchListTile, CheckboxListTile, RadioListTile + // and more exotic + // ExpansionTile, ExpansionPanelList + // + const Text('All List Tiles', style: headerStyle), + const ListTileShowcase(), + const Divider(height: 1), + const SwitchListTileShowcase(), + const Divider(height: 1), + const CheckboxListTileShowcase(), + const Divider(height: 1), + const RadioListTileShowcase(), + const Divider(), + const ExpansionTileShowcase(), + const Divider(), + const ExpansionPanelListShowcase(), + const SizedBox(height: 32), + // + // TextTheme and PrimaryTextTheme + // + const Text('Text', style: headerStyle), Card( child: Padding( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Text('Normal TextTheme', - style: theme.textTheme.titleMedium), - ), + Text('TextTheme', style: theme.textTheme.titleMedium), const TextThemeShowcase(), ], ), @@ -145,16 +252,14 @@ class ShowcaseMaterial extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 16), - child: Text('Primary TextTheme', - style: theme.primaryTextTheme.titleMedium), - ), + Text('PrimaryTextTheme', + style: theme.primaryTextTheme.titleMedium), const PrimaryTextThemeShowcase(), ], ), ), ), + const SizedBox(height: 16), ], ); } @@ -384,7 +489,6 @@ class SegmentedButtonShowcase extends StatefulWidget { enum Calendar { day, week, month, year } class _SegmentedButtonShowcaseState extends State { - List selected = [true, false, false, true]; Calendar _selected = Calendar.day; @override @@ -438,7 +542,7 @@ class _SegmentedButtonShowcaseState extends State { ButtonSegment( value: Calendar.month, icon: Icon(Icons.calendar_view_month), - label: Text('Month'), + label: Text('Mont'), ), ButtonSegment( value: Calendar.year, @@ -469,7 +573,7 @@ class _SegmentedButtonShowcaseState extends State { ButtonSegment( value: Calendar.month, icon: Icon(Icons.calendar_view_month), - label: Text('Month'), + label: Text('Mont'), enabled: false, ), ButtonSegment( @@ -491,45 +595,69 @@ class _SegmentedButtonShowcaseState extends State { } } -class FabShowcase extends StatelessWidget { +class FabShowcase extends StatefulWidget { const FabShowcase({super.key}); + @override + State createState() => _FabShowcaseState(); +} + +class _FabShowcaseState extends State { + bool extended = true; + @override Widget build(BuildContext context) { return RepaintBoundary( child: Wrap( crossAxisAlignment: WrapCrossAlignment.center, - spacing: 8, - runSpacing: 8, + spacing: 16, + runSpacing: 16, children: [ - FloatingActionButton.small( - heroTag: 'FAB small', - onPressed: () {}, - child: const Icon(Icons.accessibility), - ), - FloatingActionButton.extended( - heroTag: 'FAB extended false', - isExtended: false, - onPressed: () {}, - icon: const Icon(Icons.accessibility), - label: const Text('Extended'), + Tooltip( + verticalOffset: 40, + waitDuration: const Duration(milliseconds: 500), + message: 'FloatingActionButton.small', + child: FloatingActionButton.small( + heroTag: 'FAB small', + onPressed: () {}, + child: const Icon(Icons.accessibility), + ), ), - FloatingActionButton.extended( - heroTag: 'FAB extended true', - isExtended: true, - onPressed: () {}, - icon: const Icon(Icons.accessibility), - label: const Text('Extended'), + Tooltip( + verticalOffset: 40, + waitDuration: const Duration(milliseconds: 500), + message: 'FloatingActionButton', + child: FloatingActionButton( + heroTag: 'FAB standard', + onPressed: () {}, + child: const Icon(Icons.accessibility), + ), ), - FloatingActionButton( - heroTag: 'FAB standard', - onPressed: () {}, - child: const Icon(Icons.accessibility), + Tooltip( + verticalOffset: 40, + waitDuration: const Duration(milliseconds: 500), + message: 'FloatingActionButton.extended(isExtended: $extended)', + child: FloatingActionButton.extended( + heroTag: 'FAB extendable', + isExtended: extended, + onPressed: () { + setState(() { + extended = !extended; + }); + }, + icon: const Icon(Icons.accessibility), + label: const Text('Extended'), + ), ), - FloatingActionButton.large( - heroTag: 'FAB large', - onPressed: () {}, - child: const Icon(Icons.accessibility), + Tooltip( + verticalOffset: 60, + waitDuration: const Duration(milliseconds: 500), + message: 'FloatingActionButton.large', + child: FloatingActionButton.large( + heroTag: 'FAB large', + onPressed: () {}, + child: const Icon(Icons.accessibility), + ), ), ], ), @@ -538,7 +666,8 @@ class FabShowcase extends StatelessWidget { } class SwitchShowcase extends StatefulWidget { - const SwitchShowcase({super.key}); + const SwitchShowcase({super.key, this.showCupertinoSwitches = false}); + final bool showCupertinoSwitches; @override State createState() => _SwitchShowcaseState(); @@ -546,16 +675,18 @@ class SwitchShowcase extends StatefulWidget { class _SwitchShowcaseState extends State { bool isOn1 = true; - bool isOn2 = false; @override Widget build(BuildContext context) { + final ColorScheme colorScheme = Theme.of(context).colorScheme; + final bool isLight = Theme.of(context).brightness == Brightness.light; return RepaintBoundary( child: Wrap( crossAxisAlignment: WrapCrossAlignment.center, spacing: 8, runSpacing: 8, children: [ + if (widget.showCupertinoSwitches) const Text('M3:'), Switch( value: isOn1, onChanged: (bool value) { @@ -568,10 +699,12 @@ class _SwitchShowcaseState extends State { thumbIcon: MaterialStateProperty.resolveWith( (Set states) { if (states.contains(MaterialState.selected)) { - return const Icon(Icons.check); + return Icon(Icons.check, + color: + isLight ? colorScheme.primary : colorScheme.onPrimary); } // All other states will use the default thumbIcon. - return const Icon(Icons.close); + return Icon(Icons.close, color: colorScheme.onPrimary); }), value: isOn1, onChanged: (bool value) { @@ -581,21 +714,52 @@ class _SwitchShowcaseState extends State { }, ), Switch( - value: isOn2, + value: isOn1, + onChanged: null, + ), + Switch( + value: !isOn1, onChanged: (bool value) { setState(() { - isOn2 = value; + isOn1 = !value; }); }, ), - const Switch( - value: true, - onChanged: null, - ), - const Switch( - value: false, + Switch( + value: !isOn1, onChanged: null, ), + if (widget.showCupertinoSwitches) ...[ + const Text('iOS:'), + CupertinoSwitch( + activeColor: colorScheme.primary, + value: isOn1, + onChanged: (bool value) { + setState(() { + isOn1 = value; + }); + }, + ), + CupertinoSwitch( + activeColor: colorScheme.primary, + value: isOn1, + onChanged: null, + ), + CupertinoSwitch( + activeColor: colorScheme.primary, + value: !isOn1, + onChanged: (bool value) { + setState(() { + isOn1 = !value; + }); + }, + ), + CupertinoSwitch( + activeColor: colorScheme.primary, + value: !isOn1, + onChanged: null, + ), + ], ], ), ); @@ -886,8 +1050,8 @@ class _RangeSliderShowcaseState extends State { } class PopupMenuButtonsShowcase extends StatelessWidget { - const PopupMenuButtonsShowcase({super.key, this.explainUsage = true}); - final bool explainUsage; + const PopupMenuButtonsShowcase({super.key, this.explain = false}); + final bool explain; @override Widget build(BuildContext context) { @@ -901,7 +1065,7 @@ class PopupMenuButtonsShowcase extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (explainUsage) + if (explain) Padding( padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: Text( @@ -909,16 +1073,18 @@ class PopupMenuButtonsShowcase extends StatelessWidget { style: denseHeader, ), ), - if (explainUsage) + if (explain) Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), child: Text( - 'The classic Material popup menu.', + 'The PopupMenuButton is a Material-2 design commonly used in ' + 'Material apps. In M3 it has received a slightly updated style ' + 'with elevation tint.', style: denseBody, ), ), - Row( - children: const [ + const Row( + children: [ PopupMenuButtonShowcase(), SizedBox(width: 16), PopupMenuButtonTilesShowcase(), @@ -957,6 +1123,7 @@ class PopupMenuButtonTilesShowcase extends StatelessWidget { Widget build(BuildContext context) { return RepaintBoundary( child: PopupMenuButton( + tooltip: 'Show menu using\nListTile items', onSelected: (_) {}, position: PopupMenuPosition.under, itemBuilder: (BuildContext context) => const >[ @@ -985,83 +1152,153 @@ class PopupMenuButtonTilesShowcase extends StatelessWidget { } } -class _DropDownButton extends StatefulWidget { - const _DropDownButton(); +class DropDownButtonShowcase extends StatefulWidget { + const DropDownButtonShowcase({super.key, this.explain = false}); + final bool explain; @override - State<_DropDownButton> createState() => _DropDownButtonState(); + State createState() => _DropDownButtonShowcaseState(); } -class _DropDownButtonState extends State<_DropDownButton> { - String selectedItem = 'Dropdown button 1'; +class _DropDownButtonShowcaseState extends State { + String selectedItem = '1 DropdownButton'; @override Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle denseHeader = theme.textTheme.titleMedium!.copyWith( + fontSize: 13, + ); + final TextStyle denseBody = theme.textTheme.bodyMedium! + .copyWith(fontSize: 12, color: theme.textTheme.bodySmall!.color); + return RepaintBoundary( - child: DropdownButton( - value: selectedItem, - onChanged: (String? value) { - setState(() { - selectedItem = value ?? 'Dropdown button 1'; - }); - }, - items: [ - 'Dropdown button 1', - 'Dropdown button 2', - 'Dropdown button 3', - 'Dropdown button 4', - 'Dropdown button 5' - ].map>((String value) { - return DropdownMenuItem( - value: value, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Text(value), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.explain) + Padding( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + child: Text( + 'DropdownButton', + style: denseHeader, + ), ), - ); - }).toList(), + if (widget.explain) + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: Text( + 'An older Material-2 widget, it cannot be themed. ' + 'Consider using M3 DropdownMenu instead.', + style: denseBody, + ), + ), + DropdownButton( + value: selectedItem, + onChanged: (String? value) { + setState(() { + selectedItem = value ?? '1 DropdownButton'; + }); + }, + items: [ + '1 DropdownButton', + '2 DropdownButton', + '3 DropdownButton', + '4 DropdownButton', + '5 DropdownButton', + '6 DropdownButton', + '7 DropdownButton', + '8 DropdownButton', + ].map>((String value) { + return DropdownMenuItem( + value: value, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Text(value), + ), + ); + }).toList(), + ), + ], ), ); } } -class DropDownButtonFormField extends StatefulWidget { - const DropDownButtonFormField({super.key}); +class DropdownButtonFormFieldShowcase extends StatefulWidget { + const DropdownButtonFormFieldShowcase({super.key, this.explain = false}); + final bool explain; @override - State createState() => - _DropDownButtonFormFieldState(); + State createState() => + _DropdownButtonFormFieldShowcaseState(); } -class _DropDownButtonFormFieldState extends State { - String selectedItem = 'DropDown FormField - Option 1'; +class _DropdownButtonFormFieldShowcaseState + extends State { + String selectedItem = '1 DropdownButtonFormField'; @override Widget build(BuildContext context) { - return DropdownButtonFormField( - value: selectedItem, - onChanged: (String? value) { - setState(() { - selectedItem = value ?? 'DropDown FormField - Option 1'; - }); - }, - items: [ - 'DropDown FormField - Option 1', - 'DropDown FormField - Option 2', - 'DropDown FormField - Option 3', - 'DropDown FormField - Option 4', - 'DropDown FormField - Option 5', - ].map>((String value) { - return DropdownMenuItem( - value: value, - child: Text(value), - ); - }).toList(), + final ThemeData theme = Theme.of(context); + final TextStyle denseHeader = theme.textTheme.titleMedium!.copyWith( + fontSize: 13, + ); + final TextStyle denseBody = theme.textTheme.bodyMedium! + .copyWith(fontSize: 12, color: theme.textTheme.bodySmall!.color); + + return RepaintBoundary( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.explain) + Padding( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + child: Text( + 'DropdownButtonFormField', + style: denseHeader, + ), + ), + if (widget.explain) + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: Text( + 'An older M2 widget. Cannot theme its open style. ' + 'Closed style uses InputDecorator theme. Maybe consider ' + 'using M3 DropDownMenu instead.', + style: denseBody, + ), + ), + DropdownButtonFormField( + value: selectedItem, + onChanged: (String? value) { + setState(() { + selectedItem = value ?? '1 DropdownButtonFormField'; + }); + }, + items: [ + '1 DropdownButtonFormField', + '2 DropdownButtonFormField', + '3 DropdownButtonFormField', + '4 DropdownButtonFormField', + '5 DropdownButtonFormField', + '6 DropdownButtonFormField', + '7 DropdownButtonFormField', + '8 DropdownButtonFormField', + ].map>((String value) { + return DropdownMenuItem( + value: value, + child: Text(value), + ); + }).toList(), + ), + ], + ), ); } } class DropDownMenuShowcase extends StatefulWidget { - const DropDownMenuShowcase({super.key, this.explainUsage = false}); - final bool explainUsage; + const DropDownMenuShowcase({super.key, this.explain = false}); + final bool explain; @override State createState() => _DropDownMenuShowcaseState(); @@ -1082,7 +1319,7 @@ class _DropDownMenuShowcaseState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (widget.explainUsage) + if (widget.explain) Padding( padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: Text( @@ -1090,11 +1327,11 @@ class _DropDownMenuShowcaseState extends State { style: denseHeader, ), ), - if (widget.explainUsage) + if (widget.explain) Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), child: Text( - 'The new M3 DropdownMenu shares building blocks with MenuBar ' + 'The M3 DropdownMenu shares building blocks with MenuBar ' 'and MenuAnchor, also uses InputDecorator for text entry.', style: denseBody, ), @@ -1146,99 +1383,104 @@ class TooltipShowcase extends StatelessWidget { @override Widget build(BuildContext context) { - return RepaintBoundary( - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 16, - runSpacing: 4, - children: const [ - Tooltip( - message: 'Current tooltip theme', - child: Text('Text with tooltip'), - ), - Tooltip( - message: 'Current tooltip theme.\nThis a two row tooltip.', - child: Text('Text with two row tooltip'), - ), - Tooltip( - message: 'Current tooltip theme.\nThis tooltip is too long.\n' - 'Try to keep them short.', - child: Text('Text with three row tooltip'), - ), - ], - ), + return const Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 16, + runSpacing: 4, + children: [ + Tooltip( + message: 'Current tooltip theme', + child: Text('Text with tooltip'), + ), + Tooltip( + message: 'Current tooltip theme.\nThis a two row tooltip.', + child: Text('Text with two row tooltip'), + ), + Tooltip( + message: 'Current tooltip theme.\nThis tooltip is too long.\n' + 'Try to keep them short.', + child: Text('Text with three row tooltip'), + ), + ], ); } } -class IconButtonCircleAvatarDropdownShowcase extends StatefulWidget { - const IconButtonCircleAvatarDropdownShowcase({super.key}); +class IconShowcase extends StatelessWidget { + const IconShowcase({super.key}); @override - State createState() => - _IconButtonCircleAvatarDropdownShowcaseState(); + Widget build(BuildContext context) { + return const Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 16, + runSpacing: 4, + children: [ + Tooltip( + message: 'Icon is Icons\nAddCircle', + child: Icon(Icons.add_circle), + ), + Tooltip( + message: 'Icon is Icons\nCameraAltOutlined', + child: Icon(Icons.camera_alt_outlined), + ), + Tooltip( + message: 'Icon is Icons\nFlutterDash', + child: Icon(Icons.flutter_dash), + ), + Tooltip( + message: 'Icon is Icons\nWarningAmber', + child: Icon(Icons.warning_amber), + ), + ], + ); + } } -class _IconButtonCircleAvatarDropdownShowcaseState - extends State { - bool isLockOpen = false; +class CircleAvatarShowcase extends StatelessWidget { + const CircleAvatarShowcase({super.key}); @override Widget build(BuildContext context) { - return RepaintBoundary( - child: Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 16, - runSpacing: 4, - children: [ - const Tooltip( - message: 'This is\nan Icon', - child: Icon(Icons.add_circle), - ), - const Tooltip( - message: 'This is\nan Icon', - child: Icon(Icons.flutter_dash), - ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: IconButton( - icon: const Icon(Icons.accessibility), - tooltip: 'This is an\nIconButton', - onPressed: () {}, - ), + return const Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 16, + runSpacing: 4, + children: [ + Tooltip( + message: 'This is a\nCircleAvatar', + child: CircleAvatar( + child: Text('CA'), ), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: IconButton( - icon: const Icon(Icons.lock_outlined), - selectedIcon: const Icon(Icons.lock_open_outlined), - tooltip: isLockOpen - ? 'This is an IconButton\nIn M3 tap to close lock' - : 'This is an IconButton\nIn M3 tap to open lock', - isSelected: isLockOpen, - onPressed: () { - setState(() { - isLockOpen = !isLockOpen; - }); - }, - ), + ), + Tooltip( + message: 'CircleAvatar\nwith image', + child: CircleAvatar( + child: FlutterLogo(), ), - const Tooltip( - message: 'This is a\nCircleAvatar', - child: CircleAvatar( - child: Text('CA'), - ), + ), + Tooltip( + message: 'CircleAvatar\nwith image\nradius 30', + child: CircleAvatar( + radius: 30, + child: FlutterLogo(size: 40), ), - const _DropDownButton(), - ], - ), + ), + ], ); } } -class IconButtonShowcase extends StatelessWidget { +class IconButtonShowcase extends StatefulWidget { const IconButtonShowcase({super.key}); + @override + State createState() => _IconButtonShowcaseState(); +} + +class _IconButtonShowcaseState extends State { + bool isLockOpen = false; + @override Widget build(BuildContext context) { return RepaintBoundary( @@ -1247,67 +1489,23 @@ class IconButtonShowcase extends StatelessWidget { spacing: 16, runSpacing: 4, children: [ - Column( - // Standard IconButton - children: const [ - IconToggleButton( - isEnabled: true, - tooltip: 'Standard', - ), - SizedBox(height: 8), - IconToggleButton( - isEnabled: false, - tooltip: 'Standard (disabled)', - ), - ], - ), - Column( - children: const [ - // Filled IconButton - IconToggleButton( - isEnabled: true, - tooltip: 'Filled', - getDefaultStyle: enabledFilledButtonStyle, - ), - SizedBox(height: 8), - IconToggleButton( - isEnabled: false, - tooltip: 'Filled (disabled)', - getDefaultStyle: disabledFilledButtonStyle, - ), - ], - ), - Column( - children: const [ - // Filled Tonal IconButton - IconToggleButton( - isEnabled: true, - tooltip: 'Filled tonal', - getDefaultStyle: enabledFilledTonalButtonStyle, - ), - SizedBox(height: 8), - IconToggleButton( - isEnabled: false, - tooltip: 'Filled tonal (disabled)', - getDefaultStyle: disabledFilledTonalButtonStyle, - ), - ], + IconButton( + icon: const Icon(Icons.accessibility), + tooltip: 'This is an\nIconButton', + onPressed: () {}, ), - Column( - children: const [ - // Outlined IconButton - IconToggleButton( - isEnabled: true, - tooltip: 'Outlined', - getDefaultStyle: enabledOutlinedButtonStyle, - ), - SizedBox(height: 8), - IconToggleButton( - isEnabled: false, - tooltip: 'Outlined (disabled)', - getDefaultStyle: disabledOutlinedButtonStyle, - ), - ], + IconButton( + icon: const Icon(Icons.lock_outlined), + selectedIcon: const Icon(Icons.lock_open_outlined), + tooltip: isLockOpen + ? 'This is an IconButton\nIn M3 tap to close lock' + : 'This is an IconButton\nIn M3 tap to open lock', + isSelected: isLockOpen, + onPressed: () { + setState(() { + isLockOpen = !isLockOpen; + }); + }, ), ], ), @@ -1315,187 +1513,153 @@ class IconButtonShowcase extends StatelessWidget { } } -// TODO(rydmike): Add variant IconButtons when available in stable. -// class IconButtonM3Showcase extends StatelessWidget { -// const IconButtonM3Showcase({super.key}); -// -// @override -// Widget build(BuildContext context) { -// return RepaintBoundary( -// child: Wrap( -// crossAxisAlignment: WrapCrossAlignment.center, -// spacing: 16, -// runSpacing: 4, -// children: [ -// Column( -// // Standard IconButton -// children: const [ -// _IconM3ToggleButton( -// isEnabled: true, -// tooltip: 'Standard', -// variant: _IconButtonVariant.standard, -// ), -// const SizedBox(height: 8), -// _IconM3ToggleButton( -// isEnabled: false, -// tooltip: 'Standard (disabled)', -// variant: _IconButtonVariant.standard, -// ), -// ], -// ), -// Column( -// children: const [ -// // Filled IconButton -// _IconM3ToggleButton( -// isEnabled: true, -// tooltip: 'Filled', -// variant: _IconButtonVariant.filled, -// ), -// const SizedBox(height: 8), -// _IconM3ToggleButton( -// isEnabled: false, -// tooltip: 'Filled (disabled)', -// variant: _IconButtonVariant.filled, -// ), -// ], -// ), -// Column( -// children: const [ -// // Filled Tonal IconButton -// _IconM3ToggleButton( -// isEnabled: true, -// tooltip: 'Filled tonal', -// variant: _IconButtonVariant.filledTonal, -// ), -// const SizedBox(height: 8), -// _IconM3ToggleButton( -// isEnabled: false, -// tooltip: 'Filled tonal (disabled)', -// variant: _IconButtonVariant.filledTonal, -// ), -// ], -// ), -// Column( -// children: const [ -// // Outlined IconButton -// _IconM3ToggleButton( -// isEnabled: true, -// tooltip: 'Outlined', -// variant: _IconButtonVariant.outlined, -// ), -// const SizedBox(height: 8), -// _IconM3ToggleButton( -// isEnabled: false, -// tooltip: 'Outlined (disabled)', -// variant: _IconButtonVariant.outlined, -// ), -// ], -// ), -// ], -// ), -// ); -// } -// } - -// TODO(rydmike): Add variant IconButtons when available in stable. -// -// enum _IconButtonVariant { standard, filled, filledTonal, outlined } -// -// class _IconM3ToggleButton extends StatefulWidget { -// const _IconM3ToggleButton({ -// required this.isEnabled, -// required this.tooltip, -// required this.variant, -// }); -// -// final bool isEnabled; -// final String tooltip; -// final _IconButtonVariant variant; -// -// @override -// State<_IconM3ToggleButton> createState() => _IconM3ToggleButtonState(); -// } -// -// class _IconM3ToggleButtonState extends State<_IconM3ToggleButton> { -// bool selected = false; -// -// @override -// Widget build(BuildContext context) { -// final VoidCallback? onPressed = widget.isEnabled -// ? () { -// setState(() { -// selected = !selected; -// }); -// } -// : null; -// -// switch (widget.variant) { -// case _IconButtonVariant.standard: -// { -// return IconButton( -// isSelected: selected, -// tooltip: widget.tooltip, -// icon: const Icon(Icons.settings_outlined), -// selectedIcon: const Icon(Icons.settings), -// onPressed: onPressed, -// ); -// } -// case _IconButtonVariant.filled: -// { -// return IconButton.filled( -// isSelected: selected, -// tooltip: widget.tooltip, -// icon: const Icon(Icons.settings_outlined), -// selectedIcon: const Icon(Icons.settings), -// onPressed: onPressed, -// ); -// } -// case _IconButtonVariant.filledTonal: -// { -// return IconButton.filledTonal( -// isSelected: selected, -// tooltip: widget.tooltip, -// icon: const Icon(Icons.settings_outlined), -// selectedIcon: const Icon(Icons.settings), -// onPressed: onPressed, -// ); -// } -// case _IconButtonVariant.outlined: -// { -// return IconButton.outlined( -// isSelected: selected, -// tooltip: widget.tooltip, -// icon: const Icon(Icons.settings_outlined), -// selectedIcon: const Icon(Icons.settings), -// onPressed: onPressed, -// ); -// } -// } -// } -// } - -class IconToggleButton extends StatefulWidget { - const IconToggleButton({ +class IconButtonVariantsShowcase extends StatelessWidget { + const IconButtonVariantsShowcase({super.key}); + @override + Widget build(BuildContext context) { + return const Wrap( + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 0, + runSpacing: 4, + children: [ + Column( + // Standard IconButton + children: [ + SizedBox( + width: 65, child: Text('Default', textAlign: TextAlign.center)), + SizedBox(height: 4), + _IconToggleButton( + isEnabled: true, + tooltip: 'Standard', + variant: _IconButtonVariant.standard, + toggleable: false, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: true, + tooltip: 'Standard toggleable', + variant: _IconButtonVariant.standard, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: false, + tooltip: 'Standard (disabled)', + variant: _IconButtonVariant.standard, + toggleable: false, + ), + ], + ), + Column( + children: [ + SizedBox( + width: 65, child: Text('Filled', textAlign: TextAlign.center)), + SizedBox(height: 4), + // Filled IconButton + _IconToggleButton( + isEnabled: true, + tooltip: 'Filled', + variant: _IconButtonVariant.filled, + toggleable: false, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: true, + tooltip: 'Filled toggleable', + variant: _IconButtonVariant.filled, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: false, + tooltip: 'Filled (disabled)', + variant: _IconButtonVariant.filled, + toggleable: false, + ), + ], + ), + Column( + children: [ + SizedBox( + width: 65, child: Text('Tonal', textAlign: TextAlign.center)), + SizedBox(height: 4), + // Filled Tonal IconButton + _IconToggleButton( + isEnabled: true, + tooltip: 'Filled tonal', + variant: _IconButtonVariant.filledTonal, + toggleable: false, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: true, + tooltip: 'Filled tonal toggleable', + variant: _IconButtonVariant.filledTonal, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: false, + tooltip: 'Filled tonal (disabled)', + variant: _IconButtonVariant.filledTonal, + toggleable: false, + ), + ], + ), + Column( + children: [ + SizedBox( + width: 65, + child: Text('Outlined', textAlign: TextAlign.center)), + SizedBox(height: 4), + // Outlined IconButton + _IconToggleButton( + isEnabled: true, + tooltip: 'Outlined', + variant: _IconButtonVariant.outlined, + toggleable: false, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: true, + tooltip: 'Outlined toggleable', + variant: _IconButtonVariant.outlined, + ), + SizedBox(height: 8), + _IconToggleButton( + isEnabled: false, + tooltip: 'Outlined (disabled)', + variant: _IconButtonVariant.outlined, + toggleable: false, + ), + ], + ), + ], + ); + } +} + +enum _IconButtonVariant { standard, filled, filledTonal, outlined } + +class _IconToggleButton extends StatefulWidget { + const _IconToggleButton({ required this.isEnabled, required this.tooltip, - this.getDefaultStyle, - super.key, + required this.variant, + this.toggleable = true, }); final bool isEnabled; final String tooltip; - final ButtonStyle? Function(bool, ColorScheme)? getDefaultStyle; + final _IconButtonVariant variant; + final bool toggleable; @override - State createState() => _IconToggleButtonState(); + State<_IconToggleButton> createState() => _IconToggleButtonState(); } -class _IconToggleButtonState extends State { +class _IconToggleButtonState extends State<_IconToggleButton> { bool selected = false; @override Widget build(BuildContext context) { - final ColorScheme colors = Theme.of(context).colorScheme; final VoidCallback? onPressed = widget.isEnabled ? () { setState(() { @@ -1503,104 +1667,56 @@ class _IconToggleButtonState extends State { }); } : null; - final ButtonStyle? style = widget.getDefaultStyle?.call(selected, colors); - - return IconButton( - visualDensity: VisualDensity.standard, - isSelected: selected, - tooltip: widget.tooltip, - icon: const Icon(Icons.settings_outlined), - selectedIcon: const Icon(Icons.settings), - onPressed: onPressed, - style: style, - ); - } -} - -ButtonStyle enabledFilledButtonStyle(bool selected, ColorScheme colors) { - return IconButton.styleFrom( - foregroundColor: selected ? colors.onPrimary : colors.primary, - backgroundColor: selected ? colors.primary : colors.surfaceVariant, - disabledForegroundColor: colors.onSurface.withOpacity(0.38), - disabledBackgroundColor: colors.onSurface.withOpacity(0.12), - hoverColor: selected - ? colors.onPrimary.withOpacity(0.08) - : colors.primary.withOpacity(0.08), - focusColor: selected - ? colors.onPrimary.withOpacity(0.12) - : colors.primary.withOpacity(0.12), - highlightColor: selected - ? colors.onPrimary.withOpacity(0.12) - : colors.primary.withOpacity(0.12), - ); -} -ButtonStyle disabledFilledButtonStyle(bool selected, ColorScheme colors) { - return IconButton.styleFrom( - disabledForegroundColor: colors.onSurface.withOpacity(0.38), - disabledBackgroundColor: colors.onSurface.withOpacity(0.12), - ); -} - -ButtonStyle enabledFilledTonalButtonStyle(bool selected, ColorScheme colors) { - return IconButton.styleFrom( - foregroundColor: - selected ? colors.onSecondaryContainer : colors.onSurfaceVariant, - backgroundColor: - selected ? colors.secondaryContainer : colors.surfaceVariant, - hoverColor: selected - ? colors.onSecondaryContainer.withOpacity(0.08) - : colors.onSurfaceVariant.withOpacity(0.08), - focusColor: selected - ? colors.onSecondaryContainer.withOpacity(0.12) - : colors.onSurfaceVariant.withOpacity(0.12), - highlightColor: selected - ? colors.onSecondaryContainer.withOpacity(0.12) - : colors.onSurfaceVariant.withOpacity(0.12), - ); -} - -ButtonStyle disabledFilledTonalButtonStyle(bool selected, ColorScheme colors) { - return IconButton.styleFrom( - disabledForegroundColor: colors.onSurface.withOpacity(0.38), - disabledBackgroundColor: colors.onSurface.withOpacity(0.12), - ); -} - -ButtonStyle enabledOutlinedButtonStyle(bool selected, ColorScheme colors) { - return IconButton.styleFrom( - backgroundColor: selected ? colors.inverseSurface : null, - hoverColor: selected - ? colors.onInverseSurface.withOpacity(0.08) - : colors.onSurfaceVariant.withOpacity(0.08), - focusColor: selected - ? colors.onInverseSurface.withOpacity(0.12) - : colors.onSurfaceVariant.withOpacity(0.12), - highlightColor: selected - ? colors.onInverseSurface.withOpacity(0.12) - : colors.onSurface.withOpacity(0.12), - side: BorderSide(color: colors.outline), - ).copyWith( - foregroundColor: - MaterialStateProperty.resolveWith((Set states) { - if (states.contains(MaterialState.selected)) { - return colors.onInverseSurface; - } - if (states.contains(MaterialState.pressed)) { - return colors.onSurface; - } - return null; - }), - ); -} - -ButtonStyle disabledOutlinedButtonStyle(bool selected, ColorScheme colors) { - return IconButton.styleFrom( - disabledForegroundColor: colors.onSurface.withOpacity(0.38), - disabledBackgroundColor: - selected ? colors.onSurface.withOpacity(0.12) : null, - side: selected ? null : BorderSide(color: colors.outline.withOpacity(0.12)), - ); + final String toggleState = widget.toggleable + ? selected + ? '\n(selected)' + : '\n(not selected)' + : ''; + + switch (widget.variant) { + case _IconButtonVariant.standard: + { + return IconButton( + isSelected: selected & widget.toggleable, + tooltip: '${widget.tooltip}$toggleState', + icon: const Icon(Icons.settings_outlined), + selectedIcon: const Icon(Icons.settings), + onPressed: onPressed, + ); + } + case _IconButtonVariant.filled: + { + return IconButton.filled( + isSelected: selected & widget.toggleable, + tooltip: '${widget.tooltip}$toggleState', + icon: const Icon(Icons.settings_outlined), + selectedIcon: const Icon(Icons.settings), + onPressed: onPressed, + ); + } + case _IconButtonVariant.filledTonal: + { + return IconButton.filledTonal( + isSelected: selected & widget.toggleable, + tooltip: '${widget.tooltip}$toggleState', + icon: const Icon(Icons.settings_outlined), + selectedIcon: const Icon(Icons.settings), + onPressed: onPressed, + ); + } + case _IconButtonVariant.outlined: + { + return IconButton.outlined( + isSelected: selected & widget.toggleable, + tooltip: '${widget.tooltip}$toggleState', + icon: const Icon(Icons.settings_outlined), + selectedIcon: const Icon(Icons.settings), + onPressed: onPressed, + ); + } + } + } } class ProgressIndicatorShowcase extends StatefulWidget { @@ -1750,14 +1866,14 @@ class ChipShowcase extends StatelessWidget { } } -class TextInputField extends StatefulWidget { - const TextInputField({super.key}); +class TextFieldShowcase extends StatefulWidget { + const TextFieldShowcase({super.key}); @override - State createState() => _TextInputFieldState(); + State createState() => _TextFieldShowcaseState(); } -class _TextInputFieldState extends State { +class _TextFieldShowcaseState extends State { late TextEditingController _textController1; late TextEditingController _textController2; late TextEditingController _textController3; @@ -1909,7 +2025,7 @@ class AppBarShowcase extends StatelessWidget { icon: const Icon(Icons.menu), onPressed: () {}, ), - title: const Text('Standard AppBar'), + title: const Text('AppBar'), actions: [ IconButton( icon: const Icon(Icons.search), @@ -2030,73 +2146,204 @@ class _BehindAppBar extends StatelessWidget { } } -class BottomAppBarShowcase extends StatelessWidget { - const BottomAppBarShowcase({ - super.key, - this.explain = true, - }); +class SearchBarShowcase extends StatefulWidget { + const SearchBarShowcase({super.key, this.explain = false}); + final bool explain; + + @override + State createState() => _SearchBarShowcaseState(); +} + +class _SearchBarShowcaseState extends State { + bool isMicOn = false; + + @override + Widget build(BuildContext context) { + final ThemeData theme = Theme.of(context); + final TextStyle denseHeader = theme.textTheme.titleMedium!.copyWith( + fontSize: 13, + ); + final TextStyle denseBody = theme.textTheme.bodyMedium! + .copyWith(fontSize: 12, color: theme.textTheme.bodySmall!.color); + + return Theme( + data: Theme.of(context).copyWith( + inputDecorationTheme: const InputDecorationTheme( + border: InputBorder.none, + focusedBorder: InputBorder.none, + enabledBorder: InputBorder.none, + disabledBorder: InputBorder.none, + errorBorder: InputBorder.none, + focusedErrorBorder: InputBorder.none, + filled: false, + ), + ), + child: Builder(builder: (BuildContext context) { + return Padding( + padding: const EdgeInsets.all(16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (widget.explain) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), + child: Text( + 'SearchBar', + style: denseHeader, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: Text( + 'The M3 SearchBar can in some use cases be used instead ' + 'of an AppBar or BottomAppBar.', + style: denseBody, + ), + ), + ], + SearchAnchor( + builder: (BuildContext context, SearchController controller) { + return SearchBar( + // elevation: const MaterialStatePropertyAll(1), + controller: controller, + hintText: 'Search using SearchBar', + padding: const MaterialStatePropertyAll( + EdgeInsets.symmetric(horizontal: 16.0)), + onTap: () { + controller.openView(); + }, + onChanged: (_) { + controller.openView(); + }, + leading: const Icon(Icons.search), + trailing: [ + Tooltip( + message: 'Voice search', + child: IconButton( + isSelected: isMicOn, + onPressed: () { + setState(() { + isMicOn = !isMicOn; + }); + }, + icon: const Icon(Icons.mic_off), + selectedIcon: const Icon(Icons.mic), + ), + ) + ], + ); + }, suggestionsBuilder: + (BuildContext context, SearchController controller) { + return List.generate(7, (int index) { + final String item = 'item $index'; + return ListTile( + title: Text(item), + onTap: () { + setState(() { + controller.closeView(item); + }); + }, + ); + }); + }), + ], + ), + ); + }), + ); + } +} +class TabBarForAppBarShowcase extends StatelessWidget { + const TabBarForAppBarShowcase({super.key, this.explain = false}); final bool explain; @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); + final bool isDark = theme.brightness == Brightness.dark; + final bool useM3 = theme.useMaterial3; + final ColorScheme colorScheme = theme.colorScheme; + + final Color effectiveTabBackground = theme.appBarTheme.backgroundColor ?? + (isDark + ? colorScheme.surface + : useM3 + ? colorScheme.surface + : colorScheme.primary); final TextStyle denseHeader = theme.textTheme.titleMedium!.copyWith( fontSize: 13, ); final TextStyle denseBody = theme.textTheme.bodyMedium! .copyWith(fontSize: 12, color: theme.textTheme.bodySmall!.color); + return RepaintBoundary( - child: MediaQuery.removePadding( - context: context, - removeBottom: true, - removeTop: true, + child: DefaultTabController( + length: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BottomAppBar( - child: Row( - children: [ - IconButton( - tooltip: 'Open navigation menu', - icon: const Icon(Icons.menu), - onPressed: () {}, - ), - const Spacer(), - IconButton( - tooltip: 'Search', - icon: const Icon(Icons.search), - onPressed: () {}, - ), - IconButton( - tooltip: 'Favorite', - icon: const Icon(Icons.favorite), - onPressed: () {}, - ), - ], - ), - ), - if (explain) + if (explain) ...[ Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), child: Text( - 'BottomAppBar', + 'TabBar in an AppBar', style: denseHeader, ), ), - if (explain) Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), child: Text( - 'Flutter M2 past default color was ' - 'ThemeData.bottomAppBarColor. It was deprecated in ' - 'Flutter 3.7. New default is colorScheme.surface and ' - 'elevation 8. In M3 it defaults to colorScheme.surface ' - 'color, elevation 3, no shadow, but with surface elevation ' - 'tint.', + 'If the TabBar is used in an AppBar, then try style ' + 'FlexTabBarStyle forAppBar, it will fit contrast wise ' + 'here regardless of selected AppBar background color.', style: denseBody, ), + ) + ], + MediaQuery.removePadding( + context: context, + removeBottom: true, + removeTop: true, + child: Material( + color: effectiveTabBackground, + child: SizedBox( + height: 130, + child: AppBar( + leading: IconButton( + icon: const Icon(Icons.menu), + onPressed: () {}, + ), + actions: [ + IconButton( + icon: const Icon(Icons.search), + onPressed: () {}, + ), + ], + title: const Text('TabBar in AppBar'), + bottom: const TabBar( + tabs: [ + Tab( + text: 'Chat', + icon: Badge( + label: Text('18'), + child: Icon(Icons.chat_bubble), + ), + ), + Tab( + text: 'Tasks', + icon: Icon(Icons.beenhere), + ), + Tab( + text: 'Folder', + icon: Icon(Icons.create_new_folder), + ), + ], + ), + ), + ), ), + ), ], ), ), @@ -2104,36 +2351,43 @@ class BottomAppBarShowcase extends StatelessWidget { } } -class TabBarForAppBarShowcase extends StatelessWidget { - const TabBarForAppBarShowcase({super.key}); +class TabBarForBackgroundShowcase extends StatelessWidget { + const TabBarForBackgroundShowcase({super.key, this.explain = false}); + final bool explain; @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - final bool isDark = theme.brightness == Brightness.dark; - final bool useM3 = theme.useMaterial3; - final ColorScheme colorScheme = theme.colorScheme; - - final Color effectiveTabBackground = theme.appBarTheme.backgroundColor ?? - (isDark - ? colorScheme.surface - : useM3 - ? colorScheme.surface - : colorScheme.primary); final TextStyle denseHeader = theme.textTheme.titleMedium!.copyWith( fontSize: 13, ); final TextStyle denseBody = theme.textTheme.bodyMedium! .copyWith(fontSize: 12, color: theme.textTheme.bodySmall!.color); - return RepaintBoundary( child: DefaultTabController( length: 3, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + if (explain) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), + child: Text( + 'TabBar on a surface', + style: denseHeader, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), + child: Text( + 'If TabBar is used on surface colors, consider style ' + 'FlexTabBarStyle forBackground.', + style: denseBody, + ), + ), + ], Material( - color: effectiveTabBackground, + color: theme.colorScheme.surface, child: const SizedBox( height: 70, child: TabBar( @@ -2141,7 +2395,7 @@ class TabBarForAppBarShowcase extends StatelessWidget { Tab( text: 'Chat', icon: Badge( - label: Text('18'), + label: Text('+99'), child: Icon(Icons.chat_bubble), ), ), @@ -2157,22 +2411,6 @@ class TabBarForAppBarShowcase extends StatelessWidget { ), ), ), - Padding( - padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), - child: Text( - 'TabBar in an AppBar', - style: denseHeader, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), - child: Text( - 'If the TabBar will always be used in an AppBar, then use ' - 'style FlexTabBarStyle forAppBar (default), ' - 'it will fit contrast wise here', - style: denseBody, - ), - ), ], ), ), @@ -2180,8 +2418,10 @@ class TabBarForAppBarShowcase extends StatelessWidget { } } -class TabBarForBackgroundShowcase extends StatelessWidget { - const TabBarForBackgroundShowcase({super.key}); +class BottomAppBarShowcase extends StatelessWidget { + const BottomAppBarShowcase({super.key, this.explain = false}); + + final bool explain; @override Widget build(BuildContext context) { @@ -2192,50 +2432,49 @@ class TabBarForBackgroundShowcase extends StatelessWidget { final TextStyle denseBody = theme.textTheme.bodyMedium! .copyWith(fontSize: 12, color: theme.textTheme.bodySmall!.color); return RepaintBoundary( - child: DefaultTabController( - length: 3, + child: MediaQuery.removePadding( + context: context, + removeBottom: true, + removeTop: true, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Material( - color: theme.colorScheme.surface, - child: const SizedBox( - height: 70, - child: TabBar( - tabs: [ - Tab( - text: 'Chat', - icon: Badge( - label: Text('+99'), - child: Icon(Icons.chat_bubble), - ), - ), - Tab( - text: 'Tasks', - icon: Icon(Icons.beenhere), - ), - Tab( - text: 'Folder', - icon: Icon(Icons.create_new_folder), - ), - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), - child: Text( - 'TabBar on a surface', - style: denseHeader, - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), - child: Text( - 'If the TabBar will always be used on background and surface ' - 'colors, then use style FlexTabBarStyle forBackground, ' - 'it will fit contrast wise here', - style: denseBody, + if (explain) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), + child: Text('BottomAppBar', style: denseHeader)), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), + child: Text( + 'Typically used as a command bar at the bottom of the ' + 'screen. Flutter M2 past default color was ' + 'ThemeData.bottomAppBarColor. It was deprecated in ' + 'Flutter 3.7. New M2 default is colorScheme.surface and ' + 'elevation 8. In M3 it defaults to colorScheme.surface ' + 'color, elevation 3, no shadow, but with surface ' + 'elevation tint.', + style: denseBody)) + ], + BottomAppBar( + child: Row( + children: [ + IconButton( + tooltip: 'Open navigation menu', + icon: const Icon(Icons.menu), + onPressed: () {}, + ), + const Spacer(), + IconButton( + tooltip: 'Search', + icon: const Icon(Icons.search), + onPressed: () {}, + ), + IconButton( + tooltip: 'Favorite', + icon: const Icon(Icons.favorite), + onPressed: () {}, + ), + ], ), ), ], @@ -2246,7 +2485,7 @@ class TabBarForBackgroundShowcase extends StatelessWidget { } class BottomNavigationBarShowcase extends StatefulWidget { - const BottomNavigationBarShowcase({super.key, this.explain = true}); + const BottomNavigationBarShowcase({super.key, this.explain = false}); final bool explain; @@ -2271,6 +2510,27 @@ class _BottomNavigationBarShowcaseState child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + if (widget.explain) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), + child: Text( + 'BottomNavigationBar', + style: denseHeader, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), + child: Text( + 'Older Material 2 navigation bar, prefer using NavigationBar. ' + 'Flutter default background ' + 'color is theme canvasColor via Material. The canvasColor ' + 'typically equals colorScheme.background. Default elevation ' + 'is 8. FCS sub-theme default is colorScheme.background ' + 'and elevation 0.', + style: denseBody, + ), + ), + ], MediaQuery.removePadding( context: context, removeBottom: true, @@ -2330,25 +2590,6 @@ class _BottomNavigationBarShowcaseState ], ), ), - if (widget.explain) - Padding( - padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), - child: Text( - 'BottomNavigationBar (Material 2)', - style: denseHeader, - ), - ), - if (widget.explain) - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), - child: Text( - 'Default SDK background color is theme canvasColor via ' - 'Material. The canvasColor is typically ' - 'colorScheme.background, elevation is 8. FCS sub-theme default ' - 'is colorScheme.background and elevation 0.', - style: denseBody, - ), - ), ], ), ); @@ -2356,7 +2597,7 @@ class _BottomNavigationBarShowcaseState } class NavigationBarShowcase extends StatefulWidget { - const NavigationBarShowcase({super.key, this.explain = true}); + const NavigationBarShowcase({super.key, this.explain = false}); final bool explain; @override @@ -2378,6 +2619,26 @@ class _NavigationBarShowcaseState extends State { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ + if (widget.explain) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), + child: Text( + 'NavigationBar', + style: denseHeader, + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), + child: Text( + 'Material 3 navigation bar. Default background color is ' + 'surface with an onSurface overlay ' + 'color in M2, and primary in M3, with elevation 3. ' + 'FCS default is color scheme background, with used ' + 'surface blend and elevation 0.', + style: denseBody, + ), + ), + ], MediaQuery.removePadding( context: context, removeBottom: true, @@ -2434,25 +2695,6 @@ class _NavigationBarShowcaseState extends State { ], ), ), - if (widget.explain) - Padding( - padding: const EdgeInsets.fromLTRB(16, 8, 16, 0), - child: Text( - 'NavigationBar (Material 3)', - style: denseHeader, - ), - ), - if (widget.explain) - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), - child: Text( - 'Default background color is surface with an onSurface overlay ' - 'color in M2, and primary in M3, with elevation 3. ' - 'FlexColorScheme component theme default is color scheme ' - 'background, with used surface blend and elevation 0.', - style: denseBody, - ), - ), ], ), ); @@ -2463,8 +2705,8 @@ class NavigationRailShowcase extends StatefulWidget { const NavigationRailShowcase({ super.key, this.child, - this.height = 400, - this.explain = true, + this.height = 350, + this.explain = false, }); /// A child widget that we can use to place controls on the @@ -2514,7 +2756,7 @@ class _NavigationRailShowcaseState extends State { style: denseBody, ), ), - const Divider(height: 1), + const SizedBox(height: 8), SizedBox( height: widget.height, // If we expand the rail and have a very narrow screen, it will @@ -2603,10 +2845,10 @@ class _NavigationRailShowcaseState extends State { class MenuBarShowcase extends StatelessWidget { const MenuBarShowcase({ super.key, - this.explainUsage = true, + this.explain = false, this.explainIndent = 0, }); - final bool explainUsage; + final bool explain; final double explainIndent; @override @@ -2626,7 +2868,7 @@ class MenuBarShowcase extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.max, children: [ - if (explainUsage) + if (explain) Padding( padding: EdgeInsetsDirectional.fromSTEB(explainIndent, 16, 0, 0), child: Text( @@ -2634,11 +2876,11 @@ class MenuBarShowcase extends StatelessWidget { style: denseHeader, ), ), - if (explainUsage) + if (explain) Padding( padding: EdgeInsetsDirectional.fromSTEB(explainIndent, 0, 0, 8), child: Text( - 'The new M3 menus can be used in a MenuBar via SubMenuButton ' + 'The M3 menus can be used in a MenuBar via SubMenuButton ' 'and its MenuItemButton, but they can also be used in a ' 'MenuAnchor anywhere.', style: denseBody, @@ -2766,8 +3008,8 @@ class MenuBarShowcase extends StatelessWidget { } class MenuAnchorShowcase extends StatelessWidget { - const MenuAnchorShowcase({super.key, this.explainUsage = true}); - final bool explainUsage; + const MenuAnchorShowcase({super.key, this.explain = false}); + final bool explain; @override Widget build(BuildContext context) { @@ -2780,9 +3022,8 @@ class MenuAnchorShowcase extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, children: [ - if (explainUsage) + if (explain) ...[ Padding( padding: const EdgeInsets.fromLTRB(0, 16, 0, 0), child: Text( @@ -2790,19 +3031,19 @@ class MenuAnchorShowcase extends StatelessWidget { style: denseHeader, ), ), - if (explainUsage) Padding( padding: const EdgeInsets.fromLTRB(0, 0, 0, 8), child: Text( - 'The new M3 MenuAnchor used on a Container as a context menu.', + 'The M3 MenuAnchor used on a Container as a context menu.', style: denseBody, ), ), - Row( - children: const [ + ], + const Row( + children: [ Expanded( child: MenuAnchorContextMenu( - message: 'The new M3 MenuAnchor is cool!', + message: 'The M3 MenuAnchor is cool!', ), ), ], @@ -2998,11 +3239,9 @@ class _MenuAnchorContextMenuState extends State { applicationName: 'MenuAnchor Demo', applicationVersion: '1.0.0', ); - break; case MenuEntry.showMessage: case MenuEntry.hideMessage: showingMessage = !showingMessage; - break; case MenuEntry.colorMenu: break; case MenuEntry.colorRed: @@ -3027,7 +3266,7 @@ class _MenuAnchorContextMenuState extends State { } class DrawerShowcase extends StatelessWidget { - const DrawerShowcase({super.key, this.explain = true}); + const DrawerShowcase({super.key, this.explain = false}); final bool explain; @override @@ -3042,7 +3281,7 @@ class DrawerShowcase extends StatelessWidget { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (explain) + if (explain) ...[ Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), child: Text( @@ -3050,7 +3289,6 @@ class DrawerShowcase extends StatelessWidget { style: denseHeader, ), ), - if (explain) Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), child: Text( @@ -3061,6 +3299,7 @@ class DrawerShowcase extends StatelessWidget { style: denseBody, ), ), + ], SizedBox( height: 280, child: MediaQuery.removePadding( @@ -3080,7 +3319,7 @@ class DrawerShowcase extends StatelessWidget { } class NavigationDrawerShowcase extends StatefulWidget { - const NavigationDrawerShowcase({super.key, this.explain = true}); + const NavigationDrawerShowcase({super.key, this.explain = false}); final bool explain; @@ -3106,7 +3345,7 @@ class _NavigationDrawerShowcaseState extends State { crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ - if (widget.explain) + if (widget.explain) ...[ Padding( padding: const EdgeInsets.fromLTRB(16, 16, 16, 0), child: Text( @@ -3114,7 +3353,6 @@ class _NavigationDrawerShowcaseState extends State { style: denseHeader, ), ), - if (widget.explain) Padding( padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), child: Text( @@ -3123,6 +3361,7 @@ class _NavigationDrawerShowcaseState extends State { style: denseBody, ), ), + ], MediaQuery.removePadding( context: context, removeBottom: true, @@ -3170,25 +3409,6 @@ class _NavigationDrawerShowcaseState extends State { } } -class ListTileAllShowcase extends StatelessWidget { - const ListTileAllShowcase({super.key}); - - @override - Widget build(BuildContext context) { - return Column( - children: const [ - ListTileShowcase(), - Divider(height: 1), - SwitchTileShowcase(), - Divider(height: 1), - CheckboxTileShowcase(), - Divider(height: 1), - RadioTileShowcase(), - ], - ); - } -} - class ListTileShowcase extends StatelessWidget { const ListTileShowcase({super.key}); @@ -3226,8 +3446,8 @@ class ListTileShowcase extends StatelessWidget { } } -class SwitchTileShowcase extends StatelessWidget { - const SwitchTileShowcase({super.key}); +class SwitchListTileShowcase extends StatelessWidget { + const SwitchListTileShowcase({super.key}); @override Widget build(BuildContext context) { @@ -3261,8 +3481,8 @@ class SwitchTileShowcase extends StatelessWidget { } } -class CheckboxTileShowcase extends StatelessWidget { - const CheckboxTileShowcase({super.key}); +class CheckboxListTileShowcase extends StatelessWidget { + const CheckboxListTileShowcase({super.key}); @override Widget build(BuildContext context) { @@ -3305,8 +3525,8 @@ class CheckboxTileShowcase extends StatelessWidget { } } -class RadioTileShowcase extends StatelessWidget { - const RadioTileShowcase({super.key}); +class RadioListTileShowcase extends StatelessWidget { + const RadioListTileShowcase({super.key}); @override Widget build(BuildContext context) { @@ -3591,10 +3811,15 @@ class DatePickerDialogShowcase extends StatelessWidget { return Column( children: [ AbsorbPointer( - child: DatePickerDialog( - initialDate: DateTime.now(), - firstDate: DateTime(1930), - lastDate: DateTime(2050), + child: MediaQuery.removePadding( + context: context, + removeTop: true, + removeBottom: true, + child: DatePickerDialog( + initialDate: DateTime.now(), + firstDate: DateTime(1930), + lastDate: DateTime(2050), + ), ), ), TextButton( @@ -3629,7 +3854,7 @@ class BottomSheetShowcase extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - 'Material BottomSheet', + 'BottomSheet', style: theme.textTheme.titleMedium, ), Text( @@ -3667,7 +3892,7 @@ class BottomSheetModalShowcase extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, children: [ Text( - 'Material Modal BottomSheet', + 'Modal BottomSheet', style: theme.textTheme.titleMedium, ), Text( @@ -3690,9 +3915,9 @@ class MaterialBannerSnackBarShowcase extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( + return const Column( crossAxisAlignment: CrossAxisAlignment.start, - children: const [ + children: [ SnackBarShowcase(), SizedBox(height: 16), MaterialBannerShowcase(), @@ -3702,9 +3927,33 @@ class MaterialBannerSnackBarShowcase extends StatelessWidget { } } -class SnackBarShowcase extends StatelessWidget { +class SnackBarShowcase extends StatefulWidget { const SnackBarShowcase({super.key}); + @override + State createState() => _SnackBarShowcaseState(); +} + +class _SnackBarShowcaseState extends State { + int fixedCount = 0; + int pinnedCount = 0; + + Future _showDemoSnackBar( + BuildContext context, SnackBarBehavior style, String message) async { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(message), + behavior: style, + showCloseIcon: true, + action: SnackBarAction( + label: 'Undo', + onPressed: () {}, + ), + duration: const Duration(milliseconds: 3000), + ), + ); + } + @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); @@ -3773,7 +4022,7 @@ class SnackBarShowcase extends StatelessWidget { const SizedBox(width: 24), Text('A floating SnackBar', style: snackStyle), const Spacer(), - Text('Close', style: snackActionStyle), + Text('Undo', style: snackActionStyle), const SizedBox(width: 24), ], ), @@ -3781,6 +4030,20 @@ class SnackBarShowcase extends StatelessWidget { ), ), ), + const SizedBox(height: 8), + Center( + child: TextButton( + child: const Text( + 'Show floating SnackBar', + style: TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () { + pinnedCount++; + unawaited(_showDemoSnackBar(context, SnackBarBehavior.floating, + 'A floating SnackBar ($pinnedCount)')); + }, + ), + ), const SizedBox(height: 16), Material( color: snackBackground, @@ -3797,21 +4060,70 @@ class SnackBarShowcase extends StatelessWidget { const SizedBox(width: 24), Text('A fixed SnackBar', style: snackStyle), const Spacer(), - Text('Close', style: snackActionStyle), + Text('Undo', style: snackActionStyle), const SizedBox(width: 24), ], ), ), ), ), + const SizedBox(height: 8), + Center( + child: TextButton( + child: const Text( + 'Show fixed SnackBar', + style: TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () { + fixedCount++; + unawaited(_showDemoSnackBar(context, SnackBarBehavior.fixed, + 'A fixed SnackBar ($fixedCount)')); + }, + ), + ), ], ), ); } } -class MaterialBannerShowcase extends StatelessWidget { - const MaterialBannerShowcase({super.key}); +class MaterialBannerShowcase extends StatefulWidget { + const MaterialBannerShowcase({super.key, this.enableShowBanner = false}); + + final bool enableShowBanner; + + @override + State createState() => _MaterialBannerShowcaseState(); +} + +class _MaterialBannerShowcaseState extends State { + int showCount = 0; + + Future _showDemoMaterialBanner( + BuildContext context, bool twoButtons, String message) async { + ScaffoldMessenger.of(context).showMaterialBanner( + MaterialBanner( + // elevation: 3, + content: Text(message), + leading: const Icon(Icons.add_alert), + actions: [ + if (twoButtons) + TextButton( + child: const Text('OK'), + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentMaterialBanner(); + }, + ), + TextButton( + child: const Text('Dismiss'), + onPressed: () { + ScaffoldMessenger.of(context).hideCurrentMaterialBanner(); + }, + ), + ], + ), + ); + } @override Widget build(BuildContext context) { @@ -3819,23 +4131,54 @@ class MaterialBannerShowcase extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Divider(height: 1), MaterialBanner( - padding: const EdgeInsets.all(20), - content: const Text('Hello, I am a MaterialBanner'), + elevation: 3, + content: const Text('I am a MaterialBanner at elevation 3'), leading: const Icon(Icons.agriculture_outlined), actions: [ TextButton( - child: const Text('OPEN'), + child: const Text('Open'), onPressed: () {}, ), TextButton( - child: const Text('DISMISS'), + child: const Text('Dismiss'), onPressed: () {}, ), ], ), - const SizedBox(height: 16), + const SizedBox(height: 8), + if (widget.enableShowBanner) + Center( + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + TextButton( + child: const Text( + 'Show MaterialBanner', + style: TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () { + showCount++; + unawaited(_showDemoMaterialBanner( + context, false, 'A MaterialBanner ($showCount)')); + }, + ), + TextButton( + child: const Text( + 'Show two button MaterialBanner', + style: TextStyle(fontWeight: FontWeight.bold), + ), + onPressed: () { + showCount++; + unawaited(_showDemoMaterialBanner(context, true, + 'A MaterialBanner with two actions ($showCount)')); + }, + ), + ], + ), + ), ], ), ); @@ -3843,7 +4186,7 @@ class MaterialBannerShowcase extends StatelessWidget { } class MaterialShowcase extends StatelessWidget { - const MaterialShowcase({super.key, this.explain = true}); + const MaterialShowcase({super.key, this.explain = false}); final bool explain; @override @@ -3861,8 +4204,11 @@ class MaterialShowcase extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ if (explain) ...[ - Text('Material elevation and tint', style: denseHeader), Text( + 'Material widget is a lower level building block. It cannot ' + 'be themed, but it has Material-2 and Material-3 mode dependent ' + 'behavior. Material is responsible for clipping, elevation ' + 'and ink effects below its children. ' 'Material can also specify surfaceTint color, ' 'which is applied when Material is elevated, but only in ' 'Material 3 mode.', @@ -4171,7 +4517,7 @@ class MaterialShowcase extends StatelessWidget { } class CardShowcase extends StatelessWidget { - const CardShowcase({super.key, this.explain = true}); + const CardShowcase({super.key, this.explain = false}); final bool explain; @override @@ -4187,20 +4533,16 @@ class CardShowcase extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (explain) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text('Card', style: denseHeader), - ), if (explain) Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Text( - 'Default background color comes from Material of type card, ' - 'which by default is set to theme colorScheme surface. ' - 'When useMaterial3 is true, Card gets elevation based ' - 'surfaceTint. When it is false, surfaceTint has no ' - 'effect even if specified.', + 'In M2 default background color comes from theme.cardColor, ' + 'which typically is set to theme.colorScheme.surface. ' + 'In M3 background defaults to theme.colorScheme.surface and ' + 'it gets elevation based surfaceTint. In M2 surfaceTint has no ' + 'effect even if specified. Card gets elevation shadow by ' + 'default in both M2 and M3 mode.', style: denseBody, ), ), @@ -4391,116 +4733,200 @@ class CardShowcase extends StatelessWidget { } class TextThemeShowcase extends StatelessWidget { - const TextThemeShowcase({super.key}); + const TextThemeShowcase({super.key, this.showDetails = false}); + final bool showDetails; @override Widget build(BuildContext context) { - return TextThemeColumnShowcase(textTheme: Theme.of(context).textTheme); + return TextThemeColumnShowcase( + textTheme: Theme.of(context).textTheme, + showDetails: showDetails, + ); } } class PrimaryTextThemeShowcase extends StatelessWidget { - const PrimaryTextThemeShowcase({super.key}); + const PrimaryTextThemeShowcase({super.key, this.showDetails = false}); + final bool showDetails; @override Widget build(BuildContext context) { return TextThemeColumnShowcase( - textTheme: Theme.of(context).primaryTextTheme); + textTheme: Theme.of(context).primaryTextTheme, + showDetails: showDetails, + ); } } class TextThemeColumnShowcase extends StatelessWidget { - const TextThemeColumnShowcase({super.key, required this.textTheme}); + const TextThemeColumnShowcase({ + super.key, + required this.textTheme, + this.showDetails = false, + }); final TextTheme textTheme; + final bool showDetails; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text('Font: ${textTheme.titleSmall!.fontFamily}', - style: - textTheme.titleMedium!.copyWith(fontWeight: FontWeight.w600)), - Text( + Text('Font: ${textTheme.bodyMedium!.fontFamily}', + style: textTheme.titleSmall), + _ShowTextStyle( 'Display Large ' '(${textTheme.displayLarge!.fontSize!.toStringAsFixed(0)})', - style: textTheme.displayLarge, + style: textTheme.displayLarge!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Display Medium ' '(${textTheme.displayMedium!.fontSize!.toStringAsFixed(0)})', - style: textTheme.displayMedium, + style: textTheme.displayMedium!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Display Small ' '(${textTheme.displaySmall!.fontSize!.toStringAsFixed(0)})', - style: textTheme.displaySmall, + style: textTheme.displaySmall!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), const SizedBox(height: 12), - Text( + _ShowTextStyle( 'Headline Large ' '(${textTheme.headlineLarge!.fontSize!.toStringAsFixed(0)})', - style: textTheme.headlineLarge, + style: textTheme.headlineLarge!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Headline Medium ' '(${textTheme.headlineMedium!.fontSize!.toStringAsFixed(0)})', - style: textTheme.headlineMedium, + style: textTheme.headlineMedium!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Headline Small ' '(${textTheme.headlineSmall!.fontSize!.toStringAsFixed(0)})', - style: textTheme.headlineSmall, + style: textTheme.headlineSmall!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), const SizedBox(height: 12), - Text( + _ShowTextStyle( 'Title Large ' '(${textTheme.titleLarge!.fontSize!.toStringAsFixed(0)})', - style: textTheme.titleLarge, + style: textTheme.titleLarge!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Title Medium ' '(${textTheme.titleMedium!.fontSize!.toStringAsFixed(0)})', - style: textTheme.titleMedium, + style: textTheme.titleMedium!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Title Small ' '(${textTheme.titleSmall!.fontSize!.toStringAsFixed(0)})', - style: textTheme.titleSmall, + style: textTheme.titleSmall!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), const SizedBox(height: 12), - Text( + _ShowTextStyle( 'Body Large ' '(${textTheme.bodyLarge!.fontSize!.toStringAsFixed(0)})', - style: textTheme.bodyLarge, + style: textTheme.bodyLarge!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Body Medium ' '(${textTheme.bodyMedium!.fontSize!.toStringAsFixed(0)})', - style: textTheme.bodyMedium, + style: textTheme.bodyMedium!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Body Small ' '(${textTheme.bodySmall!.fontSize!.toStringAsFixed(0)})', - style: textTheme.bodySmall, + style: textTheme.bodySmall!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), const SizedBox(height: 12), - Text( + _ShowTextStyle( 'Label Large ' '(${textTheme.labelLarge!.fontSize!.toStringAsFixed(0)})', - style: textTheme.labelLarge, + style: textTheme.labelLarge!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Label Medium ' '(${textTheme.labelMedium!.fontSize!.toStringAsFixed(0)})', - style: textTheme.labelMedium, + style: textTheme.labelMedium!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), - Text( + _ShowTextStyle( 'Label Small ' '(${textTheme.labelSmall!.fontSize!.toStringAsFixed(0)})', - style: textTheme.labelSmall, + style: textTheme.labelSmall!, + infoStyle: textTheme.labelSmall!, + showDetails: showDetails, ), ], ); } } + +class _ShowTextStyle extends StatelessWidget { + const _ShowTextStyle( + this.label, { + required this.style, + required this.infoStyle, + this.showDetails = false, + }); + + final String label; + final TextStyle style; + final TextStyle infoStyle; + final bool showDetails; + + @override + Widget build(BuildContext context) { + final String font = style.fontFamily ?? ''; + final String size = style.fontSize!.toStringAsFixed(1); + final String fontWeight = style.fontWeight!.toString(); + final String color = style.color!.toString(); + final String spacing = style.letterSpacing != null + ? style.letterSpacing!.toStringAsFixed(2) + : ''; + final String height = style.height != null + ? ' height: ${style.height!.toStringAsFixed(2)}' + : ''; + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(label, style: style), + if (showDetails) ...[ + const SizedBox(height: 4), + Text( + '$font $size pt, $fontWeight $color ' + 'Letter spacing: $spacing$height', + style: infoStyle), + const SizedBox(height: 4), + ], + ], + ); + } +} diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 50925c1..67da002 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -27,9 +27,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - path_provider_foundation: c68054786f1b4f3343858c1e1d0caaded73f0be9 - shared_preferences_foundation: 986fc17f3d3251412d18b0265f9c64113a8c2472 - url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 diff --git a/pubspec.lock b/pubspec.lock index d33345e..1239fee 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: crypto - sha256: aa274aa7774f8964e4f4f38cc994db7b6158dd36e9187aaceaddc994b35c6c67 + sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" cupertino_icons: dependency: "direct main" description: @@ -69,10 +69,10 @@ packages: dependency: transitive description: name: ffi - sha256: a38574032c5f1dd06c4aee541789906c12ccaab8ba01446e800d9c5b79c4a978 + sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 url: "https://pub.dev" source: hosted - version: "2.0.1" + version: "2.0.2" file: dependency: transitive description: @@ -85,26 +85,26 @@ packages: dependency: "direct main" description: name: flex_color_picker - sha256: d8279250820ad279123fa8ee94151dd99400dd9ef4fb096589fcf956765d39a9 + sha256: f37476ab3e80dcaca94e428e159944d465dd16312fda9ff41e07e86f04bfa51c url: "https://pub.dev" source: hosted - version: "3.2.2" + version: "3.3.0" flex_color_scheme: dependency: "direct main" description: name: flex_color_scheme - sha256: "5be124fa61821a684c0628ca5f687a8512db06738f784516278688eb727a3ef1" + sha256: "659cf59bd5ccaa1e7de9384342be8b666ff10b108ed57a7fd46c122fb8bf6aca" url: "https://pub.dev" source: hosted - version: "7.1.2" + version: "7.2.0" flex_seed_scheme: dependency: transitive description: name: flex_seed_scheme - sha256: e4168a6fc88a3e5bc3d6b7a748c6a6083eedc193d343ddc26bbad7fb1b258555 + sha256: "29c12aba221eb8a368a119685371381f8035011d18de5ba277ad11d7dfb8657f" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" flutter: dependency: "direct main" description: flutter @@ -188,26 +188,26 @@ packages: dependency: transitive description: name: path_provider_android - sha256: da97262be945a72270513700a92b39dd2f4a54dad55d061687e2e37a6390366a + sha256: "2cec049d282c7f13c594b4a73976b0b4f2d7a1838a6dd5aaf7bd9719196bee86" url: "https://pub.dev" source: hosted - version: "2.0.25" + version: "2.0.27" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: ad4c4d011830462633f03eb34445a45345673dfd4faf1ab0b4735fbd93b19183 + sha256: "916731ccbdce44d545414dd9961f26ba5fbaa74bcbb55237d8e65a623a8c7297" url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.4" path_provider_linux: dependency: transitive description: name: path_provider_linux - sha256: "2ae08f2216225427e64ad224a24354221c2c7907e448e6e0e8b57b1eb9f10ad1" + sha256: ffbb8cc9ed2c9ec0e4b7a541e56fd79b138e8f47d2fb86815f15358a349b3b57 url: "https://pub.dev" source: hosted - version: "2.1.10" + version: "2.1.11" path_provider_platform_interface: dependency: transitive description: @@ -220,10 +220,10 @@ packages: dependency: transitive description: name: path_provider_windows - sha256: f53720498d5a543f9607db4b0e997c4b5438884de25b0f73098cc2671a51b130 + sha256: "1cb68ba4cd3a795033de62ba1b7b4564dace301f952de6bfb3cd91b202b6ee96" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.1.7" platform: dependency: transitive description: @@ -240,14 +240,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.4" - process: - dependency: transitive - description: - name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" - url: "https://pub.dev" - source: hosted - version: "4.2.4" riverpod: dependency: transitive description: @@ -260,58 +252,58 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "16d3fb6b3692ad244a695c0183fca18cf81fd4b821664394a781de42386bf022" + sha256: "0344316c947ffeb3a529eac929e1978fcd37c26be4e8468628bac399365a3ca1" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.2.0" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "7fa90471a6875d26ad78c7e4a675874b2043874586891128dc5899662c97db46" + sha256: fe8401ec5b6dcd739a0fe9588802069e608c3fdbfd3c3c93e546cf2f90438076 url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.2.0" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "0c1c16c56c9708aa9c361541a6f0e5cc6fc12a3232d866a687a7b7db30032b07" + sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.2" shared_preferences_linux: dependency: transitive description: name: shared_preferences_linux - sha256: "9d387433ca65717bbf1be88f4d5bb18f10508917a8fa2fb02e0fd0d7479a9afa" + sha256: "71d6806d1449b0a9d4e85e0c7a917771e672a3d5dc61149cc9fac871115018e1" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" shared_preferences_platform_interface: dependency: transitive description: name: shared_preferences_platform_interface - sha256: fb5cf25c0235df2d0640ac1b1174f6466bd311f621574997ac59018a6664548d + sha256: "23b052f17a25b90ff2b61aad4cc962154da76fb62848a9ce088efe30d7c50ab1" url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: "74083203a8eae241e0de4a0d597dbedab3b8fef5563f33cf3c12d7e93c655ca5" + sha256: "7347b194fb0bbeb4058e6a4e87ee70350b6b2b90f8ac5f8bd5b3a01548f6d33a" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.2.0" shared_preferences_windows: dependency: transitive description: name: shared_preferences_windows - sha256: "5e588e2efef56916a3b229c3bfe81e6a525665a454519ca51dbcc4236a274173" + sha256: f95e6a43162bce43c9c3405f3eb6f39e5b5d11f65fab19196cf8225e2777624d url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.3.0" sky_engine: dependency: transitive description: flutter @@ -377,26 +369,26 @@ packages: dependency: transitive description: name: typed_data - sha256: "26f87ade979c47a150c9eaab93ccd2bebe70a27dc0b4b29517f2904f04eb11a5" + sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c url: "https://pub.dev" source: hosted - version: "1.3.1" + version: "1.3.2" url_launcher: dependency: "direct main" description: name: url_launcher - sha256: eb1e00ab44303d50dd487aab67ebc575456c146c6af44422f9c13889984c00f3 + sha256: "781bd58a1eb16069412365c98597726cd8810ae27435f04b3b4d3a470bacd61e" url: "https://pub.dev" source: hosted - version: "6.1.11" + version: "6.1.12" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: a52628068d282d01a07cd86e6ba99e497aa45ce8c91159015b2416907d78e411 + sha256: "15f5acbf0dce90146a0f5a2c4a002b1814a6303c4c5c075aa2623b2d16156f03" url: "https://pub.dev" source: hosted - version: "6.0.27" + version: "6.0.36" url_launcher_ios: dependency: transitive description: @@ -409,42 +401,42 @@ packages: dependency: transitive description: name: url_launcher_linux - sha256: "206fb8334a700ef7754d6a9ed119e7349bc830448098f21a69bf1b4ed038cabc" + sha256: "207f4ddda99b95b4d4868320a352d374b0b7e05eefad95a4a26f57da413443f5" url: "https://pub.dev" source: hosted - version: "3.0.4" + version: "3.0.5" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: "91ee3e75ea9dadf38036200c5d3743518f4a5eb77a8d13fda1ee5764373f185e" + sha256: "1c4fdc0bfea61a70792ce97157e5cc17260f61abbe4f39354513f39ec6fd73b1" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.6" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "6c9ca697a5ae218ce56cece69d46128169a58aa8653c1b01d26fcd4aad8c4370" + sha256: bfdfa402f1f3298637d71ca8ecfe840b4696698213d5346e9d12d4ab647ee2ea url: "https://pub.dev" source: hosted - version: "2.1.2" + version: "2.1.3" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "81fe91b6c4f84f222d186a9d23c73157dc4c8e1c71489c4d08be1ad3b228f1aa" + sha256: cc26720eefe98c1b71d85f9dc7ef0cada5132617046369d9dc296b3ecaa5cbb4 url: "https://pub.dev" source: hosted - version: "2.0.16" + version: "2.0.18" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: a83ba3607a507758669cfafb03f9de09bf6e6280c14d9b9cb18f013e406dcacd + sha256: "7967065dd2b5fccc18c653b97958fdf839c5478c28e767c61ee879f4e7882422" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.7" vector_math: dependency: transitive description: @@ -457,18 +449,18 @@ packages: dependency: transitive description: name: win32 - sha256: a6f0236dbda0f63aa9a25ad1ff9a9d8a4eaaa5012da0dc59d21afdb1dc361ca4 + sha256: dfdf0136e0aa7a1b474ea133e67cb0154a0acd2599c4f3ada3b49d38d38793ee url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "5.0.5" xdg_directories: dependency: transitive description: name: xdg_directories - sha256: ee1505df1426458f7f60aac270645098d318a8b4766d85fde75f76f2e21807d1 + sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.0.1" sdks: dart: ">=3.0.0 <4.0.0" flutter: ">=3.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index 76ffb24..7510d31 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: theme_demo description: Flutter theme demo using FlexColorScheme and Riverpod. publish_to: 'none' -version: 0.9.8 +version: 0.9.9 environment: sdk: '>=3.0.0 <4.0.0' @@ -14,11 +14,11 @@ dependencies: # Color picker package, by Mike Rydstrom, rydmike.com (@rydmike). # https://pub.dev/packages/flex_color_picker - flex_color_picker: ^3.2.2 + flex_color_picker: ^3.3.0 # Used for surface colored branded theming. (by rydmike.com) # https://pub.dev/packages/flex_color_scheme - flex_color_scheme: ^7.1.2 + flex_color_scheme: ^7.2.0 # The Flutter framework (by Google, flutter.dev) # https://flutter.dev @@ -40,11 +40,11 @@ dependencies: # Store value pair shared preference data, by Google flutter.dev. # https://pub.dev/packages/shared_preferences - shared_preferences: ^2.1.1 + shared_preferences: ^2.2.0 # Used for launching a WEB URL (by Google flutter.dev). # https://pub.dev/packages/url_launcher - url_launcher: ^6.1.11 + url_launcher: ^6.1.12 dev_dependencies: flutter_test: