master #81
| @ -23,4 +23,5 @@ export './error_widget_component.dart'; | ||||
| export './loader_component.dart'; | ||||
| export './loader_style.dart'; | ||||
| export './loading_widget_component.dart'; | ||||
| export './rich_text_builder/rich_text_builder.dart'; | ||||
| export './theme_style.dart'; | ||||
|  | ||||
| @ -0,0 +1,120 @@ | ||||
| // 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'; | ||||
| 
 | ||||
| class RichTextStyleParameter { | ||||
|   const RichTextStyleParameter( | ||||
|     this.defaultStyle, | ||||
|     this.definedStyle, | ||||
|     this.styleName, | ||||
|   ); | ||||
| 
 | ||||
|   final TextStyle defaultStyle; | ||||
|   final Map<String, TextStyle> definedStyle; | ||||
|   final String? styleName; | ||||
| 
 | ||||
|   TextStyle get style { | ||||
|     if (definedStyle.containsKey(styleName)) { | ||||
|       return definedStyle[styleName]!; | ||||
|     } | ||||
|     return defaultStyle; | ||||
|   } | ||||
| 
 | ||||
|   RichTextStyleParameter copyWith({ | ||||
|     TextStyle? defaultStyle, | ||||
|     Map<String, TextStyle>? definedStyle, | ||||
|     String? styleName, | ||||
|   }) => | ||||
|       RichTextStyleParameter( | ||||
|         defaultStyle ?? this.defaultStyle, | ||||
|         definedStyle ?? this.definedStyle, | ||||
|         styleName ?? this.styleName, | ||||
|       ); | ||||
| } | ||||
| 
 | ||||
| class RichTextNode { | ||||
|   RichTextNode(this.nodes); | ||||
| 
 | ||||
|   final List<RichTextNode> nodes; | ||||
| 
 | ||||
|   static RichTextNode from( | ||||
|     String content, | ||||
|     RegExp regex, | ||||
|     RichTextStyleParameter styleParameter, | ||||
|   ) { | ||||
|     final matches = regex.allMatches(content); | ||||
|     if (matches.isNotEmpty) { | ||||
|       // match found -> construct node with leaf/nodes | ||||
|       final List<RichTextNode> nodes = []; | ||||
|       for (var i = 0; i < matches.length; i++) { | ||||
|         final previousMatch = i > 0 ? matches.elementAt(i - 1) : null; | ||||
|         final currentMatch = matches.elementAt(i); | ||||
|         // non match before | ||||
|         final nonMatchBefore = (previousMatch != null) | ||||
|             ? content.substring(previousMatch.end, currentMatch.start) | ||||
|             : content.substring(0, currentMatch.start); | ||||
|         nodes | ||||
|           ..add(RichTextNode.from(nonMatchBefore, regex, styleParameter)) | ||||
|           // match | ||||
|           ..add( | ||||
|             RichTextNode.from( | ||||
|               currentMatch.group(2)!, | ||||
|               regex, | ||||
|               styleParameter.copyWith(styleName: currentMatch.group(1)), | ||||
|             ), | ||||
|           ); | ||||
|       } | ||||
|       // non match after | ||||
|       final nonMatchAfter = content.substring(matches.last.end); | ||||
|       nodes.add(RichTextNode.from(nonMatchAfter, regex, styleParameter)); | ||||
|       return RichTextNode(nodes); | ||||
|     } else { | ||||
|       // match not found -> construct leaf | ||||
|       return RichTextLeaf(styleParameter.style, content); | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   InlineSpan toInlineSpan(RichTextParser parser) { | ||||
|     final children = <InlineSpan>[]; | ||||
|     for (final node in nodes) { | ||||
|       children.add(node.toInlineSpan(parser)); | ||||
|     } | ||||
|     return TextSpan(children: children); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| class RichTextLeaf extends RichTextNode { | ||||
|   RichTextLeaf(this.style, this.content) : super([]); | ||||
| 
 | ||||
|   final TextStyle style; | ||||
|   final String content; | ||||
| 
 | ||||
|   @override | ||||
|   InlineSpan toInlineSpan(RichTextParser parser) => | ||||
|       parser.nodeBuilder.call(content, style); | ||||
| } | ||||
| 
 | ||||
| class RichTextParser { | ||||
|   const RichTextParser({required this.nodeBuilder}); | ||||
|   factory RichTextParser.defaultBuilder() => RichTextParser( | ||||
|         nodeBuilder: (content, style) => TextSpan( | ||||
|           text: content, | ||||
|           style: style, | ||||
|         ), | ||||
|       ); | ||||
|   final InlineSpan Function(String content, TextStyle style) nodeBuilder; | ||||
| } | ||||
| @ -0,0 +1,19 @@ | ||||
| // 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 'parser.dart'; | ||||
| export 'rich_text_builder_component.dart'; | ||||
| export 'rich_text_builder_style.dart'; | ||||
| @ -0,0 +1,56 @@ | ||||
| // 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_component_copy_with_extension/component_copy_with_extension.dart'; | ||||
| import 'package:wyatt_ui_components/wyatt_wyatt_ui_components.dart'; | ||||
| 
 | ||||
| part 'rich_text_builder_component.g.dart'; | ||||
| 
 | ||||
| @ComponentProxyExtension() | ||||
| abstract class RichTextBuilderComponent extends Component | ||||
|     with CopyWithMixin<$RichTextBuilderComponentCWProxy> { | ||||
|   const RichTextBuilderComponent({ | ||||
|     this.text, | ||||
|     this.parser, | ||||
|     this.defaultStyle, | ||||
|     this.styles, | ||||
|     super.themeResolver, | ||||
|     super.key, | ||||
|   }); | ||||
| 
 | ||||
|   /// Full text | ||||
|   final String? text; | ||||
| 
 | ||||
|   /// How to build InlineSpans | ||||
|   final RichTextParser? parser; | ||||
| 
 | ||||
|   /// Default TextStyle used in this rich text component. | ||||
|   final TextStyle? defaultStyle; | ||||
| 
 | ||||
|   /// Used styles in this rich text component. | ||||
|   ///  | ||||
|   /// e.g. | ||||
|   /// ```dart | ||||
|   /// styles = {'red': TextStyle(color: Colors.red)}; | ||||
|   /// ``` | ||||
|   /// will transform: | ||||
|   /// ```text | ||||
|   /// This text <red>is red</red. | ||||
|   /// ``` | ||||
|   /// in "This text `is red`." | ||||
|   final Map<String, TextStyle>? styles; | ||||
| } | ||||
| @ -0,0 +1,25 @@ | ||||
| // GENERATED CODE - DO NOT MODIFY BY HAND | ||||
| 
 | ||||
| part of 'rich_text_builder_component.dart'; | ||||
| 
 | ||||
| // ************************************************************************** | ||||
| // ComponentProxyGenerator | ||||
| // ************************************************************************** | ||||
| 
 | ||||
| abstract class $RichTextBuilderComponentCWProxy { | ||||
|   RichTextBuilderComponent text(String? text); | ||||
|   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, | ||||
|   }); | ||||
| } | ||||
| @ -0,0 +1,83 @@ | ||||
| // 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? lerpWith(RichTextBuilderStyle? other, double t) => | ||||
|       RichTextBuilderStyle.lerp(this, other, t); | ||||
| 
 | ||||
|   @override | ||||
|   RichTextBuilderStyle copyWith({ | ||||
|     TextStyle? defaultStyle, | ||||
|     Map<String, TextStyle>? styles, | ||||
|   }) => | ||||
|       RichTextBuilderStyle( | ||||
|         defaultStyle: defaultStyle ?? this.defaultStyle, | ||||
|         styles: styles ?? this.styles, | ||||
|       ); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user