Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
48c7a04f
Commit
48c7a04f
authored
Feb 25, 2016
by
Viktor Lidholt
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Adds initial version of Markdown renderer
parent
b193854b
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
940 additions
and
0 deletions
+940
-0
README.md
packages/flutter_markdown/README.md
+22
-0
demo.dart
packages/flutter_markdown/example/demo.dart
+36
-0
flutter_markdown.dart
packages/flutter_markdown/lib/flutter_markdown.dart
+8
-0
flutter_markdown_raw.dart
packages/flutter_markdown/lib/flutter_markdown_raw.dart
+8
-0
markdown.dart
packages/flutter_markdown/lib/src/markdown.dart
+84
-0
markdown_raw.dart
packages/flutter_markdown/lib/src/markdown_raw.dart
+433
-0
markdown_style.dart
packages/flutter_markdown/lib/src/markdown_style.dart
+77
-0
markdown_style_raw.dart
packages/flutter_markdown/lib/src/markdown_style_raw.dart
+120
-0
pubspec.yaml
packages/flutter_markdown/pubspec.yaml
+18
-0
flutter_markdown_test.dart
packages/flutter_markdown/test/flutter_markdown_test.dart
+134
-0
No files found.
packages/flutter_markdown/README.md
0 → 100644
View file @
48c7a04f
# Flutter Markdown
A markdown renderer for Flutter. It supports the
[
original format
](
https://daringfireball.net/projects/markdown/
)
, but no inline
html.
## Getting Started
Using the Markdown widget is simple, just pass in the source markdown as a
string:
new Markdown(data: markdownSource);
If you do not want the padding or scrolling behavior, use the MarkdownBody
instead:
new MarkdownBody(data: markdownSource);
By default, Markdown uses the formatting from the current material design theme,
but it's possible to create your own custom styling. Use the MarkdownStyle class
to pass in your own style. If you don't want to use Markdown outside of material
design, use the MarkdownRaw class.
packages/flutter_markdown/example/demo.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'package:flutter_markdown/flutter_markdown.dart'
;
const
String
_kMarkdownData
=
"""# Markdown Example
Markdown allows you to easily include formatted text, images, and even formatted Dart code in your app.
## Styling
Style text as _italic_, __bold__, or `inline code`.
- Use bulleted lists
- To better clarify
- Your points
## Code blocks
Formatted Dart code looks really pretty too. This is an example of how to create your own Markdown widget:
new Markdown(data: "
Hello
_world_
!
");
Enjoy!
"""
;
void
main
(
)
{
runApp
(
new
MaterialApp
(
title:
"Markdown Demo"
,
routes:
<
String
,
RouteBuilder
>{
'/'
:
(
RouteArguments
args
)
=>
new
Scaffold
(
toolBar:
new
ToolBar
(
center:
new
Text
(
"Markdown Demo"
)),
body:
new
Markdown
(
data:
_kMarkdownData
)
)
}
));
}
packages/flutter_markdown/lib/flutter_markdown.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library
flutter_markdown
;
export
'src/markdown.dart'
;
export
'src/markdown_style.dart'
;
packages/flutter_markdown/lib/flutter_markdown_raw.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
library
flutter_markdown
;
export
'src/markdown_raw.dart'
;
export
'src/markdown_style_raw.dart'
;
packages/flutter_markdown/lib/src/markdown.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'markdown_raw.dart'
;
import
'markdown_style.dart'
;
/// A [Widget] that renders markdown formatted text. It supports all standard
/// markdowns from the original markdown specification found here:
/// https://daringfireball.net/projects/markdown/ The rendered markdown is
/// placed in a padded scrolling view port. If you do not want the scrolling
/// behaviour, use the [MarkdownBody] class instead.
class
Markdown
extends
MarkdownRaw
{
/// Creates a new Markdown [Widget] that renders the markdown formatted string
/// passed in as [data]. By default the markdown will be rendered using the
/// styles from the current theme, but you can optionally pass in a custom
/// [markdownStyle] that specifies colors and fonts to use. Code blocks are
/// by default not using syntax highlighting, but it's possible to pass in
/// a custom [syntaxHighlighter].
///
/// new Markdown(data: "Hello _world_!");
Markdown
({
String
data
,
SyntaxHighlighter
syntaxHighlighter
,
MarkdownStyle
markdownStyle
})
:
super
(
data:
data
,
syntaxHighlighter:
syntaxHighlighter
,
markdownStyle:
markdownStyle
);
MarkdownBody
createMarkdownBody
({
String
data
,
MarkdownStyle
markdownStyle
,
SyntaxHighlighter
syntaxHighlighter
})
{
return
new
MarkdownBody
(
data:
data
,
markdownStyle:
markdownStyle
,
syntaxHighlighter:
syntaxHighlighter
);
}
}
/// A [Widget] that renders markdown formatted text. It supports all standard
/// markdowns from the original markdown specification found here:
/// https://daringfireball.net/projects/markdown/ This class doesn't implement
/// any scrolling behavior, if you want scrolling either wrap the widget in
/// a [ScrollableViewport] or use the [Markdown] widget.
class
MarkdownBody
extends
MarkdownBodyRaw
{
/// Creates a new Markdown [Widget] that renders the markdown formatted string
/// passed in as [data]. By default the markdown will be rendered using the
/// styles from the current theme, but you can optionally pass in a custom
/// [markdownStyle] that specifies colors and fonts to use. Code blocks are
/// by default not using syntax highlighting, but it's possible to pass in
/// a custom [syntaxHighlighter].
///
/// Typically, you may want to wrap the [MarkdownBody] widget in a [Padding] and
/// a [ScrollableViewport], or use the [Markdown] class
///
/// new ScrollableViewport(
/// child: new Padding(
/// padding: new EdgeDims.all(16.0),
/// child: new Markdown(data: markdownSource)
/// )
/// )
MarkdownBody
({
String
data
,
SyntaxHighlighter
syntaxHighlighter
,
MarkdownStyle
markdownStyle
})
:
super
(
data:
data
,
syntaxHighlighter:
syntaxHighlighter
,
markdownStyle:
markdownStyle
);
MarkdownStyle
createDefaultStyle
(
BuildContext
context
)
{
return
new
MarkdownStyle
.
defaultFromTheme
(
Theme
.
of
(
context
));
}
}
packages/flutter_markdown/lib/src/markdown_raw.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:markdown/markdown.dart'
as
md
;
import
'package:flutter/widgets.dart'
;
import
'markdown_style_raw.dart'
;
/// A [Widget] that renders markdown formatted text. It supports all standard
/// markdowns from the original markdown specification found here:
/// https://daringfireball.net/projects/markdown/ The rendered markdown is
/// placed in a padded scrolling view port. If you do not want the scrolling
/// behaviour, use the [MarkdownBodyRaw] class instead.
class
MarkdownRaw
extends
StatelessComponent
{
/// Creates a new Markdown [Widget] that renders the markdown formatted string
/// passed in as [data]. By default the markdown will be rendered using the
/// styles from the current theme, but you can optionally pass in a custom
/// [markdownStyle] that specifies colors and fonts to use. Code blocks are
/// by default not using syntax highlighting, but it's possible to pass in
/// a custom [syntaxHighlighter].
///
/// new MarkdownRaw(data: "Hello _world_!", markdownStyle: myStyle);
MarkdownRaw
({
this
.
data
,
this
.
markdownStyle
,
this
.
syntaxHighlighter
,
this
.
padding
:
const
EdgeDims
.
all
(
16.0
)
});
/// Markdown styled text
final
String
data
;
/// Style used for rendering the markdown
final
MarkdownStyleRaw
markdownStyle
;
/// The syntax highlighter used to color text in code blocks
final
SyntaxHighlighter
syntaxHighlighter
;
/// Padding used
final
EdgeDims
padding
;
Widget
build
(
BuildContext
context
)
{
return
new
ScrollableViewport
(
child:
new
Padding
(
padding:
padding
,
child:
createMarkdownBody
(
data:
data
,
markdownStyle:
markdownStyle
,
syntaxHighlighter:
syntaxHighlighter
)
)
);
}
MarkdownBodyRaw
createMarkdownBody
({
String
data
,
MarkdownStyleRaw
markdownStyle
,
SyntaxHighlighter
syntaxHighlighter
})
{
return
new
MarkdownBodyRaw
(
data:
data
,
markdownStyle:
markdownStyle
,
syntaxHighlighter:
syntaxHighlighter
);
}
}
/// A [Widget] that renders markdown formatted text. It supports all standard
/// markdowns from the original markdown specification found here:
/// https://daringfireball.net/projects/markdown/ This class doesn't implement
/// any scrolling behavior, if you want scrolling either wrap the widget in
/// a [ScrollableViewport] or use the [MarkdownRaw] widget.
class
MarkdownBodyRaw
extends
StatefulComponent
{
/// Creates a new Markdown [Widget] that renders the markdown formatted string
/// passed in as [data]. You need to pass in a [markdownStyle] that defines
/// how the code is rendered. Code blocks are by default not using syntax
/// highlighting, but it's possible to pass in a custom [syntaxHighlighter].
///
/// Typically, you may want to wrap the [MarkdownBodyRaw] widget in a
/// [Padding] and a [ScrollableViewport], or use the [Markdown class]
///
/// new ScrollableViewport(
/// child: new Padding(
/// padding: new EdgeDims.all(16.0),
/// child: new MarkdownBodyRaw(
/// data: markdownSource,
/// markdownStyle: myStyle
/// )
/// )
/// )
MarkdownBodyRaw
({
this
.
data
,
this
.
markdownStyle
,
this
.
syntaxHighlighter
});
/// Markdown styled text
final
String
data
;
/// Style used for rendering the markdown
final
MarkdownStyleRaw
markdownStyle
;
/// The syntax highlighter used to color text in code blocks
final
SyntaxHighlighter
syntaxHighlighter
;
_MarkdownBodyRawState
createState
()
=>
new
_MarkdownBodyRawState
();
MarkdownStyleRaw
createDefaultStyle
(
BuildContext
context
)
=>
null
;
}
class
_MarkdownBodyRawState
extends
State
<
MarkdownBodyRaw
>
{
void
initState
()
{
super
.
initState
();
MarkdownStyleRaw
markdownStyle
=
config
.
markdownStyle
??
config
.
createDefaultStyle
(
context
);
SyntaxHighlighter
syntaxHighlighter
=
config
.
syntaxHighlighter
??
new
_DefaultSyntaxHighlighter
(
markdownStyle
.
code
);
_cachedBlocks
=
_blocksFromMarkup
(
config
.
data
,
markdownStyle
,
syntaxHighlighter
);
}
List
<
_Block
>
_cachedBlocks
;
Widget
build
(
BuildContext
context
)
{
List
<
Widget
>
blocks
=
<
Widget
>[];
for
(
_Block
block
in
_cachedBlocks
)
{
blocks
.
add
(
block
.
build
(
context
));
}
return
new
Column
(
alignItems:
FlexAlignItems
.
stretch
,
children:
blocks
);
}
}
List
<
_Block
>
_blocksFromMarkup
(
String
data
,
MarkdownStyleRaw
markdownStyle
,
SyntaxHighlighter
syntaxHighlighter
)
{
// TODO: This can be optimized by doing the split and removing \r at the same time
List
<
String
>
lines
=
data
.
replaceAll
(
'
\r\n
'
,
'
\n
'
).
split
(
'
\n
'
);
md
.
Document
document
=
new
md
.
Document
();
_Renderer
renderer
=
new
_Renderer
();
return
renderer
.
render
(
document
.
parseLines
(
lines
),
markdownStyle
,
syntaxHighlighter
);
}
class
_Renderer
implements
md
.
NodeVisitor
{
List
<
_Block
>
render
(
List
<
md
.
Node
>
nodes
,
MarkdownStyleRaw
markdownStyle
,
SyntaxHighlighter
syntaxHighlighter
)
{
assert
(
markdownStyle
!=
null
);
_blocks
=
<
_Block
>[];
_listIndents
=
<
String
>[];
_markdownStyle
=
markdownStyle
;
_syntaxHighlighter
=
syntaxHighlighter
;
for
(
final
md
.
Node
node
in
nodes
)
{
node
.
accept
(
this
);
}
return
_blocks
;
}
List
<
_Block
>
_blocks
;
List
<
String
>
_listIndents
;
MarkdownStyleRaw
_markdownStyle
;
SyntaxHighlighter
_syntaxHighlighter
;
void
visitText
(
md
.
Text
text
)
{
_MarkdownNodeList
topList
=
_currentBlock
.
stack
.
last
;
List
<
_MarkdownNode
>
top
=
topList
.
list
;
if
(
_currentBlock
.
tag
==
'pre'
)
top
.
add
(
new
_MarkdownNodeTextSpan
(
_syntaxHighlighter
.
format
(
text
.
text
)));
else
top
.
add
(
new
_MarkdownNodeString
(
text
.
text
));
}
bool
visitElementBefore
(
md
.
Element
element
)
{
if
(
_isListTag
(
element
.
tag
))
_listIndents
.
add
(
element
.
tag
);
if
(
_isBlockTag
(
element
.
tag
))
{
List
<
_Block
>
blockList
;
if
(
_currentBlock
==
null
)
blockList
=
_blocks
;
else
blockList
=
_currentBlock
.
subBlocks
;
_Block
newBlock
=
new
_Block
(
element
.
tag
,
element
.
attributes
,
_markdownStyle
,
new
List
<
String
>.
from
(
_listIndents
),
blockList
.
length
);
blockList
.
add
(
newBlock
);
}
else
{
TextStyle
style
=
_markdownStyle
.
styles
[
element
.
tag
]
??
new
TextStyle
();
List
<
_MarkdownNode
>
styleElement
=
<
_MarkdownNode
>[
new
_MarkdownNodeTextStyle
(
style
)];
_currentBlock
.
stack
.
add
(
new
_MarkdownNodeList
(
styleElement
));
}
return
true
;
}
void
visitElementAfter
(
md
.
Element
element
)
{
if
(
_isListTag
(
element
.
tag
))
_listIndents
.
removeLast
();
if
(
_isBlockTag
(
element
.
tag
))
{
if
(
_currentBlock
.
stack
.
length
>
0
)
{
_MarkdownNodeList
stackList
=
_currentBlock
.
stack
.
first
;
_currentBlock
.
stack
=
stackList
.
list
;
_currentBlock
.
open
=
false
;
}
else
{
_currentBlock
.
stack
=
<
_MarkdownNode
>[
new
_MarkdownNodeString
(
''
)];
}
}
else
{
if
(
_currentBlock
.
stack
.
length
>
1
)
{
_MarkdownNodeList
poppedList
=
_currentBlock
.
stack
.
last
;
List
<
_MarkdownNode
>
popped
=
poppedList
.
list
;
_currentBlock
.
stack
.
removeLast
();
_MarkdownNodeList
topList
=
_currentBlock
.
stack
.
last
;
List
<
_MarkdownNode
>
top
=
topList
.
list
;
top
.
add
(
new
_MarkdownNodeList
(
popped
));
}
}
}
static
const
List
<
String
>
_kBlockTags
=
const
<
String
>[
'p'
,
'h1'
,
'h2'
,
'h3'
,
'h4'
,
'h5'
,
'h6'
,
'li'
,
'blockquote'
,
'img'
,
'pre'
,
'ol'
,
'ul'
];
static
const
List
<
String
>
_kListTags
=
const
<
String
>[
'ul'
,
'ol'
];
bool
_isBlockTag
(
String
tag
)
{
return
_kBlockTags
.
contains
(
tag
);
}
bool
_isListTag
(
String
tag
)
{
return
_kListTags
.
contains
(
tag
);
}
_Block
get
_currentBlock
=>
_currentBlockInList
(
_blocks
);
_Block
_currentBlockInList
(
List
<
_Block
>
blocks
)
{
if
(
blocks
.
isEmpty
)
return
null
;
if
(!
blocks
.
last
.
open
)
return
null
;
_Block
childBlock
=
_currentBlockInList
(
blocks
.
last
.
subBlocks
);
if
(
childBlock
!=
null
)
return
childBlock
;
return
blocks
.
last
;
}
}
abstract
class
_MarkdownNode
{
}
class
_MarkdownNodeList
extends
_MarkdownNode
{
_MarkdownNodeList
(
this
.
list
);
List
<
_MarkdownNode
>
list
;
}
class
_MarkdownNodeTextStyle
extends
_MarkdownNode
{
_MarkdownNodeTextStyle
(
this
.
style
);
TextStyle
style
;
}
class
_MarkdownNodeString
extends
_MarkdownNode
{
_MarkdownNodeString
(
this
.
string
);
String
string
;
}
class
_MarkdownNodeTextSpan
extends
_MarkdownNode
{
_MarkdownNodeTextSpan
(
this
.
textSpan
);
TextSpan
textSpan
;
}
class
_Block
{
_Block
(
this
.
tag
,
this
.
attributes
,
this
.
markdownStyle
,
this
.
listIndents
,
this
.
blockPosition
)
{
TextStyle
style
=
markdownStyle
.
styles
[
tag
];
if
(
style
==
null
)
style
=
new
TextStyle
(
color:
const
Color
(
0xffff0000
));
stack
=
<
_MarkdownNode
>[
new
_MarkdownNodeList
(<
_MarkdownNode
>[
new
_MarkdownNodeTextStyle
(
style
)])];
subBlocks
=
<
_Block
>[];
}
final
String
tag
;
final
Map
<
String
,
String
>
attributes
;
final
MarkdownStyleRaw
markdownStyle
;
final
List
<
String
>
listIndents
;
final
int
blockPosition
;
List
<
_MarkdownNode
>
stack
;
List
<
_Block
>
subBlocks
;
bool
get
open
=>
_open
;
void
set
open
(
bool
open
)
{
_open
=
open
;
if
(!
open
&&
subBlocks
.
length
>
0
)
subBlocks
.
last
.
isLast
=
true
;
}
bool
_open
=
true
;
bool
isLast
=
false
;
Widget
build
(
BuildContext
context
)
{
if
(
tag
==
'img'
)
{
return
_buildImage
(
context
,
attributes
[
'src'
]);
}
double
spacing
=
markdownStyle
.
blockSpacing
;
if
(
isLast
)
spacing
=
0.0
;
Widget
contents
;
if
(
subBlocks
.
length
>
0
)
{
List
<
Widget
>
subWidgets
=
<
Widget
>[];
for
(
_Block
subBlock
in
subBlocks
)
{
subWidgets
.
add
(
subBlock
.
build
(
context
));
}
contents
=
new
Column
(
alignItems:
FlexAlignItems
.
stretch
,
children:
subWidgets
);
}
else
{
contents
=
new
RichText
(
text:
_stackToTextSpan
(
new
_MarkdownNodeList
(
stack
)));
if
(
listIndents
.
length
>
0
)
{
Widget
bullet
;
if
(
listIndents
.
last
==
'ul'
)
{
bullet
=
new
Text
(
'•'
,
style:
new
TextStyle
(
textAlign:
TextAlign
.
center
)
);
}
else
{
bullet
=
new
Padding
(
padding:
new
EdgeDims
.
only
(
right:
5.0
),
child:
new
Text
(
"
${blockPosition + 1}
."
,
style:
new
TextStyle
(
textAlign:
TextAlign
.
right
)
)
);
}
contents
=
new
Row
(
alignItems:
FlexAlignItems
.
start
,
children:
<
Widget
>[
new
SizedBox
(
width:
listIndents
.
length
*
markdownStyle
.
listIndent
,
child:
bullet
),
new
Flexible
(
child:
contents
)
]
);
}
}
BoxDecoration
decoration
;
EdgeDims
padding
;
if
(
tag
==
'blockquote'
)
{
decoration
=
markdownStyle
.
blockquoteDecoration
;
padding
=
new
EdgeDims
.
all
(
markdownStyle
.
blockquotePadding
);
}
else
if
(
tag
==
'pre'
)
{
decoration
=
markdownStyle
.
codeblockDecoration
;
padding
=
new
EdgeDims
.
all
(
markdownStyle
.
codeblockPadding
);
}
return
new
Container
(
padding:
padding
,
margin:
new
EdgeDims
.
only
(
bottom:
spacing
),
child:
contents
,
decoration:
decoration
);
}
TextSpan
_stackToTextSpan
(
_MarkdownNode
stack
)
{
if
(
stack
is
_MarkdownNodeTextSpan
)
return
stack
.
textSpan
;
if
(
stack
is
_MarkdownNodeList
)
{
List
<
_MarkdownNode
>
list
=
stack
.
list
;
_MarkdownNodeTextStyle
styleNode
=
list
[
0
];
TextStyle
style
=
styleNode
.
style
;
List
<
TextSpan
>
children
=
<
TextSpan
>[];
for
(
int
i
=
1
;
i
<
list
.
length
;
i
++)
{
children
.
add
(
_stackToTextSpan
(
list
[
i
]));
}
return
new
TextSpan
(
style:
style
,
children:
children
);
}
if
(
stack
is
_MarkdownNodeString
)
{
return
new
TextSpan
(
text:
stack
.
string
);
}
return
null
;
}
Widget
_buildImage
(
BuildContext
context
,
String
src
)
{
List
<
String
>
parts
=
src
.
split
(
'#'
);
if
(
parts
.
length
==
0
)
return
new
Container
();
String
path
=
parts
.
first
;
double
width
;
double
height
;
if
(
parts
.
length
==
2
)
{
List
<
String
>
dimensions
=
parts
.
last
.
split
(
'x'
);
if
(
dimensions
.
length
==
2
)
{
width
=
double
.
parse
(
dimensions
[
0
]);
height
=
double
.
parse
(
dimensions
[
1
]);
}
}
return
new
NetworkImage
(
src:
path
,
width:
width
,
height:
height
);
}
}
abstract
class
SyntaxHighlighter
{
TextSpan
format
(
String
source
);
}
class
_DefaultSyntaxHighlighter
extends
SyntaxHighlighter
{
_DefaultSyntaxHighlighter
(
this
.
style
);
final
TextStyle
style
;
TextSpan
format
(
String
source
)
{
return
new
TextSpan
(
style:
style
,
children:
<
TextSpan
>[
new
TextSpan
(
text:
source
)]);
}
}
packages/flutter_markdown/lib/src/markdown_style.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/material.dart'
;
import
'markdown_style_raw.dart'
;
/// Style used for rendering markdown formatted text using the [MarkdownBody]
/// widget.
class
MarkdownStyle
extends
MarkdownStyleRaw
{
/// Creates a [MarkdownStyle] from the [TextStyle]s in the provided [theme].
MarkdownStyle
.
defaultFromTheme
(
ThemeData
theme
)
:
super
(
a:
new
TextStyle
(
color:
Colors
.
blue
[
500
]),
p:
theme
.
text
.
body1
,
code:
new
TextStyle
(
color:
Colors
.
grey
[
700
],
fontFamily:
"monospace"
,
fontSize:
theme
.
text
.
body1
.
fontSize
*
0.85
),
h1:
theme
.
text
.
headline
,
h2:
theme
.
text
.
title
,
h3:
theme
.
text
.
subhead
,
h4:
theme
.
text
.
body2
,
h5:
theme
.
text
.
body2
,
h6:
theme
.
text
.
body2
,
em:
new
TextStyle
(
fontStyle:
FontStyle
.
italic
),
strong:
new
TextStyle
(
fontWeight:
FontWeight
.
bold
),
blockquote:
theme
.
text
.
body1
,
blockSpacing:
8.0
,
listIndent:
32.0
,
blockquotePadding:
8.0
,
blockquoteDecoration:
new
BoxDecoration
(
backgroundColor:
Colors
.
blue
[
100
],
borderRadius:
2.0
),
codeblockPadding:
8.0
,
codeblockDecoration:
new
BoxDecoration
(
backgroundColor:
Colors
.
grey
[
100
],
borderRadius:
2.0
)
);
/// Creates a [MarkdownStyle] from the [TextStyle]s in the provided [theme].
/// This style uses larger fonts for the headings than in
/// [MarkdownStyle.defaultFromTheme].
MarkdownStyle
.
largeFromTheme
(
ThemeData
theme
)
:
super
(
a:
new
TextStyle
(
color:
Colors
.
blue
[
500
]),
p:
theme
.
text
.
body1
,
code:
new
TextStyle
(
color:
Colors
.
grey
[
700
],
fontFamily:
"monospace"
,
fontSize:
theme
.
text
.
body1
.
fontSize
*
0.85
),
h1:
theme
.
text
.
display3
,
h2:
theme
.
text
.
display2
,
h3:
theme
.
text
.
display1
,
h4:
theme
.
text
.
headline
,
h5:
theme
.
text
.
title
,
h6:
theme
.
text
.
subhead
,
em:
new
TextStyle
(
fontStyle:
FontStyle
.
italic
),
strong:
new
TextStyle
(
fontWeight:
FontWeight
.
bold
),
blockquote:
theme
.
text
.
body1
,
blockSpacing:
8.0
,
listIndent:
32.0
,
blockquotePadding:
8.0
,
blockquoteDecoration:
new
BoxDecoration
(
backgroundColor:
Colors
.
blue
[
100
],
borderRadius:
2.0
),
codeblockPadding:
8.0
,
codeblockDecoration:
new
BoxDecoration
(
backgroundColor:
Colors
.
grey
[
100
],
borderRadius:
2.0
)
);
}
packages/flutter_markdown/lib/src/markdown_style_raw.dart
0 → 100644
View file @
48c7a04f
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/widgets.dart'
;
/// Style used for rendering markdown formatted text using the [MarkdownBody]
/// widget.
class
MarkdownStyleRaw
{
/// Creates a new [MarkdownStyleRaw]
MarkdownStyleRaw
({
this
.
a
,
this
.
p
,
this
.
code
,
this
.
h1
,
this
.
h2
,
this
.
h3
,
this
.
h4
,
this
.
h5
,
this
.
h6
,
this
.
em
,
this
.
strong
,
this
.
blockquote
,
this
.
blockSpacing
,
this
.
listIndent
,
this
.
blockquotePadding
,
this
.
blockquoteDecoration
,
this
.
codeblockPadding
,
this
.
codeblockDecoration
})
{
_init
();
}
/// Creates a new [MarkdownStyleRaw] based on the current style, with the
/// provided paramaters overridden.
MarkdownStyleRaw
copyWith
({
TextStyle
a
,
TextStyle
p
,
TextStyle
code
,
TextStyle
h1
,
TextStyle
h2
,
TextStyle
h3
,
TextStyle
h4
,
TextStyle
h5
,
TextStyle
h6
,
TextStyle
em
,
TextStyle
strong
,
TextStyle
blockquote
,
double
blockSpacing
,
double
listIndent
,
double
blockquotePadding
,
BoxDecoration
blockquoteDecoration
,
double
codeblockPadding
,
BoxDecoration
codeblockDecoration
})
{
return
new
MarkdownStyleRaw
(
a:
a
!=
null
?
a
:
this
.
a
,
p:
p
!=
null
?
p
:
this
.
p
,
code:
code
!=
null
?
code
:
this
.
code
,
h1:
h1
!=
null
?
h1
:
this
.
h1
,
h2:
h2
!=
null
?
h2
:
this
.
h2
,
h3:
h3
!=
null
?
h3
:
this
.
h3
,
h4:
h4
!=
null
?
h4
:
this
.
h4
,
h5:
h5
!=
null
?
h5
:
this
.
h5
,
h6:
h6
!=
null
?
h6
:
this
.
h6
,
em:
em
!=
null
?
em
:
this
.
em
,
strong:
strong
!=
null
?
strong
:
this
.
strong
,
blockquote:
blockquote
!=
null
?
blockquote
:
this
.
blockquote
,
blockSpacing:
blockSpacing
!=
null
?
blockSpacing
:
this
.
blockSpacing
,
listIndent:
listIndent
!=
null
?
listIndent
:
this
.
listIndent
,
blockquotePadding:
blockquotePadding
!=
null
?
blockquotePadding
:
this
.
blockquotePadding
,
blockquoteDecoration:
blockquoteDecoration
!=
null
?
blockquoteDecoration
:
this
.
blockquoteDecoration
,
codeblockPadding:
codeblockPadding
!=
null
?
codeblockPadding
:
this
.
codeblockPadding
,
codeblockDecoration:
codeblockDecoration
!=
null
?
codeblockDecoration
:
this
.
codeblockDecoration
);
}
final
TextStyle
a
;
final
TextStyle
p
;
final
TextStyle
code
;
final
TextStyle
h1
;
final
TextStyle
h2
;
final
TextStyle
h3
;
final
TextStyle
h4
;
final
TextStyle
h5
;
final
TextStyle
h6
;
final
TextStyle
em
;
final
TextStyle
strong
;
final
TextStyle
blockquote
;
final
double
blockSpacing
;
final
double
listIndent
;
final
double
blockquotePadding
;
final
BoxDecoration
blockquoteDecoration
;
final
double
codeblockPadding
;
final
BoxDecoration
codeblockDecoration
;
Map
<
String
,
TextStyle
>
_styles
;
Map
<
String
,
TextStyle
>
get
styles
=>
_styles
;
void
_init
()
{
_styles
=
{
'a'
:
a
,
'p'
:
p
,
'li'
:
p
,
'code'
:
code
,
'pre'
:
p
,
'h1'
:
h1
,
'h2'
:
h2
,
'h3'
:
h3
,
'h4'
:
h4
,
'h5'
:
h5
,
'h6'
:
h6
,
'em'
:
em
,
'strong'
:
strong
,
'blockquote'
:
blockquote
};
}
}
packages/flutter_markdown/pubspec.yaml
0 → 100644
View file @
48c7a04f
name
:
flutter_markdown
description
:
A markdown renderer for Flutter.
version
:
0.1.0
author
:
Flutter Authors <flutter-dev@googlegroups.com>
homepage
:
http://flutter.io
dependencies
:
flutter
:
path
:
../flutter
markdown
:
"
0.9.0"
string_scanner
:
"
0.1.4+1"
dev_dependencies
:
flutter_tools
:
path
:
../flutter_tools
test
:
any
# constrained by the dependency in flutter_tools
flutter_test
:
path
:
../flutter_test
packages/flutter_markdown/test/flutter_markdown_test.dart
0 → 100644
View file @
48c7a04f
import
'package:flutter_markdown/flutter_markdown.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
import
'package:flutter/widgets.dart'
;
import
'package:test/test.dart'
;
import
'package:flutter/material.dart'
;
void
main
(
)
{
test
(
"Simple string"
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
MarkdownBody
(
data:
"Hello"
));
Element
textElement
=
tester
.
findElement
((
Element
element
)
=>
element
.
widget
is
RichText
);
RichText
textWidget
=
textElement
.
widget
;
TextSpan
textSpan
=
textWidget
.
text
;
List
<
Element
>
elements
=
_listElements
(
tester
);
_expectWidgetTypes
(
elements
,
<
Type
>[
MarkdownBody
,
Column
,
Container
,
Padding
,
RichText
]);
expect
(
textSpan
.
children
[
0
].
text
,
equals
(
"Hello"
));
});
});
test
(
"Header"
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
MarkdownBody
(
data:
"# Header"
));
Element
textElement
=
tester
.
findElement
((
Element
element
)
=>
element
.
widget
is
RichText
);
RichText
textWidget
=
textElement
.
widget
;
TextSpan
textSpan
=
textWidget
.
text
;
List
<
Element
>
elements
=
_listElements
(
tester
);
_expectWidgetTypes
(
elements
,
<
Type
>[
MarkdownBody
,
Column
,
Container
,
Padding
,
RichText
]);
expect
(
textSpan
.
children
[
0
].
text
,
equals
(
"Header"
));
});
});
test
(
"Empty string"
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
MarkdownBody
(
data:
""
));
List
<
Element
>
elements
=
_listElements
(
tester
);
_expectWidgetTypes
(
elements
,
<
Type
>[
MarkdownBody
,
Column
]);
});
});
test
(
"Ordered list"
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
MarkdownBody
(
data:
"1. Item 1
\n
1. Item 2
\n
2. Item 3"
));
List
<
Element
>
elements
=
_listElements
(
tester
);
_expectTextStrings
(
elements
,
<
String
>[
"1."
,
"Item 1"
,
"2."
,
"Item 2"
,
"3."
,
"Item 3"
]
);
});
});
test
(
"Unordered list"
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
MarkdownBody
(
data:
"- Item 1
\n
- Item 2
\n
- Item 3"
));
List
<
Element
>
elements
=
_listElements
(
tester
);
_expectTextStrings
(
elements
,
<
String
>[
"•"
,
"Item 1"
,
"•"
,
"Item 2"
,
"•"
,
"Item 3"
]
);
});
});
test
(
"Scrollable wrapping"
,
()
{
testWidgets
((
WidgetTester
tester
)
{
tester
.
pumpWidget
(
new
Markdown
(
data:
""
));
List
<
Element
>
elements
=
_listElements
(
tester
);
for
(
Element
element
in
elements
)
print
(
"e:
$element
"
);
_expectWidgetTypes
(
elements
,
<
Type
>[
Markdown
,
ScrollableViewport
,
null
,
null
,
null
,
null
,
null
,
// ScrollableViewport internals
Padding
,
MarkdownBody
,
Column
]);
});
});
}
List
<
Element
>
_listElements
(
WidgetTester
tester
)
{
List
<
Element
>
elements
=
<
Element
>[];
tester
.
walkElements
((
Element
element
)
{
elements
.
add
(
element
);
});
return
elements
;
}
void
_expectWidgetTypes
(
List
<
Element
>
elements
,
List
<
Type
>
types
)
{
expect
(
elements
.
length
,
equals
(
types
.
length
));
for
(
int
i
=
0
;
i
<
elements
.
length
;
i
+=
1
)
{
Element
element
=
elements
[
i
];
Type
type
=
types
[
i
];
if
(
type
==
null
)
continue
;
expect
(
element
.
widget
.
runtimeType
,
equals
(
type
));
}
}
void
_expectTextStrings
(
List
<
Element
>
elements
,
List
<
String
>
strings
)
{
int
currentString
=
0
;
for
(
Element
element
in
elements
)
{
Widget
widget
=
element
.
widget
;
if
(
widget
is
RichText
)
{
TextSpan
span
=
widget
.
text
;
String
text
=
_extractTextFromTextSpan
(
span
);
expect
(
text
,
equals
(
strings
[
currentString
]));
currentString
+=
1
;
}
}
}
String
_extractTextFromTextSpan
(
TextSpan
span
)
{
String
text
=
span
.
text
??
""
;
if
(
span
.
children
!=
null
)
{
for
(
TextSpan
child
in
span
.
children
)
{
text
+=
_extractTextFromTextSpan
(
child
);
}
}
return
text
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment