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.Context
20 import com.android.systemui.dagger.SysUISingleton
21 import com.android.systemui.dagger.qualifiers.Application
22 import com.android.systemui.keyguard.domain.interactor.KeyguardSmartspaceInteractor
23 import com.android.systemui.res.R
24 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController
25 import javax.inject.Inject
26 import kotlinx.coroutines.CoroutineScope
27 import kotlinx.coroutines.flow.SharingStarted
28 import kotlinx.coroutines.flow.StateFlow
29 import kotlinx.coroutines.flow.combine
30 import kotlinx.coroutines.flow.map
31 import kotlinx.coroutines.flow.stateIn
32 
33 @SysUISingleton
34 class KeyguardSmartspaceViewModel
35 @Inject
36 constructor(
37     @Application applicationScope: CoroutineScope,
38     smartspaceController: LockscreenSmartspaceController,
39     keyguardClockViewModel: KeyguardClockViewModel,
40     smartspaceInteractor: KeyguardSmartspaceInteractor,
41 ) {
42     /** Whether the smartspace section is available in the build. */
43     val isSmartspaceEnabled: Boolean = smartspaceController.isEnabled()
44     /** Whether the weather area is available in the build. */
45     private val isWeatherEnabled: StateFlow<Boolean> = smartspaceInteractor.isWeatherEnabled
46 
47     /** Whether the data and weather areas are decoupled in the build. */
48     val isDateWeatherDecoupled: Boolean = smartspaceController.isDateWeatherDecoupled()
49 
50     /** Whether the date area should be visible. */
51     val isDateVisible: StateFlow<Boolean> =
52         keyguardClockViewModel.hasCustomWeatherDataDisplay
53             .map { !it }
54             .stateIn(
55                 scope = applicationScope,
56                 started = SharingStarted.WhileSubscribed(),
57                 initialValue = !keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
58             )
59 
60     /** Whether the weather area should be visible. */
61     val isWeatherVisible: StateFlow<Boolean> =
62         combine(
63                 isWeatherEnabled,
64                 keyguardClockViewModel.hasCustomWeatherDataDisplay,
65             ) { isWeatherEnabled, clockIncludesCustomWeatherDisplay ->
66                 isWeatherVisible(
67                     clockIncludesCustomWeatherDisplay = clockIncludesCustomWeatherDisplay,
68                     isWeatherEnabled = isWeatherEnabled,
69                 )
70             }
71             .stateIn(
72                 scope = applicationScope,
73                 started = SharingStarted.WhileSubscribed(),
74                 initialValue =
75                     isWeatherVisible(
76                         clockIncludesCustomWeatherDisplay =
77                             keyguardClockViewModel.hasCustomWeatherDataDisplay.value,
78                         isWeatherEnabled = smartspaceInteractor.isWeatherEnabled.value,
79                     )
80             )
81 
82     private fun isWeatherVisible(
83         clockIncludesCustomWeatherDisplay: Boolean,
84         isWeatherEnabled: Boolean,
85     ): Boolean {
86         return !clockIncludesCustomWeatherDisplay && isWeatherEnabled
87     }
88 
89     /* trigger clock and smartspace constraints change when smartspace appears */
90     val bcSmartspaceVisibility: StateFlow<Int> = smartspaceInteractor.bcSmartspaceVisibility
91 
92     companion object {
93         fun getSmartspaceStartMargin(context: Context): Int {
94             return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_start) +
95                 context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
96         }
97 
98         fun getSmartspaceEndMargin(context: Context): Int {
99             return context.resources.getDimensionPixelSize(R.dimen.below_clock_padding_end) +
100                 context.resources.getDimensionPixelSize(R.dimen.status_view_margin_horizontal)
101         }
102     }
103 }
104