• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.customization.picker.clock.ui.viewmodel
17 
18 import com.android.customization.picker.clock.domain.interactor.ClockPickerInteractor
19 import kotlinx.coroutines.ExperimentalCoroutinesApi
20 import kotlinx.coroutines.delay
21 import kotlinx.coroutines.flow.Flow
22 import kotlinx.coroutines.flow.MutableStateFlow
23 import kotlinx.coroutines.flow.combine
24 import kotlinx.coroutines.flow.distinctUntilChanged
25 import kotlinx.coroutines.flow.flatMapLatest
26 import kotlinx.coroutines.flow.map
27 import kotlinx.coroutines.flow.mapLatest
28 import kotlinx.coroutines.flow.mapNotNull
29 
30 /**
31  * Clock carousel view model that provides data for the carousel of clock previews. When there is
32  * only one item, we should show a single clock preview instead of a carousel.
33  */
34 class ClockCarouselViewModel(
35     private val interactor: ClockPickerInteractor,
36 ) {
37     @OptIn(ExperimentalCoroutinesApi::class)
38     val allClockIds: Flow<List<String>> =
39         interactor.allClocks.mapLatest { allClocks ->
40             // Delay to avoid the case that the full list of clocks is not initiated.
41             delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
42             allClocks.map { it.clockId }
43         }
44 
45     val seedColor: Flow<Int?> = interactor.seedColor
46 
47     private val shouldShowCarousel = MutableStateFlow(false)
48     val isCarouselVisible: Flow<Boolean> =
49         combine(allClockIds.map { it.size > 1 }.distinctUntilChanged(), shouldShowCarousel) {
50                 hasMoreThanOneClock,
51                 shouldShowCarousel ->
52                 hasMoreThanOneClock && shouldShowCarousel
53             }
54             .distinctUntilChanged()
55 
56     @OptIn(ExperimentalCoroutinesApi::class)
57     val selectedIndex: Flow<Int> =
58         allClockIds
59             .flatMapLatest { allClockIds ->
60                 interactor.selectedClockId.map { selectedClockId ->
61                     val index = allClockIds.indexOf(selectedClockId)
62                     if (index >= 0) {
63                         index
64                     } else {
65                         null
66                     }
67                 }
68             }
69             .mapNotNull { it }
70 
71     // Handle the case when there is only one clock in the carousel
72     private val shouldShowSingleClock = MutableStateFlow(false)
73     val isSingleClockViewVisible: Flow<Boolean> =
74         combine(allClockIds.map { it.size == 1 }.distinctUntilChanged(), shouldShowSingleClock) {
75                 hasOneClock,
76                 shouldShowSingleClock ->
77                 hasOneClock && shouldShowSingleClock
78             }
79             .distinctUntilChanged()
80 
81     val clockId: Flow<String> =
82         allClockIds
83             .map { allClockIds -> if (allClockIds.size == 1) allClockIds[0] else null }
84             .mapNotNull { it }
85 
86     fun setSelectedClock(clockId: String) {
87         interactor.setSelectedClock(clockId)
88     }
89 
90     fun showClockCarousel(shouldShow: Boolean) {
91         shouldShowCarousel.value = shouldShow
92         shouldShowSingleClock.value = shouldShow
93     }
94 
95     companion object {
96         const val CLOCKS_EVENT_UPDATE_DELAY_MILLIS: Long = 100
97     }
98 }
99