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.wallpaper.picker.preview.ui.view 17 18 import android.content.Context 19 import android.net.Uri 20 import android.util.AttributeSet 21 import android.view.LayoutInflater 22 import android.view.ViewGroup 23 import android.widget.Button 24 import android.widget.FrameLayout 25 import android.widget.TextView 26 import androidx.core.view.isVisible 27 import androidx.lifecycle.LiveData 28 import androidx.slice.Slice 29 import androidx.slice.widget.SliceLiveData 30 import androidx.slice.widget.SliceView 31 import com.android.wallpaper.R 32 import com.android.wallpaper.effects.EffectsController.EffectEnumInterface 33 import com.android.wallpaper.model.WallpaperAction 34 import com.android.wallpaper.util.SizeCalculator 35 import com.android.wallpaper.widget.floatingsheetcontent.WallpaperActionSelectionBottomSheet 36 import com.android.wallpaper.widget.floatingsheetcontent.WallpaperActionsToggleAdapter 37 import com.android.wallpaper.widget.floatingsheetcontent.WallpaperActionsToggleAdapter.WallpaperEffectSwitchListener 38 import com.android.wallpaper.widget.floatingsheetcontent.WallpaperEffectsView2 39 import com.google.android.material.bottomsheet.BottomSheetBehavior 40 import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback 41 42 /** 43 * UI that hosts the content of the floating sheet dialog sliding from the bottom when a 44 * correspondent preview action is toggled on. 45 */ 46 class PreviewActionFloatingSheet(context: Context, attrs: AttributeSet?) : 47 FrameLayout(context, attrs) { 48 49 private val floatingSheetView: ViewGroup 50 private val floatingSheetContainer: ViewGroup 51 private val floatingSheetBehavior: BottomSheetBehavior<ViewGroup> 52 53 private var customizeLiveDataAndView: Pair<LiveData<Slice>, SliceView>? = null 54 55 init { 56 LayoutInflater.from(context).inflate(R.layout.floating_sheet2, this, true) 57 floatingSheetView = requireViewById(R.id.floating_sheet_content) 58 SizeCalculator.adjustBackgroundCornerRadius(floatingSheetView) 59 floatingSheetContainer = requireViewById(R.id.floating_sheet_container) 60 floatingSheetBehavior = BottomSheetBehavior.from(floatingSheetContainer) 61 floatingSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN 62 } 63 64 fun setImageEffectContent( 65 effect: EffectEnumInterface, 66 myPhotosClickListener: OnClickListener, 67 collapseFloatingSheetListener: OnClickListener, 68 effectSwitchListener: WallpaperEffectsView2.EffectSwitchListener, 69 effectDownloadClickListener: WallpaperEffectsView2.EffectDownloadClickListener, 70 status: WallpaperEffectsView2.Status, 71 resultCode: Int?, 72 errorMessage: String?, 73 title: String, 74 effectTextRes: WallpaperEffectsView2.EffectTextRes, 75 ) { 76 val view = 77 LayoutInflater.from(context).inflate(R.layout.wallpaper_effects_view2, this, false) 78 as WallpaperEffectsView2 79 view.setEffectResources(effectTextRes) 80 view.setMyPhotosClickListener(myPhotosClickListener) 81 view.setCollapseFloatingSheetListener(collapseFloatingSheetListener) 82 view.addEffectSwitchListener(effectSwitchListener) 83 view.setEffectDownloadClickListener(effectDownloadClickListener) 84 view.updateEffectStatus( 85 effect, 86 status, 87 resultCode, 88 errorMessage, 89 ) 90 view.updateEffectTitle(title) 91 floatingSheetView.removeAllViews() 92 floatingSheetView.addView(view) 93 } 94 95 fun setCreativeEffectContent( 96 title: String, 97 subtitle: String, 98 wallpaperActions: List<WallpaperAction>, 99 wallpaperEffectSwitchListener: WallpaperEffectSwitchListener, 100 ) { 101 val view = 102 LayoutInflater.from(context) 103 .inflate(R.layout.wallpaper_action_selection_bottom_sheet, this, false) 104 as WallpaperActionSelectionBottomSheet 105 view.setBottomSheetTitle(title) 106 view.setBottomSheetSubtitle(subtitle) 107 view.setUpActionToggleOptions( 108 WallpaperActionsToggleAdapter( 109 // TODO(b/270729418): enable multiple effect options once final design is 110 // agreed upon. 111 // Forcing only one effect item for now 112 if (wallpaperActions.isNotEmpty()) wallpaperActions.subList(0, 1) else listOf(), 113 wallpaperEffectSwitchListener, 114 ) 115 ) 116 floatingSheetView.removeAllViews() 117 floatingSheetView.addView(view) 118 } 119 120 fun setInformationContent( 121 attributions: List<String?>?, 122 onExploreButtonClickListener: OnClickListener?, 123 ) { 124 val view = LayoutInflater.from(context).inflate(R.layout.wallpaper_info_view2, this, false) 125 val title: TextView = view.requireViewById(R.id.wallpaper_info_title) 126 val subtitle1: TextView = view.requireViewById(R.id.wallpaper_info_subtitle1) 127 val subtitle2: TextView = view.requireViewById(R.id.wallpaper_info_subtitle2) 128 val exploreButton: Button = view.requireViewById(R.id.wallpaper_info_explore_button) 129 attributions?.forEachIndexed { index, text -> 130 when (index) { 131 0 -> { 132 if (!text.isNullOrEmpty()) { 133 title.text = text 134 title.isVisible = true 135 } 136 } 137 1 -> { 138 if (!text.isNullOrEmpty()) { 139 subtitle1.text = text 140 subtitle1.isVisible = true 141 } 142 } 143 2 -> { 144 if (!text.isNullOrEmpty()) { 145 subtitle2.text = text 146 subtitle2.isVisible = true 147 } 148 } 149 } 150 151 exploreButton.isVisible = onExploreButtonClickListener != null 152 exploreButton.setOnClickListener(onExploreButtonClickListener) 153 } 154 floatingSheetView.removeAllViews() 155 floatingSheetView.addView(view) 156 } 157 158 fun setCustomizeContent(uri: Uri) { 159 removeCustomizeLiveDataObserver() 160 val view = 161 LayoutInflater.from(context).inflate(R.layout.preview_customize_settings2, this, false) 162 val settingsSliceView: SliceView = 163 view.requireViewById<SliceView>(R.id.settings_slice).apply { 164 mode = SliceView.MODE_LARGE 165 isScrollable = false 166 } 167 customizeLiveDataAndView = SliceLiveData.fromUri(view.context, uri) to settingsSliceView 168 customizeLiveDataAndView?.let { (liveData, observer) -> liveData.observeForever(observer) } 169 floatingSheetView.removeAllViews() 170 floatingSheetView.addView(view) 171 } 172 173 fun expand() { 174 floatingSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED 175 } 176 177 fun collapse() { 178 floatingSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN 179 removeCustomizeLiveDataObserver() 180 } 181 182 /** 183 * Adds Floating Sheet Callback to connected [BottomSheetBehavior]. 184 * 185 * @param callback the callback for floating sheet state changes, has to be in the type of 186 * [BottomSheetBehavior.BottomSheetCallback] since the floating sheet behavior is currently 187 * based on [BottomSheetBehavior] 188 */ 189 fun addFloatingSheetCallback(callback: BottomSheetCallback) { 190 floatingSheetBehavior.addBottomSheetCallback(callback) 191 } 192 193 fun removeFloatingSheetCallback(callback: BottomSheetCallback) { 194 floatingSheetBehavior.removeBottomSheetCallback(callback) 195 } 196 197 private fun removeCustomizeLiveDataObserver() { 198 customizeLiveDataAndView?.let { (liveData, observer) -> liveData.removeObserver(observer) } 199 customizeLiveDataAndView = null 200 } 201 } 202