1 /*
2  * 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.communal.ui.viewmodel
18 
19 import android.content.ComponentName
20 import android.os.UserHandle
21 import android.view.View
22 import com.android.compose.animation.scene.ObservableTransitionState
23 import com.android.compose.animation.scene.SceneKey
24 import com.android.compose.animation.scene.TransitionKey
25 import com.android.systemui.communal.domain.interactor.CommunalInteractor
26 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
27 import com.android.systemui.communal.domain.model.CommunalContentModel
28 import com.android.systemui.communal.shared.model.EditModeState
29 import com.android.systemui.communal.widgets.WidgetConfigurator
30 import com.android.systemui.media.controls.ui.view.MediaHost
31 import kotlinx.coroutines.flow.Flow
32 import kotlinx.coroutines.flow.MutableStateFlow
33 import kotlinx.coroutines.flow.StateFlow
34 import kotlinx.coroutines.flow.flowOf
35 
36 /** The base view model for the communal hub. */
37 abstract class BaseCommunalViewModel(
38     val communalSceneInteractor: CommunalSceneInteractor,
39     private val communalInteractor: CommunalInteractor,
40     val mediaHost: MediaHost,
41 ) {
42     val currentScene: Flow<SceneKey> = communalSceneInteractor.currentScene
43 
44     /** Used to animate showing or hiding the communal content. */
45     open val isCommunalContentVisible: Flow<Boolean> = MutableStateFlow(false)
46 
47     /** Whether communal hub should be focused by accessibility tools. */
48     open val isFocusable: Flow<Boolean> = MutableStateFlow(false)
49 
50     /** Whether widgets are currently being re-ordered. */
51     open val reorderingWidgets: StateFlow<Boolean> = MutableStateFlow(false)
52 
53     private val _selectedKey: MutableStateFlow<String?> = MutableStateFlow(null)
54 
55     /** The key of the currently selected item, or null if no item selected. */
56     val selectedKey: StateFlow<String?>
57         get() = _selectedKey
58 
59     /** Accessibility delegate to be set on CommunalAppWidgetHostView. */
60     open val widgetAccessibilityDelegate: View.AccessibilityDelegate? = null
61 
signalUserInteractionnull62     fun signalUserInteraction() {
63         communalInteractor.signalUserInteraction()
64     }
65 
changeScenenull66     fun changeScene(scene: SceneKey, transitionKey: TransitionKey? = null) {
67         communalSceneInteractor.changeScene(scene, transitionKey)
68     }
69 
setEditModeStatenull70     fun setEditModeState(state: EditModeState?) = communalSceneInteractor.setEditModeState(state)
71 
72     /**
73      * Updates the transition state of the hub [SceneTransitionLayout].
74      *
75      * Note that you must call is with `null` when the UI is done or risk a memory leak.
76      */
77     fun setTransitionState(transitionState: Flow<ObservableTransitionState>?) {
78         communalSceneInteractor.setTransitionState(transitionState)
79     }
80 
81     /**
82      * Called when a widget is added via drag and drop from the widget picker into the communal hub.
83      */
onAddWidgetnull84     open fun onAddWidget(
85         componentName: ComponentName,
86         user: UserHandle,
87         priority: Int,
88         configurator: WidgetConfigurator? = null
89     ) {
90         communalInteractor.addWidget(componentName, user, priority, configurator)
91     }
92 
onOpenEnableWidgetDialognull93     open fun onOpenEnableWidgetDialog() {}
94 
onOpenEnableWorkProfileDialognull95     open fun onOpenEnableWorkProfileDialog() {}
96 
97     /** A list of all the communal content to be displayed in the communal hub. */
98     abstract val communalContent: Flow<List<CommunalContentModel>>
99 
100     /**
101      * Whether to freeze the emission of the communalContent flow to prevent recomposition. Defaults
102      * to false, indicating that the flow will emit new update.
103      */
104     open val isCommunalContentFlowFrozen: Flow<Boolean> = flowOf(false)
105 
106     /** Whether in edit mode for the communal hub. */
107     open val isEditMode = false
108 
109     /** Whether the type of popup currently showing */
110     open val currentPopup: Flow<PopupType?> = flowOf(null)
111 
112     /** Whether the communal hub is empty with no widget available. */
113     open val isEmptyState: Flow<Boolean> = flowOf(false)
114 
115     /** Called as the UI request to dismiss the any displaying popup */
onHidePopupnull116     open fun onHidePopup() {}
117 
118     /** Called as the UI requests deleting a widget. */
onDeleteWidgetnull119     open fun onDeleteWidget(id: Int) {}
120 
121     /**
122      * Called as the UI requests reordering widgets.
123      *
124      * @param widgetIdToPriorityMap mapping of the widget ids to its priority. When re-ordering to
125      *   add a new item in the middle, provide the priorities of existing widgets as if the new item
126      *   existed, and then, call [onAddWidget] to add the new item at intended order.
127      */
onReorderWidgetsnull128     open fun onReorderWidgets(widgetIdToPriorityMap: Map<Int, Int>) {}
129 
130     /** Called as the UI requests opening the widget editor with an optional preselected widget. */
onOpenWidgetEditornull131     open fun onOpenWidgetEditor(
132         preselectedKey: String? = null,
133         shouldOpenWidgetPickerOnStart: Boolean = false,
134     ) {}
135 
136     /** Called as the UI requests to dismiss the CTA tile. */
onDismissCtaTilenull137     open fun onDismissCtaTile() {}
138 
139     /** Called as the user starts dragging a widget to reorder. */
onReorderWidgetStartnull140     open fun onReorderWidgetStart() {}
141 
142     /** Called as the user finishes dragging a widget to reorder. */
onReorderWidgetEndnull143     open fun onReorderWidgetEnd() {}
144 
145     /** Called as the user cancels dragging a widget to reorder. */
onReorderWidgetCancelnull146     open fun onReorderWidgetCancel() {}
147 
148     /** Called as the user request to show the customize widget button. */
onShowCustomizeWidgetButtonnull149     open fun onShowCustomizeWidgetButton() {}
150 
151     /** Set the key of the currently selected item */
setSelectedKeynull152     fun setSelectedKey(key: String?) {
153         _selectedKey.value = key
154     }
155 }
156