diff --git a/README.md b/README.md index af8d251db..c2468669c 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,9 @@ Changes to OpenBoard: * Fix white background of emoji tab selector on AMOLED theme for some Android versions, https://github.com/Helium314/openboard/pull/26 * Fix issue with spell checker incorrectly flagging words before a period as wrong on newer Android versions, https://github.com/openboard-team/openboard/pull/679 (maybe not properly fixed) * Fix always-dark settings on some Android versions, https://github.com/Helium314/openboard/pull/69 +* Fix bug with space before word being deleted in some apps / input fields, https://github.com/Helium314/openboard/commit/ce0bf06545c4547d3fc5791cc769508db0a89e87 +* Allow using auto theme on some devices with Android 9 +* Add auto theme for the new theming system Further plan / to do: * ~upgrade dependencies~ diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java index 537c4440b..4a44db50e 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardSwitcher.java @@ -99,6 +99,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { final boolean themeUpdated = updateKeyboardThemeAndContextThemeWrapper( displayContext, KeyboardTheme.getKeyboardTheme(displayContext /* context */)); if (themeUpdated && mKeyboardView != null) { + Settings settings = Settings.getInstance(); + settings.loadSettings(displayContext, settings.getCurrent().mLocale, settings.getCurrent().mInputAttributes); mLatinIME.setInputView(onCreateInputView(displayContext, mIsHardwareAcceleratedDrawingEnabled)); } } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardTheme.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardTheme.java index 3fd962923..146ea2f2f 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardTheme.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardTheme.java @@ -345,6 +345,11 @@ public final class KeyboardTheme implements Comparable { if (THEME_VARIANT_HOLO_USER.equals(variant)) return THEME_ID_KLP_CUSTOM; return THEME_ID_KLP; } + // check custom before dayNight, because now both can match + if (THEME_VARIANT_CUSTOM.equals(variant)) { + if (keyBorders) return THEME_ID_LXX_CUSTOM_BORDER; + return THEME_ID_LXX_CUSTOM; + } if (dayNight) { if (keyBorders) return THEME_ID_LXX_AUTO_BORDER; if (amoledMode) return THEME_ID_LXX_AUTO_AMOLED; @@ -355,10 +360,6 @@ public final class KeyboardTheme implements Comparable { if (amoledMode) return THEME_ID_LXX_DARK_AMOLED; return THEME_ID_LXX_DARK; } - if (THEME_VARIANT_CUSTOM.equals(variant)) { - if (keyBorders) return THEME_ID_LXX_CUSTOM_BORDER; - return THEME_ID_LXX_CUSTOM; - } if (keyBorders) return THEME_ID_LXX_LIGHT_BORDER; return THEME_ID_LXX_LIGHT; } @@ -368,7 +369,9 @@ public final class KeyboardTheme implements Comparable { public static final String THEME_DARKER = "darker"; public static final String THEME_BLACK = "black"; public static final String THEME_USER = "user"; + public static final String THEME_USER_DARK = "user_dark"; public static final String[] CUSTOM_THEME_VARIANTS = new String[] { THEME_LIGHT, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_USER }; + public static final String[] CUSTOM_THEME_VARIANTS_DARK = new String[] { THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_USER_DARK }; // todo (later): material you, system accent, ... // todo: copies of original themes might need adjustments, though maybe it's only Colors that needs to be adjusted @@ -381,6 +384,13 @@ public final class KeyboardTheme implements Comparable { final int hintTextColor = prefs.getInt(Settings.PREF_THEME_USER_COLOR_HINT_TEXT, Color.WHITE); final int background = prefs.getInt(Settings.PREF_THEME_USER_COLOR_BACKGROUND, Color.DKGRAY); return new Colors(accent, background, keyBgColor, Colors.brightenOrDarken(keyBgColor, true), keyBgColor, keyTextColor, hintTextColor); + case THEME_USER_DARK: + final int accent2 = prefs.getInt(Settings.PREF_THEME_USER_DARK_COLOR_ACCENT, Color.BLUE); + final int keyBgColor2 = prefs.getInt(Settings.PREF_THEME_USER_DARK_COLOR_KEYS, Color.LTGRAY); + final int keyTextColor2 = prefs.getInt(Settings.PREF_THEME_USER_DARK_COLOR_TEXT, Color.WHITE); + final int hintTextColor2 = prefs.getInt(Settings.PREF_THEME_USER_DARK_COLOR_HINT_TEXT, Color.WHITE); + final int background2 = prefs.getInt(Settings.PREF_THEME_USER_DARK_COLOR_BACKGROUND, Color.DKGRAY); + return new Colors(accent2, background2, keyBgColor2, Colors.brightenOrDarken(keyBgColor2, true), keyBgColor2, keyTextColor2, hintTextColor2); case THEME_DARK: return new Colors( ContextCompat.getColor(context, R.color.gesture_trail_color_lxx_dark), diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.java index e97e3ce76..84994d5d2 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.java @@ -1,7 +1,6 @@ package org.dslul.openboard.inputmethod.latin.common; import android.content.res.ColorStateList; -import android.content.res.Configuration; import android.graphics.Color; import android.graphics.ColorFilter; @@ -55,10 +54,10 @@ public class Colors { } // todo (later): remove this and isCustom, once the old themes can be completely replaced - public Colors(int themeId, int nightModeFlags) { + public Colors(int themeId, final boolean isNight) { isCustom = false; if (KeyboardTheme.getIsDayNight(themeId)) { - if (nightModeFlags == Configuration.UI_MODE_NIGHT_NO) + if (!isNight) navBar = Color.rgb(236, 239, 241); else if (themeId == KeyboardTheme.THEME_ID_LXX_DARK) navBar = Color.rgb(38, 50, 56); diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt index 56d03dc84..9b0863079 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/AppearanceSettingsFragment.kt @@ -16,6 +16,9 @@ package org.dslul.openboard.inputmethod.latin.settings import android.app.AlertDialog +import android.content.SharedPreferences +import android.content.SharedPreferences.OnSharedPreferenceChangeListener +import android.content.res.Configuration import android.graphics.Color import android.os.Build import android.os.Bundle @@ -34,7 +37,8 @@ import java.util.* * "Appearance" settings sub screen. */ @Suppress("Deprecation") // yes everything here is deprecated, but only work on this if really necessary -class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceChangeListener { +// todo: simplify when removing old themes +class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceChangeListener, OnSharedPreferenceChangeListener { private var selectedThemeId = 0 private var needsReload = false @@ -42,6 +46,7 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC private lateinit var themeFamilyPref: ListPreference private lateinit var themeVariantPref: ListPreference private lateinit var customThemeVariantPref: ListPreference + private lateinit var customThemeVariantNightPref: ListPreference private lateinit var keyBordersPref: TwoStatePreference private lateinit var amoledModePref: TwoStatePreference private var dayNightPref: TwoStatePreference? = null @@ -54,8 +59,18 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC val keyboardTheme = KeyboardTheme.getKeyboardTheme(activity) selectedThemeId = keyboardTheme.mThemeId - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) { removePreference(Settings.PREF_THEME_DAY_NIGHT) + removePreference(Settings.PREF_CUSTOM_THEME_VARIANT_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_CUSTOM_THEME_VARIANT_NIGHT) + } } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // todo: consider removing the preference, and always set the navbar color @@ -74,6 +89,7 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC override fun onResume() { super.onResume() updateThemePreferencesState() + updateAfterPreferenceChanged() CustomInputStyleSettingsFragment.updateCustomInputStylesSummary( findPreference(Settings.PREF_CUSTOM_INPUT_STYLES)) } @@ -81,7 +97,6 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC override fun onPause() { super.onPause() if (needsReload) - // todo: is this the correct "displayContext? if not it may cause weird rare issues on some android versions KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(activity) needsReload = false } @@ -94,6 +109,45 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC return true } + override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) { + super.onSharedPreferenceChanged(prefs, key) + updateAfterPreferenceChanged() + } + + // doing things on changing, but with the old values is not good, this is at least a little better + private fun updateAfterPreferenceChanged() { + customThemeVariantNightPref.apply { + if (KeyboardTheme.getIsCustom(selectedThemeId)) { + // show preference to allow choosing a night theme + // can't hide a preference, at least not without category or maybe some androidx things + // -> just disable it instead (for now...) + isEnabled = sharedPreferences.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false) + } else + isEnabled = false + + val variant = sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT_NIGHT, KeyboardTheme.THEME_DARKER) + val variants = KeyboardTheme.CUSTOM_THEME_VARIANTS_DARK + entries = variants.map { + // todo: this workaround get the same string as for "user" theme, maybe clarify that it's a separate theme + val name = if (it == "user_dark") "theme_name_user" else "theme_name_$it" + val resId = resources.getIdentifier(name, "string", activity.packageName) + if (resId == 0) it else getString(resId) + }.toTypedArray() + entryValues = variants + value = variant + val name = if (variant == "user_dark") "theme_name_user" else "theme_name_$variant" + val resId = resources.getIdentifier(name, "string", activity.packageName) + summary = if (resId == 0) variant else getString(resId) + } + userColorsPref.apply { + isEnabled = KeyboardTheme.getIsCustom(selectedThemeId) + && (sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT, KeyboardTheme.THEME_LIGHT) == KeyboardTheme.THEME_USER + || (sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT_NIGHT, KeyboardTheme.THEME_DARKER) == KeyboardTheme.THEME_USER_DARK + && sharedPreferences.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false) + )) + } + } + private fun saveSelectedThemeId( family: String = themeFamilyPref.value, variant: String = themeVariantPref.value, @@ -127,10 +181,6 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC } customThemeVariantPref.apply { val variant = sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT, KeyboardTheme.THEME_LIGHT) - // todo: some way of following system, with setting a dark and a light theme - // check whether night mode is active using context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK - // this is needed so the auto-theme can be replaced - // idea: add a "dark theme variant" preference when auto-switch is on // todo (idea): re-work setting to actually see preview of theme colors... but that's a lot of work val variants = KeyboardTheme.CUSTOM_THEME_VARIANTS entries = variants.map { @@ -154,11 +204,10 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC isChecked = !isLegacyFamily && KeyboardTheme.getIsAmoledMode(selectedThemeId) } dayNightPref?.apply { - isEnabled = !isLegacyFamily && !KeyboardTheme.getIsCustom(selectedThemeId) - isChecked = !isLegacyFamily && !KeyboardTheme.getIsCustom(selectedThemeId) && KeyboardTheme.getIsDayNight(selectedThemeId) - } - userColorsPref.apply { - isEnabled = KeyboardTheme.getIsCustom(selectedThemeId) && sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT, KeyboardTheme.THEME_LIGHT) == KeyboardTheme.THEME_USER + isEnabled = !isLegacyFamily + isChecked = !isLegacyFamily && (KeyboardTheme.getIsDayNight(selectedThemeId) + || (KeyboardTheme.getIsCustom(selectedThemeId) && sharedPreferences.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false)) + ) } } @@ -225,27 +274,34 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC true } } + customThemeVariantNightPref = preferenceScreen.findPreference(Settings.PREF_CUSTOM_THEME_VARIANT_NIGHT) as ListPreference + customThemeVariantNightPref.apply { + title = "$title new (night)" // todo: remove, this is just a workaround while there are still 2 ways of selecting variant + onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, value -> + // not so nice workaround, could be removed in the necessary re-work: new value seems + // to be stored only after this method call, but we update the summary and user-defined color enablement in here -> store it now + if (value == sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT_NIGHT, KeyboardTheme.THEME_DARK)) + return@OnPreferenceChangeListener true // avoid infinite loop + sharedPreferences.edit { putString(Settings.PREF_CUSTOM_THEME_VARIANT_NIGHT, value as String) } + + summary = entries[entryValues.indexOfFirst { it == value }] + needsReload = true + + true + } + } userColorsPref = preferenceScreen.findPreference(Settings.PREF_THEME_USER) userColorsPref.onPreferenceClickListener = Preference.OnPreferenceClickListener { _ -> - val items = listOf(R.string.select_color_background, R.string.select_color_key, R.string.select_color_key_hint, R.string.select_color_accent, R.string.select_color_key_background) - .map { activity.getString(it) } - val itemsArray = if (keyBordersPref.isChecked) items.toTypedArray() - else items.subList(0, 4).toTypedArray() - AlertDialog.Builder(activity) - .setPositiveButton(android.R.string.ok, null) - .setTitle(R.string.select_color_to_adjust) - .setItems(itemsArray) { _, i -> - val (pref, default) = when (i) { - 0 -> Settings.PREF_THEME_USER_COLOR_BACKGROUND to Color.DKGRAY - 1 -> Settings.PREF_THEME_USER_COLOR_TEXT to Color.WHITE - 2 -> Settings.PREF_THEME_USER_COLOR_HINT_TEXT to Color.WHITE - 3 -> Settings.PREF_THEME_USER_COLOR_ACCENT to Color.BLUE - else -> Settings.PREF_THEME_USER_COLOR_KEYS to Color.LTGRAY - } - val d = ColorPickerDialog(activity, items[i], sharedPreferences, pref, default) { needsReload = true} - d.show() - } - .show() + if (sharedPreferences.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false) && sharedPreferences.getString(Settings.PREF_CUSTOM_THEME_VARIANT, KeyboardTheme.THEME_LIGHT) == KeyboardTheme.THEME_USER) + AlertDialog.Builder(activity) + .setMessage(R.string.day_or_night_colors) + .setPositiveButton(R.string.day_or_night_night) { _, _ -> adjustColors(true)} + .setNegativeButton(R.string.day_or_night_day) { _, _ -> adjustColors(false)} + .show() + else if (sharedPreferences.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false)) // only night theme custom + adjustColors(true) + else // customize day theme + adjustColors(false) true } preferenceScreen.findPreference(Settings.PREF_NARROW_KEY_GAPS)?.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, _ -> @@ -254,6 +310,38 @@ class AppearanceSettingsFragment : SubScreenFragment(), Preference.OnPreferenceC } } + private fun adjustColors(dark: Boolean) { + val items = listOf(R.string.select_color_background, R.string.select_color_key, R.string.select_color_key_hint, R.string.select_color_accent, R.string.select_color_key_background) + .map { activity.getString(it) } + val itemsArray = if (keyBordersPref.isChecked) items.toTypedArray() + else items.subList(0, 4).toTypedArray() + AlertDialog.Builder(activity) + .setPositiveButton(android.R.string.ok, null) + .setTitle(R.string.select_color_to_adjust) + .setItems(itemsArray) { _, i -> + val (pref, default) = + if (dark) + when (i) { + 0 -> Settings.PREF_THEME_USER_DARK_COLOR_BACKGROUND to Color.DKGRAY + 1 -> Settings.PREF_THEME_USER_DARK_COLOR_TEXT to Color.WHITE + 2 -> Settings.PREF_THEME_USER_DARK_COLOR_HINT_TEXT to Color.WHITE + 3 -> Settings.PREF_THEME_USER_DARK_COLOR_ACCENT to Color.BLUE + else -> Settings.PREF_THEME_USER_DARK_COLOR_KEYS to Color.LTGRAY + } + else + when (i) { + 0 -> Settings.PREF_THEME_USER_COLOR_BACKGROUND to Color.DKGRAY + 1 -> Settings.PREF_THEME_USER_COLOR_TEXT to Color.WHITE + 2 -> Settings.PREF_THEME_USER_COLOR_HINT_TEXT to Color.WHITE + 3 -> Settings.PREF_THEME_USER_COLOR_ACCENT to Color.BLUE + else -> Settings.PREF_THEME_USER_COLOR_KEYS to Color.LTGRAY + } + val d = ColorPickerDialog(activity, items[i], sharedPreferences, pref, default) { needsReload = true} + d.show() + } + .show() + } + private fun setupKeyboardHeight(prefKey: String, defaultValue: Float) { val prefs = sharedPreferences val pref = findPreference(prefKey) as? SeekBarDialogPreference diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java index 986a72b1c..ae76dbce5 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/settings/Settings.java @@ -65,6 +65,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_THEME_FAMILY = "theme_family"; public static final String PREF_THEME_VARIANT = "theme_variant"; public static final String PREF_CUSTOM_THEME_VARIANT = "custom_theme_variant"; + public static final String PREF_CUSTOM_THEME_VARIANT_NIGHT = "custom_theme_variant_night"; public static final String PREF_THEME_KEY_BORDERS = "theme_key_borders"; public static final String PREF_THEME_DAY_NIGHT = "theme_auto_day_night"; public static final String PREF_THEME_AMOLED_MODE = "theme_amoled_mode"; @@ -74,6 +75,11 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang public static final String PREF_THEME_USER_COLOR_BACKGROUND = "theme_color_background"; public static final String PREF_THEME_USER_COLOR_KEYS = "theme_color_keys"; public static final String PREF_THEME_USER_COLOR_ACCENT = "theme_color_accent"; + public static final String PREF_THEME_USER_DARK_COLOR_TEXT = "theme_dark_color_text"; + public static final String PREF_THEME_USER_DARK_COLOR_HINT_TEXT = "theme_dark_color_hint_text"; + public static final String PREF_THEME_USER_DARK_COLOR_BACKGROUND = "theme_dark_color_background"; + public static final String PREF_THEME_USER_DARK_COLOR_KEYS = "theme_dark_color_keys"; + public static final String PREF_THEME_USER_DARK_COLOR_ACCENT = "theme_dark_color_accent"; // PREF_VOICE_MODE_OBSOLETE is obsolete. Use PREF_VOICE_INPUT_KEY instead. public static final String PREF_VOICE_MODE_OBSOLETE = "voice_mode"; public static final String PREF_VOICE_INPUT_KEY = "pref_voice_input_key"; @@ -557,9 +563,13 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang prefs.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false), prefs.getBoolean(Settings.PREF_THEME_AMOLED_MODE, false) ); + // todo: night mode can be unspecified -> maybe need to adjust for correct behavior on some devices? + final boolean isNight = (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; if (!KeyboardTheme.getIsCustom(keyboardThemeId)) - return new Colors(keyboardThemeId, context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK); + return new Colors(keyboardThemeId, isNight); + if (isNight && prefs.getBoolean(Settings.PREF_THEME_DAY_NIGHT, false)) + return KeyboardTheme.getCustomTheme(prefs.getString(Settings.PREF_CUSTOM_THEME_VARIANT_NIGHT, KeyboardTheme.THEME_DARKER), context, prefs); return KeyboardTheme.getCustomTheme(prefs.getString(Settings.PREF_CUSTOM_THEME_VARIANT, KeyboardTheme.THEME_LIGHT), context, prefs); } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 712c66be6..6191817bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -640,6 +640,12 @@ disposition rather than other common dispositions for Latin languages. [CHAR LIM Key borders Auto day/night mode + + Edit day or night colors? + + Day + + Night Appearance will follow system settings diff --git a/app/src/main/res/xml/prefs_screen_appearance.xml b/app/src/main/res/xml/prefs_screen_appearance.xml index cb28080a9..29365595f 100644 --- a/app/src/main/res/xml/prefs_screen_appearance.xml +++ b/app/src/main/res/xml/prefs_screen_appearance.xml @@ -35,6 +35,10 @@ android:key="custom_theme_variant" android:title="@string/theme_variant"/> + +