From 6d2881721530a19eb5b71f542a3d4b6ea09a9daa Mon Sep 17 00:00:00 2001 From: Dimitry Ivanov Date: Wed, 13 Mar 2019 16:30:43 +0300 Subject: [PATCH] Add recycler-table module --- docs/.vuepress/.artifacts.js | 2 +- docs/.vuepress/config.js | 1 + .../assets/recycler-table-screenshot.png | Bin 0 -> 78822 bytes docs/docs/v3/ext-tables/README.md | 7 +- docs/docs/v3/ext-tasklist/README.md | 136 +++++ docs/docs/v3/install.md | 56 -- docs/docs/v3/recycler-table/README.md | 90 +++ markwon-bundle.gradle | 59 -- .../main/java/ru/noties/markwon/Markwon.java | 4 + .../java/ru/noties/markwon/MarkwonImpl.java | 15 +- .../ru/noties/markwon/MarkwonReducer.java | 4 + .../noties/markwon/MarkwonSpansFactory.java | 6 + .../markwon/MarkwonSpansFactoryImpl.java | 6 + .../markwon/utils/NoCopySpannableFactory.java | 30 + .../markwon/ext/tables/TablePlugin.java | 7 + .../noties/markwon/ext/tables/TableTheme.java | 30 +- markwon-recycler-table/build.gradle | 29 + markwon-recycler-table/gradle.properties | 4 + .../src/main/AndroidManifest.xml | 1 + .../recycler/table/TableBorderDrawable.java | 48 ++ .../markwon/recycler/table/TableEntry.java | 530 ++++++++++++++++++ .../recycler/table/TableEntryPlugin.java | 65 +++ .../recycler/table/TableEntryTheme.java | 67 +++ .../recycler/table/TableEntryTest.java | 103 ++++ .../markwon/recycler/MarkwonAdapter.java | 123 ++-- .../markwon/recycler/MarkwonAdapterImpl.java | 37 +- .../noties/markwon/recycler/SimpleEntry.java | 61 +- .../layout/markwon_adapter_simple_entry.xml | 9 - sample/build.gradle | 9 +- sample/src/main/AndroidManifest.xml | 4 +- sample/src/main/assets/README.md | 1 + .../sample/recycler/RecyclerActivity.java | 33 +- .../markwon/sample/recycler/TableEntry.java | 67 --- .../markwon/sample/recycler/TableEntry2.java | 121 ---- .../sample/recycler/TableEntryView.java | 219 -------- sample/src/main/recycler/assets/README.md | 1 - .../res/layout/adapter_table_block.xml | 21 - sample/src/main/recycler/res/values/attrs.xml | 9 - .../drawable-v26/ic_launcher_background.xml | 24 - .../res/layout/activity_recycler.xml | 0 .../res/layout/adapter_default_entry.xml | 0 .../res/layout/adapter_fenced_code_block.xml | 0 .../layout/adapter_table_block.xml} | 3 +- .../res/layout/view_table_entry_cell.xml | 4 +- .../res/layout/view_table_entry_row.xml | 0 .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 - .../ic_launcher_foreground.png | Bin 3366 -> 0 bytes .../src/main/res/mipmap-hdpi/ic_launcher.png | Bin 2381 -> 0 bytes .../ic_launcher_foreground.png | Bin 4727 -> 0 bytes .../src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 3319 -> 0 bytes .../ic_launcher_foreground.png | Bin 7773 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 5093 -> 0 bytes .../ic_launcher_foreground.png | Bin 11195 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 6783 -> 0 bytes settings.gradle | 1 + 55 files changed, 1298 insertions(+), 754 deletions(-) create mode 100644 docs/.vuepress/public/assets/recycler-table-screenshot.png create mode 100644 docs/docs/v3/recycler-table/README.md delete mode 100644 markwon-bundle.gradle create mode 100644 markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java create mode 100644 markwon-recycler-table/build.gradle create mode 100644 markwon-recycler-table/gradle.properties create mode 100644 markwon-recycler-table/src/main/AndroidManifest.xml create mode 100644 markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java create mode 100644 markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java create mode 100644 markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java create mode 100644 markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java create mode 100644 markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java delete mode 100644 markwon-recycler/src/main/res/layout/markwon_adapter_simple_entry.xml create mode 120000 sample/src/main/assets/README.md delete mode 100644 sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry.java delete mode 100644 sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry2.java delete mode 100644 sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntryView.java delete mode 120000 sample/src/main/recycler/assets/README.md delete mode 100644 sample/src/main/recycler/res/layout/adapter_table_block.xml delete mode 100644 sample/src/main/recycler/res/values/attrs.xml delete mode 100644 sample/src/main/res/drawable-v26/ic_launcher_background.xml rename sample/src/main/{recycler => }/res/layout/activity_recycler.xml (100%) rename sample/src/main/{recycler => }/res/layout/adapter_default_entry.xml (100%) rename sample/src/main/{recycler => }/res/layout/adapter_fenced_code_block.xml (100%) rename sample/src/main/{recycler/res/layout/adapter_table_block_2.xml => res/layout/adapter_table_block.xml} (83%) rename sample/src/main/{recycler => }/res/layout/view_table_entry_cell.xml (69%) rename sample/src/main/{recycler => }/res/layout/view_table_entry_row.xml (100%) delete mode 100644 sample/src/main/res/mipmap-anydpi-v26/ic_launcher.xml delete mode 100644 sample/src/main/res/mipmap-hdpi-v26/ic_launcher_foreground.png delete mode 100644 sample/src/main/res/mipmap-hdpi/ic_launcher.png delete mode 100644 sample/src/main/res/mipmap-xhdpi-v26/ic_launcher_foreground.png delete mode 100644 sample/src/main/res/mipmap-xhdpi/ic_launcher.png delete mode 100644 sample/src/main/res/mipmap-xxhdpi-v26/ic_launcher_foreground.png delete mode 100644 sample/src/main/res/mipmap-xxhdpi/ic_launcher.png delete mode 100644 sample/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png delete mode 100644 sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/docs/.vuepress/.artifacts.js b/docs/.vuepress/.artifacts.js index 532f38d9..2a1c3f43 100644 --- a/docs/.vuepress/.artifacts.js +++ b/docs/.vuepress/.artifacts.js @@ -1,4 +1,4 @@ // this is a generated file, do not modify. To update it run 'collectArtifacts.js' script -const artifacts = [{"id":"core","name":"Core","group":"ru.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"ru.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"ru.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"ru.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"ru.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"ru.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image-gif","name":"Image GIF","group":"ru.noties.markwon","description":"Adds GIF media support to Markwon markdown"},{"id":"image-okhttp","name":"Image OkHttp","group":"ru.noties.markwon","description":"Adds OkHttp client to retrieve images data from network"},{"id":"image-svg","name":"Image SVG","group":"ru.noties.markwon","description":"Adds SVG media support to Markwon markdown"},{"id":"recycler","name":"Recycler","group":"ru.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"ru.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; +const artifacts = [{"id":"core","name":"Core","group":"ru.noties.markwon","description":"Core Markwon artifact that includes basic markdown parsing and rendering"},{"id":"ext-latex","name":"LaTeX","group":"ru.noties.markwon","description":"Extension to add LaTeX formulas to Markwon markdown"},{"id":"ext-strikethrough","name":"Strikethrough","group":"ru.noties.markwon","description":"Extension to add strikethrough markup to Markwon markdown"},{"id":"ext-tables","name":"Tables","group":"ru.noties.markwon","description":"Extension to add tables markup (GFM) to Markwon markdown"},{"id":"ext-tasklist","name":"Task List","group":"ru.noties.markwon","description":"Extension to add task lists (GFM) to Markwon markdown"},{"id":"html","name":"HTML","group":"ru.noties.markwon","description":"Provides HTML parsing functionality"},{"id":"image-gif","name":"Image GIF","group":"ru.noties.markwon","description":"Adds GIF media support to Markwon markdown"},{"id":"image-okhttp","name":"Image OkHttp","group":"ru.noties.markwon","description":"Adds OkHttp client to retrieve images data from network"},{"id":"image-svg","name":"Image SVG","group":"ru.noties.markwon","description":"Adds SVG media support to Markwon markdown"},{"id":"recycler","name":"Recycler","group":"ru.noties.markwon","description":"Provides RecyclerView.Adapter to display Markwon markdown"},{"id":"recycler-table","name":"Recycler Table","group":"ru.noties.markwon","description":"Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget"},{"id":"syntax-highlight","name":"Syntax Highlight","group":"ru.noties.markwon","description":"Add syntax highlight to Markwon markdown via Prism4j library"}]; export { artifacts }; diff --git a/docs/.vuepress/config.js b/docs/.vuepress/config.js index 29ab8971..85ebf762 100644 --- a/docs/.vuepress/config.js +++ b/docs/.vuepress/config.js @@ -60,6 +60,7 @@ module.exports = { '/docs/v3/image/okhttp.md', '/docs/v3/image/svg.md', '/docs/v3/recycler/', + '/docs/v3/recycler-table/', '/docs/v3/syntax-highlight/', '/docs/v3/migration-2-3.md' ], diff --git a/docs/.vuepress/public/assets/recycler-table-screenshot.png b/docs/.vuepress/public/assets/recycler-table-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..f609c65fedb6b9a6dc3ccfb35160ae677f13161a GIT binary patch literal 78822 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 LWMx=ja3cJl#b=Jg literal 0 HcmV?d00001 diff --git a/docs/docs/v3/ext-tables/README.md b/docs/docs/v3/ext-tables/README.md index a728645c..fe149ed2 100644 --- a/docs/docs/v3/ext-tables/README.md +++ b/docs/docs/v3/ext-tables/README.md @@ -54,8 +54,11 @@ final Table table = Table.parse(Markwon, TableBlock); myTableWidget.setTable(table); ``` -Unfortunately Markwon does not provide a widget that can be used for tables. But it does -provide API that can be used to achieve desired result. +:::tip +To take advantage of this functionality and render tables without limitations (including +horizontally scrollable layout when its contents exceed screen width), refer to [recycler-table](/docs/v3/recycler-table) +module documentation that adds support for rendering `TableBlock` markdown node inside Android-native `TableLayout` widget. +::: ## Theme diff --git a/docs/docs/v3/ext-tasklist/README.md b/docs/docs/v3/ext-tasklist/README.md index 7dde3d9a..3fb332f4 100644 --- a/docs/docs/v3/ext-tasklist/README.md +++ b/docs/docs/v3/ext-tasklist/README.md @@ -7,4 +7,140 @@ Adds support for GFM (Github-flavored markdown) task-lists: ```java Markwon.builder(context) .usePlugin(TaskListPlugin.create(context)); +``` + +--- + +Create a default instance of `TaskListPlugin` with `TaskListDrawable` initialized to use +`android.R.attr.textColorLink` as primary color and `android.R.attr.colorBackground` as background +```java +TaskListPlugin.create(context); +``` + +--- + +Create an instance of `TaskListPlugin` with exact color values to use: +```java +// obtain color values +final int checkedFillColor = /* */; +final int normalOutlineColor = /* */; +final int checkMarkColor = /* */; + +TaskListPlugin.create(checkedFillColor, normalOutlineColor, checkMarkColor); +``` + +--- + +Specify own drawable for a task list item: + +```java +// obtain drawable +final Drawable drawable = /* */; + +TaskListPlugin.create(drawable); +``` + +:::warning +Please note that custom drawable for a task list item must correctly handle state +in order to display done/not-done: + +```java +public class MyTaskListDrawable extends Drawable { + + private boolean isChecked; + + @Override + public void draw(@NonNull Canvas canvas) { + // draw accordingly to the isChecked value + } + + /* implementation omitted */ + + @Override + protected boolean onStateChange(int[] state) { + final boolean isChecked = contains(state, android.R.attr.state_checked); + final boolean result = this.isChecked != isChecked; + if (result) { + this.isChecked = isChecked; + } + return result; + } + + private static boolean contains(@Nullable int[] states, int value) { + if (states != null) { + for (int state : states) { + if (state == value) { + // NB return here + return true; + } + } + } + return false; + } +} +``` +::: + +## Task list mutation + +It is possible to mutate task list item state (toggle done/not-done). But note +that `Markwon` won't handle state change internally by any means and this change +is merely a visual one. If you need to persist state of a task list +item change you have to implement it yourself. This should get your started: + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(TaskListPlugin.create(context)) + .usePlugin(new AbstractMarkwonPlugin() { + @Override + public void configureSpansFactory(@NonNull MarkwonSpansFactory.Builder builder) { + + // obtain original SpanFactory set by TaskListPlugin + final SpanFactory origin = builder.getFactory(TaskListItem.class); + if (origin == null) { + // or throw, as it's a bit weird state and we expect + // this factory to be present + return; + } + + builder.setFactory(TaskListItem.class, new SpanFactory() { + @Override + public Object getSpans(@NonNull MarkwonConfiguration configuration, @NonNull RenderProps props) { + // it's a bit non-secure behavior and we should validate + // the type of returned span first, but for the sake of brevity + // we skip this step + final TaskListSpan span = (TaskListSpan) origin.getSpans(configuration, props); + + if (span == null) { + // or throw + return null; + } + + // return an array of spans + return new Object[]{ + span, + new ClickableSpan() { + @Override + public void onClick(@NonNull View widget) { + // toggle VISUAL state + span.setDone(!span.isDone()); + + // do not forget to invalidate widget + widget.invalidate(); + + // execute your persistence logic + } + + @Override + public void updateDrawState(@NonNull TextPaint ds) { + // no-op, so appearance is not changed (otherwise + // task list item will look like a link) + } + } + }; + } + }); + } + }) + .build(); ``` \ No newline at end of file diff --git a/docs/docs/v3/install.md b/docs/docs/v3/install.md index 93b6de88..7f7184b7 100644 --- a/docs/docs/v3/install.md +++ b/docs/docs/v3/install.md @@ -10,62 +10,6 @@ next: /docs/v3/core/getting-started.md -# Bundle -If you wish to include all Markwon artifacts or add specific artifacts -in a different manner than explicit gradle dependency definition, you can -use `markwon-bundle.gradle` gradle script: - -*(in your `build.gradle`)* -```groovy -apply plugin: 'com.android.application' -apply from: 'https://raw.githubusercontent.com/noties/Markwon/master/markwon-bundle.gradle' - -android { /* */ } - -ext.markwon = [ - 'version': '3.0.0', - 'includeAll': true -] - -dependencies { /* */ } -``` - -`markwon` object can have these properties: -* `version` - (required) version of `Markwon` -* `includeAll` - if _true_ will add all known Markwon artifacts. Can be used with `exclude` -* * `exclude` - an array of artifacts to _exclude_ (cannot exclude `core`) -* `artifacts` - an array of artifacts (can omit `core`, as it will be added implicitly anyway) - -If `includeAll` property is present and is `true`, then `artifacts` property won't be used. -If there is no `includeAll` property or if it is `false`, `exclude` property won't be used. - -These 2 markwon objects are equal: - -```groovy -// #1 -ext.markwon = [ - 'version': '3.0.0', - 'artifacts': [ - 'ext-latex', - 'ext-strikethrough', - 'ext-tables', - 'ext-tasklist', - 'html', - 'image-gif', - 'image-okhttp', - 'image-svg', - 'recycler', - 'syntax-highlight' - ] -] - -// #2 -ext.markwon = [ - 'version': '3.0.0', - 'includeAll': true -] -``` - ## Snapshot In order to use latest `SNAPSHOT` version add snapshot repository diff --git a/docs/docs/v3/recycler-table/README.md b/docs/docs/v3/recycler-table/README.md new file mode 100644 index 00000000..0cd90583 --- /dev/null +++ b/docs/docs/v3/recycler-table/README.md @@ -0,0 +1,90 @@ +# Recycler Table + +Artifact that provides [MarkwonAdapter.Entry](/docs/v3/recycler/) to render `TableBlock` inside +Android-native `TableLayout` widget. + +screenshot +
+* It's possible to wrap `TableLayout` inside a `HorizontalScrollView` to include all table content + +--- + +Register instance of `TableEntry` with `MarkwonAdapter` to render TableBlocks: +```java +final MarkwonAdapter adapter = MarkwonAdapter.builder(R.layout.adapter_default_entry, R.id.text) + .include(TableBlock.class, TableEntry.create(builder -> builder + .tableLayout(R.layout.adapter_table_block, R.id.table_layout) + .textLayoutIsRoot(R.layout.view_table_entry_cell))) + .build(); +``` + +`TableEntry` requires at least 2 arguments: +* `tableLayout` - layout with `TableLayout` inside +* `textLayout` - layout with `TextView` inside (represents independent table cell) + +In case when required view is the root of layout specific builder methods can be used: +* `tableLayoutIsRoot(int)` +* `textLayoutIsRoot(int)` + +If your layouts have different structure (for example wrap a `TableView` inside a `HorizontalScrollView`) +then you should use methods that accept ID of required view inside layout: +* `tableLayout(int, int)` +* `textLayout(int, int)` + +--- + +To display `TableBlock` as a `TableLayout` specific `MarkwonPlugin` must be used: `TableEntryPlugin`. + +:::warning +Do not use `TablePlugin` if you wish to display markdown tables via `TableEntry`. Use **TableEntryPlugin** instead +::: + +`TableEntryPlugin` can reuse existing `TablePlugin` to make appearance of tables the same in both contexts: +when rendering _natively_ in a TextView and when rendering in RecyclerView with TableEntry. + +* `TableEntryPlugin.create(Context)` - creates plugin with default `TableTheme` +* `TableEntryPlugin.create(TableTheme)` - creates plugin with provided `TableTheme` +* `TableEntryPlugin.create(TablePlugin.ThemeConfigure)` - creates plugin with theme configured by `ThemeConfigure` +* `TableEntryPlugin.create(TablePlugin)` - creates plugin with `TableTheme` used in provided `TablePlugin` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(TableEntryPlugin.create(context)) + // other plugins + .build(); +``` + +```java +final Markwon markwon = Markwon.builder(context) + .usePlugin(TableEntryPlugin.create(builder -> builder + .tableBorderWidth(0) + .tableHeaderRowBackgroundColor(Color.RED))) + // other plugins + .build(); +``` + +## Table with scrollable content + +To stretch table columns to fit the width of screen or to make table scrollable when content exceeds screen width +this layout can be used: + +```xml + + + + + +``` \ No newline at end of file diff --git a/markwon-bundle.gradle b/markwon-bundle.gradle deleted file mode 100644 index 603404d6..00000000 --- a/markwon-bundle.gradle +++ /dev/null @@ -1,59 +0,0 @@ -// await project initialization and check for markwon object then -// (so we do not have to force users to put `apply from` block at the bottom -// of a build.gradle file) -project.afterEvaluate { - - if (!project.hasProperty('markwon')) { - throw new RuntimeException("No `markwon` property object is found. " + - "Define it with `ext.markwon = [prop: value]`") - } - - final def markwon = project.markwon - if (!(markwon instanceof Map)) { - throw new RuntimeException("`markwon` object property must be of type Map. " + - "Groovy short-hand to define: `[:]`.") - } - - final def version = markwon.version - final def includeAll = markwon.computeIfAbsent('includeAll', { false }) - final def artifacts - if (includeAll) { - - // cannot exclude core - final def exclude = markwon.computeIfAbsent('exclude', { [] }) \ - .unique() \ - .findAll { 'core' != it } - - artifacts = [ - 'core', - 'ext-latex', - 'ext-strikethrough', - 'ext-tables', - 'ext-tasklist', - 'html', - 'image-gif', - 'image-okhttp', - 'image-svg', - 'recycler', - 'syntax-highlight' - ].findAll { !exclude.contains(it) } - - } else { - artifacts = (markwon.containsKey('artifacts') ? markwon.artifacts : ['core']).with { - // add implicit core artifact - if (!it.contains('core')) { - it.add('core') - } - return it - } - } - - if (!version) { - throw new RuntimeException("Please specify version of Markwon, for example: " + - "`ext.markwon = [ 'version': '1.0.0']`") - } - - artifacts.forEach { - project.dependencies.add('implementation', "ru.noties.markwon:$it:$version") - } -} \ No newline at end of file diff --git a/markwon-core/src/main/java/ru/noties/markwon/Markwon.java b/markwon-core/src/main/java/ru/noties/markwon/Markwon.java index 6e7e1ba3..0ac110ff 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/Markwon.java +++ b/markwon-core/src/main/java/ru/noties/markwon/Markwon.java @@ -2,6 +2,7 @@ package ru.noties.markwon; import android.content.Context; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; @@ -101,6 +102,9 @@ public abstract class Markwon { */ public abstract boolean hasPlugin(@NonNull Class plugin); + @Nullable + public abstract

P getPlugin(@NonNull Class

type); + /** * Builder for {@link Markwon}. *

diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java index a51bd62a..e90b7898 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonImpl.java @@ -1,6 +1,7 @@ package ru.noties.markwon; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.text.Spanned; import android.widget.TextView; @@ -91,13 +92,19 @@ class MarkwonImpl extends Markwon { @Override public boolean hasPlugin(@NonNull Class type) { - boolean result = false; + return getPlugin(type) != null; + } + + @Nullable + @Override + public

P getPlugin(@NonNull Class

type) { + MarkwonPlugin out = null; for (MarkwonPlugin plugin : plugins) { if (type.isAssignableFrom(plugin.getClass())) { - result = true; - break; + out = plugin; } } - return result; + //noinspection unchecked + return (P) out; } } diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java index 251cf1fe..a139e3f1 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonReducer.java @@ -13,6 +13,10 @@ import java.util.List; */ public abstract class MarkwonReducer { + /** + * @return direct children of supplied Node. In the most usual case + * will return all BlockNodes of a Document + */ @NonNull public static MarkwonReducer directChildren() { return new DirectChildren(); diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java index dbc6960d..8cf25a28 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactory.java @@ -34,6 +34,12 @@ public interface MarkwonSpansFactory { @NonNull Builder setFactory(@NonNull Class node, @Nullable SpanFactory factory); + /** + * Can be useful when enhancing an already defined SpanFactory with another one. + */ + @Nullable + SpanFactory getFactory(@NonNull Class node); + @NonNull MarkwonSpansFactory build(); } diff --git a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java b/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java index f3cd0dee..ef1906d8 100644 --- a/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java +++ b/markwon-core/src/main/java/ru/noties/markwon/MarkwonSpansFactoryImpl.java @@ -52,6 +52,12 @@ class MarkwonSpansFactoryImpl implements MarkwonSpansFactory { return this; } + @Nullable + @Override + public SpanFactory getFactory(@NonNull Class node) { + return factories.get(node); + } + @NonNull @Override public MarkwonSpansFactory build() { diff --git a/markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java b/markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java new file mode 100644 index 00000000..f5eedc2a --- /dev/null +++ b/markwon-core/src/main/java/ru/noties/markwon/utils/NoCopySpannableFactory.java @@ -0,0 +1,30 @@ +package ru.noties.markwon.utils; + +import android.support.annotation.NonNull; +import android.text.Spannable; +import android.text.SpannableString; + +/** + * Utility SpannableFactory that re-uses Spannable instance between multiple + * `TextView#setText` calls. + * + * @since 3.0.0 + */ +public class NoCopySpannableFactory extends Spannable.Factory { + + @NonNull + public static NoCopySpannableFactory getInstance() { + return Holder.INSTANCE; + } + + @Override + public Spannable newSpannable(CharSequence source) { + return source instanceof Spannable + ? (Spannable) source + : new SpannableString(source); + } + + static class Holder { + private static final NoCopySpannableFactory INSTANCE = new NoCopySpannableFactory(); + } +} diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java b/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java index ece065bf..f05a84fc 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java +++ b/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TablePlugin.java @@ -54,13 +54,20 @@ public class TablePlugin extends AbstractMarkwonPlugin { return new TablePlugin(builder.build()); } + private final TableTheme theme; private final TableVisitor visitor; @SuppressWarnings("WeakerAccess") TablePlugin(@NonNull TableTheme tableTheme) { + this.theme = tableTheme; this.visitor = new TableVisitor(tableTheme); } + @NonNull + public TableTheme theme() { + return theme; + } + @Override public void configureParser(@NonNull Parser.Builder builder) { builder.extensions(Collections.singleton(TablesExtension.create())); diff --git a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java b/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java index 6752e729..e9b1bd47 100644 --- a/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java +++ b/markwon-ext-tables/src/main/java/ru/noties/markwon/ext/tables/TableTheme.java @@ -13,15 +13,19 @@ public class TableTheme { @NonNull public static TableTheme create(@NonNull Context context) { - final Dip dip = Dip.create(context); - return builder() - .tableCellPadding(dip.toPx(4)) - .tableBorderWidth(dip.toPx(1)) - .build(); + return buildWithDefaults(context).build(); } @NonNull - public static Builder builder() { + public static Builder buildWithDefaults(@NonNull Context context) { + final Dip dip = Dip.create(context); + return emptyBuilder() + .tableCellPadding(dip.toPx(4)) + .tableBorderWidth(dip.toPx(1)); + } + + @NonNull + public static Builder emptyBuilder() { return new Builder(); } @@ -58,6 +62,20 @@ public class TableTheme { this.tableHeaderRowBackgroundColor = builder.tableHeaderRowBackgroundColor; } + /** + * @since 3.0.0 + */ + @NonNull + public Builder asBuilder() { + return new Builder() + .tableCellPadding(tableCellPadding) + .tableBorderColor(tableBorderColor) + .tableBorderWidth(tableBorderWidth) + .tableOddRowBackgroundColor(tableOddRowBackgroundColor) + .tableEvenRowBackgroundColor(tableEvenRowBackgroundColor) + .tableHeaderRowBackgroundColor(tableHeaderRowBackgroundColor); + } + public int tableCellPadding() { return tableCellPadding; } diff --git a/markwon-recycler-table/build.gradle b/markwon-recycler-table/build.gradle new file mode 100644 index 00000000..841c2b60 --- /dev/null +++ b/markwon-recycler-table/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.library' + +android { + + compileSdkVersion config['compile-sdk'] + buildToolsVersion config['build-tools'] + + defaultConfig { + minSdkVersion config['min-sdk'] + targetSdkVersion config['target-sdk'] + versionCode 1 + versionName version + } +} + +dependencies { + + api project(':markwon-core') + api project(':markwon-recycler') + api project(':markwon-ext-tables') + + deps['test'].with { + testImplementation it['junit'] + testImplementation it['robolectric'] + testImplementation it['mockito'] + } +} + +registerArtifact(this) \ No newline at end of file diff --git a/markwon-recycler-table/gradle.properties b/markwon-recycler-table/gradle.properties new file mode 100644 index 00000000..8e87be51 --- /dev/null +++ b/markwon-recycler-table/gradle.properties @@ -0,0 +1,4 @@ +POM_NAME=Recycler Table +POM_ARTIFACT_ID=recycler-table +POM_DESCRIPTION=Provides MarkwonAdapter.Entry to render TableBlocks inside Android-native TableLayout widget +POM_PACKAGING=aar \ No newline at end of file diff --git a/markwon-recycler-table/src/main/AndroidManifest.xml b/markwon-recycler-table/src/main/AndroidManifest.xml new file mode 100644 index 00000000..b215e1f6 --- /dev/null +++ b/markwon-recycler-table/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java new file mode 100644 index 00000000..06a89f24 --- /dev/null +++ b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableBorderDrawable.java @@ -0,0 +1,48 @@ +package ru.noties.markwon.recycler.table; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Paint; +import android.graphics.PixelFormat; +import android.graphics.drawable.Drawable; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.annotation.Px; + +class TableBorderDrawable extends Drawable { + + private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); + + TableBorderDrawable() { + paint.setStyle(Paint.Style.STROKE); + } + + @Override + public void draw(@NonNull Canvas canvas) { + if (paint.getStrokeWidth() > 0) { + canvas.drawRect(getBounds(), paint); + } + } + + @Override + public void setAlpha(int alpha) { + // no op + } + + @Override + public void setColorFilter(@Nullable ColorFilter colorFilter) { + // no op + } + + @Override + public int getOpacity() { + return PixelFormat.OPAQUE; + } + + void update(@Px int borderWidth, @ColorInt int color) { + paint.setStrokeWidth(borderWidth); + paint.setColor(color); + invalidateSelf(); + } +} diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java new file mode 100644 index 00000000..5ff8b25e --- /dev/null +++ b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntry.java @@ -0,0 +1,530 @@ +package ru.noties.markwon.recycler.table; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.support.annotation.ColorInt; +import android.support.annotation.IdRes; +import android.support.annotation.LayoutRes; +import android.support.annotation.NonNull; +import android.support.annotation.Px; +import android.support.annotation.VisibleForTesting; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TableLayout; +import android.widget.TableRow; +import android.widget.TextView; + +import org.commonmark.ext.gfm.tables.TableBlock; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import ru.noties.markwon.Markwon; +import ru.noties.markwon.ext.tables.Table; +import ru.noties.markwon.recycler.MarkwonAdapter; +import ru.noties.markwon.utils.NoCopySpannableFactory; + +/** + * @since 3.0.0 + */ +public class TableEntry extends MarkwonAdapter.Entry { + + public interface Builder { + + /** + * @param tableLayoutResId layout with TableLayout + * @param tableIdRes id of the TableLayout inside specified layout + * @see #tableLayoutIsRoot(int) + */ + @NonNull + Builder tableLayout(@LayoutRes int tableLayoutResId, @IdRes int tableIdRes); + + /** + * @param tableLayoutResId layout with TableLayout as the root view + * @see #tableLayout(int, int) + */ + @NonNull + Builder tableLayoutIsRoot(@LayoutRes int tableLayoutResId); + + /** + * @param textLayoutResId layout with TextView + * @param textIdRes id of the TextView inside specified layout + * @see #textLayoutIsRoot(int) + */ + @NonNull + Builder textLayout(@LayoutRes int textLayoutResId, @IdRes int textIdRes); + + /** + * @param textLayoutResId layout with TextView as the root view + * @see #textLayout(int, int) + */ + @NonNull + Builder textLayoutIsRoot(@LayoutRes int textLayoutResId); + + /** + * @param cellTextCenterVertical if text inside a table cell should centered + * vertically (by default `true`) + */ + @NonNull + Builder cellTextCenterVertical(boolean cellTextCenterVertical); + + /** + * @param isRecyclable flag to set on RecyclerView.ViewHolder (by default `true`) + */ + @NonNull + Builder isRecyclable(boolean isRecyclable); + + @NonNull + TableEntry build(); + } + + public interface BuilderConfigure { + void configure(@NonNull Builder builder); + } + + @NonNull + public static Builder builder() { + return new BuilderImpl(); + } + + @NonNull + public static TableEntry create(@NonNull BuilderConfigure configure) { + final Builder builder = builder(); + configure.configure(builder); + return builder.build(); + } + + private final int tableLayoutResId; + private final int tableIdRes; + + private final int textLayoutResId; + private final int textIdRes; + + private final boolean isRecyclable; + private final boolean cellTextCenterVertical; // by default true + + private LayoutInflater inflater; + + private final Map map = new HashMap<>(3); + + TableEntry( + @LayoutRes int tableLayoutResId, + @IdRes int tableIdRes, + @LayoutRes int textLayoutResId, + @IdRes int textIdRes, + boolean isRecyclable, + boolean cellTextCenterVertical) { + this.tableLayoutResId = tableLayoutResId; + this.tableIdRes = tableIdRes; + this.textLayoutResId = textLayoutResId; + this.textIdRes = textIdRes; + this.isRecyclable = isRecyclable; + this.cellTextCenterVertical = cellTextCenterVertical; + } + + @NonNull + @Override + public Holder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { + return new Holder( + isRecyclable, + tableIdRes, + inflater.inflate(tableLayoutResId, parent, false)); + } + + @Override + public void bindHolder(@NonNull Markwon markwon, @NonNull Holder holder, @NonNull TableBlock node) { + + Table table = map.get(node); + if (table == null) { + table = Table.parse(markwon, node); + map.put(node, table); + } + + // check if this exact TableBlock was already applied + // set tag of tableLayoutResId as it's 100% to be present (we still allow 0 as + // tableIdRes if tableLayoutResId has TableLayout as root view) + final TableLayout layout = holder.tableLayout; + if (table == null + || table == layout.getTag(tableLayoutResId)) { + return; + } + + // set this flag to indicate what table instance we current display + layout.setTag(tableLayoutResId, table); + + final TableEntryPlugin plugin = markwon.getPlugin(TableEntryPlugin.class); + if (plugin == null) { + throw new IllegalStateException("No TableEntryPlugin is found. Make sure that it " + + "is _used_ whilst configuring Markwon instance"); + } + + // we must remove unwanted ones (rows and columns) + + final TableEntryTheme theme = plugin.theme(); + final int borderWidth; + final int borderColor; + final int cellPadding; + { + final TextView textView = ensureTextView(layout, 0, 0); + borderWidth = theme.tableBorderWidth(textView.getPaint()); + borderColor = theme.tableBorderColor(textView.getPaint()); + cellPadding = theme.tableCellPadding(); + } + + ensureTableBorderBackground(layout, borderWidth, borderColor); + + //noinspection SuspiciousNameCombination +// layout.setPadding(borderWidth, borderWidth, borderWidth, borderWidth); +// layout.setClipToPadding(borderWidth == 0); + + final List rows = table.rows(); + + final int rowsSize = rows.size(); + + // all rows should have equal number of columns + final int columnsSize = rowsSize > 0 + ? rows.get(0).columns().size() + : 0; + + Table.Row row; + Table.Column column; + + TableRow tableRow; + + for (int y = 0; y < rowsSize; y++) { + + row = rows.get(y); + tableRow = ensureRow(layout, y); + + for (int x = 0; x < columnsSize; x++) { + + column = row.columns().get(x); + + final TextView textView = ensureTextView(layout, y, x); + textView.setGravity(textGravity(column.alignment(), cellTextCenterVertical)); + textView.getPaint().setFakeBoldText(row.header()); + + // apply padding only if not specified in theme (otherwise just use the value from layout) + if (cellPadding > 0) { + textView.setPadding(cellPadding, cellPadding, cellPadding, cellPadding); + } + + ensureTableBorderBackground(textView, borderWidth, borderColor); + markwon.setParsedMarkdown(textView, column.content()); + } + + // row appearance + if (row.header()) { + tableRow.setBackgroundColor(theme.tableHeaderRowBackgroundColor()); + } else { + // as we currently have no support for tables without head + // we shift even/odd calculation a bit (head should not be included in even/odd calculation) + final boolean isEven = (y % 2) == 1; + if (isEven) { + tableRow.setBackgroundColor(theme.tableEvenRowBackgroundColor()); + } else { + // just take first + final TextView textView = ensureTextView(layout, y, 0); + tableRow.setBackgroundColor( + theme.tableOddRowBackgroundColor(textView.getPaint())); + } + } + } + + // clean up here of un-used rows and columns + removeUnused(layout, rowsSize, columnsSize); + } + + @NonNull + private TableRow ensureRow(@NonNull TableLayout layout, int row) { + + final int count = layout.getChildCount(); + + // fill the requested views until we have added the `row` one + if (row >= count) { + + final Context context = layout.getContext(); + + int diff = row - count + 1; + while (diff > 0) { + layout.addView(new TableRow(context)); + diff -= 1; + } + } + + // return requested child (here it always should be the last one) + return (TableRow) layout.getChildAt(row); + } + + @NonNull + private TextView ensureTextView(@NonNull TableLayout layout, int row, int column) { + + final TableRow tableRow = ensureRow(layout, row); + final int count = tableRow.getChildCount(); + + if (column >= count) { + + final LayoutInflater inflater = ensureInflater(layout.getContext()); + + boolean textViewChecked = false; + + View view; + TextView textView; + ViewGroup.LayoutParams layoutParams; + + int diff = column - count + 1; + + while (diff > 0) { + + view = inflater.inflate(textLayoutResId, tableRow, false); + + // we should have `match_parent` as height (important for borders and text-vertical-align) + layoutParams = view.getLayoutParams(); + if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) { + layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT; + } + + // it will be enough to check only once + if (!textViewChecked) { + + if (textIdRes == 0) { + if (!(view instanceof TextView)) { + final String name = layout.getContext().getResources().getResourceName(textLayoutResId); + throw new IllegalStateException(String.format("textLayoutResId(R.layout.%s) " + + "has other than TextView root view. Specify TextView ID explicitly", name)); + } + textView = (TextView) view; + } else { + textView = view.findViewById(textIdRes); + if (textView == null) { + final Resources r = layout.getContext().getResources(); + final String layoutName = r.getResourceName(textLayoutResId); + final String idName = r.getResourceName(textIdRes); + throw new NullPointerException(String.format("textLayoutResId(R.layout.%s) " + + "has no TextView found by id(R.id.%s): %s", layoutName, idName, view)); + } + } + // mark as checked + textViewChecked = true; + } else { + if (textIdRes == 0) { + textView = (TextView) view; + } else { + textView = view.findViewById(textIdRes); + } + } + + // we should set SpannableFactory during creation (to avoid another setText method) + textView.setSpannableFactory(NoCopySpannableFactory.getInstance()); + tableRow.addView(textView); + + diff -= 1; + } + } + + // we can skip all the validation here as we have validated our views whilst inflating them + final View last = tableRow.getChildAt(column); + if (textIdRes == 0) { + return (TextView) last; + } else { + return last.findViewById(textIdRes); + } + } + + private void ensureTableBorderBackground(@NonNull View view, @Px int borderWidth, @ColorInt int borderColor) { + if (borderWidth == 0) { + view.setBackground(null); + } else { + final Drawable drawable = view.getBackground(); + if (!(drawable instanceof TableBorderDrawable)) { + final TableBorderDrawable borderDrawable = new TableBorderDrawable(); + borderDrawable.update(borderWidth, borderColor); + view.setBackground(borderDrawable); + } else { + ((TableBorderDrawable) drawable).update(borderWidth, borderColor); + } + } + } + + @NonNull + private LayoutInflater ensureInflater(@NonNull Context context) { + if (inflater == null) { + inflater = LayoutInflater.from(context); + } + return inflater; + } + + @SuppressWarnings("WeakerAccess") + @VisibleForTesting + static void removeUnused(@NonNull TableLayout layout, int usedRows, int usedColumns) { + + // clean up rows + final int rowsCount = layout.getChildCount(); + if (rowsCount > usedRows) { + layout.removeViews(usedRows, (rowsCount - usedRows)); + } + + // validate columns + // here we can use usedRows as children count + + TableRow tableRow; + int columnCount; + + for (int i = 0; i < usedRows; i++) { + tableRow = (TableRow) layout.getChildAt(i); + columnCount = tableRow.getChildCount(); + if (columnCount > usedColumns) { + tableRow.removeViews(usedColumns, (columnCount - usedColumns)); + } + } + } + + @Override + public void clear() { + map.clear(); + } + + public static class Holder extends MarkwonAdapter.Holder { + + final TableLayout tableLayout; + + public Holder(boolean isRecyclable, @IdRes int tableLayoutIdRes, @NonNull View itemView) { + super(itemView); + + // we must call this method only once (it's somehow _paired_ inside, so + // any call in `onCreateViewHolder` or `onBindViewHolder` will log an error + // `isRecyclable decremented below 0` which make little sense here) + setIsRecyclable(isRecyclable); + + final TableLayout tableLayout; + if (tableLayoutIdRes == 0) { + // try to cast directly + if (!(itemView instanceof TableLayout)) { + throw new IllegalStateException("Root view is not TableLayout. Please provide " + + "TableLayout ID explicitly"); + } + tableLayout = (TableLayout) itemView; + } else { + tableLayout = requireView(tableLayoutIdRes); + } + this.tableLayout = tableLayout; + } + } + + // we will use gravity instead of textAlignment because min sdk is 16 (textAlignment starts at 17) + @SuppressWarnings("WeakerAccess") + @SuppressLint("RtlHardcoded") + @VisibleForTesting + static int textGravity(@NonNull Table.Alignment alignment, boolean cellTextCenterVertical) { + + final int gravity; + + switch (alignment) { + + case LEFT: + gravity = Gravity.LEFT; + break; + + case CENTER: + gravity = Gravity.CENTER_HORIZONTAL; + break; + + case RIGHT: + gravity = Gravity.RIGHT; + break; + + default: + throw new IllegalStateException("Unknown table alignment: " + alignment); + } + + if (cellTextCenterVertical) { + return gravity | Gravity.CENTER_VERTICAL; + } + + // do not center vertically + return gravity; + } + + static class BuilderImpl implements Builder { + + private int tableLayoutResId; + private int tableIdRes; + + private int textLayoutResId; + private int textIdRes; + + private boolean cellTextCenterVertical = true; + + private boolean isRecyclable = true; + + @NonNull + @Override + public Builder tableLayout(int tableLayoutResId, int tableIdRes) { + this.tableLayoutResId = tableLayoutResId; + this.tableIdRes = tableIdRes; + return this; + } + + @NonNull + @Override + public Builder tableLayoutIsRoot(int tableLayoutResId) { + this.tableLayoutResId = tableLayoutResId; + this.tableIdRes = 0; + return this; + } + + @NonNull + @Override + public Builder textLayout(int textLayoutResId, int textIdRes) { + this.textLayoutResId = textLayoutResId; + this.textIdRes = textIdRes; + return this; + } + + @NonNull + @Override + public Builder textLayoutIsRoot(int textLayoutResId) { + this.textLayoutResId = textLayoutResId; + this.textIdRes = 0; + return this; + } + + @NonNull + @Override + public Builder cellTextCenterVertical(boolean cellTextCenterVertical) { + this.cellTextCenterVertical = cellTextCenterVertical; + return this; + } + + @NonNull + @Override + public Builder isRecyclable(boolean isRecyclable) { + this.isRecyclable = isRecyclable; + return this; + } + + @NonNull + @Override + public TableEntry build() { + + if (tableLayoutResId == 0) { + throw new IllegalStateException("`tableLayoutResId` argument is required"); + } + + if (textLayoutResId == 0) { + throw new IllegalStateException("`textLayoutResId` argument is required"); + } + + return new TableEntry( + tableLayoutResId, tableIdRes, + textLayoutResId, textIdRes, + isRecyclable, cellTextCenterVertical + ); + } + } +} diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java new file mode 100644 index 00000000..a92400ee --- /dev/null +++ b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryPlugin.java @@ -0,0 +1,65 @@ +package ru.noties.markwon.recycler.table; + +import android.content.Context; +import android.support.annotation.NonNull; + +import org.commonmark.ext.gfm.tables.TablesExtension; +import org.commonmark.parser.Parser; + +import java.util.Collections; + +import ru.noties.markwon.AbstractMarkwonPlugin; +import ru.noties.markwon.ext.tables.TablePlugin; +import ru.noties.markwon.ext.tables.TableTheme; + +/** + * This plugin must be used instead of {@link ru.noties.markwon.ext.tables.TablePlugin} when a markdown + * table is intended to be used in a RecyclerView via {@link TableEntry}. This is required + * because TablePlugin additionally processes markdown tables to be displayed in limited + * context of a TextView. If TablePlugin will be used, {@link TableEntry} will display table, + * but no content will be present + * + * @since 3.0.0 + */ +public class TableEntryPlugin extends AbstractMarkwonPlugin { + + @NonNull + public static TableEntryPlugin create(@NonNull Context context) { + final TableTheme tableTheme = TableTheme.create(context); + return create(tableTheme); + } + + @NonNull + public static TableEntryPlugin create(@NonNull TableTheme tableTheme) { + return new TableEntryPlugin(TableEntryTheme.create(tableTheme)); + } + + @NonNull + public static TableEntryPlugin create(@NonNull TablePlugin.ThemeConfigure themeConfigure) { + final TableTheme.Builder builder = new TableTheme.Builder(); + themeConfigure.configureTheme(builder); + return new TableEntryPlugin(new TableEntryTheme(builder)); + } + + @NonNull + public static TableEntryPlugin create(@NonNull TablePlugin plugin) { + return create(plugin.theme()); + } + + private final TableEntryTheme theme; + + @SuppressWarnings("WeakerAccess") + TableEntryPlugin(@NonNull TableEntryTheme tableTheme) { + this.theme = tableTheme; + } + + @NonNull + public TableEntryTheme theme() { + return theme; + } + + @Override + public void configureParser(@NonNull Parser.Builder builder) { + builder.extensions(Collections.singleton(TablesExtension.create())); + } +} diff --git a/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java new file mode 100644 index 00000000..e9b9b7ca --- /dev/null +++ b/markwon-recycler-table/src/main/java/ru/noties/markwon/recycler/table/TableEntryTheme.java @@ -0,0 +1,67 @@ +package ru.noties.markwon.recycler.table; + +import android.graphics.Paint; +import android.support.annotation.ColorInt; +import android.support.annotation.NonNull; +import android.support.annotation.Px; + +import ru.noties.markwon.ext.tables.TableTheme; +import ru.noties.markwon.utils.ColorUtils; + +/** + * Mimics TableTheme to allow uniform table customization + * + * @see #create(TableTheme) + * @see TableEntryPlugin + * @since 3.0.0 + */ +@SuppressWarnings("WeakerAccess") +public class TableEntryTheme extends TableTheme { + + @NonNull + public static TableEntryTheme create(@NonNull TableTheme tableTheme) { + return new TableEntryTheme(tableTheme.asBuilder()); + } + + protected TableEntryTheme(@NonNull Builder builder) { + super(builder); + } + + @Px + @Override + public int tableCellPadding() { + return tableCellPadding; + } + + @ColorInt + public int tableBorderColor(@NonNull Paint paint) { + return tableBorderColor == 0 + ? ColorUtils.applyAlpha(paint.getColor(), TABLE_BORDER_DEF_ALPHA) + : tableBorderColor; + } + + @Px + @Override + public int tableBorderWidth(@NonNull Paint paint) { + return tableBorderWidth < 0 + ? (int) (paint.getStrokeWidth() + .5F) + : tableBorderWidth; + } + + @ColorInt + public int tableOddRowBackgroundColor(@NonNull Paint paint) { + return tableOddRowBackgroundColor == 0 + ? ColorUtils.applyAlpha(paint.getColor(), TABLE_ODD_ROW_DEF_ALPHA) + : tableOddRowBackgroundColor; + } + + @ColorInt + public int tableEvenRowBackgroundColor() { + return tableEvenRowBackgroundColor; + } + + @ColorInt + public int tableHeaderRowBackgroundColor() { + return tableHeaderRowBackgroundColor; + } +} diff --git a/markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java b/markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java new file mode 100644 index 00000000..ae55f18e --- /dev/null +++ b/markwon-recycler-table/src/test/java/ru/noties/markwon/recycler/table/TableEntryTest.java @@ -0,0 +1,103 @@ +package ru.noties.markwon.recycler.table; + +import android.content.res.Resources; +import android.util.Pair; +import android.view.Gravity; +import android.view.View; +import android.widget.TableLayout; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.annotation.Config; + +import java.util.Arrays; +import java.util.List; + +import ru.noties.markwon.ext.tables.Table; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(RobolectricTestRunner.class) +@Config(manifest = Config.NONE) +public class TableEntryTest { + + @Test + public void gravity() { + // test textGravity is calculated correctly + + final List> noVerticalAlign = Arrays.asList( + new Pair(Table.Alignment.LEFT, Gravity.LEFT), + new Pair(Table.Alignment.CENTER, Gravity.CENTER_HORIZONTAL), + new Pair(Table.Alignment.RIGHT, Gravity.RIGHT) + ); + + final List> withVerticalAlign = Arrays.asList( + new Pair(Table.Alignment.LEFT, Gravity.LEFT | Gravity.CENTER_VERTICAL), + new Pair(Table.Alignment.CENTER, Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL), + new Pair(Table.Alignment.RIGHT, Gravity.RIGHT | Gravity.CENTER_VERTICAL) + ); + + for (Pair pair : noVerticalAlign) { + assertEquals(pair.first.name(), pair.second.intValue(), TableEntry.textGravity(pair.first, false)); + } + + for (Pair pair : withVerticalAlign) { + assertEquals(pair.first.name(), pair.second.intValue(), TableEntry.textGravity(pair.first, true)); + } + } + + @Test + public void holder_no_table_layout_id() { + // validate that holder correctly obtains TableLayout instance casting root view + + // root is not TableLayout + try { + new TableEntry.Holder(false, 0, mock(View.class)); + fail(); + } catch (IllegalStateException e) { + assertTrue(e.getMessage().contains("Root view is not TableLayout")); + } + + // root is TableLayout + try { + final TableLayout tableLayout = mock(TableLayout.class); + final TableEntry.Holder h = new TableEntry.Holder(false, 0, tableLayout); + assertEquals(tableLayout, h.tableLayout); + } catch (IllegalStateException e) { + fail(e.getMessage()); + } + } + + @Test + public void holder_with_table_layout_id() { + + // not found + try { + + final View view = mock(View.class); + // resources are used to obtain id name for proper error message + when(view.getResources()).thenReturn(mock(Resources.class)); + new TableEntry.Holder(false, 1, view); + fail(); + } catch (NullPointerException e) { + assertTrue(e.getMessage(), e.getMessage().contains("No view with id")); + } + + // found + try { + final TableLayout tableLayout = mock(TableLayout.class); + final View view = mock(View.class); + when(view.findViewById(3)).thenReturn(tableLayout); + final TableEntry.Holder holder = new TableEntry.Holder(false, 3, view); + assertEquals(tableLayout, holder.tableLayout); + } catch (NullPointerException e) { + e.printStackTrace(); + fail(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java b/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java index d288a44c..64241d55 100644 --- a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java +++ b/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapter.java @@ -18,17 +18,13 @@ import ru.noties.markwon.MarkwonReducer; /** * Adapter to display markdown in a RecyclerView. It is done by extracting root blocks from a - * parsed markdown document and rendering each block in a standalone RecyclerView entry. Provides + * parsed markdown document (via {@link MarkwonReducer} and rendering each block in a standalone RecyclerView entry. Provides * ability to customize rendering of blocks. For example display certain blocks in a horizontal * scrolling container or display tables in a specific widget designed for it ({@link Builder#include(Class, Entry)}). - *

- * By default each node will be rendered in a TextView provided by this artifact. It has no styling - * information and thus must be replaced with your own layout ({@link Builder#defaultEntry(int)} or - * {@link Builder#defaultEntry(Entry)}). * - * @see #builder() - * @see #create() - * @see #create(int) + * @see #builder(int, int) + * @see #builder(Entry) + * @see #create(int, int) * @see #create(Entry) * @see #setMarkdown(Markwon, String) * @see #setParsedMarkdown(Markwon, Node) @@ -37,14 +33,34 @@ import ru.noties.markwon.MarkwonReducer; */ public abstract class MarkwonAdapter extends RecyclerView.Adapter { + @NonNull + public static Builder builderTextViewIsRoot(@LayoutRes int defaultEntryLayoutResId) { + return builder(SimpleEntry.createTextViewIsRoot(defaultEntryLayoutResId)); + } + /** * Factory method to obtain {@link Builder} instance. * * @see Builder */ @NonNull - public static Builder builder() { - return new MarkwonAdapterImpl.BuilderImpl(); + public static Builder builder( + @LayoutRes int defaultEntryLayoutResId, + @IdRes int defaultEntryTextViewResId + ) { + return builder(SimpleEntry.create(defaultEntryLayoutResId, defaultEntryTextViewResId)); + } + + @NonNull + public static Builder builder(@NonNull Entry defaultEntry) { + //noinspection unchecked + return new MarkwonAdapterImpl.BuilderImpl((Entry) defaultEntry); + } + + @NonNull + public static MarkwonAdapter createTextViewIsRoot(@LayoutRes int defaultEntryLayoutResId) { + return builderTextViewIsRoot(defaultEntryLayoutResId) + .build(); } /** @@ -52,12 +68,16 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter defaultEntry) { - return new MarkwonAdapterImpl.BuilderImpl().defaultEntry(defaultEntry).build(); - } - - /** - * Factory method to create a {@link MarkwonAdapter} that will use supplied layoutResId view - * to display all nodes. - * - * Please note that supplied layout must have a TextView inside - * with {@code android:id="@+id/text"} - * - * @param layoutResId layout to be used to display all nodes - * @see SimpleEntry - */ - @NonNull - public static MarkwonAdapter create(@LayoutRes int layoutResId) { - return new MarkwonAdapterImpl.BuilderImpl().defaultEntry(layoutResId).build(); + return builder(defaultEntry).build(); } /** * Builder to create an instance of {@link MarkwonAdapter} * * @see #include(Class, Entry) - * @see #defaultEntry(int) - * @see #defaultEntry(Entry) * @see #reducer(MarkwonReducer) + * @see #build() */ public interface Builder { @@ -112,29 +116,6 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter node, @NonNull Entry entry); - /** - * Specify which {@link Entry} to use for all non-explicitly registered nodes - * - * @param defaultEntry {@link Entry} - * @return self - * @see SimpleEntry - */ - @NonNull - Builder defaultEntry(@NonNull Entry defaultEntry); - - /** - * Specify which layout {@link SimpleEntry} will use to render all non-explicitly - * registered nodes. - * - * Please note that supplied layout must have a TextView inside - * with {@code android:id="@+id/text"} - * - * @return self - * @see SimpleEntry - */ - @NonNull - Builder defaultEntry(@LayoutRes int layoutResId); - /** * Specify how root Node will be reduced to a list of nodes. There is a default * {@link MarkwonReducer} that will be used if not provided explicitly (there is no need to @@ -157,17 +138,27 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter { + public static abstract class Entry { @NonNull - H createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent); + public abstract H createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent); - void bindHolder(@NonNull Markwon markwon, @NonNull H holder, @NonNull N node); + public abstract void bindHolder(@NonNull Markwon markwon, @NonNull H holder, @NonNull N node); - long id(@NonNull N node); + /** + * Will be called when new content is available (clear internal cache if any) + */ + public void clear() { - // will be called when new content is available (clear internal cache if any) - void clear(); + } + + public long id(@NonNull N node) { + return node.hashCode(); + } + + public void onViewRecycled(@NonNull H holder) { + + } } public abstract void setMarkdown(@NonNull Markwon markwon, @NonNull String markdown); @@ -196,7 +187,15 @@ public abstract class MarkwonAdapter extends RecyclerView.Adapter V requireView(@IdRes int id) { final V v = itemView.findViewById(id); if (v == null) { - throw new NullPointerException(); + final String name; + if (id == 0 + || id == View.NO_ID) { + name = String.valueOf(id); + } else { + name = "R.id." + itemView.getResources().getResourceName(id); + } + throw new NullPointerException(String.format("No view with id(R.id.%s) is found " + + "in layout: %s", name, itemView)); } return v; } diff --git a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java b/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java index 70406e78..30b093f5 100644 --- a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java +++ b/markwon-recycler/src/main/java/ru/noties/markwon/recycler/MarkwonAdapterImpl.java @@ -32,6 +32,7 @@ class MarkwonAdapterImpl extends MarkwonAdapter { this.entries = entries; this.defaultEntry = defaultEntry; this.reducer = reducer; + setHasStableIds(true); } @@ -90,6 +91,14 @@ class MarkwonAdapterImpl extends MarkwonAdapter { : 0; } + @Override + public void onViewRecycled(@NonNull Holder holder) { + super.onViewRecycled(holder); + + final Entry entry = getEntry(holder.getItemViewType()); + entry.onViewRecycled(holder); + } + @SuppressWarnings("unused") @NonNull public List getItems() { @@ -132,9 +141,14 @@ class MarkwonAdapterImpl extends MarkwonAdapter { private final SparseArray> entries = new SparseArray<>(3); - private Entry defaultEntry; + private final Entry defaultEntry; + private MarkwonReducer reducer; + BuilderImpl(@NonNull Entry defaultEntry) { + this.defaultEntry = defaultEntry; + } + @NonNull @Override public Builder include( @@ -145,22 +159,6 @@ class MarkwonAdapterImpl extends MarkwonAdapter { return this; } - @NonNull - @Override - public Builder defaultEntry(@NonNull Entry defaultEntry) { - //noinspection unchecked - this.defaultEntry = (Entry) defaultEntry; - return this; - } - - @NonNull - @Override - public Builder defaultEntry(int layoutResId) { - //noinspection unchecked - this.defaultEntry = (Entry) (Entry) new SimpleEntry(layoutResId); - return this; - } - @NonNull @Override public Builder reducer(@NonNull MarkwonReducer reducer) { @@ -172,11 +170,6 @@ class MarkwonAdapterImpl extends MarkwonAdapter { @Override public MarkwonAdapter build() { - if (defaultEntry == null) { - //noinspection unchecked - defaultEntry = (Entry) (Entry) new SimpleEntry(); - } - if (reducer == null) { reducer = MarkwonReducer.directChildren(); } diff --git a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java b/markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java index 03ce5e56..93ef0d30 100644 --- a/markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java +++ b/markwon-recycler/src/main/java/ru/noties/markwon/recycler/SimpleEntry.java @@ -1,9 +1,8 @@ package ru.noties.markwon.recycler; +import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; -import android.text.Spannable; -import android.text.SpannableString; import android.text.Spanned; import android.view.LayoutInflater; import android.view.View; @@ -16,32 +15,43 @@ import java.util.HashMap; import java.util.Map; import ru.noties.markwon.Markwon; +import ru.noties.markwon.utils.NoCopySpannableFactory; /** * @since 3.0.0 */ @SuppressWarnings("WeakerAccess") -public class SimpleEntry implements MarkwonAdapter.Entry { +public class SimpleEntry extends MarkwonAdapter.Entry { - public static final Spannable.Factory NO_COPY_SPANNABLE_FACTORY = new NoCopySpannableFactory(); + /** + * Create {@link SimpleEntry} that has TextView as the root view of + * specified layout. + */ + @NonNull + public static SimpleEntry createTextViewIsRoot(@LayoutRes int layoutResId) { + return new SimpleEntry(layoutResId, 0); + } + + @NonNull + public static SimpleEntry create(@LayoutRes int layoutResId, @IdRes int textViewIdRes) { + return new SimpleEntry(layoutResId, textViewIdRes); + } // small cache for already rendered nodes private final Map cache = new HashMap<>(); private final int layoutResId; + private final int textViewIdRes; - public SimpleEntry() { - this(R.layout.markwon_adapter_simple_entry); - } - - public SimpleEntry(@LayoutRes int layoutResId) { + public SimpleEntry(@LayoutRes int layoutResId, @IdRes int textViewIdRes) { this.layoutResId = layoutResId; + this.textViewIdRes = textViewIdRes; } @NonNull @Override public Holder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new Holder(inflater.inflate(layoutResId, parent, false)); + return new Holder(textViewIdRes, inflater.inflate(layoutResId, parent, false)); } @Override @@ -54,11 +64,6 @@ public class SimpleEntry implements MarkwonAdapter.Entry - \ No newline at end of file diff --git a/sample/build.gradle b/sample/build.gradle index 35db7389..966d0747 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -29,14 +29,6 @@ android { targetCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8 } - - sourceSets { - main { - // let's use different res directory so sample will have _isolated_ resources from others - res.srcDirs += [ './src/main/recycler/res' ] - assets.srcDirs += ['./src/main/recycler/assets'] - } - } } dependencies { @@ -51,6 +43,7 @@ dependencies { implementation project(':markwon-image-svg') implementation project(':markwon-syntax-highlight') implementation project(':markwon-recycler') + implementation project(':markwon-recycler-table') deps.with { implementation it['support-recycler-view'] diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index d1442bf0..376348ca 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -7,11 +7,9 @@ + tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"> diff --git a/sample/src/main/assets/README.md b/sample/src/main/assets/README.md new file mode 120000 index 00000000..ff5c7960 --- /dev/null +++ b/sample/src/main/assets/README.md @@ -0,0 +1 @@ +../../../../README.md \ No newline at end of file diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java index c230aa6c..adeb6c4b 100644 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java +++ b/sample/src/main/java/ru/noties/markwon/sample/recycler/RecyclerActivity.java @@ -11,15 +11,12 @@ import android.support.v7.widget.RecyclerView; import android.text.TextUtils; import org.commonmark.ext.gfm.tables.TableBlock; -import org.commonmark.ext.gfm.tables.TablesExtension; import org.commonmark.node.FencedCodeBlock; -import org.commonmark.parser.Parser; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.Collections; import ru.noties.debug.AndroidLogDebugOutput; import ru.noties.debug.Debug; @@ -33,6 +30,8 @@ import ru.noties.markwon.image.ImagesPlugin; import ru.noties.markwon.image.svg.SvgPlugin; import ru.noties.markwon.recycler.MarkwonAdapter; import ru.noties.markwon.recycler.SimpleEntry; +import ru.noties.markwon.recycler.table.TableEntry; +import ru.noties.markwon.recycler.table.TableEntryPlugin; import ru.noties.markwon.sample.R; import ru.noties.markwon.urlprocessor.UrlProcessor; import ru.noties.markwon.urlprocessor.UrlProcessorRelativeToAbsolute; @@ -51,14 +50,12 @@ public class RecyclerActivity extends Activity { // create MarkwonAdapter and register two blocks that will be rendered differently // * fenced code block (can also specify the same Entry for indended code block) // * table block - final MarkwonAdapter adapter = MarkwonAdapter.builder() - // we can simply use bundled SimpleEntry, that will lookup a TextView - // with `@+id/text` id - .include(FencedCodeBlock.class, new SimpleEntry(R.layout.adapter_fenced_code_block)) - // create own implementation of entry for different rendering - .include(TableBlock.class, new TableEntry2()) - // specify default entry (for all other blocks) - .defaultEntry(new SimpleEntry(R.layout.adapter_default_entry)) + final MarkwonAdapter adapter = MarkwonAdapter.builder(R.layout.adapter_default_entry, R.id.text) + // we can simply use bundled SimpleEntry + .include(FencedCodeBlock.class, SimpleEntry.create(R.layout.adapter_fenced_code_block, R.id.text)) + .include(TableBlock.class, TableEntry.create(builder -> builder + .tableLayout(R.layout.adapter_table_block, R.id.table_layout) + .textLayoutIsRoot(R.layout.view_table_entry_cell))) .build(); final RecyclerView recyclerView = findViewById(R.id.recycler_view); @@ -71,10 +68,6 @@ public class RecyclerActivity extends Activity { // please note that we should notify updates (adapter doesn't do it implicitly) adapter.notifyDataSetChanged(); - - // NB, there is no currently available widget to render tables gracefully - // TableEntryView is here for demonstration purposes only (to show that rendering - // tables } @NonNull @@ -83,14 +76,8 @@ public class RecyclerActivity extends Activity { .usePlugin(CorePlugin.create()) .usePlugin(ImagesPlugin.createWithAssets(context)) .usePlugin(SvgPlugin.create(context.getResources())) - .usePlugin(new AbstractMarkwonPlugin() { - @Override - public void configureParser(@NonNull Parser.Builder builder) { - // it's important NOT to use TablePlugin - // the only thing we want from it is commonmark-java parser extension - builder.extensions(Collections.singleton(TablesExtension.create())); - } - }) + // important to use TableEntryPlugin instead of TablePlugin + .usePlugin(TableEntryPlugin.create(context)) .usePlugin(HtmlPlugin.create()) // .usePlugin(SyntaxHighlightPlugin.create()) .usePlugin(new AbstractMarkwonPlugin() { diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry.java deleted file mode 100644 index 900ce719..00000000 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry.java +++ /dev/null @@ -1,67 +0,0 @@ -package ru.noties.markwon.sample.recycler; - -import android.support.annotation.NonNull; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; - -import org.commonmark.ext.gfm.tables.TableBlock; - -import java.util.HashMap; -import java.util.Map; - -import ru.noties.debug.Debug; -import ru.noties.markwon.Markwon; -import ru.noties.markwon.ext.tables.Table; -import ru.noties.markwon.recycler.MarkwonAdapter; -import ru.noties.markwon.sample.R; - -// do not use in real applications, this is just a showcase -public class TableEntry implements MarkwonAdapter.Entry { - - private final Map cache = new HashMap<>(2); - - @NonNull - @Override - public TableNodeHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new TableNodeHolder(inflater.inflate(R.layout.adapter_table_block, parent, false)); - } - - @Override - public void bindHolder(@NonNull Markwon markwon, @NonNull TableNodeHolder holder, @NonNull TableBlock node) { - - Table table = cache.get(node); - if (table == null) { - table = Table.parse(markwon, node); - cache.put(node, table); - } - - Debug.i(table); - - if (table != null) { - holder.tableEntryView.setTable(table); - // render table - } // we need to do something with null table... - } - - @Override - public long id(@NonNull TableBlock node) { - return node.hashCode(); - } - - @Override - public void clear() { - cache.clear(); - } - - static class TableNodeHolder extends MarkwonAdapter.Holder { - - final TableEntryView tableEntryView; - - TableNodeHolder(@NonNull View itemView) { - super(itemView); - - this.tableEntryView = requireView(R.id.table_entry); - } - } -} diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry2.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry2.java deleted file mode 100644 index dcf8d061..00000000 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntry2.java +++ /dev/null @@ -1,121 +0,0 @@ -package ru.noties.markwon.sample.recycler; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.support.annotation.NonNull; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TableLayout; -import android.widget.TableRow; -import android.widget.TextView; - -import org.commonmark.ext.gfm.tables.TableBlock; - -import java.util.HashMap; -import java.util.Map; - -import ru.noties.markwon.Markwon; -import ru.noties.markwon.ext.tables.Table; -import ru.noties.markwon.recycler.MarkwonAdapter; -import ru.noties.markwon.sample.R; - -public class TableEntry2 implements MarkwonAdapter.Entry { - - private final Map map = new HashMap<>(3); - - @NonNull - @Override - public TableHolder createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent) { - return new TableHolder(inflater.inflate(R.layout.adapter_table_block_2, parent, false)); - } - - @Override - public void bindHolder(@NonNull Markwon markwon, @NonNull TableHolder holder, @NonNull TableBlock node) { - - Table table = map.get(node); - if (table == null) { - table = Table.parse(markwon, node); - map.put(node, table); - } - - // check if this exact TableBlock was already - final TableLayout layout = holder.layout; - if (table == null - || table == layout.getTag(R.id.table_layout)) { - return; - } - - layout.setTag(R.id.table_layout, table); - layout.removeAllViews(); - layout.setBackgroundResource(R.drawable.bg_table_cell); - - final Context context = layout.getContext(); - final LayoutInflater inflater = LayoutInflater.from(context); - - TableRow tableRow; - TextView textView; - - for (Table.Row row : table.rows()) { - tableRow = new TableRow(context); - for (Table.Column column : row.columns()) { - textView = (TextView) inflater.inflate(R.layout.view_table_entry_cell, tableRow, false); - textView.setGravity(textGravity(column.alignment())); - markwon.setParsedMarkdown(textView, column.content()); - textView.getPaint().setFakeBoldText(row.header()); - textView.setBackgroundResource(R.drawable.bg_table_cell); - tableRow.addView(textView); - } - layout.addView(tableRow); - } - } - - @Override - public long id(@NonNull TableBlock node) { - return node.hashCode(); - } - - @Override - public void clear() { - map.clear(); - } - - static class TableHolder extends MarkwonAdapter.Holder { - - final TableLayout layout; - - TableHolder(@NonNull View itemView) { - super(itemView); - - this.layout = requireView(R.id.table_layout); - } - } - - // we will use gravity instead of textAlignment because min sdk is 16 (textAlignment starts at 17) - @SuppressLint("RtlHardcoded") - private static int textGravity(@NonNull Table.Alignment alignment) { - - final int gravity; - - switch (alignment) { - - case LEFT: - gravity = Gravity.LEFT; - break; - - case CENTER: - gravity = Gravity.CENTER_HORIZONTAL; - break; - - case RIGHT: - gravity = Gravity.RIGHT; - break; - - default: - throw new IllegalStateException("Unknown table alignment: " + alignment); - } - - return gravity | Gravity.CENTER_VERTICAL; - } -} diff --git a/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntryView.java b/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntryView.java deleted file mode 100644 index df789728..00000000 --- a/sample/src/main/java/ru/noties/markwon/sample/recycler/TableEntryView.java +++ /dev/null @@ -1,219 +0,0 @@ -package ru.noties.markwon.sample.recycler; - -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Rect; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.text.SpannedString; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.LinearLayout; -import android.widget.TextView; - -import java.util.ArrayList; -import java.util.List; - -import ru.noties.markwon.ext.tables.Table; -import ru.noties.markwon.sample.R; - -public class TableEntryView extends LinearLayout { - - // paint and rect to draw borders - private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); - private final Rect rect = new Rect(); - - private LayoutInflater inflater; - - private int rowEvenBackgroundColor; - - public TableEntryView(Context context) { - super(context); - init(context, null); - } - - public TableEntryView(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - private void init(Context context, @Nullable AttributeSet attrs) { - inflater = LayoutInflater.from(context); - setOrientation(VERTICAL); - - if (attrs != null) { - final TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.TableEntryView); - try { - - rowEvenBackgroundColor = array.getColor(R.styleable.TableEntryView_tev_rowEvenBackgroundColor, 0); - - final int stroke = array.getDimensionPixelSize(R.styleable.TableEntryView_tev_borderWidth, 0); - - // half of requested - final float strokeWidth = stroke > 0 - ? stroke / 2.F - : context.getResources().getDisplayMetrics().density / 2.F; - - paint.setStyle(Paint.Style.STROKE); - paint.setStrokeWidth(strokeWidth); - paint.setColor(array.getColor(R.styleable.TableEntryView_tev_borderColor, Color.BLACK)); - - if (isInEditMode()) { - final String data = array.getString(R.styleable.TableEntryView_tev_debugData); - if (data != null) { - - boolean first = true; - - final List rows = new ArrayList<>(); - for (String row : data.split("\\|")) { - final List columns = new ArrayList<>(); - for (String column : row.split(",")) { - columns.add(new Table.Column(Table.Alignment.LEFT, new SpannedString(column))); - } - final boolean header = first; - first = false; - rows.add(new Table.Row(header, columns)); - } - final Table table = new Table(rows); - setTable(table); - } - } - } finally { - array.recycle(); - } - } - - setWillNotDraw(false); - } - - public void setTable(@NonNull Table table) { - final List rows = table.rows(); - for (int i = 0, size = rows.size(); i < size; i++) { - addRow(i, rows.get(i)); - } - requestLayout(); - } - - private void addRow(int index, @NonNull Table.Row row) { - - final ViewGroup group = ensureRow(index); - - final int backgroundColor = !row.header() && (index % 2) == 0 - ? rowEvenBackgroundColor - : 0; - - group.setBackgroundColor(backgroundColor); - - final List columns = row.columns(); - - TextView textView; - Table.Column column; - - for (int i = 0, size = columns.size(); i < size; i++) { - textView = ensureCell(group, i); - column = columns.get(i); - textView.setGravity(textGravity(column.alignment())); - textView.setText(column.content()); - textView.getPaint().setFakeBoldText(row.header()); - } - - group.requestLayout(); - } - - @NonNull - private ViewGroup ensureRow(int index) { - - final int count = getChildCount(); - if (index >= count) { - - // count=0,index=1, diff=2 - // count=0,index=5, diff=6 - // count=1,index=2, diff=2 - int diff = index - count + 1; - while (diff > 0) { - addView(inflater.inflate(R.layout.view_table_entry_row, this, false)); - diff -= 1; - } - } - - return (ViewGroup) getChildAt(index); - } - - @NonNull - private TextView ensureCell(@NonNull ViewGroup group, int index) { - - final int count = group.getChildCount(); - if (index >= count) { - int diff = index - count + 1; - while (diff > 0) { - group.addView(inflater.inflate(R.layout.view_table_entry_cell, group, false)); - diff -= 1; - } - } - - return (TextView) group.getChildAt(index); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - final int rows = getChildCount(); - if (rows == 0) { - return; - } - - // first draw the whole border - rect.set(0, 0, getWidth(), getHeight()); - canvas.drawRect(rect, paint); - - ViewGroup group; - View view; - - int top; - - for (int row = 0; row < rows; row++) { - group = (ViewGroup) getChildAt(row); - top = group.getTop(); - for (int col = 0, cols = group.getChildCount(); col < cols; col++) { - view = group.getChildAt(col); - rect.set(view.getLeft(), top + view.getTop(), view.getRight(), top + view.getBottom()); - canvas.drawRect(rect, paint); - } - } - } - - // we will use gravity instead of textAlignment because min sdk is 16 (textAlignment starts at 17) - @SuppressLint("RtlHardcoded") - private static int textGravity(@NonNull Table.Alignment alignment) { - - final int gravity; - - switch (alignment) { - - case LEFT: - gravity = Gravity.LEFT; - break; - - case CENTER: - gravity = Gravity.CENTER_HORIZONTAL; - break; - - case RIGHT: - gravity = Gravity.RIGHT; - break; - - default: - throw new IllegalStateException("Unknown table alignment: " + alignment); - } - - return gravity; - } -} diff --git a/sample/src/main/recycler/assets/README.md b/sample/src/main/recycler/assets/README.md deleted file mode 120000 index 1dfab242..00000000 --- a/sample/src/main/recycler/assets/README.md +++ /dev/null @@ -1 +0,0 @@ -../../../../../README.md \ No newline at end of file diff --git a/sample/src/main/recycler/res/layout/adapter_table_block.xml b/sample/src/main/recycler/res/layout/adapter_table_block.xml deleted file mode 100644 index 3358ca5a..00000000 --- a/sample/src/main/recycler/res/layout/adapter_table_block.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/sample/src/main/recycler/res/values/attrs.xml b/sample/src/main/recycler/res/values/attrs.xml deleted file mode 100644 index 1827819d..00000000 --- a/sample/src/main/recycler/res/values/attrs.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/drawable-v26/ic_launcher_background.xml b/sample/src/main/res/drawable-v26/ic_launcher_background.xml deleted file mode 100644 index a197b896..00000000 --- a/sample/src/main/res/drawable-v26/ic_launcher_background.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - diff --git a/sample/src/main/recycler/res/layout/activity_recycler.xml b/sample/src/main/res/layout/activity_recycler.xml similarity index 100% rename from sample/src/main/recycler/res/layout/activity_recycler.xml rename to sample/src/main/res/layout/activity_recycler.xml diff --git a/sample/src/main/recycler/res/layout/adapter_default_entry.xml b/sample/src/main/res/layout/adapter_default_entry.xml similarity index 100% rename from sample/src/main/recycler/res/layout/adapter_default_entry.xml rename to sample/src/main/res/layout/adapter_default_entry.xml diff --git a/sample/src/main/recycler/res/layout/adapter_fenced_code_block.xml b/sample/src/main/res/layout/adapter_fenced_code_block.xml similarity index 100% rename from sample/src/main/recycler/res/layout/adapter_fenced_code_block.xml rename to sample/src/main/res/layout/adapter_fenced_code_block.xml diff --git a/sample/src/main/recycler/res/layout/adapter_table_block_2.xml b/sample/src/main/res/layout/adapter_table_block.xml similarity index 83% rename from sample/src/main/recycler/res/layout/adapter_table_block_2.xml rename to sample/src/main/res/layout/adapter_table_block.xml index 6cdb3be6..aaaaa369 100644 --- a/sample/src/main/recycler/res/layout/adapter_table_block_2.xml +++ b/sample/src/main/res/layout/adapter_table_block.xml @@ -13,6 +13,7 @@ + android:layout_height="wrap_content" + android:stretchColumns="*" /> \ No newline at end of file diff --git a/sample/src/main/recycler/res/layout/view_table_entry_cell.xml b/sample/src/main/res/layout/view_table_entry_cell.xml similarity index 69% rename from sample/src/main/recycler/res/layout/view_table_entry_cell.xml rename to sample/src/main/res/layout/view_table_entry_cell.xml index 6261bacb..6d544918 100644 --- a/sample/src/main/recycler/res/layout/view_table_entry_cell.xml +++ b/sample/src/main/res/layout/view_table_entry_cell.xml @@ -2,9 +2,7 @@ - - - - \ No newline at end of file diff --git a/sample/src/main/res/mipmap-hdpi-v26/ic_launcher_foreground.png b/sample/src/main/res/mipmap-hdpi-v26/ic_launcher_foreground.png deleted file mode 100644 index 01bae14798f5d5444355dfb093e5a42425916c02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3366 zcmb7H`8yN}7gnUP#3*ZMj3Ikj3T4X}%VZtd#y*TC3`y5EmWwe)2H8erxwg8pQ@CX< zyO<;&k)CIrC)n|Lvaq{qp6@v>!iy_@mainaFF=b~ZM1 zLBACg6tHLNT!d4#pa1jEKPs?#A(C=H#I&=@tM?_M!&qJr(IhLBme0nyJ z$MfF&zYKh77n5NLK$K11yE~O)RDUOX`zhIgYKdV%A)ywY|BAt+&V2Ne%3~E{SQ(?< zwxXiqtM}{(+&Joz24eisM%V-`>Xp zF5;MGQK;B`uP*%0Fv$GuON_<0y%gaQVTczwKRvk}za9?%_`JOQyD8pb>S_F)6S>yr z@zq!(Hu{!^*?h~)h9PssdNMVj#e$;ck0UO$B;D>&Vv? z6$45XmRTc@z$*&S#BkTGZGozt{c6Te#+JN-0@L@cbYyf3dSGT|#%@32%=*7CPD)l+ zSDQp8gyYW{grPGN0gK+oB+hl6Y1{f18^!UhH=45Vd9=VH0_x+Cp8NGaC}Zs-Ltox5 z`bUZzp4@q7~pRud4a_Pb5{0q znH(qOOS2x7O2(IDM6bnak}!E(wQbVjU$$oBqS`ycQ>fnAtD?s@4AS1U4vSenME`Xp z<{B%J_e`WdhO3T4P$B_b8<9_QM#?S7mYlbhQhQQ)&BRdZws9dRmh))Oa68PJ`fBq) zd3~s~wA7pEdMKn&1CAGc#kR4n=)luW$G2Cdnmm%9HzVM|(#dH%s zrRmEcZnYhFIp`1gAsch@Cm=tJ{!w?~_D?)CfjIT7qdkW`!!K!EHE`4;;Z zdeZbYj(sU0vwFn|yf%+kF8W}c^b}+Bz$sPTUQ0l(OJ^O%+}s?Cj7vJm>c<0T55ULl4qh!%gCJ`kBNe@&y($v0Gs`np!wDLd zfN)a{98_@%E-fMiMhq0aJ_bB2B z7GHld)4+Z9B!EO;?&GE}JlzUH_W$fNC5*T$eZE}<+^vv{w?MWQzqt_w!kK?!@*XQ` z7d!CwMA+wx+;_ysINet_%{gmS6T{g6S|t0m3-OjH;W9hDMA=!H7uD{a zm-T`DC>OO&roVrihU9*>-cwhi;}O4yP!ez>iIyfoEJj@q?S_)AR*5J|uiTeZ(+-B_P)0{i=H($>pp4pk@2dOW{mqVUz8VF6hfcu1F`#fNL0UMj0BQ{;UCgx`gJ4&5^X4yoHm^u5lodrPbD z;vRg&_!1xzGaO7K7W#njn?O;#|xgYT46KgDSqtM;;=08uCf%U8ugo)lj$8 zc_zE!xmXF_7p6cvc2F6xmt3892rasyZnm5d+(BvSdPf zSDKM_D^U9-(@b|<89jH`k^%=u+pUe~sU>e~mYk$P@?wap2NW)qtPNzIuqyp#+HPb2 zG`O6c58M5=S8YWoJ_$oGS=Ptl^hD?fhQPx&l&~qe!D%5U8rl3)N0=mI-|s5Y($eA*ZDsZ2aXC3TIyt7rn+X5k z3F2-I9)|Wt5ON&wn8Q?9T`%`oUS6K+aI6dU4jeGCBKRwz%sw=929xvxt(RG4Ur*WE z+7^N&iM@E)QFopx8FY*W5CiR;=xA--PuVQ`x8BG_k*Y8Ui z@N41{Wa?{&b%2$X{^ZuG+|Uu+zOJOy&PH<$ z-WJ+2+fsx*e>?Mj^8Ig-MK^&tF1rty?~WJ@Mgb|iB0o<*ag?V-8Xk92@d?1Ldsk3| zBi7IwPW6HCCbTQN6Pp%wjjQ`;EQ?PAzpurEHEE)7-Bho{97~kfW&b`y^o!~Z z2cHd3sx~`S`ZJ{Hc60f9Yq|C-Dkg(2$tpn^=aPLaX6yvzgdEyXKQ}ev*Sq zY2!tq{Wr4a6(nB`YbDD$+zQJ+$8z?hb^U81y0}Z~Ss+O@Eyk^?vhse>;^8ZfA*Q=h z%QNCHkoVh#4UTDa@ibfqDkuureUNv_&+bOAgjb}umzNhgU}P9A79ABXvrggZ9*%a- zcsUJk6H;b%--9D@g`4Q-mMF`iNglS(N|%a%o}44@xHuH1t^JbOYd|!|Y@S!n_G-Nn ze{srDkQMMS(P#cDHWItD%&Wr~(0ea<$0pZw@B%|7eGQ!gP#3~zXbPJ7Jc?Bw=rGn{ zj5!ij;C4GikG4JF^~wIQBpsv)+m=(rYW$Sa8;64qx=tW(UOz1^CnD;aI*i&_v#By4 zKHsJ6Djm`7C=hSRF z%BcQuz23gRaT&mTEIqA}+DI8LFdE?RLey?}-tgqUdc4f8FQ7l2K5i4Bk*DCzG$ElC z*HqjvnR4B$-?obADD?*FlhhG2T4dCV@yE*vx2hGxg-7DdnH<`B#5{9!|yS_$LQK*62+JW-Um+B lE-umPW%~dB|6o$Y00qM{(Lyp=A*cTj3*68GRtt5H{~xOUQvLt{ diff --git a/sample/src/main/res/mipmap-hdpi/ic_launcher.png b/sample/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index 1ba57872a247eccfaf8945b7fee81b430c0c7ed8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2381 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 E5ARDejQ{`u diff --git a/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 11dcdbc94fc335ac51e8cbc7f2dc0467479d73a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5093 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 IR<#NFA5Kz!vH$=8 diff --git a/sample/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png b/sample/src/main/res/mipmap-xxxhdpi-v26/ic_launcher_foreground.png deleted file mode 100644 index b64bf44fe9cee02e463fa50ea44956311cf4535f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11195 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 diff --git a/settings.gradle b/settings.gradle index e3177a74..faf09343 100644 --- a/settings.gradle +++ b/settings.gradle @@ -10,5 +10,6 @@ include ':app', ':sample', ':markwon-image-okhttp', ':markwon-image-svg', ':markwon-recycler', + ':markwon-recycler-table', ':markwon-syntax-highlight', ':markwon-test-span'