Compare commits
56 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
2ea148c30a | ||
![]() |
205ae7b47a | ||
![]() |
c54f1154b6 | ||
![]() |
6f8b8e71f5 | ||
![]() |
50b3168491 | ||
![]() |
b8cb4d1e82 | ||
![]() |
bd3408beb3 | ||
![]() |
646e708c82 | ||
![]() |
3069432bc2 | ||
![]() |
1bc45e0195 | ||
![]() |
3e1db2abbe | ||
![]() |
79cd43bc9c | ||
![]() |
14a8746599 | ||
![]() |
48518de658 | ||
![]() |
910bf311da | ||
![]() |
05cdf2c400 | ||
![]() |
eb3a986c48 | ||
![]() |
273ecdd7cd | ||
![]() |
923b00b6d0 | ||
![]() |
89ec2a063f | ||
![]() |
02aa16a6f2 | ||
![]() |
82cb42813a | ||
![]() |
08a8cece61 | ||
![]() |
ac578906d3 | ||
![]() |
2296d0032d | ||
![]() |
bde188ecd3 | ||
![]() |
62cb8d1f4d | ||
![]() |
c4cb4420b1 | ||
![]() |
132756af4e | ||
![]() |
89e89c766e | ||
![]() |
537d8e715d | ||
![]() |
7002dbfb8d | ||
![]() |
63ed271133 | ||
![]() |
dcd9d428ee | ||
![]() |
905c9fa159 | ||
![]() |
f8eaac6197 | ||
![]() |
4c3fba8929 | ||
![]() |
2356dd4618 | ||
![]() |
8cea2e0202 | ||
![]() |
d41137f6cf | ||
![]() |
fa286287c8 | ||
![]() |
bc7890c603 | ||
![]() |
5162c13bf7 | ||
![]() |
949962ee0b | ||
![]() |
12be227620 | ||
![]() |
65309e684c | ||
![]() |
aa2ff41831 | ||
![]() |
602891566d | ||
![]() |
854fa744c7 | ||
![]() |
06413aaf36 | ||
![]() |
55e640af9c | ||
![]() |
d26da7c1a0 | ||
![]() |
df89c06f22 | ||
![]() |
be667e3b45 | ||
![]() |
961ff32c9a | ||
![]() |
0a365840e1 |
3
.github/FUNDING.yml
vendored
Normal file
3
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
#repo: https://github.com/noties/Markwon
|
||||
|
||||
custom: ["https://paypal.me/dimitryivanov"]
|
59
CHANGELOG.md
59
CHANGELOG.md
@ -1,5 +1,64 @@
|
||||
# Changelog
|
||||
|
||||
# 4.6.2
|
||||
|
||||
#### Added
|
||||
* `image` - `DefaultDownScalingMediaDecoder` which scales displayed images down ([#329])
|
||||
|
||||
[#329]: https://github.com/noties/Markwon/issues/329
|
||||
|
||||
|
||||
# 4.6.1
|
||||
|
||||
#### Changed
|
||||
* `core` - `CustomTypefaceSpan` new `mergeStyles` functionality and new factory method([#298])<br>Thanks [@c-b-h]
|
||||
* `image-coil` - update `Coil` to `0.13.0` ([#303])<br>Thanks [@ubuntudroid]
|
||||
|
||||
#### Deprecated
|
||||
* `core` - `CustomTypefaceSpan(Typeface)` constructor, use `CustomTypefaceSpan.create(Typeface)`
|
||||
or `CustomTypefaceSpan.create(Typeface, boolean)` factory methods instead
|
||||
|
||||
|
||||
[#298]: https://github.com/noties/Markwon/pull/298
|
||||
[#303]: https://github.com/noties/Markwon/pull/303
|
||||
|
||||
[@c-b-h]: https://github.com/c-b-h
|
||||
[@ubuntudroid]: https://github.com/ubuntudroid
|
||||
|
||||
|
||||
# 4.6.0
|
||||
|
||||
#### Added
|
||||
* `ext-tables` - `TableAwareMovementMethod` a special movement method to handle clicks inside tables ([#289])
|
||||
|
||||
#### Changed
|
||||
* `ext-tasklist` - changed implementation to be in line with GFM (Github flavored markdown),
|
||||
task list item is a regular list item (BulletList and OrderedList can contain it).
|
||||
Internal implementation changed from block parsing to node post processing ([#291])
|
||||
* `image-glide` - update to `4.11.0` version
|
||||
* `inline-parser` - revert parsing index when `InlineProcessor` returns `null` as result
|
||||
* `image-coil` - update `Coil` to `0.12.0` ([Coil changelog](https://coil-kt.github.io/coil/changelog/)) ([#284])<br>Thanks [@magnusvs]
|
||||
|
||||
[#284]: https://github.com/noties/Markwon/pull/284
|
||||
[#289]: https://github.com/noties/Markwon/issues/289
|
||||
[#291]: https://github.com/noties/Markwon/issues/291
|
||||
|
||||
[@magnusvs]: https://github.com/magnusvs
|
||||
|
||||
|
||||
# 4.5.1
|
||||
|
||||
#### Changed
|
||||
* `image-coil` - use `coil-base` as `api` dependency (would require explicit `coil` dependency) ([#274])
|
||||
|
||||
#### Fixed
|
||||
* `image-coil` - deliver image result if it loaded before request disposable is created ([#272])
|
||||
* `ext-tables` - fix column width rounding issue
|
||||
|
||||
[#272]: https://github.com/noties/Markwon/issues/272
|
||||
[#274]: https://github.com/noties/Markwon/issues/274
|
||||
|
||||
|
||||
# 4.5.0
|
||||
|
||||
#### Added
|
||||
|
@ -84,7 +84,7 @@ and [3.x.x](https://github.com/noties/Markwon/tree/3.x.x) branches
|
||||
|
||||
## Screenshots
|
||||
|
||||
Taken with default configuration (except for image loading):
|
||||
Taken with default configuration (except for image loading) in [sample app](./app-sample/):
|
||||
|
||||
<a href="./art/mw_light_01.png"><img src="./art/mw_light_01.png" width="30%" /></a>
|
||||
<a href="./art/mw_light_02.png"><img src="./art/mw_light_02.png" width="30%" /></a>
|
||||
@ -101,6 +101,11 @@ Please visit [documentation] web-site for reference
|
||||
|
||||
[documentation]: https://noties.github.io/Markwon
|
||||
|
||||
|
||||
## Consulting
|
||||
Paid consulting is available. Please reach me out at [markwon+consulting[at]noties.io](mailto:markwon+consulting@noties.io)
|
||||
to discuss your idea or a project
|
||||
|
||||
---
|
||||
|
||||
# Demo
|
||||
|
@ -99,10 +99,6 @@ android {
|
||||
signingConfig signingConfigs.config
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// it seems to be a bug in NDK handling, github fail to build the project with the:
|
||||
// `com.android.builder.errors.EvalIssueException: No version of NDK matched the requested version 21.0.6113669. Versions available locally: 21.3.6528147`
|
||||
ndkVersion '21.3.6528147'
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,6 +155,7 @@ dependencies {
|
||||
implementation it['debug']
|
||||
implementation it['android-svg']
|
||||
implementation it['android-gif-impl']
|
||||
implementation it['coil']
|
||||
}
|
||||
|
||||
deps['test'].with {
|
||||
@ -166,4 +163,4 @@ dependencies {
|
||||
testImplementation it['robolectric']
|
||||
testImplementation it['mockito']
|
||||
}
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ cd ./build/outputs/apk/debug/
|
||||
|
||||
revision=$(git rev-parse --short HEAD)
|
||||
|
||||
echo "output.json" > ./.gitignore
|
||||
echo "output-metadata.json" > ./.gitignore
|
||||
echo "$revision" > ./version
|
||||
|
||||
git init
|
||||
|
@ -1,4 +1,288 @@
|
||||
[
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.CopyCodeBlockSample",
|
||||
"id": "20210315112847",
|
||||
"title": "Copy code block",
|
||||
"description": "Copy contents of fenced code blocks",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"block",
|
||||
"rendering",
|
||||
"span",
|
||||
"spanFactory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.parser.RedditSuperscriptSample",
|
||||
"id": "20210224091506",
|
||||
"title": "Reddit superscript",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"html",
|
||||
"reddit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.ImageSizeResolverSample",
|
||||
"id": "20210201165512",
|
||||
"title": "ImageSizeResolver",
|
||||
"description": "Custom `ImageSizeResolver` that treats dimension values as density-based (like `dp`, `dip` in resources)",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.html.InspectHtmlTextSample",
|
||||
"id": "20210201140501",
|
||||
"title": "Inspect text",
|
||||
"description": "Inspect text content of a `HTML` node",
|
||||
"artifacts": [
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.HugeImageSample",
|
||||
"id": "20210118165230",
|
||||
"title": "Huge image downscaling",
|
||||
"description": "Downscale displayed images with `BitmapOptions` 2 step rendering (measure, downscale), use `DefaultDownScalingMediaDecoder`",
|
||||
"artifacts": [
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.html.HtmlCssStyleParserSample",
|
||||
"id": "20210118155530",
|
||||
"title": "CSS attributes in HTML",
|
||||
"description": "Parse CSS attributes of HTML tags with `CssInlineStyleParser`",
|
||||
"artifacts": [
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.basics.OneLineNoMarkdownSample",
|
||||
"id": "20210118154116",
|
||||
"title": "One line text",
|
||||
"description": "Single line text without markdown markup",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.TaskListMutateNestedSample",
|
||||
"id": "20201228120444",
|
||||
"title": "Task list mutate nested",
|
||||
"description": "Task list mutation with nested items",
|
||||
"artifacts": [
|
||||
"EXT_TASKLIST"
|
||||
],
|
||||
"tags": [
|
||||
"plugin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.ClickImageSample",
|
||||
"id": "20201221130230",
|
||||
"title": "Click images",
|
||||
"description": "Make _all_ images clickable (to open in a gallery, etc)",
|
||||
"artifacts": [
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.ChangeBulletSpanSample",
|
||||
"id": "20201208150530",
|
||||
"title": "Change bullet span",
|
||||
"description": "Use a different span implementation to render bullet lists",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering",
|
||||
"span",
|
||||
"spanFactory"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.HeadingColorSample",
|
||||
"id": "20201203224611",
|
||||
"title": "Color of heading",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.OrderedListNumbersSample",
|
||||
"id": "20201203221806",
|
||||
"title": "Ordered list numbers",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.ExcludeFromParsingSample",
|
||||
"id": "20201111221945",
|
||||
"title": "Exclude part of input from parsing",
|
||||
"description": "Exclude part of input from parsing by splitting input with delimiters",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.parser.CustomHeadingParserSample",
|
||||
"id": "20201111221207",
|
||||
"title": "Custom heading parser",
|
||||
"description": "Custom heading block parser. Actual parser is not implemented",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"parsing",
|
||||
"heading"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.editor.WYSIWYGEditorSample",
|
||||
"id": "20200908133515",
|
||||
"title": "WYSIWG editor",
|
||||
"description": "A possible direction to implement what-you-see-is-what-you-get editor",
|
||||
"artifacts": [
|
||||
"EDITOR"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.ListTaskListSample",
|
||||
"id": "20200902174132",
|
||||
"title": "Task list items with other lists",
|
||||
"description": "Mix of task list items with other lists (bullet and ordered)",
|
||||
"artifacts": [
|
||||
"EXT_TASKLIST"
|
||||
],
|
||||
"tags": [
|
||||
"lists"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.DeeplinksSample",
|
||||
"id": "20200826122247",
|
||||
"title": "Deeplinks",
|
||||
"description": "Handling of deeplinks (app handles https scheme to deep link into content)",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"links"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.CoilImageSample",
|
||||
"id": "20200826101209",
|
||||
"title": "Coil image",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"IMAGE_COIL"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.JustifyModeSample",
|
||||
"id": "20200826084338",
|
||||
"title": "Justify text",
|
||||
"description": "Justify text with `justificationMode` argument on Oreo (\u003e\u003d 26)",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.GlideGifImageSample",
|
||||
"id": "20200820071942",
|
||||
"title": "Glide GIF",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"IMAGE_GLIDE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingSquareBracketsSample",
|
||||
"id": "20200819071751",
|
||||
"title": "Inline Parsing of square brackets",
|
||||
"description": "Disable OpenBracketInlineParser in order to parse own markdown syntax based on `[` character(s). This would disable native markdown [links](#) but not images ",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.ThematicBreakBottomMarginSample",
|
||||
"id": "20200813154415",
|
||||
"title": "Thematic break bottom margin",
|
||||
"description": "Do not add a new line after thematic break (with the `BlockHandler`)",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.RedditSpoilerSample",
|
||||
"id": "20200813145316",
|
||||
"title": "Reddit spoiler",
|
||||
"description": "An attempt to implement Reddit spoiler syntax `\u003e! !\u003c`",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.CoilRecyclerViewSample",
|
||||
"id": "20200803132053",
|
||||
@ -9,9 +293,9 @@
|
||||
"RECYCLER"
|
||||
],
|
||||
"tags": [
|
||||
"image",
|
||||
"recycler-view",
|
||||
"rendering"
|
||||
"recyclerView",
|
||||
"rendering",
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -24,9 +308,9 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"image",
|
||||
"rendering"
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -132,7 +416,7 @@
|
||||
"javaClassName": "io.noties.markwon.app.samples.table.TableLinkifySample",
|
||||
"id": "20200702135739",
|
||||
"title": "Linkify table",
|
||||
"description": "Automatically linkify markdown content including content inside tables",
|
||||
"description": "Automatically linkify markdown content including content inside tables, handle clicks inside tables",
|
||||
"artifacts": [
|
||||
"EXT_TABLES",
|
||||
"LINKIFY"
|
||||
@ -163,7 +447,7 @@
|
||||
"RECYCLER_TABLE"
|
||||
],
|
||||
"tags": [
|
||||
"recycler-view"
|
||||
"recyclerView"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -189,8 +473,8 @@
|
||||
"RECYCLER"
|
||||
],
|
||||
"tags": [
|
||||
"precomputed-text",
|
||||
"recycler-view"
|
||||
"recyclerView",
|
||||
"precomputedText"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -202,7 +486,7 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"precomputed-text"
|
||||
"precomputedText"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -301,8 +585,8 @@
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"known-bug",
|
||||
"rendering"
|
||||
"rendering",
|
||||
"knownBug"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -388,10 +672,10 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"parsing",
|
||||
"plugin",
|
||||
"rendering"
|
||||
"rendering",
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -403,9 +687,9 @@
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"parsing",
|
||||
"block",
|
||||
"inline",
|
||||
"parsing"
|
||||
"inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -417,8 +701,8 @@
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
"parsing",
|
||||
"inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -430,8 +714,8 @@
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
"parsing",
|
||||
"inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -443,8 +727,8 @@
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
"parsing",
|
||||
"inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -456,8 +740,8 @@
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
"parsing",
|
||||
"inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -517,8 +801,8 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"GIF",
|
||||
"image"
|
||||
"image",
|
||||
"gif"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -530,8 +814,8 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"SVG",
|
||||
"image"
|
||||
"image",
|
||||
"svg"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -556,9 +840,9 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"image",
|
||||
"rendering"
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -571,8 +855,8 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering"
|
||||
"rendering",
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -584,8 +868,8 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering"
|
||||
"rendering",
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -598,9 +882,9 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"image",
|
||||
"rendering"
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -613,9 +897,9 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"image",
|
||||
"rendering"
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -627,9 +911,9 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"span"
|
||||
"span",
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -641,9 +925,9 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"span"
|
||||
"span",
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -655,9 +939,9 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"span"
|
||||
"span",
|
||||
"html"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -801,11 +1085,11 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"extension",
|
||||
"image",
|
||||
"parsing",
|
||||
"plugin",
|
||||
"rendering",
|
||||
"image",
|
||||
"extension",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
@ -820,12 +1104,12 @@
|
||||
"tags": [
|
||||
"parsing",
|
||||
"rendering",
|
||||
"text-added-listener"
|
||||
"textAddedListener"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.GithubUserIssueInlineParsingSample",
|
||||
"id": "20200629162024",
|
||||
"id": "20200629162023",
|
||||
"title": "User mention and issue (via text)",
|
||||
"description": "Github-like user mention and issue rendering via `CorePlugin.OnTextAddedListener`",
|
||||
"artifacts": [
|
||||
@ -835,7 +1119,7 @@
|
||||
"tags": [
|
||||
"parsing",
|
||||
"rendering",
|
||||
"text-added-listener"
|
||||
"textAddedListener"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -872,9 +1156,9 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"lists",
|
||||
"plugin",
|
||||
"rendering"
|
||||
"rendering",
|
||||
"lists"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -886,9 +1170,9 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"anchor",
|
||||
"links",
|
||||
"plugin"
|
||||
"plugin",
|
||||
"anchor"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -901,9 +1185,9 @@
|
||||
],
|
||||
"tags": [
|
||||
"block",
|
||||
"padding",
|
||||
"rendering",
|
||||
"spacing"
|
||||
"spacing",
|
||||
"padding"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -916,10 +1200,10 @@
|
||||
],
|
||||
"tags": [
|
||||
"block",
|
||||
"heading",
|
||||
"padding",
|
||||
"rendering",
|
||||
"spacing"
|
||||
"spacing",
|
||||
"padding",
|
||||
"heading"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -931,9 +1215,9 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"padding",
|
||||
"rendering",
|
||||
"spacing"
|
||||
"spacing",
|
||||
"padding"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -945,8 +1229,8 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"padding",
|
||||
"spacing",
|
||||
"padding",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
@ -959,8 +1243,8 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"new-line",
|
||||
"soft-break"
|
||||
"newLine",
|
||||
"softBreak"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -972,9 +1256,9 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"defaults",
|
||||
"new-line",
|
||||
"soft-break"
|
||||
"newLine",
|
||||
"softBreak",
|
||||
"defaults"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -998,8 +1282,8 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"defaults",
|
||||
"links"
|
||||
"links",
|
||||
"defaults"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1039,8 +1323,8 @@
|
||||
],
|
||||
"tags": [
|
||||
"paragraph",
|
||||
"span",
|
||||
"style"
|
||||
"style",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1065,9 +1349,9 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"movementMethod",
|
||||
"links",
|
||||
"movement-method",
|
||||
"recycler-view"
|
||||
"recyclerView"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1079,8 +1363,8 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"movementMethod",
|
||||
"links",
|
||||
"movement-method",
|
||||
"plugin"
|
||||
]
|
||||
},
|
||||
@ -1093,10 +1377,10 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"movementMethod",
|
||||
"links",
|
||||
"movement-method",
|
||||
"plugin",
|
||||
"recycler-view"
|
||||
"recyclerView"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1108,8 +1392,8 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"links",
|
||||
"movement-method"
|
||||
"movementMethod",
|
||||
"links"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1121,9 +1405,9 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"defaults",
|
||||
"movementMethod",
|
||||
"links",
|
||||
"movement-method"
|
||||
"defaults"
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -1135,8 +1419,8 @@
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"block",
|
||||
"parsing",
|
||||
"block",
|
||||
"plugin"
|
||||
]
|
||||
},
|
||||
@ -1150,8 +1434,8 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"hack",
|
||||
"toast"
|
||||
"toast",
|
||||
"hack"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -28,7 +28,7 @@ sealed class Deeplink {
|
||||
// https://noties.io/Markwon/app/sample/ID
|
||||
// https://noties.io/Markwon/app/search?a=core
|
||||
val segments = data.pathSegments
|
||||
if (segments.size == 3
|
||||
if (segments.size >= 3
|
||||
&& "Markwon" == segments[0]
|
||||
&& "app" == segments[1]) {
|
||||
when (segments[2]) {
|
||||
@ -41,6 +41,8 @@ sealed class Deeplink {
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}.also {
|
||||
Debug.i("parsed: $it")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ import android.os.Bundle
|
||||
import android.view.Window
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import io.noties.debug.Debug
|
||||
import io.noties.markwon.app.App
|
||||
import io.noties.markwon.app.sample.ui.SampleFragment
|
||||
import io.noties.markwon.app.sample.ui.SampleListFragment
|
||||
@ -21,6 +22,7 @@ class MainActivity : FragmentActivity() {
|
||||
|
||||
// process deeplink if we are not restored
|
||||
val deeplink = Deeplink.parse(intent.data)
|
||||
|
||||
val deepLinkFragment: Fragment? = if (deeplink != null) {
|
||||
when (deeplink) {
|
||||
is Deeplink.Sample -> App.sampleManager.sample(deeplink.id)
|
||||
|
@ -1,37 +0,0 @@
|
||||
package io.noties.markwon.app.sample
|
||||
|
||||
object Tags {
|
||||
const val basics = "basics"
|
||||
const val toast = "toast"
|
||||
const val hack = "hack"
|
||||
const val parsing = "parsing"
|
||||
const val block = "block"
|
||||
const val movementMethod = "movement-method"
|
||||
const val links = "links"
|
||||
const val plugin = "plugin"
|
||||
const val recyclerView = "recycler-view"
|
||||
const val paragraph = "paragraph"
|
||||
const val rendering = "rendering"
|
||||
const val style = "style"
|
||||
const val theme = "theme"
|
||||
const val image = "image"
|
||||
const val newLine = "new-line"
|
||||
const val softBreak = "soft-break"
|
||||
const val defaults = "defaults"
|
||||
const val spacing = "spacing"
|
||||
const val padding = "padding"
|
||||
const val heading = "heading"
|
||||
const val anchor = "anchor"
|
||||
const val lists = "lists"
|
||||
const val extension = "extension"
|
||||
const val textAddedListener = "text-added-listener"
|
||||
const val editor = "editor"
|
||||
const val span = "span"
|
||||
const val svg = "SVG"
|
||||
const val gif = "GIF"
|
||||
const val inline = "inline"
|
||||
const val html = "HTML"
|
||||
const val knownBug = "known-bug"
|
||||
const val precomputedText = "precomputed-text"
|
||||
const val cache = "cache"
|
||||
}
|
@ -276,6 +276,9 @@ class SampleListFragment : Fragment() {
|
||||
is UpdateUtils.Result.UpdateAvailable -> {
|
||||
val md = """
|
||||
## Update available
|
||||
|
||||
${BuildConfig.GIT_SHA} -> **${result.revision}**
|
||||
|
||||
Would you like to download it?
|
||||
""".trimIndent()
|
||||
builder.setMessage(markwon.toMarkdown(md))
|
||||
@ -289,7 +292,7 @@ class SampleListFragment : Fragment() {
|
||||
is UpdateUtils.Result.NoUpdate -> {
|
||||
val md = """
|
||||
## No update
|
||||
You are using latest version (${BuildConfig.GIT_SHA})
|
||||
You are using latest version (**${BuildConfig.GIT_SHA}**)
|
||||
""".trimIndent()
|
||||
builder.setMessage(markwon.toMarkdown(md))
|
||||
builder.setPositiveButton(android.R.string.ok, null)
|
||||
|
@ -7,19 +7,19 @@ import org.commonmark.node.Heading;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.MarkwonTheme;
|
||||
import io.noties.markwon.core.spans.LastLineSpacingSpan;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629125321",
|
||||
title = "Additional spacing after block",
|
||||
description = "Add additional spacing (padding) after last line of a block",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.spacing, Tags.padding, Tags.span}
|
||||
tags = {Tag.spacing, Tag.padding, Tag.span}
|
||||
)
|
||||
public class AdditionalSpacingSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -8,17 +8,17 @@ import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.BlockHandlerDef;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629130227",
|
||||
title = "All blocks no padding",
|
||||
description = "Do not render new lines (padding) after all blocks",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.block, Tags.spacing, Tags.padding, Tags.rendering}
|
||||
tags = {Tag.block, Tag.spacing, Tag.padding, Tag.rendering}
|
||||
)
|
||||
public class AllBlocksNoForcedNewLineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -7,17 +7,17 @@ import org.commonmark.node.Node;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200729090524",
|
||||
title = "Block handler",
|
||||
description = "Custom block delimiters that control new lines after block nodes",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.rendering
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class BlockHandlerSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -3,11 +3,11 @@ package io.noties.markwon.app.samples
|
||||
import android.content.Context
|
||||
import io.noties.debug.Debug
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
import java.util.Collections
|
||||
import java.util.WeakHashMap
|
||||
|
||||
@ -17,7 +17,7 @@ import java.util.WeakHashMap
|
||||
description = "A static cache for `Markwon` instance " +
|
||||
"to be associated with a `Context`",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tags.cache]
|
||||
tags = [Tag.cache]
|
||||
)
|
||||
class CacheMarkwonSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
@ -0,0 +1,66 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import android.text.style.BulletSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.ListItem;
|
||||
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.SpanFactory;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.ext.tasklist.TaskListPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20201208150530",
|
||||
title = "Change bullet span",
|
||||
description = "Use a different span implementation to render bullet lists",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tag.rendering, Tag.spanFactory, Tag.span}
|
||||
)
|
||||
public class ChangeBulletSpanSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"* one\n" +
|
||||
"* two\n" +
|
||||
"* three\n" +
|
||||
"* * four\n" +
|
||||
" * five\n\n" +
|
||||
"- [ ] and task?\n" +
|
||||
"- [x] it is";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(TaskListPlugin.create(context))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
|
||||
// store original span factory (provides both bullet and ordered lists)
|
||||
final SpanFactory original = builder.getFactory(ListItem.class);
|
||||
|
||||
builder.setFactory(ListItem.class, (configuration, props) -> {
|
||||
if (CoreProps.LIST_ITEM_TYPE.require(props) == CoreProps.ListItemType.BULLET) {
|
||||
// additionally inspect bullet level
|
||||
final int level = CoreProps.BULLET_LIST_ITEM_LEVEL.require(props);
|
||||
Debug.i("rendering bullet list with level: %d", level);
|
||||
|
||||
// return _system_ bullet span, but can be any
|
||||
return new BulletSpan();
|
||||
}
|
||||
return original != null ? original.getSpans(configuration, props) : null;
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
package io.noties.markwon.app.samples
|
||||
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Paint
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.text.Layout
|
||||
import android.text.Spanned
|
||||
import android.text.TextPaint
|
||||
import android.text.style.ClickableSpan
|
||||
import android.text.style.LeadingMarginSpan
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import io.noties.debug.Debug
|
||||
import io.noties.markwon.AbstractMarkwonPlugin
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.MarkwonSpansFactory
|
||||
import io.noties.markwon.app.R
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
import io.noties.markwon.utils.LeadingMarginUtils
|
||||
import org.commonmark.node.FencedCodeBlock
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20210315112847",
|
||||
title = "Copy code block",
|
||||
description = "Copy contents of fenced code blocks",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tag.rendering, Tag.block, Tag.spanFactory, Tag.span]
|
||||
)
|
||||
class CopyCodeBlockSample : MarkwonTextViewSample() {
|
||||
|
||||
override fun render() {
|
||||
val md = """
|
||||
# Hello code blocks!
|
||||
```java
|
||||
final int i = 0;
|
||||
final Type t = Type.init()
|
||||
.filter(i -> i.even)
|
||||
.first(null);
|
||||
```
|
||||
bye bye!
|
||||
""".trimIndent()
|
||||
|
||||
val markwon = Markwon.builder(context)
|
||||
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||
override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
|
||||
builder.appendFactory(FencedCodeBlock::class.java) { _, _ ->
|
||||
CopyContentsSpan()
|
||||
}
|
||||
builder.appendFactory(FencedCodeBlock::class.java) { _, _ ->
|
||||
CopyIconSpan(context.getDrawable(R.drawable.ic_code_white_24dp)!!)
|
||||
}
|
||||
}
|
||||
})
|
||||
.build()
|
||||
|
||||
markwon.setMarkdown(textView, md)
|
||||
}
|
||||
|
||||
class CopyContentsSpan : ClickableSpan() {
|
||||
override fun onClick(widget: View) {
|
||||
val spanned = (widget as? TextView)?.text as? Spanned ?: return
|
||||
val start = spanned.getSpanStart(this)
|
||||
val end = spanned.getSpanEnd(this)
|
||||
// by default code blocks have new lines before and after content
|
||||
val contents = spanned.subSequence(start, end).toString().trim()
|
||||
// copy code here
|
||||
Debug.i(contents)
|
||||
}
|
||||
|
||||
override fun updateDrawState(ds: TextPaint) {
|
||||
// do not apply link styling
|
||||
}
|
||||
}
|
||||
|
||||
class CopyIconSpan(val icon: Drawable) : LeadingMarginSpan {
|
||||
|
||||
init {
|
||||
if (icon.bounds.isEmpty) {
|
||||
icon.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getLeadingMargin(first: Boolean): Int = 0
|
||||
|
||||
override fun drawLeadingMargin(
|
||||
c: Canvas,
|
||||
p: Paint,
|
||||
x: Int,
|
||||
dir: Int,
|
||||
top: Int,
|
||||
baseline: Int,
|
||||
bottom: Int,
|
||||
text: CharSequence,
|
||||
start: Int,
|
||||
end: Int,
|
||||
first: Boolean,
|
||||
layout: Layout
|
||||
) {
|
||||
|
||||
// called for each line of text, we are interested only in first one
|
||||
if (!LeadingMarginUtils.selfStart(start, text, this)) return
|
||||
|
||||
val save = c.save()
|
||||
try {
|
||||
// horizontal position for icon
|
||||
val w = icon.bounds.width().toFloat()
|
||||
// minus quarter width as padding
|
||||
val left = layout.width - w - (w / 4F)
|
||||
c.translate(left, top.toFloat())
|
||||
icon.draw(c)
|
||||
} finally {
|
||||
c.restoreToCount(save)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -30,10 +30,10 @@ import java.util.regex.Pattern;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629163248",
|
||||
@ -42,7 +42,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
"icon from resources and renders it as image with " +
|
||||
"`@ic-name` syntax",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.parsing, Tags.rendering, Tags.plugin, Tags.image, Tags.extension, Tags.span}
|
||||
tags = {Tag.parsing, Tag.rendering, Tag.plugin, Tag.image, Tag.extension, Tag.span}
|
||||
)
|
||||
public class CustomExtensionSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -6,18 +6,18 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.MarkwonTheme;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629123617",
|
||||
title = "Customize theme",
|
||||
description = "Customize `MarkwonTheme` styling",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.style, Tags.theme, Tags.plugin}
|
||||
tags = {Tag.style, Tag.theme, Tag.plugin}
|
||||
)
|
||||
public class CustomizeThemeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200826122247",
|
||||
title = "Deeplinks",
|
||||
description = "Handling of deeplinks (app handles https scheme to deep link into content)",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.links
|
||||
)
|
||||
public class DeeplinksSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Deeplinks\n\n" +
|
||||
"The [link](https://noties.io/Markwon/app/sample/20200826122247) to self";
|
||||
|
||||
// nothing special is required
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -11,17 +11,17 @@ import org.commonmark.parser.delimiter.DelimiterRun;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630194017",
|
||||
title = "Custom delimiter processor",
|
||||
description = "Custom parsing delimiter processor with `?` character",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.parsing
|
||||
tags = Tag.parsing
|
||||
)
|
||||
public class DelimiterProcessorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -7,17 +7,17 @@ import org.commonmark.node.Heading;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629123308",
|
||||
title = "Disable node from rendering",
|
||||
description = "Disable _parsed_ node from being rendered (markdown syntax is still consumed)",
|
||||
artifacts = {MarkwonArtifact.CORE},
|
||||
tags = {Tags.parsing, Tags.rendering}
|
||||
tags = {Tag.parsing, Tag.rendering}
|
||||
)
|
||||
public class DisableNodeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -2,11 +2,11 @@ package io.noties.markwon.app.samples
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.core.CorePlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
import org.commonmark.node.BlockQuote
|
||||
import org.commonmark.parser.Parser
|
||||
|
||||
@ -16,7 +16,7 @@ import org.commonmark.parser.Parser
|
||||
description = "Modify/inspect enabled by `CorePlugin` block types. " +
|
||||
"Disable quotes or other blocks from being parsed",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tags.parsing, Tags.block, Tags.plugin]
|
||||
tags = [Tag.parsing, Tag.block, Tag.plugin]
|
||||
)
|
||||
class EnabledBlockTypesSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
@ -0,0 +1,75 @@
|
||||
package io.noties.markwon.app.samples
|
||||
|
||||
import android.text.SpannableStringBuilder
|
||||
import io.noties.debug.Debug
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
import java.util.regex.Pattern
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20201111221945",
|
||||
title = "Exclude part of input from parsing",
|
||||
description = "Exclude part of input from parsing by splitting input with delimiters",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tag.parsing]
|
||||
)
|
||||
class ExcludeFromParsingSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
||||
// cannot have continuous markdown between parts (so a node started in one part and ended in other)
|
||||
// with this approach
|
||||
// also exclude will start a new block and won't seamlessly continue any existing markdown one (so
|
||||
// if started inside a blockquote, then blockquote would be closed)
|
||||
|
||||
val md = """
|
||||
# Hello
|
||||
|
||||
we are **going** to exclude some parts of this input _from_ parsing
|
||||
|
||||
$EXCLUDE_START
|
||||
what is **good** is that we
|
||||
> do not need to care about blocks or inlines
|
||||
* and
|
||||
* everything
|
||||
* else
|
||||
$EXCLUDE_END
|
||||
|
||||
**then** markdown _again_
|
||||
|
||||
and empty exclude at end: $EXCLUDE_START$EXCLUDE_END
|
||||
""".trimIndent()
|
||||
|
||||
val markwon = Markwon.create(context)
|
||||
val matcher = Pattern.compile(RE, Pattern.MULTILINE).matcher(md)
|
||||
|
||||
val builder by lazy(LazyThreadSafetyMode.NONE) {
|
||||
SpannableStringBuilder()
|
||||
}
|
||||
|
||||
var end: Int = 0
|
||||
|
||||
while (matcher.find()) {
|
||||
val start = matcher.start()
|
||||
Debug.i(end, start, md.substring(end, start))
|
||||
builder.append(markwon.toMarkdown(md.substring(end, start)))
|
||||
builder.append(matcher.group(1))
|
||||
end = matcher.end()
|
||||
}
|
||||
|
||||
if (end != md.length) {
|
||||
builder.append(markwon.toMarkdown(md.substring(end)))
|
||||
}
|
||||
|
||||
markwon.setParsedMarkdown(textView, builder)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EXCLUDE_START = "##IGNORE##"
|
||||
const val EXCLUDE_END = "--IGNORE--"
|
||||
|
||||
const val RE = "${EXCLUDE_START}([\\s\\S]*?)${EXCLUDE_END}"
|
||||
}
|
||||
}
|
@ -12,20 +12,20 @@ import java.util.regex.Pattern;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.BuildConfig;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.InlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629162024",
|
||||
id = "20200629162023",
|
||||
title = "User mention and issue (via text)",
|
||||
description = "Github-like user mention and issue " +
|
||||
"rendering via `CorePlugin.OnTextAddedListener`",
|
||||
artifacts = {MarkwonArtifact.CORE, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.parsing, Tags.textAddedListener, Tags.rendering}
|
||||
tags = {Tag.parsing, Tag.textAddedListener, Tag.rendering}
|
||||
)
|
||||
public class GithubUserIssueInlineParsingSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
@ -34,7 +34,7 @@ public class GithubUserIssueInlineParsingSample extends MarkwonTextViewSample {
|
||||
"# Custom Extension 2\n" +
|
||||
"\n" +
|
||||
"This is an issue #1\n" +
|
||||
"Done by @noties";
|
||||
"Done by @noties and other @dude";
|
||||
|
||||
final InlineParserFactory inlineParserFactory = MarkwonInlineParser.factoryBuilder()
|
||||
// include all current defaults (otherwise will be empty - contain only our inline-processors)
|
||||
|
@ -14,12 +14,12 @@ import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.RenderProps;
|
||||
import io.noties.markwon.SpannableBuilder;
|
||||
import io.noties.markwon.app.BuildConfig;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CorePlugin;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629162024",
|
||||
@ -27,7 +27,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Github-like user mention and issue " +
|
||||
"rendering via `CorePlugin.OnTextAddedListener`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.parsing, Tags.textAddedListener, Tags.rendering}
|
||||
tags = {Tag.parsing, Tag.textAddedListener, Tag.rendering}
|
||||
)
|
||||
public class GithubUserIssueOnTextAddedSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
@ -36,7 +36,7 @@ public class GithubUserIssueOnTextAddedSample extends MarkwonTextViewSample {
|
||||
"# Custom Extension 2\n" +
|
||||
"\n" +
|
||||
"This is an issue #1\n" +
|
||||
"Done by @noties";
|
||||
"Done by @noties and other @dude";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
|
@ -0,0 +1,58 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.Heading;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20201203224611",
|
||||
title = "Color of heading",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class HeadingColorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
final String md = "" +
|
||||
"# Heading 1\n" +
|
||||
"## Heading 2\n" +
|
||||
"### Heading 3\n" +
|
||||
"#### Heading 4";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
builder.appendFactory(Heading.class, (configuration, props) -> {
|
||||
// here you can also inspect heading level
|
||||
final int level = CoreProps.HEADING_LEVEL.require(props);
|
||||
final int color;
|
||||
if (level == 1) {
|
||||
color = Color.RED;
|
||||
} else if (level == 2) {
|
||||
color = Color.GREEN;
|
||||
} else {
|
||||
color = Color.BLUE;
|
||||
}
|
||||
return new ForegroundColorSpan(color);
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -9,10 +9,10 @@ import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.BlockHandlerDef;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629125924",
|
||||
@ -20,7 +20,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Process padding (spacing) after heading with a " +
|
||||
"`BlockHandler`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.block, Tags.spacing, Tags.padding, Tags.heading, Tags.rendering}
|
||||
tags = {Tag.block, Tag.spacing, Tag.padding, Tag.heading, Tag.rendering}
|
||||
)
|
||||
public class HeadingNoSpaceBlockHandlerSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -7,19 +7,19 @@ import org.commonmark.node.Heading;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.core.MarkwonTheme;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629125622",
|
||||
title = "Heading no padding",
|
||||
description = "Do not add a new line after heading node",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.spacing, Tags.padding, Tags.spacing, Tags.rendering}
|
||||
tags = {Tag.spacing, Tag.padding, Tag.spacing, Tag.rendering}
|
||||
)
|
||||
public class HeadingNoSpaceSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629170857",
|
||||
title = "Inline parsing without defaults",
|
||||
description = "Configure inline parser plugin to **not** have any **inline** parsing",
|
||||
artifacts = {MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.parsing}
|
||||
tags = {Tag.parsing}
|
||||
)
|
||||
public class InlinePluginNoDefaultsSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,73 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.Spanned;
|
||||
import android.widget.TextView;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.AsyncDrawableScheduler;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200826084338",
|
||||
title = "Justify text",
|
||||
description = "Justify text with `justificationMode` argument on Oreo (>= 26)",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class JustifyModeSample extends MarkwonTextViewSample {
|
||||
@SuppressLint("WrongConstant")
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
/*
|
||||
nice, API 29 though
|
||||
```
|
||||
Error: Must be one of: LineBreaker.JUSTIFICATION_MODE_NONE, LineBreaker.JUSTIFICATION_MODE_INTER_WORD [WrongConstant]
|
||||
```
|
||||
*/
|
||||
textView.setJustificationMode(Layout.JUSTIFICATION_MODE_INTER_WORD);
|
||||
}
|
||||
|
||||
final String md = "" +
|
||||
"# Justify\n\n" +
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis rutrum orci at aliquet dapibus. Quisque laoreet fermentum bibendum. Suspendisse euismod nisl vel sapien viverra faucibus. Nulla vel neque volutpat, egestas dui ac, consequat elit. Donec et interdum massa. Quisque porta ornare posuere. Nam at ante a felis facilisis tempus eu et erat. Curabitur auctor mauris eget purus iaculis vulputate.\n\n" +
|
||||
"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis rutrum orci at aliquet dapibus. Quisque laoreet fermentum bibendum. Suspendisse euismod nisl vel sapien viverra faucibus. Nulla vel neque volutpat, egestas dui ac, consequat elit. Donec et interdum massa. Quisque porta ornare posuere. Nam at ante a felis facilisis tempus eu et erat. Curabitur auctor mauris eget purus iaculis vulputate.\n\n" +
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis rutrum orci at aliquet dapibus. Quisque laoreet fermentum bibendum. Suspendisse euismod nisl vel sapien viverra faucibus. Nulla vel neque volutpat, egestas dui ac, consequat elit. Donec et interdum massa. **Quisque porta ornare posuere.** Nam at ante a felis facilisis tempus eu et erat. Curabitur auctor mauris eget purus iaculis vulputate.\n\n" +
|
||||
"";
|
||||
|
||||
if (false) {
|
||||
// specify bufferType to make justificationMode argument be ignored
|
||||
// Actually just calling method with BufferType argument would make
|
||||
// justification gone
|
||||
textView.setText(md, TextView.BufferType.SPANNABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.build();
|
||||
|
||||
if (true) {
|
||||
final Spanned spanned = markwon.toMarkdown(md);
|
||||
|
||||
// NB! the call to `setText` without arguments
|
||||
textView.setText(spanned);
|
||||
|
||||
// if a plugin relies on `afterSetText` then we must manually call it,
|
||||
// for example images are scheduled this way:
|
||||
AsyncDrawableScheduler.schedule(textView);
|
||||
return;
|
||||
}
|
||||
|
||||
// cannot use that
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -15,20 +15,20 @@ import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.Prop;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.core.spans.BulletListItemSpan;
|
||||
import io.noties.markwon.core.spans.OrderedListItemSpan;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629130954",
|
||||
title = "Letter ordered list",
|
||||
description = "Render bullet list inside an ordered list with letters instead of bullets",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.rendering, Tags.plugin, Tags.lists}
|
||||
tags = {Tag.rendering, Tag.plugin, Tag.lists}
|
||||
)
|
||||
public class LetterOrderedListSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -11,16 +11,16 @@ import org.commonmark.node.Link;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200702101224",
|
||||
title = "Remove link underline",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.links, Tags.rendering, Tags.span}
|
||||
tags = {Tag.links, Tag.rendering, Tag.span}
|
||||
)
|
||||
public class LinkRemoveUnderlineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -16,20 +16,20 @@ import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.LinkResolver;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.core.MarkwonTheme;
|
||||
import io.noties.markwon.core.spans.LinkSpan;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629122230",
|
||||
title = "Obtain link title",
|
||||
description = "Obtain title (text) of clicked link, `[title](#destination)`",
|
||||
artifacts = {MarkwonArtifact.CORE},
|
||||
tags = {Tags.links, Tags.span}
|
||||
tags = {Tag.links, Tag.span}
|
||||
)
|
||||
public class LinkTitleSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,17 +1,17 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629124005",
|
||||
title = "Links without scheme",
|
||||
description = "Links without scheme are considered to be `https`",
|
||||
artifacts = {MarkwonArtifact.CORE},
|
||||
tags = {Tags.links, Tags.defaults}
|
||||
tags = {Tag.links, Tag.defaults}
|
||||
)
|
||||
public class LinkWithoutSchemeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -8,19 +8,19 @@ import java.util.Collections;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629171212",
|
||||
title = "No parsing",
|
||||
description = "All commonmark parsing is disabled (both inlines and blocks)",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.parsing, Tags.rendering}
|
||||
tags = {Tag.parsing, Tag.rendering}
|
||||
)
|
||||
public class NoParsingSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,48 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20201203221806",
|
||||
title = "Ordered list numbers",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class OrderedListNumbersSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "# Ordered lists\n\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"1. hello there\n" +
|
||||
"1. hello there and much much more, this text just goes and goes, and should it stop, we' know it\n" +
|
||||
"1. okay, np\n" +
|
||||
"";
|
||||
|
||||
final Markwon markwon = Markwon.create(context);
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -10,17 +10,17 @@ import org.commonmark.node.Paragraph;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629122647",
|
||||
title = "Paragraph style",
|
||||
description = "Apply a style (via span) to a paragraph",
|
||||
artifacts = {MarkwonArtifact.CORE},
|
||||
tags = {Tags.paragraph, Tags.style, Tags.span}
|
||||
tags = {Tag.paragraph, Tag.style, Tag.span}
|
||||
)
|
||||
public class ParagraphSpanStyle extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -9,7 +9,6 @@ import io.noties.markwon.MarkwonConfiguration;
|
||||
import io.noties.markwon.PrecomputedFutureTextSetterCompat;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.readme.GithubImageDestinationProcessor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonRecyclerViewSample;
|
||||
import io.noties.markwon.app.utils.SampleUtilsKtKt;
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||
@ -19,6 +18,7 @@ import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.recycler.MarkwonAdapter;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200702092446",
|
||||
@ -26,7 +26,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Usage of `PrecomputedFutureTextSetterCompat` " +
|
||||
"inside a `RecyclerView` with appcompat",
|
||||
artifacts = {MarkwonArtifact.RECYCLER},
|
||||
tags = {Tags.recyclerView, Tags.precomputedText}
|
||||
tags = {Tag.recyclerView, Tag.precomputedText}
|
||||
)
|
||||
public class PrecomputedFutureSample extends MarkwonRecyclerViewSample {
|
||||
@Override
|
||||
|
@ -4,17 +4,17 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.PrecomputedTextSetterCompat;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200702091654",
|
||||
title = "PrecomputedTextSetterCompat",
|
||||
description = "`TextSetter` to use `PrecomputedTextSetterCompat`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.precomputedText
|
||||
tags = Tag.precomputedText
|
||||
)
|
||||
public class PrecomputedSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -11,19 +11,18 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.ext.tables.TablePlugin;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629161505",
|
||||
title = "Read more plugin",
|
||||
description = "Plugin that adds expand/collapse (\"show all\"/\"show less\")",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.plugin}
|
||||
tags = {Tag.plugin}
|
||||
)
|
||||
public class ReadMorePluginSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -12,7 +12,6 @@ import io.noties.markwon.MarkwonConfiguration;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.readme.GithubImageDestinationProcessor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonRecyclerViewSample;
|
||||
import io.noties.markwon.app.utils.SampleUtilsKtKt;
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||
@ -25,13 +24,14 @@ import io.noties.markwon.recycler.table.TableEntry;
|
||||
import io.noties.markwon.recycler.table.TableEntryPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200702101750",
|
||||
title = "RecyclerView",
|
||||
description = "Usage with `RecyclerView`",
|
||||
artifacts = {MarkwonArtifact.RECYCLER, MarkwonArtifact.RECYCLER_TABLE},
|
||||
tags = Tags.recyclerView
|
||||
tags = Tag.recyclerView
|
||||
)
|
||||
public class RecyclerSample extends MarkwonRecyclerViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,126 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.Spannable;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
import io.noties.markwon.utils.ColorUtils;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200813145316",
|
||||
title = "Reddit spoiler",
|
||||
description = "An attempt to implement Reddit spoiler syntax `>! !<`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.parsing
|
||||
)
|
||||
public class RedditSpoilerSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Reddit spolier\n\n" +
|
||||
"Hello >!ugly so **ugly** !<, how are you?\n\n" +
|
||||
">!a blockquote?!< should not be >!present!< yeah" +
|
||||
"";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new RedditSpoilerPlugin())
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
||||
|
||||
class RedditSpoilerPlugin extends AbstractMarkwonPlugin {
|
||||
|
||||
private static final Pattern RE = Pattern.compile(">!.+?!<");
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String processMarkdown(@NonNull String markdown) {
|
||||
// replace all `>!` with `>!` so no blockquote would be parsed (when spoiler starts at new line)
|
||||
return markdown.replaceAll(">!", ">!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeSetText(@NonNull TextView textView, @NonNull Spanned markdown) {
|
||||
applySpoilerSpans((Spannable) markdown);
|
||||
}
|
||||
|
||||
private static void applySpoilerSpans(@NonNull Spannable spannable) {
|
||||
final String text = spannable.toString();
|
||||
final Matcher matcher = RE.matcher(text);
|
||||
|
||||
while (matcher.find()) {
|
||||
|
||||
final RedditSpoilerSpan spoilerSpan = new RedditSpoilerSpan();
|
||||
final ClickableSpan clickableSpan = new ClickableSpan() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
spoilerSpan.setRevealed(true);
|
||||
widget.postInvalidateOnAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
// no op
|
||||
}
|
||||
};
|
||||
|
||||
final int s = matcher.start();
|
||||
final int e = matcher.end();
|
||||
spannable.setSpan(spoilerSpan, s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(clickableSpan, s, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
|
||||
// we also can hide original syntax
|
||||
spannable.setSpan(new HideSpoilerSyntaxSpan(), s, s + 2, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
spannable.setSpan(new HideSpoilerSyntaxSpan(), e - 2, e, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
}
|
||||
|
||||
private static class RedditSpoilerSpan extends CharacterStyle {
|
||||
|
||||
private boolean revealed;
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint tp) {
|
||||
if (!revealed) {
|
||||
// use the same text color
|
||||
tp.bgColor = Color.BLACK;
|
||||
tp.setColor(Color.BLACK);
|
||||
} else {
|
||||
// for example keep a bit of black background to remind that it is a spoiler
|
||||
tp.bgColor = ColorUtils.applyAlpha(Color.BLACK, 25);
|
||||
}
|
||||
}
|
||||
|
||||
public void setRevealed(boolean revealed) {
|
||||
this.revealed = revealed;
|
||||
}
|
||||
}
|
||||
|
||||
// we also could make text size smaller (but then MetricAffectingSpan should be used)
|
||||
private static class HideSpoilerSyntaxSpan extends CharacterStyle {
|
||||
|
||||
@Override
|
||||
public void updateDrawState(TextPaint tp) {
|
||||
// set transparent color
|
||||
tp.setColor(0);
|
||||
}
|
||||
}
|
||||
}
|
@ -4,12 +4,12 @@ import android.graphics.Color;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.spans.EmphasisSpan;
|
||||
import io.noties.markwon.core.spans.StrongEmphasisSpan;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
import io.noties.markwon.simple.ext.SimpleExtPlugin;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
@ -17,7 +17,7 @@ import io.noties.markwon.simple.ext.SimpleExtPlugin;
|
||||
title = "Delimiter processor simple-ext",
|
||||
description = "Custom delimiter processor implemented with a `SimpleExtPlugin`",
|
||||
artifacts = MarkwonArtifact.SIMPLE_EXT,
|
||||
tags = Tags.parsing
|
||||
tags = Tag.parsing
|
||||
)
|
||||
public class SimpleExtensionSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -2,17 +2,17 @@ package io.noties.markwon.app.samples;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629125040",
|
||||
title = "Soft break new line",
|
||||
description = "Add a new line for a markdown soft-break node",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.newLine, Tags.softBreak}
|
||||
tags = {Tag.newLine, Tag.softBreak}
|
||||
)
|
||||
public class SoftBreakAddsNewLineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,10 +1,10 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629124706",
|
||||
@ -12,7 +12,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "By default a soft break (`\n`) will " +
|
||||
"add a space character instead of new line",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.newLine, Tags.softBreak, Tags.defaults}
|
||||
tags = {Tag.newLine, Tag.softBreak, Tag.defaults}
|
||||
)
|
||||
public class SoftBreakAddsSpace extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,63 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.node.ThematicBreak;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.BlockHandlerDef;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200813154415",
|
||||
title = "Thematic break bottom margin",
|
||||
description = "Do not add a new line after thematic break (with the `BlockHandler`)",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class ThematicBreakBottomMarginSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Thematic break and margin\n\n" +
|
||||
"So, what if....\n\n" +
|
||||
"---\n\n" +
|
||||
"And **now**";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.blockHandler(new BlockHandlerDef() {
|
||||
@Override
|
||||
public void blockStart(@NonNull MarkwonVisitor visitor, @NonNull Node node) {
|
||||
// also can control block start
|
||||
super.blockStart(visitor, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void blockEnd(@NonNull MarkwonVisitor visitor, @NonNull Node node) {
|
||||
if (visitor.hasNext(node)) {
|
||||
visitor.ensureNewLine();
|
||||
|
||||
// thematic break won't have a new line
|
||||
// similarly you can control other blocks
|
||||
if (!(node instanceof ThematicBreak)) {
|
||||
visitor.forceNewLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -6,18 +6,18 @@ import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.BuildConfig
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.image.ImagesPlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200627074017",
|
||||
title = "Markdown in Toast (with dynamic content)",
|
||||
description = "Display markdown in a `android.widget.Toast` with dynamic content (image)",
|
||||
artifacts = [MarkwonArtifact.CORE, MarkwonArtifact.IMAGE],
|
||||
tags = [Tags.toast, Tags.hack]
|
||||
tags = [Tag.toast, Tag.hack]
|
||||
)
|
||||
class ToastDynamicContentSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
@ -2,17 +2,17 @@ package io.noties.markwon.app.samples
|
||||
|
||||
import android.widget.Toast
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200627072642",
|
||||
title = "Markdown in Toast",
|
||||
description = "Display _static_ markdown content in a `android.widget.Toast`",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tags.toast]
|
||||
tags = [Tag.toast]
|
||||
)
|
||||
class ToastSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
@ -0,0 +1,29 @@
|
||||
package io.noties.markwon.app.samples.basics;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20210118154116",
|
||||
title = "One line text",
|
||||
description = "Single line text without markdown markup",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class OneLineNoMarkdownSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
textView.setBackgroundColor(0x40ff0000);
|
||||
|
||||
final String md = " Demo text ";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
package io.noties.markwon.app.samples.basics
|
||||
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200626152255",
|
||||
title = "Simple",
|
||||
description = "The most primitive and simple way to apply markdown to a `TextView`",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tags.basics]
|
||||
tags = [Tag.basics]
|
||||
)
|
||||
class Simple : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
@ -2,11 +2,11 @@ package io.noties.markwon.app.samples.basics
|
||||
|
||||
import android.text.Spanned
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.core.CorePlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
import org.commonmark.node.Node
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
@ -14,7 +14,7 @@ import org.commonmark.node.Node
|
||||
title = "Simple with walk-through",
|
||||
description = "Walk-through for simple use case",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tags.basics]
|
||||
tags = [Tag.basics]
|
||||
)
|
||||
class SimpleWalkthrough : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
@ -8,7 +8,6 @@ import android.text.style.MetricAffectingSpan;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.core.spans.StrongEmphasisSpan;
|
||||
import io.noties.markwon.editor.AbstractEditHandler;
|
||||
@ -18,6 +17,7 @@ import io.noties.markwon.editor.MarkwonEditorUtils;
|
||||
import io.noties.markwon.editor.PersistedSpans;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629165136",
|
||||
@ -25,7 +25,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Additional _edit_ span (span that is present in " +
|
||||
"`EditText` along with punctuation",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor, Tags.span}
|
||||
tags = {Tag.editor, Tag.span}
|
||||
)
|
||||
public class EditorAdditionalEditSpan extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -1,20 +1,20 @@
|
||||
package io.noties.markwon.app.samples.editor;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629165347",
|
||||
title = "Additional plugin",
|
||||
description = "Additional plugin for editor",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER, MarkwonArtifact.EXT_STRIKETHROUGH},
|
||||
tags = {Tags.editor}
|
||||
tags = {Tag.editor}
|
||||
)
|
||||
public class EditorAdditionalPluginSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -3,19 +3,19 @@ package io.noties.markwon.app.samples.editor;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629164627",
|
||||
title = "Custom punctuation span",
|
||||
description = "Custom span for punctuation in editor",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor, Tags.span}
|
||||
tags = {Tag.editor, Tag.span}
|
||||
)
|
||||
public class EditorCustomPunctuationSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -3,20 +3,20 @@ package io.noties.markwon.app.samples.editor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.HeadingEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630113954",
|
||||
title = "Heading edit handler",
|
||||
description = "Handling of heading node in editor",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor}
|
||||
tags = {Tag.editor}
|
||||
)
|
||||
public class EditorHeadingSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -12,11 +12,10 @@ import java.util.concurrent.Executors;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.BlockQuoteEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.CodeEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.LinkEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.StrikethroughEditHandler;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
@ -30,13 +29,14 @@ import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.linkify.LinkifyPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629165920",
|
||||
title = "Multiple edit spans",
|
||||
description = "Additional multiple edit spans for editor",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor}
|
||||
tags = {Tag.editor}
|
||||
)
|
||||
public class EditorMultipleEditSpansSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -11,12 +11,12 @@ import java.util.regex.Pattern;
|
||||
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629170348",
|
||||
@ -25,7 +25,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
"in order to add a _continuation_, for example adding a new " +
|
||||
"bullet list item if current line starts with one",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor}
|
||||
tags = {Tag.editor}
|
||||
)
|
||||
public class EditorNewLineContinuationSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -3,12 +3,12 @@ package io.noties.markwon.app.samples.editor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629164422",
|
||||
@ -16,7 +16,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Editor functionality with highlight " +
|
||||
"taking place in another thread",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor}
|
||||
tags = {Tag.editor}
|
||||
)
|
||||
public class EditorPreRenderSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package io.noties.markwon.app.samples.editor;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629164227",
|
||||
title = "Simple editor",
|
||||
description = "Simple usage of editor with markdown highlight",
|
||||
artifacts = {MarkwonArtifact.EDITOR, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.editor}
|
||||
tags = {Tag.editor}
|
||||
)
|
||||
public class EditorSimpleSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,134 @@
|
||||
package io.noties.markwon.app.samples.editor;
|
||||
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.text.style.ReplacementSpan;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin;
|
||||
import io.noties.markwon.app.samples.editor.shared.BlockQuoteEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.CodeEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.HeadingEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.LinkEditHandler;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.StrikethroughEditHandler;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
import io.noties.markwon.editor.PersistedSpans;
|
||||
import io.noties.markwon.editor.handler.EmphasisEditHandler;
|
||||
import io.noties.markwon.editor.handler.StrongEmphasisEditHandler;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200908133515",
|
||||
title = "WYSIWG editor",
|
||||
description = "A possible direction to implement what-you-see-is-what-you-get editor",
|
||||
artifacts = MarkwonArtifact.EDITOR,
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class WYSIWYGEditorSample extends MarkwonEditTextSample {
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
// when automatic line break is inserted and text is inside margin span (blockquote, list, etc)
|
||||
// be prepared to encounter selection bugs (selection would be drawn at the place as is no margin
|
||||
// span is present)
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(SoftBreakAddsNewLinePlugin.create())
|
||||
.build();
|
||||
|
||||
final MarkwonEditor editor = MarkwonEditor.builder(markwon)
|
||||
.punctuationSpan(HidePunctuationSpan.class, new PersistedSpans.SpanFactory<HidePunctuationSpan>() {
|
||||
@NonNull
|
||||
@Override
|
||||
public HidePunctuationSpan create() {
|
||||
return new HidePunctuationSpan();
|
||||
}
|
||||
})
|
||||
.useEditHandler(new EmphasisEditHandler())
|
||||
.useEditHandler(new StrongEmphasisEditHandler())
|
||||
.useEditHandler(new StrikethroughEditHandler())
|
||||
.useEditHandler(new CodeEditHandler())
|
||||
.useEditHandler(new BlockQuoteEditHandler())
|
||||
.useEditHandler(new LinkEditHandler(new LinkEditHandler.OnClick() {
|
||||
@Override
|
||||
public void onClick(@NonNull View widget, @NonNull String link) {
|
||||
Debug.e("clicked: %s", link);
|
||||
}
|
||||
}))
|
||||
.useEditHandler(new HeadingEditHandler())
|
||||
.build();
|
||||
|
||||
// for links to be clickable
|
||||
// NB! markwon MovementMethodPlugin cannot be used here as editor do not execute `beforeSetText`)
|
||||
editText.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
editText.addTextChangedListener(MarkwonEditorTextWatcher.withProcess(editor));
|
||||
}
|
||||
|
||||
private static class HidePunctuationSpan extends ReplacementSpan {
|
||||
|
||||
@Override
|
||||
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, @Nullable Paint.FontMetricsInt fm) {
|
||||
// last space (which is swallowed until next non-space character appears)
|
||||
// block quote
|
||||
// code tick
|
||||
|
||||
// Debug.i("text: '%s', %d-%d (%d)", text.subSequence(start, end), start, end, text.length());
|
||||
if (end == text.length()) {
|
||||
// TODO: find first non-space character (not just first one because commonmark allows
|
||||
// arbitrary (0-3) white spaces before content starts
|
||||
|
||||
// TODO: if all white space - render?
|
||||
final char c = text.charAt(start);
|
||||
if ('#' == c
|
||||
|| '>' == c
|
||||
|| '-' == c // TODO: not thematic break
|
||||
|| '+' == c
|
||||
// `*` is fine but only for a list
|
||||
|| isBulletList(text, c, start, end)
|
||||
|| Character.isDigit(c) // assuming ordered list (replacement should only happen for ordered lists)
|
||||
|| Character.isWhitespace(c)) {
|
||||
return (int) (paint.measureText(text, start, end) + 0.5F);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) {
|
||||
// will be called only when getSize is not 0 (and if it was once reported as 0...)
|
||||
if (end == text.length()) {
|
||||
|
||||
// if first non-space is `*` then check for is bullet
|
||||
// else `**` would be still rendered at the end of the emphasis
|
||||
if (text.charAt(start) == '*'
|
||||
&& !isBulletList(text, '*', start, end)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: inline code last tick received here, handle it (do not highlight)
|
||||
// why can't we have reported width in this method for supplied text?
|
||||
|
||||
// let's use color to make it distinct from the rest of the text for demonstration purposes
|
||||
paint.setColor(0xFFff0000);
|
||||
|
||||
canvas.drawText(text, start, end, x, y, paint);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isBulletList(@NonNull CharSequence text, char firstChar, int start, int end) {
|
||||
return '*' == firstChar
|
||||
&& ((end - start == 1) || (Character.isWhitespace(text.charAt(start + 1))));
|
||||
}
|
||||
}
|
||||
}
|
@ -13,20 +13,20 @@ import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonConfiguration;
|
||||
import io.noties.markwon.RenderProps;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlTag;
|
||||
import io.noties.markwon.html.tag.SimpleTagHandler;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630114630",
|
||||
title = "Align HTML tag",
|
||||
description = "Implement custom HTML tag handling",
|
||||
artifacts = MarkwonArtifact.HTML,
|
||||
tags = {Tags.rendering, Tags.span, Tags.html}
|
||||
tags = {Tag.rendering, Tag.span, Tag.html}
|
||||
)
|
||||
public class HtmlAlignSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -12,7 +12,6 @@ import io.noties.debug.Debug;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.SpannableBuilder;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.html.shared.IFrameHtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
@ -22,13 +21,14 @@ import io.noties.markwon.html.TagHandler;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630120101",
|
||||
title = "Center HTML tag",
|
||||
description = "Handling of `center` HTML tag",
|
||||
artifacts = {MarkwonArtifact.HTML, MarkwonArtifact.IMAGE},
|
||||
tags = {Tags.rendering, Tags.html}
|
||||
tags = {Tag.rendering, Tag.html}
|
||||
)
|
||||
public class HtmlCenterTagSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,99 @@
|
||||
package io.noties.markwon.app.samples.html;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonConfiguration;
|
||||
import io.noties.markwon.RenderProps;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.CssInlineStyleParser;
|
||||
import io.noties.markwon.html.CssProperty;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlTag;
|
||||
import io.noties.markwon.html.tag.SimpleTagHandler;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20210118155530",
|
||||
title = "CSS attributes in HTML",
|
||||
description = "Parse CSS attributes of HTML tags with `CssInlineStyleParser`",
|
||||
artifacts = MarkwonArtifact.HTML,
|
||||
tags = Tag.html
|
||||
)
|
||||
public class HtmlCssStyleParserSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
final String md = "# CSS\n\n" +
|
||||
"<span style=\"background-color: #ff0000;\">this has red background</span> and then\n\n" +
|
||||
"this <span style=\"color: #00ff00;\">is green</span>";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(HtmlPlugin.create(plugin -> plugin.addHandler(new SpanTagHandler())))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
|
||||
private static class SpanTagHandler extends SimpleTagHandler {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps renderProps, @NonNull HtmlTag tag) {
|
||||
final String style = tag.attributes().get("style");
|
||||
if (TextUtils.isEmpty(style)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int color = 0;
|
||||
int backgroundColor = 0;
|
||||
|
||||
for (CssProperty property : CssInlineStyleParser.create().parse(style)) {
|
||||
switch (property.key()) {
|
||||
|
||||
case "color":
|
||||
color = Color.parseColor(property.value());
|
||||
break;
|
||||
|
||||
case "background-color":
|
||||
backgroundColor = Color.parseColor(property.value());
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.i("unexpected CSS property: %s", property);
|
||||
}
|
||||
}
|
||||
|
||||
final List<Object> spans = new ArrayList<>(3);
|
||||
|
||||
if (color != 0) {
|
||||
spans.add(new ForegroundColorSpan(color));
|
||||
}
|
||||
if (backgroundColor != 0) {
|
||||
spans.add(new BackgroundColorSpan(backgroundColor));
|
||||
}
|
||||
|
||||
return spans.toArray();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Collection<String> supportedTags() {
|
||||
return Collections.singleton("span");
|
||||
}
|
||||
}
|
||||
}
|
@ -30,7 +30,6 @@ import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.SpannableBuilder;
|
||||
import io.noties.markwon.app.BuildConfig;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonSample;
|
||||
import io.noties.markwon.core.MarkwonTheme;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
@ -40,6 +39,7 @@ import io.noties.markwon.html.TagHandler;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
import io.noties.markwon.utils.LeadingMarginUtils;
|
||||
import io.noties.markwon.utils.NoCopySpannableFactory;
|
||||
|
||||
@ -48,7 +48,7 @@ import io.noties.markwon.utils.NoCopySpannableFactory;
|
||||
title = "Details HTML tag",
|
||||
description = "Handling of `details` HTML tag",
|
||||
artifacts = {MarkwonArtifact.HTML, MarkwonArtifact.IMAGE},
|
||||
tags = {Tags.image, Tags.rendering, Tags.html}
|
||||
tags = {Tag.image, Tag.rendering, Tag.html}
|
||||
)
|
||||
public class HtmlDetailsSample extends MarkwonSample {
|
||||
|
||||
|
@ -4,17 +4,17 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630171424",
|
||||
title = "Disable HTML",
|
||||
description = "Disable HTML via replacing special `<` and `>` symbols",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.html, Tags.rendering, Tags.parsing, Tags.plugin}
|
||||
tags = {Tag.html, Tag.rendering, Tag.parsing, Tag.plugin}
|
||||
)
|
||||
public class HtmlDisableSanitizeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -4,13 +4,13 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.HtmlEmptyTagReplacement;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlTag;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630115725",
|
||||
@ -19,7 +19,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
"in case of self-closed HTML tags or tags without content (closed " +
|
||||
"right after opened)",
|
||||
artifacts = MarkwonArtifact.HTML,
|
||||
tags = {Tags.rendering, Tags.html}
|
||||
tags = {Tag.rendering, Tag.html}
|
||||
)
|
||||
public class HtmlEmptyTagReplacementSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -13,7 +13,6 @@ import java.util.Collections;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlTag;
|
||||
@ -21,6 +20,7 @@ import io.noties.markwon.html.MarkwonHtmlRenderer;
|
||||
import io.noties.markwon.html.TagHandler;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630115103",
|
||||
@ -28,7 +28,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Custom HTML tag implementation " +
|
||||
"that _enhances_ a part of text given start and end indices",
|
||||
artifacts = MarkwonArtifact.HTML,
|
||||
tags = {Tags.rendering, Tags.span, Tags.html}
|
||||
tags = {Tag.rendering, Tag.span, Tag.html}
|
||||
)
|
||||
public class HtmlEnhanceSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,20 +1,20 @@
|
||||
package io.noties.markwon.app.samples.html;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.html.shared.IFrameHtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630115521",
|
||||
title = "IFrame HTML tag",
|
||||
description = "Handling of `iframe` HTML tag",
|
||||
artifacts = {MarkwonArtifact.HTML, MarkwonArtifact.IMAGE},
|
||||
tags = {Tags.image, Tags.rendering, Tags.html}
|
||||
tags = {Tag.image, Tag.rendering, Tag.html}
|
||||
)
|
||||
public class HtmlIFrameSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package io.noties.markwon.app.samples.html;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630115300",
|
||||
title = "Html images",
|
||||
description = "Usage of HTML images",
|
||||
artifacts = {MarkwonArtifact.HTML, MarkwonArtifact.IMAGE},
|
||||
tags = {Tags.image, Tags.rendering, Tags.html}
|
||||
tags = {Tag.image, Tag.rendering, Tag.html}
|
||||
)
|
||||
public class HtmlImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -12,7 +12,6 @@ import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.SpannableBuilder;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.html.HtmlTag;
|
||||
@ -20,6 +19,7 @@ import io.noties.markwon.html.MarkwonHtmlRenderer;
|
||||
import io.noties.markwon.html.TagHandler;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630114923",
|
||||
@ -27,7 +27,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "Implementation of a custom HTML tag handler " +
|
||||
"that assigns each character a random size",
|
||||
artifacts = MarkwonArtifact.HTML,
|
||||
tags = {Tags.rendering, Tags.span, Tags.html}
|
||||
tags = {Tag.rendering, Tag.span, Tag.html}
|
||||
)
|
||||
public class HtmlRandomCharSize extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,57 @@
|
||||
package io.noties.markwon.app.samples.html
|
||||
|
||||
import android.text.style.URLSpan
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.MarkwonVisitor
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.html.HtmlPlugin
|
||||
import io.noties.markwon.html.HtmlTag
|
||||
import io.noties.markwon.html.MarkwonHtmlRenderer
|
||||
import io.noties.markwon.html.TagHandler
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20210201140501",
|
||||
title = "Inspect text",
|
||||
description = "Inspect text content of a `HTML` node",
|
||||
artifacts = [MarkwonArtifact.HTML],
|
||||
tags = [Tag.html]
|
||||
)
|
||||
class InspectHtmlTextSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
val md = """
|
||||
<p>lorem ipsum</p>
|
||||
<div class="custom-youtube-player">https://www.youtube.com/watch?v=abcdefgh</div>
|
||||
""".trimIndent()
|
||||
|
||||
val markwon = Markwon.builder(context)
|
||||
.usePlugin(HtmlPlugin.create {
|
||||
it.addHandler(DivHandler())
|
||||
})
|
||||
.build()
|
||||
|
||||
markwon.setMarkdown(textView, md)
|
||||
}
|
||||
|
||||
class DivHandler : TagHandler() {
|
||||
override fun handle(visitor: MarkwonVisitor, renderer: MarkwonHtmlRenderer, tag: HtmlTag) {
|
||||
val attr = tag.attributes()["class"] ?: return
|
||||
if (attr.contains(CUSTOM_CLASS)) {
|
||||
val text = visitor.builder().substring(tag.start(), tag.end())
|
||||
visitor.builder().setSpan(
|
||||
URLSpan(text),
|
||||
tag.start(),
|
||||
tag.end()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun supportedTags(): Collection<String> = setOf("div")
|
||||
|
||||
companion object {
|
||||
const val CUSTOM_CLASS = "custom-youtube-player"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package io.noties.markwon.app.samples.image
|
||||
|
||||
import android.view.View
|
||||
import io.noties.markwon.AbstractMarkwonPlugin
|
||||
import io.noties.markwon.LinkResolver
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.MarkwonConfiguration
|
||||
import io.noties.markwon.MarkwonSpansFactory
|
||||
import io.noties.markwon.app.readme.GithubImageDestinationProcessor
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.app.utils.loadReadMe
|
||||
import io.noties.markwon.core.spans.LinkSpan
|
||||
import io.noties.markwon.image.ImageProps
|
||||
import io.noties.markwon.image.ImagesPlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
import org.commonmark.node.Image
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20201221130230",
|
||||
title = "Click images",
|
||||
description = "Make _all_ images clickable (to open in a gallery, etc)",
|
||||
artifacts = [MarkwonArtifact.IMAGE],
|
||||
tags = [Tag.rendering, Tag.image]
|
||||
)
|
||||
class ClickImageSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
|
||||
val md = loadReadMe(context)
|
||||
|
||||
// please note that if an image is already inside a link, original link would be overriden
|
||||
|
||||
val markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||
builder.imageDestinationProcessor(GithubImageDestinationProcessor())
|
||||
}
|
||||
})
|
||||
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||
override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) {
|
||||
builder.appendFactory(Image::class.java) { configuration, props ->
|
||||
|
||||
// this is the destination of image, you can additionally process it
|
||||
val url = ImageProps.DESTINATION.require(props)
|
||||
|
||||
LinkSpan(
|
||||
configuration.theme(),
|
||||
url,
|
||||
ImageLinkResolver(configuration.linkResolver())
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
.build()
|
||||
|
||||
markwon.setMarkdown(textView, md)
|
||||
}
|
||||
|
||||
class ImageLinkResolver(val original: LinkResolver) : LinkResolver {
|
||||
override fun resolve(view: View, link: String) {
|
||||
// decide if you want to open gallery or anything else,
|
||||
// here we just pass to original
|
||||
if (false) {
|
||||
// do your thing
|
||||
} else {
|
||||
// just use original
|
||||
original.resolve(view, link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package io.noties.markwon.app.samples.image
|
||||
|
||||
import coil.ImageLoader
|
||||
import coil.request.Disposable
|
||||
import coil.request.ImageRequest
|
||||
import coil.transform.CircleCropTransformation
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.image.AsyncDrawable
|
||||
import io.noties.markwon.image.coil.CoilImagesPlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200826101209",
|
||||
title = "Coil image",
|
||||
artifacts = [MarkwonArtifact.IMAGE_COIL],
|
||||
tags = [Tag.image]
|
||||
)
|
||||
class CoilImageSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
val md = """
|
||||
# H1
|
||||
## H2
|
||||
### H3
|
||||
#### H4
|
||||
##### H5
|
||||
|
||||
> a quote
|
||||
|
||||
+ one
|
||||
- two
|
||||
* three
|
||||
|
||||
1. one
|
||||
1. two
|
||||
1. three
|
||||
|
||||
---
|
||||
|
||||
# Images
|
||||
|
||||

|
||||
""".trimIndent()
|
||||
|
||||
// pick one
|
||||
val markwon = Markwon.builder(context)
|
||||
// .usePlugin(coilPlugin1)
|
||||
// .usePlugin(coilPlugin2)
|
||||
.usePlugin(coilPlugin3)
|
||||
.build()
|
||||
|
||||
markwon.setMarkdown(textView, md)
|
||||
}
|
||||
|
||||
val coilPlugin1: CoilImagesPlugin
|
||||
get() = CoilImagesPlugin.create(context)
|
||||
|
||||
val coilPlugin2: CoilImagesPlugin
|
||||
get() = CoilImagesPlugin.create(context, imageLoader)
|
||||
|
||||
val coilPlugin3: CoilImagesPlugin
|
||||
get() {
|
||||
val loader = imageLoader
|
||||
return CoilImagesPlugin.create(
|
||||
object : CoilImagesPlugin.CoilStore {
|
||||
override fun load(drawable: AsyncDrawable): ImageRequest {
|
||||
return ImageRequest.Builder(context)
|
||||
.defaults(loader.defaults)
|
||||
.data(drawable.destination)
|
||||
.crossfade(true)
|
||||
.transformations(CircleCropTransformation())
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun cancel(disposable: Disposable) {
|
||||
disposable.dispose()
|
||||
}
|
||||
},
|
||||
loader
|
||||
)
|
||||
}
|
||||
|
||||
val imageLoader: ImageLoader
|
||||
get() = ImageLoader.Builder(context)
|
||||
.apply {
|
||||
availableMemoryPercentage(0.5)
|
||||
bitmapPoolPercentage(0.5)
|
||||
crossfade(true)
|
||||
}
|
||||
.build()
|
||||
}
|
@ -1,27 +1,26 @@
|
||||
package io.noties.markwon.app.samples.image
|
||||
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import coil.ImageLoader
|
||||
import coil.request.LoadRequest
|
||||
import coil.request.RequestDisposable
|
||||
import coil.Coil
|
||||
import coil.request.Disposable
|
||||
import coil.request.ImageRequest
|
||||
import coil.transform.RoundedCornersTransformation
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.app.R
|
||||
import io.noties.markwon.app.sample.Tags
|
||||
import io.noties.markwon.app.sample.ui.MarkwonRecyclerViewSample
|
||||
import io.noties.markwon.image.AsyncDrawable
|
||||
import io.noties.markwon.image.coil.CoilImagesPlugin
|
||||
import io.noties.markwon.recycler.MarkwonAdapter
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import okhttp3.OkHttpClient
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200803132053",
|
||||
title = "Coil inside RecyclerView",
|
||||
description = "Display images via Coil plugin in `RecyclerView`",
|
||||
artifacts = [MarkwonArtifact.IMAGE_COIL, MarkwonArtifact.RECYCLER],
|
||||
tags = [Tags.rendering, Tags.recyclerView, Tags.image]
|
||||
tags = [Tag.rendering, Tag.recyclerView, Tag.image]
|
||||
)
|
||||
class CoilRecyclerViewSample : MarkwonRecyclerViewSample() {
|
||||
override fun render() {
|
||||
@ -52,8 +51,8 @@ class CoilRecyclerViewSample : MarkwonRecyclerViewSample() {
|
||||
val markwon = Markwon.builder(context)
|
||||
.usePlugin(CoilImagesPlugin.create(
|
||||
object : CoilImagesPlugin.CoilStore {
|
||||
override fun load(drawable: AsyncDrawable): LoadRequest {
|
||||
return LoadRequest.Builder(context)
|
||||
override fun load(drawable: AsyncDrawable): ImageRequest {
|
||||
return ImageRequest.Builder(context)
|
||||
.transformations(
|
||||
RoundedCornersTransformation(14F)
|
||||
)
|
||||
@ -62,15 +61,11 @@ class CoilRecyclerViewSample : MarkwonRecyclerViewSample() {
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun cancel(disposable: RequestDisposable) {
|
||||
override fun cancel(disposable: Disposable) {
|
||||
disposable.dispose()
|
||||
}
|
||||
},
|
||||
ImageLoader.Builder(context)
|
||||
.okHttpClient(OkHttpClient())
|
||||
// this line of code makes unit tests fail
|
||||
// .placeholder(R.drawable.ic_image_gray_24dp)
|
||||
.build()))
|
||||
Coil.imageLoader(context)))
|
||||
.build()
|
||||
|
||||
val adapter = MarkwonAdapter.createTextViewIsRoot(R.layout.adapter_node)
|
||||
|
@ -8,17 +8,17 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630165828",
|
||||
title = "Image error handler",
|
||||
artifacts = MarkwonArtifact.IMAGE,
|
||||
tags = Tags.image
|
||||
tags = Tag.image
|
||||
)
|
||||
public class ErrorImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,18 +1,18 @@
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.image.gif.GifMediaDecoder;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630162214",
|
||||
title = "GIF image",
|
||||
artifacts = MarkwonArtifact.IMAGE,
|
||||
tags = {Tags.image, Tags.gif}
|
||||
tags = {Tag.image, Tag.gif}
|
||||
)
|
||||
public class GifImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,84 @@
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.bumptech.glide.Glide;
|
||||
import com.bumptech.glide.RequestBuilder;
|
||||
import com.bumptech.glide.RequestManager;
|
||||
import com.bumptech.glide.load.DataSource;
|
||||
import com.bumptech.glide.load.engine.GlideException;
|
||||
import com.bumptech.glide.request.RequestListener;
|
||||
import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.AsyncDrawable;
|
||||
import io.noties.markwon.image.glide.GlideImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200820071942",
|
||||
title = "Glide GIF",
|
||||
artifacts = MarkwonArtifact.IMAGE_GLIDE,
|
||||
tags = Tag.image
|
||||
)
|
||||
public class GlideGifImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "# Glide GIF\n" +
|
||||
" " +
|
||||
"and some other resource: \n\n" +
|
||||
"Hey: ";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(GlideImagesPlugin.create(new GifGlideStore(Glide.with(context))))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
|
||||
private static class GifGlideStore implements GlideImagesPlugin.GlideStore {
|
||||
private final RequestManager requestManager;
|
||||
|
||||
GifGlideStore(RequestManager requestManager) {
|
||||
this.requestManager = requestManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RequestBuilder<Drawable> load(@NonNull AsyncDrawable drawable) {
|
||||
// NB! Strange behaviour: First time a resource is requested - it fails, the next time it loads fine
|
||||
final String destination = drawable.getDestination();
|
||||
return requestManager
|
||||
// it is enough to call this (in order to load GIF and non-GIF)
|
||||
.asDrawable()
|
||||
.addListener(new RequestListener<Drawable>() {
|
||||
@Override
|
||||
public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) {
|
||||
// we must start GIF animation manually
|
||||
if (resource instanceof Animatable) {
|
||||
((Animatable) resource).start();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.load(destination);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NonNull Target<?> target) {
|
||||
requestManager.clear(target);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.glide.GlideImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630170112",
|
||||
title = "Glide image",
|
||||
artifacts = MarkwonArtifact.IMAGE_GLIDE,
|
||||
tags = Tags.image
|
||||
tags = Tag.image
|
||||
)
|
||||
public class GlideImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -11,18 +11,18 @@ import com.bumptech.glide.request.target.Target;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.AsyncDrawable;
|
||||
import io.noties.markwon.image.glide.GlideImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630170241",
|
||||
title = "Glide image with placeholder",
|
||||
artifacts = MarkwonArtifact.IMAGE_GLIDE,
|
||||
tags = Tags.image
|
||||
tags = Tag.image
|
||||
)
|
||||
public class GlidePlaceholderImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,69 @@
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import android.view.ViewTreeObserver;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.DefaultDownScalingMediaDecoder;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20210118165230",
|
||||
title = "Huge image downscaling",
|
||||
description = "Downscale displayed images with `BitmapOptions` 2 step rendering " +
|
||||
"(measure, downscale), use `DefaultDownScalingMediaDecoder`",
|
||||
artifacts = MarkwonArtifact.IMAGE,
|
||||
tags = Tag.image
|
||||
)
|
||||
public class HugeImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
// NB! this is based on the width of the widget. In case you have big vertical
|
||||
// images (with big vertical dimension, use some reasonable value or fallback to real OpenGL
|
||||
// maximum, see: https://stackoverflow.com/questions/15313807/android-maximum-allowed-width-height-of-bitmap
|
||||
|
||||
final int width = textView.getWidth();
|
||||
if (width > 0) {
|
||||
renderWithMaxWidth(width);
|
||||
return;
|
||||
}
|
||||
|
||||
textView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
final int w = textView.getWidth();
|
||||
if (w > 0) {
|
||||
renderWithMaxWidth(w);
|
||||
|
||||
final ViewTreeObserver observer = textView.getViewTreeObserver();
|
||||
if (observer.isAlive()) {
|
||||
observer.removeOnPreDrawListener(this);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void renderWithMaxWidth(int maxWidth) {
|
||||
|
||||
final String md = "" +
|
||||
"# Huge image\n\n" +
|
||||
"\n\n" +
|
||||
"hey!";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||
plugin
|
||||
.defaultMediaDecoder(DefaultDownScalingMediaDecoder.create(maxWidth, 0));
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +1,17 @@
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630144659",
|
||||
title = "Markdown image",
|
||||
artifacts = MarkwonArtifact.IMAGE,
|
||||
tags = Tags.image
|
||||
tags = Tag.image
|
||||
)
|
||||
public class ImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,64 @@
|
||||
package io.noties.markwon.app.samples.image
|
||||
|
||||
import android.content.res.Resources
|
||||
import io.noties.markwon.AbstractMarkwonPlugin
|
||||
import io.noties.markwon.Markwon
|
||||
import io.noties.markwon.MarkwonConfiguration
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
|
||||
import io.noties.markwon.html.HtmlPlugin
|
||||
import io.noties.markwon.image.ImageSize
|
||||
import io.noties.markwon.image.ImageSizeResolverDef
|
||||
import io.noties.markwon.image.ImagesPlugin
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
|
||||
import io.noties.markwon.sample.annotations.Tag
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20210201165512",
|
||||
title = "ImageSizeResolver",
|
||||
description = "Custom `ImageSizeResolver` that treats dimension values " +
|
||||
"as density-based (like `dp`, `dip` in resources)",
|
||||
artifacts = [MarkwonArtifact.CORE],
|
||||
tags = [Tag.image]
|
||||
)
|
||||
class ImageSizeResolverSample : MarkwonTextViewSample() {
|
||||
override fun render() {
|
||||
val image = "https://github.com/dcurtis/markdown-mark/raw/master/png/208x128-solid.png"
|
||||
val md = """
|
||||
**150px x 150px**: <img src="$image" width="150px" height="150px" alt="150px x 150px" />
|
||||
|
||||
**150 x 150**: <img src="$image" width="150" height="150" alt="150 x 150" />
|
||||
|
||||
**no dimension**: <img src="$image" alt="no dimension" />
|
||||
|
||||
**just width 150**: <img src="$image" width="150" alt="150" />
|
||||
""".trimIndent()
|
||||
|
||||
val markwon = Markwon.builder(context)
|
||||
.usePlugin(object : AbstractMarkwonPlugin() {
|
||||
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
|
||||
builder.imageSizeResolver(DensityImageSizeResolver())
|
||||
}
|
||||
})
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(HtmlPlugin.create())
|
||||
.build()
|
||||
|
||||
markwon.setMarkdown(textView, md)
|
||||
}
|
||||
|
||||
class DensityImageSizeResolver : ImageSizeResolverDef() {
|
||||
|
||||
val density: Float by lazy(LazyThreadSafetyMode.NONE) {
|
||||
Resources.getSystem().displayMetrics.density
|
||||
}
|
||||
|
||||
override fun resolveAbsolute(dimension: ImageSize.Dimension, original: Int, textSize: Float): Int {
|
||||
if (dimension.unit == null) {
|
||||
// assume density pixels
|
||||
return (dimension.value * density + 0.5F).toInt()
|
||||
}
|
||||
return super.resolveAbsolute(dimension, original, textSize)
|
||||
}
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ import java.util.Collections;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.ImageItem;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
@ -17,6 +16,7 @@ import io.noties.markwon.image.SchemeHandler;
|
||||
import io.noties.markwon.image.network.NetworkSchemeHandler;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200629124201",
|
||||
@ -25,7 +25,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
"(`https`, `ftp`, `whatever`, etc.) for images destination URLs " +
|
||||
"with `ImagesPlugin`",
|
||||
artifacts = {MarkwonArtifact.IMAGE},
|
||||
tags = {Tags.image}
|
||||
tags = {Tag.image}
|
||||
)
|
||||
public class ImagesCustomSchemeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -8,7 +8,6 @@ import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.RenderProps;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.image.AsyncDrawable;
|
||||
@ -18,13 +17,14 @@ import io.noties.markwon.image.ImageSize;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200803115847",
|
||||
title = "Native and HTML image",
|
||||
description = "Define images in both native markdown and HTML. Native markdown images take 100% of available width",
|
||||
artifacts = {MarkwonArtifact.IMAGE, MarkwonArtifact.HTML},
|
||||
tags = {Tags.rendering, Tags.image, Tags.html}
|
||||
tags = {Tag.rendering, Tag.image, Tag.html}
|
||||
)
|
||||
public class NativeAndHtmlImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -8,18 +8,18 @@ import androidx.core.content.ContextCompat;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.AsyncDrawable;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630165504",
|
||||
title = "Image with placeholder",
|
||||
artifacts = MarkwonArtifact.IMAGE,
|
||||
tags = Tags.image
|
||||
tags = Tag.image
|
||||
)
|
||||
public class PlaceholderImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,18 +1,18 @@
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.image.svg.SvgPictureMediaDecoder;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630161952",
|
||||
title = "SVG image",
|
||||
artifacts = MarkwonArtifact.IMAGE,
|
||||
tags = {Tags.image, Tags.svg}
|
||||
tags = {Tag.image, Tag.svg}
|
||||
)
|
||||
public class SvgImageSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -13,19 +13,19 @@ import java.util.Set;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CorePlugin;
|
||||
import io.noties.markwon.inlineparser.BackticksInlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630170607",
|
||||
title = "Disable code inline parsing",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.inline, Tags.parsing}
|
||||
tags = {Tag.inline, Tag.parsing}
|
||||
)
|
||||
public class InlineParsingDisableCodeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -7,19 +7,19 @@ import org.commonmark.parser.Parser;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.CloseBracketInlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.inlineparser.OpenBracketInlineProcessor;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630170412",
|
||||
title = "Links only inline parsing",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.parsing, Tags.inline}
|
||||
tags = {Tag.parsing, Tag.inline}
|
||||
)
|
||||
public class InlineParsingLinksOnlySample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -4,20 +4,20 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.BackticksInlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParser;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630170823",
|
||||
title = "Inline parsing no defaults",
|
||||
description = "Parsing only inline code and disable all the rest",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.inline, Tags.parsing}
|
||||
tags = {Tag.inline, Tag.parsing}
|
||||
)
|
||||
public class InlineParsingNoDefaultsSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -10,19 +10,19 @@ import java.util.Set;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.core.CorePlugin;
|
||||
import io.noties.markwon.inlineparser.HtmlInlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630171239",
|
||||
title = "Inline parsing exclude HTML",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.parsing, Tags.inline, Tags.block}
|
||||
tags = {Tag.parsing, Tag.inline, Tag.block}
|
||||
)
|
||||
public class InlineParsingNoHtmlSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -0,0 +1,114 @@
|
||||
package io.noties.markwon.app.samples.inlineparsing;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.commonmark.node.CustomNode;
|
||||
import org.commonmark.node.Node;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonSpansFactory;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.InlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.inlineparser.OpenBracketInlineProcessor;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200819071751",
|
||||
title = "Inline Parsing of square brackets",
|
||||
description = "Disable OpenBracketInlineParser in order " +
|
||||
"to parse own markdown syntax based on `[` character(s). This would disable native " +
|
||||
"markdown [links](#) but not images ",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tag.parsing}
|
||||
)
|
||||
public class InlineParsingSquareBracketsSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Hello\n" +
|
||||
"Hey! [[my text]] here and what to do with it?\n\n" +
|
||||
"[[at the beginning]] of a line with [links](#) disabled";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create(factoryBuilder ->
|
||||
factoryBuilder
|
||||
.addInlineProcessor(new MyTextInlineProcessor())
|
||||
.excludeInlineProcessor(OpenBracketInlineProcessor.class)))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder
|
||||
.on(MyTextNode.class, new GenericInlineNodeVisitor())
|
||||
.on(NotMyTextNode.class, new GenericInlineNodeVisitor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
builder
|
||||
.setFactory(MyTextNode.class, (configuration, props) -> new ForegroundColorSpan(Color.RED))
|
||||
.setFactory(NotMyTextNode.class, (configuration, props) -> new ForegroundColorSpan(Color.GREEN));
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
|
||||
private static class GenericInlineNodeVisitor implements MarkwonVisitor.NodeVisitor<Node> {
|
||||
@Override
|
||||
public void visit(@NonNull MarkwonVisitor visitor, @NonNull Node node) {
|
||||
final int length = visitor.length();
|
||||
visitor.visitChildren(node);
|
||||
visitor.setSpansForNodeOptional(node, length);
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyTextInlineProcessor extends InlineProcessor {
|
||||
|
||||
private static final Pattern RE = Pattern.compile("\\[\\[(.+?)\\]\\]");
|
||||
|
||||
@Override
|
||||
public char specialCharacter() {
|
||||
return '[';
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Node parse() {
|
||||
final String match = match(RE);
|
||||
Debug.i(match);
|
||||
if (match != null) {
|
||||
// consume syntax
|
||||
final String text = match.substring(2, match.length() - 2);
|
||||
final Node node;
|
||||
// for example some condition checking
|
||||
if (text.equals("my text")) {
|
||||
node = new MyTextNode();
|
||||
} else {
|
||||
node = new NotMyTextNode();
|
||||
}
|
||||
node.appendChild(text(text));
|
||||
return node;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MyTextNode extends CustomNode {
|
||||
}
|
||||
|
||||
private static class NotMyTextNode extends CustomNode {
|
||||
}
|
||||
}
|
@ -24,18 +24,19 @@ import java.util.regex.Pattern;
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.MarkwonVisitor;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.inlineparser.InlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630195409",
|
||||
title = "Tooltip with inline parser",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.parsing, Tags.rendering}
|
||||
tags = {Tag.parsing, Tag.rendering}
|
||||
)
|
||||
public class InlineParsingTooltipSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
@ -56,7 +57,7 @@ public class InlineParsingTooltipSample extends MarkwonTextViewSample {
|
||||
"# Hello tooltip!\n\n" +
|
||||
"This is the !{tooltip label}(and actual content comes here)\n\n" +
|
||||
"what if it is !{here}(The contents can be blocks, limited though) instead?\n\n" +
|
||||
" anyway";
|
||||
" anyway";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create(factoryBuilder ->
|
||||
@ -71,6 +72,7 @@ public class InlineParsingTooltipSample extends MarkwonTextViewSample {
|
||||
});
|
||||
}
|
||||
})
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
|
@ -4,19 +4,19 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.inlineparser.OpenBracketInlineProcessor;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630170723",
|
||||
title = "Inline parsing with defaults",
|
||||
description = "Parsing with all defaults except links",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.inline, Tags.parsing}
|
||||
tags = {Tag.inline, Tag.parsing}
|
||||
)
|
||||
public class InlineParsingWithDefaultsSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.latex.shared.LatexHolder;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200630200257",
|
||||
title = "LaTex block",
|
||||
description = "Render LaTeX block",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = {Tags.rendering}
|
||||
tags = {Tag.rendering}
|
||||
)
|
||||
public class LatexBlockSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,11 +1,11 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200701094225",
|
||||
@ -13,7 +13,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
description = "LaTeX automatically uses `TextView` text color " +
|
||||
"if not configured explicitly",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class LatexDarkSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -3,19 +3,19 @@ package io.noties.markwon.app.samples.latex;
|
||||
import android.graphics.Color;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.latex.shared.LatexHolder;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200701120848",
|
||||
title = "LaTeX default text color",
|
||||
description = "LaTeX will use text color of `TextView` by default",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class LatexDefaultTextColorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.latex.shared.LatexHolder;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200701093504",
|
||||
title = "LaTeX inline/block different text size",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.rendering}
|
||||
tags = {Tag.rendering}
|
||||
)
|
||||
public class LatexDifferentTextSizesSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -9,19 +9,19 @@ import androidx.core.content.ContextCompat;
|
||||
import io.noties.debug.Debug;
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200701122624",
|
||||
title = "LaTeX error handling",
|
||||
description = "Log error when parsing LaTeX and display error drawable",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class LatexErrorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,20 +1,20 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.latex.shared.LatexHolder;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200701085820",
|
||||
title = "LaTeX inline",
|
||||
description = "Display LaTeX inline",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = Tags.rendering
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class LatexInlineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
@ -1,19 +1,19 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.latex.shared.LatexHolder;
|
||||
import io.noties.markwon.ext.latex.JLatexMathPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.sample.annotations.Tag;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "20200701090335",
|
||||
title = "LaTeX blocks in legacy mode",
|
||||
description = "Sample using _legacy_ LaTeX block parsing (pre `4.3.0` Markwon version)",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
tags = Tag.rendering
|
||||
)
|
||||
public class LatexLegacySample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user