diff --git a/CHANGELOG.md b/CHANGELOG.md index a649339..eb86c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ +## 3.3.0 (2019-11-08) + +### Enhancements +* Introducing `IntegerListPreference` for `integer-array` type entry values. +* Added `OnBindTextInputLayoutListener` as replacement for `OnBindEditTextListener`. +* All preference classes are now `open`. + ## 3.1.8 (2019-23-04) ### Enhancements diff --git a/README.md b/README.md index 7c8975e..afe5509 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ android { } } dependencies { - implementation 'com.anggrayudi:materialpreference:3.2.3' + implementation 'com.anggrayudi:materialpreference:3.3.0' } ``` @@ -127,7 +127,7 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' // Add this line dependencies { - implementation 'com.anggrayudi:materialpreference:3.2.3' + implementation 'com.anggrayudi:materialpreference:3.3.0' kapt 'com.anggrayudi:materialpreference-compiler:1.1' } ```` @@ -141,7 +141,7 @@ class SettingsFragment : PreferenceFragmentMaterial() { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { addPreferencesFromResource(R.xml.preferences) // You can access the constant values with auto-generated class named PrefKey - findPreference(PrefKey.ABOUT)!!.summary = BuildConfig.VERSION_NAME + findPreference(PrefKey.ABOUT)?.summary = BuildConfig.VERSION_NAME } } ```` diff --git a/build.gradle b/build.gradle index 4dc093e..f6dbcc7 100644 --- a/build.gradle +++ b/build.gradle @@ -33,8 +33,8 @@ task clean(type: Delete) { } ext { - appVersionCode = 11 - libVersion = '3.2.3' + appVersionCode = 13 + libVersion = '3.3.0' processorVersion = '1.1' minSdkVersion = 17 targetSdkVersion = 28 diff --git a/materialpreference/build.gradle b/materialpreference/build.gradle index 6fc60eb..4dc41e5 100644 --- a/materialpreference/build.gradle +++ b/materialpreference/build.gradle @@ -36,8 +36,10 @@ repositories { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" api 'androidx.appcompat:appcompat:1.1.0-rc01' - api 'com.google.android.material:material:1.1.0-alpha08' + api 'com.google.android.material:material:1.1.0-alpha09' + api 'androidx.documentfile:documentfile:1.0.1' api 'androidx.cardview:cardview:1.0.0' + api 'com.wdullaer:materialdatetimepicker:4.2.1' api "com.afollestad.material-dialogs:core:$dialogVersion" api "com.afollestad.material-dialogs:files:$dialogVersion" diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/ArrayPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/ArrayPreference.kt index a22e741..f3fa789 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/ArrayPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/ArrayPreference.kt @@ -6,10 +6,7 @@ import androidx.annotation.ArrayRes * @see ListPreference * @see MultiSelectListPreference */ -interface ArrayPreference { - - /** Get or set value to this preference */ - var value: ValueType? +internal interface ArrayPreference { /** * Sets the human-readable entries to be shown in the list. This will be @@ -29,7 +26,7 @@ interface ArrayPreference { * * @return The array of values to be saved for the preference. */ - var entryValues: Array? + var entryValues: Array? /** * @param entriesResId The entries array as a resource. @@ -49,7 +46,7 @@ interface ArrayPreference { * @param value The value whose index should be returned. * @return The index of the value, or -1 if not found. */ - fun findIndexOfValue(value: String?): Int { + fun findIndexOfValue(value: T?): Int { if (value != null && entryValues != null) { for (i in entryValues!!.indices.reversed()) { if (entryValues!![i] == value) { diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/CheckBoxPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/CheckBoxPreference.kt index eec6eb2..cd37655 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/CheckBoxPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/CheckBoxPreference.kt @@ -42,14 +42,15 @@ import androidx.core.content.res.TypedArrayUtils * @see SwitchPreference */ @SuppressLint("RestrictedApi") -class CheckBoxPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.checkBoxPreferenceStyle, - android.R.attr.checkBoxPreferenceStyle), defStyleRes: Int = 0) - : TwoStatePreference(context, attrs, defStyleAttr, defStyleRes) { +open class CheckBoxPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.checkBoxPreferenceStyle, + android.R.attr.checkBoxPreferenceStyle), + defStyleRes: Int = 0 +) : TwoStatePreference(context, attrs, defStyleAttr, defStyleRes) { - private val listener = CompoundButton.OnCheckedChangeListener { - buttonView, isChecked -> + private val listener = CompoundButton.OnCheckedChangeListener { buttonView, isChecked -> if (!callChangeListener(isChecked)) { // Listener didn't like it, change it back. // CompoundButton will make sure we don't recurse. diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/ColorPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/ColorPreference.kt index 948731d..3020f7a 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/ColorPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/ColorPreference.kt @@ -18,11 +18,13 @@ import com.anggrayudi.materialpreference.widget.ColorCircleView * | app:defaultColor | Color | */ @SuppressLint("RestrictedApi") -class ColorPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.colorPreferenceStyle, - android.R.attr.dialogPreferenceStyle), defStyleRes: Int = 0) - : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { +open class ColorPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.colorPreferenceStyle, + android.R.attr.dialogPreferenceStyle), + defStyleRes: Int = 0 +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { var colorList = DEFAULT_COLOR_LIST set(a) { @@ -41,7 +43,8 @@ class ColorPreference @JvmOverloads constructor( var defaultColor: Int init { - val a = context.obtainStyledAttributes(attrs, R.styleable.ColorPreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.ColorPreference, + defStyleAttr, defStyleRes) defaultColor = a.getColor(R.styleable.ColorPreference_defaultColor, colorList[0]) a.recycle() } @@ -138,25 +141,25 @@ class ColorPreference @JvmOverloads constructor( companion object { val DEFAULT_COLOR_LIST = intArrayOf( - Color.parseColor("#F44336"), // red - Color.parseColor("#E91E63"), // pink - Color.parseColor("#9C27B0"), // purple - Color.parseColor("#673AB7"), // deep purple - Color.parseColor("#3F51B5"), // indigo - Color.parseColor("#2196F3"), // blue - Color.parseColor("#03A9F4"), // light blue - Color.parseColor("#00BCD4"), // cyan - Color.parseColor("#009688"), // teal - Color.parseColor("#4CAF50"), // green - Color.parseColor("#8BC34A"), // light green - Color.parseColor("#CDDC39"), // lime - Color.parseColor("#FFEB3B"), // yellow - Color.parseColor("#FFC107"), // amber - Color.parseColor("#FF9800"), // orange - Color.parseColor("#FF5722"), // deep orange - Color.parseColor("#795548"), // brown - Color.parseColor("#9E9E9E"), // gray - Color.parseColor("#607D8B"), // blue gray - Color.parseColor("#000000")) // black + Color.parseColor("#F44336"), // red + Color.parseColor("#E91E63"), // pink + Color.parseColor("#9C27B0"), // purple + Color.parseColor("#673AB7"), // deep purple + Color.parseColor("#3F51B5"), // indigo + Color.parseColor("#2196F3"), // blue + Color.parseColor("#03A9F4"), // light blue + Color.parseColor("#00BCD4"), // cyan + Color.parseColor("#009688"), // teal + Color.parseColor("#4CAF50"), // green + Color.parseColor("#8BC34A"), // light green + Color.parseColor("#CDDC39"), // lime + Color.parseColor("#FFEB3B"), // yellow + Color.parseColor("#FFC107"), // amber + Color.parseColor("#FF9800"), // orange + Color.parseColor("#FF5722"), // deep orange + Color.parseColor("#795548"), // brown + Color.parseColor("#9E9E9E"), // gray + Color.parseColor("#607D8B"), // blue gray + Color.parseColor("#000000")) // black } } \ No newline at end of file diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/DatePreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/DatePreference.kt index 6980bba..a940718 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/DatePreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/DatePreference.kt @@ -4,26 +4,30 @@ import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import com.wdullaer.materialdatetimepicker.date.DatePickerDialog +import java.text.DateFormat import java.text.SimpleDateFormat import java.util.* /** - * * @see TimePreference */ @SuppressLint("RestrictedApi") -class DatePreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.preferenceStyle, defStyleRes: Int = 0) - : Preference(context, attrs, defStyleAttr, defStyleRes), - DatePickerDialog.OnDateSetListener { +open class DatePreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.preferenceStyle, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes), DatePickerDialog.OnDateSetListener { var minDate: Long = 0 + var maxDate: Long = 0 + var disabledDays: Array? = null + var highlightedDays: Array? = null - var dateFormatter = SimpleDateFormat.getDateInstance() + var dateFormatter: DateFormat = SimpleDateFormat.getDateInstance() set(f) { field = f val v = value @@ -54,9 +58,9 @@ class DatePreference @JvmOverloads constructor( val now = Calendar.getInstance() now.timeInMillis = millis val dialog = DatePickerDialog.newInstance(this, - now.get(Calendar.YEAR), - now.get(Calendar.MONTH), - now.get(Calendar.DAY_OF_MONTH)) + now.get(Calendar.YEAR), + now.get(Calendar.MONTH), + now.get(Calendar.DAY_OF_MONTH)) dialog.version = DatePickerDialog.Version.VERSION_2 dialog.dismissOnPause(false) diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/EditTextPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/EditTextPreference.kt index 42ee9e8..4407cde 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/EditTextPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/EditTextPreference.kt @@ -25,6 +25,7 @@ import android.text.InputType import android.util.AttributeSet import android.widget.EditText import androidx.core.content.res.TypedArrayUtils +import com.anggrayudi.materialpreference.callback.OnBindTextInputLayoutListener import com.anggrayudi.materialpreference.dialog.DialogPreference import com.anggrayudi.materialpreference.util.StringSummaryFormatter @@ -50,11 +51,13 @@ import com.anggrayudi.materialpreference.util.StringSummaryFormatter * | app:counterEnabled | Boolean | */ @SuppressLint("RestrictedApi") -class EditTextPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.editTextPreferenceStyle, - android.R.attr.editTextPreferenceStyle), defStyleRes: Int = 0) - : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { +open class EditTextPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.editTextPreferenceStyle, + android.R.attr.editTextPreferenceStyle), + defStyleRes: Int = 0 +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { /** * Saves the text to the [android.content.SharedPreferences]. @@ -93,22 +96,32 @@ class EditTextPreference @JvmOverloads constructor( updateSummary() } + var onBindTextInputLayoutListener: OnBindTextInputLayoutListener? = null + var hint: String? = null + var message: String? = null + var inputType: Int = 0 + var maxLength: Int = 0 + var minLength: Int = 0 + var isCounterEnabled: Boolean = false + var inputFilters: Array? = null init { - val a = context.obtainStyledAttributes(attrs, R.styleable.EditTextPreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.EditTextPreference, + defStyleAttr, defStyleRes) isCounterEnabled = a.getBoolean(R.styleable.EditTextPreference_counterEnabled, true) hint = a.getString(R.styleable.EditTextPreference_android_hint) message = a.getString(R.styleable.EditTextPreference_android_dialogMessage) maxLength = a.getInt(R.styleable.EditTextPreference_android_maxLength, 100) minLength = a.getInt(R.styleable.EditTextPreference_minLength, 0) - inputType = a.getInt(R.styleable.EditTextPreference_android_inputType, InputType.TYPE_CLASS_TEXT) + inputType = a.getInt(R.styleable.EditTextPreference_android_inputType, + InputType.TYPE_CLASS_TEXT) a.recycle() } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt index 837e799..5e39964 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/FolderPreference.kt @@ -31,7 +31,7 @@ import java.io.File */ @TargetApi(21) @SuppressLint("RestrictedApi") -class FolderPreference @JvmOverloads constructor( +open class FolderPreference @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0) : Preference(context, attrs, defStyleAttr, defStyleRes) { diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/IndicatorPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/IndicatorPreference.kt index 7f65fae..b742b6f 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/IndicatorPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/IndicatorPreference.kt @@ -18,11 +18,12 @@ import com.anggrayudi.materialpreference.util.applyTint * | app:tint | Color | */ @SuppressLint("RestrictedApi") -class IndicatorPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.indicatorPreferenceStyle, 0), - defStyleRes: Int = 0) - : Preference(context, attrs, defStyleAttr, defStyleRes) { +open class IndicatorPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.indicatorPreferenceStyle, 0), + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes) { override var isLegacySummary: Boolean get() = true @@ -48,7 +49,8 @@ class IndicatorPreference @JvmOverloads constructor( private var _tint: Int = 0 init { - val a = context.obtainStyledAttributes(attrs, R.styleable.IndicatorPreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.IndicatorPreference, + defStyleAttr, defStyleRes) _tint = a.getColor(R.styleable.IndicatorPreference_tint, 0) _drawable = a.getDrawable(R.styleable.IndicatorPreference_android_src) a.recycle() @@ -62,6 +64,7 @@ class IndicatorPreference @JvmOverloads constructor( override fun onSetupFinished(fragment: PreferenceFragmentMaterial) { tint = _tint - preferenceViewHolder?.itemView?.findViewById(R.id.material_summary)!!.visibility = View.GONE + preferenceViewHolder?.itemView?.findViewById( + R.id.material_summary)!!.visibility = View.GONE } } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/IntegerListPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/IntegerListPreference.kt new file mode 100644 index 0000000..9f5654e --- /dev/null +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/IntegerListPreference.kt @@ -0,0 +1,187 @@ +package com.anggrayudi.materialpreference + +import android.annotation.SuppressLint +import android.content.Context +import android.os.Parcel +import android.os.Parcelable +import android.util.AttributeSet +import androidx.annotation.ArrayRes +import androidx.core.content.res.TypedArrayUtils +import com.anggrayudi.materialpreference.dialog.DialogPreference +import com.anggrayudi.materialpreference.util.EntrySummaryFormatter + +/** + * A [Preference] that displays a list of entries as a dialog. + * + * This preference will store a string into the SharedPreferences. + * This string will be the value from the [entryValues] array. + * + * | Attribute | Value Type | + * |:-------------------:|:-------------------------:| + * | android:entries | String or integer array | + * | android:entryValues | Integer array | + * | app:entryIcons | Drawable array | + */ +@SuppressLint("RestrictedApi") +open class IntegerListPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.dialogPreferenceStyle, + android.R.attr.dialogPreferenceStyle), + defStyleRes: Int = 0 +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes), ArrayPreference { + + override var entries: Array? + get() = _entries + set(value) { + _entries = value + } + private var _entries: Array? = null + + override var entryValues: Array? + get() = _entryValues + set(value) { + _entryValues = value + } + private var _entryValues: Array? = null + + /** Get or set value to this preference */ + var value: Int + get() = _value + set(v) { + if (_value != v && callChangeListener(v)) { + _value = v + // Always persist/notify the first time. + persistInt(v) + if (isBindValueToSummary) { + summary = summaryFormatter?.invoke(entry, v.toString()) ?: entry + } + } + } + private var _value: Int = 0 + + /** + * Lets you control how displaying value to summary. Suppose that the selected entry is + * **Weekly**, then you set: + * + * listPreference.summaryFormatter = { entry, value -> "Value for $entry is $value" } + * + * It will produce **Value for Weekly is 7** to the summary. + * + * With this callback you don't need to set "%s" or "%1$s" to summary. + */ + var summaryFormatter: EntrySummaryFormatter? = null + set(f) { + field = f + if (isBindValueToSummary) { + summary = f?.invoke(entry, value.toString()) ?: entry + } + } + + var disabledEntryValues: Array? = null + + /** + * Returns the entry corresponding to the current value. + * + * @return The entry corresponding to the current value, or null. + */ + val entry: CharSequence? + get() { + val index = findIndexOfValue(value) + return if (index >= 0 && entries != null) entries!![index] else null + } + + init { + val a = context.obtainStyledAttributes(attrs, R.styleable.ListPreference, + defStyleAttr, defStyleRes) + + val entries = a.getTextArray(R.styleable.ListPreference_android_entries) + _entries = if (entries != null) + entries + else { + val entriesResId = a.getResourceId(R.styleable.ListPreference_android_entries, 0) + context.resources.getIntArray(entriesResId) + .map { it.toString() } + .toTypedArray() + } + + val entryValuesResId = a.getResourceId(R.styleable.ListPreference_android_entryValues, 0) + _entryValues = context.resources.getIntArray(entryValuesResId).toTypedArray() + + a.recycle() + + negativeButtonText = null + positiveButtonText = null + } + + override fun setEntries(@ArrayRes entriesResId: Int) { + val e = context.resources.getTextArray(entriesResId) + entries = if (e[0] != null) + e + else { + // the array resource ID contains integer-array + context.resources.getIntArray(entriesResId) + .map { it.toString() } + .toTypedArray() + } + } + + override fun setEntryValues(@ArrayRes entryValuesResId: Int) { + entryValues = context.resources.getIntArray(entryValuesResId).toTypedArray() + } + + override fun onSetInitialValue() { + _value = getPersistedInt(value) + if (isBindValueToSummary) + summary = summaryFormatter?.invoke(entry, _value.toString()) ?: entry + } + + override fun onSaveInstanceState(): Parcelable? { + val superState = super.onSaveInstanceState() + if (isPersistent) { + // No need to save instance state since it's persistent + return superState + } + + val myState = SavedState(superState!!) + myState.value = value + return myState + } + + override fun onRestoreInstanceState(state: Parcelable?) { + if (state == null || state.javaClass != SavedState::class.java) { + // Didn't save state for us in onSaveInstanceState + super.onRestoreInstanceState(state) + return + } + + val myState = state as SavedState? + super.onRestoreInstanceState(myState!!.superState) + value = myState.value + } + + private class SavedState : BaseSavedState { + internal var value: Int = 0 + + constructor(source: Parcel) : super(source) { + value = source.readInt() + } + + override fun writeToParcel(dest: Parcel, flags: Int) { + super.writeToParcel(dest, flags) + dest.writeInt(value) + } + + constructor(superState: Parcelable) : super(superState) + + companion object CREATOR : Parcelable.Creator { + override fun createFromParcel(`in`: Parcel): SavedState { + return SavedState(`in`) + } + + override fun newArray(size: Int): Array { + return arrayOfNulls(size) + } + } + } +} diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/ListPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/ListPreference.kt index 8ebdfe4..b5a086f 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/ListPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/ListPreference.kt @@ -39,26 +39,35 @@ import com.anggrayudi.materialpreference.util.EntrySummaryFormatter * | app:entryIcons | Drawable array | */ @SuppressLint("RestrictedApi") -class ListPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.dialogPreferenceStyle, - android.R.attr.dialogPreferenceStyle), defStyleRes: Int = 0) - : DialogPreference(context, attrs, defStyleAttr, defStyleRes), ArrayPreference { +open class ListPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.dialogPreferenceStyle, + android.R.attr.dialogPreferenceStyle), + defStyleRes: Int = 0 +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes), ArrayPreference { + + override var entries: Array? + get() = _entries + set(value) { + _entries = value + } + private var _entries: Array? = null - override var entries: Array? = null - override var entryValues: Array? = null + override var entryValues: Array? + get() = _entryValues + set(value) { + _entryValues = value + } + private var _entryValues: Array? = null - /** - * Sets the value of the key. This should be one of the entries in [entryValues]. - * - * @return The value of the key. This should be one of the entries in [entryValues]. - */ - // Always persist/notify the first time. - override var value: String? + /** Get or set value to this preference */ + var value: String? get() = _value set(v) { if (_value != v && callChangeListener(v)) { _value = v + // Always persist/notify the first time. persistString(v) if (isBindValueToSummary) { summary = summaryFormatter?.invoke(entry, v) ?: entry @@ -99,22 +108,24 @@ class ListPreference @JvmOverloads constructor( } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.ListPreference, defStyleAttr, defStyleRes) - entries = a.getTextArray(R.styleable.ListPreference_android_entries) - entryValues = a.getTextArray(R.styleable.ListPreference_android_entryValues) + val a = context.obtainStyledAttributes(attrs, R.styleable.ListPreference, + defStyleAttr, defStyleRes) + _entries = a.getTextArray(R.styleable.ListPreference_android_entries) + _entryValues = a.getTextArray(R.styleable.ListPreference_android_entryValues) + .map { it.toString() } + .toTypedArray() a.recycle() negativeButtonText = null positiveButtonText = null } - override fun setEntries(@ArrayRes entriesResId: Int) { entries = context.resources.getTextArray(entriesResId) } override fun setEntryValues(@ArrayRes entryValuesResId: Int) { - entryValues = context.resources.getTextArray(entryValuesResId) + entryValues = context.resources.getStringArray(entryValuesResId) } override fun onSetInitialValue() { @@ -161,7 +172,7 @@ class ListPreference @JvmOverloads constructor( constructor(superState: Parcelable) : super(superState) - companion object CREATOR: Parcelable.Creator { + companion object CREATOR : Parcelable.Creator { override fun createFromParcel(`in`: Parcel): SavedState { return SavedState(`in`) } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/MultiSelectListPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/MultiSelectListPreference.kt index 188e5c1..4ae3b94 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/MultiSelectListPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/MultiSelectListPreference.kt @@ -39,20 +39,34 @@ import kotlin.collections.HashSet * | app:entryIcons | Drawable array | * | app:summaryNothing | String | */ -class MultiSelectListPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.multiSelectListPreferenceStyle, - defStyleRes: Int = R.style.Preference_DialogPreference) - : DialogPreference(context, attrs, defStyleAttr, defStyleRes), ArrayPreference> { - - override var entries: Array? = null - override var entryValues: Array? = null +open class MultiSelectListPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.multiSelectListPreferenceStyle, + defStyleRes: Int = R.style.Preference_DialogPreference +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes), ArrayPreference { + + override var entries: Array? + get() = _entries + set(value) { + _entries = value + } + private var _entries: Array? = null + + override var entryValues: Array? + get() = _entryValues + set(value) { + _entryValues = value + } + private var _entryValues: Array? = null + var disabledEntryValues: Array? = null private val values = HashSet() private var _nothingText: CharSequence? = null - override var value: Set? + /** Get or set value to this preference */ + var value: Set? get() = values set(v) { values.clear() @@ -61,8 +75,11 @@ class MultiSelectListPreference @JvmOverloads constructor( } if (persistStringSet(v ?: HashSet()) && isBindValueToSummary) { summary = when { - value!!.isEmpty() -> if (summaryFormatter == null) nothingText else summaryFormatter!!.invoke(value!!.toTypedArray()) + value!!.isEmpty() -> if (summaryFormatter == null) nothingText + else summaryFormatter!!.invoke(value!!.toTypedArray()) + summaryFormatter != null -> summaryFormatter!!.invoke(value!!.toTypedArray()) + else -> "${value!!.size}/${entryValues!!.size}" } } @@ -76,8 +93,11 @@ class MultiSelectListPreference @JvmOverloads constructor( field = f if (isBindValueToSummary) { summary = when { - value!!.isEmpty() -> if (f == null) nothingText else f.invoke(value!!.toTypedArray()) + value!!.isEmpty() -> if (f == null) nothingText + else f.invoke(value!!.toTypedArray()) + f != null -> f.invoke(value!!.toTypedArray()) + else -> "${value!!.size}/${entryValues!!.size}" } } @@ -93,18 +113,24 @@ class MultiSelectListPreference @JvmOverloads constructor( _nothingText = nothing if (isBindValueToSummary) { summary = when { - value!!.isEmpty() -> if (summaryFormatter == null) nothing else summaryFormatter!!.invoke(value!!.toTypedArray()) + value!!.isEmpty() -> if (summaryFormatter == null) nothing + else summaryFormatter!!.invoke(value!!.toTypedArray()) + summaryFormatter != null -> summaryFormatter!!.invoke(value!!.toTypedArray()) + else -> "${value!!.size}/${entryValues!!.size}" } } } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.MultiSelectListPreference, defStyleAttr, defStyleRes) - entries = a.getTextArray(R.styleable.MultiSelectListPreference_android_entries) - entryValues = a.getTextArray(R.styleable.MultiSelectListPreference_android_entryValues) + val a = context.obtainStyledAttributes(attrs, R.styleable.MultiSelectListPreference, + defStyleAttr, defStyleRes) _nothingText = a.getText(R.styleable.MultiSelectListPreference_summaryNothing) + _entries = a.getTextArray(R.styleable.MultiSelectListPreference_android_entries) + _entryValues = a.getTextArray(R.styleable.MultiSelectListPreference_android_entryValues) + .map { it.toString() } + .toTypedArray() a.recycle() } @@ -121,7 +147,7 @@ class MultiSelectListPreference @JvmOverloads constructor( * @see entryValues */ override fun setEntryValues(@ArrayRes entryValuesResId: Int) { - entryValues = context.resources.getTextArray(entryValuesResId) + entryValues = context.resources.getStringArray(entryValuesResId) } fun setPrettySummaryFormatter() { @@ -141,8 +167,11 @@ class MultiSelectListPreference @JvmOverloads constructor( values.addAll(getPersistedStringSet(value)!!) if (isBindValueToSummary) { summary = when { - value!!.isEmpty() -> if (summaryFormatter == null) nothingText else summaryFormatter!!.invoke(value!!.toTypedArray()) + value!!.isEmpty() -> if (summaryFormatter == null) nothingText + else summaryFormatter!!.invoke(value!!.toTypedArray()) + summaryFormatter != null -> summaryFormatter!!.invoke(value!!.toTypedArray()) + else -> "${value!!.size}/${entryValues!!.size}" } } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/Preference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/Preference.kt index 70cd449..42154fe 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/Preference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/Preference.kt @@ -88,10 +88,12 @@ import java.util.* */ @SuppressLint("RestrictedApi") open class Preference @JvmOverloads constructor( - val context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.preferenceStyle, - android.R.attr.preferenceStyle), defStyleRes: Int = 0) - : Comparable { + val context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.preferenceStyle, + android.R.attr.preferenceStyle), + defStyleRes: Int = 0 +) : Comparable { /** * Gets the [PreferenceManager] that manages this Preference object's tree. @@ -251,7 +253,7 @@ open class Preference @JvmOverloads constructor( internal var onPreferenceChangeInternalListener: OnPreferenceChangeInternalListener? = null private var dependents: MutableList? = null - + /** * Returns the [PreferenceGroup] which is this Preference assigned to or null if this * preference is not assigned to any group or is a root Preference. @@ -268,7 +270,9 @@ open class Preference @JvmOverloads constructor( private val clickListener = View.OnClickListener { v -> performClick(v) } private val longClickListener = View.OnLongClickListener { - onPreferenceLongClickListener != null && onPreferenceLongClickListener!!.invoke(this@Preference) } + onPreferenceLongClickListener != null + && onPreferenceLongClickListener!!.invoke(this@Preference) + } /** * Set to `true` if you want to put the summary horizontally with this preference's title. @@ -288,7 +292,7 @@ open class Preference @JvmOverloads constructor( set(enable) { if (javaClass != Preference::class.java) { _legacySummary = (this is TwoStatePreference || this is PreferenceGroup - || enable && this !is SeekBarPreference) + || enable && this !is SeekBarPreference) notifyChanged() } } @@ -614,6 +618,7 @@ open class Preference @JvmOverloads constructor( * addition/removal of [Preference](s). This is used internally. */ internal interface OnPreferenceChangeInternalListener { + /** * Called when this Preference has changed. * @@ -637,7 +642,8 @@ open class Preference @JvmOverloads constructor( } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.Preference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.Preference, + defStyleAttr, defStyleRes) _key = a.getString(R.styleable.Preference_android_key) _title = a.getText(R.styleable.Preference_android_title) _summary = a.getText(R.styleable.Preference_android_summary) @@ -688,9 +694,10 @@ open class Preference @JvmOverloads constructor( * @param index The index of the default value attribute. * @return The default value of this preference type. */ - @Deprecated("It causes complexity and unreliable for preference's default value. Since v3.0.0 this method always returns null." + - " Use your own method to set the default values as described in the com.anggrayudi.materialpreference.sample.App.kt", - ReplaceWith("")) + @Deprecated("It causes complexity and unreliable for preference's default value." + + " Since v3.0.0 this method always returns null." + + " Use your own method to set the default values as described in the com.anggrayudi.materialpreference.sample.App.kt", + ReplaceWith("")) protected fun onGetDefaultValue(a: TypedArray, index: Int): Any? = null /** @@ -822,7 +829,7 @@ open class Preference @JvmOverloads constructor( * @see title * @param titleResId The title as a resource ID. */ - fun setTitle(@StringRes titleResId: Int) { + open fun setTitle(@StringRes titleResId: Int) { title = context.getString(titleResId) } @@ -832,7 +839,7 @@ open class Preference @JvmOverloads constructor( * @see summary * @param summaryResId The summary as a resource. */ - fun setSummary(@StringRes summaryResId: Int) { + open fun setSummary(@StringRes summaryResId: Int) { summary = context.getString(summaryResId) } @@ -856,6 +863,7 @@ open class Preference @JvmOverloads constructor( } _requiresKey = true } + private var _requiresKey: Boolean = false /** @@ -873,7 +881,7 @@ open class Preference @JvmOverloads constructor( * * @return `true` if it should persist the value */ - protected fun shouldPersist(): Boolean = preferenceManager != null && isPersistent && hasKey() + protected open fun shouldPersist(): Boolean = preferenceManager != null && isPersistent && hasKey() /** * Call this method after the user changes the preference, but before the @@ -884,7 +892,7 @@ open class Preference @JvmOverloads constructor( * value (and persisted). */ fun callChangeListener(newValue: Any?): Boolean = onPreferenceChangeListener == null - || onPreferenceChangeListener!!(this, newValue) + || onPreferenceChangeListener!!(this, newValue) @RestrictTo(LIBRARY_GROUP) internal open fun performClick(view: View) { @@ -900,7 +908,7 @@ open class Preference @JvmOverloads constructor( onClick() if (onPreferenceClickListener?.invoke(this) == true || - preferenceManager?.onPreferenceTreeClickListener?.onPreferenceTreeClick(this) == true) { + preferenceManager?.onPreferenceTreeClickListener?.onPreferenceTreeClick(this) == true) { return } @@ -1010,7 +1018,7 @@ open class Preference @JvmOverloads constructor( preference.registerDependent(this) } else { throw IllegalStateException("Dependency \"$_dependencyKey\" " + - "not found for preference \"$key\" (title: \"$_title\"") + "not found for preference \"$key\" (title: \"$_title\"") } } @@ -1145,7 +1153,7 @@ open class Preference @JvmOverloads constructor( * @return `true` if the Preference is persistent, `false` otherwise * @see getPersistedString */ - fun persistString(value: String?): Boolean { + open fun persistString(value: String?): Boolean { if (!shouldPersist()) { return false } @@ -1175,7 +1183,7 @@ open class Preference @JvmOverloads constructor( * @return the value from the storage or the default return value * @see persistString */ - protected fun getPersistedString(defaultReturnValue: String?): String? { + protected open fun getPersistedString(defaultReturnValue: String?): String? { if (!shouldPersist()) { return defaultReturnValue } @@ -1196,7 +1204,7 @@ open class Preference @JvmOverloads constructor( * @return `true` if the Preference is persistent, `false` otherwise * @see getPersistedStringSet */ - fun persistStringSet(values: Set?): Boolean { + open fun persistStringSet(values: Set?): Boolean { if (!shouldPersist()) { return false } @@ -1226,7 +1234,7 @@ open class Preference @JvmOverloads constructor( * @return the value from the storage or the default return value * @see persistStringSet */ - fun getPersistedStringSet(defaultReturnValue: Set?): Set? { + open fun getPersistedStringSet(defaultReturnValue: Set?): Set? { if (!shouldPersist()) { return defaultReturnValue } @@ -1249,7 +1257,7 @@ open class Preference @JvmOverloads constructor( * @see persistString * @see getPersistedInt */ - protected fun persistInt(value: Int): Boolean { + protected open fun persistInt(value: Int): Boolean { if (!shouldPersist()) { return false } @@ -1279,13 +1287,13 @@ open class Preference @JvmOverloads constructor( * @see getPersistedString * @see persistInt */ - protected fun getPersistedInt(defaultReturnValue: Int): Int { + protected open fun getPersistedInt(defaultReturnValue: Int): Int { if (!shouldPersist()) { return defaultReturnValue } return preferenceDataStore?.getInt(key!!, defaultReturnValue) - ?: preferenceManager!!.sharedPreferences!!.getInt(key, defaultReturnValue) + ?: preferenceManager!!.sharedPreferences!!.getInt(key, defaultReturnValue) } /** @@ -1299,7 +1307,7 @@ open class Preference @JvmOverloads constructor( * @see persistString * @see getPersistedFloat */ - protected fun persistFloat(value: Float): Boolean { + protected open fun persistFloat(value: Float): Boolean { if (!shouldPersist()) { return false } @@ -1329,13 +1337,13 @@ open class Preference @JvmOverloads constructor( * @see getPersistedString * @see persistFloat */ - protected fun getPersistedFloat(defaultReturnValue: Float): Float { + protected open fun getPersistedFloat(defaultReturnValue: Float): Float { if (!shouldPersist()) { return defaultReturnValue } return preferenceDataStore?.getFloat(key!!, defaultReturnValue) - ?: preferenceManager!!.sharedPreferences!!.getFloat(key, defaultReturnValue) + ?: preferenceManager!!.sharedPreferences!!.getFloat(key, defaultReturnValue) } /** @@ -1349,7 +1357,7 @@ open class Preference @JvmOverloads constructor( * @see persistString * @see getPersistedLong */ - protected fun persistLong(value: Long): Boolean { + protected open fun persistLong(value: Long): Boolean { if (!shouldPersist()) { return false } @@ -1379,13 +1387,13 @@ open class Preference @JvmOverloads constructor( * @see getPersistedString * @see persistLong */ - protected fun getPersistedLong(defaultReturnValue: Long): Long { + protected open fun getPersistedLong(defaultReturnValue: Long): Long { if (!shouldPersist()) { return defaultReturnValue } return preferenceDataStore?.getLong(key!!, defaultReturnValue) - ?: preferenceManager!!.sharedPreferences!!.getLong(key, defaultReturnValue) + ?: preferenceManager!!.sharedPreferences!!.getLong(key, defaultReturnValue) } /** @@ -1399,7 +1407,7 @@ open class Preference @JvmOverloads constructor( * @see persistString * @see getPersistedBoolean */ - protected fun persistBoolean(value: Boolean): Boolean { + protected open fun persistBoolean(value: Boolean): Boolean { if (!shouldPersist()) { return false } @@ -1429,13 +1437,13 @@ open class Preference @JvmOverloads constructor( * @see getPersistedString * @see persistBoolean */ - protected fun getPersistedBoolean(defaultReturnValue: Boolean): Boolean { + protected open fun getPersistedBoolean(defaultReturnValue: Boolean): Boolean { if (!shouldPersist()) { return defaultReturnValue } return preferenceDataStore?.getBoolean(key!!, defaultReturnValue) - ?: preferenceManager!!.sharedPreferences!!.getBoolean(key, defaultReturnValue) + ?: preferenceManager!!.sharedPreferences!!.getBoolean(key, defaultReturnValue) } override fun toString(): String = filterableStringBuilder.toString() @@ -1465,7 +1473,8 @@ open class Preference @JvmOverloads constructor( baseMethodCalled = false val state = onSaveInstanceState() if (!baseMethodCalled) { - throw IllegalStateException("Derived class did not call super.onSaveInstanceState()") + throw IllegalStateException( + "Derived class did not call super.onSaveInstanceState()") } if (state != null) { container.putParcelable(key, state) @@ -1517,7 +1526,8 @@ open class Preference @JvmOverloads constructor( baseMethodCalled = false onRestoreInstanceState(state) if (!baseMethodCalled) { - throw IllegalStateException("Derived class did not call super.onRestoreInstanceState()") + throw IllegalStateException( + "Derived class did not call super.onRestoreInstanceState()") } } } @@ -1548,6 +1558,7 @@ open class Preference @JvmOverloads constructor( /** A base class for managing the instance state of a [Preference]. */ open class BaseSavedState : AbsSavedState { + constructor(source: Parcel) : super(source) constructor(superState: Parcelable) : super(superState) diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceCategory.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceCategory.kt index b1c7174..2e3317a 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceCategory.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceCategory.kt @@ -29,10 +29,12 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionIt */ @SuppressLint("RestrictedApi") class PreferenceCategory @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.preferenceCategoryStyle, - android.R.attr.preferenceCategoryStyle), defStyleRes: Int = 0) - : PreferenceGroup(context, attrs, defStyleAttr, defStyleRes) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = TypedArrayUtils.getAttr(context, R.attr.preferenceCategoryStyle, + android.R.attr.preferenceCategoryStyle), + defStyleRes: Int = 0 +) : PreferenceGroup(context, attrs, defStyleAttr, defStyleRes) { override var isEnabled: Boolean get() = false diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt index dcf15f8..e846b6e 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceFragmentMaterial.kt @@ -267,8 +267,7 @@ abstract class PreferenceFragmentMaterial : Fragment(), if (key != null) { root = xmlRoot.findPreference(key) if (root !is PreferenceScreen) { - throw IllegalArgumentException("Preference object with key " + key - + " is not a PreferenceScreen") + throw IllegalArgumentException("Preference object with key $key is not a PreferenceScreen") } } else { root = xmlRoot @@ -436,6 +435,7 @@ abstract class PreferenceFragmentMaterial : Fragment(), val f: DialogFragment = when (preference) { is EditTextPreference -> EditTextPreferenceDialogFragment.newInstance(preference.key!!) is ListPreference -> ListPreferenceDialogFragment.newInstance(preference.key!!) + is IntegerListPreference -> IntegerListPreferenceDialogFragment.newInstance(preference.key!!) is MultiSelectListPreference -> MultiSelectListPreferenceDialogFragment.newInstance(preference.key!!) is SeekBarDialogPreference -> SeekBarPreferenceDialogFragment.newInstance(preference.key!!) is ColorPreference -> ColorPreferenceDialogFragment.newInstance(preference.key!!) diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroup.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroup.kt index 8d27230..f1e9244 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroup.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroup.kt @@ -38,8 +38,11 @@ import kotlin.collections.ArrayList */ @SuppressLint("RestrictedApi") abstract class PreferenceGroup @JvmOverloads constructor( - context: Context, attrs: AttributeSet?, defStyleAttr: Int = 0, defStyleRes: Int = 0) - : Preference(context, attrs, defStyleAttr, defStyleRes) { + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes) { /** * The container for child [Preference]s. This is sorted based on the @@ -99,7 +102,8 @@ abstract class PreferenceGroup @JvmOverloads constructor( init { isPersistent = false - val a = context.obtainStyledAttributes(attrs, R.styleable.PreferenceGroup, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.PreferenceGroup, + defStyleAttr, defStyleRes) isOrderingAsAdded = a.getBoolean(R.styleable.PreferenceGroup_android_orderingFromXml, true) a.recycle() } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroupAdapter.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroupAdapter.kt index f2d83a9..48eeb87 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroupAdapter.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceGroupAdapter.kt @@ -252,10 +252,10 @@ internal class PreferenceGroupAdapter internal constructor( return rootParent if (preference.parent!!.preferenceViewHolder == null) { - var message = ("Make sure that you wrap " + preference.javaClass.simpleName + var message = ("Make sure that you wrap ${preference.javaClass.simpleName}" + " inside PreferenceCategory in the XML.") if (preference.key != null) - message += " Key=\"" + preference.key + "\"" + message += " Key=\"${preference.key}\"" throw InflateException(message) } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceInflater.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceInflater.kt index 9169d62..27b31d9 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceInflater.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceInflater.kt @@ -31,7 +31,8 @@ import java.util.* /** * The [PreferenceInflater] is used to inflate preference hierarchies from XML files. */ -internal class PreferenceInflater(val context: Context, private val preferenceManager: PreferenceManager) { +internal class PreferenceInflater(val context: Context, + private val preferenceManager: PreferenceManager) { private val constructorArgs = arrayOfNulls(2) @@ -171,7 +172,7 @@ internal class PreferenceInflater(val context: Context, private val preferenceMa } if (clazz == null) { if (notFoundException == null) { - throw InflateException(attrs.positionDescription + ": Error inflating class " + name) + throw InflateException(attrs.positionDescription + ": Error inflating class $name") } else { throw notFoundException as ClassNotFoundException } @@ -190,7 +191,7 @@ internal class PreferenceInflater(val context: Context, private val preferenceMa // If loadClass fails, we should propagate the exception. throw e } catch (e: Exception) { - val ie = InflateException(attrs.positionDescription + ": Error inflating class " + name) + val ie = InflateException(attrs.positionDescription + ": Error inflating class $name") ie.initCause(e) throw ie } @@ -221,11 +222,11 @@ internal class PreferenceInflater(val context: Context, private val preferenceMa } catch (e: InflateException) { throw e } catch (e: ClassNotFoundException) { - val ie = InflateException(attrs.positionDescription + ": Error inflating class (not found)" + name) + val ie = InflateException(attrs.positionDescription + ": Error inflating class (not found) $name") ie.initCause(e) throw ie } catch (e: Exception) { - val ie = InflateException(attrs.positionDescription + ": Error inflating class " + name) + val ie = InflateException(attrs.positionDescription + ": Error inflating class $name") ie.initCause(e) throw ie } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceManager.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceManager.kt index e05b307..73086ae 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceManager.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/PreferenceManager.kt @@ -458,7 +458,12 @@ constructor(val context: Context) { companion object { + /** + * Use this constant to prevents preferences from being reset after boot, + * instead of [android.preference.PreferenceManager.KEY_HAS_SET_DEFAULT_VALUES]. + */ const val KEY_HAS_SET_DEFAULT_VALUES = "hasSetDefaultValues" + private const val STORAGE_DEFAULT = 0 private const val STORAGE_DEVICE_PROTECTED = 1 diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/RingtonePreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/RingtonePreference.kt index 6edf0d1..1dd4d07 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/RingtonePreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/RingtonePreference.kt @@ -43,11 +43,12 @@ import com.anggrayudi.materialpreference.dialog.DialogPreference * | android:showDefault | Boolean | * | android:showSilent | Boolean | */ -class RingtonePreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.ringtonePreferenceStyle, - defStyleRes: Int = R.style.Preference_DialogPreference_RingtonePreference) - : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { +open class RingtonePreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.ringtonePreferenceStyle, + defStyleRes: Int = R.style.Preference_DialogPreference_RingtonePreference +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { /** * Sets the sound type(s) that are shown in the picker. @@ -109,7 +110,8 @@ class RingtonePreference @JvmOverloads constructor( } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.RingtonePreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.RingtonePreference, + defStyleAttr, defStyleRes) ringtoneType = a.getInt(R.styleable.RingtonePreference_android_ringtoneType, RingtoneManager.TYPE_RINGTONE) showDefault = a.getBoolean(R.styleable.RingtonePreference_android_showDefault, true) showSilent = a.getBoolean(R.styleable.RingtonePreference_android_showSilent, true) @@ -163,12 +165,12 @@ class RingtonePreference @JvmOverloads constructor( fun buildRingtonePickerIntent(): Intent { val type = ringtoneType return Intent(RingtoneManager.ACTION_RINGTONE_PICKER) - .putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, onRestoreRingtone()) - .putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(type)) - .putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, showDefault) - .putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, showSilent) - .putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, type) - .putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, nonEmptyDialogTitle) + .putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, onRestoreRingtone()) + .putExtra(RingtoneManager.EXTRA_RINGTONE_DEFAULT_URI, RingtoneManager.getDefaultUri(type)) + .putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, showDefault) + .putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, showSilent) + .putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, type) + .putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, nonEmptyDialogTitle) } /** @@ -208,30 +210,31 @@ class RingtonePreference @JvmOverloads constructor( } } - fun getNotificationSoundDefaultString(context: Context): String - = context.getString(R.string.notification_sound_default) + fun getNotificationSoundDefaultString(context: Context): String = + context.getString(R.string.notification_sound_default) - fun getAlarmSoundDefaultString(context: Context): String - = context.getString(R.string.alarm_sound_default) + fun getAlarmSoundDefaultString(context: Context): String = + context.getString(R.string.alarm_sound_default) - fun getRingtoneDefaultString(context: Context): String - = context.getString(R.string.ringtone_default) + fun getRingtoneDefaultString(context: Context): String = + context.getString(R.string.ringtone_default) - fun getRingtoneDefaultWithActualString(context: Context, actual: String): String - = context.getString(R.string.ringtone_default_with_actual, actual) + fun getRingtoneDefaultWithActualString(context: Context, actual: String): String = + context.getString(R.string.ringtone_default_with_actual, actual) - fun getRingtoneSilentString(context: Context): String - = context.getString(R.string.ringtone_silent) + fun getRingtoneSilentString(context: Context): String = + context.getString(R.string.ringtone_silent) - fun getRingtoneUnknownString(context: Context): String - = context.getString(R.string.ringtone_unknown) + fun getRingtoneUnknownString(context: Context): String = + context.getString(R.string.ringtone_unknown) - fun getRingtonePickerTitleString(context: Context): String = context.getString(R.string.ringtone_picker_title) + fun getRingtonePickerTitleString(context: Context): String = + context.getString(R.string.ringtone_picker_title) - fun getRingtonePickerTitleAlarmString(context: Context): String - = context.applicationContext.getString(R.string.ringtone_picker_title_alarm) + fun getRingtonePickerTitleAlarmString(context: Context): String = + context.applicationContext.getString(R.string.ringtone_picker_title_alarm) - fun getRingtonePickerTitleNotificationString(context: Context): String - = context.applicationContext.getString(R.string.ringtone_picker_title_notification) + fun getRingtonePickerTitleNotificationString(context: Context): String = + context.applicationContext.getString(R.string.ringtone_picker_title_notification) } } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarDialogPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarDialogPreference.kt index b1ff00a..81dbb2f 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarDialogPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarDialogPreference.kt @@ -27,11 +27,12 @@ import com.anggrayudi.materialpreference.util.IntSummaryFormatter * * @see SeekBarPreference */ -class SeekBarDialogPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.seekBarDialogPreferenceStyle, - defStyleRes: Int = R.style.Preference_DialogPreference_SeekBarDialogPreference) - : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { +open class SeekBarDialogPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.seekBarDialogPreferenceStyle, + defStyleRes: Int = R.style.Preference_DialogPreference_SeekBarDialogPreference +) : DialogPreference(context, attrs, defStyleAttr, defStyleRes) { private var progress: Int = 0 private var preferredMax = 100 @@ -71,7 +72,8 @@ class SeekBarDialogPreference @JvmOverloads constructor( } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.SeekBarPreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.SeekBarPreference, + defStyleAttr, defStyleRes) preferredMax = a.getInt(R.styleable.SeekBarPreference_android_max, preferredMax) val hasAspMin = a.hasValue(R.styleable.SeekBarPreference_min) if (hasAspMin) { diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarPreference.kt index df39607..ccfaa2a 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/SeekBarPreference.kt @@ -41,14 +41,17 @@ import com.anggrayudi.materialpreference.util.IntSummaryFormatter * * @see SeekBarDialogPreference */ -class SeekBarPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.seekBarPreferenceStyle, defStyleRes: Int = 0) - : Preference(context, attrs, defStyleAttr, defStyleRes) { +open class SeekBarPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.seekBarPreferenceStyle, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes) { private var seekBarValue: Int = 0 private var trackingTouch: Boolean = false private var seekBar: SeekBar? = null + var isAdjustable: Boolean = false // whether the seekbar should respond to the left/right keys var summaryFormatter: IntSummaryFormatter? = null @@ -161,7 +164,8 @@ class SeekBarPreference @JvmOverloads constructor( set(seekBarValue) = setValueInternal(seekBarValue, true) init { - val a = context.obtainStyledAttributes(attrs, R.styleable.SeekBarPreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.SeekBarPreference, + defStyleAttr, defStyleRes) /* * The ordering of these two statements are important. If we want to set max first, we need * to perform the same steps by changing min/max to max/min as following: @@ -276,6 +280,7 @@ class SeekBarPreference @JvmOverloads constructor( * It is important to always call through to super methods. */ private class SavedState : BaseSavedState { + internal var seekBarValue: Int = 0 internal var min: Int = 0 internal var max: Int = 0 diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/SwitchPreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/SwitchPreference.kt index 41359a0..02ba22d 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/SwitchPreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/SwitchPreference.kt @@ -45,10 +45,12 @@ import com.anggrayudi.materialpreference.widget.AspSwitchCompat * @see CheckBoxPreference */ @SuppressLint("RestrictedApi") -class SwitchPreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.switchPreferenceStyle, defStyleRes: Int = 0) : - TwoStatePreference(context, attrs, defStyleAttr, defStyleRes) { +open class SwitchPreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.switchPreferenceStyle, + defStyleRes: Int = 0 +) : TwoStatePreference(context, attrs, defStyleAttr, defStyleRes) { private val listener = Listener() @@ -93,7 +95,8 @@ class SwitchPreference @JvmOverloads constructor( } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.SwitchPreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.SwitchPreference, + defStyleAttr, defStyleRes) _switchTextOn = a.getString(R.styleable.SwitchPreference_android_switchTextOn) _switchTextOff = a.getString(R.styleable.SwitchPreference_android_switchTextOff) a.recycle() diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/TimePreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/TimePreference.kt index 2925b9e..cb46f7e 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/TimePreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/TimePreference.kt @@ -11,26 +11,31 @@ import java.util.* * * @see DatePreference */ -class TimePreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = R.attr.preferenceStyle, defStyleRes: Int = 0) - : Preference(context, attrs, defStyleAttr, defStyleRes), TimePickerDialog.OnTimeSetListener { +open class TimePreference @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = R.attr.preferenceStyle, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes), TimePickerDialog.OnTimeSetListener { var enableMinute = true + var enableSecond = false + var minTime: Timepoint? = null + var maxTime: Timepoint? = null var is24HourMode = DateFormat.is24HourFormat(context) var timeFormatter: java.text.DateFormat = DateFormat.getTimeFormat(context) - set(f) { - field = f - val v = value - if (isBindValueToSummary && v != null) { - summary = f.format(v) + set(f) { + field = f + val v = value + if (isBindValueToSummary && v != null) { + summary = f.format(v) + } } - } /** * Get saved value from this preference @@ -58,7 +63,7 @@ class TimePreference @JvmOverloads constructor( time = Time(now.get(Calendar.HOUR_OF_DAY), now.get(Calendar.MINUTE), now.get(Calendar.SECOND)) } val dialog = TimePickerDialog.newInstance(this, - time.hourOfDay, time.minute, time.second, is24HourMode) + time.hourOfDay, time.minute, time.second, is24HourMode) dialog.version = TimePickerDialog.Version.VERSION_2 dialog.dismissOnPause(false) dialog.enableMinutes(enableMinute) @@ -96,8 +101,10 @@ class TimePreference @JvmOverloads constructor( } class Time constructor( - /** 24 hours format */ - var hourOfDay: Int, var minute: Int, var second: Int) { + /** 24 hours format */ + var hourOfDay: Int, + var minute: Int, + var second: Int) { override fun toString(): String = "$hourOfDay:$minute:$second" diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/TwoStatePreference.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/TwoStatePreference.kt index acdf8be..7c62a12 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/TwoStatePreference.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/TwoStatePreference.kt @@ -32,9 +32,11 @@ import androidx.annotation.StringRes * enabled/disabled based on the current state. */ abstract class TwoStatePreference @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, - defStyleAttr: Int = 0, defStyleRes: Int = 0) - : Preference(context, attrs, defStyleAttr, defStyleRes) { + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : Preference(context, attrs, defStyleAttr, defStyleRes) { /** * Sets the summary to be shown when checked. @@ -106,7 +108,8 @@ abstract class TwoStatePreference @JvmOverloads constructor( } init { - val a = context.obtainStyledAttributes(attrs, R.styleable.TwoStatePreference, defStyleAttr, defStyleRes) + val a = context.obtainStyledAttributes(attrs, R.styleable.TwoStatePreference, + defStyleAttr, defStyleRes) disableDependentsState = a.getBoolean(R.styleable.TwoStatePreference_android_disableDependentsState, false) _summaryOn = a.getString(R.styleable.TwoStatePreference_android_summaryOn) _summaryOff = a.getString(R.styleable.TwoStatePreference_android_summaryOff) diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/callback/PreferenceCallbacks.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/callback/PreferenceCallbacks.kt index 31c99c4..f282870 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/callback/PreferenceCallbacks.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/callback/PreferenceCallbacks.kt @@ -1,6 +1,7 @@ package com.anggrayudi.materialpreference.callback import com.anggrayudi.materialpreference.Preference +import com.google.android.material.textfield.TextInputLayout /** * Called when a Preference has been clicked. @@ -20,4 +21,12 @@ typealias OnPreferenceLongClickListener = (preference: Preference) -> Boolean * * @return True to update the state of the Preference with the new value. */ -typealias OnPreferenceChangeListener = (preference: Preference, newValue: Any?) -> Boolean \ No newline at end of file +typealias OnPreferenceChangeListener = (preference: Preference, newValue: Any?) -> Boolean + +/** + * Called when the dialog view for this preference has been bound, + * allowing you to customize the [TextInputLayout] displayed in the dialog. + * It has the same function with [OnBindEditTextListener](https://developer.android.com/reference/androidx/preference/EditTextPreference.OnBindEditTextListener), + * except it uses [TextInputLayout] as the callback's parameter. + */ +typealias OnBindTextInputLayoutListener = (textInputLayout: TextInputLayout) -> Unit \ No newline at end of file diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/EditTextPreferenceDialogFragment.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/EditTextPreferenceDialogFragment.kt index 27c70b9..2427548 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/EditTextPreferenceDialogFragment.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/EditTextPreferenceDialogFragment.kt @@ -57,11 +57,11 @@ class EditTextPreferenceDialogFragment : PreferenceDialogFragment() { override fun onPrepareDialog(dialog: MaterialDialog): MaterialDialog { return dialog - .positiveButton(text = positiveButtonText ?: getString(android.R.string.ok)) { - whichButtonClicked = WhichButton.POSITIVE - }.negativeButton(text = negativeButtonText ?: getString(android.R.string.cancel)) { - whichButtonClicked = WhichButton.NEGATIVE - } + .positiveButton(text = positiveButtonText ?: getString(android.R.string.ok)) { + whichButtonClicked = WhichButton.POSITIVE + }.negativeButton(text = negativeButtonText ?: getString(android.R.string.cancel)) { + whichButtonClicked = WhichButton.NEGATIVE + } } override fun onBindDialogView(view: View) { @@ -91,7 +91,7 @@ class EditTextPreferenceDialogFragment : PreferenceDialogFragment() { val underMinChars = text == null || preference.minLength > 0 && text.length < preference.minLength (dialog as MaterialDialog).getActionButton(WhichButton.POSITIVE).isEnabled = - !underMinChars && text!!.length <= preference.maxLength + !underMinChars && text!!.length <= preference.maxLength textInputLayout!!.error = if (underMinChars && preference.minLength > 0) getString(R.string.min_preference_input_chars_, preference.minLength) @@ -103,6 +103,8 @@ class EditTextPreferenceDialogFragment : PreferenceDialogFragment() { } editText!!.addTextChangedListener(textWatcher) editText!!.post { textWatcher.onTextChanged(text, 0, 0, 0) } + + preference.onBindTextInputLayoutListener?.invoke(textInputLayout!!) } @RestrictTo(LIBRARY_GROUP) diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/IntegerListPreferenceDialogFragment.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/IntegerListPreferenceDialogFragment.kt new file mode 100644 index 0000000..39b8e84 --- /dev/null +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/IntegerListPreferenceDialogFragment.kt @@ -0,0 +1,89 @@ +package com.anggrayudi.materialpreference.dialog + +import android.os.Bundle +import com.afollestad.materialdialogs.MaterialDialog +import com.afollestad.materialdialogs.WhichButton +import com.afollestad.materialdialogs.list.listItemsSingleChoice +import com.anggrayudi.materialpreference.IntegerListPreference +import com.anggrayudi.materialpreference.dialog.ListPreferenceDialogFragment.Companion.getCharSequenceArray +import com.anggrayudi.materialpreference.dialog.ListPreferenceDialogFragment.Companion.putCharSequenceArray + +class IntegerListPreferenceDialogFragment : PreferenceDialogFragment() { + + private var clickedDialogEntryIndex: Int = 0 + private var entries: Array? = null + private var entryValues: Array? = null + + private val listPreference: IntegerListPreference + get() = preference as IntegerListPreference + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + if (savedInstanceState == null) { + val preference = listPreference + if (preference.entries == null || preference.entryValues == null) { + throw IllegalStateException( + "IntegerListPreference requires an entries array and an entryValues array.") + } + + clickedDialogEntryIndex = preference.findIndexOfValue(preference.value) + entryValues = preference.entryValues + entries = preference.entries + } else { + clickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0) + entryValues = savedInstanceState.getIntArray(SAVE_STATE_ENTRY_VALUES)?.toTypedArray() + entries = getCharSequenceArray(savedInstanceState, SAVE_STATE_ENTRIES) + } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putInt(SAVE_STATE_INDEX, clickedDialogEntryIndex) + outState.putIntArray(SAVE_STATE_ENTRY_VALUES, entryValues!!.toIntArray()) + putCharSequenceArray(outState, SAVE_STATE_ENTRIES, entries!!) + } + + override fun onPrepareDialog(dialog: MaterialDialog): MaterialDialog { + return dialog.listItemsSingleChoice(items = entries!!.map { it.toString() }, + initialSelection = clickedDialogEntryIndex, + waitForPositiveButton = false, disabledIndices = getDisabledIndices()) { _, index, _ -> + clickedDialogEntryIndex = index + whichButtonClicked = WhichButton.POSITIVE + dialog.dismiss() + } + } + + override fun onDialogClosed(positiveResult: Boolean) { + if (positiveResult && clickedDialogEntryIndex >= 0) { + listPreference.value = entryValues!![clickedDialogEntryIndex] + } + } + + private fun getDisabledIndices(): IntArray? { + val e = listPreference.disabledEntryValues + if (e != null && e.size <= entryValues!!.size) { + val a = mutableListOf() + for (item in entryValues!!.withIndex()) { + if (e.contains(item.value)) + a.add(item.index) + } + return a.toIntArray() + } + return null + } + + companion object { + + private const val SAVE_STATE_INDEX = "IntegerListPreferenceDialogFragment.index" + private const val SAVE_STATE_ENTRIES = "IntegerListPreferenceDialogFragment.entries" + private const val SAVE_STATE_ENTRY_VALUES = "IntegerListPreferenceDialogFragment.entryValues" + + fun newInstance(key: String): IntegerListPreferenceDialogFragment { + val b = Bundle(1) + b.putString(ARG_KEY, key) + val fragment = IntegerListPreferenceDialogFragment() + fragment.arguments = b + return fragment + } + } +} diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/ListPreferenceDialogFragment.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/ListPreferenceDialogFragment.kt index 40f5d8c..1fd0c2b 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/ListPreferenceDialogFragment.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/ListPreferenceDialogFragment.kt @@ -21,13 +21,12 @@ import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.WhichButton import com.afollestad.materialdialogs.list.listItemsSingleChoice import com.anggrayudi.materialpreference.ListPreference -import java.util.* class ListPreferenceDialogFragment : PreferenceDialogFragment() { private var clickedDialogEntryIndex: Int = 0 private var entries: Array? = null - private var entryValues: Array? = null + private var entryValues: Array? = null private val listPreference: ListPreference get() = preference as ListPreference @@ -37,7 +36,8 @@ class ListPreferenceDialogFragment : PreferenceDialogFragment() { if (savedInstanceState == null) { val preference = listPreference if (preference.entries == null || preference.entryValues == null) { - throw IllegalStateException("ListPreference requires an entries array and an entryValues array.") + throw IllegalStateException( + "ListPreference requires an entries array and an entryValues array.") } clickedDialogEntryIndex = preference.findIndexOfValue(preference.value) @@ -45,7 +45,7 @@ class ListPreferenceDialogFragment : PreferenceDialogFragment() { entries = preference.entries } else { clickedDialogEntryIndex = savedInstanceState.getInt(SAVE_STATE_INDEX, 0) - entryValues = getCharSequenceArray(savedInstanceState, SAVE_STATE_ENTRY_VALUES) + entryValues = savedInstanceState.getStringArrayList(SAVE_STATE_ENTRY_VALUES)?.toTypedArray() entries = getCharSequenceArray(savedInstanceState, SAVE_STATE_ENTRIES) } } @@ -53,15 +53,14 @@ class ListPreferenceDialogFragment : PreferenceDialogFragment() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putInt(SAVE_STATE_INDEX, clickedDialogEntryIndex) - putCharSequenceArray(outState, SAVE_STATE_ENTRY_VALUES, entryValues!!) + outState.putStringArrayList(SAVE_STATE_ENTRY_VALUES, ArrayList(entryValues!!.toList())) putCharSequenceArray(outState, SAVE_STATE_ENTRIES, entries!!) } override fun onPrepareDialog(dialog: MaterialDialog): MaterialDialog { - val listItem = mutableListOf() - entries!!.forEach { listItem.add(it.toString()) } - return dialog.listItemsSingleChoice(items = listItem, initialSelection = clickedDialogEntryIndex, - waitForPositiveButton = false, disabledIndices = getDisabledIndices()) { _, index, _ -> + return dialog.listItemsSingleChoice(items = entries!!.map { it.toString() }, + initialSelection = clickedDialogEntryIndex, + waitForPositiveButton = false, disabledIndices = getDisabledIndices()) { _, index, _ -> clickedDialogEntryIndex = index whichButtonClicked = WhichButton.POSITIVE dialog.dismiss() @@ -70,7 +69,7 @@ class ListPreferenceDialogFragment : PreferenceDialogFragment() { override fun onDialogClosed(positiveResult: Boolean) { if (positiveResult && clickedDialogEntryIndex >= 0) { - listPreference.value = entryValues!![clickedDialogEntryIndex].toString() + listPreference.value = entryValues!![clickedDialogEntryIndex] } } @@ -101,13 +100,13 @@ class ListPreferenceDialogFragment : PreferenceDialogFragment() { return fragment } - private fun putCharSequenceArray(out: Bundle, key: String, entries: Array) { + internal fun putCharSequenceArray(out: Bundle, key: String, entries: Array) { val stored = ArrayList(entries.size) entries.forEach { stored.add(it.toString()) } out.putStringArrayList(key, stored) } - private fun getCharSequenceArray(`in`: Bundle, key: String): Array? { + internal fun getCharSequenceArray(`in`: Bundle, key: String): Array? { val stored = `in`.getStringArrayList(key) return stored?.toTypedArray() } diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/MultiSelectListPreferenceDialogFragment.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/MultiSelectListPreferenceDialogFragment.kt index 44b4315..6086b25 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/MultiSelectListPreferenceDialogFragment.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/dialog/MultiSelectListPreferenceDialogFragment.kt @@ -28,7 +28,7 @@ class MultiSelectListPreferenceDialogFragment : PreferenceDialogFragment() { private val newValues = HashSet() private var preferenceChanged: Boolean = false private var entries: Array? = null - private var entryValues: Array? = null + private var entryValues: Array? = null private val listPreference: MultiSelectListPreference get() = preference as MultiSelectListPreference @@ -53,7 +53,7 @@ class MultiSelectListPreferenceDialogFragment : PreferenceDialogFragment() { newValues.addAll(savedInstanceState.getStringArrayList(SAVE_STATE_VALUES)!!) preferenceChanged = savedInstanceState.getBoolean(SAVE_STATE_CHANGED, false) entries = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRIES) - entryValues = savedInstanceState.getCharSequenceArray(SAVE_STATE_ENTRY_VALUES) + entryValues = savedInstanceState.getStringArray(SAVE_STATE_ENTRY_VALUES) } } @@ -62,19 +62,17 @@ class MultiSelectListPreferenceDialogFragment : PreferenceDialogFragment() { outState.putStringArrayList(SAVE_STATE_VALUES, ArrayList(newValues)) outState.putBoolean(SAVE_STATE_CHANGED, preferenceChanged) outState.putCharSequenceArray(SAVE_STATE_ENTRIES, entries) - outState.putCharSequenceArray(SAVE_STATE_ENTRY_VALUES, entryValues) + outState.putStringArray(SAVE_STATE_ENTRY_VALUES, entryValues) } override fun onPrepareDialog(dialog: MaterialDialog): MaterialDialog { val integers = ArrayList(entryValues!!.size) entryValues!!.indices.forEach { - if (newValues.contains(entryValues!![it].toString())) + if (newValues.contains(entryValues!![it])) integers.add(it) } - val checkedItems = IntArray(integers.size) {integers[it]} - - val listItem = mutableListOf() - entries!!.forEach { listItem.add(it.toString()) } + val checkedItems = IntArray(integers.size) { integers[it] } + val listItem = entries!!.map { it.toString() } preferenceChanged = false return dialog diff --git a/materialpreference/src/main/java/com/anggrayudi/materialpreference/util/FileUtils.kt b/materialpreference/src/main/java/com/anggrayudi/materialpreference/util/FileUtils.kt index 632a7a8..1991302 100644 --- a/materialpreference/src/main/java/com/anggrayudi/materialpreference/util/FileUtils.kt +++ b/materialpreference/src/main/java/com/anggrayudi/materialpreference/util/FileUtils.kt @@ -144,7 +144,7 @@ object FileUtils { private fun getExternalFile(context: Context, file: String): DocumentFile? { var current = getExternalRoot(context, file) val cleanedPath = cleanSdCardPath(file) - if (!cleanedPath.isEmpty()) { + if (cleanedPath.isNotEmpty()) { val dirs = if (cleanedPath.contains("/")) cleanedPath.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() else arrayOf(cleanedPath) var i = 0 while (i < dirs.size && current != null) { diff --git a/materialpreference/src/main/res/values/attrs.xml b/materialpreference/src/main/res/values/attrs.xml index f08d418..a8d561b 100644 --- a/materialpreference/src/main/res/values/attrs.xml +++ b/materialpreference/src/main/res/values/attrs.xml @@ -5,69 +5,69 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - + - + @@ -75,67 +75,67 @@ - + - - + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - + + + + + @@ -148,46 +148,59 @@ - + - + - + - + - + - + - + - + - + + + + + + + + + + + - + - + - - + + @@ -195,51 +208,51 @@ - + - + - + - + - + - + - + - + - + - + - + - + @@ -249,12 +262,12 @@ - - - - - - + + + + + + @@ -274,8 +287,8 @@ - - + + diff --git a/sample/build.gradle b/sample/build.gradle index af29e65..72359f0 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -69,6 +69,8 @@ dependencies { // compileOnly project(':annotation') kapt project(':processor') +// implementation 'androidx.preference:preference:1.1.0-rc01' + // implementation 'com.anggrayudi:materialpreference:3.1.7' // implementation 'com.anggrayudi:materialpreference-api:1.1' // kapt 'com.anggrayudi:materialpreference-compiler:1.1' diff --git a/sample/src/main/res/values/arrays.xml b/sample/src/main/res/values/arrays.xml index 52de111..1ab5ae1 100644 --- a/sample/src/main/res/values/arrays.xml +++ b/sample/src/main/res/values/arrays.xml @@ -35,4 +35,11 @@ Monthly Whenever ready + + + 1 + 2 + 4 + 8 + \ No newline at end of file diff --git a/sample/src/main/res/xml/preferences.xml b/sample/src/main/res/xml/preferences.xml index aee094d..b2c8924 100644 --- a/sample/src/main/res/xml/preferences.xml +++ b/sample/src/main/res/xml/preferences.xml @@ -28,6 +28,14 @@ android:entryValues="@array/entries_update_interval" app:bindValueToSummary="true"/> + +