From f929caa4d88e196dcc2fe60be78fd3e567696d85 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sun, 2 Mar 2025 07:28:37 +0100 Subject: [PATCH] Remove old settings and clean up (#1392) --- app/build.gradle.kts | 8 +- app/src/main/AndroidManifest.xml | 30 +- .../latin/utils/BinaryDictionaryUtils.java | 1 + .../helium314/keyboard/keyboard/Keyboard.java | 10 - .../keyboard/keyboard/KeyboardLayout.java | 112 --- .../keyboard/keyboard/KeyboardSwitcher.java | 18 +- .../clipboard/ClipboardHistoryRecyclerView.kt | 1 + .../keyboard/emoji/EmojiCategory.java | 1 - .../keyboard/internal/CodesArrayParser.java | 98 --- .../internal/MoreCodesArrayParser.java | 57 -- .../keyboard_parser/KeyboardParser.kt | 12 - .../main/java/helium314/keyboard/latin/App.kt | 10 + .../keyboard/latin/DictionaryCollection.java | 18 +- .../helium314/keyboard/latin/LatinIME.java | 9 +- .../latin/SystemBroadcastReceiver.java | 4 +- .../keyboard/latin/common/LocaleUtils.kt | 5 - .../keyboard/latin/common/StringUtils.java | 86 --- .../permissions/PermissionsActivity.java | 88 --- .../latin/permissions/PermissionsManager.java | 81 --- .../latin/permissions/PermissionsUtil.java | 50 +- .../keyboard/latin/settings/AboutFragment.kt | 92 --- .../settings/AdvancedSettingsFragment.kt | 642 ------------------ .../settings/AppearanceSettingsFragment.kt | 476 ------------- .../latin/settings/ColorsSettingsFragment.kt | 440 ------------ .../settings/CorrectionSettingsFragment.java | 86 --- .../latin/settings/DebugSettings.java | 1 + .../latin/settings/DebugSettingsFragment.java | 111 --- .../keyboard/latin/settings/Defaults.kt | 3 +- .../latin/settings/FragmentBindingUtils.kt | 48 -- .../settings/GestureSettingsFragment.java | 165 ----- .../latin/settings/LanguageFilterList.kt | 159 ----- .../latin/settings/LanguageSettingsDialog.kt | 430 ------------ .../settings/LanguageSettingsFragment.kt | 227 ------- .../latin/settings/OldSettingsActivity.java | 74 -- .../settings/PreferencesSettingsFragment.java | 278 -------- .../settings/SeekBarDialogPreference.java | 136 ---- .../keyboard/latin/settings/Settings.java | 14 +- .../latin/settings/SettingsFragment.java | 153 ----- .../latin/settings/SettingsValues.java | 45 +- .../latin/settings/SubScreenFragment.java | 144 ---- .../latin/settings/ToolbarSettingsFragment.kt | 68 -- .../UserDictionaryAddWordContents.java | 294 -------- .../UserDictionaryAddWordFragment.java | 215 ------ .../settings/UserDictionaryListFragment.java | 171 ----- .../settings/UserDictionarySettings.java | 348 ---------- .../keyboard/latin/setup/SetupActivity.java | 33 - .../latin/setup/SetupStartIndicatorView.java | 98 --- .../latin/setup/SetupStepIndicatorView.java | 53 -- .../latin/setup/SetupWizardActivity.java | 434 ------------ .../AndroidWordLevelSpellCheckerSession.java | 9 +- .../SpellCheckerSettingsActivity.kt | 5 +- .../latin/utils/ActivityThemeUtils.java | 27 - .../keyboard/latin/utils/DebugLogUtils.java | 14 - .../latin/utils/DeviceProtectedUtils.java | 11 +- .../keyboard/latin/utils/DialogUtils.kt | 126 +--- .../keyboard/latin/utils/DictionaryUtils.kt | 63 -- .../helium314/keyboard/latin/utils/Ktx.kt | 15 - .../keyboard/latin/utils/LayoutUtilsCustom.kt | 97 --- .../latin/utils/NewDictionaryAdder.kt | 144 ---- .../keyboard/latin/utils/PopupKeysUtils.kt | 3 +- .../keyboard/latin/utils/ResourceUtils.java | 8 - .../keyboard/latin/utils/SubtypeSettings.kt | 2 - .../latin/utils/SubtypeUtilsAdditional.kt | 11 - .../keyboard/settings/SettingsActivity.kt | 45 +- .../preferences/BackgroundImagePreference.kt | 1 - .../preferences/BackupRestorePreference.kt | 10 +- .../preferences/LoadGestureLibPreference.kt | 6 - .../settings/preferences/Preference.kt | 4 +- .../keyboard/settings/screens/AboutScreen.kt | 10 +- .../settings/screens/AppearanceScreen.kt | 13 +- .../keyboard/settings/screens/DebugScreen.kt | 5 +- .../settings/screens/MainSettingsScreen.kt | 61 +- .../settings/screens/TextCorrectionScreen.kt | 13 +- .../color/setup_step_action_background.xml | 16 - .../main/res/color/setup_step_action_text.xml | 14 - .../main/res/drawable/ic_settings_about.xml | 17 +- .../drawable/ic_settings_about_foreground.xml | 13 - .../res/drawable/ic_settings_about_github.xml | 17 +- .../ic_settings_about_github_foreground.xml | 13 - .../ic_settings_about_hidden_features.xml | 17 +- ...tings_about_hidden_features_foreground.xml | 13 - .../drawable/ic_settings_about_license.xml | 17 +- .../ic_settings_about_license_foreground.xml | 13 - .../res/drawable/ic_settings_about_log.xml | 17 +- .../ic_settings_about_log_foreground.xml | 13 - .../res/drawable/ic_settings_advanced.xml | 17 +- .../ic_settings_advanced_foreground.xml | 13 - .../res/drawable/ic_settings_appearance.xml | 18 +- .../ic_settings_appearance_foreground.xml | 14 - .../res/drawable/ic_settings_correction.xml | 17 +- .../ic_settings_correction_foreground.xml | 13 - .../main/res/drawable/ic_settings_gesture.xml | 18 +- .../ic_settings_gesture_foreground.xml | 14 - .../res/drawable/ic_settings_languages.xml | 18 +- .../ic_settings_languages_foreground.xml | 14 - .../res/drawable/ic_settings_preferences.xml | 17 +- .../ic_settings_preferences_foreground.xml | 13 - .../main/res/drawable/ic_settings_toolbar.xml | 17 +- .../ic_settings_toolbar_foreground.xml | 13 - .../drawable/setup_step_action_background.xml | 16 - .../res/layout-land/setup_steps_screen.xml | 27 - .../res/layout-land/setup_welcome_screen.xml | 27 - app/src/main/res/layout/color_setting.xml | 43 -- app/src/main/res/layout/color_settings.xml | 37 - .../main/res/layout/language_list_item.xml | 63 -- .../res/layout/language_search_filter.xml | 45 -- app/src/main/res/layout/language_settings.xml | 23 - .../res/layout/locale_settings_dialog.xml | 119 ---- .../main/res/layout/reorder_dialog_item.xml | 43 -- app/src/main/res/layout/seek_bar_dialog.xml | 30 - app/src/main/res/layout/settings_activity.xml | 19 - .../layout/setup_start_indicator_label.xml | 18 - app/src/main/res/layout/setup_step.xml | 29 - app/src/main/res/layout/setup_steps_cards.xml | 61 -- .../main/res/layout/setup_steps_screen.xml | 16 - app/src/main/res/layout/setup_steps_title.xml | 13 - .../main/res/layout/setup_welcome_image.xml | 37 - .../main/res/layout/setup_welcome_screen.xml | 15 - .../main/res/layout/setup_welcome_title.xml | 19 - app/src/main/res/layout/setup_wizard.xml | 22 - .../res/layout/toolbar_key_customizer.xml | 42 -- .../user_dictionary_add_word_fullscreen.xml | 140 ---- .../main/res/layout/user_dictionary_item.xml | 52 -- ...user_dictionary_settings_list_fragment.xml | 55 -- .../res/values-h1200dp-port/setup-dimens.xml | 16 - .../res/values-h330dp-land/setup-dimens.xml | 25 - .../res/values-h520dp-land/setup-dimens.xml | 22 - .../res/values-h540dp-port/setup-dimens.xml | 24 - .../res/values-h720dp-land/setup-dimens.xml | 16 - .../res/values-h800dp-port/setup-dimens.xml | 19 - app/src/main/res/values-land/setup-dimens.xml | 17 - .../main/res/values-v29/donottranslate.xml | 8 - .../main/res/values-v31/platform-theme.xml | 19 +- .../config-auto-correction-thresholds.xml | 39 -- app/src/main/res/values/config-common.xml | 22 - app/src/main/res/values/donottranslate.xml | 48 -- .../res/values/ic_launcher_background.xml | 4 - .../main/res/values/preferences_styles.xml | 17 - app/src/main/res/values/setup-dimens.xml | 32 - .../main/res/values/setup-styles-common.xml | 59 -- app/src/main/res/values/setup-styles.xml | 15 - app/src/main/res/values/setup-wizard.xml | 7 - app/src/main/res/xml/prefs.xml | 58 -- app/src/main/res/xml/prefs_screen_about.xml | 50 -- .../main/res/xml/prefs_screen_advanced.xml | 148 ---- .../main/res/xml/prefs_screen_appearance.xml | 173 ----- .../main/res/xml/prefs_screen_correction.xml | 141 ---- app/src/main/res/xml/prefs_screen_debug.xml | 41 -- app/src/main/res/xml/prefs_screen_gesture.xml | 51 -- .../main/res/xml/prefs_screen_preferences.xml | 141 ---- app/src/main/res/xml/prefs_screen_toolbar.xml | 56 -- .../helium314/keyboard/latin/SuggestTest.kt | 10 +- 152 files changed, 263 insertions(+), 9262 deletions(-) delete mode 100644 app/src/main/java/helium314/keyboard/keyboard/KeyboardLayout.java delete mode 100644 app/src/main/java/helium314/keyboard/keyboard/internal/CodesArrayParser.java delete mode 100644 app/src/main/java/helium314/keyboard/keyboard/internal/MoreCodesArrayParser.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/permissions/PermissionsActivity.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/permissions/PermissionsManager.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/AboutFragment.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/AdvancedSettingsFragment.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/AppearanceSettingsFragment.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/ColorsSettingsFragment.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/CorrectionSettingsFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/DebugSettingsFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/FragmentBindingUtils.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/GestureSettingsFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/LanguageFilterList.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsFragment.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/OldSettingsActivity.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/PreferencesSettingsFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/SeekBarDialogPreference.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/SettingsFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/SubScreenFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/ToolbarSettingsFragment.kt delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordContents.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryListFragment.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/settings/UserDictionarySettings.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/setup/SetupActivity.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/setup/SetupStartIndicatorView.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/setup/SetupStepIndicatorView.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/setup/SetupWizardActivity.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/utils/ActivityThemeUtils.java delete mode 100644 app/src/main/java/helium314/keyboard/latin/utils/NewDictionaryAdder.kt delete mode 100644 app/src/main/res/color/setup_step_action_background.xml delete mode 100644 app/src/main/res/color/setup_step_action_text.xml delete mode 100644 app/src/main/res/drawable/ic_settings_about_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_about_github_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_about_hidden_features_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_about_license_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_about_log_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_advanced_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_appearance_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_correction_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_gesture_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_languages_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_preferences_foreground.xml delete mode 100644 app/src/main/res/drawable/ic_settings_toolbar_foreground.xml delete mode 100644 app/src/main/res/drawable/setup_step_action_background.xml delete mode 100644 app/src/main/res/layout-land/setup_steps_screen.xml delete mode 100644 app/src/main/res/layout-land/setup_welcome_screen.xml delete mode 100644 app/src/main/res/layout/color_setting.xml delete mode 100644 app/src/main/res/layout/color_settings.xml delete mode 100644 app/src/main/res/layout/language_list_item.xml delete mode 100644 app/src/main/res/layout/language_search_filter.xml delete mode 100644 app/src/main/res/layout/language_settings.xml delete mode 100644 app/src/main/res/layout/locale_settings_dialog.xml delete mode 100644 app/src/main/res/layout/reorder_dialog_item.xml delete mode 100644 app/src/main/res/layout/seek_bar_dialog.xml delete mode 100644 app/src/main/res/layout/settings_activity.xml delete mode 100644 app/src/main/res/layout/setup_start_indicator_label.xml delete mode 100644 app/src/main/res/layout/setup_step.xml delete mode 100644 app/src/main/res/layout/setup_steps_cards.xml delete mode 100644 app/src/main/res/layout/setup_steps_screen.xml delete mode 100644 app/src/main/res/layout/setup_steps_title.xml delete mode 100644 app/src/main/res/layout/setup_welcome_image.xml delete mode 100644 app/src/main/res/layout/setup_welcome_screen.xml delete mode 100644 app/src/main/res/layout/setup_welcome_title.xml delete mode 100644 app/src/main/res/layout/setup_wizard.xml delete mode 100644 app/src/main/res/layout/toolbar_key_customizer.xml delete mode 100644 app/src/main/res/layout/user_dictionary_add_word_fullscreen.xml delete mode 100644 app/src/main/res/layout/user_dictionary_item.xml delete mode 100644 app/src/main/res/layout/user_dictionary_settings_list_fragment.xml delete mode 100644 app/src/main/res/values-h1200dp-port/setup-dimens.xml delete mode 100644 app/src/main/res/values-h330dp-land/setup-dimens.xml delete mode 100644 app/src/main/res/values-h520dp-land/setup-dimens.xml delete mode 100644 app/src/main/res/values-h540dp-port/setup-dimens.xml delete mode 100644 app/src/main/res/values-h720dp-land/setup-dimens.xml delete mode 100644 app/src/main/res/values-h800dp-port/setup-dimens.xml delete mode 100644 app/src/main/res/values-land/setup-dimens.xml delete mode 100644 app/src/main/res/values-v29/donottranslate.xml delete mode 100644 app/src/main/res/values/config-auto-correction-thresholds.xml delete mode 100644 app/src/main/res/values/ic_launcher_background.xml delete mode 100644 app/src/main/res/values/preferences_styles.xml delete mode 100644 app/src/main/res/values/setup-dimens.xml delete mode 100644 app/src/main/res/values/setup-styles-common.xml delete mode 100644 app/src/main/res/values/setup-styles.xml delete mode 100644 app/src/main/res/values/setup-wizard.xml delete mode 100644 app/src/main/res/xml/prefs.xml delete mode 100644 app/src/main/res/xml/prefs_screen_about.xml delete mode 100644 app/src/main/res/xml/prefs_screen_advanced.xml delete mode 100644 app/src/main/res/xml/prefs_screen_appearance.xml delete mode 100644 app/src/main/res/xml/prefs_screen_correction.xml delete mode 100644 app/src/main/res/xml/prefs_screen_debug.xml delete mode 100644 app/src/main/res/xml/prefs_screen_gesture.xml delete mode 100644 app/src/main/res/xml/prefs_screen_preferences.xml delete mode 100644 app/src/main/res/xml/prefs_screen_toolbar.xml diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 115c2bef0..445f17ff9 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -13,8 +13,8 @@ android { applicationId = "helium314.keyboard" minSdk = 21 targetSdk = 34 - versionCode = 2309 - versionName = "2.3+dev8" + versionCode = 2310 + versionName = "2.3+dev9" ndk { abiFilters.clear() abiFilters.addAll(listOf("armeabi-v7a", "arm64-v8a", "x86", "x86_64")) @@ -100,7 +100,6 @@ dependencies { // androidx implementation("androidx.core:core-ktx:1.13.1") implementation("androidx.appcompat:appcompat:1.7.0") - implementation("androidx.preference:preference:1.2.1") implementation("androidx.recyclerview:recyclerview:1.3.2") implementation("androidx.autofill:autofill:1.1.0") @@ -117,9 +116,6 @@ dependencies { implementation("sh.calvin.reorderable:reorderable:2.4.2") // for easier re-ordering implementation("com.github.skydoves:colorpicker-compose:1.1.2") // for user-defined colors - // color picker for user-defined colors - implementation("com.github.martin-stone:hsv-alpha-color-picker-android:3.1.0") - // test testImplementation(kotlin("test")) testImplementation("junit:junit:4.13.2") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index abe4ada1f..943a58029 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -49,41 +49,15 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - - - - - - - - - - - - - - - - + diff --git a/app/src/main/java/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java b/app/src/main/java/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java index b920fc334..c2e24943e 100644 --- a/app/src/main/java/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java +++ b/app/src/main/java/com/android/inputmethod/latin/utils/BinaryDictionaryUtils.java @@ -94,6 +94,7 @@ public final class BinaryDictionaryUtils { valueArray); } + /** normalized score is >= 0, with 0 being a bad match, ~0.1 ok for autocorrect, and ~1.5 a very good match */ public static float calcNormalizedScore(final String before, final String after, final int score) { return calcNormalizedScoreNative(StringUtils.toCodePointArray(before), diff --git a/app/src/main/java/helium314/keyboard/keyboard/Keyboard.java b/app/src/main/java/helium314/keyboard/keyboard/Keyboard.java index 802370cf0..c89423538 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/Keyboard.java +++ b/app/src/main/java/helium314/keyboard/keyboard/Keyboard.java @@ -88,8 +88,6 @@ public class Keyboard { @NonNull private final ProximityInfo mProximityInfo; - @NonNull - private final KeyboardLayout mKeyboardLayout; private final boolean mProximityCharsCorrectionEnabled; @@ -117,8 +115,6 @@ public class Keyboard { mOccupiedWidth, mOccupiedHeight, mMostCommonKeyWidth, mMostCommonKeyHeight, mSortedKeys, params.mTouchPositionCorrection); mProximityCharsCorrectionEnabled = params.mProximityCharsCorrectionEnabled; - mKeyboardLayout = KeyboardLayout.newKeyboardLayout(mSortedKeys, mMostCommonKeyWidth, - mMostCommonKeyHeight, mOccupiedWidth, mOccupiedHeight); } protected Keyboard(@NonNull final Keyboard keyboard) { @@ -143,7 +139,6 @@ public class Keyboard { mProximityInfo = keyboard.mProximityInfo; mProximityCharsCorrectionEnabled = keyboard.mProximityCharsCorrectionEnabled; - mKeyboardLayout = keyboard.mKeyboardLayout; } public boolean hasProximityCharsCorrection(final int code) { @@ -163,11 +158,6 @@ public class Keyboard { return mProximityInfo; } - @NonNull - public KeyboardLayout getKeyboardLayout() { - return mKeyboardLayout; - } - /** * Return the sorted list of keys of this keyboard. * The keys are sorted from top-left to bottom-right order. diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayout.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayout.java deleted file mode 100644 index 75af09ac7..000000000 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayout.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.keyboard; - -import androidx.annotation.NonNull; - -import com.android.inputmethod.keyboard.ProximityInfo; - -import java.util.ArrayList; -import java.util.List; - -/** - * KeyboardLayout maintains the keyboard layout information. - */ -public class KeyboardLayout { - - private final int[] mKeyCodes; - - private final int[] mKeyXCoordinates; - private final int[] mKeyYCoordinates; - - private final int[] mKeyWidths; - private final int[] mKeyHeights; - - public final int mMostCommonKeyWidth; - public final int mMostCommonKeyHeight; - - public final int mKeyboardWidth; - public final int mKeyboardHeight; - - public KeyboardLayout(ArrayList layoutKeys, int mostCommonKeyWidth, - int mostCommonKeyHeight, int keyboardWidth, int keyboardHeight) { - mMostCommonKeyWidth = mostCommonKeyWidth; - mMostCommonKeyHeight = mostCommonKeyHeight; - mKeyboardWidth = keyboardWidth; - mKeyboardHeight = keyboardHeight; - - mKeyCodes = new int[layoutKeys.size()]; - mKeyXCoordinates = new int[layoutKeys.size()]; - mKeyYCoordinates = new int[layoutKeys.size()]; - mKeyWidths = new int[layoutKeys.size()]; - mKeyHeights = new int[layoutKeys.size()]; - - for (int i = 0; i < layoutKeys.size(); i++) { - Key key = layoutKeys.get(i); - mKeyCodes[i] = Character.toLowerCase(key.getCode()); - mKeyXCoordinates[i] = key.getX(); - mKeyYCoordinates[i] = key.getY(); - mKeyWidths[i] = key.getWidth(); - mKeyHeights[i] = key.getHeight(); - } - } - - public int[] getKeyCodes() { - return mKeyCodes; - } - - /** - * The x-coordinate for the top-left corner of the keys. - * - */ - public int[] getKeyXCoordinates() { - return mKeyXCoordinates; - } - - /** - * The y-coordinate for the top-left corner of the keys. - */ - public int[] getKeyYCoordinates() { - return mKeyYCoordinates; - } - - /** - * The widths of the keys which are smaller than the true hit-area due to the gaps - * between keys. The mostCommonKey(Width/Height) represents the true key width/height - * including the gaps. - */ - public int[] getKeyWidths() { - return mKeyWidths; - } - - /** - * The heights of the keys which are smaller than the true hit-area due to the gaps - * between keys. The mostCommonKey(Width/Height) represents the true key width/height - * including the gaps. - */ - public int[] getKeyHeights() { - return mKeyHeights; - } - - /** - * Factory method to create {@link KeyboardLayout} objects. - */ - public static KeyboardLayout newKeyboardLayout(@NonNull final List sortedKeys, - int mostCommonKeyWidth, int mostCommonKeyHeight, - int occupiedWidth, int occupiedHeight) { - final ArrayList layoutKeys = new ArrayList(); - for (final Key key : sortedKeys) { - if (!ProximityInfo.needsProximityInfo(key)) { - continue; - } - if (key.getCode() != ',') { - layoutKeys.add(key); - } - } - return new KeyboardLayout(layoutKeys, mostCommonKeyWidth, mostCommonKeyHeight, occupiedWidth, occupiedHeight); - } -} diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java index e041c64ac..ff143cb22 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java @@ -114,18 +114,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { } } - // todo: maybe we can remove this after removing old setting? - public void forceUpdateKeyboardTheme(@NonNull Context displayContext) { - Settings settings = Settings.getInstance(); - settings.loadSettings(displayContext, settings.getCurrent().mLocale, settings.getCurrent().mInputAttributes); - final boolean showing = mLatinIME.isInputViewShown(); - if (showing) - mLatinIME.hideWindow(); - mLatinIME.setInputView(onCreateInputView(displayContext, mIsHardwareAcceleratedDrawingEnabled)); - if (showing) - mLatinIME.showWindow(true); - } - private boolean updateKeyboardThemeAndContextThemeWrapper(final Context context, final KeyboardTheme keyboardTheme) { final Resources res = context.getResources(); if (mThemeNeedsReload @@ -739,6 +727,10 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { // Hide and show IME, showing will trigger the reload. // Reloading while IME is shown is glitchy, and hiding / showing is so fast the user shouldn't notice. mLatinIME.hideWindow(); - mLatinIME.showWindow(true); + try { + mLatinIME.showWindow(true); + } catch (IllegalStateException e) { + // in tests isInputViewShown returns true, but showWindow throws "IllegalStateException: Window token is not set yet." + } } } diff --git a/app/src/main/java/helium314/keyboard/keyboard/clipboard/ClipboardHistoryRecyclerView.kt b/app/src/main/java/helium314/keyboard/keyboard/clipboard/ClipboardHistoryRecyclerView.kt index e04179e7f..33549be18 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/clipboard/ClipboardHistoryRecyclerView.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/clipboard/ClipboardHistoryRecyclerView.kt @@ -17,6 +17,7 @@ class ClipboardHistoryRecyclerView @JvmOverloads constructor( var placeholderView: View? = null val historyManager: ClipboardHistoryManager? get() = (adapter as? ClipboardAdapter?)?.clipboardHistoryManager + @Suppress("unused") private val touchHelper = ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) { override fun onMove(recyclerView: RecyclerView, viewHolder: ViewHolder, target: ViewHolder) = false override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: ViewHolder): Int { diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java index 088a66d50..910fcb38a 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java @@ -13,7 +13,6 @@ import android.content.res.TypedArray; import android.graphics.Paint; import android.graphics.Rect; -import helium314.keyboard.latin.common.DefaultColors; import helium314.keyboard.latin.settings.Defaults; import helium314.keyboard.latin.utils.KtxKt; import helium314.keyboard.latin.utils.Log; diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/CodesArrayParser.java b/app/src/main/java/helium314/keyboard/keyboard/internal/CodesArrayParser.java deleted file mode 100644 index 7cd1a6873..000000000 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/CodesArrayParser.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.keyboard.internal; - -import android.text.TextUtils; - -import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; -import helium314.keyboard.latin.common.Constants; -import helium314.keyboard.latin.common.StringUtils; - -/** - * The string parser of codesArray specification for . The attribute codesArray is an - * array of string. - * Each element of the array defines a key label by specifying a code point as a hexadecimal string. - * A key label may consist of multiple code points separated by comma. - * Each element of the array optionally can have an output text definition after vertical bar - * marker. An output text may consist of multiple code points separated by comma. - * The format of the codesArray element should be: - *
- *   label1[,label2]*(|outputText1[,outputText2]*(|minSupportSdkVersion)?)?
- * 
- */ -// TODO: Write unit tests for this class. -public final class CodesArrayParser { - // Constants for parsing. - private static final char COMMA = Constants.CODE_COMMA; - private static final String COMMA_REGEX = StringUtils.newSingleCodePointString(COMMA); - private static final String VERTICAL_BAR_REGEX = // "\\|" - new String(new char[] { Constants.CODE_BACKSLASH, Constants.CODE_VERTICAL_BAR }); - private static final int BASE_HEX = 16; - - private CodesArrayParser() { - // This utility class is not publicly instantiable. - } - - private static String getLabelSpec(final String codesArraySpec) { - final String[] strs = codesArraySpec.split(VERTICAL_BAR_REGEX, -1); - if (strs.length <= 1) { - return codesArraySpec; - } - return strs[0]; - } - - public static String parseLabel(final String codesArraySpec) { - final String labelSpec = getLabelSpec(codesArraySpec); - final StringBuilder sb = new StringBuilder(); - for (final String codeInHex : labelSpec.split(COMMA_REGEX)) { - final int codePoint = Integer.parseInt(codeInHex, BASE_HEX); - sb.appendCodePoint(codePoint); - } - return sb.toString(); - } - - private static String getCodeSpec(final String codesArraySpec) { - final String[] strs = codesArraySpec.split(VERTICAL_BAR_REGEX, -1); - if (strs.length <= 1) { - return codesArraySpec; - } - return TextUtils.isEmpty(strs[1]) ? strs[0] : strs[1]; - } - - public static int getMinSupportSdkVersion(final String codesArraySpec) { - final String[] strs = codesArraySpec.split(VERTICAL_BAR_REGEX, -1); - if (strs.length <= 2) { - return 0; - } - try { - return Integer.parseInt(strs[2]); - } catch (NumberFormatException e) { - return 0; - } - } - - public static int parseCode(final String codesArraySpec) { - final String codeSpec = getCodeSpec(codesArraySpec); - if (codeSpec.indexOf(COMMA) < 0) { - return Integer.parseInt(codeSpec, BASE_HEX); - } - return KeyCode.MULTIPLE_CODE_POINTS; - } - - public static String parseOutputText(final String codesArraySpec) { - final String codeSpec = getCodeSpec(codesArraySpec); - if (codeSpec.indexOf(COMMA) < 0) { - return null; - } - final StringBuilder sb = new StringBuilder(); - for (final String codeInHex : codeSpec.split(COMMA_REGEX)) { - final int codePoint = Integer.parseInt(codeInHex, BASE_HEX); - sb.appendCodePoint(codePoint); - } - return sb.toString(); - } -} diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/MoreCodesArrayParser.java b/app/src/main/java/helium314/keyboard/keyboard/internal/MoreCodesArrayParser.java deleted file mode 100644 index 1b3bf7953..000000000 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/MoreCodesArrayParser.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.keyboard.internal; - -import android.os.Build; -import android.text.TextUtils; - -import androidx.annotation.Nullable; - -import helium314.keyboard.latin.common.StringUtils; - -/** - * The string parser of moreCodesArray specification for . The attribute moreCodesArray is an - * array of string. - * The more codes array specification is semicolon separated "codes array specification" each of which represents one - * "popup key". - * Each element of the array defines a sequence of key labels specified as hexadecimal strings - * representing code points separated by a vertical bar. - * - */ -public final class MoreCodesArrayParser { - // Constants for parsing. - private static final char SEMICOLON = ';'; - private static final String SEMICOLON_REGEX = StringUtils.newSingleCodePointString(SEMICOLON); - - private MoreCodesArrayParser() { - // This utility class is not publicly instantiable. - } - - public static String parseKeySpecs(@Nullable String codeArraySpecs) { - if (codeArraySpecs == null || TextUtils.isEmpty(codeArraySpecs)) { - return null; - } - - final StringBuilder sb = new StringBuilder(); - for (final String codeArraySpec : codeArraySpecs.split(SEMICOLON_REGEX)) { - final int supportedMinSdkVersion = CodesArrayParser.getMinSupportSdkVersion(codeArraySpec); - if (Build.VERSION.SDK_INT < supportedMinSdkVersion) { - continue; - } - final String label = CodesArrayParser.parseLabel(codeArraySpec); - final String outputText = CodesArrayParser.parseOutputText(codeArraySpec); - - sb.append(label).append("|").append(outputText); - sb.append(","); - } - - // Remove last comma - if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1); - - return sb.length() > 0 ? sb.toString() : null; - } -} diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt index bef599f22..999716ac6 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/KeyboardParser.kt @@ -332,15 +332,3 @@ class KeyboardParser(private val params: KeyboardParams, private val context: Co } } - -const val LAYOUT_SYMBOLS = "symbols" -const val LAYOUT_SYMBOLS_SHIFTED = "symbols_shifted" -const val LAYOUT_SYMBOLS_ARABIC = "symbols_arabic" -const val LAYOUT_NUMPAD = "numpad" -const val LAYOUT_NUMPAD_LANDSCAPE = "numpad_landscape" -const val LAYOUT_NUMBER = "number" -const val LAYOUT_PHONE = "phone" -const val LAYOUT_PHONE_SYMBOLS = "phone_symbols" -const val LAYOUT_NUMBER_ROW = "number_row" -const val LAYOUT_EMOJI_BOTTOM_ROW = "emoji_bottom_row" -const val LAYOUT_CLIPBOARD_BOTTOM_ROW = "clip_bottom_row" diff --git a/app/src/main/java/helium314/keyboard/latin/App.kt b/app/src/main/java/helium314/keyboard/latin/App.kt index 37f658d78..0fd190f29 100644 --- a/app/src/main/java/helium314/keyboard/latin/App.kt +++ b/app/src/main/java/helium314/keyboard/latin/App.kt @@ -516,6 +516,16 @@ fun checkVersionUpgrade(context: Context) { } } } + if (oldVersion <= 2309) { + if (prefs.contains("auto_correction_confidence")) { + val value = when (prefs.getString("auto_correction_confidence", "0")) { + "1" -> 0.067f + "2" -> -1f + else -> 0.185f + } + prefs.edit().remove("auto_correction_confidence").putFloat(Settings.PREF_AUTO_CORRECT_THRESHOLD, value).apply() + } + } upgradeToolbarPrefs(prefs) LayoutUtilsCustom.onLayoutFileChanged() // just to be sure prefs.edit { putInt(Settings.PREF_VERSION_CODE, BuildConfig.VERSION_CODE) } diff --git a/app/src/main/java/helium314/keyboard/latin/DictionaryCollection.java b/app/src/main/java/helium314/keyboard/latin/DictionaryCollection.java index 10b0f1fd1..7496f86f1 100644 --- a/app/src/main/java/helium314/keyboard/latin/DictionaryCollection.java +++ b/app/src/main/java/helium314/keyboard/latin/DictionaryCollection.java @@ -23,23 +23,7 @@ import java.util.concurrent.CopyOnWriteArrayList; */ public final class DictionaryCollection extends Dictionary { private final String TAG = DictionaryCollection.class.getSimpleName(); - protected final CopyOnWriteArrayList mDictionaries; - - public DictionaryCollection(final String dictType, final Locale locale) { - super(dictType, locale); - mDictionaries = new CopyOnWriteArrayList<>(); - } - - public DictionaryCollection(final String dictType, final Locale locale, - final Dictionary... dictionaries) { - super(dictType, locale); - if (null == dictionaries) { - mDictionaries = new CopyOnWriteArrayList<>(); - } else { - mDictionaries = new CopyOnWriteArrayList<>(dictionaries); - mDictionaries.removeAll(Collections.singleton(null)); - } - } + private final CopyOnWriteArrayList mDictionaries; public DictionaryCollection(final String dictType, final Locale locale, final Collection dictionaries) { diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 4a6f1e69b..d2e75a457 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -70,7 +70,6 @@ import helium314.keyboard.latin.common.ViewOutlineProviderUtilsKt; import helium314.keyboard.latin.define.DebugFlags; import helium314.keyboard.latin.define.ProductionFlags; import helium314.keyboard.latin.inputlogic.InputLogic; -import helium314.keyboard.latin.permissions.PermissionsManager; import helium314.keyboard.latin.personalization.PersonalizationHelper; import helium314.keyboard.latin.settings.Settings; import helium314.keyboard.latin.settings.SettingsValues; @@ -109,8 +108,7 @@ import androidx.core.content.ContextCompat; */ public class LatinIME extends InputMethodService implements SuggestionStripView.Listener, SuggestionStripViewAccessor, - DictionaryFacilitator.DictionaryInitializationListener, - PermissionsManager.PermissionsResultCallback { + DictionaryFacilitator.DictionaryInitializationListener { static final String TAG = LatinIME.class.getSimpleName(); private static final boolean TRACE = false; @@ -1379,11 +1377,6 @@ public class LatinIME extends InputMethodService implements return keyboard.getCoordinates(codePoints); } - @Override - public void onRequestPermissionsResult(boolean allGranted) { - setNeutralSuggestionStrip(); - } - public void displaySettingsDialog() { launchSettings(); } diff --git a/app/src/main/java/helium314/keyboard/latin/SystemBroadcastReceiver.java b/app/src/main/java/helium314/keyboard/latin/SystemBroadcastReceiver.java index 40bd89eaa..8a9904506 100644 --- a/app/src/main/java/helium314/keyboard/latin/SystemBroadcastReceiver.java +++ b/app/src/main/java/helium314/keyboard/latin/SystemBroadcastReceiver.java @@ -21,8 +21,8 @@ import android.view.inputmethod.InputMethodManager; import helium314.keyboard.keyboard.KeyboardLayoutSet; import helium314.keyboard.latin.settings.Settings; -import helium314.keyboard.latin.setup.SetupActivity; import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils; +import helium314.keyboard.settings.SettingsActivity; /** * This class detects the {@link Intent#ACTION_MY_PACKAGE_REPLACED} broadcast intent when this IME @@ -89,7 +89,7 @@ public final class SystemBroadcastReceiver extends BroadcastReceiver { return; // can't change visibility in Android 10 and above final SharedPreferences prefs = KtxKt.prefs(context); context.getPackageManager().setComponentEnabledSetting( - new ComponentName(context, SetupActivity.class), + new ComponentName(context, SettingsActivity.class), Settings.readShowSetupWizardIcon(prefs, context) ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED, diff --git a/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt b/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt index f645032f7..377d0c08d 100644 --- a/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/common/LocaleUtils.kt @@ -181,11 +181,6 @@ object LocaleUtils { } } - @JvmStatic - fun getLocaleDisplayNameInSystemLocale(locale: Locale, context: Context): String { - return getLocaleDisplayNameInLocale(locale, context.resources, context.resources.configuration.locale()) - } - fun Locale.localizedDisplayName(context: Context) = getLocaleDisplayNameInLocale(this, context.resources, context.resources.configuration.locale()) diff --git a/app/src/main/java/helium314/keyboard/latin/common/StringUtils.java b/app/src/main/java/helium314/keyboard/latin/common/StringUtils.java index e191c359f..1e12835d6 100644 --- a/app/src/main/java/helium314/keyboard/latin/common/StringUtils.java +++ b/app/src/main/java/helium314/keyboard/latin/common/StringUtils.java @@ -12,7 +12,6 @@ import androidx.annotation.Nullable; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.latin.utils.ScriptUtils; -import java.util.ArrayList; import java.util.Arrays; import java.util.Locale; @@ -22,9 +21,6 @@ public final class StringUtils { public static final int CAPITALIZE_FIRST = 1; // First only public static final int CAPITALIZE_ALL = 2; // All caps - @NonNull - private static final String EMPTY_STRING = ""; - private static final char CHAR_LINE_FEED = 0X000A; private static final char CHAR_VERTICAL_TAB = 0X000B; private static final char CHAR_FORM_FEED = 0X000C; @@ -50,61 +46,6 @@ public final class StringUtils { return (str == null || str.length() == 0); } - // Taken from android.text.TextUtils to cut the dependency to the Android framework. - - /** - * Returns a string containing the tokens joined by delimiters. - * - * @param delimiter the delimiter - * @param tokens an array objects to be joined. Strings will be formed from - * the objects by calling object.toString(). - */ - @NonNull - public static String join(@NonNull final CharSequence delimiter, - @NonNull final Iterable tokens) { - final StringBuilder sb = new StringBuilder(); - boolean firstTime = true; - for (final Object token : tokens) { - if (firstTime) { - firstTime = false; - } else { - sb.append(delimiter); - } - sb.append(token); - } - return sb.toString(); - } - - // Taken from android.text.TextUtils to cut the dependency to the Android framework. - - /** - * Returns true if a and b are equal, including if they are both null. - *

Note: In platform versions 1.1 and earlier, this method only worked well if - * both the arguments were instances of String.

- * - * @param a first CharSequence to check - * @param b second CharSequence to check - * @return true if a and b are equal - */ - public static boolean equals(@Nullable final CharSequence a, @Nullable final CharSequence b) { - if (a == b) { - return true; - } - final int length; - if (a != null && b != null && (length = a.length()) == b.length()) { - if (a instanceof String && b instanceof String) { - return a.equals(b); - } - for (int i = 0; i < length; i++) { - if (a.charAt(i) != b.charAt(i)) { - return false; - } - } - return true; - } - return false; - } - public static int codePointCount(@Nullable final CharSequence text) { if (isEmpty(text)) { return 0; @@ -123,33 +64,6 @@ public final class StringUtils { return new String(Character.toChars(codePoint)); } - /** - * Remove duplicates from an array of strings. - *

- * This method will always keep the first occurrence of all strings at their position - * in the array, removing the subsequent ones. - */ - public static void removeDupes(@NonNull final ArrayList suggestions) { - if (suggestions.size() < 2) { - return; - } - int i = 1; - // Don't cache suggestions.size(), since we may be removing items - while (i < suggestions.size()) { - final String cur = suggestions.get(i); - // Compare each suggestion with each previous suggestion - for (int j = 0; j < i; j++) { - final String previous = suggestions.get(j); - if (equals(cur, previous)) { - suggestions.remove(i); - i--; - break; - } - } - i++; - } - } - @NonNull public static String capitalizeFirstCodePoint(@NonNull final String s, @NonNull final Locale locale) { diff --git a/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsActivity.java b/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsActivity.java deleted file mode 100644 index 1d190e9a5..000000000 --- a/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsActivity.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.permissions; - - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; - -/** - * An activity to help request permissions. It's used when no other activity is available, e.g. in - * InputMethodService. This activity assumes that all permissions are not granted yet. - */ -public final class PermissionsActivity - extends Activity implements ActivityCompat.OnRequestPermissionsResultCallback { - - /** - * Key to retrieve requested permissions from the intent. - */ - public static final String EXTRA_PERMISSION_REQUESTED_PERMISSIONS = "requested_permissions"; - - /** - * Key to retrieve request code from the intent. - */ - public static final String EXTRA_PERMISSION_REQUEST_CODE = "request_code"; - - private static final int INVALID_REQUEST_CODE = -1; - - private int mPendingRequestCode = INVALID_REQUEST_CODE; - - /** - * Starts a PermissionsActivity and checks/requests supplied permissions. - */ - public static void run( - @NonNull Context context, int requestCode, @NonNull String... permissionStrings) { - Intent intent = new Intent(context.getApplicationContext(), PermissionsActivity.class); - intent.putExtra(EXTRA_PERMISSION_REQUESTED_PERMISSIONS, permissionStrings); - intent.putExtra(EXTRA_PERMISSION_REQUEST_CODE, requestCode); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - context.startActivity(intent); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mPendingRequestCode = (savedInstanceState != null) - ? savedInstanceState.getInt(EXTRA_PERMISSION_REQUEST_CODE, INVALID_REQUEST_CODE) - : INVALID_REQUEST_CODE; - } - - @Override - protected void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(EXTRA_PERMISSION_REQUEST_CODE, mPendingRequestCode); - } - - @Override - protected void onResume() { - super.onResume(); - // Only do request when there is no pending request to avoid duplicated requests. - if (mPendingRequestCode == INVALID_REQUEST_CODE) { - final Bundle extras = getIntent().getExtras(); - if (extras == null) return; - final String[] permissionsToRequest = extras.getStringArray(EXTRA_PERMISSION_REQUESTED_PERMISSIONS); - mPendingRequestCode = extras.getInt(EXTRA_PERMISSION_REQUEST_CODE); - // Assuming that all supplied permissions are not granted yet, so that we don't need to - // check them again. - PermissionsUtil.requestPermissions(this, mPendingRequestCode, permissionsToRequest); - } - } - - @Override - public void onRequestPermissionsResult( - int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - mPendingRequestCode = INVALID_REQUEST_CODE; - PermissionsManager.get(this).onRequestPermissionsResult( - requestCode, permissions, grantResults); - finish(); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsManager.java b/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsManager.java deleted file mode 100644 index 26caa601c..000000000 --- a/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsManager.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.permissions; - -import android.app.Activity; -import android.content.Context; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * Manager to perform permission related tasks. Always call on the UI thread. - */ -public class PermissionsManager { - - public interface PermissionsResultCallback { - void onRequestPermissionsResult(boolean allGranted); - } - - private int mRequestCodeId; - - private final Context mContext; - private final Map mRequestIdToCallback = new HashMap<>(); - - private static PermissionsManager sInstance; - - public PermissionsManager(Context context) { - mContext = context; - } - - @NonNull - public static synchronized PermissionsManager get(@NonNull Context context) { - if (sInstance == null) { - sInstance = new PermissionsManager(context); - } - return sInstance; - } - - private synchronized int getNextRequestId() { - return ++mRequestCodeId; - } - - - public synchronized void requestPermissions(@NonNull PermissionsResultCallback callback, - @Nullable Activity activity, - String... permissionsToRequest) { - List deniedPermissions = PermissionsUtil.getDeniedPermissions( - mContext, permissionsToRequest); - if (deniedPermissions.isEmpty()) { - return; - } - // otherwise request the permissions. - int requestId = getNextRequestId(); - String[] permissionsArray = deniedPermissions.toArray( - new String[deniedPermissions.size()]); - - mRequestIdToCallback.put(requestId, callback); - if (activity != null) { - PermissionsUtil.requestPermissions(activity, requestId, permissionsArray); - } else { - PermissionsActivity.run(mContext, requestId, permissionsArray); - } - } - - public synchronized void onRequestPermissionsResult( - int requestCode, String[] permissions, int[] grantResults) { - PermissionsResultCallback permissionsResultCallback = mRequestIdToCallback.get(requestCode); - mRequestIdToCallback.remove(requestCode); - - boolean allGranted = PermissionsUtil.allGranted(grantResults); - permissionsResultCallback.onRequestPermissionsResult(allGranted); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsUtil.java b/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsUtil.java index a4f2fd0a3..d1bb69ccc 100644 --- a/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsUtil.java +++ b/app/src/main/java/helium314/keyboard/latin/permissions/PermissionsUtil.java @@ -6,70 +6,22 @@ package helium314.keyboard.latin.permissions; -import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; -import java.util.ArrayList; -import java.util.List; - -import androidx.annotation.NonNull; -import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; /** * Utility class for permissions. */ public class PermissionsUtil { - - /** - * Returns the list of permissions not granted from the given list of permissions. - * @param context Context - * @param permissions list of permissions to check. - * @return the list of permissions that do not have permission to use. - */ - public static List getDeniedPermissions(Context context, - String... permissions) { - final List deniedPermissions = new ArrayList<>(); - for (String permission : permissions) { - if (ContextCompat.checkSelfPermission(context, permission) - != PackageManager.PERMISSION_GRANTED) { - deniedPermissions.add(permission); - } - } - return deniedPermissions; - } - - /** - * Uses the given activity and requests the user for permissions. - * @param activity activity to use. - * @param requestCode request code/id to use. - * @param permissions String array of permissions that needs to be requested. - */ - public static void requestPermissions(Activity activity, int requestCode, - String[] permissions) { - ActivityCompat.requestPermissions(activity, permissions, requestCode); - } - - /** - * Checks if all the permissions are granted. - */ - public static boolean allGranted(@NonNull int[] grantResults) { - for (int result : grantResults) { - if (result != PackageManager.PERMISSION_GRANTED) { - return false; - } - } - return true; - } - /** * Queries if al the permissions are granted for the given permission strings. */ public static boolean checkAllPermissionsGranted(Context context, String... permissions) { if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) { - // For all pre-M devices, we should have all the premissions granted on install. + // For all pre-M devices, we should have all the permissions granted on install. return true; } diff --git a/app/src/main/java/helium314/keyboard/latin/settings/AboutFragment.kt b/app/src/main/java/helium314/keyboard/latin/settings/AboutFragment.kt deleted file mode 100644 index 51f9ca982..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/AboutFragment.kt +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ -package helium314.keyboard.latin.settings - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import android.text.method.LinkMovementMethod -import android.view.View -import android.widget.TextView -import android.widget.Toast -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.preference.Preference -import helium314.keyboard.latin.BuildConfig -import helium314.keyboard.latin.R -import helium314.keyboard.latin.utils.ExecutorUtils -import helium314.keyboard.latin.utils.Log -import helium314.keyboard.latin.utils.SpannableStringUtils - -/** - * "About" sub screen. - */ -class AboutFragment : SubScreenFragment() { - override fun onCreate(icicle: Bundle?) { - super.onCreate(icicle) - addPreferencesFromResource(R.xml.prefs_screen_about) - - setupHiddenFeatures() - setupVersionPref() - findPreference("log_reader")?.setOnPreferenceClickListener { - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .putExtra(Intent.EXTRA_TITLE, - requireContext().getString(R.string.english_ime_name) - .replace(" ", "_") + "_log_${System.currentTimeMillis()}.txt" - ) - .setType("text/plain") - logFilePicker.launch(intent) - true - } - } - - private val logFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = result.data?.data ?: return@registerForActivityResult - ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { - activity?.contentResolver?.openOutputStream(uri)?.use { os -> - os.bufferedWriter().use { it.write(Log.getLog().joinToString("\n")) } - } - } - } - - private fun setupHiddenFeatures() { - findPreference("hidden_features")?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - val link = ("" - + getString(R.string.hidden_features_text) + "") - val message = requireContext().getString(R.string.hidden_features_message, link) - val dialogMessage = SpannableStringUtils.fromHtml(message) - val builder = AlertDialog.Builder(requireContext()) - .setIcon(R.drawable.ic_settings_about_hidden_features) - .setTitle(R.string.hidden_features_title) - .setMessage(dialogMessage) - .setPositiveButton(R.string.dialog_close, null) - .create() - builder.show() - (builder.findViewById(android.R.id.message) as TextView).movementMethod = LinkMovementMethod.getInstance() - true - } - } - - private fun setupVersionPref() { - val versionPreference = findPreference("version") ?: return - versionPreference.summary = BuildConfig.VERSION_NAME - if (BuildConfig.DEBUG) return - var count = 0 - versionPreference.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - if (sharedPreferences.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, false)) - return@OnPreferenceClickListener true - count++ - if (count < 5) return@OnPreferenceClickListener true - sharedPreferences.edit().putBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, true).apply() - Toast.makeText(requireContext(), R.string.prefs_debug_settings_enabled, Toast.LENGTH_LONG).show() - true - } - } -} \ No newline at end of file diff --git a/app/src/main/java/helium314/keyboard/latin/settings/AdvancedSettingsFragment.kt b/app/src/main/java/helium314/keyboard/latin/settings/AdvancedSettingsFragment.kt deleted file mode 100644 index e5ac61c95..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/AdvancedSettingsFragment.kt +++ /dev/null @@ -1,642 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ -package helium314.keyboard.latin.settings - -import android.annotation.SuppressLint -import android.app.Activity -import android.content.Intent -import android.content.SharedPreferences -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.widget.EditText -import android.widget.LinearLayout -import android.widget.TextView -import helium314.keyboard.latin.utils.Log -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.core.content.edit -import androidx.core.widget.doAfterTextChanged -import androidx.preference.Preference -import androidx.preference.PreferenceManager -import kotlinx.serialization.json.Json -import helium314.keyboard.dictionarypack.DictionaryPackConstants -import helium314.keyboard.keyboard.KeyboardActionListener -import helium314.keyboard.latin.utils.ChecksumCalculator -import helium314.keyboard.keyboard.KeyboardLayoutSet -import helium314.keyboard.keyboard.KeyboardSwitcher -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_NUMBER -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_NUMPAD -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_NUMPAD_LANDSCAPE -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_PHONE -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_PHONE_SYMBOLS -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_SYMBOLS -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_SYMBOLS_ARABIC -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_SYMBOLS_SHIFTED -import helium314.keyboard.latin.AudioAndHapticFeedbackManager -import helium314.keyboard.latin.BuildConfig -import helium314.keyboard.latin.R -import helium314.keyboard.latin.SystemBroadcastReceiver -import helium314.keyboard.latin.checkVersionUpgrade -import helium314.keyboard.latin.common.FileUtils -import helium314.keyboard.latin.common.LocaleUtils.constructLocale -import helium314.keyboard.latin.common.splitOnWhitespace -import helium314.keyboard.latin.settings.SeekBarDialogPreference.ValueProxy -import helium314.keyboard.latin.utils.DeviceProtectedUtils -import helium314.keyboard.latin.utils.DictionaryInfoUtils.USER_DICTIONARY_SUFFIX -import helium314.keyboard.latin.utils.ExecutorUtils -import helium314.keyboard.latin.utils.JniUtils -import helium314.keyboard.latin.utils.ResourceUtils -import helium314.keyboard.latin.utils.SubtypeSettings -import helium314.keyboard.latin.utils.SubtypeUtilsAdditional -import helium314.keyboard.latin.utils.infoDialog -import java.io.File -import java.io.FileInputStream -import java.io.FileOutputStream -import java.io.IOException -import java.io.OutputStream -import java.text.SimpleDateFormat -import java.util.Calendar -import java.util.Locale -import java.util.concurrent.CountDownLatch -import java.util.zip.ZipEntry -import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream - -@Suppress("KotlinConstantConditions") // build type might be a constant, but depends on... build type! -class AdvancedSettingsFragment : SubScreenFragment() { - private val libfile by lazy { File(requireContext().filesDir.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME) } - private val backupFilePatterns by lazy { listOf( - "blacklists/.*\\.txt".toRegex(), -// "layouts/$CUSTOM_LAYOUT_PREFIX+\\..{0,4}".toRegex(), // can't expect a period at the end, as this would break restoring older backups - "dicts/.*/.*user\\.dict".toRegex(), - "UserHistoryDictionary.*/UserHistoryDictionary.*\\.(body|header)".toRegex(), - "custom_background_image.*".toRegex(), - "custom_font".toRegex(), - ) } - - // is there any way to get additional information into the ActivityResult? would remove the need for 5 times the (almost) same code - private val libraryFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - copyLibrary(uri) - } - - private val backupFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - backup(uri) - } - - private val restoreFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - restore(uri) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setupPreferences() - } - - private fun setupPreferences() { - addPreferencesFromResource(R.xml.prefs_screen_advanced) - setDebugPrefVisibility() - val context = requireContext() - - // When we are called from the Settings application but we are not already running, some - // singleton and utility classes may not have been initialized. We have to call - // initialization method of these classes here. See {@link LatinIME#onCreate()}. - AudioAndHapticFeedbackManager.init(context) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { - removePreference(Settings.PREF_SHOW_SETUP_WIZARD_ICON) - } - if (BuildConfig.BUILD_TYPE == "nouserlib") { - removePreference("load_gesture_library") - } - setupKeyLongpressTimeoutSettings() - setupEmojiSdkSetting() - setupLanguageSwipeDistanceSettings() - updateLangSwipeDistanceVisibility(sharedPreferences) - findPreference("load_gesture_library")?.setOnPreferenceClickListener { onClickLoadLibrary() } - findPreference("backup_restore")?.setOnPreferenceClickListener { showBackupRestoreDialog() } - - findPreference("custom_symbols_number_layouts")?.setOnPreferenceClickListener { - showCustomizeSymbolNumberLayoutsDialog() - true - } - findPreference("custom_functional_key_layouts")?.setOnPreferenceClickListener { -// showCustomizeFunctionalKeyLayoutsDialog() - true - } - - findPreference(Settings.PREF_CUSTOM_CURRENCY_KEY)?.setOnPreferenceClickListener { - customCurrencyDialog() - true - } - - findPreference("switch_after")?.setOnPreferenceClickListener { - switchToMainDialog() - true - } - } - - override fun onStart() { - super.onStart() - // Remove debug preference. This is already done in onCreate, but if we come back from - // debug prefs and have just disabled debug settings, they should disappear. - setDebugPrefVisibility() - } - - private fun setDebugPrefVisibility() { - if (!BuildConfig.DEBUG && !sharedPreferences.getBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, false)) { - removePreference(Settings.SCREEN_DEBUG) - } - } - - private fun showCustomizeSymbolNumberLayoutsDialog() { -/* val layoutNames = RawKeyboardParser.symbolAndNumberLayouts.map { it.getStringResourceOrName("layout_", requireContext()) }.toTypedArray() - AlertDialog.Builder(requireContext()) - .setTitle(R.string.customize_symbols_number_layouts) - .setItems(layoutNames) { di, i -> - di.dismiss() - customizeSymbolNumberLayout(RawKeyboardParser.symbolAndNumberLayouts[i]) - } - .setNegativeButton(android.R.string.cancel, null) - .show() -*/ } -/* - private fun customizeSymbolNumberLayout(layoutName: String) { - val customLayoutName = getCustomLayoutFiles(requireContext()).map { it.name } - .firstOrNull { it.startsWith("$CUSTOM_LAYOUT_PREFIX$layoutName.") } - val originalLayout = if (customLayoutName != null) null - else { - requireContext().assets.list("layouts")?.firstOrNull { it.startsWith("$layoutName.") } - ?.let { requireContext().assets.open("layouts" + File.separator + it).reader().readText() } - } - val displayName = layoutName.getStringResourceOrName("layout_", requireContext()) - editCustomLayout(customLayoutName ?: "$CUSTOM_LAYOUT_PREFIX$layoutName.", requireContext(), originalLayout, displayName) - } - - private fun showCustomizeFunctionalKeyLayoutsDialog() { - val list = listOf(CUSTOM_FUNCTIONAL_LAYOUT_NORMAL, CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS, CUSTOM_FUNCTIONAL_LAYOUT_SYMBOLS_SHIFTED) - .map { it.substringBeforeLast(".") } - val layoutNames = list.map { it.substringAfter(CUSTOM_LAYOUT_PREFIX).getStringResourceOrName("layout_", requireContext()) }.toTypedArray() - AlertDialog.Builder(requireContext()) - .setTitle(R.string.customize_functional_key_layouts) - .setItems(layoutNames) { di, i -> - di.dismiss() - customizeFunctionalKeysLayout(list[i]) - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - - private fun customizeFunctionalKeysLayout(layoutName: String) { - val customLayoutName = getCustomLayoutFiles(requireContext()).map { it.name } - .firstOrNull { it.startsWith("$layoutName.") } - val originalLayout = if (customLayoutName != null) null - else { - val defaultLayoutName = if (Settings.getInstance().isTablet) "functional_keys_tablet.json" else "functional_keys.json" - requireContext().assets.open("layouts" + File.separator + defaultLayoutName).reader().readText() - } - val displayName = layoutName.substringAfter(CUSTOM_LAYOUT_PREFIX).getStringResourceOrName("layout_", requireContext()) - editCustomLayout(customLayoutName ?: "$layoutName.", requireContext(), originalLayout, displayName) - } -*/ - @SuppressLint("ApplySharedPref") - private fun onClickLoadLibrary(): Boolean { - // get architecture for telling user which file to use - val abi = Build.SUPPORTED_ABIS[0] - // show delete / add dialog - val builder = AlertDialog.Builder(requireContext()) - .setTitle(R.string.load_gesture_library) - .setMessage(requireContext().getString(R.string.load_gesture_library_message, abi)) - .setPositiveButton(R.string.load_gesture_library_button_load) { _, _ -> - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("application/octet-stream") - libraryFilePicker.launch(intent) - } - .setNegativeButton(android.R.string.cancel, null) - if (libfile.exists()) { - builder.setNeutralButton(R.string.load_gesture_library_button_delete) { _, _ -> - libfile.delete() - PreferenceManager.getDefaultSharedPreferences(requireContext()).edit().remove(Settings.PREF_LIBRARY_CHECKSUM).commit() - Runtime.getRuntime().exit(0) - } - } - builder.show() - return true - } - - private fun copyLibrary(uri: Uri) { - val tmpfile = File(requireContext().filesDir.absolutePath + File.separator + "tmplib") - try { - val otherTemporaryFile = File(requireContext().filesDir.absolutePath + File.separator + "tmpfile") - FileUtils.copyContentUriToNewFile(uri, requireContext(), otherTemporaryFile) - val inputStream = FileInputStream(otherTemporaryFile) - val outputStream = FileOutputStream(tmpfile) - outputStream.use { - tmpfile.setReadOnly() // as per recommendations in https://developer.android.com/about/versions/14/behavior-changes-14#safer-dynamic-code-loading - FileUtils.copyStreamToOtherStream(inputStream, it) - } - otherTemporaryFile.delete() - - val checksum = ChecksumCalculator.checksum(tmpfile.inputStream()) ?: "" - if (checksum == JniUtils.expectedDefaultChecksum()) { - renameToLibfileAndRestart(tmpfile, checksum) - } else { - val abi = Build.SUPPORTED_ABIS[0] - AlertDialog.Builder(requireContext()) - .setMessage(getString(R.string.checksum_mismatch_message, abi)) - .setPositiveButton(android.R.string.ok) { _, _ -> renameToLibfileAndRestart(tmpfile, checksum) } - .setNegativeButton(android.R.string.cancel) { _, _ -> tmpfile.delete() } - .show() - } - } catch (e: IOException) { - tmpfile.delete() - // should inform user, but probably the issues will only come when reading the library - } - } - - @SuppressLint("ApplySharedPref") - private fun renameToLibfileAndRestart(file: File, checksum: String) { - libfile.delete() - // store checksum in default preferences (soo JniUtils) - PreferenceManager.getDefaultSharedPreferences(requireContext()).edit().putString(Settings.PREF_LIBRARY_CHECKSUM, checksum).commit() - file.renameTo(libfile) - Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded - } - - private fun showBackupRestoreDialog(): Boolean { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.backup_restore_title) - .setMessage(R.string.backup_restore_message) - .setNegativeButton(R.string.button_backup) { _, _ -> - val currentDate = SimpleDateFormat("yyyyMMdd", Locale.getDefault()).format(Calendar.getInstance().time) - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .putExtra( - Intent.EXTRA_TITLE, - requireContext().getString(R.string.english_ime_name) - .replace(" ", "_") + "_backup_$currentDate.zip" - ) - .setType("application/zip") - backupFilePicker.launch(intent) - } - .setPositiveButton(android.R.string.cancel, null) - .setNeutralButton(R.string.button_restore) { _, _ -> - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("application/zip") - restoreFilePicker.launch(intent) - } - .show() - return true - } - - private fun backup(uri: Uri) { - // zip all files matching the backup patterns - // essentially this is the typed words information, and user-added dictionaries - val filesDir = requireContext().filesDir ?: return - val filesPath = filesDir.path + File.separator - val files = mutableListOf() - filesDir.walk().forEach { file -> - val path = file.path.replace(filesPath, "") - if (backupFilePatterns.any { path.matches(it) }) - files.add(file) - } - val protectedFilesDir = DeviceProtectedUtils.getFilesDir(requireContext()) - val protectedFilesPath = protectedFilesDir.path + File.separator - val protectedFiles = mutableListOf() - protectedFilesDir.walk().forEach { file -> - val path = file.path.replace(protectedFilesPath, "") - if (backupFilePatterns.any { path.matches(it) }) - protectedFiles.add(file) - } - var error: String? = "" - val wait = CountDownLatch(1) - ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { - try { - activity?.contentResolver?.openOutputStream(uri)?.use { os -> - // write files to zip - val zipStream = ZipOutputStream(os) - files.forEach { - val fileStream = FileInputStream(it).buffered() - zipStream.putNextEntry(ZipEntry(it.path.replace(filesPath, ""))) - fileStream.copyTo(zipStream, 1024) - fileStream.close() - zipStream.closeEntry() - } - protectedFiles.forEach { - val fileStream = FileInputStream(it).buffered() - zipStream.putNextEntry(ZipEntry(it.path.replace(protectedFilesDir.path, "unprotected"))) - fileStream.copyTo(zipStream, 1024) - fileStream.close() - zipStream.closeEntry() - } - zipStream.putNextEntry(ZipEntry(PREFS_FILE_NAME)) - settingsToJsonStream(sharedPreferences.all, zipStream) - zipStream.closeEntry() - zipStream.putNextEntry(ZipEntry(PROTECTED_PREFS_FILE_NAME)) - settingsToJsonStream(PreferenceManager.getDefaultSharedPreferences(requireContext()).all, zipStream) - zipStream.closeEntry() - zipStream.close() - } - } catch (t: Throwable) { - error = t.message - Log.w(TAG, "error during backup", t) - } finally { - wait.countDown() - } - } - wait.await() - if (!error.isNullOrBlank()) { - // inform about every error - infoDialog(requireContext(), requireContext().getString(R.string.backup_error, error)) - } - } - - private fun restore(uri: Uri) { - var error: String? = "" - val wait = CountDownLatch(1) - ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { - try { - activity?.contentResolver?.openInputStream(uri)?.use { inputStream -> - ZipInputStream(inputStream).use { zip -> - var entry: ZipEntry? = zip.nextEntry - val filesDir = requireContext().filesDir?.path ?: return@execute - val deviceProtectedFilesDir = DeviceProtectedUtils.getFilesDir(requireContext()).path - Settings.getInstance().stopListener() - while (entry != null) { - if (entry.name.startsWith("unprotected${File.separator}")) { - val adjustedName = entry.name.substringAfter("unprotected${File.separator}") - if (backupFilePatterns.any { adjustedName.matches(it) }) { - val targetFileName = upgradeFileNames(adjustedName) - val file = File(deviceProtectedFilesDir, targetFileName) - FileUtils.copyStreamToNewFile(zip, file) - } - } else if (backupFilePatterns.any { entry!!.name.matches(it) }) { - val targetFileName = upgradeFileNames(entry.name) - val file = File(filesDir, targetFileName) - FileUtils.copyStreamToNewFile(zip, file) - } else if (entry.name == PREFS_FILE_NAME) { - val prefLines = String(zip.readBytes()).split("\n") - sharedPreferences.edit().clear().apply() - readJsonLinesToSettings(prefLines, sharedPreferences) - } else if (entry.name == PROTECTED_PREFS_FILE_NAME) { - val prefLines = String(zip.readBytes()).split("\n") - val protectedPrefs = PreferenceManager.getDefaultSharedPreferences(requireContext()) - protectedPrefs.edit().clear().apply() - readJsonLinesToSettings(prefLines, protectedPrefs) - } - zip.closeEntry() - entry = zip.nextEntry - } - } - } - } catch (t: Throwable) { - error = t.message - Log.w(TAG, "error during restore", t) - } finally { - wait.countDown() - } - } - wait.await() - if (!error.isNullOrBlank()) { - // inform about every error - infoDialog(requireContext(), requireContext().getString(R.string.restore_error, error)) - } - checkVersionUpgrade(requireContext()) - Settings.getInstance().startListener() - SubtypeSettings.reloadEnabledSubtypes(requireContext()) - val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION) - activity?.sendBroadcast(newDictBroadcast) - // reload current prefs screen - preferenceScreen.removeAll() - setupPreferences() -// onCustomLayoutFileListChanged() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } - - // todo (later): remove this when new package name has been in use for long enough, this is only for migrating from old openboard name - private fun upgradeFileNames(originalName: String): String { - return when { - originalName.endsWith(USER_DICTIONARY_SUFFIX) -> { - // replace directory after switch to language tag - val dirName = originalName.substringAfter(File.separator).substringBefore(File.separator) - originalName.replace(dirName, dirName.constructLocale().toLanguageTag()) - } - originalName.startsWith("blacklists") -> { - // replace file name after switch to language tag - val fileName = originalName.substringAfter("blacklists${File.separator}").substringBefore(".txt") - originalName.replace(fileName, fileName.constructLocale().toLanguageTag()) - } - originalName.startsWith("layouts") -> { - // replace file name after switch to language tag, but only if it's not a layout - val localeString = originalName.substringAfter(".").substringBefore(".") - if (localeString in listOf(LAYOUT_SYMBOLS, LAYOUT_SYMBOLS_SHIFTED, LAYOUT_SYMBOLS_ARABIC, LAYOUT_NUMBER, LAYOUT_NUMPAD, LAYOUT_NUMPAD_LANDSCAPE, LAYOUT_PHONE, LAYOUT_PHONE_SYMBOLS)) - return originalName // it's a layout! - val locale = localeString.constructLocale() - if (locale.toLanguageTag() != "und") - originalName.replace(localeString, locale.toLanguageTag()) - else - originalName // no valid locale -> must be symbols layout, don't change - } - originalName.startsWith("UserHistoryDictionary") -> { - val localeString = originalName.substringAfter(".").substringBefore(".") - val locale = localeString.constructLocale() - originalName.replace(localeString, locale.toLanguageTag()) - } - else -> originalName - } - } - - private fun customCurrencyDialog() { - val layout = LinearLayout(requireContext()) - layout.orientation = LinearLayout.VERTICAL - layout.addView(TextView(requireContext()).apply { setText(R.string.customize_currencies_detail) }) - val et = EditText(requireContext()).apply { setText(sharedPreferences.getString(Settings.PREF_CUSTOM_CURRENCY_KEY, "")) } - layout.addView(et) - val padding = ResourceUtils.toPx(8, resources) - layout.setPadding(3 * padding, padding, padding, padding) - val d = AlertDialog.Builder(requireContext()) - .setTitle(R.string.customize_currencies) - .setView(layout) - .setPositiveButton(android.R.string.ok) { _, _ -> - sharedPreferences.edit { putString(Settings.PREF_CUSTOM_CURRENCY_KEY, et.text.toString()) } - KeyboardLayoutSet.onSystemLocaleChanged() - } - .setNegativeButton(android.R.string.cancel, null) - .setNeutralButton(R.string.button_default) { _, _ -> sharedPreferences.edit { putString(Settings.PREF_CUSTOM_CURRENCY_KEY, "") } } - .create() - et.doAfterTextChanged { d.getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled = et.text.toString().splitOnWhitespace().none { it.length > 8 } } - d.show() - } - - private fun switchToMainDialog() { - val checked = booleanArrayOf( - sharedPreferences.getBoolean(Settings.PREF_ABC_AFTER_SYMBOL_SPACE, true), - sharedPreferences.getBoolean(Settings.PREF_ABC_AFTER_EMOJI, false), - sharedPreferences.getBoolean(Settings.PREF_ABC_AFTER_CLIP, false), - ) - val titles = arrayOf( - requireContext().getString(R.string.after_symbol_and_space), - requireContext().getString(R.string.after_emoji), - requireContext().getString(R.string.after_clip), - ) - AlertDialog.Builder(requireContext()) - .setTitle(R.string.switch_keyboard_after) - .setMultiChoiceItems(titles, checked) { _, i, b -> checked[i] = b } - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok) { _, _ -> - sharedPreferences.edit { - putBoolean(Settings.PREF_ABC_AFTER_SYMBOL_SPACE, checked[0]) - putBoolean(Settings.PREF_ABC_AFTER_EMOJI, checked[1]) - putBoolean(Settings.PREF_ABC_AFTER_CLIP, checked[2]) - } - } - .show() - } - - private fun setupKeyLongpressTimeoutSettings() { - val prefs = sharedPreferences - findPreference(Settings.PREF_KEY_LONGPRESS_TIMEOUT)?.setInterface(object : ValueProxy { - override fun writeValue(value: Int, key: String) = prefs.edit().putInt(key, value).apply() - - override fun writeDefaultValue(key: String) = prefs.edit().remove(key).apply() - - override fun readValue(key: String) = prefs.getInt(Settings.PREF_KEY_LONGPRESS_TIMEOUT, Defaults.PREF_KEY_LONGPRESS_TIMEOUT) - - override fun readDefaultValue(key: String) = 300 - - override fun getValueText(value: Int) = - resources.getString(R.string.abbreviation_unit_milliseconds, value.toString()) - - override fun feedbackValue(value: Int) {} - }) - } - - private fun setupEmojiSdkSetting() { - val prefs = sharedPreferences - findPreference(Settings.PREF_EMOJI_MAX_SDK)?.setInterface(object : ValueProxy { - override fun writeValue(value: Int, key: String) = prefs.edit().putInt(key, value).apply() - - override fun writeDefaultValue(key: String) = prefs.edit().remove(key).apply() - - override fun readValue(key: String) = prefs.getInt(Settings.PREF_EMOJI_MAX_SDK, Build.VERSION.SDK_INT) - - override fun readDefaultValue(key: String) = Build.VERSION.SDK_INT - - override fun getValueText(value: Int) = "Android " + when(value) { - 21 -> "5.0" - 22 -> "5.1" - 23 -> "6" - 24 -> "7.0" - 25 -> "7.1" - 26 -> "8.0" - 27 -> "8.1" - 28 -> "9" - 29 -> "10" - 30 -> "11" - 31 -> "12" - 32 -> "12L" - 33 -> "13" - 34 -> "14" - 35 -> "15" - else -> "version unknown" - } - - override fun feedbackValue(value: Int) {} - }) - } - - private fun setupLanguageSwipeDistanceSettings() { - val prefs = sharedPreferences - findPreference(Settings.PREF_LANGUAGE_SWIPE_DISTANCE)?.setInterface(object : ValueProxy { - override fun writeValue(value: Int, key: String) = prefs.edit().putInt(key, value).apply() - - override fun writeDefaultValue(key: String) = prefs.edit().remove(key).apply() - - override fun readValue(key: String) = prefs.getInt(Settings.PREF_LANGUAGE_SWIPE_DISTANCE, 5) - - override fun readDefaultValue(key: String) = 5 - - override fun getValueText(value: Int) = value.toString() - - override fun feedbackValue(value: Int) {} - }) - } - - private fun updateLangSwipeDistanceVisibility(prefs: SharedPreferences) { - val horizontalSpaceSwipe = Settings.readHorizontalSpaceSwipe(prefs) - val verticalSpaceSwipe = Settings.readVerticalSpaceSwipe(prefs) - val visibility = horizontalSpaceSwipe == KeyboardActionListener.SWIPE_SWITCH_LANGUAGE - || verticalSpaceSwipe == KeyboardActionListener.SWIPE_SWITCH_LANGUAGE - setPreferenceVisible(Settings.PREF_LANGUAGE_SWIPE_DISTANCE, visibility) - } - - override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String?) { - when (key) { - Settings.PREF_SHOW_SETUP_WIZARD_ICON -> SystemBroadcastReceiver.toggleAppIcon(requireContext()) - "more_popup_keys" -> KeyboardLayoutSet.onSystemLocaleChanged() - Settings.PREF_SPACE_HORIZONTAL_SWIPE -> updateLangSwipeDistanceVisibility(prefs) - Settings.PREF_SPACE_VERTICAL_SWIPE -> updateLangSwipeDistanceVisibility(prefs) - Settings.PREF_EMOJI_MAX_SDK -> KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } - } - - companion object { - @Suppress("UNCHECKED_CAST") // it is checked... but whatever (except string set, because can't check for that)) - private fun settingsToJsonStream(settings: Map, out: OutputStream) { - val booleans = settings.filter { it.key is String && it.value is Boolean } as Map - val ints = settings.filter { it.key is String && it.value is Int } as Map - val longs = settings.filter { it.key is String && it.value is Long } as Map - val floats = settings.filter { it.key is String && it.value is Float } as Map - val strings = settings.filter { it.key is String && it.value is String } as Map - val stringSets = settings.filter { it.key is String && it.value is Set<*> } as Map> - // now write - out.write("boolean settings\n".toByteArray()) - out.write(Json.encodeToString(booleans).toByteArray()) - out.write("\nint settings\n".toByteArray()) - out.write(Json.encodeToString(ints).toByteArray()) - out.write("\nlong settings\n".toByteArray()) - out.write(Json.encodeToString(longs).toByteArray()) - out.write("\nfloat settings\n".toByteArray()) - out.write(Json.encodeToString(floats).toByteArray()) - out.write("\nstring settings\n".toByteArray()) - out.write(Json.encodeToString(strings).toByteArray()) - out.write("\nstring set settings\n".toByteArray()) - out.write(Json.encodeToString(stringSets).toByteArray()) - } - - private fun readJsonLinesToSettings(list: List, prefs: SharedPreferences): Boolean { - val i = list.iterator() - val e = prefs.edit() - try { - while (i.hasNext()) { - when (i.next()) { - "boolean settings" -> Json.decodeFromString>(i.next()).forEach { e.putBoolean(it.key, it.value) } - "int settings" -> Json.decodeFromString>(i.next()).forEach { e.putInt(it.key, it.value) } - "long settings" -> Json.decodeFromString>(i.next()).forEach { e.putLong(it.key, it.value) } - "float settings" -> Json.decodeFromString>(i.next()).forEach { e.putFloat(it.key, it.value) } - "string settings" -> Json.decodeFromString>(i.next()).forEach { e.putString(it.key, it.value) } - "string set settings" -> Json.decodeFromString>>(i.next()).forEach { e.putStringSet(it.key, it.value) } - } - } - e.apply() - return true - } catch (e: Exception) { - return false - } - } - } -} - -private const val PREFS_FILE_NAME = "preferences.json" -private const val PROTECTED_PREFS_FILE_NAME = "protected_preferences.json" -private const val TAG = "AdvancedSettingsFragment" diff --git a/app/src/main/java/helium314/keyboard/latin/settings/AppearanceSettingsFragment.kt b/app/src/main/java/helium314/keyboard/latin/settings/AppearanceSettingsFragment.kt deleted file mode 100644 index 8c9bc8a69..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/AppearanceSettingsFragment.kt +++ /dev/null @@ -1,476 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -package helium314.keyboard.latin.settings - -import android.app.Activity -import android.content.Intent -import android.content.SharedPreferences -import android.content.res.Configuration -import android.graphics.BitmapFactory -import android.graphics.Typeface -import android.net.Uri -import android.os.Build -import android.os.Bundle -import android.view.LayoutInflater -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.ScrollView -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.core.content.ContextCompat -import androidx.core.graphics.BlendModeColorFilterCompat -import androidx.core.graphics.BlendModeCompat -import androidx.core.util.TypedValueCompat -import androidx.core.view.forEach -import androidx.core.view.isGone -import androidx.core.view.isVisible -import androidx.preference.ListPreference -import androidx.preference.Preference -import androidx.preference.TwoStatePreference -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import helium314.keyboard.keyboard.KeyboardSwitcher -import helium314.keyboard.keyboard.KeyboardTheme -import helium314.keyboard.keyboard.internal.KeyboardIconsSet -import helium314.keyboard.latin.R -import helium314.keyboard.latin.common.FileUtils -import helium314.keyboard.latin.databinding.ReorderDialogItemBinding -import helium314.keyboard.latin.utils.DeviceProtectedUtils -import helium314.keyboard.latin.utils.ResourceUtils -import helium314.keyboard.latin.utils.confirmDialog -import helium314.keyboard.latin.utils.getStringResourceOrName -import helium314.keyboard.latin.utils.infoDialog -import kotlinx.serialization.encodeToString -import kotlinx.serialization.json.Json -import java.io.File -import java.lang.Float.max -import java.lang.Float.min -import java.util.* - -/** - * "Appearance" settings sub screen. - */ -class AppearanceSettingsFragment : SubScreenFragment() { - private var needsReload = false - - private val stylePref: ListPreference by lazy { preferenceScreen.findPreference(Settings.PREF_THEME_STYLE)!! } - private val iconStylePref: ListPreference by lazy { preferenceScreen.findPreference(Settings.PREF_ICON_STYLE)!! } - private val colorsPref: ListPreference by lazy { preferenceScreen.findPreference(Settings.PREF_THEME_COLORS)!! } - private val colorsNightPref: ListPreference? by lazy { preferenceScreen.findPreference(Settings.PREF_THEME_COLORS_NIGHT) } - private val dayNightPref: TwoStatePreference? by lazy { preferenceScreen.findPreference(Settings.PREF_THEME_DAY_NIGHT) } - private val userColorsPref: Preference by lazy { preferenceScreen.findPreference("theme_select_colors")!! } - private val userColorsPrefNight: Preference? by lazy { preferenceScreen.findPreference("theme_select_colors_night") } - private val splitLandscapePref: TwoStatePreference? by lazy { preferenceScreen.findPreference(Settings.PREF_ENABLE_SPLIT_KEYBOARD_LANDSCAPE) } - private val splitPortraitPref: TwoStatePreference? by lazy { preferenceScreen.findPreference(Settings.PREF_ENABLE_SPLIT_KEYBOARD) } - private val splitScalePref: Preference? by lazy { preferenceScreen.findPreference(Settings.PREF_SPLIT_SPACER_SCALE) } - private val splitScaleLandscapePref: Preference? by lazy { preferenceScreen.findPreference(Settings.PREF_SPLIT_SPACER_SCALE_LANDSCAPE) } - - private val dayImageFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - loadImage(uri, false, false) - } - - private val nightImageFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - loadImage(uri, true, false) - } - - private val dayImageFilePickerLandscape = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - loadImage(uri, false, true) - } - - private val nightImageFilePickerLandscape = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - loadImage(uri, true, true) - } - - private val fontFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - saveCustomTypeface(uri) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - addPreferencesFromResource(R.xml.prefs_screen_appearance) - - removeUnsuitablePreferences() - setupTheme() - setColorPrefs(sharedPreferences.getString(Settings.PREF_THEME_STYLE, KeyboardTheme.STYLE_MATERIAL)!!) - - setupScalePrefs(Settings.PREF_KEYBOARD_HEIGHT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE) - setupScalePrefs(Settings.PREF_BOTTOM_PADDING_SCALE, SettingsValues.DEFAULT_SIZE_SCALE) - setupScalePrefs(Settings.PREF_BOTTOM_PADDING_SCALE_LANDSCAPE, 0f) - setupScalePrefs(Settings.PREF_FONT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE) - setupScalePrefs(Settings.PREF_EMOJI_FONT_SCALE, SettingsValues.DEFAULT_SIZE_SCALE) - setupScalePrefs(Settings.PREF_SIDE_PADDING_SCALE, 0f) - setupScalePrefs(Settings.PREF_SIDE_PADDING_SCALE_LANDSCAPE, 0f) - if (splitScalePref != null) { - setupScalePrefs(Settings.PREF_SPLIT_SPACER_SCALE, SettingsValues.DEFAULT_SIZE_SCALE) - splitScalePref?.isVisible = splitPortraitPref?.isChecked == true - splitPortraitPref?.setOnPreferenceChangeListener { _, value -> - splitScalePref?.isVisible = value as Boolean - true - } - } - if (splitScaleLandscapePref != null) { - setupScalePrefs(Settings.PREF_SPLIT_SPACER_SCALE_LANDSCAPE, SettingsValues.DEFAULT_SIZE_SCALE) - splitScaleLandscapePref?.isVisible = splitLandscapePref?.isChecked == true - splitLandscapePref?.setOnPreferenceChangeListener { _, value -> - splitScaleLandscapePref?.isVisible = value as Boolean - true - } - } - findPreference("custom_background_image")?.setOnPreferenceClickListener { onClickLoadImage(false) } - findPreference("custom_background_image_landscape")?.setOnPreferenceClickListener { onClickLoadImage(true) } - findPreference("custom_font")?.setOnPreferenceClickListener { onClickCustomFont() } - findPreference(Settings.PREF_CUSTOM_ICON_NAMES)?.setOnPreferenceClickListener { - if (needsReload) - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - onClickCustomizeIcons() - } - } - - override fun onPause() { - super.onPause() - if (needsReload) - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - needsReload = false - } - - override fun onSharedPreferenceChanged(prefs: SharedPreferences?, key: String?) { - super.onSharedPreferenceChanged(prefs, key) - needsReload = true // may not always necessary, but that's ok - } - - private fun removeUnsuitablePreferences() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { - removePreference(Settings.PREF_THEME_DAY_NIGHT) - removePreference(Settings.PREF_THEME_COLORS_NIGHT) - } else { - // on P there is experimental support for night mode, exposed by some roms like LineageOS - // try to detect this using UI_MODE_NIGHT_UNDEFINED, but actually the system could always report day too? - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q - && (resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_UNDEFINED - ) { - removePreference(Settings.PREF_THEME_DAY_NIGHT) - removePreference(Settings.PREF_THEME_COLORS_NIGHT) - removePreference("theme_select_colors_night") - } - } - } - - private fun setColorPrefs(style: String) { -/* colorsPref.apply { - entryValues = if (style == KeyboardTheme.STYLE_HOLO) KeyboardTheme.COLORS.toTypedArray() - else KeyboardTheme.COLORS.filterNot { it == KeyboardTheme.THEME_HOLO_WHITE }.toTypedArray() - entries = entryValues.getNamesFromResourcesIfAvailable("theme_name_") - if (value !in entryValues) - value = entryValues.first().toString() - summary = entries[entryValues.indexOfFirst { it == value }] - - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> - summary = entries[entryValues.indexOfFirst { it == value }] - userColorsPref.isVisible = value == KeyboardTheme.THEME_USER - true - } - } - colorsNightPref?.apply { - entryValues = if (style == KeyboardTheme.STYLE_HOLO) KeyboardTheme.COLORS_DARK.toTypedArray() - else KeyboardTheme.COLORS_DARK.filterNot { it == KeyboardTheme.THEME_HOLO_WHITE }.toTypedArray() - entries = entryValues.getNamesFromResourcesIfAvailable("theme_name_") - if (value !in entryValues) - value = entryValues.first().toString() - summary = entries[entryValues.indexOfFirst { it == value }] - - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> - summary = entries[entryValues.indexOfFirst { it == value }] - userColorsPrefNight?.isVisible = value == KeyboardTheme.THEME_USER_NIGHT - true - } - }*/ - } - - private fun setupTheme() { -/* stylePref.apply { - entryValues = KeyboardTheme.STYLES - entries = entryValues.getNamesFromResourcesIfAvailable("style_name_") - if (value !in entryValues) - value = entryValues.first().toString() - - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> - summary = entries[entryValues.indexOfFirst { it == value }] - setColorPrefs(value.toString()) - true - } - summary = entries[entryValues.indexOfFirst { it == value }] - } - iconStylePref.apply { - entryValues = KeyboardTheme.STYLES - entries = entryValues.getNamesFromResourcesIfAvailable("style_name_") - if (value !in entryValues) - value = entryValues.first().toString() - - onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> - summary = entries[entryValues.indexOfFirst { it == value }] - true - } - summary = entries[entryValues.indexOfFirst { it == value }] - } - dayNightPref?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> - val yesThisIsBoolean = value as Boolean // apparently kotlin smartcast got less smart with 2.0.0 - colorsNightPref?.isVisible = yesThisIsBoolean - userColorsPrefNight?.isVisible = yesThisIsBoolean && colorsNightPref?.value == KeyboardTheme.THEME_USER_NIGHT - true - } - colorsNightPref?.isVisible = dayNightPref?.isChecked == true - userColorsPref.isVisible = colorsPref.value == KeyboardTheme.THEME_USER - userColorsPrefNight?.isVisible = dayNightPref?.isChecked == true && colorsNightPref?.value == KeyboardTheme.THEME_USER_NIGHT*/ - } - - // performance is not good, but not bad enough to justify work - private fun onClickCustomizeIcons(): Boolean { - val ctx = requireContext() - val padding = ResourceUtils.toPx(8, ctx.resources) - val ll = LinearLayout(context).apply { - orientation = LinearLayout.VERTICAL - setPadding(padding, 3 * padding, padding, padding) - } - val builder = AlertDialog.Builder(ctx) - .setTitle(R.string.customize_icons) - .setView(ScrollView(context).apply { addView(ll) }) - .setPositiveButton(R.string.dialog_close, null) - if (sharedPreferences.contains(Settings.PREF_CUSTOM_ICON_NAMES)) - builder.setNeutralButton(R.string.button_default) { _, _ -> - confirmDialog( - ctx, - ctx.getString(R.string.customize_icons_reset_message), - ctx.getString(android.R.string.ok), - { sharedPreferences.edit().remove(Settings.PREF_CUSTOM_ICON_NAMES).apply() } - ) - } - val dialog = builder.create() - - val cf = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(ContextCompat.getColor(ctx, R.color.foreground), BlendModeCompat.SRC_IN) - val iconsAndNames = KeyboardIconsSet.getAllIcons(ctx).keys.map { iconName -> - val name = iconName.getStringResourceOrName("", ctx) - if (name == iconName) iconName to iconName.getStringResourceOrName("label_", ctx).toString() - else iconName to name.toString() - } - iconsAndNames.sortedBy { it.second }.forEach { (iconName, name) -> - val b = ReorderDialogItemBinding.inflate(LayoutInflater.from(ctx), ll, true) - b.reorderItemIcon.setImageDrawable(KeyboardIconsSet.instance.getNewDrawable(iconName, ctx)) - b.reorderItemIcon.colorFilter = cf - b.reorderItemIcon.isVisible = true - b.reorderItemName.text = name - b.root.setOnClickListener { - customizeIcon(iconName) - dialog.dismiss() - } - b.reorderItemSwitch.isGone = true - b.reorderItemDragIndicator.isGone = true - } - dialog.show() - return true - } - - // todo: icon size is an important difference between holo and others, but really awful to work with - // scaling the intrinsic icon width may look awful depending on display density - private fun customizeIcon(iconName: String) { - val ctx = requireContext() - val rv = RecyclerView(ctx) - rv.layoutManager = GridLayoutManager(ctx, 6) - val padding = ResourceUtils.toPx(6, resources) - rv.setPadding(padding, 3 * padding, padding, padding) - val icons = KeyboardIconsSet.getAllIcons(ctx) - val iconsList = icons[iconName].orEmpty().toSet().toMutableList() - val iconsSet = icons.values.flatten().toMutableSet() - iconsSet.removeAll(iconsList) - iconsList.addAll(iconsSet) - val foregroundColor = ContextCompat.getColor(ctx, R.color.foreground) - val iconColorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(foregroundColor, BlendModeCompat.SRC_IN) - - var currentIconId = KeyboardIconsSet.instance.iconIds[iconName] - - val adapter = object : RecyclerView.Adapter() { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val v = ImageView(ctx) - v.colorFilter = iconColorFilter - v.setPadding(padding, padding, padding, padding) - return object : RecyclerView.ViewHolder(v) { } - } - - override fun getItemCount(): Int = iconsList.size - - override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) { - val icon = ContextCompat.getDrawable(ctx, iconsList[position])?.mutate() - val imageView = viewHolder.itemView as? ImageView - imageView?.setImageDrawable(icon) - if (iconsList[position] == currentIconId) imageView?.setColorFilter(R.color.accent) - else imageView?.colorFilter = iconColorFilter - viewHolder.itemView.setOnClickListener { v -> - rv.forEach { (it as? ImageView)?.colorFilter = iconColorFilter } - (v as? ImageView)?.setColorFilter(R.color.accent) - currentIconId = iconsList[position] - } - } - } - rv.adapter = adapter - val title = iconName.getStringResourceOrName("", ctx).takeUnless { it == iconName } - ?: iconName.getStringResourceOrName("label_", ctx) - val builder = AlertDialog.Builder(ctx) - .setTitle(title) - .setView(rv) - .setPositiveButton(android.R.string.ok) { _, _ -> - runCatching { - val icons2 = customIconNames(sharedPreferences).toMutableMap() - icons2[iconName] = currentIconId?.let { resources.getResourceEntryName(it) } ?: return@runCatching - sharedPreferences.edit().putString(Settings.PREF_CUSTOM_ICON_NAMES, Json.encodeToString(icons2)).apply() - KeyboardIconsSet.instance.loadIcons(ctx) - } - onClickCustomizeIcons() - } - .setNegativeButton(android.R.string.cancel) { _, _ -> onClickCustomizeIcons() } - if (customIconNames(sharedPreferences).contains(iconName)) - builder.setNeutralButton(R.string.button_default) { _, _ -> - runCatching { - val icons2 = customIconNames(sharedPreferences).toMutableMap() - icons2.remove(iconName) - if (icons2.isEmpty()) sharedPreferences.edit().remove(Settings.PREF_CUSTOM_ICON_NAMES).apply() - else sharedPreferences.edit().putString(Settings.PREF_CUSTOM_ICON_NAMES, Json.encodeToString(icons2)).apply() - KeyboardIconsSet.instance.loadIcons(ctx) - } - onClickCustomizeIcons() - } - - builder.show() - } - - private fun onClickLoadImage(landscape: Boolean): Boolean { - if (sharedPreferences.getBoolean(Settings.PREF_THEME_DAY_NIGHT, Defaults.PREF_THEME_DAY_NIGHT)) { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.day_or_night_image) - .setPositiveButton(R.string.day_or_night_day) { _, _ -> customImageDialog(false, landscape) } - .setNegativeButton(R.string.day_or_night_night) { _, _ -> customImageDialog(true, landscape) } - .setNeutralButton(android.R.string.cancel, null) - .show() - } else { - customImageDialog(false, landscape) - } - return true - } - - private fun customImageDialog(night: Boolean, landscape: Boolean) { - val imageFile = Settings.getCustomBackgroundFile(requireContext(), night, landscape) - val builder = AlertDialog.Builder(requireContext()) - .setMessage(if (landscape) R.string.customize_background_image_landscape else R.string.customize_background_image) - .setPositiveButton(R.string.button_load_custom) { _, _ -> - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("image/*") - if (landscape) { - if (night) nightImageFilePickerLandscape.launch(intent) - else dayImageFilePickerLandscape.launch(intent) - } else { - if (night) nightImageFilePicker.launch(intent) - else dayImageFilePicker.launch(intent) - } - } - .setNegativeButton(android.R.string.cancel, null) - if (imageFile.exists()) { - builder.setNeutralButton(R.string.delete) { _, _ -> - imageFile.delete() - Settings.clearCachedBackgroundImages() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } - } - builder.show() - } - - private fun loadImage(uri: Uri, night: Boolean, landscape: Boolean) { - val imageFile = Settings.getCustomBackgroundFile(requireContext(), night, landscape) - FileUtils.copyContentUriToNewFile(uri, requireContext(), imageFile) - try { - BitmapFactory.decodeFile(imageFile.absolutePath) - } catch (_: Exception) { - infoDialog(requireContext(), R.string.file_read_error) - imageFile.delete() - } - Settings.clearCachedBackgroundImages() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } - - private fun onClickCustomFont(): Boolean { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("*/*") - val fontFile = Settings.getCustomFontFile(requireContext()) - if (fontFile.exists()) { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.custom_font) - .setPositiveButton(R.string.load) { _, _ -> fontFilePicker.launch(intent) } - .setNegativeButton(android.R.string.cancel, null) - .setNeutralButton(R.string.delete) { _, _ -> - fontFile.delete() - Settings.clearCachedTypeface() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } - .show() - } else { - fontFilePicker.launch(intent) - } - return true - } - - private fun saveCustomTypeface(uri: Uri) { - val fontFile = Settings.getCustomFontFile(requireContext()) - val tempFile = File(DeviceProtectedUtils.getFilesDir(context), "temp_file") - FileUtils.copyContentUriToNewFile(uri, requireContext(), tempFile) - try { - val typeface = Typeface.createFromFile(tempFile) - fontFile.delete() - tempFile.renameTo(fontFile) - Settings.clearCachedTypeface() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } catch (_: Exception) { - infoDialog(requireContext(), R.string.file_read_error) - tempFile.delete() - } - } - - private fun setupScalePrefs(prefKey: String, defaultValue: Float) { - val prefs = sharedPreferences - val pref = findPreference(prefKey) as? SeekBarDialogPreference - pref?.setInterface(object : SeekBarDialogPreference.ValueProxy { - - private fun getValueFromPercentage(percentage: Int) = percentage / PERCENTAGE_FLOAT - - private fun getPercentageFromValue(floatValue: Float) = (floatValue * PERCENTAGE_FLOAT).toInt() - - override fun writeValue(value: Int, key: String) = prefs.edit().putFloat(key, getValueFromPercentage(value)).apply() - - override fun writeDefaultValue(key: String) = prefs.edit().remove(key).apply() - - override fun readValue(key: String) = getPercentageFromValue(prefs.getFloat(prefKey, defaultValue)) - - override fun readDefaultValue(key: String) = getPercentageFromValue(defaultValue) - - override fun getValueText(value: Int) = String.format(Locale.ROOT, "%d%%", value) - - override fun feedbackValue(value: Int) = Unit - }) - } - - private fun Array.getNamesFromResourcesIfAvailable(prefix: String) = - map { it.getStringResourceOrName(prefix, requireContext()) }.toTypedArray() - - companion object { - private const val PERCENTAGE_FLOAT = 100.0f - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/ColorsSettingsFragment.kt b/app/src/main/java/helium314/keyboard/latin/settings/ColorsSettingsFragment.kt deleted file mode 100644 index d5305312a..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/ColorsSettingsFragment.kt +++ /dev/null @@ -1,440 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -package helium314.keyboard.latin.settings - -import android.app.Activity -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context -import android.content.Intent -import android.content.SharedPreferences -import android.content.res.Configuration -import android.os.Bundle -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.WindowManager -import android.widget.CompoundButton -import android.widget.EditText -import android.widget.ImageView -import android.widget.LinearLayout -import android.widget.TextView -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AlertDialog -import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.edit -import androidx.core.view.MenuProvider -import androidx.core.view.forEach -import androidx.core.view.isGone -import androidx.core.view.isVisible -import androidx.core.widget.doAfterTextChanged -import androidx.fragment.app.Fragment -import com.rarepebble.colorpicker.ColorPickerView -import helium314.keyboard.keyboard.KeyboardSwitcher -import helium314.keyboard.keyboard.KeyboardTheme -import helium314.keyboard.latin.R -import helium314.keyboard.latin.RichInputMethodManager -import helium314.keyboard.latin.common.ColorType -import helium314.keyboard.latin.common.default -import helium314.keyboard.latin.databinding.ColorSettingBinding -import helium314.keyboard.latin.databinding.ColorSettingsBinding -import helium314.keyboard.latin.utils.ExecutorUtils -import helium314.keyboard.latin.utils.ResourceUtils -import helium314.keyboard.latin.utils.infoDialog -import helium314.keyboard.latin.utils.prefs -import kotlinx.serialization.Serializable -import kotlinx.serialization.SerializationException -import kotlinx.serialization.json.Json -import java.util.EnumMap - -open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvider { -/* - private val binding by viewBinding(ColorSettingsBinding::bind) - open val isNight = false - open val titleResId = R.string.select_user_colors - - // 0 for default - // 1 for more colors - // 2 for all colors - private var moreColors: Int - get() = prefs.getInt(Settings.getColorPref(Settings.PREF_SHOW_MORE_COLORS, isNight), 0) - set(value) { prefs.edit().putInt(Settings.getColorPref(Settings.PREF_SHOW_MORE_COLORS, isNight), value).apply() } - - private val prefs by lazy { requireContext().prefs() } - - private val colorPrefsAndNames by lazy { - listOf( - Settings.PREF_COLOR_BACKGROUND_SUFFIX to R.string.select_color_background, - Settings.PREF_COLOR_KEYS_SUFFIX to R.string.select_color_key_background, - Settings.PREF_COLOR_FUNCTIONAL_KEYS_SUFFIX to R.string.select_color_functional_key_background, - Settings.PREF_COLOR_SPACEBAR_SUFFIX to R.string.select_color_spacebar_background, - Settings.PREF_COLOR_TEXT_SUFFIX to R.string.select_color_key, - Settings.PREF_COLOR_HINT_TEXT_SUFFIX to R.string.select_color_key_hint, - Settings.PREF_COLOR_SUGGESTION_TEXT_SUFFIX to R.string.select_color_suggestion, - Settings.PREF_COLOR_SPACEBAR_TEXT_SUFFIX to R.string.select_color_spacebar_text, - Settings.PREF_COLOR_ACCENT_SUFFIX to R.string.select_color_accent, - Settings.PREF_COLOR_GESTURE_SUFFIX to R.string.select_color_gesture, - ).map { it.first to requireContext().getString(it.second) } - } - - private val colorPrefsToHideInitially by lazy { - listOf(Settings.PREF_COLOR_SUGGESTION_TEXT_SUFFIX,Settings.PREF_COLOR_SPACEBAR_TEXT_SUFFIX, Settings.PREF_COLOR_GESTURE_SUFFIX) + - if (prefs.getBoolean(Settings.PREF_THEME_KEY_BORDERS, false)) listOf(Settings.PREF_COLOR_SPACEBAR_SUFFIX) - else listOf(Settings.PREF_COLOR_FUNCTIONAL_KEYS_SUFFIX) - } - - override fun onResume() { - super.onResume() - if (isNight != ResourceUtils.isNight(requireContext().resources)) { - // reload to get the right configuration - forceOppositeTheme = true - reloadKeyboard(false) - } - val activity = activity - if (activity is AppCompatActivity) { - val actionBar = activity.supportActionBar ?: return - actionBar.setTitle(titleResId) - } - activity?.addMenuProvider(this) - } - - override fun onPause() { - super.onPause() - forceOppositeTheme = false - if (isNight != ResourceUtils.isNight(requireContext().resources)) - // reload again so the correct configuration is applied - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - activity?.removeMenuProvider(this) - } -*/ - override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { - menu.add(Menu.NONE, 0, Menu.NONE, R.string.main_colors) - menu.add(Menu.NONE, 1, Menu.NONE, R.string.more_colors) - menu.add(Menu.NONE, 2, Menu.NONE, R.string.all_colors) - menu.add(Menu.NONE, 3, Menu.NONE, R.string.save) - menu.add(Menu.NONE, 4, Menu.NONE, R.string.load) - } - - override fun onMenuItemSelected(menuItem: MenuItem): Boolean { - // necessary, even though we only have a single menu item - // because the back arrow on top absurdly is implemented as a menu item -/* if (menuItem.itemId in 0..2) { - if (moreColors == menuItem.itemId) return true - if (moreColors == 2 || menuItem.itemId == 2) { - RichInputMethodManager.getInstance().inputMethodManager.hideSoftInputFromWindow(binding.dummyText.windowToken, 0) - reloadKeyboard(false) - } - moreColors = menuItem.itemId - updateColorPrefs() - return true - } - if (menuItem.itemId == 3) { - saveDialog() - return true - } - if (menuItem.itemId == 4) { - loadDialog() - return true - }*/ - return false - } -/* - override fun onViewStateRestored(savedInstanceState: Bundle?) { - super.onViewStateRestored(savedInstanceState) - // updateColorPrefs must be called after super.onViewStateRestored because for some reason Android - // decides to set the checked state of the bottom-most switch to ALL switches during "restore" - updateColorPrefs() - } - - private fun updateColorPrefs() { - binding.colorSettingsContainer.removeAllViews() - if (moreColors == 2) showAllColors() - else showMainColors() - } - - private fun showAllColors() { - binding.info.isVisible = true - val colors = readAllColorsMap(prefs, isNight) - ColorType.entries.forEach { type -> - val color = colors[type] ?: type.default() - - val csb = ColorSettingBinding.inflate(layoutInflater, binding.colorSettingsContainer, true) - csb.root.tag = type - csb.colorSwitch.isGone = true - csb.colorPreview.setColorFilter(color) - csb.colorText.text = type.name - - val clickListener = View.OnClickListener { - val hidden = RichInputMethodManager.getInstance().inputMethodManager.hideSoftInputFromWindow(binding.dummyText.windowToken, 0) - val picker = ColorPickerView(requireContext()) - picker.showAlpha(type != ColorType.MAIN_BACKGROUND) // background behind background looks broken and sometimes is dark, sometimes light - picker.showHex(true) - picker.showPreview(true) - picker.color = color - val builder = AlertDialog.Builder(requireContext()) - builder - .setTitle(type.name) - .setView(picker) - .setCancelable(false) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok) { _, _ -> - val colorMap = readAllColorsMap(prefs, isNight) // better re-read it - colorMap[type] = picker.color - writeAllColorsMap(colorMap, prefs, isNight) - updateAllColorPreviews() - reloadKeyboard(hidden) - } - val dialog = builder.create() - dialog.show() - // Reduce the size of the dialog in portrait mode - val wrapContent = WindowManager.LayoutParams.WRAP_CONTENT - val widthPortrait = (resources.displayMetrics.widthPixels * 0.80f).toInt() - val orientation = (resources.configuration.orientation) - if (orientation == Configuration.ORIENTATION_LANDSCAPE) - dialog.window?.setLayout(wrapContent, wrapContent) - else - dialog.window?.setLayout(widthPortrait, wrapContent) - } - csb.colorTextContainer.setOnClickListener(clickListener) - csb.colorPreview.setOnClickListener(clickListener) - } - } - - private fun showMainColors() { - binding.info.isGone = true - val prefPrefix = if (isNight) Settings.PREF_THEME_USER_COLOR_NIGHT_PREFIX else Settings.PREF_THEME_USER_COLOR_PREFIX - colorPrefsAndNames.forEachIndexed { index, (colorPref, colorPrefName) -> - val autoColor = prefs.getBoolean(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, true) - if (moreColors == 0 && colorPref in colorPrefsToHideInitially && autoColor) - return@forEachIndexed - val csb = ColorSettingBinding.inflate(layoutInflater, binding.colorSettingsContainer, true) - csb.root.tag = index - csb.colorSwitch.isChecked = !autoColor - csb.colorPreview.setColorFilter(Settings.readUserColor(prefs, requireContext(), colorPref, isNight)) - csb.colorText.text = colorPrefName - if (!csb.colorSwitch.isChecked) { - csb.colorSummary.setText(R.string.auto_user_color) - } - val switchListener = CompoundButton.OnCheckedChangeListener { _, b -> - val hidden = RichInputMethodManager.getInstance().inputMethodManager.hideSoftInputFromWindow(binding.dummyText.windowToken, 0) - prefs.edit { putBoolean(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, !b) } - if (b) csb.colorSummary.text = "" - else csb.colorSummary.setText(R.string.auto_user_color) - reloadKeyboard(hidden) - updateMainColorPreviews() - } - csb.colorSwitch.setOnCheckedChangeListener(switchListener) - - val clickListener = View.OnClickListener { - val hidden = RichInputMethodManager.getInstance().inputMethodManager.hideSoftInputFromWindow(binding.dummyText.windowToken, 0) - val initialColor = Settings.readUserColor(prefs, requireContext(), colorPref, isNight) - val picker = ColorPickerView(requireContext()) - picker.showAlpha(colorPref != Settings.PREF_COLOR_BACKGROUND_SUFFIX) // background behind background looks broken and sometimes is dark, sometimes light - picker.showHex(true) - picker.showPreview(true) - picker.color = initialColor - // without the observer, the color previews in the background don't update - // but storing the pref and resetting on cancel is really bad style, so this is disabled for now -/* picker.addColorObserver { observer -> - prefs.edit { putInt(prefPrefix + colorPref, observer.color) } - if (!csb.colorSwitch.isChecked) { - prefs.edit { putBoolean(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, false) } - csb.colorSwitch.setOnCheckedChangeListener(null) - csb.colorSwitch.isChecked = true - csb.colorSummary.text = "" - csb.colorSwitch.setOnCheckedChangeListener(switchListener) - updateColorPreviews() - return@addColorObserver - } - updateColorPreviews() - }*/ - val builder = AlertDialog.Builder(requireContext()) - builder - .setTitle(colorPrefName) - .setView(picker) - .setCancelable(false) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(android.R.string.ok) { _, _ -> - prefs.edit { putInt(prefPrefix + colorPref, picker.color) } - if (!csb.colorSwitch.isChecked) { - prefs.edit { putBoolean(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, false) } - csb.colorSwitch.setOnCheckedChangeListener(null) - csb.colorSwitch.isChecked = true - csb.colorSummary.text = "" - csb.colorSwitch.setOnCheckedChangeListener(switchListener) - updateMainColorPreviews() - } else { - updateMainColorPreviews() - } - reloadKeyboard(hidden) - } - // The Default button appears only when a color has already been defined - if (csb.colorSwitch.isChecked) { - // Reset the color and the color picker to their initial state - builder.setNeutralButton(R.string.button_default) { _, _ -> - prefs.edit { remove(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX) } - csb.colorSwitch.isChecked = false - } - } - val dialog = builder.create() - dialog.show() - // Reduce the size of the dialog in portrait mode - val wrapContent = WindowManager.LayoutParams.WRAP_CONTENT - val widthPortrait = (resources.displayMetrics.widthPixels * 0.80f).toInt() - val orientation = (resources.configuration.orientation) - if (orientation == Configuration.ORIENTATION_LANDSCAPE) - dialog.window?.setLayout(wrapContent, wrapContent) - else - dialog.window?.setLayout(widthPortrait, wrapContent) - } - csb.colorTextContainer.setOnClickListener(clickListener) - csb.colorPreview.setOnClickListener(clickListener) - } - } - - private fun updateMainColorPreviews() { - binding.colorSettingsContainer.forEach { view -> - val index = view.tag as? Int ?: return@forEach - val color = Settings.readUserColor(prefs, requireContext(), colorPrefsAndNames[index].first, isNight) - view.findViewById(R.id.color_preview)?.setColorFilter(color) - } - } - - private fun updateAllColorPreviews() { - val colorMap = readAllColorsMap(prefs, isNight) - binding.colorSettingsContainer.forEach { view -> - val type = view.tag as? ColorType ?: return@forEach - val color = colorMap[type] ?: type.default() - view.findViewById(R.id.color_preview)?.setColorFilter(color) - } - } - - private fun reloadKeyboard(show: Boolean) { - ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - if (!show) return@execute - // for some reason showing again does not work when running with executor - // but when running without it's noticeably slow, and sometimes produces glitches - Thread.sleep(100) - RichInputMethodManager.getInstance().inputMethodManager.showSoftInput(binding.dummyText, 0) - } - } -*/ - companion object { - var forceOppositeTheme = false - } -/* - // ----------------- stuff for import / export --------------------------- - - private fun saveDialog() { - AlertDialog.Builder(requireContext()) - .setTitle(R.string.save) - .setPositiveButton(R.string.button_save_file) { _, _ -> - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .putExtra(Intent.EXTRA_TITLE,"theme.json") - .setType("application/json") - saveFilePicker.launch(intent) - } - .setNegativeButton(android.R.string.cancel, null) - .setNeutralButton(R.string.copy_to_clipboard) { _, _ -> - val cm = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager - cm.setPrimaryClip(ClipData.newPlainText("HeliBoard theme", getColorString())) - } - .show() - } - - private fun loadDialog() { - val layout = LinearLayout(requireContext()) - layout.orientation = LinearLayout.VERTICAL - layout.addView(TextView(requireContext()).apply { setText(R.string.load_will_overwrite) }) - val et = EditText(requireContext()) - layout.addView(et) - val padding = ResourceUtils.toPx(8, resources) - layout.setPadding(3 * padding, padding, padding, padding) - val d = AlertDialog.Builder(requireContext()) - .setTitle(R.string.load) - .setView(layout) - .setPositiveButton(android.R.string.ok) { _, _ -> - loadColorString(et.text.toString()) - } - .setNegativeButton(android.R.string.cancel, null) - .setNeutralButton(R.string.button_load_custom) { _, _ -> - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/*", "application/octet-stream", "application/json")) - .setType("*/*") - loadFilePicker.launch(intent) - } - .create() - et.doAfterTextChanged { d.getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled = et.text.toString().isNotBlank() } - d.show() - d.getButton(AlertDialog.BUTTON_POSITIVE)?.isEnabled = false - } - - private fun loadColorString(colorString: String) { - // show dialog - // load from file or from text field - // do some sanity check (only write correct settings, consider current night mode) - try { - val that = Json.decodeFromString(colorString) - // save mode to moreColors and PREF_SHOW_MORE_COLORS (with night dependence!) - that.colors.forEach { - val pref = Settings.getColorPref(it.key, isNight) - if (it.value.first == null) - prefs.edit { remove(pref) } - else prefs.edit { putInt(pref, it.value.first!!) } - prefs.edit { putBoolean(pref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, it.value.second) } - } - moreColors = that.moreColors - } catch (e: SerializationException) { - try { - val allColorsStringMap = Json.decodeFromString>(colorString) - val allColors = EnumMap(ColorType::class.java) - allColorsStringMap.forEach { - try { - allColors[ColorType.valueOf(it.key)] = it.value - } catch (_: IllegalArgumentException) {} - } - writeAllColorsMap(allColors, prefs, isNight) - moreColors = 2 - } catch (e: SerializationException) { - infoDialog(requireContext(), "error") - } - } - updateColorPrefs() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - } - - private fun getColorString(): String { - if (moreColors == 2) - return Json.encodeToString(readAllColorsMap(prefs, isNight).map { it.key.name to it.value }.toMap()) - // read the actual prefs! - val colors = colorPrefsAndResIds.associate { - val pref = Settings.getColorPref(it.first, isNight) - val color = if (prefs.contains(pref)) prefs.getInt(pref, 0) else null - it.first to (color to prefs.getBoolean(pref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, true)) - } - return Json.encodeToString(SaveThoseColors(moreColors, colors)) - } - - private val saveFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - activity?.contentResolver?.openOutputStream(uri)?.writer()?.use { it.write(getColorString()) } - } - - private val loadFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - activity?.contentResolver?.openInputStream(uri)?.use { - loadColorString(it.reader().readText()) - } ?: infoDialog(requireContext(), R.string.file_read_error) - } -*/ -} - -class ColorsNightSettingsFragment : ColorsSettingsFragment() { -// override val isNight = true -// override val titleResId = R.string.select_user_colors_night -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/CorrectionSettingsFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/CorrectionSettingsFragment.java deleted file mode 100644 index e99dc6f0f..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/CorrectionSettingsFragment.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import static helium314.keyboard.latin.permissions.PermissionsManager.get; - -import android.Manifest; -import android.content.SharedPreferences; -import android.os.Bundle; - -import androidx.appcompat.app.AlertDialog; -import androidx.preference.SwitchPreference; -import androidx.preference.TwoStatePreference; - -import helium314.keyboard.keyboard.KeyboardSwitcher; -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.permissions.PermissionsManager; -import helium314.keyboard.latin.permissions.PermissionsUtil; - -public final class CorrectionSettingsFragment extends SubScreenFragment - implements SharedPreferences.OnSharedPreferenceChangeListener, - PermissionsManager.PermissionsResultCallback { - - private SwitchPreference mLookupContactsPreference; - - @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.prefs_screen_correction); - - mLookupContactsPreference = findPreference(Settings.PREF_USE_CONTACTS); - - refreshEnabledSettings(); - } - - @Override - public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - if (Settings.PREF_USE_CONTACTS.equals(key) - && prefs.getBoolean(key, false) - && !PermissionsUtil.checkAllPermissionsGranted(getActivity(), Manifest.permission.READ_CONTACTS) - ) { - get(requireContext()).requestPermissions(this, getActivity(), Manifest.permission.READ_CONTACTS); - } else if (Settings.PREF_KEY_USE_PERSONALIZED_DICTS.equals(key) && !prefs.getBoolean(key, true)) { - new AlertDialog.Builder(requireContext()) - .setMessage(R.string.disable_personalized_dicts_message) - .setNegativeButton(android.R.string.cancel, (dialogInterface, i) -> ((TwoStatePreference) findPreference(key)).setChecked(true)) - .setPositiveButton(android.R.string.ok, null) - .setOnCancelListener(dialogInterface -> ((TwoStatePreference) findPreference(key)).setChecked(true)) - .show(); - } else if (Settings.PREF_SHOW_SUGGESTIONS.equals(key) && !prefs.getBoolean(key, true)) { - ((TwoStatePreference)findPreference(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS)).setChecked(false); - } else if (Settings.PREF_BIGRAM_PREDICTIONS.equals(key)) { - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()); - } - refreshEnabledSettings(); - } - - // contacts and permission stuff from SpellCheckerSettingsFragment - @Override - public void onRequestPermissionsResult(boolean allGranted) { - turnOffLookupContactsIfNoPermission(); - if (allGranted) - mLookupContactsPreference.setChecked(true); - } - - private void turnOffLookupContactsIfNoPermission() { - if (!PermissionsUtil.checkAllPermissionsGranted( - getActivity(), Manifest.permission.READ_CONTACTS)) { - mLookupContactsPreference.setChecked(false); - } - } - - private void refreshEnabledSettings() { - setPreferenceVisible(Settings.PREF_AUTO_CORRECTION_CONFIDENCE, getSharedPreferences().getBoolean(Settings.PREF_AUTO_CORRECTION, Defaults.PREF_AUTO_CORRECTION)); - setPreferenceVisible(Settings.PREF_MORE_AUTO_CORRECTION, getSharedPreferences().getBoolean(Settings.PREF_AUTO_CORRECTION, Defaults.PREF_AUTO_CORRECTION)); - setPreferenceVisible(Settings.PREF_ADD_TO_PERSONAL_DICTIONARY, getSharedPreferences().getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, true)); - setPreferenceVisible(Settings.PREF_ALWAYS_SHOW_SUGGESTIONS, getSharedPreferences().getBoolean(Settings.PREF_SHOW_SUGGESTIONS, true)); - setPreferenceVisible(Settings.PREF_CENTER_SUGGESTION_TEXT_TO_ENTER, getSharedPreferences().getBoolean(Settings.PREF_SHOW_SUGGESTIONS, true)); - turnOffLookupContactsIfNoPermission(); - } - -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/DebugSettings.java b/app/src/main/java/helium314/keyboard/latin/settings/DebugSettings.java index a51ca78d4..00db92ee7 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/DebugSettings.java +++ b/app/src/main/java/helium314/keyboard/latin/settings/DebugSettings.java @@ -14,6 +14,7 @@ public final class DebugSettings { public static final String PREF_FORCE_NON_DISTINCT_MULTITOUCH = "force_non_distinct_multitouch"; public static final String PREF_SLIDING_KEY_INPUT_PREVIEW = "sliding_key_input_preview"; public static final String PREF_SHOW_DEBUG_SETTINGS = "show_debug_settings"; + public static final String PREF_KEY_DUMP_DICT_PREFIX = "dump_dictionaries"; public static final String PREF_SHOW_SUGGESTION_INFOS = "show_suggestion_infos"; private DebugSettings() { diff --git a/app/src/main/java/helium314/keyboard/latin/settings/DebugSettingsFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/DebugSettingsFragment.java deleted file mode 100644 index 578c0fae3..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/DebugSettingsFragment.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.Context; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; - -import androidx.annotation.NonNull; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; -import androidx.preference.TwoStatePreference; - -import helium314.keyboard.keyboard.KeyboardSwitcher; -import helium314.keyboard.latin.BuildConfig; -import helium314.keyboard.latin.DictionaryDumpBroadcastReceiver; -import helium314.keyboard.latin.DictionaryFacilitator; -import helium314.keyboard.latin.R; - -/** - * "Debug mode" settings sub screen. - *

- * This settings sub screen handles a several preference options for debugging. - */ -public final class DebugSettingsFragment extends SubScreenFragment - implements Preference.OnPreferenceClickListener { - private static final String PREF_KEY_DUMP_DICTS = "dump_dictionaries"; - public static final String PREF_KEY_DUMP_DICT_PREFIX = "dump_dictionaries"; - - private boolean mServiceNeedsRestart = false; - private TwoStatePreference mDebugMode; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.prefs_screen_debug); - - final PreferenceGroup dictDumpPreferenceGroup = findPreference(PREF_KEY_DUMP_DICTS); - for (final String dictName : DictionaryFacilitator.DYNAMIC_DICTIONARY_TYPES) { - final Preference pref = new DictDumpPreference(getActivity(), dictName); - pref.setOnPreferenceClickListener(this); - dictDumpPreferenceGroup.addPreference(pref); - } - if (BuildConfig.DEBUG) - removePreference(DebugSettings.PREF_SHOW_DEBUG_SETTINGS); - - mServiceNeedsRestart = false; - mDebugMode = findPreference(DebugSettings.PREF_DEBUG_MODE); - findPreference(DebugSettings.PREF_SHOW_SUGGESTION_INFOS).setVisible(mDebugMode.isChecked()); - updateDebugMode(); - } - - private static class DictDumpPreference extends Preference { - public final String mDictName; - - public DictDumpPreference(final Context context, final String dictName) { - super(context); - setKey(PREF_KEY_DUMP_DICT_PREFIX + dictName); - setTitle("Dump " + dictName + " dictionary"); - mDictName = dictName; - } - } - - @Override - public boolean onPreferenceClick(@NonNull final Preference pref) { - if (pref instanceof final DictDumpPreference dictDumpPref) { - final String dictName = dictDumpPref.mDictName; - final Intent intent = new Intent( - DictionaryDumpBroadcastReceiver.DICTIONARY_DUMP_INTENT_ACTION); - intent.putExtra(DictionaryDumpBroadcastReceiver.DICTIONARY_NAME_KEY, dictName); - pref.getContext().sendBroadcast(intent); - return true; - } - return true; - } - - @Override - public void onStop() { - super.onStop(); - if (mServiceNeedsRestart) { - Runtime.getRuntime().exit(0); - } - } - - @Override - public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - if (DebugSettings.PREF_DEBUG_MODE.equals(key) && mDebugMode != null) { - final boolean enabled = prefs.getBoolean(DebugSettings.PREF_DEBUG_MODE, false); - mDebugMode.setChecked(enabled); - findPreference(DebugSettings.PREF_SHOW_SUGGESTION_INFOS).setVisible(enabled); - mServiceNeedsRestart = true; - } else if (key.equals(DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH)) { - mServiceNeedsRestart = true; - } else if (key.equals(DebugSettings.PREF_SHOW_SUGGESTION_INFOS)) { - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()); - } else if (key.equals(DebugSettings.PREF_SHOW_DEBUG_SETTINGS) && mDebugMode.isChecked()) { - mDebugMode.setChecked(false); - } - } - - private void updateDebugMode() { - final String version = getString(R.string.version_text, BuildConfig.VERSION_NAME); - mDebugMode.setSummary(version); - } - -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt b/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt index 69b22155c..0301409ba 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt +++ b/app/src/main/java/helium314/keyboard/latin/settings/Defaults.kt @@ -62,7 +62,7 @@ object Defaults { var PREF_POPUP_ON = true const val PREF_AUTO_CORRECTION = true const val PREF_MORE_AUTO_CORRECTION = false - const val PREF_AUTO_CORRECTION_CONFIDENCE = "0" + const val PREF_AUTO_CORRECT_THRESHOLD = 0.185f const val PREF_AUTOCORRECT_SHORTCUTS = true const val PREF_CENTER_SUGGESTION_TEXT_TO_ENTER = false const val PREF_SHOW_SUGGESTIONS = true @@ -128,7 +128,6 @@ object Defaults { const val PREF_LANGUAGE_SWIPE_DISTANCE = 5 const val PREF_ENABLE_CLIPBOARD_HISTORY = true const val PREF_CLIPBOARD_HISTORY_RETENTION_TIME = 10 // minutes - const val PREF_SECONDARY_LOCALES = "" const val PREF_ADD_TO_PERSONAL_DICTIONARY = false @JvmField val PREF_NAVBAR_COLOR = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q diff --git a/app/src/main/java/helium314/keyboard/latin/settings/FragmentBindingUtils.kt b/app/src/main/java/helium314/keyboard/latin/settings/FragmentBindingUtils.kt deleted file mode 100644 index 6f22b4b56..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/FragmentBindingUtils.kt +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -package helium314.keyboard.latin.settings - -import android.view.View -import android.view.ViewGroup -import androidx.fragment.app.Fragment -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.LifecycleEventObserver -import androidx.lifecycle.LifecycleOwner -import androidx.viewbinding.ViewBinding -import kotlin.properties.ReadOnlyProperty -import kotlin.reflect.KProperty - -// taken from StreetComplete, ViewBinder.kt -inline fun Fragment.viewBinding( - noinline viewBinder: (View) -> T, - rootViewId: Int? = null -) = FragmentViewBindingPropertyDelegate(this, viewBinder, rootViewId) - -class FragmentViewBindingPropertyDelegate( - private val fragment: Fragment, - private val viewBinder: (View) -> T, - private val rootViewId: Int? = null -) : ReadOnlyProperty, LifecycleEventObserver { - - private var binding: T? = null - - override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { - if (event == Lifecycle.Event.ON_DESTROY) { - binding = null - source.lifecycle.removeObserver(this) - } - } - - override fun getValue(thisRef: Fragment, property: KProperty<*>): T { - if (binding == null) { - val rootView = if (rootViewId != null) { - thisRef.requireView().findViewById(rootViewId)!!.getChildAt(0) - } else { - thisRef.requireView() - } - binding = viewBinder(rootView) - fragment.viewLifecycleOwner.lifecycle.addObserver(this) - } - return binding!! - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/GestureSettingsFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/GestureSettingsFragment.java deleted file mode 100644 index ea1dbc285..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/GestureSettingsFragment.java +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.os.Bundle; - -import androidx.preference.SwitchPreference; - -import helium314.keyboard.keyboard.KeyboardSwitcher; -import helium314.keyboard.latin.R; - -/** - * "Gesture typing preferences" settings sub screen. - *

- * This settings sub screen handles the following gesture typing preferences. - * - Enable gesture typing - * - Dynamic floating preview - * - Show gesture trail - * - Phrase gesture - */ -public final class GestureSettingsFragment extends SubScreenFragment { - private boolean needsReload = false; - - @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.prefs_screen_gesture); - setupGestureDynamicPreviewPref(); - setupGestureFastTypingCooldownPref(); - setupGestureTrailFadeoutPref(); - refreshSettingsEnablement(); - } - - @Override - public void onPause() { - super.onPause(); - if (needsReload) { - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()); - needsReload = false; - } - } - - @Override - public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - refreshSettingsEnablement(); - } - - private void refreshSettingsEnablement() { - final SharedPreferences prefs = getSharedPreferences(); - final boolean gestureInputEnabled = prefs.getBoolean(Settings.PREF_GESTURE_INPUT, Defaults.PREF_GESTURE_INPUT); - setPreferenceVisible(Settings.PREF_GESTURE_PREVIEW_TRAIL, gestureInputEnabled); - setPreferenceVisible(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, gestureInputEnabled); - final boolean gesturePreviewEnabled = gestureInputEnabled - && prefs.getBoolean(Settings.PREF_GESTURE_FLOATING_PREVIEW_TEXT, true); - setPreferenceVisible(Settings.PREF_GESTURE_FLOATING_PREVIEW_DYNAMIC, gesturePreviewEnabled); - setPreferenceVisible(Settings.PREF_GESTURE_SPACE_AWARE, gestureInputEnabled); - setPreferenceVisible(Settings.PREF_GESTURE_FAST_TYPING_COOLDOWN, gestureInputEnabled); - final boolean gestureTrailEnabled = gestureInputEnabled - && prefs.getBoolean(Settings.PREF_GESTURE_PREVIEW_TRAIL, true); - // This setting also affects the preview linger duration, so it's visible if either setting is enabled. - setPreferenceVisible(Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION, gestureTrailEnabled || gesturePreviewEnabled); - } - - private void setupGestureDynamicPreviewPref() { - final SwitchPreference pref = findPreference(Settings.PREF_GESTURE_FLOATING_PREVIEW_DYNAMIC); - if (pref == null) return; - final SharedPreferences prefs = getSharedPreferences(); - pref.setChecked(Settings.readGestureDynamicPreviewEnabled(prefs)); - pref.setOnPreferenceChangeListener((preference, newValue) -> { - // default value is based on system reduced motion - final boolean defValue = Settings.readGestureDynamicPreviewDefault(requireContext()); - final boolean followingSystem = newValue.equals(defValue); - // allow the default to be overridden - prefs.edit().putBoolean(Settings.PREF_GESTURE_DYNAMIC_PREVIEW_FOLLOW_SYSTEM, followingSystem).apply(); - needsReload = true; - return true; - }); - } - - private void setupGestureFastTypingCooldownPref() { - final SeekBarDialogPreference pref = findPreference( - Settings.PREF_GESTURE_FAST_TYPING_COOLDOWN); - if (pref == null) return; - final SharedPreferences prefs = getSharedPreferences(); - final Resources res = getResources(); - pref.setInterface(new SeekBarDialogPreference.ValueProxy() { - @Override - public void writeValue(final int value, final String key) { - prefs.edit().putInt(key, value).apply(); - } - - @Override - public void writeDefaultValue(final String key) { - prefs.edit().remove(key).apply(); - } - - @Override - public int readValue(final String key) { - return prefs.getInt(Settings.PREF_GESTURE_FAST_TYPING_COOLDOWN, Defaults.PREF_GESTURE_FAST_TYPING_COOLDOWN); - } - - @Override - public int readDefaultValue(final String key) { - return Settings.readDefaultGestureFastTypingCooldown(res); - } - - @Override - public String getValueText(final int value) { - if (value == 0) { - return res.getString(R.string.gesture_fast_typing_cooldown_instant); - } - return res.getString(R.string.abbreviation_unit_milliseconds, String.valueOf(value)); - } - - @Override - public void feedbackValue(final int value) {} - }); - } - - private void setupGestureTrailFadeoutPref() { - final SeekBarDialogPreference pref = findPreference(Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION); - if (pref == null) return; - final SharedPreferences prefs = getSharedPreferences(); - final Resources res = getResources(); - pref.setInterface(new SeekBarDialogPreference.ValueProxy() { - @Override - public void writeValue(final int value, final String key) { - prefs.edit().putInt(key, value).apply(); - needsReload = true; - } - - @Override - public void writeDefaultValue(final String key) { - prefs.edit().remove(key).apply(); - needsReload = true; - } - - @Override - public int readValue(final String key) { - return prefs.getInt(Settings.PREF_GESTURE_TRAIL_FADEOUT_DURATION, Defaults.PREF_GESTURE_TRAIL_FADEOUT_DURATION); - } - - @Override - public int readDefaultValue(final String key) { - return 800; - } - - @Override - public String getValueText(final int value) { - // fade-out has a constant start delay, value text is adjusted accordingly. - final int adjustedValue = res.getInteger(R.integer.config_gesture_trail_fadeout_start_delay) + value; - return res.getString(R.string.abbreviation_unit_milliseconds, String.valueOf(adjustedValue)); - } - - @Override - public void feedbackValue(final int value) {} - }); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/LanguageFilterList.kt b/app/src/main/java/helium314/keyboard/latin/settings/LanguageFilterList.kt deleted file mode 100644 index 758f6fce8..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/LanguageFilterList.kt +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -package helium314.keyboard.latin.settings - -import android.content.Context -import android.graphics.Typeface -import android.text.Spannable -import android.text.SpannableString -import android.text.SpannableStringBuilder -import android.text.style.StyleSpan -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.EditText -import android.widget.LinearLayout -import android.widget.Switch -import android.widget.TextView -import androidx.core.view.isGone -import androidx.core.view.isVisible -import androidx.core.widget.doAfterTextChanged -import androidx.recyclerview.widget.RecyclerView -import helium314.keyboard.latin.R -import helium314.keyboard.latin.common.LocaleUtils -import helium314.keyboard.latin.utils.SubtypeLocaleUtils -import helium314.keyboard.latin.utils.SubtypeSettings -import helium314.keyboard.latin.utils.displayName -import helium314.keyboard.latin.utils.locale -import helium314.keyboard.latin.utils.prefs -import helium314.keyboard.latin.utils.showMissingDictionaryDialog -import java.util.Locale - -class LanguageFilterList(searchField: EditText, recyclerView: RecyclerView) { - - private val adapter = LanguageAdapter(emptyList(), recyclerView.context) - private val sortedSubtypes = mutableListOf>() - - fun setSettingsFragment(newFragment: LanguageSettingsFragment?) { - adapter.fragment = newFragment - } - - init { - recyclerView.adapter = adapter - searchField.doAfterTextChanged { text -> - adapter.list = sortedSubtypes.filter { it.first().displayName.startsWith(text.toString(), ignoreCase = true) } - } - } - - fun setLanguages(list: Collection>, onlySystemLocales: Boolean) { - sortedSubtypes.clear() - sortedSubtypes.addAll(list) - adapter.onlySystemLocales = onlySystemLocales - adapter.list = sortedSubtypes - } - -} - -private class LanguageAdapter(list: List> = listOf(), context: Context) : - RecyclerView.Adapter() { - var onlySystemLocales = false - private val prefs = context.prefs() - var fragment: LanguageSettingsFragment? = null - - var list: List> = list - set(value) { - field = value - notifyDataSetChanged() - } - - override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.onBind(list[position]) - } - - override fun getItemCount() = list.size - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LanguageAdapter.ViewHolder { - val v = LayoutInflater.from(parent.context).inflate(R.layout.language_list_item, parent, false) - return ViewHolder(v) - } - - inner class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) { - - fun onBind(infos: MutableList) { - sort(infos) - fun setupDetailsTextAndSwitch() { - view.findViewById(R.id.language_details).apply { - // input styles if more than one in infos - val sb = SpannableStringBuilder() - if (infos.size > 1 && !onlySystemLocales) { - var start = true - infos.forEach { - val string = SpannableString(SubtypeLocaleUtils.getMainLayoutDisplayName(it.subtype) - ?: it.subtype.displayName(context)) - if (it.isEnabled) - string.setSpan(StyleSpan(Typeface.BOLD), 0, string.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - if (!start) { - sb.append(", ") - } - start = false - sb.append(string) - } - } - val secondaryLocales = emptyList() - if (secondaryLocales.isNotEmpty()) { - if (sb.isNotEmpty()) - sb.append("\n") - //sb.append(Settings.getSecondaryLocales(prefs, infos.first().subtype.locale()) - // .joinToString(", ") { - // LocaleUtils.getLocaleDisplayNameInSystemLocale(it, context) - // }) - } - text = sb - if (text.isBlank()) isGone = true - else isVisible = true - } - - view.findViewById(R.id.language_switch).apply { - isEnabled = !onlySystemLocales - // take care: isChecked changes if the language is scrolled out of view and comes back! - // disable the change listener when setting the checked status on scroll - // so it's only triggered on user interactions - setOnCheckedChangeListener(null) - isChecked = onlySystemLocales || infos.any { it.isEnabled } - setOnCheckedChangeListener { _, b -> - if (b) { - if (!infos.first().hasDictionary) - showMissingDictionaryDialog(context, infos.first().subtype.locale()) - SubtypeSettings.addEnabledSubtype(prefs, infos.first().subtype) - infos.first().isEnabled = true - } else { - SubtypeSettings.removeEnabledSubtype(context, infos.first().subtype) - infos.first().isEnabled = false - } - } - } - view.findViewById(R.id.blocker).apply { - if (infos.size < 2) { - isGone = true - return@apply - } - isVisible = true - setOnClickListener { - LanguageSettingsDialog(view.context, infos, fragment, onlySystemLocales, { setupDetailsTextAndSwitch() }).show() - } - } - } - - view.findViewById(R.id.language_name).text = infos.first().displayName - view.findViewById(R.id.language_text).setOnClickListener { - LanguageSettingsDialog(view.context, infos, fragment, onlySystemLocales, { setupDetailsTextAndSwitch() }).show() - } - setupDetailsTextAndSwitch() - } - - private fun sort(infos: MutableList) { - if (infos.size <= 1) return - infos.sortWith(compareBy({ SubtypeSettings.isAdditionalSubtype(it.subtype) }, { it.displayName })) - } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt b/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt deleted file mode 100644 index 3045c2e9c..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsDialog.kt +++ /dev/null @@ -1,430 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -package helium314.keyboard.latin.settings - -import android.content.Context -import android.content.Intent -import android.net.Uri -import android.text.method.LinkMovementMethod -import android.util.TypedValue -import android.view.LayoutInflater -import android.view.View -import android.widget.ImageView -import android.widget.ScrollView -import android.widget.Switch -import android.widget.TextView -import androidx.appcompat.app.AlertDialog -import androidx.core.view.get -import androidx.core.view.isGone -import androidx.core.view.isVisible -import androidx.core.view.size -import helium314.keyboard.compat.locale -import helium314.keyboard.dictionarypack.DictionaryPackConstants -import helium314.keyboard.keyboard.KeyboardLayoutSet -import helium314.keyboard.keyboard.KeyboardSwitcher -import helium314.keyboard.latin.R -import helium314.keyboard.latin.common.Links.DICTIONARY_URL -import helium314.keyboard.latin.common.Links.LAYOUT_FORMAT_URL -import helium314.keyboard.latin.common.LocaleUtils -import helium314.keyboard.latin.common.LocaleUtils.constructLocale -import helium314.keyboard.latin.databinding.LanguageListItemBinding -import helium314.keyboard.latin.databinding.LocaleSettingsDialogBinding -import helium314.keyboard.latin.utils.* -import helium314.keyboard.latin.utils.DictionaryInfoUtils.USER_DICTIONARY_SUFFIX -import helium314.keyboard.latin.utils.ScriptUtils.script -import java.io.File -import java.util.* - -class LanguageSettingsDialog( - context: Context, - private val infos: MutableList, - private val fragment: LanguageSettingsFragment?, - private val onlySystemLocales: Boolean, - private val reloadSetting: () -> Unit -) : AlertDialog(context), LanguageSettingsFragment.Listener { - private val prefs = context.prefs() - private val binding = LocaleSettingsDialogBinding.inflate(LayoutInflater.from(context)) - private val mainLocale = infos.first().subtype.locale() - private var hasInternalDictForLanguage = false - private val userDicts = mutableSetOf() - - init { - setTitle(infos.first().displayName) - setView(ScrollView(context).apply { addView(binding.root) }) - setButton(BUTTON_NEGATIVE, context.getString(R.string.dialog_close)) { _, _ -> - dismiss() - } - - if (onlySystemLocales) - // don't allow setting subtypes, because - // a. subtypes are set purely based on system locales (in SubtypeSettings) - // b. extra handling needed if user disables all subtypes for a locale - // todo (later): fix above and allow it - binding.subtypes.isGone = true - else - fillSubtypesView() - fillSecondaryLocaleView() - fillDictionariesView() - setupPopupSettings() - } - - override fun onStart() { - super.onStart() - fragment?.setListener(this) - } - - override fun onStop() { - super.onStop() - fragment?.setListener(null) - } - - private fun fillSubtypesView() { - if (infos.first().subtype.isAsciiCapable) { - binding.addSubtype.setOnClickListener { - val layouts = context.resources.getStringArray(R.array.predefined_layouts) - .filterNot { layoutName -> infos.any { SubtypeLocaleUtils.getMainLayoutName(it.subtype) == layoutName } } - val displayNames = layouts.map { SubtypeLocaleUtils.getMainLayoutDisplayName(it) } - Builder(context) - .setTitle(R.string.keyboard_layout_set) - .setItems(displayNames.toTypedArray()) { di, i -> - di.dismiss() - addSubtype(layouts[i]) - } - .setNeutralButton(R.string.button_title_add_custom_layout) { _, _ -> onClickAddCustomSubtype() } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - } else - binding.addSubtype.setOnClickListener { onClickAddCustomSubtype() } - - // add subtypes - infos.sortedBy { it.displayName }.forEach { - addSubtypeToView(it) - } - } - - private fun addSubtype(name: String) { - LayoutUtilsCustom.onLayoutFileChanged() - val newSubtype = SubtypeUtilsAdditional.createEmojiCapableAdditionalSubtype(mainLocale, name, infos.first().subtype.isAsciiCapable) - val newSubtypeInfo = newSubtype.toSubtypeInfo(mainLocale, context, true, infos.first().hasDictionary) // enabled by default - val displayName = SubtypeLocaleUtils.getMainLayoutDisplayName(newSubtype) - val old = infos.firstOrNull { SubtypeSettings.isAdditionalSubtype(it.subtype) && displayName == SubtypeLocaleUtils.getMainLayoutDisplayName(it.subtype) } - if (old != null) { - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(context) - reloadSetting() - return - } - - SubtypeUtilsAdditional.addAdditionalSubtype(prefs, newSubtype) - SubtypeSettings.addEnabledSubtype(prefs, newSubtype) - addSubtypeToView(newSubtypeInfo) - KeyboardLayoutSet.onKeyboardThemeChanged() - infos.add(newSubtypeInfo) - reloadSetting() - } - - private fun onClickAddCustomSubtype() { - val link = "" + context.getString(R.string.dictionary_link_text) + "" - val message = SpannableStringUtils.fromHtml(context.getString(R.string.message_add_custom_layout, link)) - val dialog = Builder(context) - .setTitle(R.string.button_title_add_custom_layout) - .setMessage(message) - .setNegativeButton(android.R.string.cancel, null) - .setNeutralButton(R.string.button_copy_existing_layout) { _, _ -> copyLayout() } - .setPositiveButton(R.string.button_load_custom) { _, _ -> fragment?.requestLayoutFile() } - .create() - dialog.show() - (dialog.findViewById(android.R.id.message) as? TextView)?.movementMethod = LinkMovementMethod.getInstance() - } - - private fun copyLayout() { - val layouts = mutableListOf() - val displayNames = mutableListOf() - infos.forEach { - val mainLayoutName = it.subtype.mainLayoutName() ?: "qwerty" - if (!LayoutUtilsCustom.isCustomLayout(mainLayoutName) // don't allow copying custom layout (at least for now) - && !mainLayoutName.endsWith("+")) { // don't allow copying layouts only defined via extra keys - layouts.add(mainLayoutName) - displayNames.add(it.subtype.displayName(context).toString()) - } - } - if (infos.first().subtype.isAsciiCapable) { - context.resources.getStringArray(R.array.predefined_layouts).forEach { - layouts.add(it) - displayNames.add(SubtypeLocaleUtils.getMainLayoutDisplayName(it) ?: it) - } - } - Builder(context) - .setTitle(R.string.keyboard_layout_set) - .setItems(displayNames.toTypedArray()) { di, i -> - di.dismiss() - val fileName = context.assets.list("layouts")?.firstOrNull { it.startsWith(layouts[i]) } ?: return@setItems - LayoutUtilsCustom.loadLayout(context.assets.open("layouts${File.separator}$fileName").reader().readText(), - displayNames[i], mainLocale.toLanguageTag(), context) { addSubtype(it) } - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - - override fun onNewLayoutFile(uri: Uri?) { - LayoutUtilsCustom.loadLayout(uri, mainLocale.toLanguageTag(), context) { addSubtype(it) } - } - - private fun addSubtypeToView(subtype: SubtypeInfo) { - val row = LayoutInflater.from(context).inflate(R.layout.language_list_item, listView) - val layoutSetName = subtype.subtype.mainLayoutName() ?: "qwerty" - row.findViewById(R.id.language_name).text = - SubtypeLocaleUtils.getMainLayoutDisplayName(subtype.subtype) - ?: subtype.subtype.displayName(context) - if (LayoutUtilsCustom.isCustomLayout(layoutSetName)) { - row.findViewById(R.id.language_details).setText(R.string.edit_layout) - row.findViewById(R.id.language_text).setOnClickListener { LayoutUtilsCustom.editLayout(layoutSetName, context) } - } else { - row.findViewById(R.id.language_details).isGone = true - } - row.findViewById(R.id.language_switch).apply { - isChecked = subtype.isEnabled - isEnabled = !onlySystemLocales - setOnCheckedChangeListener { _, b -> - if (b) { - if (!infos.first().hasDictionary) - showMissingDictionaryDialog(context, mainLocale) - SubtypeSettings.addEnabledSubtype(prefs, subtype.subtype) - } - else - SubtypeSettings.removeEnabledSubtype(context, subtype.subtype) - subtype.isEnabled = b - reloadSetting() - } - } - if (SubtypeSettings.isAdditionalSubtype(subtype.subtype)) { - row.findViewById(R.id.language_switch).isEnabled = true - row.findViewById(R.id.delete_button).apply { - isVisible = true - setOnClickListener { - val isCustom = LayoutUtilsCustom.isCustomLayout(layoutSetName) - fun delete() { - binding.subtypes.removeView(row) - infos.remove(subtype) - //if (isCustom) - // LayoutUtilsCustom.removeCustomLayoutFile(layoutSetName, context) - SubtypeUtilsAdditional.removeAdditionalSubtype(context, subtype.subtype) - SubtypeSettings.removeEnabledSubtype(context, subtype.subtype) - reloadSetting() - } - if (isCustom) { - confirmDialog(context, context.getString(R.string.delete_layout, LayoutUtilsCustom.getDisplayName(layoutSetName)), context.getString(R.string.delete)) { delete() } - } else { - delete() - } - } - } - } - binding.subtypes.addView(row) - } - - private fun fillSecondaryLocaleView() { - // can only use multilingual typing if there is more than one dictionary available - val availableSecondaryLocales = getAvailableSecondaryLocales( - context, - mainLocale, - infos.first().subtype.isAsciiCapable - ) - val selectedSecondaryLocales = emptyList()// Settings.getSecondaryLocales(prefs, mainLocale) - selectedSecondaryLocales.forEach { - addSecondaryLocaleView(it) - } - if (availableSecondaryLocales.isNotEmpty()) { - binding.addSecondaryLanguage.apply { - isVisible = true - setOnClickListener { - val locales = (availableSecondaryLocales).sortedBy { it.displayName } - val localeNames = locales.map { LocaleUtils.getLocaleDisplayNameInSystemLocale(it, context) }.toTypedArray() - Builder(context) - .setTitle(R.string.button_select_language) - .setItems(localeNames) { di, i -> - val locale = locales[i] - //val currentSecondaryLocales = Settings.getSecondaryLocales(prefs, mainLocale) - //Settings.setSecondaryLocales(prefs, mainLocale, currentSecondaryLocales + locale) - addSecondaryLocaleView(locale) - di.dismiss() - reloadSetting() - reloadDictionaries() - KeyboardLayoutSet.onSystemLocaleChanged() - } - .setNegativeButton(android.R.string.cancel, null) - .show() - } - } - } else if (selectedSecondaryLocales.isEmpty()) - binding.secondaryLocales.isGone = true - } - - private fun addSecondaryLocaleView(locale: Locale) { - val rowBinding = LanguageListItemBinding.inflate(LayoutInflater.from(context), listView, false) - rowBinding.languageSwitch.isGone = true - rowBinding.languageDetails.isGone = true - rowBinding.languageName.text = locale.displayName - rowBinding.deleteButton.apply { - isVisible = true - setOnClickListener { - //val currentSecondaryLocales = Settings.getSecondaryLocales(prefs, mainLocale) - //Settings.setSecondaryLocales(prefs, mainLocale, currentSecondaryLocales - locale) - binding.secondaryLocales.removeView(rowBinding.root) - reloadSetting() - reloadDictionaries() - KeyboardLayoutSet.onSystemLocaleChanged() - } - } - binding.secondaryLocales.addView(rowBinding.root) - } - - private fun fillDictionariesView() { - binding.addDictionary.setOnClickListener { - val dictLink = "" + context.getString(R.string.dictionary_link_text) + "" - val startMessage = context.getString(R.string.add_dictionary, dictLink) - val messageRawText = createDictionaryTextHtml(startMessage, mainLocale, context) - val message = SpannableStringUtils.fromHtml(messageRawText) - val dialog = Builder(context) - .setTitle(R.string.add_new_dictionary_title) - .setMessage(message) - .setPositiveButton(R.string.user_dict_settings_add_menu_title) { _, _ -> fragment?.requestDictionary() } - .setNegativeButton(android.R.string.cancel, null) - .create() - dialog.show() - (dialog.findViewById(android.R.id.message) as? TextView)?.movementMethod = LinkMovementMethod.getInstance() - } - val userDictsAndHasInternal = getUserAndInternalDictionaries(context, mainLocale) - hasInternalDictForLanguage = userDictsAndHasInternal.second - userDicts.addAll(userDictsAndHasInternal.first) - if (hasInternalDictForLanguage) { - binding.dictionaries.addView(TextView(context, null, R.style.PreferenceCategoryTitleText).apply { - setText(R.string.internal_dictionary_summary) - // just setting a text size can be complicated... - val attrs = context.obtainStyledAttributes(R.style.PreferenceSubtitleText, intArrayOf(android.R.attr.textSize)) - setTextSize(TypedValue.COMPLEX_UNIT_PX, attrs.getDimension(0, 20f)) - attrs.recycle() - setPadding(ResourceUtils.toPx(16, context.resources), 0, 0, 0) - isEnabled = userDicts.none { it.name == "${DictionaryInfoUtils.MAIN_DICT_PREFIX}${USER_DICTIONARY_SUFFIX}" } - }) - } - userDicts.sorted().forEach { - addDictionaryToView(it) - } - } - - override fun onNewDictionary(uri: Uri?) { - NewDictionaryAdder(context) { replaced, dictFile -> - if (!replaced) { - addDictionaryToView(dictFile) - userDicts.add(dictFile) - if (hasInternalDictForLanguage) { - binding.dictionaries[1].isEnabled = - userDicts.none { it.name == "${DictionaryInfoUtils.MAIN_DICT_PREFIX}${USER_DICTIONARY_SUFFIX}" } - } - } - }.addDictionary(uri, mainLocale) - } - - private fun addDictionaryToView(dictFile: File) { - if (!infos.first().hasDictionary) { - infos.forEach { it.hasDictionary = true } - } - val dictType = dictFile.name.substringBefore("_${USER_DICTIONARY_SUFFIX}") - val rowBinding = LanguageListItemBinding.inflate(LayoutInflater.from(context), listView, false) - val header = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(dictFile, 0, dictFile.length()) - rowBinding.languageName.text = dictType - rowBinding.languageDetails.apply { - if (header?.description == null) { - isGone = true - } else { - // what would potentially be interesting? locale? description? version? timestamp? - text = header.description - } - } - rowBinding.languageText.setOnClickListener { - if (header == null) return@setOnClickListener - val locale = context.resources.configuration.locale() - Builder(context) - .setMessage(header.info(locale)) - .setPositiveButton(android.R.string.ok, null) - .show() - } - rowBinding.languageSwitch.isGone = true - rowBinding.deleteButton.apply { - isVisible = true - setOnClickListener { - confirmDialog(context, context.getString(R.string.remove_dictionary_message, dictType), context.getString( - R.string.delete)) { - val parent = dictFile.parentFile - dictFile.delete() - if (parent?.list()?.isEmpty() == true) - parent.delete() - reloadDictionaries() - binding.dictionaries.removeView(rowBinding.root) - if (binding.dictionaries.size < 2) { // first view is "Dictionaries" - infos.forEach { it.hasDictionary = false } - } - userDicts.remove(dictFile) - if (hasInternalDictForLanguage) { - binding.dictionaries[1].isEnabled = - userDicts.none { it.name == "${DictionaryInfoUtils.MAIN_DICT_PREFIX}${USER_DICTIONARY_SUFFIX}" } - } - } - } - } - binding.dictionaries.addView(rowBinding.root) - } - - private fun setupPopupSettings() { - binding.popupOrder.setOnClickListener { - val popupKeyTypesDefault = prefs.getString(Settings.PREF_POPUP_KEYS_ORDER, POPUP_KEYS_ORDER_DEFAULT)!! - reorderDialog(context, Settings.PREF_POPUP_KEYS_ORDER + "_" + mainLocale.toLanguageTag(), popupKeyTypesDefault, R.string.popup_order) - KeyboardLayoutSet.onKeyboardThemeChanged() - } - binding.popupLabelPriority.setOnClickListener { - val popupKeyTypesDefault = prefs.getString(Settings.PREF_POPUP_KEYS_LABELS_ORDER, POPUP_KEYS_LABEL_DEFAULT)!! - reorderDialog(context, Settings.PREF_POPUP_KEYS_LABELS_ORDER + "_" + mainLocale.toLanguageTag(), popupKeyTypesDefault, R.string.hint_source) - KeyboardLayoutSet.onKeyboardThemeChanged() - } - } - - private fun reloadDictionaries() = fragment?.activity?.sendBroadcast(Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)) -} - -/** @return list of user dictionary files and whether an internal dictionary exists */ -private fun getUserAndInternalDictionaries(context: Context, locale: Locale): Pair, Boolean> { - val userDicts = mutableListOf() - var hasInternalDict = false - val userLocaleDir = File(DictionaryInfoUtils.getAndCreateCacheDirectoryForLocale(locale, context)) - if (userLocaleDir.exists() && userLocaleDir.isDirectory) { - userLocaleDir.listFiles()?.forEach { - if (it.name.endsWith(USER_DICTIONARY_SUFFIX)) - userDicts.add(it) - else if (it.name.startsWith(DictionaryInfoUtils.MAIN_DICT_PREFIX)) - hasInternalDict = true - } - } - if (hasInternalDict) - return userDicts to true - val internalDicts = DictionaryInfoUtils.getAssetsDictionaryList(context) ?: return userDicts to false - val best = LocaleUtils.getBestMatch(locale, internalDicts.toList()) { - DictionaryInfoUtils.extractLocaleFromAssetsDictionaryFile(it)?.constructLocale() ?: SubtypeLocaleUtils.NO_LANGUAGE.constructLocale() - } - return userDicts to (best != null) -} - -// get locales with same script as main locale, but different language -private fun getAvailableSecondaryLocales(context: Context, mainLocale: Locale, asciiCapable: Boolean): Set { - val locales = getDictionaryLocales(context) - val mainScript = if (asciiCapable) ScriptUtils.SCRIPT_LATIN - else mainLocale.script() - // script() extension function may return latin in case script cannot be determined - // workaround: don't allow secondary locales for these locales - if (!asciiCapable && mainScript == ScriptUtils.SCRIPT_LATIN) return emptySet() - - locales.removeAll { - it.language == mainLocale.language || it.script() != mainScript - } - return locales -} - diff --git a/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsFragment.kt b/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsFragment.kt deleted file mode 100644 index 850e06cb0..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/LanguageSettingsFragment.kt +++ /dev/null @@ -1,227 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -package helium314.keyboard.latin.settings - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.content.SharedPreferences -import android.net.Uri -import android.os.Bundle -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.view.inputmethod.InputMethodSubtype -import android.widget.Switch -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.edit -import androidx.fragment.app.Fragment -import helium314.keyboard.latin.R -import helium314.keyboard.latin.common.LocaleUtils -import helium314.keyboard.latin.common.LocaleUtils.constructLocale -import helium314.keyboard.latin.utils.DictionaryInfoUtils -import helium314.keyboard.latin.utils.ScriptUtils.script -import helium314.keyboard.latin.utils.SubtypeLocaleUtils -import helium314.keyboard.latin.utils.SubtypeSettings -import helium314.keyboard.latin.utils.getDictionaryLocales -import helium314.keyboard.latin.utils.locale -import helium314.keyboard.latin.utils.prefs -import java.util.* - -// not a SettingsFragment, because with androidx.preferences it's very complicated or -// impossible to have the languages RecyclerView scrollable (this way it works nicely out of the box) -class LanguageSettingsFragment : Fragment(R.layout.language_settings) { - private val sortedSubtypesByDisplayName = LinkedHashMap>() - private val enabledSubtypes = mutableListOf() - private val systemLocales = mutableListOf() - private lateinit var languageFilterList: LanguageFilterList - private lateinit var prefs: SharedPreferences - private lateinit var systemOnlySwitch: Switch - private val dictionaryLocales by lazy { getDictionaryLocales(requireContext()) } - - private val dictionaryFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - listener?.onNewDictionary(uri) - } - - private val layoutFilePicker = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { - if (it.resultCode != Activity.RESULT_OK) return@registerForActivityResult - val uri = it.data?.data ?: return@registerForActivityResult - listener?.onNewLayoutFile(uri) - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - prefs = requireContext().prefs() - - SubtypeLocaleUtils.init(requireContext()) - - enabledSubtypes.addAll(SubtypeSettings.getEnabledSubtypes()) - systemLocales.addAll(SubtypeSettings.getSystemLocales()) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val view = super.onCreateView(inflater, container, savedInstanceState) ?: return null - systemOnlySwitch = view.findViewById(R.id.language_switch) - systemOnlySwitch.isChecked = false - systemOnlySwitch.setOnCheckedChangeListener { _, b -> - enabledSubtypes.clear() - enabledSubtypes.addAll(SubtypeSettings.getEnabledSubtypes()) - loadSubtypes(b) - } - languageFilterList = LanguageFilterList(view.findViewById(R.id.search_field), view.findViewById(R.id.language_list)) - loadSubtypes(systemOnlySwitch.isChecked) - return view - } - - override fun onResume() { - super.onResume() - languageFilterList.setSettingsFragment(this) - val activity: Activity? = activity - if (activity is AppCompatActivity) { - val actionBar = activity.supportActionBar ?: return - actionBar.setTitle(R.string.language_and_layouts_title) - } - } - - override fun onPause() { - super.onPause() - languageFilterList.setSettingsFragment(null) - } - - private fun loadSubtypes(systemOnly: Boolean) { - sortedSubtypesByDisplayName.clear() - // list of all subtypes, any subtype added to sortedSubtypes will be removed to avoid duplicates - val allSubtypes = SubtypeSettings.getAllAvailableSubtypes().toMutableList() - fun List.sortedAddToSubtypesAndRemoveFromAllSubtypes() { - val subtypesToAdd = mutableListOf() - forEach { locale -> - val iterator = allSubtypes.iterator() - var added = false - while (iterator.hasNext()) { - val subtype = iterator.next() - if (subtype.locale() == locale) { - // add subtypes with matching locale - subtypesToAdd.add(subtype.toSubtypeInfo(locale)) - iterator.remove() - added = true - } - } - // if locale has a country try again, but match language and script only - if (!added && locale.country.isNotEmpty()) { - val language = locale.language - val script = locale.script() - val iter = allSubtypes.iterator() - while (iter.hasNext()) { - val subtype = iter.next() - val subtypeLocale = subtype.locale() - if (subtypeLocale.toLanguageTag() == subtypeLocale.language && subtypeLocale.language == language && script == subtypeLocale.script()) { - // add subtypes using the language only - subtypesToAdd.add(subtype.toSubtypeInfo(language.constructLocale())) - iter.remove() - added = true - } - } - } - // try again if script is not the default script, match language only - if (!added && locale.script() != locale.language.constructLocale().script()) { - val language = locale.language - val iter = allSubtypes.iterator() - while (iter.hasNext()) { - val subtype = iter.next() - if (subtype.locale().language == language) { - subtypesToAdd.add(subtype.toSubtypeInfo(subtype.locale())) - iter.remove() - } - } - } - } - subtypesToAdd.sortedBy { it.displayName }.addToSortedSubtypes() - } - - // add enabled subtypes - enabledSubtypes.map { it.toSubtypeInfo(it.locale(), true) } - .sortedBy { it.displayName }.addToSortedSubtypes() - allSubtypes.removeAll(enabledSubtypes) - - if (systemOnly) { // don't add anything else - languageFilterList.setLanguages(sortedSubtypesByDisplayName.values, systemOnly) - return - } - - // add subtypes that have a dictionary - val localesWithDictionary = DictionaryInfoUtils.getCachedDirectoryList(requireContext())?.mapNotNull { dir -> - if (!dir.isDirectory) - return@mapNotNull null - if (dir.list()?.any { it.endsWith(DictionaryInfoUtils.USER_DICTIONARY_SUFFIX) } == true) - dir.name.constructLocale() - else null - } - localesWithDictionary?.sortedAddToSubtypesAndRemoveFromAllSubtypes() - - // add subtypes for device locales - systemLocales.sortedAddToSubtypesAndRemoveFromAllSubtypes() - - // add the remaining ones - allSubtypes.map { it.toSubtypeInfo(it.locale()) } - .sortedBy { if (it.subtype.locale().toLanguageTag().equals(SubtypeLocaleUtils.NO_LANGUAGE, true)) - SubtypeLocaleUtils.NO_LANGUAGE // "No language (Alphabet)" should be last - else it.displayName - }.addToSortedSubtypes() - - // set languages - languageFilterList.setLanguages(sortedSubtypesByDisplayName.values, systemOnly) - } - - private fun InputMethodSubtype.toSubtypeInfo(locale: Locale, isEnabled: Boolean = false) = - toSubtypeInfo(locale, requireContext(), isEnabled, LocaleUtils.getBestMatch(locale, dictionaryLocales) {it} != null) - - private fun List.addToSortedSubtypes() { - forEach { - sortedSubtypesByDisplayName.getOrPut(it.displayName) { mutableListOf() }.add(it) - } - } - - interface Listener { - fun onNewDictionary(uri: Uri?) - fun onNewLayoutFile(uri: Uri?) - } - - private var listener: Listener? = null - - fun setListener(newListener: Listener?) { - listener = newListener - } - - fun requestDictionary() { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - .setType("application/octet-stream") - dictionaryFilePicker.launch(intent) - } - - fun requestLayoutFile() { - val intent = Intent(Intent.ACTION_OPEN_DOCUMENT) - .addCategory(Intent.CATEGORY_OPENABLE) - // todo: any working way to allow only json and text files? - .putExtra(Intent.EXTRA_MIME_TYPES, arrayOf("text/*", "application/octet-stream", "application/json")) - .setType("*/*") - layoutFilePicker.launch(intent) - } -} - -class SubtypeInfo(val displayName: String, val subtype: InputMethodSubtype, var isEnabled: Boolean, var hasDictionary: Boolean) { - override fun equals(other: Any?): Boolean { - if (other !is SubtypeInfo) return false - return subtype == other.subtype - } - - override fun hashCode(): Int { - return subtype.hashCode() - } -} - -fun InputMethodSubtype.toSubtypeInfo(locale: Locale, context: Context, isEnabled: Boolean, hasDictionary: Boolean): SubtypeInfo = - SubtypeInfo(LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context), this, isEnabled, hasDictionary) diff --git a/app/src/main/java/helium314/keyboard/latin/settings/OldSettingsActivity.java b/app/src/main/java/helium314/keyboard/latin/settings/OldSettingsActivity.java deleted file mode 100644 index 18b6a9207..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/OldSettingsActivity.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import static android.preference.PreferenceActivity.EXTRA_NO_HEADERS; -import static android.preference.PreferenceActivity.EXTRA_SHOW_FRAGMENT; - -import android.content.Intent; -import android.os.Bundle; - -import helium314.keyboard.latin.permissions.PermissionsManager; -import helium314.keyboard.latin.utils.ActivityThemeUtils; -import helium314.keyboard.latin.utils.NewDictionaryAdder; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; - -public final class OldSettingsActivity extends AppCompatActivity - implements ActivityCompat.OnRequestPermissionsResultCallback { - private static final String DEFAULT_FRAGMENT = SettingsFragment.class.getName(); - - public static final String EXTRA_ENTRY_KEY = "entry"; - public static final String EXTRA_ENTRY_VALUE_APP_ICON = "app_icon"; - - @Override - protected void onCreate(final Bundle savedState) { - super.onCreate(savedState); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - } - final Intent i = getIntent(); - if (Intent.ACTION_VIEW.equals(i.getAction()) && i.getData() != null) { - new NewDictionaryAdder(this, null).addDictionary(i.getData(), null); - setIntent(new Intent()); // avoid opening again - } - if (getSupportFragmentManager().getFragments().isEmpty()) - getSupportFragmentManager().beginTransaction() - .replace(android.R.id.content, new SettingsFragment()) - .commit(); - - ActivityThemeUtils.setActivityTheme(this); - } - - @Override - public boolean onSupportNavigateUp() { - onBackPressed(); - return true; - } - - @Override - public Intent getIntent() { - final Intent intent = super.getIntent(); - final String fragment = intent.getStringExtra(EXTRA_SHOW_FRAGMENT); - if (fragment == null) { - intent.putExtra(EXTRA_SHOW_FRAGMENT, DEFAULT_FRAGMENT); - } - intent.putExtra(EXTRA_NO_HEADERS, true); - return intent; - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - PermissionsManager.get(this).onRequestPermissionsResult(requestCode, permissions, grantResults); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/PreferencesSettingsFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/PreferencesSettingsFragment.java deleted file mode 100644 index f25e62a52..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/PreferencesSettingsFragment.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.Context; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.media.AudioManager; -import android.os.Bundle; -import android.view.inputmethod.InputMethodSubtype; - -import androidx.preference.Preference; - -import helium314.keyboard.keyboard.KeyboardLayoutSet; -import helium314.keyboard.keyboard.KeyboardSwitcher; -import helium314.keyboard.latin.AudioAndHapticFeedbackManager; -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.RichInputMethodManager; -import helium314.keyboard.latin.utils.DialogUtilsKt; -import helium314.keyboard.latin.utils.PopupKeysUtilsKt; -import helium314.keyboard.latin.utils.SubtypeSettings; -import helium314.keyboard.latin.utils.SubtypeUtilsKt; - -import kotlin.collections.ArraysKt; - -public final class PreferencesSettingsFragment extends SubScreenFragment { - - private boolean mReloadKeyboard = false; - - @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); - addPreferencesFromResource(R.xml.prefs_screen_preferences); - - final Context context = getActivity(); - - // When we are called from the Settings application but we are not already running, some - // singleton and utility classes may not have been initialized. We have to call - // initialization method of these classes here. See {@link LatinIME#onCreate()}. - RichInputMethodManager.init(context); - - if (!AudioAndHapticFeedbackManager.getInstance().hasVibrator()) { - removePreference(Settings.PREF_VIBRATE_ON); - removePreference(Settings.PREF_VIBRATE_IN_DND_MODE); - removePreference(Settings.PREF_VIBRATION_DURATION_SETTINGS); - } - - setupKeypressVibrationDurationSettings(); - setupKeypressSoundVolumeSettings(); - setupHistoryRetentionTimeSettings(); - refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings(); - setLocalizedNumberRowVisibility(); - setNumberRowHintsVisibility(); - findPreference(Settings.PREF_POPUP_KEYS_LABELS_ORDER).setVisible(getSharedPreferences().getBoolean(Settings.PREF_SHOW_HINTS, false)); - findPreference(Settings.PREF_POPUP_KEYS_ORDER).setOnPreferenceClickListener((pref) -> { - DialogUtilsKt.reorderDialog(requireContext(), Settings.PREF_POPUP_KEYS_ORDER, - PopupKeysUtilsKt.POPUP_KEYS_ORDER_DEFAULT, R.string.popup_order, (x) -> null); - return true; - }); - findPreference(Settings.PREF_POPUP_KEYS_LABELS_ORDER).setOnPreferenceClickListener((pref) -> { - DialogUtilsKt.reorderDialog(requireContext(), Settings.PREF_POPUP_KEYS_LABELS_ORDER, - PopupKeysUtilsKt.POPUP_KEYS_LABEL_DEFAULT, R.string.hint_source, (x) -> null); - return true; - }); - } - - @Override - public void onResume() { - super.onResume(); - } - - @Override - public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings(); - if (key == null) return; - switch (key) { - case Settings.PREF_POPUP_KEYS_ORDER, Settings.PREF_SHOW_POPUP_HINTS, Settings.PREF_SHOW_NUMBER_ROW_HINTS, - Settings.PREF_POPUP_KEYS_LABELS_ORDER, Settings.PREF_LANGUAGE_SWITCH_KEY, - Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, Settings.PREF_REMOVE_REDUNDANT_POPUPS -> mReloadKeyboard = true; - case Settings.PREF_SHOW_NUMBER_ROW -> { - setNumberRowHintsVisibility(); - mReloadKeyboard = true; - } - case Settings.PREF_LOCALIZED_NUMBER_ROW -> KeyboardLayoutSet.onSystemLocaleChanged(); - case Settings.PREF_SHOW_HINTS -> { - findPreference(Settings.PREF_POPUP_KEYS_LABELS_ORDER).setVisible(prefs.getBoolean(Settings.PREF_SHOW_HINTS, false)); - setNumberRowHintsVisibility(); - } - } - } - - @Override - public void onPause() { - super.onPause(); - if (mReloadKeyboard) - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()); - mReloadKeyboard = false; - } - - private void setLocalizedNumberRowVisibility() { - final Preference pref = findPreference(Settings.PREF_LOCALIZED_NUMBER_ROW); - if (pref == null) return; - // locales that have a number row defined (not good to have it hardcoded, but reading a bunch of files may be noticeably slow) - final String[] numberRowLocales = new String[] { "ar", "bn", "fa", "gu", "hi", "kn", "mr", "ne", "ur" }; - for (final InputMethodSubtype subtype : SubtypeSettings.INSTANCE.getEnabledSubtypes(true)) { - if (ArraysKt.any(numberRowLocales, (l) -> l.equals(SubtypeUtilsKt.locale(subtype).getLanguage()))) { - pref.setVisible(true); - return; - } - } - pref.setVisible(false); - } - - private void setNumberRowHintsVisibility() { - var prefs = getSharedPreferences(); - setPreferenceVisible(Settings.PREF_SHOW_NUMBER_ROW_HINTS, prefs.getBoolean(Settings.PREF_SHOW_HINTS, false) - && prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false)); - } - - private void refreshEnablingsOfKeypressSoundAndVibrationAndHistRetentionSettings() { - final SharedPreferences prefs = getSharedPreferences(); - final Resources res = getResources(); - setPreferenceVisible(Settings.PREF_VIBRATION_DURATION_SETTINGS, - Settings.readVibrationEnabled(prefs)); - setPreferenceVisible(Settings.PREF_VIBRATE_IN_DND_MODE, - Settings.readVibrationEnabled(prefs)); - setPreferenceVisible(Settings.PREF_KEYPRESS_SOUND_VOLUME, - prefs.getBoolean(Settings.PREF_SOUND_ON, Defaults.PREF_SOUND_ON)); - setPreferenceVisible(Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, - prefs.getBoolean(Settings.PREF_ENABLE_CLIPBOARD_HISTORY, Defaults.PREF_ENABLE_CLIPBOARD_HISTORY)); - } - - private void setupKeypressVibrationDurationSettings() { - final SeekBarDialogPreference pref = findPreference( - Settings.PREF_VIBRATION_DURATION_SETTINGS); - if (pref == null) { - return; - } - final SharedPreferences prefs = getSharedPreferences(); - final Resources res = getResources(); - pref.setInterface(new SeekBarDialogPreference.ValueProxy() { - @Override - public void writeValue(final int value, final String key) { - prefs.edit().putInt(key, value).apply(); - } - - @Override - public void writeDefaultValue(final String key) { - prefs.edit().remove(key).apply(); - } - - @Override - public int readValue(final String key) { - return prefs.getInt(Settings.PREF_VIBRATION_DURATION_SETTINGS, Defaults.PREF_VIBRATION_DURATION_SETTINGS); - } - - @Override - public int readDefaultValue(final String key) { - return -1; - } - - @Override - public void feedbackValue(final int value) { - AudioAndHapticFeedbackManager.getInstance().vibrate(value); - } - - @Override - public String getValueText(final int value) { - if (value < 0) { - return res.getString(R.string.settings_system_default); - } - return res.getString(R.string.abbreviation_unit_milliseconds, Integer.toString(value)); - } - }); - } - - private void setupKeypressSoundVolumeSettings() { - final SeekBarDialogPreference pref = findPreference( - Settings.PREF_KEYPRESS_SOUND_VOLUME); - if (pref == null) { - return; - } - final SharedPreferences prefs = getSharedPreferences(); - final Resources res = getResources(); - final AudioManager am = (AudioManager) requireContext().getSystemService(Context.AUDIO_SERVICE); - pref.setInterface(new SeekBarDialogPreference.ValueProxy() { - private static final float PERCENTAGE_FLOAT = 100.0f; - - private float getValueFromPercentage(final int percentage) { - return percentage / PERCENTAGE_FLOAT; - } - - private int getPercentageFromValue(final float floatValue) { - return (int)(floatValue * PERCENTAGE_FLOAT); - } - - @Override - public void writeValue(final int value, final String key) { - prefs.edit().putFloat(key, getValueFromPercentage(value)).apply(); - } - - @Override - public void writeDefaultValue(final String key) { - prefs.edit().remove(key).apply(); - } - - @Override - public int readValue(final String key) { - return getPercentageFromValue(prefs.getFloat(Settings.PREF_KEYPRESS_SOUND_VOLUME, Defaults.PREF_KEYPRESS_SOUND_VOLUME)); - } - - @Override - public int readDefaultValue(final String key) { - return getPercentageFromValue(-1f); - } - - @Override - public String getValueText(final int value) { - if (value < 0) { - return res.getString(R.string.settings_system_default); - } - return Integer.toString(value); - } - - @Override - public void feedbackValue(final int value) { - am.playSoundEffect( - AudioManager.FX_KEYPRESS_STANDARD, getValueFromPercentage(value)); - } - }); - } - - private void setupHistoryRetentionTimeSettings() { - final SharedPreferences prefs = getSharedPreferences(); - final Resources res = getResources(); - final SeekBarDialogPreference pref = findPreference( - Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME); - if (pref == null) { - return; - } - pref.setInterface(new SeekBarDialogPreference.ValueProxy() { - @Override - public void writeValue(final int value, final String key) { - prefs.edit().putInt(key, value).apply(); - } - - @Override - public void writeDefaultValue(final String key) { - prefs.edit().remove(key).apply(); - } - - @Override - public int readValue(final String key) { - return prefs.getInt(Settings.PREF_CLIPBOARD_HISTORY_RETENTION_TIME, Defaults.PREF_CLIPBOARD_HISTORY_RETENTION_TIME); - } - - @Override - public int readDefaultValue(final String key) { - return Settings.readDefaultClipboardHistoryRetentionTime(res); - } - - @Override - public String getValueText(final int value) { - if (value <= 0) { - return res.getString(R.string.settings_no_limit); - } - return res.getString(R.string.abbreviation_unit_minutes, Integer.toString(value)); - } - - @Override - public void feedbackValue(final int value) {} - }); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/SeekBarDialogPreference.java b/app/src/main/java/helium314/keyboard/latin/settings/SeekBarDialogPreference.java deleted file mode 100644 index 11cf5b6e7..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/SeekBarDialogPreference.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.Context; -import android.content.DialogInterface; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.SeekBar; -import android.widget.TextView; - -import androidx.appcompat.app.AlertDialog; -import androidx.preference.Preference; - -import helium314.keyboard.latin.R; - -public final class SeekBarDialogPreference extends Preference - implements SeekBar.OnSeekBarChangeListener, DialogInterface.OnClickListener { - public interface ValueProxy { - int readValue(final String key); - int readDefaultValue(final String key); - void writeValue(final int value, final String key); - void writeDefaultValue(final String key); - String getValueText(final int value); - void feedbackValue(final int value); - } - - private final int mMaxValue; - private final int mMinValue; - private final int mStepValue; - - private TextView mValueView; - private SeekBar mSeekBar; - - private ValueProxy mValueProxy; - - public SeekBarDialogPreference(final Context context, final AttributeSet attrs) { - super(context, attrs); - final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.SeekBarDialogPreference, 0, 0); - mMaxValue = a.getInt(R.styleable.SeekBarDialogPreference_maxValue, 0); - mMinValue = a.getInt(R.styleable.SeekBarDialogPreference_minValue, 0); - mStepValue = a.getInt(R.styleable.SeekBarDialogPreference_stepValue, 0); - a.recycle(); - } - - public void setInterface(final ValueProxy proxy) { - mValueProxy = proxy; - final int value = mValueProxy.readValue(getKey()); - setSummary(mValueProxy.getValueText(value)); - } - - private int getProgressFromValue(final int value) { - return value - mMinValue; - } - - private int getValueFromProgress(final int progress) { - return progress + mMinValue; - } - - private int clipValue(final int value) { - final int clippedValue = Math.min(mMaxValue, Math.max(mMinValue, value)); - if (mStepValue <= 1) { - return clippedValue; - } - return clippedValue - (clippedValue % mStepValue); - } - - private int getClippedValueFromProgress(final int progress) { - return clipValue(getValueFromProgress(progress)); - } - - private void onCreateDialogView(final View view) { - mSeekBar = view.findViewById(R.id.seek_bar_dialog_bar); - mSeekBar.setMax(mMaxValue - mMinValue); - mSeekBar.setOnSeekBarChangeListener(this); - mValueView = view.findViewById(R.id.seek_bar_dialog_value); - final int value = mValueProxy.readValue(getKey()); - mValueView.setText(mValueProxy.getValueText(value)); - mSeekBar.setProgress(getProgressFromValue(clipValue(value))); - } - - @Override - public void onClick() { - final View view = LayoutInflater.from(getContext()).inflate(R.layout.seek_bar_dialog, null); - final AlertDialog dialog = new AlertDialog.Builder(getContext()) - .setTitle(getTitle()) - .setView(view) - .setPositiveButton(android.R.string.ok, this) - .setNegativeButton(android.R.string.cancel, this) - .setNeutralButton(R.string.button_default, this) - .create(); - dialog.setOnShowListener((d) -> onCreateDialogView(view)); - dialog.show(); - } - - @Override - public void onClick(final DialogInterface dialog, final int which) { - final String key = getKey(); - if (which == DialogInterface.BUTTON_NEUTRAL) { - final int value = mValueProxy.readDefaultValue(key); - setSummary(mValueProxy.getValueText(value)); - mValueProxy.writeDefaultValue(key); - return; - } - if (which == DialogInterface.BUTTON_POSITIVE) { - final int value = getClippedValueFromProgress(mSeekBar.getProgress()); - setSummary(mValueProxy.getValueText(value)); - mValueProxy.writeValue(value, key); - } - } - - @Override - public void onProgressChanged(final SeekBar seekBar, final int progress, - final boolean fromUser) { - final int value = getClippedValueFromProgress(progress); - mValueView.setText(mValueProxy.getValueText(value)); - if (!fromUser) { - mSeekBar.setProgress(getProgressFromValue(value)); - } - } - - @Override - public void onStartTrackingTouch(final SeekBar seekBar) {} - - @Override - public void onStopTrackingTouch(final SeekBar seekBar) { - mValueProxy.feedbackValue(getClippedValueFromProgress(seekBar.getProgress())); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/Settings.java b/app/src/main/java/helium314/keyboard/latin/settings/Settings.java index 667dec1c3..89e93e8dd 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/Settings.java +++ b/app/src/main/java/helium314/keyboard/latin/settings/Settings.java @@ -46,9 +46,6 @@ import java.util.concurrent.locks.ReentrantLock; public final class Settings implements SharedPreferences.OnSharedPreferenceChangeListener { private static final String TAG = Settings.class.getSimpleName(); - // Settings screens - public static final String SCREEN_DEBUG = "screen_debug"; - public static final String SCREEN_GESTURE = "screen_gesture"; // theme-related stuff public static final String PREF_THEME_STYLE = "theme_style"; @@ -72,7 +69,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_POPUP_ON = "popup_on"; public static final String PREF_AUTO_CORRECTION = "auto_correction"; public static final String PREF_MORE_AUTO_CORRECTION = "more_auto_correction"; - public static final String PREF_AUTO_CORRECTION_CONFIDENCE = "auto_correction_confidence"; + public static final String PREF_AUTO_CORRECT_THRESHOLD = "auto_correct_threshold"; public static final String PREF_AUTOCORRECT_SHORTCUTS = "autocorrect_shortcuts"; public static final String PREF_CENTER_SUGGESTION_TEXT_TO_ENTER = "center_suggestion_text_to_enter"; public static final String PREF_SHOW_SUGGESTIONS = "show_suggestions"; @@ -290,11 +287,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang mPrefs.edit().putBoolean(Settings.PREF_AUTO_CORRECTION, !oldValue).apply(); } - public static String readAutoCorrectConfidence(final SharedPreferences prefs, final Resources res) { - return prefs.getString(PREF_AUTO_CORRECTION_CONFIDENCE, - res.getString(R.string.auto_correction_threshold_mode_index_modest)); - } - public static boolean readGestureDynamicPreviewEnabled(final SharedPreferences prefs) { final boolean followSystem = prefs.getBoolean(PREF_GESTURE_DYNAMIC_PREVIEW_FOLLOW_SYSTEM, Defaults.PREF_GESTURE_DYNAMIC_PREVIEW_FOLLOW_SYSTEM); final boolean defValue = Defaults.PREF_GESTURE_DYNAMIC_PREVIEW_FOLLOW_SYSTEM; @@ -324,10 +316,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang prefs.edit().putString(PREF_ADDITIONAL_SUBTYPES, prefSubtypes).apply(); } - public static int readDefaultClipboardHistoryRetentionTime(final Resources res) { - return res.getInteger(R.integer.config_clipboard_history_retention_time); - } - public static int readHorizontalSpaceSwipe(final SharedPreferences prefs) { return switch (prefs.getString(PREF_SPACE_HORIZONTAL_SWIPE, Defaults.PREF_SPACE_HORIZONTAL_SWIPE)) { case "move_cursor" -> KeyboardActionListener.SWIPE_MOVE_CURSOR; diff --git a/app/src/main/java/helium314/keyboard/latin/settings/SettingsFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/SettingsFragment.java deleted file mode 100644 index 3da0a172b..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/SettingsFragment.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.inputmethod.InputMethodSubtype; - -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.preference.Preference; -import androidx.preference.PreferenceFragmentCompat; - -import helium314.keyboard.latin.BuildConfig; -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.common.FileUtils; -import helium314.keyboard.latin.define.DebugFlags; -import helium314.keyboard.latin.utils.DictionaryUtilsKt; -import helium314.keyboard.latin.utils.ExecutorUtils; -import helium314.keyboard.latin.utils.JniUtils; -import helium314.keyboard.latin.utils.KtxKt; -import helium314.keyboard.latin.utils.SubtypeSettings; -import helium314.keyboard.latin.utils.SubtypeUtilsKt; - -import java.util.List; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; - -public final class SettingsFragment extends PreferenceFragmentCompat { - private final ArrayList crashReportFiles = new ArrayList<>(); - - @Override - public void onCreate(final Bundle icicle) { - super.onCreate(icicle); - setHasOptionsMenu(true); - } - - @Override - public void onCreatePreferences(@Nullable Bundle bundle, @Nullable String s) { - addPreferencesFromResource(R.xml.prefs); - if (!JniUtils.sHaveGestureLib) { - final Preference gesturePreference = findPreference(Settings.SCREEN_GESTURE); - getPreferenceScreen().removePreference(gesturePreference); - } - ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD) - .execute(() -> DictionaryUtilsKt.cleanUnusedMainDicts(requireContext())); - } - - @Override - public void onResume() { - super.onResume(); - final Activity activity = getActivity(); - if (activity instanceof AppCompatActivity) { - final ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar(); - final CharSequence screenTitle = getPreferenceScreen().getTitle(); - if (actionBar != null && screenTitle != null) { - actionBar.setTitle(screenTitle); - } - } - - findPreference("screen_languages").setSummary(getEnabledSubtypesLabel()); - if (BuildConfig.DEBUG || DebugFlags.DEBUG_ENABLED) - askAboutCrashReports(); - } - - private String getEnabledSubtypesLabel() { - final List subtypes = SubtypeSettings.INSTANCE.getEnabledSubtypes(true); - final StringBuilder sb = new StringBuilder(); - for (final InputMethodSubtype subtype : subtypes) { - if (sb.length() > 0) - sb.append(", "); - sb.append(SubtypeUtilsKt.displayName(subtype, requireContext())); - } - return sb.toString(); - } - - private void askAboutCrashReports() { - // find crash report files - final File dir = requireContext().getExternalFilesDir(null); - if (dir == null) return; - final File[] allFiles = dir.listFiles(); - if (allFiles == null) return; - crashReportFiles.clear(); - for (File file : allFiles) { - if (file.getName().startsWith("crash_report")) - crashReportFiles.add(file); - } - if (crashReportFiles.isEmpty()) return; - new AlertDialog.Builder(requireContext()) - .setMessage("Crash report files found") - .setPositiveButton("get", (dialogInterface, i) -> { - final Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - intent.putExtra(Intent.EXTRA_TITLE, "crash_reports.zip"); - intent.setType("application/zip"); - crashReportFilePicker.launch(intent); - }) - .setNeutralButton("delete", (dialogInterface, i) -> { - for (File file : crashReportFiles) { - file.delete(); // don't care whether it fails, though user will complain - } - }) - .setNegativeButton("ignore", null) - .show(); - } - - final ActivityResultLauncher crashReportFilePicker = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), (intent) -> { - if (intent.getResultCode() != Activity.RESULT_OK || intent.getData() == null) return; - final Uri uri = intent.getData().getData(); - if (uri != null) - ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute(() -> saveCrashReport(uri)); - }); - - private void saveCrashReport(final Uri uri) { - if (uri == null || crashReportFiles.isEmpty()) return; - final OutputStream os; - try { - os = requireContext().getContentResolver().openOutputStream(uri); - if (os == null) return; - final BufferedOutputStream bos = new BufferedOutputStream(os); - final ZipOutputStream z = new ZipOutputStream(bos); - for (File file : crashReportFiles) { - FileInputStream f = new FileInputStream(file); - z.putNextEntry(new ZipEntry(file.getName())); - FileUtils.copyStreamToOtherStream(f, z); - f.close(); - z.closeEntry(); - } - z.close(); - bos.close(); - os.close(); - for (File file : crashReportFiles) { - file.delete(); - } - } catch (IOException ignored) { } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java b/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java index e8d657927..8576bc1d2 100644 --- a/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java +++ b/app/src/main/java/helium314/keyboard/latin/settings/SettingsValues.java @@ -28,12 +28,10 @@ import helium314.keyboard.latin.common.Colors; import helium314.keyboard.latin.permissions.PermissionsUtil; import helium314.keyboard.latin.utils.InputTypeUtils; import helium314.keyboard.latin.utils.JniUtils; -import helium314.keyboard.latin.utils.Log; import helium314.keyboard.latin.utils.ScriptUtils; import helium314.keyboard.latin.utils.SubtypeSettings; import helium314.keyboard.latin.utils.SubtypeUtilsKt; -import java.util.Arrays; import java.util.List; import java.util.Locale; @@ -43,13 +41,7 @@ import java.util.Locale; */ // Non-final for testing via mock library. public class SettingsValues { - private static final String TAG = SettingsValues.class.getSimpleName(); - // "floatMaxValue" and "floatNegativeInfinity" are special marker strings for - // Float.NEGATIVE_INFINITE and Float.MAX_VALUE. Currently used for auto-correction settings. - private static final String FLOAT_MAX_VALUE_MARKER_STRING = "floatMaxValue"; - private static final String FLOAT_NEGATIVE_INFINITY_MARKER_STRING = "floatNegativeInfinity"; public static final float DEFAULT_SIZE_SCALE = 1.0f; // 100% - public static final float AUTO_CORRECTION_DISABLED_THRESHOLD = Float.MAX_VALUE; // From resources: public final SpacingAndPunctuations mSpacingAndPunctuations; @@ -194,8 +186,8 @@ public class SettingsValues { && (mUrlDetectionEnabled || !InputTypeUtils.isUriOrEmailType(mInputAttributes.mInputType)); mCenterSuggestionTextToEnter = prefs.getBoolean(Settings.PREF_CENTER_SUGGESTION_TEXT_TO_ENTER, Defaults.PREF_CENTER_SUGGESTION_TEXT_TO_ENTER); mAutoCorrectionThreshold = mAutoCorrectEnabled - ? readAutoCorrectionThreshold(res, prefs) - : AUTO_CORRECTION_DISABLED_THRESHOLD; + ? prefs.getFloat(Settings.PREF_AUTO_CORRECT_THRESHOLD, Defaults.PREF_AUTO_CORRECT_THRESHOLD) + : Float.MAX_VALUE; mScoreLimitForAutocorrect = (mAutoCorrectionThreshold < 0) ? 600000 // very aggressive : (mAutoCorrectionThreshold < 0.07 ? 800000 : 950000); // aggressive or modest mAutoCorrectShortcuts = prefs.getBoolean(Settings.PREF_AUTOCORRECT_SHORTCUTS, Defaults.PREF_AUTOCORRECT_SHORTCUTS); @@ -342,39 +334,6 @@ public class SettingsValues { return mDisplayOrientation == configuration.orientation; } - // todo: way too complicated - private static float readAutoCorrectionThreshold(final Resources res, - final SharedPreferences prefs) { - final String currentAutoCorrectionSetting = Settings.readAutoCorrectConfidence(prefs, res); - final String[] autoCorrectionThresholdValues = res.getStringArray( - R.array.auto_correction_threshold_values); - // When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off. - final float autoCorrectionThreshold; - try { - final int arrayIndex = Integer.parseInt(currentAutoCorrectionSetting); - if (arrayIndex >= 0 && arrayIndex < autoCorrectionThresholdValues.length) { - final String val = autoCorrectionThresholdValues[arrayIndex]; - if (FLOAT_MAX_VALUE_MARKER_STRING.equals(val)) { - autoCorrectionThreshold = Float.MAX_VALUE; - } else if (FLOAT_NEGATIVE_INFINITY_MARKER_STRING.equals(val)) { - autoCorrectionThreshold = Float.NEGATIVE_INFINITY; - } else { - autoCorrectionThreshold = Float.parseFloat(val); - } - } else { - autoCorrectionThreshold = Float.MAX_VALUE; - } - } catch (final NumberFormatException e) { - // Whenever the threshold settings are correct, never come here. - Log.w(TAG, "Cannot load auto correction threshold setting." - + " currentAutoCorrectionSetting: " + currentAutoCorrectionSetting - + ", autoCorrectionThresholdValues: " - + Arrays.toString(autoCorrectionThresholdValues), e); - return Float.MAX_VALUE; - } - return autoCorrectionThreshold; - } - private static boolean readUseContactsEnabled(final SharedPreferences prefs, final Context context) { final boolean setting = prefs.getBoolean(Settings.PREF_USE_CONTACTS, Defaults.PREF_USE_CONTACTS); if (!setting) return false; diff --git a/app/src/main/java/helium314/keyboard/latin/settings/SubScreenFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/SubScreenFragment.java deleted file mode 100644 index 44b234a34..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/SubScreenFragment.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.app.Activity; -import android.app.backup.BackupManager; -import android.content.Context; -import android.content.SharedPreferences; -import android.content.SharedPreferences.OnSharedPreferenceChangeListener; -import android.os.Build; -import android.os.Bundle; -import helium314.keyboard.latin.utils.Log; - -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; - -/** - * A base abstract class for a {@link PreferenceFragmentCompat} that implements a nested - * {@link PreferenceScreen} of the main preference screen. - */ -public abstract class SubScreenFragment extends PreferenceFragmentCompat - implements OnSharedPreferenceChangeListener { - private OnSharedPreferenceChangeListener mSharedPreferenceChangeListener; - - static void setPreferenceVisible(final String prefKey, final boolean visible, - final PreferenceScreen screen) { - final Preference preference = screen.findPreference(prefKey); - if (preference != null) { - preference.setVisible(visible); - } - } - - static void removePreference(final String prefKey, final PreferenceScreen screen) { - final Preference preference = screen.findPreference(prefKey); - if (preference != null && !screen.removePreference(preference)) { - final int count = screen.getPreferenceCount(); - for (int i = 0; i < count; i++) { - final Preference pref = screen.getPreference(i); - if (pref instanceof PreferenceCategory - && ((PreferenceCategory) pref).removePreference(preference)) - break; - } - } - } - - final void setPreferenceVisible(final String prefKey, final boolean visible) { - setPreferenceVisible(prefKey, visible, getPreferenceScreen()); - } - - final void removePreference(final String prefKey) { - removePreference(prefKey, getPreferenceScreen()); - } - - final SharedPreferences getSharedPreferences() { - return getPreferenceManager().getSharedPreferences(); - } - - @Override - public void onCreatePreferences(final Bundle savedInstanceState, final String s) { - // this must be overridden, but is useless, because it's called during onCreate - // so there is no possibility of calling setStorageDeviceProtected before this is called... - } - - @Override - public void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - getPreferenceManager().setStorageDeviceProtected(); - } - mSharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() { - @Override - public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - final SubScreenFragment fragment = SubScreenFragment.this; - final Context context = fragment.getActivity(); - if (context == null || fragment.getPreferenceScreen() == null) { - final String tag = fragment.getClass().getSimpleName(); - // TODO: Introduce a static function to register this class and ensure that - // onCreate must be called before "onSharedPreferenceChanged" is called. - Log.w(tag, "onSharedPreferenceChanged called before activity starts."); - return; - } - new BackupManager(context).dataChanged(); - fragment.onSharedPreferenceChanged(prefs, key); - } - }; - getSharedPreferences().registerOnSharedPreferenceChangeListener( - mSharedPreferenceChangeListener); - } - - @Override - public void onResume() { - super.onResume(); - final Activity activity = getActivity(); - if (activity instanceof AppCompatActivity) { - final ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar(); - final PreferenceScreen ps = getPreferenceScreen(); - if (ps == null) return; - final CharSequence screenTitle = ps.getTitle(); - if (actionBar != null && screenTitle != null) { - actionBar.setTitle(screenTitle); - } - } - } - - @Override - public void onDestroy() { - getSharedPreferences().unregisterOnSharedPreferenceChangeListener( - mSharedPreferenceChangeListener); - super.onDestroy(); - } - - @Override - public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { - // This method may be overridden by an extended class. - } - - // for fixing the indent appearing with androidx preferences - // we don't have icons in subscreens, so we don't want indent - // should also be possible in xml, but didn't find a way to have it in a theme/style - @Override - public void setPreferenceScreen(PreferenceScreen preferenceScreen) { - super.setPreferenceScreen(preferenceScreen); - if (preferenceScreen == null) return; - int count = preferenceScreen.getPreferenceCount(); - for (int i = 0; i < count; i++) { - final Preference pref = preferenceScreen.getPreference(i); - pref.setIconSpaceReserved(false); - if (pref instanceof PreferenceCategory) { - final int subPrefCount = ((PreferenceCategory) pref).getPreferenceCount(); - for (int j = 0; j < subPrefCount; j++) { - ((PreferenceCategory) pref).getPreference(j).setIconSpaceReserved(false); - } - } - } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/ToolbarSettingsFragment.kt b/app/src/main/java/helium314/keyboard/latin/settings/ToolbarSettingsFragment.kt deleted file mode 100644 index b34821271..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/ToolbarSettingsFragment.kt +++ /dev/null @@ -1,68 +0,0 @@ -package helium314.keyboard.latin.settings - -import android.content.SharedPreferences -import android.os.Bundle -import androidx.preference.Preference -import helium314.keyboard.keyboard.KeyboardSwitcher -import helium314.keyboard.keyboard.internal.KeyboardIconsSet -import helium314.keyboard.latin.R -import helium314.keyboard.latin.utils.defaultClipboardToolbarPref -import helium314.keyboard.latin.utils.defaultPinnedToolbarPref -import helium314.keyboard.latin.utils.defaultToolbarPref -import helium314.keyboard.latin.utils.reorderDialog - -class ToolbarSettingsFragment : SubScreenFragment() { - private var reloadKeyboard = false - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - val iconsSet = KeyboardIconsSet.instance - iconsSet.loadIcons(requireContext()) - addPreferencesFromResource(R.xml.prefs_screen_toolbar) - - findPreference(Settings.PREF_TOOLBAR_KEYS)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - reorderDialog( - requireContext(), Settings.PREF_TOOLBAR_KEYS, defaultToolbarPref, - R.string.toolbar_keys - ) { iconsSet.getNewDrawable(it, requireContext()) } - true - } - findPreference(Settings.PREF_PINNED_TOOLBAR_KEYS)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - reorderDialog( - requireContext(), Settings.PREF_PINNED_TOOLBAR_KEYS, defaultPinnedToolbarPref, - R.string.pinned_toolbar_keys - ) { iconsSet.getNewDrawable(it, requireContext()) } - true - } - findPreference(Settings.PREF_CLIPBOARD_TOOLBAR_KEYS)?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - reorderDialog( - requireContext(), Settings.PREF_CLIPBOARD_TOOLBAR_KEYS, defaultClipboardToolbarPref, - R.string.clipboard_toolbar_keys - ) { iconsSet.getNewDrawable(it, requireContext()) } - true - } - findPreference("customize_key_codes")?.onPreferenceClickListener = - Preference.OnPreferenceClickListener { - //toolbarKeysCustomizer(requireContext()) - true - } - } - - override fun onPause() { - super.onPause() - if (reloadKeyboard) - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) - reloadKeyboard = false - } - - override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String?) { - if (key == null) return - when (key) { - Settings.PREF_TOOLBAR_KEYS, Settings.PREF_CLIPBOARD_TOOLBAR_KEYS, Settings.PREF_PINNED_TOOLBAR_KEYS, - Settings.PREF_QUICK_PIN_TOOLBAR_KEYS -> reloadKeyboard = true - } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordContents.java b/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordContents.java deleted file mode 100644 index 237325b9f..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordContents.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.ContentResolver; -import android.content.Context; -import android.database.Cursor; -import android.os.Build; -import android.os.Bundle; -import android.os.LocaleList; -import android.provider.UserDictionary; -import android.text.TextUtils; -import android.text.method.DigitsKeyListener; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import helium314.keyboard.compat.ConfigurationCompatKt; -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.common.LocaleUtils; - -import java.util.ArrayList; -import java.util.Locale; -import java.util.TreeSet; - -public class UserDictionaryAddWordContents { - public static final String EXTRA_MODE = "mode"; - public static final String EXTRA_WORD = "word"; - public static final String EXTRA_WEIGHT = "weight"; - public static final String EXTRA_SHORTCUT = "shortcut"; - public static final String EXTRA_LOCALE = "locale"; - - public static final int MODE_EDIT = 0; // To modify a word - public static final int MODE_INSERT = 1; // To add a new or modified word - - static final int CODE_WORD_ADDED = 0; - static final int CODE_CANCEL = 1; - static final int CODE_UPDATED = 2; - static final int CODE_ALREADY_PRESENT = 3; - - public static final int WEIGHT_FOR_USER_DICTIONARY_ADDS = 250; - - private int mMode; // Either MODE_EDIT or MODE_INSERT - private final EditText mWordEditText; - private final EditText mShortcutEditText; - private final EditText mWeightEditText; - private Locale mLocale; - private final String mOldWord; - private final String mOldShortcut; - private final String mOldWeight; - private String mSavedWord; - private String mSavedShortcut; - private String mSavedWeight; - private Context mContext; - - UserDictionaryAddWordContents(final View view, final Bundle args) { - mWordEditText = view.findViewById(R.id.user_dictionary_add_word_text); - mWordEditText.requestFocus(); - mShortcutEditText = view.findViewById(R.id.user_dictionary_add_shortcut); - mWeightEditText = view.findViewById(R.id.user_dictionary_add_weight); - mWeightEditText.setKeyListener(DigitsKeyListener.getInstance("0123456789")); - final Button deleteWordButton = view.findViewById(R.id.user_dictionary_delete_button); - - final String word = args.getString(EXTRA_WORD); - if (null != word) { - mWordEditText.setText(word); - // Use getText in case the edit text modified the text we set. This happens when - // it's too long to be edited. - mWordEditText.setSelection(mWordEditText.getText().length()); - } - - final String shortcut = args.getString(EXTRA_SHORTCUT); - if (null != shortcut) { - mShortcutEditText.setText(shortcut); - } - mOldShortcut = args.getString(EXTRA_SHORTCUT); - - final String weight = args.getString(EXTRA_WEIGHT); - if (null != weight) { - mWeightEditText.setText(weight); - } - - mMode = args.getInt(EXTRA_MODE); - if (mMode == MODE_EDIT) { - deleteWordButton.setVisibility(View.VISIBLE); - } else if (mMode == MODE_INSERT) { - deleteWordButton.setVisibility(View.INVISIBLE); - } - - mOldWord = args.getString(EXTRA_WORD); - mOldWeight = args.getString(EXTRA_WEIGHT); - final String extraLocale = args.getString(EXTRA_LOCALE); - updateLocale(mContext, extraLocale == null ? null : LocaleUtils.constructLocale(extraLocale)); - } - - UserDictionaryAddWordContents(final View view, final UserDictionaryAddWordContents oldInstanceToBeEdited) { - mWordEditText = view.findViewById(R.id.user_dictionary_add_word_text); - mShortcutEditText = view.findViewById(R.id.user_dictionary_add_shortcut); - mWeightEditText = view.findViewById(R.id.user_dictionary_add_weight); - - mOldWord = oldInstanceToBeEdited.mSavedWord; - mOldShortcut = oldInstanceToBeEdited.mSavedShortcut; - mOldWeight = oldInstanceToBeEdited.mSavedWeight; - updateLocale(mContext, mLocale); - } - - // locale may be null, this means system locale - // It may also be the empty string, which means "For all languages" - void updateLocale(final Context context, @Nullable final Locale locale) { - mContext = context; - - mLocale = null == locale - ? ConfigurationCompatKt.locale(mContext.getResources().getConfiguration()) - : locale; - // The keyboard uses the language layout of the user dictionary - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - mWordEditText.setImeHintLocales(new LocaleList(mLocale)); - } - - } - - Locale getLocale() { - return mLocale; - } - - void delete(final Context context) { - // do nothing if mode is wrong or word is empty - if (MODE_EDIT != mMode || TextUtils.isEmpty(mOldWord)) - return; - final ContentResolver resolver = context.getContentResolver(); - // Remove the old entry. - UserDictionarySettings.deleteWordInEditMode(mOldWord, mOldShortcut, mOldWeight, mLocale, resolver); - } - - public final int apply(@NonNull final Context context) { - final ContentResolver resolver = context.getContentResolver(); - final String newWord = mWordEditText.getText().toString(); - - if (TextUtils.isEmpty(newWord)) { - // If the word is empty, don't insert it. - return CODE_CANCEL; - } - - mSavedShortcut = mShortcutEditText.getText().toString(); - if (TextUtils.isEmpty(mSavedShortcut)) { - mSavedShortcut = null; - } - - mSavedWeight = mWeightEditText.getText().toString(); - if (TextUtils.isEmpty(mSavedWeight)) { - mSavedWeight = String.valueOf(WEIGHT_FOR_USER_DICTIONARY_ADDS); - } - - mSavedWord = newWord; - - // In edit mode, everything is modified without overwriting other existing words - if (MODE_EDIT == mMode && hasWord(newWord, mLocale, context) && newWord.equals(mOldWord)) { - UserDictionarySettings.deleteWordInEditMode(mOldWord, mOldShortcut, mOldWeight, mLocale, resolver); - } else { - mMode = MODE_INSERT; - } - - if (mMode == MODE_INSERT && hasWord(newWord, mLocale, context)) { - return CODE_ALREADY_PRESENT; - } - - if (mMode == MODE_INSERT) { - // Delete duplicate when adding or updating new word - UserDictionarySettings.deleteWordInEditMode(mOldWord, mOldShortcut, mOldWeight, mLocale, resolver); - // Update the existing word by adding a new one - UserDictionary.Words.addWord(context, newWord, Integer.parseInt(mSavedWeight), - mSavedShortcut, TextUtils.isEmpty(mLocale.toString()) ? null : mLocale); - - return CODE_UPDATED; - } - - // Delete duplicates - UserDictionarySettings.deleteWord(newWord, mLocale, resolver); - - // In this class we use the empty string to represent 'all locales' and mLocale cannot - // be null. However the addWord method takes null to mean 'all locales'. - UserDictionary.Words.addWord(context, newWord, Integer.parseInt(mSavedWeight), - mSavedShortcut, mLocale.equals(UserDictionarySettings.emptyLocale) ? null : mLocale); - - return CODE_WORD_ADDED; - } - - public boolean isExistingWord(final Context context) { - final String newWord = mWordEditText.getText().toString(); - if (mMode != MODE_EDIT) { - return hasWord(newWord, mLocale, context); - } else { - return false; - } - } - - private static final String[] HAS_WORD_PROJECTION = { UserDictionary.Words.WORD, UserDictionary.Words.LOCALE }; - private static final String HAS_WORD_AND_LOCALE_SELECTION = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.LOCALE + "=?"; - private static final String HAS_WORD_AND_ALL_LOCALES_SELECTION = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.LOCALE + " is null"; - - private boolean hasWord(final String word, final Locale locale, final Context context) { - final Cursor cursor; - - if (locale.equals(UserDictionarySettings.emptyLocale)) { - cursor = context.getContentResolver().query(UserDictionary.Words.CONTENT_URI, - HAS_WORD_PROJECTION, HAS_WORD_AND_ALL_LOCALES_SELECTION, - new String[] { word }, null); - } else { - // requires use of locale string for interaction with Android system - cursor = context.getContentResolver().query(UserDictionary.Words.CONTENT_URI, - HAS_WORD_PROJECTION, HAS_WORD_AND_LOCALE_SELECTION, - new String[] { word, locale.toString()}, null); - } - try { - if (null == cursor) return false; - return cursor.getCount() > 0; - } finally { - if (null != cursor) cursor.close(); - } - } - - public static class LocaleRenderer { - private final String mLocaleString; - private final String mDescription; - private final Locale mLocale; - - public LocaleRenderer(final Context context, @NonNull final Locale locale) { - mLocaleString = locale.toString(); - mLocale = locale; - - if ("".equals(locale.toString())) { - mDescription = context.getString(R.string.user_dict_settings_all_languages); - } else { - mDescription = UserDictionarySettings.getLocaleDisplayName(context, locale); - } - } - @Override - // used in ArrayAdapter of spinner in UserDictionaryAddWordFragment - public String toString() { - return mDescription; - } - public String getLocaleString() { - return mLocaleString; - } - public Locale getLocale() { - return mLocale; - } - - } - - private static void addLocaleDisplayNameToList(final Context context, - final ArrayList list, final Locale locale) { - if (null != locale) { - list.add(new LocaleRenderer(context, locale)); - } - } - - // Helper method to get the list of locales and subtypes to display for this word - public ArrayList getLocaleRendererList(final Context context) { - final TreeSet sortedLocales = UserDictionaryListFragment.getSortedDictionaryLocales(context); - - // mLocale is removed from the language list as it will be added to the top of the list - sortedLocales.remove(mLocale); - // "For all languages" is removed from the language list as it will be added at the end of the list - sortedLocales.remove(UserDictionarySettings.emptyLocale); - - // final list of locales to show - final ArrayList localesList = new ArrayList<>(); - // First, add the language of the personal dictionary at the top of the list - addLocaleDisplayNameToList(context, localesList, mLocale); - - // Next, add all other languages which will be sorted alphabetically in UserDictionaryAddWordFragment.updateSpinner() - for (Locale locale : sortedLocales) { - addLocaleDisplayNameToList(context, localesList, locale); - } - - // Finally, add "All languages" at the end of the list - if (!mLocale.equals(UserDictionarySettings.emptyLocale)) { - addLocaleDisplayNameToList(context, localesList, UserDictionarySettings.emptyLocale); - } - - return localesList; - } - -} \ No newline at end of file diff --git a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordFragment.java deleted file mode 100644 index 6574239d3..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryAddWordFragment.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.Context; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.EditText; -import android.widget.Spinner; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AlertDialog; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.content.ContextCompat; -import androidx.core.graphics.drawable.DrawableKt; -import androidx.core.widget.TextViewKt; - -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.common.LocaleUtils; -import helium314.keyboard.latin.settings.UserDictionaryAddWordContents.LocaleRenderer; - -import java.util.ArrayList; -import java.util.Collections; - -/** - * Fragment to add a word/shortcut to the user dictionary. - * As opposed to the UserDictionaryActivity, this is only invoked within Settings - * from the UserDictionarySettings. - */ -public class UserDictionaryAddWordFragment extends SubScreenFragment { - - private UserDictionaryAddWordContents mContents; - private View mRootView; - private EditText mWordEditText; - private EditText mWeightEditText; - private InputMethodManager mInput; - private ActionBar mActionBar; - private String mLocaleDisplayString; - - @NonNull - @Override - public View onCreateView(final LayoutInflater inflater, final ViewGroup container, - final Bundle savedState) { - mRootView = inflater.inflate(R.layout.user_dictionary_add_word_fullscreen, null); - // If we have a non-null mContents object, it's the old value before a configuration - // change (eg rotation) so we need to use its values. Otherwise, read from the arguments. - if (null == mContents) { - mContents = new UserDictionaryAddWordContents(mRootView, getArguments()); - } else { - // We create a new mContents object to account for the new situation : a word has - // been added to the user dictionary when we started rotating, and we are now editing - // it. That means in particular if the word undergoes any change, the old version should - // be updated, so the mContents object needs to switch to EDIT mode if it was in - // INSERT mode. - mContents = new UserDictionaryAddWordContents(mRootView, mContents); - } - - mWordEditText = mRootView.findViewById(R.id.user_dictionary_add_word_text); - mWeightEditText = mRootView.findViewById(R.id.user_dictionary_add_weight); - - final Bundle args = getArguments(); - mActionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar(); - mLocaleDisplayString = UserDictionarySettings.getLocaleDisplayName(requireContext(), mContents.getLocale()); - if (args != null && mActionBar != null) { - if (args.getInt(UserDictionaryAddWordContents.EXTRA_MODE) == UserDictionaryAddWordContents.MODE_EDIT) { - mActionBar.setTitle(R.string.user_dict_settings_edit_dialog_title); - } else { - mActionBar.setTitle(R.string.user_dict_settings_add_dialog_title); - } - mActionBar.setSubtitle(mLocaleDisplayString); - } - - final Button saveWordButton = mRootView.findViewById(R.id.user_dictionary_save_button); - saveWordButton.setOnClickListener(v -> addWord()); - - TextViewKt.doAfterTextChanged(mWordEditText, (editable) -> { - final int visibility = TextUtils.isEmpty(editable.toString()) ? View.INVISIBLE : View.VISIBLE; - saveWordButton.setVisibility(visibility); - return null; - }); - saveWordButton.setVisibility(TextUtils.isEmpty(mWordEditText.getText().toString()) ? View.INVISIBLE : View.VISIBLE); - - final Button deleteWordButton = mRootView.findViewById(R.id.user_dictionary_delete_button); - final Drawable deleteWordIcon = toScaledBitmapDrawable(R.drawable.ic_bin, 0.75f); - deleteWordButton.setCompoundDrawablesWithIntrinsicBounds(null, null, deleteWordIcon, null); - deleteWordButton.setOnClickListener(v -> { - mContents.delete(requireContext()); - requireActivity().onBackPressed(); - }); - - return mRootView; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - // Automatically display the keyboard when we want to add or modify a word - mInput = (InputMethodManager) requireContext().getSystemService(Context.INPUT_METHOD_SERVICE); - mInput.showSoftInput(mWordEditText, InputMethodManager.SHOW_IMPLICIT); - - // Add a word using the Enter key - mWeightEditText.setOnEditorActionListener((v, actionId, event) -> { - if (actionId == EditorInfo.IME_ACTION_DONE) { - addWord(); - } - return false; - }); - } - - @Override - public void onResume() { - super.onResume(); - // We are being shown: display the word - updateSpinner(); - } - - // The bin icon is too big compared to the plus icon; we need to reduce it. - // We therefore need to convert the drawable image to a BitmapDrawable. - private BitmapDrawable toScaledBitmapDrawable(int drawableResId, float scale) { - final Drawable drawable = ContextCompat.getDrawable(requireContext(), drawableResId); - if (drawable == null) return null; - return new BitmapDrawable(getResources(), DrawableKt.toBitmap(drawable, - (int) (scale * drawable.getIntrinsicHeight()), (int) (scale * drawable.getIntrinsicWidth()), null)); - } - - private void addWord() { - if (mContents.isExistingWord(requireContext())) { - new AlertDialog.Builder(requireContext()) - .setMessage(getString(R.string.user_dict_word_already_present, mLocaleDisplayString)) - .setPositiveButton(android.R.string.ok, (dialog, which) -> - mInput.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_IMPLICIT_ONLY)) - .show(); - - mWordEditText.requestFocus(); - - } else if (!mWordEditText.getText().toString().isEmpty()) { - mContents.apply(requireContext()); - requireActivity().onBackPressed(); - } - } - - private void updateSpinner() { - final ArrayList localesList = mContents.getLocaleRendererList(requireContext()); - - final Spinner localeSpinner = mRootView.findViewById(R.id.user_dictionary_add_locale); - final ArrayAdapter adapter = new ArrayAdapter<>( - requireContext(), android.R.layout.simple_spinner_item, localesList); - adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); - localeSpinner.setAdapter(adapter); - localeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { - @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) { - final LocaleRenderer localeRenderer = (LocaleRenderer)parent.getItemAtPosition(position); - - mContents.updateLocale(requireContext(), localeRenderer.getLocale()); - // To have the selected language at the top of the list, this one is removed from the list - localesList.remove(position); - // The other languages are then sorted alphabetically by name, with the exception of "For all languages" - Collections.sort(localesList, (localeRenderer1, localeRenderer2) -> { - if (!localeRenderer1.getLocale().equals(UserDictionarySettings.emptyLocale) && !localeRenderer2.getLocale().equals(UserDictionarySettings.emptyLocale)) { - return localeRenderer1.toString().compareToIgnoreCase(localeRenderer2.toString()); - } else { - return localeRenderer1.getLocaleString().compareToIgnoreCase(localeRenderer2.getLocaleString()); - } - }); - - // Set "For all languages" to the end of the list - if (!localeRenderer.getLocale().equals(UserDictionarySettings.emptyLocale)) { - // After alphabetical sorting, "For all languages" is always in 1st position. - // (The position is 0 because the spinner menu item count starts at 0) - final LocaleRenderer forAllLanguages = adapter.getItem(0); - // So we delete its entry ... - localesList.remove(forAllLanguages); - // ... and we set it at the end of the list. - localesList.add(localesList.size(), forAllLanguages); - } - - // Finally, we add the selected language to the top of the list. - localesList.add(0, localeRenderer); - - // When a language is selected, the keyboard layout changes automatically - mInput.restartInput(mWordEditText); - - // The action bar subtitle is updated when a language is selected in the drop-down menu - mActionBar.setSubtitle(localeRenderer.toString()); - } - - @Override - public void onNothingSelected(AdapterView parent) { - // I'm not sure we can come here, but if we do, that's the right thing to do. - final Bundle args = getArguments(); - if (args == null) return; - final String localeString = args.getString(UserDictionaryAddWordContents.EXTRA_LOCALE); - mContents.updateLocale(requireContext(), localeString == null ? null : LocaleUtils.constructLocale(localeString)); - } - }); - } - -} \ No newline at end of file diff --git a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryListFragment.java b/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryListFragment.java deleted file mode 100644 index 247569927..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionaryListFragment.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.Context; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.inputmethod.InputMethodSubtype; -import android.widget.Button; -import android.widget.LinearLayout; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.preference.Preference; -import androidx.preference.PreferenceGroup; - -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.utils.KtxKt; -import helium314.keyboard.latin.utils.SubtypeLocaleUtils; -import helium314.keyboard.latin.utils.SubtypeSettings; -import helium314.keyboard.latin.utils.SubtypeUtilsKt; - -import java.util.Comparator; -import java.util.List; -import java.util.Locale; -import java.util.TreeSet; - -public class UserDictionaryListFragment extends SubScreenFragment { - - // TODO : Implement the import/export function in these menus - /*private static final int OPTIONS_MENU_EXPORT = Menu.NONE; - private static final int OPTIONS_MENU_IMPORT = Menu.NONE;*/ - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setPreferenceScreen(getPreferenceManager().createPreferenceScreen(requireContext())); - - createUserDictSettings(getPreferenceScreen()); - // TODO : Uncomment to create the import/export function in the menu - //setHasOptionsMenu(true); - } - - @Override - public void onResume() { - super.onResume(); - final ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar(); - if (actionBar != null) { - actionBar.setTitle(R.string.edit_personal_dictionary); - actionBar.setSubtitle(null); - } - } - - @NonNull - @Override - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - LinearLayout view = (LinearLayout) super.onCreateView(inflater, container, savedInstanceState); - View v = inflater.inflate(R.layout.user_dictionary_settings_list_fragment, null); - Button addWordButton = v.findViewById(R.id.user_dictionary_add_word_button); - addWordButton.setOnClickListener(v1 -> showAddWordFragment()); - view.addView(v); - return view; - } - - // TODO : Implement the import/export function in these menus -/* @Override - public void onCreateOptionsMenu(Menu menu, @NonNull MenuInflater inflater) { - *//*menu.add(0, OPTIONS_MENU_EXPORT, 0, R.string.button_backup); - menu.add(0, OPTIONS_MENU_IMPORT, 0, R.string.button_restore);*//* - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == OPTIONS_MENU_EXPORT) { - return true; - } - if (item.getItemId() == OPTIONS_MENU_IMPORT) { - return true; - } - - return false; - }*/ - - /** - * Creates the entries that allow the user to go into the user dictionary for each locale. - * @param userDictGroup The group to put the settings in. - */ - private void createUserDictSettings(final PreferenceGroup userDictGroup) { - final TreeSet sortedLocales = getSortedDictionaryLocales(requireContext()); - - // Add preference "for all locales" - userDictGroup.addPreference(createUserDictionaryPreference(UserDictionarySettings.emptyLocale)); - // Add preference for each dictionary locale - for (final Locale locale : sortedLocales) { - userDictGroup.addPreference(createUserDictionaryPreference(locale)); - } - } - - static TreeSet getSortedDictionaryLocales(final Context context) { - final SharedPreferences prefs = KtxKt.prefs(context); - final TreeSet sortedLocales = new TreeSet<>(new LocaleComparator()); - - // Add the main language selected in the "Language and Layouts" setting except "No language" - for (InputMethodSubtype mainSubtype : SubtypeSettings.INSTANCE.getEnabledSubtypes(true)) { - final Locale mainLocale = SubtypeUtilsKt.locale(mainSubtype); - if (!mainLocale.toLanguageTag().equals(SubtypeLocaleUtils.NO_LANGUAGE)) { - sortedLocales.add(mainLocale); - } - // Secondary language is added only if main language is selected and if system language is not enabled - final List enabled = SubtypeSettings.INSTANCE.getEnabledSubtypes(false); - for (InputMethodSubtype subtype : enabled) { - if (SubtypeUtilsKt.locale(subtype).equals(mainLocale)) - sortedLocales.addAll(SubtypeUtilsKt.getSecondaryLocales(subtype.getExtraValue())); - } - } - - sortedLocales.addAll(SubtypeSettings.INSTANCE.getSystemLocales()); - return sortedLocales; - } - - private static class LocaleComparator implements Comparator { - @Override - public int compare(Locale locale1, Locale locale2) { - return locale1.toLanguageTag().compareToIgnoreCase(locale2.toLanguageTag()); - } - } - - /** - * Create a single User Dictionary Preference object, with its parameters set. - * @param locale The locale for which this user dictionary is for. - * @return The corresponding preference. - */ - private Preference createUserDictionaryPreference(@NonNull final Locale locale) { - final Preference newPref = new Preference(requireContext()); - - if (locale.toString().isEmpty()) { - newPref.setTitle(getString(R.string.user_dict_settings_all_languages)); - } else { - newPref.setTitle(UserDictionarySettings.getLocaleDisplayName(requireContext(), locale)); - } - if (locale == UserDictionarySettings.emptyLocale) newPref.getExtras().putString("locale", ""); - else newPref.getExtras().putString("locale", locale.toLanguageTag()); - newPref.setIconSpaceReserved(false); - newPref.setFragment(UserDictionarySettings.class.getName()); - - return newPref; - } - - private void showAddWordFragment() { - final Bundle args = new Bundle(); - args.putInt(UserDictionaryAddWordContents.EXTRA_MODE, UserDictionaryAddWordContents.MODE_INSERT); - args.putString(UserDictionaryAddWordContents.EXTRA_WORD, ""); - args.putString(UserDictionaryAddWordContents.EXTRA_SHORTCUT, ""); - args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, ""); // Empty means "For all languages" - AppCompatActivity activity = (AppCompatActivity) requireActivity(); - activity.getSupportFragmentManager().beginTransaction() - .replace(android.R.id.content, UserDictionaryAddWordFragment.class, args) - .addToBackStack(null) - .commit(); - } - -} \ No newline at end of file diff --git a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionarySettings.java b/app/src/main/java/helium314/keyboard/latin/settings/UserDictionarySettings.java deleted file mode 100644 index f019286e6..000000000 --- a/app/src/main/java/helium314/keyboard/latin/settings/UserDictionarySettings.java +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.settings; - -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.database.Cursor; -import android.os.Bundle; -import android.provider.UserDictionary; -import android.text.TextUtils; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.AlphabetIndexer; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.SectionIndexer; -import android.widget.SimpleCursorAdapter; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.fragment.app.ListFragment; - -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.common.LocaleUtils; - -import java.util.Locale; - -public class UserDictionarySettings extends ListFragment { - static final Locale emptyLocale = new Locale(""); - private static final String[] QUERY_PROJECTION = - { UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT, UserDictionary.Words.FREQUENCY }; - - // The index of the shortcut in the above array (1 is used for the words) - private static final int INDEX_SHORTCUT = 2; - private static final int INDEX_WEIGHT = 3; - - private static final String[] ADAPTER_FROM = { - UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT, UserDictionary.Words.FREQUENCY - }; - - private static final int[] ADAPTER_TO = { - R.id.user_dictionary_item_word, R.id.user_dictionary_item_shortcut - }; - - // Either the locale is empty (means the word is applicable to all locales) - // or the word equals our current locale - private static final String QUERY_SELECTION = UserDictionary.Words.LOCALE + "=?"; - private static final String QUERY_SELECTION_ALL_LOCALES = UserDictionary.Words.LOCALE + " is null"; - - private static final String DELETE_SELECTION_WITH_SHORTCUT_AND_WITH_LOCALE = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.SHORTCUT + "=? AND " - + UserDictionary.Words.FREQUENCY + "=? AND " - + UserDictionary.Words.LOCALE + "=?"; - - private static final String DELETE_SELECTION_WITH_SHORTCUT_AND_WITH_ALL_LOCALES = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.SHORTCUT + "=? AND " - + UserDictionary.Words.FREQUENCY + "=? AND " - + UserDictionary.Words.LOCALE + " is null"; - - private static final String DELETE_SELECTION_WITHOUT_SHORTCUT_AND_WITH_LOCALE = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.SHORTCUT + " is null AND " - + UserDictionary.Words.FREQUENCY + "=? AND " - + UserDictionary.Words.LOCALE + "=? OR " - - + UserDictionary.Words.SHORTCUT + "='' AND " - + UserDictionary.Words.FREQUENCY + "=? AND " - + UserDictionary.Words.LOCALE + "=?"; - - private static final String DELETE_SELECTION_WITHOUT_SHORTCUT_AND_WITH_ALL_LOCALES = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.SHORTCUT + " is null AND " - + UserDictionary.Words.FREQUENCY + "=? AND " - + UserDictionary.Words.LOCALE + " is null OR " - - + UserDictionary.Words.SHORTCUT + "='' AND " - + UserDictionary.Words.FREQUENCY + "=? AND " - + UserDictionary.Words.LOCALE + " is null"; - - private static final String DELETE_WORD_AND_LOCALE = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.LOCALE + "=?"; - - private static final String DELETE_WORD_AND_ALL_LOCALES = UserDictionary.Words.WORD + "=? AND " - + UserDictionary.Words.LOCALE + " is null"; - - private Cursor mCursor; - - protected Locale mLocale; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar(); - if (actionBar == null) return; - actionBar.setTitle(R.string.edit_personal_dictionary); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - LinearLayout view = (LinearLayout) inflater.inflate(R.layout.user_dictionary_settings_list_fragment, container, false); - Button addWordButton = view.findViewById(R.id.user_dictionary_add_word_button); - addWordButton.setOnClickListener(v -> showAddOrEditFragment(null, null, null)); - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - final Intent intent = requireActivity().getIntent(); - final String localeFromIntent = null == intent ? null : intent.getStringExtra("locale"); - - final Bundle arguments = getArguments(); - final String localeFromArguments = null == arguments ? null : arguments.getString("locale"); - - final String localeString; - if (null != localeFromArguments) { - localeString = localeFromArguments; - } else localeString = localeFromIntent; - mLocale = localeString == null ? null : LocaleUtils.constructLocale(localeString); - - createCursor(mLocale == null ? null : mLocale); - TextView emptyView = view.findViewById(android.R.id.empty); - emptyView.setText(R.string.user_dict_settings_empty_text); - - final ListView listView = getListView(); - listView.setAdapter(createAdapter()); - listView.setFastScrollEnabled(true); - listView.setEmptyView(emptyView); - - final ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar(); - if (actionBar == null) return; - actionBar.setTitle(R.string.edit_personal_dictionary); - actionBar.setSubtitle(getLocaleDisplayName(requireContext(), mLocale)); - } - - @Override - public void onResume() { - super.onResume(); - final ActionBar actionBar = ((AppCompatActivity) requireActivity()).getSupportActionBar(); - if (actionBar == null) return; - - ListAdapter adapter = getListView().getAdapter(); - if (adapter instanceof MyAdapter listAdapter) { - // The list view is forced refreshed here. This allows the changes done - // in UserDictionaryAddWordFragment (update/delete/insert) to be seen when - // user goes back to this view. - listAdapter.notifyDataSetChanged(); - } - } - - private void createCursor(@Nullable final Locale locale) { - // locale can be any of: - // - An actual locale, for use of Locale#toString() - // - The emptyLocale. This means we want a cursor returning words valid for all locales. - // - null. This means we want a cursor for the current locale, whatever this is. - - // Note that this contrasts with the data inside the database, where NULL means "all - // locales" and there should never be an empty string. - // The confusion is called by the historical use of null for "all locales". - - // TODO: it should be easy to make this more readable by making the special values - // human-readable, like "all_locales" and "current_locales" strings, provided they - // can be guaranteed not to match locales that may exist. - - if (emptyLocale.equals(locale)) { - // Case-insensitive sort - mCursor = requireContext().getContentResolver().query(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, - QUERY_SELECTION_ALL_LOCALES, null, - "UPPER(" + UserDictionary.Words.WORD + ")"); - } else { - // requires use of locale string for interaction with Android system - final String queryLocaleString = null != locale ? locale.toString() : Locale.getDefault().toString(); - mCursor = requireContext().getContentResolver().query(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, - QUERY_SELECTION, new String[] { queryLocaleString }, - "UPPER(" + UserDictionary.Words.WORD + ")"); - } - } - - private ListAdapter createAdapter() { - return new MyAdapter(requireContext(), R.layout.user_dictionary_item, mCursor, - ADAPTER_FROM, ADAPTER_TO); - } - - @Override - public void onListItemClick(@NonNull ListView l, @NonNull View v, int position, long id) { - final String word = getWord(position); - final String shortcut = getShortcut(position); - final String weight = getWeight(position); - if (word != null) { - showAddOrEditFragment(word, shortcut, weight); - } - } - - public static String getLocaleDisplayName(Context context, Locale locale) { - if (locale.equals(UserDictionarySettings.emptyLocale)) { - // CAVEAT: localeStr should not be null because a null locale stands for the system - // locale in UserDictionary.Words.addWord. - return context.getResources().getString(R.string.user_dict_settings_all_languages); - } - return LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context); - } - - /** - * Add or edit a word. If editingWord is null, it's an add; otherwise, it's an edit. - * @param editingWord the word to edit, or null if it's an add. - * @param editingShortcut the shortcut for this entry, or null if none. - */ - private void showAddOrEditFragment(final String editingWord, final String editingShortcut, final String editingWeight) { - final Bundle args = new Bundle(); - args.putInt(UserDictionaryAddWordContents.EXTRA_MODE, null == editingWord - ? UserDictionaryAddWordContents.MODE_INSERT - : UserDictionaryAddWordContents.MODE_EDIT); - args.putString(UserDictionaryAddWordContents.EXTRA_WORD, editingWord); - args.putString(UserDictionaryAddWordContents.EXTRA_SHORTCUT, editingShortcut); - args.putString(UserDictionaryAddWordContents.EXTRA_WEIGHT, editingWeight); - args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale.equals(emptyLocale) ? "" : mLocale.toLanguageTag()); - AppCompatActivity activity = (AppCompatActivity) requireActivity(); - activity.getSupportFragmentManager().beginTransaction() - .replace(android.R.id.content, UserDictionaryAddWordFragment.class, args) - .addToBackStack(null) - .commit(); - } - - private String getWord(final int position) { - return getEntry(position, UserDictionary.Words.WORD); - } - - private String getShortcut(final int position) { - return getEntry(position, UserDictionary.Words.SHORTCUT); - } - - private String getWeight(final int position) { - return getEntry(position, UserDictionary.Words.FREQUENCY); - } - - private String getEntry(final int position, final String column) { - if (null == mCursor) return null; - mCursor.moveToPosition(position); - // Handle a possible race-condition - if (mCursor.isAfterLast()) return null; - - return mCursor.getString(mCursor.getColumnIndexOrThrow(column)); - } - - public static void deleteWordInEditMode(final String word, final String shortcut, final String weight, - final Locale locale, final ContentResolver resolver) { - if (TextUtils.isEmpty(shortcut)) { - if (locale.equals(UserDictionarySettings.emptyLocale)) { - resolver.delete( - UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITHOUT_SHORTCUT_AND_WITH_ALL_LOCALES, - new String[] { word, weight }); - } else { - resolver.delete( - // requires use of locale string for interaction with Android system - UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITHOUT_SHORTCUT_AND_WITH_LOCALE, - new String[] { word, weight, locale.toString() }); - } - } else { - if (locale.equals(UserDictionarySettings.emptyLocale)) { - resolver.delete( - UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITH_SHORTCUT_AND_WITH_ALL_LOCALES, - new String[] { word, shortcut, weight }); - } else { - resolver.delete( - // requires use of locale string for interaction with Android system - UserDictionary.Words.CONTENT_URI, DELETE_SELECTION_WITH_SHORTCUT_AND_WITH_LOCALE, - new String[] { word, shortcut, weight, locale.toString() }); - } - } - } - - public static void deleteWord(final String word, final Locale locale, final ContentResolver resolver) { - if (locale.equals(UserDictionarySettings.emptyLocale)) { - resolver.delete( - UserDictionary.Words.CONTENT_URI, DELETE_WORD_AND_ALL_LOCALES, - new String[] { word }); - } else { - resolver.delete( - UserDictionary.Words.CONTENT_URI, DELETE_WORD_AND_LOCALE, - new String[] { word, locale.toString() }); - } - } - - private class MyAdapter extends SimpleCursorAdapter implements SectionIndexer { - private AlphabetIndexer mIndexer; - - private final ViewBinder mViewBinder = (v, c, columnIndex) -> { - final String weightTitle = String.format(getString(R.string.user_dict_settings_add_weight_value)); - final String weightText = c.getString(INDEX_WEIGHT); - final String weight = weightTitle + " " + weightText; - - final String shortcutTitle = String.format(getString(R.string.user_dict_settings_add_shortcut_option_name)); - final String shortcutText = c.getString(INDEX_SHORTCUT); - final String shortcut = shortcutTitle + " " + shortcutText; - - final String weightAndShortcut = weight + " | " + shortcut; - - if (columnIndex == INDEX_SHORTCUT) { - if (TextUtils.isEmpty(shortcutText)) { - ((TextView)v).setText(weight); - } else { - ((TextView)v).setText(weightAndShortcut); - } - v.invalidate(); - return true; - } - - return false; - }; - - public MyAdapter(final Context context, final int layout, final Cursor c, - final String[] from, final int[] to) { - super(context, layout, c, from, to, 0 /* flags */); - - if (null != c) { - final String alphabet = context.getString(R.string.user_dict_fast_scroll_alphabet); - final int wordColIndex = c.getColumnIndexOrThrow(UserDictionary.Words.WORD); - mIndexer = new AlphabetIndexer(c, wordColIndex, alphabet); - } - setViewBinder(mViewBinder); - } - - @Override - public int getPositionForSection(final int section) { - return null == mIndexer ? 0 : mIndexer.getPositionForSection(section); - } - - @Override - public int getSectionForPosition(final int position) { - return null == mIndexer ? 0 : mIndexer.getSectionForPosition(position); - } - - @Override - public Object[] getSections() { - return null == mIndexer ? null : mIndexer.getSections(); - } - } -} \ No newline at end of file diff --git a/app/src/main/java/helium314/keyboard/latin/setup/SetupActivity.java b/app/src/main/java/helium314/keyboard/latin/setup/SetupActivity.java deleted file mode 100644 index 5474f00fb..000000000 --- a/app/src/main/java/helium314/keyboard/latin/setup/SetupActivity.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.setup; - -import android.app.Activity; -import android.content.Intent; -import android.os.Bundle; -import android.view.inputmethod.InputMethodManager; - -import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils; -import helium314.keyboard.settings.SettingsActivity; - -public final class SetupActivity extends Activity { - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final Intent intent = new Intent(); - final InputMethodManager imm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); -// if (UncachedInputMethodManagerUtils.isThisImeCurrent(this, imm)) - intent.setClass(this, SettingsActivity.class); -// else intent.setClass(this, SetupWizardActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP - | Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - if (!isFinishing()) { - finish(); - } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/setup/SetupStartIndicatorView.java b/app/src/main/java/helium314/keyboard/latin/setup/SetupStartIndicatorView.java deleted file mode 100644 index bab9415d8..000000000 --- a/app/src/main/java/helium314/keyboard/latin/setup/SetupStartIndicatorView.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.setup; - -import android.content.Context; -import android.content.res.ColorStateList; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.LinearLayout; - -import helium314.keyboard.latin.R; - -import androidx.annotation.NonNull; -import androidx.appcompat.content.res.AppCompatResources; -import androidx.appcompat.widget.AppCompatTextView; - -public final class SetupStartIndicatorView extends LinearLayout { - public SetupStartIndicatorView(final Context context, final AttributeSet attrs) { - super(context, attrs); - setOrientation(HORIZONTAL); - LayoutInflater.from(context).inflate(R.layout.setup_start_indicator_label, this); - - final LabelView labelView = findViewById(R.id.setup_start_label); - labelView.setIndicatorView(findViewById(R.id.setup_start_indicator)); - } - - public static final class LabelView extends AppCompatTextView { - private View mIndicatorView; - - public LabelView(final Context context, final AttributeSet attrs) { - super(context, attrs); - } - - public void setIndicatorView(final View indicatorView) { - mIndicatorView = indicatorView; - } - - @Override - public void setPressed(final boolean pressed) { - super.setPressed(pressed); - updateIndicatorView(pressed); - } - - private void updateIndicatorView(final boolean pressed) { - if (mIndicatorView != null) { - mIndicatorView.setPressed(pressed); - mIndicatorView.invalidate(); - } - } - } - - public static final class IndicatorView extends View { - private final Path mIndicatorPath = new Path(); - private final Paint mIndicatorPaint = new Paint(); - private final ColorStateList mIndicatorColor; - - public IndicatorView(final Context context, final AttributeSet attrs) { - super(context, attrs); - mIndicatorColor = AppCompatResources.getColorStateList(context, R.color.setup_step_action_background); - mIndicatorPaint.setStyle(Paint.Style.FILL); - } - - @Override - protected void onDraw(@NonNull final Canvas canvas) { - super.onDraw(canvas); - final int layoutDirection = getLayoutDirection(); - final int width = getWidth(); - final int height = getHeight(); - final float halfHeight = height / 2.0f; - final Path path = mIndicatorPath; - path.rewind(); - if (layoutDirection == View.LAYOUT_DIRECTION_RTL) { - // Left arrow - path.moveTo(width, 0.0f); - path.lineTo(0.0f, halfHeight); - path.lineTo(width, height); - } else { // LAYOUT_DIRECTION_LTR - // Right arrow - path.moveTo(0.0f, 0.0f); - path.lineTo(width, halfHeight); - path.lineTo(0.0f, height); - } - path.close(); - final int[] stateSet = getDrawableState(); - final int color = mIndicatorColor.getColorForState(stateSet, 0); - mIndicatorPaint.setColor(color); - canvas.drawPath(path, mIndicatorPaint); - } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/setup/SetupStepIndicatorView.java b/app/src/main/java/helium314/keyboard/latin/setup/SetupStepIndicatorView.java deleted file mode 100644 index 320c0fe48..000000000 --- a/app/src/main/java/helium314/keyboard/latin/setup/SetupStepIndicatorView.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.setup; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Path; -import android.util.AttributeSet; -import android.view.View; - -import androidx.annotation.NonNull; - -import helium314.keyboard.latin.R; - -public final class SetupStepIndicatorView extends View { - private final Path mIndicatorPath = new Path(); - private final Paint mIndicatorPaint = new Paint(); - private float mXRatio; - - public SetupStepIndicatorView(final Context context, final AttributeSet attrs) { - super(context, attrs); - mIndicatorPaint.setColor(getResources().getColor(R.color.setup_step_background)); - mIndicatorPaint.setStyle(Paint.Style.FILL); - } - - public void setIndicatorPosition(final int stepPos, final int totalStepNum) { - final int layoutDirection = getLayoutDirection(); - // The indicator position is the center of the partition that is equally divided into - // the total step number. - final float partionWidth = 1.0f / totalStepNum; - final float pos = stepPos * partionWidth + partionWidth / 2.0f; - mXRatio = (layoutDirection == View.LAYOUT_DIRECTION_RTL) ? 1.0f - pos : pos; - invalidate(); - } - - @Override - protected void onDraw(@NonNull final Canvas canvas) { - super.onDraw(canvas); - final int xPos = (int)(getWidth() * mXRatio); - final int height = getHeight(); - mIndicatorPath.rewind(); - mIndicatorPath.moveTo(xPos, 0); - mIndicatorPath.lineTo(xPos + height, height); - mIndicatorPath.lineTo(xPos - height, height); - mIndicatorPath.close(); - canvas.drawPath(mIndicatorPath, mIndicatorPaint); - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/setup/SetupWizardActivity.java b/app/src/main/java/helium314/keyboard/latin/setup/SetupWizardActivity.java deleted file mode 100644 index 32a77e809..000000000 --- a/app/src/main/java/helium314/keyboard/latin/setup/SetupWizardActivity.java +++ /dev/null @@ -1,434 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * modified - * SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - */ - -package helium314.keyboard.latin.setup; - -import android.content.Intent; -import android.content.res.ColorStateList; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Message; -import android.provider.Settings; -import android.view.View; -import android.view.inputmethod.InputMethodManager; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.appcompat.app.ActionBar; -import androidx.appcompat.app.AppCompatActivity; -import androidx.appcompat.content.res.AppCompatResources; -import androidx.core.content.ContextCompat; -import androidx.core.content.res.ResourcesCompat; -import androidx.core.graphics.drawable.DrawableCompat; - -import helium314.keyboard.latin.R; -import helium314.keyboard.latin.utils.ActivityThemeUtils; -import helium314.keyboard.latin.utils.JniUtils; -import helium314.keyboard.latin.utils.LeakGuardHandlerWrapper; -import helium314.keyboard.latin.utils.ResourceUtils; -import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils; -import helium314.keyboard.settings.SettingsActivity; - -import java.util.ArrayList; - -public final class SetupWizardActivity extends AppCompatActivity implements View.OnClickListener { - // For debugging purpose. - private static final boolean FORCE_TO_SHOW_WELCOME_SCREEN = false; - - private InputMethodManager mImm; - - private View mSetupWizard; - private View mWelcomeScreen; - private View mSetupScreen; - private View mActionStart; - private TextView mActionNext; - private TextView mStep1Bullet; - private TextView mActionFinish; - private SetupStepGroup mSetupStepGroup; - private static final String STATE_STEP = "step"; - private int mStepNumber; - private boolean mNeedsToAdjustStepNumberToSystemState; - private static final int STEP_WELCOME = 0; - private static final int STEP_1 = 1; - private static final int STEP_2 = 2; - private static final int STEP_3 = 3; - private static final int STEP_LAUNCHING_IME_SETTINGS = 4; - private static final int STEP_BACK_FROM_IME_SETTINGS = 5; - - private SettingsPoolingHandler mHandler; - - private static final class SettingsPoolingHandler - extends LeakGuardHandlerWrapper { - private static final int MSG_POLLING_IME_SETTINGS = 0; - private static final long IME_SETTINGS_POLLING_INTERVAL = 200; - - private final InputMethodManager mImmInHandler; - - public SettingsPoolingHandler(@NonNull final SetupWizardActivity ownerInstance, - final InputMethodManager imm) { - super(ownerInstance); - mImmInHandler = imm; - } - - @Override - public void handleMessage(@NonNull final Message msg) { - final SetupWizardActivity setupWizardActivity = getOwnerInstance(); - if (setupWizardActivity == null) { - return; - } - if (msg.what == MSG_POLLING_IME_SETTINGS) { - if (UncachedInputMethodManagerUtils.isThisImeEnabled(setupWizardActivity, - mImmInHandler)) { - setupWizardActivity.invokeSetupWizardOfThisIme(); - return; - } - startPollingImeSettings(); - } - } - - public void startPollingImeSettings() { - sendMessageDelayed(obtainMessage(MSG_POLLING_IME_SETTINGS), - IME_SETTINGS_POLLING_INTERVAL); - } - - public void cancelPollingImeSettings() { - removeMessages(MSG_POLLING_IME_SETTINGS); - } - } - - @Override - protected void onCreate(final Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - final ActionBar actionBar = getSupportActionBar(); - if (actionBar != null) { - actionBar.hide(); - } - getWindow().setStatusBarColor(getResources().getColor(R.color.setup_background)); - ActivityThemeUtils.setActivityTheme(this); - - mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); - mHandler = new SettingsPoolingHandler(this, mImm); - setContentView(R.layout.setup_wizard); - mSetupWizard = findViewById(R.id.setup_wizard); - - if (savedInstanceState == null) { - mStepNumber = determineSetupStepNumberFromLauncher(); - } else { - mStepNumber = savedInstanceState.getInt(STATE_STEP); - } - - final String applicationName = getResources().getString(getApplicationInfo().labelRes); - mWelcomeScreen = findViewById(R.id.setup_welcome_screen); - final TextView welcomeTitle = findViewById(R.id.setup_welcome_title); - welcomeTitle.setText(getString(R.string.setup_welcome_title, applicationName)); - - // disable the "with gesture typing" when no library is available (at this point, this likely means library is in system and this is a system app) - if (!JniUtils.sHaveGestureLib) - ((TextView) findViewById(R.id.setup_welcome_description)).setText(""); - - mSetupScreen = findViewById(R.id.setup_steps_screen); - final TextView stepsTitle = findViewById(R.id.setup_title); - stepsTitle.setText(getString(R.string.setup_steps_title, applicationName)); - - final SetupStepIndicatorView indicatorView = findViewById(R.id.setup_step_indicator); - mSetupStepGroup = new SetupStepGroup(indicatorView); - - mStep1Bullet = findViewById(R.id.setup_step1_bullet); - mStep1Bullet.setOnClickListener(this); - final SetupStep step1 = new SetupStep(STEP_1, applicationName, - mStep1Bullet, findViewById(R.id.setup_step1), - R.string.setup_step1_title, R.string.setup_step1_instruction, - R.string.setup_step1_finished_instruction, R.drawable.ic_setup_key, - R.string.setup_step1_action); - final SettingsPoolingHandler handler = mHandler; - step1.setAction(() -> { - invokeLanguageAndInputSettings(); - handler.startPollingImeSettings(); - }); - mSetupStepGroup.addStep(step1); - - final SetupStep step2 = new SetupStep(STEP_2, applicationName, - findViewById(R.id.setup_step2_bullet), findViewById(R.id.setup_step2), - R.string.setup_step2_title, R.string.setup_step2_instruction, - 0 /* finishedInstruction */, R.drawable.ic_setup_select, - R.string.setup_step2_action); - step2.setAction(this::invokeInputMethodPicker); - mSetupStepGroup.addStep(step2); - - final SetupStep step3 = new SetupStep(STEP_3, applicationName, - findViewById(R.id.setup_step3_bullet), findViewById(R.id.setup_step3), - R.string.setup_step3_title, R.string.setup_step3_instruction, - 0 /* finishedInstruction */, R.drawable.sym_keyboard_language_switch, - R.string.setup_step3_action); - step3.setAction(() -> { - final Intent intent = new Intent(getApplicationContext(), SettingsActivity.class); - intent.setAction(Intent.ACTION_VIEW); - startActivity(intent); - finish(); - }); - mSetupStepGroup.addStep(step3); - - mActionStart = findViewById(R.id.setup_start_label); - mActionStart.setOnClickListener(this); - - mActionNext = findViewById(R.id.setup_next); - mActionNext.setOnClickListener(this); - - mActionFinish = findViewById(R.id.setup_finish); - final Drawable finishDrawable = ContextCompat.getDrawable(this, R.drawable.ic_setup_check); - if (finishDrawable == null) { - return; - } - DrawableCompat.setTintList(finishDrawable, step1.mTextColorStateList); - mActionFinish.setCompoundDrawablesRelativeWithIntrinsicBounds(finishDrawable, null, null, null); - mActionFinish.setOnClickListener(this); - } - - @Override - public void onClick(final View v) { - if (v == mActionFinish) { - finish(); - return; - } - final int currentStep = determineSetupStepNumber(); - final int nextStep; - if (v == mActionStart) { - nextStep = STEP_1; - } else if (v == mActionNext) { - nextStep = mStepNumber + 1; - } else if (v == mStep1Bullet && currentStep == STEP_2) { - nextStep = STEP_1; - } else { - nextStep = mStepNumber; - } - if (mStepNumber != nextStep) { - mStepNumber = nextStep; - updateSetupStepView(); - } - } - - void invokeSetupWizardOfThisIme() { - final Intent intent = new Intent(); - intent.setClass(this, SetupWizardActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED - | Intent.FLAG_ACTIVITY_SINGLE_TOP - | Intent.FLAG_ACTIVITY_CLEAR_TOP); - startActivity(intent); - mNeedsToAdjustStepNumberToSystemState = true; - } - - private void invokeSettingsOfThisIme() { - final Intent intent = new Intent(); - intent.setClass(this, SettingsActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED - | Intent.FLAG_ACTIVITY_CLEAR_TOP); -// intent.putExtra(OldSettingsActivity.EXTRA_ENTRY_KEY, -// OldSettingsActivity.EXTRA_ENTRY_VALUE_APP_ICON); - startActivity(intent); - } - - void invokeLanguageAndInputSettings() { - final Intent intent = new Intent(); - intent.setAction(Settings.ACTION_INPUT_METHOD_SETTINGS); - intent.addCategory(Intent.CATEGORY_DEFAULT); - startActivity(intent); - mNeedsToAdjustStepNumberToSystemState = true; - } - - void invokeInputMethodPicker() { - // Invoke input method picker. - mImm.showInputMethodPicker(); - mNeedsToAdjustStepNumberToSystemState = true; - } - - private int determineSetupStepNumberFromLauncher() { - final int stepNumber = determineSetupStepNumber(); - if (stepNumber == STEP_1) { - return STEP_WELCOME; - } - if (stepNumber == STEP_3) { - return STEP_LAUNCHING_IME_SETTINGS; - } - return stepNumber; - } - - private int determineSetupStepNumber() { - mHandler.cancelPollingImeSettings(); - if (FORCE_TO_SHOW_WELCOME_SCREEN) { - return STEP_1; - } - if (!UncachedInputMethodManagerUtils.isThisImeEnabled(this, mImm)) { - return STEP_1; - } - if (!UncachedInputMethodManagerUtils.isThisImeCurrent(this, mImm)) { - return STEP_2; - } - return STEP_3; - } - - @Override - protected void onSaveInstanceState(@NonNull final Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(STATE_STEP, mStepNumber); - } - - @Override - protected void onRestoreInstanceState(@NonNull final Bundle savedInstanceState) { - super.onRestoreInstanceState(savedInstanceState); - mStepNumber = savedInstanceState.getInt(STATE_STEP); - } - - private static boolean isInSetupSteps(final int stepNumber) { - return stepNumber >= STEP_1 && stepNumber <= STEP_3; - } - - @Override - protected void onRestart() { - super.onRestart(); - // Probably the setup wizard has been invoked from "Recent" menu. The setup step number - // needs to be adjusted to system state, because the state (IME is enabled and/or current) - // may have been changed. - if (isInSetupSteps(mStepNumber)) { - mStepNumber = determineSetupStepNumber(); - } - } - - @Override - protected void onResume() { - super.onResume(); - if (mStepNumber == STEP_LAUNCHING_IME_SETTINGS) { - // Prevent white screen flashing while launching settings activity. - mSetupWizard.setVisibility(View.INVISIBLE); - invokeSettingsOfThisIme(); - mStepNumber = STEP_BACK_FROM_IME_SETTINGS; - return; - } - if (mStepNumber == STEP_BACK_FROM_IME_SETTINGS) { - finish(); - return; - } - updateSetupStepView(); - } - - @Override - public void onBackPressed() { - if (mStepNumber == STEP_1) { - mStepNumber = STEP_WELCOME; - updateSetupStepView(); - return; - } - super.onBackPressed(); - } - - @Override - public void onWindowFocusChanged(final boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - if (hasFocus && mNeedsToAdjustStepNumberToSystemState) { - mNeedsToAdjustStepNumberToSystemState = false; - mStepNumber = determineSetupStepNumber(); - updateSetupStepView(); - } - } - - private void updateSetupStepView() { - mSetupWizard.setVisibility(View.VISIBLE); - final boolean welcomeScreen = (mStepNumber == STEP_WELCOME); - mWelcomeScreen.setVisibility(welcomeScreen ? View.VISIBLE : View.GONE); - mSetupScreen.setVisibility(welcomeScreen ? View.GONE : View.VISIBLE); - if (welcomeScreen) { - return; - } - final boolean isStepActionAlreadyDone = mStepNumber < determineSetupStepNumber(); - mSetupStepGroup.enableStep(mStepNumber, isStepActionAlreadyDone); - mActionNext.setVisibility(isStepActionAlreadyDone ? View.VISIBLE : View.GONE); - mActionFinish.setVisibility((mStepNumber == STEP_3) ? View.VISIBLE : View.GONE); - } - - static final class SetupStep implements View.OnClickListener { - public final int mStepNo; - private final View mStepView; - private final TextView mBulletView; - private final ColorStateList mTextColorStateList; - private final String mInstruction; - private final String mFinishedInstruction; - private final TextView mActionLabel; - private Runnable mAction; - - public SetupStep(final int stepNo, final String applicationName, final TextView bulletView, - final View stepView, final int title, final int instruction, - final int finishedInstruction, final int actionIcon, final int actionLabel) { - mStepNo = stepNo; - mStepView = stepView; - mBulletView = bulletView; - final Resources res = stepView.getResources(); - mTextColorStateList = AppCompatResources.getColorStateList(mStepView.getContext(), R.color.setup_step_action_text); - - final TextView titleView = mStepView.findViewById(R.id.setup_step_title); - titleView.setText(res.getString(title, applicationName)); - - mInstruction = (instruction == 0) ? null : res.getString(instruction, applicationName); - mFinishedInstruction = (finishedInstruction == 0) ? null : res.getString(finishedInstruction, applicationName); - - mActionLabel = mStepView.findViewById(R.id.setup_step_action_label); - mActionLabel.setText(res.getString(actionLabel)); - final Drawable actionIconDrawable = ResourcesCompat.getDrawable(res, actionIcon, null); - if (actionIconDrawable == null) { - return; - } - DrawableCompat.setTintList(actionIconDrawable, mTextColorStateList); - if (actionIcon == 0) { - final int paddingEnd = mActionLabel.getPaddingEnd(); - mActionLabel.setPaddingRelative(paddingEnd, 0, paddingEnd, 0); - } else { - final int size = ResourceUtils.toPx(24, res); - actionIconDrawable.setBounds(0,0, size, size); - mActionLabel.setCompoundDrawablesRelative(actionIconDrawable, null, null, null); - } - } - - public void setEnabled(final boolean enabled, final boolean isStepActionAlreadyDone) { - mStepView.setVisibility(enabled ? View.VISIBLE : View.GONE); - mBulletView.setTextColor(enabled - ? mBulletView.getContext().getResources().getColor(R.color.setup_step_action_text_pressed) - : mBulletView.getContext().getResources().getColor(R.color.setup_text_action)); - final TextView instructionView = mStepView.findViewById(R.id.setup_step_instruction); - instructionView.setText(isStepActionAlreadyDone ? mFinishedInstruction : mInstruction); - mActionLabel.setVisibility(isStepActionAlreadyDone ? View.GONE : View.VISIBLE); - } - - public void setAction(final Runnable action) { - mActionLabel.setOnClickListener(this); - mAction = action; - } - - @Override - public void onClick(final View v) { - if (v == mActionLabel && mAction != null) - mAction.run(); - } - } - - static final class SetupStepGroup { - private final SetupStepIndicatorView mIndicatorView; - private final ArrayList mGroup = new ArrayList<>(); - - public SetupStepGroup(final SetupStepIndicatorView indicatorView) { - mIndicatorView = indicatorView; - } - - public void addStep(final SetupStep step) { - mGroup.add(step); - } - - public void enableStep(final int enableStepNo, final boolean isStepActionAlreadyDone) { - for (final SetupStep step : mGroup) { - step.setEnabled(step.mStepNo == enableStepNo, isStepActionAlreadyDone); - } - mIndicatorView.setIndicatorPosition(enableStepNo - STEP_1, mGroup.size()); - } - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java b/app/src/main/java/helium314/keyboard/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java index 264fe4e69..94cd176d8 100644 --- a/app/src/main/java/helium314/keyboard/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java +++ b/app/src/main/java/helium314/keyboard/latin/spellcheck/AndroidWordLevelSpellCheckerSession.java @@ -38,6 +38,7 @@ import helium314.keyboard.latin.utils.SubtypeSettings; import helium314.keyboard.latin.utils.SuggestionResults; import java.util.ArrayList; +import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; @@ -394,7 +395,7 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { return new Result(null /* gatheredSuggestions */, false /* hasRecommendedSuggestions */); } - final ArrayList suggestions = new ArrayList<>(); + final LinkedHashSet suggestionsSet = new LinkedHashSet<>(); for (final SuggestedWordInfo suggestedWordInfo : suggestionResults) { final String suggestion; if (StringUtils.CAPITALIZE_ALL == capitalizeType) { @@ -405,15 +406,15 @@ public abstract class AndroidWordLevelSpellCheckerSession extends Session { } else { suggestion = suggestedWordInfo.mWord; } - suggestions.add(suggestion); + suggestionsSet.add(suggestion); } - StringUtils.removeDupes(suggestions); + final ArrayList suggestions = new ArrayList<>(suggestionsSet); // This returns a String[], while toArray() returns an Object[] which cannot be cast // into a String[]. final List gatheredSuggestionsList = suggestions.subList(0, Math.min(suggestions.size(), suggestionsLimit)); final String[] gatheredSuggestions = - gatheredSuggestionsList.toArray(new String[gatheredSuggestionsList.size()]); + gatheredSuggestionsList.toArray(new String[0]); final int bestScore = suggestionResults.first().mScore; final String bestSuggestion = suggestions.get(0); diff --git a/app/src/main/java/helium314/keyboard/latin/spellcheck/SpellCheckerSettingsActivity.kt b/app/src/main/java/helium314/keyboard/latin/spellcheck/SpellCheckerSettingsActivity.kt index ff5f37c7b..af0a22ea2 100644 --- a/app/src/main/java/helium314/keyboard/latin/spellcheck/SpellCheckerSettingsActivity.kt +++ b/app/src/main/java/helium314/keyboard/latin/spellcheck/SpellCheckerSettingsActivity.kt @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-3.0-only package helium314.keyboard.latin.spellcheck +import android.app.Activity import android.content.Intent import android.os.Bundle -import androidx.activity.ComponentActivity import helium314.keyboard.settings.SettingsActivity -// the Settings in SettingsContainer expect to be in a SettingsActivity, so we use a simple way of getting there -class SpellCheckerSettingsActivity : ComponentActivity() { +class SpellCheckerSettingsActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) val intent = Intent() diff --git a/app/src/main/java/helium314/keyboard/latin/utils/ActivityThemeUtils.java b/app/src/main/java/helium314/keyboard/latin/utils/ActivityThemeUtils.java deleted file mode 100644 index a82963f9a..000000000 --- a/app/src/main/java/helium314/keyboard/latin/utils/ActivityThemeUtils.java +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only -package helium314.keyboard.latin.utils; - -import android.app.Activity; -import android.os.Build; -import android.view.View; -import android.view.WindowInsetsController; - -public class ActivityThemeUtils { - - public static void setActivityTheme(final Activity activity) { - final boolean isNight = ResourceUtils.isNight(activity.getResources()); - - // Set the icons of the status bar and the navigation bar light or dark - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - final WindowInsetsController controller = activity.getWindow().getInsetsController(); - if (controller != null && !isNight) { - controller.setSystemBarsAppearance(WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS); - controller.setSystemBarsAppearance(WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS, WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS); - } - } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - final View view = activity.getWindow().getDecorView(); - view.setSystemUiVisibility(!isNight ? View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0); - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DebugLogUtils.java b/app/src/main/java/helium314/keyboard/latin/utils/DebugLogUtils.java index 275d75f75..3ae833454 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DebugLogUtils.java +++ b/app/src/main/java/helium314/keyboard/latin/utils/DebugLogUtils.java @@ -36,18 +36,4 @@ public final class DebugLogUtils { } return sb.toString(); } - - /** - * Get the stack trace contained in an exception as a human-readable string. - * @param t the throwable - * @return the human-readable stack trace - */ - public static String getStackTrace(final Throwable t) { - final StringBuilder sb = new StringBuilder(); - final StackTraceElement[] frames = t.getStackTrace(); - for (int j = 0; j < frames.length; ++j) { - sb.append(frames[j].toString() + "\n"); - } - return sb.toString(); - } } diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DeviceProtectedUtils.java b/app/src/main/java/helium314/keyboard/latin/utils/DeviceProtectedUtils.java index 3d5a1d475..a3ab79ded 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DeviceProtectedUtils.java +++ b/app/src/main/java/helium314/keyboard/latin/utils/DeviceProtectedUtils.java @@ -10,8 +10,6 @@ import android.content.Context; import android.content.SharedPreferences; import android.os.Build; -import androidx.preference.PreferenceManager; - import java.io.File; public final class DeviceProtectedUtils { @@ -23,11 +21,11 @@ public final class DeviceProtectedUtils { if (prefs != null) return prefs; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - prefs = PreferenceManager.getDefaultSharedPreferences(context); + prefs = getDefaultSharedPreferences(context); return prefs; } final Context deviceProtectedContext = getDeviceProtectedContext(context); - prefs = PreferenceManager.getDefaultSharedPreferences(deviceProtectedContext); + prefs = getDefaultSharedPreferences(deviceProtectedContext); if (prefs.getAll() == null) return prefs; // happens for compose previews if (prefs.getAll().isEmpty()) { @@ -45,6 +43,11 @@ public final class DeviceProtectedUtils { else return ctx; } + private static SharedPreferences getDefaultSharedPreferences(Context context) { + // from androidx.preference.PreferenceManager + return context.getSharedPreferences(context.getPackageName() + "_preferences", Context.MODE_PRIVATE); + } + public static File getFilesDir(final Context context) { return getDeviceProtectedContext(context).getFilesDir(); } diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DialogUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/DialogUtils.kt index de56e4441..470743bbb 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DialogUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/DialogUtils.kt @@ -1,136 +1,12 @@ package helium314.keyboard.latin.utils import android.content.Context -import android.graphics.PorterDuff -import android.graphics.drawable.Drawable -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import android.widget.ImageView -import android.widget.Switch -import android.widget.TextView -import androidx.annotation.StringRes -import androidx.appcompat.app.AlertDialog import androidx.appcompat.view.ContextThemeWrapper -import androidx.core.content.ContextCompat -import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ItemTouchHelper -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.ListAdapter -import androidx.recyclerview.widget.RecyclerView import helium314.keyboard.latin.R -import java.util.Collections +// todo: ideally the custom InputMethodPicker would be removed / replaced with compose dialog, then this can be removed fun getPlatformDialogThemeContext(context: Context): Context { // Because {@link AlertDialog.Builder.create()} doesn't honor the specified theme with // createThemeContextWrapper=false, the result dialog box has unneeded paddings around it. return ContextThemeWrapper(context, R.style.platformActivityTheme) } - -fun confirmDialog(context: Context, message: String, confirmButton: String, onConfirmed: (() -> Unit)) { - AlertDialog.Builder(context) - .setMessage(message) - .setNegativeButton(android.R.string.cancel, null) - .setPositiveButton(confirmButton) { _, _ -> onConfirmed() } - .show() -} - -fun infoDialog(context: Context, messageId: Int) { - AlertDialog.Builder(context) - .setMessage(messageId) - .setNegativeButton(android.R.string.ok, null) - .show() -} - -fun infoDialog(context: Context, message: String) { - AlertDialog.Builder(context) - .setMessage(message) - .setNegativeButton(android.R.string.ok, null) - .show() -} - -/** - * Show a dialog that allows re-ordering and dis/enabling items (currently toolbar keys and popup keys). - * The items are stored in a string pref in [key]. Each item contains a name and true/false, comma-separated. - * Items are semicolon-separated, see e.g. [POPUP_KEYS_LABEL_DEFAULT] for an example. - */ -// this should probably be a class -fun reorderDialog( - context: Context, - key: String, - defaultSetting: String, - @StringRes dialogTitleId: Int, - getIcon: (String) -> Drawable? = { null } -) { - val prefs = context.prefs() - val orderedItems = prefs.getString(key, defaultSetting)!!.split(";").mapTo(ArrayList()) { - val both = it.split(",") - both.first() to both.last().toBoolean() - } - val rv = RecyclerView(context) - val bgColor = ContextCompat.getColor(context, R.color.sliding_items_background) - val fgColor = ContextCompat.getColor(context, R.color.foreground) - val padding = ResourceUtils.toPx(8, context.resources) - rv.setPadding(3 * padding, padding, padding, padding) - rv.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) - - val callback = object : DiffUtil.ItemCallback>() { - override fun areItemsTheSame(p0: Pair, p1: Pair) = p0 == p1 - override fun areContentsTheSame(p0: Pair, p1: Pair) = p0 == p1 - } - - val adapter = object : ListAdapter, RecyclerView.ViewHolder>(callback) { - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val b = LayoutInflater.from(context).inflate(R.layout.reorder_dialog_item, rv, false) - b.setBackgroundColor(bgColor) - return object : RecyclerView.ViewHolder(b) { } - } - override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) { - val (text, wasChecked) = orderedItems[position] - val displayText = text.lowercase().getStringResourceOrName("", context) - viewHolder.itemView.findViewById(R.id.reorder_item_name)?.text = displayText - val switch = viewHolder.itemView.findViewById(R.id.reorder_item_switch) - switch?.setOnCheckedChangeListener(null) - switch?.isChecked = wasChecked - switch?.setOnCheckedChangeListener { _, isChecked -> - val pos = orderedItems.indexOfFirst { it.first == text } - orderedItems[pos] = text to isChecked - } - val icon = getIcon(text) - viewHolder.itemView.findViewById(R.id.reorder_item_icon)?.let { - it.visibility = if (icon == null) View.GONE else View.VISIBLE - it.setColorFilter(fgColor, PorterDuff.Mode.SRC_IN) - it.setImageDrawable(icon) - } - } - } - rv.adapter = adapter - - ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(ItemTouchHelper.UP or ItemTouchHelper.DOWN, 0) { - override fun onMove(rv: RecyclerView, viewHolder: RecyclerView.ViewHolder, target: RecyclerView.ViewHolder): Boolean { - val pos1 = viewHolder.absoluteAdapterPosition - val pos2 = target.absoluteAdapterPosition - Collections.swap(orderedItems, pos1, pos2) - adapter.notifyItemMoved(pos1, pos2) - return true - } - override fun onSwiped(rv: RecyclerView.ViewHolder, direction: Int) { } - }).attachToRecyclerView(rv) - - adapter.submitList(orderedItems) - - val builder = AlertDialog.Builder(context) - .setTitle(dialogTitleId) - .setPositiveButton(android.R.string.ok) { _, _ -> - val value = orderedItems.joinToString(";") { it.first + "," + it.second } - prefs.edit().putString(key, value).apply() - } - .setNegativeButton(android.R.string.cancel, null) - .setView(rv) - if (prefs.contains(key)) - builder.setNeutralButton(R.string.button_default) { _, _ -> - prefs.edit().remove(key).apply() - } - - builder.show() -} diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt index 3a38bc757..3bbb310c4 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryUtils.kt @@ -3,10 +3,6 @@ package helium314.keyboard.latin.utils import android.content.Context -import android.text.method.LinkMovementMethod -import android.view.View -import android.widget.TextView -import androidx.appcompat.app.AlertDialog import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext @@ -46,65 +42,6 @@ fun getDictionaryLocales(context: Context): MutableSet { return locales } -fun showMissingDictionaryDialog(context: Context, locale: Locale) { - val prefs = context.prefs() - if (prefs.getBoolean(Settings.PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG, Defaults.PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG) - || locale.toString() == SubtypeLocaleUtils.NO_LANGUAGE) - return - val repositoryLink = "" + context.getString(R.string.dictionary_link_text) + "" - val dictionaryLink = "" + context.getString( - R.string.dictionary_link_text) + "" - val startMessage = context.getString( // todo: now with the available dicts csv, is the full text still necessary? - R.string.no_dictionary_message, - repositoryLink, - locale.toString(), // toString because that's how default AOSP dictionaries are named - dictionaryLink, - ) - val message = createDictionaryTextHtml(startMessage, locale, context) - - val messageSpannable = SpannableStringUtils.fromHtml(message) - val dialog = AlertDialog.Builder(context) - .setTitle(R.string.no_dictionaries_available) - .setMessage(messageSpannable) - .setNegativeButton(R.string.dialog_close, null) - .setNeutralButton(R.string.no_dictionary_dont_show_again_button) { _, _ -> - prefs.edit { putBoolean(Settings.PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG, true) } - } - .create() - dialog.show() - (dialog.findViewById(android.R.id.message) as? TextView)?.movementMethod = LinkMovementMethod.getInstance() -} - -/** returns the [message], and if dictionaries for [locale] or language are available, a links to them */ -fun createDictionaryTextHtml(message: String, locale: Locale, context: Context): String { - val knownDicts = mutableListOf() - context.assets.open("dictionaries_in_dict_repo.csv").reader().forEachLine { - if (it.isBlank()) return@forEachLine - val (type, localeString, experimental) = it.split(",") - // we use a locale string here because that's in the dictionaries repo - // ideally the repo would switch to language tag, but not sure how this is handled in the dictionary header - // further, the dicts in the dictionaries repo should be compatible with other AOSP-based keyboards - val dictLocale = localeString.constructLocale() - if (LocaleUtils.getMatchLevel(locale, dictLocale) < LocaleUtils.LOCALE_GOOD_MATCH) return@forEachLine - val rawDictString = "$type: ${dictLocale.getDisplayName(context.resources.configuration.locale())}" - val dictString = if (experimental.isEmpty()) rawDictString - else context.getString(R.string.available_dictionary_experimental, rawDictString) - val dictBaseUrl = Links.DICTIONARY_URL + Links.DICTIONARY_DOWNLOAD_SUFFIX + - if (experimental.isEmpty()) Links.DICTIONARY_NORMAL_SUFFIX else Links.DICTIONARY_EXPERIMENTAL_SUFFIX - val dictLink = dictBaseUrl + type + "_" + localeString.lowercase() + ".dict" - val fullText = "

  • $dictString
  • " - knownDicts.add(fullText) - } - if (knownDicts.isEmpty()) return message - return """ -

    $message

    - ${context.getString(R.string.dictionary_available)} -
      - ${knownDicts.joinToString("\n")} -
    - """.trimIndent() -} - // why is this so horrible with annotated string? @Composable fun MissingDictionaryDialog(onDismissRequest: () -> Unit, locale: Locale) { diff --git a/app/src/main/java/helium314/keyboard/latin/utils/Ktx.kt b/app/src/main/java/helium314/keyboard/latin/utils/Ktx.kt index 304ad837f..bdd08cfbf 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/Ktx.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/Ktx.kt @@ -1,13 +1,9 @@ package helium314.keyboard.latin.utils -import android.app.Activity import android.content.Context import android.content.ContextWrapper import android.content.SharedPreferences -import android.view.View -import android.widget.RelativeLayout import androidx.activity.ComponentActivity -import androidx.appcompat.app.AppCompatActivity import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.text.AnnotatedString @@ -15,8 +11,6 @@ import androidx.compose.ui.text.LinkAnnotation import androidx.compose.ui.text.SpanStyle import androidx.compose.ui.text.TextLinkStyles import androidx.compose.ui.text.withLink -import androidx.fragment.app.commit -import helium314.keyboard.latin.R // generic extension functions @@ -80,15 +74,6 @@ fun Context.getActivity(): ComponentActivity? { return componentActivity } -// todo: should not be necessary after full pref switch to compose -fun Activity.switchTo(fragment: androidx.fragment.app.Fragment) { - (this as AppCompatActivity).supportFragmentManager.commit { - findViewById(R.id.settingsFragmentContainer).visibility = View.VISIBLE - replace(R.id.settingsFragmentContainer, fragment) - addToBackStack(null) - } -} - /** SharedPreferences from deviceProtectedContext, which are accessible even without unlocking. * They should not be used to store sensitive data! */ fun Context.prefs(): SharedPreferences = DeviceProtectedUtils.getSharedPreferences(this) diff --git a/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt b/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt index 225a9f173..224ebf71c 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/LayoutUtilsCustom.kt @@ -2,12 +2,6 @@ package helium314.keyboard.latin.utils import android.content.Context -import android.net.Uri -import android.provider.OpenableColumns -import android.text.InputType -import android.widget.EditText -import androidx.appcompat.app.AlertDialog -import androidx.core.widget.doAfterTextChanged import helium314.keyboard.keyboard.Key import helium314.keyboard.keyboard.KeyboardId import helium314.keyboard.keyboard.KeyboardLayoutSet @@ -16,8 +10,6 @@ import helium314.keyboard.keyboard.internal.KeyboardParams import helium314.keyboard.keyboard.internal.keyboard_parser.LayoutParser import helium314.keyboard.keyboard.internal.keyboard_parser.POPUP_KEYS_NORMAL import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams -import helium314.keyboard.latin.R -import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.common.decodeBase36 import helium314.keyboard.latin.common.encodeBase36 import helium314.keyboard.latin.settings.Settings @@ -25,63 +17,10 @@ import helium314.keyboard.latin.utils.LayoutType.Companion.folder import helium314.keyboard.latin.utils.ScriptUtils.script import kotlinx.serialization.SerializationException import java.io.File -import java.io.IOException import java.util.EnumMap import java.util.Locale object LayoutUtilsCustom { - fun loadLayout(uri: Uri?, languageTag: String, context: Context, onAdded: (String) -> Unit) { - if (uri == null) - return infoDialog(context, context.getString(R.string.layout_error, "layout file not found")) - val layoutContent: String - try { - val tmpFile = File(context.filesDir.absolutePath + File.separator + "tmpfile") - FileUtils.copyContentUriToNewFile(uri, context, tmpFile) - layoutContent = tmpFile.readText() - tmpFile.delete() - } catch (e: IOException) { - return infoDialog(context, context.getString(R.string.layout_error, "cannot read layout file")) - } - - var name = "" - context.contentResolver.query(uri, null, null, null, null).use { - if (it != null && it.moveToFirst()) { - val idx = it.getColumnIndex(OpenableColumns.DISPLAY_NAME) - if (idx >= 0) - name = it.getString(idx).substringBeforeLast(".") - } - } - loadLayout(layoutContent, name, languageTag, context, onAdded) - } - - fun loadLayout(layoutContent: String, layoutName: String, languageTag: String, context: Context, onAdded: (String) -> Unit) { - var name = layoutName - if (!checkLayout(layoutContent, context)) - return infoDialog(context, context.getString(R.string.layout_error, "invalid layout file, ${Log.getLog(10).lastOrNull { it.tag == TAG }?.message}")) -// val isJson = checkLayout(layoutContent, context) -// ?: return infoDialog(context, context.getString(R.string.layout_error, "invalid layout file, ${Log.getLog(10).lastOrNull { it.tag == TAG }?.message}")) - - AlertDialog.Builder(context) - .setTitle(R.string.title_layout_name_select) - .setView(EditText(context).apply { - setText(name) - doAfterTextChanged { name = it.toString() } - val padding = ResourceUtils.toPx(8, context.resources) - setPadding(3 * padding, padding, 3 * padding, padding) - inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_NORMAL - }) - .setPositiveButton(android.R.string.ok) { _, _ -> - // name must be encoded to avoid issues with validity of subtype extra string or file name - name = "$CUSTOM_LAYOUT_PREFIX${languageTag}.${encodeBase36(name)}." - val file = getLayoutFile(name, LayoutType.MAIN, context) - if (file.exists()) - file.delete() - file.parentFile?.mkdir() - file.writeText(layoutContent) - onAdded(name) - } - .show() - } fun checkLayout(layoutContent: String, context: Context): Boolean { if (Settings.getValues() == null) @@ -204,42 +143,6 @@ object LayoutUtilsCustom { return file } - fun editLayout(layoutName: String, context: Context, startContent: String? = null, displayName: CharSequence? = null) { - val file = getLayoutFile(layoutName, LayoutType.MAIN, context) - val editText = EditText(context).apply { - setText(startContent ?: file.readText()) - } - val builder = AlertDialog.Builder(context) - .setTitle(getDisplayName(layoutName)) - .setView(editText) - .setPositiveButton(R.string.save) { _, _ -> - val content = editText.text.toString() - if (!checkLayout(content, context)) { - editLayout(layoutName, context, content) - infoDialog(context, context.getString(R.string.layout_error, Log.getLog(10).lastOrNull { it.tag == TAG }?.message)) - } else { - file.parentFile?.mkdir() - file.writeText(content) - onLayoutFileChanged() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(context) - } - } - .setNegativeButton(android.R.string.cancel, null) - if (displayName != null) { - if (file.exists()) { - builder.setNeutralButton(R.string.delete) { _, _ -> - confirmDialog(context, context.getString(R.string.delete_layout, displayName), context.getString(R.string.delete)) { - file.delete() - onLayoutFileChanged() - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(context) - } - } - } - builder.setTitle(displayName) - } - builder.show() - } - // this goes into prefs and file names, so do not change! const val CUSTOM_LAYOUT_PREFIX = "custom." private const val TAG = "LayoutUtilsCustom" diff --git a/app/src/main/java/helium314/keyboard/latin/utils/NewDictionaryAdder.kt b/app/src/main/java/helium314/keyboard/latin/utils/NewDictionaryAdder.kt deleted file mode 100644 index 1a5a1a401..000000000 --- a/app/src/main/java/helium314/keyboard/latin/utils/NewDictionaryAdder.kt +++ /dev/null @@ -1,144 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -package helium314.keyboard.latin.utils - -import android.content.Context -import android.content.Intent -import android.net.Uri -import androidx.appcompat.app.AlertDialog -import helium314.keyboard.compat.locale -import helium314.keyboard.dictionarypack.DictionaryPackConstants -import helium314.keyboard.latin.Dictionary -import helium314.keyboard.latin.R -import helium314.keyboard.latin.ReadOnlyBinaryDictionary -import helium314.keyboard.latin.common.FileUtils -import helium314.keyboard.latin.common.LocaleUtils -import helium314.keyboard.latin.common.LocaleUtils.constructLocale -import helium314.keyboard.latin.makedict.DictionaryHeader -import helium314.keyboard.latin.settings.* -import helium314.keyboard.latin.utils.ScriptUtils.script -import java.io.File -import java.io.IOException -import java.util.* - -class NewDictionaryAdder(private val context: Context, private val onAdded: ((Boolean, File) -> Unit)?) { - private val cachedDictionaryFile = File(context.cacheDir.path + File.separator + "temp_dict") - - fun addDictionary(uri: Uri?, mainLocale: Locale?) { - if (uri == null) - return onDictionaryLoadingError(R.string.dictionary_load_error) - - cachedDictionaryFile.delete() - try { - FileUtils.copyContentUriToNewFile(uri, context, cachedDictionaryFile) - } catch (e: IOException) { - return onDictionaryLoadingError(R.string.dictionary_load_error) - } - - val newHeader = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(cachedDictionaryFile, 0, cachedDictionaryFile.length()) - ?: return onDictionaryLoadingError(R.string.dictionary_file_error) - val locale = newHeader.mLocaleString.constructLocale() - - val dict = ReadOnlyBinaryDictionary(cachedDictionaryFile.absolutePath, 0, cachedDictionaryFile.length(), false, locale, "test") - if (!dict.isValidDictionary) { - dict.close() - return onDictionaryLoadingError(R.string.dictionary_load_error) - } - - if (mainLocale == null) { - val localeName = LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context) - val message = context.getString(R.string.add_new_dictionary_ask_locale, - newHeader.mIdString.substringBefore(":"), - localeName - ) - val b = AlertDialog.Builder(context) - .setTitle(R.string.add_new_dictionary_title) - .setMessage(message) - .setNeutralButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() } - .setNegativeButton(R.string.button_select_language) { _, _ -> selectLocaleForDictionary(newHeader, locale) } - if (SubtypeSettings.hasMatchingSubtypeForLocale(locale)) { - val buttonText = context.getString(R.string.button_add_to_language, localeName) - b.setPositiveButton(buttonText) { _, _ -> - addDictAndAskToReplace(newHeader, locale) - } - } - b.show() - return - } - - // ScriptUtils.getScriptFromSpellCheckerLocale may return latin when it should not, - // e.g. for Persian or Chinese. But at least fail when dictionary certainly is incompatible - if (locale.script() != mainLocale.script()) - return onDictionaryLoadingError(R.string.dictionary_file_wrong_script) - - if (locale != mainLocale) { - val message = context.resources.getString( - R.string.dictionary_file_wrong_locale, - LocaleUtils.getLocaleDisplayNameInSystemLocale(locale, context), - LocaleUtils.getLocaleDisplayNameInSystemLocale(mainLocale, context) - ) - AlertDialog.Builder(context) - .setMessage(message) - .setNegativeButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() } - .setPositiveButton(R.string.dictionary_file_wrong_locale_ok) { _, _ -> - addDictAndAskToReplace(newHeader, mainLocale) - } - .show() - return - } - addDictAndAskToReplace(newHeader, mainLocale) - } - - private fun selectLocaleForDictionary(newHeader: DictionaryHeader, dictLocale: Locale) { - val locales = SubtypeSettings.getAvailableSubtypeLocales().sortedBy { it.language != dictLocale.language } // matching languages should show first - val displayNamesArray = locales.map { LocaleUtils.getLocaleDisplayNameInSystemLocale(it, context) }.toTypedArray() - AlertDialog.Builder(context) - .setTitle(R.string.button_select_language) - .setItems(displayNamesArray) { di, i -> - di.dismiss() - locales.forEachIndexed { index, locale -> - if (index == i) - addDictAndAskToReplace(newHeader, locale) - } - } - .setNegativeButton(android.R.string.cancel) { _, _ -> cachedDictionaryFile.delete() } - .show() - } - - private fun addDictAndAskToReplace(header: DictionaryHeader, mainLocale: Locale) { - val dictionaryType = header.mIdString.substringBefore(":") - val cacheDir = DictionaryInfoUtils.getAndCreateCacheDirectoryForLocale(mainLocale, context) - val dictFile = File(cacheDir, dictionaryType + "_" + DictionaryInfoUtils.USER_DICTIONARY_SUFFIX) - - fun moveDict(replaced: Boolean) { - if (!cachedDictionaryFile.renameTo(dictFile)) { - return onDictionaryLoadingError(R.string.dictionary_load_error) - } - if (dictionaryType == Dictionary.TYPE_MAIN) { - // replaced main dict, remove the one created from internal data - val internalMainDictFile = File(cacheDir, DictionaryInfoUtils.getExtractedMainDictFilename()) - internalMainDictFile.delete() - } - val newDictBroadcast = Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION) - context.sendBroadcast(newDictBroadcast) - onAdded?.let { it(replaced, dictFile) } - } - - if (!dictFile.exists()) { - return moveDict(false) - } - - val systemLocale = context.resources.configuration.locale() - val newInfo = header.info(systemLocale) - val oldInfo = DictionaryInfoUtils.getDictionaryFileHeaderOrNull(dictFile, 0, dictFile.length())?.info(systemLocale) - confirmDialog(context, - context.getString(R.string.replace_dictionary_message, dictionaryType, oldInfo, newInfo), - context.getString(R.string.replace_dictionary) - ) { moveDict(true) } - } - - private fun onDictionaryLoadingError(messageId: Int) { - cachedDictionaryFile.delete() - infoDialog(context, messageId) - } -} diff --git a/app/src/main/java/helium314/keyboard/latin/utils/PopupKeysUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/PopupKeysUtils.kt index cc0c6724c..5d47d27b8 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/PopupKeysUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/PopupKeysUtils.kt @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only package helium314.keyboard.latin.utils -import android.content.SharedPreferences import helium314.keyboard.keyboard.Key import helium314.keyboard.keyboard.internal.KeySpecParser import helium314.keyboard.keyboard.internal.KeyboardParams @@ -97,7 +96,7 @@ private fun transformLabel(label: String, params: KeyboardParams): String = label.rtlLabel(params) } else label -/** returns a list of enabled popup keys for pref [key] */ +/** returns a list of enabled popup keys */ fun getEnabledPopupKeys(string: String): List { return string.split(Separators.ENTRY).mapNotNull { val split = it.split(Separators.KV) diff --git a/app/src/main/java/helium314/keyboard/latin/utils/ResourceUtils.java b/app/src/main/java/helium314/keyboard/latin/utils/ResourceUtils.java index 321c7e3a1..3ff53dadd 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/ResourceUtils.java +++ b/app/src/main/java/helium314/keyboard/latin/utils/ResourceUtils.java @@ -15,14 +15,10 @@ import android.graphics.Rect; import android.os.Build; import android.util.DisplayMetrics; import android.util.TypedValue; -import android.view.Display; -import android.view.DisplayCutout; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowMetrics; -import androidx.core.util.TypedValueCompat; - import helium314.keyboard.latin.R; import helium314.keyboard.latin.settings.SettingsValues; @@ -137,8 +133,4 @@ public final class ResourceUtils { public static boolean isNight(final Resources res) { return (res.getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; } - - public static int toPx(final int dp, final Resources res) { - return (int) TypedValueCompat.dpToPx(dp, res.getDisplayMetrics()); - } } diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt index 115dc86f8..18739953b 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeSettings.kt @@ -123,8 +123,6 @@ object SubtypeSettings { fun getSystemLocales(): List = systemLocales.toList() - fun hasMatchingSubtypeForLocale(locale: Locale): Boolean = !resourceSubtypesByLocale[locale].isNullOrEmpty() - fun getResourceSubtypesForLocale(locale: Locale): List = resourceSubtypesByLocale[locale].orEmpty() fun getAvailableSubtypeLocales(): List = resourceSubtypesByLocale.keys.toList() diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeUtilsAdditional.kt b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeUtilsAdditional.kt index 05b982127..048a7410b 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SubtypeUtilsAdditional.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/SubtypeUtilsAdditional.kt @@ -1,7 +1,6 @@ package helium314.keyboard.latin.utils import android.content.Context -import android.content.SharedPreferences import android.os.Build import android.view.inputmethod.InputMethodSubtype import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder @@ -50,16 +49,6 @@ object SubtypeUtilsAdditional { fun createEmojiCapableAdditionalSubtype(locale: Locale, mainLayoutName: String, asciiCapable: Boolean) = createAdditionalSubtype(locale, "${ExtraValue.KEYBOARD_LAYOUT_SET}=MAIN${Separators.KV}$mainLayoutName", asciiCapable, true) - // todo: consider using SettingsSubtype (nah, this can be removed after removing old settings) - fun addAdditionalSubtype(prefs: SharedPreferences, subtype: InputMethodSubtype) { - val oldAdditionalSubtypesString = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!! - val additionalSubtypes = createAdditionalSubtypes(oldAdditionalSubtypesString).toMutableSet() - additionalSubtypes.add(subtype) - val newAdditionalSubtypesString = createPrefSubtypes(additionalSubtypes) - Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString) - } - - // todo: SettingsSubtype? fun removeAdditionalSubtype(context: Context, subtype: InputMethodSubtype) { val prefs = context.prefs() SubtypeSettings.removeEnabledSubtype(context, subtype) diff --git a/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt b/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt index b17a8f096..af3f1ec0e 100644 --- a/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt +++ b/app/src/main/java/helium314/keyboard/settings/SettingsActivity.kt @@ -7,11 +7,11 @@ import android.content.SharedPreferences import android.net.Uri import android.os.Build import android.os.Bundle +import android.view.View import android.view.WindowInsets.Type import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputMethodManager -import android.widget.RelativeLayout -import androidx.appcompat.app.AppCompatActivity +import androidx.activity.ComponentActivity import androidx.compose.foundation.layout.Column import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -22,16 +22,15 @@ import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.platform.ComposeView import androidx.core.view.ViewCompat -import androidx.core.view.isGone import helium314.keyboard.compat.locale import helium314.keyboard.keyboard.KeyboardSwitcher import helium314.keyboard.latin.BuildConfig import helium314.keyboard.latin.InputAttributes -import helium314.keyboard.latin.R import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.define.DebugFlags import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.utils.ExecutorUtils +import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.UncachedInputMethodManagerUtils import helium314.keyboard.latin.utils.cleanUnusedMainDicts import helium314.keyboard.latin.utils.prefs @@ -51,7 +50,7 @@ import java.util.zip.ZipOutputStream // https://developer.android.com/codelabs/jetpack-compose-performance#2 // https://developer.android.com/topic/performance/baselineprofiles/overview // todo: consider viewModel, at least for LanguageScreen and ColorsScreen it might help making them less awkward and complicated -class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener { +class SettingsActivity : ComponentActivity(), SharedPreferences.OnSharedPreferenceChangeListener { private val prefs by lazy { this.prefs() } val prefChanged = MutableStateFlow(0) // simple counter, as the only relevant information is that something changed private val dictUriFlow = MutableStateFlow(null) @@ -68,6 +67,7 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { cleanUnusedMainDicts(this) } if (BuildConfig.DEBUG || DebugFlags.DEBUG_ENABLED) crashReportFiles.value = findCrashReports() + setStatusBarIconColor() val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager // with this the layout edit dialog is not covered by the keyboard @@ -84,15 +84,9 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen val spellchecker = intent?.getBooleanExtra("spellchecker", false) ?: false - // todo: when removing old settings completely, remove settings_activity.xml and supportFragmentManager stuff -// val cv = ComposeView(context = this) -// setContentView(cv) - setContentView(R.layout.settings_activity) - supportFragmentManager.addOnBackStackChangedListener { - updateContainerVisibility() - } -// cv.setContent { // todo: when removing old settings - findViewById(R.id.navHost).setContent { + val cv = ComposeView(context = this) + setContentView(cv) + cv.setContent { Theme { Surface { val dictUri by dictUriFlow.collectAsState() @@ -108,14 +102,7 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen settingsContainer[Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE]!!.Preference() } else - SettingsNavHost( - onClickBack = { -// this.finish() // todo: when removing old settings - if (supportFragmentManager.findFragmentById(R.id.settingsFragmentContainer) == null) - this.finish() - else supportFragmentManager.popBackStack() - } - ) + SettingsNavHost(onClickBack = { this.finish() }) if (dictUri != null) { NewDictionaryDialog( onDismissRequest = { dictUriFlow.value = null }, @@ -157,10 +144,6 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen } } - private fun updateContainerVisibility() { // todo: remove when removing old settings - findViewById(R.id.settingsFragmentContainer).isGone = supportFragmentManager.findFragmentById(R.id.settingsFragmentContainer) == null - } - override fun onStart() { super.onStart() prefs.registerOnSharedPreferenceChangeListener(this) @@ -225,6 +208,16 @@ class SettingsActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferen } } + // deprecated but works... ideally it would be done automatically like it worked before switching to compose + private fun setStatusBarIconColor() { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return + val view = window.decorView + if (ResourceUtils.isNight(resources)) + view.systemUiVisibility = view.systemUiVisibility and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() + else + view.systemUiVisibility = view.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR + } + companion object { // public write so compose previews can show the screens // having it in a companion object is not ideal as it will stay in memory even after settings are closed diff --git a/app/src/main/java/helium314/keyboard/settings/preferences/BackgroundImagePreference.kt b/app/src/main/java/helium314/keyboard/settings/preferences/BackgroundImagePreference.kt index 0f1f5a3aa..8b70448b8 100644 --- a/app/src/main/java/helium314/keyboard/settings/preferences/BackgroundImagePreference.kt +++ b/app/src/main/java/helium314/keyboard/settings/preferences/BackgroundImagePreference.kt @@ -13,7 +13,6 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue diff --git a/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt b/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt index f1999111a..675dc2c9d 100644 --- a/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt +++ b/app/src/main/java/helium314/keyboard/settings/preferences/BackupRestorePreference.kt @@ -13,14 +13,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import helium314.keyboard.dictionarypack.DictionaryPackConstants import helium314.keyboard.keyboard.KeyboardSwitcher -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_NUMBER -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_NUMPAD -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_NUMPAD_LANDSCAPE -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_PHONE -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_PHONE_SYMBOLS -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_SYMBOLS -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_SYMBOLS_ARABIC -import helium314.keyboard.keyboard.internal.keyboard_parser.LAYOUT_SYMBOLS_SHIFTED import helium314.keyboard.latin.R import helium314.keyboard.latin.checkVersionUpgrade import helium314.keyboard.latin.common.FileUtils @@ -277,7 +269,7 @@ private fun upgradeFileNames(originalName: String): String { originalName.startsWith("layouts") -> { // replace file name after switch to language tag, but only if it's not a layout val localeString = originalName.substringAfter(".").substringBefore(".") - if (localeString in listOf(LAYOUT_SYMBOLS, LAYOUT_SYMBOLS_SHIFTED, LAYOUT_SYMBOLS_ARABIC, LAYOUT_NUMBER, LAYOUT_NUMPAD, LAYOUT_NUMPAD_LANDSCAPE, LAYOUT_PHONE, LAYOUT_PHONE_SYMBOLS)) + if (localeString in listOf("symbols", "symbols_shifted", "symbols_arabic", "number", "numpad", "numpad_landscape", "phone", "phone_symbols")) return originalName // it's a layout! val locale = localeString.constructLocale() if (locale.toLanguageTag() != "und") diff --git a/app/src/main/java/helium314/keyboard/settings/preferences/LoadGestureLibPreference.kt b/app/src/main/java/helium314/keyboard/settings/preferences/LoadGestureLibPreference.kt index d18f89149..99b123118 100644 --- a/app/src/main/java/helium314/keyboard/settings/preferences/LoadGestureLibPreference.kt +++ b/app/src/main/java/helium314/keyboard/settings/preferences/LoadGestureLibPreference.kt @@ -3,7 +3,6 @@ package helium314.keyboard.settings.preferences import android.content.Intent import android.os.Build -import androidx.appcompat.app.AlertDialog import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -59,11 +58,6 @@ fun LoadGestureLibPreference(setting: Setting) { renameToLibFileAndRestart(tmpfile, checksum) } else { tempFilePath = tmpfile.absolutePath - AlertDialog.Builder(ctx) - .setMessage(ctx.getString(R.string.checksum_mismatch_message, abi)) - .setPositiveButton(android.R.string.ok) { _, _ -> renameToLibFileAndRestart(tmpfile, checksum) } - .setNegativeButton(android.R.string.cancel) { _, _ -> tmpfile.delete() } - .show() } } catch (e: IOException) { tmpfile.delete() diff --git a/app/src/main/java/helium314/keyboard/settings/preferences/Preference.kt b/app/src/main/java/helium314/keyboard/settings/preferences/Preference.kt index d13a82d7d..33cd45b63 100644 --- a/app/src/main/java/helium314/keyboard/settings/preferences/Preference.kt +++ b/app/src/main/java/helium314/keyboard/settings/preferences/Preference.kt @@ -118,7 +118,7 @@ private fun PreferencePreview() { Preference( name = "Preference with icon", onClick = {}, - icon = R.drawable.ic_settings_about_foreground + icon = R.drawable.ic_settings_about ) SliderPreference( name = "SliderPreference", @@ -131,7 +131,7 @@ private fun PreferencePreview() { name = "Preference with icon and description", description = "some text", onClick = {}, - icon = R.drawable.ic_settings_about_foreground + icon = R.drawable.ic_settings_about ) Preference( name = "Preference with switch", diff --git a/app/src/main/java/helium314/keyboard/settings/screens/AboutScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/AboutScreen.kt index 681fcefe0..0b827952b 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/AboutScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/AboutScreen.kt @@ -87,7 +87,7 @@ fun createAboutSettings(context: Context) = listOf( prefs.edit().putBoolean(DebugSettings.PREF_SHOW_DEBUG_SETTINGS, true).apply() Toast.makeText(ctx, R.string.prefs_debug_settings_enabled, Toast.LENGTH_LONG).show() }, - icon = R.drawable.ic_settings_about_foreground + icon = R.drawable.ic_settings_about ) }, Setting(context, SettingsWithoutKey.LICENSE, R.string.license, R.string.gnu_gpl) { @@ -101,7 +101,7 @@ fun createAboutSettings(context: Context) = listOf( intent.action = Intent.ACTION_VIEW ctx.startActivity(intent) }, - icon = R.drawable.ic_settings_about_license_foreground + icon = R.drawable.ic_settings_about_license ) }, Setting(context, SettingsWithoutKey.HIDDEN_FEATURES, R.string.hidden_features_title, R.string.hidden_features_summary) { @@ -125,7 +125,7 @@ fun createAboutSettings(context: Context) = listOf( builder.show() (builder.findViewById(android.R.id.message) as TextView).movementMethod = LinkMovementMethod.getInstance() }, - icon = R.drawable.ic_settings_about_hidden_features_foreground + icon = R.drawable.ic_settings_about_hidden_features ) }, Setting(context, SettingsWithoutKey.GITHUB, R.string.about_github_link) { @@ -139,7 +139,7 @@ fun createAboutSettings(context: Context) = listOf( intent.action = Intent.ACTION_VIEW ctx.startActivity(intent) }, - icon = R.drawable.ic_settings_about_github_foreground + icon = R.drawable.ic_settings_about_github ) }, Setting(context, SettingsWithoutKey.SAVE_LOG, R.string.save_log) { setting -> @@ -169,7 +169,7 @@ fun createAboutSettings(context: Context) = listOf( .setType("text/plain") launcher.launch(intent) }, - icon = R.drawable.ic_settings_about_log_foreground + icon = R.drawable.ic_settings_about_log ) }, ) diff --git a/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt index 6254a78ab..f8a43ca25 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/AppearanceScreen.kt @@ -108,6 +108,7 @@ fun createAppearanceSettings(context: Context) = listOf( if (prefs.getString(Settings.PREF_THEME_COLORS_NIGHT, Defaults.PREF_THEME_COLORS_NIGHT) == KeyboardTheme.THEME_HOLO_WHITE) prefs.edit().remove(Settings.PREF_THEME_COLORS_NIGHT).apply() } + KeyboardIconsSet.needsReload = true // only relevant for Settings.PREF_CUSTOM_ICON_NAMES } }, Setting(context, Settings.PREF_ICON_STYLE, R.string.icon_style) { setting -> @@ -117,7 +118,10 @@ fun createAppearanceSettings(context: Context) = listOf( setting, items, Defaults.PREF_ICON_STYLE - ) { KeyboardSwitcher.getInstance().setThemeNeedsReload() } + ) { + KeyboardIconsSet.needsReload = true // only relevant for Settings.PREF_CUSTOM_ICON_NAMES + KeyboardSwitcher.getInstance().setThemeNeedsReload() + } }, Setting(context, Settings.PREF_CUSTOM_ICON_NAMES, R.string.customize_icons) { setting -> var showDialog by rememberSaveable { mutableStateOf(false) } @@ -126,11 +130,8 @@ fun createAppearanceSettings(context: Context) = listOf( onClick = { showDialog = true } ) if (showDialog) { -/* if (keyboardNeedsReload) { - KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(LocalContext.current) - keyboardNeedsReload = false - } -*/ CustomizeIconsDialog(setting.key) { showDialog = false } + KeyboardIconsSet.instance.loadIcons(LocalContext.current) + CustomizeIconsDialog(setting.key) { showDialog = false } } }, Setting(context, Settings.PREF_THEME_COLORS, R.string.theme_colors) { setting -> diff --git a/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt index 6c9e41f57..13658bdbd 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/DebugScreen.kt @@ -16,7 +16,6 @@ import helium314.keyboard.latin.DictionaryDumpBroadcastReceiver import helium314.keyboard.latin.DictionaryFacilitator import helium314.keyboard.latin.R import helium314.keyboard.latin.settings.DebugSettings -import helium314.keyboard.latin.settings.DebugSettingsFragment import helium314.keyboard.latin.settings.Defaults import helium314.keyboard.latin.utils.prefs import helium314.keyboard.settings.Setting @@ -41,7 +40,7 @@ fun DebugScreen( DebugSettings.PREF_FORCE_NON_DISTINCT_MULTITOUCH, DebugSettings.PREF_SLIDING_KEY_INPUT_PREVIEW, R.string.prefs_dump_dynamic_dicts - ) + DictionaryFacilitator.DYNAMIC_DICTIONARY_TYPES.map { DebugSettingsFragment.PREF_KEY_DUMP_DICT_PREFIX + it } + ) + DictionaryFacilitator.DYNAMIC_DICTIONARY_TYPES.map { DebugSettings.PREF_KEY_DUMP_DICT_PREFIX + it } SearchSettingsScreen( onClickBack = { if (needsRestart) { @@ -95,7 +94,7 @@ private fun createDebugSettings(context: Context) = listOf( SwitchPreference(def, Defaults.PREF_SLIDING_KEY_INPUT_PREVIEW) }, ) + DictionaryFacilitator.DYNAMIC_DICTIONARY_TYPES.map { type -> - Setting(context, DebugSettingsFragment.PREF_KEY_DUMP_DICT_PREFIX + type, R.string.button_default) { + Setting(context, DebugSettings.PREF_KEY_DUMP_DICT_PREFIX + type, R.string.button_default) { val ctx = LocalContext.current Preference( name = "Dump $type dictionary", diff --git a/app/src/main/java/helium314/keyboard/settings/screens/MainSettingsScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/MainSettingsScreen.kt index 82c41183d..85fde377a 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/MainSettingsScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/MainSettingsScreen.kt @@ -11,22 +11,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import helium314.keyboard.latin.R -import helium314.keyboard.latin.settings.AboutFragment -import helium314.keyboard.latin.settings.AdvancedSettingsFragment -import helium314.keyboard.latin.settings.AppearanceSettingsFragment -import helium314.keyboard.latin.settings.CorrectionSettingsFragment -import helium314.keyboard.latin.settings.GestureSettingsFragment -import helium314.keyboard.latin.settings.LanguageSettingsFragment -import helium314.keyboard.latin.settings.PreferencesSettingsFragment -import helium314.keyboard.latin.settings.ToolbarSettingsFragment import helium314.keyboard.latin.utils.JniUtils import helium314.keyboard.latin.utils.SubtypeSettings import helium314.keyboard.latin.utils.displayName -import helium314.keyboard.latin.utils.getActivity -import helium314.keyboard.latin.utils.switchTo import helium314.keyboard.settings.NextScreenIcon import helium314.keyboard.settings.preferences.Preference -import helium314.keyboard.settings.preferences.PreferenceCategory import helium314.keyboard.settings.SearchSettingsScreen import helium314.keyboard.settings.Theme import helium314.keyboard.settings.initPreview @@ -58,33 +47,33 @@ fun MainSettingsScreen( name = stringResource(R.string.language_and_layouts_title), description = enabledSubtypes.joinToString(", ") { it.displayName(ctx) }, onClick = onClickLanguage, - icon = R.drawable.ic_settings_languages_foreground + icon = R.drawable.ic_settings_languages ) { NextScreenIcon() } Preference( name = stringResource(R.string.settings_screen_preferences), onClick = onClickPreferences, - icon = R.drawable.ic_settings_preferences_foreground + icon = R.drawable.ic_settings_preferences ) { NextScreenIcon() } Preference( name = stringResource(R.string.settings_screen_appearance), onClick = onClickAppearance, - icon = R.drawable.ic_settings_appearance_foreground + icon = R.drawable.ic_settings_appearance ) { NextScreenIcon() } Preference( name = stringResource(R.string.settings_screen_toolbar), onClick = onClickToolbar, - icon = R.drawable.ic_settings_toolbar_foreground + icon = R.drawable.ic_settings_toolbar ) { NextScreenIcon() } if (JniUtils.sHaveGestureLib) Preference( name = stringResource(R.string.settings_screen_gesture), onClick = onClickGestureTyping, - icon = R.drawable.ic_settings_gesture_foreground + icon = R.drawable.ic_settings_gesture ) { NextScreenIcon() } Preference( name = stringResource(R.string.settings_screen_correction), onClick = onClickTextCorrection, - icon = R.drawable.ic_settings_correction_foreground + icon = R.drawable.ic_settings_correction ) { NextScreenIcon() } Preference( name = stringResource(R.string.settings_screen_secondary_layouts), @@ -99,47 +88,13 @@ fun MainSettingsScreen( Preference( name = stringResource(R.string.settings_screen_advanced), onClick = onClickAdvanced, - icon = R.drawable.ic_settings_advanced_foreground + icon = R.drawable.ic_settings_advanced ) { NextScreenIcon() } Preference( name = stringResource(R.string.settings_screen_about), onClick = onClickAbout, - icon = R.drawable.ic_settings_about_foreground + icon = R.drawable.ic_settings_about ) { NextScreenIcon() } - PreferenceCategory(title = "old screens") - Preference( - name = stringResource(R.string.language_and_layouts_title), - onClick = { ctx.getActivity()?.switchTo(LanguageSettingsFragment()) } - ) - Preference( - name = stringResource(R.string.settings_screen_preferences), - onClick = { ctx.getActivity()?.switchTo(PreferencesSettingsFragment()) } - ) - Preference( - name = stringResource(R.string.settings_screen_appearance), - onClick = { ctx.getActivity()?.switchTo(AppearanceSettingsFragment()) } - ) - Preference( - name = stringResource(R.string.settings_screen_toolbar), - onClick = { ctx.getActivity()?.switchTo(ToolbarSettingsFragment()) } - ) - if (JniUtils.sHaveGestureLib) - Preference( - name = stringResource(R.string.settings_screen_gesture), - onClick = { ctx.getActivity()?.switchTo(GestureSettingsFragment()) } - ) - Preference( - name = stringResource(R.string.settings_screen_correction), - onClick = { ctx.getActivity()?.switchTo(CorrectionSettingsFragment()) } - ) - Preference( - name = stringResource(R.string.settings_screen_advanced), - onClick = { ctx.getActivity()?.switchTo(AdvancedSettingsFragment()) } - ) - Preference( - name = stringResource(R.string.settings_screen_about), - onClick = { ctx.getActivity()?.switchTo(AboutFragment()) } - ) } } } diff --git a/app/src/main/java/helium314/keyboard/settings/screens/TextCorrectionScreen.kt b/app/src/main/java/helium314/keyboard/settings/screens/TextCorrectionScreen.kt index 11353d4db..97d641885 100644 --- a/app/src/main/java/helium314/keyboard/settings/screens/TextCorrectionScreen.kt +++ b/app/src/main/java/helium314/keyboard/settings/screens/TextCorrectionScreen.kt @@ -56,7 +56,7 @@ fun TextCorrectionScreen( Settings.PREF_AUTO_CORRECTION, if (autocorrectEnabled) Settings.PREF_MORE_AUTO_CORRECTION else null, if (autocorrectEnabled) Settings.PREF_AUTOCORRECT_SHORTCUTS else null, - if (autocorrectEnabled) Settings.PREF_AUTO_CORRECTION_CONFIDENCE else null, + if (autocorrectEnabled) Settings.PREF_AUTO_CORRECT_THRESHOLD else null, Settings.PREF_AUTO_CAP, Settings.PREF_KEY_USE_DOUBLE_SPACE_PERIOD, Settings.PREF_AUTOSPACE_AFTER_PUNCTUATION, @@ -105,13 +105,14 @@ fun createCorrectionSettings(context: Context) = listOf( ) { SwitchPreference(it, Defaults.PREF_AUTOCORRECT_SHORTCUTS) }, - Setting(context, Settings.PREF_AUTO_CORRECTION_CONFIDENCE, R.string.auto_correction_confidence) { + Setting(context, Settings.PREF_AUTO_CORRECT_THRESHOLD, R.string.auto_correction_confidence) { val items = listOf( - stringResource(R.string.auto_correction_threshold_mode_modest) to "0", - stringResource(R.string.auto_correction_threshold_mode_aggressive) to "1", - stringResource(R.string.auto_correction_threshold_mode_very_aggressive) to "2", + stringResource(R.string.auto_correction_threshold_mode_modest) to 0.185f, + stringResource(R.string.auto_correction_threshold_mode_aggressive) to 0.067f, + stringResource(R.string.auto_correction_threshold_mode_very_aggressive) to -1f, ) - ListPreference(it, items, Defaults.PREF_AUTO_CORRECTION_CONFIDENCE) + // todo: consider making it a slider, and maybe somehow adjust range so we can show % + ListPreference(it, items, Defaults.PREF_AUTO_CORRECT_THRESHOLD) }, Setting(context, Settings.PREF_AUTO_CAP, R.string.auto_cap, R.string.auto_cap_summary diff --git a/app/src/main/res/color/setup_step_action_background.xml b/app/src/main/res/color/setup_step_action_background.xml deleted file mode 100644 index 73a7e7aea..000000000 --- a/app/src/main/res/color/setup_step_action_background.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/color/setup_step_action_text.xml b/app/src/main/res/color/setup_step_action_text.xml deleted file mode 100644 index 34d8b6ef1..000000000 --- a/app/src/main/res/color/setup_step_action_text.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/drawable/ic_settings_about.xml b/app/src/main/res/drawable/ic_settings_about.xml index 7a84fa0fe..fea588f5d 100644 --- a/app/src/main/res/drawable/ic_settings_about.xml +++ b/app/src/main/res/drawable/ic_settings_about.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + diff --git a/app/src/main/res/drawable/ic_settings_about_foreground.xml b/app/src/main/res/drawable/ic_settings_about_foreground.xml deleted file mode 100644 index fea588f5d..000000000 --- a/app/src/main/res/drawable/ic_settings_about_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_settings_about_github.xml b/app/src/main/res/drawable/ic_settings_about_github.xml index 9f39fa876..4a306f2d6 100644 --- a/app/src/main/res/drawable/ic_settings_about_github.xml +++ b/app/src/main/res/drawable/ic_settings_about_github.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_about_github_foreground.xml b/app/src/main/res/drawable/ic_settings_about_github_foreground.xml deleted file mode 100644 index 4a306f2d6..000000000 --- a/app/src/main/res/drawable/ic_settings_about_github_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_about_hidden_features.xml b/app/src/main/res/drawable/ic_settings_about_hidden_features.xml index a337ec935..414dc194e 100644 --- a/app/src/main/res/drawable/ic_settings_about_hidden_features.xml +++ b/app/src/main/res/drawable/ic_settings_about_hidden_features.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_about_hidden_features_foreground.xml b/app/src/main/res/drawable/ic_settings_about_hidden_features_foreground.xml deleted file mode 100644 index 414dc194e..000000000 --- a/app/src/main/res/drawable/ic_settings_about_hidden_features_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_about_license.xml b/app/src/main/res/drawable/ic_settings_about_license.xml index b6f5e522a..12d086fa0 100644 --- a/app/src/main/res/drawable/ic_settings_about_license.xml +++ b/app/src/main/res/drawable/ic_settings_about_license.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_about_license_foreground.xml b/app/src/main/res/drawable/ic_settings_about_license_foreground.xml deleted file mode 100644 index 12d086fa0..000000000 --- a/app/src/main/res/drawable/ic_settings_about_license_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_about_log.xml b/app/src/main/res/drawable/ic_settings_about_log.xml index a2fc756e5..03d6751f2 100644 --- a/app/src/main/res/drawable/ic_settings_about_log.xml +++ b/app/src/main/res/drawable/ic_settings_about_log.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + diff --git a/app/src/main/res/drawable/ic_settings_about_log_foreground.xml b/app/src/main/res/drawable/ic_settings_about_log_foreground.xml deleted file mode 100644 index 03d6751f2..000000000 --- a/app/src/main/res/drawable/ic_settings_about_log_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/ic_settings_advanced.xml b/app/src/main/res/drawable/ic_settings_advanced.xml index 175fcf695..7cee65cad 100644 --- a/app/src/main/res/drawable/ic_settings_advanced.xml +++ b/app/src/main/res/drawable/ic_settings_advanced.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_advanced_foreground.xml b/app/src/main/res/drawable/ic_settings_advanced_foreground.xml deleted file mode 100644 index 7cee65cad..000000000 --- a/app/src/main/res/drawable/ic_settings_advanced_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_appearance.xml b/app/src/main/res/drawable/ic_settings_appearance.xml index 837f360a4..3d1b940b1 100644 --- a/app/src/main/res/drawable/ic_settings_appearance.xml +++ b/app/src/main/res/drawable/ic_settings_appearance.xml @@ -1,4 +1,14 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_appearance_foreground.xml b/app/src/main/res/drawable/ic_settings_appearance_foreground.xml deleted file mode 100644 index 3d1b940b1..000000000 --- a/app/src/main/res/drawable/ic_settings_appearance_foreground.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_correction.xml b/app/src/main/res/drawable/ic_settings_correction.xml index 89885307f..1aaf1d0ba 100644 --- a/app/src/main/res/drawable/ic_settings_correction.xml +++ b/app/src/main/res/drawable/ic_settings_correction.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_correction_foreground.xml b/app/src/main/res/drawable/ic_settings_correction_foreground.xml deleted file mode 100644 index 1aaf1d0ba..000000000 --- a/app/src/main/res/drawable/ic_settings_correction_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_gesture.xml b/app/src/main/res/drawable/ic_settings_gesture.xml index 18f231d44..0e376d2fd 100644 --- a/app/src/main/res/drawable/ic_settings_gesture.xml +++ b/app/src/main/res/drawable/ic_settings_gesture.xml @@ -1,4 +1,14 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_gesture_foreground.xml b/app/src/main/res/drawable/ic_settings_gesture_foreground.xml deleted file mode 100644 index 0e376d2fd..000000000 --- a/app/src/main/res/drawable/ic_settings_gesture_foreground.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_languages.xml b/app/src/main/res/drawable/ic_settings_languages.xml index d921bfb8c..6347c242a 100644 --- a/app/src/main/res/drawable/ic_settings_languages.xml +++ b/app/src/main/res/drawable/ic_settings_languages.xml @@ -1,4 +1,14 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_languages_foreground.xml b/app/src/main/res/drawable/ic_settings_languages_foreground.xml deleted file mode 100644 index 6347c242a..000000000 --- a/app/src/main/res/drawable/ic_settings_languages_foreground.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_preferences.xml b/app/src/main/res/drawable/ic_settings_preferences.xml index 37387dead..57647528b 100644 --- a/app/src/main/res/drawable/ic_settings_preferences.xml +++ b/app/src/main/res/drawable/ic_settings_preferences.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_preferences_foreground.xml b/app/src/main/res/drawable/ic_settings_preferences_foreground.xml deleted file mode 100644 index 57647528b..000000000 --- a/app/src/main/res/drawable/ic_settings_preferences_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_settings_toolbar.xml b/app/src/main/res/drawable/ic_settings_toolbar.xml index 5db7c5eb7..3831fb738 100644 --- a/app/src/main/res/drawable/ic_settings_toolbar.xml +++ b/app/src/main/res/drawable/ic_settings_toolbar.xml @@ -1,4 +1,13 @@ - - \ No newline at end of file + + + + diff --git a/app/src/main/res/drawable/ic_settings_toolbar_foreground.xml b/app/src/main/res/drawable/ic_settings_toolbar_foreground.xml deleted file mode 100644 index 3831fb738..000000000 --- a/app/src/main/res/drawable/ic_settings_toolbar_foreground.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/setup_step_action_background.xml b/app/src/main/res/drawable/setup_step_action_background.xml deleted file mode 100644 index c74c6dd0c..000000000 --- a/app/src/main/res/drawable/setup_step_action_background.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout-land/setup_steps_screen.xml b/app/src/main/res/layout-land/setup_steps_screen.xml deleted file mode 100644 index 3fb43358e..000000000 --- a/app/src/main/res/layout-land/setup_steps_screen.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/layout-land/setup_welcome_screen.xml b/app/src/main/res/layout-land/setup_welcome_screen.xml deleted file mode 100644 index 3376637bd..000000000 --- a/app/src/main/res/layout-land/setup_welcome_screen.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/layout/color_setting.xml b/app/src/main/res/layout/color_setting.xml deleted file mode 100644 index f73865e19..000000000 --- a/app/src/main/res/layout/color_setting.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/color_settings.xml b/app/src/main/res/layout/color_settings.xml deleted file mode 100644 index b6c4533b4..000000000 --- a/app/src/main/res/layout/color_settings.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/layout/language_list_item.xml b/app/src/main/res/layout/language_list_item.xml deleted file mode 100644 index 0f988324d..000000000 --- a/app/src/main/res/layout/language_list_item.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/language_search_filter.xml b/app/src/main/res/layout/language_search_filter.xml deleted file mode 100644 index c44c86ffe..000000000 --- a/app/src/main/res/layout/language_search_filter.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - diff --git a/app/src/main/res/layout/language_settings.xml b/app/src/main/res/layout/language_settings.xml deleted file mode 100644 index faf72a68a..000000000 --- a/app/src/main/res/layout/language_settings.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - diff --git a/app/src/main/res/layout/locale_settings_dialog.xml b/app/src/main/res/layout/locale_settings_dialog.xml deleted file mode 100644 index 77f17a904..000000000 --- a/app/src/main/res/layout/locale_settings_dialog.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/reorder_dialog_item.xml b/app/src/main/res/layout/reorder_dialog_item.xml deleted file mode 100644 index 8aad852e9..000000000 --- a/app/src/main/res/layout/reorder_dialog_item.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/layout/seek_bar_dialog.xml b/app/src/main/res/layout/seek_bar_dialog.xml deleted file mode 100644 index aac8d9a4c..000000000 --- a/app/src/main/res/layout/seek_bar_dialog.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - diff --git a/app/src/main/res/layout/settings_activity.xml b/app/src/main/res/layout/settings_activity.xml deleted file mode 100644 index b689a448d..000000000 --- a/app/src/main/res/layout/settings_activity.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/setup_start_indicator_label.xml b/app/src/main/res/layout/setup_start_indicator_label.xml deleted file mode 100644 index 703a1c700..000000000 --- a/app/src/main/res/layout/setup_start_indicator_label.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/setup_step.xml b/app/src/main/res/layout/setup_step.xml deleted file mode 100644 index ab15c4467..000000000 --- a/app/src/main/res/layout/setup_step.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/setup_steps_cards.xml b/app/src/main/res/layout/setup_steps_cards.xml deleted file mode 100644 index ccd0eb882..000000000 --- a/app/src/main/res/layout/setup_steps_cards.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/setup_steps_screen.xml b/app/src/main/res/layout/setup_steps_screen.xml deleted file mode 100644 index e53d91958..000000000 --- a/app/src/main/res/layout/setup_steps_screen.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/setup_steps_title.xml b/app/src/main/res/layout/setup_steps_title.xml deleted file mode 100644 index f2c346aef..000000000 --- a/app/src/main/res/layout/setup_steps_title.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/app/src/main/res/layout/setup_welcome_image.xml b/app/src/main/res/layout/setup_welcome_image.xml deleted file mode 100644 index a2c135bb8..000000000 --- a/app/src/main/res/layout/setup_welcome_image.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/layout/setup_welcome_screen.xml b/app/src/main/res/layout/setup_welcome_screen.xml deleted file mode 100644 index fbb5836fc..000000000 --- a/app/src/main/res/layout/setup_welcome_screen.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/setup_welcome_title.xml b/app/src/main/res/layout/setup_welcome_title.xml deleted file mode 100644 index 949ba1863..000000000 --- a/app/src/main/res/layout/setup_welcome_title.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/setup_wizard.xml b/app/src/main/res/layout/setup_wizard.xml deleted file mode 100644 index 2c83ecc74..000000000 --- a/app/src/main/res/layout/setup_wizard.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/layout/toolbar_key_customizer.xml b/app/src/main/res/layout/toolbar_key_customizer.xml deleted file mode 100644 index 9d5149dfa..000000000 --- a/app/src/main/res/layout/toolbar_key_customizer.xml +++ /dev/null @@ -1,42 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/user_dictionary_add_word_fullscreen.xml b/app/src/main/res/layout/user_dictionary_add_word_fullscreen.xml deleted file mode 100644 index aa5226e18..000000000 --- a/app/src/main/res/layout/user_dictionary_add_word_fullscreen.xml +++ /dev/null @@ -1,140 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/user_dictionary_item.xml b/app/src/main/res/layout/user_dictionary_item.xml deleted file mode 100644 index c2dca562a..000000000 --- a/app/src/main/res/layout/user_dictionary_item.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/user_dictionary_settings_list_fragment.xml b/app/src/main/res/layout/user_dictionary_settings_list_fragment.xml deleted file mode 100644 index cd601bab2..000000000 --- a/app/src/main/res/layout/user_dictionary_settings_list_fragment.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values-h1200dp-port/setup-dimens.xml b/app/src/main/res/values-h1200dp-port/setup-dimens.xml deleted file mode 100644 index 9d5f38b67..000000000 --- a/app/src/main/res/values-h1200dp-port/setup-dimens.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 72sp - 38sp - 24sp - 96dp - 144dp - 62dp - 50 - diff --git a/app/src/main/res/values-h330dp-land/setup-dimens.xml b/app/src/main/res/values-h330dp-land/setup-dimens.xml deleted file mode 100644 index 1bcd2fcac..000000000 --- a/app/src/main/res/values-h330dp-land/setup-dimens.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - 40sp - 22sp - 22sp - 24dp - 20sp - 16sp - 18sp - 16dp - 54dp - 24dp - 12dp - 16dp - 24dp - 10dp - 12dp - 15 - diff --git a/app/src/main/res/values-h520dp-land/setup-dimens.xml b/app/src/main/res/values-h520dp-land/setup-dimens.xml deleted file mode 100644 index ee4c84d6a..000000000 --- a/app/src/main/res/values-h520dp-land/setup-dimens.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - 50sp - 32sp - 24sp - 24sp - 18sp - 20sp - 32dp - 96dp - 50 - 50 - 12dp - 24dp - 30 - diff --git a/app/src/main/res/values-h540dp-port/setup-dimens.xml b/app/src/main/res/values-h540dp-port/setup-dimens.xml deleted file mode 100644 index b44265103..000000000 --- a/app/src/main/res/values-h540dp-port/setup-dimens.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - 48sp - 26sp - 22sp - 24dp - 20sp - 16sp - 18sp - 8dp - 16dp - 54dp - 24dp - 12dp - 16dp - 24dp - 6dp - diff --git a/app/src/main/res/values-h720dp-land/setup-dimens.xml b/app/src/main/res/values-h720dp-land/setup-dimens.xml deleted file mode 100644 index b41ab229e..000000000 --- a/app/src/main/res/values-h720dp-land/setup-dimens.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - 72sp - 38sp - 24sp - 96dp - 160dp - 62dp - 50 - diff --git a/app/src/main/res/values-h800dp-port/setup-dimens.xml b/app/src/main/res/values-h800dp-port/setup-dimens.xml deleted file mode 100644 index 3f32fff5e..000000000 --- a/app/src/main/res/values-h800dp-port/setup-dimens.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - 24sp - 24sp - 18sp - 20sp - 32dp - 64dp - 12dp - 24dp - 24dp - 40 - diff --git a/app/src/main/res/values-land/setup-dimens.xml b/app/src/main/res/values-land/setup-dimens.xml deleted file mode 100644 index a50cbd256..000000000 --- a/app/src/main/res/values-land/setup-dimens.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - 32sp - 18sp - 16dp - 42dp - 12dp - 12dp - 0dp - 20 - diff --git a/app/src/main/res/values-v29/donottranslate.xml b/app/src/main/res/values-v29/donottranslate.xml deleted file mode 100644 index 852e10b6b..000000000 --- a/app/src/main/res/values-v29/donottranslate.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - true - diff --git a/app/src/main/res/values-v31/platform-theme.xml b/app/src/main/res/values-v31/platform-theme.xml index ce9c4f67b..4c40353c6 100644 --- a/app/src/main/res/values-v31/platform-theme.xml +++ b/app/src/main/res/values-v31/platform-theme.xml @@ -5,7 +5,7 @@ - - - - - diff --git a/app/src/main/res/values/config-auto-correction-thresholds.xml b/app/src/main/res/values/config-auto-correction-thresholds.xml deleted file mode 100644 index c9929a535..000000000 --- a/app/src/main/res/values/config-auto-correction-thresholds.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - 0.185 - - 0.067 - - floatNegativeInfinity - - - - 0 - 1 - 2 - - - - @string/auto_correction_threshold_mode_index_modest - @string/auto_correction_threshold_mode_index_aggressive - @string/auto_correction_threshold_mode_index_very_aggressive - - - - @string/auto_correction_threshold_mode_modest - @string/auto_correction_threshold_mode_aggressive - @string/auto_correction_threshold_mode_very_aggressive - - diff --git a/app/src/main/res/values/config-common.xml b/app/src/main/res/values/config-common.xml index 6366b02cd..33ad67c43 100644 --- a/app/src/main/res/values/config-common.xml +++ b/app/src/main/res/values/config-common.xml @@ -6,15 +6,6 @@ --> - - false - true - - true - - - 10 100 1100 @@ -27,13 +18,6 @@ 100 - false - 100 - - 300 - 700 - 100 - 10 3000 5 @@ -49,9 +33,6 @@ 3dp 100 - 800 - 1900 - 50 20 500 @@ -97,9 +78,6 @@ 32.0dp 18% - - true - 9.6dp diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index bc2565a93..675128454 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -94,53 +94,5 @@ 100% FOSS keyboard, based on AOSP. - - false - - internal - input_method - both - - - @string/switch_language - @string/language_switch_key_switch_input_method - @string/language_switch_key_switch_both - - - normal - main - more - all - - - @string/show_popup_keys_normal - @string/show_popup_keys_main - @string/show_popup_keys_more - @string/show_popup_keys_all - - - move_cursor - switch_language - toggle_numpad - none - - - @string/space_swipe_move_cursor_entry - @string/switch_language - @string/space_swipe_toggle_numpad_entry - @string/action_none - - - move_cursor - switch_language - toggle_numpad - none - - - @string/space_swipe_move_cursor_entry - @string/switch_language - @string/space_swipe_toggle_numpad_entry - @string/action_none - diff --git a/app/src/main/res/values/ic_launcher_background.xml b/app/src/main/res/values/ic_launcher_background.xml deleted file mode 100644 index c5d5899fd..000000000 --- a/app/src/main/res/values/ic_launcher_background.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - #FFFFFF - \ No newline at end of file diff --git a/app/src/main/res/values/preferences_styles.xml b/app/src/main/res/values/preferences_styles.xml deleted file mode 100644 index 7c2356fb2..000000000 --- a/app/src/main/res/values/preferences_styles.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - diff --git a/app/src/main/res/values/setup-dimens.xml b/app/src/main/res/values/setup-dimens.xml deleted file mode 100644 index 6d513112e..000000000 --- a/app/src/main/res/values/setup-dimens.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - 40sp - 20sp - 18sp - 18dp - 18sp - 14sp - 16sp - 2dp - 12dp - 46dp - 20dp - 10dp - 6dp - 12dp - 2dp - 40 - 60 - 16dp - 4dp - 12dp - 12dp - 30 - 5 - diff --git a/app/src/main/res/values/setup-styles-common.xml b/app/src/main/res/values/setup-styles-common.xml deleted file mode 100644 index 348fbe8c3..000000000 --- a/app/src/main/res/values/setup-styles-common.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - diff --git a/app/src/main/res/values/setup-styles.xml b/app/src/main/res/values/setup-styles.xml deleted file mode 100644 index 11106d899..000000000 --- a/app/src/main/res/values/setup-styles.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - diff --git a/app/src/main/res/values/setup-wizard.xml b/app/src/main/res/values/setup-wizard.xml deleted file mode 100644 index 4dc390307..000000000 --- a/app/src/main/res/values/setup-wizard.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/app/src/main/res/xml/prefs.xml b/app/src/main/res/xml/prefs.xml deleted file mode 100644 index cbe4fe762..000000000 --- a/app/src/main/res/xml/prefs.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_about.xml b/app/src/main/res/xml/prefs_screen_about.xml deleted file mode 100644 index 94430c96e..000000000 --- a/app/src/main/res/xml/prefs_screen_about.xml +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_advanced.xml b/app/src/main/res/xml/prefs_screen_advanced.xml deleted file mode 100644 index 35474182c..000000000 --- a/app/src/main/res/xml/prefs_screen_advanced.xml +++ /dev/null @@ -1,148 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_appearance.xml b/app/src/main/res/xml/prefs_screen_appearance.xml deleted file mode 100644 index 715d3cf67..000000000 --- a/app/src/main/res/xml/prefs_screen_appearance.xml +++ /dev/null @@ -1,173 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_correction.xml b/app/src/main/res/xml/prefs_screen_correction.xml deleted file mode 100644 index 443720861..000000000 --- a/app/src/main/res/xml/prefs_screen_correction.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_debug.xml b/app/src/main/res/xml/prefs_screen_debug.xml deleted file mode 100644 index 30f31467c..000000000 --- a/app/src/main/res/xml/prefs_screen_debug.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_gesture.xml b/app/src/main/res/xml/prefs_screen_gesture.xml deleted file mode 100644 index e725b5960..000000000 --- a/app/src/main/res/xml/prefs_screen_gesture.xml +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_preferences.xml b/app/src/main/res/xml/prefs_screen_preferences.xml deleted file mode 100644 index 858016f8b..000000000 --- a/app/src/main/res/xml/prefs_screen_preferences.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/xml/prefs_screen_toolbar.xml b/app/src/main/res/xml/prefs_screen_toolbar.xml deleted file mode 100644 index 7e0f65176..000000000 --- a/app/src/main/res/xml/prefs_screen_toolbar.xml +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/test/java/helium314/keyboard/latin/SuggestTest.kt b/app/src/test/java/helium314/keyboard/latin/SuggestTest.kt index e0b11d104..79d59179f 100644 --- a/app/src/test/java/helium314/keyboard/latin/SuggestTest.kt +++ b/app/src/test/java/helium314/keyboard/latin/SuggestTest.kt @@ -40,9 +40,9 @@ class SuggestTest { private val suggest get() = latinIME.mInputLogic.mSuggest // values taken from the string array auto_correction_threshold_mode_indexes - private val thresholdModest = "0" - private val thresholdAggressive = "1" - private val thresholdVeryAggressive = "2" + private val thresholdModest = 0.185f + private val thresholdAggressive = 0.067f + private val thresholdVeryAggressive = -1f @BeforeTest fun setUp() { latinIME = Robolectric.setupService(LatinIME::class.java) @@ -273,9 +273,9 @@ class SuggestTest { firstSuggestionForEmpty: SuggestedWordInfo?, // first suggestion if typed word would be empty (null if none) typedWordSuggestionForEmpty: SuggestedWordInfo?, // suggestion for actually typed word if typed word would be empty (null if none) typingLocale: Locale, // used for checking whether suggestion locale is the same, relevant e.g. for English i -> I shortcut, but we want Polish i - autoCorrectThreshold: String // 0, 1, or 2, but better use the vals on top with the corresponding name + autoCorrectThreshold: Float ): List { - latinIME.prefs().edit { putString(Settings.PREF_AUTO_CORRECTION_CONFIDENCE, autoCorrectThreshold) } + latinIME.prefs().edit { putFloat(Settings.PREF_AUTO_CORRECT_THRESHOLD, autoCorrectThreshold) } // enable "more autocorrect" so we actually have autocorrect even though we don't set a compatible input type latinIME.prefs().edit { putBoolean(Settings.PREF_MORE_AUTO_CORRECTION, true) } currentTypingLocale = typingLocale