diff options
| author | George Zacharia <george.zcharia@gmail.com> | 2023-07-02 14:33:47 +0530 |
|---|---|---|
| committer | George Zacharia <george.zcharia@gmail.com> | 2023-07-02 14:33:47 +0530 |
| commit | 913b11dfd2b52e445c773838c766f0d4f8ba0d05 (patch) | |
| tree | adb07f584833593bad6fca5495927c276ceef531 /src/com/android/customization/picker/clock/ui/binder | |
| parent | b2d9a4961b3804f79c151630421d480846fd0176 (diff) | |
| parent | cc6f666d7c0bc3b6927f6e9e3c7e46123be6263d (diff) | |
Merge tag 'android-13.0.0_r52' of https://android.googlesource.com/platform/packages/apps/ThemePicker into HEADHEADt13.0
Android 13.0.0 Release 52 (TQ3A.230605.012)
Change-Id: I2cea11fa2f1f02fbd3c9d21cfc1697a79d42a5b7
Diffstat (limited to 'src/com/android/customization/picker/clock/ui/binder')
3 files changed, 344 insertions, 0 deletions
diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt new file mode 100644 index 00000000..9ad735d3 --- /dev/null +++ b/src/com/android/customization/picker/clock/ui/binder/ClockCarouselViewBinder.kt @@ -0,0 +1,110 @@ +/* + * 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. + */ +package com.android.customization.picker.clock.ui.binder + +import android.view.ViewGroup +import android.widget.FrameLayout +import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.customization.picker.clock.ui.view.ClockCarouselView +import com.android.customization.picker.clock.ui.view.ClockViewFactory +import com.android.customization.picker.clock.ui.viewmodel.ClockCarouselViewModel +import com.android.wallpaper.R +import kotlinx.coroutines.launch + +object ClockCarouselViewBinder { + /** + * The binding is used by the view where there is an action executed from another view, e.g. + * toggling show/hide of the view that the binder is holding. + */ + interface Binding { + fun show() + fun hide() + } + + @JvmStatic + fun bind( + carouselView: ClockCarouselView, + singleClockView: ViewGroup, + viewModel: ClockCarouselViewModel, + clockViewFactory: ClockViewFactory, + 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 { carouselView.isVisible = it } } + + launch { + viewModel.allClockIds.collect { allClockIds -> + carouselView.setUpClockCarouselView( + clockIds = allClockIds, + onGetClockPreview = { clockId -> clockViewFactory.getView(clockId) }, + onClockSelected = { clockId -> viewModel.setSelectedClock(clockId) }, + ) + } + } + + launch { + viewModel.selectedIndex.collect { selectedIndex -> + carouselView.setSelectedClockIndex(selectedIndex) + } + } + + launch { + viewModel.seedColor.collect { clockViewFactory.updateColorForAllClocks(it) } + } + + launch { + viewModel.isSingleClockViewVisible.collect { singleClockView.isVisible = it } + } + + launch { + viewModel.clockId.collect { clockId -> + singleClockHostView.removeAllViews() + val clockView = clockViewFactory.getView(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) + } + } + } + } + + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { + clockViewFactory.registerTimeTicker() + } + // When paused + clockViewFactory.unregisterTimeTicker() + } + + return object : Binding { + override fun show() { + viewModel.showClockCarousel(true) + } + + override fun hide() { + viewModel.showClockCarousel(false) + } + } + } +} diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt new file mode 100644 index 00000000..7dc0d0c4 --- /dev/null +++ b/src/com/android/customization/picker/clock/ui/binder/ClockSectionViewBinder.kt @@ -0,0 +1,53 @@ +/* + * 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. + * + */ + +package com.android.customization.picker.clock.ui.binder + +import android.view.View +import android.widget.TextView +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import com.android.customization.picker.clock.ui.viewmodel.ClockSectionViewModel +import com.android.wallpaper.R +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch + +object ClockSectionViewBinder { + fun bind( + view: View, + viewModel: ClockSectionViewModel, + lifecycleOwner: LifecycleOwner, + onClicked: () -> Unit, + ) { + view.setOnClickListener { onClicked() } + + val selectedClockColorAndSize: TextView = + view.requireViewById(R.id.selected_clock_color_and_size) + + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.selectedClockColorAndSizeText.collectLatest { + selectedClockColorAndSize.text = it + } + } + } + } + } +} diff --git a/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt new file mode 100644 index 00000000..66d92513 --- /dev/null +++ b/src/com/android/customization/picker/clock/ui/binder/ClockSettingsBinder.kt @@ -0,0 +1,181 @@ +/* + * 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. + */ +package com.android.customization.picker.clock.ui.binder + +import android.view.View +import android.view.ViewGroup +import android.widget.FrameLayout +import android.widget.SeekBar +import androidx.core.view.isInvisible +import androidx.core.view.isVisible +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView +import com.android.customization.picker.clock.shared.ClockSize +import com.android.customization.picker.clock.ui.adapter.ClockSettingsTabAdapter +import com.android.customization.picker.clock.ui.view.ClockSizeRadioButtonGroup +import com.android.customization.picker.clock.ui.view.ClockViewFactory +import com.android.customization.picker.clock.ui.viewmodel.ClockSettingsViewModel +import com.android.customization.picker.color.ui.adapter.ColorOptionAdapter +import com.android.customization.picker.common.ui.view.ItemSpacing +import com.android.wallpaper.R +import kotlinx.coroutines.flow.mapNotNull +import kotlinx.coroutines.launch + +/** Bind between the clock settings screen and its view model. */ +object ClockSettingsBinder { + fun bind( + view: View, + viewModel: ClockSettingsViewModel, + clockViewFactory: ClockViewFactory, + lifecycleOwner: LifecycleOwner, + ) { + val clockHostView: FrameLayout = view.requireViewById(R.id.clock_host_view) + + val tabView: RecyclerView = view.requireViewById(R.id.tabs) + val tabAdapter = ClockSettingsTabAdapter() + tabView.adapter = tabAdapter + tabView.layoutManager = LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false) + tabView.addItemDecoration(ItemSpacing(ItemSpacing.TAB_ITEM_SPACING_DP)) + + val colorOptionContainerView: RecyclerView = view.requireViewById(R.id.color_options) + val colorOptionAdapter = ColorOptionAdapter() + colorOptionContainerView.adapter = colorOptionAdapter + colorOptionContainerView.layoutManager = + LinearLayoutManager(view.context, RecyclerView.HORIZONTAL, false) + colorOptionContainerView.addItemDecoration(ItemSpacing(ItemSpacing.ITEM_SPACING_DP)) + + val slider: SeekBar = view.requireViewById(R.id.slider) + slider.setOnSeekBarChangeListener( + object : SeekBar.OnSeekBarChangeListener { + override fun onProgressChanged(p0: SeekBar?, progress: Int, fromUser: Boolean) { + if (fromUser) { + viewModel.onSliderProgressChanged(progress) + } + } + + override fun onStartTrackingTouch(seekBar: SeekBar?) = Unit + override fun onStopTrackingTouch(seekBar: SeekBar?) { + seekBar?.progress?.let { viewModel.onSliderProgressStop(it) } + } + } + ) + + val sizeOptions = + view.requireViewById<ClockSizeRadioButtonGroup>(R.id.clock_size_radio_button_group) + sizeOptions.onRadioButtonClickListener = + object : ClockSizeRadioButtonGroup.OnRadioButtonClickListener { + override fun onClick(size: ClockSize) { + viewModel.setClockSize(size) + } + } + + val colorOptionContainer = view.requireViewById<View>(R.id.color_picker_container) + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { + launch { + viewModel.selectedClockId + .mapNotNull { it } + .collect { clockId -> + val clockView = clockViewFactory.getView(clockId) + (clockView.parent as? ViewGroup)?.removeView(clockView) + clockHostView.removeAllViews() + clockHostView.addView(clockView) + } + } + + launch { + viewModel.seedColor.collect { seedColor -> + viewModel.selectedClockId.value?.let { selectedClockId -> + clockViewFactory.updateColor(selectedClockId, seedColor) + } + } + } + + launch { viewModel.tabs.collect { tabAdapter.setItems(it) } } + + launch { + viewModel.selectedTab.collect { tab -> + when (tab) { + ClockSettingsViewModel.Tab.COLOR -> { + colorOptionContainer.isVisible = true + sizeOptions.isInvisible = true + } + ClockSettingsViewModel.Tab.SIZE -> { + colorOptionContainer.isInvisible = true + sizeOptions.isVisible = true + } + } + } + } + + launch { + viewModel.colorOptions.collect { colorOptions -> + colorOptionAdapter.setItems(colorOptions) + } + } + + launch { + viewModel.selectedColorOptionPosition.collect { selectedPosition -> + if (selectedPosition != -1) { + // We use "post" because we need to give the adapter item a pass to + // update the view. + colorOptionContainerView.post { + colorOptionContainerView.smoothScrollToPosition(selectedPosition) + } + } + } + } + + launch { + viewModel.selectedClockSize.collect { size -> + when (size) { + ClockSize.DYNAMIC -> { + sizeOptions.radioButtonDynamic.isChecked = true + sizeOptions.radioButtonSmall.isChecked = false + } + ClockSize.SMALL -> { + sizeOptions.radioButtonDynamic.isChecked = false + sizeOptions.radioButtonSmall.isChecked = true + } + } + } + } + + launch { + viewModel.sliderProgress.collect { progress -> + slider.setProgress(progress, true) + } + } + + launch { + viewModel.isSliderEnabled.collect { isEnabled -> slider.isEnabled = isEnabled } + } + } + } + + lifecycleOwner.lifecycleScope.launch { + lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) { + clockViewFactory.registerTimeTicker() + } + // When paused + clockViewFactory.unregisterTimeTicker() + } + } +} |
