Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2351579f authored by George Lin's avatar George Lin
Browse files

[TP] Handle case for single default clock

For the case that the phone only has the single default clock
- Show the single clock on the preview

Test: manually test that the color option is hidden
Bug: 269631245
Change-Id: Iaa62ca98596eba343ec5a7bb30a5d8a5402e8599
parent c8a1c87e
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?><!--
     Copyright (C) 2023 The Android Open Source Project

     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
     You may obtain a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
-->
<com.android.wallpaper.picker.DisplayAspectRatioFrameLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="@dimen/clock_carousel_item_height">
    <FrameLayout
        android:id="@+id/single_clock_host_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center" />
</com.android.wallpaper.picker.DisplayAspectRatioFrameLayout>
 No newline at end of file
+24 −3
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@
package com.android.customization.picker.clock.ui.binder

import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
@@ -23,7 +25,7 @@ import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.customization.picker.clock.ui.view.ClockCarouselView
import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel
import kotlinx.coroutines.flow.collect
import com.android.wallpaper.R
import kotlinx.coroutines.launch

object ClockCarouselViewBinder {
@@ -39,12 +41,17 @@ object ClockCarouselViewBinder {
    @JvmStatic
    fun bind(
        view: ClockCarouselView,
        singleClockView: ViewGroup,
        viewModel: ClockCarouselViewModel,
        clockViewFactory: (clockId: String) -> View,
        lifecycleOwner: LifecycleOwner,
    ): Binding {
        val singleClockHostView =
            singleClockView.requireViewById<FrameLayout>(R.id.single_clock_host_view)
        lifecycleOwner.lifecycleScope.launch {
            lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                launch { viewModel.isCarouselVisible.collect { view.isVisible = it } }

                launch {
                    viewModel.allClockIds.collect { allClockIds ->
                        view.setUpClockCarouselView(
@@ -54,20 +61,34 @@ object ClockCarouselViewBinder {
                        )
                    }
                }

                launch {
                    viewModel.selectedIndex.collect { selectedIndex ->
                        view.setSelectedClockIndex(selectedIndex)
                    }
                }

                launch { viewModel.isSingleClockViewVisible.collect { view.isVisible = it } }

                launch {
                    viewModel.clockId.collect { clockId ->
                        singleClockHostView.removeAllViews()
                        val clockView = clockViewFactory(clockId)
                        // The clock view might still be attached to an existing parent. Detach
                        // before adding to another parent.
                        (clockView.parent as? ViewGroup)?.removeView(clockView)
                        singleClockHostView.addView(clockView)
                    }
                }
            }
        }
        return object : Binding {
            override fun show() {
                view.isVisible = true
                viewModel.showClockCarousel(true)
            }

            override fun hide() {
                view.isVisible = false
                viewModel.showClockCarousel(false)
            }
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -83,7 +83,7 @@ object ClockSettingsBinder {
                launch { viewModel.tabs.collect { tabAdapter.setItems(it) } }

                launch {
                    viewModel.selectedTabPosition.collect { tab ->
                    viewModel.selectedTab.collect { tab ->
                        when (tab) {
                            ClockSettingsViewModel.Tab.COLOR -> {
                                colorOptionContainer.isVisible = true
+38 −3
Original line number Diff line number Diff line
@@ -19,22 +19,37 @@ import com.android.customization.picker.clock.domain.interactor.ClockPickerInter
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.mapLatest
import kotlinx.coroutines.flow.mapNotNull

/**
 * Clock carousel view model that provides data for the carousel of clock previews. When there is
 * only one item, we should show a single clock preview instead of a carousel.
 */
class ClockCarouselViewModel(
    private val interactor: ClockPickerInteractor,
) {

    @OptIn(ExperimentalCoroutinesApi::class)
    val allClockIds: Flow<List<String>> =
        interactor.allClocks.mapLatest { clockArray ->
        interactor.allClocks.mapLatest { allClocks ->
            // Delay to avoid the case that the full list of clocks is not initiated.
            delay(CLOCKS_EVENT_UPDATE_DELAY_MILLIS)
            clockArray.map { it.clockId }
            allClocks.map { it.clockId }
        }

    private val shouldShowCarousel = MutableStateFlow(false)
    val isCarouselVisible: Flow<Boolean> =
        combine(allClockIds.map { it.size > 1 }.distinctUntilChanged(), shouldShowCarousel) {
                hasMoreThanOneClock,
                shouldShowCarousel ->
                hasMoreThanOneClock && shouldShowCarousel
            }
            .distinctUntilChanged()

    @OptIn(ExperimentalCoroutinesApi::class)
    val selectedIndex: Flow<Int> =
@@ -51,10 +66,30 @@ class ClockCarouselViewModel(
            }
            .mapNotNull { it }

    // Handle the case when there is only one clock in the carousel
    private val shouldShowSingleClock = MutableStateFlow(false)
    val isSingleClockViewVisible: Flow<Boolean> =
        combine(allClockIds.map { it.size == 1 }.distinctUntilChanged(), shouldShowSingleClock) {
                hasOneClock,
                shouldShowSingleClock ->
                hasOneClock && shouldShowSingleClock
            }
            .distinctUntilChanged()

    val clockId: Flow<String> =
        allClockIds
            .map { allClockIds -> if (allClockIds.size == 1) allClockIds[0] else null }
            .mapNotNull { it }

    fun setSelectedClock(clockId: String) {
        interactor.setSelectedClock(clockId)
    }

    fun showClockCarousel(shouldShow: Boolean) {
        shouldShowCarousel.value = shouldShow
        shouldShowSingleClock.value = shouldShow
    }

    companion object {
        const val CLOCKS_EVENT_UPDATE_DELAY_MILLIS: Long = 100
    }
+2 −2
Original line number Diff line number Diff line
@@ -194,9 +194,9 @@ private constructor(context: Context, private val interactor: ClockPickerInterac
    }

    private val _selectedTabPosition = MutableStateFlow(Tab.COLOR)
    val selectedTabPosition: StateFlow<Tab> = _selectedTabPosition.asStateFlow()
    val selectedTab: StateFlow<Tab> = _selectedTabPosition.asStateFlow()
    val tabs: Flow<List<ClockSettingsTabViewModel>> =
        selectedTabPosition.map {
        selectedTab.map {
            listOf(
                ClockSettingsTabViewModel(
                    name = context.resources.getString(R.string.clock_color),
Loading