Finished moving samples to app-sample
This commit is contained in:
parent
0b1544feae
commit
12a73d982c
@ -5,6 +5,7 @@
|
||||
#### Added
|
||||
* `core` - `MovementMethodPlugin.none()`, `MovementMethodPlugin.link()` factory methods
|
||||
* `core` - `CorePlugin` `hasExplicitMovementMethod` configuration method to **not** add implicit `LinkMovementMethod` in `afterSetText`
|
||||
* `ext-latex` - `JLatexMathTheme.Padding.of(int,int,int,int)` factory method
|
||||
|
||||
#### Changed
|
||||
* `html` - `SimpleTagHandler` visits children tags if supplied tag is block one ([#235])
|
||||
|
12
app-sample/README.md
Normal file
12
app-sample/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# Markwon sample app
|
||||
|
||||
## Building
|
||||
|
||||
When adding/removing samples _most likely_ a clean build would be required.
|
||||
First, for annotation processor to create `samples.json`. And secondly,
|
||||
in order for Android Gradle plugin to bundle resources references via
|
||||
symbolic links (the `sample.json` itself and `io.noties.markwon.app.samples.*` directory)
|
||||
|
||||
```gradle
|
||||
./gradlew :app-s:clean :app-s:asDe
|
||||
```
|
@ -76,6 +76,7 @@ dependencies {
|
||||
implementation project(':markwon-image-glide')
|
||||
|
||||
deps.with {
|
||||
// implementation it['x-appcompat']
|
||||
implementation it['x-recycler-view']
|
||||
implementation it['x-cardview']
|
||||
implementation it['x-fragment']
|
||||
|
@ -1,4 +1,435 @@
|
||||
[
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.TaskListMutateSample",
|
||||
"id": "202007184140901",
|
||||
"title": "GFM task list mutate",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"EXT_TASKLIST"
|
||||
],
|
||||
"tags": [
|
||||
"plugin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.TaskListCustomDrawableSample",
|
||||
"id": "202007184140749",
|
||||
"title": "GFM task list custom drawable",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"EXT_TASKLIST"
|
||||
],
|
||||
"tags": [
|
||||
"plugin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.TaskListCustomColorsSample",
|
||||
"id": "202007184140536",
|
||||
"title": "GFM task list custom colors",
|
||||
"description": "Custom colors for task list extension",
|
||||
"artifacts": [
|
||||
"EXT_TASKLIST"
|
||||
],
|
||||
"tags": [
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.tasklist.TaskListSample",
|
||||
"id": "202007184140352",
|
||||
"title": "GFM task list",
|
||||
"description": "Github Flavored Markdown (GFM) task list extension",
|
||||
"artifacts": [
|
||||
"EXT_TASKLIST"
|
||||
],
|
||||
"tags": [
|
||||
"plugin"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.table.TableLatexSample",
|
||||
"id": "202007184140041",
|
||||
"title": "LaTeX inside table",
|
||||
"description": "Usage of LaTeX formulas inside markdown tables",
|
||||
"artifacts": [
|
||||
"EXT_LATEX",
|
||||
"EXT_TABLES",
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.table.TableWithImagesSample",
|
||||
"id": "202007184135932",
|
||||
"title": "Images inside table",
|
||||
"description": "Usage of images inside markdown tables",
|
||||
"artifacts": [
|
||||
"EXT_TABLES",
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.table.TableLinkifySample",
|
||||
"id": "202007184135739",
|
||||
"title": "Linkify table",
|
||||
"description": "Automatically linkify markdown content including content inside tables",
|
||||
"artifacts": [
|
||||
"EXT_TABLES",
|
||||
"LINKIFY"
|
||||
],
|
||||
"tags": [
|
||||
"links"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.table.TableCustomizeSample",
|
||||
"id": "202007184135621",
|
||||
"title": "Customize table theme",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"EXT_TABLES"
|
||||
],
|
||||
"tags": [
|
||||
"theme"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.RecyclerSample",
|
||||
"id": "202007184101750",
|
||||
"title": "RecyclerView",
|
||||
"description": "Usage with `RecyclerView`",
|
||||
"artifacts": [
|
||||
"RECYCLER",
|
||||
"RECYCLER_TABLE"
|
||||
],
|
||||
"tags": [
|
||||
"recycler-view"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.LinkRemoveUnderlineSample",
|
||||
"id": "202007184101224",
|
||||
"title": "Remove link underline",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"links",
|
||||
"rendering",
|
||||
"span"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.PrecomputedFutureSample",
|
||||
"id": "202007184092446",
|
||||
"title": "PrecomputedFutureTextSetterCompat",
|
||||
"description": "Usage of `PrecomputedFutureTextSetterCompat` inside a `RecyclerView` with appcompat",
|
||||
"artifacts": [
|
||||
"RECYCLER"
|
||||
],
|
||||
"tags": [
|
||||
"precomputed-text",
|
||||
"recycler-view"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.PrecomputedSample",
|
||||
"id": "202007184091654",
|
||||
"title": "PrecomputedTextSetterCompat",
|
||||
"description": "`TextSetter` to use `PrecomputedTextSetterCompat`",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"precomputed-text"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.notification.RemoteViewsSample",
|
||||
"id": "202007184090140",
|
||||
"title": "RemoteViews in notification",
|
||||
"description": "Display markdown with platform (system) spans in notification via `RemoteViews`",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"hack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.notification.NotificationSample",
|
||||
"id": "202007183130729",
|
||||
"title": "Markdown in Notification",
|
||||
"description": "Proof of concept of using `Markwon` with `android.app.Notification`",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"hack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexErrorSample",
|
||||
"id": "202007183122624",
|
||||
"title": "LaTeX error handling",
|
||||
"description": "Log error when parsing LaTeX and display error drawable",
|
||||
"artifacts": [
|
||||
"EXT_LATEX"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexThemeSample",
|
||||
"id": "202007183121528",
|
||||
"title": "LaTeX theme",
|
||||
"description": "Sample of theme customization for LaTeX",
|
||||
"artifacts": [
|
||||
"EXT_LATEX",
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexDefaultTextColorSample",
|
||||
"id": "202007183120848",
|
||||
"title": "LaTeX default text color",
|
||||
"description": "LaTeX will use text color of `TextView` by default",
|
||||
"artifacts": [
|
||||
"EXT_LATEX"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexDarkSample",
|
||||
"id": "202007183094225",
|
||||
"title": "LaTeX dark",
|
||||
"description": "LaTeX automatically uses `TextView` text color if not configured explicitly",
|
||||
"artifacts": [
|
||||
"EXT_LATEX"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexDifferentTextSizesSample",
|
||||
"id": "202007183093504",
|
||||
"title": "LaTeX inline/block different text size",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"EXT_LATEX",
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexOmegaSample",
|
||||
"id": "202007183090618",
|
||||
"title": "LaTeX omega symbol",
|
||||
"description": "Bug rendering omega symbol in LaTeX",
|
||||
"artifacts": [
|
||||
"EXT_LATEX",
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"known-bug",
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexLegacySample",
|
||||
"id": "202007183090335",
|
||||
"title": "LaTeX blocks in legacy mode",
|
||||
"description": "Sample using _legacy_ LaTeX block parsing (pre `4.3.0` Markwon version)",
|
||||
"artifacts": [
|
||||
"EXT_LATEX"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexInlineSample",
|
||||
"id": "202007183085820",
|
||||
"title": "LaTeX inline",
|
||||
"description": "Display LaTeX inline",
|
||||
"artifacts": [
|
||||
"EXT_LATEX",
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.latex.LatexBlockSample",
|
||||
"id": "202006182200257",
|
||||
"title": "LaTex block",
|
||||
"description": "Render LaTeX block",
|
||||
"artifacts": [
|
||||
"EXT_LATEX"
|
||||
],
|
||||
"tags": [
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingTooltipSample",
|
||||
"id": "202006182195409",
|
||||
"title": "Tooltip with inline parser",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"parsing",
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.SimpleExtensionSample",
|
||||
"id": "202006182194335",
|
||||
"title": "Delimiter processor simple-ext",
|
||||
"description": "Custom delimiter processor implemented with a `SimpleExtPlugin`",
|
||||
"artifacts": [
|
||||
"SIMPLE_EXT"
|
||||
],
|
||||
"tags": [
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.DelimiterProcessorSample",
|
||||
"id": "202006182194017",
|
||||
"title": "Custom delimiter processor",
|
||||
"description": "Custom parsing delimiter processor with `?` character",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.html.HtmlDisableSanitizeSample",
|
||||
"id": "202006182171424",
|
||||
"title": "Disable HTML",
|
||||
"description": "Disable HTML via replacing special `\u003c` and `\u003e` symbols",
|
||||
"artifacts": [
|
||||
"CORE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"parsing",
|
||||
"plugin",
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingNoHtmlSample",
|
||||
"id": "202006182171239",
|
||||
"title": "Inline parsing exclude HTML",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"block",
|
||||
"inline",
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingNoDefaultsSample",
|
||||
"id": "202006182170823",
|
||||
"title": "Inline parsing no defaults",
|
||||
"description": "Parsing only inline code and disable all the rest",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingWithDefaultsSample",
|
||||
"id": "202006182170723",
|
||||
"title": "Inline parsing with defaults",
|
||||
"description": "Parsing with all defaults except links",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingDisableCodeSample",
|
||||
"id": "202006182170607",
|
||||
"title": "Disable code inline parsing",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.inlineparsing.InlineParsingLinksOnlySample",
|
||||
"id": "202006182170412",
|
||||
"title": "Links only inline parsing",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"INLINE_PARSER"
|
||||
],
|
||||
"tags": [
|
||||
"inline",
|
||||
"parsing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.GlidePlaceholderImageSample",
|
||||
"id": "202006182170241",
|
||||
"title": "Glide image with placeholder",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"IMAGE_GLIDE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.GlideImageSample",
|
||||
"id": "202006182170112",
|
||||
"title": "Glide image",
|
||||
"description": "",
|
||||
"artifacts": [
|
||||
"IMAGE_GLIDE"
|
||||
],
|
||||
"tags": [
|
||||
"image"
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.ErrorImageSample",
|
||||
"id": "202006182165828",
|
||||
@ -71,6 +502,7 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"image",
|
||||
"rendering"
|
||||
]
|
||||
@ -85,6 +517,7 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
@ -97,6 +530,7 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering"
|
||||
]
|
||||
},
|
||||
@ -110,6 +544,7 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"image",
|
||||
"rendering"
|
||||
]
|
||||
@ -124,6 +559,7 @@
|
||||
"IMAGE"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"image",
|
||||
"rendering"
|
||||
]
|
||||
@ -137,6 +573,7 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"span"
|
||||
]
|
||||
@ -150,6 +587,7 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"span"
|
||||
]
|
||||
@ -163,6 +601,7 @@
|
||||
"HTML"
|
||||
],
|
||||
"tags": [
|
||||
"HTML",
|
||||
"rendering",
|
||||
"span"
|
||||
]
|
||||
@ -485,7 +924,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"javaClassName": "io.noties.markwon.app.samples.ImagesCustomSchemeSample",
|
||||
"javaClassName": "io.noties.markwon.app.samples.image.ImagesCustomSchemeSample",
|
||||
"id": "202006181124201",
|
||||
"title": "Image destination custom scheme",
|
||||
"description": "Example of handling custom scheme (`https`, `ftp`, `whatever`, etc.) for images destination URLs with `ImagesPlugin`",
|
||||
|
@ -31,4 +31,6 @@ object Tags {
|
||||
const val gif = "GIF"
|
||||
const val inline = "inline"
|
||||
const val html = "HTML"
|
||||
const val knownBug = "known-bug"
|
||||
const val precomputedText = "precomputed-text"
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package io.noties.markwon.app.sample.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import io.noties.markwon.app.R
|
||||
|
||||
abstract class MarkwonRecyclerViewSample : MarkwonSample() {
|
||||
|
||||
protected lateinit var context: Context
|
||||
protected lateinit var recyclerView: RecyclerView
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
context = view.context
|
||||
recyclerView = view.findViewById(R.id.recycler_view)
|
||||
render()
|
||||
}
|
||||
|
||||
override val layoutResId: Int
|
||||
get() = R.layout.sample_recycler_view
|
||||
|
||||
abstract fun render()
|
||||
}
|
@ -2,6 +2,7 @@ package io.noties.markwon.app.sample.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.view.View
|
||||
import android.widget.ScrollView
|
||||
import android.widget.TextView
|
||||
|
||||
import io.noties.markwon.app.R
|
||||
@ -9,12 +10,14 @@ import io.noties.markwon.app.R
|
||||
abstract class MarkwonTextViewSample : MarkwonSample() {
|
||||
|
||||
protected lateinit var context: Context
|
||||
protected lateinit var scrollView: ScrollView
|
||||
protected lateinit var textView: TextView
|
||||
|
||||
override val layoutResId: Int = R.layout.sample_text_view
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
context = view.context
|
||||
scrollView = view.findViewById(R.id.scroll_view)
|
||||
textView = view.findViewById(R.id.text_view)
|
||||
render()
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ class SampleListFragment : Fragment() {
|
||||
private val sampleManager: SampleManager
|
||||
get() = App.sampleManager
|
||||
|
||||
override fun onAttach(context: Context?) {
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
|
||||
context?.also {
|
||||
context.also {
|
||||
markwon = markwon(it)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.Emphasis;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.node.Text;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.parser.delimiter.DelimiterProcessor;
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202006182194017",
|
||||
title = "Custom delimiter processor",
|
||||
description = "Custom parsing delimiter processor with `?` character",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.parsing
|
||||
)
|
||||
public class DelimiterProcessorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"?hello? there!";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureParser(@NonNull Parser.Builder builder) {
|
||||
builder.customDelimiterProcessor(new QuestionDelimiterProcessor());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
||||
|
||||
class QuestionDelimiterProcessor implements DelimiterProcessor {
|
||||
|
||||
@Override
|
||||
public char getOpeningCharacter() {
|
||||
return '?';
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getClosingCharacter() {
|
||||
return '?';
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinLength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDelimiterUse(DelimiterRun opener, DelimiterRun closer) {
|
||||
if (opener.length() >= 1 && closer.length() >= 1) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void process(Text opener, Text closer, int delimiterUse) {
|
||||
final Node node = new Emphasis();
|
||||
|
||||
Node tmp = opener.getNext();
|
||||
while (tmp != null && tmp != closer) {
|
||||
Node next = tmp.getNext();
|
||||
node.appendChild(tmp);
|
||||
tmp = next;
|
||||
}
|
||||
|
||||
opener.insertAfter(node);
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.spacing, Tags.padding, Tags.spacing, Tags.rendering}
|
||||
)
|
||||
class HeadingNoSpaceSample extends MarkwonTextViewSample {
|
||||
public class HeadingNoSpaceSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
|
@ -0,0 +1,49 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.CharacterStyle;
|
||||
import android.text.style.UpdateAppearance;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184101224",
|
||||
title = "Remove link underline",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.links, Tags.rendering, Tags.span}
|
||||
)
|
||||
public class LinkRemoveUnderlineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"There are a lot of [links](#) [here](#)";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
builder.appendFactory(Link.class, (configuration, props) -> new RemoveUnderlineSpan());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
||||
|
||||
class RemoveUnderlineSpan extends CharacterStyle implements UpdateAppearance {
|
||||
@Override
|
||||
public void updateDrawState(TextPaint tp) {
|
||||
tp.setUnderlineText(false);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
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;
|
||||
import io.noties.markwon.ext.tables.TablePlugin;
|
||||
import io.noties.markwon.ext.tasklist.TaskListPlugin;
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184092446",
|
||||
title = "PrecomputedFutureTextSetterCompat",
|
||||
description = "Usage of `PrecomputedFutureTextSetterCompat` " +
|
||||
"inside a `RecyclerView` with appcompat",
|
||||
artifacts = {MarkwonArtifact.RECYCLER},
|
||||
tags = {Tags.recyclerView, Tags.precomputedText}
|
||||
)
|
||||
public class PrecomputedFutureSample extends MarkwonRecyclerViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
if (!hasAppCompat()) {
|
||||
/*
|
||||
PLEASE COMPILE WITH `APPCOMPAT` dependency
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
final String md = SampleUtilsKtKt.loadReadMe(context);
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.textSetter(PrecomputedFutureTextSetterCompat.create())
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(TablePlugin.create(context))
|
||||
.usePlugin(TaskListPlugin.create(context))
|
||||
.usePlugin(StrikethroughPlugin.create())
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.imageDestinationProcessor(new GithubImageDestinationProcessor());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
final MarkwonAdapter adapter = MarkwonAdapter
|
||||
.createTextViewIsRoot(R.layout.adapter_appcompat_default_entry);
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
adapter.setMarkdown(markwon, md);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private static boolean hasAppCompat() {
|
||||
try {
|
||||
Class.forName("androidx.appcompat.widget.AppCompatTextView");
|
||||
return true;
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184091654",
|
||||
title = "PrecomputedTextSetterCompat",
|
||||
description = "`TextSetter` to use `PrecomputedTextSetterCompat`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.precomputedText
|
||||
)
|
||||
public class PrecomputedSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Heading\n" +
|
||||
"**bold** some precomputed spans via `PrecomputedTextSetterCompat`";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.textSetter(PrecomputedTextSetterCompat.create(Executors.newCachedThreadPool()))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
||||
import org.commonmark.ext.gfm.tables.TableBlock;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
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;
|
||||
import io.noties.markwon.ext.tasklist.TaskListPlugin;
|
||||
import io.noties.markwon.html.HtmlPlugin;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.recycler.MarkwonAdapter;
|
||||
import io.noties.markwon.recycler.SimpleEntry;
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184101750",
|
||||
title = "RecyclerView",
|
||||
description = "Usage with `RecyclerView`",
|
||||
artifacts = {MarkwonArtifact.RECYCLER, MarkwonArtifact.RECYCLER_TABLE},
|
||||
tags = Tags.recyclerView
|
||||
)
|
||||
public class RecyclerSample extends MarkwonRecyclerViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = SampleUtilsKtKt.loadReadMe(context);
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(TableEntryPlugin.create(context))
|
||||
.usePlugin(HtmlPlugin.create())
|
||||
.usePlugin(StrikethroughPlugin.create())
|
||||
.usePlugin(TaskListPlugin.create(context))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureConfiguration(@NonNull MarkwonConfiguration.Builder builder) {
|
||||
builder.imageDestinationProcessor(new GithubImageDestinationProcessor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(FencedCodeBlock.class, (visitor, fencedCodeBlock) -> {
|
||||
// we actually won't be applying code spans here, as our custom view will
|
||||
// draw background and apply mono typeface
|
||||
//
|
||||
// NB the `trim` operation on literal (as code will have a new line at the end)
|
||||
final CharSequence code = visitor.configuration()
|
||||
.syntaxHighlight()
|
||||
.highlight(fencedCodeBlock.getInfo(), fencedCodeBlock.getLiteral().trim());
|
||||
visitor.builder().append(code);
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
final MarkwonAdapter adapter = MarkwonAdapter.builderTextViewIsRoot(R.layout.adapter_node)
|
||||
.include(FencedCodeBlock.class, SimpleEntry.create(R.layout.adapter_node_code_block, R.id.text_view))
|
||||
.include(TableBlock.class, TableEntry.create(builder -> {
|
||||
builder
|
||||
.tableLayout(R.layout.adapter_node_table_block, R.id.table_layout)
|
||||
.textLayoutIsRoot(R.layout.view_table_entry_cell);
|
||||
}))
|
||||
.build();
|
||||
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
adapter.setMarkdown(markwon, md);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
|
||||
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.simple.ext.SimpleExtPlugin;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202006182194335",
|
||||
title = "Delimiter processor simple-ext",
|
||||
description = "Custom delimiter processor implemented with a `SimpleExtPlugin`",
|
||||
artifacts = MarkwonArtifact.SIMPLE_EXT,
|
||||
tags = Tags.parsing
|
||||
)
|
||||
public class SimpleExtensionSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# SimpleExt\n" +
|
||||
"\n" +
|
||||
"+let's start with `+`, ??then we can use this, and finally @@this$$??+";
|
||||
;
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(SimpleExtPlugin.create(plugin -> {
|
||||
plugin
|
||||
.addExtension(1, '+', (configuration, props) -> new EmphasisSpan())
|
||||
.addExtension(2, '?', (configuration, props) -> new StrongEmphasisSpan())
|
||||
.addExtension(
|
||||
2,
|
||||
'@',
|
||||
'?',
|
||||
(configuration, props) -> new ForegroundColorSpan(Color.RED)
|
||||
);
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = {Tags.newLine, Tags.softBreak}
|
||||
)
|
||||
class SoftBreakAddsNewLineSample extends MarkwonTextViewSample {
|
||||
public class SoftBreakAddsNewLineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
|
@ -9,7 +9,7 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.core.spans.StrongEmphasisSpan;
|
||||
import io.noties.markwon.editor.AbstractEditHandler;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
|
@ -2,7 +2,7 @@ package io.noties.markwon.app.samples.editor;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonEditTextSample;
|
||||
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;
|
||||
|
@ -4,7 +4,7 @@ import android.text.style.ForegroundColorSpan;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonEditTextSample;
|
||||
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;
|
||||
|
@ -4,7 +4,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.MarkwonEditTextSample;
|
||||
import io.noties.markwon.app.samples.editor.shared.HeadingEditHandler;
|
||||
import io.noties.markwon.editor.MarkwonEditor;
|
||||
import io.noties.markwon.editor.MarkwonEditorTextWatcher;
|
||||
|
@ -13,7 +13,7 @@ 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.sample.ui.MarkwonEditTextSample;
|
||||
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;
|
||||
|
@ -12,7 +12,7 @@ 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.sample.ui.MarkwonEditTextSample;
|
||||
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;
|
||||
|
@ -4,7 +4,7 @@ import java.util.concurrent.Executors;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonEditTextSample;
|
||||
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;
|
||||
|
@ -2,7 +2,7 @@ package io.noties.markwon.app.samples.editor;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonEditTextSample;
|
||||
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;
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.noties.markwon.app.sample.ui
|
||||
package io.noties.markwon.app.samples.editor.shared
|
||||
|
||||
import android.content.Context
|
||||
import android.text.SpannableStringBuilder
|
||||
@ -9,6 +9,7 @@ import android.widget.Button
|
||||
import android.widget.EditText
|
||||
import android.widget.TextView
|
||||
import io.noties.markwon.app.R
|
||||
import io.noties.markwon.app.sample.ui.MarkwonSample
|
||||
import io.noties.markwon.core.spans.EmphasisSpan
|
||||
import io.noties.markwon.core.spans.StrongEmphasisSpan
|
||||
import java.util.ArrayList
|
||||
@ -19,7 +20,7 @@ abstract class MarkwonEditTextSample : MarkwonSample() {
|
||||
protected lateinit var editText: EditText
|
||||
|
||||
override val layoutResId: Int
|
||||
get() = R.layout.activity_edit_text
|
||||
get() = R.layout.sample_edit_text
|
||||
|
||||
override fun onViewCreated(view: View) {
|
||||
context = view.context
|
@ -28,14 +28,15 @@ public class ErrorImageSample extends MarkwonTextViewSample {
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
// error handler additionally allows to log/inspect errors during image loading
|
||||
.usePlugin(ImagesPlugin.create(plugin ->
|
||||
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||
plugin.errorHandler(new ImagesPlugin.ErrorHandler() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Drawable handleError(@NonNull String url, @NonNull Throwable throwable) {
|
||||
return ContextCompat.getDrawable(context, R.drawable.ic_home_black_36dp);
|
||||
}
|
||||
})))
|
||||
});
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
|
@ -23,8 +23,9 @@ public class GifImageSample extends MarkwonTextViewSample {
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
// GIF is handled by default if library is used in the app
|
||||
// .usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(ImagesPlugin.create(plugin ->
|
||||
plugin.addMediaDecoder(GifMediaDecoder.create())))
|
||||
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||
plugin.addMediaDecoder(GifMediaDecoder.create());
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
|
@ -1,4 +1,4 @@
|
||||
package io.noties.markwon.app.samples;
|
||||
package io.noties.markwon.app.samples.image;
|
||||
|
||||
import android.net.Uri;
|
||||
|
@ -28,7 +28,7 @@ public class PlaceholderImageSample extends MarkwonTextViewSample {
|
||||
"";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create(plugin ->
|
||||
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
|
||||
@Nullable
|
||||
@Override
|
||||
@ -37,7 +37,8 @@ public class PlaceholderImageSample extends MarkwonTextViewSample {
|
||||
// otherwise bounds can be applied explicitly
|
||||
return ContextCompat.getDrawable(context, R.drawable.ic_android_black_24dp);
|
||||
}
|
||||
})))
|
||||
});
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
|
@ -25,11 +25,12 @@ public class SvgImageSample extends MarkwonTextViewSample {
|
||||
// libraries are in path (specified in dependencies block)
|
||||
// .usePlugin(ImagesPlugin.create())
|
||||
// let's make it implicit
|
||||
.usePlugin(ImagesPlugin.create(plugin ->
|
||||
.usePlugin(ImagesPlugin.create(plugin -> {
|
||||
// there 2 svg media decoders:
|
||||
// - regular `SvgMediaDecoder`
|
||||
// - special one when SVG doesn't have width and height specified - `SvgPictureMediaDecoder`
|
||||
plugin.addMediaDecoder(SvgPictureMediaDecoder.create())))
|
||||
plugin.addMediaDecoder(SvgPictureMediaDecoder.create());
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
|
@ -3,15 +3,11 @@ package io.noties.markwon.app.samples.inlineparsing;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.Block;
|
||||
import org.commonmark.node.BlockQuote;
|
||||
import org.commonmark.node.Heading;
|
||||
import org.commonmark.node.HtmlBlock;
|
||||
import org.commonmark.node.ListBlock;
|
||||
import org.commonmark.node.ThematicBreak;
|
||||
import org.commonmark.node.FencedCodeBlock;
|
||||
import org.commonmark.node.IndentedCodeBlock;
|
||||
import org.commonmark.parser.InlineParserFactory;
|
||||
import org.commonmark.parser.Parser;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@ -19,6 +15,7 @@ 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;
|
||||
@ -49,16 +46,12 @@ public class InlineParsingDisableCodeSample extends MarkwonTextViewSample {
|
||||
.excludeInlineProcessor(BackticksInlineProcessor.class)
|
||||
.build();
|
||||
|
||||
// unfortunately there is no _exclude_ method for parser-builder
|
||||
final Set<Class<? extends Block>> enabledBlocks = new HashSet<Class<? extends Block>>() {{
|
||||
// IndentedCodeBlock.class and FencedCodeBlock.class are missing
|
||||
// this is full list (including above) that can be passed to `enabledBlockTypes` method
|
||||
addAll(Arrays.asList(
|
||||
BlockQuote.class,
|
||||
Heading.class,
|
||||
HtmlBlock.class,
|
||||
ThematicBreak.class,
|
||||
ListBlock.class));
|
||||
addAll(CorePlugin.enabledBlockTypes());
|
||||
|
||||
remove(FencedCodeBlock.class);
|
||||
remove(IndentedCodeBlock.class);
|
||||
}};
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
|
@ -14,7 +14,8 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202006182170823",
|
||||
title = "Inline parsing with defaults",
|
||||
title = "Inline parsing no defaults",
|
||||
description = "Parsing only inline code and disable all the rest",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.inline, Tags.parsing}
|
||||
)
|
||||
|
@ -0,0 +1,202 @@
|
||||
package io.noties.markwon.app.samples.inlineparsing;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Point;
|
||||
import android.text.Layout;
|
||||
import android.text.Spannable;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.commonmark.node.CustomNode;
|
||||
import org.commonmark.node.Node;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
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.inlineparser.InlineProcessor;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202006182195409",
|
||||
title = "Tooltip with inline parser",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.parsing, Tags.rendering}
|
||||
)
|
||||
public class InlineParsingTooltipSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
// NB! tooltip contents cannot have new lines
|
||||
final String md = "" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi vitae enim ut sem aliquet ultrices. Nunc a accumsan orci. Suspendisse tortor ante, lacinia ac scelerisque sed, dictum eget metus. Morbi ante augue, tristique eget quam in, vestibulum rutrum lacus. Nulla aliquam auctor cursus. Nulla at lacus condimentum, viverra lacus eget, sollicitudin ex. Cras efficitur leo dui, sit amet rutrum tellus venenatis et. Sed in facilisis libero. Etiam ultricies, nulla ut venenatis tincidunt, tortor erat tristique ante, non aliquet massa arcu eget nisl. Etiam gravida erat ante, sit amet lobortis mauris commodo nec. Praesent vitae sodales quam. Vivamus condimentum porta suscipit. Donec posuere id felis ac scelerisque. Vestibulum lacinia et leo id lobortis. Sed vitae dolor nec ligula dapibus finibus vel eu libero. Nam tincidunt maximus elit, sit amet tincidunt lacus laoreet malesuada.\n" +
|
||||
"\n" +
|
||||
"Aenean at urna leo. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla facilisi. Integer lectus elit, congue a orci sed, dignissim sagittis sem. Aenean et pretium magna, nec ornare justo. Sed quis nunc blandit, luctus justo eget, pellentesque arcu. Pellentesque porta semper tristique. Donec et odio arcu. Nullam ultrices gravida congue. Praesent vel leo sed orci tempor luctus. Vivamus eget tortor arcu. Nullam sapien nulla, iaculis sit amet semper in, mattis nec metus. In porttitor augue id elit euismod mattis. Ut est justo, dapibus suscipit erat eu, pellentesque porttitor magna.\n" +
|
||||
"\n" +
|
||||
"Nunc porta orci eget dictum malesuada. Donec vehicula felis sit amet leo tincidunt placerat. Cras quis elit faucibus, porta elit at, sodales tortor. Donec elit mi, eleifend et maximus vitae, pretium varius velit. Integer maximus egestas urna, at semper augue egestas vitae. Phasellus arcu tellus, tincidunt eget tellus nec, hendrerit mollis mauris. Pellentesque commodo urna quis nisi ultrices, quis vehicula felis ultricies. Vivamus eu feugiat leo.\n" +
|
||||
"\n" +
|
||||
"Etiam sit amet lorem et eros suscipit rhoncus a a tellus. Sed pharetra dui purus, quis molestie leo congue nec. Suspendisse sed scelerisque quam. Vestibulum non laoreet felis. Fusce interdum euismod purus at scelerisque. Vivamus tempus varius nibh, sed accumsan nisl interdum non. Pellentesque rutrum egestas eros sit amet sollicitudin. Vivamus ultrices est erat. Curabitur gravida justo non felis euismod mollis. Ut porta finibus nulla, sed pellentesque purus euismod ac.\n" +
|
||||
"\n" +
|
||||
"Aliquam erat volutpat. Nullam suscipit sit amet tortor vel fringilla. Nulla facilisi. Nullam lacinia ex lacus, sit amet scelerisque justo semper a. Nullam ullamcorper, erat ac malesuada porta, augue erat sagittis mi, in auctor turpis mauris nec orci. Nunc sit amet felis placerat, pharetra diam nec, dapibus metus. Proin nulla orci, iaculis vitae vulputate vel, placerat ac erat. Morbi sit amet blandit velit. Cras consectetur vehicula lacus vel sagittis. Nunc tincidunt lacus in blandit faucibus. Curabitur vestibulum auctor vehicula. Sed quis ligula sit amet quam venenatis venenatis eget id felis. Maecenas feugiat nisl elit, facilisis tempus risus malesuada quis. " +
|
||||
"# 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";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create(factoryBuilder ->
|
||||
factoryBuilder.addInlineProcessor(new TooltipInlineProcessor())))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureVisitor(@NonNull MarkwonVisitor.Builder builder) {
|
||||
builder.on(TooltipNode.class, (visitor, tooltipNode) -> {
|
||||
final int start = visitor.length();
|
||||
visitor.builder().append(tooltipNode.label);
|
||||
visitor.setSpans(start, new TooltipSpan(tooltipNode.contents));
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
||||
|
||||
class TooltipInlineProcessor extends InlineProcessor {
|
||||
|
||||
// NB! without bang
|
||||
// `\\{` is required (although marked as redundant), without it - runtime crash
|
||||
@SuppressWarnings("RegExpRedundantEscape")
|
||||
private static final Pattern RE = Pattern.compile("\\{(.+?)\\}\\((.+?)\\)");
|
||||
|
||||
@Override
|
||||
public char specialCharacter() {
|
||||
return '!';
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected Node parse() {
|
||||
final String match = match(RE);
|
||||
if (match == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final Matcher matcher = RE.matcher(match);
|
||||
if (matcher.matches()) {
|
||||
final String label = matcher.group(1);
|
||||
final String contents = matcher.group(2);
|
||||
return new TooltipNode(label, contents);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class TooltipNode extends CustomNode {
|
||||
final String label;
|
||||
final String contents;
|
||||
|
||||
TooltipNode(@NonNull String label, @NonNull String contents) {
|
||||
this.label = label;
|
||||
this.contents = contents;
|
||||
}
|
||||
}
|
||||
|
||||
class TooltipSpan extends ClickableSpan {
|
||||
final String contents;
|
||||
|
||||
TooltipSpan(@NonNull String contents) {
|
||||
this.contents = contents;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
// just to be safe
|
||||
if (!(widget instanceof TextView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final TextView textView = (TextView) widget;
|
||||
final Spannable spannable = (Spannable) textView.getText();
|
||||
|
||||
// find self ending position (can also obtain start)
|
||||
// final int start = spannable.getSpanStart(this);
|
||||
final int end = spannable.getSpanEnd(this);
|
||||
|
||||
// weird, didn't find self
|
||||
if (/*start < 0 ||*/ end < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Layout layout = textView.getLayout();
|
||||
if (layout == null) {
|
||||
// also weird
|
||||
return;
|
||||
}
|
||||
|
||||
final int line = layout.getLineForOffset(end);
|
||||
|
||||
// position inside TextView, these values must also be adjusted to parent widget
|
||||
// also note that container can
|
||||
final int y = layout.getLineBottom(line);
|
||||
final int x = (int) (layout.getPrimaryHorizontal(end) + 0.5F);
|
||||
|
||||
final Window window = ((Activity) widget.getContext()).getWindow();
|
||||
final View decor = window.getDecorView();
|
||||
final Point point = relativeTo(decor, widget);
|
||||
|
||||
// new Tooltip.Builder(widget.getContext())
|
||||
// .anchor(x + point.x, y + point.y)
|
||||
// .text(contents)
|
||||
// .create()
|
||||
// .show(widget, Tooltip.Gravity.TOP, false);
|
||||
|
||||
// Toast is not reliable when tried to position on the screen
|
||||
// but anyway, this is to showcase only
|
||||
final Toast toast = Toast.makeText(widget.getContext(), contents, Toast.LENGTH_LONG);
|
||||
toast.setGravity(Gravity.TOP | Gravity.START, x + point.x, y + point.y);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
// can customize appearance here as spans will be rendered as links
|
||||
super.updateDrawState(ds);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Point relativeTo(@NonNull View parent, @NonNull View who) {
|
||||
return relativeTo(parent, who, new Point());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private static Point relativeTo(@NonNull View parent, @NonNull View who, @NonNull Point point) {
|
||||
// NB! the scroll adjustments (we are interested in screen position,
|
||||
// not real position inside parent)
|
||||
point.x += who.getLeft();
|
||||
point.y += who.getTop();
|
||||
point.x -= who.getScrollX();
|
||||
point.y -= who.getScrollY();
|
||||
if (who != parent
|
||||
&& who.getParent() instanceof View) {
|
||||
relativeTo(parent, (View) who.getParent(), point);
|
||||
}
|
||||
return point;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
@MarkwonSampleInfo(
|
||||
id = "202006182170723",
|
||||
title = "Inline parsing with defaults",
|
||||
description = "Parsing with all defaults except links",
|
||||
artifacts = MarkwonArtifact.INLINE_PARSER,
|
||||
tags = {Tags.inline, Tags.parsing}
|
||||
)
|
||||
|
@ -0,0 +1,33 @@
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202006182200257",
|
||||
title = "LaTex block",
|
||||
description = "Render LaTeX block",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = {Tags.rendering}
|
||||
)
|
||||
public class LatexBlockSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# LaTeX\n" +
|
||||
"$$\n" +
|
||||
"" + LatexHolder.LATEX_ARRAY + "\n" +
|
||||
"$$";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize()))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183094225",
|
||||
title = "LaTeX dark",
|
||||
description = "LaTeX automatically uses `TextView` text color " +
|
||||
"if not configured explicitly",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
)
|
||||
public class LatexDarkSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
scrollView.setBackgroundColor(0xFF000000);
|
||||
textView.setTextColor(0xFFffffff);
|
||||
|
||||
final String md = "" +
|
||||
"# LaTeX\n" +
|
||||
"$$\n" +
|
||||
"\\int \\frac{1}{x} dx = \\ln \\left| x \\right| + C\n" +
|
||||
"$$\n" +
|
||||
"text color is taken from text";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize()))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183120848",
|
||||
title = "LaTeX default text color",
|
||||
description = "LaTeX will use text color of `TextView` by default",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
)
|
||||
public class LatexDefaultTextColorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
// @since 4.3.0 text color is automatically taken from textView
|
||||
// (if it's not specified explicitly via configuration)
|
||||
textView.setTextColor(Color.RED);
|
||||
|
||||
final String md = "" +
|
||||
"# LaTeX default text color\n" +
|
||||
"$$\n" +
|
||||
"" + LatexHolder.LATEX_LONG_DIVISION + "\n" +
|
||||
"$$\n" +
|
||||
"";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize()))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183093504",
|
||||
title = "LaTeX inline/block different text size",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.rendering}
|
||||
)
|
||||
public class LatexDifferentTextSizesSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# LaTeX different text sizes\n" +
|
||||
"inline: " + LatexHolder.LATEX_BANGLE + ", okay and block:\n" +
|
||||
"$$\n" +
|
||||
"" + LatexHolder.LATEX_BANGLE + "\n" +
|
||||
"$$\n" +
|
||||
"that's it";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(
|
||||
textView.getTextSize() * 0.75F,
|
||||
textView.getTextSize() * 1.50F,
|
||||
builder -> {
|
||||
builder.inlinesEnabled(true);
|
||||
}
|
||||
))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183122624",
|
||||
title = "LaTeX error handling",
|
||||
description = "Log error when parsing LaTeX and display error drawable",
|
||||
artifacts = MarkwonArtifact.EXT_LATEX,
|
||||
tags = Tags.rendering
|
||||
)
|
||||
public class LatexErrorSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# LaTeX with error\n" +
|
||||
"$$\n" +
|
||||
"\\sum_{i=0}^\\infty x \\cdot 0 \\rightarrow \\iMightNotExist{0}\n" +
|
||||
"$$\n\n" +
|
||||
"must **not** be rendered";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
|
||||
builder.inlinesEnabled(true);
|
||||
//noinspection Convert2Lambda
|
||||
builder.errorHandler(new JLatexMathPlugin.ErrorHandler() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Drawable handleError(@Nullable String latex, @NonNull Throwable error) {
|
||||
Debug.e(error, latex);
|
||||
return ContextCompat.getDrawable(context, R.drawable.ic_android_black_24dp);
|
||||
}
|
||||
});
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183085820",
|
||||
title = "LaTeX inline",
|
||||
description = "Display LaTeX inline",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = Tags.rendering
|
||||
)
|
||||
public class LatexInlineSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# LaTeX inline\n" +
|
||||
"hey = $$" + LatexHolder.LATEX_BANGLE + "$$,\n" +
|
||||
"that's it!";
|
||||
|
||||
// inlines must be explicitly enabled and require `MarkwonInlineParserPlugin`
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
|
||||
builder.inlinesEnabled(true);
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183090335",
|
||||
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
|
||||
)
|
||||
public class LatexLegacySample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# LaTeX legacy\n" +
|
||||
"There are no inlines in previous versions, only blocks:\n" +
|
||||
"$$\n" +
|
||||
"" + LatexHolder.LATEX_BOXES + "\n" +
|
||||
"$$\n" +
|
||||
"yeah";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
|
||||
builder.blocksLegacy(true);
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
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.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183090618",
|
||||
title = "LaTeX omega symbol",
|
||||
description = "Bug rendering omega symbol in LaTeX",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = {Tags.rendering, Tags.knownBug}
|
||||
)
|
||||
public class LatexOmegaSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Block\n\n" +
|
||||
"$$\n" +
|
||||
"\\Omega\n" +
|
||||
"$$\n\n" +
|
||||
"# Inline\n\n" +
|
||||
"$$\\Omega$$";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
|
||||
builder.inlinesEnabled(true);
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
package io.noties.markwon.app.samples.latex;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
|
||||
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.ext.latex.JLatexMathTheme;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183121528",
|
||||
title = "LaTeX theme",
|
||||
description = "Sample of theme customization for LaTeX",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.INLINE_PARSER},
|
||||
tags = Tags.rendering
|
||||
)
|
||||
public class LatexThemeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# LaTeX theme\n" +
|
||||
"Hello there $$" + LatexHolder.LATEX_BANGLE + "$$, how was it?" +
|
||||
"Now, what about a _different_ approach and block:\n\n" +
|
||||
"$$\n" +
|
||||
"" + LatexHolder.LATEX_LONG_DIVISION + "\n" +
|
||||
"$$\n\n" +
|
||||
"Seems **fine**";
|
||||
|
||||
final int blockPadding = (int) (16 * context.getResources().getDisplayMetrics().density + 0.5F);
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> {
|
||||
builder.inlinesEnabled(true);
|
||||
builder.theme()
|
||||
.inlineBackgroundProvider(() -> new ColorDrawable(0x200000ff))
|
||||
.inlineTextColor(Color.GREEN)
|
||||
.blockBackgroundProvider(() -> new ColorDrawable(0x2000ff00))
|
||||
.blockPadding(JLatexMathTheme.Padding.all(blockPadding))
|
||||
.blockTextColor(Color.RED)
|
||||
;
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
package io.noties.markwon.app.samples.latex.shared;
|
||||
|
||||
public abstract class LatexHolder {
|
||||
|
||||
public static final String LATEX_ARRAY;
|
||||
public static final String LATEX_LONG_DIVISION = "\\text{A long division \\longdiv{12345}{13}";
|
||||
public static final String LATEX_BANGLE = "{a \\bangle b} {c \\brace d} {e \\brack f} {g \\choose h}";
|
||||
public static final String LATEX_BOXES;
|
||||
|
||||
static {
|
||||
String latex = "\\begin{array}{cc}";
|
||||
latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
|
||||
latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
|
||||
latex += "\\end{array}";
|
||||
LATEX_BOXES = latex;
|
||||
}
|
||||
|
||||
static {
|
||||
String latex = "\\begin{array}{l}";
|
||||
latex += "\\forall\\varepsilon\\in\\mathbb{R}_+^*\\ \\exists\\eta>0\\ |x-x_0|\\leq\\eta\\Longrightarrow|f(x)-f(x_0)|\\leq\\varepsilon\\\\";
|
||||
latex += "\\det\\begin{bmatrix}a_{11}&a_{12}&\\cdots&a_{1n}\\\\a_{21}&\\ddots&&\\vdots\\\\\\vdots&&\\ddots&\\vdots\\\\a_{n1}&\\cdots&\\cdots&a_{nn}\\end{bmatrix}\\overset{\\mathrm{def}}{=}\\sum_{\\sigma\\in\\mathfrak{S}_n}\\varepsilon(\\sigma)\\prod_{k=1}^n a_{k\\sigma(k)}\\\\";
|
||||
latex += "\\sideset{_\\alpha^\\beta}{_\\gamma^\\delta}{\\begin{pmatrix}a&b\\\\c&d\\end{pmatrix}}\\\\";
|
||||
latex += "\\int_0^\\infty{x^{2n} e^{-a x^2}\\,dx} = \\frac{2n-1}{2a} \\int_0^\\infty{x^{2(n-1)} e^{-a x^2}\\,dx} = \\frac{(2n-1)!!}{2^{n+1}} \\sqrt{\\frac{\\pi}{a^{2n+1}}}\\\\";
|
||||
latex += "\\int_a^b{f(x)\\,dx} = (b - a) \\sum\\limits_{n = 1}^\\infty {\\sum\\limits_{m = 1}^{2^n - 1} {\\left( { - 1} \\right)^{m + 1} } } 2^{ - n} f(a + m\\left( {b - a} \\right)2^{-n} )\\\\";
|
||||
latex += "\\int_{-\\pi}^{\\pi} \\sin(\\alpha x) \\sin^n(\\beta x) dx = \\textstyle{\\left \\{ \\begin{array}{cc} (-1)^{(n+1)/2} (-1)^m \\frac{2 \\pi}{2^n} \\binom{n}{m} & n \\mbox{ odd},\\ \\alpha = \\beta (2m-n) \\\\ 0 & \\mbox{otherwise} \\\\ \\end{array} \\right .}\\\\";
|
||||
latex += "L = \\int_a^b \\sqrt{ \\left|\\sum_{i,j=1}^ng_{ij}(\\gamma(t))\\left(\\frac{d}{dt}x^i\\circ\\gamma(t)\\right)\\left(\\frac{d}{dt}x^j\\circ\\gamma(t)\\right)\\right|}\\,dt\\\\";
|
||||
latex += "\\begin{array}{rl} s &= \\int_a^b\\left\\|\\frac{d}{dt}\\vec{r}\\,(u(t),v(t))\\right\\|\\,dt \\\\ &= \\int_a^b \\sqrt{u'(t)^2\\,\\vec{r}_u\\cdot\\vec{r}_u + 2u'(t)v'(t)\\, \\vec{r}_u\\cdot\\vec{r}_v+ v'(t)^2\\,\\vec{r}_v\\cdot\\vec{r}_v}\\,\\,\\, dt. \\end{array}\\\\";
|
||||
latex += "\\end{array}";
|
||||
LATEX_ARRAY = latex;
|
||||
}
|
||||
|
||||
|
||||
private LatexHolder() {
|
||||
}
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
package io.noties.markwon.app.samples.notification;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.BulletSpan;
|
||||
import android.text.style.QuoteSpan;
|
||||
import android.text.style.StrikethroughSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||
import org.commonmark.node.BlockQuote;
|
||||
import org.commonmark.node.Code;
|
||||
import org.commonmark.node.Emphasis;
|
||||
import org.commonmark.node.ListItem;
|
||||
import org.commonmark.node.StrongEmphasis;
|
||||
|
||||
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.app.samples.notification.shared.NotificationUtils;
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007183130729",
|
||||
title = "Markdown in Notification",
|
||||
description = "Proof of concept of using `Markwon` with `android.app.Notification`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.hack
|
||||
)
|
||||
public class NotificationSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
// supports:
|
||||
// * bold -> StyleSpan(BOLD)
|
||||
// * italic -> StyleSpan(ITALIC)
|
||||
// * quote -> QuoteSpan()
|
||||
// * strikethrough -> StrikethroughSpan()
|
||||
// * bullet list -> BulletSpan()
|
||||
|
||||
// * link -> is styled but not clickable
|
||||
// * code -> typeface monospace works, background is not
|
||||
|
||||
final String md = "" +
|
||||
"**bold _bold-italic_ bold** ~~strike~~ `code` [link](#)\n\n" +
|
||||
"* bullet-one\n" +
|
||||
"* * bullet-two\n" +
|
||||
" * bullet-three\n\n" +
|
||||
"> a quote\n\n" +
|
||||
"";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(StrikethroughPlugin.create())
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
builder
|
||||
.setFactory(Emphasis.class, (configuration, props) -> new StyleSpan(Typeface.ITALIC))
|
||||
.setFactory(StrongEmphasis.class, (configuration, props) -> new StyleSpan(Typeface.BOLD))
|
||||
.setFactory(BlockQuote.class, (configuration, props) -> new QuoteSpan())
|
||||
.setFactory(Strikethrough.class, (configuration, props) -> new StrikethroughSpan())
|
||||
// NB! notification does not handle background color
|
||||
.setFactory(Code.class, (configuration, props) -> new Object[]{
|
||||
new BackgroundColorSpan(Color.GRAY),
|
||||
new TypefaceSpan("monospace")
|
||||
})
|
||||
// NB! both ordered and bullet list items
|
||||
.setFactory(ListItem.class, (configuration, props) -> new BulletSpan());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
|
||||
NotificationUtils.display(context, markwon.toMarkdown(md));
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
package io.noties.markwon.app.samples.notification;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.style.BackgroundColorSpan;
|
||||
import android.text.style.BulletSpan;
|
||||
import android.text.style.QuoteSpan;
|
||||
import android.text.style.RelativeSizeSpan;
|
||||
import android.text.style.StrikethroughSpan;
|
||||
import android.text.style.StyleSpan;
|
||||
import android.text.style.TypefaceSpan;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
|
||||
import org.commonmark.node.BlockQuote;
|
||||
import org.commonmark.node.Code;
|
||||
import org.commonmark.node.Emphasis;
|
||||
import org.commonmark.node.Heading;
|
||||
import org.commonmark.node.ListItem;
|
||||
import org.commonmark.node.StrongEmphasis;
|
||||
|
||||
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.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.app.samples.notification.shared.NotificationUtils;
|
||||
import io.noties.markwon.core.CoreProps;
|
||||
import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184090140",
|
||||
title = "RemoteViews in notification",
|
||||
description = "Display markdown with platform (system) spans in notification via `RemoteViews`",
|
||||
artifacts = MarkwonArtifact.CORE,
|
||||
tags = Tags.hack
|
||||
)
|
||||
public class RemoteViewsSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"# Heading 1\n" +
|
||||
// "## Heading 2\n" +
|
||||
// "### Heading 3\n" +
|
||||
// "#### Heading 4\n" +
|
||||
// "##### Heading 5\n" +
|
||||
// "###### Heading 6\n" +
|
||||
"**bold _italic_ bold** `code` [link](#) ~~strike~~\n" +
|
||||
"* Bullet 1\n" +
|
||||
"* * Bullet 2\n" +
|
||||
" * Bullet 3\n" +
|
||||
"> A quote **here**";
|
||||
|
||||
final float[] headingSizes = {
|
||||
2.F, 1.5F, 1.17F, 1.F, .83F, .67F,
|
||||
};
|
||||
|
||||
final int bulletGapWidth = (int) (8 * context.getResources().getDisplayMetrics().density + 0.5F);
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(StrikethroughPlugin.create())
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
builder
|
||||
.setFactory(Heading.class, (configuration, props) -> new Object[]{
|
||||
new StyleSpan(Typeface.BOLD),
|
||||
new RelativeSizeSpan(headingSizes[CoreProps.HEADING_LEVEL.require(props) - 1])
|
||||
})
|
||||
.setFactory(StrongEmphasis.class, (configuration, props) -> new StyleSpan(Typeface.BOLD))
|
||||
.setFactory(Emphasis.class, (configuration, props) -> new StyleSpan(Typeface.ITALIC))
|
||||
.setFactory(Code.class, (configuration, props) -> new Object[]{
|
||||
new BackgroundColorSpan(Color.GRAY),
|
||||
new TypefaceSpan("monospace")
|
||||
})
|
||||
.setFactory(Strikethrough.class, (configuration, props) -> new StrikethroughSpan())
|
||||
.setFactory(ListItem.class, (configuration, props) -> new BulletSpan(bulletGapWidth))
|
||||
.setFactory(BlockQuote.class, (configuration, props) -> new QuoteSpan());
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
final RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.sample_remote_view);
|
||||
remoteViews.setTextViewText(R.id.text_view, markwon.toMarkdown(md));
|
||||
|
||||
NotificationUtils.display(context, remoteViews);
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package io.noties.markwon.app.samples.notification.shared;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationChannel;
|
||||
import android.app.NotificationManager;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.widget.RemoteViews;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import io.noties.markwon.app.R;
|
||||
|
||||
public abstract class NotificationUtils {
|
||||
|
||||
private static final int ID = 2;
|
||||
private static final String CHANNEL_ID = "2";
|
||||
|
||||
public static void display(@NonNull Context context, @NonNull CharSequence cs) {
|
||||
final NotificationManager manager = context.getSystemService(NotificationManager.class);
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensureChannel(manager, CHANNEL_ID);
|
||||
|
||||
final Notification.Builder builder = new Notification.Builder(context)
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setContentTitle(context.getString(R.string.app_name))
|
||||
.setContentText(cs)
|
||||
.setStyle(new Notification.BigTextStyle().bigText(cs));
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder.setChannelId(CHANNEL_ID);
|
||||
}
|
||||
|
||||
manager.notify(ID, builder.build());
|
||||
}
|
||||
|
||||
public static void display(@NonNull Context context, @NonNull RemoteViews remoteViews) {
|
||||
final NotificationManager manager = context.getSystemService(NotificationManager.class);
|
||||
if (manager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensureChannel(manager, CHANNEL_ID);
|
||||
|
||||
final Notification.Builder builder = new Notification.Builder(context)
|
||||
.setSmallIcon(R.drawable.ic_stat_name)
|
||||
.setContentTitle(context.getString(R.string.app_name));
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
builder
|
||||
.setCustomContentView(remoteViews)
|
||||
.setCustomBigContentView(remoteViews);
|
||||
} else {
|
||||
builder.setContent(remoteViews);
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
builder.setChannelId(CHANNEL_ID);
|
||||
}
|
||||
|
||||
manager.notify(ID, builder.build());
|
||||
}
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static void ensureChannel(@NonNull NotificationManager manager, @NonNull String channelId) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
|
||||
return;
|
||||
}
|
||||
|
||||
final NotificationChannel channel = manager.getNotificationChannel(channelId);
|
||||
if (channel == null) {
|
||||
manager.createNotificationChannel(new NotificationChannel(
|
||||
channelId,
|
||||
channelId,
|
||||
NotificationManager.IMPORTANCE_DEFAULT
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
private NotificationUtils() {
|
||||
}
|
||||
}
|
@ -1,10 +1,5 @@
|
||||
package io.noties.markwon.app.samples.plugins;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import io.noties.markwon.Markwon;
|
||||
import io.noties.markwon.app.R;
|
||||
import io.noties.markwon.app.sample.Tags;
|
||||
@ -22,14 +17,6 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
)
|
||||
public class AnchorSample extends MarkwonTextViewSample {
|
||||
|
||||
private ScrollView scrollView;
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NotNull View view) {
|
||||
scrollView = view.findViewById(R.id.scroll_view);
|
||||
super.onViewCreated(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
package io.noties.markwon.app.samples.plugins;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.ScrollView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.commonmark.node.AbstractVisitor;
|
||||
@ -13,7 +10,6 @@ import org.commonmark.node.Link;
|
||||
import org.commonmark.node.ListItem;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.node.Text;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import io.noties.markwon.AbstractMarkwonPlugin;
|
||||
import io.noties.markwon.Markwon;
|
||||
@ -35,14 +31,6 @@ import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
)
|
||||
public class TableOfContentsSample extends MarkwonTextViewSample {
|
||||
|
||||
private ScrollView scrollView;
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NotNull View view) {
|
||||
scrollView = view.findViewById(R.id.scroll_view);
|
||||
super.onViewCreated(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render() {
|
||||
final String lorem = context.getString(R.string.lorem);
|
||||
|
@ -0,0 +1,47 @@
|
||||
package io.noties.markwon.app.samples.table;
|
||||
|
||||
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.ext.tables.TablePlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
import io.noties.markwon.utils.ColorUtils;
|
||||
import io.noties.markwon.utils.Dip;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184135621",
|
||||
title = "Customize table theme",
|
||||
artifacts = MarkwonArtifact.EXT_TABLES,
|
||||
tags = {Tags.theme}
|
||||
)
|
||||
public class TableCustomizeSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"| HEADER | HEADER | HEADER |\n" +
|
||||
"|:----:|:----:|:----:|\n" +
|
||||
"| 测试 | 测试 | 测试 |\n" +
|
||||
"| 测试 | 测试 | 测测测12345试测试测试 |\n" +
|
||||
"| 测试 | 测试 | 123445 |\n" +
|
||||
"| 测试 | 测试 | (650) 555-1212 |\n" +
|
||||
"| 测试 | 测试 | [link](#) |\n";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(TablePlugin.create(builder -> {
|
||||
final Dip dip = Dip.create(context);
|
||||
builder
|
||||
.tableBorderWidth(dip.toPx(2))
|
||||
.tableBorderColor(Color.YELLOW)
|
||||
.tableCellPadding(dip.toPx(4))
|
||||
.tableHeaderRowBackgroundColor(ColorUtils.applyAlpha(Color.RED, 80))
|
||||
.tableEvenRowBackgroundColor(ColorUtils.applyAlpha(Color.GREEN, 80))
|
||||
.tableOddRowBackgroundColor(ColorUtils.applyAlpha(Color.BLUE, 80));
|
||||
}))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
package io.noties.markwon.app.samples.table;
|
||||
|
||||
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.ext.tables.TablePlugin;
|
||||
import io.noties.markwon.image.ImagesPlugin;
|
||||
import io.noties.markwon.inlineparser.MarkwonInlineParserPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184140041",
|
||||
title = "LaTeX inside table",
|
||||
description = "Usage of LaTeX formulas inside markdown tables",
|
||||
artifacts = {MarkwonArtifact.EXT_LATEX, MarkwonArtifact.EXT_TABLES, MarkwonArtifact.IMAGE},
|
||||
tags = {Tags.image}
|
||||
)
|
||||
public class TableLatexSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
String latex = "\\begin{array}{cc}";
|
||||
latex += "\\fbox{\\text{A framed box with \\textdbend}}&\\shadowbox{\\text{A shadowed box}}\\cr";
|
||||
latex += "\\doublebox{\\text{A double framed box}}&\\ovalbox{\\text{An oval framed box}}\\cr";
|
||||
latex += "\\end{array}";
|
||||
|
||||
final String md = "" +
|
||||
"| HEADER | HEADER |\n" +
|
||||
"|:----:|:----:|\n" +
|
||||
"|  | Build |\n" +
|
||||
"| Stable |  |\n" +
|
||||
"| BIG | $$" + latex + "$$ |\n" +
|
||||
"\n";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(MarkwonInlineParserPlugin.create())
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(JLatexMathPlugin.create(textView.getTextSize(), builder -> builder.inlinesEnabled(true)))
|
||||
.usePlugin(TablePlugin.create(context))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package io.noties.markwon.app.samples.table;
|
||||
|
||||
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.linkify.LinkifyPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184135739",
|
||||
title = "Linkify table",
|
||||
description = "Automatically linkify markdown content " +
|
||||
"including content inside tables",
|
||||
artifacts = {MarkwonArtifact.EXT_TABLES, MarkwonArtifact.LINKIFY},
|
||||
tags = {Tags.links}
|
||||
)
|
||||
public class TableLinkifySample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"| HEADER | HEADER | HEADER |\n" +
|
||||
"|:----:|:----:|:----:|\n" +
|
||||
"| 测试 | 测试 | 测试 |\n" +
|
||||
"| 测试 | 测试 | 测测测12345试测试测试 |\n" +
|
||||
"| 测试 | 测试 | 123445 |\n" +
|
||||
"| 测试 | 测试 | (650) 555-1212 |\n" +
|
||||
"| 测试 | 测试 | [link](#) |\n" +
|
||||
"\n" +
|
||||
"测试\n" +
|
||||
"\n" +
|
||||
"[link link](https://link.link)";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(LinkifyPlugin.create())
|
||||
.usePlugin(TablePlugin.create(context))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package io.noties.markwon.app.samples.table;
|
||||
|
||||
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;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184135932",
|
||||
title = "Images inside table",
|
||||
description = "Usage of images inside markdown tables",
|
||||
artifacts = {MarkwonArtifact.EXT_TABLES, MarkwonArtifact.IMAGE},
|
||||
tags = Tags.image
|
||||
)
|
||||
public class TableWithImagesSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final String md = "" +
|
||||
"| HEADER | HEADER |\n" +
|
||||
"|:----:|:----:|\n" +
|
||||
"|  | Build |\n" +
|
||||
"| Stable |  |\n" +
|
||||
"| BIG |  |\n" +
|
||||
"\n";
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(ImagesPlugin.create())
|
||||
.usePlugin(TablePlugin.create(context))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, md);
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package io.noties.markwon.app.samples.tasklist;
|
||||
|
||||
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.ext.tasklist.TaskListPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
import static io.noties.markwon.app.samples.tasklist.shared.TaskListHolder.MD;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184140536",
|
||||
title = "GFM task list custom colors",
|
||||
description = "Custom colors for task list extension",
|
||||
artifacts = MarkwonArtifact.EXT_TASKLIST,
|
||||
tags = Tags.parsing
|
||||
)
|
||||
public class TaskListCustomColorsSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final int checkedFillColor = Color.RED;
|
||||
final int normalOutlineColor = Color.GREEN;
|
||||
final int checkMarkColor = Color.BLUE;
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(TaskListPlugin.create(checkedFillColor, normalOutlineColor, checkMarkColor))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, MD);
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
package io.noties.markwon.app.samples.tasklist;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
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.tasklist.TaskListPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
import static io.noties.markwon.app.samples.tasklist.shared.TaskListHolder.MD;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184140749",
|
||||
title = "GFM task list custom drawable",
|
||||
artifacts = MarkwonArtifact.EXT_TASKLIST,
|
||||
tags = Tags.plugin
|
||||
)
|
||||
public class TaskListCustomDrawableSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final Drawable drawable = Objects.requireNonNull(
|
||||
ContextCompat.getDrawable(context, R.drawable.custom_task_list));
|
||||
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(TaskListPlugin.create(drawable))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, MD);
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package io.noties.markwon.app.samples.tasklist;
|
||||
|
||||
import android.text.Spanned;
|
||||
import android.text.TextPaint;
|
||||
import android.text.style.ClickableSpan;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
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.Tags;
|
||||
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample;
|
||||
import io.noties.markwon.ext.tasklist.TaskListItem;
|
||||
import io.noties.markwon.ext.tasklist.TaskListPlugin;
|
||||
import io.noties.markwon.ext.tasklist.TaskListSpan;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
import static io.noties.markwon.app.samples.tasklist.shared.TaskListHolder.MD;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184140901",
|
||||
title = "GFM task list mutate",
|
||||
artifacts = MarkwonArtifact.EXT_TASKLIST,
|
||||
tags = Tags.plugin
|
||||
)
|
||||
public class TaskListMutateSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(TaskListPlugin.create(context))
|
||||
.usePlugin(new AbstractMarkwonPlugin() {
|
||||
@Override
|
||||
public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) {
|
||||
// obtain origin task-list-factory
|
||||
final SpanFactory origin = builder.getFactory(TaskListItem.class);
|
||||
if (origin == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
builder.setFactory(TaskListItem.class, (configuration, props) -> {
|
||||
// maybe it's better to validate the actual type here also
|
||||
// and not force cast to task-list-span
|
||||
final TaskListSpan span = (TaskListSpan) origin.getSpans(configuration, props);
|
||||
if (span == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// NB, toggle click will intercept possible links inside task-list-item
|
||||
return new Object[]{
|
||||
span,
|
||||
new TaskListToggleSpan(span)
|
||||
};
|
||||
});
|
||||
}
|
||||
})
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, MD);
|
||||
}
|
||||
}
|
||||
|
||||
class TaskListToggleSpan extends ClickableSpan {
|
||||
|
||||
private final TaskListSpan span;
|
||||
|
||||
TaskListToggleSpan(@NonNull TaskListSpan span) {
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(@NonNull View widget) {
|
||||
// toggle span (this is a mere visual change)
|
||||
span.setDone(!span.isDone());
|
||||
// request visual update
|
||||
widget.invalidate();
|
||||
|
||||
// it must be a TextView
|
||||
final TextView textView = (TextView) widget;
|
||||
// it must be spanned
|
||||
final Spanned spanned = (Spanned) textView.getText();
|
||||
|
||||
// actual text of the span (this can be used along with the `span`)
|
||||
final CharSequence task = spanned.subSequence(
|
||||
spanned.getSpanStart(this),
|
||||
spanned.getSpanEnd(this)
|
||||
);
|
||||
|
||||
Debug.i("task done: %s, '%s'", span.isDone(), task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateDrawState(@NonNull TextPaint ds) {
|
||||
// no op, so text is not rendered as a link
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package io.noties.markwon.app.samples.tasklist;
|
||||
|
||||
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.tasklist.TaskListPlugin;
|
||||
import io.noties.markwon.sample.annotations.MarkwonArtifact;
|
||||
import io.noties.markwon.sample.annotations.MarkwonSampleInfo;
|
||||
|
||||
import static io.noties.markwon.app.samples.tasklist.shared.TaskListHolder.MD;
|
||||
|
||||
@MarkwonSampleInfo(
|
||||
id = "202007184140352",
|
||||
title = "GFM task list",
|
||||
description = "Github Flavored Markdown (GFM) task list extension",
|
||||
artifacts = MarkwonArtifact.EXT_TASKLIST,
|
||||
tags = Tags.plugin
|
||||
)
|
||||
public class TaskListSample extends MarkwonTextViewSample {
|
||||
@Override
|
||||
public void render() {
|
||||
final Markwon markwon = Markwon.builder(context)
|
||||
.usePlugin(TaskListPlugin.create(context))
|
||||
.build();
|
||||
|
||||
markwon.setMarkdown(textView, MD);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package io.noties.markwon.app.samples.tasklist.shared;
|
||||
|
||||
public abstract class TaskListHolder {
|
||||
|
||||
public static final String MD = "" +
|
||||
"- [ ] Not done here!\n" +
|
||||
"- [x] and done\n" +
|
||||
"- [X] and again!\n" +
|
||||
"* [ ] **and** syntax _included_ `code`\n" +
|
||||
"- [ ] [link](#)\n" +
|
||||
"- [ ] [a check box](https://examp.le)\n" +
|
||||
"- [x] [test]()\n" +
|
||||
"- [List](https://examp.le) 3";
|
||||
|
||||
private TaskListHolder() {
|
||||
}
|
||||
}
|
5
app-sample/src/main/res/drawable/custom_task_list.xml
Normal file
5
app-sample/src/main/res/drawable/custom_task_list.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_checked="true" android:drawable="@drawable/ic_android_black_24dp" />
|
||||
<item android:drawable="@drawable/ic_home_black_36dp" />
|
||||
</selector>
|
31
app-sample/src/main/res/drawable/ic_stat_name.xml
Normal file
31
app-sample/src/main/res/drawable/ic_stat_name.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:name="vector"
|
||||
android:width="512dp"
|
||||
android:height="512dp"
|
||||
android:viewportWidth="512"
|
||||
android:viewportHeight="512">
|
||||
<group android:name="group_3">
|
||||
<group android:name="group">
|
||||
<path
|
||||
android:name="path"
|
||||
android:pathData="M 296.339 368.334 L 296.339 351.583 L 299.412 351.583 Q 304.33 351.583 308.018 350.969 Q 311.86 350.354 314.318 348.51 Q 316.777 346.666 318.007 343.285 Q 319.236 339.751 319.236 334.065 L 319.236 174.708 L 255.77 368.334 L 234.409 368.334 L 167.87 174.708 L 167.87 331.145 Q 167.87 337.907 169.406 341.902 Q 171.097 345.898 174.016 348.049 Q 177.09 350.2 181.393 350.969 Q 185.696 351.583 191.228 351.583 L 193.072 351.583 L 193.072 368.334 L 115.007 368.334 L 115.007 351.583 L 128.222 351.583 Q 131.603 351.583 134.523 350.969 Q 137.443 350.354 139.594 348.51 Q 141.899 346.512 143.129 342.824 Q 144.358 338.982 144.358 332.836 L 144.358 179.472 Q 144.358 173.171 143.129 169.483 Q 141.899 165.641 139.594 163.643 Q 137.443 161.646 134.523 161.031 Q 131.603 160.263 128.222 160.263 L 115.007 160.263 L 115.007 143.666 L 205.673 143.666 L 257.921 295.647 L 308.018 143.666 L 396.994 143.666 L 396.994 160.263 L 383.778 160.263 Q 380.397 160.263 377.477 161.031 Q 374.558 161.646 372.406 163.797 Q 370.255 165.948 369.025 169.944 Q 367.796 173.939 367.796 180.701 L 367.796 331.145 Q 367.796 337.907 369.025 341.902 Q 370.255 345.898 372.406 348.049 Q 374.558 350.2 377.477 350.969 Q 380.397 351.583 383.778 351.583 L 396.994 351.583 L 396.994 368.334 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
</group>
|
||||
<group android:name="group_1">
|
||||
<path
|
||||
android:name="path_1"
|
||||
android:pathData="M 122.034 58.217 L 132.361 34.981 L 177.542 63.525 L 169.94 16.909 L 195.471 16.909 L 187.296 63.238 L 232.764 35.699 L 243.091 58.504 L 193.463 72.991 L 243.091 87.334 L 232.764 109.997 L 187.296 82.601 L 195.471 129.073 L 169.94 129.073 L 177.256 82.601 L 132.361 110.57 L 122.034 87.621 L 171.375 72.991 Z M 268.909 58.217 L 279.236 34.981 L 324.417 63.525 L 316.815 16.909 L 342.346 16.909 L 334.171 63.238 L 379.639 35.699 L 389.966 58.504 L 340.338 72.991 L 389.966 87.334 L 379.639 109.997 L 334.171 82.601 L 342.346 129.073 L 316.815 129.073 L 324.13 82.601 L 279.236 110.57 L 268.909 87.621 L 318.25 72.991 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
</group>
|
||||
<group android:name="group_2">
|
||||
<path
|
||||
android:name="path_2"
|
||||
android:pathData="M 122.034 428.561 L 132.361 405.325 L 177.542 433.868 L 169.94 387.252 L 195.471 387.252 L 187.296 433.581 L 232.764 406.042 L 243.091 428.848 L 193.463 443.334 L 243.091 457.678 L 232.764 480.34 L 187.296 452.944 L 195.471 499.417 L 169.94 499.417 L 177.256 452.944 L 132.361 480.914 L 122.034 457.964 L 171.375 443.334 Z M 268.909 428.561 L 279.236 405.325 L 324.417 433.868 L 316.815 387.252 L 342.346 387.252 L 334.171 433.581 L 379.639 406.042 L 389.966 428.848 L 340.338 443.334 L 389.966 457.678 L 379.639 480.34 L 334.171 452.944 L 342.346 499.417 L 316.815 499.417 L 324.13 452.944 L 279.236 480.914 L 268.909 457.964 L 318.25 443.334 Z"
|
||||
android:fillColor="#ffffff"
|
||||
android:strokeWidth="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</vector>
|
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.appcompat.widget.AppCompatTextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="16dip"
|
||||
android:layout_marginRight="16dip"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:paddingTop="8dip"
|
||||
android:paddingBottom="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="#000"
|
||||
tools:text="Hello" />
|
5
app-sample/src/main/res/layout/sample_recycler_view.xml
Normal file
5
app-sample/src/main/res/layout/sample_recycler_view.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
17
app-sample/src/main/res/layout/sample_remote_view.xml
Normal file
17
app-sample/src/main/res/layout/sample_remote_view.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="8dip"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
tools:text="Hello" />
|
||||
|
||||
</LinearLayout>
|
@ -13,6 +13,7 @@
|
||||
android:id="@+id/text_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:lineSpacingExtra="2dip"
|
||||
android:padding="@dimen/content_padding_double"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
|
95
art/markwon-icon-foreground-stroked.svg
Normal file
95
art/markwon-icon-foreground-stroked.svg
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
sodipodi:docname="markwon-icon-foreground-stroked.svg"
|
||||
inkscape:export-ydpi="89.93"
|
||||
inkscape:export-xdpi="89.93"
|
||||
inkscape:export-filename="/Users/di/text4169.png"
|
||||
inkscape:version="1.0beta2 (2b71d25, 2019-12-03)"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
viewBox="0 0 512.00001 512.00001"
|
||||
height="512"
|
||||
width="512">
|
||||
<defs
|
||||
id="defs4" />
|
||||
<sodipodi:namedview
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:window-y="23"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-height="788"
|
||||
inkscape:window-width="1440"
|
||||
units="px"
|
||||
showgrid="false"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-units="px"
|
||||
inkscape:cy="237.21893"
|
||||
inkscape:cx="151.88384"
|
||||
inkscape:zoom="0.92578125"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base" />
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
transform="translate(0,-540.36216)"
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="text4136"
|
||||
aria-label="M">
|
||||
<path
|
||||
id="path26"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:314.719px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif Bold'"
|
||||
d="m 296.33892,908.6958 v -16.75018 h 3.07342 q 4.91749,0 8.6056,-0.61469 3.84179,-0.61468 6.30053,-2.45874 2.45874,-1.84405 3.68811,-5.22482 1.22937,-3.53445 1.22937,-9.22029 V 715.06986 L 255.76967,908.6958 H 234.40935 L 167.86964,715.06986 v 156.43747 q 0,6.76154 1.53671,10.75699 1.69039,3.99546 4.61014,6.14686 3.07343,2.1514 7.37623,2.91975 4.3028,0.61469 9.83497,0.61469 h 1.84406 v 16.75018 h -78.06507 v -16.75018 h 13.21574 q 3.38077,0 6.30053,-0.61469 2.91975,-0.61468 5.07115,-2.45874 2.30507,-1.99773 3.53445,-5.68584 1.22937,-3.84178 1.22937,-9.98864 V 719.83367 q 0,-6.30053 -1.22937,-9.98864 -1.22938,-3.84178 -3.53445,-5.83951 -2.1514,-1.99773 -5.07115,-2.61242 -2.91976,-0.76835 -6.30053,-0.76835 h -13.21574 v -16.59651 h 90.66612 l 52.24827,151.981 50.09687,-151.981 h 88.97573 v 16.59651 h -13.21574 q -3.38077,0 -6.30052,0.76835 -2.91976,0.61469 -5.07116,2.76609 -2.1514,2.1514 -3.38077,6.14685 -1.22937,3.99546 -1.22937,10.757 v 150.44429 q 0,6.76154 1.22937,10.75699 1.22937,3.99546 3.38077,6.14686 2.1514,2.1514 5.07116,2.91975 2.91975,0.61469 6.30052,0.61469 h 13.21574 v 16.75018 z" />
|
||||
</g>
|
||||
<g
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#666666;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="text4140"
|
||||
aria-label="**">
|
||||
<path
|
||||
id="path21"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:293.75px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';fill:#666666"
|
||||
d="m 122.03394,598.57965 10.32715,-23.23608 45.18128,28.54309 -7.60193,-46.6156 h 25.531 l -8.17566,46.32873 45.46814,-27.53906 10.32715,22.80579 -49.62768,14.48669 49.62768,14.34326 -10.32715,22.66236 -45.46814,-27.39563 8.17566,46.47216 h -25.531 l 7.31506,-46.47216 -44.89441,27.96936 -10.32715,-22.94922 49.34082,-14.63013 z" />
|
||||
<path
|
||||
id="path23"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:293.75px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';fill:#666666"
|
||||
d="m 268.90894,598.57965 10.32715,-23.23608 45.18128,28.54309 -7.60193,-46.6156 h 25.531 l -8.17566,46.32873 45.46814,-27.53906 10.32715,22.80579 -49.62768,14.48669 49.62768,14.34326 -10.32715,22.66236 -45.46814,-27.39563 8.17566,46.47216 h -25.531 l 7.31506,-46.47216 -44.89441,27.96936 -10.32715,-22.94922 49.34082,-14.63013 z" />
|
||||
</g>
|
||||
<g
|
||||
style="font-style:normal;font-weight:normal;line-height:0%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#666666;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
id="text4169"
|
||||
aria-label="**">
|
||||
<path
|
||||
id="path29"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:293.75px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';fill:#666666"
|
||||
d="m 122.03394,968.92297 10.32715,-23.23608 45.18128,28.54309 -7.60193,-46.6156 h 25.531 l -8.17566,46.32874 45.46814,-27.53907 10.32715,22.80579 -49.62768,14.48669 49.62768,14.34326 -10.32715,22.66231 -45.46814,-27.39558 8.17566,46.47218 h -25.531 l 7.31506,-46.47218 -44.89441,27.96938 -10.32715,-22.94924 49.34082,-14.63013 z" />
|
||||
<path
|
||||
id="path31"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:293.75px;line-height:1.25;font-family:'Noto Serif';-inkscape-font-specification:'Noto Serif';fill:#666666"
|
||||
d="m 268.90894,968.92297 10.32715,-23.23608 45.18128,28.54309 -7.60193,-46.6156 h 25.531 l -8.17566,46.32874 45.46814,-27.53907 10.32715,22.80579 -49.62768,14.48669 49.62768,14.34326 -10.32715,22.66231 -45.46814,-27.39558 8.17566,46.47218 h -25.531 l 7.31506,-46.47218 -44.89441,27.96938 -10.32715,-22.94924 49.34082,-14.63013 z" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.2 KiB |
@ -81,6 +81,14 @@ public abstract class JLatexMathTheme {
|
||||
public static Padding symmetric(int vertical, int horizontal) {
|
||||
return new Padding(horizontal, vertical, horizontal, vertical);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since $nap;
|
||||
*/
|
||||
@NonNull
|
||||
public static Padding of(int left, int top, int right, int bottom) {
|
||||
return new Padding(left, top, right, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -175,6 +183,10 @@ public abstract class JLatexMathTheme {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure if `LaTeX` formula should take all available widget width.
|
||||
* By default - `true`
|
||||
*/
|
||||
@NonNull
|
||||
public Builder blockFitCanvas(boolean blockFitCanvas) {
|
||||
this.blockFitCanvas = blockFitCanvas;
|
||||
|
Loading…
x
Reference in New Issue
Block a user