1
0
Fork 0

split the SettingsStore into smaller sub-classes

This commit is contained in:
sspanak 2024-03-30 12:07:25 +02:00 committed by Dimo Karaivanov
parent cc0ce856c5
commit 35d0f0bf32
35 changed files with 420 additions and 370 deletions

View file

@ -23,7 +23,7 @@ import io.github.sspanak.tt9.languages.EmojiLanguage;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageCharactersException;
import io.github.sspanak.tt9.languages.exceptions.InvalidLanguageException;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.DictionaryLoadingBar;
import io.github.sspanak.tt9.ui.dialogs.ConfirmDictionaryUpdateDialog;
import io.github.sspanak.tt9.util.ConsumerCompat;

View file

@ -2,10 +2,10 @@ package io.github.sspanak.tt9.db;
import java.util.HashMap;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.TextTools;
import io.github.sspanak.tt9.preferences.SettingsStore;
public class SlowQueryStats {
private static final String LOG_TAG = SlowQueryStats.class.getSimpleName();

View file

@ -16,7 +16,7 @@ import io.github.sspanak.tt9.db.sqlite.UpdateOps;
import io.github.sspanak.tt9.languages.EmojiLanguage;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.NullLanguage;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.dialogs.AddWordDialog;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Text;

View file

@ -5,10 +5,10 @@ import android.database.sqlite.SQLiteStatement;
import androidx.annotation.NonNull;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Text;
import io.github.sspanak.tt9.preferences.SettingsStore;
public class UpdateOps {

View file

@ -5,7 +5,7 @@ import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
abstract public class AbstractHandler extends InputMethodService {
// hardware key handlers

View file

@ -5,8 +5,8 @@ import android.view.View;
import android.view.inputmethod.EditorInfo;
import io.github.sspanak.tt9.ime.helpers.Key;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.screens.debug.ItemInputHandlingMode;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Timer;

View file

@ -14,7 +14,7 @@ import androidx.annotation.NonNull;
import io.github.sspanak.tt9.db.DictionaryLoader;
import io.github.sspanak.tt9.db.WordStoreAsync;
import io.github.sspanak.tt9.ime.modes.ModePassthrough;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.UI;
import io.github.sspanak.tt9.ui.dialogs.PopupDialog;
import io.github.sspanak.tt9.ui.main.MainView;

View file

@ -7,7 +7,7 @@ import android.view.inputmethod.InputConnection;
import androidx.annotation.NonNull;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class AppHacks {
private final EditorInfo editorInfo;

View file

@ -4,7 +4,7 @@ import android.view.KeyEvent;
import java.util.HashMap;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class Key {
private static final HashMap<Integer, Boolean> handledKeys = new HashMap<>();

View file

@ -4,12 +4,12 @@ import androidx.annotation.NonNull;
import java.util.ArrayList;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.ime.helpers.InputType;
import io.github.sspanak.tt9.ime.helpers.TextField;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.NaturalLanguage;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
abstract public class InputMode {
// typing mode

View file

@ -5,7 +5,7 @@ import androidx.annotation.NonNull;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageKind;
import io.github.sspanak.tt9.languages.NaturalLanguage;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class ModeABC extends InputMode {
private final SettingsStore settings;

View file

@ -14,7 +14,7 @@ import io.github.sspanak.tt9.languages.EmojiLanguage;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageKind;
import io.github.sspanak.tt9.languages.NaturalLanguage;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.util.Text;

View file

@ -2,8 +2,8 @@ package io.github.sspanak.tt9.ime.modes.helpers;
import io.github.sspanak.tt9.ime.helpers.InputType;
import io.github.sspanak.tt9.ime.helpers.TextField;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Text;
import io.github.sspanak.tt9.preferences.SettingsStore;
public class AutoSpace {
private final SettingsStore settings;

View file

@ -1,8 +1,8 @@
package io.github.sspanak.tt9.ime.modes.helpers;
import io.github.sspanak.tt9.util.Text;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Text;
public class AutoTextCase {
private final SettingsStore settings;

View file

@ -5,7 +5,7 @@ import java.util.ArrayList;
import io.github.sspanak.tt9.db.WordStoreAsync;
import io.github.sspanak.tt9.languages.EmojiLanguage;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class Predictions {

View file

@ -13,7 +13,6 @@ import androidx.fragment.app.FragmentTransaction;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.LegacyDb;
import io.github.sspanak.tt9.db.WordStoreAsync;
@ -30,6 +29,8 @@ 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.languages.LanguagesScreen;
import io.github.sspanak.tt9.preferences.screens.setup.SetupScreen;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
public class PreferencesActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
private SettingsStore settings;

View file

@ -1,337 +0,0 @@
package io.github.sspanak.tt9.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.preference.PreferenceManager;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.screens.debug.ItemInputHandlingMode;
import io.github.sspanak.tt9.preferences.screens.hotkeys.SectionKeymap;
public class SettingsStore {
private final Context context;
private final SharedPreferences prefs;
private final SharedPreferences.Editor prefsEditor;
public SettingsStore(Context context) {
this.context = context;
prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefsEditor = prefs.edit();
}
/************* validators *************/
private boolean doesLanguageExist(int langId) {
return LanguageCollection.getLanguage(context, langId) != null;
}
private boolean validateSavedLanguage(int langId, String logTag) {
if (!doesLanguageExist(langId)) {
Logger.w(logTag, "Not saving invalid language with ID: " + langId);
return false;
}
return true;
}
@SuppressWarnings("SameParameterValue")
private boolean isIntInList(int number, ArrayList<Integer> list, String logTag, String logMsg) {
if (!list.contains(number)) {
Logger.w(logTag, logMsg);
return false;
}
return true;
}
/************* input settings *************/
public ArrayList<Integer> getEnabledLanguageIds() {
Set<String> languagesPref = getEnabledLanguagesIdsAsStrings();
ArrayList<Integer>languageIds = new ArrayList<>();
for (String languageId : languagesPref) {
languageIds.add(Integer.valueOf(languageId));
}
return languageIds;
}
public Set<String> getEnabledLanguagesIdsAsStrings() {
return prefs.getStringSet("pref_languages", new HashSet<>(Collections.singletonList(
String.valueOf(LanguageCollection.getDefault(context).getId())
)));
}
public void saveEnabledLanguageIds(ArrayList<Integer> languageIds) {
Set<String> idsAsStrings = new HashSet<>();
for (int langId : languageIds) {
idsAsStrings.add(String.valueOf(langId));
}
saveEnabledLanguageIds(idsAsStrings);
}
public void saveEnabledLanguageIds(Set<String> languageIds) {
Set<String> validLanguageIds = new HashSet<>();
for (String langId : languageIds) {
if (!validateSavedLanguage(Integer.parseInt(langId), "saveEnabledLanguageIds")){
continue;
}
validLanguageIds.add(langId);
}
if (validLanguageIds.isEmpty()) {
Logger.w("saveEnabledLanguageIds", "Refusing to save an empty language list");
return;
}
prefsEditor.putStringSet("pref_languages", validLanguageIds);
prefsEditor.apply();
}
public int getTextCase() {
return prefs.getInt("pref_text_case", InputMode.CASE_LOWER);
}
public void saveTextCase(int textCase) {
boolean isTextCaseValid = isIntInList(
textCase,
new ArrayList<>(Arrays.asList(InputMode.CASE_CAPITALIZE, InputMode.CASE_LOWER, InputMode.CASE_UPPER)),
"saveTextCase",
"Not saving invalid text case: " + textCase
);
if (isTextCaseValid) {
prefsEditor.putInt("pref_text_case", textCase);
prefsEditor.apply();
}
}
public int getInputLanguage() {
return prefs.getInt("pref_input_language", LanguageCollection.getDefault(context).getId());
}
public void saveInputLanguage(int language) {
if (validateSavedLanguage(language, "saveInputLanguage")){
prefsEditor.putInt("pref_input_language", language);
prefsEditor.apply();
}
}
public int getInputMode() {
return prefs.getInt("pref_input_mode", InputMode.MODE_PREDICTIVE);
}
public void saveInputMode(int mode) {
boolean isModeValid = isIntInList(
mode,
new ArrayList<>(Arrays.asList(InputMode.MODE_123, InputMode.MODE_PREDICTIVE, InputMode.MODE_ABC)),
"saveInputMode",
"Not saving invalid input mode: " + mode
);
if (isModeValid) {
prefsEditor.putInt("pref_input_mode", mode);
prefsEditor.apply();
}
}
/************* function key settings *************/
public boolean areHotkeysInitialized() {
return !prefs.getBoolean("hotkeys_initialized", false);
}
public void setDefaultKeys(
int addWord,
int backspace,
int changeKeyboard,
int filterClear,
int filterSuggestions,
int previousSuggestion,
int nextSuggestion,
int nextInputMode,
int nextLanguage,
int showSettings
) {
prefsEditor
.putString(SectionKeymap.ITEM_ADD_WORD, String.valueOf(addWord))
.putString(SectionKeymap.ITEM_BACKSPACE, String.valueOf(backspace))
.putString(SectionKeymap.ITEM_CHANGE_KEYBOARD, String.valueOf(changeKeyboard))
.putString(SectionKeymap.ITEM_FILTER_CLEAR, String.valueOf(filterClear))
.putString(SectionKeymap.ITEM_FILTER_SUGGESTIONS, String.valueOf(filterSuggestions))
.putString(SectionKeymap.ITEM_PREVIOUS_SUGGESTION, String.valueOf(previousSuggestion))
.putString(SectionKeymap.ITEM_NEXT_SUGGESTION, String.valueOf(nextSuggestion))
.putString(SectionKeymap.ITEM_NEXT_INPUT_MODE, String.valueOf(nextInputMode))
.putString(SectionKeymap.ITEM_NEXT_LANGUAGE, String.valueOf(nextLanguage))
.putString(SectionKeymap.ITEM_SHOW_SETTINGS, String.valueOf(showSettings))
.putBoolean("hotkeys_initialized", true)
.apply();
}
public int getFunctionKey(String functionName) {
try {
return Integer.parseInt(prefs.getString(functionName, "0"));
} catch (NumberFormatException e) {
return 0;
}
}
public int getKeyAddWord() {
return getFunctionKey(SectionKeymap.ITEM_ADD_WORD);
}
public int getKeyBackspace() {
return getFunctionKey(SectionKeymap.ITEM_BACKSPACE);
}
public int getKeyChangeKeyboard() {
return getFunctionKey(SectionKeymap.ITEM_CHANGE_KEYBOARD);
}
public int getKeyFilterClear() {
return getFunctionKey(SectionKeymap.ITEM_FILTER_CLEAR);
}
public int getKeyFilterSuggestions() {
return getFunctionKey(SectionKeymap.ITEM_FILTER_SUGGESTIONS);
}
public int getKeyPreviousSuggestion() {
return getFunctionKey(SectionKeymap.ITEM_PREVIOUS_SUGGESTION);
}
public int getKeyNextSuggestion() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_SUGGESTION);
}
public int getKeyNextInputMode() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_INPUT_MODE);
}
public int getKeyNextLanguage() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_LANGUAGE);
}
public int getKeyShowSettings() {
return getFunctionKey(SectionKeymap.ITEM_SHOW_SETTINGS);
}
/************* UI settings *************/
public boolean getDarkTheme() {
int theme = getTheme();
if (theme == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
} else {
return theme == AppCompatDelegate.MODE_NIGHT_YES;
}
}
public int getTheme() {
try {
return Integer.parseInt(prefs.getString("pref_theme", String.valueOf(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)));
} catch (NumberFormatException e) {
return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
}
}
public boolean getShowSoftKeys() { return prefs.getBoolean("pref_show_soft_keys", true); }
public boolean getShowSoftNumpad() { return getShowSoftKeys() && prefs.getBoolean("pref_show_soft_numpad", false); }
/************* typing settings *************/
public int getAbcAutoAcceptTimeout() { return prefs.getBoolean("abc_auto_accept", true) ? 800 + getKeyPadDebounceTime() : -1; }
public boolean getAutoSpace() { return prefs.getBoolean("auto_space", true); }
public boolean getAutoTextCase() { return prefs.getBoolean("auto_text_case", true); }
public String getDoubleZeroChar() {
String character = prefs.getString("pref_double_zero_char", ".");
// SharedPreferences return a corrupted string when using the real "\n"... :(
return character.equals("\\n") ? "\n" : character;
}
public boolean getUpsideDownKeys() { return prefs.getBoolean("pref_upside_down_keys", false); }
/************* internal settings *************/
public int getLogLevel() {
try {
return Integer.parseInt(prefs.getString("pref_log_level", String.valueOf(Logger.LEVEL)));
} catch (NumberFormatException ignored) {
return Logger.LEVEL;
}
}
public int getInputHandlingMode() {
try {
return Integer.parseInt(prefs.getString("pref_input_handling_mode", String.valueOf(ItemInputHandlingMode.NORMAL)));
} catch (NumberFormatException ignored) {
return ItemInputHandlingMode.NORMAL;
}
}
public final static int DELETE_WORDS_SEARCH_DELAY = 500; // ms
public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 120000; // ms
public final static int DICTIONARY_IMPORT_BATCH_SIZE = 5000; // words
public final static int DICTIONARY_IMPORT_PROGRESS_UPDATE_TIME = 250; // ms
public final static byte SLOW_QUERY_TIME = 50; // ms
public final static int SOFT_KEY_REPEAT_DELAY = 40; // ms
public final static float SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE = 0.55f;
public final static float SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE = 0.72f;
public final static float SOFT_KEY_COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f;
public final static int SUGGESTIONS_MAX = 20;
public final static int SUGGESTIONS_MIN = 8;
public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66;
public final static int SUGGESTIONS_TRANSLATE_ANIMATION_DURATION = 0;
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_NORMALIZATION_DELAY = 120000; // ms
/************* hack settings *************/
public int getSuggestionScrollingDelay() {
return prefs.getBoolean("pref_alternative_suggestion_scrolling", false) ? 200 : 0;
}
public boolean getFbMessengerHack() {
return prefs.getBoolean("pref_hack_fb_messenger", false);
}
public boolean getGoogleChatHack() {
return prefs.getBoolean("pref_hack_google_chat", false);
}
/**
* Protection against faulty devices, that sometimes send two (or more) click events
* per a single key press, which absolutely undesirable side effects.
* There were reports about this on <a href="https://github.com/sspanak/tt9/issues/117">Kyocera KYF31</a>
* and on <a href="https://github.com/sspanak/tt9/issues/399">CAT S22</a>.
*/
public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms
public int getKeyPadDebounceTime() {
try {
return Integer.parseInt(prefs.getString("pref_key_pad_debounce_time", "0"));
} catch (NumberFormatException e) {
return 0;
}
}
}

View file

@ -10,7 +10,7 @@ import java.util.LinkedHashMap;
import java.util.Set;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class Hotkeys {
private final Context context;

View file

@ -5,8 +5,8 @@ import androidx.preference.Preference;
import java.util.ArrayList;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.preferences.SettingsStore;
abstract public class ItemClickable {
private long lastClickTime = 0;

View file

@ -4,8 +4,8 @@ import androidx.preference.DropDownPreference;
import java.util.LinkedHashMap;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.items.ItemDropDown;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class ItemInputHandlingMode extends ItemDropDown {
public static final int NORMAL = 0;

View file

@ -12,7 +12,7 @@ import androidx.preference.PreferenceCategory;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.db.WordStoreAsync;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.ui.UI;
public class PreferenceDeletableWord extends Preference {

View file

@ -11,13 +11,13 @@ import androidx.preference.PreferenceViewHolder;
import java.util.ArrayList;
import io.github.sspanak.tt9.util.ConsumerCompat;
import io.github.sspanak.tt9.util.Logger;
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.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.ConsumerCompat;
import io.github.sspanak.tt9.util.Logger;
public class PreferenceSearchWords extends Preference {
public static final String NAME = "dictionary_delete_words_search";

View file

@ -7,8 +7,8 @@ import android.text.TextWatcher;
import androidx.annotation.NonNull;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.ConsumerCompat;
import io.github.sspanak.tt9.preferences.SettingsStore;
class TextChangeListener implements TextWatcher {
private static TextChangeListener self;

View file

@ -6,10 +6,10 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import io.github.sspanak.tt9.util.Logger;
import io.github.sspanak.tt9.preferences.PreferencesActivity;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.helpers.Hotkeys;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
public class SectionKeymap {
public static final String ITEM_ADD_WORD = "key_add_word";

View file

@ -0,0 +1,19 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
class BaseSettings {
protected final Context context;
protected final SharedPreferences prefs;
protected final SharedPreferences.Editor prefsEditor;
BaseSettings(Context context) {
this.context = context;
prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefsEditor = prefs.edit();
}
}

View file

@ -0,0 +1,58 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
import io.github.sspanak.tt9.preferences.screens.debug.ItemInputHandlingMode;
import io.github.sspanak.tt9.util.Logger;
class SettingsHacks extends BaseSettings {
SettingsHacks(Context context) { super(context); }
/************* debugging settings *************/
public int getLogLevel() {
try {
return Integer.parseInt(prefs.getString("pref_log_level", String.valueOf(Logger.LEVEL)));
} catch (NumberFormatException ignored) {
return Logger.LEVEL;
}
}
public int getInputHandlingMode() {
try {
return Integer.parseInt(prefs.getString("pref_input_handling_mode", String.valueOf(ItemInputHandlingMode.NORMAL)));
} catch (NumberFormatException ignored) {
return ItemInputHandlingMode.NORMAL;
}
}
/************* hack settings *************/
public int getSuggestionScrollingDelay() {
return prefs.getBoolean("pref_alternative_suggestion_scrolling", false) ? 200 : 0;
}
public boolean getFbMessengerHack() {
return prefs.getBoolean("pref_hack_fb_messenger", false);
}
public boolean getGoogleChatHack() {
return prefs.getBoolean("pref_hack_google_chat", false);
}
/**
* Protection against faulty devices, that sometimes send two (or more) click events
* per a single key press, which absolutely undesirable side effects.
* There were reports about this on <a href="https://github.com/sspanak/tt9/issues/117">Kyocera KYF31</a>
* and on <a href="https://github.com/sspanak/tt9/issues/399">CAT S22</a>.
*/
public int getKeyPadDebounceTime() {
try {
return Integer.parseInt(prefs.getString("pref_key_pad_debounce_time", "0"));
} catch (NumberFormatException e) {
return 0;
}
}
}

View file

@ -0,0 +1,79 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
import io.github.sspanak.tt9.preferences.screens.hotkeys.SectionKeymap;
class SettingsHotkeys extends SettingsHacks {
SettingsHotkeys(Context context) { super(context); }
public boolean areHotkeysInitialized() {
return !prefs.getBoolean("hotkeys_initialized", false);
}
public void setDefaultKeys(
int addWord,
int backspace,
int changeKeyboard,
int filterClear,
int filterSuggestions,
int previousSuggestion,
int nextSuggestion,
int nextInputMode,
int nextLanguage,
int showSettings
) {
prefsEditor
.putString(SectionKeymap.ITEM_ADD_WORD, String.valueOf(addWord))
.putString(SectionKeymap.ITEM_BACKSPACE, String.valueOf(backspace))
.putString(SectionKeymap.ITEM_CHANGE_KEYBOARD, String.valueOf(changeKeyboard))
.putString(SectionKeymap.ITEM_FILTER_CLEAR, String.valueOf(filterClear))
.putString(SectionKeymap.ITEM_FILTER_SUGGESTIONS, String.valueOf(filterSuggestions))
.putString(SectionKeymap.ITEM_PREVIOUS_SUGGESTION, String.valueOf(previousSuggestion))
.putString(SectionKeymap.ITEM_NEXT_SUGGESTION, String.valueOf(nextSuggestion))
.putString(SectionKeymap.ITEM_NEXT_INPUT_MODE, String.valueOf(nextInputMode))
.putString(SectionKeymap.ITEM_NEXT_LANGUAGE, String.valueOf(nextLanguage))
.putString(SectionKeymap.ITEM_SHOW_SETTINGS, String.valueOf(showSettings))
.putBoolean("hotkeys_initialized", true)
.apply();
}
public int getFunctionKey(String functionName) {
try {
return Integer.parseInt(prefs.getString(functionName, "0"));
} catch (NumberFormatException e) {
return 0;
}
}
public int getKeyAddWord() {
return getFunctionKey(SectionKeymap.ITEM_ADD_WORD);
}
public int getKeyBackspace() {
return getFunctionKey(SectionKeymap.ITEM_BACKSPACE);
}
public int getKeyChangeKeyboard() {
return getFunctionKey(SectionKeymap.ITEM_CHANGE_KEYBOARD);
}
public int getKeyFilterClear() {
return getFunctionKey(SectionKeymap.ITEM_FILTER_CLEAR);
}
public int getKeyFilterSuggestions() {
return getFunctionKey(SectionKeymap.ITEM_FILTER_SUGGESTIONS);
}
public int getKeyPreviousSuggestion() {
return getFunctionKey(SectionKeymap.ITEM_PREVIOUS_SUGGESTION);
}
public int getKeyNextSuggestion() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_SUGGESTION);
}
public int getKeyNextInputMode() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_INPUT_MODE);
}
public int getKeyNextLanguage() {
return getFunctionKey(SectionKeymap.ITEM_NEXT_LANGUAGE);
}
public int getKeyShowSettings() {
return getFunctionKey(SectionKeymap.ITEM_SHOW_SETTINGS);
}
}

View file

@ -0,0 +1,119 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.util.Logger;
class SettingsInput extends SettingsHotkeys {
SettingsInput(Context context) { super(context); }
public ArrayList<Integer> getEnabledLanguageIds() {
Set<String> languagesPref = getEnabledLanguagesIdsAsStrings();
ArrayList<Integer>languageIds = new ArrayList<>();
for (String languageId : languagesPref) {
languageIds.add(Integer.valueOf(languageId));
}
return languageIds;
}
public Set<String> getEnabledLanguagesIdsAsStrings() {
return prefs.getStringSet("pref_languages", new HashSet<>(Collections.singletonList(
String.valueOf(LanguageCollection.getDefault(context).getId())
)));
}
public void saveEnabledLanguageIds(ArrayList<Integer> languageIds) {
Set<String> idsAsStrings = new HashSet<>();
for (int langId : languageIds) {
idsAsStrings.add(String.valueOf(langId));
}
saveEnabledLanguageIds(idsAsStrings);
}
public void saveEnabledLanguageIds(Set<String> languageIds) {
Set<String> validLanguageIds = new HashSet<>();
for (String langId : languageIds) {
if (!Validators.validateSavedLanguage(context, Integer.parseInt(langId), "saveEnabledLanguageIds")){
continue;
}
validLanguageIds.add(langId);
}
if (validLanguageIds.isEmpty()) {
Logger.w("saveEnabledLanguageIds", "Refusing to save an empty language list");
return;
}
prefsEditor.putStringSet("pref_languages", validLanguageIds);
prefsEditor.apply();
}
public int getTextCase() {
return prefs.getInt("pref_text_case", InputMode.CASE_LOWER);
}
public void saveTextCase(int textCase) {
boolean isTextCaseValid = Validators.isIntInList(
textCase,
new ArrayList<>(Arrays.asList(InputMode.CASE_CAPITALIZE, InputMode.CASE_LOWER, InputMode.CASE_UPPER)),
"saveTextCase",
"Not saving invalid text case: " + textCase
);
if (isTextCaseValid) {
prefsEditor.putInt("pref_text_case", textCase);
prefsEditor.apply();
}
}
public int getInputLanguage() {
return prefs.getInt("pref_input_language", LanguageCollection.getDefault(context).getId());
}
public void saveInputLanguage(int language) {
if (Validators.validateSavedLanguage(context, language, "saveInputLanguage")){
prefsEditor.putInt("pref_input_language", language);
prefsEditor.apply();
}
}
public int getInputMode() {
return prefs.getInt("pref_input_mode", InputMode.MODE_PREDICTIVE);
}
public void saveInputMode(int mode) {
boolean isModeValid = Validators.isIntInList(
mode,
new ArrayList<>(Arrays.asList(InputMode.MODE_123, InputMode.MODE_PREDICTIVE, InputMode.MODE_ABC)),
"saveInputMode",
"Not saving invalid input mode: " + mode
);
if (isModeValid) {
prefsEditor.putInt("pref_input_mode", mode);
prefsEditor.apply();
}
}
}

View file

@ -0,0 +1,29 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
public class SettingsStore extends SettingsUI {
public SettingsStore(Context context) { super(context); }
/************* internal settings *************/
public final static int DELETE_WORDS_SEARCH_DELAY = 500; // ms
public final static int DICTIONARY_AUTO_LOAD_COOLDOWN_TIME = 120000; // ms
public final static int DICTIONARY_IMPORT_BATCH_SIZE = 5000; // words
public final static int DICTIONARY_IMPORT_PROGRESS_UPDATE_TIME = 250; // ms
public final static byte SLOW_QUERY_TIME = 50; // ms
public final static int SOFT_KEY_REPEAT_DELAY = 40; // ms
public final static float SOFT_KEY_COMPLEX_LABEL_TITLE_SIZE = 0.55f;
public final static float SOFT_KEY_COMPLEX_LABEL_ARABIC_TITLE_SIZE = 0.72f;
public final static float SOFT_KEY_COMPLEX_LABEL_SUB_TITLE_SIZE = 0.8f;
public final static int SUGGESTIONS_MAX = 20;
public final static int SUGGESTIONS_MIN = 8;
public final static int SUGGESTIONS_SELECT_ANIMATION_DURATION = 66;
public final static int SUGGESTIONS_TRANSLATE_ANIMATION_DURATION = 0;
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_NORMALIZATION_DELAY = 120000; // ms
/************* hacks *************/
public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms
}

View file

@ -0,0 +1,18 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
class SettingsTyping extends SettingsInput {
SettingsTyping(Context context) { super(context); }
public int getAbcAutoAcceptTimeout() { return prefs.getBoolean("abc_auto_accept", true) ? 800 + getKeyPadDebounceTime() : -1; }
public boolean getAutoSpace() { return prefs.getBoolean("auto_space", true); }
public boolean getAutoTextCase() { return prefs.getBoolean("auto_text_case", true); }
public String getDoubleZeroChar() {
String character = prefs.getString("pref_double_zero_char", ".");
// SharedPreferences return a corrupted string when using the real "\n"... :(
return character.equals("\\n") ? "\n" : character;
}
public boolean getUpsideDownKeys() { return prefs.getBoolean("pref_upside_down_keys", false); }
}

View file

@ -0,0 +1,31 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
import android.content.res.Configuration;
import androidx.appcompat.app.AppCompatDelegate;
class SettingsUI extends SettingsTyping {
SettingsUI(Context context) { super(context); }
public boolean getDarkTheme() {
int theme = getTheme();
if (theme == AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM) {
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
} else {
return theme == AppCompatDelegate.MODE_NIGHT_YES;
}
}
public int getTheme() {
try {
return Integer.parseInt(prefs.getString("pref_theme", String.valueOf(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)));
} catch (NumberFormatException e) {
return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;
}
}
public boolean getShowSoftKeys() { return prefs.getBoolean("pref_show_soft_keys", true); }
public boolean getShowSoftNumpad() { return getShowSoftKeys() && prefs.getBoolean("pref_show_soft_numpad", false); }
}

View file

@ -0,0 +1,33 @@
package io.github.sspanak.tt9.preferences.settings;
import android.content.Context;
import java.util.ArrayList;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.util.Logger;
class Validators {
static boolean doesLanguageExist(Context context, int langId) {
return LanguageCollection.getLanguage(context, langId) != null;
}
static boolean validateSavedLanguage(Context context, int langId, String logTag) {
if (!doesLanguageExist(context, langId)) {
Logger.w(logTag, "Not saving invalid language with ID: " + langId);
return false;
}
return true;
}
@SuppressWarnings("SameParameterValue")
static boolean isIntInList(int number, ArrayList<Integer> list, String logTag, String logMsg) {
if (!list.contains(number)) {
Logger.w(logTag, logMsg);
return false;
}
return true;
}
}

View file

@ -19,7 +19,7 @@ import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.TraditionalT9;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageCollection;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
public class SoftKey extends androidx.appcompat.widget.AppCompatButton implements View.OnTouchListener, View.OnLongClickListener {

View file

@ -11,7 +11,7 @@ import io.github.sspanak.tt9.ime.helpers.Key;
import io.github.sspanak.tt9.ime.modes.InputMode;
import io.github.sspanak.tt9.languages.Language;
import io.github.sspanak.tt9.languages.LanguageKind;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
import io.github.sspanak.tt9.util.Logger;
public class SoftNumberKey extends SoftKey {

View file

@ -19,7 +19,7 @@ import java.util.List;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.ime.AbstractHandler;
import io.github.sspanak.tt9.preferences.SettingsStore;
import io.github.sspanak.tt9.preferences.settings.SettingsStore;
public class SuggestionsBar {
private final List<String> suggestions = new ArrayList<>();