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