1 /* 2 * Copyright (C) 2025 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.wallpaper.picker.customization.ui.view 18 19 import android.content.Context 20 import android.graphics.Canvas 21 import android.graphics.Path 22 import android.graphics.drawable.GradientDrawable 23 import android.util.AttributeSet 24 import android.view.Gravity 25 import android.widget.FrameLayout 26 import android.widget.TextView 27 import androidx.constraintlayout.widget.ConstraintLayout 28 import androidx.core.view.isVisible 29 import androidx.recyclerview.widget.RecyclerView 30 import com.android.wallpaper.R 31 32 /** 33 * The wallpaper entry on the main screen. This view needs to be in a [ConstraintLayout]. 34 * 35 * This view is used to display the wallpaper option in the customization screen. It has a collapsed 36 * state and an expanded state. The collapsed state shows a button that allows the user to select a 37 * wallpaper. The expanded state shows a carousel of wallpapers that are related to the selected 38 * wallpaper. 39 */ 40 class WallpaperPickerEntry 41 @JvmOverloads 42 constructor(context: Context, attrs: AttributeSet? = null) : FrameLayout(context, attrs) { 43 44 val collapsedButton: TextView 45 val moreWallpapersButton: TextView 46 val suggestedPhotosText: TextView 47 val wallpaperCarousel: RecyclerView 48 49 private val backgroundLayout: FrameLayout 50 val background: GradientDrawable 51 private val expandedContainer: ConstraintLayout 52 53 private val defaultCornerRadius: Float 54 private val expandedBackgroundTopCornerRadius: Float 55 56 private var expandedWidth = 0 57 private var expandedHeight = 0 58 private var collapsedHeight = 0 59 private var collapsedWidth = 0 60 61 init { 62 inflate(context, R.layout.wallpaper_picker_entry, this) 63 64 collapsedButton = 65 requireViewById(R.id.customization_option_entry_wallpaper_collapsed_button) 66 moreWallpapersButton = requireViewById(R.id.more_wallpapers_button) 67 suggestedPhotosText = requireViewById(R.id.wallpaper_picker_entry_title) 68 wallpaperCarousel = requireViewById(R.id.wallpaper_carousel) 69 70 backgroundLayout = requireViewById(R.id.wallpaper_picker_entry_background) 71 background = backgroundLayout.background as GradientDrawable 72 expandedContainer = requireViewById(R.id.wallpaper_picker_entry_expanded_container) 73 74 defaultCornerRadius = 75 resources 76 .getDimensionPixelSize(R.dimen.customization_option_entry_corner_radius_large) 77 .toFloat() 78 expandedBackgroundTopCornerRadius = 79 resources 80 .getDimensionPixelSize(R.dimen.wallpaper_picker_entry_background_top_corner_radius) 81 .toFloat() 82 83 clipChildren = false 84 clipToPadding = false 85 <lambda>null86 post { 87 // Make fixed width and height of the container, so it does not shrink with parent. 88 expandedContainer.layoutParams = 89 LayoutParams(expandedContainer.width, expandedContainer.height).apply { 90 gravity = Gravity.CENTER 91 } 92 93 expandedWidth = width 94 expandedHeight = height 95 collapsedWidth = 96 collapsedButton.width + 97 resources.getDimensionPixelSize( 98 R.dimen.customization_option_container_horizontal_padding 99 ) * 4 100 collapsedHeight = collapsedButton.height 101 } 102 } 103 dispatchDrawnull104 override fun dispatchDraw(canvas: Canvas) { 105 val clipPath = Path() 106 107 clipPath.addRoundRect( 108 paddingStart.toFloat(), 109 0f, 110 paddingStart.toFloat() + backgroundLayout.width.toFloat(), 111 backgroundLayout.height.toFloat(), 112 background.cornerRadii ?: FloatArray(8), 113 Path.Direction.CW, 114 ) 115 canvas.clipPath(clipPath) 116 117 super.dispatchDraw(canvas) 118 } 119 120 /** 121 * Set collapsing progress of the [WallpaperPickerEntry] 122 * 123 * @param progress 0.0 means fully expanded and 1.0 means fully collapsed 124 */ setProgressnull125 fun setProgress(progress: Float) { 126 collapsedButton.alpha = progress 127 collapsedButton.isVisible = progress > 0 128 expandedContainer.alpha = 1 - progress 129 val radii = background.cornerRadii ?: FloatArray(8) 130 val topCornerRadius = 131 expandedBackgroundTopCornerRadius - 132 (expandedBackgroundTopCornerRadius - defaultCornerRadius) * progress 133 radii[0] = topCornerRadius 134 radii[1] = topCornerRadius 135 radii[2] = topCornerRadius 136 radii[3] = topCornerRadius 137 radii[4] = defaultCornerRadius 138 radii[5] = defaultCornerRadius 139 radii[6] = defaultCornerRadius 140 radii[7] = defaultCornerRadius 141 background.cornerRadii = radii 142 143 val params = layoutParams as ConstraintLayout.LayoutParams 144 145 params.width = (expandedWidth - (expandedWidth - collapsedWidth) * progress).toInt() 146 params.height = (expandedHeight - (expandedHeight - collapsedHeight) * progress).toInt() 147 layoutParams = params 148 } 149 } 150