- Created clickable behaviour for images.

- Clicks can be consumed with ImageClickResolver
This commit is contained in:
zTrap 2017-10-26 19:08:41 +03:00
parent 18938a1aa2
commit 30b6c01601
6 changed files with 103 additions and 13 deletions

View File

@ -0,0 +1,13 @@
package ru.noties.markwon;
import android.support.annotation.NonNull;
import android.view.View;
/**
* @author pa.gulko zTrap (25.10.2017)
* @since 1.0.1
*/
public interface ImageClickResolver {
void resolve(View view, @NonNull String link);
}

View File

@ -0,0 +1,30 @@
package ru.noties.markwon;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.provider.Browser;
import android.support.annotation.NonNull;
import android.util.Log;
import android.view.View;
/**
* @author pa.gulko zTrap (25.10.2017)
* @since 1.0.1
*/
public class ImageClickResolverDef implements ImageClickResolver {
@Override
public void resolve(View view, @NonNull String link) {
final Uri uri = Uri.parse(link);
final Context context = view.getContext();
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
try {
context.startActivity(intent);
} catch (ActivityNotFoundException e) {
Log.w("LinkResolverDef", "Actvity was not found for intent, " + intent.toString());
}
}
}

View File

@ -26,6 +26,7 @@ public class SpannableConfiguration {
private final LinkSpan.Resolver linkResolver;
private final UrlProcessor urlProcessor;
private final SpannableHtmlParser htmlParser;
private final ImageClickResolver imageClickResolver;
private SpannableConfiguration(Builder builder) {
this.theme = builder.theme;
@ -34,6 +35,7 @@ public class SpannableConfiguration {
this.linkResolver = builder.linkResolver;
this.urlProcessor = builder.urlProcessor;
this.htmlParser = builder.htmlParser;
this.imageClickResolver = builder.imageClickResolver;
}
public SpannableTheme theme() {
@ -60,6 +62,10 @@ public class SpannableConfiguration {
return htmlParser;
}
public ImageClickResolver imageClickResolver() {
return imageClickResolver;
}
public static class Builder {
private final Context context;
@ -69,6 +75,7 @@ public class SpannableConfiguration {
private LinkSpan.Resolver linkResolver;
private UrlProcessor urlProcessor;
private SpannableHtmlParser htmlParser;
private ImageClickResolver imageClickResolver;
Builder(Context context) {
this.context = context;
@ -104,6 +111,11 @@ public class SpannableConfiguration {
return this;
}
public Builder setImageClickResolver(ImageClickResolver imageClickResolver) {
this.imageClickResolver = imageClickResolver;
return this;
}
public SpannableConfiguration build() {
if (theme == null) {
theme = SpannableTheme.create(context);
@ -120,8 +132,12 @@ public class SpannableConfiguration {
if (urlProcessor == null) {
urlProcessor = new UrlProcessorNoOp();
}
if (imageClickResolver == null) {
imageClickResolver = new ImageClickResolverDef();
}
if (htmlParser == null) {
htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor, linkResolver);
htmlParser = SpannableHtmlParser.create(theme, asyncDrawableLoader, urlProcessor,
linkResolver, imageClickResolver);
}
return new SpannableConfiguration(this);
}

View File

@ -4,7 +4,9 @@ import android.support.annotation.NonNull;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.text.style.StrikethroughSpan;
import android.view.View;
import org.commonmark.ext.gfm.strikethrough.Strikethrough;
import org.commonmark.ext.gfm.tables.TableBody;
@ -431,8 +433,12 @@ public class SpannableMarkdownVisitor extends AbstractVisitor {
)
);
// todo, maybe, if image is not inside a link, we should make it clickable, so
// user can open it in external viewer?
setSpan(length, new ClickableSpan() {
@Override
public void onClick(View view) {
configuration.imageClickResolver().resolve(view, destination);
}
});
}
@Override

View File

@ -4,9 +4,12 @@ import android.support.annotation.NonNull;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ClickableSpan;
import android.view.View;
import java.util.Map;
import ru.noties.markwon.ImageClickResolver;
import ru.noties.markwon.UrlProcessor;
import ru.noties.markwon.spans.AsyncDrawable;
import ru.noties.markwon.spans.AsyncDrawableSpan;
@ -17,14 +20,17 @@ class ImageProviderImpl implements SpannableHtmlParser.ImageProvider {
private final SpannableTheme theme;
private final AsyncDrawable.Loader loader;
private final UrlProcessor urlProcessor;
private final ImageClickResolver imageClickResolver;
ImageProviderImpl(
@NonNull SpannableTheme theme,
@NonNull AsyncDrawable.Loader loader,
@NonNull UrlProcessor urlProcessor) {
@NonNull UrlProcessor urlProcessor,
@NonNull ImageClickResolver imageClickResolver) {
this.theme = theme;
this.loader = loader;
this.urlProcessor = urlProcessor;
this.imageClickResolver = imageClickResolver;
}
@Override
@ -53,6 +59,14 @@ class ImageProviderImpl implements SpannableHtmlParser.ImageProvider {
final SpannableString string = new SpannableString(replacement);
string.setSpan(span, 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
final ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(View view) {
imageClickResolver.resolve(view, destination);
}
};
string.setSpan(clickableSpan, 0, string.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
spanned = string;
} else {
spanned = null;

View File

@ -10,6 +10,8 @@ import android.text.Spanned;
import java.util.HashMap;
import java.util.Map;
import ru.noties.markwon.ImageClickResolver;
import ru.noties.markwon.ImageClickResolverDef;
import ru.noties.markwon.LinkResolverDef;
import ru.noties.markwon.UrlProcessor;
import ru.noties.markwon.UrlProcessorNoOp;
@ -25,7 +27,8 @@ public class SpannableHtmlParser {
@NonNull SpannableTheme theme,
@NonNull AsyncDrawable.Loader loader
) {
return builderWithDefaults(theme, loader, null, null)
return builderWithDefaults(theme, loader, null, null,
null)
.build();
}
@ -33,9 +36,10 @@ public class SpannableHtmlParser {
@NonNull SpannableTheme theme,
@NonNull AsyncDrawable.Loader loader,
@NonNull UrlProcessor urlProcessor,
@NonNull LinkSpan.Resolver resolver
@NonNull LinkSpan.Resolver linkResolver,
@NonNull ImageClickResolver imageClickResolver
) {
return builderWithDefaults(theme, loader, urlProcessor, resolver)
return builderWithDefaults(theme, loader, urlProcessor, linkResolver, imageClickResolver)
.build();
}
@ -44,22 +48,28 @@ public class SpannableHtmlParser {
}
public static Builder builderWithDefaults(@NonNull SpannableTheme theme) {
return builderWithDefaults(theme, null, null, null);
return builderWithDefaults(theme, null, null, null,
null);
}
public static Builder builderWithDefaults(
@NonNull SpannableTheme theme,
@Nullable AsyncDrawable.Loader asyncDrawableLoader,
@Nullable UrlProcessor urlProcessor,
@Nullable LinkSpan.Resolver resolver
@Nullable LinkSpan.Resolver linkResolver,
@Nullable ImageClickResolver imageClickResolver
) {
if (urlProcessor == null) {
urlProcessor = new UrlProcessorNoOp();
}
if (resolver == null) {
resolver = new LinkResolverDef();
if (linkResolver == null) {
linkResolver = new LinkResolverDef();
}
if (imageClickResolver == null) {
imageClickResolver = new ImageClickResolverDef();
}
final BoldProvider boldProvider = new BoldProvider();
@ -68,7 +78,8 @@ public class SpannableHtmlParser {
final ImageProvider imageProvider;
if (asyncDrawableLoader != null) {
imageProvider = new ImageProviderImpl(theme, asyncDrawableLoader, urlProcessor);
imageProvider = new ImageProviderImpl(theme, asyncDrawableLoader, urlProcessor,
imageClickResolver);
} else {
imageProvider = null;
}
@ -86,7 +97,7 @@ public class SpannableHtmlParser {
.simpleTag("del", strikeProvider)
.simpleTag("s", strikeProvider)
.simpleTag("strike", strikeProvider)
.simpleTag("a", new LinkProvider(theme, urlProcessor, resolver))
.simpleTag("a", new LinkProvider(theme, urlProcessor, linkResolver))
.imageProvider(imageProvider);
}