Sample app, adding samples

This commit is contained in:
Dimitry Ivanov 2020-06-27 11:24:55 +03:00
parent 377d8c6deb
commit 25740d7389
15 changed files with 415 additions and 18 deletions

View File

@ -4,7 +4,7 @@
#### Added #### Added
* `core` - `MovementMethodPlugin.none()`, `MovementMethodPlugin.link()` factory methods * `core` - `MovementMethodPlugin.none()`, `MovementMethodPlugin.link()` factory methods
* `core` - `CorePlugin` `hasExplicitMovementMethodPlugin` configuration method to **not** add implicit `LinkMovementMethod` in `afterSetText` * `core` - `CorePlugin` `hasExplicitMovementMethod` configuration method to **not** add implicit `LinkMovementMethod` in `afterSetText`
#### Changed #### Changed
* `html` - `SimpleTagHandler` visits children tags if supplied tag is block one ([#235]) * `html` - `SimpleTagHandler` visits children tags if supplied tag is block one ([#235])

View File

@ -1,4 +1,99 @@
[ [
{
"javaClassName": "io.noties.markwon.app.samples.movementmethod.MovementMethodPluginSample",
"id": "202006179081631",
"title": "MovementMethodPlugin",
"description": "Plugin to control movement method",
"artifacts": [
"CORE"
],
"tags": [
"links",
"movement-method",
"plugin"
]
},
{
"javaClassName": "io.noties.markwon.app.samples.movementmethod.DisableImplicitMovementMethodSample",
"id": "202006179081256",
"title": "Disable implicit movement method",
"description": "Configure `Markwon` to **not** apply implicit movement method",
"artifacts": [
"CORE"
],
"tags": [
"links",
"movement-method",
"plugin",
"recycler-view"
]
},
{
"javaClassName": "io.noties.markwon.app.samples.movementmethod.ExplicitMovementMethodSample",
"id": "202006179080007",
"title": "Explicit movement method",
"description": "When a movement method already applied to a `TextView``Markwon` won\u0027t try to apply own (implicit) one",
"artifacts": [
"CORE"
],
"tags": [
"links",
"movement-method"
]
},
{
"javaClassName": "io.noties.markwon.app.samples.movementmethod.ImplicitMovementMethodSample",
"id": "202006179075524",
"title": "Implicit movement method",
"description": "By default movement method is applied for links to be clickable",
"artifacts": [
"CORE"
],
"tags": [
"links",
"movement-method"
]
},
{
"javaClassName": "io.noties.markwon.app.samples.EnabledBlockTypesSample",
"id": "202006179075012",
"title": "Enabled markdown blocks",
"description": "Modify/inspect enabled by `CorePlugin` block types. Disable quotes or other blocks from being parsed",
"artifacts": [
"CORE"
],
"tags": [
"block",
"parsing",
"plugin"
]
},
{
"javaClassName": "io.noties.markwon.app.samples.ToastDynamicContentSample",
"id": "202006179074017",
"title": "Markdown in Toast (with dynamic content)",
"description": "Display markdown in a `android.widget.Toast` with dynamic content (image)",
"artifacts": [
"CORE",
"IMAGE"
],
"tags": [
"hack",
"toast"
]
},
{
"javaClassName": "io.noties.markwon.app.samples.ToastSample",
"id": "202006179072642",
"title": "Markdown in Toast",
"description": "Display _static_ markdown content in a `android.widget.Toast`",
"artifacts": [
"CORE"
],
"tags": [
"toast"
]
},
{ {
"javaClassName": "io.noties.markwon.app.samples.basics.SimpleWalkthrough", "javaClassName": "io.noties.markwon.app.samples.basics.SimpleWalkthrough",
"id": "202006178153426", "id": "202006178153426",

View File

@ -2,4 +2,12 @@ package io.noties.markwon.app.sample
object Tags { object Tags {
const val basics = "basics" const val basics = "basics"
const val toast = "toast"
const val hack = "hack"
const val parsing = "parsing"
const val block = "block"
const val movementMethod = "movement-method"
const val links = "links"
const val plugin = "plugin"
const val recyclerView = "recycler-view"
} }

View File

@ -0,0 +1,45 @@
package io.noties.markwon.app.samples
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.app.sample.Tags
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
import io.noties.markwon.core.CorePlugin
import io.noties.markwon.sample.annotations.MarkwonArtifact
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
import org.commonmark.node.BlockQuote
import org.commonmark.parser.Parser
@MarkwonSampleInfo(
id = "202006179075012",
title = "Enabled markdown blocks",
description = "Modify/inspect enabled by `CorePlugin` block types. " +
"Disable quotes or other blocks from being parsed",
artifacts = [MarkwonArtifact.CORE],
tags = [Tags.parsing, Tags.block, Tags.plugin]
)
class EnabledBlockTypesSample : MarkwonTextViewSample() {
override fun render() {
val md = """
# Heading
## Second level
> Quote is not handled
""".trimIndent()
val markwon = Markwon.builder(context)
.usePlugin(object : AbstractMarkwonPlugin() {
override fun configureParser(builder: Parser.Builder) {
// obtain all enabled block types
val enabledBlockTypes = CorePlugin.enabledBlockTypes()
// it is safe to modify returned collection
// remove quotes
enabledBlockTypes.remove(BlockQuote::class.java)
builder.enabledBlockTypes(enabledBlockTypes)
}
})
.build()
markwon.setMarkdown(textView, md)
}
}

View File

@ -0,0 +1,73 @@
package io.noties.markwon.app.samples
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import io.noties.markwon.Markwon
import io.noties.markwon.app.sample.Tags
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
import io.noties.markwon.image.ImagesPlugin
import io.noties.markwon.sample.annotations.MarkwonArtifact
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
@MarkwonSampleInfo(
id = "202006179074017",
title = "Markdown in Toast (with dynamic content)",
description = "Display markdown in a `android.widget.Toast` with dynamic content (image)",
artifacts = [MarkwonArtifact.CORE, MarkwonArtifact.IMAGE],
tags = [Tags.toast, Tags.hack]
)
class ToastDynamicContentSample : MarkwonTextViewSample() {
override fun render() {
val md = """
# Head!
![alt](https://github.com/noties/Markwon/raw/master/art/markwon_logo.png)
Do you see an image?
""".trimIndent()
val markwon = Markwon.builder(context)
.usePlugin(ImagesPlugin.create())
.build()
val markdown = markwon.toMarkdown(md)
val toast = Toast.makeText(context, markdown, Toast.LENGTH_LONG)
// try to obtain textView
val textView = toast.textView
if (textView != null) {
markwon.setParsedMarkdown(textView, markdown)
}
// finally show toast (at this point, if we didn't find TextView it will still
// present markdown, just without dynamic content (image))
toast.show()
}
}
private val Toast.textView: TextView?
get() {
fun find(view: View?): TextView? {
if (view is TextView) {
return view
}
if (view is ViewGroup) {
for (i in 0 until view.childCount) {
val textView = find(view.getChildAt(i))
if (textView != null) {
return textView
}
}
}
return null
}
return find(view)
}

View File

@ -0,0 +1,38 @@
package io.noties.markwon.app.samples
import android.widget.Toast
import io.noties.markwon.Markwon
import io.noties.markwon.app.sample.Tags
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
import io.noties.markwon.sample.annotations.MarkwonArtifact
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
@MarkwonSampleInfo(
id = "202006179072642",
title = "Markdown in Toast",
description = "Display _static_ markdown content in a `android.widget.Toast`",
artifacts = [MarkwonArtifact.CORE],
tags = [Tags.toast]
)
class ToastSample : MarkwonTextViewSample() {
override fun render() {
// NB! only _static_ content is going to be displayed,
// so, no images, tables or latex in a Toast
val md = """
# Heading is fine
> Even quote if **fine**
```
finally code works;
```
_italic_ to put an end to it
""".trimIndent()
val markwon = Markwon.create(context)
// render raw input to styled markdown
val markdown = markwon.toMarkdown(md)
// Toast accepts CharSequence and allows styling via spans
Toast.makeText(context, markdown, Toast.LENGTH_LONG).show()
}
}

View File

@ -0,0 +1,43 @@
package io.noties.markwon.app.samples.movementmethod
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonPlugin
import io.noties.markwon.app.sample.Tags
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
import io.noties.markwon.core.CorePlugin
import io.noties.markwon.sample.annotations.MarkwonArtifact
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
@MarkwonSampleInfo(
id = "202006179081256",
title = "Disable implicit movement method",
description = "Configure `Markwon` to **not** apply implicit movement method",
artifacts = [MarkwonArtifact.CORE],
tags = [Tags.plugin, Tags.movementMethod, Tags.links, Tags.recyclerView]
)
class DisableImplicitMovementMethodSample : MarkwonTextViewSample() {
override fun render() {
val md = """
# Disable implicit movement method
Sometimes it is required to stop `Markwon` from applying _implicit_
movement method (for example when used inside in a `RecyclerView`
in order to make the whole itemView clickable). `Markwon` inspects
`TextView` and applies implicit movement method if `getMovementMethod()`
returns `null`. No [links](https://github.com) will be clickable in this
markdown
""".trimIndent()
val markwon = Markwon.builder(context)
.usePlugin(object : AbstractMarkwonPlugin() {
override fun configure(registry: MarkwonPlugin.Registry) {
registry.require(CorePlugin::class.java)
// this flag will make sure that CorePlugin won't apply any movement method
.hasExplicitMovementMethod(true)
}
})
.build()
markwon.setMarkdown(textView, md)
}
}

View File

@ -0,0 +1,37 @@
package io.noties.markwon.app.samples.movementmethod
import android.text.method.ScrollingMovementMethod
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 = "202006179080007",
title = "Explicit movement method",
description = "When a movement method already applied to a `TextView`" +
"`Markwon` won't try to apply own (implicit) one",
artifacts = [MarkwonArtifact.CORE],
tags = [Tags.movementMethod, Tags.links]
)
class ExplicitMovementMethodSample : MarkwonTextViewSample() {
override fun render() {
val md = """
# Explicit movement method
If `TextView` already has a movement method specified, then `Markwon`
won't be applying a default one. You can specify movement
method via call to `setMovementMethod`. If your movement method can
handle [links](https://github.com/noties/Markwon) then link would be
_clickable_
""".trimIndent()
val markwon = Markwon.create(context)
// own movement method that does not handle clicks would still be used
// (no default aka implicit method would be applied by Markwon)
textView.movementMethod = ScrollingMovementMethod.getInstance()
markwon.setMarkdown(textView, md)
}
}

View File

@ -0,0 +1,33 @@
package io.noties.markwon.app.samples.movementmethod
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 = "202006179075524",
title = "Implicit movement method",
description = "By default movement method is applied for links to be clickable",
artifacts = [MarkwonArtifact.CORE],
tags = [Tags.movementMethod, Tags.links]
)
class ImplicitMovementMethodSample : MarkwonTextViewSample() {
override fun render() {
val md = """
# Implicit movement method
By default `Markwon` applies `LinkMovementMethod` if it is missing,
so in order for [links](https://github.com/noties/Markwon) to be clickable
nothing special should be done
""".trimIndent()
// by default Markwon will apply a `LinkMovementMethod` if
// it is missing. So, in order for links to be clickable
// nothing should be done
val markwon = Markwon.create(context)
markwon.setMarkdown(textView, md)
}
}

View File

@ -0,0 +1,33 @@
package io.noties.markwon.app.samples.movementmethod
import io.noties.markwon.Markwon
import io.noties.markwon.app.sample.Tags
import io.noties.markwon.app.sample.ui.MarkwonTextViewSample
import io.noties.markwon.movement.MovementMethodPlugin
import io.noties.markwon.sample.annotations.MarkwonArtifact
import io.noties.markwon.sample.annotations.MarkwonSampleInfo
@MarkwonSampleInfo(
id = "202006179081631",
title = "MovementMethodPlugin",
description = "Plugin to control movement method",
artifacts = [MarkwonArtifact.CORE],
tags = [Tags.movementMethod, Tags.links, Tags.plugin]
)
class MovementMethodPluginSample : MarkwonTextViewSample() {
override fun render() {
val md = """
# MovementMethodPlugin
`MovementMethodPlugin` can be used to apply movement method
explicitly. Including specific case to disable implicit movement
method which is applied when `TextView.getMovementMethod()`
returns `null`. A [link](https://github.com)
""".trimIndent()
val markwon = Markwon.builder(context)
.usePlugin(MovementMethodPlugin.link())
.build()
markwon.setMarkdown(textView, md)
}
}

Binary file not shown.

View File

@ -116,7 +116,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
private final List<OnTextAddedListener> onTextAddedListeners = new ArrayList<>(0); private final List<OnTextAddedListener> onTextAddedListeners = new ArrayList<>(0);
// @since $nap; // @since $nap;
private boolean hasExplicitMovementMethodPlugin; private boolean hasExplicitMovementMethod;
protected CorePlugin() { protected CorePlugin() {
} }
@ -126,8 +126,8 @@ public class CorePlugin extends AbstractMarkwonPlugin {
*/ */
@SuppressWarnings("UnusedReturnValue") @SuppressWarnings("UnusedReturnValue")
@NonNull @NonNull
public CorePlugin hasExplicitMovementMethodPlugin(boolean hasExplicitMovementMethodPlugin) { public CorePlugin hasExplicitMovementMethod(boolean hasExplicitMovementMethod) {
this.hasExplicitMovementMethodPlugin = hasExplicitMovementMethodPlugin; this.hasExplicitMovementMethod = hasExplicitMovementMethod;
return this; return this;
} }
@ -202,7 +202,7 @@ public class CorePlugin extends AbstractMarkwonPlugin {
// we do it `afterSetText` so any user-defined movement method won't be // we do it `afterSetText` so any user-defined movement method won't be
// replaced (it should be done in `beforeSetText` or manually on a TextView) // replaced (it should be done in `beforeSetText` or manually on a TextView)
// @since $nap; we additionally check if we should apply _implicit_ movement method // @since $nap; we additionally check if we should apply _implicit_ movement method
if (!hasExplicitMovementMethodPlugin && textView.getMovementMethod() == null) { if (!hasExplicitMovementMethod && textView.getMovementMethod() == null) {
textView.setMovementMethod(LinkMovementMethod.getInstance()); textView.setMovementMethod(LinkMovementMethod.getInstance());
} }
} }

View File

@ -68,7 +68,7 @@ public class MovementMethodPlugin extends AbstractMarkwonPlugin {
@Override @Override
public void configure(@NonNull Registry registry) { public void configure(@NonNull Registry registry) {
registry.require(CorePlugin.class) registry.require(CorePlugin.class)
.hasExplicitMovementMethodPlugin(true); .hasExplicitMovementMethod(true);
} }
@Override @Override

View File

@ -30,13 +30,8 @@ import org.mockito.ArgumentCaptor;
import org.robolectric.RobolectricTestRunner; import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config; import org.robolectric.annotation.Config;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set;
import io.noties.markwon.MarkwonConfiguration; import io.noties.markwon.MarkwonConfiguration;
import io.noties.markwon.MarkwonSpansFactory; import io.noties.markwon.MarkwonSpansFactory;
@ -44,9 +39,6 @@ import io.noties.markwon.MarkwonVisitor;
import io.noties.markwon.RenderProps; import io.noties.markwon.RenderProps;
import io.noties.markwon.SpanFactory; import io.noties.markwon.SpanFactory;
import io.noties.markwon.SpannableBuilder; import io.noties.markwon.SpannableBuilder;
import ix.Ix;
import ix.IxFunction;
import ix.IxPredicate;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@ -279,7 +271,7 @@ public class CorePluginTest {
public void explicit_movement_method() { public void explicit_movement_method() {
final TextView textView = mock(TextView.class); final TextView textView = mock(TextView.class);
final CorePlugin plugin = CorePlugin.create() final CorePlugin plugin = CorePlugin.create()
.hasExplicitMovementMethodPlugin(true); .hasExplicitMovementMethod(true);
plugin.afterSetText(textView); plugin.afterSetText(textView);
verify(textView, never()).setMovementMethod(any(MovementMethod.class)); verify(textView, never()).setMovementMethod(any(MovementMethod.class));
} }

View File

@ -192,7 +192,7 @@ public class CoreActivity extends ActivityWithMenuOptions {
textView.setMovementMethod(null); textView.setMovementMethod(null);
// by default Markwon will set a LinkMovementMethod on a TextView if it is missing // by default Markwon will set a LinkMovementMethod on a TextView if it is missing
// to control that `hasExplicitMovementMethodPlugin` can be used // to control that `hasExplicitMovementMethod` can be used
final String md = "[1 link](#) here"; final String md = "[1 link](#) here";
final Markwon markwon = Markwon.builder(this) final Markwon markwon = Markwon.builder(this)
@ -202,7 +202,7 @@ public class CoreActivity extends ActivityWithMenuOptions {
// Markwon **won't** set implicit movement method // Markwon **won't** set implicit movement method
// thus making the link in markdown input not clickable // thus making the link in markdown input not clickable
registry.require(CorePlugin.class) registry.require(CorePlugin.class)
.hasExplicitMovementMethodPlugin(true); .hasExplicitMovementMethod(true);
} }
}) })
.build(); .build();
@ -211,7 +211,7 @@ public class CoreActivity extends ActivityWithMenuOptions {
} }
private void explicitMovementMethodPlugin() { private void explicitMovementMethodPlugin() {
// additionally special MovementMethodPlugin.none() can be used to control `hasExplicitMovementMethodPlugin` // additionally special MovementMethodPlugin.none() can be used to control `hasExplicitMovementMethod`
final String md = "[2 link](#) here"; final String md = "[2 link](#) here";