Showing
7 changed files
with
109 additions
and
24 deletions
@@ -126,7 +126,7 @@ packages: | @@ -126,7 +126,7 @@ packages: | ||
126 | path: ".." | 126 | path: ".." |
127 | relative: true | 127 | relative: true |
128 | source: path | 128 | source: path |
129 | - version: "1.0.9" | 129 | + version: "1.0.15" |
130 | http: | 130 | http: |
131 | dependency: transitive | 131 | dependency: transitive |
132 | description: | 132 | description: |
@@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; | @@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; | ||
2 | 2 | ||
3 | /// A custom widget that adds an indent to the left or right of its child. | 3 | /// A custom widget that adds an indent to the left or right of its child. |
4 | /// | 4 | /// |
5 | -/// The [IndentWidget] widget is used to create a visual indent in the UI. | 5 | +/// The [BlockQuoteWidget] widget is used to create a visual indent in the UI. |
6 | /// It takes a [child] parameter which is the content of the widget, | 6 | /// It takes a [child] parameter which is the content of the widget, |
7 | /// a [direction] parameter which specifies the direction of the indent, | 7 | /// a [direction] parameter which specifies the direction of the indent, |
8 | /// and a [color] parameter to set the color of the indent. | 8 | /// and a [color] parameter to set the color of the indent. |
9 | -class IndentWidget extends StatelessWidget { | ||
10 | - const IndentWidget({ | 9 | +class BlockQuoteWidget extends StatelessWidget { |
10 | + const BlockQuoteWidget({ | ||
11 | super.key, | 11 | super.key, |
12 | required this.child, | 12 | required this.child, |
13 | required this.direction, | 13 | required this.direction, |
@@ -128,6 +128,7 @@ class GptMarkdown extends StatelessWidget { | @@ -128,6 +128,7 @@ class GptMarkdown extends StatelessWidget { | ||
128 | return ClipRRect( | 128 | return ClipRRect( |
129 | child: MdWidget( | 129 | child: MdWidget( |
130 | tex, | 130 | tex, |
131 | + true, | ||
131 | config: GptMarkdownConfig( | 132 | config: GptMarkdownConfig( |
132 | textDirection: textDirection, | 133 | textDirection: textDirection, |
133 | style: style, | 134 | style: style, |
@@ -5,7 +5,7 @@ abstract class MarkdownComponent { | @@ -5,7 +5,7 @@ abstract class MarkdownComponent { | ||
5 | static final List<MarkdownComponent> components = [ | 5 | static final List<MarkdownComponent> components = [ |
6 | CodeBlockMd(), | 6 | CodeBlockMd(), |
7 | NewLines(), | 7 | NewLines(), |
8 | - IndentMd(), | 8 | + BlockQuote(), |
9 | ImageMd(), | 9 | ImageMd(), |
10 | ATagMd(), | 10 | ATagMd(), |
11 | TableMd(), | 11 | TableMd(), |
@@ -20,7 +20,20 @@ abstract class MarkdownComponent { | @@ -20,7 +20,20 @@ abstract class MarkdownComponent { | ||
20 | ItalicMd(), | 20 | ItalicMd(), |
21 | LatexMath(), | 21 | LatexMath(), |
22 | LatexMathMultiLine(), | 22 | LatexMathMultiLine(), |
23 | + HighlightedText(), | ||
24 | + SourceTag(), | ||
25 | + IndentMd(), | ||
26 | + ]; | ||
27 | + | ||
28 | + static final List<MarkdownComponent> inlineComponents = [ | ||
23 | ImageMd(), | 29 | ImageMd(), |
30 | + ATagMd(), | ||
31 | + TableMd(), | ||
32 | + StrikeMd(), | ||
33 | + BoldMd(), | ||
34 | + ItalicMd(), | ||
35 | + LatexMath(), | ||
36 | + LatexMathMultiLine(), | ||
24 | HighlightedText(), | 37 | HighlightedText(), |
25 | SourceTag(), | 38 | SourceTag(), |
26 | ]; | 39 | ]; |
@@ -30,10 +43,14 @@ abstract class MarkdownComponent { | @@ -30,10 +43,14 @@ abstract class MarkdownComponent { | ||
30 | BuildContext context, | 43 | BuildContext context, |
31 | String text, | 44 | String text, |
32 | final GptMarkdownConfig config, | 45 | final GptMarkdownConfig config, |
46 | + bool includeGlobalComponents, | ||
33 | ) { | 47 | ) { |
48 | + var components = | ||
49 | + includeGlobalComponents | ||
50 | + ? MarkdownComponent.components | ||
51 | + : MarkdownComponent.inlineComponents; | ||
34 | List<InlineSpan> spans = []; | 52 | List<InlineSpan> spans = []; |
35 | - List<String> regexes = | ||
36 | - components.map<String>((e) => e.exp.pattern).toList(); | 53 | + Iterable<String> regexes = components.map<String>((e) => e.exp.pattern); |
37 | final combinedRegex = RegExp( | 54 | final combinedRegex = RegExp( |
38 | regexes.join("|"), | 55 | regexes.join("|"), |
39 | multiLine: true, | 56 | multiLine: true, |
@@ -46,7 +63,7 @@ abstract class MarkdownComponent { | @@ -46,7 +63,7 @@ abstract class MarkdownComponent { | ||
46 | for (var each in components) { | 63 | for (var each in components) { |
47 | var p = each.exp.pattern; | 64 | var p = each.exp.pattern; |
48 | var exp = RegExp( | 65 | var exp = RegExp( |
49 | - '^$p', | 66 | + '^$p\$', |
50 | multiLine: each.exp.isMultiLine, | 67 | multiLine: each.exp.isMultiLine, |
51 | dotAll: each.exp.isDotAll, | 68 | dotAll: each.exp.isDotAll, |
52 | ); | 69 | ); |
@@ -133,7 +150,11 @@ abstract class BlockMd extends MarkdownComponent { | @@ -133,7 +150,11 @@ abstract class BlockMd extends MarkdownComponent { | ||
133 | var child = build(context, text, config); | 150 | var child = build(context, text, config); |
134 | length = min(length, 4); | 151 | length = min(length, 4); |
135 | if (length > 0) { | 152 | if (length > 0) { |
136 | - child = UnorderedListView(spacing: length * 1.0, child: child); | 153 | + child = UnorderedListView( |
154 | + spacing: length * 1.0, | ||
155 | + textDirection: config.textDirection, | ||
156 | + child: child, | ||
157 | + ); | ||
137 | } | 158 | } |
138 | return WidgetSpan(child: child, alignment: PlaceholderAlignment.middle); | 159 | return WidgetSpan(child: child, alignment: PlaceholderAlignment.middle); |
139 | } | 160 | } |
@@ -145,6 +166,40 @@ abstract class BlockMd extends MarkdownComponent { | @@ -145,6 +166,40 @@ abstract class BlockMd extends MarkdownComponent { | ||
145 | ); | 166 | ); |
146 | } | 167 | } |
147 | 168 | ||
169 | +/// Indent component | ||
170 | +class IndentMd extends BlockMd { | ||
171 | + @override | ||
172 | + String get expString => (r"^(\ \ +)([^\n]+)$"); | ||
173 | + @override | ||
174 | + Widget build( | ||
175 | + BuildContext context, | ||
176 | + String text, | ||
177 | + final GptMarkdownConfig config, | ||
178 | + ) { | ||
179 | + var match = this.exp.firstMatch(text); | ||
180 | + var conf = config.copyWith(); | ||
181 | + return Directionality( | ||
182 | + textDirection: config.textDirection, | ||
183 | + child: Row( | ||
184 | + children: [ | ||
185 | + Expanded( | ||
186 | + child: config.getRich( | ||
187 | + TextSpan( | ||
188 | + children: MarkdownComponent.generate( | ||
189 | + context, | ||
190 | + match?[2]?.trim() ?? "", | ||
191 | + conf, | ||
192 | + false, | ||
193 | + ), | ||
194 | + ), | ||
195 | + ), | ||
196 | + ), | ||
197 | + ], | ||
198 | + ), | ||
199 | + ); | ||
200 | + } | ||
201 | +} | ||
202 | + | ||
148 | /// Heading component | 203 | /// Heading component |
149 | class HTag extends BlockMd { | 204 | class HTag extends BlockMd { |
150 | @override | 205 | @override |
@@ -174,6 +229,7 @@ class HTag extends BlockMd { | @@ -174,6 +229,7 @@ class HTag extends BlockMd { | ||
174 | context, | 229 | context, |
175 | "${match.namedGroup('data')}", | 230 | "${match.namedGroup('data')}", |
176 | conf, | 231 | conf, |
232 | + false, | ||
177 | )), | 233 | )), |
178 | if (match.namedGroup('hash')!.length == 1) ...[ | 234 | if (match.namedGroup('hash')!.length == 1) ...[ |
179 | const TextSpan( | 235 | const TextSpan( |
@@ -205,8 +261,12 @@ class NewLines extends InlineMd { | @@ -205,8 +261,12 @@ class NewLines extends InlineMd { | ||
205 | final GptMarkdownConfig config, | 261 | final GptMarkdownConfig config, |
206 | ) { | 262 | ) { |
207 | return TextSpan( | 263 | return TextSpan( |
208 | - text: "\n\n\n\n", | ||
209 | - style: TextStyle(fontSize: 6, color: config.style?.color), | 264 | + text: "\n\n", |
265 | + style: TextStyle( | ||
266 | + fontSize: config.style?.fontSize ?? 14, | ||
267 | + height: 1.15, | ||
268 | + color: config.style?.color, | ||
269 | + ), | ||
210 | ); | 270 | ); |
211 | } | 271 | } |
212 | } | 272 | } |
@@ -246,7 +306,7 @@ class CheckBoxMd extends BlockMd { | @@ -246,7 +306,7 @@ class CheckBoxMd extends BlockMd { | ||
246 | return CustomCb( | 306 | return CustomCb( |
247 | value: ("${match?[1]}" == "x"), | 307 | value: ("${match?[1]}" == "x"), |
248 | textDirection: config.textDirection, | 308 | textDirection: config.textDirection, |
249 | - child: MdWidget("${match?[2]}", config: config), | 309 | + child: MdWidget("${match?[2]}", false, config: config), |
250 | ); | 310 | ); |
251 | } | 311 | } |
252 | } | 312 | } |
@@ -267,13 +327,13 @@ class RadioButtonMd extends BlockMd { | @@ -267,13 +327,13 @@ class RadioButtonMd extends BlockMd { | ||
267 | return CustomRb( | 327 | return CustomRb( |
268 | value: ("${match?[1]}" == "x"), | 328 | value: ("${match?[1]}" == "x"), |
269 | textDirection: config.textDirection, | 329 | textDirection: config.textDirection, |
270 | - child: MdWidget("${match?[2]}", config: config), | 330 | + child: MdWidget("${match?[2]}", false, config: config), |
271 | ); | 331 | ); |
272 | } | 332 | } |
273 | } | 333 | } |
274 | 334 | ||
275 | -/// Indent | ||
276 | -class IndentMd extends InlineMd { | 335 | +/// Block quote component |
336 | +class BlockQuote extends InlineMd { | ||
277 | @override | 337 | @override |
278 | bool get inline => false; | 338 | bool get inline => false; |
279 | @override | 339 | @override |
@@ -292,7 +352,7 @@ class IndentMd extends InlineMd { | @@ -292,7 +352,7 @@ class IndentMd extends InlineMd { | ||
292 | // data = data.replaceAll(RegExp(r'\n\ {' '$spaces' '}'), '\n').trim(); | 352 | // data = data.replaceAll(RegExp(r'\n\ {' '$spaces' '}'), '\n').trim(); |
293 | data = data.trim(); | 353 | data = data.trim(); |
294 | var child = TextSpan( | 354 | var child = TextSpan( |
295 | - children: MarkdownComponent.generate(context, data, config), | 355 | + children: MarkdownComponent.generate(context, data, config, true), |
296 | ); | 356 | ); |
297 | return TextSpan( | 357 | return TextSpan( |
298 | children: [ | 358 | children: [ |
@@ -301,7 +361,7 @@ class IndentMd extends InlineMd { | @@ -301,7 +361,7 @@ class IndentMd extends InlineMd { | ||
301 | textDirection: config.textDirection, | 361 | textDirection: config.textDirection, |
302 | child: Padding( | 362 | child: Padding( |
303 | padding: const EdgeInsets.symmetric(vertical: 2), | 363 | padding: const EdgeInsets.symmetric(vertical: 2), |
304 | - child: IndentWidget( | 364 | + child: BlockQuoteWidget( |
305 | color: Theme.of(context).colorScheme.onSurfaceVariant, | 365 | color: Theme.of(context).colorScheme.onSurfaceVariant, |
306 | direction: config.textDirection, | 366 | direction: config.textDirection, |
307 | child: Padding( | 367 | child: Padding( |
@@ -330,7 +390,7 @@ class UnOrderedList extends BlockMd { | @@ -330,7 +390,7 @@ class UnOrderedList extends BlockMd { | ||
330 | ) { | 390 | ) { |
331 | var match = this.exp.firstMatch(text); | 391 | var match = this.exp.firstMatch(text); |
332 | 392 | ||
333 | - var child = MdWidget("${match?[1]?.trim()}", config: config); | 393 | + var child = MdWidget("${match?[1]?.trim()}", false, config: config); |
334 | 394 | ||
335 | return config.unOrderedListBuilder?.call( | 395 | return config.unOrderedListBuilder?.call( |
336 | context, | 396 | context, |
@@ -368,7 +428,7 @@ class OrderedList extends BlockMd { | @@ -368,7 +428,7 @@ class OrderedList extends BlockMd { | ||
368 | 428 | ||
369 | var no = "${match?[1]}"; | 429 | var no = "${match?[1]}"; |
370 | 430 | ||
371 | - var child = MdWidget("${match?[2]?.trim()}", config: config); | 431 | + var child = MdWidget("${match?[2]?.trim()}", false, config: config); |
372 | return config.orderedListBuilder?.call( | 432 | return config.orderedListBuilder?.call( |
373 | context, | 433 | context, |
374 | no, | 434 | no, |
@@ -450,7 +510,12 @@ class BoldMd extends InlineMd { | @@ -450,7 +510,12 @@ class BoldMd extends InlineMd { | ||
450 | const TextStyle(fontWeight: FontWeight.bold), | 510 | const TextStyle(fontWeight: FontWeight.bold), |
451 | ); | 511 | ); |
452 | return TextSpan( | 512 | return TextSpan( |
453 | - children: MarkdownComponent.generate(context, "${match?[1]}", conf), | 513 | + children: MarkdownComponent.generate( |
514 | + context, | ||
515 | + "${match?[1]}", | ||
516 | + conf, | ||
517 | + false, | ||
518 | + ), | ||
454 | style: conf.style, | 519 | style: conf.style, |
455 | ); | 520 | ); |
456 | } | 521 | } |
@@ -476,7 +541,12 @@ class StrikeMd extends InlineMd { | @@ -476,7 +541,12 @@ class StrikeMd extends InlineMd { | ||
476 | const TextStyle(decoration: TextDecoration.lineThrough), | 541 | const TextStyle(decoration: TextDecoration.lineThrough), |
477 | ); | 542 | ); |
478 | return TextSpan( | 543 | return TextSpan( |
479 | - children: MarkdownComponent.generate(context, "${match?[1]}", conf), | 544 | + children: MarkdownComponent.generate( |
545 | + context, | ||
546 | + "${match?[1]}", | ||
547 | + conf, | ||
548 | + false, | ||
549 | + ), | ||
480 | style: conf.style, | 550 | style: conf.style, |
481 | ); | 551 | ); |
482 | } | 552 | } |
@@ -504,7 +574,7 @@ class ItalicMd extends InlineMd { | @@ -504,7 +574,7 @@ class ItalicMd extends InlineMd { | ||
504 | ), | 574 | ), |
505 | ); | 575 | ); |
506 | return TextSpan( | 576 | return TextSpan( |
507 | - children: MarkdownComponent.generate(context, "$data", conf), | 577 | + children: MarkdownComponent.generate(context, "$data", conf, false), |
508 | style: conf.style, | 578 | style: conf.style, |
509 | ); | 579 | ); |
510 | } | 580 | } |
@@ -898,6 +968,7 @@ class TableMd extends BlockMd { | @@ -898,6 +968,7 @@ class TableMd extends BlockMd { | ||
898 | ), | 968 | ), |
899 | child: MdWidget( | 969 | child: MdWidget( |
900 | (e[index] ?? "").trim(), | 970 | (e[index] ?? "").trim(), |
971 | + false, | ||
901 | config: config, | 972 | config: config, |
902 | ), | 973 | ), |
903 | ), | 974 | ), |
@@ -2,11 +2,19 @@ part of 'gpt_markdown.dart'; | @@ -2,11 +2,19 @@ part of 'gpt_markdown.dart'; | ||
2 | 2 | ||
3 | /// It creates a markdown widget closed to each other. | 3 | /// It creates a markdown widget closed to each other. |
4 | class MdWidget extends StatelessWidget { | 4 | class MdWidget extends StatelessWidget { |
5 | - const MdWidget(this.exp, {super.key, required this.config}); | 5 | + const MdWidget( |
6 | + this.exp, | ||
7 | + this.includeGlobalComponents, { | ||
8 | + super.key, | ||
9 | + required this.config, | ||
10 | + }); | ||
6 | 11 | ||
7 | /// The expression to be displayed. | 12 | /// The expression to be displayed. |
8 | final String exp; | 13 | final String exp; |
9 | 14 | ||
15 | + /// Whether to include global components. | ||
16 | + final bool includeGlobalComponents; | ||
17 | + | ||
10 | /// The configuration of the markdown widget. | 18 | /// The configuration of the markdown widget. |
11 | final GptMarkdownConfig config; | 19 | final GptMarkdownConfig config; |
12 | 20 | ||
@@ -28,6 +36,7 @@ class MdWidget extends StatelessWidget { | @@ -28,6 +36,7 @@ class MdWidget extends StatelessWidget { | ||
28 | // return "\\[$body\\]"; | 36 | // return "\\[$body\\]"; |
29 | // }), | 37 | // }), |
30 | config, | 38 | config, |
39 | + includeGlobalComponents, | ||
31 | ), | 40 | ), |
32 | ); | 41 | ); |
33 | return config.getRich( | 42 | return config.getRich( |
1 | name: gpt_markdown | 1 | name: gpt_markdown |
2 | description: "Powerful Markdown & LaTeX Renderer for Flutter: Rich Text, Math, Tables, Links, and Text Selection. Ideal for ChatGPT, Gemini, and more." | 2 | description: "Powerful Markdown & LaTeX Renderer for Flutter: Rich Text, Math, Tables, Links, and Text Selection. Ideal for ChatGPT, Gemini, and more." |
3 | -version: 1.0.15 | 3 | +version: 1.0.16 |
4 | homepage: https://github.com/Infinitix-LLC/gpt_markdown | 4 | homepage: https://github.com/Infinitix-LLC/gpt_markdown |
5 | 5 | ||
6 | environment: | 6 | environment: |
-
Please register or login to post a comment