From 2ea148c30a07f91ffa37c0aa36af1cf2670441af Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Mon, 15 Mar 2021 14:55:39 +0300 Subject: [PATCH] sample, add copy code block --- app-sample/samples.json | 15 +++ .../app/samples/CopyCodeBlockSample.kt | 119 ++++++++++++++++++ .../GithubUserIssueInlineParsingSample.java | 2 +- .../GithubUserIssueOnTextAddedSample.java | 2 +- 4 files changed, 136 insertions(+), 2 deletions(-) create mode 100644 app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt diff --git a/app-sample/samples.json b/app-sample/samples.json index ea8bf2d5..1b4c5275 100644 --- a/app-sample/samples.json +++ b/app-sample/samples.json @@ -1,4 +1,19 @@ [ + { + "javaClassName": "io.noties.markwon.app.samples.CopyCodeBlockSample", + "id": "20210315112847", + "title": "Copy code block", + "description": "Copy contents of fenced code blocks", + "artifacts": [ + "CORE" + ], + "tags": [ + "block", + "rendering", + "span", + "spanFactory" + ] + }, { "javaClassName": "io.noties.markwon.app.samples.parser.RedditSuperscriptSample", "id": "20210224091506", diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt b/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt new file mode 100644 index 00000000..9860111a --- /dev/null +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/CopyCodeBlockSample.kt @@ -0,0 +1,119 @@ +package io.noties.markwon.app.samples + +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.drawable.Drawable +import android.text.Layout +import android.text.Spanned +import android.text.TextPaint +import android.text.style.ClickableSpan +import android.text.style.LeadingMarginSpan +import android.view.View +import android.widget.TextView +import io.noties.debug.Debug +import io.noties.markwon.AbstractMarkwonPlugin +import io.noties.markwon.Markwon +import io.noties.markwon.MarkwonSpansFactory +import io.noties.markwon.app.R +import io.noties.markwon.app.sample.ui.MarkwonTextViewSample +import io.noties.markwon.sample.annotations.MarkwonArtifact +import io.noties.markwon.sample.annotations.MarkwonSampleInfo +import io.noties.markwon.sample.annotations.Tag +import io.noties.markwon.utils.LeadingMarginUtils +import org.commonmark.node.FencedCodeBlock + +@MarkwonSampleInfo( + id = "20210315112847", + title = "Copy code block", + description = "Copy contents of fenced code blocks", + artifacts = [MarkwonArtifact.CORE], + tags = [Tag.rendering, Tag.block, Tag.spanFactory, Tag.span] +) +class CopyCodeBlockSample : MarkwonTextViewSample() { + + override fun render() { + val md = """ + # Hello code blocks! + ```java + final int i = 0; + final Type t = Type.init() + .filter(i -> i.even) + .first(null); + ``` + bye bye! + """.trimIndent() + + val markwon = Markwon.builder(context) + .usePlugin(object : AbstractMarkwonPlugin() { + override fun configureSpansFactory(builder: MarkwonSpansFactory.Builder) { + builder.appendFactory(FencedCodeBlock::class.java) { _, _ -> + CopyContentsSpan() + } + builder.appendFactory(FencedCodeBlock::class.java) { _, _ -> + CopyIconSpan(context.getDrawable(R.drawable.ic_code_white_24dp)!!) + } + } + }) + .build() + + markwon.setMarkdown(textView, md) + } + + class CopyContentsSpan : ClickableSpan() { + override fun onClick(widget: View) { + val spanned = (widget as? TextView)?.text as? Spanned ?: return + val start = spanned.getSpanStart(this) + val end = spanned.getSpanEnd(this) + // by default code blocks have new lines before and after content + val contents = spanned.subSequence(start, end).toString().trim() + // copy code here + Debug.i(contents) + } + + override fun updateDrawState(ds: TextPaint) { + // do not apply link styling + } + } + + class CopyIconSpan(val icon: Drawable) : LeadingMarginSpan { + + init { + if (icon.bounds.isEmpty) { + icon.setBounds(0, 0, icon.intrinsicWidth, icon.intrinsicHeight) + } + } + + override fun getLeadingMargin(first: Boolean): Int = 0 + + override fun drawLeadingMargin( + c: Canvas, + p: Paint, + x: Int, + dir: Int, + top: Int, + baseline: Int, + bottom: Int, + text: CharSequence, + start: Int, + end: Int, + first: Boolean, + layout: Layout + ) { + + // called for each line of text, we are interested only in first one + if (!LeadingMarginUtils.selfStart(start, text, this)) return + + val save = c.save() + try { + // horizontal position for icon + val w = icon.bounds.width().toFloat() + // minus quarter width as padding + val left = layout.width - w - (w / 4F) + c.translate(left, top.toFloat()) + icon.draw(c) + } finally { + c.restoreToCount(save) + } + } + } +} \ No newline at end of file diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java index a71b3df6..884d4c5c 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueInlineParsingSample.java @@ -34,7 +34,7 @@ public class GithubUserIssueInlineParsingSample extends MarkwonTextViewSample { "# Custom Extension 2\n" + "\n" + "This is an issue #1\n" + - "Done by @noties"; + "Done by @noties and other @dude"; final InlineParserFactory inlineParserFactory = MarkwonInlineParser.factoryBuilder() // include all current defaults (otherwise will be empty - contain only our inline-processors) diff --git a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java index 1a8aaf79..68f1e9c2 100644 --- a/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java +++ b/app-sample/src/main/java/io/noties/markwon/app/samples/GithubUserIssueOnTextAddedSample.java @@ -36,7 +36,7 @@ public class GithubUserIssueOnTextAddedSample extends MarkwonTextViewSample { "# Custom Extension 2\n" + "\n" + "This is an issue #1\n" + - "Done by @noties"; + "Done by @noties and other @dude"; final Markwon markwon = Markwon.builder(context) .usePlugin(new AbstractMarkwonPlugin() {