Showing
8 changed files
with
122 additions
and
4 deletions
| 1 | ## 1.1.2 | 1 | ## 1.1.2 |
| 2 | 2 | ||
| 3 | -* 🔗 Fixed text decoration color of link markdown component | ||
| 4 | * 📊 Fixed table column alignment support ([#65](https://github.com/Infinitix-LLC/gpt_markdown/issues/65)) | 3 | * 📊 Fixed table column alignment support ([#65](https://github.com/Infinitix-LLC/gpt_markdown/issues/65)) |
| 4 | +* 🎨 Added `tableBuilder` parameter to customize table rendering | ||
| 5 | +* 🔗 Fixed text decoration color of link markdown component | ||
| 5 | 6 | ||
| 6 | ## 1.1.1 | 7 | ## 1.1.1 |
| 7 | 8 |
| @@ -32,7 +32,7 @@ gpt_markdown is a drop-in replacement for flutter_markdown, offering extended su | @@ -32,7 +32,7 @@ gpt_markdown is a drop-in replacement for flutter_markdown, offering extended su | ||
| 32 | | 🔗 Links | ✅ | | 32 | | 🔗 Links | ✅ | |
| 33 | | 📱 Selectable | ✅ | | 33 | | 📱 Selectable | ✅ | |
| 34 | | 🧩 Custom components | ✅ | | | 34 | | 🧩 Custom components | ✅ | | |
| 35 | -| 📎 Underline | | 🔜 | | 35 | +| 📎 Underline | ✅ | | |
| 36 | 36 | ||
| 37 | ## ✨ Key Features | 37 | ## ✨ Key Features |
| 38 | 38 | ||
| @@ -86,6 +86,11 @@ Render a wide variety of content with full Markdown and LaTeX support, including | @@ -86,6 +86,11 @@ Render a wide variety of content with full Markdown and LaTeX support, including | ||
| 86 | *Italic text* | 86 | *Italic text* |
| 87 | ``` | 87 | ``` |
| 88 | 88 | ||
| 89 | +- <u>Underline text</u> | ||
| 90 | +``` | ||
| 91 | +<u>Underline text</u> | ||
| 92 | +``` | ||
| 93 | + | ||
| 89 | - heading texts | 94 | - heading texts |
| 90 | 95 | ||
| 91 | ``` | 96 | ``` |
| @@ -123,5 +123,28 @@ darkTheme: ThemeData( | @@ -123,5 +123,28 @@ darkTheme: ThemeData( | ||
| 123 | ), | 123 | ), |
| 124 | ``` | 124 | ``` |
| 125 | 125 | ||
| 126 | +Use `tableBuilder` to customize table rendering: | ||
| 127 | + | ||
| 128 | +```dart | ||
| 129 | +GptMarkdown( | ||
| 130 | + markdownText, | ||
| 131 | + tableBuilder: (context, tableRows, textStyle, config) { | ||
| 132 | + return Table( | ||
| 133 | + border: TableBorder.all( | ||
| 134 | + width: 1, | ||
| 135 | + color: Colors.red, | ||
| 136 | + ), | ||
| 137 | + children: tableRows.map((e) { | ||
| 138 | + return TableRow( | ||
| 139 | + children: e.fields.map((e) { | ||
| 140 | + return Text(e.data); | ||
| 141 | + }).toList(), | ||
| 142 | + ); | ||
| 143 | + }).toList(), | ||
| 144 | + ); | ||
| 145 | + }, | ||
| 146 | +); | ||
| 147 | +``` | ||
| 148 | + | ||
| 126 | Please see the [README.md](https://github.com/Infinitix-LLC/gpt_markdown) and also [example](https://github.com/Infinitix-LLC/gpt_markdown/tree/main/example/lib/main.dart) app for more details. | 149 | Please see the [README.md](https://github.com/Infinitix-LLC/gpt_markdown) and also [example](https://github.com/Infinitix-LLC/gpt_markdown/tree/main/example/lib/main.dart) app for more details. |
| 127 | 150 |
| @@ -329,6 +329,12 @@ This document was created to test the robustness of Markdown parsers and to ensu | @@ -329,6 +329,12 @@ This document was created to test the robustness of Markdown parsers and to ensu | ||
| 329 | 329 | ||
| 330 | @override | 330 | @override |
| 331 | Widget build(BuildContext context) { | 331 | Widget build(BuildContext context) { |
| 332 | +// var data = '''|asdfasfd|asdfasf| | ||
| 333 | +// |---|---| | ||
| 334 | +// |sohag|asdfasf| | ||
| 335 | +// |asdfasf|asdfasf| | ||
| 336 | +// '''; | ||
| 337 | + | ||
| 332 | return GptMarkdownTheme( | 338 | return GptMarkdownTheme( |
| 333 | gptThemeData: GptMarkdownTheme.of(context).copyWith( | 339 | gptThemeData: GptMarkdownTheme.of(context).copyWith( |
| 334 | highlightColor: Colors.purple, | 340 | highlightColor: Colors.purple, |
| @@ -411,6 +417,7 @@ This document was created to test the robustness of Markdown parsers and to ensu | @@ -411,6 +417,7 @@ This document was created to test the robustness of Markdown parsers and to ensu | ||
| 411 | ListenableBuilder( | 417 | ListenableBuilder( |
| 412 | listenable: _controller, | 418 | listenable: _controller, |
| 413 | builder: (context, _) { | 419 | builder: (context, _) { |
| 420 | + var data = _controller.text; | ||
| 414 | return Container( | 421 | return Container( |
| 415 | padding: const EdgeInsets.all(8), | 422 | padding: const EdgeInsets.all(8), |
| 416 | decoration: BoxDecoration( | 423 | decoration: BoxDecoration( |
| @@ -440,7 +447,7 @@ This document was created to test the robustness of Markdown parsers and to ensu | @@ -440,7 +447,7 @@ This document was created to test the robustness of Markdown parsers and to ensu | ||
| 440 | child: Builder( | 447 | child: Builder( |
| 441 | builder: (context) { | 448 | builder: (context) { |
| 442 | Widget child = GptMarkdown( | 449 | Widget child = GptMarkdown( |
| 443 | - _controller.text, | 450 | + data, |
| 444 | textDirection: _direction, | 451 | textDirection: _direction, |
| 445 | onLinkTap: (url, title) { | 452 | onLinkTap: (url, title) { |
| 446 | debugPrint(url); | 453 | debugPrint(url); |
| @@ -614,6 +621,24 @@ This document was created to test the robustness of Markdown parsers and to ensu | @@ -614,6 +621,24 @@ This document was created to test the robustness of Markdown parsers and to ensu | ||
| 614 | ), | 621 | ), |
| 615 | ); | 622 | ); |
| 616 | }, | 623 | }, |
| 624 | + | ||
| 625 | + // tableBuilder: (context, tableRows, | ||
| 626 | + // textStyle, config) { | ||
| 627 | + // return Table( | ||
| 628 | + // border: TableBorder.all( | ||
| 629 | + // width: 1, | ||
| 630 | + // color: Colors.red, | ||
| 631 | + // ), | ||
| 632 | + // children: tableRows.map((e) { | ||
| 633 | + // return TableRow( | ||
| 634 | + // children: e.fields.map((e) { | ||
| 635 | + // return Text(e.data); | ||
| 636 | + // }).toList(), | ||
| 637 | + // ); | ||
| 638 | + // }).toList(), | ||
| 639 | + // ); | ||
| 640 | + // }, | ||
| 641 | + | ||
| 617 | // components: [ | 642 | // components: [ |
| 618 | // CodeBlockMd(), | 643 | // CodeBlockMd(), |
| 619 | // NewLines(), | 644 | // NewLines(), |
| @@ -49,6 +49,15 @@ typedef LinkBuilder = | @@ -49,6 +49,15 @@ typedef LinkBuilder = | ||
| 49 | TextStyle style, | 49 | TextStyle style, |
| 50 | ); | 50 | ); |
| 51 | 51 | ||
| 52 | +/// A builder function for the table. | ||
| 53 | +typedef TableBuilder = | ||
| 54 | + Widget Function( | ||
| 55 | + BuildContext context, | ||
| 56 | + List<CustomTableRow> tableRows, | ||
| 57 | + TextStyle textStyle, | ||
| 58 | + GptMarkdownConfig config, | ||
| 59 | + ); | ||
| 60 | + | ||
| 52 | /// A builder function for the highlight. | 61 | /// A builder function for the highlight. |
| 53 | typedef HighlightBuilder = | 62 | typedef HighlightBuilder = |
| 54 | Widget Function(BuildContext context, String text, TextStyle style); | 63 | Widget Function(BuildContext context, String text, TextStyle style); |
| @@ -83,6 +92,7 @@ class GptMarkdownConfig { | @@ -83,6 +92,7 @@ class GptMarkdownConfig { | ||
| 83 | this.overflow, | 92 | this.overflow, |
| 84 | this.components, | 93 | this.components, |
| 85 | this.inlineComponents, | 94 | this.inlineComponents, |
| 95 | + this.tableBuilder, | ||
| 86 | }); | 96 | }); |
| 87 | 97 | ||
| 88 | /// The direction of the text. | 98 | /// The direction of the text. |
| @@ -142,6 +152,9 @@ class GptMarkdownConfig { | @@ -142,6 +152,9 @@ class GptMarkdownConfig { | ||
| 142 | /// The list of inline components. | 152 | /// The list of inline components. |
| 143 | final List<MarkdownComponent>? inlineComponents; | 153 | final List<MarkdownComponent>? inlineComponents; |
| 144 | 154 | ||
| 155 | + /// The table builder. | ||
| 156 | + final TableBuilder? tableBuilder; | ||
| 157 | + | ||
| 145 | /// A copy of the configuration with the specified parameters. | 158 | /// A copy of the configuration with the specified parameters. |
| 146 | GptMarkdownConfig copyWith({ | 159 | GptMarkdownConfig copyWith({ |
| 147 | TextStyle? style, | 160 | TextStyle? style, |
| @@ -163,6 +176,7 @@ class GptMarkdownConfig { | @@ -163,6 +176,7 @@ class GptMarkdownConfig { | ||
| 163 | final UnOrderedListBuilder? unOrderedListBuilder, | 176 | final UnOrderedListBuilder? unOrderedListBuilder, |
| 164 | final List<MarkdownComponent>? components, | 177 | final List<MarkdownComponent>? components, |
| 165 | final List<MarkdownComponent>? inlineComponents, | 178 | final List<MarkdownComponent>? inlineComponents, |
| 179 | + final TableBuilder? tableBuilder, | ||
| 166 | }) { | 180 | }) { |
| 167 | return GptMarkdownConfig( | 181 | return GptMarkdownConfig( |
| 168 | style: style ?? this.style, | 182 | style: style ?? this.style, |
| @@ -184,6 +198,7 @@ class GptMarkdownConfig { | @@ -184,6 +198,7 @@ class GptMarkdownConfig { | ||
| 184 | unOrderedListBuilder: unOrderedListBuilder ?? this.unOrderedListBuilder, | 198 | unOrderedListBuilder: unOrderedListBuilder ?? this.unOrderedListBuilder, |
| 185 | components: components ?? this.components, | 199 | components: components ?? this.components, |
| 186 | inlineComponents: inlineComponents ?? this.inlineComponents, | 200 | inlineComponents: inlineComponents ?? this.inlineComponents, |
| 201 | + tableBuilder: tableBuilder ?? this.tableBuilder, | ||
| 187 | ); | 202 | ); |
| 188 | } | 203 | } |
| 189 | 204 |
| @@ -40,6 +40,7 @@ class GptMarkdown extends StatelessWidget { | @@ -40,6 +40,7 @@ class GptMarkdown extends StatelessWidget { | ||
| 40 | this.overflow, | 40 | this.overflow, |
| 41 | this.orderedListBuilder, | 41 | this.orderedListBuilder, |
| 42 | this.unOrderedListBuilder, | 42 | this.unOrderedListBuilder, |
| 43 | + this.tableBuilder, | ||
| 43 | this.components, | 44 | this.components, |
| 44 | this.inlineComponents, | 45 | this.inlineComponents, |
| 45 | this.useDollarSignsForLatex = false, | 46 | this.useDollarSignsForLatex = false, |
| @@ -100,6 +101,9 @@ class GptMarkdown extends StatelessWidget { | @@ -100,6 +101,9 @@ class GptMarkdown extends StatelessWidget { | ||
| 100 | /// Whether to use dollar signs for LaTeX. | 101 | /// Whether to use dollar signs for LaTeX. |
| 101 | final bool useDollarSignsForLatex; | 102 | final bool useDollarSignsForLatex; |
| 102 | 103 | ||
| 104 | + /// The table builder. | ||
| 105 | + final TableBuilder? tableBuilder; | ||
| 106 | + | ||
| 103 | /// The list of components. | 107 | /// The list of components. |
| 104 | /// ```dart | 108 | /// ```dart |
| 105 | /// List<MarkdownComponent> components = [ | 109 | /// List<MarkdownComponent> components = [ |
| @@ -202,6 +206,7 @@ class GptMarkdown extends StatelessWidget { | @@ -202,6 +206,7 @@ class GptMarkdown extends StatelessWidget { | ||
| 202 | unOrderedListBuilder: unOrderedListBuilder, | 206 | unOrderedListBuilder: unOrderedListBuilder, |
| 203 | components: components, | 207 | components: components, |
| 204 | inlineComponents: inlineComponents, | 208 | inlineComponents: inlineComponents, |
| 209 | + tableBuilder: tableBuilder, | ||
| 205 | ), | 210 | ), |
| 206 | ), | 211 | ), |
| 207 | ); | 212 | ); |
| @@ -1058,6 +1058,36 @@ class TableMd extends BlockMd { | @@ -1058,6 +1058,36 @@ class TableMd extends BlockMd { | ||
| 1058 | columnAlignments.add(TextAlign.left); | 1058 | columnAlignments.add(TextAlign.left); |
| 1059 | } | 1059 | } |
| 1060 | 1060 | ||
| 1061 | + var tableBuilder = config.tableBuilder; | ||
| 1062 | + | ||
| 1063 | + if (tableBuilder != null) { | ||
| 1064 | + var customTable = | ||
| 1065 | + List<CustomTableRow?>.generate(value.length, (index) { | ||
| 1066 | + var isHeader = index == 0; | ||
| 1067 | + var row = value[index]; | ||
| 1068 | + if (row.isEmpty) { | ||
| 1069 | + return null; | ||
| 1070 | + } | ||
| 1071 | + if (index == 1) { | ||
| 1072 | + return null; | ||
| 1073 | + } | ||
| 1074 | + var fields = List<CustomTableField>.generate(maxCol, (index) { | ||
| 1075 | + var field = row[index]; | ||
| 1076 | + return CustomTableField( | ||
| 1077 | + data: field ?? "", | ||
| 1078 | + alignment: columnAlignments[index], | ||
| 1079 | + ); | ||
| 1080 | + }); | ||
| 1081 | + return CustomTableRow(isHeader: isHeader, fields: fields); | ||
| 1082 | + }).nonNulls.toList(); | ||
| 1083 | + return tableBuilder( | ||
| 1084 | + context, | ||
| 1085 | + customTable, | ||
| 1086 | + config.style ?? const TextStyle(), | ||
| 1087 | + config, | ||
| 1088 | + ); | ||
| 1089 | + } | ||
| 1090 | + | ||
| 1061 | final controller = ScrollController(); | 1091 | final controller = ScrollController(); |
| 1062 | return Scrollbar( | 1092 | return Scrollbar( |
| 1063 | controller: controller, | 1093 | controller: controller, |
| @@ -1195,3 +1225,17 @@ class UnderLineMd extends InlineMd { | @@ -1195,3 +1225,17 @@ class UnderLineMd extends InlineMd { | ||
| 1195 | ); | 1225 | ); |
| 1196 | } | 1226 | } |
| 1197 | } | 1227 | } |
| 1228 | + | ||
| 1229 | +class CustomTableField { | ||
| 1230 | + final String data; | ||
| 1231 | + final TextAlign alignment; | ||
| 1232 | + | ||
| 1233 | + CustomTableField({required this.data, this.alignment = TextAlign.left}); | ||
| 1234 | +} | ||
| 1235 | + | ||
| 1236 | +class CustomTableRow { | ||
| 1237 | + final bool isHeader; | ||
| 1238 | + final List<CustomTableField> fields; | ||
| 1239 | + | ||
| 1240 | + CustomTableRow({this.isHeader = false, required this.fields}); | ||
| 1241 | +} |
| 1 | name: gpt_markdown | 1 | name: gpt_markdown |
| 2 | description: "Powerful Flutter Markdown & LaTeX Renderer: Rich Text, Math, Tables, Links, and Text Selection. Ideal for ChatGPT, Gemini, and more." | 2 | description: "Powerful Flutter Markdown & LaTeX Renderer: Rich Text, Math, Tables, Links, and Text Selection. Ideal for ChatGPT, Gemini, and more." |
| 3 | -version: 1.1.1 | 3 | +version: 1.1.2 |
| 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