1 /* <lambda>null2 * Copyright (C) 2023 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 package com.android.systemui.unfold.domain.interactor 17 18 import android.view.View 19 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.res.R 22 import com.android.systemui.shade.ShadeDisplayAware 23 import com.android.systemui.unfold.data.repository.UnfoldTransitionRepository 24 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus 25 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionFinished 26 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionInProgress 27 import com.android.systemui.unfold.data.repository.UnfoldTransitionStatus.TransitionStarted 28 import javax.inject.Inject 29 import kotlinx.coroutines.flow.Flow 30 import kotlinx.coroutines.flow.combine 31 import kotlinx.coroutines.flow.distinctUntilChanged 32 import kotlinx.coroutines.flow.filter 33 import kotlinx.coroutines.flow.first 34 import kotlinx.coroutines.flow.map 35 import kotlinx.coroutines.flow.onStart 36 37 /** 38 * Contains business-logic related to fold-unfold transitions while interacting with 39 * [UnfoldTransitionRepository] 40 */ 41 @SysUISingleton 42 class UnfoldTransitionInteractor 43 @Inject 44 constructor( 45 private val repository: UnfoldTransitionRepository, 46 @ShadeDisplayAware private val configurationInteractor: ConfigurationInteractor, 47 ) { 48 /** Returns availability of fold/unfold transitions on the device */ 49 val isAvailable: Boolean 50 get() = repository.isAvailable 51 52 /** Flow of latest [UnfoldTransitionStatus] changes */ 53 val unfoldTransitionStatus: Flow<UnfoldTransitionStatus> = repository.transitionStatus 54 55 /** 56 * This mapping emits 1 when the device is completely unfolded and 0.0 when the device is 57 * completely folded. 58 */ 59 private val unfoldProgress: Flow<Float> = 60 repository.transitionStatus 61 .map { (it as? TransitionInProgress)?.progress ?: 1f } 62 .onStart { emit(1f) } 63 .distinctUntilChanged() 64 65 /** 66 * Amount of X-axis translation to apply to various elements as the unfolded foldable is folded 67 * slightly, in pixels. 68 * 69 * @param isOnStartSide Whether the consumer wishes to get a translation amount that's suitable 70 * for an element that's on the start-side (left hand-side in left-to-right layouts); if 71 * `true`, the values will provide positive translations to push the left-hand-side element 72 * towards the foldable hinge; if `false`, the values will be inverted to provide negative 73 * translations to push the right-hand-side element towards the foldable hinge. Note that this 74 * method already accounts for left-to-right vs. right-to-left layout directions. 75 */ 76 fun unfoldTranslationX(isOnStartSide: Boolean): Flow<Float> { 77 return combine( 78 unfoldProgress, 79 configurationInteractor.dimensionPixelSize(R.dimen.notification_side_paddings), 80 configurationInteractor.layoutDirection.map { 81 if (it == View.LAYOUT_DIRECTION_RTL) -1 else 1 82 }, 83 ) { unfoldedAmount, max, layoutDirectionMultiplier -> 84 val sideMultiplier = if (isOnStartSide) 1 else -1 85 max * (1 - unfoldedAmount) * sideMultiplier * layoutDirectionMultiplier 86 } 87 } 88 89 /** Suspends and waits for a fold/unfold transition to finish */ 90 suspend fun waitForTransitionFinish() { 91 repository.transitionStatus.filter { it is TransitionFinished }.first() 92 } 93 94 /** Suspends and waits for a fold/unfold transition to start */ 95 suspend fun waitForTransitionStart() { 96 repository.transitionStatus.filter { it is TransitionStarted }.first() 97 } 98 } 99