diff options
| author | 2024-10-16 10:29:51 -0400 | |
|---|---|---|
| committer | 2024-10-16 10:34:52 -0400 | |
| commit | c565bef9929dc4f02d391cffc9dbdd9e65ad6446 (patch) | |
| tree | e5ab1634fb88ec5455d13ec0b7fe72799fcd1087 | |
| parent | 0a53b6c221de04d5068cc8ef73c072aa6b573240 (diff) | |
Implement translation animation
This is missing animateHeaderSlidingOut
Test: manual
Bug: 373382675
Flag: com.android.systemui.qs_ui_refactor_compose_fragment
Change-Id: I0064c6a465105e3e7f77d8013475177512a0d950
2 files changed, 93 insertions, 20 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt index 3ea11026706d..f4d91627fdab 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt @@ -45,6 +45,7 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable @@ -59,6 +60,7 @@ import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier import androidx.compose.ui.layout.approachLayout import androidx.compose.ui.layout.onPlaced +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.positionInRoot import androidx.compose.ui.platform.ComposeView import androidx.compose.ui.res.dimensionResource @@ -66,7 +68,9 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.semantics.CustomAccessibilityAction import androidx.compose.ui.semantics.customActions import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.unit.IntOffset import androidx.compose.ui.unit.round +import androidx.compose.ui.util.fastRoundToInt import androidx.lifecycle.Lifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.lifecycleScope @@ -144,9 +148,6 @@ constructor( private lateinit var viewModel: QSFragmentComposeViewModel - // Starting with a non-zero value makes it so that it has a non-zero height on first expansion - // This is important for `QuickSettingsControllerImpl.mMinExpansionHeight` to detect a "change". - private val qqsHeight = MutableStateFlow(1) private val qsHeight = MutableStateFlow(0) private val qqsVisible = MutableStateFlow(false) private val qqsPositionOnRoot = Rect() @@ -235,11 +236,15 @@ constructor( AnimatedVisibility( visible = viewModel.isQsVisible, modifier = - Modifier.windowInsetsPadding(WindowInsets.navigationBars).thenIf( - notificationScrimClippingParams.isEnabled - ) { - Modifier.notificationScrimClip { notificationScrimClippingParams.params } - }, + Modifier.windowInsetsPadding(WindowInsets.navigationBars) + .thenIf(notificationScrimClippingParams.isEnabled) { + Modifier.notificationScrimClip { + notificationScrimClippingParams.params + } + } + .offset { + IntOffset(x = 0, y = viewModel.viewTranslationY.fastRoundToInt()) + }, ) { val isEditing by viewModel.containerViewModel.editModeViewModel.isEditing @@ -317,7 +322,7 @@ constructor( override fun getQsMinExpansionHeight(): Int { // TODO (b/353253277) implement split screen - return qqsHeight.value + return viewModel.qqsHeight } override fun getDesiredHeight(): Int { @@ -383,8 +388,7 @@ constructor( viewModel.setQsExpansionValue(qsExpansionFraction) viewModel.panelExpansionFraction = panelExpansionFraction viewModel.squishinessFraction = squishinessFraction - - // TODO(b/353254353) Handle header translation + viewModel.proposedTranslation = headerTranslation } override fun setHeaderListening(listening: Boolean) { @@ -404,7 +408,7 @@ constructor( } override fun getHeightDiff(): Int { - return 0 // For now TODO(b/353254353) + return viewModel.heightDiff } override fun getHeader(): View? { @@ -466,7 +470,7 @@ constructor( } override fun setOverScrollAmount(overScrollAmount: Int) { - super.setOverScrollAmount(overScrollAmount) + viewModel.overScrollAmount = overScrollAmount } override fun setIsNotificationPanelFullWidth(isFullWidth: Boolean) { @@ -525,7 +529,7 @@ constructor( @Composable private fun SceneScope.QuickQuickSettingsElement() { val qqsPadding = viewModel.qqsHeaderHeight - val bottomPadding = dimensionResource(id = R.dimen.qqs_layout_padding_bottom) + val bottomPadding = viewModel.qqsBottomPadding DisposableEffect(Unit) { qqsVisible.value = true @@ -555,11 +559,11 @@ constructor( .approachLayout(isMeasurementApproachInProgress = { squishiness < 1f }) { measurable, constraints -> - qqsHeight.value = lookaheadSize.height + viewModel.qqsHeight = lookaheadSize.height val placeable = measurable.measure(constraints) layout(placeable.width, placeable.height) { placeable.place(0, 0) } } - .padding(top = { qqsPadding }, bottom = { bottomPadding.roundToPx() }) + .padding(top = { qqsPadding }, bottom = { bottomPadding }) ) { if (viewModel.isQsEnabled) { QuickQuickSettings( @@ -602,7 +606,17 @@ constructor( onDispose { lifecycleScope.launch { scrollState.scrollTo(0) } } } - Column(modifier = Modifier.verticalScroll(scrollState)) { + Column( + modifier = + Modifier.offset { + IntOffset( + x = 0, + y = viewModel.qsScrollTranslationY.fastRoundToInt(), + ) + } + .onSizeChanged { viewModel.qsScrollHeight = it.height } + .verticalScroll(scrollState) + ) { Spacer( modifier = Modifier.height { qqsPadding + qsExtraPadding.roundToPx() } ) diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt index 408ea5243f7b..dd83fc928dad 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/viewmodel/QSFragmentComposeViewModel.kt @@ -38,6 +38,7 @@ import com.android.systemui.qs.footer.ui.viewmodel.FooterActionsViewModel import com.android.systemui.qs.panels.domain.interactor.TileSquishinessInteractor import com.android.systemui.qs.panels.ui.viewmodel.PaginatedGridViewModel import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel +import com.android.systemui.res.R import com.android.systemui.shade.LargeScreenHeaderHelper import com.android.systemui.shade.transition.LargeScreenShadeInterpolator import com.android.systemui.statusbar.StatusBarState @@ -123,8 +124,26 @@ constructor( }, ) + val qqsBottomPadding by + hydrator.hydratedStateOf( + traceName = "qqsBottomPadding", + initialValue = resources.getDimensionPixelSize(R.dimen.qqs_layout_padding_bottom), + source = configurationInteractor.dimensionPixelSize(R.dimen.qqs_layout_padding_bottom), + ) + + // Starting with a non-zero value makes it so that it has a non-zero height on first expansion + // This is important for `QuickSettingsControllerImpl.mMinExpansionHeight` to detect a "change". + var qqsHeight by mutableStateOf(1) + + var qsScrollHeight by mutableStateOf(0) + + val heightDiff: Int + get() = qsScrollHeight - qqsHeight + qqsBottomPadding + var isStackScrollerOverscrolling by mutableStateOf(false) + var proposedTranslation by mutableStateOf(0f) + /** * Whether QS is enabled by policy. This is normally true, except when it's disabled by some * policy. See [DisableFlagsRepository]. @@ -165,6 +184,25 @@ constructor( val inFirstPage: Boolean get() = paginatedGridViewModel.inFirstPage + var overScrollAmount by mutableStateOf(0) + + val viewTranslationY by derivedStateOf { + if (isOverscrolling) { + overScrollAmount.toFloat() + } else { + if (onKeyguardAndExpanded) { + translationScaleY * qqsHeight + } else { + headerTranslation + } + } + } + + val qsScrollTranslationY by derivedStateOf { + val panelTranslationY = translationScaleY * heightDiff + if (onKeyguardAndExpanded) panelTranslationY else 0f + } + private var qsBounds by mutableStateOf(Rect()) private val constrainedSquishinessFraction: Float @@ -209,8 +247,6 @@ constructor( private var viewHeight by mutableStateOf(0) - private var headerTranslation by mutableStateOf(0f) - private val isBypassEnabled by hydrator.hydratedStateOf( traceName = "isBypassEnabled", @@ -221,7 +257,11 @@ constructor( isBypassEnabled || (isTransitioningToFullShade && !isInSplitShade) } - private var overscrolling = mutableStateOf(false) + private val onKeyguardAndExpanded: Boolean + get() = isKeyguardState && !showCollapsedOnKeyguard + + private val isOverscrolling: Boolean + get() = overScrollAmount != 0 private var shouldUpdateMediaSquishiness by mutableStateOf(false) @@ -230,6 +270,13 @@ constructor( (isKeyguardState && !showCollapsedOnKeyguard) } + private val translationScaleY: Float + get() = (qsExpansion - 1) * (if (isInSplitShade) 1f else SHORT_PARALLAX_AMOUNT) + + private val headerTranslation by derivedStateOf { + if (isTransitioningToFullShade) 0f else proposedTranslation + } + override suspend fun onActivated(): Nothing { coroutineScope { launch { hydrateSquishinessInteractor() } @@ -255,8 +302,15 @@ constructor( println("qsExpansion", qsExpansion) println("panelExpansionFraction", panelExpansionFraction) println("squishinessFraction", squishinessFraction) + println("proposedTranslation", proposedTranslation) println("expansionState", expansionState) println("forceQS", forceQs) + printSection("Derived values") { + println("headerTranslation", headerTranslation) + println("translationScaleY", translationScaleY) + println("viewTranslationY", viewTranslationY) + println("qsScrollTranslationY", qsScrollTranslationY) + } } printSection("Shade state") { println("stackOverscrolling", isStackScrollerOverscrolling) @@ -265,8 +319,11 @@ constructor( println("isSmallScreen", isSmallScreen) println("heightOverride", "${heightOverride}px") println("qqsHeaderHeight", "${qqsHeaderHeight}px") + println("qqsBottomPadding", "${qqsBottomPadding}px") println("isSplitShade", isInSplitShade) println("showCollapsedOnKeyguard", showCollapsedOnKeyguard) + println("qqsHeight", "${qqsHeight}px") + println("qsScrollHeight", "${qsScrollHeight}px") } } } @@ -283,3 +340,5 @@ constructor( private fun Float.constrainSquishiness(): Float { return (0.1f + this * 0.9f).coerceIn(0f, 1f) } + +private val SHORT_PARALLAX_AMOUNT = 0.1f |