1 /* 2 * Copyright (C) 2020 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.deskclock.settings 18 19 import android.content.Context 20 import android.util.AttributeSet 21 import android.view.View 22 import android.view.ViewGroup 23 import android.widget.ArrayAdapter 24 import androidx.core.content.ContextCompat 25 import androidx.preference.DropDownPreference 26 27 import com.android.deskclock.R 28 import com.android.deskclock.Utils 29 30 /** 31 * Bend [DropDownPreference] to support 32 * [Simple Menus](https://material.google.com/components/menus.html#menus-behavior). 33 */ 34 class SimpleMenuPreference( 35 context: Context?, 36 attrs: AttributeSet?, 37 defStyleAttr: Int, 38 defStyleRes: Int 39 ) : DropDownPreference(context!!, attrs, defStyleAttr, defStyleRes) { 40 private lateinit var mAdapter: SimpleMenuAdapter 41 42 constructor(context: Context?) : this(context, null) { 43 } 44 45 constructor(context: Context?, attrs: AttributeSet?) : 46 this(context, attrs, R.attr.dropdownPreferenceStyle) { 47 } 48 49 constructor(context: Context?, attrs: AttributeSet?, defStyle: Int) : 50 this(context, attrs, defStyle, 0) { 51 } 52 createAdapternull53 override fun createAdapter(): ArrayAdapter<CharSequence?> { 54 mAdapter = SimpleMenuAdapter(getContext(), R.layout.simple_menu_dropdown_item) 55 return mAdapter 56 } 57 setSummarynull58 override fun setSummary(summary: CharSequence?) { 59 val entries: Array<CharSequence> = getEntries() 60 val index = Utils.indexOf(entries, summary!!) 61 require(index != -1) { "Illegal Summary" } 62 val lastSelectedOriginalPosition = mAdapter.lastSelectedOriginalPosition 63 mAdapter.setSelectedPosition(index) 64 setSelectedPosition(entries, lastSelectedOriginalPosition, index) 65 setSelectedPosition(getEntryValues(), lastSelectedOriginalPosition, index) 66 super.setSummary(summary) 67 } 68 69 private class SimpleMenuAdapter internal constructor(context: Context, resource: Int) : 70 ArrayAdapter<CharSequence?>(context, resource) { 71 72 /** The original position of the last selected element */ 73 var lastSelectedOriginalPosition = 0 74 private set 75 restoreOriginalOrdernull76 private fun restoreOriginalOrder() { 77 val item: CharSequence? = getItem(0) 78 remove(item) 79 insert(item, lastSelectedOriginalPosition) 80 } 81 swapSelectedToFrontnull82 private fun swapSelectedToFront(position: Int) { 83 val item: CharSequence? = getItem(position) 84 remove(item) 85 insert(item, 0) 86 lastSelectedOriginalPosition = position 87 } 88 setSelectedPositionnull89 fun setSelectedPosition(position: Int) { 90 setNotifyOnChange(false) 91 val item: CharSequence? = getItem(position) 92 restoreOriginalOrder() 93 val originalPosition: Int = getPosition(item) 94 swapSelectedToFront(originalPosition) 95 notifyDataSetChanged() 96 } 97 getDropDownViewnull98 override fun getDropDownView(position: Int, convertView: View?, parent: ViewGroup): View { 99 val view: View = super.getDropDownView(position, convertView, parent) 100 if (position == 0) { 101 view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.white_08p)) 102 } else { 103 view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.transparent)) 104 } 105 return view 106 } 107 } 108 109 companion object { restoreOriginalOrdernull110 private fun restoreOriginalOrder( 111 array: Array<CharSequence>, 112 lastSelectedOriginalPosition: Int 113 ) { 114 val item = array[0] 115 System.arraycopy(array, 1, array, 0, lastSelectedOriginalPosition) 116 array[lastSelectedOriginalPosition] = item 117 } 118 swapSelectedToFrontnull119 private fun swapSelectedToFront(array: Array<CharSequence>, position: Int) { 120 val item = array[position] 121 System.arraycopy(array, 0, array, 1, position) 122 array[0] = item 123 } 124 setSelectedPositionnull125 private fun setSelectedPosition( 126 array: Array<CharSequence>, 127 lastSelectedOriginalPosition: Int, 128 position: Int 129 ) { 130 val item = array[position] 131 restoreOriginalOrder(array, lastSelectedOriginalPosition) 132 val originalPosition = Utils.indexOf(array, item) 133 swapSelectedToFront(array, originalPosition) 134 } 135 } 136 } 137