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 package com.android.systemui.keyguard.ui.viewmodel
18 
19 import android.content.res.Resources
20 import com.android.internal.annotations.VisibleForTesting
21 import com.android.systemui.biometrics.AuthController
22 import com.android.systemui.dagger.SysUISingleton
23 import com.android.systemui.dagger.qualifiers.Application
24 import com.android.systemui.keyguard.domain.interactor.KeyguardBlueprintInteractor
25 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
26 import com.android.systemui.keyguard.shared.model.ClockSize
27 import com.android.systemui.res.R
28 import com.android.systemui.shade.domain.interactor.ShadeInteractor
29 import com.android.systemui.shade.shared.model.ShadeMode
30 import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor
31 import javax.inject.Inject
32 import kotlinx.coroutines.CoroutineScope
33 import kotlinx.coroutines.flow.SharingStarted
34 import kotlinx.coroutines.flow.StateFlow
35 import kotlinx.coroutines.flow.combine
36 import kotlinx.coroutines.flow.distinctUntilChanged
37 import kotlinx.coroutines.flow.map
38 import kotlinx.coroutines.flow.stateIn
39 
40 @SysUISingleton
41 class LockscreenContentViewModel
42 @Inject
43 constructor(
44     clockInteractor: KeyguardClockInteractor,
45     private val interactor: KeyguardBlueprintInteractor,
46     private val authController: AuthController,
47     val longPress: KeyguardLongPressViewModel,
48     val shadeInteractor: ShadeInteractor,
49     @Application private val applicationScope: CoroutineScope,
50     unfoldTransitionInteractor: UnfoldTransitionInteractor,
51 ) {
52     @VisibleForTesting val clockSize = clockInteractor.clockSize
53 
54     val isUdfpsVisible: Boolean
55         get() = authController.isUdfpsSupported
56 
57     val shouldUseSplitNotificationShade: StateFlow<Boolean> =
58         shadeInteractor.shadeMode
59             .map { it == ShadeMode.Split }
60             .stateIn(
61                 scope = applicationScope,
62                 started = SharingStarted.WhileSubscribed(),
63                 initialValue = false,
64             )
65 
66     val areNotificationsVisible: StateFlow<Boolean> =
67         combine(
68                 clockSize,
69                 shouldUseSplitNotificationShade,
70             ) { clockSize, shouldUseSplitNotificationShade ->
71                 clockSize == ClockSize.SMALL || shouldUseSplitNotificationShade
72             }
73             .stateIn(
74                 scope = applicationScope,
75                 started = SharingStarted.WhileSubscribed(),
76                 initialValue = false,
77             )
78 
79     /** Amount of horizontal translation that should be applied to elements in the scene. */
80     val unfoldTranslations: StateFlow<UnfoldTranslations> =
81         combine(
82                 unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = true),
83                 unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = false),
84             ) { start, end ->
85                 UnfoldTranslations(
86                     start = start,
87                     end = end,
88                 )
89             }
90             .stateIn(
91                 scope = applicationScope,
92                 started = SharingStarted.WhileSubscribed(),
93                 initialValue = UnfoldTranslations(),
94             )
95 
96     fun getSmartSpacePaddingTop(resources: Resources): Int {
97         return if (clockSize.value == ClockSize.LARGE) {
98             resources.getDimensionPixelSize(R.dimen.keyguard_smartspace_top_offset) +
99                 resources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin)
100         } else {
101             0
102         }
103     }
104 
105     fun blueprintId(scope: CoroutineScope): StateFlow<String> {
106         return interactor.blueprint
107             .map { it.id }
108             .distinctUntilChanged()
109             .stateIn(
110                 scope = scope,
111                 started = SharingStarted.WhileSubscribed(),
112                 initialValue = interactor.getCurrentBlueprint().id,
113             )
114     }
115 
116     data class UnfoldTranslations(
117 
118         /**
119          * Amount of horizontal translation to apply to elements that are aligned to the start side
120          * (left in left-to-right layouts). Can also be used as horizontal padding for elements that
121          * need horizontal padding on both side. In pixels.
122          */
123         val start: Float = 0f,
124 
125         /**
126          * Amount of horizontal translation to apply to elements that are aligned to the end side
127          * (right in left-to-right layouts). In pixels.
128          */
129         val end: Float = 0f,
130     )
131 }
132