/* * Copyright (C) 2024 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 com.android.systemui.volume.dialog.sliders.ui import android.view.View import androidx.dynamicanimation.animation.FloatValueHolder import androidx.dynamicanimation.animation.SpringAnimation import androidx.dynamicanimation.animation.SpringForce import com.android.app.tracing.coroutines.launchInTraced import com.android.systemui.volume.dialog.domain.interactor.DesktopAudioTileDetailsFeatureInteractor import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderScope import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogOverscrollViewModel.OverscrollEventModel import javax.inject.Inject import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.onEach @VolumeDialogSliderScope class VolumeDialogOverscrollViewBinder @Inject constructor( private val viewModel: VolumeDialogOverscrollViewModel, desktopAudioTileDetailsFeatureInteractor: DesktopAudioTileDetailsFeatureInteractor, ) { // Use horizontal volume dialog if the audio tile details view is enabled private val isVolumeDialogVertical = !desktopAudioTileDetailsFeatureInteractor.isEnabled() /** * [viewsToAnimate] is an array of [View] to be affected by the overscroll animation. [view] is * NOT animated by default. */ fun CoroutineScope.bind(view: View, viewsToAnimate: Array) { val animationValueHolder = FloatValueHolder(0f) val animation: SpringAnimation = SpringAnimation(animationValueHolder) .setSpring( SpringForce(0f).apply { stiffness = 800f dampingRatio = 0.6f } ) .addUpdateListener { _, value, _ -> viewsToAnimate.setTranslation(value, isVolumeDialogVertical) } viewModel.overscrollEvent .onEach { event -> when (event) { is OverscrollEventModel.Animate -> { animation.animateToFinalPosition(event.targetOffsetPx) } is OverscrollEventModel.Move -> { animation.cancel() viewsToAnimate.setTranslation(event.touchOffsetPx, isVolumeDialogVertical) animationValueHolder.value = event.touchOffsetPx } } } .launchInTraced("VDOVB#overscrollEvent", this) } } private fun Array.setTranslation(translation: Float, isVertical: Boolean) { for (viewToAnimate in this) { if (isVertical) { viewToAnimate.translationY = translation } else { viewToAnimate.translationX = translation } } }