1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.notifications.ui.composable 18 19 import androidx.compose.foundation.gestures.FlingBehavior 20 import androidx.compose.foundation.gestures.Orientation 21 import androidx.compose.ui.input.nestedscroll.NestedScrollConnection 22 import androidx.compose.ui.input.nestedscroll.NestedScrollSource 23 import androidx.compose.ui.util.fastCoerceAtLeast 24 import androidx.compose.ui.util.fastCoerceAtMost 25 import com.android.compose.nestedscroll.OnStopScope 26 import com.android.compose.nestedscroll.PriorityNestedScrollConnection 27 import com.android.compose.nestedscroll.ScrollController 28 29 /** 30 * A [NestedScrollConnection] that listens for all vertical scroll events and responds in the 31 * following way: 32 * - If you **scroll up**, it **first brings the [scrimOffset]** back to the [minScrimOffset] and 33 * then allows scrolling of the children (usually the content). 34 * - If you **scroll down**, it **first allows scrolling of the children** (usually the content) and 35 * then resets the [scrimOffset] to [maxScrimOffset]. 36 */ 37 fun NotificationScrimNestedScrollConnection( 38 scrimOffset: () -> Float, 39 snapScrimOffset: (Float) -> Unit, 40 animateScrimOffset: (Float) -> Unit, 41 minScrimOffset: () -> Float, 42 maxScrimOffset: Float, 43 contentHeight: () -> Float, 44 minVisibleScrimHeight: () -> Float, 45 isCurrentGestureOverscroll: () -> Boolean, 46 onStart: (Float) -> Unit = {}, <lambda>null47 onStop: (Float) -> Unit = {}, 48 flingBehavior: FlingBehavior, 49 ): PriorityNestedScrollConnection { 50 return PriorityNestedScrollConnection( 51 orientation = Orientation.Vertical, 52 // scrolling up and inner content is taller than the scrim, so scrim needs to 53 // expand; content can scroll once scrim is at the minScrimOffset. offsetBeforeStartnull54 canStartPreScroll = { offsetAvailable, offsetBeforeStart, _ -> 55 offsetAvailable < 0 && 56 offsetBeforeStart == 0f && 57 contentHeight() > minVisibleScrimHeight() && 58 scrimOffset() > minScrimOffset() 59 }, 60 // scrolling down and content is done scrolling to top. After that, the scrim 61 // needs to collapse; collapse the scrim until it is at the maxScrimOffset. offsetAvailablenull62 canStartPostScroll = { offsetAvailable, _, _ -> 63 offsetAvailable > 0 && (scrimOffset() < maxScrimOffset || isCurrentGestureOverscroll()) 64 }, firstScrollnull65 onStart = { firstScroll -> 66 onStart(firstScroll) 67 object : ScrollController { 68 override fun onScroll(deltaScroll: Float, source: NestedScrollSource): Float { 69 val currentHeight = scrimOffset() 70 val amountConsumed = 71 if (deltaScroll > 0) { 72 val amountLeft = maxScrimOffset - currentHeight 73 deltaScroll.fastCoerceAtMost(amountLeft) 74 } else { 75 val amountLeft = minScrimOffset() - currentHeight 76 deltaScroll.fastCoerceAtLeast(amountLeft) 77 } 78 snapScrimOffset(currentHeight + amountConsumed) 79 return amountConsumed 80 } 81 82 override suspend fun OnStopScope.onStop(initialVelocity: Float): Float { 83 val consumedByScroll = flingToScroll(initialVelocity, flingBehavior) 84 onStop(initialVelocity - consumedByScroll) 85 if (scrimOffset() < minScrimOffset()) { 86 animateScrimOffset(minScrimOffset()) 87 } 88 // Don't consume the velocity on pre/post fling 89 return 0f 90 } 91 92 override fun onCancel() { 93 onStop(0f) 94 if (scrimOffset() < minScrimOffset()) { 95 animateScrimOffset(minScrimOffset()) 96 } 97 } 98 99 override fun canStopOnPreFling() = false 100 } 101 }, 102 ) 103 } 104