summaryrefslogtreecommitdiff
path: root/src/com/android/customization/model/grid/ui
diff options
context:
space:
mode:
authorGeorge Zacharia <george.zcharia@gmail.com>2023-07-02 14:33:47 +0530
committerGeorge Zacharia <george.zcharia@gmail.com>2023-07-02 14:33:47 +0530
commit913b11dfd2b52e445c773838c766f0d4f8ba0d05 (patch)
treeadb07f584833593bad6fca5495927c276ceef531 /src/com/android/customization/model/grid/ui
parentb2d9a4961b3804f79c151630421d480846fd0176 (diff)
parentcc6f666d7c0bc3b6927f6e9e3c7e46123be6263d (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/model/grid/ui')
-rw-r--r--src/com/android/customization/model/grid/ui/binder/GridIconViewBinder.kt17
-rw-r--r--src/com/android/customization/model/grid/ui/binder/GridScreenBinder.kt81
-rw-r--r--src/com/android/customization/model/grid/ui/fragment/GridFragment2.kt132
-rw-r--r--src/com/android/customization/model/grid/ui/viewmodel/GridIconViewModel.kt24
-rw-r--r--src/com/android/customization/model/grid/ui/viewmodel/GridScreenViewModel.kt106
5 files changed, 360 insertions, 0 deletions
diff --git a/src/com/android/customization/model/grid/ui/binder/GridIconViewBinder.kt b/src/com/android/customization/model/grid/ui/binder/GridIconViewBinder.kt
new file mode 100644
index 00000000..fba89a74
--- /dev/null
+++ b/src/com/android/customization/model/grid/ui/binder/GridIconViewBinder.kt
@@ -0,0 +1,17 @@
+package com.android.customization.model.grid.ui.binder
+
+import android.widget.ImageView
+import com.android.customization.model.grid.ui.viewmodel.GridIconViewModel
+import com.android.customization.widget.GridTileDrawable
+
+object GridIconViewBinder {
+ fun bind(view: ImageView, viewModel: GridIconViewModel) {
+ view.setImageDrawable(
+ GridTileDrawable(
+ viewModel.columns,
+ viewModel.rows,
+ viewModel.path,
+ )
+ )
+ }
+}
diff --git a/src/com/android/customization/model/grid/ui/binder/GridScreenBinder.kt b/src/com/android/customization/model/grid/ui/binder/GridScreenBinder.kt
new file mode 100644
index 00000000..78536ca9
--- /dev/null
+++ b/src/com/android/customization/model/grid/ui/binder/GridScreenBinder.kt
@@ -0,0 +1,81 @@
+/*
+ * 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.model.grid.ui.binder
+
+import android.view.View
+import android.widget.ImageView
+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.model.grid.ui.viewmodel.GridIconViewModel
+import com.android.customization.model.grid.ui.viewmodel.GridScreenViewModel
+import com.android.customization.picker.common.ui.view.ItemSpacing
+import com.android.wallpaper.R
+import com.android.wallpaper.picker.option.ui.adapter.OptionItemAdapter
+import com.android.wallpaper.picker.option.ui.binder.OptionItemBinder
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.launch
+
+object GridScreenBinder {
+ fun bind(
+ view: View,
+ viewModel: GridScreenViewModel,
+ lifecycleOwner: LifecycleOwner,
+ backgroundDispatcher: CoroutineDispatcher,
+ onOptionsChanged: () -> Unit,
+ ) {
+ val optionView: RecyclerView = view.requireViewById(R.id.options)
+ optionView.layoutManager =
+ LinearLayoutManager(
+ view.context,
+ RecyclerView.HORIZONTAL,
+ /* reverseLayout= */ false,
+ )
+ optionView.addItemDecoration(ItemSpacing(ItemSpacing.ITEM_SPACING_DP))
+ val adapter =
+ OptionItemAdapter(
+ layoutResourceId = R.layout.grid_option_2,
+ lifecycleOwner = lifecycleOwner,
+ backgroundDispatcher = backgroundDispatcher,
+ foregroundTintSpec =
+ OptionItemBinder.TintSpec(
+ selectedColor = view.context.getColor(R.color.text_color_primary),
+ unselectedColor = view.context.getColor(R.color.text_color_secondary),
+ ),
+ bindIcon = { foregroundView: View, gridIcon: GridIconViewModel ->
+ val imageView = foregroundView as? ImageView
+ imageView?.let { GridIconViewBinder.bind(imageView, gridIcon) }
+ }
+ )
+ optionView.adapter = adapter
+
+ lifecycleOwner.lifecycleScope.launch {
+ lifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
+ launch {
+ viewModel.optionItems.collect { options ->
+ adapter.setItems(options)
+ onOptionsChanged()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/customization/model/grid/ui/fragment/GridFragment2.kt b/src/com/android/customization/model/grid/ui/fragment/GridFragment2.kt
new file mode 100644
index 00000000..d8cad828
--- /dev/null
+++ b/src/com/android/customization/model/grid/ui/fragment/GridFragment2.kt
@@ -0,0 +1,132 @@
+/*
+ * 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.model.grid.ui.fragment
+
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.lifecycle.ViewModelProvider
+import com.android.customization.model.grid.ui.binder.GridScreenBinder
+import com.android.customization.model.grid.ui.viewmodel.GridScreenViewModel
+import com.android.customization.module.ThemePickerInjector
+import com.android.wallpaper.R
+import com.android.wallpaper.module.CurrentWallpaperInfoFactory
+import com.android.wallpaper.module.CustomizationSections
+import com.android.wallpaper.module.InjectorProvider
+import com.android.wallpaper.picker.AppbarFragment
+import com.android.wallpaper.picker.customization.domain.interactor.WallpaperInteractor
+import com.android.wallpaper.picker.customization.ui.binder.ScreenPreviewBinder
+import com.android.wallpaper.picker.customization.ui.viewmodel.ScreenPreviewViewModel
+import com.android.wallpaper.util.PreviewUtils
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class GridFragment2 : AppbarFragment() {
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ val view =
+ inflater.inflate(
+ R.layout.fragment_grid,
+ container,
+ false,
+ )
+ setUpToolbar(view)
+
+ val injector = InjectorProvider.getInjector() as ThemePickerInjector
+
+ val wallpaperInfoFactory = injector.getCurrentWallpaperInfoFactory(requireContext())
+ var screenPreviewBinding =
+ bindScreenPreview(
+ view,
+ wallpaperInfoFactory,
+ injector.getWallpaperInteractor(requireContext())
+ )
+
+ val viewModelFactory = injector.getGridScreenViewModelFactory(requireContext())
+ GridScreenBinder.bind(
+ view = view,
+ viewModel =
+ ViewModelProvider(
+ this,
+ viewModelFactory,
+ )[GridScreenViewModel::class.java],
+ lifecycleOwner = this,
+ backgroundDispatcher = Dispatchers.IO,
+ onOptionsChanged = {
+ screenPreviewBinding.destroy()
+ screenPreviewBinding =
+ bindScreenPreview(
+ view,
+ wallpaperInfoFactory,
+ injector.getWallpaperInteractor(requireContext())
+ )
+ }
+ )
+
+ return view
+ }
+
+ override fun getDefaultTitle(): CharSequence {
+ return getString(R.string.grid_title)
+ }
+
+ private fun bindScreenPreview(
+ view: View,
+ wallpaperInfoFactory: CurrentWallpaperInfoFactory,
+ wallpaperInteractor: WallpaperInteractor,
+ ): ScreenPreviewBinder.Binding {
+ return ScreenPreviewBinder.bind(
+ activity = requireActivity(),
+ previewView = view.requireViewById(R.id.preview),
+ viewModel =
+ ScreenPreviewViewModel(
+ previewUtils =
+ PreviewUtils(
+ context = requireContext(),
+ authorityMetadataKey =
+ requireContext()
+ .getString(
+ R.string.grid_control_metadata_name,
+ ),
+ ),
+ wallpaperInfoProvider = {
+ suspendCancellableCoroutine { continuation ->
+ wallpaperInfoFactory.createCurrentWallpaperInfos(
+ { homeWallpaper, lockWallpaper, _ ->
+ continuation.resume(homeWallpaper ?: lockWallpaper, null)
+ },
+ /* forceRefresh= */ true,
+ )
+ }
+ },
+ wallpaperInteractor = wallpaperInteractor,
+ ),
+ lifecycleOwner = this,
+ offsetToStart = false,
+ screen = CustomizationSections.Screen.HOME_SCREEN,
+ onPreviewDirty = { activity?.recreate() },
+ )
+ }
+}
diff --git a/src/com/android/customization/model/grid/ui/viewmodel/GridIconViewModel.kt b/src/com/android/customization/model/grid/ui/viewmodel/GridIconViewModel.kt
new file mode 100644
index 00000000..3942d7cc
--- /dev/null
+++ b/src/com/android/customization/model/grid/ui/viewmodel/GridIconViewModel.kt
@@ -0,0 +1,24 @@
+/*
+ * 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.model.grid.ui.viewmodel
+
+data class GridIconViewModel(
+ val columns: Int,
+ val rows: Int,
+ val path: String,
+)
diff --git a/src/com/android/customization/model/grid/ui/viewmodel/GridScreenViewModel.kt b/src/com/android/customization/model/grid/ui/viewmodel/GridScreenViewModel.kt
new file mode 100644
index 00000000..c11a5947
--- /dev/null
+++ b/src/com/android/customization/model/grid/ui/viewmodel/GridScreenViewModel.kt
@@ -0,0 +1,106 @@
+/*
+ * 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.model.grid.ui.viewmodel
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.res.Resources
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
+import com.android.customization.model.ResourceConstants
+import com.android.customization.model.grid.domain.interactor.GridInteractor
+import com.android.customization.model.grid.shared.model.GridOptionItemsModel
+import com.android.wallpaper.picker.common.text.ui.viewmodel.Text
+import com.android.wallpaper.picker.option.ui.viewmodel.OptionItemViewModel
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.launch
+
+class GridScreenViewModel(
+ context: Context,
+ private val interactor: GridInteractor,
+) : ViewModel() {
+
+ @SuppressLint("StaticFieldLeak") // We're not leaking this context as it is the app context.
+ private val applicationContext = context.applicationContext
+
+ val optionItems: Flow<List<OptionItemViewModel<GridIconViewModel>>> =
+ interactor.options.map { model -> toViewModel(model) }
+
+ private fun toViewModel(
+ model: GridOptionItemsModel,
+ ): List<OptionItemViewModel<GridIconViewModel>> {
+ val iconShapePath =
+ applicationContext.resources.getString(
+ Resources.getSystem()
+ .getIdentifier(
+ ResourceConstants.CONFIG_ICON_MASK,
+ "string",
+ ResourceConstants.ANDROID_PACKAGE,
+ )
+ )
+
+ return when (model) {
+ is GridOptionItemsModel.Loaded ->
+ model.options.map { option ->
+ val text = Text.Loaded(option.name)
+ OptionItemViewModel<GridIconViewModel>(
+ key =
+ MutableStateFlow("${option.cols}x${option.rows}") as StateFlow<String>,
+ payload =
+ GridIconViewModel(
+ columns = option.cols,
+ rows = option.rows,
+ path = iconShapePath,
+ ),
+ text = text,
+ isSelected = option.isSelected,
+ onClicked =
+ option.isSelected.map { isSelected ->
+ if (!isSelected) {
+ { viewModelScope.launch { option.onSelected() } }
+ } else {
+ null
+ }
+ },
+ )
+ }
+ is GridOptionItemsModel.Error -> emptyList()
+ }
+ }
+
+ class Factory(
+ context: Context,
+ private val interactor: GridInteractor,
+ ) : ViewModelProvider.Factory {
+
+ private val applicationContext = context.applicationContext
+
+ @Suppress("UNCHECKED_CAST")
+ override fun <T : ViewModel> create(modelClass: Class<T>): T {
+ return GridScreenViewModel(
+ context = applicationContext,
+ interactor = interactor,
+ )
+ as T
+ }
+ }
+}