diff --git a/catalog/gallery/lib/catalog/catalog_app_colors_screen.dart b/catalog/gallery/lib/catalog/catalog_app_colors_screen.dart index 8002e4ad..a6bb9256 100644 --- a/catalog/gallery/lib/catalog/catalog_app_colors_screen.dart +++ b/catalog/gallery/lib/catalog/catalog_app_colors_screen.dart @@ -11,7 +11,6 @@ class CatalogAppColorsScreen extends StatelessWidget { Widget build(BuildContext context) => CatalogScaffold( title: 'COLORS', child: ListView.separated( - shrinkWrap: true, separatorBuilder: (BuildContext context, int index) => const Divider(), itemCount: _CatalogColors.values.length, @@ -52,19 +51,19 @@ extension _CatalogScreenExtensions on _CatalogColors { Color color(BuildContext context) { switch (this) { case _CatalogColors.primary: - return context.theme.colors.primary; + return context.theme.colorScheme.primary; case _CatalogColors.secondary: - return context.theme.colors.secondary; + return context.theme.colorScheme.secondary; case _CatalogColors.success: - return context.theme.colors.success; + return context.theme.customColors.success!; case _CatalogColors.info: - return context.theme.colors.info; + return context.theme.customColors.info!; case _CatalogColors.warning: - return context.theme.colors.warning; + return context.theme.customColors.warning!; case _CatalogColors.danger: - return context.theme.colors.danger; + return context.theme.customColors.danger!; case _CatalogColors.text: - return context.theme.colors.textColor; + return context.theme.customColors.textColor!; } } } diff --git a/catalog/gallery/lib/catalog/catalog_app_text_fields_screen.dart b/catalog/gallery/lib/catalog/catalog_app_text_fields_screen.dart index ddfe29fe..d1f0153f 100644 --- a/catalog/gallery/lib/catalog/catalog_app_text_fields_screen.dart +++ b/catalog/gallery/lib/catalog/catalog_app_text_fields_screen.dart @@ -1,5 +1,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:catalog/catalog.dart'; +import 'package:catalog/extensions/color_extensions.dart'; import 'package:catalog/widgets/app_text_fields.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -21,45 +22,45 @@ class _CatalogTextFieldsScreenState extends State { @override Widget build(BuildContext context) => CatalogScaffold( - title: 'TEXT FIELDS', - child: Container( - margin: const EdgeInsets.all(20), - child: Column( - children: [ - AppTextField( - controller: labelTextController, - labelText: 'Label', - helperText: 'Helper text', - hintText: 'Text', - suffixIcon: Icon( - Icons.close, - color: context.theme.colors.textColor.shade200, + title: 'TEXT FIELDS', + child: Container( + margin: const EdgeInsets.all(20), + child: Column( + children: [ + AppTextField( + controller: labelTextController, + labelText: 'Label', + helperText: 'Helper text', + hintText: 'Text', + suffixIcon: Icon( + Icons.close, + color: context.theme.customColors.textColor!.getShade(200), + ), + prefixIcon: Icon( + Icons.close, + color: context.theme.customColors.textColor!.getShade(200), + ), + keyboardType: TextInputType.emailAddress, ), - prefixIcon: Icon( - Icons.close, - color: context.theme.colors.textColor.shade200, + SizedBox(height: 10.h), + AppTextField( + keyboardType: TextInputType.multiline, + controller: textAreaTextController, + maxLength: 100, + labelText: 'Label', + hintText: 'Text', + currentLength: _characterCount, + onChange: (value) { + setState(() { + _characterCount = value.length; + }); + }, + minLines: 8, + maxLines: 10, ), - keyboardType: TextInputType.emailAddress, - ), - SizedBox(height: 10.h), - AppTextField( - keyboardType: TextInputType.multiline, - controller: textAreaTextController, - maxLength: 100, - labelText: 'Label', - hintText: 'Text', - currentLength: _characterCount, - onChange: (value) { - setState(() { - _characterCount = value.length; - }); - }, - minLines: 8, - maxLines: 10, - ), - SizedBox(height: 10.h), - ], + SizedBox(height: 10.h), + ], + ), ), - ), - ); + ); } diff --git a/catalog/gallery/lib/catalog/catalog_app_typography_screen.dart b/catalog/gallery/lib/catalog/catalog_app_typography_screen.dart index 0b77a3bd..62be858b 100644 --- a/catalog/gallery/lib/catalog/catalog_app_typography_screen.dart +++ b/catalog/gallery/lib/catalog/catalog_app_typography_screen.dart @@ -23,9 +23,9 @@ class CatalogAppTypographyScreen extends StatelessWidget { child: Center( child: Text( element.name.toUpperCase(), - style: element - .textStyle(context) - .copyWith(color: context.theme.colors.textColor), + style: element.textStyle(context).copyWith( + color: context.theme.customColors.textColor, + ), ), ), ), @@ -76,17 +76,17 @@ extension _CatalogScreenExtensions on _CatalogTypography { case _CatalogTypography.bodySmall: return context.theme.textStyles.bodySmall!; case _CatalogTypography.bodyXSmall: - return context.theme.textStyles.bodyXSmall; + return context.theme.customTextStyles.bodyXSmall; case _CatalogTypography.buttonXSmall: - return context.theme.textStyles.buttonXSmall; + return context.theme.customTextStyles.buttonXSmall; case _CatalogTypography.buttonLarge: - return context.theme.textStyles.buttonLarge; + return context.theme.customTextStyles.buttonLarge; case _CatalogTypography.buttonMedium: - return context.theme.textStyles.buttonMedium; + return context.theme.customTextStyles.buttonMedium; case _CatalogTypography.buttonSmall: - return context.theme.textStyles.buttonSmall; + return context.theme.customTextStyles.buttonSmall; case _CatalogTypography.buttonXLarge: - return context.theme.textStyles.buttonXLarge; + return context.theme.customTextStyles.buttonXLarge; } } } diff --git a/catalog/gallery/lib/catalog/catalog_scaffold_screen.dart b/catalog/gallery/lib/catalog/catalog_scaffold_screen.dart index 3efc8e6c..0e6252d2 100644 --- a/catalog/gallery/lib/catalog/catalog_scaffold_screen.dart +++ b/catalog/gallery/lib/catalog/catalog_scaffold_screen.dart @@ -1,4 +1,5 @@ import 'package:auto_route/auto_route.dart'; +import 'package:catalog/extensions/color_extensions.dart'; import 'package:flutter/material.dart'; import 'package:catalog/catalog.dart'; @@ -21,13 +22,14 @@ class CatalogScaffold extends StatelessWidget { ? IconButton( icon: Icon( Icons.chevron_left, - color: context.theme.colors.primary.shade100, + color: context.theme.colorScheme.primary.getShade(100), ), onPressed: () => context.router.pop(), ) : null, title: Text(title), ), + backgroundColor: context.theme.customColors.textColor!.getShade(100), body: SafeArea( child: Padding( padding: const EdgeInsets.all(8.0), diff --git a/catalog/gallery/lib/main/catalog_main_screen.dart b/catalog/gallery/lib/main/catalog_main_screen.dart index c29a75ea..60f41c55 100644 --- a/catalog/gallery/lib/main/catalog_main_screen.dart +++ b/catalog/gallery/lib/main/catalog_main_screen.dart @@ -15,7 +15,7 @@ class CatalogMainScreen extends StatelessWidget { child: ListView.separated( shrinkWrap: true, separatorBuilder: (BuildContext context, int index) => Divider( - color: context.theme.colors.primary, + color: context.theme.colorScheme.primary, ), itemCount: _CatalogScreen.values.length, itemBuilder: (BuildContext context, int index) { diff --git a/catalog/lib/catalog.dart b/catalog/lib/catalog.dart index 16fe9d48..c14a2f35 100644 --- a/catalog/lib/catalog.dart +++ b/catalog/lib/catalog.dart @@ -1,6 +1,6 @@ library catalog; -export 'theme/app_colors.dart'; +export 'theme/custom_colors.dart'; export 'theme/app_text_styles.dart'; export 'theme/app_dimensions.dart'; export 'theme/app_theme.dart'; diff --git a/catalog/lib/common/helper.dart b/catalog/lib/common/helper.dart new file mode 100644 index 00000000..e23206c5 --- /dev/null +++ b/catalog/lib/common/helper.dart @@ -0,0 +1,47 @@ +import 'package:catalog/extensions/color_extensions.dart'; +import 'package:flutter/material.dart'; + +Color? _getMaterialStatesColor( + MaterialState states, + Color baseColor, { + Color? customDisabledColor, + Color? defaultColor, + Color? customHoveredColor, + Color? customFocusedColor, +}) => + switch (states) { + MaterialState.disabled => customDisabledColor ?? baseColor.getShade(500), + MaterialState.focused => customFocusedColor ?? baseColor + ..getShade(400), + MaterialState.hovered => customHoveredColor ?? baseColor.getShade(300), + MaterialState.pressed => baseColor.getShade(400), + _ => defaultColor ?? Colors.transparent, + }; + +MaterialStateProperty getMaterialStatesColors( + Color baseColor, { + Color? customDisabledColor, + Color? defaultColor, + Color? customHoveredColor, + Color? customFocusedColor, +}) => + MaterialStateProperty.resolveWith((Set states) { + for (final element in states) { + return _getMaterialStatesColor(element, baseColor); + } + return baseColor; + }); + +MaterialStateProperty getBorderSidesStates( + Color baseColor, { + Color? customDisabledColor, + Color? defaultColor, + Color? customHoveredColor, + Color? customFocusedColor, +}) => + MaterialStateProperty.resolveWith((Set states) { + for (final element in states) { + return BorderSide(color: _getMaterialStatesColor(element, baseColor)!); + } + return BorderSide(color: baseColor); + }); diff --git a/catalog/lib/extensions/color_extensions.dart b/catalog/lib/extensions/color_extensions.dart new file mode 100644 index 00000000..33736b9c --- /dev/null +++ b/catalog/lib/extensions/color_extensions.dart @@ -0,0 +1,61 @@ +import 'dart:math'; +import 'package:flutter/material.dart'; + +extension ColorExtension on Color { + Color getShade(int shade) => this is MaterialColor + ? (this as MaterialColor)[shade]! + : _generateMaterialColor(); + + MaterialColor _generateMaterialColor() => MaterialColor(value, { + 50: _tintColor(0.9), + 100: _tintColor(0.8), + 200: _tintColor(0.6), + 300: _tintColor(0.4), + 400: _tintColor(0.2), + 500: this, + 600: _shadeColor(0.1), + 700: _shadeColor(0.2), + 800: _shadeColor(0.3), + 900: _shadeColor(0.4), + }); + + int _tintValue(int value, double factor) => + max(0, min((value + ((255 - value) * factor)).round(), 255)); + + Color _tintColor(double factor) => Color.fromRGBO( + _tintValue(red, factor), + _tintValue(green, factor), + _tintValue(blue, factor), + 1, + ); + + int _shadeValue(int value, double factor) => + max(0, min(value - (value * factor).round(), 255)); + + Color _shadeColor(double factor) => Color.fromRGBO( + _shadeValue(red, factor), + _shadeValue(green, factor), + _shadeValue(blue, factor), + 1, + ); + + // Color? get shade100 => _getShade(100); + // + // Color? get shade200 => _getShade(200); + // + // Color? get shade300 => _getShade(300); + // + // Color? get shade400 => _getShade(400); + // + // Color? get shade500 => _getShade(500); + // + // Color? get shade600 => _getShade(600); + // + // Color? get shade700 => _getShade(700); + // + // Color? get shade800 => _getShade(800); + // + // Color? get shade900 => _getShade(900); + // + // Color? get shade1000 => _getShade(1000); +} diff --git a/catalog/lib/theme/app_buttons.dart b/catalog/lib/theme/app_buttons.dart index 7ecc7da1..030af968 100644 --- a/catalog/lib/theme/app_buttons.dart +++ b/catalog/lib/theme/app_buttons.dart @@ -1,132 +1,108 @@ -import 'package:catalog/theme/app_text_styles.dart'; +import 'package:catalog/catalog.dart'; +import 'package:catalog/extensions/color_extensions.dart'; +import 'package:catalog/theme/custom_text_styles.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:catalog/theme/app_colors.dart'; +import 'package:catalog/common/helper.dart'; typedef StrokeButton = OutlinedButton; typedef GhostButton = TextButton; -class AppButtonsStyle { - final ButtonStyle filledButton = _appFilledButton; - final ButtonStyle outlineButton = _appOutlineButton; - final ButtonStyle textButton = _appTextButton; - final ButtonStyle secondaryFilledButton = _appSecondaryFilledButton; - final ButtonStyle secondaryOutlineButton = _appSecondaryOutlineButton; - final ButtonStyle secondaryTextButton = _appSecondaryTextButton; +class AppButtonsStyle extends ThemeExtension { + final CustomColors _customColors; + final CustomTextStyles _customTextStyles; + final ColorScheme _colorScheme; - AppButtonsStyle(); + late final ButtonStyle filledButton; + late final ButtonStyle outlineButton; + late final ButtonStyle textButton; + late final ButtonStyle secondaryFilledButton; + late final ButtonStyle secondaryOutlineButton; + late final ButtonStyle secondaryTextButton; - static AppButtonsStyle getButtonTheme() => AppButtonsStyle(); -} + AppButtonsStyle( + this._customColors, + this._customTextStyles, + this._colorScheme, + ) { + final roundedRectangleBorder = RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16.r), + ); + + filledButton = FilledButton.styleFrom( + shape: roundedRectangleBorder, + textStyle: _customTextStyles.buttonLarge, + elevation: 0.0, + foregroundColor: _customColors.textColor!.getShade(100), + ); + + outlineButton = OutlinedButton.styleFrom( + shape: roundedRectangleBorder, + side: BorderSide( + width: 2, + color: _colorScheme.primary, + ), + textStyle: _customTextStyles.buttonLarge, + elevation: 0.0, + ); -final _appFilledButton = FilledButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.r), - ), - textStyle: AppTextStyles.getAppStyles().buttonLarge, - elevation: 0.0, - foregroundColor: AppColors.getColorScheme().textColor.shade100, -); + textButton = TextButton.styleFrom( + shape: roundedRectangleBorder, + textStyle: _customTextStyles.buttonLarge, + elevation: 0.0, + ); -final _appOutlineButton = OutlinedButton.styleFrom( - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16.r), - ), - side: BorderSide( - width: 2, - color: AppColors.getColorScheme().primary, - ), - textStyle: AppTextStyles.getAppStyles().buttonLarge, - elevation: 0.0, -); + secondaryFilledButton = filledButton.copyWith( + backgroundColor: + getMaterialStatesColors(_customColors.textColor!.getShade(300)), + foregroundColor: getMaterialStatesColors( + _customColors.textColor!.getShade(100), + ), + ); -final _appTextButton = TextButton.styleFrom( - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16.r)), - textStyle: AppTextStyles.getAppStyles().buttonLarge, - elevation: 0.0, -); + secondaryOutlineButton = outlineButton.copyWith( + backgroundColor: getMaterialStatesColors( + _colorScheme.surface.getShade(100), + ), + foregroundColor: getMaterialStatesColors( + _customColors.textColor!.getShade(300), + ), + side: getBorderSidesStates(_customColors.textColor!.getShade(300)), + ); -final _appSecondaryFilledButton = _appFilledButton.copyWith( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.pressed)) { - return AppColors.getColorScheme().textColor.shade500; - } - if (states.contains(MaterialState.disabled)) { - return AppColors.getColorScheme().surface.shade500; - } - if (states.contains(MaterialState.hovered)) { - return AppColors.getColorScheme().onSurface.shade400; - } - if (states.contains(MaterialState.focused)) { - return AppColors.getColorScheme().textColor.shade400; - } - return AppColors.getColorScheme().textColor.shade300; - }, - ), - foregroundColor: MaterialStateProperty.resolveWith( - (Set states) => - AppColors.getColorScheme().textColor.shade100, - ), -); + secondaryTextButton = textButton.copyWith( + backgroundColor: getMaterialStatesColors( + Colors.transparent, + ), + foregroundColor: getMaterialStatesColors( + _customColors.textColor!.getShade(300), + ), + ); + } -final _appSecondaryOutlineButton = _appOutlineButton.copyWith( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.pressed)) { - return AppColors.getColorScheme().surface.shade400; - } - if (states.contains(MaterialState.disabled)) { - return AppColors.getColorScheme().surface.shade500; - } - if (states.contains(MaterialState.hovered)) { - return AppColors.getColorScheme().surface.shade300; - } - if (states.contains(MaterialState.focused)) { - return AppColors.getColorScheme().surface.shade300; - } - return Colors.transparent; - }, - ), - foregroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.pressed)) { - return AppColors.getColorScheme().textColor.shade500; - } - return AppColors.getColorScheme().textColor.shade300; - }, - ), - side: MaterialStateProperty.resolveWith( - (Set states) => BorderSide( - color: AppColors.getColorScheme().textColor.shade300, - ), - ), -); + static AppButtonsStyle getDefaultButtonTheme( + CustomColors customColors, + CustomTextStyles customTextStyles, + ColorScheme colorScheme, + ) => + AppButtonsStyle(customColors, customTextStyles, colorScheme); -final _appSecondaryTextButton = _appTextButton.copyWith( - backgroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.pressed)) { - return AppColors.getColorScheme().surface.shade300; - } - if (states.contains(MaterialState.disabled)) { - return AppColors.getColorScheme().surface.shade500; - } - if (states.contains(MaterialState.hovered)) { - return AppColors.getColorScheme().surface.shade200; - } - if (states.contains(MaterialState.focused)) { - return AppColors.getColorScheme().surface.shade200; - } - return Colors.transparent; - }, - ), - foregroundColor: MaterialStateProperty.resolveWith( - (Set states) { - if (states.contains(MaterialState.pressed)) { - return AppColors.getColorScheme().textColor.shade500; - } - return AppColors.getColorScheme().textColor.shade300; - }, - ), -); + @override + AppButtonsStyle copyWith() => AppButtonsStyle.getDefaultButtonTheme( + _customColors, + _customTextStyles, + _colorScheme, + ); + + @override + AppButtonsStyle lerp(AppButtonsStyle other, double t) { + if (other is! CustomTextStyles) { + return this; + } + return AppButtonsStyle( + _customColors, + _customTextStyles, + _colorScheme, + ); + } +} diff --git a/catalog/lib/theme/app_colors.dart b/catalog/lib/theme/app_color_scheme.dart similarity index 73% rename from catalog/lib/theme/app_colors.dart rename to catalog/lib/theme/app_color_scheme.dart index 5be2a71f..3a7ec486 100644 --- a/catalog/lib/theme/app_colors.dart +++ b/catalog/lib/theme/app_color_scheme.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; // Colors name extracted from https://www.color-name.com @immutable -class AppColors extends ColorScheme { +class AppColorScheme extends ColorScheme { @override final Color onPrimary; @override @@ -16,19 +16,8 @@ class AppColors extends ColorScheme { @override final MaterialColor onSurface; - final MaterialColor textColor; - final MaterialColor info; - final MaterialColor success; - final MaterialColor warning; - final MaterialColor danger; - - AppColors({ + AppColorScheme({ required ColorScheme colorScheme, - required this.textColor, - required this.info, - required this.success, - required this.warning, - required this.danger, required this.onPrimary, required this.onSurface, required this.secondary, @@ -68,7 +57,7 @@ class AppColors extends ColorScheme { surfaceTint: colorScheme.surfaceTint, ); - static AppColors getColorScheme() => AppColors( + static AppColorScheme getDefaultColorScheme() => AppColorScheme( colorScheme: ColorScheme.fromSeed( brightness: Brightness.light, seedColor: const MaterialColor( @@ -102,56 +91,6 @@ class AppColors extends ColorScheme { onBackground: const Color(0xffadadad), background: const Color(0xfff7fafd), ), - textColor: const MaterialColor( - 0xff414158, - { - 100: Color(0xffffffff), - 200: Color(0xffc2c2cc), - 300: Color(0xff8a8aa8), - 400: Color(0xff414158), - 500: Color(0xff1d1616), - }, - ), - info: const MaterialColor( - 0xff1169f7, - { - 100: Color(0xffcfe8fe), - 200: Color(0xff6fb0fc), - 300: Color(0xff1169f7), - 400: Color(0xff083cb1), - 500: Color(0xff031d76), - }, - ), - success: const MaterialColor( - 0xff8ec144, - { - 100: Color(0xffeaf4dd), - 200: Color(0xffc6dfa1), - 300: Color(0xff8ec144), - 400: Color(0xff5d7f2a), - 500: Color(0xff435c1f), - }, - ), - warning: const MaterialColor( - 0xffffbf00, - { - 100: Color(0xfffff2cc), - 200: Color(0xffffdc73), - 300: Color(0xffffbf00), - 400: Color(0xffe5b217), - 500: Color(0xff99770f), - }, - ), - danger: const MaterialColor( - 0xfff4642c, - { - 100: Color(0xfffeebd4), - 200: Color(0xfffbb37f), - 300: Color(0xfff4642c), - 400: Color(0xffd74824), - 500: Color(0xff750908), - }, - ), primary: const MaterialColor( 0xffee1a64, { @@ -203,7 +142,7 @@ class AppColors extends ColorScheme { }, ), onSurface: const MaterialColor( - 0xfff7fafd, + 0xff5b5b5b, { 100: Color(0xffffffff), 200: Color(0xffadadad), diff --git a/catalog/lib/theme/app_dimensions.dart b/catalog/lib/theme/app_dimensions.dart index 8df5c80a..52a1f82c 100644 --- a/catalog/lib/theme/app_dimensions.dart +++ b/catalog/lib/theme/app_dimensions.dart @@ -1,4 +1,6 @@ -class AppDimens { +import 'package:flutter/material.dart'; + +class AppDimension extends ThemeExtension { final int spacing2; final int spacing4; final int spacing8; @@ -7,7 +9,7 @@ class AppDimens { final int spacing20; final int spacing24; - AppDimens({ + AppDimension({ required this.spacing2, required this.spacing4, required this.spacing8, @@ -17,7 +19,7 @@ class AppDimens { required this.spacing24, }); - static AppDimens getDimensions() => AppDimens( + static AppDimension getDefaultDimensions() => AppDimension( spacing2: 2, spacing4: 4, spacing8: 8, @@ -26,4 +28,27 @@ class AppDimens { spacing20: 20, spacing24: 24, ); + + @override + AppDimension copyWith({MaterialColor? primary}) => + AppDimension.getDefaultDimensions(); + + @override + AppDimension lerp(AppDimension? other, double t) { + if (other is! AppDimension) { + return this; + } + return AppDimension( + spacing2: _lerpInt(spacing2, other.spacing2, t).toInt(), + spacing4: _lerpInt(spacing4, other.spacing4, t).toInt(), + spacing8: _lerpInt(spacing8, other.spacing8, t).toInt(), + spacing12: _lerpInt(spacing12, other.spacing12, t).toInt(), + spacing16: _lerpInt(spacing16, other.spacing16, t).toInt(), + spacing20: _lerpInt(spacing20, other.spacing20, t).toInt(), + spacing24: _lerpInt(spacing24, other.spacing24, t).toInt(), + ); + } + + double _lerpInt(int oldValue, int newValue, double factor) => + oldValue + (newValue - oldValue) * factor; } diff --git a/catalog/lib/theme/app_text_styles.dart b/catalog/lib/theme/app_text_styles.dart index b8fe683b..80c6b8ba 100644 --- a/catalog/lib/theme/app_text_styles.dart +++ b/catalog/lib/theme/app_text_styles.dart @@ -7,26 +7,8 @@ import 'package:google_fonts/google_fonts.dart'; const FontWeight _semiboldWeight = FontWeight.w600; class AppTextStyles extends TextTheme { - final TextStyle tinyText; - final TextStyle customOverline; - final TextStyle buttonXLarge; - final TextStyle buttonLarge; - final TextStyle buttonMedium; - final TextStyle buttonSmall; - final TextStyle buttonXSmall; - final TextStyle buttonTiny; - final TextStyle bodyXSmall; const AppTextStyles({ - required this.tinyText, - required this.buttonXLarge, - required this.buttonLarge, - required this.buttonMedium, - required this.buttonSmall, - required this.buttonXSmall, - required this.bodyXSmall, - required this.buttonTiny, - required this.customOverline, super.headlineLarge, super.headlineMedium, super.headlineSmall, @@ -39,21 +21,10 @@ class AppTextStyles extends TextTheme { super.labelLarge, super.labelMedium, super.labelSmall, - labelXSmall, }); factory AppTextStyles.fromTextTheme({ required TextTheme textTheme, - required TextStyle customOverline, - required TextStyle tinyText, - required TextStyle buttonXLarge, - required TextStyle buttonLarge, - required TextStyle buttonMedium, - required TextStyle buttonSmall, - required TextStyle buttonXSmall, - required TextStyle bodyXSmall, - required TextStyle labelXSmall, - required TextStyle buttonTiny, }) => AppTextStyles( headlineSmall: textTheme.headlineSmall, @@ -68,16 +39,6 @@ class AppTextStyles extends TextTheme { labelLarge: textTheme.labelLarge, labelMedium: textTheme.labelMedium, labelSmall: textTheme.labelSmall, - tinyText: tinyText, - customOverline: customOverline, - buttonXLarge: buttonXLarge, - buttonLarge: buttonLarge, - buttonMedium: buttonMedium, - buttonSmall: buttonSmall, - buttonTiny: buttonTiny, - buttonXSmall: buttonXSmall, - bodyXSmall: bodyXSmall, - labelXSmall: labelXSmall, ); static TextStyle _robotoTextStyle( @@ -90,7 +51,7 @@ class AppTextStyles extends TextTheme { color: Colors.white, ); - static AppTextStyles getAppStyles() => AppTextStyles.fromTextTheme( + static AppTextStyles getDefaultAppStyles() => AppTextStyles.fromTextTheme( textTheme: GoogleFonts.robotoTextTheme().copyWith( labelLarge: _robotoTextStyle(20.sp, FontWeight.normal), labelMedium: _robotoTextStyle(16.sp, FontWeight.normal), @@ -98,19 +59,9 @@ class AppTextStyles extends TextTheme { headlineMedium: _robotoTextStyle(20.sp, FontWeight.bold), headlineLarge: _robotoTextStyle(24.sp, FontWeight.bold), ), - tinyText: _robotoTextStyle(10.sp, FontWeight.normal), - customOverline: _robotoTextStyle(10.sp, FontWeight.normal), - buttonXLarge: _robotoTextStyle(24.sp, _semiboldWeight), - buttonLarge: _robotoTextStyle(16.sp, _semiboldWeight), - buttonMedium: _robotoTextStyle(14.sp, _semiboldWeight), - buttonSmall: _robotoTextStyle(12.sp, _semiboldWeight), - buttonXSmall: _robotoTextStyle(10.sp, _semiboldWeight), - bodyXSmall: _robotoTextStyle(12.sp, _semiboldWeight), - labelXSmall: _robotoTextStyle(12.sp, _semiboldWeight), - buttonTiny: _robotoTextStyle(10.sp, _semiboldWeight), ); - TextTheme getThemeData() => getAppStyles(); + TextTheme getThemeData() => getDefaultAppStyles(); } extension TextStyleExtensions on TextStyle { diff --git a/catalog/lib/theme/app_theme.dart b/catalog/lib/theme/app_theme.dart index dc80291a..29b3468f 100644 --- a/catalog/lib/theme/app_theme.dart +++ b/catalog/lib/theme/app_theme.dart @@ -1,97 +1,102 @@ -import 'package:catalog/theme/app_buttons.dart'; -import 'package:catalog/theme/app_text_styles.dart'; +import 'package:catalog/catalog.dart'; +import 'package:catalog/common/helper.dart'; +import 'package:catalog/extensions/color_extensions.dart'; +import 'package:catalog/theme/app_color_scheme.dart'; +import 'package:catalog/theme/custom_text_styles.dart'; import 'package:flutter/material.dart'; -import 'package:catalog/theme/app_colors.dart'; -import 'package:catalog/theme/app_dimensions.dart'; +import 'package:catalog/theme/app_buttons.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -//TODO: add theme extensions - -late AppColors _colors; -late AppDimens _dimensions; -late AppTextStyles _styles; -late AppButtonsStyle _buttonStyles; class AppTheme { static ThemeData provideAppTheme(BuildContext buildContext) { // It can be changed based on the device - _styles = AppTextStyles.getAppStyles(); - _dimensions = AppDimens.getDimensions(); - _colors = AppColors.getColorScheme(); - _buttonStyles = AppButtonsStyle.getButtonTheme(); + final textTheme = AppTextStyles.getDefaultAppStyles().getThemeData(); + final colors = AppColorScheme.getDefaultColorScheme(); + final customColors = CustomColors.getCustomColors(); + final customTextStyles = CustomTextStyles.getCustomTextStyles(customColors); + final appDimension = AppDimension.getDefaultDimensions(); + final buttonTheme = AppButtonsStyle.getDefaultButtonTheme( + customColors, + customTextStyles, + colors, + ); return ThemeData( + extensions: [customColors, customTextStyles, appDimension, buttonTheme], + primaryColor: colors.primary, + colorScheme: colors, dialogTheme: DialogTheme( - backgroundColor: _colors.surface.shade100, + backgroundColor: colors.surface.shade100, elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8.r), - side: BorderSide(color: _colors.surface.shade500), + side: BorderSide(color: colors.surface.shade500), ), - titleTextStyle: _styles.customOverline - .copyWith(color: _colors.textColor.shade300) + titleTextStyle: customTextStyles.customOverline + .copyWith(color: customColors.textColor!.getShade(300)) .semibold(), - contentTextStyle: - _styles.bodyMedium?.copyWith(color: _colors.textColor.shade400), + contentTextStyle: textTheme.bodyMedium + ?.copyWith(color: customColors.textColor!.getShade(400)), ), inputDecorationTheme: InputDecorationTheme( - labelStyle: - _styles.bodyMedium?.copyWith(color: _colors.textColor.shade400), + labelStyle: textTheme.bodyMedium + ?.copyWith(color: customColors.textColor!.getShade(400)), filled: true, - helperStyle: - _styles.bodySmall?.copyWith(color: _colors.textColor.shade300), - hintStyle: - _styles.bodyMedium?.copyWith(color: _colors.textColor.shade300), + helperStyle: textTheme.bodySmall + ?.copyWith(color: customColors.textColor!..getShade(300)), + hintStyle: textTheme.bodyMedium + ?.copyWith(color: customColors.textColor!.getShade(300)), border: OutlineInputBorder( borderRadius: BorderRadius.circular(4.r), borderSide: BorderSide( width: 2, - color: _colors.textColor.shade100, + color: customColors.textColor!.getShade(100), ), ), - fillColor: _colors.surface.shade100, + fillColor: colors.surface.shade100, enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.r), borderSide: BorderSide( width: 2, - color: _colors.textColor.shade200, + color: customColors.textColor!.getShade(200), ), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.r), borderSide: BorderSide( width: 2, - color: _colors.danger.shade300, + color: customColors.danger!.getShade(300), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.r), borderSide: BorderSide( width: 2, - color: _colors.primary.shade800, + color: colors.primary.shade800, ), ), disabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.r), borderSide: BorderSide( width: 2, - color: _colors.textColor.shade200, + color: customColors.textColor!.getShade(200), ), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(4.r), borderSide: BorderSide( width: 2, - color: _colors.error, + color: colors.error, ), ), - errorStyle: _styles.labelSmall?.copyWith(color: _colors.danger), + errorStyle: textTheme.labelSmall?.copyWith(color: customColors.danger), errorMaxLines: 2, - hoverColor: _colors.primary.shade400, - focusColor: _colors.primary.shade800, + hoverColor: colors.primary.shade400, + focusColor: colors.primary.shade800, ), dropdownMenuTheme: DropdownMenuThemeData( - textStyle: _styles.bodyMedium?.copyWith( - color: _colors.primary.shade500, + textStyle: textTheme.bodyMedium?.copyWith( + color: colors.primary.shade500, ), menuStyle: MenuStyle( maximumSize: MaterialStateProperty.resolveWith( @@ -102,58 +107,57 @@ class AppTheme { filled: true, enabledBorder: OutlineInputBorder( borderSide: BorderSide( - color: _colors.onSurface.shade200, + color: colors.onSurface.shade200, ), borderRadius: BorderRadius.all(Radius.circular(4.r)), ), ), ), - primaryColor: _colors.primary, - colorScheme: _colors, filledButtonTheme: FilledButtonThemeData( - style: _buttonStyles.filledButton, + style: buttonTheme.filledButton, ), outlinedButtonTheme: OutlinedButtonThemeData( - style: _buttonStyles.outlineButton, + style: buttonTheme.outlineButton, ), textButtonTheme: TextButtonThemeData( - style: _buttonStyles.textButton, + style: buttonTheme.textButton, + ), + textTheme: textTheme.apply( + bodyColor: CustomColors.getCustomColors().textColor, + displayColor: CustomColors.getCustomColors().textColor!.getShade(500), ), - textTheme: _styles.getThemeData().apply( - bodyColor: _colors.textColor, - displayColor: _colors.textColor.shade500, - ), appBarTheme: AppBarTheme( - backgroundColor: _colors.primary.shade400, - titleTextStyle: TextStyle(color: _colors.textColor.shade100), + backgroundColor: colors.primary.shade400, + titleTextStyle: TextStyle( + color: CustomColors.getCustomColors().textColor!.getShade(500), + ), ), + primaryTextTheme: textTheme, checkboxTheme: CheckboxThemeData( - checkColor: MaterialStateProperty.resolveWith( - (Set states) => _colors.primary.shade600, - ), - fillColor: MaterialStateProperty.resolveWith( - (Set states) => _colors.textColor.shade100, - ), + checkColor: getMaterialStatesColors(colors.primary.shade600), + fillColor: + getMaterialStatesColors(customColors.textColor!..getShade(100)), side: BorderSide( width: 2, - color: _colors.textColor.shade400, + color: customColors.textColor!.getShade(400), ), ), radioTheme: RadioThemeData( - fillColor: MaterialStateProperty.resolveWith( - (Set states) => _colors.textColor.shade400, - ), + fillColor: + getMaterialStatesColors(customColors.textColor!.getShade(400)), ), ); } } extension ThemeExtensions on ThemeData { - AppDimens get dimensions => _dimensions; + CustomColors get customColors => extension()!; + + AppDimension get dimensions => extension()!; - AppColors get colors => _colors; + CustomTextStyles get customTextStyles => extension()!; - AppTextStyles get textStyles => _styles; + TextTheme get textStyles => primaryTextTheme; - AppButtonsStyle get buttonsStyle => _buttonStyles; + AppButtonsStyle get buttonsStyle => extension()!; } diff --git a/catalog/lib/theme/custom_colors.dart b/catalog/lib/theme/custom_colors.dart new file mode 100644 index 00000000..1af6b7b8 --- /dev/null +++ b/catalog/lib/theme/custom_colors.dart @@ -0,0 +1,94 @@ +// ignore_for_file: overridden_fields + +import 'package:flutter/material.dart'; + +@immutable +class CustomColors extends ThemeExtension { + const CustomColors({ + required this.textColor, + required this.info, + required this.success, + required this.warning, + required this.danger, + }) : super(); + + final Color? textColor; + final Color? info; + final Color? success; + final Color? warning; + final Color? danger; + + static CustomColors getCustomColors() => const CustomColors( + textColor: MaterialColor( + 0xff414158, + { + 100: Color(0xffffffff), + 200: Color(0xffc2c2cc), + 300: Color(0xff8a8aa8), + 400: Color(0xff414158), + 500: Color(0xff1d1616), + }, + ), + info: MaterialColor( + 0xff1169f7, + { + 100: Color(0xffcfe8fe), + 200: Color(0xff6fb0fc), + 300: Color(0xff1169f7), + 400: Color(0xff083cb1), + 500: Color(0xff031d76), + }, + ), + success: MaterialColor( + 0xff8ec144, + { + 100: Color(0xffeaf4dd), + 200: Color(0xffc6dfa1), + 300: Color(0xff8ec144), + 400: Color(0xff5d7f2a), + 500: Color(0xff435c1f), + }, + ), + warning: MaterialColor( + 0xffffbf00, + { + 100: Color(0xfffff2cc), + 200: Color(0xffffdc73), + 300: Color(0xffffbf00), + 400: Color(0xffe5b217), + 500: Color(0xff99770f), + }, + ), + danger: MaterialColor( + 0xfff4642c, + { + 100: Color(0xfffeebd4), + 200: Color(0xfffbb37f), + 300: Color(0xfff4642c), + 400: Color(0xffd74824), + 500: Color(0xff750908), + }, + ), + ); + + @override + CustomColors copyWith({MaterialColor? primary}) => + CustomColors.getCustomColors(); + + @override + CustomColors lerp(CustomColors? other, double t) { + if (other is! CustomColors) { + return this; + } + return CustomColors( + textColor: Color.lerp(textColor, other.textColor, t), + info: Color.lerp(info, other.info, t), + success: Color.lerp(success, other.success, t), + warning: Color.lerp(warning, other.warning, t), + danger: Color.lerp(danger, other.danger, t), + ); + } + + @override + Object get type => CustomColors; +} diff --git a/catalog/lib/theme/custom_text_styles.dart b/catalog/lib/theme/custom_text_styles.dart new file mode 100644 index 00000000..170f27a8 --- /dev/null +++ b/catalog/lib/theme/custom_text_styles.dart @@ -0,0 +1,92 @@ +// ignore_for_file: overridden_fields + +import 'package:catalog/extensions/color_extensions.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_screenutil/flutter_screenutil.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:catalog/theme/custom_colors.dart'; + +const FontWeight _semiboldWeight = FontWeight.w600; + +@immutable +class CustomTextStyles extends ThemeExtension { + const CustomTextStyles({ + required this.tinyText, + required this.customOverline, + required this.buttonXLarge, + required this.buttonLarge, + required this.buttonMedium, + required this.buttonSmall, + required this.buttonXSmall, + required this.buttonTiny, + required this.labelXSmall, + required this.bodyXSmall, + required this.customColors, + }) : super(); + + final TextStyle tinyText; + final TextStyle customOverline; + final TextStyle buttonXLarge; + final TextStyle buttonLarge; + final TextStyle buttonMedium; + final TextStyle buttonSmall; + final TextStyle buttonXSmall; + final TextStyle buttonTiny; + final TextStyle bodyXSmall; + final TextStyle labelXSmall; + final CustomColors customColors; + + static CustomTextStyles getCustomTextStyles(CustomColors customColors) => + CustomTextStyles( + tinyText: _robotoTextStyle(10.sp, FontWeight.normal, customColors), + customOverline: + _robotoTextStyle(10.sp, FontWeight.normal, customColors), + buttonXLarge: _robotoTextStyle(24.sp, _semiboldWeight, customColors), + buttonLarge: _robotoTextStyle(16.sp, _semiboldWeight, customColors), + buttonMedium: _robotoTextStyle(14.sp, _semiboldWeight, customColors), + buttonSmall: _robotoTextStyle(12.sp, _semiboldWeight, customColors), + buttonXSmall: _robotoTextStyle(10.sp, _semiboldWeight, customColors), + bodyXSmall: _robotoTextStyle(12.sp, _semiboldWeight, customColors), + labelXSmall: _robotoTextStyle(12.sp, _semiboldWeight, customColors), + buttonTiny: _robotoTextStyle(10.sp, _semiboldWeight, customColors), + customColors: customColors, + ); + + static TextStyle _robotoTextStyle( + double fontSize, + FontWeight fontWeight, + CustomColors customColors, + ) => + GoogleFonts.roboto( + fontSize: fontSize, + fontWeight: fontWeight, + color: customColors.textColor!.getShade(500), + ); + + @override + CustomTextStyles copyWith({MaterialColor? primary}) => + CustomTextStyles.getCustomTextStyles(customColors); + + @override + CustomTextStyles lerp(CustomTextStyles? other, double t) { + if (other is! CustomTextStyles) { + return this; + } + return CustomTextStyles( + tinyText: TextStyle.lerp(tinyText, other.tinyText, t)!, + customOverline: TextStyle.lerp(customOverline, other.customOverline, t)!, + buttonXLarge: TextStyle.lerp(buttonXLarge, other.buttonXLarge, t)!, + buttonLarge: TextStyle.lerp(buttonLarge, other.buttonLarge, t)!, + buttonMedium: TextStyle.lerp(buttonMedium, other.buttonMedium, t)!, + buttonSmall: TextStyle.lerp(buttonSmall, other.buttonSmall, t)!, + buttonXSmall: TextStyle.lerp(buttonXSmall, other.buttonXSmall, t)!, + buttonTiny: TextStyle.lerp(buttonTiny, other.buttonTiny, t)!, + bodyXSmall: TextStyle.lerp(bodyXSmall, other.bodyXSmall, t)!, + labelXSmall: TextStyle.lerp(labelXSmall, other.labelXSmall, t)!, + customColors: customColors, + ); + } + + @override + Object get type => CustomTextStyles; +} diff --git a/catalog/lib/widgets/app_dialog.dart b/catalog/lib/widgets/app_dialog.dart index d4943644..71b0aec7 100644 --- a/catalog/lib/widgets/app_dialog.dart +++ b/catalog/lib/widgets/app_dialog.dart @@ -1,4 +1,5 @@ import 'package:catalog/catalog.dart'; +import 'package:catalog/extensions/color_extensions.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -28,52 +29,56 @@ class AppDialog extends StatelessWidget { onPressed: Navigator.of(context).pop, icon: Icon( Icons.close, - color: context.theme.colors.textColor.shade300, + color: context.theme.customColors.textColor!.getShade(300), ), ), ], ), content: content != null ? Text(content!) : null, - actionsAlignment: _getAligment(), + actionsAlignment: _getAlignment(), actions: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - if (cancelButtonText != null) - Expanded( - child: TextButton( - onPressed: Navigator.of(context).pop, - child: Text( - cancelButtonText!, - style: context.theme.textStyles.buttonMedium.copyWith( - color: context.theme.colors.textColor.shade300, - ), + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + if (cancelButtonText != null) + Expanded( + child: TextButton( + onPressed: Navigator.of(context).pop, + child: Text( + cancelButtonText!, + style: + context.theme.customTextStyles.buttonMedium.copyWith( + color: + context.theme.customColors.textColor!.getShade(300), ), ), ), - if (actionButtonText != null) - Expanded( - child: FilledButton( - child: Text( - actionButtonText!, - style: context.theme.textStyles.buttonMedium.copyWith( - color: context.theme.colors.textColor.shade100, - ), + ), + if (actionButtonText != null) + Expanded( + child: FilledButton( + child: Text( + actionButtonText!, + style: + context.theme.customTextStyles.buttonMedium.copyWith( + color: + context.theme.customColors.textColor!.getShade(100), ), - onPressed: () { - if (onActionPressed != null) { - onActionPressed!(); - } - Navigator.of(context).pop(); - }, ), + onPressed: () { + if (onActionPressed != null) { + onActionPressed!(); + } + Navigator.of(context).pop(); + }, ), - ], - ), + ), + ], + ), ], ); - MainAxisAlignment _getAligment() { + MainAxisAlignment _getAlignment() { if (actionButtonText == null) { return MainAxisAlignment.start; } else if (cancelButtonText == null) { diff --git a/catalog/lib/widgets/app_dropdown.dart b/catalog/lib/widgets/app_dropdown.dart index a55d98d5..3f8882a9 100644 --- a/catalog/lib/widgets/app_dropdown.dart +++ b/catalog/lib/widgets/app_dropdown.dart @@ -1,4 +1,5 @@ import 'package:catalog/catalog.dart'; +import 'package:catalog/extensions/color_extensions.dart'; import 'package:flutter/material.dart'; typedef AppDropdownItems = ({T value, String label}); @@ -27,7 +28,7 @@ class _AppDropdownMenuState extends State> { initialSelection: widget.initialValue, trailingIcon: Icon( Icons.arrow_drop_down_outlined, - color: context.theme.colors.textColor.shade200, + color: context.theme.customColors.textColor!.getShade(200), ), controller: _controller, onSelected: (T? value) => widget.onSelected(value), @@ -39,11 +40,11 @@ class _AppDropdownMenuState extends State> { style: ButtonStyle( backgroundColor: MaterialStateProperty.resolveWith( (Set states) => - context.theme.colors.surface.shade100, + context.theme.colorScheme.surface.getShade(100), ), foregroundColor: MaterialStateProperty.resolveWith( (Set states) => - context.theme.colors.textColor.shade400, + context.theme.customColors.textColor!.getShade(400), ), ), ), diff --git a/catalog/lib/widgets/app_radio_button.dart b/catalog/lib/widgets/app_radio_button.dart index 221ba6aa..22f5cb4c 100644 --- a/catalog/lib/widgets/app_radio_button.dart +++ b/catalog/lib/widgets/app_radio_button.dart @@ -1,4 +1,5 @@ import 'package:catalog/catalog.dart'; +import 'package:catalog/extensions/color_extensions.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -47,7 +48,7 @@ class _AppRadioButtonState extends State> { return SizedBox( width: 1.sw, child: RadioListTile( - activeColor: context.theme.colors.primary.shade600, + activeColor: context.theme.colorScheme.primary.getShade(600), title: Text(element.label), value: element.value, groupValue: selectedValue, diff --git a/catalog/lib/widgets/app_text_fields.dart b/catalog/lib/widgets/app_text_fields.dart index 6e0a50da..6035c68a 100644 --- a/catalog/lib/widgets/app_text_fields.dart +++ b/catalog/lib/widgets/app_text_fields.dart @@ -1,5 +1,6 @@ //ignore_for_file: prefer-moving-to-variable, unused-files, unused-code import 'package:catalog/catalog.dart'; +import 'package:catalog/extensions/color_extensions.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; @@ -50,7 +51,7 @@ class AppTextField extends StatefulWidget { class _AppTextFieldState extends State { @override Widget build(BuildContext context) { - final colors = context.theme.colors; + final textColor = context.theme.customColors.textColor!.getShade(400); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -62,7 +63,7 @@ class _AppTextFieldState extends State { textAlign: TextAlign.left, style: context.theme.textStyles.labelMedium! .bold() - .copyWith(color: colors.textColor.shade400), + .copyWith(color: textColor), ), ), SizedBox(height: 5.h), @@ -74,8 +75,8 @@ class _AppTextFieldState extends State { textAlignVertical: TextAlignVertical.center, controller: widget.controller, onChanged: widget.onChange, - style: context.theme.textStyles.bodyMedium - ?.copyWith(color: colors.textColor.shade400), + style: + context.theme.textStyles.bodyMedium?.copyWith(color: textColor), decoration: InputDecoration( helperText: widget.helperText, hintText: widget.hintText, diff --git a/lib/ui/welcome/welcome_screen.dart b/lib/ui/welcome/welcome_screen.dart index bed3281f..134a97db 100644 --- a/lib/ui/welcome/welcome_screen.dart +++ b/lib/ui/welcome/welcome_screen.dart @@ -31,7 +31,7 @@ class _WelcomeContentScreen extends StatelessWidget { TextButton( style: ButtonStyle( foregroundColor: MaterialStateProperty.all( - context.theme.colors.onPrimary, + context.theme.colorScheme.onPrimary, ), ), onPressed: () => context.read().logOut(),