ListGroupPreference: Make items abstract

Allow items to be of any class instead of strings.

Item serialization and deserialization methods are in a separate class
because they are also used in a static context.
This commit is contained in:
Jules Aguillon 2023-08-08 17:58:27 +02:00
parent 20ab3915e8
commit 0269cd65ea
3 changed files with 70 additions and 35 deletions

View File

@ -17,10 +17,12 @@ import org.json.JSONException;
/** Allows to enter custom keys to be added to the keyboard. This shows up at /** Allows to enter custom keys to be added to the keyboard. This shows up at
the top of the "Add keys to the keyboard" option. */ the top of the "Add keys to the keyboard" option. */
public class CustomExtraKeysPreference extends ListGroupPreference public class CustomExtraKeysPreference extends ListGroupPreference<String>
{ {
/** This pref stores a list of strings encoded as JSON. */ /** This pref stores a list of strings encoded as JSON. */
static final String KEY = "custom_extra_keys"; static final String KEY = "custom_extra_keys";
static final ListGroupPreference.Serializer<String> SERIALIZER =
new ListGroupPreference.StringSerializer();
public CustomExtraKeysPreference(Context context, AttributeSet attrs) public CustomExtraKeysPreference(Context context, AttributeSet attrs)
{ {
@ -31,7 +33,7 @@ public class CustomExtraKeysPreference extends ListGroupPreference
public static List<KeyValue> get(SharedPreferences prefs) public static List<KeyValue> get(SharedPreferences prefs)
{ {
List<KeyValue> kvs = new ArrayList<KeyValue>(); List<KeyValue> kvs = new ArrayList<KeyValue>();
List<String> key_names = load_from_preferences(KEY, prefs, null); List<String> key_names = load_from_preferences(KEY, prefs, null, SERIALIZER);
if (key_names != null) if (key_names != null)
{ {
for (String key_name : key_names) for (String key_name : key_names)
@ -40,8 +42,10 @@ public class CustomExtraKeysPreference extends ListGroupPreference
return kvs; return kvs;
} }
String label_of_value(String value, int i) { return value; }
@Override @Override
void select(final SelectionCallback callback) void select(final SelectionCallback<String> callback)
{ {
new AlertDialog.Builder(getContext()) new AlertDialog.Builder(getContext())
.setView(R.layout.custom_extra_key_add_dialog) .setView(R.layout.custom_extra_key_add_dialog)
@ -58,4 +62,7 @@ public class CustomExtraKeysPreference extends ListGroupPreference
.setIcon(android.R.drawable.ic_dialog_alert) .setIcon(android.R.drawable.ic_dialog_alert)
.show(); .show();
} }
@Override
Serializer<String> get_serializer() { return SERIALIZER; }
} }

View File

@ -13,10 +13,12 @@ import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class LayoutsPreference extends ListGroupPreference public class LayoutsPreference extends ListGroupPreference<String>
{ {
static final String KEY = "layouts"; static final String KEY = "layouts";
static final List<String> DEFAULT = Collections.singletonList("system"); static final List<String> DEFAULT = Collections.singletonList("system");
static final ListGroupPreference.Serializer<String> SERIALIZER =
new ListGroupPreference.StringSerializer();
/** Layout names as stored in the preferences. */ /** Layout names as stored in the preferences. */
List<String> _layout_names; List<String> _layout_names;
@ -34,7 +36,7 @@ public class LayoutsPreference extends ListGroupPreference
public static List<String> load_from_preferences(SharedPreferences prefs) public static List<String> load_from_preferences(SharedPreferences prefs)
{ {
return load_from_preferences(KEY, prefs, DEFAULT); return load_from_preferences(KEY, prefs, DEFAULT, SERIALIZER);
} }
@Override @Override
@ -67,6 +69,9 @@ public class LayoutsPreference extends ListGroupPreference
return (_values.size() > 1); return (_values.size() > 1);
} }
@Override
Serializer<String> get_serializer() { return SERIALIZER; }
void select(final SelectionCallback callback) void select(final SelectionCallback callback)
{ {
ArrayAdapter layouts = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, _layout_display_names); ArrayAdapter layouts = new ArrayAdapter(getContext(), android.R.layout.simple_list_item_1, _layout_display_names);

View File

@ -15,10 +15,10 @@ import org.json.JSONException;
/** A list of preferences where the users can add items to the end and modify /** A list of preferences where the users can add items to the end and modify
and remove items. Backed by a string list. Implement user selection in and remove items. Backed by a string list. Implement user selection in
[select()]. */ [select()]. */
public abstract class ListGroupPreference extends PreferenceGroup public abstract class ListGroupPreference<E> extends PreferenceGroup
{ {
boolean _attached = false; boolean _attached = false;
List<String> _values; List<E> _values;
/** The "add" button currently displayed. */ /** The "add" button currently displayed. */
AddButton _add_button = null; AddButton _add_button = null;
@ -27,16 +27,13 @@ public abstract class ListGroupPreference extends PreferenceGroup
super(context, attrs); super(context, attrs);
setOrderingAsAdded(true); setOrderingAsAdded(true);
setLayoutResource(R.layout.pref_listgroup_group); setLayoutResource(R.layout.pref_listgroup_group);
_values = new ArrayList<String>(); _values = new ArrayList<E>();
} }
/** Overrideable */ /** Overrideable */
/** The label to display on the item for a given value. */ /** The label to display on the item for a given value. */
String label_of_value(String value, int i) abstract String label_of_value(E value, int i);
{
return value;
}
/** Called every time the list changes and allows to change the "Add" button /** Called every time the list changes and allows to change the "Add" button
appearance. appearance.
@ -58,29 +55,34 @@ public abstract class ListGroupPreference extends PreferenceGroup
/** Called when an item is added or modified. Returns [null] to cancel the /** Called when an item is added or modified. Returns [null] to cancel the
action. */ action. */
abstract void select(SelectionCallback callback); abstract void select(SelectionCallback<E> callback);
/** A separate class is used as the same serializer must be used in the
static context. See [Serializer] below. */
abstract Serializer<E> get_serializer();
/** Load/save utils */ /** Load/save utils */
/** Read a value saved by preference from a [SharedPreferences] object. /** Read a value saved by preference from a [SharedPreferences] object.
[serializer] must be the same that is returned by [get_serializer()].
Returns [null] on error. */ Returns [null] on error. */
static List<String> load_from_preferences(String key, static <E> List<E> load_from_preferences(String key,
SharedPreferences prefs, List<String> def) SharedPreferences prefs, List<E> def, Serializer<E> serializer)
{ {
String s = prefs.getString(key, null); String s = prefs.getString(key, null);
return (s != null) ? load_from_string(s) : def; return (s != null) ? load_from_string(s, serializer) : def;
} }
/** Decode a list of string previously encoded with [save_to_string]. Returns /** Decode a list of string previously encoded with [save_to_string]. Returns
[null] on error. */ [null] on error. */
static List<String> load_from_string(String inp) static <E> List<E> load_from_string(String inp, Serializer<E> serializer)
{ {
try try
{ {
List<String> l = new ArrayList<String>(); List<E> l = new ArrayList<E>();
JSONArray arr = new JSONArray(inp); JSONArray arr = new JSONArray(inp);
for (int i = 0; i < arr.length(); i++) for (int i = 0; i < arr.length(); i++)
l.add(arr.getString(i)); l.add(serializer.load_item(arr.get(i)));
return l; return l;
} }
catch (JSONException e) catch (JSONException e)
@ -91,29 +93,32 @@ public abstract class ListGroupPreference extends PreferenceGroup
/** Encode a list of string so it can be passed to /** Encode a list of string so it can be passed to
[Preference.persistString()]. Decode with [load_from_string]. */ [Preference.persistString()]. Decode with [load_from_string]. */
static String save_to_string(List<String> l) static <E> String save_to_string(List<E> items, Serializer<E> serializer)
{ {
return (new JSONArray(l)).toString(); List<Object> serialized_items = new ArrayList<Object>();
for (E it : items)
serialized_items.add(serializer.save_item(it));
return (new JSONArray(serialized_items)).toString();
} }
/** Protected API */ /** Protected API */
/** Set the values. If [persist] is [true], persist into the store. */ /** Set the values. If [persist] is [true], persist into the store. */
void set_values(List<String> vs, boolean persist) void set_values(List<E> vs, boolean persist)
{ {
_values = vs; _values = vs;
reattach(); reattach();
if (persist) if (persist)
persistString(save_to_string(vs)); persistString(save_to_string(vs, get_serializer()));
} }
void add_item(String v) void add_item(E v)
{ {
_values.add(v); _values.add(v);
set_values(_values, true); set_values(_values, true);
} }
void change_item(int i, String v) void change_item(int i, E v)
{ {
_values.set(i, v); _values.set(i, v);
set_values(_values, true); set_values(_values, true);
@ -133,7 +138,7 @@ public abstract class ListGroupPreference extends PreferenceGroup
String input = (restoreValue) ? getPersistedString(null) : (String)defaultValue; String input = (restoreValue) ? getPersistedString(null) : (String)defaultValue;
if (input != null) if (input != null)
{ {
List<String> values = load_from_string(input); List<E> values = load_from_string(input, get_serializer());
if (values != null) if (values != null)
set_values(values, false); set_values(values, false);
} }
@ -156,7 +161,7 @@ public abstract class ListGroupPreference extends PreferenceGroup
removeAll(); removeAll();
boolean allow_remove_item = should_allow_remove_item(); boolean allow_remove_item = should_allow_remove_item();
int i = 0; int i = 0;
for (String v : _values) for (E v : _values)
{ {
addPreference(this.new Item(getContext(), i, v, allow_remove_item)); addPreference(this.new Item(getContext(), i, v, allow_remove_item));
i++; i++;
@ -168,10 +173,10 @@ public abstract class ListGroupPreference extends PreferenceGroup
class Item extends Preference class Item extends Preference
{ {
final String _value; final E _value;
final int _index; final int _index;
public Item(Context ctx, int index, String value, boolean allow_remove) public Item(Context ctx, int index, E value, boolean allow_remove)
{ {
super(ctx); super(ctx);
_value = value; _value = value;
@ -185,8 +190,8 @@ public abstract class ListGroupPreference extends PreferenceGroup
@Override @Override
protected void onClick() protected void onClick()
{ {
select(new SelectionCallback() { select(new SelectionCallback<E>() {
public void select(String value) public void select(E value)
{ {
change_item(_index, value); change_item(_index, value);
} }
@ -222,8 +227,8 @@ public abstract class ListGroupPreference extends PreferenceGroup
@Override @Override
protected void onClick() protected void onClick()
{ {
select(new SelectionCallback() { select(new SelectionCallback<E>() {
public void select(String value) public void select(E value)
{ {
add_item(value); add_item(value);
} }
@ -231,8 +236,26 @@ public abstract class ListGroupPreference extends PreferenceGroup
} }
} }
public interface SelectionCallback public interface SelectionCallback<E>
{ {
public void select(String value); public void select(E value);
}
/** Methods for serializing and deserializing abstract items.
[StringSerializer] is an implementation. */
public interface Serializer<E>
{
/** [obj] is an object returned by [save_item()]. */
E load_item(Object obj);
/** Serialize an item into JSON. Might return an object that can be inserted
in a [JSONArray]. */
Object save_item(E v);
}
public static class StringSerializer implements Serializer<String>
{
public String load_item(Object obj) { return (String)obj; }
public Object save_item(String v) { return v; }
} }
} }