diff --git a/app/src/main/assets/ime/config.json b/app/src/main/assets/ime/config.json index 1c97e6c7..951c790d 100644 --- a/app/src/main/assets/ime/config.json +++ b/app/src/main/assets/ime/config.json @@ -27,7 +27,8 @@ "greek": "Ελληνικά", "hebrew": "עברית", "serbian_latin": "Serbian (QWERTZ)", - "serbian_cyrillic": "Serbian (ЉЊЕРТЗ)" + "serbian_cyrillic": "Serbian (ЉЊЕРТЗ)", + "kurdish": "کوردی" }, "defaultSubtypes": [ { @@ -207,6 +208,11 @@ }, { "id": 2001, + "languageTag": "ckb", + "preferredLayout": "kurdish" + }, + { + "id": 2101, "languageTag": "sr-RS", "preferredLayout": "serbian_cyrillic" } diff --git a/app/src/main/assets/ime/text/characters/extended_popups/ckb.json b/app/src/main/assets/ime/text/characters/extended_popups/ckb.json new file mode 100644 index 00000000..21c3bfcb --- /dev/null +++ b/app/src/main/assets/ime/text/characters/extended_popups/ckb.json @@ -0,0 +1,167 @@ +{ + "type": "characters/extended_popups", + "name": "ckb", + "authors": [ "GoRaN" ], + "mapping": { + "all": { + "ق": { + "relevant": [ + { "code": 1647, "label": "ٯ" } + ] + }, + "ئ": { + "relevant": [ + {"code": 1569, "label": "ء" } + ] + }, + "ە": { + "relevant": [ + { "code": 1577, "label": "ة" }, + { "code": 1729, "label": "ـہ" } + ] + }, + "ر": { + "relevant": [ + { "code": 1685, "label": "ڕ" }, + { "code": 1682, "label": "ڒ" } + ] + }, + "ف": { + "relevant": [ + { "code": 1701, "label": "ڥ" }, + { "code": 1698, "label": "ڢ" }, + { "code": 1700, "label": "ڤ" }, + { "code": 1697, "label": "ڡ" } + ] + }, + "": { + "relevant": [ + { "code": 65163, "label": "ﺋ" }, + { "code": 1569, "label": "ء" }, + { "code": 65139, "label": "ﹳ" } + ] + }, + "ع": { + "relevant": [ + { "code": 1551, "label": "؏" }, + { "code": 1594, "label": "غ" } + ] + }, + "د": { + "relevant": [ + { "code": 1676, "label": "ڌ" }, + { "code": 64390, "label": "ﮆ" }, + { "code": 1584, "label": "ذ" }, + { "code": 1774, "label": "ۮ" } + ] + }, + "ه": { + "relevant": [ + { "code": 1726, "label": "ھ" } + ] + }, + "خ": { + "relevant": [ + { "code": 1567, "label": "؟" } + ] + }, + "س": { + "relevant": [ + { "code": 1589, "label": "ص" } + ] + }, + "ش": { + "relevant": [ + { "code": 1590, "label": "ض" } + ] + }, + "ب": { + "relevant": [ + { "code": 65010, "label": "ﷲ" }, + { "code": 65021, "label": "﷽" }, + { "code": 65019, "label": "ﷻ" } + ] + }, + "م": { + "relevant": [ + { "code": 65018, "label": "ﷺ" }, + { "code": 65012, "label": "ﷴ" } + ] + }, + "ل": { + "relevant": [ + { "code": 1718, "label": "ڶ" }, + { "code": 1719, "label": "ڷ" }, + { "code": 1717, "label": "ڵ" }, + { "code": 1720, "label": "ڸ" } + ] + }, + "ا": { + "relevant": [ + { "code": 1571, "label": "أ" }, + { "code": 1573, "label": "إ" }, + { "code": 1570, "label": "آ" }, + { "code": 1649, "label": "ٱ" } + ] + }, + "ک": { + "relevant": [ + { "code": 1706, "label": "ڪ" }, + { "code": 1603, "label": "ك"} + ] + }, + "ی": { + "relevant": [ + { "code": 1746, "label": "ے" }, + { "code": 1610, "label": "ي" }, + { "code": 1744, "label": "ې" }, + { "code": 1741, "label": "ۍ" }, + { "code": 1742, "label": "ێ" }, + { "code": 1597, "label": "ؽ" } + ] + }, + "ۆ": { + "relevant": [ + { "code": 1743, "label": "ۏ" }, + { "code": 1735, "label": "ۇ" }, + { "code": 1737, "label": "ۉ" }, + { "code": 1738, "label": "ۊ" }, + { "code": 1572, "label": "ؤ" }, + { "code": 1739, "label": "ۋ" } + ] + }, + "~right": { + "main": { "code": 1567, "label": "؟" }, + "relevant": [ + { "code": 1600, "label": "ــ" }, + { "code": 33, "label": "!" }, + { "code": 1548, "label": "،" }, + { "code": 44, "label": "," }, + { "code": 1549, "label": "؍" }, + { "code": 1563, "label": "؛" }, + { "code": 59, "label": ";" }, + { "code": 58, "label": ":" }, + { "code": 64, "label": "@" }, + { "code": 35, "label": "#" }, + { "code": 42, "label": "*" }, + { "code": 95, "label": "_" }, + { "code": 45, "label": "-" } + ] + } + }, + "uri": { + "~right": { + "main": { "code": -255, "label": ".krd"}, + "relevant": [ + { "code": -255, "label": ".gov" }, + { "code": -255, "label": ".edu" }, + { "code": -255, "label": ".com" }, + { "code": -255, "label": ".org" }, + { "code": -255, "label": ".net" }, + { "code": -255, "label": ".iq" }, + { "code": -255, "label": ".tv" } + ] + } + } + } +} diff --git a/app/src/main/assets/ime/text/characters/kurdish.json b/app/src/main/assets/ime/text/characters/kurdish.json new file mode 100644 index 00000000..d2927e0e --- /dev/null +++ b/app/src/main/assets/ime/text/characters/kurdish.json @@ -0,0 +1,57 @@ +{ + "type": "characters", + "name": "kurdish", + "authors": [ "GoRaN" ], + "direction": "rtl", + "modifier": "kurdish", + "arrangement": [ + [ + { "code": 1602, "label": "ق", "popup": { + "main": { "code": 1647, "label": "ٯ" } + } }, + { "code": 1608, "label": "و", "popup": { + "main": { "code": -255, "label": "وو" } + } }, + { "code": 1749, "label": "ﻪ", "popup": { + "main": { "code": 1577, "label": "ة" } + } }, + { "code": 1585, "label": "ر" }, + { "code": 1578, "label": "ت", "popup": { + "main": { "code": 1591, "label": "ط" } + } }, + { "code": 1740, "label": "ی" }, + { "code": 1574, "label": "ﺋ", "popup": { + "main": { "code": 1569, "label": "ء" } + } }, + { "code": 1593, "label": "ع" }, + { "code": 1734, "label": "ۆ" }, + { "code": 1662, "label": "پ", "popup": { + "main": { "code": 1579, "label": "ث" } + } } + ], + [ + { "code": 1575, "label": "ا" }, + { "code": 1587, "label": "س" }, + { "code": 1588, "label": "ش" }, + { "code": 1583, "label": "د" }, + { "code": 1601, "label": "ف" }, + { "code": 1607, "label": "ھ" }, + { "code": 1688, "label": "ژ" }, + { "code": 1604, "label": "ل" }, + { "code": 1705, "label": "ک" }, + { "code": 1711, "label": "گ" } + ], + [ + { "code": 1586, "label": "ز", "popup": { + "main": {"code": 1592, "label": "ظ" } + } }, + { "code": 1582, "label": "خ" }, + { "code": 1580, "label": "ج" }, + { "code": 1670, "label": "چ" }, + { "code": 1581, "label": "ح" }, + { "code": 1576, "label": "ب" }, + { "code": 1606, "label": "ن" }, + { "code": 1605, "label": "م" } + ] + ] +} diff --git a/app/src/main/assets/ime/text/characters/mod/kurdish.json b/app/src/main/assets/ime/text/characters/mod/kurdish.json new file mode 100644 index 00000000..ca9f9a6a --- /dev/null +++ b/app/src/main/assets/ime/text/characters/mod/kurdish.json @@ -0,0 +1,27 @@ +{ + "type": "characters/mod", + "name": "kurdish", + "authors": [ "GoRaN" ], + "direction": "rtl", + "arrangement": [ + [ + { "code": 0, "type": "placeholder" }, + { "code": -5, "label": "delete", "type": "enter_editing" } + ], + [ + { "code": -202, "label": "view_symbols", "type": "system_gui" }, + { "code": 64, "label": "@", "groupId": 1, "variation": "email_address" }, + { "code": 1567, "label": "؟", "groupId": 1, "variation": "normal" }, + { "code": 1548, "label": "،", "groupId": 1, "variation": "password" }, + { "code": 47, "label": "/", "groupId": 1, "variation": "uri" }, + { "code": -210, "label": "language_switch", "type": "system_gui" }, + { "code": -213, "label": "switch_to_media_context", "type": "system_gui" }, + { "code": 32, "label": " " }, + { "code": 46, "label": ".", "groupId": 2, "variation": "email_address" }, + { "code": 46, "label": ".", "groupId": 2, "variation": "normal" }, + { "code": 46, "label": ".", "groupId": 2, "variation": "password" }, + { "code": 46, "label": ".", "groupId": 2, "variation": "uri" }, + { "code": 10, "label": "enter", "groupId": 3, "type": "enter_editing" } + ] + ] +} diff --git a/app/src/main/assets/ime/theme/floris_day.json b/app/src/main/assets/ime/theme/floris_day.json index 2a158052..68681901 100644 --- a/app/src/main/assets/ime/theme/floris_day.json +++ b/app/src/main/assets/ime/theme/floris_day.json @@ -59,6 +59,15 @@ "smartbarButton": { "background": "@key/background", "foreground": "@key/foreground" + }, + "extractEditLayout": { + "background": "#E8E8E8", + "foreground": "@window/textColor", + "foregroundAlt": "#8A8A8A" + }, + "extractActionButton": { + "background": "@smartbarButton/background", + "foreground": "@smartbarButton/foreground" } } } diff --git a/app/src/main/assets/ime/theme/floris_day_borderless.json b/app/src/main/assets/ime/theme/floris_day_borderless.json index 80973c99..691d44fb 100644 --- a/app/src/main/assets/ime/theme/floris_day_borderless.json +++ b/app/src/main/assets/ime/theme/floris_day_borderless.json @@ -63,6 +63,15 @@ "smartbarButton": { "background": "#FFFFFF", "foreground": "@window/textColor" + }, + "extractEditLayout": { + "background": "#E8E8E8", + "foreground": "@window/textColor", + "foregroundAlt": "#8A8A8A" + }, + "extractActionButton": { + "background": "@smartbarButton/background", + "foreground": "@smartbarButton/foreground" } } } diff --git a/app/src/main/assets/ime/theme/floris_night.json b/app/src/main/assets/ime/theme/floris_night.json index 1a25b0a9..1d62dfcb 100644 --- a/app/src/main/assets/ime/theme/floris_night.json +++ b/app/src/main/assets/ime/theme/floris_night.json @@ -59,6 +59,15 @@ "smartbarButton": { "background": "@key/background", "foreground": "@key/foreground" + }, + "extractEditLayout": { + "background": "#282828", + "foreground": "@window/textColor", + "foregroundAlt": "#73FFFFFF" + }, + "extractActionButton": { + "background": "@smartbarButton/background", + "foreground": "@smartbarButton/foreground" } } } diff --git a/app/src/main/assets/ime/theme/floris_night_borderless.json b/app/src/main/assets/ime/theme/floris_night_borderless.json index bd6b6949..df971d4b 100644 --- a/app/src/main/assets/ime/theme/floris_night_borderless.json +++ b/app/src/main/assets/ime/theme/floris_night_borderless.json @@ -63,6 +63,15 @@ "smartbarButton": { "background": "#424242", "foreground": "@window/textColor" + }, + "extractEditLayout": { + "background": "#282828", + "foreground": "@window/textColor", + "foregroundAlt": "#73FFFFFF" + }, + "extractActionButton": { + "background": "@smartbarButton/background", + "foreground": "@smartbarButton/foreground" } } } diff --git a/app/src/main/java/dev/patrickgold/florisboard/ime/core/FlorisBoard.kt b/app/src/main/java/dev/patrickgold/florisboard/ime/core/FlorisBoard.kt index e63d8cc4..506b23fe 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/ime/core/FlorisBoard.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/ime/core/FlorisBoard.kt @@ -23,16 +23,19 @@ import android.content.Intent import android.content.res.ColorStateList import android.content.res.Configuration import android.graphics.Color +import android.inputmethodservice.ExtractEditText import android.inputmethodservice.InputMethodService import android.media.AudioManager import android.os.* import android.provider.Settings import android.view.Gravity import android.view.View +import android.view.ViewGroup import android.view.WindowManager import android.view.inputmethod.EditorInfo import android.view.inputmethod.InputConnection import android.view.inputmethod.InputMethodManager +import android.widget.Button import com.squareup.moshi.Json import dev.patrickgold.florisboard.BuildConfig import dev.patrickgold.florisboard.R @@ -67,11 +70,12 @@ class FlorisBoard : InputMethodService(), ClipboardManager.OnPrimaryClipChangedL val context: Context get() = inputWindowView?.context ?: this + private var extractEditLayout: WeakReference = WeakReference(null) var inputView: InputView? = null private set + private var inputWindowView: InputWindowView? = null var popupLayerView: PopupLayerView? = null private set - private var inputWindowView: InputWindowView? = null private var eventListeners: MutableList?> = mutableListOf() private var audioManager: AudioManager? = null @@ -204,16 +208,34 @@ class FlorisBoard : InputMethodService(), ClipboardManager.OnPrimaryClipChangedL baseContext.setTheme(currentThemeResId) inputWindowView = layoutInflater.inflate(R.layout.florisboard, null) as InputWindowView - popupLayerView = inputWindowView?.findViewById(R.id.popup_layer) - eventListeners.toList().forEach { it?.get()?.onCreateInputView() } return inputWindowView } + /** + * Disable the default candidates view. + */ + override fun onCreateCandidatesView(): View? { + return null + } + + @SuppressLint("InflateParams") + override fun onCreateExtractTextView(): View? { + val eel = super.onCreateExtractTextView() + extractEditLayout = WeakReference(eel) + return eel + } + fun registerInputView(inputView: InputView) { Timber.i("registerInputView($inputView)") + window?.window?.findViewById(android.R.id.content)?.let { content -> + popupLayerView = PopupLayerView(content.context) + if (content is ViewGroup) { + content.addView(popupLayerView) + } + } this.inputView = inputView initializeOneHandedEnvironment() updateSoftInputWindowLayoutParameters() @@ -375,6 +397,25 @@ class FlorisBoard : InputMethodService(), ClipboardManager.OnPrimaryClipChangedL inputView?.oneHandedCtrlCloseStart?.imageTintList = it inputView?.oneHandedCtrlCloseEnd?.imageTintList = it } + inputView?.invalidate() + + // Update ExtractTextView theme + extractEditLayout.get()?.let { eel -> + if (eel is ViewGroup) { + eel.setBackgroundColor(theme.getAttr(Theme.Attr.EXTRACT_EDIT_LAYOUT_BACKGROUND).toSolidColor().color) + eel.findViewById(android.R.id.inputExtractEditText)?.let { textView -> + textView.background?.setTint(theme.getAttr(Theme.Attr.WINDOW_COLOR_PRIMARY).toSolidColor().color) + textView.setTextColor(theme.getAttr(Theme.Attr.EXTRACT_EDIT_LAYOUT_FOREGROUND).toSolidColor().color) + textView.setHintTextColor(theme.getAttr(Theme.Attr.EXTRACT_EDIT_LAYOUT_FOREGROUND_ALT).toSolidColor().color) + textView.highlightColor = theme.getAttr(Theme.Attr.WINDOW_COLOR_PRIMARY).toSolidColor().color + } + eel.findViewWithType(Button::class)?.let { actionButton -> + actionButton.setBackgroundColor(theme.getAttr(Theme.Attr.EXTRACT_ACTION_BUTTON_BACKGROUND).toSolidColor().color) + actionButton.setTextColor(theme.getAttr(Theme.Attr.EXTRACT_ACTION_BUTTON_FOREGROUND).toSolidColor().color) + } + } + } + eventListeners.toList().forEach { it?.get()?.onApplyThemeAttributes() } } diff --git a/app/src/main/java/dev/patrickgold/florisboard/ime/media/emoji/EmojiCategory.kt b/app/src/main/java/dev/patrickgold/florisboard/ime/media/emoji/EmojiCategory.kt index 4997309d..322b42fe 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/ime/media/emoji/EmojiCategory.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/ime/media/emoji/EmojiCategory.kt @@ -16,7 +16,7 @@ package dev.patrickgold.florisboard.ime.media.emoji -import android.annotation.SuppressLint +import java.util.* /** * Enum for emoji category. @@ -38,9 +38,8 @@ enum class EmojiCategory { } companion object { - @SuppressLint("DefaultLocale") fun fromString(string: String): EmojiCategory { - return valueOf(string.replace(" & ", "_").toUpperCase()) + return valueOf(string.replace(" & ", "_").toUpperCase(Locale.ENGLISH)) } } } diff --git a/app/src/main/java/dev/patrickgold/florisboard/ime/popup/PopupLayerView.kt b/app/src/main/java/dev/patrickgold/florisboard/ime/popup/PopupLayerView.kt index 3f0fd667..8e291350 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/ime/popup/PopupLayerView.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/ime/popup/PopupLayerView.kt @@ -20,12 +20,14 @@ import android.annotation.SuppressLint import android.content.Context import android.util.AttributeSet import android.view.MotionEvent +import android.view.ViewGroup import android.widget.FrameLayout -import dev.patrickgold.florisboard.ime.core.PrefHelper +/** + * Basic helper view class which acts as a non-interactive layer view, which sits above the whole + * input UI. Automatically rejects any touch events and passes it through to the View below. + */ class PopupLayerView : FrameLayout { - private val prefs: PrefHelper = PrefHelper.getDefaultInstance(context) - constructor(context: Context) : this(context, null) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) @@ -34,6 +36,9 @@ class PopupLayerView : FrameLayout { background = null isClickable = false isFocusable = false + layoutParams = ViewGroup.LayoutParams( + ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT + ) } override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean { diff --git a/app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyVariation.kt b/app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyVariation.kt index 8f287eff..f9449c47 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyVariation.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/ime/text/key/KeyVariation.kt @@ -16,8 +16,8 @@ package dev.patrickgold.florisboard.ime.text.key -import android.annotation.SuppressLint import com.squareup.moshi.FromJson +import java.util.* enum class KeyVariation { ALL, @@ -27,9 +27,8 @@ enum class KeyVariation { URI; companion object { - @SuppressLint("DefaultLocale") fun fromString(string: String): KeyVariation { - return valueOf(string.toUpperCase()) + return valueOf(string.toUpperCase(Locale.ENGLISH)) } } } diff --git a/app/src/main/java/dev/patrickgold/florisboard/ime/text/layout/LayoutType.kt b/app/src/main/java/dev/patrickgold/florisboard/ime/text/layout/LayoutType.kt index d9796970..d743655e 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/ime/text/layout/LayoutType.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/ime/text/layout/LayoutType.kt @@ -1,7 +1,7 @@ package dev.patrickgold.florisboard.ime.text.layout -import android.annotation.SuppressLint import com.squareup.moshi.FromJson +import java.util.* /** * Defines the type of the layout. @@ -19,15 +19,13 @@ enum class LayoutType { SYMBOLS2, SYMBOLS2_MOD; - @SuppressLint("DefaultLocale") override fun toString(): String { - return super.toString().replace("_", "/").toLowerCase() + return super.toString().replace("_", "/").toLowerCase(Locale.ENGLISH) } companion object { - @SuppressLint("DefaultLocale") fun fromString(string: String): LayoutType { - return valueOf(string.replace("/", "_").toUpperCase()) + return valueOf(string.replace("/", "_").toUpperCase(Locale.ENGLISH)) } } } diff --git a/app/src/main/java/dev/patrickgold/florisboard/ime/theme/Theme.kt b/app/src/main/java/dev/patrickgold/florisboard/ime/theme/Theme.kt index 030c3ab8..6a29630e 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/ime/theme/Theme.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/ime/theme/Theme.kt @@ -80,20 +80,20 @@ open class Theme( */ fun getUiAttrNameString(context: Context, attrName: String): String { val strId = when (attrName) { - "background" -> R.string.settings__theme__attr_background - "backgroundActive" -> R.string.settings__theme__attr_backgroundActive - "backgroundPressed" -> R.string.settings__theme__attr_backgroundPressed - "foreground" -> R.string.settings__theme__attr_foreground - "foregroundAlt" -> R.string.settings__theme__attr_foregroundAlt - "foregroundPressed" -> R.string.settings__theme__attr_foregroundPressed - "showBorder" -> R.string.settings__theme__attr_showBorder - "colorPrimary" -> R.string.settings__theme__attr_colorPrimary - "colorPrimaryDark" -> R.string.settings__theme__attr_colorPrimaryDark - "colorAccent" -> R.string.settings__theme__attr_colorAccent - "navigationBarColor" -> R.string.settings__theme__attr_navBarColor - "navigationBarLight" -> R.string.settings__theme__attr_navBarLight - "semiTransparentColor" -> R.string.settings__theme__attr_semiTransparentColor - "textColor" -> R.string.settings__theme__attr_textColor + "background" -> R.string.settings__theme__attr_background + "backgroundActive" -> R.string.settings__theme__attr_backgroundActive + "backgroundPressed" -> R.string.settings__theme__attr_backgroundPressed + "foreground" -> R.string.settings__theme__attr_foreground + "foregroundAlt" -> R.string.settings__theme__attr_foregroundAlt + "foregroundPressed" -> R.string.settings__theme__attr_foregroundPressed + "showBorder" -> R.string.settings__theme__attr_showBorder + "colorPrimary" -> R.string.settings__theme__attr_colorPrimary + "colorPrimaryDark" -> R.string.settings__theme__attr_colorPrimaryDark + "colorAccent" -> R.string.settings__theme__attr_colorAccent + "navigationBarColor" -> R.string.settings__theme__attr_navBarColor + "navigationBarLight" -> R.string.settings__theme__attr_navBarLight + "semiTransparentColor" -> R.string.settings__theme__attr_semiTransparentColor + "textColor" -> R.string.settings__theme__attr_textColor else -> null } return if (strId != null) { @@ -121,15 +121,17 @@ open class Theme( ) else -> { val strId = when (groupName) { - "window" -> R.string.settings__theme__group_window - "keyboard" -> R.string.settings__theme__group_keyboard - "key" -> R.string.settings__theme__group_key - "media" -> R.string.settings__theme__group_media - "oneHanded" -> R.string.settings__theme__group_oneHanded - "popup" -> R.string.settings__theme__group_popup - "privateMode" -> R.string.settings__theme__group_privateMode - "smartbar" -> R.string.settings__theme__group_smartbar - "smartbarButton" -> R.string.settings__theme__group_smartbarButton + "window" -> R.string.settings__theme__group_window + "keyboard" -> R.string.settings__theme__group_keyboard + "key" -> R.string.settings__theme__group_key + "media" -> R.string.settings__theme__group_media + "oneHanded" -> R.string.settings__theme__group_oneHanded + "popup" -> R.string.settings__theme__group_popup + "privateMode" -> R.string.settings__theme__group_privateMode + "smartbar" -> R.string.settings__theme__group_smartbar + "smartbarButton" -> R.string.settings__theme__group_smartbarButton + "extractEditLayout" -> R.string.settings__theme__group_extractEditLayout + "extractActionButton" -> R.string.settings__theme__group_extractActionButton else -> null } if (strId != null) { @@ -210,6 +212,15 @@ open class Theme( Pair("smartbarButton", mapOf( Pair("background", ThemeValue.fromString("@key/background")), Pair("foreground", ThemeValue.fromString("@key/foreground")), + )), + Pair("extractEditLayout", mapOf( + Pair("background", bgColor), + Pair("foreground", ThemeValue.fromString("@window/textColor")), + Pair("foregroundAlt", ThemeValue.fromString("#73FFFFFF")), + )), + Pair("extractActionButton", mapOf( + Pair("background", ThemeValue.fromString("@smartbarButton/background")), + Pair("foreground", ThemeValue.fromString("@smartbarButton/foreground")), )) ) ) @@ -306,7 +317,7 @@ open class Theme( getAttrOrNull(ref.copy(group = "${ref.group}::$s2"))?.let { return it } } getAttrOrNull(ref)?.let { return it } - return ThemeValue.SolidColor(0) + return BASE_THEME.getAttrOrNull(ref) ?: ThemeValue.SolidColor(0) } /** @@ -367,6 +378,13 @@ open class Theme( val SMARTBAR_BUTTON_BACKGROUND = ThemeValue.Reference("smartbarButton", "background") val SMARTBAR_BUTTON_FOREGROUND = ThemeValue.Reference("smartbarButton", "foreground") + + val EXTRACT_EDIT_LAYOUT_BACKGROUND = ThemeValue.Reference("extractEditLayout", "background") + val EXTRACT_EDIT_LAYOUT_FOREGROUND = ThemeValue.Reference("extractEditLayout", "foreground") + val EXTRACT_EDIT_LAYOUT_FOREGROUND_ALT = ThemeValue.Reference("extractEditLayout", "foregroundAlt") + + val EXTRACT_ACTION_BUTTON_BACKGROUND = ThemeValue.Reference("extractActionButton", "background") + val EXTRACT_ACTION_BUTTON_FOREGROUND = ThemeValue.Reference("extractActionButton", "foreground") } } diff --git a/app/src/main/java/dev/patrickgold/florisboard/settings/ThemeEditorActivity.kt b/app/src/main/java/dev/patrickgold/florisboard/settings/ThemeEditorActivity.kt index cacf55f9..f65c7d2d 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/settings/ThemeEditorActivity.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/settings/ThemeEditorActivity.kt @@ -261,19 +261,24 @@ class ThemeEditorActivity : AppCompatActivity() { val sortedMap = baseMap.toList().sortedBy { (_, v) -> v }.toMap().toMutableMap() val groupIds = sortedMap.keys.toMutableList() val groupNames = sortedMap.values.toMutableList() - if (groupNames.contains("keyboard")) { - val windowGroupId = groupIds[groupNames.indexOf("keyboard")] - groupIds.remove(windowGroupId) - groupNames.remove("keyboard") - groupIds.add(0, windowGroupId) - groupNames.add(0, "keyboard") - } - if (groupNames.contains("window")) { - val windowGroupId = groupIds[groupNames.indexOf("window")] - groupIds.remove(windowGroupId) - groupNames.remove("window") - groupIds.add(0, windowGroupId) - groupNames.add(0, "window") + listOf( + Pair("keyboard", true), + Pair("window", true), + Pair("extractEditLayout", false), + Pair("extractActionButton", false), + ).forEach { (groupName, addFirst) -> + if (groupNames.contains(groupName)) { + val groupId = groupIds[groupNames.indexOf(groupName)] + groupIds.remove(groupId) + groupNames.remove(groupName) + if (addFirst) { + groupIds.add(0, groupId) + groupNames.add(0, groupName) + } else { + groupIds.add(groupId) + groupNames.add(groupName) + } + } } for ((n, groupId) in groupIds.withIndex()) { binding.themeAttributes.findViewById(groupId)?.let { groupView -> diff --git a/app/src/main/java/dev/patrickgold/florisboard/util/view_utils.kt b/app/src/main/java/dev/patrickgold/florisboard/util/view_utils.kt index 61b918d8..f89fdbd8 100644 --- a/app/src/main/java/dev/patrickgold/florisboard/util/view_utils.kt +++ b/app/src/main/java/dev/patrickgold/florisboard/util/view_utils.kt @@ -1,6 +1,5 @@ package dev.patrickgold.florisboard.util -import android.app.Activity import android.content.Context import android.content.ContextWrapper import android.content.res.ColorStateList @@ -11,6 +10,7 @@ import android.widget.Button import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity import androidx.core.view.children +import kotlin.reflect.KClass fun getColorFromAttr( context: Context, @@ -73,6 +73,18 @@ fun refreshLayoutOf(view: View?) { } } +@Suppress("UNCHECKED_CAST") +fun ViewGroup.findViewWithType(type: KClass): T? { + for (child in this.children) { + if (type.isInstance(child)) { + return child as T + } else if (child is ViewGroup) { + child.findViewWithType(type)?.let { return it } + } + } + return null +} + /** * Context extension function to get the Activity from the Context. Originally written by Vlad as * an SO answer. Modified to return an AppCompatActivity, as FlorisBoard relies on some compat diff --git a/app/src/main/res/layout/florisboard.xml b/app/src/main/res/layout/florisboard.xml index 50aa24c5..adb2caa0 100644 --- a/app/src/main/res/layout/florisboard.xml +++ b/app/src/main/res/layout/florisboard.xml @@ -81,9 +81,4 @@ - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fa45abb3..bb9b64ca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -134,6 +134,8 @@ Private mode Smartbar Smartbar button + Extract edit layout + Extract action button Custom group (%s) Background color