From c425773c84e8916291928fb2e0362317aa7fbf88 Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Thu, 12 Mar 2020 10:25:18 +0300 Subject: [PATCH] Add remote views sample --- sample/src/main/AndroidManifest.xml | 1 + .../noties/markwon/sample/MainActivity.java | 5 + .../java/io/noties/markwon/sample/Sample.java | 4 +- .../notification/NotificationActivity.java | 254 ++++++++++++++++++ .../res/drawable-anydpi-v24/ic_stat_name.xml | 13 + .../main/res/drawable-hdpi/ic_stat_name.png | Bin 0 -> 513 bytes .../main/res/drawable-mdpi/ic_stat_name.png | Bin 0 -> 346 bytes .../main/res/drawable-xhdpi/ic_stat_name.png | Bin 0 -> 687 bytes .../main/res/drawable-xxhdpi/ic_stat_name.png | Bin 0 -> 1044 bytes .../src/main/res/values/strings-samples.xml | 2 + 10 files changed, 278 insertions(+), 1 deletion(-) create mode 100644 sample/src/main/java/io/noties/markwon/sample/notification/NotificationActivity.java create mode 100644 sample/src/main/res/drawable-anydpi-v24/ic_stat_name.xml create mode 100644 sample/src/main/res/drawable-hdpi/ic_stat_name.png create mode 100644 sample/src/main/res/drawable-mdpi/ic_stat_name.png create mode 100644 sample/src/main/res/drawable-xhdpi/ic_stat_name.png create mode 100644 sample/src/main/res/drawable-xxhdpi/ic_stat_name.png diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index d3266265..f85d8750 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -37,6 +37,7 @@ + diff --git a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java index a8391ce8..2ac55d99 100644 --- a/sample/src/main/java/io/noties/markwon/sample/MainActivity.java +++ b/sample/src/main/java/io/noties/markwon/sample/MainActivity.java @@ -28,6 +28,7 @@ import io.noties.markwon.sample.htmldetails.HtmlDetailsActivity; import io.noties.markwon.sample.images.ImagesActivity; import io.noties.markwon.sample.inlineparser.InlineParserActivity; import io.noties.markwon.sample.latex.LatexActivity; +import io.noties.markwon.sample.notification.NotificationActivity; import io.noties.markwon.sample.precomputed.PrecomputedActivity; import io.noties.markwon.sample.recycler.RecyclerActivity; import io.noties.markwon.sample.simpleext.SimpleExtActivity; @@ -142,6 +143,10 @@ public class MainActivity extends Activity { activity = ImagesActivity.class; break; + case REMOTE_VIEWS: + activity = NotificationActivity.class; + break; + default: throw new IllegalStateException("No Activity is associated with sample-item: " + item); } diff --git a/sample/src/main/java/io/noties/markwon/sample/Sample.java b/sample/src/main/java/io/noties/markwon/sample/Sample.java index bf05297d..f18ed25b 100644 --- a/sample/src/main/java/io/noties/markwon/sample/Sample.java +++ b/sample/src/main/java/io/noties/markwon/sample/Sample.java @@ -31,7 +31,9 @@ public enum Sample { TASK_LIST(R.string.sample_task_list), - IMAGES(R.string.sample_images); + IMAGES(R.string.sample_images), + + REMOTE_VIEWS(R.string.sample_remote_views); private final int textResId; diff --git a/sample/src/main/java/io/noties/markwon/sample/notification/NotificationActivity.java b/sample/src/main/java/io/noties/markwon/sample/notification/NotificationActivity.java new file mode 100644 index 00000000..0012f41f --- /dev/null +++ b/sample/src/main/java/io/noties/markwon/sample/notification/NotificationActivity.java @@ -0,0 +1,254 @@ +package io.noties.markwon.sample.notification; + +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.os.Build; +import android.text.SpannableStringBuilder; +import android.text.Spanned; +import android.text.style.AbsoluteSizeSpan; +import android.text.style.BulletSpan; +import android.text.style.DynamicDrawableSpan; +import android.text.style.ImageSpan; +import android.text.style.QuoteSpan; +import android.text.style.StrikethroughSpan; +import android.text.style.StyleSpan; + +import androidx.annotation.NonNull; + +import org.commonmark.ext.gfm.strikethrough.Strikethrough; +import org.commonmark.node.BlockQuote; +import org.commonmark.node.Emphasis; +import org.commonmark.node.Heading; +import org.commonmark.node.ListItem; +import org.commonmark.node.StrongEmphasis; + +import io.noties.debug.Debug; +import io.noties.markwon.AbstractMarkwonPlugin; +import io.noties.markwon.Markwon; +import io.noties.markwon.MarkwonSpansFactory; +import io.noties.markwon.core.CoreProps; +import io.noties.markwon.ext.strikethrough.StrikethroughPlugin; +import io.noties.markwon.sample.ActivityWithMenuOptions; +import io.noties.markwon.sample.MenuOptions; +import io.noties.markwon.sample.R; + +public class NotificationActivity extends ActivityWithMenuOptions { + + private static final String CHANNEL_ID = "whatever"; + + @NonNull + @Override + public MenuOptions menuOptions() { + return MenuOptions.create() + .add("bold-italic", this::bold_italic) + .add("heading", this::heading) + .add("lists", this::lists) + .add("image", this::image) + .add("link", this::link) + .add("blockquote", this::blockquote) + .add("strikethrough", this::strikethrough); + } + + private void bold_italic() { + // Unfortunately we cannot just use Markwon created CharSequence in a RemoteViews context + // because it requires for spans to be platform ones + + final String md = "Just a **bold** here and _italic_, but what if **it is bold _and italic_**?"; + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder + .setFactory(StrongEmphasis.class, (configuration, props) -> new StyleSpan(Typeface.BOLD)) + .setFactory(Emphasis.class, (configuration, props) -> new StyleSpan(Typeface.ITALIC)); + } + }) + .build(); + display(markwon.toMarkdown(md)); + } + + private void heading() { + + // please note that heading doesn't seem to be working in remote views, + // tried both `RelativeSizeSpan` and `AbsoluteSizeSpan` with no effect + + final float base = 12; + + final float[] sizes = { + 2.F, 1.5F, 1.17F, 1.F, .83F, .67F, + }; + + final String md = "" + + "# H1\n" + + "## H2\n" + + "### H3\n" + + "#### H4\n" + + "##### H5\n" + + "###### H6\n\n"; + + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Heading.class, (configuration, props) -> { + final Integer level = CoreProps.HEADING_LEVEL.get(props); + Debug.i(level); + if (level != null && level > 0 && level <= sizes.length) { +// return new RelativeSizeSpan(sizes[level - 1]); + final Object span = new AbsoluteSizeSpan((int) (base * sizes[level - 1] + .5F), true); + return new Object[]{ + span, + new StyleSpan(Typeface.BOLD) + }; + } + return null; + }); + } + }) + .build(); + display(markwon.toMarkdown(md)); + } + + private void lists() { + final String md = "" + + "* bullet 1\n" + + "* bullet 2\n" + + "* * bullet 2 1\n" + + " * bullet 2 0 1\n" + + "1) order 1\n" + + "1) order 2\n" + + "1) order 3\n"; + + // ordered lists _could_ be translated to raw text representation (`1.`, `1)` etc) in resulting markdown + // or they could be _disabled_ all together... (can ordered lists be disabled in parser?) + + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(ListItem.class, (configuration, props) -> { + final CoreProps.ListItemType type = CoreProps.LIST_ITEM_TYPE.get(props); + if (type != null) { + // bullet and ordered list share the same markdown node + return new BulletSpan(); + } + return null; + }); + } + }) + .build(); + + display(markwon.toMarkdown(md)); + } + + private void image() { + // please note that image _could_ be supported only if it would be available immediately + // debugging possibility + // + // doesn't seem to be working + + final Bitmap bitmap = Bitmap.createBitmap(128, 256, Bitmap.Config.ARGB_4444); + final Canvas canvas = new Canvas(bitmap); + canvas.drawColor(0xFFAD1457); + + final SpannableStringBuilder builder = new SpannableStringBuilder(); + builder.append("An image: "); + + final int length = builder.length(); + builder.append("[bitmap]"); + builder.setSpan( + new ImageSpan(this, bitmap, DynamicDrawableSpan.ALIGN_BOTTOM), + length, + builder.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + + builder.append(" okay, and "); + + final int start = builder.length(); + builder.append("[resource]"); + builder.setSpan( + new ImageSpan(this, R.drawable.ic_memory_black_48dp), + start, + builder.length(), + Spanned.SPAN_EXCLUSIVE_EXCLUSIVE + ); + + display(builder); + } + + private void link() { + final String md = "" + + "[a link](https://isa.link/) is here, styling yes, clicking - no"; + display(Markwon.create(this).toMarkdown(md)); + } + + private void blockquote() { + final String md = "" + + "> This was once said by me\n" + + "> > And this one also\n\n" + + "Me"; + final Markwon markwon = Markwon.builder(this) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(BlockQuote.class, (configuration, props) -> new QuoteSpan()); + } + }) + .build(); + display(markwon.toMarkdown(md)); + } + + private void strikethrough() { + final String md = "~~strike that!~~"; + final Markwon markwon = Markwon.builder(this) + .usePlugin(new StrikethroughPlugin()) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + builder.setFactory(Strikethrough.class, (configuration, props) -> new StrikethroughSpan()); + } + }) + .build(); + display(markwon.toMarkdown(md)); + } + + private void display(@NonNull CharSequence cs) { + final NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + if (manager == null) { + throw new IllegalStateException("No NotificationManager is available"); + } + + ensureChannel(manager); + + final Notification.Builder builder = new Notification.Builder(this) + .setSmallIcon(R.drawable.ic_stat_name) + .setContentTitle("Markwon") + .setContentText(cs) + .setStyle(new Notification.BigTextStyle().bigText(cs)); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + builder.setChannelId(CHANNEL_ID); + } + + manager.notify(1, builder.build()); + } + + private void ensureChannel(@NonNull NotificationManager manager) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + return; + } + + final NotificationChannel channel = manager.getNotificationChannel(CHANNEL_ID); + if (channel == null) { + manager.createNotificationChannel(new NotificationChannel( + CHANNEL_ID, + CHANNEL_ID, + NotificationManager.IMPORTANCE_DEFAULT)); + } + } +} diff --git a/sample/src/main/res/drawable-anydpi-v24/ic_stat_name.xml b/sample/src/main/res/drawable-anydpi-v24/ic_stat_name.xml new file mode 100644 index 00000000..fd7cefc2 --- /dev/null +++ b/sample/src/main/res/drawable-anydpi-v24/ic_stat_name.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/sample/src/main/res/drawable-hdpi/ic_stat_name.png b/sample/src/main/res/drawable-hdpi/ic_stat_name.png new file mode 100644 index 0000000000000000000000000000000000000000..19e7a26b3b180660ea0a6d9430f2a1324f9da287 GIT binary patch literal 513 zcmV+c0{;DpP)*o+g4g`bSX3yK8K6w9b8n~+O*LYhQ#z; zIKts@o$j3(Yl1oO1DW&3k2&|;dnb{IEw(=}*LAbt1Ps7Em=SlN4~{|RH-uEcE%NpJ?vz1D*AQH+XBvgbWk*Rk33mTa1G%r_Km%x=l&?HP)NzL~zIE?+08!-|cB zZ!Si;smX7On7Qzen6G0ZsLvAG!Z#6nQC^du7kkh|_}k3aHxV>t2?v^Xbg6Y!j~Z2q z>B_dKnymiRM9_?azd&jS$54uDE1UgGL0elEk|67rc`fP|IJBe{bWwYaz2oEh;RGFf zuZ^(?-Yvwa*kYiK(d+0SUjw`uh*2>Ok!yc+m>jO^V5Ix=S|emlzH(@XtLgQFgr9;- zLjA6Ue*K8#1ub${*hpUTBl#H=$q&WIeoDs{o5sEY5t|;T!-c>b00000NkvXXu0mjf Dp2_dd literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-mdpi/ic_stat_name.png b/sample/src/main/res/drawable-mdpi/ic_stat_name.png new file mode 100644 index 0000000000000000000000000000000000000000..0525d8746741507a21e5dcae150b947eeb7aa447 GIT binary patch literal 346 zcmV-g0j2(lP)ifEhVxe$h;-248|ZxPcUe z22IGm8?}onGrx0YV+Z}1S{XAf69*JuU4j>q$e5G0CM>8}%61oQ!Q7yov#-l`%CU(p z!I4W1*-umAu6 literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-xhdpi/ic_stat_name.png b/sample/src/main/res/drawable-xhdpi/ic_stat_name.png new file mode 100644 index 0000000000000000000000000000000000000000..c5f2f07610c1453770c4cc984d2ae2401320f764 GIT binary patch literal 687 zcmV;g0#N;lP)jhG9Hq?0mgaieLfF|NF z|4LI>qp`DVuL&5B^huFD^Y3iDo;_SslUQPjCFVBAahkvYm;?)8o__a%#^0Ls5ZDEm zj=z0@bFd8te?#Kq;KB)Rr(mQSiT8tJ$DSR4-k(Z-8a#O<@(zk%4-~*GQJ`x@@{#NT zWMtf+&u|bd3GO9U|HG^jh`(dTgY;_{jSxWfq(oAh#(6zFZ&{@o-g#Chv9r5|Y z+G5UNIbAR8rgTij)JL|QHrdeNS}oWBFB*xzkZ*0|8yeFsC9b!FO*&#MyJE_8P2Fq% zu`OlTO+9=%6jj~S|M_E;SR8D{;%G4zhr6*jUXR5Gj@W!+@>z=it&e<(C6-wA>>Gl< VCxPrB2><{9002ovPDHLkV1j9XJI(+A literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-xxhdpi/ic_stat_name.png b/sample/src/main/res/drawable-xxhdpi/ic_stat_name.png new file mode 100644 index 0000000000000000000000000000000000000000..993df1f0d759f41fe0247a987270744b9ce64319 GIT binary patch literal 1044 zcmV+v1nc{WP)6 zd6$6$z(>G&{{0O25O@pN@jnQX1>Oa|1%3wp@zik!+y%Y@4*qMxTmvowzj@}c z4}1>1a*>58;Bfiv*~2k#$^Q~Ak}#KmPk}!?cQ^z-2IkT(&Q0K6j0gRRjEXw2H?874 z03Inm$N_KzI0d{7%!l~P<7ZR&zXyuGzXR{3O`KVURp|t{4lKopQ$imn3aj2sTEuxN zN%j;c>w<*^;8YTOJ`KMd5k3Kn7ULH&h6poBiE|%+%3<(_Th(9D9IcvF!4N-lJ}2R7 zbto88V+nj=V}c>)Puw?L);V7U;tVA?jr8tBva-7fh5Wg_PnHkw`g#P*>;*yMmaM1tiAIg|-sJJjlgbLI)r zPs*AUs6-^UCa{^7?8|yI;`d1QU(*8HHNs}lq(EhyFObcI+peN7Kk@ z2_DUaVM1cpDQMKMM#y88@a4zol-N!XwgV;v8X=tDQLya=)&e#Sta95Ta*|l?4-NxkI@ZxMu5KTQ+KNIGZTb{rBy;qP!HryAK(YO^u8+js#v}Z!taCdp z(aQ^gpRe)jFJRY&=U+a%BKk=F`U@t)7pN2x;wyLx$?+x57zHF>13vdl;)~>xHvG_;o0aiIiWcQ|JQlE18N-H-4#CLoj|VoWWo)7z_p@#rO+5y9eqhf~vXz O0000M&r-` literal 0 HcmV?d00001 diff --git a/sample/src/main/res/values/strings-samples.xml b/sample/src/main/res/values/strings-samples.xml index d174e736..0305b471 100644 --- a/sample/src/main/res/values/strings-samples.xml +++ b/sample/src/main/res/values/strings-samples.xml @@ -35,4 +35,6 @@ # \# Images\n\nUsage of different images plugins + # \# Notification\n\nExample usage in notifications and other remote views + \ No newline at end of file