From 0edbf9c08a27606c31da9500d1b92d27e65af2ee Mon Sep 17 00:00:00 2001 From: BlackyHawky Date: Tue, 19 Dec 2023 07:48:10 +0100 Subject: [PATCH] Add dynamic colors (#277) Add "dynamic colors" using Android 12+ system colors Change colors into an interface * allow the desired more exact copy of colors from Gboard * avoid needlessly exposing Colors stuffs --------- Co-authored-by: Helium314 --- .../keyboard/KeyboardSwitcher.java | 3 +- .../inputmethod/keyboard/KeyboardTheme.java | 30 +- .../inputmethod/keyboard/KeyboardView.java | 38 +- .../keyboard/MainKeyboardView.java | 3 +- .../keyboard/clipboard/ClipboardAdapter.kt | 6 +- .../clipboard/ClipboardHistoryView.kt | 10 +- .../keyboard/emoji/EmojiPalettesView.java | 39 +- .../GestureFloatingTextDrawingPreview.java | 5 +- .../internal/GestureTrailDrawingParams.java | 3 +- .../internal/KeyPreviewChoreographer.java | 4 +- .../internal/KeyVisualAttributes.java | 11 +- .../SlidingKeyInputDrawingPreview.java | 3 +- .../inputmethod/latin/KeyboardWrapperView.kt | 12 +- .../openboard/inputmethod/latin/LatinIME.java | 3 +- .../inputmethod/latin/common/Colors.kt | 582 ++++++++++++++---- .../SuggestionStripLayoutHelper.java | 12 +- .../suggestions/SuggestionStripView.java | 22 +- .../inputmethod/latin/utils/ColorUtil.kt | 4 +- app/src/main/res/values-fr/strings.xml | 1 + app/src/main/res/values/strings.xml | 2 + 20 files changed, 593 insertions(+), 200 deletions(-) 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 0f3feea2..c877a043 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 @@ -102,7 +102,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions { final boolean nightModeChanged = (mCurrentUiMode & Configuration.UI_MODE_NIGHT_MASK) != (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK); if (mThemeContext == null || !keyboardTheme.equals(mKeyboardTheme) || nightModeChanged - || !mThemeContext.getResources().equals(context.getResources())) { + || !mThemeContext.getResources().equals(context.getResources()) + || Settings.getInstance().getCurrent().mColors.haveColorsChanged(context)) { mKeyboardTheme = keyboardTheme; mThemeContext = new ContextThemeWrapper(context, keyboardTheme.mStyleId); mCurrentUiMode = context.getResources().getConfiguration().uiMode; 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 73453de7..86602fc0 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 @@ -9,12 +9,15 @@ package org.dslul.openboard.inputmethod.keyboard; import android.content.Context; import android.content.SharedPreferences; import android.graphics.Color; +import android.os.Build; import android.os.Build.VERSION_CODES; import androidx.core.content.ContextCompat; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.common.Colors; +import org.dslul.openboard.inputmethod.latin.common.DynamicColors; +import org.dslul.openboard.inputmethod.latin.common.DefaultColors; import org.dslul.openboard.inputmethod.latin.settings.Settings; import org.dslul.openboard.inputmethod.latin.utils.DeviceProtectedUtils; @@ -33,10 +36,15 @@ public final class KeyboardTheme implements Comparable { public static final String THEME_DARK = "dark"; public static final String THEME_DARKER = "darker"; public static final String THEME_BLACK = "black"; + public static final String THEME_DYNAMIC = "dynamic"; public static final String THEME_USER = "user"; public static final String THEME_USER_NIGHT = "user_night"; - public static final String[] COLORS = new String[] { THEME_LIGHT, THEME_HOLO_WHITE, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_USER }; - public static final String[] COLORS_DARK = new String[] { THEME_HOLO_WHITE, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_USER_NIGHT }; + public static final String[] COLORS = Build.VERSION.SDK_INT < Build.VERSION_CODES.S + ? new String[] { THEME_LIGHT, THEME_HOLO_WHITE, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_USER } + : new String[] { THEME_LIGHT, THEME_HOLO_WHITE, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_DYNAMIC, THEME_USER } ; + public static final String[] COLORS_DARK = Build.VERSION.SDK_INT < Build.VERSION_CODES.S + ? new String[] { THEME_HOLO_WHITE, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_USER_NIGHT } + : new String[] { THEME_HOLO_WHITE, THEME_DARK, THEME_DARKER, THEME_BLACK, THEME_DYNAMIC, THEME_USER_NIGHT } ; public static final String[] STYLES = { STYLE_MATERIAL, STYLE_HOLO, STYLE_ROUNDED }; @@ -146,7 +154,7 @@ public final class KeyboardTheme implements Comparable { final boolean hasBorders = prefs.getBoolean(Settings.PREF_THEME_KEY_BORDERS, false); switch (themeColors) { case THEME_USER: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, Settings.readUserColor(prefs, context, Settings.PREF_COLOR_ACCENT_SUFFIX, false), @@ -160,7 +168,7 @@ public final class KeyboardTheme implements Comparable { Settings.readUserColor(prefs, context, Settings.PREF_COLOR_SPACEBAR_TEXT_SUFFIX, false) ); case THEME_USER_NIGHT: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, Settings.readUserColor(prefs, context, Settings.PREF_COLOR_ACCENT_SUFFIX, true), @@ -174,7 +182,7 @@ public final class KeyboardTheme implements Comparable { Settings.readUserColor(prefs, context, Settings.PREF_COLOR_SPACEBAR_TEXT_SUFFIX, true) ); case THEME_DARK: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, ContextCompat.getColor(context, R.color.gesture_trail_color_lxx_dark), @@ -189,7 +197,7 @@ public final class KeyboardTheme implements Comparable { ContextCompat.getColor(context, R.color.spacebar_letter_color_lxx_dark) ); case THEME_HOLO_WHITE: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, Color.parseColor("#FFFFFF"), @@ -204,7 +212,7 @@ public final class KeyboardTheme implements Comparable { Color.parseColor("#80FFFFFF") ); case THEME_DARKER: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, ContextCompat.getColor(context, R.color.gesture_trail_color_lxx_dark), @@ -218,7 +226,7 @@ public final class KeyboardTheme implements Comparable { ContextCompat.getColor(context, R.color.spacebar_letter_color_lxx_dark) ); case THEME_BLACK: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, ContextCompat.getColor(context, R.color.gesture_trail_color_lxx_dark), @@ -231,9 +239,13 @@ public final class KeyboardTheme implements Comparable { ContextCompat.getColor(context, R.color.key_hint_letter_color_lxx_dark), ContextCompat.getColor(context, R.color.spacebar_letter_color_lxx_dark) ); + case THEME_DYNAMIC: + if (Build.VERSION.SDK_INT >= VERSION_CODES.S) { + return new DynamicColors(context, themeStyle, hasBorders); + } case THEME_LIGHT: default: - return new Colors( + return new DefaultColors( themeStyle, hasBorders, ContextCompat.getColor(context, R.color.gesture_trail_color_lxx_light), diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardView.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardView.java index 21e41ecd..70bee7a6 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardView.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/KeyboardView.java @@ -31,12 +31,13 @@ import org.dslul.openboard.inputmethod.keyboard.emoji.EmojiPageKeyboardView; import org.dslul.openboard.inputmethod.keyboard.internal.KeyDrawParams; import org.dslul.openboard.inputmethod.keyboard.internal.KeyVisualAttributes; import org.dslul.openboard.inputmethod.latin.R; -import org.dslul.openboard.inputmethod.latin.common.BackgroundType; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.common.StringUtils; import org.dslul.openboard.inputmethod.latin.settings.Settings; import org.dslul.openboard.inputmethod.latin.settings.SettingsValues; +import org.dslul.openboard.inputmethod.latin.suggestions.MoreSuggestions; import org.dslul.openboard.inputmethod.latin.suggestions.MoreSuggestionsView; import org.dslul.openboard.inputmethod.latin.utils.TypefaceUtils; @@ -139,18 +140,18 @@ public class KeyboardView extends View { final TypedArray keyboardViewAttr = context.obtainStyledAttributes(attrs, R.styleable.KeyboardView, defStyle, R.style.KeyboardView); if (this instanceof EmojiPageKeyboardView || this instanceof MoreSuggestionsView) - mKeyBackground = mColors.getDrawable(BackgroundType.BACKGROUND, keyboardViewAttr); + mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.BACKGROUND); else if (this instanceof MoreKeysKeyboardView) - mKeyBackground = mColors.getDrawable(BackgroundType.ADJUSTED_BACKGROUND, keyboardViewAttr); + mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.MORE_KEYS_BACKGROUND); else - mKeyBackground = mColors.getDrawable(BackgroundType.KEY, keyboardViewAttr); + mKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.KEY_BACKGROUND); mKeyBackground.getPadding(mKeyBackgroundPadding); - mFunctionalKeyBackground = mColors.getDrawable(BackgroundType.FUNCTIONAL, keyboardViewAttr); - mSpacebarBackground = mColors.getDrawable(BackgroundType.SPACE, keyboardViewAttr); + mFunctionalKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.FUNCTIONAL_KEY_BACKGROUND); + mSpacebarBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.SPACE_BAR_BACKGROUND); if (this instanceof MoreKeysKeyboardView) - mActionKeyBackground = mColors.getDrawable(BackgroundType.ACTION_MORE_KEYS, keyboardViewAttr); + mActionKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.ACTION_KEY_MORE_KEYS_BACKGROUND); else - mActionKeyBackground = mColors.getDrawable(BackgroundType.ACTION, keyboardViewAttr); + mActionKeyBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.ACTION_KEY_BACKGROUND); mSpacebarIconWidthRatio = keyboardViewAttr.getFloat( R.styleable.KeyboardView_spacebarIconWidthRatio, 1.0f); @@ -176,7 +177,6 @@ public class KeyboardView extends View { keyAttr.recycle(); mPaint.setAntiAlias(true); - mColors.setKeyboardBackground(this); } @Nullable @@ -204,6 +204,14 @@ public class KeyboardView extends View { * @param keyboard the keyboard to display in this view */ public void setKeyboard(@NonNull final Keyboard keyboard) { + if (keyboard instanceof MoreSuggestions) { + mColors.setBackground(this, ColorType.MORE_SUGGESTIONS_BACKGROUND); + } else if (keyboard instanceof MoreKeysKeyboard) { + mColors.setBackground(this, ColorType.MORE_KEYS_BACKGROUND); + } else { + mColors.setBackground(this, ColorType.KEYBOARD_BACKGROUND); + } + mKeyboard = keyboard; final SettingsValues sv = Settings.getInstance().getCurrent(); // scale should not depend on mOneHandedModeScale for emoji and clipboard, because those views are not affected by one-handed mode (yet) @@ -625,24 +633,24 @@ public class KeyboardView extends View { private void setKeyIconColor(Key key, Drawable icon, Keyboard keyboard) { if (key.isAccentColored()) { - icon.setColorFilter(mColors.getActionKeyIconColorFilter()); + mColors.setColor(icon, ColorType.ACTION_KEY_ICON); } else if (key.isShift() && keyboard != null) { if (keyboard.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_MANUAL_SHIFTED || keyboard.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCKED || keyboard.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_AUTOMATIC_SHIFTED || keyboard.mId.mElementId == KeyboardId.ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED ) - icon.setColorFilter(mColors.getAccentColorFilter()); + mColors.setColor(icon, ColorType.SHIFT_KEY_ICON); else - icon.setColorFilter(mColors.getKeyTextFilter()); // key text if not shifted + mColors.setColor(icon, ColorType.KEY_ICON); // normal key if not shifted } else if (key.getBackgroundType() != Key.BACKGROUND_TYPE_NORMAL) { - icon.setColorFilter(mColors.getKeyTextFilter()); + mColors.setColor(icon, ColorType.KEY_ICON); } else if (this instanceof MoreKeysKeyboardView) { // set color filter for long press comma key, should not trigger anywhere else - icon.setColorFilter(mColors.getKeyTextFilter()); + mColors.setColor(icon, ColorType.KEY_ICON); } else if (key.getCode() == Constants.CODE_SPACE || key.getCode() == 0x200C) { // set color of default number pad space bar icon for Holo style, or for zero-width non-joiner (zwnj) on some layouts like nepal - icon.setColorFilter(mColors.getKeyTextFilter()); + mColors.setColor(icon, ColorType.KEY_ICON); } } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/MainKeyboardView.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/MainKeyboardView.java index 740dd534..621b3068 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/MainKeyboardView.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/MainKeyboardView.java @@ -46,6 +46,7 @@ import org.dslul.openboard.inputmethod.keyboard.internal.TimerHandler; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype; import org.dslul.openboard.inputmethod.latin.SuggestedWords; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.common.CoordinateUtils; @@ -202,7 +203,7 @@ public final class MainKeyboardView extends KeyboardView implements DrawingProxy mLanguageOnSpacebarTextRatio = mainKeyboardViewAttr.getFraction( R.styleable.MainKeyboardView_languageOnSpacebarTextRatio, 1, 1, 1.0f); final Colors colors = Settings.getInstance().getCurrent().mColors; - mLanguageOnSpacebarTextColor = colors.getSpaceBarText(); + mLanguageOnSpacebarTextColor = colors.get(ColorType.SPACE_BAR_TEXT); mLanguageOnSpacebarTextShadowRadius = mainKeyboardViewAttr.getFloat( R.styleable.MainKeyboardView_languageOnSpacebarTextShadowRadius, LANGUAGE_ON_SPACEBAR_TEXT_SHADOW_RADIUS_DISABLED); diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardAdapter.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardAdapter.kt index a42efce5..730c7b88 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardAdapter.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardAdapter.kt @@ -14,7 +14,7 @@ import androidx.recyclerview.widget.RecyclerView import org.dslul.openboard.inputmethod.latin.ClipboardHistoryEntry import org.dslul.openboard.inputmethod.latin.ClipboardHistoryManager import org.dslul.openboard.inputmethod.latin.R -import org.dslul.openboard.inputmethod.latin.common.BackgroundType +import org.dslul.openboard.inputmethod.latin.common.ColorType import org.dslul.openboard.inputmethod.latin.settings.Settings class ClipboardAdapter( @@ -57,8 +57,8 @@ class ClipboardAdapter( setOnTouchListener(this@ViewHolder) setOnLongClickListener(this@ViewHolder) setBackgroundResource(itemBackgroundId) - Settings.getInstance().current.mColors.setBackgroundColor(background, BackgroundType.KEY) } + Settings.getInstance().current.mColors.setBackground(view, ColorType.KEY_BACKGROUND) pinnedIconView = view.findViewById(R.id.clipboard_entry_pinned_icon).apply { visibility = View.GONE setImageResource(pinnedIconResId) @@ -70,7 +70,7 @@ class ClipboardAdapter( } clipboardLayoutParams.setItemProperties(view) val colors = Settings.getInstance().current.mColors - pinnedIconView.colorFilter = colors.accentColorFilter + colors.setColor(pinnedIconView, ColorType.CLIPBOARD_PIN) } fun setContent(historyEntry: ClipboardHistoryEntry?) { diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardHistoryView.kt b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardHistoryView.kt index 7e4e4e62..94379778 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardHistoryView.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/clipboard/ClipboardHistoryView.kt @@ -18,7 +18,7 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyVisualAttributes import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet import org.dslul.openboard.inputmethod.latin.ClipboardHistoryManager import org.dslul.openboard.inputmethod.latin.R -import org.dslul.openboard.inputmethod.latin.common.BackgroundType +import org.dslul.openboard.inputmethod.latin.common.ColorType import org.dslul.openboard.inputmethod.latin.common.Constants import org.dslul.openboard.inputmethod.latin.settings.Settings import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils @@ -95,16 +95,16 @@ class ClipboardHistoryView @JvmOverloads constructor( clearKey = findViewById(R.id.clipboard_clear).apply { setOnTouchListener(this@ClipboardHistoryView) setOnClickListener(this@ClipboardHistoryView) - colorFilter = colors.keyTextFilter - colors.setBackgroundColor(background, BackgroundType.SUGGESTION) } + colors.setColor(clearKey, ColorType.CLEAR_CLIPBOARD_HISTORY_KEY) + colors.setBackground(clearKey, ColorType.CLEAR_CLIPBOARD_HISTORY_KEY) } private fun setupAlphabetKey(key: TextView?, label: String, params: KeyDrawParams) { key?.apply { text = label typeface = params.mTypeface - Settings.getInstance().current.mColors.setBackgroundColor(this.background, BackgroundType.FUNCTIONAL) + Settings.getInstance().current.mColors.setBackground(this, ColorType.FUNCTIONAL_KEY_BACKGROUND) setTextColor(params.mFunctionalTextColor) setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize.toFloat()) } @@ -155,7 +155,7 @@ class ClipboardHistoryView @JvmOverloads constructor( clipboardRecyclerView.apply { adapter = clipboardAdapter } - Settings.getInstance().current.mColors.setKeyboardBackground(this) + Settings.getInstance().current.mColors.setBackground(this, ColorType.CLIPBOARD_BACKGROUND) } fun stopClipboardHistory() { diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/emoji/EmojiPalettesView.java index 3b1bcf30..c32b502c 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/emoji/EmojiPalettesView.java @@ -37,7 +37,7 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet; import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype; -import org.dslul.openboard.inputmethod.latin.common.BackgroundType; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.settings.Settings; @@ -68,7 +68,7 @@ public final class EmojiPalettesView extends LinearLayout private final int mCategoryIndicatorDrawableResId; private final int mCategoryIndicatorBackgroundResId; private final int mCategoryPageIndicatorColor; - private final int mCategoryPageIndicatorBackground; + private final Colors mColors; private EmojiPalettesAdapter mEmojiPalettesAdapter; private final EmojiLayoutParams mEmojiLayoutParams; private final DeleteKeyOnTouchListener mDeleteKeyOnTouchListener; @@ -101,7 +101,8 @@ public final class EmojiPalettesView extends LinearLayout R.styleable.KeyboardView_keyBackground, 0); mFunctionalKeyBackgroundId = keyboardViewAttr.getResourceId( R.styleable.KeyboardView_functionalKeyBackground, keyBackgroundId); - mSpacebarBackground = Settings.getInstance().getCurrent().mColors.getDrawable(BackgroundType.SPACE, keyboardViewAttr); + mColors = Settings.getInstance().getCurrent().mColors; + mSpacebarBackground = mColors.selectAndColorDrawable(keyboardViewAttr, ColorType.SPACE_BAR_BACKGROUND); keyboardViewAttr.recycle(); final KeyboardLayoutSet.Builder builder = new KeyboardLayoutSet.Builder(context, null); final Resources res = context.getResources(); @@ -122,7 +123,6 @@ public final class EmojiPalettesView extends LinearLayout R.styleable.EmojiPalettesView_categoryIndicatorBackground, 0); mCategoryPageIndicatorColor = emojiPalettesViewAttr.getColor( R.styleable.EmojiPalettesView_categoryPageIndicatorColor, 0); - mCategoryPageIndicatorBackground = Settings.getInstance().getCurrent().mColors.getAdjustedBackground(); //emojiPalettesViewAttr.getColor(R.styleable.EmojiPalettesView_categoryPageIndicatorBackground, 0); emojiPalettesViewAttr.recycle(); mDeleteKeyOnTouchListener = new DeleteKeyOnTouchListener(); mEmojiLayoutManager = new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false); @@ -147,10 +147,8 @@ public final class EmojiPalettesView extends LinearLayout tspec.setContent(R.id.emoji_keyboard_dummy); final ImageView iconView = (ImageView) LayoutInflater.from(getContext()).inflate( R.layout.emoji_keyboard_tab_icon, null); - // TODO: Replace background color with its own setting rather than using the - // category page indicator background as a workaround. - iconView.setBackgroundColor(mCategoryPageIndicatorBackground); - iconView.setColorFilter(Settings.getInstance().getCurrent().mColors.getKeyTextFilter()); + mColors.setBackground(iconView, ColorType.EMOJI_CATEGORY_BACKGROUND); + mColors.setColor(iconView, ColorType.EMOJI_CATEGORY); iconView.setImageResource(mEmojiCategory.getCategoryTabIcon(categoryId)); iconView.setContentDescription(mEmojiCategory.getAccessibilityDescription(categoryId)); tspec.setIndicator(iconView); @@ -160,7 +158,6 @@ public final class EmojiPalettesView extends LinearLayout @Override protected void onFinishInflate() { super.onFinishInflate(); - final Colors colors = Settings.getInstance().getCurrent().mColors; mTabHost = findViewById(R.id.emoji_category_tabhost); mTabHost.setup(); @@ -177,7 +174,7 @@ public final class EmojiPalettesView extends LinearLayout tabWidget.setBackgroundResource(mCategoryIndicatorDrawableResId); tabWidget.setLeftStripDrawable(mCategoryIndicatorBackgroundResId); tabWidget.setRightStripDrawable(mCategoryIndicatorBackgroundResId); - tabWidget.setBackgroundColor(colors.getAccent()); + tabWidget.setBackgroundColor(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED)); } mEmojiPalettesAdapter = new EmojiPalettesAdapter(mEmojiCategory, this); @@ -221,7 +218,7 @@ public final class EmojiPalettesView extends LinearLayout mEmojiCategoryPageIndicatorView = findViewById(R.id.emoji_category_page_id_view); mEmojiCategoryPageIndicatorView.setColors( - mCategoryPageIndicatorColor, mCategoryPageIndicatorBackground); + mCategoryPageIndicatorColor, mColors.get(ColorType.EMOJI_CATEGORY_BACKGROUND)); mEmojiLayoutParams.setCategoryPageIdViewProperties(mEmojiCategoryPageIndicatorView); setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), @@ -235,7 +232,7 @@ public final class EmojiPalettesView extends LinearLayout // deleteKey depends only on OnTouchListener. mDeleteKey = findViewById(R.id.emoji_keyboard_delete); mDeleteKey.setBackgroundResource(mFunctionalKeyBackgroundId); - mDeleteKey.setColorFilter(colors.getKeyTextFilter()); + mColors.setColor(mDeleteKey, ColorType.KEY_ICON); mDeleteKey.setTag(Constants.CODE_DELETE); mDeleteKey.setOnTouchListener(mDeleteKeyOnTouchListener); @@ -260,10 +257,10 @@ public final class EmojiPalettesView extends LinearLayout mEmojiLayoutParams.setKeyProperties(mSpacebar); mSpacebarIcon = findViewById(R.id.emoji_keyboard_space_icon); - colors.setBackgroundColor(mAlphabetKeyLeft.getBackground(), BackgroundType.FUNCTIONAL); - colors.setBackgroundColor(mDeleteKey.getBackground(), BackgroundType.FUNCTIONAL); - colors.setBackgroundColor(mSpacebar.getBackground(), BackgroundType.SPACE); - mEmojiCategoryPageIndicatorView.setColors(colors.getAccent(), colors.getAdjustedBackground()); + mColors.setBackground(mAlphabetKeyLeft, ColorType.FUNCTIONAL_KEY_BACKGROUND); + mColors.setBackground(mDeleteKey, ColorType.FUNCTIONAL_KEY_BACKGROUND); + mColors.setBackground(mSpacebar, ColorType.SPACE_BAR_BACKGROUND); + mEmojiCategoryPageIndicatorView.setColors(mColors.get(ColorType.EMOJI_CATEGORY_SELECTED), mColors.get(ColorType.EMOJI_CATEGORY_BACKGROUND)); } @Override @@ -283,11 +280,10 @@ public final class EmojiPalettesView extends LinearLayout setCurrentCategoryAndPageId(categoryId, 0, false /* force */); updateEmojiCategoryPageIdView(); } - final Colors colors = Settings.getInstance().getCurrent().mColors; if (mCurrentTab != null) - mCurrentTab.setColorFilter(colors.getKeyTextFilter()); + mColors.setColor(mCurrentTab, ColorType.EMOJI_CATEGORY); mCurrentTab = (ImageView) mTabHost.getCurrentTabView(); - mCurrentTab.setColorFilter(colors.getAccentColorFilter()); + mColors.setColor(mCurrentTab, ColorType.EMOJI_CATEGORY_SELECTED); } /** @@ -387,10 +383,9 @@ public final class EmojiPalettesView extends LinearLayout setupAlphabetKey(mAlphabetKeyLeft, switchToAlphaLabel, params); if (mEmojiRecyclerView.getAdapter() == null) { mEmojiRecyclerView.setAdapter(mEmojiPalettesAdapter); - setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), - true /* force */); + setCurrentCategoryAndPageId(mEmojiCategory.getCurrentCategoryId(), mEmojiCategory.getCurrentCategoryPageId(), true); } - Settings.getInstance().getCurrent().mColors.setKeyboardBackground(this); + mColors.setBackground(this, ColorType.EMOJI_BACKGROUND); } public void stopEmojiPalettes() { diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java index 3070b819..d73a897a 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureFloatingTextDrawingPreview.java @@ -19,6 +19,7 @@ import androidx.annotation.NonNull; import org.dslul.openboard.inputmethod.keyboard.PointerTracker; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.SuggestedWords; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.common.CoordinateUtils; import org.dslul.openboard.inputmethod.latin.settings.Settings; @@ -55,10 +56,10 @@ public class GestureFloatingTextDrawingPreview extends AbstractDrawingPreview { final Colors colors = Settings.getInstance().getCurrent().mColors; mGesturePreviewTextSize = mainKeyboardViewAttr.getDimensionPixelSize( R.styleable.MainKeyboardView_gestureFloatingPreviewTextSize, 0); - mGesturePreviewTextColor = colors.getKeyText(); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_gestureFloatingPreviewTextColor, 0); + mGesturePreviewTextColor = colors.get(ColorType.KEY_TEXT); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_gestureFloatingPreviewTextColor, 0); mGesturePreviewTextOffset = mainKeyboardViewAttr.getDimensionPixelOffset( R.styleable.MainKeyboardView_gestureFloatingPreviewTextOffset, 0); - mGesturePreviewColor = colors.getAdjustedBackground(); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_gestureFloatingPreviewColor, 0); + mGesturePreviewColor = colors.get(ColorType.GESTURE_PREVIEW); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_gestureFloatingPreviewColor, 0); mGesturePreviewHorizontalPadding = mainKeyboardViewAttr.getDimension( R.styleable.MainKeyboardView_gestureFloatingPreviewHorizontalPadding, 0.0f); mGesturePreviewVerticalPadding = mainKeyboardViewAttr.getDimension( diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureTrailDrawingParams.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureTrailDrawingParams.java index 8219763c..52c4901a 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureTrailDrawingParams.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/GestureTrailDrawingParams.java @@ -9,6 +9,7 @@ package org.dslul.openboard.inputmethod.keyboard.internal; import android.content.res.TypedArray; import org.dslul.openboard.inputmethod.latin.R; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.settings.Settings; /** @@ -41,7 +42,7 @@ final class GestureTrailDrawingParams { public final int mTrailLingerDuration; public GestureTrailDrawingParams(final TypedArray mainKeyboardViewAttr) { - mTrailColor = Settings.getInstance().getCurrent().mColors.getGesture(); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_gestureTrailColor, 0); + mTrailColor = Settings.getInstance().getCurrent().mColors.get(ColorType.GESTURE_TRAIL); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_gestureTrailColor, 0); mTrailStartWidth = mainKeyboardViewAttr.getDimension( R.styleable.MainKeyboardView_gestureTrailStartWidth, 0.0f); mTrailEndWidth = mainKeyboardViewAttr.getDimension( diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyPreviewChoreographer.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyPreviewChoreographer.java index 6462c35b..fc72829b 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyPreviewChoreographer.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyPreviewChoreographer.java @@ -11,6 +11,7 @@ import android.view.View; import android.view.ViewGroup; import org.dslul.openboard.inputmethod.keyboard.Key; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.common.CoordinateUtils; import org.dslul.openboard.inputmethod.latin.settings.Settings; @@ -108,7 +109,8 @@ public final class KeyPreviewChoreographer { final boolean hasMoreKeys = (key.getMoreKeys() != null); keyPreviewView.setPreviewBackground(hasMoreKeys, keyPreviewPosition); final Colors colors = Settings.getInstance().getCurrent().mColors; - keyPreviewView.getBackground().setColorFilter(colors.getAdjustedBackgroundFilter()); + colors.setBackground(keyPreviewView, ColorType.KEY_PREVIEW); + // The key preview is placed vertically above the top edge of the parent key with an // arbitrary offset. final int previewY = key.getY() - previewHeight + key.getHeight() - mParams.mPreviewOffset diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyVisualAttributes.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyVisualAttributes.java index 2558ba61..fe96d3f3 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyVisualAttributes.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyVisualAttributes.java @@ -14,6 +14,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import org.dslul.openboard.inputmethod.latin.R; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.settings.Settings; import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils; @@ -118,19 +119,19 @@ public final class KeyVisualAttributes { R.styleable.Keyboard_Key_keyPreviewTextRatio); final Colors colors = Settings.getInstance().getCurrent().mColors; - mTextColor = colors.getKeyText(); //keyAttr.getColor(R.styleable.Keyboard_Key_keyTextColor, 0); + mTextColor = colors.get(ColorType.KEY_TEXT); //keyAttr.getColor(R.styleable.Keyboard_Key_keyTextColor, 0); mTextInactivatedColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyTextInactivatedColor, 0); mTextShadowColor = keyAttr.getColor(R.styleable.Keyboard_Key_keyTextShadowColor, 0); // todo: maybe a separate color? - mFunctionalTextColor = colors.getKeyText(); //keyAttr.getColor(R.styleable.Keyboard_Key_functionalTextColor, 0); - mHintLetterColor = colors.getKeyHintText(); //keyAttr.getColor(R.styleable.Keyboard_Key_keyHintLetterColor, 0); - mHintLabelColor = colors.getKeyText(); //keyAttr.getColor(R.styleable.Keyboard_Key_keyHintLabelColor, 0); + mFunctionalTextColor = colors.get(ColorType.KEY_TEXT); //keyAttr.getColor(R.styleable.Keyboard_Key_functionalTextColor, 0); + mHintLetterColor = colors.get(ColorType.KEY_HINT_TEXT); //keyAttr.getColor(R.styleable.Keyboard_Key_keyHintLetterColor, 0); + mHintLabelColor = colors.get(ColorType.KEY_TEXT); //keyAttr.getColor(R.styleable.Keyboard_Key_keyHintLabelColor, 0); mShiftedLetterHintInactivatedColor = keyAttr.getColor( R.styleable.Keyboard_Key_keyShiftedLetterHintInactivatedColor, 0); mShiftedLetterHintActivatedColor = keyAttr.getColor( R.styleable.Keyboard_Key_keyShiftedLetterHintActivatedColor, 0); // todo: maybe a separate color? - mPreviewTextColor = colors.getKeyText(); //keyAttr.getColor(R.styleable.Keyboard_Key_keyPreviewTextColor, 0); + mPreviewTextColor = colors.get(ColorType.KEY_TEXT); //keyAttr.getColor(R.styleable.Keyboard_Key_keyPreviewTextColor, 0); mHintLabelVerticalAdjustment = ResourceUtils.getFraction(keyAttr, R.styleable.Keyboard_Key_keyHintLabelVerticalAdjustment, 0.0f); diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java index 5c6b220d..fd783886 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/SlidingKeyInputDrawingPreview.java @@ -15,6 +15,7 @@ import androidx.annotation.NonNull; import org.dslul.openboard.inputmethod.keyboard.PointerTracker; import org.dslul.openboard.inputmethod.latin.R; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.CoordinateUtils; import org.dslul.openboard.inputmethod.latin.settings.Settings; @@ -38,7 +39,7 @@ public final class SlidingKeyInputDrawingPreview extends AbstractDrawingPreview private final Paint mPaint = new Paint(); public SlidingKeyInputDrawingPreview(final TypedArray mainKeyboardViewAttr) { - final int previewColor = Settings.getInstance().getCurrent().mColors.getGesture(); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_slidingKeyInputPreviewColor, 0); + final int previewColor = Settings.getInstance().getCurrent().mColors.get(ColorType.GESTURE_TRAIL); //mainKeyboardViewAttr.getColor(R.styleable.MainKeyboardView_slidingKeyInputPreviewColor, 0); final float previewRadius = mainKeyboardViewAttr.getDimension( R.styleable.MainKeyboardView_slidingKeyInputPreviewWidth, 0) / 2.0f; final int PERCENTAGE_INT = 100; diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/KeyboardWrapperView.kt b/app/src/main/java/org/dslul/openboard/inputmethod/latin/KeyboardWrapperView.kt index 1d44e5f4..f63d4d3b 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/KeyboardWrapperView.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/KeyboardWrapperView.kt @@ -13,7 +13,7 @@ import android.view.View import android.widget.FrameLayout import android.widget.ImageButton import org.dslul.openboard.inputmethod.keyboard.KeyboardActionListener -import org.dslul.openboard.inputmethod.latin.common.BackgroundType +import org.dslul.openboard.inputmethod.latin.common.ColorType import org.dslul.openboard.inputmethod.latin.common.Constants import org.dslul.openboard.inputmethod.latin.settings.Settings import org.dslul.openboard.inputmethod.latin.utils.DeviceProtectedUtils @@ -95,12 +95,12 @@ class KeyboardWrapperView @JvmOverloads constructor( } val colors = Settings.getInstance().current.mColors - stopOneHandedModeBtn.colorFilter = colors.keyTextFilter - switchOneHandedModeBtn.colorFilter = colors.keyTextFilter - colors.setBackgroundColor(stopOneHandedModeBtn.background, BackgroundType.BACKGROUND) - colors.setBackgroundColor(switchOneHandedModeBtn.background, BackgroundType.BACKGROUND) + colors.setColor(stopOneHandedModeBtn, ColorType.ONE_HANDED_MODE_BUTTON) + colors.setColor(switchOneHandedModeBtn, ColorType.ONE_HANDED_MODE_BUTTON) + colors.setBackground(stopOneHandedModeBtn, ColorType.BACKGROUND) + colors.setBackground(switchOneHandedModeBtn, ColorType.BACKGROUND) setBackgroundColor(Color.WHITE) // otherwise background might be null - colors.setKeyboardBackground(this) + colors.setBackground(this, ColorType.KEYBOARD_WRAPPER_BACKGROUND) } @SuppressLint("RtlHardcoded") diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java index 1b5d2eec..2f44caa6 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/LatinIME.java @@ -55,6 +55,7 @@ import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher; import org.dslul.openboard.inputmethod.keyboard.MainKeyboardView; import org.dslul.openboard.inputmethod.latin.Suggest.OnGetSuggestedWordsCallback; import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.common.CoordinateUtils; import org.dslul.openboard.inputmethod.latin.common.InputPointers; @@ -2040,7 +2041,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen final SettingsValues settingsValues = mSettings.getCurrent(); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP || !settingsValues.mCustomNavBarColor) return; - final int color = settingsValues.mColors.getNavBar(); + final int color = settingsValues.mColors.get(ColorType.NAVIGATION_BAR); final Window window = getWindow().getWindow(); if (window == null) return; diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.kt b/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.kt index 1ed7ee3b..5fedeeaf 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/common/Colors.kt @@ -2,61 +2,120 @@ package org.dslul.openboard.inputmethod.latin.common +import android.content.Context import android.content.res.ColorStateList +import android.content.res.Configuration import android.content.res.TypedArray import android.graphics.Color import android.graphics.ColorFilter import android.graphics.PorterDuff import android.graphics.drawable.Drawable import android.graphics.drawable.GradientDrawable +import android.os.Build import android.view.View +import android.widget.ImageView +import androidx.annotation.ColorInt +import androidx.annotation.RequiresApi +import androidx.core.content.ContextCompat import androidx.core.graphics.BlendModeColorFilterCompat import androidx.core.graphics.BlendModeCompat +import androidx.core.graphics.ColorUtils import androidx.core.graphics.drawable.DrawableCompat import org.dslul.openboard.inputmethod.keyboard.KeyboardTheme.STYLE_HOLO import org.dslul.openboard.inputmethod.keyboard.KeyboardTheme.STYLE_MATERIAL -import org.dslul.openboard.inputmethod.keyboard.MainKeyboardView -import org.dslul.openboard.inputmethod.keyboard.MoreKeysKeyboardView -import org.dslul.openboard.inputmethod.keyboard.clipboard.ClipboardHistoryView -import org.dslul.openboard.inputmethod.keyboard.emoji.EmojiPageKeyboardView -import org.dslul.openboard.inputmethod.keyboard.emoji.EmojiPalettesView -import org.dslul.openboard.inputmethod.latin.KeyboardWrapperView +import org.dslul.openboard.inputmethod.latin.common.ColorType.* import org.dslul.openboard.inputmethod.latin.R -import org.dslul.openboard.inputmethod.latin.suggestions.MoreSuggestionsView -import org.dslul.openboard.inputmethod.latin.suggestions.SuggestionStripView -import org.dslul.openboard.inputmethod.latin.utils.* +import org.dslul.openboard.inputmethod.latin.utils.adjustLuminosityAndKeepAlpha +import org.dslul.openboard.inputmethod.latin.utils.brighten +import org.dslul.openboard.inputmethod.latin.utils.brightenOrDarken +import org.dslul.openboard.inputmethod.latin.utils.darken +import org.dslul.openboard.inputmethod.latin.utils.isBrightColor +import org.dslul.openboard.inputmethod.latin.utils.isDarkColor -class Colors ( - val themeStyle: String, - val hasKeyBorders: Boolean, - val accent: Int, - val gesture: Int, - val background: Int, - val keyBackground: Int, - val functionalKey: Int, - val spaceBar: Int, - val keyText: Int, - val keyHintText: Int, - val spaceBarText: Int -) { - val navBar: Int +interface Colors { + // these theme parameters should no be in here, but are still used + /** used in KeyboardView for label placement */ + val themeStyle: String + /** used in parser to decide background of ZWNJ key */ + val hasKeyBorders: Boolean + + /** use to check whether colors have changed, for colors (in)directly derived from context, + * e.g. night mode or potentially changing system colors */ + fun haveColorsChanged(context: Context): Boolean + + /** get the colorInt */ + @ColorInt fun get(color: ColorType): Int + + /** apply a color to the [drawable], may be through color filter or tint (with or without state list) */ + fun setColor(drawable: Drawable, color: ColorType) + + /** set a foreground color to the [view] */ + fun setColor(view: ImageView, color: ColorType) + + /** set a background to the [view], may replace or adjust existing background */ + fun setBackground(view: View, color: ColorType) + + /** returns a colored drawable selected from [attr], which must contain using R.styleable.KeyboardView_* */ + fun selectAndColorDrawable(attr: TypedArray, color: ColorType): Drawable +} + +@RequiresApi(Build.VERSION_CODES.S) +class DynamicColors(context: Context, override val themeStyle: String, override val hasKeyBorders: Boolean) : Colors { + + private val isNight = context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK == Configuration.UI_MODE_NIGHT_YES + + private val accent = getAccent(context) + private val gesture = getGesture(context) + private val background = getBackground(context) + private val keyBackground = getKeyBackground(context) + private val functionalKey = getFunctionalKey(context) + private val spaceBar = getKeyBackground(context) + private val keyText = getKeyText(context) + private val keyHintText = getKeyHintText(context) + private val spaceBarText = getSpaceBarText(context) + + private fun getAccent(context: Context) = if (isNight) ContextCompat.getColor(context, android.R.color.system_accent1_100) + else ContextCompat.getColor(context, android.R.color.system_accent1_200) + private fun getGesture(context: Context) = if (isNight) accent + else ContextCompat.getColor(context, android.R.color.system_accent1_600) + private fun getBackground(context: Context) = if (isNight) ContextCompat.getColor(context, android.R.color.system_neutral1_900) + else ContextCompat.getColor(context, android.R.color.system_neutral1_50) + private fun getKeyBackground(context: Context) = if (isNight) ContextCompat.getColor(context, android.R.color.system_neutral1_800) + else ContextCompat.getColor(context, android.R.color.system_neutral1_0) + private fun getFunctionalKey(context: Context) = if (isNight) ContextCompat.getColor(context, android.R.color.system_accent2_300) + else ContextCompat.getColor(context, android.R.color.system_accent2_100) + private fun getKeyText(context: Context) = if (isNight) ContextCompat.getColor(context, android.R.color.system_neutral1_50) + else ContextCompat.getColor(context, android.R.color.system_accent3_900) + private fun getKeyHintText(context: Context) = if (isNight) keyText + else ContextCompat.getColor(context, android.R.color.system_accent3_700) + private fun getSpaceBarText(context: Context) = if (isNight) ColorUtils.setAlphaComponent(ContextCompat.getColor(context, android.R.color.system_neutral1_50), 127) + else ColorUtils.setAlphaComponent(ContextCompat.getColor(context, android.R.color.system_accent3_700), 127) + + override fun haveColorsChanged(context: Context) = + accent != getAccent(context) + || gesture != getGesture(context) + || background != getBackground(context) + || keyBackground != getKeyBackground(context) + || functionalKey != getFunctionalKey(context) + || keyText != getKeyText(context) + || keyHintText != getKeyHintText(context) + || spaceBarText != getSpaceBarText(context) + + private val navBar: Int /** brightened or darkened variant of [background], to be used if exact background color would be * bad contrast, e.g. more keys popup or no border space bar */ - val adjustedBackground: Int + private val adjustedBackground: Int /** further brightened or darkened variant of [adjustedBackground] */ - val doubleAdjustedBackground: Int + private val doubleAdjustedBackground: Int /** brightened or darkened variant of [keyText] */ - val adjustedKeyText: Int + private val adjustedKeyText: Int - val backgroundFilter: ColorFilter - val adjustedBackgroundFilter: ColorFilter -// val keyBackgroundFilter: ColorFilter -// val functionalKeyBackgroundFilter: ColorFilter -// val spaceBarFilter: ColorFilter - val keyTextFilter: ColorFilter - val accentColorFilter: ColorFilter + private val backgroundFilter: ColorFilter + private val adjustedBackgroundFilter: ColorFilter + private val keyTextFilter: ColorFilter + private val accentColorFilter: ColorFilter /** color filter for the white action key icons in material theme, switches to gray if necessary for contrast */ - val actionKeyIconColorFilter: ColorFilter? + private val actionKeyIconColorFilter: ColorFilter? private val backgroundStateList: ColorStateList private val keyStateList: ColorStateList @@ -69,8 +128,24 @@ class Colors ( /** custom drawable used for keyboard background */ private val keyboardBackground: Drawable? + /** darkened variant of [accent] because the accent color is always light for dynamic colors */ + private val adjustedAccent: Int = darken(accent) + /** further darkened variant of [adjustedAccent] */ + private val doubleAdjustedAccent: Int = darken(adjustedAccent) + + /** darkened variant of [functionalKey] used in day mode */ + private val adjustedFunctionalKey: Int = darken(functionalKey) + /** further darkened variant of [adjustedFunctionalKey] */ + private val doubleAdjustedFunctionalKey: Int = darken(adjustedFunctionalKey) + + /** brightened variant of [keyBackground] used in night mode */ + private val adjustedKeyBackground: Int = brighten(keyBackground) + /** further brightened variant of [adjustedKeyBackground] */ + private val doubleAdjustedKeyBackground: Int = brighten(adjustedKeyBackground) + init { - accentColorFilter = colorFilter(accent) + accentColorFilter = colorFilter(doubleAdjustedAccent) + if (themeStyle == STYLE_HOLO) { val darkerBackground = adjustLuminosityAndKeepAlpha(background, -0.2f) navBar = darkerBackground @@ -80,15 +155,247 @@ class Colors ( keyboardBackground = null } - // create color filters - val states = arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf(-android.R.attr.state_pressed)) - fun stateList(pressed: Int, normal: Int) = ColorStateList(states, intArrayOf(pressed, normal)) // todo (idea): make better use of the states? // could also use / create StateListDrawables in colors (though that's a style than a color...) // this would better allow choosing e.g. cornered/rounded drawables for moreKeys or moreSuggestions backgroundFilter = colorFilter(background) adjustedKeyText = brightenOrDarken(keyText, true) + if (isDarkColor(background)) { + adjustedBackground = brighten(background) + doubleAdjustedBackground = brighten(adjustedBackground) + } else { + adjustedBackground = darken(background) + doubleAdjustedBackground = darken(adjustedBackground) + } + adjustedBackgroundStateList = + if (themeStyle == STYLE_HOLO) { + stateList(accent, adjustedBackground) + } else if (isNight) { + if (hasKeyBorders) stateList(doubleAdjustedAccent, keyBackground) + else stateList(adjustedAccent, adjustedKeyBackground) + } else { + stateList(accent, Color.WHITE) + } + + suggestionBackgroundList = if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) + stateList(doubleAdjustedBackground, Color.TRANSPARENT) + else + stateList(adjustedBackground, Color.TRANSPARENT) + + adjustedBackgroundFilter = + if (themeStyle == STYLE_HOLO) colorFilter(adjustedBackground) + else colorFilter(keyBackground) + + if (hasKeyBorders) { + backgroundStateList = + if (!isNight) stateList(adjustedFunctionalKey, background) + else stateList(adjustedKeyBackground, background) + + keyStateList = + if (!isNight) stateList(adjustedBackground, keyBackground) + else stateList(adjustedKeyBackground, keyBackground) + + functionalKeyStateList = + if (!isNight) stateList(doubleAdjustedFunctionalKey, functionalKey) + else stateList(functionalKey, doubleAdjustedKeyBackground) + + actionKeyStateList = + if (!isNight) stateList(gesture, accent) + else stateList(doubleAdjustedAccent, accent) + + spaceBarStateList = + if (themeStyle == STYLE_HOLO) stateList(spaceBar, spaceBar) + else keyStateList + + } else { + // need to set color to background if key borders are disabled, or there will be ugly keys + backgroundStateList = + if (!isNight) stateList(adjustedFunctionalKey, background) + else stateList(adjustedKeyBackground, background) + + keyStateList = + if (!isNight) stateList(adjustedFunctionalKey, Color.TRANSPARENT) + else stateList(functionalKey, Color.TRANSPARENT) + + functionalKeyStateList = + if (themeStyle == STYLE_HOLO) stateList(functionalKey, Color.TRANSPARENT) + else keyStateList + + actionKeyStateList = + if (themeStyle == STYLE_HOLO) stateList(accent, Color.TRANSPARENT) + else if (!isNight) stateList(gesture, accent) + else stateList(doubleAdjustedAccent, accent) + + spaceBarStateList = + if (!isNight) stateList(gesture, adjustedFunctionalKey) + else stateList(adjustedKeyBackground, spaceBar) + } + keyTextFilter = colorFilter(keyText) + + actionKeyIconColorFilter = when { + themeStyle == STYLE_HOLO -> keyTextFilter + // the white icon may not have enough contrast, and can't be adjusted by the user + isBrightColor(accent) -> colorFilter(Color.DKGRAY) + else -> null + } + } + + override fun get(color: ColorType): Int = when (color) { + TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND, + CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent + EMOJI_CATEGORY_BACKGROUND, GESTURE_PREVIEW, MORE_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground + TOOL_BAR_EXPAND_KEY_BACKGROUND -> if (!isNight) accent else doubleAdjustedBackground + GESTURE_TRAIL -> gesture + KEY_TEXT, SUGGESTION_AUTO_CORRECT, REMOVE_SUGGESTION_ICON, CLEAR_CLIPBOARD_HISTORY_KEY, + KEY_ICON, ONE_HANDED_MODE_BUTTON, EMOJI_CATEGORY, TOOL_BAR_KEY -> keyText + KEY_HINT_TEXT -> keyHintText + SPACE_BAR_TEXT -> spaceBarText + FUNCTIONAL_KEY_BACKGROUND -> functionalKey + SPACE_BAR_BACKGROUND -> spaceBar + BACKGROUND, KEYBOARD_WRAPPER_BACKGROUND, CLIPBOARD_BACKGROUND, EMOJI_BACKGROUND, KEYBOARD_BACKGROUND -> background + KEY_BACKGROUND -> keyBackground + ACTION_KEY_MORE_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent + SUGGESTION_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background + NAVIGATION_BAR -> navBar + MORE_SUGGESTIONS_HINT, SUGGESTED_WORD, SUGGESTION_TYPED_WORD, SUGGESTION_VALID_WORD -> adjustedKeyText + ACTION_KEY_ICON, TOOL_BAR_EXPAND_KEY -> Color.WHITE + } + + override fun setColor(drawable: Drawable, color: ColorType) { + val colorStateList = when (color) { + BACKGROUND -> backgroundStateList + KEY_BACKGROUND -> keyStateList + FUNCTIONAL_KEY_BACKGROUND -> functionalKeyStateList + ACTION_KEY_BACKGROUND -> actionKeyStateList + SPACE_BAR_BACKGROUND -> spaceBarStateList + MORE_KEYS_BACKGROUND -> adjustedBackgroundStateList + SUGGESTION_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackgroundStateList + else backgroundStateList + ACTION_KEY_MORE_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackgroundStateList + else actionKeyStateList + else -> null // use color filter + } + if (colorStateList == null) { + drawable.colorFilter = getColorFilter(color) + return + } + DrawableCompat.setTintMode(drawable, PorterDuff.Mode.MULTIPLY) + DrawableCompat.setTintList(drawable, colorStateList) + } + + override fun setColor(view: ImageView, color: ColorType) { + view.colorFilter = getColorFilter(color) + } + + private fun getColorFilter(color: ColorType): ColorFilter? = when (color) { + EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter + REMOVE_SUGGESTION_ICON, CLEAR_CLIPBOARD_HISTORY_KEY, EMOJI_CATEGORY, KEY_TEXT, + KEY_ICON, ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> keyTextFilter + KEY_PREVIEW -> adjustedBackgroundFilter + ACTION_KEY_ICON -> actionKeyIconColorFilter + else -> colorFilter(get(color)) + } + + override fun selectAndColorDrawable(attr: TypedArray, color: ColorType): Drawable { + val drawable = when (color) { + KEY_BACKGROUND, BACKGROUND, SUGGESTION_BACKGROUND, ACTION_KEY_MORE_KEYS_BACKGROUND, MORE_KEYS_BACKGROUND -> + attr.getDrawable(R.styleable.KeyboardView_keyBackground) + FUNCTIONAL_KEY_BACKGROUND -> attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) + SPACE_BAR_BACKGROUND -> { + if (hasKeyBorders) attr.getDrawable(R.styleable.KeyboardView_spacebarBackground) + else attr.getDrawable(R.styleable.KeyboardView_spacebarNoBorderBackground) + } + ACTION_KEY_BACKGROUND -> { + if (themeStyle == STYLE_HOLO && hasKeyBorders) // no borders has a very small pressed drawable otherwise + attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) + else + attr.getDrawable(R.styleable.KeyboardView_keyBackground) + } + else -> null // keyBackground + }?.mutate() ?: attr.getDrawable(R.styleable.KeyboardView_keyBackground)?.mutate()!! // keyBackground always exists + + setColor(drawable, color) + return drawable + } + + override fun setBackground(view: View, color: ColorType) { + when (color) { + CLEAR_CLIPBOARD_HISTORY_KEY -> setColor(view.background, SUGGESTION_BACKGROUND) + EMOJI_CATEGORY_BACKGROUND -> view.setBackgroundColor(get(color)) + KEY_PREVIEW -> view.background.colorFilter = adjustedBackgroundFilter + FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, BACKGROUND, SPACE_BAR_BACKGROUND, SUGGESTION_BACKGROUND -> setColor(view.background, color) + MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter + MORE_KEYS_BACKGROUND -> + if (themeStyle != STYLE_HOLO) + setColor(view.background, MORE_KEYS_BACKGROUND) + else view.background.colorFilter = adjustedBackgroundFilter + KEYBOARD_BACKGROUND -> view.setBackgroundColor(Color.TRANSPARENT) + EMOJI_BACKGROUND, CLIPBOARD_BACKGROUND, KEYBOARD_WRAPPER_BACKGROUND -> { + if (keyboardBackground != null) view.background = keyboardBackground + else view.background.colorFilter = backgroundFilter + } + else -> view.background.colorFilter = backgroundFilter + } + } +} + +class DefaultColors ( + override val themeStyle: String, + override val hasKeyBorders: Boolean, + private val accent: Int, + private val gesture: Int, + private val background: Int, + private val keyBackground: Int, + private val functionalKey: Int, + private val spaceBar: Int, + private val keyText: Int, + private val keyHintText: Int, + private val spaceBarText: Int +) : Colors { + private val navBar: Int + /** brightened or darkened variant of [background], to be used if exact background color would be + * bad contrast, e.g. more keys popup or no border space bar */ + private val adjustedBackground: Int + /** further brightened or darkened variant of [adjustedBackground] */ + private val doubleAdjustedBackground: Int + /** brightened or darkened variant of [keyText] */ + private val adjustedKeyText: Int + + private val backgroundFilter: ColorFilter + private val adjustedBackgroundFilter: ColorFilter + private val keyTextFilter: ColorFilter + private val accentColorFilter: ColorFilter = colorFilter(accent) + + /** color filter for the white action key icons in material theme, switches to gray if necessary for contrast */ + private val actionKeyIconColorFilter: ColorFilter? + + private val backgroundStateList: ColorStateList + private val keyStateList: ColorStateList + private val functionalKeyStateList: ColorStateList + private val actionKeyStateList: ColorStateList + private val spaceBarStateList: ColorStateList + private val adjustedBackgroundStateList: ColorStateList + private val suggestionBackgroundList: ColorStateList + + /** custom drawable used for keyboard background */ + private val keyboardBackground: Drawable? + + override fun haveColorsChanged(context: Context) = false + + init { + if (themeStyle == STYLE_HOLO) { + val darkerBackground = adjustLuminosityAndKeepAlpha(background, -0.2f) + navBar = darkerBackground + keyboardBackground = GradientDrawable(GradientDrawable.Orientation.TOP_BOTTOM, intArrayOf(background, darkerBackground)) + } else { + navBar = background + keyboardBackground = null + } + + backgroundFilter = colorFilter(background) + adjustedKeyText = brightenOrDarken(keyText, true) + if (isDarkColor(background)) { adjustedBackground = brighten(background) doubleAdjustedBackground = brighten(adjustedBackground) @@ -104,9 +411,6 @@ class Colors ( adjustedBackgroundFilter = colorFilter(adjustedBackground) if (hasKeyBorders) { -// keyBackgroundFilter = colorFilter(keyBackground) -// functionalKeyBackgroundFilter = colorFilter(functionalKey) -// spaceBarFilter = colorFilter(spaceBar) backgroundStateList = stateList(brightenOrDarken(background, true), background) keyStateList = if (themeStyle == STYLE_HOLO) stateList(keyBackground, keyBackground) else stateList(brightenOrDarken(keyBackground, true), keyBackground) @@ -117,9 +421,6 @@ class Colors ( else stateList(brightenOrDarken(spaceBar, true), spaceBar) } else { // need to set color to background if key borders are disabled, or there will be ugly keys -// keyBackgroundFilter = backgroundFilter -// functionalKeyBackgroundFilter = keyBackgroundFilter -// spaceBarFilter = colorFilter(spaceBar) backgroundStateList = stateList(brightenOrDarken(background, true), background) keyStateList = stateList(brightenOrDarken(background, true), Color.TRANSPARENT) functionalKeyStateList = keyStateList @@ -136,60 +437,62 @@ class Colors ( } } - /** set background colors including state list to the drawable */ - fun setBackgroundColor(background: Drawable, type: BackgroundType) { - val colorStateList = when (type) { - BackgroundType.BACKGROUND -> backgroundStateList - BackgroundType.KEY -> keyStateList - BackgroundType.FUNCTIONAL -> functionalKeyStateList - BackgroundType.ACTION -> actionKeyStateList - BackgroundType.SPACE -> spaceBarStateList - BackgroundType.ADJUSTED_BACKGROUND -> adjustedBackgroundStateList - BackgroundType.SUGGESTION -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) - adjustedBackgroundStateList + override fun get(color: ColorType): Int = when (color) { + TOOL_BAR_KEY_ENABLED_BACKGROUND, EMOJI_CATEGORY_SELECTED, ACTION_KEY_BACKGROUND, + CLIPBOARD_PIN, SHIFT_KEY_ICON -> accent + EMOJI_CATEGORY_BACKGROUND, GESTURE_PREVIEW, MORE_KEYS_BACKGROUND, MORE_SUGGESTIONS_BACKGROUND, KEY_PREVIEW -> adjustedBackground + TOOL_BAR_EXPAND_KEY_BACKGROUND -> doubleAdjustedBackground + GESTURE_TRAIL -> gesture + KEY_TEXT, SUGGESTION_AUTO_CORRECT, REMOVE_SUGGESTION_ICON, CLEAR_CLIPBOARD_HISTORY_KEY, + KEY_ICON, ONE_HANDED_MODE_BUTTON, EMOJI_CATEGORY, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> keyText + KEY_HINT_TEXT -> keyHintText + SPACE_BAR_TEXT -> spaceBarText + FUNCTIONAL_KEY_BACKGROUND -> functionalKey + SPACE_BAR_BACKGROUND -> spaceBar + BACKGROUND, KEYBOARD_WRAPPER_BACKGROUND, CLIPBOARD_BACKGROUND, EMOJI_BACKGROUND, KEYBOARD_BACKGROUND -> background + KEY_BACKGROUND -> keyBackground + ACTION_KEY_MORE_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackground else accent + SUGGESTION_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackground else background + NAVIGATION_BAR -> navBar + MORE_SUGGESTIONS_HINT, SUGGESTED_WORD, SUGGESTION_TYPED_WORD, SUGGESTION_VALID_WORD -> adjustedKeyText + ACTION_KEY_ICON -> Color.WHITE + } + + override fun setColor(drawable: Drawable, color: ColorType) { + val colorStateList = when (color) { + BACKGROUND -> backgroundStateList + KEY_BACKGROUND -> keyStateList + FUNCTIONAL_KEY_BACKGROUND -> functionalKeyStateList + ACTION_KEY_BACKGROUND -> actionKeyStateList + SPACE_BAR_BACKGROUND -> spaceBarStateList + MORE_KEYS_BACKGROUND -> adjustedBackgroundStateList + SUGGESTION_BACKGROUND -> if (!hasKeyBorders && themeStyle == STYLE_MATERIAL) adjustedBackgroundStateList else backgroundStateList - BackgroundType.ACTION_MORE_KEYS -> if (themeStyle == STYLE_HOLO) - adjustedBackgroundStateList + ACTION_KEY_MORE_KEYS_BACKGROUND -> if (themeStyle == STYLE_HOLO) adjustedBackgroundStateList else actionKeyStateList + else -> null // use color filter } - DrawableCompat.setTintMode(background, PorterDuff.Mode.MULTIPLY) - DrawableCompat.setTintList(background, colorStateList) + if (colorStateList == null) { + drawable.colorFilter = getColorFilter(color) + return + } + DrawableCompat.setTintMode(drawable, PorterDuff.Mode.MULTIPLY) + DrawableCompat.setTintList(drawable, colorStateList) } - // using !! for the color filter because null is only returned for unsupported blend modes, which are not used - private fun colorFilter(color: Int, mode: BlendModeCompat = BlendModeCompat.MODULATE): ColorFilter = - BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, mode)!! - - fun getDrawable(type: BackgroundType, attr: TypedArray): Drawable { - val drawable = when (type) { - BackgroundType.KEY, BackgroundType.ADJUSTED_BACKGROUND, BackgroundType.BACKGROUND, - BackgroundType.SUGGESTION, BackgroundType.ACTION_MORE_KEYS -> - attr.getDrawable(R.styleable.KeyboardView_keyBackground) - BackgroundType.FUNCTIONAL -> attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) - BackgroundType.SPACE -> { - if (hasKeyBorders) attr.getDrawable(R.styleable.KeyboardView_spacebarBackground) - else attr.getDrawable(R.styleable.KeyboardView_spacebarNoBorderBackground) - } - BackgroundType.ACTION -> { - if (themeStyle == STYLE_HOLO && hasKeyBorders) // no borders has a very small pressed drawable otherwise - attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) - else - attr.getDrawable(R.styleable.KeyboardView_keyBackground) - } - }?.mutate() ?: attr.getDrawable(R.styleable.KeyboardView_keyBackground)?.mutate()!! // keyBackground always exists - - setBackgroundColor(drawable, type) - return drawable + override fun setColor(view: ImageView, color: ColorType) { + view.colorFilter = getColorFilter(color) } - fun setKeyboardBackground(view: View) { - when (view) { - is MoreSuggestionsView -> view.background.colorFilter = backgroundFilter - is MoreKeysKeyboardView -> view.background.colorFilter = adjustedBackgroundFilter - is SuggestionStripView -> setBackgroundColor(view.background, BackgroundType.SUGGESTION) - is EmojiPageKeyboardView, // to make EmojiPalettesView background visible, which does not scroll - is MainKeyboardView -> view.setBackgroundColor(Color.TRANSPARENT) // otherwise causes issues with wrapper view when using one-handed mode - is KeyboardWrapperView, is EmojiPalettesView, is ClipboardHistoryView -> { + override fun setBackground(view: View, color: ColorType) { + when (color) { + CLEAR_CLIPBOARD_HISTORY_KEY -> setColor(view.background, SUGGESTION_BACKGROUND) + EMOJI_CATEGORY_BACKGROUND -> view.setBackgroundColor(get(color)) + KEY_PREVIEW, MORE_KEYS_BACKGROUND -> view.background.colorFilter = adjustedBackgroundFilter + FUNCTIONAL_KEY_BACKGROUND, KEY_BACKGROUND, BACKGROUND, SPACE_BAR_BACKGROUND, SUGGESTION_BACKGROUND -> setColor(view.background, color) + KEYBOARD_BACKGROUND -> view.setBackgroundColor(Color.TRANSPARENT) + MORE_SUGGESTIONS_BACKGROUND -> view.background.colorFilter = backgroundFilter + EMOJI_BACKGROUND, CLIPBOARD_BACKGROUND, KEYBOARD_WRAPPER_BACKGROUND -> { if (keyboardBackground != null) view.background = keyboardBackground else view.background.colorFilter = backgroundFilter } @@ -197,23 +500,86 @@ class Colors ( } } + private fun getColorFilter(color: ColorType): ColorFilter? = when (color) { + EMOJI_CATEGORY_SELECTED, CLIPBOARD_PIN, SHIFT_KEY_ICON -> accentColorFilter + REMOVE_SUGGESTION_ICON, CLEAR_CLIPBOARD_HISTORY_KEY, EMOJI_CATEGORY, KEY_TEXT, KEY_ICON, + ONE_HANDED_MODE_BUTTON, TOOL_BAR_KEY, TOOL_BAR_EXPAND_KEY -> keyTextFilter + KEY_PREVIEW -> adjustedBackgroundFilter + ACTION_KEY_ICON -> actionKeyIconColorFilter + else -> colorFilter(get(color)) // create color filter (not great for performance, so the frequently used filters should be stored) + } + + override fun selectAndColorDrawable(attr: TypedArray, color: ColorType): Drawable { + val drawable = when (color) { + KEY_BACKGROUND, BACKGROUND, SUGGESTION_BACKGROUND, ACTION_KEY_MORE_KEYS_BACKGROUND, MORE_KEYS_BACKGROUND -> + attr.getDrawable(R.styleable.KeyboardView_keyBackground) + FUNCTIONAL_KEY_BACKGROUND -> attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) + SPACE_BAR_BACKGROUND -> { + if (hasKeyBorders) attr.getDrawable(R.styleable.KeyboardView_spacebarBackground) + else attr.getDrawable(R.styleable.KeyboardView_spacebarNoBorderBackground) + } + ACTION_KEY_BACKGROUND -> { + if (themeStyle == STYLE_HOLO && hasKeyBorders) // no borders has a very small pressed drawable otherwise + attr.getDrawable(R.styleable.KeyboardView_functionalKeyBackground) + else + attr.getDrawable(R.styleable.KeyboardView_keyBackground) + } + else -> null // keyBackground + }?.mutate() ?: attr.getDrawable(R.styleable.KeyboardView_keyBackground)?.mutate()!! // keyBackground always exists + + setColor(drawable, color) + return drawable + } } -enum class BackgroundType { - /** generic background */ - BACKGROUND, - /** key background */ - KEY, - /** functional key background */ - FUNCTIONAL, - /** action key background */ - ACTION, - /** action key more keys background */ - ACTION_MORE_KEYS, - /** space bar background */ - SPACE, - /** background with some contrast to [BACKGROUND], based on adjustedBackground color */ - ADJUSTED_BACKGROUND, - /** background for suggestions and similar, transparent when not pressed */ - SUGGESTION +private fun colorFilter(color: Int, mode: BlendModeCompat = BlendModeCompat.MODULATE): ColorFilter { + // using !! for the color filter because null is only returned for unsupported blend modes, which are not used + return BlendModeColorFilterCompat.createBlendModeColorFilterCompat(color, mode)!! +} + +private fun stateList(pressed: Int, normal: Int): ColorStateList { + val states = arrayOf(intArrayOf(android.R.attr.state_pressed), intArrayOf(-android.R.attr.state_pressed)) + return ColorStateList(states, intArrayOf(pressed, normal)) +} + +enum class ColorType { + ACTION_KEY_ICON, + ACTION_KEY_BACKGROUND, + ACTION_KEY_MORE_KEYS_BACKGROUND, + BACKGROUND, + CLEAR_CLIPBOARD_HISTORY_KEY, + CLIPBOARD_PIN, + CLIPBOARD_BACKGROUND, + EMOJI_BACKGROUND, + EMOJI_CATEGORY, + EMOJI_CATEGORY_BACKGROUND, + EMOJI_CATEGORY_SELECTED, + FUNCTIONAL_KEY_BACKGROUND, + GESTURE_TRAIL, + GESTURE_PREVIEW, + KEY_BACKGROUND, + KEY_ICON, + KEY_TEXT, + KEY_HINT_TEXT, + KEY_PREVIEW, + KEYBOARD_BACKGROUND, + KEYBOARD_WRAPPER_BACKGROUND, + MORE_SUGGESTIONS_HINT, + MORE_SUGGESTIONS_BACKGROUND, + MORE_KEYS_BACKGROUND, + NAVIGATION_BAR, + SHIFT_KEY_ICON, + SPACE_BAR_BACKGROUND, + SPACE_BAR_TEXT, + ONE_HANDED_MODE_BUTTON, + REMOVE_SUGGESTION_ICON, + SUGGESTED_WORD, + SUGGESTION_AUTO_CORRECT, + SUGGESTION_BACKGROUND, + SUGGESTION_TYPED_WORD, + SUGGESTION_VALID_WORD, + TOOL_BAR_EXPAND_KEY, + TOOL_BAR_EXPAND_KEY_BACKGROUND, + TOOL_BAR_KEY, + TOOL_BAR_KEY_ENABLED_BACKGROUND, } diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java index 4e27fe15..44325fec 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripLayoutHelper.java @@ -42,6 +42,7 @@ import org.dslul.openboard.inputmethod.latin.PunctuationSuggestions; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.SuggestedWords; import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.settings.Settings; import org.dslul.openboard.inputmethod.latin.settings.SettingsValues; @@ -121,10 +122,11 @@ final class SuggestionStripLayoutHelper { R.styleable.SuggestionStripView_alphaObsoleted, 1.0f); final Colors colors = Settings.getInstance().getCurrent().mColors; - mColorValidTypedWord = colors.getAdjustedKeyText(); //a.getColor(R.styleable.SuggestionStripView_colorValidTypedWord, 0); - mColorTypedWord = colors.getAdjustedKeyText(); //a.getColor(R.styleable.SuggestionStripView_colorTypedWord, 0); - mColorAutoCorrect = colors.getKeyText(); //a.getColor(R.styleable.SuggestionStripView_colorAutoCorrect, 0); - mColorSuggested = colors.getAdjustedKeyText(); //a.getColor(R.styleable.SuggestionStripView_colorSuggested, 0); + mColorValidTypedWord = colors.get(ColorType.SUGGESTION_VALID_WORD); //a.getColor(R.styleable.SuggestionStripView_colorValidTypedWord, 0); + mColorTypedWord = colors.get(ColorType.SUGGESTION_TYPED_WORD); //a.getColor(R.styleable.SuggestionStripView_colorTypedWord, 0); + mColorAutoCorrect = colors.get(ColorType.SUGGESTION_AUTO_CORRECT); //a.getColor(R.styleable.SuggestionStripView_colorAutoCorrect, 0); + mColorSuggested = colors.get(ColorType.SUGGESTED_WORD); //a.getColor(R.styleable.SuggestionStripView_colorSuggested, 0); + final int colorMoreSuggestionsHint = colors.get(ColorType.MORE_SUGGESTIONS_HINT); mSuggestionsCountInStrip = a.getInt( R.styleable.SuggestionStripView_suggestionsCountInStrip, @@ -141,7 +143,7 @@ final class SuggestionStripLayoutHelper { mMoreSuggestionsHint = getMoreSuggestionsHint(res, res.getDimension(R.dimen.config_more_suggestions_hint_text_size), - mColorAutoCorrect); + colorMoreSuggestionsHint); mCenterPositionInStrip = mSuggestionsCountInStrip / 2; // Assuming there are at least three suggestions. Also, note that the suggestions are // laid out according to script direction, so this is left of the center for LTR scripts diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java b/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java index ce5a8236..bda6c3b1 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/suggestions/SuggestionStripView.java @@ -45,7 +45,7 @@ import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.SuggestedWords; import org.dslul.openboard.inputmethod.latin.SuggestedWords.SuggestedWordInfo; -import org.dslul.openboard.inputmethod.latin.common.BackgroundType; +import org.dslul.openboard.inputmethod.latin.common.ColorType; import org.dslul.openboard.inputmethod.latin.common.Colors; import org.dslul.openboard.inputmethod.latin.common.Constants; import org.dslul.openboard.inputmethod.latin.define.DebugFlags; @@ -176,12 +176,12 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick word.setContentDescription(getResources().getString(R.string.spoken_empty_suggestion)); word.setOnClickListener(this); word.setOnLongClickListener(this); - colors.setBackgroundColor(word.getBackground(), BackgroundType.SUGGESTION); + colors.setBackground(word, ColorType.SUGGESTION_BACKGROUND); mWordViews.add(word); final View divider = inflater.inflate(R.layout.suggestion_divider, null); mDividerViews.add(divider); final TextView info = new TextView(context, null, R.attr.suggestionWordStyle); - info.setTextColor(colors.getKeyText()); + info.setTextColor(colors.get(ColorType.KEY_TEXT)); info.setTextSize(TypedValue.COMPLEX_UNIT_DIP, DEBUG_INFO_TEXT_SIZE_IN_DIP); mDebugInfoViews.add(info); } @@ -216,17 +216,17 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick final int toolbarHeight = Math.min(mToolbarKey.getLayoutParams().height, (int) getResources().getDimension(R.dimen.config_suggestions_strip_height)); mToolbarKey.getLayoutParams().height = toolbarHeight; mToolbarKey.getLayoutParams().width = toolbarHeight; // we want it square + colors.setBackground(mToolbarKey, ColorType.SUGGESTION_BACKGROUND); mDefaultBackground = mToolbarKey.getBackground(); - colors.setBackgroundColor(mDefaultBackground, BackgroundType.SUGGESTION); - mEnabledToolKeyBackground.setColors(new int[] {colors.getAccent() | 0xFF000000, Color.TRANSPARENT}); // ignore alpha on accent color + mEnabledToolKeyBackground.setColors(new int[] {colors.get(ColorType.TOOL_BAR_KEY_ENABLED_BACKGROUND) | 0xFF000000, Color.TRANSPARENT}); // ignore alpha on accent color mEnabledToolKeyBackground.setGradientType(GradientDrawable.RADIAL_GRADIENT); mEnabledToolKeyBackground.setGradientRadius(mToolbarKey.getLayoutParams().height / 2f); // nothing else has a usable height at this state mToolbarKey.setOnClickListener(this); mToolbarKey.setImageDrawable(Settings.getInstance().getCurrent().mIncognitoModeEnabled ? mIncognitoIcon : mToolbarArrowIcon); - mToolbarKey.setColorFilter(colors.getKeyTextFilter()); // maybe different color? + colors.setColor(mToolbarKey, ColorType.TOOL_BAR_EXPAND_KEY); mToolbarKey.setBackground(new ShapeDrawable(new OvalShape())); // ShapeDrawable color is black, need src_atop filter - mToolbarKey.getBackground().setColorFilter(colors.getDoubleAdjustedBackground(), PorterDuff.Mode.SRC_ATOP); + mToolbarKey.getBackground().setColorFilter(colors.get(ColorType.TOOL_BAR_EXPAND_KEY_BACKGROUND), PorterDuff.Mode.SRC_ATOP); mToolbarKey.getLayoutParams().height *= 0.82; // shrink the whole key a little (drawable not affected) mToolbarKey.getLayoutParams().width *= 0.82; @@ -238,7 +238,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick addKeyToPinnedKeys(pinnedKey, inflater); } - colors.setKeyboardBackground(this); + colors.setBackground(this, ColorType.SUGGESTION_BACKGROUND); } /** @@ -394,7 +394,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick @SuppressLint("ClickableViewAccessibility") // no need for View#performClick, we return false mostly anyway private boolean onLongClickSuggestion(final TextView wordView) { final Drawable icon = mBinIcon; - icon.setColorFilter(Settings.getInstance().getCurrent().mColors.getKeyTextFilter()); + Settings.getInstance().getCurrent().mColors.setColor(icon, ColorType.REMOVE_SUGGESTION_ICON); int w = icon.getIntrinsicWidth(); int h = icon.getIntrinsicWidth(); wordView.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); @@ -719,8 +719,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick private void setupKey(final ImageButton view, final Colors colors) { view.setOnClickListener(this); view.setOnLongClickListener(this); - view.setColorFilter(colors.getKeyTextFilter()); - colors.setBackgroundColor(view.getBackground(), BackgroundType.SUGGESTION); + colors.setColor(view, ColorType.TOOL_BAR_KEY); + colors.setBackground(view, ColorType.SUGGESTION_BACKGROUND); } private static int getKeyLayoutIdForTag(final String tag) { diff --git a/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/ColorUtil.kt b/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/ColorUtil.kt index d403d9f0..5b644745 100644 --- a/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/ColorUtil.kt +++ b/app/src/main/java/org/dslul/openboard/inputmethod/latin/utils/ColorUtil.kt @@ -5,8 +5,6 @@ package org.dslul.openboard.inputmethod.latin.utils import android.graphics.Color import androidx.annotation.ColorInt import androidx.core.graphics.ColorUtils -import kotlin.math.max -import kotlin.math.min fun isBrightColor(@ColorInt color: Int) = if (android.R.color.transparent == color) true @@ -57,4 +55,4 @@ fun brighten(@ColorInt color: Int) = adjustLuminosityAndKeepAlpha(color, 0.06f) @ColorInt -fun darken(@ColorInt color: Int) = adjustLuminosityAndKeepAlpha(color, -0.06f) +fun darken(@ColorInt color: Int) = adjustLuminosityAndKeepAlpha(color, -0.06f) \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index eee72493..74e04c94 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -222,6 +222,7 @@ Nouveau dictionnaire: Sombre Noir Amoled + Couleurs dynamiques Personnalisé Personnalisé (mode nuit) Personnaliser le thème diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1f1d591f..a4ccde6b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -620,6 +620,8 @@ New dictionary: Darker Black + + Dynamic colors User-Defined