package ru.noties.markwon.recycler; import android.support.annotation.IdRes; import android.support.annotation.LayoutRes; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import org.commonmark.node.Node; import java.util.List; import ru.noties.markwon.Markwon; /** * Class 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 * 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 #create(Entry) * @see #setMarkdown(Markwon, String) * @see #setParsedMarkdown(Markwon, Node) * @see #setParsedMarkdown(Markwon, List) * @since 3.0.0 */ public abstract class MarkwonAdapter extends RecyclerView.Adapter { @NonNull public static Builder builder() { return new MarkwonAdapterImpl.BuilderImpl(); } @NonNull public static MarkwonAdapter create() { return new MarkwonAdapterImpl.BuilderImpl().build(); } // for an adapter with only one entry (all blocks are rendered the same with this entry) @NonNull public static MarkwonAdapter create(@NonNull Entry defaultEntry) { return new MarkwonAdapterImpl.BuilderImpl().defaultEntry(defaultEntry).build(); } @NonNull public static MarkwonAdapter create(@LayoutRes int layoutResId) { return new MarkwonAdapterImpl.BuilderImpl().defaultEntry(layoutResId).build(); } public interface Builder { @NonNull Builder include( @NonNull Class node, @NonNull Entry entry); @NonNull Builder defaultEntry(@NonNull Entry defaultEntry); @NonNull Builder defaultEntry(@LayoutRes int layoutResId); @NonNull Builder reducer(@NonNull Reducer reducer); @NonNull MarkwonAdapter build(); } /** * @see SimpleEntry */ public interface Entry { @NonNull H createHolder(@NonNull LayoutInflater inflater, @NonNull ViewGroup parent); 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) void clear(); } public interface Reducer { @NonNull List reduce(@NonNull Node root); } public abstract void setMarkdown(@NonNull Markwon markwon, @NonNull String markdown); public abstract void setParsedMarkdown(@NonNull Markwon markwon, @NonNull Node document); public abstract void setParsedMarkdown(@NonNull Markwon markwon, @NonNull List nodes); @SuppressWarnings("WeakerAccess") public static class Holder extends RecyclerView.ViewHolder { public Holder(@NonNull View itemView) { super(itemView); } // please note that this method should be called after constructor @Nullable protected V findView(@IdRes int id) { return itemView.findViewById(id); } // please note that this method should be called after constructor @NonNull protected V requireView(@IdRes int id) { final V v = itemView.findViewById(id); if (v == null) { throw new NullPointerException(); } return v; } } }