refactor(ui): replace ThemeResolver by ThemeHelper in Loader / RichTextBuilder (closes #148)
This commit is contained in:
		
							parent
							
								
									6c54689393
								
							
						
					
					
						commit
						1a48b606a4
					
				| @ -19,8 +19,7 @@ export './buttons/buttons.dart'; | ||||
| export './cards/cards.dart'; | ||||
| export './component.dart'; | ||||
| export './error_widget_component.dart'; | ||||
| export './loader_component.dart'; | ||||
| export './loader_style.dart'; | ||||
| export './loader/loader.dart'; | ||||
| export './loading_widget_component.dart'; | ||||
| export './rich_text_builder/rich_text_builder.dart'; | ||||
| export './text_inputs/text_inputs.dart'; | ||||
|  | ||||
| @ -0,0 +1,17 @@ | ||||
| // Copyright (C) 2023 WYATT GROUP | ||||
| // Please see the AUTHORS file for details. | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| export './loader_component.dart'; | ||||
| @ -1,82 +0,0 @@ | ||||
| // Copyright (C) 2023 WYATT GROUP | ||||
| // Please see the AUTHORS file for details. | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'dart:ui'; | ||||
| 
 | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| 
 | ||||
| class LoaderStyle extends ThemeStyle<LoaderStyle> { | ||||
|   const LoaderStyle({ | ||||
|     this.colors, | ||||
|     this.stroke, | ||||
|   }); | ||||
| 
 | ||||
|   /// Merges non-null `b` attributes in `a` | ||||
|   static LoaderStyle? merge( | ||||
|     LoaderStyle? a, | ||||
|     LoaderStyle? b, | ||||
|   ) { | ||||
|     if (b == null) { | ||||
|       return a?.copyWith(); | ||||
|     } | ||||
|     if (a == null) { | ||||
|       return b.copyWith(); | ||||
|     } | ||||
| 
 | ||||
|     return a.copyWith( | ||||
|       colors: b.colors, | ||||
|       stroke: b.stroke, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Used for interpolation. | ||||
|   static LoaderStyle? lerp( | ||||
|     LoaderStyle? a, | ||||
|     LoaderStyle? b, | ||||
|     double t, | ||||
|   ) { | ||||
|     if (a == null || b == null) { | ||||
|       return null; | ||||
|     } | ||||
|     // b.copyWith to return b attributes even if they are not lerped | ||||
|     return b.copyWith( | ||||
|       colors: MultiColor.lerp(a.colors, b.colors, t), | ||||
|       stroke: lerpDouble(a.stroke, b.stroke, t), | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Gradient colors from start to end. | ||||
|   final MultiColor? colors; | ||||
| 
 | ||||
|   /// Loader stroke width | ||||
|   final double? stroke; | ||||
| 
 | ||||
|   @override | ||||
|   LoaderStyle? mergeWith(LoaderStyle? other) => LoaderStyle.merge(this, other); | ||||
| 
 | ||||
|   @override | ||||
|   LoaderStyle copyWith({ | ||||
|     MultiColor? colors, | ||||
|     double? stroke, | ||||
|   }) => | ||||
|       LoaderStyle( | ||||
|         colors: colors ?? this.colors, | ||||
|         stroke: stroke ?? this.stroke, | ||||
|       ); | ||||
| 
 | ||||
|   @override | ||||
|   String toString() => 'LoaderStyle($colors, $stroke)'; | ||||
| } | ||||
| @ -16,4 +16,3 @@ | ||||
| 
 | ||||
| export 'parser.dart'; | ||||
| export 'rich_text_builder_component.dart'; | ||||
| export 'rich_text_builder_style.dart'; | ||||
|  | ||||
| @ -28,7 +28,6 @@ abstract class RichTextBuilderComponent extends Component | ||||
|     this.parser, | ||||
|     this.defaultStyle, | ||||
|     this.styles, | ||||
|     super.themeResolver, | ||||
|     super.key, | ||||
|   }); | ||||
| 
 | ||||
|  | ||||
| @ -11,15 +11,12 @@ abstract class $RichTextBuilderComponentCWProxy { | ||||
|   RichTextBuilderComponent parser(RichTextParser? parser); | ||||
|   RichTextBuilderComponent defaultStyle(TextStyle? defaultStyle); | ||||
|   RichTextBuilderComponent styles(Map<String, TextStyle>? styles); | ||||
|   RichTextBuilderComponent themeResolver( | ||||
|       ThemeResolver<dynamic, dynamic, dynamic>? themeResolver); | ||||
|   RichTextBuilderComponent key(Key? key); | ||||
|   RichTextBuilderComponent call({ | ||||
|     String? text, | ||||
|     RichTextParser? parser, | ||||
|     TextStyle? defaultStyle, | ||||
|     Map<String, TextStyle>? styles, | ||||
|     ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, | ||||
|     Key? key, | ||||
|   }); | ||||
| } | ||||
|  | ||||
| @ -1,79 +0,0 @@ | ||||
| // Copyright (C) 2023 WYATT GROUP | ||||
| // Please see the AUTHORS file for details. | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:flutter/widgets.dart'; | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| 
 | ||||
| class RichTextBuilderStyle extends ThemeStyle<RichTextBuilderStyle> { | ||||
|   const RichTextBuilderStyle({ | ||||
|     this.defaultStyle, | ||||
|     this.styles, | ||||
|   }); | ||||
| 
 | ||||
|   /// Merges non-null `b` attributes in `a` | ||||
|   static RichTextBuilderStyle? merge( | ||||
|     RichTextBuilderStyle? a, | ||||
|     RichTextBuilderStyle? b, | ||||
|   ) { | ||||
|     if (b == null) { | ||||
|       return a?.copyWith(); | ||||
|     } | ||||
|     if (a == null) { | ||||
|       return b.copyWith(); | ||||
|     } | ||||
| 
 | ||||
|     return a.copyWith( | ||||
|       defaultStyle: b.defaultStyle, | ||||
|       styles: b.styles, | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Used for interpolation. | ||||
|   static RichTextBuilderStyle? lerp( | ||||
|     RichTextBuilderStyle? a, | ||||
|     RichTextBuilderStyle? b, | ||||
|     double t, | ||||
|   ) { | ||||
|     if (a == null || b == null) { | ||||
|       return null; | ||||
|     } | ||||
|     // b.copyWith to return b attributes even if they are not lerped | ||||
|     return b.copyWith( | ||||
|       defaultStyle: TextStyle.lerp(a.defaultStyle, b.defaultStyle, t), | ||||
|       styles: b.styles, // TODO(wyatt): compute lerp value of each styles | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   /// Default TextStyle used in this rich text component. | ||||
|   final TextStyle? defaultStyle; | ||||
| 
 | ||||
|   /// Used styles in this rich text component. | ||||
|   final Map<String, TextStyle>? styles; | ||||
| 
 | ||||
|   @override | ||||
|   RichTextBuilderStyle? mergeWith(RichTextBuilderStyle? other) => | ||||
|       RichTextBuilderStyle.merge(this, other); | ||||
| 
 | ||||
|   @override | ||||
|   RichTextBuilderStyle? copyWith({ | ||||
|     TextStyle? defaultStyle, | ||||
|     Map<String, TextStyle>? styles, | ||||
|   }) => | ||||
|       RichTextBuilderStyle( | ||||
|         defaultStyle: defaultStyle ?? this.defaultStyle, | ||||
|         styles: styles ?? this.styles, | ||||
|       ); | ||||
| } | ||||
| @ -20,7 +20,6 @@ import 'package:flutter/material.dart'; | ||||
| import 'package:flutter_animate/flutter_animate.dart'; | ||||
| import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| import 'package:wyatt_ui_kit/src/components/loader/loader_theme_resolver.dart'; | ||||
| import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; | ||||
| 
 | ||||
| part 'loader.g.dart'; | ||||
| @ -33,30 +32,11 @@ class Loader extends LoaderComponent with $LoaderCWMixin { | ||||
|     super.stroke, | ||||
|     super.duration, | ||||
|     super.flip, | ||||
|     super.themeResolver, | ||||
|     super.key, | ||||
|   }); | ||||
| 
 | ||||
|   @override | ||||
|   LoaderThemeResolver? get themeResolver => | ||||
|       super.themeResolver as LoaderThemeResolver?; | ||||
| 
 | ||||
|   /// Negotiate the theme to get a complete style. | ||||
|   LoaderStyle _resolve(BuildContext context) { | ||||
|     final LoaderThemeResolver resolver = themeResolver ?? | ||||
|         LoaderThemeResolver( | ||||
|           customStyleFn: (context, {extra}) => LoaderStyle( | ||||
|             colors: colors, | ||||
|             stroke: stroke, | ||||
|           ), | ||||
|         ); | ||||
| 
 | ||||
|     return resolver.negotiate(context); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final style = _resolve(context); | ||||
|     final dimension = | ||||
|         (radius != null) ? radius! * 2 : context.buttonTheme.height; | ||||
|     return SizedBox.square( | ||||
| @ -64,9 +44,34 @@ class Loader extends LoaderComponent with $LoaderCWMixin { | ||||
|       child: RepaintBoundary( | ||||
|         child: CustomPaint( | ||||
|           painter: _LoaderPainter( | ||||
|             style.colors ?? const MultiColor([]), | ||||
|             ThemeHelper.getThemeElement<MultiColor, MultiColor>( | ||||
|               [ | ||||
|                 colors, | ||||
|                 Theme.of(context).extension<LoaderThemeExtension>()?.colors, | ||||
|                 MultiColor([ | ||||
|                   Theme.of(context).progressIndicatorTheme.color ?? | ||||
|                       context.colorScheme.primary, | ||||
|                   context.colorScheme.onPrimary, | ||||
|                 ]), | ||||
| 
 | ||||
|                 /// This is the default value. So the final | ||||
|                 /// value cannot be null. | ||||
|                 const MultiColor([]) | ||||
|               ], | ||||
|               valueValidator: (multiColor) => | ||||
|                   multiColor != null && multiColor.isColor, | ||||
|               transform: (multiColor) => multiColor, | ||||
|             )!, | ||||
|             dimension / 2, | ||||
|             style.stroke ?? 4, | ||||
|             ThemeHelper.getThemeElement<double, double>( | ||||
|               [ | ||||
|                 stroke, | ||||
|                 Theme.of(context).extension<LoaderThemeExtension>()?.stroke, | ||||
|                 4, | ||||
|               ], | ||||
|               valueValidator: (stroke) => stroke != null, | ||||
|               transform: (stroke) => stroke, | ||||
|             )!, | ||||
|             flip: flip ?? false, | ||||
|           ), | ||||
|         ) | ||||
|  | ||||
| @ -41,7 +41,6 @@ class $LoaderCWProxyImpl implements $LoaderComponentCWProxy { | ||||
|         stroke: stroke ?? _value.stroke, | ||||
|         duration: duration ?? _value.duration, | ||||
|         flip: flip ?? _value.flip, | ||||
|         themeResolver: themeResolver ?? _value.themeResolver, | ||||
|         key: key ?? _value.key, | ||||
|       ); | ||||
| } | ||||
|  | ||||
| @ -1,58 +0,0 @@ | ||||
| // Copyright (C) 2023 WYATT GROUP | ||||
| // Please see the AUTHORS file for details. | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; | ||||
| 
 | ||||
| class LoaderThemeResolver | ||||
|     extends ThemeResolver<LoaderStyle, LoaderThemeExtension, void> { | ||||
|   const LoaderThemeResolver({ | ||||
|     required this.customStyleFn, | ||||
|   }); | ||||
| 
 | ||||
|   @override | ||||
|   final LoaderStyle? Function( | ||||
|     BuildContext context, { | ||||
|     void extra, | ||||
|   }) customStyleFn; | ||||
| 
 | ||||
|   /// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html> | ||||
|   @override | ||||
|   LoaderStyle computeDefaultValue( | ||||
|     BuildContext context, { | ||||
|     void extra, | ||||
|   }) => | ||||
|       LoaderStyle( | ||||
|         colors: MultiColor([ | ||||
|           Theme.of(context).progressIndicatorTheme.color ?? | ||||
|               context.colorScheme.primary, | ||||
|           context.colorScheme.onPrimary, | ||||
|         ]), | ||||
|         stroke: 4, | ||||
|       ); | ||||
| 
 | ||||
|   @override | ||||
|   LoaderStyle? computeExtensionValueFn( | ||||
|     BuildContext context, | ||||
|     LoaderThemeExtension? themeExtension, { | ||||
|     void extra, | ||||
|   }) => | ||||
|       LoaderStyle( | ||||
|         colors: themeExtension?.colors, | ||||
|         stroke: themeExtension?.stroke, | ||||
|       ); | ||||
| } | ||||
| @ -17,7 +17,6 @@ | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:wyatt_component_copy_with_extension/component_copy_with_extension.dart'; | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| import 'package:wyatt_ui_kit/src/components/rich_text_builder/rich_text_builder_theme_resolver.dart'; | ||||
| import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; | ||||
| 
 | ||||
| part 'rich_text_builder.g.dart'; | ||||
| @ -30,37 +29,39 @@ class RichTextBuilder extends RichTextBuilderComponent | ||||
|     super.parser, | ||||
|     super.defaultStyle, | ||||
|     super.styles, | ||||
|     super.themeResolver, | ||||
|     super.key, | ||||
|   }); | ||||
| 
 | ||||
|   @override | ||||
|   RichTextBuilderThemeResolver? get themeResolver => | ||||
|       super.themeResolver as RichTextBuilderThemeResolver?; | ||||
| 
 | ||||
|   /// Negotiate the theme to get a complete style. | ||||
|   RichTextBuilderStyle _resolve(BuildContext context) { | ||||
|     final RichTextBuilderThemeResolver resolver = themeResolver ?? | ||||
|         RichTextBuilderThemeResolver( | ||||
|           customStyleFn: (context, {extra}) => RichTextBuilderStyle( | ||||
|             defaultStyle: defaultStyle, | ||||
|             styles: styles, | ||||
|           ), | ||||
|         ); | ||||
| 
 | ||||
|     return resolver.negotiate(context); | ||||
|   } | ||||
| 
 | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final style = _resolve(context); | ||||
|     final RegExp regex = RegExp(r'<(.*?)>(.*?)<\/\1>'); | ||||
|     final root = RichTextNode.from( | ||||
|       text ?? '', | ||||
|       regex, | ||||
|       RichTextStyleParameter( | ||||
|         style.defaultStyle, | ||||
|         style.styles ?? {}, | ||||
|         ThemeHelper.getThemeElement<TextStyle, TextStyle>( | ||||
|           [ | ||||
|             defaultStyle, | ||||
|             Theme.of(context) | ||||
|                 .extension<RichTextBuilderThemeExtension>() | ||||
|                 ?.defaultStyle, | ||||
|             context.textTheme.bodyMedium, | ||||
|           ], | ||||
|           valueValidator: (style) => style != null, | ||||
|           transform: (style) => style, | ||||
|         ), | ||||
|         ThemeHelper.getThemeElement<Map<String, TextStyle>, | ||||
|             Map<String, TextStyle>>( | ||||
|           [ | ||||
|             styles, | ||||
|             Theme.of(context) | ||||
|                 .extension<RichTextBuilderThemeExtension>() | ||||
|                 ?.styles, | ||||
|             const <String, TextStyle>{}, | ||||
|           ], | ||||
|           valueValidator: (styles) => styles != null, | ||||
|           transform: (styles) => styles, | ||||
|         )!, | ||||
|         null, | ||||
|       ), | ||||
|     ); | ||||
|  | ||||
| @ -20,10 +20,6 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy { | ||||
|   RichTextBuilder styles(Map<String, TextStyle>? styles) => | ||||
|       this(styles: styles); | ||||
|   @override | ||||
|   RichTextBuilder themeResolver( | ||||
|           ThemeResolver<dynamic, dynamic, dynamic>? themeResolver) => | ||||
|       this(themeResolver: themeResolver); | ||||
|   @override | ||||
|   RichTextBuilder key(Key? key) => this(key: key); | ||||
|   @override | ||||
|   RichTextBuilder call({ | ||||
| @ -31,7 +27,6 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy { | ||||
|     RichTextParser? parser, | ||||
|     TextStyle? defaultStyle, | ||||
|     Map<String, TextStyle>? styles, | ||||
|     ThemeResolver<dynamic, dynamic, dynamic>? themeResolver, | ||||
|     Key? key, | ||||
|   }) => | ||||
|       RichTextBuilder( | ||||
| @ -39,7 +34,6 @@ class $RichTextBuilderCWProxyImpl implements $RichTextBuilderComponentCWProxy { | ||||
|         parser: parser ?? _value.parser, | ||||
|         defaultStyle: defaultStyle ?? _value.defaultStyle, | ||||
|         styles: styles ?? _value.styles, | ||||
|         themeResolver: themeResolver ?? _value.themeResolver, | ||||
|         key: key ?? _value.key, | ||||
|       ); | ||||
| } | ||||
|  | ||||
| @ -1,53 +0,0 @@ | ||||
| // Copyright (C) 2023 WYATT GROUP | ||||
| // Please see the AUTHORS file for details. | ||||
| // | ||||
| // This program is free software: you can redistribute it and/or modify | ||||
| // it under the terms of the GNU General Public License as published by | ||||
| // the Free Software Foundation, either version 3 of the License, or | ||||
| // any later version. | ||||
| // | ||||
| // This program is distributed in the hope that it will be useful, | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
| // GNU General Public License for more details. | ||||
| // | ||||
| // You should have received a copy of the GNU General Public License | ||||
| // along with this program. If not, see <https://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| import 'package:wyatt_ui_kit/wyatt_ui_kit.dart'; | ||||
| 
 | ||||
| class RichTextBuilderThemeResolver extends ThemeResolver<RichTextBuilderStyle, | ||||
|     RichTextBuilderThemeExtension, void> { | ||||
|   const RichTextBuilderThemeResolver({ | ||||
|     required this.customStyleFn, | ||||
|   }); | ||||
| 
 | ||||
|   /// Values taken from <https://api.flutter.dev/flutter/material/ElevatedButton/defaultStyleOf.html> | ||||
|   @override | ||||
|   RichTextBuilderStyle computeDefaultValue( | ||||
|     BuildContext context, { | ||||
|     void extra, | ||||
|   }) => | ||||
|       RichTextBuilderStyle( | ||||
|         defaultStyle: context.textTheme.bodyMedium, | ||||
|       ); | ||||
| 
 | ||||
|   @override | ||||
|   final RichTextBuilderStyle? Function( | ||||
|     BuildContext context, { | ||||
|     void extra, | ||||
|   }) customStyleFn; | ||||
| 
 | ||||
|   @override | ||||
|   RichTextBuilderStyle? computeExtensionValueFn( | ||||
|     BuildContext context, | ||||
|     RichTextBuilderThemeExtension? themeExtension, { | ||||
|     void extra, | ||||
|   }) => | ||||
|       RichTextBuilderStyle( | ||||
|         defaultStyle: themeExtension?.defaultStyle, | ||||
|         styles: themeExtension?.styles, | ||||
|       ); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user