From 500f4e41d3a72f5865aa489c89ad11b947fa54b7 Mon Sep 17 00:00:00 2001 From: Jules Aguillon Date: Thu, 10 Aug 2023 12:57:31 +0200 Subject: [PATCH] Allow multiple custom layouts This merges the "Layouts" option with the "Custom layout" option. A custom layout becomes an item in the "Layouts" list among the other layouts. It's possible to add several custom layouts. Selecting the "Custom layout" item in the list opens a second dialog for entering the layout description. Layouts are serialized as JSON object and are decoded solely in the LayoutsPreference class. --- gen_layouts.py | 4 +- res/values-cs/strings.xml | 5 +- res/values-de/strings.xml | 5 +- res/values-es/strings.xml | 5 +- res/values-fa/strings.xml | 5 +- res/values-fr/strings.xml | 5 +- res/values-it/strings.xml | 5 +- res/values-ko/strings.xml | 5 +- res/values-lv/strings.xml | 5 +- res/values-pl/strings.xml | 5 +- res/values-pt/strings.xml | 5 +- res/values-ro/strings.xml | 5 +- res/values-ru/strings.xml | 5 +- res/values-tr/strings.xml | 5 +- res/values-vi/strings.xml | 5 +- res/values-zh-rCN/strings.xml | 5 +- res/values/strings.xml | 6 +- res/xml/settings.xml | 3 - srcs/juloo.keyboard2/Config.java | 38 +---- srcs/juloo.keyboard2/Keyboard2.java | 2 +- srcs/juloo.keyboard2/LayoutsPreference.java | 173 ++++++++++++++++++-- 21 files changed, 194 insertions(+), 107 deletions(-) diff --git a/gen_layouts.py b/gen_layouts.py index 44c3563..c2e6e8d 100644 --- a/gen_layouts.py +++ b/gen_layouts.py @@ -54,9 +54,9 @@ def generate_arrays(out, layouts): item.text = s elem.append(item) return elem - none_item = [ ("system", "@string/pref_layout_e_system") ] + system_item = [ ("system", "@string/pref_layout_e_system") ] custom_item = [ ("custom", "@string/pref_layout_e_custom") ] - values_items, entries_items = zip(*(none_item + layouts + custom_item)) # unzip + values_items, entries_items = zip(*(system_item + layouts + custom_item)) # unzip ids_items = map(lambda s: "@xml/%s" % s if s not in ["system", "custom"] else "-1", values_items) root = XML.Element("resources") root.append(XML.Comment(text="DO NOT EDIT. This file is generated, see gen_layouts.py.")) diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml index 5371835..f4df544 100644 --- a/res/values-cs/strings.xml +++ b/res/values-cs/strings.xml @@ -14,6 +14,7 @@ Vlastní rozvržení Přidat alternativní rozložení Rozložení %1$d: %2$s + Vlastní rozvržení Zobrazit NumPad Nikdy Pouze v režimu na šířku @@ -65,9 +66,6 @@ Velmi dlouhá Horizontální mezery mezi klávesami Vertikální mezery mezi klávesami - Pokročilé - Vlastní rozvržení - Více informací naleznete ve zdrojovém kódu. Tato možnost není určena pro běžné užití. Deaktivovány Dle systému Silné @@ -101,4 +99,5 @@ Indikátor řadové číslovky Horní index Dolní index + Pokročilé diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index 1a20fef..cebedd4 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -14,6 +14,7 @@ Eigenes Layout Alternatives Layout hinzufügen Layout %1$d: %2$s + Eigenes Layout Ziffernblock anzeigen Nie Nur im Querformat @@ -65,9 +66,6 @@ Sehr weit Horizontaler Abstand zwischen den Tasten Vertikaler Abstand zwischen den Tasten - Erweitert - Eigenes Layout - Bitte Sourcecode ansehen. Diese Option ist nicht zur Verwendung vorgesehen. Deaktiviert System Stark @@ -101,4 +99,5 @@ Ordinalzeichen Hochgestellt Tiefgestellt + Erweitert diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index ddc7358..9b26c53 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -14,6 +14,7 @@ Formato personalizado + Formato personalizado Mostrar pad numérico Nunca Solo en modo paisaje @@ -65,9 +66,6 @@ Muy lejana Espaciado horizontal entre las teclas Espaciado vertical entre las teclas - Avanzado - Formato personalizado - Revisar el código fuente. Esta opción no está pensada para ser usada. Deshabilitada Sistema Fuerte @@ -101,4 +99,5 @@ + Avanzado diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml index 87ed44b..32cd8e0 100644 --- a/res/values-fa/strings.xml +++ b/res/values-fa/strings.xml @@ -14,6 +14,7 @@ طرح صفارشی + طرح شخصی نمایش پد شماره‌ها هرگز فقط در حالت افقی @@ -65,9 +66,6 @@ بسیار دور فاصله افقی بین کلیدها فاصله عمودی بین کلیدها - پیشرفته - طرح شخصی - کد منبع را ببینید. این گزینه قرار نیست استفاده شود. @@ -101,4 +99,5 @@ + پیشرفته diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index ee1d60c..b5407bb 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -14,6 +14,7 @@ Disposition personnalisée Ajouter un clavier alternatif Disposition %1$d: %2$s + Disposition personnalisée Afficher le pavé numérique Jamais Seulement en mode paysage @@ -65,9 +66,6 @@ Très longue Espacement horizontal entre les touches Espacement vertical entre les touches - Avancé - Disposition personnalisée - Cette option n\'est pas faite pour être utilisée. Désactivé Système Fort @@ -101,4 +99,5 @@ + Avancé diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml index 9483cec..d8424ad 100644 --- a/res/values-it/strings.xml +++ b/res/values-it/strings.xml @@ -14,6 +14,7 @@ + @@ -65,9 +66,6 @@ Molto distante Spazio orizzontale tra i tasti Spazio verticale tra i tasti - - - @@ -101,4 +99,5 @@ + diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml index eebbe33..1ee49df 100644 --- a/res/values-ko/strings.xml +++ b/res/values-ko/strings.xml @@ -14,6 +14,7 @@ + @@ -65,9 +66,6 @@ 매우 넓음 키보드 양 옆 간격 키보드 세로 간격 - - - @@ -101,4 +99,5 @@ + diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml index 9c339ef..829cd3c 100644 --- a/res/values-lv/strings.xml +++ b/res/values-lv/strings.xml @@ -14,6 +14,7 @@ Pielāgots izkārtojums Pievienot aizstājējizkārtojumu Izkārtojums %1$d: %2$s + Pielāgots izkārtojums Rādīt ciparnīcu Nekad Tikai guleniskajā skatā @@ -65,9 +66,6 @@ Ļoti tāls Līmeniskais attālums starp taustiņiem Stateniskais attālums starp taustiņiem - Papildu - Pielāgots izkārtojums - Skatīt pirmkodu. Šī iespēja nav paredzēta izmantošanai. Atspējota Sistēmas Spēcīga @@ -103,4 +101,5 @@ Kārtas rādītājs Augšraksts Apakšraksts + Papildu diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml index 3e517dc..867d3c5 100644 --- a/res/values-pl/strings.xml +++ b/res/values-pl/strings.xml @@ -14,6 +14,7 @@ Własny układ Dodaj dodatkowy układ Układ %1$d: %2$s + Własny układ Pokaż klawiaturę numeryczną Nigdy Tylko w orientacji poziomej @@ -65,9 +66,6 @@ Bardzo duża Odległość pomiędzy klawiszami w poziomie Odległość pomiędzy klawiszami w pionie - Zaawansowane - Własny układ - Zobacz kod źródłowy. Ta opcja nie jest przeznaczona do użycia. Wyłączone Systemowe Silne @@ -101,4 +99,5 @@ Wskaźnik porządkowy (męski) Indeks górny Indeks dolny + Zaawansowane diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml index ea80b76..f7ac20f 100644 --- a/res/values-pt/strings.xml +++ b/res/values-pt/strings.xml @@ -14,6 +14,7 @@ Layout personalizado Adicione um layout alternativo Layout %1$d: %2$s + Layout personalizado Mostrar Teclado Numérico Nunca Somente no modo paisagem @@ -65,9 +66,6 @@ Muito longo Distância horizontal entre teclas Distância vertical entre teclas - Avançado - Layout personalizado - Veja o código-fonte. Esta opção não deve ser usada. Desabilitado Sistema Intenso @@ -101,4 +99,5 @@ Indicador Ordinal Sobrescrito Subscrito + Avançado diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml index 383f207..0b3beec 100644 --- a/res/values-ro/strings.xml +++ b/res/values-ro/strings.xml @@ -14,6 +14,7 @@ Aranjament personalizat + Aranjament personalizat Arată NumPad Niciodată Doar în mod panoramă @@ -65,9 +66,6 @@ Foarte depărtată Distanța orizontală dintre taste Distanța verticală dintre taste - Setări avansate - Aranjament personalizat - Deschide codul sursă. Această opțiune nu e destinată spre folosință. @@ -101,4 +99,5 @@ + Setări avansate diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index fe97626..e79648d 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -14,6 +14,7 @@ Пользовательская раскладка + Пользовательская раскладка Показывать NumPad Никогда Только в ландшафтном режиме @@ -65,9 +66,6 @@ Очень далеко Горизонтальное расстояние между клавишами Расстояние по вертикали между клавишами - Расширенные настройки - Пользовательская раскладка - Откройте исходный код. Эта параметр не предназначен для использования. @@ -101,4 +99,5 @@ + Расширенные настройки diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml index b277718..4022f2c 100644 --- a/res/values-tr/strings.xml +++ b/res/values-tr/strings.xml @@ -14,6 +14,7 @@ + @@ -65,9 +66,6 @@ Çok uzun Tuşlar arasındaki yatay boşluk Tuşlar arasındaki dikey boşluk - - - @@ -101,4 +99,5 @@ + diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml index 31c8ec6..1037d9b 100644 --- a/res/values-vi/strings.xml +++ b/res/values-vi/strings.xml @@ -14,6 +14,7 @@ Tùy chỉnh bố cục + Tùy chỉnh bố cục Hiện NumPad Không bao giờ Chỉ trong chế độ phong cảnh @@ -65,9 +66,6 @@ Rất xa Khoảng cách giữa các phím theo chiều ngang Khoảng cách giữa các phím theo chiều dọc - Nâng cao - Tùy chỉnh bố cục - Hãy xem mã nguồn. Lựa chọn này không có mục đích sử dụng. @@ -101,4 +99,5 @@ + Nâng cao diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml index 7f6129b..80277b0 100644 --- a/res/values-zh-rCN/strings.xml +++ b/res/values-zh-rCN/strings.xml @@ -14,6 +14,7 @@ 自定义布局 + 自定义布局 显示数字小键盘 从不 只在横屏显示 @@ -65,9 +66,6 @@ 非常长 按键的左右边距 按键的上下边距 - 高级设置 - 自定义布局 - 请查看源代码。这个选项不应该在正常情况下使用。 禁用 使用系统振动强度 @@ -101,4 +99,5 @@ + 高级设置 diff --git a/res/values/strings.xml b/res/values/strings.xml index 72e651a..c8620f7 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -14,6 +14,7 @@ Custom layout Add an alternate layout Layout %1$d: %2$s + Custom layout Show NumPad Never Only in landscape mode @@ -65,9 +66,6 @@ Very far Horizontal spacing between the keys Vertical spacing between the keys - Advanced - Custom layout - See the source code. This option is not meant to be used. Disabled System Strong @@ -101,4 +99,6 @@ Ordinal Indicator Superscript Subscript + + Advanced diff --git a/res/xml/settings.xml b/res/xml/settings.xml index c670dfb..f6467d6 100644 --- a/res/xml/settings.xml +++ b/res/xml/settings.xml @@ -46,7 +46,4 @@ - - - diff --git a/srcs/juloo.keyboard2/Config.java b/srcs/juloo.keyboard2/Config.java index 24565ab..4684194 100644 --- a/srcs/juloo.keyboard2/Config.java +++ b/srcs/juloo.keyboard2/Config.java @@ -3,7 +3,6 @@ package juloo.keyboard2; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; -import android.content.res.TypedArray; import android.os.Build; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -28,7 +27,6 @@ final class Config // From preferences /** [null] represent the [system] layout. */ public List layouts; - public KeyboardData custom_layout; // Might be 'null' public boolean show_numpad = false; // From the 'numpad_layout' option, also apply to the numeric pane. public boolean inverse_numpad = false; @@ -114,11 +112,7 @@ final class Config { keyboardHeightPercent = _prefs.getInt("keyboard_height", 35); } - List layout_names = LayoutsPreference.load_from_preferences(_prefs); - layouts = new ArrayList(); - for (String l : layout_names) - layouts.add(layout_of_string(res, l)); - custom_layout = KeyboardData.load_string(_prefs.getString("custom_layout", "")); + layouts = LayoutsPreference.load_from_preferences(res, _prefs); inverse_numpad = _prefs.getString("numpad_layout", "default").equals("low_first"); number_row = _prefs.getBoolean("number_row", false); // The baseline for the swipe distance correspond to approximately the @@ -335,36 +329,6 @@ final class Config } } - /** Obtained from XML. */ - static List layout_ids_str = null; - static TypedArray layout_ids_res = null; - - /** Might return [null] if the selected layout is "system", "custom" or if - the name is not recognized. */ - public KeyboardData layout_of_string(Resources res, String name) - { - if (layout_ids_str == null) - { - layout_ids_str = Arrays.asList(res.getStringArray(R.array.pref_layout_values)); - layout_ids_res = res.obtainTypedArray(R.array.layout_ids); - } - int i = layout_ids_str.indexOf(name); - if (i >= 0) - { - int id = layout_ids_res.getResourceId(i, 0); - if (id > 0) - return KeyboardData.load(res, id); - // Fallthrough - } - switch (name) - { - case "custom": return custom_layout; - case "system": - case "none": - default: return null; - } - } - char inverse_numpad_char(char c) { switch (c) diff --git a/srcs/juloo.keyboard2/Keyboard2.java b/srcs/juloo.keyboard2/Keyboard2.java index 5f7442b..92507ed 100644 --- a/srcs/juloo.keyboard2/Keyboard2.java +++ b/srcs/juloo.keyboard2/Keyboard2.java @@ -155,7 +155,7 @@ public class Keyboard2 extends InputMethodService { String s = subtype.getExtraValueOf("default_layout"); if (s != null) - default_layout = _config.layout_of_string(getResources(), s); + default_layout = LayoutsPreference.layout_of_string(getResources(), s); refreshAccentsOption(imm, subtype); } } diff --git a/srcs/juloo.keyboard2/LayoutsPreference.java b/srcs/juloo.keyboard2/LayoutsPreference.java index ba28630..a65b350 100644 --- a/srcs/juloo.keyboard2/LayoutsPreference.java +++ b/srcs/juloo.keyboard2/LayoutsPreference.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.SharedPreferences; import android.content.res.Resources; +import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.ArrayAdapter; import android.widget.EditText; @@ -12,16 +13,17 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import org.json.JSONException; +import org.json.JSONObject; -public class LayoutsPreference extends ListGroupPreference +public class LayoutsPreference extends ListGroupPreference { static final String KEY = "layouts"; - static final List DEFAULT = Collections.singletonList("system"); - static final ListGroupPreference.Serializer SERIALIZER = - new ListGroupPreference.StringSerializer(); + static final List DEFAULT = + Collections.singletonList((Layout)new SystemLayout()); + static final ListGroupPreference.Serializer SERIALIZER = + new Serializer(); - /** Layout names as stored in the preferences. */ - List _layout_names; /** Text displayed for each layout in the dialog list. */ String[] _layout_display_names; @@ -30,13 +32,56 @@ public class LayoutsPreference extends ListGroupPreference super(ctx, attrs); setKey(KEY); Resources res = ctx.getResources(); - _layout_names = Arrays.asList(res.getStringArray(R.array.pref_layout_values)); _layout_display_names = res.getStringArray(R.array.pref_layout_entries); } - public static List load_from_preferences(SharedPreferences prefs) + /** Obtained from [res/values/layouts.xml]. */ + static List _unsafe_layout_ids_str = null; + static TypedArray _unsafe_layout_ids_res = null; + + /** Layout internal names. Contains "system" and "custom". */ + public static List get_layout_names(Resources res) { - return load_from_preferences(KEY, prefs, DEFAULT, SERIALIZER); + if (_unsafe_layout_ids_str == null) + _unsafe_layout_ids_str = Arrays.asList( + res.getStringArray(R.array.pref_layout_values)); + return _unsafe_layout_ids_str; + } + + /** Layout resource id for a layout name. [-1] if not found. */ + public static int layout_id_of_name(Resources res, String name) + { + if (_unsafe_layout_ids_res == null) + _unsafe_layout_ids_res = res.obtainTypedArray(R.array.layout_ids); + int i = get_layout_names(res).indexOf(name); + if (i >= 0) + return _unsafe_layout_ids_res.getResourceId(i, 0); + return -1; + } + + /** [null] for the "system" layout. */ + public static List load_from_preferences(Resources res, SharedPreferences prefs) + { + List layouts = new ArrayList(); + for (Layout l : load_from_preferences(KEY, prefs, DEFAULT, SERIALIZER)) + { + if (l instanceof NamedLayout) + layouts.add(layout_of_string(res, ((NamedLayout)l).name)); + else if (l instanceof CustomLayout) + layouts.add(KeyboardData.load_string(((CustomLayout)l).xml)); + else // instanceof SystemLayout + layouts.add(null); + } + return layouts; + } + + public static KeyboardData layout_of_string(Resources res, String name) + { + int id = layout_id_of_name(res, name); + if (id > 0) + return KeyboardData.load(res, id); + // Might happen when the app is downgraded, return the system layout. + return null; } @Override @@ -44,15 +89,28 @@ public class LayoutsPreference extends ListGroupPreference { super.onSetInitialValue(restoreValue, defaultValue); if (_values.size() == 0) - set_values(new ArrayList(DEFAULT), false); + set_values(new ArrayList(DEFAULT), false); + } + + String label_of_layout(Layout l) + { + if (l instanceof NamedLayout) + { + String lname = ((NamedLayout)l).name; + int value_i = get_layout_names(getContext().getResources()).indexOf(lname); + return value_i < 0 ? lname : _layout_display_names[value_i]; + } + else if (l instanceof CustomLayout) + return getContext().getString(R.string.pref_layout_e_custom); + else // instanceof SystemLayout + return getContext().getString(R.string.pref_layout_e_system); } @Override - String label_of_value(String value, int i) + String label_of_value(Layout value, int i) { - int value_i = _layout_names.indexOf(value); - String lname = value_i < 0 ? value : _layout_display_names[value_i]; - return getContext().getString(R.string.pref_layouts_item, i + 1, lname); + return getContext().getString(R.string.pref_layouts_item, i + 1, + label_of_layout(value)); } @Override @@ -70,7 +128,7 @@ public class LayoutsPreference extends ListGroupPreference } @Override - Serializer get_serializer() { return SERIALIZER; } + ListGroupPreference.Serializer get_serializer() { return SERIALIZER; } @Override void select(final SelectionCallback callback) @@ -81,12 +139,40 @@ public class LayoutsPreference extends ListGroupPreference .setAdapter(layouts, new DialogInterface.OnClickListener(){ public void onClick(DialogInterface _dialog, int which) { - callback.select(_layout_names.get(which)); + String name = get_layout_names(getContext().getResources()).get(which); + switch (name) + { + case "system": + callback.select(new SystemLayout()); + break; + case "custom": + select_custom(callback); + break; + default: + callback.select(new NamedLayout(name)); + break; + } } }) .show(); } + void select_custom(final SelectionCallback callback) + { + new AlertDialog.Builder(getContext()) + .setView(R.layout.dialog_edit_text) + .setTitle(R.string.pref_custom_layout_title) + .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener(){ + public void onClick(DialogInterface dialog, int _which) + { + EditText input = (EditText)((AlertDialog)dialog).findViewById(R.id.text); + callback.select(new CustomLayout(input.getText().toString())); + } + }) + .setNegativeButton(android.R.string.cancel, null) + .show(); + } + class LayoutsAddButton extends AddButton { public LayoutsAddButton(Context ctx) @@ -95,4 +181,59 @@ public class LayoutsPreference extends ListGroupPreference setLayoutResource(R.layout.pref_layouts_add_btn); } } + + /** A layout selected by the user. The only implementations are + [NamedLayout], [SystemLayout] and [CustomLayout]. */ + interface Layout {} + + static final class SystemLayout implements Layout + { + public SystemLayout() {} + } + + /** The name of a layout defined in [res/xml]. */ + static final class NamedLayout implements Layout + { + public final String name; + public NamedLayout(String n) { name = n; } + } + + /** The XML description of a custom layout. */ + static final class CustomLayout implements Layout + { + public final String xml; + public CustomLayout(String c) { xml = c; } + } + + /** Named layouts are serialized to strings and custom layouts to JSON + objects with a [kind] field. */ + static class Serializer implements ListGroupPreference.Serializer + { + public Layout load_item(Object obj) throws JSONException + { + if (obj instanceof String) + { + String name = (String)obj; + if (name.equals("system")) + return new SystemLayout(); + return new NamedLayout(name); + } + JSONObject obj_ = (JSONObject)obj; + switch (obj_.getString("kind")) + { + case "custom": return new CustomLayout(obj_.getString("xml")); + case "system": default: return new SystemLayout(); + } + } + + public Object save_item(Layout v) throws JSONException + { + if (v instanceof NamedLayout) + return ((NamedLayout)v).name; + if (v instanceof CustomLayout) + return new JSONObject().put("kind", "custom") + .put("xml", ((CustomLayout)v).xml); + return new JSONObject().put("kind", "system"); + } + } }