diff --git a/app/src/main/java/org/mozilla/fenix/components/topsheet/TopSheetBehavior.kt b/app/src/main/java/org/mozilla/fenix/components/topsheet/TopSheetBehavior.kt deleted file mode 100644 index ca1d3288d..000000000 --- a/app/src/main/java/org/mozilla/fenix/components/topsheet/TopSheetBehavior.kt +++ /dev/null @@ -1,841 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Added the Mozilla Public License above to avoid failing detekt rule */ - -/* -* Copyright (C) 2015 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package org.mozilla.fenix.components.topsheet - -import android.animation.ValueAnimator -import android.content.Context -import android.os.Parcel -import android.os.Parcelable -import android.util.AttributeSet -import android.util.TypedValue -import android.view.AbsSavedState -import android.view.MotionEvent -import android.view.VelocityTracker -import android.view.View -import android.view.ViewConfiguration -import android.view.ViewGroup -import androidx.annotation.IntDef -import androidx.coordinatorlayout.widget.CoordinatorLayout -import androidx.core.view.NestedScrollingChild -import androidx.core.view.ViewCompat -import androidx.customview.widget.ViewDragHelper -import com.google.android.material.R -import com.google.android.material.bottomsheet.BottomSheetBehavior -import com.google.android.material.shape.MaterialShapeDrawable -import com.google.android.material.shape.ShapeAppearanceModel -import java.lang.ref.WeakReference -import kotlin.math.abs - -/** - * An interaction behavior plugin for a child view of [CoordinatorLayout] to make it work as - * a top sheet. - */ -@Suppress("TooManyFunctions", "LargeClass") -class TopSheetBehavior -/** - * Default constructor for inflating TopSheetBehaviors from layout. - * - * @param context The [Context]. - * @param attrs The [AttributeSet]. - */(context: Context, attrs: AttributeSet?) : CoordinatorLayout.Behavior(context, attrs) { - /** - * Callback for monitoring events about top sheets. - */ - interface TopSheetCallback { - /** - * Called when the top sheet changes its state. - * - * @param topSheet The top sheet view. - * @param newState The new state. This will be one of [.STATE_DRAGGING], - * [.STATE_SETTLING], [.STATE_EXPANDED], - * [.STATE_COLLAPSED], or [.STATE_HIDDEN]. - */ - fun onStateChanged(topSheet: View, @State newState: Int) - - /** - * Called when the top sheet is being dragged. - * - * @param topSheet The top sheet view. - * @param slideOffset The new offset of this top sheet within its range, from 0 to 1 - * when it is moving upward, and from 0 to -1 when it moving downward. - * @param isOpening detect showing - */ - fun onSlide(topSheet: View, slideOffset: Float, isOpening: Boolean?) - } - - /** - * @hide - */ - @IntDef( - STATE_EXPANDED, - STATE_COLLAPSED, - STATE_DRAGGING, - STATE_SETTLING, - STATE_HIDDEN, - ) - @kotlin.annotation.Retention(AnnotationRetention.SOURCE) - annotation class State - - private var mMaximumVelocity = 0f - private var mPeekHeight = 0 - private var mMinOffset = 0 - private var mMaxOffset = 0 - private var skipCollapsed = false - - /** - * Gets/Sets the height of the top sheet when it is collapsed. - * - * @var peekHeight The height of the collapsed top sheet in pixels. - * @attr ref com.google.android.material.R.styleable#TopSheetBehavior_Params_behavior_peekHeight - */ - private var peekHeight: Int - get() = mPeekHeight - set(peekHeight) { - mPeekHeight = 0.coerceAtLeast(peekHeight) - if (mViewRef != null && mViewRef!!.get() != null) { - mMinOffset = - (-mViewRef!!.get()!!.height).coerceAtLeast( - -(mViewRef!!.get()!!.height - mPeekHeight), - ) - } - } - - @State - private var mState = STATE_COLLAPSED - private var mViewDragHelper: ViewDragHelper? = null - private var mIgnoreEvents = false - private var mLastNestedScrollDy = 0 - private var mNestedScrolled = false - private var mParentHeight = 0 - private var mViewRef: WeakReference? = null - private var mNestedScrollingChildRef: WeakReference? = null - private var mCallback: TopSheetCallback? = null - private var mVelocityTracker: VelocityTracker? = null - private var mActivePointerId = 0 - private var mInitialY = 0 - private var mTouchingScrollingChild = false - - /** True if Behavior has a non-null value for the @shapeAppearance attribute */ - private var shapeThemingEnabled = false - - /** Default Shape Appearance to be used in topsheet */ - private var shapeAppearanceModelDefault: ShapeAppearanceModel? = null - private var materialShapeDrawable: MaterialShapeDrawable? = null - private var interpolatorAnimator: ValueAnimator? = null - private var isShapeExpanded = false - - var elevation = -1f - var isHideable = false - - init { - val a = context.obtainStyledAttributes( - attrs, - R.styleable.BottomSheetBehavior_Layout, - ) - shapeThemingEnabled = - a.hasValue(R.styleable.BottomSheetBehavior_Layout_shapeAppearance) - createMaterialShapeDrawable(context, attrs!!) - createShapeValueAnimator() - peekHeight = (context.resources.displayMetrics.heightPixels * PEEK_HEIGHT_RATIO).toInt() - isHideable = a.getBoolean( - R.styleable.BottomSheetBehavior_Layout_behavior_hideable, - false, - ) - skipCollapsed = a.getBoolean( - R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed, - false, - ) - a.recycle() - val configuration = - ViewConfiguration.get(context) - mMaximumVelocity = configuration.scaledMaximumFlingVelocity.toFloat() - } - - override fun onSaveInstanceState(parent: CoordinatorLayout, child: V): Parcelable? { - return SavedState( - super.onSaveInstanceState( - parent, - child!!, - ), - mState, - ) - } - - override fun onRestoreInstanceState( - parent: CoordinatorLayout, - child: V, - state: Parcelable, - ) { - val ss = - state as SavedState - super.onRestoreInstanceState(parent, child!!, ss.superState) - // Intermediate states are restored as collapsed state - mState = if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) { - STATE_COLLAPSED - } else { - ss.state - } - } - - @Suppress("ComplexMethod") - override fun onLayoutChild( - parent: CoordinatorLayout, - child: V, - layoutDirection: Int, - ): Boolean { - if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child as View)) { - child.fitsSystemWindows = true - } - - // Only set MaterialShapeDrawable as background if shapeTheming is enabled, otherwise will - // default to android:background declared in styles or layout. - if (shapeThemingEnabled && materialShapeDrawable != null) { - ViewCompat.setBackground(child as View, materialShapeDrawable) - } - // Set elevation on MaterialShapeDrawable - // Set elevation on MaterialShapeDrawable - if (materialShapeDrawable != null) { - // Use elevation attr if set on topsheet; otherwise, use elevation of child view. - materialShapeDrawable!!.elevation = - if (elevation == -1f) ViewCompat.getElevation(child as View) else elevation - // Update the material shape based on initial state. - isShapeExpanded = state == BottomSheetBehavior.STATE_EXPANDED - materialShapeDrawable!!.interpolation = if (isShapeExpanded) 0f else 1f - } - - val savedTop = child!!.top - // First let the parent lay it out - parent.onLayoutChild(child, layoutDirection) - // Offset the top sheet - mParentHeight = parent.height - mMinOffset = (-child.height).coerceAtLeast(-(child.height - mPeekHeight)) - mMaxOffset = 0 - if (mState == STATE_EXPANDED) { - ViewCompat.offsetTopAndBottom(child, mMaxOffset) - } else if (isHideable && mState == STATE_HIDDEN) { - ViewCompat.offsetTopAndBottom(child, mParentHeight) - } else if (mState == STATE_COLLAPSED) { - ViewCompat.offsetTopAndBottom(child, mMinOffset) - } else if (mState == STATE_DRAGGING || mState == STATE_SETTLING) { - ViewCompat.offsetTopAndBottom(child, savedTop - child.top) - } - if (mViewDragHelper == null) { - mViewDragHelper = ViewDragHelper.create(parent, mDragCallback) - } - mViewRef = WeakReference(child) - mNestedScrollingChildRef = - WeakReference(findScrollingChild(child)) - return true - } - - @Suppress("ComplexMethod", "ReturnCount") - override fun onInterceptTouchEvent( - parent: CoordinatorLayout, - child: V, - event: MotionEvent, - ): Boolean { - if (!child!!.isShown) { - return false - } - val action = event.actionMasked - // Record the velocity - if (action == MotionEvent.ACTION_DOWN) { - reset() - } - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain() - } - mVelocityTracker!!.addMovement(event) - when (action) { - MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> { - mTouchingScrollingChild = false - mActivePointerId = MotionEvent.INVALID_POINTER_ID - // Reset the ignore flag - if (mIgnoreEvents) { - mIgnoreEvents = false - return false - } - } - MotionEvent.ACTION_DOWN -> { - val initialX = event.x.toInt() - mInitialY = event.y.toInt() - val scroll = mNestedScrollingChildRef!!.get() - if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) { - mActivePointerId = event.getPointerId(event.actionIndex) - mTouchingScrollingChild = true - } - mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID && - !parent.isPointInChildBounds(child, initialX, mInitialY) - } - } - if (!mIgnoreEvents && mViewDragHelper!!.shouldInterceptTouchEvent(event)) { - return true - } - // We have to handle cases that the ViewDragHelper does not capture the top sheet because - // it is not the top most view of its parent. This is not necessary when the touch event is - // happening over the scrolling content as nested scrolling logic handles that case. - val scroll = mNestedScrollingChildRef!!.get() - return action == MotionEvent.ACTION_MOVE && scroll != null && - !mIgnoreEvents && mState != STATE_DRAGGING && - !parent.isPointInChildBounds( - scroll, - event.x.toInt(), - event.y.toInt(), - ) && abs(mInitialY - event.y) > mViewDragHelper!!.touchSlop - } - - override fun onTouchEvent( - parent: CoordinatorLayout, - child: V, - event: MotionEvent, - ): Boolean { - if (!child!!.isShown) { - return false - } - val action = event.actionMasked - if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) { - return true - } - if (mViewDragHelper != null) { - // no crash - mViewDragHelper!!.processTouchEvent(event) - // Record the velocity - if (action == MotionEvent.ACTION_DOWN) { - reset() - } - if (mVelocityTracker == null) { - mVelocityTracker = VelocityTracker.obtain() - } - mVelocityTracker!!.addMovement(event) - // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it - // to capture the top sheet in case it is not captured and the touch slop is passed. - if (action == MotionEvent.ACTION_MOVE && !mIgnoreEvents && - abs(mInitialY - event.y) > mViewDragHelper!!.touchSlop - ) { - mViewDragHelper!!.captureChildView( - child, - event.getPointerId(event.actionIndex), - ) - } - } - return !mIgnoreEvents - } - - override fun onStartNestedScroll( - coordinatorLayout: CoordinatorLayout, - child: V, - directTargetChild: View, - target: View, - nestedScrollAxes: Int, - ): Boolean { - mLastNestedScrollDy = 0 - mNestedScrolled = false - return nestedScrollAxes and ViewCompat.SCROLL_AXIS_VERTICAL != 0 - } - - override fun onNestedPreScroll( - coordinatorLayout: CoordinatorLayout, - child: V, - target: View, - dx: Int, - dy: Int, - consumed: IntArray, - ) { - val scrollingChild = mNestedScrollingChildRef!!.get() - if (target !== scrollingChild) { - return - } - val currentTop = child!!.top - val newTop = currentTop - dy - if (dy > 0) { // Upward - if (!target.canScrollVertically(1)) { - if (newTop >= mMinOffset || isHideable) { - consumed[1] = dy - ViewCompat.offsetTopAndBottom(child, -dy) - setStateInternal(STATE_DRAGGING) - } else { - consumed[1] = currentTop - mMinOffset - ViewCompat.offsetTopAndBottom(child, -consumed[1]) - setStateInternal(STATE_COLLAPSED) - } - } - } else if (dy < 0) { // Downward - // Negative to check scrolling up, positive to check scrolling down - if (newTop < mMaxOffset) { - consumed[1] = dy - ViewCompat.offsetTopAndBottom(child, -dy) - setStateInternal(STATE_DRAGGING) - } else { - consumed[1] = currentTop - mMaxOffset - ViewCompat.offsetTopAndBottom(child, -consumed[1]) - setStateInternal(STATE_EXPANDED) - } - } - dispatchOnSlide(child.top) - mLastNestedScrollDy = dy - mNestedScrolled = true - } - - override fun onStopNestedScroll( - coordinatorLayout: CoordinatorLayout, - child: V, - target: View, - ) { - if (child!!.top == mMaxOffset) { - setStateInternal(STATE_EXPANDED) - return - } - if (target !== mNestedScrollingChildRef!!.get() || !mNestedScrolled) { - return - } - val top: Int - val targetState: Int - if (mLastNestedScrollDy < 0) { - top = mMaxOffset - targetState = STATE_EXPANDED - } else if (isHideable && shouldHide(child, yVelocity)) { - top = -child.height - targetState = STATE_HIDDEN - } else if (mLastNestedScrollDy == 0) { - val currentTop = child.top - if (abs(currentTop - mMinOffset) > abs(currentTop - mMaxOffset)) { - top = mMaxOffset - targetState = STATE_EXPANDED - } else { - top = mMinOffset - targetState = STATE_COLLAPSED - } - } else { - top = mMinOffset - targetState = STATE_COLLAPSED - } - if (mViewDragHelper!!.smoothSlideViewTo(child, child.left, top)) { - setStateInternal(STATE_SETTLING) - ViewCompat.postOnAnimation( - child, - SettleRunnable( - child, - targetState, - ), - ) - } else { - setStateInternal(targetState) - } - mNestedScrolled = false - } - - override fun onNestedPreFling( - coordinatorLayout: CoordinatorLayout, - child: V, - target: View, - velocityX: Float, - velocityY: Float, - ): Boolean { - return target === mNestedScrollingChildRef!!.get() && - ( - mState != STATE_EXPANDED || - super.onNestedPreFling( - coordinatorLayout, - child!!, - target, - velocityX, - velocityY, - ) - ) - } - - /** - * Sets a callback to be notified of top sheet events. - * - * @param callback The callback to notify when top sheet events occur. - */ - fun setTopSheetCallback(callback: TopSheetCallback?) { - mCallback = callback - } - - /** - * Gets/Sets the state of the top sheet. When set, the top sheet will transition to - * that state with animation. - * - * @var state One of [.STATE_EXPANDED], [.STATE_COLLAPSED], [.STATE_DRAGGING], - * and [.STATE_SETTLING]. - */ - @get:State - var state: Int - get() = mState - set(state) { - if (state == mState) { - return - } - if (mViewRef == null) { - // The view is not laid out yet; modify mState and let onLayoutChild handle it later - val stateCondition = state == STATE_COLLAPSED || state == STATE_EXPANDED || - isHideable && state == STATE_HIDDEN - if (stateCondition) { - mState = state - } - return - } - val child = mViewRef!!.get() ?: return - val top: Int - top = if (state == STATE_COLLAPSED) { - mMinOffset - } else if (state == STATE_EXPANDED) { - mMaxOffset - } else if (isHideable && state == STATE_HIDDEN) { - -child.height - } else { - throw IllegalArgumentException("Illegal state argument: $state") - } - setStateInternal(STATE_SETTLING) - if (mViewDragHelper!!.smoothSlideViewTo(child, child.left, top)) { - ViewCompat.postOnAnimation( - child, - SettleRunnable(child, state), - ) - } - } - - private var oldState = mState - private fun setStateInternal(@State state: Int) { - if (state == STATE_COLLAPSED || state == STATE_EXPANDED) { - oldState = state - } - if (mState == state) { - return - } - mState = state - updateDrawableForTargetState(state) - val topSheet: View? = mViewRef!!.get() - if (topSheet != null && mCallback != null) { - mCallback!!.onStateChanged(topSheet, state) - } - } - - @Suppress("NestedBlockDepth") - private fun updateDrawableForTargetState(@BottomSheetBehavior.State state: Int) { - if (state == BottomSheetBehavior.STATE_SETTLING) { - // Special case: we want to know which state we're settling to, so wait for another call. - return - } - val expand = state == BottomSheetBehavior.STATE_EXPANDED - if (isShapeExpanded != expand) { - isShapeExpanded = expand - if (materialShapeDrawable != null && interpolatorAnimator != null) { - if (interpolatorAnimator!!.isRunning) { - interpolatorAnimator!!.reverse() - } else { - val to = if (expand) 0f else 1f - val from = 1f - to - interpolatorAnimator!!.setFloatValues(from, to) - interpolatorAnimator!!.start() - } - } - } - } - - private fun reset() { - mActivePointerId = ViewDragHelper.INVALID_POINTER - if (mVelocityTracker != null) { - mVelocityTracker!!.recycle() - mVelocityTracker = null - } - } - - private fun shouldHide(child: View, yvel: Float): Boolean { - if (child.top > mMinOffset) { - // It should not hide, but collapse. - return false - } - val newTop = child.top + yvel * HIDE_FRICTION - return abs(newTop - mMinOffset) / mPeekHeight.toFloat() > HIDE_THRESHOLD - } - - private fun findScrollingChild(view: View): View? { - if (view is NestedScrollingChild) { - return view - } - if (view is ViewGroup) { - var i = 0 - val count = view.childCount - while (i < count) { - val scrollingChild = findScrollingChild(view.getChildAt(i)) - if (scrollingChild != null) { - return scrollingChild - } - i++ - } - } - return null - } - - private val yVelocity: Float - get() { - mVelocityTracker!!.computeCurrentVelocity(VELOCITY_UNITS, mMaximumVelocity) - return mVelocityTracker!!.getYVelocity(mActivePointerId) - } - - private val mDragCallback: ViewDragHelper.Callback = object : ViewDragHelper.Callback() { - @Suppress("ReturnCount") - override fun tryCaptureView( - child: View, - pointerId: Int, - ): Boolean { - if (mState == STATE_DRAGGING) { - return false - } - if (mTouchingScrollingChild) { - return false - } - if (mState == STATE_EXPANDED && mActivePointerId == pointerId) { - val scroll = mNestedScrollingChildRef!!.get() - if (scroll != null && scroll.canScrollVertically(-1)) { - // Let the content scroll up - return false - } - } - return mViewRef != null && mViewRef!!.get() === child - } - - override fun onViewPositionChanged( - changedView: View, - left: Int, - top: Int, - dx: Int, - dy: Int, - ) { - dispatchOnSlide(top) - } - - override fun onViewDragStateChanged(state: Int) { - if (state == ViewDragHelper.STATE_DRAGGING) { - setStateInternal(STATE_DRAGGING) - } - } - - override fun onViewReleased( - releasedChild: View, - xvel: Float, - yvel: Float, - ) { - val top: Int - - @State val targetState: Int - if (yvel > 0) { // Moving up - top = mMaxOffset - targetState = STATE_EXPANDED - } else if (isHideable && shouldHide(releasedChild, yvel)) { - top = -mViewRef!!.get()!!.height - targetState = STATE_HIDDEN - } else if (yvel == 0f) { - val currentTop = releasedChild.top - if (abs(currentTop - mMinOffset) > abs(currentTop - mMaxOffset)) { - top = mMaxOffset - targetState = STATE_EXPANDED - } else { - top = mMinOffset - targetState = STATE_COLLAPSED - } - } else { - top = mMinOffset - targetState = STATE_COLLAPSED - } - if (mViewDragHelper!!.settleCapturedViewAt(releasedChild.left, top)) { - setStateInternal(STATE_SETTLING) - ViewCompat.postOnAnimation( - releasedChild, - SettleRunnable( - releasedChild, - targetState, - ), - ) - } else { - setStateInternal(targetState) - } - } - - override fun clampViewPositionVertical( - child: View, - top: Int, - dy: Int, - ): Int { - return constrain( - top, - if (isHideable) -child.height else mMinOffset, - mMaxOffset, - ) - } - - override fun clampViewPositionHorizontal( - child: View, - left: Int, - dx: Int, - ): Int { - return child.left - } - - override fun getViewVerticalDragRange(child: View): Int { - return if (isHideable) { - child.height - } else { - mMaxOffset - mMinOffset - } - } - } - - private fun createMaterialShapeDrawable( - context: Context, - attrs: AttributeSet, - ) { - if (shapeThemingEnabled) { - shapeAppearanceModelDefault = ShapeAppearanceModel.builder( - context, - attrs, - R.attr.bottomSheetStyle, - DEF_STYLE_RES, - ) - .build() - materialShapeDrawable = MaterialShapeDrawable(shapeAppearanceModelDefault!!) - materialShapeDrawable?.initializeElevationOverlay(context) - val defaultColor = TypedValue() - context.theme - .resolveAttribute(android.R.attr.colorBackground, defaultColor, true) - materialShapeDrawable?.setTint(defaultColor.data) - } - } - - private fun createShapeValueAnimator() { - interpolatorAnimator = ValueAnimator.ofFloat(0f, 1f) - interpolatorAnimator?.duration = CORNER_ANIMATION_DURATION.toLong() - interpolatorAnimator!!.addUpdateListener { animation -> - val value = animation.animatedValue as Float - if (materialShapeDrawable != null) { - materialShapeDrawable!!.interpolation = value - } - } - } - - private fun dispatchOnSlide(top: Int) { - val topSheet: View? = mViewRef!!.get() - if (topSheet != null && mCallback != null) { - val isOpening = oldState == STATE_COLLAPSED - if (top < mMinOffset) { - mCallback!!.onSlide( - topSheet, - (top - mMinOffset).toFloat() / mPeekHeight, - isOpening, - ) - } else { - mCallback!!.onSlide( - topSheet, - (top - mMinOffset).toFloat() / (mMaxOffset - mMinOffset), - isOpening, - ) - } - } - } - - private inner class SettleRunnable internal constructor( - private val mView: View, - @field:State @param:State - private val mTargetState: Int, - ) : - Runnable { - - override fun run() { - if (mViewDragHelper != null && mViewDragHelper!!.continueSettling(true)) { - ViewCompat.postOnAnimation(mView, this) - } else { - setStateInternal(mTargetState) - } - } - } - - private class SavedState(superState: Parcelable?, @State val state: Int) : - AbsSavedState(superState) { - - override fun writeToParcel(out: Parcel, flags: Int) { - super.writeToParcel(out, flags) - out.writeInt(state) - } - } - - companion object { - /** - * The top sheet is dragging. - */ - const val STATE_DRAGGING = 1 - - /** - * The top sheet is settling. - */ - const val STATE_SETTLING = 2 - - /** - * The top sheet is expanded. - */ - const val STATE_EXPANDED = 3 - - /** - * The top sheet is collapsed. - */ - const val STATE_COLLAPSED = 4 - - /** - * The top sheet is hidden. - */ - const val STATE_HIDDEN = 5 - private const val HIDE_THRESHOLD = 0.5f - private const val HIDE_FRICTION = 0.1f - - /** - * A utility function to get the [TopSheetBehavior] associated with the `view`. - * - * @param view The [View] with [TopSheetBehavior]. - * @return The [TopSheetBehavior] associated with the `view`. - */ - @Suppress("UNCHECKED_CAST") - fun from(view: V): TopSheetBehavior { - val params = view!!.layoutParams - require(params is CoordinatorLayout.LayoutParams) { "The view is not a child of CoordinatorLayout" } - val behavior = - params - .behavior - require(behavior is TopSheetBehavior<*>) { "The view is not associated with TopSheetBehavior" } - return behavior as TopSheetBehavior - } - - /** - * Constrain a number between limits. - */ - fun constrain(amount: Int, low: Int, high: Int): Int { - return if (amount < low) low else if (amount > high) high else amount - } - - private const val CORNER_ANIMATION_DURATION = 500 - private val DEF_STYLE_RES = R.style.Widget_Design_BottomSheet_Modal - - private const val PEEK_HEIGHT_RATIO = 0.75 - private const val VELOCITY_UNITS = 1000 - } -}