Skip to content

Commit c0d9c20

Browse files
committed
Add VersatileTextWithASwitchPreference
VersatileTextWithASwitchPreference is a combination of a TextPreference and a SwitchPreference. It mostly looks like a SwitchPreference, but the switch and the title can be clicked separately. The behavior is a bit special, see the javadoc for explanation.
1 parent b781020 commit c0d9c20

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
/*
2+
* This program is free software; you can redistribute it and/or modify it under
3+
* the terms of the GNU General Public License as published by the Free Software
4+
* Foundation; either version 3 of the License, or (at your option) any later
5+
* version.
6+
*
7+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
8+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9+
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public License along with
12+
* this program. If not, see <http://www.gnu.org/licenses/>.
13+
*/
14+
15+
package com.ichi2.preferences
16+
17+
import android.content.Context
18+
import android.util.AttributeSet
19+
import androidx.appcompat.widget.SwitchCompat
20+
import androidx.core.content.edit
21+
import androidx.preference.EditTextPreference
22+
import androidx.preference.PreferenceViewHolder
23+
import com.ichi2.anki.R
24+
25+
/**
26+
* A combination of an EditTextPreference and a SwitchPreference.
27+
* It mostly looks like a SwitchPreference, but the switch and the title can be clicked separately.
28+
* If some text is set, it is possible to have the switch either of on off.
29+
* However, if text is null or empty, the switch can only be in the off state.
30+
*
31+
* The text value is stored with the key of the preference.
32+
* The key of the switch is suffixed with [SWITCH_SUFFIX].
33+
*
34+
* Notes on behavior:
35+
* * If text is present, tapping on the switch toggles it.
36+
* * If text is empty, tapping on the switch will open the dialog, as if the title was tapped.
37+
* * If the dialog is closed with Cancel, no changes happen.
38+
* * If the dialog is closed with Ok, and text is present, the switch will be set to on.
39+
* * If the dialog is closed with Ok, and text is empty, the switch will be set to off.
40+
*
41+
* The preference inherits from [VersatileTextPreference] and supports any attributes it does,
42+
* including the regular [EditTextPreference] attributes.
43+
*/
44+
class VersatileTextWithASwitchPreference(context: Context, attrs: AttributeSet?) :
45+
VersatileTextPreference(context, attrs), DialogFragmentProvider {
46+
47+
init { widgetLayoutResource = R.layout.preference_widget_switch_with_separator }
48+
49+
private val preferences get() = sharedPreferences!!
50+
51+
private val switchKey get() = key + SWITCH_SUFFIX
52+
53+
private val canBeSwitchedOn get() = !text.isNullOrEmpty()
54+
55+
// * If there is no text, we make the switch not focusable and not clickable.
56+
// This is exactly how SwitchPreference sets up its widget;
57+
// if you tap on the switch, it will behave as if you tapped on the preference itself.
58+
// * If there is text, the switch can be tapped separately.
59+
override fun onBindViewHolder(holder: PreferenceViewHolder) {
60+
super.onBindViewHolder(holder)
61+
62+
val switch = holder.findViewById(R.id.switch_widget) as SwitchCompat
63+
64+
switch.isFocusable = canBeSwitchedOn
65+
switch.isClickable = canBeSwitchedOn
66+
67+
switch.isChecked = preferences.getBoolean(switchKey, false)
68+
69+
switch.setOnCheckedChangeListener { _, checked ->
70+
preferences.edit { putBoolean(switchKey, checked) }
71+
}
72+
}
73+
74+
fun onDialogClosedAndNewTextSet() {
75+
preferences.edit { putBoolean(switchKey, canBeSwitchedOn) }
76+
}
77+
78+
override fun makeDialogFragment() = VersatileTextWithASwitchPreferenceDialogFragment()
79+
80+
companion object {
81+
const val SWITCH_SUFFIX = "_switch"
82+
}
83+
}
84+
85+
class VersatileTextWithASwitchPreferenceDialogFragment : VersatileTextPreferenceDialogFragment() {
86+
87+
// This replicates what the overridden method does, which is needed as we want to catch
88+
// the event when the Ok button was pressed and the change listener approved the new value.
89+
override fun onDialogClosed(positiveResult: Boolean) {
90+
if (positiveResult) {
91+
val preference = preference as VersatileTextWithASwitchPreference
92+
val newText = editText.text.toString()
93+
94+
if (preference.callChangeListener(newText)) {
95+
preference.text = newText
96+
preference.onDialogClosedAndNewTextSet()
97+
}
98+
}
99+
}
100+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:layout_width="wrap_content"
4+
android:layout_height="wrap_content"
5+
android:orientation="horizontal"
6+
>
7+
8+
<View
9+
android:layout_width="1dp"
10+
android:layout_height="match_parent"
11+
android:background="#66888888"
12+
android:layout_marginVertical="16dp"
13+
/>
14+
15+
<androidx.appcompat.widget.SwitchCompat
16+
android:id="@+id/switch_widget"
17+
android:layout_width="wrap_content"
18+
android:layout_height="match_parent"
19+
android:paddingStart="16dp"
20+
android:background="@null"
21+
/>
22+
</LinearLayout>

0 commit comments

Comments
 (0)