<commit_before>/*
 * Copyright © 2017 <NAME>
 */

package com.arasthel.spannedgridlayoutmanager

import android.graphics.PointF
import android.graphics.Rect
import android.os.Parcel
import android.os.Parcelable
import android.support.v7.widget.LinearSmoothScroller
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.util.SparseArray
import android.view.View

/**
 * A [android.support.v7.widget.RecyclerView.LayoutManager] which layouts and orders its views
 * based on width and height spans.
 *
 * @param orientation Whether the views will be layouted and scrolled in vertical or horizontal
 * @param spans How many spans does the layout have per row or column
 */
open class SpannedGridLayoutManager(val orientation: Orientation,
                               val spans: Int) : RecyclerView.LayoutManager() {

    //==============================================================================================
    //  ~ Orientation & Direction enums
    //==============================================================================================

    /**
     * Orientations to layout and scroll views
     * <li>VERTICAL</li>
     * <li>HORIZONTAL</li>
     */
    enum class Orientation {
        VERTICAL, HORIZONTAL
    }

    /**
     * Direction of scroll for layouting process
     * <li>START</li>
     * <li>END</li>
     */
    enum class Direction {
        START, END
    }

    //==============================================================================================
    //  ~ Properties
    //==============================================================================================

    /**
     * Current scroll amount
     */
    protected var scroll = 0

    /**
     * Helper get free rects to place views
     */
    protected lateinit var rectsHelper: RectsHelper

    /**
     * First visible position in layout - changes with recycling
     */
    open val firstVisiblePosition: Int get() {
        if (childCount == 0) { return 0 }
        return getPosition(getChildAt(0)!!)
    }

    /**
     * Last visible position in layout - changes with recycling
     */
    open val lastVisiblePosition: Int get() {
        if (childCount == 0) { return 0 }
        return getPosition(getChildAt(childCount-1)!!)
    }

    /**
     * Start of the layout. Should be [getPaddingEndForOrientation] + first visible item top
     */
    protected var layoutStart = 0
    /**
     * End of the layout. Should be [layoutStart] + last visible item bottom + [getPaddingEndForOrientation]
     */
    protected var layoutEnd = 0

    /**
     * Total length of the layout depending on current orientation
     */
    val size: Int get() = if (orientation == Orientation.VERTICAL) height else width

    /**
     * Cache of rects for layouted views
     */
    protected val childFrames = mutableMapOf<Int, Rect>()

    /**
     * Temporary variable to store wanted scroll by [scrollToPosition]
     */
    protected var pendingScrollToPosition: Int? = null

    /**
     * Whether item order will be kept along re-creations of this LayoutManager with different
     * configurations of not. Default is false. Only set to true if this condition is met.
     * Otherwise, scroll bugs will happen.
     */
    var itemOrderIsStable = false

    /**
     * Provides SpanSize values for the LayoutManager. Otherwise they will all be (1, 1).
     */
    var spanSizeLookup: SpanSizeLookup? = null
        set(newValue) {
            field = newValue
            // If the SpanSizeLookup changes, the views need a whole re-layout
            requestLayout()
        }

    /**
     * SpanSize provider for this LayoutManager.
     * SpanSizes can be cached to improve efficiency.
     */
    open class SpanSizeLookup(
            /** Used to provide an SpanSize for each item. */
            var lookupFunction: ((Int) -> SpanSize)? = null
    ) {
        
        private var cache = SparseArray<SpanSize>()

        /**
         * Enable SpanSize caching. Can be used to improve performance if calculating the SpanSize
         * for items is a complex process.
         */
        var usesCache = false

        /**
         * Returns an SpanSize for the provided position.
         * @param position Adapter position of the item
         * @return An SpanSize, either provided by the user or the default one.
         */
        fun getSpanSize(position: Int): SpanSize {
            if (usesCache) {
                val cachedValue = cache[position]
                if (cachedValue != null) return cachedValue
                
                val value = getSpanSizeFromFunction(position)
                cache.put(position, value)
                return value
            } else {
                return getSpanSizeFromFunction(position)
            }
        }
        
        private fun getSpanSizeFromFunction(position: Int): SpanSize {
            return lookupFunction?.invoke(position) ?: getDefaultSpanSize()
        }
        
        protected open fun getDefaultSpanSize(): SpanSize {
            return SpanSize(1, 1)
        }
        
        fun invalidateCache() {
            cache.clear()
        }
    }

    //==============================================================================================
    //  ~ Initializer
    //==============================================================================================

    init {
        if (spans < 1) {
            throw InvalidMaxSpansException(spans)
        }
    }

    //==============================================================================================
    //  ~ Override parent
    //==============================================================================================

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
                RecyclerView.LayoutParams.MATCH_PARENT,
                RecyclerView.LayoutParams.WRAP_CONTENT
        )
    }

    //==============================================================================================
    //  ~ View layouting methods
    //==============================================================================================

    override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
        if (childCount <= 0 && scroll != 0) scroll = 0
        rectsHelper = RectsHelper(this, orientation)

        layoutStart = getPaddingStartForOrientation()

        layoutEnd = if (scroll != 0) {
            val currentRow = (scroll - layoutStart) / rectsHelper.itemSize
            currentRow * rectsHelper.itemSize
        } else {
            getPaddingEndForOrientation()
        }

        // Clear cache, since layout may change
        childFrames.clear()
<commit_msg>Just change the <= 0 to == 0<commit_after>/*
 * Copyright © 2017 <NAME>
 */

package com.arasthel.spannedgridlayoutmanager

import android.graphics.PointF
import android.graphics.Rect
import android.os.Parcel
import android.os.Parcelable
import android.support.v7.widget.LinearSmoothScroller
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.util.SparseArray
import android.view.View

/**
 * A [android.support.v7.widget.RecyclerView.LayoutManager] which layouts and orders its views
 * based on width and height spans.
 *
 * @param orientation Whether the views will be layouted and scrolled in vertical or horizontal
 * @param spans How many spans does the layout have per row or column
 */
open class SpannedGridLayoutManager(val orientation: Orientation,
                               val spans: Int) : RecyclerView.LayoutManager() {

    //==============================================================================================
    //  ~ Orientation & Direction enums
    //==============================================================================================

    /**
     * Orientations to layout and scroll views
     * <li>VERTICAL</li>
     * <li>HORIZONTAL</li>
     */
    enum class Orientation {
        VERTICAL, HORIZONTAL
    }

    /**
     * Direction of scroll for layouting process
     * <li>START</li>
     * <li>END</li>
     */
    enum class Direction {
        START, END
    }

    //==============================================================================================
    //  ~ Properties
    //==============================================================================================

    /**
     * Current scroll amount
     */
    protected var scroll = 0

    /**
     * Helper get free rects to place views
     */
    protected lateinit var rectsHelper: RectsHelper

    /**
     * First visible position in layout - changes with recycling
     */
    open val firstVisiblePosition: Int get() {
        if (childCount == 0) { return 0 }
        return getPosition(getChildAt(0)!!)
    }

    /**
     * Last visible position in layout - changes with recycling
     */
    open val lastVisiblePosition: Int get() {
        if (childCount == 0) { return 0 }
        return getPosition(getChildAt(childCount-1)!!)
    }

    /**
     * Start of the layout. Should be [getPaddingEndForOrientation] + first visible item top
     */
    protected var layoutStart = 0
    /**
     * End of the layout. Should be [layoutStart] + last visible item bottom + [getPaddingEndForOrientation]
     */
    protected var layoutEnd = 0

    /**
     * Total length of the layout depending on current orientation
     */
    val size: Int get() = if (orientation == Orientation.VERTICAL) height else width

    /**
     * Cache of rects for layouted views
     */
    protected val childFrames = mutableMapOf<Int, Rect>()

    /**
     * Temporary variable to store wanted scroll by [scrollToPosition]
     */
    protected var pendingScrollToPosition: Int? = null

    /**
     * Whether item order will be kept along re-creations of this LayoutManager with different
     * configurations of not. Default is false. Only set to true if this condition is met.
     * Otherwise, scroll bugs will happen.
     */
    var itemOrderIsStable = false

    /**
     * Provides SpanSize values for the LayoutManager. Otherwise they will all be (1, 1).
     */
    var spanSizeLookup: SpanSizeLookup? = null
        set(newValue) {
            field = newValue
            // If the SpanSizeLookup changes, the views need a whole re-layout
            requestLayout()
        }

    /**
     * SpanSize provider for this LayoutManager.
     * SpanSizes can be cached to improve efficiency.
     */
    open class SpanSizeLookup(
            /** Used to provide an SpanSize for each item. */
            var lookupFunction: ((Int) -> SpanSize)? = null
    ) {
        
        private var cache = SparseArray<SpanSize>()

        /**
         * Enable SpanSize caching. Can be used to improve performance if calculating the SpanSize
         * for items is a complex process.
         */
        var usesCache = false

        /**
         * Returns an SpanSize for the provided position.
         * @param position Adapter position of the item
         * @return An SpanSize, either provided by the user or the default one.
         */
        fun getSpanSize(position: Int): SpanSize {
            if (usesCache) {
                val cachedValue = cache[position]
                if (cachedValue != null) return cachedValue
                
                val value = getSpanSizeFromFunction(position)
                cache.put(position, value)
                return value
            } else {
                return getSpanSizeFromFunction(position)
            }
        }
        
        private fun getSpanSizeFromFunction(position: Int): SpanSize {
            return lookupFunction?.invoke(position) ?: getDefaultSpanSize()
        }
        
        protected open fun getDefaultSpanSize(): SpanSize {
            return SpanSize(1, 1)
        }
        
        fun invalidateCache() {
            cache.clear()
        }
    }

    //==============================================================================================
    //  ~ Initializer
    //==============================================================================================

    init {
        if (spans < 1) {
            throw InvalidMaxSpansException(spans)
        }
    }

    //==============================================================================================
    //  ~ Override parent
    //==============================================================================================

    override fun generateDefaultLayoutParams(): RecyclerView.LayoutParams {
        return RecyclerView.LayoutParams(
                RecyclerView.LayoutParams.MATCH_PARENT,
                RecyclerView.LayoutParams.WRAP_CONTENT
        )
    }

    //==============================================================================================
    //  ~ View layouting methods
    //==============================================================================================

    override fun onLayoutChildren(recycler: RecyclerView.Recycler, state: RecyclerView.State) {
        if (childCount == 0 && scroll != 0) scroll = 0
        rectsHelper = RectsHelper(this, orientation)

        layoutStart = getPaddingStartForOrientation()

        layoutEnd = if (scroll != 0) {
            val currentRow = (scroll - layoutStart) / rectsHelper.itemSize
            currentRow * rectsHelper.itemSize
        } else {
            getPaddingEndForOrientation()
        }

        // Clear cache, since layout may change
        childFrames.clear()

{'fraction_non_alphanumeric': 0.21072712598136326, 'fraction_numerical': 0.0038153936459021207, 'mean_word_length': 2.4912909836065573, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3442424', 'n_tokens_mistral': 3360, 'n_tokens_neox': 3115, 'n_words': 977}