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 */ 17 18 package com.android.systemui.statusbar.notification.stack.domain.interactor 19 20 import com.android.systemui.dagger.SysUISingleton 21 import com.android.systemui.shade.domain.interactor.ShadeInteractor 22 import com.android.systemui.shade.shared.model.ShadeMode 23 import com.android.systemui.statusbar.notification.stack.data.repository.NotificationPlaceholderRepository 24 import com.android.systemui.statusbar.notification.stack.data.repository.NotificationViewHeightRepository 25 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds 26 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding 27 import javax.inject.Inject 28 import kotlinx.coroutines.flow.Flow 29 import kotlinx.coroutines.flow.StateFlow 30 import kotlinx.coroutines.flow.asStateFlow 31 import kotlinx.coroutines.flow.combine 32 import kotlinx.coroutines.flow.distinctUntilChanged 33 import kotlinx.coroutines.flow.flowOf 34 35 /** An interactor which controls the appearance of the NSSL */ 36 @SysUISingleton 37 class NotificationStackAppearanceInteractor 38 @Inject 39 constructor( 40 private val viewHeightRepository: NotificationViewHeightRepository, 41 private val placeholderRepository: NotificationPlaceholderRepository, 42 shadeInteractor: ShadeInteractor, 43 ) { 44 /** The bounds of the notification stack in the current scene. */ 45 val shadeScrimBounds: StateFlow<ShadeScrimBounds?> = 46 placeholderRepository.shadeScrimBounds.asStateFlow() 47 48 /** 49 * Whether the stack is expanding from GONE-with-HUN to SHADE 50 * 51 * TODO(b/296118689): implement this to match legacy QSController logic 52 */ 53 private val isExpandingFromHeadsUp: Flow<Boolean> = flowOf(false) 54 55 /** The rounding of the notification stack. */ 56 val shadeScrimRounding: Flow<ShadeScrimRounding> = 57 combine( 58 shadeInteractor.shadeMode, 59 isExpandingFromHeadsUp, 60 ) { shadeMode, isExpandingFromHeadsUp -> 61 ShadeScrimRounding( 62 isTopRounded = !(shadeMode == ShadeMode.Split && isExpandingFromHeadsUp), 63 isBottomRounded = shadeMode != ShadeMode.Single, 64 ) 65 } 66 .distinctUntilChanged() 67 68 /** The alpha of the Notification Stack for the brightness mirror */ 69 val alphaForBrightnessMirror: StateFlow<Float> = 70 placeholderRepository.alphaForBrightnessMirror.asStateFlow() 71 72 /** The height of the keyguard's available space bounds */ 73 val constrainedAvailableSpace: StateFlow<Int> = 74 placeholderRepository.constrainedAvailableSpace.asStateFlow() 75 76 /** 77 * Whether the notification stack is scrolled to the top; i.e., it cannot be scrolled down any 78 * further. 79 */ 80 val scrolledToTop: StateFlow<Boolean> = placeholderRepository.scrolledToTop.asStateFlow() 81 82 /** 83 * The amount in px that the notification stack should scroll due to internal expansion. This 84 * should only happen when a notification expansion hits the bottom of the screen, so it is 85 * necessary to scroll up to keep expanding the notification. 86 */ 87 val syntheticScroll: Flow<Float> = viewHeightRepository.syntheticScroll.asStateFlow() 88 89 /** 90 * Whether the current touch gesture is overscroll. If true, it means the NSSL has already 91 * consumed part of the gesture. 92 */ 93 val isCurrentGestureOverscroll: Flow<Boolean> = 94 viewHeightRepository.isCurrentGestureOverscroll.asStateFlow() 95 96 /** Sets the alpha to apply to the NSSL for the brightness mirror */ 97 fun setAlphaForBrightnessMirror(alpha: Float) { 98 placeholderRepository.alphaForBrightnessMirror.value = alpha 99 } 100 101 /** Sets the position of the notification stack in the current scene. */ 102 fun setShadeScrimBounds(bounds: ShadeScrimBounds?) { 103 check(bounds == null || bounds.top <= bounds.bottom) { "Invalid bounds: $bounds" } 104 placeholderRepository.shadeScrimBounds.value = bounds 105 } 106 107 /** Sets whether the notification stack is scrolled to the top. */ 108 fun setScrolledToTop(scrolledToTop: Boolean) { 109 placeholderRepository.scrolledToTop.value = scrolledToTop 110 } 111 112 /** Sets the amount (px) that the notification stack should scroll due to internal expansion. */ 113 fun setSyntheticScroll(delta: Float) { 114 viewHeightRepository.syntheticScroll.value = delta 115 } 116 117 /** Sets whether the current touch gesture is overscroll. */ 118 fun setCurrentGestureOverscroll(isOverscroll: Boolean) { 119 viewHeightRepository.isCurrentGestureOverscroll.value = isOverscroll 120 } 121 122 fun setConstrainedAvailableSpace(height: Int) { 123 placeholderRepository.constrainedAvailableSpace.value = height 124 } 125 } 126