Showing
8 changed files
with
190 additions
and
25 deletions
@@ -3,7 +3,6 @@ import 'dart:io'; | @@ -3,7 +3,6 @@ import 'dart:io'; | ||
3 | 3 | ||
4 | import 'package:file_picker/file_picker.dart'; | 4 | import 'package:file_picker/file_picker.dart'; |
5 | import 'package:flutter/material.dart'; | 5 | import 'package:flutter/material.dart'; |
6 | -// import 'package:flutter/services.dart'; | ||
7 | import 'package:tex_markdown/tex_markdown.dart'; | 6 | import 'package:tex_markdown/tex_markdown.dart'; |
8 | import 'package:url_launcher/url_launcher_string.dart'; | 7 | import 'package:url_launcher/url_launcher_string.dart'; |
9 | 8 | ||
@@ -71,7 +70,7 @@ class _MyHomePageState extends State<MyHomePage> { | @@ -71,7 +70,7 @@ class _MyHomePageState extends State<MyHomePage> { | ||
71 | hello | 70 | hello |
72 | --- | 71 | --- |
73 | my name is | 72 | my name is |
74 | - | 73 | + |
75 | **bold$x^2\cfrac a{\cfrac ab}$ text** | 74 | **bold$x^2\cfrac a{\cfrac ab}$ text** |
76 | *Italic text$x^2\cfrac a{b}$* | 75 | *Italic text$x^2\cfrac a{b}$* |
77 | **hello** | 76 | **hello** |
@@ -491,7 +491,7 @@ packages: | @@ -491,7 +491,7 @@ packages: | ||
491 | path: ".." | 491 | path: ".." |
492 | relative: true | 492 | relative: true |
493 | source: path | 493 | source: path |
494 | - version: "0.1.6" | 494 | + version: "0.1.7" |
495 | tex_text: | 495 | tex_text: |
496 | dependency: transitive | 496 | dependency: transitive |
497 | description: | 497 | description: |
@@ -67,8 +67,22 @@ class RenderCustomImageError extends RenderProxyBox { | @@ -67,8 +67,22 @@ class RenderCustomImageError extends RenderProxyBox { | ||
67 | 67 | ||
68 | @override | 68 | @override |
69 | void performLayout() { | 69 | void performLayout() { |
70 | + if (constraints.hasBoundedHeight && constraints.hasBoundedWidth) { | ||
71 | + size = constraints.constrain(Size( | ||
72 | + min(constraints.maxWidth, constraints.maxHeight), | ||
73 | + min(constraints.maxHeight, constraints.maxWidth))); | ||
74 | + return; | ||
75 | + } | ||
76 | + if (constraints.hasBoundedHeight || constraints.hasBoundedWidth) { | ||
77 | + size = constraints.constrain(Size( | ||
78 | + min(constraints.maxHeight, constraints.maxWidth), | ||
79 | + min(constraints.maxHeight, constraints.maxWidth), | ||
80 | + )); | ||
81 | + return; | ||
82 | + } | ||
70 | size = constraints.constrain( | 83 | size = constraints.constrain( |
71 | - Size(min(constraints.maxWidth, 80), min(constraints.maxHeight, 80))); | 84 | + const Size(80, 80), |
85 | + ); | ||
72 | } | 86 | } |
73 | 87 | ||
74 | @override | 88 | @override |
@@ -101,3 +115,132 @@ class RenderCustomImageError extends RenderProxyBox { | @@ -101,3 +115,132 @@ class RenderCustomImageError extends RenderProxyBox { | ||
101 | ); | 115 | ); |
102 | } | 116 | } |
103 | } | 117 | } |
118 | + | ||
119 | +class CustomImageLoading extends LeafRenderObjectWidget { | ||
120 | + const CustomImageLoading({ | ||
121 | + super.key, | ||
122 | + this.iconColor, | ||
123 | + this.backgroundColor, | ||
124 | + this.outlineColor, | ||
125 | + this.progress = 1, | ||
126 | + }); | ||
127 | + final Color? iconColor; | ||
128 | + final Color? backgroundColor; | ||
129 | + final Color? outlineColor; | ||
130 | + final double progress; | ||
131 | + | ||
132 | + @override | ||
133 | + RenderObject createRenderObject(BuildContext context) { | ||
134 | + return RenderCustomImageLoading( | ||
135 | + iconColor ?? Theme.of(context).colorScheme.onSurfaceVariant, | ||
136 | + backgroundColor ?? Theme.of(context).colorScheme.surfaceVariant, | ||
137 | + outlineColor ?? Theme.of(context).colorScheme.outline, | ||
138 | + progress, | ||
139 | + ); | ||
140 | + } | ||
141 | + | ||
142 | + @override | ||
143 | + void updateRenderObject( | ||
144 | + BuildContext context, covariant RenderCustomImageLoading renderObject) { | ||
145 | + renderObject._backgroundColor = | ||
146 | + backgroundColor ?? Theme.of(context).colorScheme.surfaceVariant; | ||
147 | + renderObject._iconColor = | ||
148 | + iconColor ?? Theme.of(context).colorScheme.onSurfaceVariant; | ||
149 | + renderObject._outlineColor = | ||
150 | + outlineColor ?? Theme.of(context).colorScheme.outline; | ||
151 | + renderObject.progress = progress; | ||
152 | + } | ||
153 | +} | ||
154 | + | ||
155 | +class RenderCustomImageLoading extends RenderProxyBox { | ||
156 | + RenderCustomImageLoading(this._iconColor, this._backgroundColor, | ||
157 | + this._outlineColor, this._progress); | ||
158 | + Color _iconColor; | ||
159 | + Color _outlineColor; | ||
160 | + Color _backgroundColor; | ||
161 | + double _progress; | ||
162 | + set iconColor(Color value) { | ||
163 | + if (value == _iconColor) { | ||
164 | + return; | ||
165 | + } | ||
166 | + _iconColor = value; | ||
167 | + markNeedsPaint(); | ||
168 | + } | ||
169 | + | ||
170 | + set backgroundColor(Color value) { | ||
171 | + if (value == _backgroundColor) { | ||
172 | + return; | ||
173 | + } | ||
174 | + _backgroundColor = value; | ||
175 | + markNeedsPaint(); | ||
176 | + } | ||
177 | + | ||
178 | + set outlineColor(Color value) { | ||
179 | + if (value == _outlineColor) { | ||
180 | + return; | ||
181 | + } | ||
182 | + _outlineColor = value; | ||
183 | + markNeedsPaint(); | ||
184 | + } | ||
185 | + | ||
186 | + set progress(double value) { | ||
187 | + if (value == _progress) { | ||
188 | + return; | ||
189 | + } | ||
190 | + _progress = value; | ||
191 | + markNeedsPaint(); | ||
192 | + } | ||
193 | + | ||
194 | + @override | ||
195 | + void performLayout() { | ||
196 | + if (constraints.hasBoundedHeight && constraints.hasBoundedWidth) { | ||
197 | + size = constraints.constrain(Size( | ||
198 | + min(constraints.maxWidth, constraints.maxHeight), | ||
199 | + min(constraints.maxHeight, constraints.maxWidth))); | ||
200 | + return; | ||
201 | + } | ||
202 | + if (constraints.hasBoundedHeight || constraints.hasBoundedWidth) { | ||
203 | + size = constraints.constrain(Size( | ||
204 | + min(constraints.maxHeight, constraints.maxWidth), | ||
205 | + min(constraints.maxHeight, constraints.maxWidth), | ||
206 | + )); | ||
207 | + return; | ||
208 | + } | ||
209 | + size = constraints.constrain( | ||
210 | + const Size(80, 80), | ||
211 | + ); | ||
212 | + } | ||
213 | + | ||
214 | + @override | ||
215 | + void paint(PaintingContext context, Offset offset) { | ||
216 | + context.canvas.drawRect( | ||
217 | + offset & size, | ||
218 | + Paint()..color = _backgroundColor, | ||
219 | + ); | ||
220 | + context.canvas.drawRect( | ||
221 | + offset & size, | ||
222 | + Paint() | ||
223 | + ..style = PaintingStyle.stroke | ||
224 | + ..color = _outlineColor, | ||
225 | + ); | ||
226 | + const icon = Icons.image; | ||
227 | + TextPainter textPainter = TextPainter(textDirection: TextDirection.rtl); | ||
228 | + textPainter.text = TextSpan( | ||
229 | + text: String.fromCharCode(icon.codePoint), | ||
230 | + style: TextStyle( | ||
231 | + fontSize: min(min(size.width, size.height), 35), | ||
232 | + fontFamily: icon.fontFamily, | ||
233 | + color: _iconColor), | ||
234 | + ); | ||
235 | + textPainter.layout(); | ||
236 | + context.canvas.drawRect( | ||
237 | + (offset + Offset(0, size.height - 5)) & Size(size.width * _progress, 5), | ||
238 | + Paint()..color = _iconColor); | ||
239 | + textPainter.paint( | ||
240 | + context.canvas, | ||
241 | + offset + | ||
242 | + Offset(size.width / 2 - textPainter.size.width / 2, | ||
243 | + size.height / 2 - textPainter.size.height / 2), | ||
244 | + ); | ||
245 | + } | ||
246 | +} |
1 | -import 'dart:math'; | ||
2 | - | ||
3 | import 'package:flutter/material.dart'; | 1 | import 'package:flutter/material.dart'; |
4 | import 'package:tex_markdown/custom_widgets/custom_divider.dart'; | 2 | import 'package:tex_markdown/custom_widgets/custom_divider.dart'; |
5 | import 'package:tex_markdown/custom_widgets/custom_error_image.dart'; | 3 | import 'package:tex_markdown/custom_widgets/custom_error_image.dart'; |
@@ -72,19 +70,21 @@ abstract class MarkdownComponent { | @@ -72,19 +70,21 @@ abstract class MarkdownComponent { | ||
72 | } else { | 70 | } else { |
73 | if (each is BlockMd) { | 71 | if (each is BlockMd) { |
74 | spans.addAll([ | 72 | spans.addAll([ |
75 | - const TextSpan( | 73 | + TextSpan( |
76 | text: "\n ", | 74 | text: "\n ", |
77 | style: TextStyle( | 75 | style: TextStyle( |
78 | fontSize: 0, | 76 | fontSize: 0, |
79 | height: 0, | 77 | height: 0, |
78 | + color: style?.color, | ||
80 | ), | 79 | ), |
81 | ), | 80 | ), |
82 | each.span(context, element.trim(), style, onLinkTab), | 81 | each.span(context, element.trim(), style, onLinkTab), |
83 | - const TextSpan( | 82 | + TextSpan( |
84 | text: "\n ", | 83 | text: "\n ", |
85 | style: TextStyle( | 84 | style: TextStyle( |
86 | fontSize: 0, | 85 | fontSize: 0, |
87 | height: 0, | 86 | height: 0, |
87 | + color: style?.color, | ||
88 | ), | 88 | ), |
89 | ), | 89 | ), |
90 | ]); | 90 | ]); |
@@ -505,15 +505,24 @@ class ImageMd extends InlineMd { | @@ -505,15 +505,24 @@ class ImageMd extends InlineMd { | ||
505 | child: SizedBox( | 505 | child: SizedBox( |
506 | width: width, | 506 | width: width, |
507 | height: height, | 507 | height: height, |
508 | - child: Image.network( | ||
509 | - "${match?[2]}", | 508 | + child: Image( |
509 | + image: NetworkImage( | ||
510 | + "${match?[2]}", | ||
511 | + ), | ||
512 | + loadingBuilder: (BuildContext context, Widget child, | ||
513 | + ImageChunkEvent? loadingProgress) { | ||
514 | + if (loadingProgress == null) { | ||
515 | + return child; | ||
516 | + } | ||
517 | + return CustomImageLoading( | ||
518 | + progress: loadingProgress.expectedTotalBytes != null | ||
519 | + ? loadingProgress.cumulativeBytesLoaded / | ||
520 | + loadingProgress.expectedTotalBytes! | ||
521 | + : 1, | ||
522 | + ); | ||
523 | + }, | ||
510 | fit: BoxFit.fill, | 524 | fit: BoxFit.fill, |
511 | errorBuilder: (context, error, stackTrace) { | 525 | errorBuilder: (context, error, stackTrace) { |
512 | - double size = 35; | ||
513 | - // if (height != null && width != null) { | ||
514 | - size = min(size, height ?? size); | ||
515 | - size = min(size, width ?? size); | ||
516 | - // } | ||
517 | return const CustomImageError(); | 526 | return const CustomImageError(); |
518 | }, | 527 | }, |
519 | ), | 528 | ), |
@@ -53,7 +53,13 @@ $value | @@ -53,7 +53,13 @@ $value | ||
53 | RegExp(r"\n\n+"), | 53 | RegExp(r"\n\n+"), |
54 | onMatch: (p0) { | 54 | onMatch: (p0) { |
55 | list.add( | 55 | list.add( |
56 | - const TextSpan(text: "\n\n", style: TextStyle(fontSize: 16)), | 56 | + TextSpan( |
57 | + text: "\n\n", | ||
58 | + style: TextStyle( | ||
59 | + fontSize: 16, | ||
60 | + color: style?.color, | ||
61 | + ), | ||
62 | + ), | ||
57 | ); | 63 | ); |
58 | return ""; | 64 | return ""; |
59 | }, | 65 | }, |
@@ -79,14 +85,11 @@ $value | @@ -79,14 +85,11 @@ $value | ||
79 | maxCol = each.keys.length; | 85 | maxCol = each.keys.length; |
80 | } | 86 | } |
81 | } | 87 | } |
82 | - // if (maxCol == 0) { | ||
83 | - // return Text("", style: style); | ||
84 | - // } | ||
85 | list.addAll( | 88 | list.addAll( |
86 | [ | 89 | [ |
87 | - const TextSpan( | 90 | + TextSpan( |
88 | text: "\n ", | 91 | text: "\n ", |
89 | - style: TextStyle(height: 0, fontSize: 0), | 92 | + style: TextStyle(height: 0, fontSize: 0, color: style?.color), |
90 | ), | 93 | ), |
91 | WidgetSpan( | 94 | WidgetSpan( |
92 | child: Table( | 95 | child: Table( |
@@ -114,9 +117,9 @@ $value | @@ -114,9 +117,9 @@ $value | ||
114 | .toList(), | 117 | .toList(), |
115 | ), | 118 | ), |
116 | ), | 119 | ), |
117 | - const TextSpan( | 120 | + TextSpan( |
118 | text: "\n ", | 121 | text: "\n ", |
119 | - style: TextStyle(height: 0, fontSize: 0), | 122 | + style: TextStyle(height: 0, fontSize: 0, color: style?.color), |
120 | ), | 123 | ), |
121 | ], | 124 | ], |
122 | ); | 125 | ); |
@@ -132,6 +135,7 @@ $value | @@ -132,6 +135,7 @@ $value | ||
132 | return Text.rich( | 135 | return Text.rich( |
133 | TextSpan( | 136 | TextSpan( |
134 | children: list, | 137 | children: list, |
138 | + style: style, | ||
135 | ), | 139 | ), |
136 | ); | 140 | ); |
137 | } | 141 | } |
@@ -27,6 +27,12 @@ class TexMarkdown extends StatelessWidget { | @@ -27,6 +27,12 @@ class TexMarkdown extends StatelessWidget { | ||
27 | 27 | ||
28 | @override | 28 | @override |
29 | Widget build(BuildContext context) { | 29 | Widget build(BuildContext context) { |
30 | - return ClipRRect(child: MdWidget(data.trim())); | 30 | + return ClipRRect( |
31 | + child: MdWidget( | ||
32 | + data.trim(), | ||
33 | + style: style, | ||
34 | + onLinkTab: onLinkTab, | ||
35 | + followLinkColor: followLinkColor, | ||
36 | + )); | ||
31 | } | 37 | } |
32 | } | 38 | } |
1 | name: tex_markdown | 1 | name: tex_markdown |
2 | description: This package is used to create flutter widget that can render markdown and latex formulas. It is very simple to use and uses native flutter components. | 2 | description: This package is used to create flutter widget that can render markdown and latex formulas. It is very simple to use and uses native flutter components. |
3 | -version: 0.1.6 | 3 | +version: 0.1.7 |
4 | homepage: https://github.com/saminsohag/flutter_packages/tree/main/tex_markdown | 4 | homepage: https://github.com/saminsohag/flutter_packages/tree/main/tex_markdown |
5 | 5 | ||
6 | environment: | 6 | environment: |
-
Please register or login to post a comment