Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
gpt_markdown
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
saminsohag
2023-04-23 22:15:21 +0600
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
144362a6094b62b849dc5dbc37f4509e342f9b62
144362a6
1 parent
e4f6e8b3
ui improved
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
935 additions
and
214 deletions
tex_markdown/example/lib/main.dart
tex_markdown/lib/custom_widgets/custom_divider.dart
tex_markdown/lib/custom_widgets/custom_rb_cb.dart
tex_markdown/lib/custom_widgets/unordered_ordered_list.dart
tex_markdown/lib/markdown_component.dart
tex_markdown/lib/md_widget.dart
tex_markdown/lib/tex_markdown.dart
tex_markdown/example/lib/main.dart
View file @
144362a
...
...
@@ -110,16 +110,21 @@ $hello$
shape:
const
RoundedRectangleBorder
(
side:
BorderSide
(
width:
1
),
),
child:
TexMarkdown
(
_controller
.
text
,
onLinkTab:
(
url
,
title
)
{
log
(
title
,
name:
"title"
);
log
(
url
,
name:
"url"
);
},
style:
const
TextStyle
(
color:
Colors
.
green
,
),
),
child:
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
return
SingleChildScrollView
(
scrollDirection:
Axis
.
horizontal
,
child:
TexMarkdown
(
_controller
.
text
,
onLinkTab:
(
url
,
title
)
{
log
(
title
,
name:
"title"
);
log
(
url
,
name:
"url"
);
},
style:
const
TextStyle
(
// color: Colors.green,
),
),
);
}),
);
}),
],
...
...
tex_markdown/lib/custom_widgets/custom_divider.dart
0 → 100644
View file @
144362a
import
'package:flutter/material.dart'
;
class
CustomDivider
extends
LeafRenderObjectWidget
{
const
CustomDivider
({
super
.
key
,
this
.
height
,
this
.
color
});
final
Color
?
color
;
final
double
?
height
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
return
RenderDivider
(
color
??
Theme
.
of
(
context
).
colorScheme
.
onSurfaceVariant
,
MediaQuery
.
of
(
context
).
size
.
width
,
height
??
2
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
RenderDivider
renderObject
)
{
renderObject
.
color
=
color
??
Theme
.
of
(
context
).
colorScheme
.
onSurfaceVariant
;
renderObject
.
height
=
height
??
2
;
renderObject
.
width
=
MediaQuery
.
of
(
context
).
size
.
width
;
}
}
class
RenderDivider
extends
RenderBox
{
RenderDivider
(
Color
color
,
double
width
,
double
height
)
:
_color
=
color
,
_height
=
height
,
_width
=
width
;
Color
_color
;
double
_height
;
double
_width
;
set
color
(
Color
value
)
{
if
(
value
==
_color
)
{
return
;
}
_color
=
value
;
markNeedsPaint
();
}
set
height
(
double
value
)
{
if
(
value
==
_height
)
{
return
;
}
_height
=
value
;
markNeedsLayout
();
}
set
width
(
double
value
)
{
if
(
value
==
_width
)
{
return
;
}
_width
=
value
;
markNeedsLayout
();
}
@override
Size
computeDryLayout
(
BoxConstraints
constraints
)
{
return
BoxConstraints
.
tightFor
(
width:
null
,
height:
_height
)
.
enforce
(
constraints
)
.
smallest
;
}
@override
void
performLayout
()
{
size
=
getDryLayout
(
constraints
);
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
context
.
canvas
.
drawRect
(
offset
&
Size
(
Rect
.
largest
.
size
.
width
,
_height
),
Paint
()..
color
=
_color
);
}
}
...
...
tex_markdown/lib/custom_widgets/custom_rb_cb.dart
0 → 100644
View file @
144362a
import
'dart:math'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
enum
CustomRbSlot
{
rb
,
child
,
}
class
CustomRb
extends
RenderObjectWidget
with
SlottedMultiChildRenderObjectWidgetMixin
<
CustomRbSlot
>
{
const
CustomRb
(
{
super
.
key
,
this
.
spacing
=
5
,
required
this
.
child
,
required
this
.
value
});
final
Widget
child
;
final
bool
value
;
final
double
spacing
;
@override
Widget
?
childForSlot
(
CustomRbSlot
slot
)
{
switch
(
slot
)
{
case
CustomRbSlot
.
rb
:
return
Radio
(
value:
value
,
groupValue:
true
,
onChanged:
(
value
)
{});
case
CustomRbSlot
.
child
:
return
child
;
}
}
@override
SlottedContainerRenderObjectMixin
<
CustomRbSlot
>
createRenderObject
(
BuildContext
context
)
{
return
RenderCustomRb
(
spacing
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
RenderCustomRb
renderObject
)
{
renderObject
.
spacing
=
spacing
;
}
@override
Iterable
<
CustomRbSlot
>
get
slots
=>
CustomRbSlot
.
values
;
}
class
RenderCustomRb
extends
RenderBox
with
SlottedContainerRenderObjectMixin
<
CustomRbSlot
>
{
RenderCustomRb
(
this
.
_spacing
);
double
_spacing
;
set
spacing
(
double
value
)
{
if
(
_spacing
==
value
)
{
return
;
}
_spacing
=
value
;
markNeedsLayout
();
}
RenderBox
?
get
rb
=>
childForSlot
(
CustomRbSlot
.
rb
);
RenderBox
?
get
body
=>
childForSlot
(
CustomRbSlot
.
child
);
Size
_layoutBox
(
RenderBox
box
,
BoxConstraints
constraints
)
{
box
.
layout
(
constraints
,
parentUsesSize:
true
);
return
box
.
size
;
}
@override
void
performLayout
()
{
if
(
rb
==
null
||
body
==
null
)
{
size
=
constraints
.
constrain
(
const
Size
(
50
,
10
));
return
;
}
rb
;
Size
rbSize
=
_layoutBox
(
rb
!,
const
BoxConstraints
(
maxWidth:
50
));
Size
bodySize
=
_layoutBox
(
body
!,
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
rbSize
.
width
-
_spacing
));
body
!.
parentData
=
BoxParentData
()
..
offset
=
Offset
(
rbSize
.
width
+
_spacing
,
0
);
rb
!.
parentData
=
BoxParentData
()
..
offset
=
Offset
(
0
,
body
!.
computeDistanceToActualBaseline
(
TextBaseline
.
alphabetic
)!
-
rb
!.
size
.
height
/
1.5
);
size
=
constraints
.
constrain
(
Size
(
bodySize
.
width
+
rbSize
.
width
+
_spacing
,
max
(
rbSize
.
height
,
bodySize
.
height
)));
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
context
.
paintChild
(
body
!,
offset
+
(
body
!.
parentData
as
BoxParentData
).
offset
);
context
.
paintChild
(
rb
!,
offset
+
(
rb
!.
parentData
as
BoxParentData
).
offset
);
}
@override
bool
hitTestSelf
(
Offset
position
)
{
return
true
;
}
@override
bool
hitTestChildren
(
BoxHitTestResult
result
,
{
required
Offset
position
})
{
for
(
final
RenderBox
child
in
children
)
{
final
BoxParentData
parentData
=
child
.
parentData
!
as
BoxParentData
;
final
bool
isHit
=
result
.
addWithPaintOffset
(
offset:
parentData
.
offset
,
position:
position
,
hitTest:
(
BoxHitTestResult
result
,
Offset
transformed
)
{
assert
(
transformed
==
position
-
parentData
.
offset
);
return
child
.
hitTest
(
result
,
position:
transformed
);
},
);
if
(
isHit
)
{
return
true
;
}
}
return
false
;
}
}
enum
CustomCbSlot
{
cb
,
child
,
}
class
CustomCb
extends
RenderObjectWidget
with
SlottedMultiChildRenderObjectWidgetMixin
<
CustomCbSlot
>
{
const
CustomCb
(
{
super
.
key
,
this
.
spacing
=
5
,
required
this
.
child
,
required
this
.
value
});
final
Widget
child
;
final
bool
value
;
final
double
spacing
;
@override
Widget
?
childForSlot
(
CustomCbSlot
slot
)
{
switch
(
slot
)
{
case
CustomCbSlot
.
cb
:
return
Checkbox
(
value:
value
,
onChanged:
(
value
)
{});
case
CustomCbSlot
.
child
:
return
child
;
}
}
@override
SlottedContainerRenderObjectMixin
<
CustomCbSlot
>
createRenderObject
(
BuildContext
context
)
{
return
RenderCustomCb
(
spacing
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
RenderCustomCb
renderObject
)
{
renderObject
.
spacing
=
spacing
;
}
@override
Iterable
<
CustomCbSlot
>
get
slots
=>
CustomCbSlot
.
values
;
}
class
RenderCustomCb
extends
RenderBox
with
SlottedContainerRenderObjectMixin
<
CustomCbSlot
>
{
RenderCustomCb
(
this
.
_spacing
);
double
_spacing
;
set
spacing
(
double
value
)
{
if
(
_spacing
==
value
)
{
return
;
}
_spacing
=
value
;
markNeedsLayout
();
}
RenderBox
?
get
rb
=>
childForSlot
(
CustomCbSlot
.
cb
);
RenderBox
?
get
body
=>
childForSlot
(
CustomCbSlot
.
child
);
Size
_layoutBox
(
RenderBox
box
,
BoxConstraints
constraints
)
{
box
.
layout
(
constraints
,
parentUsesSize:
true
);
return
box
.
size
;
}
@override
void
performLayout
()
{
if
(
rb
==
null
||
body
==
null
)
{
size
=
constraints
.
constrain
(
const
Size
(
50
,
10
));
return
;
}
rb
;
Size
rbSize
=
_layoutBox
(
rb
!,
const
BoxConstraints
(
maxWidth:
50
));
Size
bodySize
=
_layoutBox
(
body
!,
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
rbSize
.
width
-
_spacing
));
body
!.
parentData
=
BoxParentData
()
..
offset
=
Offset
(
rbSize
.
width
+
_spacing
,
0
);
rb
!.
parentData
=
BoxParentData
()
..
offset
=
Offset
(
0
,
body
!.
computeDistanceToActualBaseline
(
TextBaseline
.
alphabetic
)!
-
rb
!.
size
.
height
/
1.5
);
size
=
constraints
.
constrain
(
Size
(
bodySize
.
width
+
rbSize
.
width
+
_spacing
,
max
(
rbSize
.
height
,
bodySize
.
height
)));
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
context
.
paintChild
(
body
!,
offset
+
(
body
!.
parentData
as
BoxParentData
).
offset
);
context
.
paintChild
(
rb
!,
offset
+
(
rb
!.
parentData
as
BoxParentData
).
offset
);
}
@override
bool
hitTestSelf
(
Offset
position
)
{
return
true
;
}
@override
bool
hitTestChildren
(
BoxHitTestResult
result
,
{
required
Offset
position
})
{
for
(
final
RenderBox
child
in
children
)
{
final
BoxParentData
parentData
=
child
.
parentData
!
as
BoxParentData
;
final
bool
isHit
=
result
.
addWithPaintOffset
(
offset:
parentData
.
offset
,
position:
position
,
hitTest:
(
BoxHitTestResult
result
,
Offset
transformed
)
{
assert
(
transformed
==
position
-
parentData
.
offset
);
return
child
.
hitTest
(
result
,
position:
transformed
);
},
);
if
(
isHit
)
{
return
true
;
}
}
return
false
;
}
}
...
...
tex_markdown/lib/custom_widgets/unordered_ordered_list.dart
0 → 100644
View file @
144362a
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
class
UnorderedListView
extends
SingleChildRenderObjectWidget
{
const
UnorderedListView
(
{
super
.
key
,
this
.
spacing
=
6
,
this
.
padding
=
10
,
this
.
bulletColor
,
this
.
bulletSize
=
4
,
required
super
.
child
});
final
double
bulletSize
;
final
double
spacing
;
final
double
padding
;
final
Color
?
bulletColor
;
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
return
UnorderedListRenderObject
(
spacing
,
padding
,
bulletColor
??
Theme
.
of
(
context
).
colorScheme
.
onSurface
,
bulletSize
,
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
UnorderedListRenderObject
renderObject
)
{
renderObject
.
bulletColor
=
bulletColor
??
Theme
.
of
(
context
).
colorScheme
.
onSurface
;
renderObject
.
bulletSize
=
bulletSize
;
renderObject
.
spacing
=
spacing
;
renderObject
.
padding
=
padding
;
}
}
class
UnorderedListRenderObject
extends
RenderProxyBox
{
UnorderedListRenderObject
(
double
spacing
,
double
padding
,
Color
bulletColor
,
this
.
_bulletSize
,
{
RenderBox
?
child
,
})
:
_bulletColor
=
bulletColor
,
_spacing
=
spacing
,
_padding
=
padding
,
super
(
child
);
double
_spacing
;
double
_padding
;
Offset
_bulletOffset
=
Offset
.
zero
;
set
spacing
(
double
value
)
{
if
(
_spacing
==
value
)
{
return
;
}
_spacing
=
value
;
markNeedsLayout
();
}
set
padding
(
double
value
)
{
if
(
_padding
==
value
)
{
return
;
}
_padding
=
value
;
markNeedsLayout
();
}
Color
_bulletColor
;
double
_bulletSize
;
set
bulletSize
(
double
value
)
{
if
(
_bulletSize
==
value
)
{
return
;
}
_bulletSize
=
value
;
markNeedsLayout
();
}
set
bulletColor
(
Color
value
)
{
if
(
_bulletColor
==
value
)
{
return
;
}
_bulletColor
=
value
;
markNeedsLayout
();
}
@override
double
computeMinIntrinsicWidth
(
double
height
)
{
child
!.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
_spacing
-
6
-
_bulletSize
-
_padding
,
),
parentUsesSize:
true
);
return
child
!.
size
.
width
;
}
@override
double
computeMaxIntrinsicWidth
(
double
height
)
{
child
!.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
_spacing
-
6
-
_bulletSize
-
_padding
,
),
parentUsesSize:
true
);
return
child
!.
size
.
width
;
}
@override
double
computeMinIntrinsicHeight
(
double
width
)
{
child
!.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
_spacing
-
6
-
_bulletSize
-
_padding
,
),
parentUsesSize:
true
);
return
child
!.
size
.
height
;
}
@override
double
computeMaxIntrinsicHeight
(
double
width
)
{
child
!.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
_spacing
-
6
-
_bulletSize
-
_padding
,
),
parentUsesSize:
true
);
return
child
!.
size
.
height
;
}
@override
void
performLayout
()
{
super
.
performLayout
();
if
(
child
==
null
)
{
return
;
}
child
!.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
_spacing
-
6
-
_bulletSize
-
_padding
,
),
parentUsesSize:
true
);
child
!.
parentData
=
BoxParentData
()
..
offset
=
Offset
(
_spacing
+
_padding
+
6
+
_bulletSize
,
0
);
var
value
=
child
!.
computeDistanceToActualBaseline
(
TextBaseline
.
alphabetic
);
_bulletOffset
=
Offset
(
4
+
_padding
,
value
!
-
_bulletSize
);
size
=
constraints
.
constrain
(
Size
(
child
!.
size
.
width
+
_spacing
+
_padding
+
6
+
_bulletSize
,
child
!.
size
.
height
));
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
child
==
null
)
{
return
;
}
context
.
paintChild
(
child
!,
offset
+
(
child
!.
parentData
as
BoxParentData
).
offset
);
context
.
canvas
.
drawCircle
(
offset
+
_bulletOffset
,
_bulletSize
,
Paint
()..
color
=
_bulletColor
);
}
}
class
OrderedListView
extends
SingleChildRenderObjectWidget
{
final
String
no
;
final
double
spacing
;
final
double
padding
;
const
OrderedListView
(
{
super
.
key
,
this
.
spacing
=
6
,
this
.
padding
=
10
,
TextStyle
?
style
,
required
super
.
child
,
required
this
.
no
})
:
_style
=
style
;
final
TextStyle
?
_style
;
TextStyle
getStyle
(
BuildContext
context
)
{
if
(
_style
==
null
||
_style
!.
inherit
)
{
return
DefaultTextStyle
.
of
(
context
).
style
.
merge
(
_style
);
}
return
_style
!;
}
@override
RenderObject
createRenderObject
(
BuildContext
context
)
{
return
OrderedListRenderObject
(
no
,
spacing
,
padding
,
getStyle
(
context
),
);
}
@override
void
updateRenderObject
(
BuildContext
context
,
covariant
OrderedListRenderObject
renderObject
)
{
renderObject
.
no
=
no
;
renderObject
.
spacing
=
spacing
;
renderObject
.
padding
=
padding
;
renderObject
.
style
=
getStyle
(
context
);
}
}
class
OrderedListRenderObject
extends
RenderProxyBox
{
OrderedListRenderObject
(
String
no
,
double
spacing
,
double
padding
,
TextStyle
style
,
{
RenderBox
?
child
,
})
:
_no
=
no
,
_style
=
style
,
_spacing
=
spacing
,
_padding
=
padding
,
super
(
child
);
double
_spacing
;
double
_padding
;
Offset
_ptOffset
=
Offset
.
zero
;
set
spacing
(
double
value
)
{
if
(
_spacing
==
value
)
{
return
;
}
_spacing
=
value
;
markNeedsLayout
();
}
set
padding
(
double
value
)
{
if
(
_padding
==
value
)
{
return
;
}
_padding
=
value
;
markNeedsLayout
();
}
TextStyle
_style
;
set
style
(
TextStyle
value
)
{
_style
=
value
;
markNeedsLayout
();
}
String
_no
;
set
no
(
String
value
)
{
if
(
_no
==
value
)
{
return
;
}
_no
=
value
;
markNeedsLayout
();
}
@override
double
computeMinIntrinsicHeight
(
double
width
)
{
pt
=
TextPainter
(
text:
TextSpan
(
text:
_no
,
style:
_style
,
),
textDirection:
TextDirection
.
ltr
);
pt
.
layout
(
maxWidth:
constraints
.
maxWidth
-
50
-
_spacing
-
_padding
);
return
child
!
.
computeMinIntrinsicHeight
(
width
-
pt
.
width
-
_spacing
-
_padding
);
}
@override
double
computeMaxIntrinsicHeight
(
double
width
)
{
pt
=
TextPainter
(
text:
TextSpan
(
text:
_no
,
style:
_style
,
),
textDirection:
TextDirection
.
ltr
);
pt
.
layout
(
maxWidth:
constraints
.
maxWidth
-
50
-
_spacing
-
_padding
);
return
child
!
.
computeMaxIntrinsicHeight
(
width
-
pt
.
width
-
_spacing
-
_padding
);
}
late
TextPainter
pt
;
@override
void
performLayout
()
{
super
.
performLayout
();
if
(
child
==
null
)
{
return
;
}
pt
=
TextPainter
(
text:
TextSpan
(
text:
_no
,
style:
_style
,
),
textDirection:
TextDirection
.
ltr
);
pt
.
layout
(
maxWidth:
constraints
.
maxWidth
-
50
-
_spacing
-
_padding
);
child
!.
layout
(
BoxConstraints
(
maxWidth:
constraints
.
maxWidth
-
pt
.
width
-
_spacing
-
_padding
,
),
parentUsesSize:
true
);
child
!.
parentData
=
BoxParentData
()
..
offset
=
Offset
(
_spacing
+
_padding
+
pt
.
width
,
0
);
var
value
=
child
!.
computeDistanceToActualBaseline
(
TextBaseline
.
alphabetic
);
_ptOffset
=
Offset
(
_padding
,
value
!
-
pt
.
computeDistanceToActualBaseline
(
TextBaseline
.
alphabetic
));
size
=
constraints
.
constrain
(
Size
(
child
!.
size
.
width
+
_spacing
+
_padding
+
pt
.
width
,
child
!.
size
.
height
));
}
@override
void
paint
(
PaintingContext
context
,
Offset
offset
)
{
if
(
child
==
null
)
{
return
;
}
context
.
paintChild
(
child
!,
offset
+
(
child
!.
parentData
as
BoxParentData
).
offset
,
);
pt
.
paint
(
context
.
canvas
,
offset
+
_ptOffset
);
}
}
...
...
tex_markdown/lib/markdown_component.dart
View file @
144362a
import
'package:flutter/material.dart'
;
import
'package:tex_markdown/custom_widgets/custom_divider.dart'
;
import
'package:tex_markdown/custom_widgets/custom_rb_cb.dart'
;
import
'package:tex_markdown/custom_widgets/unordered_ordered_list.dart'
;
import
'package:tex_text/tex_text.dart'
;
import
'md_widget.dart'
;
/// Markdown components
abstract
class
MarkdownComponent
{
static
final
List
<
MarkdownComponent
>
components
=
[
// TableMd(),
HTag
(),
BoldMd
(),
ItalicMd
(),
ATagMd
(),
ImageMd
(),
ATagMd
(),
UnOrderedList
(),
OrderedList
(),
RadioButtonMd
(),
...
...
@@ -38,7 +42,7 @@ abstract class MarkdownComponent {
}
/// Generate widget for markdown widget
static
Widget
generate
(
static
List
<
InlineSpan
>
generate
(
BuildContext
context
,
String
text
,
TextStyle
?
style
,
...
...
@@ -52,7 +56,7 @@ abstract class MarkdownComponent {
if
(
each
is
InlineMd
)
{
spans
.
add
(
each
.
span
(
context
,
element
,
element
.
trim
()
,
style
,
onLinkTab
,
));
...
...
@@ -65,7 +69,7 @@ abstract class MarkdownComponent {
}
else
{
if
(
each
is
BlockMd
)
{
spans
.
add
(
each
.
span
(
context
,
element
,
style
,
onLinkTab
),
each
.
span
(
context
,
element
.
trim
()
,
style
,
onLinkTab
),
);
}
}
...
...
@@ -74,12 +78,13 @@ abstract class MarkdownComponent {
}
},
);
return
Text
.
rich
(
TextSpan
(
children:
List
.
from
(
spans
),
),
textAlign:
TextAlign
.
left
,
);
// return Text.rich(
// TextSpan(
// children: List.from(spans),
// ),
// // textAlign: TextAlign.left,
// );
return
spans
;
}
InlineSpan
span
(
...
...
@@ -119,11 +124,27 @@ abstract class BlockMd extends MarkdownComponent {
TextStyle
?
style
,
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
return
WidgetSpan
(
child:
Align
(
alignment:
Alignment
.
centerLeft
,
child:
build
(
context
,
text
,
style
,
onLinkTab
),
),
return
TextSpan
(
children:
[
const
TextSpan
(
text:
"
\n
"
,
style:
TextStyle
(
fontSize:
0
,
),
),
WidgetSpan
(
child:
build
(
context
,
text
,
style
,
onLinkTab
),
alignment:
PlaceholderAlignment
.
middle
,
),
const
TextSpan
(
text:
"
\n
"
,
style:
TextStyle
(
fontSize:
0
),
),
],
// child: Align(
// alignment: Alignment.centerLeft,
// child: build(context, text, style, onLinkTab),
// ),
);
}
...
...
@@ -148,50 +169,53 @@ class HTag extends BlockMd {
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
var
match
=
exp
.
firstMatch
(
text
.
trim
());
return
Colum
n
(
return
Text
.
rich
(
TextSpa
n
(
children:
[
Row
(
children:
[
Expanded
(
child:
TexText
(
"
${match?[2]}
"
,
style:
[
Theme
.
of
(
context
)
.
textTheme
.
headlineLarge
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
headlineMedium
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
headlineSmall
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
titleLarge
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
titleMedium
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
titleSmall
?.
copyWith
(
color:
style
?.
color
),
][
match
![
1
]!.
length
-
1
]),
),
],
WidgetSpan
(
child:
TexText
(
"
${match?[2]}
"
,
style:
[
Theme
.
of
(
context
)
.
textTheme
.
headlineLarge
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
headlineMedium
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
headlineSmall
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
titleLarge
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
titleMedium
?.
copyWith
(
color:
style
?.
color
),
Theme
.
of
(
context
)
.
textTheme
.
titleSmall
?.
copyWith
(
color:
style
?.
color
),
][
match
![
1
]!.
length
-
1
]),
),
if
(
match
[
1
]!.
length
==
1
)
Divider
(
height:
6
,
thickness:
2
,
color:
style
?.
color
??
Theme
.
of
(
context
).
colorScheme
.
onSurfaceVariant
,
if
(
match
[
1
]!.
length
==
1
)
...[
const
TextSpan
(
text:
"
\n
"
,
style:
TextStyle
(
fontSize:
0
,
height:
0
),
),
WidgetSpan
(
alignment:
PlaceholderAlignment
.
top
,
child:
CustomDivider
(
height:
2
,
color:
style
?.
color
??
Theme
.
of
(
context
).
colorScheme
.
onSurfaceVariant
,
),
),
],
],
);
)
)
;
}
@override
...
...
@@ -212,9 +236,8 @@ class HrLine extends BlockMd {
TextStyle
?
style
,
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
return
Divider
(
height:
6
,
thickness:
2
,
return
CustomDivider
(
height:
2
,
color:
style
?.
color
??
Theme
.
of
(
context
).
colorScheme
.
onSurfaceVariant
,
);
}
...
...
@@ -237,27 +260,13 @@ class CheckBoxMd extends BlockMd {
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
var
match
=
exp
.
firstMatch
(
text
.
trim
());
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
child:
Checkbox
(
// value: true,
value:
(
"
${match?[1]}
"
==
"x"
),
onChanged:
(
value
)
{},
fillColor:
ButtonStyleButton
.
allOrNull
(
style
?.
color
),
),
),
Expanded
(
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
),
],
return
CustomCb
(
value:
(
"
${match?[1]}
"
==
"x"
),
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
);
}
...
...
@@ -283,27 +292,13 @@ class RadioButtonMd extends BlockMd {
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
var
match
=
exp
.
firstMatch
(
text
.
trim
());
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisSize:
MainAxisSize
.
min
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
child:
Radio
(
value:
true
,
groupValue:
(
"
${match?[1]}
"
==
"x"
),
onChanged:
(
value
)
{},
fillColor:
ButtonStyleButton
.
allOrNull
(
style
?.
color
),
),
),
Expanded
(
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
),
],
return
CustomRb
(
value:
(
"
${match?[1]}
"
==
"x"
),
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
);
}
...
...
@@ -329,26 +324,13 @@ class UnOrderedList extends BlockMd {
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
var
match
=
exp
.
firstMatch
(
text
.
trim
());
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisSize:
MainAxisSize
.
max
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
10
),
child:
Icon
(
Icons
.
circle
,
color:
style
?.
color
,
size:
8
,
),
),
Expanded
(
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
),
],
return
UnorderedListView
(
bulletColor:
style
?.
color
,
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
);
}
...
...
@@ -377,26 +359,14 @@ class OrderedList extends BlockMd {
final
void
Function
(
String
url
,
String
title
)?
onLinkTab
,
)
{
var
match
=
exp
.
firstMatch
(
text
.
trim
());
return
Row
(
crossAxisAlignment:
CrossAxisAlignment
.
center
,
mainAxisSize:
MainAxisSize
.
max
,
children:
[
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
horizontal:
11
),
child:
Text
(
"
${match?[1]}
"
,
style:
(
style
??
const
TextStyle
())
.
copyWith
(
fontWeight:
FontWeight
.
bold
),
),
),
Expanded
(
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
),
],
return
OrderedListView
(
no:
"
${match?[1]}
"
,
style:
(
style
??
const
TextStyle
()).
copyWith
(
fontWeight:
FontWeight
.
bold
),
child:
MdWidget
(
"
${match?[2]}
"
,
onLinkTab:
onLinkTab
,
style:
style
,
),
);
}
...
...
@@ -576,6 +546,89 @@ class ImageMd extends InlineMd {
}
}
/// Table component
class
TableMd
extends
BlockMd
{
@override
Widget
build
(
BuildContext
context
,
String
text
,
TextStyle
?
style
,
void
Function
(
String
url
,
String
title
)?
onLinkTab
)
{
final
List
<
Map
<
int
,
String
>>
value
=
text
.
split
(
'
\n
'
)
.
map
<
Map
<
int
,
String
>>(
(
e
)
=>
e
.
split
(
'|'
)
.
where
((
element
)
=>
element
.
isNotEmpty
)
.
toList
()
.
asMap
(),
)
.
toList
();
int
maxCol
=
0
;
for
(
final
each
in
value
)
{
if
(
maxCol
<
each
.
keys
.
length
)
{
maxCol
=
each
.
keys
.
length
;
}
}
if
(
maxCol
==
0
)
{
return
Text
(
""
,
style:
style
);
}
return
Table
(
defaultVerticalAlignment:
TableCellVerticalAlignment
.
middle
,
border:
TableBorder
.
all
(
width:
1
,
color:
Theme
.
of
(
context
).
colorScheme
.
onSurface
,
),
children:
value
.
map
<
TableRow
>(
(
e
)
=>
TableRow
(
children:
List
.
generate
(
maxCol
,
(
index
)
=>
Center
(
child:
MdWidget
(
(
e
[
index
]
??
""
).
trim
(),
onLinkTab:
onLinkTab
,
style:
style
,
),
),
),
),
)
.
toList
(),
);
}
@override
RegExp
get
exp
=>
RegExp
(
r"(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?))(\n(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?)))+)?"
,
);
@override
String
toHtml
(
String
text
)
{
final
String
value
=
text
.
trim
().
splitMapJoin
(
RegExp
(
r'^\||\|\n\||\|$'
),
onMatch:
(
p0
)
=>
"
\n
"
,
onNonMatch:
(
p0
)
{
if
(
p0
.
trim
().
isEmpty
)
{
return
""
;
}
// return p0;
return
'<tr>
${p0.trim().splitMapJoin(
'|',
onMatch: (p0) {
return "";
}
,
onNonMatch: (p0) {
return '
<
td
>
$p0
</
td
>
';
},
)}</tr>'
;
},
);
return
'''
<table border="1" cellspacing="0">
$value
</table>
'''
;
}
}
/// Text component
class
TextMd
extends
InlineMd
{
@override
...
...
tex_markdown/lib/md_widget.dart
View file @
144362a
import
'dart:math'
;
import
'package:flutter/material.dart'
;
import
'package:tex_markdown/markdown_component.dart'
;
...
...
@@ -46,53 +48,110 @@ $value
@override
Widget
build
(
BuildContext
context
)
{
final
RegExp
table
=
RegExp
(
r"^(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?))(\n(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?)))+)?$"
,
);
if
(
table
.
hasMatch
(
exp
))
{
final
List
<
Map
<
int
,
String
>>
value
=
exp
.
split
(
'
\n
'
)
.
map
<
Map
<
int
,
String
>>(
(
e
)
=>
e
.
split
(
'|'
)
.
where
((
element
)
=>
element
.
isNotEmpty
)
.
toList
()
.
asMap
(),
)
.
toList
();
int
maxCol
=
0
;
for
(
final
each
in
value
)
{
if
(
maxCol
<
each
.
keys
.
length
)
{
maxCol
=
each
.
keys
.
length
;
}
}
if
(
maxCol
==
0
)
{
return
Text
(
""
,
style:
style
);
}
return
Table
(
defaultVerticalAlignment:
TableCellVerticalAlignment
.
middle
,
border:
TableBorder
.
all
(
width:
1
,
color:
Theme
.
of
(
context
).
colorScheme
.
onSurface
,
),
children:
value
.
map
<
TableRow
>(
(
e
)
=>
TableRow
(
children:
List
.
generate
(
maxCol
,
(
index
)
=>
Center
(
child:
MdWidget
(
(
e
[
index
]
??
""
).
trim
(),
onLinkTab:
onLinkTab
,
style:
style
,
),
List
<
InlineSpan
>
list
=
[];
exp
.
trim
().
splitMapJoin
(
RegExp
(
r"\n\n+"
),
onMatch:
(
p0
)
{
list
.
add
(
const
TextSpan
(
text:
"
\n
"
),
);
return
""
;
},
onNonMatch:
(
eachLn
)
{
final
RegExp
table
=
RegExp
(
r"^(((\|[^\n\|]+\|)((([^\n\|]+\|)+)?))(\n(((\|[^\n\|]+\|)(([^\n\|]+\|)+)?)))+)?$"
,
);
if
(
table
.
hasMatch
(
eachLn
))
{
final
List
<
Map
<
int
,
String
>>
value
=
eachLn
.
split
(
'
\n
'
)
.
map
<
Map
<
int
,
String
>>(
(
e
)
=>
e
.
split
(
'|'
)
.
where
((
element
)
=>
element
.
isNotEmpty
)
.
toList
()
.
asMap
(),
)
.
toList
();
int
maxCol
=
0
;
for
(
final
each
in
value
)
{
if
(
maxCol
<
each
.
keys
.
length
)
{
maxCol
=
each
.
keys
.
length
;
}
}
// if (maxCol == 0) {
// return Text("", style: style);
// }
list
.
addAll
(
[
const
TextSpan
(
text:
"
\n
"
,
style:
TextStyle
(
height:
0
),
),
WidgetSpan
(
child:
Table
(
defaultColumnWidth:
CustomTableColumnWidth
(),
defaultVerticalAlignment:
TableCellVerticalAlignment
.
middle
,
// defaultColumnWidth: const FixedColumnWidth(double.infinity),
border:
TableBorder
.
all
(
width:
1
,
color:
Theme
.
of
(
context
).
colorScheme
.
onSurface
,
),
children:
value
.
map
<
TableRow
>(
(
e
)
=>
TableRow
(
children:
List
.
generate
(
maxCol
,
(
index
)
=>
Center
(
child:
MdWidget
(
(
e
[
index
]
??
""
).
trim
(),
onLinkTab:
onLinkTab
,
style:
style
,
),
),
),
),
)
.
toList
(),
),
),
)
.
toList
(),
);
const
TextSpan
(
text:
"
\n
"
,
style:
TextStyle
(
height:
0
),
),
],
);
}
else
{
list
.
addAll
(
MarkdownComponent
.
generate
(
context
,
eachLn
,
style
,
onLinkTab
),
);
}
return
""
;
},
);
return
Text
.
rich
(
TextSpan
(
children:
list
,
),
);
}
}
class
CustomTableColumnWidth
extends
TableColumnWidth
{
@override
double
maxIntrinsicWidth
(
Iterable
<
RenderBox
>
cells
,
double
containerWidth
)
{
double
width
=
50
;
for
(
var
each
in
cells
)
{
each
.
layout
(
const
BoxConstraints
(),
parentUsesSize:
true
);
width
=
max
(
width
,
each
.
size
.
width
);
}
if
(
containerWidth
==
double
.
infinity
)
{
return
width
;
}
return
MarkdownComponent
.
generate
(
context
,
exp
,
style
,
onLinkTab
);
return
min
(
containerWidth
,
width
);
}
@override
double
minIntrinsicWidth
(
Iterable
<
RenderBox
>
cells
,
double
containerWidth
)
{
return
50
;
}
}
...
...
tex_markdown/lib/tex_markdown.dart
View file @
144362a
...
...
@@ -27,25 +27,6 @@ class TexMarkdown extends StatelessWidget {
@override
Widget
build
(
BuildContext
context
)
{
return
Column
(
crossAxisAlignment:
CrossAxisAlignment
.
start
,
children:
data
.
trim
()
.
split
(
RegExp
(
r"\n\n+"
),
)
.
map
<
Widget
>(
(
e
)
=>
Padding
(
padding:
const
EdgeInsets
.
symmetric
(
vertical:
4
,
horizontal:
4
),
child:
MdWidget
(
e
,
style:
style
,
followLinkColor:
followLinkColor
,
onLinkTab:
onLinkTab
,
),
),
)
.
toList
(),
);
return
ClipRRect
(
child:
MdWidget
(
data
.
trim
()));
}
}
...
...
Please
register
or
login
to post a comment