Preparing for release, started README and javadocs
This commit is contained in:
parent
58c2f26491
commit
0f1b6c4cf7
@ -1,7 +1,7 @@
|
||||
# Markwon
|
||||
|
||||
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
||||
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
||||
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
||||
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
||||
|
||||
Android library for rendering markdown as system-native Spannables. Based on [commonmark-java][commonmark-java]
|
||||
|
||||
|
97
library/README.md
Normal file
97
library/README.md
Normal file
@ -0,0 +1,97 @@
|
||||
# Markwon
|
||||
|
||||
[](http://search.maven.org/#search|ga|1|g%3A%22ru.noties%22%20AND%20a%3A%markwon%22)
|
||||
|
||||
|
||||
## Installation
|
||||
```groovy
|
||||
compile 'ru.noties:markwon:1.0.0'
|
||||
```
|
||||
|
||||
## Intoduction
|
||||
|
||||
The aim for this library is to render markdown as first class citizen on Android - Spannables. It has reasonable defaults to display markdown, but also gives ability to customize almost every detail for your liking.
|
||||
|
||||
The most basic example would be:
|
||||
```java
|
||||
Markwon.setMarkdown(textView, "**Hello *there*!!**")
|
||||
```
|
||||
|
||||
## Images
|
||||
|
||||
By default this library does not render any of the images. It's done to simplify rendering of text-based markdown. But if images must be supported, then the `AsyncDrawable.Loader` can be specified whilst building a `SpannableConfiguration` instance:
|
||||
|
||||
```java
|
||||
final AsyncDrawable.Loader loader = new AsyncDrawable.Loader() {
|
||||
@Override
|
||||
public void load(@NonNull String destination, @NonNull final AsyncDrawable drawable) {
|
||||
// `download` method is here for demonstration purposes, it's not included in this interface
|
||||
download(destination, new Callback() {
|
||||
@Override
|
||||
public void onDownloaded(Drawable d) {
|
||||
drawable.setResult(d);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(@NonNull String destination) {
|
||||
// cancel download here
|
||||
}
|
||||
};
|
||||
|
||||
// `this` here referrs to a Context instance
|
||||
final SpannableConfiguration configuration = SpannableConfiguration.builder(this)
|
||||
.asyncDrawableLoader(loader)
|
||||
.build();
|
||||
```
|
||||
|
||||
There is also standalone artifact that supports image loading *out-of-box* (including support for **SVG** & **GIF**), but provides little to none configuration and could be somewhat not optimal. Please refer to the [README][mil-README] of the module.
|
||||
|
||||
|
||||
## Tables
|
||||
|
||||
Tables are supported but with some limitations. First of all: table will always take the full width of the TextView Canvas. Second: each column will have the same width (we do not calculate the weight of column) - so, a column width will be: `totalWidth / columnsNumber`.
|
||||
|
||||
|
||||
## Syntax highlight
|
||||
This library does not provide ready-to-be-used implementation of syntax highlight, but it can be easily added via `SyntaxHighlight` interface whilst building `SpannableConfiguration`:
|
||||
|
||||
```java
|
||||
final SyntaxHighlight syntaxHighlight = new SyntaxHighlight() {
|
||||
@NonNull
|
||||
@Override
|
||||
public CharSequence highlight(@Nullable String info, @NonNull String code) {
|
||||
// create Spanned of highlight here
|
||||
return null; // must not return `null` here
|
||||
}
|
||||
};
|
||||
|
||||
final SpannableConfiguration configuration = SpannableConfiguration.builder(this)
|
||||
.syntaxHighlight(syntaxHighlight)
|
||||
.build();
|
||||
```
|
||||
|
||||
## Url processing
|
||||
If you wish to process urls (links & images) that markdown contains, the `UrlProcessor` can be used:
|
||||
```java
|
||||
final UrlProcessor urlProcessor = new UrlProcessor() {
|
||||
@NonNull
|
||||
@Override
|
||||
public String process(@NonNull String destination) {
|
||||
// modify the `destination` or return as-is
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
final SpannableConfiguration configuration = SpannableConfiguration.builder(this)
|
||||
.urlProcessor(urlProcessor)
|
||||
.build();
|
||||
```
|
||||
The primary goal of additing this abstraction is to give ability to convert relative urls to absolute ones. If it fits your purpose, then `UrlProcessorRelativeToAbsolute` can be used:
|
||||
```java
|
||||
final UrlProcessor urlProcessor = new UrlProcessorRelativeToAbsolute("https://this-is-base.org");
|
||||
```
|
||||
|
||||
|
||||
[mil-README]: https://github.com/noties/Markwon/blob/master/library-image-loader/README.md
|
@ -14,6 +14,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ru.noties.markwon.renderer.R;
|
||||
import ru.noties.markwon.spans.AsyncDrawable;
|
||||
import ru.noties.markwon.spans.AsyncDrawableSpan;
|
||||
|
||||
@ -23,18 +24,24 @@ abstract class DrawablesScheduler {
|
||||
|
||||
final List<AsyncDrawable> list = extract(textView);
|
||||
if (list.size() > 0) {
|
||||
textView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
|
||||
}
|
||||
if (textView.getTag(R.id.markwon_drawables_scheduler) == null) {
|
||||
final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
// we obtain a new list in case text was changed
|
||||
unschedule(textView);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
unschedule(textView);
|
||||
v.removeOnAttachStateChangeListener(this);
|
||||
v.setTag(R.id.markwon_drawables_scheduler, null);
|
||||
}
|
||||
};
|
||||
textView.addOnAttachStateChangeListener(listener);
|
||||
textView.setTag(R.id.markwon_drawables_scheduler, listener);
|
||||
}
|
||||
|
||||
for (AsyncDrawable drawable : list) {
|
||||
drawable.setCallback2(new DrawableCallbackImpl(textView, drawable.getBounds()));
|
||||
|
@ -19,16 +19,38 @@ import ru.noties.markwon.renderer.SpannableRenderer;
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public abstract class Markwon {
|
||||
|
||||
/**
|
||||
* Helper method to obtain a {@link Parser} with registered strike-through & table extensions
|
||||
*
|
||||
* @return a {@link Parser} instance that is supported by this library
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static Parser createParser() {
|
||||
return new Parser.Builder()
|
||||
.extensions(Arrays.asList(StrikethroughExtension.create(), TablesExtension.create()))
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see #setMarkdown(TextView, SpannableConfiguration, String)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void setMarkdown(@NonNull TextView view, @NonNull String markdown) {
|
||||
setMarkdown(view, SpannableConfiguration.create(view.getContext()), markdown);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses submitted raw markdown, converts it to CharSequence (with Spannables)
|
||||
* and applies it to view
|
||||
*
|
||||
* @param view {@link TextView} to set markdown into
|
||||
* @param configuration a {@link SpannableConfiguration} instance
|
||||
* @param markdown raw markdown String (for example: {@code `**Hello**`})
|
||||
* @see #markdown(SpannableConfiguration, String)
|
||||
* @see #setText(TextView, CharSequence)
|
||||
* @see SpannableConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void setMarkdown(
|
||||
@NonNull TextView view,
|
||||
@NonNull SpannableConfiguration configuration,
|
||||
@ -38,6 +60,15 @@ public abstract class Markwon {
|
||||
setText(view, markdown(configuration, markdown));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to apply parsed markdown. Please note, that if images or tables are used
|
||||
*
|
||||
* @param view {@link TextView} to set markdown into
|
||||
* @param text parsed markdown
|
||||
* @see #scheduleDrawables(TextView)
|
||||
* @see #scheduleTableRows(TextView)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void setText(@NonNull TextView view, CharSequence text) {
|
||||
|
||||
unscheduleDrawables(view);
|
||||
@ -52,7 +83,14 @@ public abstract class Markwon {
|
||||
scheduleTableRows(view);
|
||||
}
|
||||
|
||||
// with default configuration
|
||||
/**
|
||||
* Returns parsed markdown with default {@link SpannableConfiguration} obtained from {@link Context}
|
||||
*
|
||||
* @param context {@link Context}
|
||||
* @param markdown raw markdown
|
||||
* @return parsed markdown
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static CharSequence markdown(@NonNull Context context, @Nullable String markdown) {
|
||||
final CharSequence out;
|
||||
if (TextUtils.isEmpty(markdown)) {
|
||||
@ -64,6 +102,15 @@ public abstract class Markwon {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns parsed markdown with provided {@link SpannableConfiguration}
|
||||
*
|
||||
* @param configuration a {@link SpannableConfiguration}
|
||||
* @param markdown raw markdown
|
||||
* @return parsed markdown
|
||||
* @see SpannableConfiguration
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static CharSequence markdown(@NonNull SpannableConfiguration configuration, @Nullable String markdown) {
|
||||
final CharSequence out;
|
||||
if (TextUtils.isEmpty(markdown)) {
|
||||
@ -77,18 +124,64 @@ public abstract class Markwon {
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method adds support for {@link ru.noties.markwon.spans.AsyncDrawable} to be used. As
|
||||
* textView seems not to support drawables that change bounds (and gives no means
|
||||
* to update the layout), we create own {@link android.graphics.drawable.Drawable.Callback}
|
||||
* and apply it. So, textView can display drawables, that are: async (loading from disk, network);
|
||||
* dynamic (requires `invalidate`) - GIF, animations.
|
||||
* Please note, that this method should be preceded with {@link #unscheduleDrawables(TextView)}
|
||||
* in order to avoid keeping drawables in memory after they have been removed from layout
|
||||
*
|
||||
* @param view a {@link TextView}
|
||||
* @see ru.noties.markwon.spans.AsyncDrawable
|
||||
* @see ru.noties.markwon.spans.AsyncDrawableSpan
|
||||
* @see DrawablesScheduler#schedule(TextView)
|
||||
* @see DrawablesScheduler#unschedule(TextView)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void scheduleDrawables(@NonNull TextView view) {
|
||||
DrawablesScheduler.schedule(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* De-references previously scheduled {@link ru.noties.markwon.spans.AsyncDrawableSpan}'s
|
||||
*
|
||||
* @param view a {@link TextView}
|
||||
* @see #scheduleDrawables(TextView)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void unscheduleDrawables(@NonNull TextView view) {
|
||||
DrawablesScheduler.unschedule(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required in order to use tables. A bit of background:
|
||||
* this library uses a {@link android.text.style.ReplacementSpan} to
|
||||
* render tables, but the flow is not really flexible. We are required
|
||||
* to return `size` (width) of our replacement, but we are not provided
|
||||
* with the total one (canvas width). In order to correctly calculate height of our
|
||||
* table cell text, we must have available width first. This method gives
|
||||
* ability for {@link ru.noties.markwon.spans.TableRowSpan} to invalidate
|
||||
* `view` when it encounters such a situation (when available width is not known or have changed).
|
||||
* Precede this call with {@link #unscheduleTableRows(TextView)} in order to
|
||||
* de-reference previously scheduled {@link ru.noties.markwon.spans.TableRowSpan}'s
|
||||
*
|
||||
* @param view a {@link TextView}
|
||||
* @see #unscheduleTableRows(TextView)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void scheduleTableRows(@NonNull TextView view) {
|
||||
TableRowsScheduler.schedule(view);
|
||||
}
|
||||
|
||||
/**
|
||||
* De-references previously scheduled {@link ru.noties.markwon.spans.TableRowSpan}'s
|
||||
*
|
||||
* @param view a {@link TextView}
|
||||
* @see #scheduleTableRows(TextView)
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public static void unscheduleTableRows(@NonNull TextView view) {
|
||||
TableRowsScheduler.unschedule(view);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import ru.noties.markwon.renderer.R;
|
||||
import ru.noties.markwon.spans.TableRowSpan;
|
||||
|
||||
abstract class TableRowsScheduler {
|
||||
@ -14,24 +15,32 @@ abstract class TableRowsScheduler {
|
||||
final Object[] spans = extract(view);
|
||||
if (spans != null
|
||||
&& spans.length > 0) {
|
||||
view.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
|
||||
}
|
||||
if (view.getTag(R.id.markwon_tables_scheduler) == null) {
|
||||
final View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
unschedule(view);
|
||||
view.removeOnAttachStateChangeListener(this);
|
||||
view.setTag(R.id.markwon_tables_scheduler, null);
|
||||
}
|
||||
};
|
||||
view.addOnAttachStateChangeListener(listener);
|
||||
view.setTag(R.id.markwon_tables_scheduler, listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
unschedule(view);
|
||||
view.removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
});
|
||||
final TableRowSpan.Invalidator invalidator = new TableRowSpan.Invalidator() {
|
||||
@Override
|
||||
public void invalidate() {
|
||||
view.setText(view.getText());
|
||||
}
|
||||
};
|
||||
|
||||
for (Object span : spans) {
|
||||
((TableRowSpan) span).invalidator(invalidator);
|
||||
}
|
||||
|
7
library/src/main/res/values/ids.xml
Normal file
7
library/src/main/res/values/ids.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<item name="markwon_drawables_scheduler" type="id" />
|
||||
<item name="markwon_tables_scheduler" type="id" />
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user