@SuppressWarnings({"unused", "unchecked", "WeakerAccess", "SameParameterValue"})
public class GenericMultipleLayoutAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    /* Adapter Variables */
    @NonNull
    private final Context mContext;
    @NonNull
    private final List<IGenericRecyclerViewLayout> mDataSet;
    private final boolean mSkipQueuedUpdates;

    /* UI & Worker Thread Variables */
    @NonNull
    private final ArrayDeque<List<? extends IGenericRecyclerViewLayout>> mPendingUpdates = new ArrayDeque<>();
    @NonNull
    private final Handler mHandler = new Handler();

    /* View Type Auxiliary Variable */
    @NonNull
    private final SparseArray<IGenericRecyclerViewLayout> mViewTypes = new SparseArray<>();

    /**
     * Instantiates a new GenericMultipleLayoutAdapter.
     * @param dataSet the list of items to populate this adapter.
     * @param context the application's current {@link Context}.
     * @param skipQueuedUpdates a boolean value indicating whether this adapter should ignore pending updates and
     *                          skip to the newest one or execute all pending updates sequentially.
     */
    public GenericMultipleLayoutAdapter(@NonNull final List<? extends IGenericRecyclerViewLayout> dataSet,
                                        @NonNull final Context context, final boolean skipQueuedUpdates) {
        super();
        mContext = context;
        mDataSet = (List<IGenericRecyclerViewLayout>) dataSet;
        mSkipQueuedUpdates = skipQueuedUpdates;
        updateViewTypes();
    }

    /** {@inheritDoc} */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull final ViewGroup parent,
                                                      @IntRange(from = 0) final int viewType) {
        return mViewTypes.get(viewType).createViewHolder(parent);
    }

    /** {@inheritDoc} */
    @Override
    public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder,
                                 @IntRange(from = 0) final int position) {
        mDataSet.get(position).setElements(holder);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void onViewRecycled(RecyclerView.ViewHolder holder) {
        if (holder != null && holder instanceof IViewHolder) {
            ((IViewHolder) holder).recycle();
        }

        super.onViewRecycled(holder);
    }

    /** {@inheritDoc} */
    @Override
    public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, @IntRange(from = 0) final int position,
                                 @NonNull final List<Object> payloads) {
        if (payloads.isEmpty()) {
            onBindViewHolder(holder, position);
        } else {
            applyPayloads(payloads, position);
        }
    }

    /** {@inheritDoc} */
    @Override
    public int getItemCount() {
        return mDataSet.size();
    }

    /** {@inheritDoc} */
    @Override
    public int getItemViewType(@IntRange(from = 0) final int position) {
        return mDataSet.get(position).getViewType();
    }

    /**
     * Procedure meant to insert a Generic Layout Implementation item on this adapter's data set.
     * @param item a Generic Layout Implementation item to be inserted.
     *             See {@link IGenericRecyclerViewLayout} for more information.
     */
    @UiThread
    public void add(@NonNull final IGenericRecyclerViewLayout item) {
        final List<IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        newList.add(item);
        updateList(newList);
    }

    /**
     * Procedure meant to insert a list of Generic Layout Implementation item on this adapter's data set.
     * @param items the list of Generic Layout Implementation items to be inserted.
     *              See {@link IGenericRecyclerViewLayout} for more information.
     */
    @UiThread
    public void add(@NonNull final List<? extends IGenericRecyclerViewLayout> items) {
        final List<IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        newList.addAll(items);
        updateList(newList);
    }

    /**
     * Procedure meant to insert a Generic Layout Implementation item on this adapter's data set, at a target position.
     * @param item a Generic Layout Implementation item to be inserted.
     *             See {@link IGenericRecyclerViewLayout} for more information.
     * @param position the target position for this item to be inserted.
     * @throws IndexOutOfBoundsException if the position is out of range
     *                                  (<tt>position &lt; 0 || position &gt; size()</tt>).
     */
    @UiThread
    public void add(@NonNull final IGenericRecyclerViewLayout item, @IntRange(from = 0) final int position) {
        final List<IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        newList.add(position, item);
        updateList(newList);
    }

    /**
     * Procedure meant to remove a Generic Layout Implementation item on this adapter's data set.
     * @param item a Generic Layout Implementation item to be removed.
     *             See {@link IGenericRecyclerViewLayout} for more information.
     */
    @UiThread
    public void remove(@NonNull final IGenericRecyclerViewLayout item) {
        final List<? extends IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        if (!newList.isEmpty() && newList.contains(item)) {
            newList.remove(item);
            updateList(newList);
        }
    }

    /**
     * Unsupported operation, meant to remove a Generic Layout Implementation item on this adapter's data set, at a
     * target position.
     * This procedure is unsupported because the position value is likely to be wrong if there is a pending update.
     * @param position the target position for this item to be removed.
     * @deprecated use {@link #remove} instead.
     */
    @Deprecated
    public void remove(@IntRange(from = 0) final int position) {
        throw new UnsupportedOperationException(mContext.getString(R.string.gmlrva_unsupported_remove_position));
    }

    /**
     * Procedure meant to remove a list of Generic Layout Implementation items on this adapter's data set.
     * @param items the list of Generic Layout Implementation items to be removed.
     *              See {@link IGenericRecyclerViewLayout} for more information.
     */
    @UiThread
    public void remove(@NonNull final List<IGenericRecyclerViewLayout> items) {
        final List<IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        if (!newList.isEmpty() && !items.isEmpty()) {
            newList.removeAll(items);
            updateList(newList);
        }
    }

    /**
     * Procedure meant to retrieve a Generic Layout Implementation item on this adapter's data set.
     * @param position the target position of the item to be retrieved.
     * @return the Generic Layout Implementation item whose index is the specified target position.
     * @throws NullPointerException if the data set is empty.
     * @throws IndexOutOfBoundsException if the target position is out of range
     *                                  (<tt>position &lt; 0 || position &gt; size()</tt>).
     */
    @UiThread
    @Nullable
    public IGenericRecyclerViewLayout get(@IntRange(from = 0) final int position) {
        final List<IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        if (newList.isEmpty()) {
            return null;
        }
        if (position < 0 && position >= newList.size()) {
            throw new ArrayIndexOutOfBoundsException(position);
        }
        return newList.get(position);
    }

    /**
     * Procedure meant to update a Generic Layout Implementation item on this adapter's data set.
     * @param item a Generic Layout Implementation item to be updated.
     *             See {@link IGenericRecyclerViewLayout} for more information.
     * @param holderInfoAction an Integer value representing the custom animation that should be executed in this
     *                         update.
     */
    @UiThread
    public void updateItem(@NonNull final IGenericRecyclerViewLayout item,
                           @IntRange(from = 0) final int holderInfoAction) {
        final List<IGenericRecyclerViewLayout> newList
                = new ArrayList<>(mPendingUpdates.isEmpty() ? mDataSet : mPendingUpdates.peekLast());
        if (!newList.isEmpty() && newList.contains(item)) {
            notifyItemChanged(newList.indexOf(item), holderInfoAction);
        }
    }

    /**
     * Procedure meant to prepare an update this adapter's entire data set.
     * This procedure checks for the changes made to this adapter's data set and applies these changes exclusively,
     * meaning there are no wasted operations.
     * Allows for update queueing and recursion.
     * @param items the list of Generic Layout Implementation items for the data set.
     */
    @UiThread
    public void updateList(@NonNull final List<? extends IGenericRecyclerViewLayout> items) {
        mPendingUpdates.add(items);
        if (mPendingUpdates.size() == 1) {
            innerUpdateList(items); // no pending update, so execute the update
        }
    }

    /**
     * Procedure meant to update this adapter's entire data set.
     * Makes use of a background thread to execute the update operation and off load work from the UIThread.
     * @param items the list of Generic Layout Implementation items for the data set.
     */
    @UiThread
    private void innerUpdateList(@NonNull final List<? extends IGenericRecyclerViewLayout> items) {
        mHandler.post(new BackgroundDiffUtilWorker(mDataSet, items, mContext, this));
    }

    /**
     * Procedure meant to update this adapter's entire data set.
     * This procedure handles and commits the update results.
     * @param newItems the list of Generic Layout Implementation items for the data set.
     * @param diffResult the {@link DiffUtil.DiffResult} with the exclusive changes.
     */
    @UiThread
    public void applyDiffResult(@NonNull final List<? extends IGenericRecyclerViewLayout> newItems,
                                @NonNull final DiffUtil.DiffResult diffResult) {
        mPendingUpdates.remove(); // the data set is processed
        mDataSet.clear();
        mDataSet.addAll(newItems);
        diffResult.dispatchUpdatesTo(this);
        updateViewTypes();

        /* Process the next queued data set if there is any */
        if (!mPendingUpdates.isEmpty()) {
            if (mSkipQueuedUpdates) {
                skipQueuedUpdates();
            }
            innerUpdateList(mPendingUpdates.peek());
        }
    }

    /** Procedure meant to skip any pending queued update. */
    private void skipQueuedUpdates() {
        if (mPendingUpdates.size() > 1) {
            /* More than one update queued */
            final List<? extends IGenericRecyclerViewLayout> lastList = mPendingUpdates.peekLast();
            mPendingUpdates.clear();
            mPendingUpdates.add(lastList);
        }
    }

    /**
     * Procedure meant to apply a given payload to this adapter's data set.
     * @param payloads the payload list object with the updates.
     * @param position the adapter's position to be updated.
     */
    private void applyPayloads(@NonNull final List<Object> payloads, final int position) {
        for (final Object payload : payloads) {
            if (payload instanceof Bundle) {
                applyBundledPayloads((Bundle) payloads.get(0), position);
            }
        }
    }

    /**
     * Procedure meant to apply a {@link DiffUtil} result payload to this adapter's data set.
     * @param bundledPayloads the {@link Bundle} list object with the updates.
     * @param position the adapter's position to be updated.
     */
    private void applyBundledPayloads(@Nullable final Bundle bundledPayloads, final int position) {
        if (bundledPayloads != null && bundledPayloads.keySet() != null) {
            for (final String key : bundledPayloads.keySet()) {
                if (UPDATE_ITEM.equals(key)) {
                    applyPayloadChange(position, bundledPayloads, key);
                }
            }
        }
    }

    /**
     * Procedure meant to apply a given {@link RecyclerView.ViewHolder} change on this adapter's data set.
     * @param position the adapter's position to be updated.
     * @param payload the payload bundle object with the updates.
     * @param key the payload key for the update value object.
     */
    private void applyPayloadChange(@IntRange(from = 0) final int position, @NonNull final Bundle payload,
                                    @NonNull final String key) {
        if (payload.get(key) instanceof RecyclerView.ViewHolder) {
            final RecyclerView.ViewHolder newHolder = (RecyclerView.ViewHolder) payload.get(key);
            if (newHolder != null) {
                mDataSet.get(position).setElements(newHolder);
            }
        }
    }

    /** Procedure meant to update this Adapter's handled View Types. */
    private void updateViewTypes() {
        mViewTypes.clear();
        for (final IGenericRecyclerViewLayout item : mDataSet) {
            if (mViewTypes.get(item.getViewType()) == null) {
                mViewTypes.put(item.getViewType(), item);
            }
        }
    }

} @SuppressWarnings("WeakerAccess")
public interface IGenericRecyclerViewLayout<T extends RecyclerView.ViewHolder & IViewHolder> extends Serializable {

    /**
     * Procedure meant to handle the ViewHolder instance creation.
     * @param parent the root ViewGroup {@link ViewGroup} for the ViewHolder instance.
     * @return the created ViewHolder instance.
     */
    @NonNull T createViewHolder(@NonNull final ViewGroup parent);

    /**
     * Procedure meant to bind the target data from a model to the ViewHolder item {@link RecyclerView.ViewHolder}.
     * @param holder the {@link RecyclerView.ViewHolder} instance.
     */
    void setElements(@NonNull final T holder);

    /**
     * Procedure meant to define a tag for the ViewHolder item {@link RecyclerView.ViewHolder}.
     * @return the {@link Object} representing the ViewHolder item {@link RecyclerView.ViewHolder}'s tag.
     */
    @NonNull Object getTag();

    /**
     * Procedure meant to define a ViewType for the ViewHolder item {@link RecyclerView.ViewHolder}.
     * @return the Integer value representing the ViewHolder item {@link RecyclerView.ViewHolder}'s ViewType.
     */
    @IntRange(from = 0) int getViewType();

} public class SimpleDividerItemDecoration extends GenericItemDecoration<SimpleDividerItemDecorationSpec> {

    @NonNull
    private final DecoratorDrawOverManager mDrawOverManager = new DecoratorDrawOverManager();

    @IntRange(from = 0)
    private int mTopSpacing;
    @IntRange(from = 0)
    private int mBottomSpacing;
    @IntRange(from = 0)
    private int mStartSpacing;
    @IntRange(from = 0)
    private int mEndSpacing;
    @IntRange(from = 0, to = 5)
    private int mDividerPosition;

    @Nullable
    private Drawable mDivider;
    @Nullable
    private Paint mDrawnDivider;

    /**
     * Instantiates a new SimpleDividerItemDecoration.
     * @param configurationSpec a valid {@link ItemDecorationSpec} containing this item decoration specification.
     */
    public SimpleDividerItemDecoration(@NonNull final SimpleDividerItemDecorationSpec configurationSpec) {
        super(configurationSpec);
    }

    /** {@inheritDoc} */
    @Override
    public void getItemOffsets(@NonNull final Rect outRect, @NonNull final View view,
                               @NonNull final RecyclerView parent, @NonNull final RecyclerView.State state) {
        outRect.top = mTopSpacing;
        outRect.bottom = mBottomSpacing;
        outRect.left = mStartSpacing;
        outRect.right = mEndSpacing;
    }

    /** {@inheritDoc} */
    @Override
    public void onDrawOver(@NonNull final Canvas canvas, @NonNull final RecyclerView parent,
                           @NonNull final RecyclerView.State state) {
        if (mDivider != null) {
            mDrawOverManager.applyDrawableDivider(canvas, parent, mDivider, mDividerPosition);
        } else if (mDrawnDivider != null) {
            mDrawOverManager.applyDrawnDivider(canvas, parent, state, mDrawnDivider, mDividerPosition);
        }
    }

    /** {@inheritDoc} */
    @Override
    protected void applySpec(@NonNull final SimpleDividerItemDecorationSpec configurationSpec) {
        /* Get Spacing Rules */
        mTopSpacing = configurationSpec.getTopSpacing();
        mBottomSpacing = configurationSpec.getBottomSpacing();
        mStartSpacing = configurationSpec.getStartSpacing();
        mEndSpacing = configurationSpec.getEndSpacing();

        /* Get Divider Rules */
        mDivider = configurationSpec.getDivider();
        mDividerPosition = configurationSpec.getDividerPosition();
        mDrawnDivider = configurationSpec.getDrawnDivider();
    }

} @SuppressWarnings({"WeakerAccess", "unused"})
@AllArgsConstructor
public class GenericDecorationDividerPosition {

    /* Constants */

    /** POSITION_TOP representing an item has its divider placed above it. */
    public static final int POSITION_TOP = 0;

    /** POSITION_BOTTOM representing an item has its divider placed below it. */
    public static final int POSITION_BOTTOM = 1;

    /** POSITION_START representing an item has its divider placed to it's left. */
    public static final int POSITION_START = 2;

    /** POSITION_END representing an item has its divider placed to it's right. */
    public static final int POSITION_END = 3;

    /** POSITION_START_END representing an item has its divider placed to it's left and to it's right. */
    public static final int POSITION_START_END = 4;

    /** POSITION_TOP_BOTTOM representing an item has its divider placed above and below it. */
    public static final int POSITION_TOP_BOTTOM = 5;

    // Declare the @StringDef for these constants
    @IntDef({ POSITION_TOP, POSITION_BOTTOM, POSITION_START, POSITION_END })
    @Retention(RetentionPolicy.SOURCE)
    public @interface GenericDecorationDividerPositionConstants { /* Do nothing here ... */ }

} @SuppressWarnings("WeakerAccess")
@ToString
@EqualsAndHashCode
public final class SimpleDividerItemDecorationSpec implements ItemDecorationSpec, Serializable {

    /** This ItemDecoration's top spacing value */
    @Getter
    private final int mTopSpacing;

    /** This ItemDecoration's bottom spacing value */
    @Getter
    private final int mBottomSpacing;

    /** This ItemDecoration's start spacing value */
    @Getter
    private final int mStartSpacing;

    /** This ItemDecoration's end spacing value */
    @Getter
    private final int mEndSpacing;

    /** This ItemDecoration's divider position value {@link GenericDecorationDividerPosition} */
    @Getter
    private final int mDividerPosition;

    /** This ItemDecoration's divider resource */
    @Nullable
    @Getter
    private final Drawable mDivider;

    /** This ItemDecoration's divider {@link Paint} resource */
    @Nullable
    @Getter
    private final Paint mDrawnDivider;

    /**
     * Instantiates a new SimpleDividerItemDecorationSpec.
     * Private to prevent instantiation.
     * @param builder the builder object responsible for harboring
     *                all the required fields of a {@link SimpleDividerItemDecorationSpec}.
     */
    SimpleDividerItemDecorationSpec(@NonNull final DecorationSpecBuilder builder) {
        mDividerPosition = builder.mDividerPosition;
        mDivider = builder.mDivider;
        mDrawnDivider = builder.mDrawnDivider;

        mTopSpacing = builder.mTopSpacing;
        mBottomSpacing = builder.mBottomSpacing;
        mStartSpacing = builder.mStartSpacing;
        mEndSpacing = builder.mEndSpacing;
    }

    /**
     * SimpleDividerItemDecorationSpec builder class responsible for harboring
     * all the required fields of a {@link SimpleDividerItemDecorationSpec}.
     */
    @SuppressWarnings("unused")
    @NoArgsConstructor
    public static final class DecorationSpecBuilder {

        @Nullable
        private Drawable mDivider;
        @Nullable
        private Paint mDrawnDivider;

        private int mTopSpacing;
        private int mBottomSpacing;
        private int mStartSpacing;
        private int mEndSpacing;
        private int mDividerPosition;

        /**
         * Procedure meant to set the value for {@link #mDrawnDivider} optional parameter.
         * @param color the divider's target {@link Color} value.
         *              See {@link Paint#setColor(int)} for more information.
         * @param thickness the divider's target line thickness value. This value must be greater or equal than 0.
         *                  See {@link Paint#setStrokeWidth(float)} for more information.
         * @param style the divider's target {@link Paint.Style}.
         *              See {@link Paint#setStyle(Paint.Style)} for more information.
         * @param pathEffect the divider's target {@link PathEffect}.
         *                   See {@link Paint#setPathEffect(PathEffect)} for more information.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withDrawnDivider(@ColorInt int color,
                                                      @FloatRange(from = 0, fromInclusive = false) float thickness,
                                                      @Nullable final Paint.Style style,
                                                      @Nullable final PathEffect pathEffect) {
            mDrawnDivider = new Paint();
            mDrawnDivider.setColor(color);
            mDrawnDivider.setStrokeWidth(thickness);
            if (style != null) {
                mDrawnDivider.setStyle(style);
            }
            if (pathEffect != null) {
                mDrawnDivider.setPathEffect(pathEffect);
            }
            return this;
        }

        /**
         * Procedure meant to set the value for {@link #mDivider} optional parameter.
         * @param divider the divider's target {@link Drawable} value.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withDrawableDivider(@Nullable final Drawable divider) {
            mDivider = divider;
            return this;
        }

        /**
         * Procedure meant to set the value for {@link #mDividerPosition} optional parameter.
         * @param dividerPosition the divider's target position value. This value is ranged.
         *                        See {@link GenericDecorationDividerPosition} for more information.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withDividerPosition(@IntRange(from = 0, to = 5) final int dividerPosition) {
            mDividerPosition = dividerPosition;
            return this;
        }

        /**
         * Procedure meant to set the value for {@link #mTopSpacing} optional parameter.
         * @param topSpacing the {@link RecyclerView}'s outer top spacing value.
         *                   This value must be greater or equal than 0.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withTopSpacing(@IntRange(from = 0) final int topSpacing) {
            mTopSpacing = topSpacing;
            return this;
        }

        /**
         * Procedure meant to set the value for {@link #mBottomSpacing} optional parameter.
         * @param bottomSpacing the {@link RecyclerView}'s outer bottom spacing value.
         *                      This value must be greater or equal than 0.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withBottomSpacing(@IntRange(from = 0) final int bottomSpacing) {
            mBottomSpacing = bottomSpacing;
            return this;
        }

        /**
         * Procedure meant to set the value for {@link #mStartSpacing} optional parameter.
         * @param startSpacing the {@link RecyclerView}'s outer start / left spacing value.
         *                     This value must be greater or equal than 0.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withStartSpacing(@IntRange(from = 0) final int startSpacing) {
            mStartSpacing = startSpacing;
            return this;
        }

        /**
         * Procedure meant to set the value for {@link #mEndSpacing} optional parameter.
         * @param endSpacing the {@link RecyclerView}'s outer end / right spacing value.
         *                   This value must be greater or equal than 0.
         * @return the same object builder object after setting the optional attribute.
         */
        @NonNull
        public DecorationSpecBuilder withEndSpacing(@IntRange(from = 0) final int endSpacing) {
            mEndSpacing = endSpacing;
            return this;
        }

        /**
         * Procedure meant to return the desired {@link SimpleDividerItemDecorationSpec}.
         * @return the built SimpleDividerItemDecorationSpec instance.
         */
        @NonNull
        public SimpleDividerItemDecorationSpec buildDecorationSpec() {
            return new SimpleDividerItemDecorationSpec(this);
        }

    }

} public final class GenericUtils {

    /**
     * Instantiates a new GenericUtils.
     * Private to prevent instantiation.
     * @throws AssertionError if this constructor is ever called. Utility classes should not be instantiated.
     */
    private GenericUtils() {
        throw new AssertionError(GMLRVAConstants.ASSERTION_ERROR); // Throw an exception if this *is* ever called
    }

    /**
     * Procedure meant to apply the optimal configuration on a target {@link RecyclerView} instance.
     * @param recyclerView a target {@link RecyclerView} instance.
     */
    public static void setOptimalConfigurationForRecyclerView(@NonNull final RecyclerView recyclerView) {
        recyclerView.setItemViewCacheSize(30);
        recyclerView.setDrawingCacheEnabled(true);
        recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
        recyclerView.setHasFixedSize(true);
        recyclerView.setNestedScrollingEnabled(true);
    }

} public final class ExampleItemAnimator extends GenericItemAnimator {

    /** {@inheritDoc} */
    @Nullable
    @Override
    public AnimatorSet handleCustomAnimation(@NonNull final GenericAnimatedViewHolderInfo holderInfo,
                                             @NonNull final IAnimatedViewHolder holder) {
        switch (holderInfo.getUpdateAction()) {
            case 0:
                return holder.runChangeAnimation(this);
            default:
                throw new UnsupportedOperationException(UNSUPPORTED_ERROR);
        }
    }

} public interface ClickListener {

    /** Procedure meant to handle click call to actions applied to the target {@link IGenericRecyclerViewLayout}. */
    void onClick();

} @AllArgsConstructor
@Getter
@EqualsAndHashCode(exclude = "mDescription")
public final class FakeDataObject implements Comparable<FakeDataObject> {

    private String mTitle;
    private String mDescription;

    @Override
    public int compareTo(@NonNull final FakeDataObject o) {
        return getTitle().compareToIgnoreCase(o.getTitle());
    }

} @NoArgsConstructor
public final class FakeDataProvider {

    private static final int MAX_LENGTH = 10;

    /**
     * Procedure meant to return a {@link FakeDataObject} instance, containing the randomly generated data.
     * @return the {@link FakeDataObject} instance, containing the randomly generated data.
     */
    @NonNull
    public FakeDataObject provideFakeData() {
        final Random random = new Random();
        return new FakeDataObject(RandomStringGenerator.getRandomString(random.nextInt(MAX_LENGTH)),
                RandomStringGenerator.getRandomString(random.nextInt(MAX_LENGTH)));
    }

    /** Auxiliary class meant to handle the random generation of data. */
    private static final class RandomStringGenerator {

        private static final String ALLOWED_CHARACTERS = "0123456789qwertyuiopasdfghjklzxcvbnm";

        /**
         * Procedure meant to generate and return a {@link String} object containing randomly generated output.
         * @param sizeOfRandomString the desired size of the resulting {@link String} object.
         * @return the {@link String} object containing randomly generated output.
         */
        @NonNull
        private static String getRandomString(@IntRange(from = 0) final int sizeOfRandomString) {
            final Random random = new Random();
            final StringBuilder sb = new StringBuilder(sizeOfRandomString);
            for (int i = 0; i < sizeOfRandomString; i++) {
                sb.append(ALLOWED_CHARACTERS.charAt(random.nextInt(ALLOWED_CHARACTERS.length())));
            }
            return sb.toString();
        }

    }

} @AllArgsConstructor
public class CarouselCategoryItemLayout
        implements IGenericRecyclerViewLayout<CarouselCategoryItemLayout.CarouselCategoryViewHolder> {

    private final String mCategoryTitle;
    private final List<? extends IGenericRecyclerViewLayout> mCategoryData;
    private final Context mContext;

    @NonNull
    @Override
    public CarouselCategoryViewHolder createViewHolder(@NonNull final ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gmlrva_layout_carousel_category_item, parent, false);
        return new CarouselCategoryViewHolder(view);
    }

    @Override
    public void setElements(@NonNull final CarouselCategoryViewHolder holder) {
        holder.getTitle().setText(mCategoryTitle);
        final Drawable aux = ContextCompat
                .getDrawable(holder.itemView.getContext(), R.drawable.gmlrva_vertical_red_line_item_divider);
        if (aux != null) {
            loadItems(holder.getItems(), aux);
        }
    }

    @NonNull
    @Override
    public Object getTag() {
        return mCategoryTitle;
    }

    @Override
    public int getViewType() {
        return GenericRecyclerViewLayoutTypes.CAROUSEL_ITEM_CATEGORY;
    }

    /**
     * Procedure meant to load the Carousel Item Layout items, bound by this Carousel Category Layout.
     * @param items the {@link RecyclerView} which will hold the Carousel Item Layout items.
     * @param drawable the divider's target {@link Drawable} value.
     */
    private void loadItems(@NonNull final RecyclerView items, @NonNull final Drawable drawable) {
        items.setAdapter(new GenericMultipleLayoutAdapter(mCategoryData, mContext, false));
        items.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));

        final SimpleDividerItemDecorationSpec spec = new SimpleDividerItemDecorationSpec.DecorationSpecBuilder()
                .withDrawableDivider(drawable)
                .withDividerPosition(GenericDecorationDividerPosition.POSITION_END)
                .buildDecorationSpec();
        items.addItemDecoration(new SimpleDividerItemDecoration(spec));

        GenericUtils.setOptimalConfigurationForRecyclerView(items);
    }

    /** Class meant to define the {@link RecyclerView.ViewHolder} for a Carousel Category Layout instance. */
    class CarouselCategoryViewHolder extends RecyclerView.ViewHolder implements IAnimatedViewHolder, IViewHolder {

        @Getter
        private TextView mTitle;
        @Getter
        private RecyclerView mItems;

        /**
         * Instantiates a new CarouselCategoryViewHolder.
         * @param view this {@link RecyclerView.ViewHolder}'s root view.
         */
        CarouselCategoryViewHolder(@NonNull final View view) {
            super(view);
            bindViews(view);
        }

        /** {@inheritDoc} */
        @Override
        public void runAddAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.ADD_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Override
        public void runRemoveAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.REMOVE_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Nullable
        @Override
        public AnimatorSet runChangeAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.CHANGE_ANIMATION_FINISHED);
            return null;
        }

        /**
         * Procedure meant to bind this {@link RecyclerView.ViewHolder}'s views.
         * @param view this {@link CarouselCategoryViewHolder}'s root view.
         */
        private void bindViews(@NonNull final View view) {
            mTitle = view.findViewById(R.id.tvCarouselCategoryItemTitle);
            mItems = view.findViewById(R.id.rvCarouselCategoryItemData);
        }

        @Override
        public void recycle() {

        }
    }

} @AllArgsConstructor
public class CarouselCategoryItemWithOptionLayout
        implements IGenericRecyclerViewLayout<CarouselCategoryItemWithOptionLayout.CarouselCategoryViewHolder> {

    private final String mCategoryTitle;
    private final List<? extends IGenericRecyclerViewLayout> mCategoryData;
    private final Context mContext;

    @NonNull
    @Override
    public CarouselCategoryViewHolder createViewHolder(@NonNull final ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gmlrva_layout_carousel_category_item, parent, false);
        return new CarouselCategoryViewHolder(view);
    }

    @Override
    public void setElements(@NonNull final CarouselCategoryViewHolder holder) {
        holder.getTitle().setText(mCategoryTitle);
        loadItems(holder.getItems());
    }

    @NonNull
    @Override
    public Object getTag() {
        return mCategoryTitle;
    }

    @Override
    public int getViewType() {
        return GenericRecyclerViewLayoutTypes.CAROUSEL_ITEM_CATEGORY_WITH_OPTIONS;
    }

    /**
     * Procedure meant to load the Carousel Item Layout items, bound by this Carousel Category Layout.
     * @param items the {@link RecyclerView} which will hold the Carousel Item Layout items.
     */
    private void loadItems(@NonNull final RecyclerView items) {
        items.setAdapter(new GenericMultipleLayoutAdapter(mCategoryData, mContext, false));
        items.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.HORIZONTAL, false));
        GenericUtils.setOptimalConfigurationForRecyclerView(items);
    }

    /** Class meant to define the {@link RecyclerView.ViewHolder} for a Carousel Category Layout instance. */
    class CarouselCategoryViewHolder extends RecyclerView.ViewHolder implements IAnimatedViewHolder, IViewHolder {

        @Getter
        private TextView mTitle;
        @Getter
        private RecyclerView mItems;

        /**
         * Instantiates a new CarouselCategoryViewHolder.
         * @param view this {@link RecyclerView.ViewHolder}'s root view.
         */
        CarouselCategoryViewHolder(@NonNull final View view) {
            super(view);
            bindViews(view);
        }

        /** {@inheritDoc} */
        @Override
        public void runAddAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.ADD_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Override
        public void runRemoveAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.REMOVE_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Nullable
        @Override
        public AnimatorSet runChangeAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.CHANGE_ANIMATION_FINISHED);
            return null;
        }

        /**
         * Procedure meant to bind this {@link RecyclerView.ViewHolder}'s views.
         * @param view this {@link CarouselCategoryViewHolder}'s root view.
         */
        private void bindViews(@NonNull final View view) {
            mTitle = view.findViewById(R.id.tvCarouselCategoryItemTitle);
            mItems = view.findViewById(R.id.rvCarouselCategoryItemData);
        }

        @Override
        public void recycle() {

        }
    }

} @AllArgsConstructor
public class CarouselItemLayout
        implements IGenericRecyclerViewLayout<CarouselItemLayout.CarouselItemViewHolder> {

    private final String mTitle;
    private final String mDescription;
    @IntRange(from = 0)
    private final int mCoverResource;

    @NonNull
    @Override
    public CarouselItemViewHolder createViewHolder(@NonNull final ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gmlrva_layout_carousel_item, parent, false);
        return new CarouselItemViewHolder(view);
    }

    @Override
    public void setElements(@NonNull final CarouselItemViewHolder holder) {
        holder.getTitle().setText(mTitle);
        holder.getDescription().setText(mDescription);
        holder.getCover().setImageResource(mCoverResource);
    }

    @NonNull
    @Override
    public Object getTag() {
        return mTitle;
    }

    @Override
    public int getViewType() {
        return GenericRecyclerViewLayoutTypes.CAROUSEL_ITEM;
    }

    /** Class meant to define the {@link RecyclerView.ViewHolder} for a Carousel Item Layout instance. */
    class CarouselItemViewHolder extends RecyclerView.ViewHolder implements IAnimatedViewHolder, View.OnClickListener, IViewHolder {

        @Getter
        private TextView mTitle;
        @Getter
        private TextView mDescription;
        @Getter
        private ImageView mCover;

        /**
         * Instantiates a new CarouselItemViewHolder.
         * @param view this {@link RecyclerView.ViewHolder}'s root view.
         */
        CarouselItemViewHolder(@NonNull final View view) {
            super(view);
            bindViews(view);
            bindListeners();
        }

        /** {@inheritDoc} */
        @Override
        public void runAddAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.ADD_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Override
        public void runRemoveAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.REMOVE_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Nullable
        @Override
        public AnimatorSet runChangeAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.CHANGE_ANIMATION_FINISHED);
            return null;
        }

        /** {@inheritDoc} */
        @Override
        public void onClick(@NonNull final View v) {
            final int viewId = v.getId();
            if (viewId == mTitle.getId()) {
                handleTitleClick();
            } else if (viewId == mDescription.getId()) {
                handleDescriptionClick();
            } else if (viewId == mCover.getId()) {
                handleCoverClick();
            } else {
                throw new UnsupportedOperationException(GMLRVAConstants.UNSUPPORTED_ERROR);
            }
        }

        /** Procedure meant to handle a Cover view Carousel Item Layout click action. */
        private void handleCoverClick() {
            Toast.makeText(itemView.getContext(), "Cover Click!", Toast.LENGTH_SHORT).show();
        }

        /** Procedure meant to handle a Description view Carousel Item Layout click action. */
        private void handleDescriptionClick() {
            Toast.makeText(itemView.getContext(), "Description Click!", Toast.LENGTH_SHORT).show();
        }

        /** Procedure meant to handle a Title view Carousel Item Layout click action. */
        private void handleTitleClick() {
            Toast.makeText(itemView.getContext(), "Title Click!", Toast.LENGTH_SHORT).show();
        }

        /** Procedure meant to bind this {@link RecyclerView.ViewHolder}'s listeners. */
        private void bindListeners() {
            final View[] clickableViews = {mTitle, mCover, mDescription};
            for (final View view : clickableViews) {
                view.setOnClickListener(this);
            }
        }

        /**
         * Procedure meant to bind this {@link RecyclerView.ViewHolder}'s views.
         * @param view this {@link CarouselItemViewHolder}'s root view.
         */
        private void bindViews(@NonNull final View view) {
            mTitle = view.findViewById(R.id.tvCarouselItemTitle);
            mDescription = view.findViewById(R.id.tvCarouselItemDescription);
            mCover = view.findViewById(R.id.ivCarouselItemCover);
        }

        @Override
        public void recycle() {

        }
    }

} @AllArgsConstructor
public class CarouselItemWithOptionLayout
        implements IGenericRecyclerViewLayout<CarouselItemWithOptionLayout.CarouselItemWithOptionViewHolder> {

    private final String mTitle;
    private final String mDescription;
    @IntRange(from = 0)
    private final int mCoverResource;

    @NonNull
    @Override
    public CarouselItemWithOptionViewHolder createViewHolder(@NonNull final ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gmlrva_layout_carousel_item_option, parent, false);
        return new CarouselItemWithOptionViewHolder(view);
    }

    @Override
    public void setElements(@NonNull final CarouselItemWithOptionViewHolder holder) {
        holder.getTitle().setText(mTitle);
        holder.getDescription().setText(mDescription);
        holder.getCover().setImageResource(mCoverResource);
    }

    @NonNull
    @Override
    public Object getTag() {
        return mTitle;
    }

    @Override
    public int getViewType() {
        return GenericRecyclerViewLayoutTypes.CAROUSEL_ITEM_WITH_OPTIONS;
    }

    /** Class meant to define the {@link RecyclerView.ViewHolder} for a Carousel Item Layout instance. */
    class CarouselItemWithOptionViewHolder extends RecyclerView.ViewHolder
            implements IAnimatedViewHolder, View.OnClickListener, IViewHolder {

        @Getter
        private TextView mTitle;
        @Getter
        private TextView mDescription;
        @Getter
        private ImageView mCover;
        @Getter
        private ImageView mOption;
        @Getter
        private RelativeLayout mOptionSection;
        @Getter
        private View mLeftOption;
        @Getter
        private View mRightOption;

        /**
         * Instantiates a new CarouselItemViewHolder.
         * @param view this {@link RecyclerView.ViewHolder}'s root view.
         */
        CarouselItemWithOptionViewHolder(@NonNull final View view) {
            super(view);
            bindViews(view);
            bindListeners();
        }

        /** {@inheritDoc} */
        @Override
        public void runAddAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.ADD_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Override
        public void runRemoveAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.REMOVE_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Nullable
        @Override
        public AnimatorSet runChangeAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.CHANGE_ANIMATION_FINISHED);
            return null;
        }

        /** {@inheritDoc} */
        @Override
        public void onClick(@NonNull final View v) {
            final int viewId = v.getId();
            if (viewId == mTitle.getId()) {
                handleTitleClick();
            } else if (viewId == mDescription.getId()) {
                handleDescriptionClick();
            } else if (viewId == mCover.getId()) {
                handleCoverClick();
            } else if (viewId == mOption.getId()) {
                handleOptionClick();
            } else if (viewId == mLeftOption.getId()) {
                handleLeftOptionClick();
            } else if (viewId == mRightOption.getId()) {
                handleRightOptionClick();
            } else {
                throw new UnsupportedOperationException(GMLRVAConstants.UNSUPPORTED_ERROR);
            }
        }

        /** Procedure meant to handle a Left Option view Carousel Item Layout click action. */
        private void handleLeftOptionClick() {
            Toast.makeText(itemView.getContext(), "Left Option selected!", Toast.LENGTH_SHORT).show();
            handleOptionClick();
        }

        /** Procedure meant to handle a Right Option view Carousel Item Layout click action. */
        private void handleRightOptionClick() {
            Toast.makeText(itemView.getContext(), "Right Option selected!", Toast.LENGTH_SHORT).show();
            handleOptionClick();
        }

        /** Procedure meant to handle an Option view Carousel Item Layout click action. */
        private void handleOptionClick() {
            if (mOptionSection.getVisibility() == View.GONE) {
                mOptionSection.setVisibility(View.VISIBLE);
            } else {
                mOptionSection.setVisibility(View.GONE);
            }
        }

        /** Procedure meant to handle a Cover view Carousel Item Layout click action. */
        private void handleCoverClick() {
            Toast.makeText(itemView.getContext(), "Cover Click!", Toast.LENGTH_SHORT).show();
        }

        /** Procedure meant to handle a Description view Carousel Item Layout click action. */
        private void handleDescriptionClick() {
            Toast.makeText(itemView.getContext(), "Description Click!", Toast.LENGTH_SHORT).show();
        }

        /** Procedure meant to handle a Title view Carousel Item Layout click action. */
        private void handleTitleClick() {
            Toast.makeText(itemView.getContext(), "Title Click!", Toast.LENGTH_SHORT).show();
        }

        /** Procedure meant to bind this {@link RecyclerView.ViewHolder}'s listeners. */
        private void bindListeners() {
            final View[] clickableViews = {mTitle, mCover, mDescription, mOption, mLeftOption, mRightOption};
            for (final View view : clickableViews) {
                view.setOnClickListener(this);
            }
        }

        /**
         * Procedure meant to bind this {@link RecyclerView.ViewHolder}'s views.
         * @param view this {@link CarouselItemWithOptionViewHolder}'s root view.
         */
        private void bindViews(@NonNull final View view) {
            mTitle = view.findViewById(R.id.tvCarouselItemTitle);
            mDescription = view.findViewById(R.id.tvCarouselItemDescription);
            mCover = view.findViewById(R.id.ivCarouselItemCover);
            mOption = view.findViewById(R.id.ivCarouselItemOption);
            mOptionSection = view.findViewById(R.id.rlOptionSection);
            mLeftOption = view.findViewById(R.id.vOptionsSectionLeft);
            mRightOption = view.findViewById(R.id.vOptionsSectionRight);
        }

        @Override
        public void recycle() {

        }
    }

} @AllArgsConstructor
public class SingleImageItemLayout
        implements IGenericRecyclerViewLayout<SingleImageItemLayout.SingleImageItemViewHolder> {

    @IntRange(from = 0)
    private final int mCoverResource;
    @SuppressWarnings("WeakerAccess")
    protected final ClickListener mListener;

    @NonNull
    @Override
    public SingleImageItemViewHolder createViewHolder(@NonNull final ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gmlrva_layout_generic_single_image_item, parent, false);
        return new SingleImageItemViewHolder(view);
    }

    @Override
    public void setElements(@NonNull final SingleImageItemViewHolder holder) {
        holder.getCover().setImageResource(mCoverResource);
    }

    @NonNull
    @Override
    public Object getTag() {
        return mCoverResource;
    }

    @Override
    public int getViewType() {
        return GenericRecyclerViewLayoutTypes.SINGLE_IMAGE_ITEM;
    }

    /** Class meant to define the {@link RecyclerView.ViewHolder} for a Single Image Layout instance. */
    final class SingleImageItemViewHolder extends RecyclerView.ViewHolder
            implements View.OnClickListener, IAnimatedViewHolder, IViewHolder {

        @Getter
        private ImageView mCover;

        /**
         * Instantiates a new SingleImageItemViewHolder.
         * @param view this {@link RecyclerView.ViewHolder}'s root view.
         */
        SingleImageItemViewHolder(@NonNull final View view) {
            super(view);
            bindViews(view);
            bindListeners();
        }

        /** {@inheritDoc} */
        @Override
        public void runAddAnimation(@NonNull final GenericItemAnimator listener) {
            ViewHolderAnimationHelper.runTestAddAnimation(this, itemView, listener);
        }

        /** {@inheritDoc} */
        @Override
        public void runRemoveAnimation(@NonNull final GenericItemAnimator listener) {
            ViewHolderAnimationHelper.runTestRemoveAnimation(this, itemView, listener);
        }

        /** {@inheritDoc} */
        @Nullable
        @Override
        public AnimatorSet runChangeAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.CHANGE_ANIMATION_FINISHED);
            return null;
        }

        /** {@inheritDoc} */
        @Override
        public void onClick(@NonNull final View v) {
            final int viewId = v.getId();
            if (viewId == mCover.getId()) {
                handleCoverClick();
            } else {
                throw new UnsupportedOperationException(GMLRVAConstants.UNSUPPORTED_ERROR);
            }
        }

        /** Procedure meant to handle a Single Image Layout click action. */
        private void handleCoverClick() {
            Toast.makeText(itemView.getContext(), "Cover Click!", Toast.LENGTH_SHORT).show();
            if (mListener != null) {
                mListener.onClick();
            }
        }

        /** Procedure meant to bind this {@link RecyclerView.ViewHolder}'s listeners. */
        private void bindListeners() {
            mCover.setOnClickListener(this);
        }

        /**
         * Procedure meant to bind this {@link RecyclerView.ViewHolder}'s views.
         * @param view this {@link SingleImageItemViewHolder}'s root view.
         */
        private void bindViews(@NonNull final View view) {
            mCover = view.findViewById(R.id.ivSingleImageItemLayoutCover);
        }

        @Override
        public void recycle() {

        }
    }

} @AllArgsConstructor
public class SingleTextItemLayout
        implements IGenericRecyclerViewLayout<SingleTextItemLayout.SingleTextItemViewHolder> {

    private final String mTextResource;
    @SuppressWarnings("WeakerAccess")
    protected final ClickListener mListener;

    @NonNull
    @Override
    public SingleTextItemViewHolder createViewHolder(@NonNull final ViewGroup parent) {
        final View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.gmlrva_layout_generic_single_text_item, parent, false);
        return new SingleTextItemViewHolder(view);
    }

    @Override
    public void setElements(@NonNull final SingleTextItemViewHolder holder) {
        holder.getTitle().setText(mTextResource);
    }

    @NonNull
    @Override
    public Object getTag() {
        return mTextResource;
    }

    @Override
    public int getViewType() {
        return GenericRecyclerViewLayoutTypes.SINGLE_TEXT_ITEM;
    }

    /** Class meant to define the {@link RecyclerView.ViewHolder} for a Single Text Layout instance. */
    final class SingleTextItemViewHolder extends RecyclerView.ViewHolder
            implements IAnimatedViewHolder, View.OnClickListener, IViewHolder {

        @Getter
        private TextView mTitle;

        /**
         * Instantiates a new SingleTextItemViewHolder.
         * @param view this {@link RecyclerView.ViewHolder}'s root view.
         */
        SingleTextItemViewHolder(@NonNull final View view) {
            super(view);
            bindViews(view);
            bindListeners();
        }

        /** {@inheritDoc} */
        @Override
        public void runAddAnimation(@NonNull final GenericItemAnimator listener) {
            ViewHolderAnimationHelper.runTestAddAnimation(this, itemView, listener);
//            listener.onAnimationFinished(this, ADD_ANIMATION_FINISHED)
        }

        /** {@inheritDoc} */
        @Override
        public void runRemoveAnimation(@NonNull final GenericItemAnimator listener) {
            listener.onAnimationFinished(this, GenericAnimationFinishedOperation.REMOVE_ANIMATION_FINISHED);
        }

        /** {@inheritDoc} */
        @Override
        public AnimatorSet runChangeAnimation(@NonNull final GenericItemAnimator listener) {
            return ViewHolderAnimationHelper.runTestChangeAnimation(this, mTitle, listener);
        }

        /** {@inheritDoc} */
        @Override
        public void onClick(@NonNull final View v) {
            final int viewId = v.getId();
            if (viewId == mTitle.getId()) {
                handleTitleClick();
            } else {
                throw new UnsupportedOperationException(GMLRVAConstants.UNSUPPORTED_ERROR);
            }
        }

        /** Procedure meant to handle a Single Text Layout click action. */
        private void handleTitleClick() {
            Toast.makeText(itemView.getContext(), "Title Click!", Toast.LENGTH_SHORT).show();
            if (mListener != null) {
                mListener.onClick();
            }
        }

        /** Procedure meant to bind this {@link RecyclerView.ViewHolder}'s listeners. */
        private void bindListeners() {
            mTitle.setOnClickListener(this);
        }

        /**
         * Procedure meant to bind this {@link RecyclerView.ViewHolder}'s views.
         * @param view this {@link SingleTextItemViewHolder}'s root view.
         */
        private void bindViews(@NonNull final View view) {
            mTitle = view.findViewById(R.id.tvSingleTextItemLayoutTitle);
        }

        @Override
        public void recycle() {

        }
    }

} public static final int ROTATION_TRIGGER = 0;
import android.content.Context;
import android.content.Intent;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.os.Bundle;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.TypedValue;
import java.util.ArrayList;
import java.util.List;
import pt.simdea.gmlrva.lib.GenericMultipleLayoutAdapter;
import pt.simdea.gmlrva.lib.IGenericRecyclerViewLayout;
import pt.simdea.gmlrva.lib.decoration.decorators.SimpleDividerItemDecoration;
import pt.simdea.gmlrva.lib.decoration.helpers.GenericDecorationDividerPosition;
import pt.simdea.gmlrva.lib.decoration.specs.SimpleDividerItemDecorationSpec;
import pt.simdea.gmlrva.lib.utilities.GenericUtils;
import pt.simdea.gmlrva.lib.animation.animators.ExampleItemAnimator;
import pt.simdea.gmlrva.sample.R;
import pt.simdea.gmlrva.sample.data.ClickListener;
import pt.simdea.gmlrva.sample.data.FakeDataObject;
import pt.simdea.gmlrva.sample.data.FakeDataProvider;
import pt.simdea.gmlrva.sample.layouts.holders.CarouselCategoryItemLayout;
import pt.simdea.gmlrva.sample.layouts.holders.CarouselCategoryItemWithOptionLayout;
import pt.simdea.gmlrva.sample.layouts.holders.CarouselItemLayout;
import pt.simdea.gmlrva.sample.layouts.holders.CarouselItemWithOptionLayout;
import pt.simdea.gmlrva.sample.layouts.holders.SingleImageItemLayout;
import pt.simdea.gmlrva.sample.layouts.holders.SingleTextItemLayout;
import static pt.simdea.gmlrva.sample.layouts.animation.ChangeAnimationTypes.ROTATION_TRIGGER;
/*
 * Copyright (c) 2017. Simdea.
 */

package pt.simdea.gmlrva.sample.ui;





/**
 * Class responsible for the Sample Screen for the (GMLRVA) library.
 *
 * Created by Paulo Ribeiro on 7/16/2017.
 * Simdea © All Rights Reserved.
 * paulo.ribeiro@simdea.pt
 */
@SuppressWarnings({"unchecked", "SameParameterValue"})
public class SampleActivity extends AppCompatActivity implements ClickListener {

    private final FakeDataProvider mDataProvider = new FakeDataProvider();

    private RecyclerView mGenericTest;
    private List<CarouselItemWithOptionLayout> mCarouselItemDataWithOptions = new ArrayList<>();