allow customizing all colors, fixes #529

This commit is contained in:
Helium314 2024-05-18 20:27:22 +02:00
parent eada9bc51c
commit 77f03b0756
8 changed files with 158 additions and 65 deletions

View file

@ -133,7 +133,6 @@ __Planned features and improvements:__
* Additional and customizable key swipe functionality * Additional and customizable key swipe functionality
* Some functionality will not be possible when using glide typing * Some functionality will not be possible when using glide typing
* Ability to enter all emojis independent of Android version (optional, #297) * Ability to enter all emojis independent of Android version (optional, #297)
* (limited) support for customizing _all_ internally used colors
* Add and enable emoji dictionaries by default (if available for language) * Add and enable emoji dictionaries by default (if available for language)
* Clearer / more intuitive arrangement of settings * Clearer / more intuitive arrangement of settings
* Maybe hide some less used settings by default (similar to color customization) * Maybe hide some less used settings by default (similar to color customization)

View file

@ -12,9 +12,11 @@ import android.os.Build
import android.os.Build.VERSION_CODES import android.os.Build.VERSION_CODES
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.common.AllColors
import helium314.keyboard.latin.common.Colors import helium314.keyboard.latin.common.Colors
import helium314.keyboard.latin.common.DefaultColors import helium314.keyboard.latin.common.DefaultColors
import helium314.keyboard.latin.common.DynamicColors import helium314.keyboard.latin.common.DynamicColors
import helium314.keyboard.latin.common.readAllColorsMap
import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.DeviceProtectedUtils import helium314.keyboard.latin.utils.DeviceProtectedUtils
import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.ResourceUtils
@ -101,10 +103,11 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
@JvmStatic @JvmStatic
fun getThemeColors(themeColors: String, themeStyle: String, context: Context, prefs: SharedPreferences): Colors { fun getThemeColors(themeColors: String, themeStyle: String, context: Context, prefs: SharedPreferences): Colors {
val hasBorders = prefs.getBoolean(Settings.PREF_THEME_KEY_BORDERS, false) val hasBorders = prefs.getBoolean(Settings.PREF_THEME_KEY_BORDERS, false)
val useNightImage = Settings.readDayNightPref(prefs, context.resources) && ResourceUtils.isNight(context.resources) val useNightMode = Settings.readDayNightPref(prefs, context.resources) && ResourceUtils.isNight(context.resources)
val backgroundImage = Settings.readUserBackgroundImage(context, useNightImage) val backgroundImage = Settings.readUserBackgroundImage(context, useNightMode)
return when (themeColors) { return when (themeColors) {
THEME_USER -> DefaultColors( THEME_USER -> if (prefs.getInt(Settings.PREF_SHOW_MORE_COLORS, 0) == 2) AllColors(readAllColorsMap(prefs, false), themeStyle, hasBorders, backgroundImage)
else DefaultColors(
themeStyle, themeStyle,
hasBorders, hasBorders,
Settings.readUserColor(prefs, context, Settings.PREF_COLOR_ACCENT_SUFFIX, false), Settings.readUserColor(prefs, context, Settings.PREF_COLOR_ACCENT_SUFFIX, false),
@ -119,7 +122,8 @@ private constructor(val themeId: Int, @JvmField val mStyleId: Int) {
Settings.readUserColor(prefs, context, Settings.PREF_COLOR_GESTURE_SUFFIX, false), Settings.readUserColor(prefs, context, Settings.PREF_COLOR_GESTURE_SUFFIX, false),
keyboardBackground = backgroundImage keyboardBackground = backgroundImage
) )
THEME_USER_NIGHT -> DefaultColors( THEME_USER_NIGHT -> if (prefs.getInt(Settings.PREF_SHOW_MORE_COLORS, 0) == 2) AllColors(readAllColorsMap(prefs, true), themeStyle, hasBorders, backgroundImage)
else DefaultColors(
themeStyle, themeStyle,
hasBorders, hasBorders,
Settings.readUserColor(prefs, context, Settings.PREF_COLOR_ACCENT_SUFFIX, true), Settings.readUserColor(prefs, context, Settings.PREF_COLOR_ACCENT_SUFFIX, true),

View file

@ -27,7 +27,6 @@ import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import helium314.keyboard.keyboard.emoji.EmojiPageKeyboardView;
import helium314.keyboard.keyboard.internal.KeyDrawParams; import helium314.keyboard.keyboard.internal.KeyDrawParams;
import helium314.keyboard.keyboard.internal.KeyVisualAttributes; import helium314.keyboard.keyboard.internal.KeyVisualAttributes;
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode;
@ -107,8 +106,8 @@ public class KeyboardView extends View {
final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs, final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs,
R.styleable.KeyboardView, defStyle, R.style.KeyboardView); R.styleable.KeyboardView, defStyle, R.style.KeyboardView);
if (this instanceof EmojiPageKeyboardView || this instanceof PopupSuggestionsView) if (this instanceof PopupSuggestionsView)
mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.BACKGROUND); mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.MORE_SUGGESTIONS_WORD_BACKGROUND);
else if (this instanceof PopupKeysKeyboardView) else if (this instanceof PopupKeysKeyboardView)
mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.POPUP_KEYS_BACKGROUND); mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.POPUP_KEYS_BACKGROUND);
else else

View file

@ -29,6 +29,7 @@ import helium314.keyboard.keyboard.KeyboardTheme.Companion.STYLE_HOLO
import helium314.keyboard.keyboard.KeyboardTheme.Companion.STYLE_MATERIAL import helium314.keyboard.keyboard.KeyboardTheme.Companion.STYLE_MATERIAL
import helium314.keyboard.latin.common.ColorType.* import helium314.keyboard.latin.common.ColorType.*
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.settings.Settings
import helium314.keyboard.latin.utils.adjustLuminosityAndKeepAlpha import helium314.keyboard.latin.utils.adjustLuminosityAndKeepAlpha
import helium314.keyboard.latin.utils.brighten import helium314.keyboard.latin.utils.brighten
import helium314.keyboard.latin.utils.brightenOrDarken import helium314.keyboard.latin.utils.brightenOrDarken
@ -63,7 +64,7 @@ interface Colors {
/** returns a colored drawable selected from [attr], which must contain using R.styleable.KeyboardView_* */ /** returns a colored drawable selected from [attr], which must contain using R.styleable.KeyboardView_* */
fun selectAndColorDrawable(attr: TypedArray, color: ColorType): Drawable { fun selectAndColorDrawable(attr: TypedArray, color: ColorType): Drawable {
val drawable = when (color) { val drawable = when (color) {
KEY_BACKGROUND, BACKGROUND, ACTION_KEY_POPUP_KEYS_BACKGROUND, POPUP_KEYS_BACKGROUND -> KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, ACTION_KEY_POPUP_KEYS_BACKGROUND, POPUP_KEYS_BACKGROUND ->
attr.getDrawable(R.styleable.KeyboardView_keyBackground) attr.getDrawable(R.styleable.KeyboardView_keyBackground)
FUNCTIONAL_KEY_BACKGROUND -> attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) FUNCTIONAL_KEY_BACKGROUND -> attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground)
SPACE_BAR_BACKGROUND -> { SPACE_BAR_BACKGROUND -> {
@ -281,7 +282,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
SPACE_BAR_TEXT -> spaceBarText SPACE_BAR_TEXT -> spaceBarText
FUNCTIONAL_KEY_BACKGROUND -> functionalKey FUNCTIONAL_KEY_BACKGROUND -> functionalKey
SPACE_BAR_BACKGROUND -> spaceBar SPACE_BAR_BACKGROUND -> spaceBar
BACKGROUND, MAIN_BACKGROUND -> background MORE_SUGGESTIONS_WORD_BACKGROUND, MAIN_BACKGROUND -> background
KEY_BACKGROUND -> keyBackground KEY_BACKGROUND -> keyBackground
ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent
STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background
@ -292,7 +293,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override
override fun setColor(drawable: Drawable, color: ColorType) { override fun setColor(drawable: Drawable, color: ColorType) {
val colorStateList = when (color) { val colorStateList = when (color) {
BACKGROUND -> backgroundStateList MORE_SUGGESTIONS_WORD_BACKGROUND -> backgroundStateList
KEY_BACKGROUND -> keyStateList KEY_BACKGROUND -> keyStateList
FUNCTIONAL_KEY_BACKGROUND -> functionalKeyStateList FUNCTIONAL_KEY_BACKGROUND -> functionalKeyStateList
ACTION_KEY_BACKGROUND -> actionKeyStateList ACTION_KEY_BACKGROUND -> actionKeyStateList
@ -334,8 +335,8 @@ class DynamicColors(context: Context, override val themeStyle: String, override
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) { when (color) {
KEY_PREVIEW -> view.background.colorFilter = adjustedBackgroundFilter KEY_PREVIEW -> view.background.colorFilter = adjustedBackgroundFilter
FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND -> setColor(view.background, color) FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND -> setColor(view.background, color)
ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) BACKGROUND else STRIP_BACKGROUND) ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
POPUP_KEYS_BACKGROUND -> POPUP_KEYS_BACKGROUND ->
if (themeStyle != STYLE_HOLO) if (themeStyle != STYLE_HOLO)
@ -473,7 +474,7 @@ class DefaultColors (
SPACE_BAR_TEXT -> spaceBarText SPACE_BAR_TEXT -> spaceBarText
FUNCTIONAL_KEY_BACKGROUND -> functionalKey FUNCTIONAL_KEY_BACKGROUND -> functionalKey
SPACE_BAR_BACKGROUND -> spaceBar SPACE_BAR_BACKGROUND -> spaceBar
BACKGROUND, MAIN_BACKGROUND -> background MORE_SUGGESTIONS_WORD_BACKGROUND, MAIN_BACKGROUND -> background
KEY_BACKGROUND -> keyBackground KEY_BACKGROUND -> keyBackground
ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent ACTION_KEY_POPUP_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent
STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background STRIP_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background
@ -485,7 +486,7 @@ class DefaultColors (
override fun setColor(drawable: Drawable, color: ColorType) { override fun setColor(drawable: Drawable, color: ColorType) {
val colorStateList = when (color) { val colorStateList = when (color) {
BACKGROUND -> backgroundStateList MORE_SUGGESTIONS_WORD_BACKGROUND -> backgroundStateList
KEY_BACKGROUND -> keyStateList KEY_BACKGROUND -> keyStateList
FUNCTIONAL_KEY_BACKGROUND -> functionalKeyStateList FUNCTIONAL_KEY_BACKGROUND -> functionalKeyStateList
ACTION_KEY_BACKGROUND -> actionKeyStateList ACTION_KEY_BACKGROUND -> actionKeyStateList
@ -518,8 +519,8 @@ class DefaultColors (
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) { when (color) {
KEY_PREVIEW, POPUP_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter KEY_PREVIEW, POPUP_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter
FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND -> setColor(view.background, color) FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, MORE_SUGGESTIONS_WORD_BACKGROUND, SPACE_BAR_BACKGROUND, STRIP_BACKGROUND -> setColor(view.background, color)
ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) BACKGROUND else STRIP_BACKGROUND) ONE_HANDED_MODE_BUTTON -> setColor(view.background, if (keyboardBackground == null) MAIN_BACKGROUND else STRIP_BACKGROUND)
MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter
MAIN_BACKGROUND -> { MAIN_BACKGROUND -> {
if (keyboardBackground != null) { if (keyboardBackground != null) {
@ -546,17 +547,12 @@ class DefaultColors (
} }
} }
// todo: allow users to use this class class AllColors(private val colorMap: EnumMap<ColorType, Int>, override val themeStyle: String, override val hasKeyBorders: Boolean, backgroundImage: Drawable?) : Colors {
// the colorMap should be stored in settings private var keyboardBackground: Drawable? = backgroundImage
// settings read and write untested
// color settings should add another menu option for "all colors"
// just show all ColorTypes with current value read from the map (default to black, same as in get)
// no string name, as it is not stable
class AllColors(private val colorMap: EnumMap<ColorType, Int>, override val themeStyle: String, override val hasKeyBorders: Boolean) : Colors {
private var keyboardBackground: Drawable? = null
private val stateListMap = EnumMap<ColorType, ColorStateList>(ColorType::class.java) private val stateListMap = EnumMap<ColorType, ColorStateList>(ColorType::class.java)
private var backgroundSetupDone = false private var backgroundSetupDone = false
override fun get(color: ColorType): Int = colorMap[color] ?: Color.BLACK private val colorFilters = hashMapOf<ColorType, ColorFilter>()
override fun get(color: ColorType): Int = colorMap[color] ?: Color.GRAY
override fun setColor(drawable: Drawable, color: ColorType) { override fun setColor(drawable: Drawable, color: ColorType) {
val colorStateList = stateListMap.getOrPut(color) { stateList(brightenOrDarken(get(color), true), get(color)) } val colorStateList = stateListMap.getOrPut(color) { stateList(brightenOrDarken(get(color), true), get(color)) }
@ -565,14 +561,18 @@ class AllColors(private val colorMap: EnumMap<ColorType, Int>, override val them
} }
override fun setColor(view: ImageView, color: ColorType) { override fun setColor(view: ImageView, color: ColorType) {
if (color == TOOL_BAR_KEY) {
setColor(view.drawable, color) setColor(view.drawable, color)
return
}
view.colorFilter = getColorFilter(color)
} }
override fun setBackground(view: View, color: ColorType) { override fun setBackground(view: View, color: ColorType) {
if (view.background == null) if (view.background == null)
view.setBackgroundColor(Color.WHITE) // set white to make the color filters work view.setBackgroundColor(Color.WHITE) // set white to make the color filters work
when (color) { when (color) {
ONE_HANDED_MODE_BUTTON -> setColor(view.background, BACKGROUND) // button has no separate background color ONE_HANDED_MODE_BUTTON -> setColor(view.background, MAIN_BACKGROUND) // button has no separate background color
MAIN_BACKGROUND -> { MAIN_BACKGROUND -> {
if (keyboardBackground != null) { if (keyboardBackground != null) {
if (!backgroundSetupDone) { if (!backgroundSetupDone) {
@ -587,25 +587,32 @@ class AllColors(private val colorMap: EnumMap<ColorType, Int>, override val them
else -> setColor(view.background, color) else -> setColor(view.background, color)
} }
} }
private fun getColorFilter(color: ColorType) = colorFilters.getOrPut(color) { colorFilter(get(color)) }
} }
fun readAllColorsMap(prefs: SharedPreferences): EnumMap<ColorType, Int> { fun readAllColorsMap(prefs: SharedPreferences, isNight: Boolean): EnumMap<ColorType, Int> {
val s = prefs.getString("all_colors", "") ?: "" val prefPrefix = if (isNight) Settings.PREF_THEME_USER_COLOR_NIGHT_PREFIX else Settings.PREF_THEME_USER_COLOR_PREFIX
val c = EnumMap<ColorType, Int>(ColorType::class.java) val colorsString = prefs.getString(prefPrefix + Settings.PREF_ALL_COLORS_SUFFIX, "") ?: ""
s.split(";").forEach { val colorMap = EnumMap<ColorType, Int>(ColorType::class.java)
colorsString.split(";").forEach {
val ct = try { val ct = try {
ColorType.valueOf(it.substringBefore(",").uppercase()) ColorType.valueOf(it.substringBefore(",").uppercase())
} catch (_: Exception) { // todo: which one? } catch (_: Exception) { // todo: which one?
return@forEach return@forEach
} }
val i = it.substringAfter(",").toIntOrNull() ?: return@forEach val i = it.substringAfter(",").toIntOrNull() ?: return@forEach
c[ct] = i colorMap[ct] = i
} }
return c return colorMap
} }
fun writeAllColorsMap(c: EnumMap<ColorType, Int>, prefs: SharedPreferences) { fun writeAllColorsMap(colorMap: EnumMap<ColorType, Int>, prefs: SharedPreferences, isNight: Boolean) {
prefs.edit { putString("all_colors", c.map { "${it.key},${it.value}" }.joinToString(";")) } val prefPrefix = if (isNight) Settings.PREF_THEME_USER_COLOR_NIGHT_PREFIX else Settings.PREF_THEME_USER_COLOR_PREFIX
prefs.edit { putString(
prefPrefix + Settings.PREF_ALL_COLORS_SUFFIX,
colorMap.map { "${it.key},${it.value}" }.joinToString(";")
) }
} }
private fun colorFilter(color: Int, mode: BlendModeCompat = BlendModeCompat.MODULATE): ColorFilter { private fun colorFilter(color: Int, mode: BlendModeCompat = BlendModeCompat.MODULATE): ColorFilter {
@ -628,7 +635,6 @@ enum class ColorType {
ACTION_KEY_BACKGROUND, ACTION_KEY_BACKGROUND,
ACTION_KEY_POPUP_KEYS_BACKGROUND, ACTION_KEY_POPUP_KEYS_BACKGROUND,
AUTOFILL_BACKGROUND_CHIP, AUTOFILL_BACKGROUND_CHIP,
BACKGROUND,
CLIPBOARD_PIN, CLIPBOARD_PIN,
EMOJI_CATEGORY, EMOJI_CATEGORY,
EMOJI_CATEGORY_SELECTED, EMOJI_CATEGORY_SELECTED,
@ -643,6 +649,7 @@ enum class ColorType {
KEY_PREVIEW, KEY_PREVIEW,
MORE_SUGGESTIONS_HINT, MORE_SUGGESTIONS_HINT,
MORE_SUGGESTIONS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND,
MORE_SUGGESTIONS_WORD_BACKGROUND,
POPUP_KEYS_BACKGROUND, POPUP_KEYS_BACKGROUND,
NAVIGATION_BAR, NAVIGATION_BAR,
SHIFT_KEY_ICON, SHIFT_KEY_ICON,

View file

@ -2,6 +2,7 @@
package helium314.keyboard.latin.settings package helium314.keyboard.latin.settings
import android.content.res.Configuration import android.content.res.Configuration
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuInflater import android.view.MenuInflater
@ -15,12 +16,15 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.edit import androidx.core.content.edit
import androidx.core.view.MenuProvider import androidx.core.view.MenuProvider
import androidx.core.view.forEach import androidx.core.view.forEach
import androidx.core.view.get import androidx.core.view.isGone
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.rarepebble.colorpicker.ColorPickerView import com.rarepebble.colorpicker.ColorPickerView
import helium314.keyboard.keyboard.KeyboardSwitcher import helium314.keyboard.keyboard.KeyboardSwitcher
import helium314.keyboard.latin.R import helium314.keyboard.latin.R
import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.RichInputMethodManager
import helium314.keyboard.latin.common.ColorType
import helium314.keyboard.latin.common.readAllColorsMap
import helium314.keyboard.latin.common.writeAllColorsMap
import helium314.keyboard.latin.databinding.ColorSettingBinding import helium314.keyboard.latin.databinding.ColorSettingBinding
import helium314.keyboard.latin.databinding.ColorSettingsBinding import helium314.keyboard.latin.databinding.ColorSettingsBinding
import helium314.keyboard.latin.utils.DeviceProtectedUtils import helium314.keyboard.latin.utils.DeviceProtectedUtils
@ -32,9 +36,14 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
private val binding by viewBinding(ColorSettingsBinding::bind) private val binding by viewBinding(ColorSettingsBinding::bind)
open val isNight = false open val isNight = false
open val titleResId = R.string.select_user_colors open val titleResId = R.string.select_user_colors
private var moreColors: Boolean
get() = prefs.getBoolean(Settings.PREF_SHOW_ALL_COLORS, false) // 0 for default
set(value) { prefs.edit().putBoolean(Settings.PREF_SHOW_ALL_COLORS, value).apply() } // 1 for more colors
// 2 for all colors
private var moreColors: Int
get() = prefs.getInt(Settings.PREF_SHOW_MORE_COLORS, 0)
set(value) { prefs.edit().putInt(Settings.PREF_SHOW_MORE_COLORS, value).apply() }
private val prefs by lazy { DeviceProtectedUtils.getSharedPreferences(requireContext()) } private val prefs by lazy { DeviceProtectedUtils.getSharedPreferences(requireContext()) }
private val colorPrefsAndNames by lazy { private val colorPrefsAndNames by lazy {
@ -83,24 +92,28 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
} }
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
if (menu.size() == 1) menu[0].setTitle(getMenuTitle()) menu.add(Menu.NONE, 0, Menu.NONE, R.string.main_colors)
else menu.add(Menu.NONE, 1, Menu.NONE, getMenuTitle()) menu.add(Menu.NONE, 1, Menu.NONE, R.string.more_colors)
menu.add(Menu.NONE, 2, Menu.NONE, R.string.all_colors)
} }
override fun onMenuItemSelected(menuItem: MenuItem): Boolean { override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
// necessary, even though we only have a single menu item // necessary, even though we only have a single menu item
// because the back arrow on top absurdly is implemented as a menu item // because the back arrow on top absurdly is implemented as a menu item
if (menuItem.itemId == 1) { if (menuItem.itemId in 0..2) {
moreColors = !moreColors if (moreColors == menuItem.itemId) return true
menuItem.setTitle(getMenuTitle()) if (moreColors == 2 || menuItem.itemId == 2) {
RichInputMethodManager.getInstance().inputMethodManager.hideSoftInputFromWindow(binding.dummyText.windowToken, 0)
reloadKeyboard(false)
}
moreColors = menuItem.itemId
binding.info.isGone = menuItem.itemId != 2
updateColorPrefs() updateColorPrefs()
return true return true
} }
return false return false
} }
private fun getMenuTitle() = if (moreColors) R.string.main_colors else R.string.all_colors
override fun onViewStateRestored(savedInstanceState: Bundle?) { override fun onViewStateRestored(savedInstanceState: Bundle?) {
super.onViewStateRestored(savedInstanceState) super.onViewStateRestored(savedInstanceState)
// updateColorPrefs must be called after super.onViewStateRestored because for some reason Android // updateColorPrefs must be called after super.onViewStateRestored because for some reason Android
@ -110,10 +123,61 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
private fun updateColorPrefs() { private fun updateColorPrefs() {
binding.colorSettingsContainer.removeAllViews() binding.colorSettingsContainer.removeAllViews()
if (moreColors == 2) showAllColors()
else showMainColors()
}
private fun showAllColors() {
val colors = readAllColorsMap(prefs, isNight)
ColorType.entries.forEach { type ->
val color = colors[type] ?: Color.GRAY
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() {
val prefPrefix = if (isNight) Settings.PREF_THEME_USER_COLOR_NIGHT_PREFIX else Settings.PREF_THEME_USER_COLOR_PREFIX val prefPrefix = if (isNight) Settings.PREF_THEME_USER_COLOR_NIGHT_PREFIX else Settings.PREF_THEME_USER_COLOR_PREFIX
colorPrefsAndNames.forEachIndexed { index, (colorPref, colorPrefName) -> colorPrefsAndNames.forEachIndexed { index, (colorPref, colorPrefName) ->
val autoColor = prefs.getBoolean(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, true) val autoColor = prefs.getBoolean(prefPrefix + colorPref + Settings.PREF_AUTO_USER_COLOR_SUFFIX, true)
if (!moreColors && colorPref in colorPrefsToHideInitially && autoColor) if (moreColors == 0 && colorPref in colorPrefsToHideInitially && autoColor)
return@forEachIndexed return@forEachIndexed
val csb = ColorSettingBinding.inflate(layoutInflater, binding.colorSettingsContainer, true) val csb = ColorSettingBinding.inflate(layoutInflater, binding.colorSettingsContainer, true)
csb.root.tag = index csb.root.tag = index
@ -129,7 +193,7 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
if (b) csb.colorSummary.text = "" if (b) csb.colorSummary.text = ""
else csb.colorSummary.setText(R.string.auto_user_color) else csb.colorSummary.setText(R.string.auto_user_color)
reloadKeyboard(hidden) reloadKeyboard(hidden)
updateColorPreviews() updateMainColorPreviews()
} }
csb.colorSwitch.setOnCheckedChangeListener(switchListener) csb.colorSwitch.setOnCheckedChangeListener(switchListener)
@ -160,6 +224,7 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
builder builder
.setTitle(colorPrefName) .setTitle(colorPrefName)
.setView(picker) .setView(picker)
.setCancelable(false)
.setNegativeButton(android.R.string.cancel, null) .setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok) { _, _ -> .setPositiveButton(android.R.string.ok) { _, _ ->
prefs.edit { putInt(prefPrefix + colorPref, picker.color) } prefs.edit { putInt(prefPrefix + colorPref, picker.color) }
@ -169,9 +234,9 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
csb.colorSwitch.isChecked = true csb.colorSwitch.isChecked = true
csb.colorSummary.text = "" csb.colorSummary.text = ""
csb.colorSwitch.setOnCheckedChangeListener(switchListener) csb.colorSwitch.setOnCheckedChangeListener(switchListener)
updateColorPreviews() updateMainColorPreviews()
} else { } else {
updateColorPreviews() updateMainColorPreviews()
} }
reloadKeyboard(hidden) reloadKeyboard(hidden)
} }
@ -199,14 +264,23 @@ open class ColorsSettingsFragment : Fragment(R.layout.color_settings), MenuProvi
} }
} }
private fun updateColorPreviews() { private fun updateMainColorPreviews() {
binding.colorSettingsContainer.forEach { view -> binding.colorSettingsContainer.forEach { view ->
val index = view.tag as Int val index = view.tag as? Int ?: return@forEach
val color = Settings.readUserColor(prefs, requireContext(), colorPrefsAndNames[index].first, isNight) val color = Settings.readUserColor(prefs, requireContext(), colorPrefsAndNames[index].first, isNight)
view.findViewById<ImageView>(R.id.color_preview)?.setColorFilter(color) view.findViewById<ImageView>(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] ?: Color.GRAY
view.findViewById<ImageView>(R.id.color_preview)?.setColorFilter(color)
}
}
private fun reloadKeyboard(show: Boolean) { private fun reloadKeyboard(show: Boolean) {
ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute { ExecutorUtils.getBackgroundExecutor(ExecutorUtils.KEYBOARD).execute {
KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext()) KeyboardSwitcher.getInstance().forceUpdateKeyboardTheme(requireContext())

View file

@ -79,6 +79,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_COLOR_HINT_TEXT_SUFFIX = "hint_text"; public static final String PREF_COLOR_HINT_TEXT_SUFFIX = "hint_text";
public static final String PREF_COLOR_BACKGROUND_SUFFIX = "background"; public static final String PREF_COLOR_BACKGROUND_SUFFIX = "background";
public static final String PREF_AUTO_USER_COLOR_SUFFIX = "_auto"; public static final String PREF_AUTO_USER_COLOR_SUFFIX = "_auto";
public static final String PREF_ALL_COLORS_SUFFIX = "all_colors";
public static final String PREF_AUTO_CAP = "auto_cap"; public static final String PREF_AUTO_CAP = "auto_cap";
public static final String PREF_VIBRATE_ON = "vibrate_on"; public static final String PREF_VIBRATE_ON = "vibrate_on";
@ -158,7 +159,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_PINNED_CLIPS = "pinned_clips"; public static final String PREF_PINNED_CLIPS = "pinned_clips";
public static final String PREF_VERSION_CODE = "version_code"; public static final String PREF_VERSION_CODE = "version_code";
public static final String PREF_SHOW_ALL_COLORS = "show_all_colors"; public static final String PREF_SHOW_MORE_COLORS = "show_more_colors";
public static final String PREF_LIBRARY_CHECKSUM = "lib_checksum"; public static final String PREF_LIBRARY_CHECKSUM = "lib_checksum";
private static final float UNDEFINED_PREFERENCE_VALUE_FLOAT = -1.0f; private static final float UNDEFINED_PREFERENCE_VALUE_FLOAT = -1.0f;
@ -182,7 +183,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
add(PREF_LAST_SHOWN_EMOJI_CATEGORY_ID); add(PREF_LAST_SHOWN_EMOJI_CATEGORY_ID);
add(PREF_EMOJI_RECENT_KEYS); add(PREF_EMOJI_RECENT_KEYS);
add(PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG); add(PREF_DONT_SHOW_MISSING_DICTIONARY_DIALOG);
add(PREF_SHOW_ALL_COLORS); add(PREF_SHOW_MORE_COLORS);
add(PREF_SELECTED_SUBTYPE); add(PREF_SELECTED_SUBTYPE);
}}; }};

View file

@ -5,22 +5,27 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView
android:id="@+id/info"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:layout_marginHorizontal="16dp"
android:layout_alignParentTop="true"
android:visibility="gone"
android:text="@string/all_colors_warning"
style="?android:attr/textAppearanceSmall" />
<ScrollView <ScrollView
android:id="@+id/colors_scroller"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_alignParentTop="true" android:layout_below="@id/info"
android:layout_above="@id/dummy_text"> android:layout_above="@id/dummy_text">
<LinearLayout
android:orientation="vertical"
android:paddingTop="6dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout <LinearLayout
android:id="@+id/color_settings_container" android:id="@+id/color_settings_container"
android:paddingTop="6dp"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" /> android:orientation="vertical" />
</LinearLayout>
</ScrollView> </ScrollView>
<EditText <EditText
android:id="@+id/dummy_text" android:id="@+id/dummy_text"

View file

@ -694,8 +694,12 @@ New dictionary:
<string name="auto_user_color">Choose color automatically</string> <string name="auto_user_color">Choose color automatically</string>
<!-- Menu item for showing fewer colors --> <!-- Menu item for showing fewer colors -->
<string name="main_colors">Show main colors only</string> <string name="main_colors">Show main colors only</string>
<!-- Menu item for showing more colors -->
<string name="more_colors">Show more colors</string>
<!-- Menu item for showing all colors --> <!-- Menu item for showing all colors -->
<string name="all_colors">Show all colors</string> <string name="all_colors">Show all colors</string>
<!-- Warning message displayed when showing all colors -->
<string name="all_colors_warning">This setting exposes all colors that are used internally. The list of colors may change at any time. There is no default color, and the names will not be translated.</string>
<!-- Hint for text field just to show keyboard (in color settings) --> <!-- Hint for text field just to show keyboard (in color settings) -->
<string name="hint_show_keyboard">Click for preview</string> <string name="hint_show_keyboard">Click for preview</string>
<!-- Description for selection of user-defined colors. --> <!-- Description for selection of user-defined colors. -->