1
0
Fork 0

New languages screen (#595)

* added a dictionary size property

* new language selection screen

* added a language search field

* SettingsStore now return a copy of the enabled languages to prevent accidental overwriting of the original settings object
This commit is contained in:
Dimo Karaivanov 2024-08-08 14:59:50 +03:00 committed by GitHub
parent 76099862e5
commit 2eea62b26f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 540 additions and 160 deletions

View file

@ -103,8 +103,14 @@ android {
flavorDimensions = ['app'] flavorDimensions = ['app']
productFlavors { productFlavors {
full { dimension 'app' } full {
lite { dimension 'app' } dimension 'app'
buildConfigField 'Boolean', 'LITE', 'false'
}
lite {
dimension 'app'
buildConfigField 'Boolean', 'LITE', 'true'
}
} }
applicationVariants.configureEach { variant -> applicationVariants.configureEach { variant ->

View file

@ -2,8 +2,9 @@ ext.getDictionaryProperties = { dictionariesDir, sizesDir ->
fileTree(dir: dictionariesDir).getFiles().parallelStream().forEach {dictionary -> fileTree(dir: dictionariesDir).getFiles().parallelStream().forEach {dictionary ->
def hash = dictionary.exists() ? dictionary.text.digest("SHA-1") : "" def hash = dictionary.exists() ? dictionary.text.digest("SHA-1") : ""
def revision = dictionary.exists() ? exec("git log --pretty=tformat:%H -n 1 ${dictionary}") : "" def revision = dictionary.exists() ? exec("git log --pretty=tformat:%H -n 1 ${dictionary}") : ""
def size = dictionary.exists() ? dictionary.length() : 0
def words = dictionary.exists() ? dictionary.text.split("\n").length : 0 def words = dictionary.exists() ? dictionary.text.split("\n").length : 0
new File(sizesDir, "${dictionary.getName()}.props.yml").text = "hash: ${hash}\nrevision: ${revision}\nwords: ${words}" new File(sizesDir, "${dictionary.getName()}.props.yml").text = "hash: ${hash}\nrevision: ${revision}\nsize: ${size}\nwords: ${words}"
} }
} }

View file

@ -53,6 +53,26 @@ public class WordStore {
} }
/**
* Returns a list of the languages that are already loaded in the database.
*/
public ArrayList<Integer> exists(ArrayList<Language> languages) {
ArrayList<Integer> loadedLanguages = new ArrayList<>();
if (!checkOrNotify()) {
return loadedLanguages;
}
for (Language language : languages) {
if (readOps.exists(sqlite.getDb(), language.getId())) {
loadedLanguages.add(language.getId());
}
}
return loadedLanguages;
}
/** /**
* Loads words matching and similar to a given digit sequence * Loads words matching and similar to a given digit sequence
* For example: "7655" -> "roll" (exact match), but also: "rolled", "roller", "rolling", ... * For example: "7655" -> "roll" (exact match), but also: "rolled", "roller", "rolling", ...

View file

@ -79,4 +79,11 @@ public class WordStoreAsync {
getStore().getSimilarCustom(language, wordFilter))) getStore().getSimilarCustom(language, wordFilter)))
).start(); ).start();
} }
public static void exists(ConsumerCompat<ArrayList<Integer>> dataHandler, ArrayList<Language> languages) {
new Thread(() -> asyncHandler.post(() -> dataHandler.accept(
getStore().exists(languages))
)).start();
}
} }

View file

@ -24,6 +24,7 @@ public class WordFile {
private String hash = null; private String hash = null;
private String downloadUrl = null; private String downloadUrl = null;
private int totalLines = -1; private int totalLines = -1;
private long size = -1;
public WordFile(Context context, String name, AssetManager assets) { public WordFile(Context context, String name, AssetManager assets) {
@ -151,6 +152,29 @@ public class WordFile {
} }
public long getSize() {
if (size < 0) {
loadProperties();
}
return size;
}
private void setSize(String rawProperty, String rawValue) {
if (!rawProperty.equals("size")) {
return;
}
try {
size = Long.parseLong(rawValue);
} catch (Exception e) {
Logger.w(LOG_TAG, "Invalid 'size' property of: " + name + ". Expecting an integer, got: '" + rawValue + "'.");
size = 0;
}
}
private void loadProperties() { private void loadProperties() {
String propertyFilename = name + ".props.yml"; String propertyFilename = name + ".props.yml";
@ -164,6 +188,7 @@ public class WordFile {
setDownloadUrl(parts[0], parts[1]); setDownloadUrl(parts[0], parts[1]);
setHash(parts[0], parts[1]); setHash(parts[0], parts[1]);
setTotalLines(parts[0], parts[1]); setTotalLines(parts[0], parts[1]);
setSize(parts[0], parts[1]);
} }
} catch (Exception e) { } catch (Exception e) {
Logger.w(LOG_TAG, "Could not read the property file: " + propertyFilename + ". " + e.getMessage()); Logger.w(LOG_TAG, "Could not read the property file: " + propertyFilename + ". " + e.getMessage());

View file

@ -17,6 +17,7 @@ public class NaturalLanguage extends Language implements Comparable<NaturalLangu
final public static String PREFERRED_CHAR_SEQUENCE = "00"; final public static String PREFERRED_CHAR_SEQUENCE = "00";
private String localizedName = null;
protected final ArrayList<ArrayList<String>> layout = new ArrayList<>(); protected final ArrayList<ArrayList<String>> layout = new ArrayList<>();
private final HashMap<Character, String> characterKeyMap = new HashMap<>(); private final HashMap<Character, String> characterKeyMap = new HashMap<>();
@ -183,6 +184,15 @@ public class NaturalLanguage extends Language implements Comparable<NaturalLangu
} }
public String getLocalizedName() {
if (localizedName == null) {
localizedName = locale.getDisplayName();
}
return localizedName;
}
private void generateCharacterKeyMap() { private void generateCharacterKeyMap() {
characterKeyMap.clear(); characterKeyMap.clear();
for (int digit = 0; digit <= 9; digit++) { for (int digit = 0; digit <= 9; digit++) {

View file

@ -25,6 +25,7 @@ import io.github.sspanak.tt9.preferences.screens.debug.DebugScreen;
import io.github.sspanak.tt9.preferences.screens.deleteWords.DeleteWordsScreen; import io.github.sspanak.tt9.preferences.screens.deleteWords.DeleteWordsScreen;
import io.github.sspanak.tt9.preferences.screens.hotkeys.HotkeysScreen; import io.github.sspanak.tt9.preferences.screens.hotkeys.HotkeysScreen;
import io.github.sspanak.tt9.preferences.screens.keypad.KeyPadScreen; import io.github.sspanak.tt9.preferences.screens.keypad.KeyPadScreen;
import io.github.sspanak.tt9.preferences.screens.languageSelection.LanguageSelectionScreen;
import io.github.sspanak.tt9.preferences.screens.languages.LanguagesScreen; import io.github.sspanak.tt9.preferences.screens.languages.LanguagesScreen;
import io.github.sspanak.tt9.preferences.screens.main.MainSettingsScreen; import io.github.sspanak.tt9.preferences.screens.main.MainSettingsScreen;
import io.github.sspanak.tt9.preferences.screens.setup.SetupScreen; import io.github.sspanak.tt9.preferences.screens.setup.SetupScreen;
@ -143,6 +144,8 @@ public class PreferencesActivity extends ActivityWithNavigation implements Prefe
return new KeyPadScreen(this); return new KeyPadScreen(this);
case LanguagesScreen.NAME: case LanguagesScreen.NAME:
return new LanguagesScreen(this); return new LanguagesScreen(this);
case LanguageSelectionScreen.NAME:
return new LanguageSelectionScreen(this);
case SetupScreen.NAME: case SetupScreen.NAME:
return new SetupScreen(this); return new SetupScreen(this);
case UsageStatsScreen.NAME: case UsageStatsScreen.NAME:

View file

@ -0,0 +1,68 @@
package io.github.sspanak.tt9.preferences.items;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceViewHolder;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.custom.ScreenPreference;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
abstract public class ItemTextInput extends ScreenPreference implements TextWatcher {
@NonNull private final Handler debouncer = new Handler(Looper.getMainLooper());
private int debounceTime = SettingsStore.TEXT_INPUT_DEBOUNCE_TIME;
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ItemTextInput(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public ItemTextInput(@NonNull Context context) {
super(context);
}
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
EditText editText = holder.itemView.findViewById(R.id.input_text_input_field);
if (editText == null) {
Logger.e(getClass().getSimpleName(), "Cannot attach a text change listener. Unable to find the EditText element.");
} else {
editText.addTextChangedListener(this);
}
}
@Override protected int getDefaultLayout() { return R.layout.pref_input_text; }
@Override protected int getLargeLayout() { return R.layout.pref_input_text_large; }
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
@Override
public void afterTextChanged(Editable s) {
if (debounceTime > 0) {
debouncer.removeCallbacksAndMessages(null);
debouncer.postDelayed(() -> onChange(s.toString()), debounceTime);
} else {
onChange(s.toString());
}
}
protected abstract void onChange(String word);
}

View file

@ -41,7 +41,7 @@ class DeletableWordsList {
void addNoResult(boolean noSearchTerm) { void addNoResult(boolean noSearchTerm) {
if (item != null) { if (item != null) {
Preference pref = new PreferencePlainText(item.getContext()); Preference pref = new PreferencePlainText(item.getContext());
pref.setSummary(noSearchTerm ? "--" : item.getContext().getString(R.string.delete_words_no_result)); pref.setSummary(noSearchTerm ? "--" : item.getContext().getString(R.string.search_results_void));
item.addPreference(pref); item.addPreference(pref);
} }
} }

View file

@ -2,24 +2,21 @@ package io.github.sspanak.tt9.preferences.screens.deleteWords;
import android.content.Context; import android.content.Context;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.widget.EditText;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.preference.PreferenceViewHolder;
import java.util.ArrayList; import java.util.ArrayList;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.WordStoreAsync; import io.github.sspanak.tt9.db.WordStoreAsync;
import io.github.sspanak.tt9.languages.Language; import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection; import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.custom.ScreenPreference; import io.github.sspanak.tt9.preferences.items.ItemTextInput;
import io.github.sspanak.tt9.preferences.settings.SettingsStore; import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.ConsumerCompat; import io.github.sspanak.tt9.util.ConsumerCompat;
import io.github.sspanak.tt9.util.Logger; import io.github.sspanak.tt9.util.Logger;
public class PreferenceSearchWords extends ScreenPreference { public class PreferenceSearchWords extends ItemTextInput {
public static final String NAME = "dictionary_delete_words_search"; public static final String NAME = "dictionary_delete_words_search";
private static final String LOG_TAG = PreferenceSearchWords.class.getSimpleName(); private static final String LOG_TAG = PreferenceSearchWords.class.getSimpleName();
@ -33,28 +30,6 @@ public class PreferenceSearchWords extends ScreenPreference {
public PreferenceSearchWords(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public PreferenceSearchWords(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); }
public PreferenceSearchWords(@NonNull Context context) { super(context); } public PreferenceSearchWords(@NonNull Context context) { super(context); }
@Override
public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
EditText editText = holder.itemView.findViewById(R.id.input_text_input_field);
if (editText == null) {
Logger.e(LOG_TAG, "Cannot attach a text change listener. Unable to find the EditText element.");
} else {
editText.addTextChangedListener(TextChangeListener.getInstance(this::onChange));
}
}
@Override protected int getDefaultLayout() { return R.layout.pref_input_text; }
@Override protected int getLargeLayout() { return R.layout.pref_input_text_large; }
@NonNull
public String getLastSearchTerm() {
return lastSearchTerm;
}
private SettingsStore getSettings() { private SettingsStore getSettings() {
if (settings == null) { if (settings == null) {
settings = new SettingsStore(getContext()); settings = new SettingsStore(getContext());
@ -64,7 +39,14 @@ public class PreferenceSearchWords extends ScreenPreference {
} }
private void onChange(String word) { @NonNull
public String getLastSearchTerm() {
return lastSearchTerm;
}
@Override
protected void onChange(String word) {
lastSearchTerm = word == null || word.trim().isEmpty() ? "" : word.trim(); lastSearchTerm = word == null || word.trim().isEmpty() ? "" : word.trim();
if (onWords == null) { if (onWords == null) {

View file

@ -1,39 +0,0 @@
package io.github.sspanak.tt9.preferences.screens.deleteWords;
import android.os.Handler;
import android.os.Looper;
import android.text.Editable;
import android.text.TextWatcher;
import androidx.annotation.NonNull;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.ConsumerCompat;
class TextChangeListener implements TextWatcher {
private static TextChangeListener self;
@NonNull private ConsumerCompat<String> onChange;
@NonNull private final Handler debouncer = new Handler(Looper.getMainLooper());
private TextChangeListener(@NonNull ConsumerCompat<String> onChange) {
this.onChange = onChange;
}
static TextChangeListener getInstance(@NonNull ConsumerCompat<String> onChange) {
if (self == null) {
self = new TextChangeListener(onChange);
}
self.onChange = onChange;
return self;
}
@Override public void afterTextChanged(Editable s) {
debouncer.removeCallbacksAndMessages(null);
debouncer.postDelayed(() -> onChange.accept(s.toString()), SettingsStore.DELETE_WORDS_SEARCH_DELAY);
}
@Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
@Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
}

View file

@ -0,0 +1,97 @@
package io.github.sspanak.tt9.preferences.screens.languageSelection;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceCategory;
import java.util.ArrayList;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.WordStoreAsync;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.languages.NaturalLanguage;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.preferences.screens.BaseScreenFragment;
public class LanguageSelectionScreen extends BaseScreenFragment {
public static final String NAME = "LanguageSelection";
private PreferenceCategory languagesCategory;
public LanguageSelectionScreen() { init(); }
public LanguageSelectionScreen(PreferencesActivity activity) { init(activity); }
@Override public String getName() { return NAME; }
@Override protected int getTitle() { return R.string.language_selection_title; }
@Override protected int getXml() { return R.xml.prefs_screen_language_selection; }
@Override
protected void onCreate() {
createLanguageList();
enableFiltering();
resetFontSize(false);
}
private void createLanguageList() {
languagesCategory = findPreference("language_list");
if (languagesCategory == null) {
return;
}
ArrayList<Language> allLanguages = LanguageCollection.getAll(activity, true);
if (allLanguages.isEmpty()) {
return;
}
addLanguagesToCategory(languagesCategory, allLanguages);
WordStoreAsync.exists(this::addLoadedStatus, allLanguages);
}
private void addLanguagesToCategory(@NonNull PreferenceCategory category, ArrayList<Language> allLanguages) {
ArrayList<Integer> enabledLanguageIds = activity.getSettings().getEnabledLanguageIds();
PreferenceSwitchLanguage.clearItems();
for (Language language : allLanguages) {
if (language instanceof NaturalLanguage) {
PreferenceSwitchLanguage item = new PreferenceSwitchLanguage(activity, (NaturalLanguage) language);
category.addPreference(item);
// Inflating sometimes resets the checked state to false for some reason.
// This is why we have to set it at the end.
// https://stackoverflow.com/q/42951557
item.setChecked(enabledLanguageIds.contains(language.getId()));
}
}
}
private void addLoadedStatus(ArrayList<Integer> enabledLanguageIds) {
if (languagesCategory == null) {
return;
}
activity.runOnUiThread(() -> {
for (int languageId : enabledLanguageIds) {
PreferenceSwitchLanguage item = languagesCategory.findPreference(PreferenceSwitchLanguage.KEY_PREFIX + languageId);
if (item != null) {
item.setLoaded();
}
}
});
}
private void enableFiltering() {
PreferenceSearchLanguage search = findPreference("language_search");
if (search != null) {
search
.setLanguageItems(PreferenceSwitchLanguage.getItems())
.setNoResultItem(findPreference("language_search_no_result"));
}
}
}

View file

@ -0,0 +1,71 @@
package io.github.sspanak.tt9.preferences.screens.languageSelection;
import android.content.Context;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.Preference;
import java.util.ArrayList;
import io.github.sspanak.tt9.preferences.items.ItemTextInput;
import io.github.sspanak.tt9.util.Logger;
public class PreferenceSearchLanguage extends ItemTextInput {
@NonNull private ArrayList<PreferenceSwitchLanguage> languageItems = new ArrayList<>();
private Preference noResultItem;
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public PreferenceSearchLanguage(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public PreferenceSearchLanguage(@NonNull Context context) {
super(context);
}
private void showNoResultItem(boolean show) {
if (noResultItem != null) {
noResultItem.setVisible(show);
}
}
@Override
protected void onChange(String word) {
word = word == null ? "" : word.trim();
int visibleLanguages = languageItems.size();
for (PreferenceSwitchLanguage languageItem : languageItems) {
CharSequence title = languageItem.getTitle() == null ? "" : languageItem.getTitle();
CharSequence summary = languageItem.getSummary() == null ? "" : languageItem.getSummary();
languageItem.setVisible(
title.toString().toLowerCase().startsWith(word.toLowerCase()) ||
summary.toString().toLowerCase().startsWith(word.toLowerCase())
);
if (!languageItem.isVisible()) {
visibleLanguages--;
}
}
showNoResultItem(visibleLanguages == 0);
}
PreferenceSearchLanguage setLanguageItems(@NonNull ArrayList<PreferenceSwitchLanguage> languageItems) {
this.languageItems = languageItems;
return this;
}
void setNoResultItem(Preference noResultItem) {
this.noResultItem = noResultItem;
}
}

View file

@ -0,0 +1,106 @@
package io.github.sspanak.tt9.preferences.screens.languageSelection;
import android.app.Activity;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import androidx.preference.SwitchPreferenceCompat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import io.github.sspanak.tt9.BuildConfig;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.entities.WordFile;
import io.github.sspanak.tt9.languages.NaturalLanguage;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class PreferenceSwitchLanguage extends SwitchPreferenceCompat {
public static final String KEY_PREFIX = "language_";
private static final ArrayList<PreferenceSwitchLanguage> items = new ArrayList<>();
public PreferenceSwitchLanguage(@NonNull PreferencesActivity activity, @NonNull NaturalLanguage language) {
super(activity);
setKey(KEY_PREFIX + language.getId());
setTitle(language.getName());
setSummary(generateSummary(activity, language));
setOnPreferenceChangeListener(PreferenceSwitchLanguage::handleChange);
items.add(this);
}
static void clearItems() {
items.clear();
}
static ArrayList<PreferenceSwitchLanguage> getItems() {
return new ArrayList<>(items);
}
private String generateSummary(Activity activity, NaturalLanguage language) {
String summary = language.getLocale().getDisplayLanguage();
String wordsString = activity.getString(R.string.language_selection_words);
WordFile wordFile = new WordFile(activity, language.getDictionaryFile(), activity.getAssets());
if (wordFile.getTotalLines() > 1000000) {
summary += String.format(", %1.2fM %s", wordFile.getTotalLines() / 1000000.0, wordsString);
} else {
summary += ", " + wordFile.getTotalLines() / 1000 + "k " + wordsString;
}
if (BuildConfig.LITE) {
summary += String.format(", %1.2f Mb", wordFile.getSize() / 1048576.0);
}
return summary;
}
private String getLanguageId() {
return getKey().substring(KEY_PREFIX.length());
}
private static boolean handleChange(Preference p, Object newValue) {
SettingsStore settings = ((PreferencesActivity) p.getContext()).getSettings();
String languageSettingsId = ((PreferenceSwitchLanguage) p).getLanguageId();
Set<String> enabledLanguages = new HashSet<>();
for (PreferenceSwitchLanguage item : items) {
if (item.isChecked()) {
enabledLanguages.add(item.getLanguageId());
}
}
if ((boolean) newValue) {
enabledLanguages.add(languageSettingsId);
} else {
enabledLanguages.remove(languageSettingsId);
}
settings.saveEnabledLanguageIds(enabledLanguages);
return true;
}
void setLoaded() {
Context context = getContext();
String summary = getSummary() != null ? getSummary().toString() : null;
if (summary == null) {
return;
}
summary += " " + context.getString(R.string.language_selection_language_loaded);
setSummary(summary);
}
}

View file

@ -1,80 +1,32 @@
package io.github.sspanak.tt9.preferences.screens.languages; package io.github.sspanak.tt9.preferences.screens.languages;
import androidx.preference.MultiSelectListPreference; import androidx.preference.Preference;
import java.util.ArrayList;
import java.util.HashSet;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection; import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.PreferencesActivity; import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.ui.UI;
class ItemSelectLanguage { class ItemSelectLanguage {
public static final String NAME = "pref_languages"; public static final String NAME = "pref_languages";
private final PreferencesActivity activity; private final PreferencesActivity activity;
private final MultiSelectListPreference item; private final Preference item;
ItemSelectLanguage(PreferencesActivity activity, MultiSelectListPreference multiSelect) { ItemSelectLanguage(PreferencesActivity activity, Preference item) {
this.activity = activity; this.activity = activity;
this.item = multiSelect; this.item = item;
} }
public ItemSelectLanguage populate() { public ItemSelectLanguage populate() {
if (item == null) {
return this;
}
ArrayList<Language> languages = LanguageCollection.getAll(activity, true);
if (languages.isEmpty()) {
UI.alert(activity, R.string.error, R.string.failed_loading_language_definitions);
// do not return, the MultiSelect component requires arrays, even if empty, otherwise it crashes
}
ArrayList<CharSequence> values = new ArrayList<>();
for (Language l : languages) {
values.add(String.valueOf(l.getId()));
}
ArrayList<String> keys = new ArrayList<>();
for (Language l : languages) {
keys.add(l.getName());
}
item.setEntries(keys.toArray(new CharSequence[0]));
item.setEntryValues(values.toArray(new CharSequence[0]));
item.setValues(activity.getSettings().getEnabledLanguagesIdsAsStrings());
previewSelection(); previewSelection();
return this; return this;
} }
public void enableValidation() {
if (item == null) {
return;
}
item.setOnPreferenceChangeListener((preference, newValue) -> {
@SuppressWarnings("unchecked") HashSet<String> newLanguages = (HashSet<String>) newValue;
if (newLanguages.isEmpty()) {
newLanguages.add("1");
}
activity.getSettings().saveEnabledLanguageIds(newLanguages);
item.setValues(activity.getSettings().getEnabledLanguagesIdsAsStrings());
previewSelection();
// we validate and save manually above, so "false" disables automatic save
return false;
});
}
private void previewSelection() { private void previewSelection() {
if (item == null) {
return;
}
item.setSummary( item.setSummary(
LanguageCollection.toString(LanguageCollection.getAll(activity, activity.getSettings().getEnabledLanguageIds(), true)) LanguageCollection.toString(LanguageCollection.getAll(activity, activity.getSettings().getEnabledLanguageIds(), true))
); );

View file

@ -36,11 +36,7 @@ public class LanguagesScreen extends BaseScreenFragment {
@Override @Override
protected void onCreate() { protected void onCreate() {
ItemSelectLanguage multiSelect = new ItemSelectLanguage( new ItemSelectLanguage(activity, findPreference(ItemSelectLanguage.NAME)).populate();
activity,
findPreference(ItemSelectLanguage.NAME)
);
multiSelect.populate().enableValidation();
new ItemDictionaryNotifications(findPreference(ItemDictionaryNotifications.NAME), activity) new ItemDictionaryNotifications(findPreference(ItemDictionaryNotifications.NAME), activity)
.populate() .populate()
@ -111,6 +107,7 @@ public class LanguagesScreen extends BaseScreenFragment {
private void refreshItems() { private void refreshItems() {
new ItemSelectLanguage(activity, findPreference(ItemSelectLanguage.NAME)).populate();
loadItem.refreshStatus(); loadItem.refreshStatus();
exportDictionaryItem.refreshStatus(); exportDictionaryItem.refreshStatus();
exportCustomWordsItem.refreshStatus(); exportCustomWordsItem.refreshStatus();

View file

@ -39,9 +39,11 @@ class SettingsInput extends SettingsHotkeys {
public Set<String> getEnabledLanguagesIdsAsStrings() { public Set<String> getEnabledLanguagesIdsAsStrings() {
return prefs.getStringSet("pref_languages", new HashSet<>(Collections.singletonList( Set<String> defaultLanguages = new HashSet<>(Collections.singletonList(
String.valueOf(LanguageCollection.getDefault(context).getId()) String.valueOf(LanguageCollection.getDefault(context).getId())
))); ));
return new HashSet<>(prefs.getStringSet("pref_languages", defaultLanguages));
} }

View file

@ -8,7 +8,6 @@ public class SettingsStore extends SettingsUI {
/************* internal settings *************/ /************* internal settings *************/
public final static int CLIPBOARD_PREVIEW_LENGTH = 20; public final static int CLIPBOARD_PREVIEW_LENGTH = 20;
public final static int DELETE_WORDS_SEARCH_DELAY = 500; // ms
public final static int CUSTOM_WORDS_IMPORT_MAX_LINES = 250; public final static int CUSTOM_WORDS_IMPORT_MAX_LINES = 250;
public final static int CUSTOM_WORDS_MAX = 1000; public final static int CUSTOM_WORDS_MAX = 1000;
public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 1200000; // 20 minutes in ms public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 1200000; // 20 minutes in ms
@ -28,6 +27,7 @@ public class SettingsStore extends SettingsUI {
public final static int SUGGESTIONS_MIN = 8; public final static int SUGGESTIONS_MIN = 8;
public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66; public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66;
public final static int SUGGESTIONS_TRANSLATE_ANIMATION_DURATION = 0; public final static int SUGGESTIONS_TRANSLATE_ANIMATION_DURATION = 0;
public final static int TEXT_INPUT_DEBOUNCE_TIME = 500; // ms
public final static int WORD_FREQUENCY_MAX = 25500; public final static int WORD_FREQUENCY_MAX = 25500;
public final static int WORD_FREQUENCY_NORMALIZATION_DIVIDER = 100; // normalized frequency = WORD_FREQUENCY_MAX / WORD_FREQUENCY_NORMALIZATION_DIVIDER public final static int WORD_FREQUENCY_NORMALIZATION_DIVIDER = 100; // normalized frequency = WORD_FREQUENCY_MAX / WORD_FREQUENCY_NORMALIZATION_DIVIDER
public final static int WORD_NORMALIZATION_DELAY = 15000; // ms public final static int WORD_NORMALIZATION_DELAY = 15000; // ms

View file

@ -64,8 +64,8 @@
<string name="delete_words_delete">Изтрий</string> <string name="delete_words_delete">Изтрий</string>
<string name="delete_words_link_summary">Намери и изтрий на неправилно написани или ненужни думи.</string> <string name="delete_words_link_summary">Намери и изтрий на неправилно написани или ненужни думи.</string>
<string name="delete_words_search_placeholder">Търси думи</string> <string name="delete_words_search_placeholder">Търси думи</string>
<string name="delete_words_list">Намерени думи</string> <string name="search_results">Намерени думи</string>
<string name="delete_words_no_result">Няма резултати.</string> <string name="search_results_void">Няма резултати.</string>
<string name="delete_words_deleted_confirm_deletion_title">Потвърдете изтриването</string> <string name="delete_words_deleted_confirm_deletion_title">Потвърдете изтриването</string>
<string name="delete_words_deleted_confirm_deletion_question">Наистина ли искате да изтриете „%1$s“?</string> <string name="delete_words_deleted_confirm_deletion_question">Наистина ли искате да изтриете „%1$s“?</string>
<string name="delete_words_deleted_x">„%1$s“ беше изтрита.</string> <string name="delete_words_deleted_x">„%1$s“ беше изтрита.</string>
@ -165,4 +165,8 @@
<string name="dictionary_import_custom_words_summary">Импортиране на думи от по-рано експортирано CSV.</string> <string name="dictionary_import_custom_words_summary">Импортиране на думи от по-рано експортирано CSV.</string>
<string name="dictionary_import_progress">Импортиране на CSV (%1$s)…</string> <string name="dictionary_import_progress">Импортиране на CSV (%1$s)…</string>
<string name="dictionary_import_running">Импортиране на CSV…</string> <string name="dictionary_import_running">Импортиране на CSV…</string>
<string name="language_selection_language_loaded">(зареден)</string>
<string name="language_selection_title">Избор на езици</string>
<string name="language_selection_search_placeholder">Търси езици</string>
<string name="language_selection_words">думи</string>
</resources> </resources>

View file

@ -102,8 +102,8 @@
<string name="delete_words_delete">Löschen</string> <string name="delete_words_delete">Löschen</string>
<string name="delete_words_link_summary">Finde und lösche falsch geschriebene oder überflüssige Wörter.</string> <string name="delete_words_link_summary">Finde und lösche falsch geschriebene oder überflüssige Wörter.</string>
<string name="delete_words_search_placeholder">Nach Wörtern suchen</string> <string name="delete_words_search_placeholder">Nach Wörtern suchen</string>
<string name="delete_words_list">Suchergebnisse</string> <string name="search_results">Suchergebnisse</string>
<string name="delete_words_no_result">Keine Ergebnisse.</string> <string name="search_results_void">Keine Ergebnisse.</string>
<string name="delete_words_deleted_confirm_deletion_title">Löschung bestätigen</string> <string name="delete_words_deleted_confirm_deletion_title">Löschung bestätigen</string>
<string name="delete_words_deleted_confirm_deletion_question">Sind Sie sicher, dass Sie \"%1$s\" löschen möchten?</string> <string name="delete_words_deleted_confirm_deletion_question">Sind Sie sicher, dass Sie \"%1$s\" löschen möchten?</string>
<string name="delete_words_deleted_x">\"%1$s\" wurde gelöscht.</string> <string name="delete_words_deleted_x">\"%1$s\" wurde gelöscht.</string>
@ -154,4 +154,8 @@
<string name="dictionary_import_custom_words_summary">Wörter aus einer zuvor exportierten CSV-Datei importieren.</string> <string name="dictionary_import_custom_words_summary">Wörter aus einer zuvor exportierten CSV-Datei importieren.</string>
<string name="dictionary_import_progress">CSV importieren (%1$s)…</string> <string name="dictionary_import_progress">CSV importieren (%1$s)…</string>
<string name="dictionary_import_running">CSV importieren…</string> <string name="dictionary_import_running">CSV importieren…</string>
<string name="language_selection_language_loaded">(geladen)</string>
<string name="language_selection_title">Sprachen aktivieren</string>
<string name="language_selection_search_placeholder">Nach Sprachen suchen</string>
<string name="language_selection_words">Wörter</string>
</resources> </resources>

View file

@ -115,8 +115,8 @@
<string name="delete_words_delete">Eliminar</string> <string name="delete_words_delete">Eliminar</string>
<string name="delete_words_link_summary">Buscar y eliminar palabras mal escritas o innecesarias.</string> <string name="delete_words_link_summary">Buscar y eliminar palabras mal escritas o innecesarias.</string>
<string name="delete_words_search_placeholder">Buscar palabras</string> <string name="delete_words_search_placeholder">Buscar palabras</string>
<string name="delete_words_list">Palabras encontradas</string> <string name="search_results">Palabras encontradas</string>
<string name="delete_words_no_result">Sin resultados.</string> <string name="search_results_void">Sin resultados.</string>
<string name="delete_words_deleted_confirm_deletion_title">Confirma la eliminación</string> <string name="delete_words_deleted_confirm_deletion_title">Confirma la eliminación</string>
<string name="delete_words_deleted_confirm_deletion_question">¿Estás seguro de que quieres eliminar \"%1$s\"?</string> <string name="delete_words_deleted_confirm_deletion_question">¿Estás seguro de que quieres eliminar \"%1$s\"?</string>
<string name="delete_words_deleted_x">\"%1$s\" fue eliminada.</string> <string name="delete_words_deleted_x">\"%1$s\" fue eliminada.</string>
@ -163,4 +163,8 @@
<string name="dictionary_import_custom_words_summary">Importar palabras de un CSV previamente exportado.</string> <string name="dictionary_import_custom_words_summary">Importar palabras de un CSV previamente exportado.</string>
<string name="dictionary_import_progress">Importando CSV (%1$s)…</string> <string name="dictionary_import_progress">Importando CSV (%1$s)…</string>
<string name="dictionary_import_running">Importando CSV…</string> <string name="dictionary_import_running">Importando CSV…</string>
<string name="language_selection_language_loaded">(cargado)</string>
<string name="language_selection_title">Habilitar idiomas</string>
<string name="language_selection_search_placeholder">Buscar idiomas</string>
<string name="language_selection_words">palabras</string>
</resources> </resources>

View file

@ -117,8 +117,8 @@
<string name="delete_words_delete">Supprimer</string> <string name="delete_words_delete">Supprimer</string>
<string name="delete_words_link_summary">Trouver et supprimer des mots mal orthographiés ou inutiles.</string> <string name="delete_words_link_summary">Trouver et supprimer des mots mal orthographiés ou inutiles.</string>
<string name="delete_words_search_placeholder">Rechercher des mots</string> <string name="delete_words_search_placeholder">Rechercher des mots</string>
<string name="delete_words_list">Mots trouvés</string> <string name="search_results">Mots trouvés</string>
<string name="delete_words_no_result">Aucun résultat.</string> <string name="search_results_void">Aucun résultat.</string>
<string name="delete_words_deleted_confirm_deletion_title">Confirmer la suppression</string> <string name="delete_words_deleted_confirm_deletion_title">Confirmer la suppression</string>
<string name="delete_words_deleted_confirm_deletion_question">Êtes-vous sûr de vouloir supprimer « %1$s » ?</string> <string name="delete_words_deleted_confirm_deletion_question">Êtes-vous sûr de vouloir supprimer « %1$s » ?</string>
<string name="delete_words_deleted_x">\"%1$s\" a été supprimé.</string> <string name="delete_words_deleted_x">\"%1$s\" a été supprimé.</string>
@ -161,4 +161,8 @@
<string name="dictionary_import_custom_words_summary">Importer des mots à partir d\'un fichier CSV précédemment exporté.</string> <string name="dictionary_import_custom_words_summary">Importer des mots à partir d\'un fichier CSV précédemment exporté.</string>
<string name="dictionary_import_progress">Importation de CSV (%1$s)…</string> <string name="dictionary_import_progress">Importation de CSV (%1$s)…</string>
<string name="dictionary_import_running">Importation de CSV…</string> <string name="dictionary_import_running">Importation de CSV…</string>
<string name="language_selection_language_loaded">(chargée)</string>
<string name="language_selection_title">Activer les langues</string>
<string name="language_selection_search_placeholder">Rechercher des langues</string>
<string name="language_selection_words">mots</string>
</resources> </resources>

View file

@ -102,8 +102,8 @@
<string name="delete_words_delete">Elimina</string> <string name="delete_words_delete">Elimina</string>
<string name="delete_words_link_summary">Trova ed elimina parole errate o non necessarie.</string> <string name="delete_words_link_summary">Trova ed elimina parole errate o non necessarie.</string>
<string name="delete_words_search_placeholder">Ricerca di parole</string> <string name="delete_words_search_placeholder">Ricerca di parole</string>
<string name="delete_words_list">Parole trovate</string> <string name="search_results">Parole trovate</string>
<string name="delete_words_no_result">Nessun risultato.</string> <string name="search_results_void">Nessun risultato.</string>
<string name="delete_words_deleted_confirm_deletion_title">Conferma l\'eliminazione</string> <string name="delete_words_deleted_confirm_deletion_title">Conferma l\'eliminazione</string>
<string name="delete_words_deleted_confirm_deletion_question">Sei sicuro di voler eliminare \"%1$s\"?</string> <string name="delete_words_deleted_confirm_deletion_question">Sei sicuro di voler eliminare \"%1$s\"?</string>
<string name="delete_words_deleted_x">\"%1$s\" è stata eliminata.</string> <string name="delete_words_deleted_x">\"%1$s\" è stata eliminata.</string>
@ -153,5 +153,9 @@
<string name="dictionary_import_custom_words_summary">Importare parole da un CSV precedentemente esportato.</string> <string name="dictionary_import_custom_words_summary">Importare parole da un CSV precedentemente esportato.</string>
<string name="dictionary_import_progress">Importazione CSV (%1$s)…</string> <string name="dictionary_import_progress">Importazione CSV (%1$s)…</string>
<string name="dictionary_import_running">Importazione CSV…</string> <string name="dictionary_import_running">Importazione CSV…</string>
<string name="language_selection_language_loaded">(caricata)</string>
<string name="language_selection_title">Abilita lingue</string>
<string name="language_selection_search_placeholder">Cerca lingue</string>
<string name="language_selection_words">parole</string>
</resources> </resources>

View file

@ -115,8 +115,8 @@
<string name="delete_words_delete">מחיקה</string> <string name="delete_words_delete">מחיקה</string>
<string name="delete_words_link_summary">מצא ומחק מילים שכתובות בטעות או שאינן נדרשות.</string> <string name="delete_words_link_summary">מצא ומחק מילים שכתובות בטעות או שאינן נדרשות.</string>
<string name="delete_words_search_placeholder">חיפוש מילים</string> <string name="delete_words_search_placeholder">חיפוש מילים</string>
<string name="delete_words_list">תוצאות חיפוש</string> <string name="search_results">תוצאות חיפוש</string>
<string name="delete_words_no_result">אין תוצאות.</string> <string name="search_results_void">אין תוצאות.</string>
<string name="delete_words_deleted_confirm_deletion_title">אישור מחיקה</string> <string name="delete_words_deleted_confirm_deletion_title">אישור מחיקה</string>
<string name="delete_words_deleted_confirm_deletion_question">האם אתה בטוח שברצונך להסיר את \"%1$s\"?</string> <string name="delete_words_deleted_confirm_deletion_question">האם אתה בטוח שברצונך להסיר את \"%1$s\"?</string>
<string name="delete_words_deleted_x">\"%1$s\" נמחקה.</string> <string name="delete_words_deleted_x">\"%1$s\" נמחקה.</string>
@ -166,4 +166,8 @@
<string name="dictionary_import_custom_words_summary">ייבוא מילים מקובץ CSV שיוצא קודם לכן.</string> <string name="dictionary_import_custom_words_summary">ייבוא מילים מקובץ CSV שיוצא קודם לכן.</string>
<string name="dictionary_import_progress">מייבא CSV (%1$s)…</string> <string name="dictionary_import_progress">מייבא CSV (%1$s)…</string>
<string name="dictionary_import_running">מייבא CSV…</string> <string name="dictionary_import_running">מייבא CSV…</string>
<string name="language_selection_language_loaded">(נטען)</string>
<string name="language_selection_title">הפעל שפות</string>
<string name="language_selection_search_placeholder">חיפוש שפות</string>
<string name="language_selection_words">מילים</string>
</resources> </resources>

View file

@ -134,8 +134,8 @@
<string name="delete_words_delete">Ištrinti</string> <string name="delete_words_delete">Ištrinti</string>
<string name="delete_words_link_summary">Raskite ir ištrinkite neteisingai parašytus arba nereikalingus žodžius.</string> <string name="delete_words_link_summary">Raskite ir ištrinkite neteisingai parašytus arba nereikalingus žodžius.</string>
<string name="delete_words_search_placeholder">Ieškoti žodžių</string> <string name="delete_words_search_placeholder">Ieškoti žodžių</string>
<string name="delete_words_list">Paieškos rezultatai</string> <string name="search_results">Paieškos rezultatai</string>
<string name="delete_words_no_result">Jokių rezultatų.</string> <string name="search_results_void">Jokių rezultatų.</string>
<string name="delete_words_deleted_confirm_deletion_title">Patvirtinkite ištrynimą</string> <string name="delete_words_deleted_confirm_deletion_title">Patvirtinkite ištrynimą</string>
<string name="delete_words_deleted_confirm_deletion_question">Ar tikrai norite ištrinti „%1$s“?</string> <string name="delete_words_deleted_confirm_deletion_question">Ar tikrai norite ištrinti „%1$s“?</string>
<string name="delete_words_deleted_x">„%1$s“ buvo ištrintas.</string> <string name="delete_words_deleted_x">„%1$s“ buvo ištrintas.</string>
@ -172,4 +172,8 @@
<string name="dictionary_import_custom_words_summary">Importuoti žodžius iš anksčiau eksportuoto CSV.</string> <string name="dictionary_import_custom_words_summary">Importuoti žodžius iš anksčiau eksportuoto CSV.</string>
<string name="dictionary_import_progress">Importuojamas CSV (%1$s)…</string> <string name="dictionary_import_progress">Importuojamas CSV (%1$s)…</string>
<string name="dictionary_import_running">Importuojamas CSV…</string> <string name="dictionary_import_running">Importuojamas CSV…</string>
<string name="language_selection_language_loaded">(įkelta)</string>
<string name="language_selection_title">Įjungti kalbas</string>
<string name="language_selection_search_placeholder">Ieškoti kalbų</string>
<string name="language_selection_words">žodžių</string>
</resources> </resources>

View file

@ -100,8 +100,8 @@
<string name="delete_words_delete">Verwijderen</string> <string name="delete_words_delete">Verwijderen</string>
<string name="delete_words_link_summary">Zoek en verwijder verkeerd gespelde of onnodige woorden.</string> <string name="delete_words_link_summary">Zoek en verwijder verkeerd gespelde of onnodige woorden.</string>
<string name="delete_words_search_placeholder">Zoeken naar woorden</string> <string name="delete_words_search_placeholder">Zoeken naar woorden</string>
<string name="delete_words_list">Zoekresultaten</string> <string name="search_results">Zoekresultaten</string>
<string name="delete_words_no_result">Geen resultaten.</string> <string name="search_results_void">Geen resultaten.</string>
<string name="delete_words_deleted_confirm_deletion_title">Bevestig verwijdering</string> <string name="delete_words_deleted_confirm_deletion_title">Bevestig verwijdering</string>
<string name="delete_words_deleted_confirm_deletion_question">Weet u zeker dat u \"%1$s\" wilt verwijderen?</string> <string name="delete_words_deleted_confirm_deletion_question">Weet u zeker dat u \"%1$s\" wilt verwijderen?</string>
<string name="delete_words_deleted_x">\"%1$s\" is verwijderd.</string> <string name="delete_words_deleted_x">\"%1$s\" is verwijderd.</string>
@ -152,4 +152,8 @@
<string name="dictionary_import_custom_words_summary">Woorden importeren uit een eerder geëxporteerde CSV.</string> <string name="dictionary_import_custom_words_summary">Woorden importeren uit een eerder geëxporteerde CSV.</string>
<string name="dictionary_import_progress">CSV importeren (%1$s)…</string> <string name="dictionary_import_progress">CSV importeren (%1$s)…</string>
<string name="dictionary_import_running">CSV importeren…</string> <string name="dictionary_import_running">CSV importeren…</string>
<string name="language_selection_language_loaded">(geladen)</string>
<string name="language_selection_title">Talen inschakelen</string>
<string name="language_selection_search_placeholder">Zoeken naar talen</string>
<string name="language_selection_words">woorden</string>
</resources> </resources>

View file

@ -115,8 +115,8 @@
<string name="delete_words_delete">Excluir</string> <string name="delete_words_delete">Excluir</string>
<string name="delete_words_link_summary">Encontrar e excluir palavras escritas incorretamente ou desnecessárias.</string> <string name="delete_words_link_summary">Encontrar e excluir palavras escritas incorretamente ou desnecessárias.</string>
<string name="delete_words_search_placeholder">Buscar palavras</string> <string name="delete_words_search_placeholder">Buscar palavras</string>
<string name="delete_words_list">Palavras encontradas</string> <string name="search_results">Palavras encontradas</string>
<string name="delete_words_no_result">Sem resultados.</string> <string name="search_results_void">Sem resultados.</string>
<string name="delete_words_deleted_confirm_deletion_title">Confirme a exclusão</string> <string name="delete_words_deleted_confirm_deletion_title">Confirme a exclusão</string>
<string name="delete_words_deleted_confirm_deletion_question">Tem certeza de que deseja excluir \"%1$s\"?</string> <string name="delete_words_deleted_confirm_deletion_question">Tem certeza de que deseja excluir \"%1$s\"?</string>
<string name="delete_words_deleted_x">\"%1$s\" foi excluída.</string> <string name="delete_words_deleted_x">\"%1$s\" foi excluída.</string>
@ -166,4 +166,8 @@
<string name="dictionary_import_custom_words_summary">Importar palavras de um CSV previamente exportado.</string> <string name="dictionary_import_custom_words_summary">Importar palavras de um CSV previamente exportado.</string>
<string name="dictionary_import_progress">Importando CSV (%1$s)…</string> <string name="dictionary_import_progress">Importando CSV (%1$s)…</string>
<string name="dictionary_import_running">Importando CSV…</string> <string name="dictionary_import_running">Importando CSV…</string>
<string name="language_selection_language_loaded">(carregado)</string>
<string name="language_selection_title">Habilitar idiomas</string>
<string name="language_selection_search_placeholder">Buscar por idiomas</string>
<string name="language_selection_words">palavras</string>
</resources> </resources>

View file

@ -116,8 +116,8 @@
<string name="delete_words_delete">Удалить</string> <string name="delete_words_delete">Удалить</string>
<string name="delete_words_link_summary">Найти и удалить ошибочно написанные или ненужные слова.</string> <string name="delete_words_link_summary">Найти и удалить ошибочно написанные или ненужные слова.</string>
<string name="delete_words_search_placeholder">Поиск слов</string> <string name="delete_words_search_placeholder">Поиск слов</string>
<string name="delete_words_list">Найденные слова</string> <string name="search_results">Найденные слова</string>
<string name="delete_words_no_result">Нет результатов.</string> <string name="search_results_void">Нет результатов.</string>
<string name="delete_words_deleted_confirm_deletion_title">Подтвердите удаление</string> <string name="delete_words_deleted_confirm_deletion_title">Подтвердите удаление</string>
<string name="delete_words_deleted_confirm_deletion_question">Уверены, что хотите удалить «%1$s»?</string> <string name="delete_words_deleted_confirm_deletion_question">Уверены, что хотите удалить «%1$s»?</string>
<string name="delete_words_deleted_x">\"%1$s\" было удалено.</string> <string name="delete_words_deleted_x">\"%1$s\" было удалено.</string>
@ -163,4 +163,8 @@
<string name="dictionary_import_custom_words_summary">Импортировать слова из ранее экспортированного CSV.</string> <string name="dictionary_import_custom_words_summary">Импортировать слова из ранее экспортированного CSV.</string>
<string name="dictionary_import_progress">Импортирование CSV (%1$s)…</string> <string name="dictionary_import_progress">Импортирование CSV (%1$s)…</string>
<string name="dictionary_import_running">Импортирование CSV…</string> <string name="dictionary_import_running">Импортирование CSV…</string>
<string name="language_selection_language_loaded">(загружен)</string>
<string name="language_selection_title">Включить языки</string>
<string name="language_selection_search_placeholder">Поиск языков</string>
<string name="language_selection_words">слов</string>
</resources> </resources>

View file

@ -100,8 +100,8 @@
<string name="delete_words_delete">Sil</string> <string name="delete_words_delete">Sil</string>
<string name="delete_words_link_summary">Yanlış yazılan ya da gereksiz kelimeleri bulun ve silin.</string> <string name="delete_words_link_summary">Yanlış yazılan ya da gereksiz kelimeleri bulun ve silin.</string>
<string name="delete_words_search_placeholder">Aramak istediğiniz kelimeyi yazın…</string> <string name="delete_words_search_placeholder">Aramak istediğiniz kelimeyi yazın…</string>
<string name="delete_words_list">Ara</string> <string name="search_results">Ara</string>
<string name="delete_words_no_result">Eşleşme bulunamadı.</string> <string name="search_results_void">Eşleşme bulunamadı.</string>
<string name="delete_words_deleted_confirm_deletion_title">Silmeyi Onayla</string> <string name="delete_words_deleted_confirm_deletion_title">Silmeyi Onayla</string>
<string name="delete_words_deleted_confirm_deletion_question">\"%1$s\" kelimesini silmeyi onaylıyor musunuz?</string> <string name="delete_words_deleted_confirm_deletion_question">\"%1$s\" kelimesini silmeyi onaylıyor musunuz?</string>
<string name="delete_words_deleted_x">\"%1$s\" kelimesi başarıyla silindi.</string> <string name="delete_words_deleted_x">\"%1$s\" kelimesi başarıyla silindi.</string>
@ -166,4 +166,8 @@
<string name="dictionary_import_custom_words_summary">Daha önce dışa aktarılan bir CSV\'den kelimeleri içe aktar.</string> <string name="dictionary_import_custom_words_summary">Daha önce dışa aktarılan bir CSV\'den kelimeleri içe aktar.</string>
<string name="dictionary_import_progress">CSV İçe aktarılıyor (%1$s)…</string> <string name="dictionary_import_progress">CSV İçe aktarılıyor (%1$s)…</string>
<string name="dictionary_import_running">CSV İçe aktarılıyor…</string> <string name="dictionary_import_running">CSV İçe aktarılıyor…</string>
<string name="language_selection_language_loaded">(yüklendi)</string>
<string name="language_selection_title">Dilleri etkinleştir</string>
<string name="language_selection_search_placeholder">Diller için arama</string>
<string name="language_selection_words">kelime</string>
</resources> </resources>

View file

@ -99,8 +99,8 @@
<string name="delete_words_delete">Видалити</string> <string name="delete_words_delete">Видалити</string>
<string name="delete_words_link_summary">Знайти та видалити неправильно написані або зайві слова.</string> <string name="delete_words_link_summary">Знайти та видалити неправильно написані або зайві слова.</string>
<string name="delete_words_search_placeholder">Пошук слів</string> <string name="delete_words_search_placeholder">Пошук слів</string>
<string name="delete_words_list">Знайдені слова</string> <string name="search_results">Знайдені слова</string>
<string name="delete_words_no_result">Немає результатів.</string> <string name="search_results_void">Немає результатів.</string>
<string name="delete_words_deleted_confirm_deletion_title">Підтвердіть видалення</string> <string name="delete_words_deleted_confirm_deletion_title">Підтвердіть видалення</string>
<string name="delete_words_deleted_confirm_deletion_question">Ви впевнені, що хочете видалити \"%1$s\"?</string> <string name="delete_words_deleted_confirm_deletion_question">Ви впевнені, що хочете видалити \"%1$s\"?</string>
<string name="delete_words_deleted_x">\"%1$s\" було видалено.</string> <string name="delete_words_deleted_x">\"%1$s\" було видалено.</string>
@ -174,4 +174,8 @@
<string name="dictionary_import_custom_words_summary">Імпортувати слова з раніше експортованого CSV.</string> <string name="dictionary_import_custom_words_summary">Імпортувати слова з раніше експортованого CSV.</string>
<string name="dictionary_import_progress">Імпорт CSV (%1$s)…</string> <string name="dictionary_import_progress">Імпорт CSV (%1$s)…</string>
<string name="dictionary_import_running">Імпорт CSV…</string> <string name="dictionary_import_running">Імпорт CSV…</string>
<string name="language_selection_language_loaded">(завантажено)</string>
<string name="language_selection_title">Увімкнути мови</string>
<string name="language_selection_search_placeholder">Пошук мов</string>
<string name="language_selection_words">слів</string>
</resources> </resources>

View file

@ -8,6 +8,8 @@
<string name="error">Error</string> <string name="error">Error</string>
<string name="loading">Loading…</string> <string name="loading">Loading…</string>
<string name="no_language">No Language</string> <string name="no_language">No Language</string>
<string name="search_results">Search Results</string>
<string name="search_results_void">No results.</string>
<string name="error_unexpected">Unexpected error occurred.</string> <string name="error_unexpected">Unexpected error occurred.</string>
<string name="failed_loading_language_definitions">Failed loading all language definitions.</string> <string name="failed_loading_language_definitions">Failed loading all language definitions.</string>
@ -125,8 +127,6 @@
<string name="delete_words_delete">Delete</string> <string name="delete_words_delete">Delete</string>
<string name="delete_words_link_summary">Find and delete misspelled or unneeded words.</string> <string name="delete_words_link_summary">Find and delete misspelled or unneeded words.</string>
<string name="delete_words_search_placeholder">Search for Words</string> <string name="delete_words_search_placeholder">Search for Words</string>
<string name="delete_words_list">Search Results</string>
<string name="delete_words_no_result">No results.</string>
<string name="delete_words_deleted_confirm_deletion_title">Confirm Deletion</string> <string name="delete_words_deleted_confirm_deletion_title">Confirm Deletion</string>
<string name="delete_words_deleted_confirm_deletion_question">Are you sure you want to delete \"%1$s\"?</string> <string name="delete_words_deleted_confirm_deletion_question">Are you sure you want to delete \"%1$s\"?</string>
<string name="delete_words_deleted_x">\"%1$s\" was deleted.</string> <string name="delete_words_deleted_x">\"%1$s\" was deleted.</string>
@ -155,6 +155,12 @@
<string name="function_reset_keys_title">Restore Default Keys</string> <string name="function_reset_keys_title">Restore Default Keys</string>
<string name="function_reset_keys_done">Default key settings restored.</string> <string name="function_reset_keys_done">Default key settings restored.</string>
<string name="language_selection_language_loaded">(loaded)</string>
<string name="language_selection_title">Enable Languages</string>
<string name="language_selection_search_placeholder">Search for Languages</string>
<string name="language_selection_words">words</string>
<string name="setup_keyboard_status">Status</string> <string name="setup_keyboard_status">Status</string>
<string name="setup_default_keyboard">Select Default Keyboard</string> <string name="setup_default_keyboard">Select Default Keyboard</string>
<string name="setup_tt9_on">%1$s is enabled</string> <string name="setup_tt9_on">%1$s is enabled</string>

View file

@ -7,5 +7,5 @@
<PreferenceCategory <PreferenceCategory
android:key="delete_words_list" android:key="delete_words_list"
android:title="@string/delete_words_list" /> android:title="@string/search_results" />
</PreferenceScreen> </PreferenceScreen>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<io.github.sspanak.tt9.preferences.screens.languageSelection.PreferenceSearchLanguage
android:key="language_search"
android:title="@string/language_selection_search_placeholder" />
<PreferenceCategory
android:key="language_list"
android:persistent="false"
android:title="@string/language_selection_title"/>
<io.github.sspanak.tt9.preferences.custom.PreferencePlainText
android:key="language_search_no_result"
android:summary="@string/search_results_void"
app:isPreferenceVisible="false" />
</androidx.preference.PreferenceScreen>

View file

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" app:orderingFromXml="true"> <PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto" app:orderingFromXml="true">
<MultiSelectListPreference <Preference
app:fragment="io.github.sspanak.tt9.preferences.screens.languageSelection.LanguageSelectionScreen"
app:key="pref_languages" app:key="pref_languages"
app:title="@string/pref_choose_languages" /> app:title="@string/pref_choose_languages" />