chromium/chrome/browser/ui/android/omnibox/java/src/org/chromium/chrome/browser/omnibox/suggestions/base/SpacingRecyclerViewItemDecoration.java

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.omnibox.suggestions.base;

import android.graphics.Rect;
import android.view.View;

import androidx.annotation.Px;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ItemDecoration;

/**
 * Configures space before the first element of the recycler view, and between each of the elements.
 */
public class SpacingRecyclerViewItemDecoration extends ItemDecoration {
    private final @Px int mLeadInSpace;
    private @Px int mElementSpace;

    /**
     * @param parent the RecyclerView component receiving the decoration
     * @param leadInSpace the space before the first element
     * @param elementSpace the total space between each two elements, applied evenly to each side of
     *     every child
     */
    public SpacingRecyclerViewItemDecoration(@Px int leadInSpace, @Px int elementSpace) {
        mLeadInSpace = leadInSpace;
        mElementSpace = elementSpace;
    }

    @Override
    public void getItemOffsets(
            Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.left = outRect.right = mElementSpace / 2;

        int childCount = parent.getAdapter().getItemCount();
        int itemPosition = parent.getChildAdapterPosition(view);
        if (itemPosition != 0 && itemPosition != (childCount - 1)) return;

        // Apply lead-in padding ahead of the first and after the last element.
        if (parent.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL ^ itemPosition != 0) {
            outRect.right = mLeadInSpace;
        } else {
            outRect.left = mLeadInSpace;
        }
    }

    /**
     * Method to be invoked by the owning RecyclerView when its measured size is changed.
     *
     * <p>Permits any derived implementations to adjust their spaces and paddings. This call should
     * be run from `onMeasure()`, ahead of `layout()` pass.
     *
     * @param isPortraitOrientation whether screen orientation is portrait
     * @param newWidth new width of the RecyclerView
     * @param newHeight new height of the RecyclerView
     * @return true, if decorations have changed and item decorations should be invalidated
     */
    public boolean notifyViewSizeChanged(
            boolean isPortraitOrientation, int newWidth, int newHeight) {
        return false;
    }

    /**
     * Specify new element space to be used as an item decoration.
     *
     * <p>Triggers RecyclerView update if the new spacing is different from the old one.
     *
     * <p>This call is intended to be used by derived classes. Keep this call protected.
     *
     * @return true if element space has been updated
     */
    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
    public boolean setElementSpace(int elementSpace) {
        if (elementSpace == mElementSpace) return false;
        mElementSpace = elementSpace;
        return true;
    }

    /** Returns the space between two consecutive elements. */
    public int getElementSpace() {
        return mElementSpace;
    }

    /** Returns the space before the first element. */
    public int getLeadInSpace() {
        return mLeadInSpace;
    }
}