From 3eb2f45d9791b0e038607e1811851070fb62013c Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sun, 6 Jul 2025 04:23:40 +0300 Subject: [PATCH 01/56] Add emoji search --- app/build.gradle.kts | 2 +- app/src/main/AndroidManifest.xml | 5 + .../emoji_bottom/emoji_bottom_row.json | 1 + .../accessibility/KeyCodeDescriptionMapper.kt | 1 + .../java/helium314/keyboard/keyboard/Key.java | 3 +- .../keyboard/keyboard/KeyboardId.java | 2 +- .../keyboard/keyboard/KeyboardSwitcher.java | 6 +- .../keyboard/emoji/DynamicGridKeyboard.java | 15 +- .../keyboard/emoji/EmojiCategory.java | 8 +- .../keyboard/emoji/EmojiPageKeyboardView.java | 15 +- .../keyboard/emoji/EmojiPalettesView.java | 4 +- .../keyboard/emoji/EmojiSearchActivity.kt | 325 ++++++++++++++++++ .../keyboard/internal/KeyboardCodesSet.java | 6 +- .../internal/keyboard_parser/EmojiParser.kt | 50 ++- .../keyboard_parser/floris/KeyCode.kt | 4 +- .../keyboard_parser/floris/KeyLabel.kt | 2 + .../keyboard_parser/floris/TextKeyData.kt | 2 +- .../helium314/keyboard/latin/LatinIME.java | 38 +- .../latin/SingleDictionaryFacilitator.kt | 26 +- .../keyboard/latin/common/Constants.java | 1 + .../keyboard/latin/inputlogic/InputLogic.java | 10 + .../latin/suggestions/SuggestionStripView.kt | 5 +- .../latin/utils/SuggestionResults.java | 3 +- app/src/main/res/layout/input_view.xml | 3 +- app/src/main/res/values-land/config.xml | 2 +- .../main/res/values-sw600dp-land/config.xml | 2 +- app/src/main/res/values-sw600dp/config.xml | 2 +- .../main/res/values-sw768dp-land/config.xml | 2 +- app/src/main/res/values-sw768dp/config.xml | 2 +- app/src/main/res/values/config.xml | 2 +- app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/themes-common.xml | 5 + 32 files changed, 502 insertions(+), 56 deletions(-) create mode 100644 app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 97bad787c5..7f38a5b4b9 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -114,7 +114,7 @@ dependencies { // compose coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") - implementation(platform("androidx.compose:compose-bom:2025.05.00")) + implementation(platform("androidx.compose:compose-bom-beta:2025.06.01")) implementation("androidx.compose.material3:material3") implementation("androidx.compose.ui:ui-tooling-preview") debugImplementation("androidx.compose.ui:ui-tooling") diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a7dcab1e62..4ebab05c10 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,6 +76,11 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only + + diff --git a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json index 2a7c8f6b17..27d048e46c 100644 --- a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json +++ b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json @@ -1,6 +1,7 @@ [ [ { "label": "alpha", "width": 0.15 }, + { "label": "search", "width": 0.15 }, { "label": "space", "width": -1 }, { "label": "delete", "width": 0.15 } ] diff --git a/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt b/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt index cd1841ce67..50060b0db4 100644 --- a/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt +++ b/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt @@ -35,6 +35,7 @@ internal class KeyCodeDescriptionMapper private constructor() { put(KeyCode.ACTION_NEXT, R.string.spoken_description_action_next) put(KeyCode.ACTION_PREVIOUS, R.string.spoken_description_action_previous) put(KeyCode.EMOJI, R.string.spoken_description_emoji) + put(KeyCode.SEARCH, R.string.spoken_description_search) // Because the upper-case and lower-case mappings of the following letters is depending on // the locale, the upper case descriptions should be defined here. The lower case // descriptions are handled in {@link #getSpokenLetterDescriptionId(Context,int)}. diff --git a/app/src/main/java/helium314/keyboard/keyboard/Key.java b/app/src/main/java/helium314/keyboard/keyboard/Key.java index 5b4c8c5d9c..9261007260 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/Key.java +++ b/app/src/main/java/helium314/keyboard/keyboard/Key.java @@ -1174,7 +1174,8 @@ public KeyParams( // fallthrough case KeyCode.SHIFT, Constants.CODE_ENTER, KeyCode.SHIFT_ENTER, KeyCode.ALPHA, Constants.CODE_SPACE, KeyCode.NUMPAD, KeyCode.SYMBOL, KeyCode.SYMBOL_ALPHA, KeyCode.LANGUAGE_SWITCH, KeyCode.EMOJI, KeyCode.CLIPBOARD, - KeyCode.MOVE_START_OF_LINE, KeyCode.MOVE_END_OF_LINE, KeyCode.MOVE_START_OF_PAGE, KeyCode.MOVE_END_OF_PAGE: + KeyCode.MOVE_START_OF_LINE, KeyCode.MOVE_END_OF_LINE, KeyCode.MOVE_START_OF_PAGE, KeyCode.MOVE_END_OF_PAGE, + KeyCode.SEARCH: actionFlags |= ACTION_FLAGS_NO_KEY_PREVIEW; // no preview even if icon! } if (mCode == KeyCode.SETTINGS || mCode == KeyCode.LANGUAGE_SWITCH) diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java index 62523f488b..9fe3fe385f 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java @@ -60,7 +60,7 @@ public final class KeyboardId { public static final int ELEMENT_EMOJI_CATEGORY13 = 23; public static final int ELEMENT_EMOJI_CATEGORY14 = 24; public static final int ELEMENT_EMOJI_CATEGORY15 = 25; - public static final int ELEMENT_EMOJI_CATEGORY16 = 26; + public static final int ELEMENT_EMOJI_CATEGORY16 = 26; // Emoji search public static final int ELEMENT_CLIPBOARD = 27; public static final int ELEMENT_NUMPAD = 28; public static final int ELEMENT_EMOJI_BOTTOM_ROW = 29; diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java index 34330ad48c..cf662f2c54 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java @@ -309,7 +309,7 @@ private void setMainKeyboardFrame( @NonNull final SettingsValues settingsValues, @NonNull final KeyboardSwitchState toggleState) { final int visibility = isImeSuppressedByHardwareKeyboard(settingsValues, toggleState) ? View.GONE : View.VISIBLE; - final int stripVisibility = settingsValues.mToolbarMode == ToolbarMode.HIDDEN ? View.GONE : View.VISIBLE; + final int stripVisibility = settingsValues.mToolbarMode == ToolbarMode.HIDDEN || mLatinIME.isEmojiSearch()? View.GONE : View.VISIBLE; mStripContainer.setVisibility(stripVisibility); PointerTracker.switchTo(mKeyboardView); mKeyboardView.setVisibility(visibility); @@ -632,6 +632,10 @@ public boolean isShowingStripContainer() { return mStripContainer.isShown(); } + public EmojiPalettesView getEmojiPalettesView() { + return mEmojiPalettesView; + } + public View getVisibleKeyboardView() { if (isShowingEmojiPalettes()) { return mEmojiPalettesView; diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java index eea566a720..286174e497 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java @@ -51,7 +51,7 @@ final class DynamicGridKeyboard extends Keyboard { private final ArrayList mEmptyColumnIndices = new ArrayList<>(4); public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard, - final int maxKeyCount, final int categoryId, final int width) { + final int maxRowCount, final int categoryId, final int width) { super(templateKeyboard); // todo: would be better to keep them final and not require width, but how to properly set width of the template keyboard? // an alternative would be to always create the templateKeyboard with full width @@ -69,7 +69,7 @@ public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templat mColumnsNum = mBaseWidth / mHorizontalStep; if (spacerWidth > 0) setSpacerColumns(spacerWidth); - mMaxKeyCount = maxKeyCount; + mMaxKeyCount = maxRowCount * getOccupiedColumnCount(); mIsRecents = categoryId == EmojiCategory.ID_RECENTS; mPrefs = prefs; } @@ -111,8 +111,8 @@ private Key getTemplateKey(final int code) { throw new RuntimeException("Can't find template key: code=" + code); } - public int getDynamicOccupiedHeight() { - final int row = (mGridKeys.size() - 1) / getOccupiedColumnCount() + 1; + int getOccupiedHeight() { + final int row = (mMaxKeyCount - 1) / getOccupiedColumnCount() + 1; return row * mVerticalStep; } @@ -146,6 +146,13 @@ public void addKeyLast(final Key usedKey) { addKey(usedKey, false); } + public void removeAllKeys() { + synchronized (mLock) { + mGridKeys.clear(); + mCachedGridKeys = null; + } + } + private void addKey(final Key usedKey, final boolean addFirst) { if (usedKey == null) { return; diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java index 413a6b8f62..fd89e7b4d4 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java @@ -119,7 +119,7 @@ public int getPageCount() { private final SharedPreferences mPrefs; private final Resources mRes; private final Context mContext; - private final int mMaxRecentsKeyCount; + private final int mMaxRecentsRowCount; private final KeyboardLayoutSet mLayoutSet; private final HashMap mCategoryNameToIdMap = new HashMap<>(); private final int[] mCategoryTabIconId = new int[sCategoryName.length]; @@ -133,7 +133,7 @@ public EmojiCategory(final Context ctx, final KeyboardLayoutSet layoutSet, final mPrefs = KtxKt.prefs(ctx); mRes = ctx.getResources(); mContext = ctx; - mMaxRecentsKeyCount = mRes.getInteger(R.integer.config_emoji_keyboard_max_recents_key_count); + mMaxRecentsRowCount = mRes.getInteger(R.integer.config_emoji_keyboard_max_recents_row_count); mLayoutSet = layoutSet; for (int i = 0; i < sCategoryName.length; ++i) { mCategoryNameToIdMap.put(sCategoryName[i], i); @@ -294,7 +294,7 @@ public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { if (categoryId == EmojiCategory.ID_RECENTS) { final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs, mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - mMaxRecentsKeyCount, categoryId, currentWidth); + mMaxRecentsRowCount, categoryId, currentWidth); mCategoryKeyboardMap.put(categoryKeyboardMapKey, kbd); kbd.loadRecentKeys(mCategoryKeyboardMap.values()); return kbd; @@ -307,7 +307,7 @@ public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { for (int pageId = 0; pageId < sortedKeysPages.length; ++pageId) { final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - keyCountPerPage, categoryId, currentWidth); + MAX_LINE_COUNT_PER_PAGE, categoryId, currentWidth); for (final Key emojiKey : sortedKeysPages[pageId]) { if (emojiKey == null) { break; diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPageKeyboardView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPageKeyboardView.java index cc1e0a359d..4227263738 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPageKeyboardView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPageKeyboardView.java @@ -113,6 +113,7 @@ public EmojiPageKeyboardView(final Context context, final AttributeSet attrs, mPopupKeysKeyboardContainer = inflater.inflate(popupKeysKeyboardLayoutId, null); mDescriptionView = mPopupKeysKeyboardContainer.findViewById(R.id.description_view); mPopupKeysKeyboardView = mPopupKeysKeyboardContainer.findViewById(R.id.popup_keys_keyboard_view); + setFitsSystemWindows(false); } @Override @@ -120,7 +121,7 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final Keyboard keyboard = getKeyboard(); if (keyboard instanceof DynamicGridKeyboard) { final int width = keyboard.mOccupiedWidth + getPaddingLeft() + getPaddingRight(); - final int occupiedHeight = ((DynamicGridKeyboard) keyboard).getDynamicOccupiedHeight(); + final int occupiedHeight = ((DynamicGridKeyboard) keyboard).getOccupiedHeight(); final int height = occupiedHeight + getPaddingTop() + getPaddingBottom(); setMeasuredDimension(width, height); return; @@ -442,23 +443,25 @@ public boolean onMove(final MotionEvent e) { final int x = (int)e.getX(); final int y = (int)e.getY(); final Key key = getKey(x, y); - final boolean isShowingPopupKeysPanel = isShowingPopupKeysPanel(); + final boolean isShowingPopupKeyboard = isShowingPopupKeysPanel() && mPopupKeysKeyboardView.getVisibility() == VISIBLE; // Touched key has changed, release previous key's callbacks and // re-register them for the new key. - if (key != mCurrentKey && !isShowingPopupKeysPanel) { + if (key != mCurrentKey && !isShowingPopupKeyboard) { releaseCurrentKey(false); mCurrentKey = key; + cancelLongPress(); + if (isShowingPopupKeysPanel()) { + onCancelPopupKeysPanel(); + } if (key == null) { return false; } registerPress(key); - - cancelLongPress(); registerLongPress(key); } - if (isShowingPopupKeysPanel) { + if (isShowingPopupKeyboard) { final long eventTime = e.getEventTime(); final int translatedX = mPopupKeysPanel.translateX(x); final int translatedY = mPopupKeysPanel.translateY(y); diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index c29d9280da..36fe561f39 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -341,12 +341,12 @@ public void startEmojiPalettes(final KeyVisualAttributes keyVisualAttr, initDictionaryFacilitator(); } - private void addRecentKey(final Key key) { + public void addRecentKey(final Key key) { if (Settings.getValues().mIncognitoModeEnabled) { // We do not want to log recent keys while being in incognito return; } - if (mEmojiCategory.isInRecentTab()) { + if (getVisibility() == VISIBLE && mEmojiCategory.isInRecentTab()) { getRecentsKeyboard().addPendingKey(key); return; } diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt new file mode 100644 index 0000000000..3a44969972 --- /dev/null +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -0,0 +1,325 @@ +package helium314.keyboard.keyboard.emoji + +import android.R.string.cancel +import android.content.Context +import android.content.Intent +import android.content.res.Configuration +import android.os.Bundle +import android.view.ContextThemeWrapper +import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.background +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.ExperimentalLayoutApi +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.exclude +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.isImeVisible +import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.windowInsetsPadding +import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.text.BasicTextField +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableIntStateOf +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusRequester +import androidx.compose.ui.focus.focusRequester +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextRange +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.PlatformImeOptions +import androidx.compose.ui.text.input.TextFieldValue +import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.style.TextDirection +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.viewinterop.AndroidView +import helium314.keyboard.keyboard.Key +import helium314.keyboard.keyboard.Key.KeyParams +import helium314.keyboard.keyboard.KeyboardId +import helium314.keyboard.keyboard.KeyboardLayoutSet +import helium314.keyboard.keyboard.KeyboardSwitcher +import helium314.keyboard.keyboard.KeyboardTheme +import helium314.keyboard.keyboard.internal.KeyboardBuilder +import helium314.keyboard.keyboard.internal.KeyboardParams +import helium314.keyboard.keyboard.internal.keyboard_parser.EMOJI_HINT_LABEL +import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode +import helium314.keyboard.keyboard.internal.keyboard_parser.getCode +import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiKeyDimensions +import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiPopupSpec +import helium314.keyboard.latin.Dictionary +import helium314.keyboard.latin.DictionaryFactory +import helium314.keyboard.latin.LatinIME +import helium314.keyboard.latin.R +import helium314.keyboard.latin.RichInputMethodManager +import helium314.keyboard.latin.RichInputMethodSubtype +import helium314.keyboard.latin.SingleDictionaryFacilitator +import helium314.keyboard.latin.common.ColorType +import helium314.keyboard.latin.common.StringUtils +import helium314.keyboard.latin.common.splitOnWhitespace +import helium314.keyboard.latin.settings.Settings +import helium314.keyboard.latin.utils.DictionaryInfoUtils +import helium314.keyboard.latin.utils.ResourceUtils +import helium314.keyboard.latin.utils.prefs +import helium314.keyboard.settings.CloseIcon +import helium314.keyboard.settings.SearchIcon + +/** + * This activity is displayed in a gap created for it above the keyboard and below the host app, and partly obscures the host app. + */ +class EmojiSearchActivity : ComponentActivity() { + private var startup: Boolean = true + private var emojiPageKeyboardView: EmojiPageKeyboardView? = null + private var keyboardParams: KeyboardParams? = null + private var keyWidth: Float? = null + private var keyHeight: Float? = null + private var pressedKey: Key? = null + private var imeClosed: Boolean = false + + @OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class) + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + init() + enableEdgeToEdge() + setContent { + Surface(modifier = Modifier.fillMaxSize(), color = Color(0x80000000)) { + val imeVisible = WindowInsets.isImeVisible + val localDensity = LocalDensity.current + var heightPx by remember { + mutableIntStateOf(0) + } + var heightDp by remember { + mutableStateOf(0.dp) + } + Column( + modifier = Modifier.fillMaxSize() + .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), + verticalArrangement = Arrangement.Bottom + ) { + Column(modifier = Modifier.wrapContentHeight().onGloballyPositioned { + if (!startup && !imeVisible) { + imeClosed = true + cancel() + return@onGloballyPositioned + } + if (!startup && (KeyboardSwitcher.getInstance().isShowingEmojiPalettes + || KeyboardSwitcher.getInstance().isShowingClipboardHistory)) { + cancel() + return@onGloballyPositioned + } + heightPx = it.size.height + heightDp = with(localDensity) { it.size.height.toDp() } + }) { + Row(modifier = Modifier.background(Color.White).fillMaxWidth().height(30.dp)) { + IconButton(onClick = { cancel() }) { + Icon( + painterResource(R.drawable.ic_arrow_back), + stringResource(R.string.spoken_description_action_previous) + ) + } + Text( + text = stringResource(R.string.emoji_search_title), fontSize = 18.sp, + modifier = Modifier.fillMaxWidth().align(Alignment.CenterVertically) + ) + } + AndroidView({ emojiPageKeyboardView!! }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) + val focusRequester = remember { FocusRequester() } + var text by remember { mutableStateOf(TextFieldValue(searchText, selection = TextRange(searchText.length))) } + BasicTextField( + value = text, + modifier = Modifier.fillMaxWidth().heightIn(20.dp, 30.dp).focusRequester(focusRequester), + textStyle = TextStyle(textDirection = TextDirection.Content), + onValueChange = { it: TextFieldValue -> + text = it + search(it.text) + }, + enabled = true, + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Done, + platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx))) + ), + keyboardActions = KeyboardActions(onDone = { finish() }), + singleLine = true, + ) { + TextFieldDefaults.DecorationBox( + value = text.text, + contentPadding = PaddingValues(0.dp), + visualTransformation = VisualTransformation.None, + innerTextField = it, + placeholder = { Text(stringResource(R.string.search_field_placeholder)) }, + leadingIcon = { SearchIcon() }, + trailingIcon = { + IconButton(onClick = { + text = TextFieldValue() + search("") + }) { CloseIcon(cancel) } + }, + singleLine = true, + enabled = true, + interactionSource = MutableInteractionSource(), + ) + } + LaunchedEffect(Unit) { focusRequester.requestFocus() } + } + } + } + } + } + + override fun onEnterAnimationComplete() { + search(searchText) + } + + override fun onStop() { + val intent = Intent(this, LatinIME::class.java).setAction(EMOJI_SEARCH_DONE_ACTION) + intent.putExtra(IME_CLOSED_KEY, imeClosed) + if (pressedKey != null) { + intent.putExtra( + EMOJI_KEY, if (pressedKey!!.code == KeyCode.MULTIPLE_CODE_POINTS) + pressedKey!!.getOutputText() + else + Character.toString(pressedKey!!.code) + ) + + KeyboardSwitcher.getInstance().emojiPalettesView.addRecentKey(pressedKey) + } + startService(intent) + super.onStop() + } + + private fun init() { + val contextThemeWrapper = ContextThemeWrapper(this, KeyboardTheme.getKeyboardTheme(this).mStyleId) + val keyboardWidth = ResourceUtils.getKeyboardWidth(contextThemeWrapper, Settings.getValues()) + val layoutSet = KeyboardLayoutSet.Builder(contextThemeWrapper, null) + .setSubtype(RichInputMethodSubtype.emojiSubtype) + .setKeyboardGeometry(keyboardWidth, EmojiLayoutParams(contextThemeWrapper.resources).emojiKeyboardHeight).build() + + // Initialize popup specs + layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_CATEGORY2) + + val keyboard = DynamicGridKeyboard(contextThemeWrapper.prefs(), layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 1 else 2, + KeyboardId.ELEMENT_EMOJI_CATEGORY16, keyboardWidth) + val builder = KeyboardBuilder(contextThemeWrapper, KeyboardParams()) + builder.load(keyboard.mId) + keyboardParams = builder.mParams + val (width, height) = getEmojiKeyDimensions(keyboardParams!!, contextThemeWrapper) + keyWidth = width + keyHeight = height + emojiPageKeyboardView = EmojiPageKeyboardView(contextThemeWrapper, null) + emojiPageKeyboardView!!.setKeyboard(keyboard) + emojiPageKeyboardView!!.layoutParams = + ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + emojiPageKeyboardView!!.background = null + Settings.getValues().mColors.setBackground(emojiPageKeyboardView!!, ColorType.MAIN_BACKGROUND) + emojiPageKeyboardView!!.setPadding(0, 10, 0, 10) + + emojiPageKeyboardView!!.setEmojiViewCallback(object : EmojiViewCallback { + override fun onPressKey(key: Key) { + } + + override fun onReleaseKey(key: Key) { + pressedKey = key + finish() + } + + override fun getDescription(emoji: String): String? = if (Settings.getValues().mShowEmojiDescriptions) + dictionaryFacilitator?.getWordProperty(emoji)?.mShortcutTargets[0]?.mWord else null + }) + } + + fun search(text: String) { + searchText = text + initDictionaryFacilitator(this) + if (dictionaryFacilitator == null) { + cancel() + return + } + + startup = false + val keyboard = emojiPageKeyboardView!!.keyboard as DynamicGridKeyboard + keyboard.removeAllKeys() + pressedKey = null + dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { StringUtils.mightBeEmoji(it.word) }.forEach { + val emoji = it.word + val popupSpec = getEmojiPopupSpec(emoji) + val keyParams = KeyParams( + emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, + Key.LABEL_FLAGS_FONT_NORMAL, keyboardParams + ) + keyParams.mAbsoluteWidth = keyWidth!! + keyParams.mAbsoluteHeight = keyHeight!! + val key = keyParams.createKey() + keyboard.addKeyLast(key) + if (pressedKey == null && Settings.getValues().mAutoCorrectEnabled) + pressedKey = key + } + emojiPageKeyboardView!!.invalidate() + } + + private fun cancel() { + pressedKey = null + finish() + } + + @JvmRecord + data class PrivateImeOptions(val height: Int) + + companion object { + const val EMOJI_SEARCH_DONE_ACTION: String = "EMOJI_SEARCH_DONE" + const val IME_CLOSED_KEY: String = "IME_CLOSED" + const val EMOJI_KEY: String = "EMOJI" + private const val PRIVATE_IME_OPTIONS_PREFIX: String = "helium314.keyboard.keyboard.emoji.search" + private var dictionaryFacilitator: SingleDictionaryFacilitator? = null + private var searchText: String = "" + + fun isSupported(context: Context): Boolean { + initDictionaryFacilitator(context) + return dictionaryFacilitator != null + } + + fun decodePrivateImeOptions(editorInfo: EditorInfo?): PrivateImeOptions = PrivateImeOptions( + editorInfo?.privateImeOptions?.takeIf { it.startsWith(PRIVATE_IME_OPTIONS_PREFIX) } + ?.substring(PRIVATE_IME_OPTIONS_PREFIX.length + 1)?.toInt() ?: 0) + + private fun encodePrivateImeOptions(privateImeOptions: PrivateImeOptions) = + "$PRIVATE_IME_OPTIONS_PREFIX,${privateImeOptions.height}" + + private fun initDictionaryFacilitator(context: Context) { + val locale = RichInputMethodManager.getInstance().currentSubtype.locale + if (dictionaryFacilitator?.isForLocale(locale) != true) { + dictionaryFacilitator?.closeDictionaries() + dictionaryFacilitator = DictionaryInfoUtils.getCachedDictForLocaleAndType(locale, Dictionary.TYPE_EMOJI, context) + ?.let { DictionaryFactory.getDictionary(it, locale) }?.let { SingleDictionaryFacilitator(it) } + } + } + } +} diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java b/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java index 7671784e05..8b8d0a993c 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java @@ -55,7 +55,8 @@ public static int getCode(final String name) { "key_toggle_onehanded", "key_start_onehanded", // keep name to avoid breaking custom layouts "key_stop_onehanded", // keep name to avoid breaking custom layouts - "key_switch_onehanded" + "key_switch_onehanded", + "key_search" }; private static final int[] DEFAULT = { @@ -81,7 +82,8 @@ public static int getCode(final String name) { KeyCode.TOGGLE_ONE_HANDED_MODE, KeyCode.TOGGLE_ONE_HANDED_MODE, KeyCode.TOGGLE_ONE_HANDED_MODE, - KeyCode.SWITCH_ONE_HANDED_MODE + KeyCode.SWITCH_ONE_HANDED_MODE, + KeyCode.SEARCH }; static { diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt index f58a0b5225..30b01eab85 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt @@ -17,6 +17,7 @@ import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.prefs import java.util.Collections +import kotlin.let import kotlin.math.sqrt class EmojiParser(private val params: KeyboardParams, private val context: Context) { @@ -65,21 +66,7 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte var currentX = params.mLeftPadding.toFloat() val currentY = params.mTopPadding.toFloat() // no need to ever change, assignment to rows into rows is done in DynamicGridKeyboard - // determine key width for default settings (no number row, no one-handed mode, 100% height and bottom padding scale) - // this is a bit long, but ensures that emoji size stays the same, independent of these settings - // we also ignore side padding for key width, and prefer fewer keys per row over narrower keys - val defaultKeyWidth = ResourceUtils.getDefaultKeyboardWidth(context) * params.mDefaultKeyWidth - var keyWidth = defaultKeyWidth * sqrt(Settings.getValues().mKeyboardHeightScale) - val defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(context.resources, false) - val defaultBottomPadding = context.resources.getFraction(R.fraction.config_keyboard_bottom_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight) - val emojiKeyboardHeight = defaultKeyboardHeight * 0.75f + params.mVerticalGap - defaultBottomPadding - context.resources.getDimensionPixelSize(R.dimen.config_emoji_category_page_id_height) - var keyHeight = emojiKeyboardHeight * params.mDefaultRowHeight * Settings.getValues().mKeyboardHeightScale // still apply height scale to key - - if (Settings.getValues().mEmojiKeyFit) { - keyWidth *= Settings.getValues().mFontSizeMultiplierEmoji - keyHeight *= Settings.getValues().mFontSizeMultiplierEmoji - } - + val (keyWidth, keyHeight) = getEmojiKeyDimensions(params, context) lines.forEach { line -> val keyParams = parseEmojiKeyNew(line) ?: return@forEach @@ -104,6 +91,7 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte if (SupportedEmojis.isUnsupported(label)) return null val popupKeysSpec = split.drop(1).filterNot { SupportedEmojis.isUnsupported(it) } .takeIf { it.isNotEmpty() }?.joinToString(",") + popupKeysSpec?.let { emojiPopupSpecs[label] = popupKeysSpec } return KeyParams( label, label.getCode(), @@ -113,10 +101,36 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte params ) } +} + +fun getEmojiKeyDimensions(params: KeyboardParams, context: Context): Pair { + // determine key width for default settings (no number row, no one-handed mode, 100% height and bottom padding scale) + // this is a bit long, but ensures that emoji size stays the same, independent of these settings + // we also ignore side padding for key width, and prefer fewer keys per row over narrower keys + val defaultKeyWidth = ResourceUtils.getDefaultKeyboardWidth(context) * params.mDefaultKeyWidth + var keyWidth = defaultKeyWidth * sqrt(Settings.getValues().mKeyboardHeightScale) + val defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(context.resources, false) + val defaultBottomPadding = context.resources.getFraction( + R.fraction.config_keyboard_bottom_padding_holo, defaultKeyboardHeight, defaultKeyboardHeight + ) + val emojiKeyboardHeight = defaultKeyboardHeight * 0.75f + params.mVerticalGap - defaultBottomPadding - + context.resources.getDimensionPixelSize(R.dimen.config_emoji_category_page_id_height) + var keyHeight = + emojiKeyboardHeight * params.mDefaultRowHeight * Settings.getValues().mKeyboardHeightScale // still apply height scale to key - private fun String.getCode(): Int = - if (StringUtils.codePointCount(this) != 1) KeyCode.MULTIPLE_CODE_POINTS - else Character.codePointAt(this, 0) + if (Settings.getValues().mEmojiKeyFit) { + keyWidth *= Settings.getValues().mFontSizeMultiplierEmoji + keyHeight *= Settings.getValues().mFontSizeMultiplierEmoji + } + return Pair(keyWidth, keyHeight) } +fun String.getCode(): Int = + if (StringUtils.codePointCount(this) != 1) KeyCode.MULTIPLE_CODE_POINTS + else Character.codePointAt(this, 0) + const val EMOJI_HINT_LABEL = "◥" + +private val emojiPopupSpecs: MutableMap = mutableMapOf() + +fun getEmojiPopupSpec(emoji: String): String? = emojiPopupSpecs[emoji] diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt index eccf62ebbd..b939872c31 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt @@ -53,6 +53,7 @@ object KeyCode { const val CLIPBOARD_CLEAR_HISTORY = -36 //const val CLIPBOARD_CLEAR_FULL_HISTORY = -37 //const val CLIPBOARD_CLEAR_PRIMARY_CLIP = -38 + const val SEARCH = -39 //const val COMPACT_LAYOUT_TO_LEFT = -111 //const val COMPACT_LAYOUT_TO_RIGHT = -112 @@ -196,7 +197,8 @@ object KeyCode { ACTION_NEXT, ACTION_PREVIOUS, NOT_SPECIFIED, CLIPBOARD_COPY_ALL, WORD_LEFT, WORD_RIGHT, PAGE_UP, PAGE_DOWN, META, TAB, ESCAPE, INSERT, SLEEP, MEDIA_PLAY, MEDIA_PAUSE, MEDIA_PLAY_PAUSE, MEDIA_NEXT, MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK, - TIMESTAMP, CTRL_LEFT, CTRL_RIGHT, ALT_LEFT, ALT_RIGHT, META_LEFT, META_RIGHT, SEND_INTENT_ONE, SEND_INTENT_TWO, SEND_INTENT_THREE, + TIMESTAMP, CTRL_LEFT, CTRL_RIGHT, ALT_LEFT, ALT_RIGHT, META_LEFT, META_RIGHT, SEND_INTENT_ONE, SEND_INTENT_TWO, + SEND_INTENT_THREE, SEARCH -> this // conversion diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt index 214a4df816..9b9777b1eb 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt @@ -39,6 +39,7 @@ object KeyLabel { const val TAB = "tab" const val ESCAPE = "esc" const val TIMESTAMP = "timestamp" + const val SEARCH = "search" /** to make sure a FlorisBoard label works when reading a JSON layout */ // resulting special labels should be names of FunctionalKey enum, case insensitive @@ -107,6 +108,7 @@ object KeyLabel { CTRL, ALT, FN, META, ESCAPE -> label.uppercase(Locale.US) TAB -> "!icon/tab_key|!code/${KeyCode.TAB}" TIMESTAMP -> "⌚|!code/${KeyCode.TIMESTAMP}" + SEARCH -> "!icon/search_key|!code/key_search" else -> null } diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt index 0f7c2f7f66..0af8e626a5 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt @@ -411,7 +411,7 @@ sealed interface KeyData : AbstractKeyData { when (label) { // or use code? KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL, KeyLabel.ALPHA, KeyLabel.COMMA, KeyLabel.PERIOD, KeyLabel.DELETE, KeyLabel.COM, KeyLabel.LANGUAGE_SWITCH, KeyLabel.NUMPAD, KeyLabel.CTRL, KeyLabel.ALT, - KeyLabel.FN, KeyLabel.META, toolbarKeyStrings[ToolbarKey.EMOJI] -> return Key.BACKGROUND_TYPE_FUNCTIONAL + KeyLabel.FN, KeyLabel.META, KeyLabel.SEARCH, toolbarKeyStrings[ToolbarKey.EMOJI] -> return Key.BACKGROUND_TYPE_FUNCTIONAL KeyLabel.SPACE, KeyLabel.ZWNJ -> return Key.BACKGROUND_TYPE_SPACEBAR KeyLabel.ACTION -> return Key.BACKGROUND_TYPE_ACTION KeyLabel.SHIFT -> return getShiftBackground(params) diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 0d4fc4bd1b..3730d6ada0 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -45,6 +45,7 @@ import helium314.keyboard.compat.EditorInfoCompatUtils; import helium314.keyboard.keyboard.KeyboardActionListener; import helium314.keyboard.keyboard.KeyboardActionListenerImpl; +import helium314.keyboard.keyboard.emoji.EmojiSearchActivity; import helium314.keyboard.keyboard.internal.KeyboardIconsSet; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.latin.common.InsetsOutlineProvider; @@ -868,7 +869,7 @@ public void setInputView(final View view) { mInputView = view; mInsetsUpdater = ViewOutlineProviderUtilsKt.setInsetsOutlineProvider(view); updateSoftInputWindowLayoutParameters(); - mSuggestionStripView = mSettings.getCurrent().mToolbarMode == ToolbarMode.HIDDEN? + mSuggestionStripView = mSettings.getCurrent().mToolbarMode == ToolbarMode.HIDDEN || isEmojiSearch()? null : view.findViewById(R.id.suggestion_strip_view); if (hasSuggestionStripView()) { mSuggestionStripView.setListener(this, view); @@ -1289,7 +1290,7 @@ public void onComputeInsets(final InputMethodService.Insets outInsets) { return; } final int stripHeight = mKeyboardSwitcher.isShowingStripContainer() ? mKeyboardSwitcher.getStripContainer().getHeight() : 0; - final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - stripHeight; + int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - stripHeight; if (hasSuggestionStripView()) { mSuggestionStripView.setMoreSuggestionsHeight(visibleTopY); @@ -1306,6 +1307,10 @@ public void onComputeInsets(final InputMethodService.Insets outInsets) { outInsets.touchableInsets = InputMethodService.Insets.TOUCHABLE_INSETS_REGION; outInsets.touchableRegion.set(touchLeft, touchTop, touchRight, touchBottom); } + + // Has to be subtracted after calculating touchableRegion + visibleTopY -= getEmojiSearchActivityHeight(); + outInsets.contentTopInsets = visibleTopY; outInsets.visibleTopInsets = visibleTopY; mInsetsUpdater.setInsets(outInsets); @@ -1856,6 +1861,35 @@ void launchSettings() { startActivity(intent); } + public void launchEmojiSearch() { + startActivity(new Intent().setClass(this, EmojiSearchActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (intent != null && EmojiSearchActivity.EMOJI_SEARCH_DONE_ACTION.equals(intent.getAction())) { + if (intent.getBooleanExtra(EmojiSearchActivity.IME_CLOSED_KEY, false)) { + requestHideSelf(0); + } else { + KeyboardSwitcher.getInstance().setEmojiKeyboard(); + if (intent.hasExtra(EmojiSearchActivity.EMOJI_KEY)) { + onTextInput(intent.getStringExtra(EmojiSearchActivity.EMOJI_KEY)); + } + } + return START_STICKY; + } + + return super.onStartCommand(intent, flags, startId); + } + + public boolean isEmojiSearch() { + return getEmojiSearchActivityHeight() > 0; + } + + private int getEmojiSearchActivityHeight() { + return EmojiSearchActivity.Companion.decodePrivateImeOptions(getCurrentInputEditorInfo()).height(); + } + public void dumpDictionaryForDebug(final String dictName) { if (!mDictionaryFacilitator.isActive()) { resetDictionaryFacilitatorIfNecessary(); diff --git a/app/src/main/java/helium314/keyboard/latin/SingleDictionaryFacilitator.kt b/app/src/main/java/helium314/keyboard/latin/SingleDictionaryFacilitator.kt index 4e2d62486e..18ef3f144f 100644 --- a/app/src/main/java/helium314/keyboard/latin/SingleDictionaryFacilitator.kt +++ b/app/src/main/java/helium314/keyboard/latin/SingleDictionaryFacilitator.kt @@ -5,6 +5,7 @@ import android.content.Context import android.util.LruCache import helium314.keyboard.keyboard.Keyboard import helium314.keyboard.keyboard.KeyboardSwitcher +import helium314.keyboard.keyboard.emoji.SupportedEmojis import helium314.keyboard.latin.DictionaryFacilitator.DictionaryInitializationListener import helium314.keyboard.latin.common.ComposedData import helium314.keyboard.latin.makedict.WordProperty @@ -17,6 +18,29 @@ import java.util.concurrent.TimeUnit class SingleDictionaryFacilitator(private val dict: Dictionary) : DictionaryFacilitator { var suggestionLogger: SuggestionLogger? = null + /** + * Returns combined suggestions that match any of the given words, with scores that reflect the matches against all words. + * The combined score is calculated as the average absolute (above [Int.MIN_VALUE]) score, + * where a non-match is considered an absolute zero. + * Other suggestion fields of combined matches are taken arbitrarily from one of them. + */ + fun getSuggestions(words: List): SuggestionResults { + val suggestionResults = SuggestionResults(SuggestedWords.MAX_SUGGESTIONS, false, false) + words.flatMap { word -> getSuggestions(word).distinctBy { it.word } } // Filter out duplicate results per word + .groupBy { it.word } + .forEach { (_, results) -> + val info = results.maxBy { it.mScore } + val score = (results.sumOf { it.mScore.toLong() - Int.MIN_VALUE } / words.size + Int.MIN_VALUE).toInt() + suggestionResults.add( + SuggestedWords.SuggestedWordInfo( + info.word, info.mPrevWordsContext, score, info.mKindAndFlags, + info.mSourceDict, info.mIndexOfTouchPointOfSecondWord, info.mAutoCommitFirstWordConfidence + ) + ) + } + return suggestionResults + } + // this will not work from spell checker if used together with a different keyboard app fun getSuggestions(word: String): SuggestionResults { val suggestionResults = getSuggestionResults( @@ -41,7 +65,7 @@ class SingleDictionaryFacilitator(private val dict: Dictionary) : DictionaryFaci dict.getSuggestions(composedData, ngramContext, keyboard.proximityInfo.nativeProximityInfo, settingsValuesForSuggestion, sessionId, 1f, floatArrayOf(Dictionary.NOT_A_WEIGHT_OF_LANG_MODEL_VS_SPATIAL_MODEL) - ) + )?.filter { !SupportedEmojis.isUnsupported(it.word) } ) suggestionLogger?.onNewSuggestions(suggestionResults, composedData, ngramContext, keyboard, inputStyle) diff --git a/app/src/main/java/helium314/keyboard/latin/common/Constants.java b/app/src/main/java/helium314/keyboard/latin/common/Constants.java index b61586bb2b..e84d740a95 100644 --- a/app/src/main/java/helium314/keyboard/latin/common/Constants.java +++ b/app/src/main/java/helium314/keyboard/latin/common/Constants.java @@ -233,6 +233,7 @@ public static String printableCode(final int code) { case KeyCode.SWITCH_ONE_HANDED_MODE: return "switchOneHandedMode"; case KeyCode.SPLIT_LAYOUT: return "splitLayout"; case KeyCode.NUMPAD: return "numpad"; + case KeyCode.SEARCH: return "search"; default: if (code < CODE_SPACE) return String.format("\\u%02X", code); if (code < 0x100) return String.format("%c", code); diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index e059e0b130..e578ae332f 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -25,6 +25,7 @@ import helium314.keyboard.event.InputTransaction; import helium314.keyboard.keyboard.Keyboard; import helium314.keyboard.keyboard.KeyboardSwitcher; +import helium314.keyboard.keyboard.emoji.EmojiSearchActivity; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.latin.Dictionary; import helium314.keyboard.latin.DictionaryFacilitator; @@ -779,6 +780,15 @@ private void handleFunctionalEvent(final Event event, final InputTransaction inp case KeyCode.TIMESTAMP: mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME)); break; + case KeyCode.SEARCH: + if (EmojiSearchActivity.Companion.isSupported(mLatinIME)) { + commitTyped(Settings.getValues(), LastComposedWord.NOT_A_SEPARATOR); + mLatinIME.launchEmojiSearch(); + } else { + // todo: open dictionary settings? + onSettingsKeyPressed(); + } + break; case KeyCode.SEND_INTENT_ONE, KeyCode.SEND_INTENT_TWO, KeyCode.SEND_INTENT_THREE: IntentUtils.handleSendIntentKey(mLatinIME, event.getMKeyCode()); case KeyCode.IME_HIDE_UI: diff --git a/app/src/main/java/helium314/keyboard/latin/suggestions/SuggestionStripView.kt b/app/src/main/java/helium314/keyboard/latin/suggestions/SuggestionStripView.kt index ae55648c8c..e5479fa7a5 100644 --- a/app/src/main/java/helium314/keyboard/latin/suggestions/SuggestionStripView.kt +++ b/app/src/main/java/helium314/keyboard/latin/suggestions/SuggestionStripView.kt @@ -59,6 +59,7 @@ import helium314.keyboard.latin.utils.removePinnedKey import helium314.keyboard.latin.utils.setToolbarButtonsActivatedStateOnPrefChange import java.util.concurrent.atomic.AtomicBoolean import kotlin.math.min +import androidx.core.view.isGone @SuppressLint("InflateParams") class SuggestionStripView(context: Context, attrs: AttributeSet?, defStyle: Int) : @@ -136,7 +137,7 @@ class SuggestionStripView(context: Context, attrs: AttributeSet?, defStyle: Int) enabledToolKeyBackground.gradientType = GradientDrawable.RADIAL_GRADIENT enabledToolKeyBackground.gradientRadius = resources.getDimensionPixelSize(R.dimen.config_suggestions_strip_height) / 2.1f - val mToolbarMode = Settings.getValues().mToolbarMode + val mToolbarMode = if (isGone) ToolbarMode.HIDDEN else Settings.getValues().mToolbarMode if (mToolbarMode == ToolbarMode.TOOLBAR_KEYS) { setToolbarVisibility(true) } @@ -154,7 +155,7 @@ class SuggestionStripView(context: Context, attrs: AttributeSet?, defStyle: Int) toolbar.addView(button) } } - if (!Settings.getValues().mSuggestionStripHiddenPerUserSettings) { + if (!isGone && !Settings.getValues().mSuggestionStripHiddenPerUserSettings) { for (pinnedKey in getPinnedToolbarKeys(context.prefs())) { val button = createToolbarKey(context, pinnedKey) button.layoutParams = toolbarKeyLayoutParams diff --git a/app/src/main/java/helium314/keyboard/latin/utils/SuggestionResults.java b/app/src/main/java/helium314/keyboard/latin/utils/SuggestionResults.java index 44a594fa39..15d029b316 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/SuggestionResults.java +++ b/app/src/main/java/helium314/keyboard/latin/utils/SuggestionResults.java @@ -6,6 +6,7 @@ package helium314.keyboard.latin.utils; +import androidx.annotation.Nullable; import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo; import helium314.keyboard.latin.define.ProductionFlags; @@ -56,7 +57,7 @@ public boolean add(final SuggestedWordInfo e) { } @Override - public boolean addAll(final Collection e) { + public boolean addAll(@Nullable final Collection e) { if (null == e) return false; return super.addAll(e); } diff --git a/app/src/main/res/layout/input_view.xml b/app/src/main/res/layout/input_view.xml index 0bd874eeef..52faeca364 100644 --- a/app/src/main/res/layout/input_view.xml +++ b/app/src/main/res/layout/input_view.xml @@ -8,8 +8,7 @@ + android:layout_height="wrap_content"> diff --git a/app/src/main/res/values-land/config.xml b/app/src/main/res/values-land/config.xml index e1d909847c..1ffb399990 100644 --- a/app/src/main/res/values-land/config.xml +++ b/app/src/main/res/values-land/config.xml @@ -62,7 +62,7 @@ 41%p 78%p 78%p - 32 + 2 3 diff --git a/app/src/main/res/values-sw600dp-land/config.xml b/app/src/main/res/values-sw600dp-land/config.xml index 448b73c0e1..bc5a17579f 100644 --- a/app/src/main/res/values-sw600dp-land/config.xml +++ b/app/src/main/res/values-sw600dp-land/config.xml @@ -52,7 +52,7 @@ 40%p 64%p 64%p - 36 + 3 4 diff --git a/app/src/main/res/values-sw600dp/config.xml b/app/src/main/res/values-sw600dp/config.xml index 3fac28c125..be55360d1f 100644 --- a/app/src/main/res/values-sw600dp/config.xml +++ b/app/src/main/res/values-sw600dp/config.xml @@ -72,7 +72,7 @@ 28%p 78%p 78%p - 36 + 3 3 diff --git a/app/src/main/res/values-sw768dp-land/config.xml b/app/src/main/res/values-sw768dp-land/config.xml index a315051013..c0fe32b58e 100644 --- a/app/src/main/res/values-sw768dp-land/config.xml +++ b/app/src/main/res/values-sw768dp-land/config.xml @@ -50,5 +50,5 @@ 33%p 58%p 58%p - 39 + 3 diff --git a/app/src/main/res/values-sw768dp/config.xml b/app/src/main/res/values-sw768dp/config.xml index 578de4d85b..642e8bf733 100644 --- a/app/src/main/res/values-sw768dp/config.xml +++ b/app/src/main/res/values-sw768dp/config.xml @@ -67,5 +67,5 @@ 30%p 64%p 64%p - 39 + 3 diff --git a/app/src/main/res/values/config.xml b/app/src/main/res/values/config.xml index bc22125eb1..a2b97d8639 100644 --- a/app/src/main/res/values/config.xml +++ b/app/src/main/res/values/config.xml @@ -75,7 +75,7 @@ 30%p 78%p 78%p - 32 + 3 2 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1ea905d049..050d4c9c75 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -905,4 +905,8 @@ New dictionary: Custom subtype Landscape + + Search emoji + + Search diff --git a/app/src/main/res/values/themes-common.xml b/app/src/main/res/values/themes-common.xml index ed3533b51f..88b01c3a65 100644 --- a/app/src/main/res/values/themes-common.xml +++ b/app/src/main/res/values/themes-common.xml @@ -115,4 +115,9 @@ true none + From 23426c059f5dbe61905022e71d08349bd949dd1e Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Mon, 7 Jul 2025 02:06:04 +0300 Subject: [PATCH 02/56] respect _Default emoji skin tone_ --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 11 +++++------ .../keyboard/internal/keyboard_parser/EmojiParser.kt | 3 +++ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 3a44969972..6f4534581c 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -73,6 +73,7 @@ import helium314.keyboard.keyboard.internal.KeyboardParams import helium314.keyboard.keyboard.internal.keyboard_parser.EMOJI_HINT_LABEL import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode import helium314.keyboard.keyboard.internal.keyboard_parser.getCode +import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiDefaultVersion import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiKeyDimensions import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiPopupSpec import helium314.keyboard.latin.Dictionary @@ -222,7 +223,7 @@ class EmojiSearchActivity : ComponentActivity() { .setSubtype(RichInputMethodSubtype.emojiSubtype) .setKeyboardGeometry(keyboardWidth, EmojiLayoutParams(contextThemeWrapper.resources).emojiKeyboardHeight).build() - // Initialize popup specs + // Initialize default versions and popup specs layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_CATEGORY2) val keyboard = DynamicGridKeyboard(contextThemeWrapper.prefs(), layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), @@ -269,12 +270,10 @@ class EmojiSearchActivity : ComponentActivity() { keyboard.removeAllKeys() pressedKey = null dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { StringUtils.mightBeEmoji(it.word) }.forEach { - val emoji = it.word + val emoji = getEmojiDefaultVersion(it.word) val popupSpec = getEmojiPopupSpec(emoji) - val keyParams = KeyParams( - emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, - Key.LABEL_FLAGS_FONT_NORMAL, keyboardParams - ) + val keyParams = KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, + Key.LABEL_FLAGS_FONT_NORMAL, keyboardParams) keyParams.mAbsoluteWidth = keyWidth!! keyParams.mAbsoluteHeight = keyHeight!! val key = keyParams.createKey() diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt index 30b01eab85..003a69b88d 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt @@ -52,6 +52,7 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte // find the line containing the skin tone, and swap with first val foundIndex = split.indexOfFirst { it.contains(defaultSkinTone) } if (foundIndex > 0) { + emojiDefaultVersions[split[0]] = split[foundIndex] Collections.swap(split, 0, foundIndex) } split.joinToString(" ") @@ -131,6 +132,8 @@ fun String.getCode(): Int = const val EMOJI_HINT_LABEL = "◥" +private val emojiDefaultVersions: MutableMap = mutableMapOf() private val emojiPopupSpecs: MutableMap = mutableMapOf() +fun getEmojiDefaultVersion(emoji: String): String = emojiDefaultVersions[emoji] ?: emoji fun getEmojiPopupSpec(emoji: String): String? = emojiPopupSpecs[emoji] From 197b84bde66645e3942719c176cd4166de71349d Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:15:12 +0300 Subject: [PATCH 03/56] Minor fix --- .../keyboard/emoji/EmojiSearchActivity.kt | 3 +-- .../internal/keyboard_parser/EmojiParser.kt | 26 +++++++++++-------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 6f4534581c..255dba53dd 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -63,7 +63,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.compose.ui.viewinterop.AndroidView import helium314.keyboard.keyboard.Key -import helium314.keyboard.keyboard.Key.KeyParams import helium314.keyboard.keyboard.KeyboardId import helium314.keyboard.keyboard.KeyboardLayoutSet import helium314.keyboard.keyboard.KeyboardSwitcher @@ -272,7 +271,7 @@ class EmojiSearchActivity : ComponentActivity() { dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { StringUtils.mightBeEmoji(it.word) }.forEach { val emoji = getEmojiDefaultVersion(it.word) val popupSpec = getEmojiPopupSpec(emoji) - val keyParams = KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, + val keyParams = Key.KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, Key.LABEL_FLAGS_FONT_NORMAL, keyboardParams) keyParams.mAbsoluteWidth = keyWidth!! keyParams.mAbsoluteHeight = keyHeight!! diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt index 003a69b88d..cecefb325f 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt @@ -45,19 +45,23 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte context.assets.open("emoji/$emojiFileName").reader().use { it.readLines() } } val defaultSkinTone = context.prefs().getString(Settings.PREF_EMOJI_SKIN_TONE, Defaults.PREF_EMOJI_SKIN_TONE)!! - if (params.mId.mElementId == KeyboardId.ELEMENT_EMOJI_CATEGORY2 && defaultSkinTone != "") { - // adjust PEOPLE_AND_BODY if we have a non-yellow default skin tone - val modifiedLines = emojiLines.map { - val split = it.splitOnWhitespace().toMutableList() - // find the line containing the skin tone, and swap with first - val foundIndex = split.indexOfFirst { it.contains(defaultSkinTone) } - if (foundIndex > 0) { - emojiDefaultVersions[split[0]] = split[foundIndex] - Collections.swap(split, 0, foundIndex) + if (params.mId.mElementId == KeyboardId.ELEMENT_EMOJI_CATEGORY2) { + emojiDefaultVersions.clear() + emojiPopupSpecs.clear() + if (defaultSkinTone != "") { + // adjust PEOPLE_AND_BODY if we have a non-yellow default skin tone + val modifiedLines = emojiLines.map { + val split = it.splitOnWhitespace().toMutableList() + // find the line containing the skin tone, and swap with first + val foundIndex = split.indexOfFirst { it.contains(defaultSkinTone) } + if (foundIndex > 0) { + emojiDefaultVersions[split[0]] = split[foundIndex] + Collections.swap(split, 0, foundIndex) + } + split.joinToString(" ") } - split.joinToString(" ") + return parseLines(modifiedLines) } - return parseLines(modifiedLines) } return parseLines(emojiLines) } From 408c893f1556058304937004dc90ee51cfea89c3 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Tue, 8 Jul 2025 02:28:38 +0300 Subject: [PATCH 04/56] Minor fix --- .../helium314/keyboard/keyboard/emoji/EmojiPalettesView.java | 3 ++- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 3 ++- .../keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt | 4 ++++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index 36fe561f39..d69445ca0a 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -36,6 +36,7 @@ import helium314.keyboard.keyboard.PointerTracker; import helium314.keyboard.keyboard.internal.KeyDrawParams; import helium314.keyboard.keyboard.internal.KeyVisualAttributes; +import helium314.keyboard.keyboard.internal.keyboard_parser.EmojiParserKt; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.latin.AudioAndHapticFeedbackManager; import helium314.keyboard.latin.Dictionary; @@ -316,7 +317,7 @@ public String getDescription(String emoji) { return null; } - var wordProperty = sDictionaryFacilitator.getWordProperty(emoji); + var wordProperty = sDictionaryFacilitator.getWordProperty(EmojiParserKt.getEmojiNeutralVersion(emoji)); if (wordProperty == null || ! wordProperty.mHasShortcuts) { return null; } diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 255dba53dd..0d051beb8d 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -74,6 +74,7 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode import helium314.keyboard.keyboard.internal.keyboard_parser.getCode import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiDefaultVersion import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiKeyDimensions +import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiNeutralVersion import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiPopupSpec import helium314.keyboard.latin.Dictionary import helium314.keyboard.latin.DictionaryFactory @@ -252,7 +253,7 @@ class EmojiSearchActivity : ComponentActivity() { } override fun getDescription(emoji: String): String? = if (Settings.getValues().mShowEmojiDescriptions) - dictionaryFacilitator?.getWordProperty(emoji)?.mShortcutTargets[0]?.mWord else null + dictionaryFacilitator?.getWordProperty(getEmojiNeutralVersion(emoji))?.mShortcutTargets[0]?.mWord else null }) } diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt index cecefb325f..cb8cb20aa6 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/EmojiParser.kt @@ -47,6 +47,7 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte val defaultSkinTone = context.prefs().getString(Settings.PREF_EMOJI_SKIN_TONE, Defaults.PREF_EMOJI_SKIN_TONE)!! if (params.mId.mElementId == KeyboardId.ELEMENT_EMOJI_CATEGORY2) { emojiDefaultVersions.clear() + emojiNeutralVersions.clear() emojiPopupSpecs.clear() if (defaultSkinTone != "") { // adjust PEOPLE_AND_BODY if we have a non-yellow default skin tone @@ -56,6 +57,7 @@ class EmojiParser(private val params: KeyboardParams, private val context: Conte val foundIndex = split.indexOfFirst { it.contains(defaultSkinTone) } if (foundIndex > 0) { emojiDefaultVersions[split[0]] = split[foundIndex] + emojiNeutralVersions[split[foundIndex]] = split[0] Collections.swap(split, 0, foundIndex) } split.joinToString(" ") @@ -137,7 +139,9 @@ fun String.getCode(): Int = const val EMOJI_HINT_LABEL = "◥" private val emojiDefaultVersions: MutableMap = mutableMapOf() +private val emojiNeutralVersions: MutableMap = mutableMapOf() private val emojiPopupSpecs: MutableMap = mutableMapOf() fun getEmojiDefaultVersion(emoji: String): String = emojiDefaultVersions[emoji] ?: emoji +fun getEmojiNeutralVersion(emoji: String): String = emojiNeutralVersions[emoji] ?: emoji fun getEmojiPopupSpec(emoji: String): String? = emojiPopupSpecs[emoji] From 494f76bf9bfe077272a422242a5a976acb66ed84 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 9 Jul 2025 01:36:33 +0300 Subject: [PATCH 05/56] Minor fix --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 0d051beb8d..003e71038c 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -12,6 +12,7 @@ import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column @@ -120,9 +121,8 @@ class EmojiSearchActivity : ComponentActivity() { var heightDp by remember { mutableStateOf(0.dp) } - Column( - modifier = Modifier.fillMaxSize() - .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), + Column(modifier = Modifier.fillMaxSize().clickable(onClick = { cancel() }) + .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), verticalArrangement = Arrangement.Bottom ) { Column(modifier = Modifier.wrapContentHeight().onGloballyPositioned { From 7679d3e6520207aa5fada62bd8544e8181befcc4 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 9 Jul 2025 23:28:27 +0300 Subject: [PATCH 06/56] Styling --- .../keyboard/emoji/EmojiSearchActivity.kt | 155 ++++++++++-------- 1 file changed, 83 insertions(+), 72 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 003e71038c..d5e4b43dac 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -5,7 +5,6 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle -import android.view.ContextThemeWrapper import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.activity.ComponentActivity @@ -32,12 +31,14 @@ import androidx.compose.foundation.layout.wrapContentHeight import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions +import androidx.compose.foundation.text.selection.LocalTextSelectionColors import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Surface import androidx.compose.material3.Text import androidx.compose.material3.TextFieldDefaults +import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableIntStateOf @@ -49,7 +50,9 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.lerp import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource @@ -98,6 +101,7 @@ import helium314.keyboard.settings.SearchIcon * This activity is displayed in a gap created for it above the keyboard and below the host app, and partly obscures the host app. */ class EmojiSearchActivity : ComponentActivity() { + private val colors = Settings.getValues().mColors private var startup: Boolean = true private var emojiPageKeyboardView: EmojiPageKeyboardView? = null private var keyboardParams: KeyboardParams? = null @@ -112,6 +116,7 @@ class EmojiSearchActivity : ComponentActivity() { init() enableEdgeToEdge() setContent { + LocalContext.current.setTheme(KeyboardTheme.getKeyboardTheme(this).mStyleId) Surface(modifier = Modifier.fillMaxSize(), color = Color(0x80000000)) { val imeVisible = WindowInsets.isImeVisible val localDensity = LocalDensity.current @@ -125,68 +130,78 @@ class EmojiSearchActivity : ComponentActivity() { .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), verticalArrangement = Arrangement.Bottom ) { - Column(modifier = Modifier.wrapContentHeight().onGloballyPositioned { - if (!startup && !imeVisible) { - imeClosed = true - cancel() - return@onGloballyPositioned - } - if (!startup && (KeyboardSwitcher.getInstance().isShowingEmojiPalettes - || KeyboardSwitcher.getInstance().isShowingClipboardHistory)) { - cancel() - return@onGloballyPositioned - } - heightPx = it.size.height - heightDp = with(localDensity) { it.size.height.toDp() } - }) { - Row(modifier = Modifier.background(Color.White).fillMaxWidth().height(30.dp)) { + Column(modifier = Modifier.wrapContentHeight() + .background(Color(colors.get(ColorType.MAIN_BACKGROUND))).onGloballyPositioned { + if (!startup && !imeVisible) { + imeClosed = true + cancel() + return@onGloballyPositioned + } + if (!startup && (KeyboardSwitcher.getInstance().isShowingEmojiPalettes + || KeyboardSwitcher.getInstance().isShowingClipboardHistory)) { + cancel() + return@onGloballyPositioned + } + heightPx = it.size.height + heightDp = with(localDensity) { it.size.height.toDp() } + }) { + Row(modifier = Modifier.fillMaxWidth().height(30.dp)) { IconButton(onClick = { cancel() }) { - Icon( - painterResource(R.drawable.ic_arrow_back), - stringResource(R.string.spoken_description_action_previous) - ) + Icon(painter = painterResource(R.drawable.ic_arrow_back), + stringResource(R.string.spoken_description_action_previous), + tint = Color(colors.get(ColorType.EMOJI_KEY_TEXT))) } - Text( - text = stringResource(R.string.emoji_search_title), fontSize = 18.sp, - modifier = Modifier.fillMaxWidth().align(Alignment.CenterVertically) - ) + Text(text = stringResource(R.string.emoji_search_title), fontSize = 18.sp, + color = Color(colors.get(ColorType.EMOJI_KEY_TEXT)), + modifier = Modifier.fillMaxWidth().align(Alignment.CenterVertically)) } AndroidView({ emojiPageKeyboardView!! }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) val focusRequester = remember { FocusRequester() } var text by remember { mutableStateOf(TextFieldValue(searchText, selection = TextRange(searchText.length))) } - BasicTextField( - value = text, - modifier = Modifier.fillMaxWidth().heightIn(20.dp, 30.dp).focusRequester(focusRequester), - textStyle = TextStyle(textDirection = TextDirection.Content), - onValueChange = { it: TextFieldValue -> - text = it - search(it.text) - }, - enabled = true, - keyboardOptions = KeyboardOptions( - imeAction = ImeAction.Done, - platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx))) - ), - keyboardActions = KeyboardActions(onDone = { finish() }), - singleLine = true, - ) { - TextFieldDefaults.DecorationBox( - value = text.text, - contentPadding = PaddingValues(0.dp), - visualTransformation = VisualTransformation.None, - innerTextField = it, - placeholder = { Text(stringResource(R.string.search_field_placeholder)) }, - leadingIcon = { SearchIcon() }, - trailingIcon = { - IconButton(onClick = { - text = TextFieldValue() - search("") - }) { CloseIcon(cancel) } + val textFieldColors = TextFieldDefaults.colors() + .copy(unfocusedContainerColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_BACKGROUND)), + unfocusedTextColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + cursorColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + unfocusedLeadingIconColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + unfocusedTrailingIconColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + unfocusedPlaceholderColor = lerp(Color(colors.get(ColorType.FUNCTIONAL_KEY_BACKGROUND)), + Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), 0.5f)) + CompositionLocalProvider(LocalTextSelectionColors provides textFieldColors.textSelectionColors) { + BasicTextField( + value = text, + modifier = Modifier.fillMaxWidth().heightIn(20.dp, 30.dp).focusRequester(focusRequester), + textStyle = TextStyle(textDirection = TextDirection.Content, color = textFieldColors.unfocusedTextColor), + onValueChange = { it: TextFieldValue -> + text = it + search(it.text) }, - singleLine = true, enabled = true, - interactionSource = MutableInteractionSource(), - ) + keyboardOptions = KeyboardOptions( + imeAction = ImeAction.Done, + platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx))) + ), + keyboardActions = KeyboardActions(onDone = { finish() }), + singleLine = true, + ) { + TextFieldDefaults.DecorationBox( + value = text.text, + colors = textFieldColors, + contentPadding = PaddingValues(2.dp), + visualTransformation = VisualTransformation.None, + innerTextField = it, + placeholder = { Text(stringResource(R.string.search_field_placeholder)) }, + leadingIcon = { SearchIcon() }, + trailingIcon = { + IconButton(onClick = { + text = TextFieldValue() + search("") + }) { CloseIcon(cancel) } + }, + singleLine = true, + enabled = true, + interactionSource = MutableInteractionSource(), + ) + } } LaunchedEffect(Unit) { focusRequester.requestFocus() } } @@ -201,14 +216,12 @@ class EmojiSearchActivity : ComponentActivity() { override fun onStop() { val intent = Intent(this, LatinIME::class.java).setAction(EMOJI_SEARCH_DONE_ACTION) - intent.putExtra(IME_CLOSED_KEY, imeClosed) + .putExtra(IME_CLOSED_KEY, imeClosed) if (pressedKey != null) { - intent.putExtra( - EMOJI_KEY, if (pressedKey!!.code == KeyCode.MULTIPLE_CODE_POINTS) - pressedKey!!.getOutputText() - else - Character.toString(pressedKey!!.code) - ) + intent.putExtra(EMOJI_KEY, if (pressedKey!!.code == KeyCode.MULTIPLE_CODE_POINTS) + pressedKey!!.getOutputText() + else + Character.toString(pressedKey!!.code)) KeyboardSwitcher.getInstance().emojiPalettesView.addRecentKey(pressedKey) } @@ -217,30 +230,28 @@ class EmojiSearchActivity : ComponentActivity() { } private fun init() { - val contextThemeWrapper = ContextThemeWrapper(this, KeyboardTheme.getKeyboardTheme(this).mStyleId) - val keyboardWidth = ResourceUtils.getKeyboardWidth(contextThemeWrapper, Settings.getValues()) - val layoutSet = KeyboardLayoutSet.Builder(contextThemeWrapper, null) - .setSubtype(RichInputMethodSubtype.emojiSubtype) - .setKeyboardGeometry(keyboardWidth, EmojiLayoutParams(contextThemeWrapper.resources).emojiKeyboardHeight).build() + val keyboardWidth = ResourceUtils.getKeyboardWidth(this, Settings.getValues()) + val layoutSet = KeyboardLayoutSet.Builder(this, null).setSubtype(RichInputMethodSubtype.emojiSubtype) + .setKeyboardGeometry(keyboardWidth, EmojiLayoutParams(resources).emojiKeyboardHeight).build() // Initialize default versions and popup specs layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_CATEGORY2) - val keyboard = DynamicGridKeyboard(contextThemeWrapper.prefs(), layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + val keyboard = DynamicGridKeyboard(prefs(), layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 1 else 2, KeyboardId.ELEMENT_EMOJI_CATEGORY16, keyboardWidth) - val builder = KeyboardBuilder(contextThemeWrapper, KeyboardParams()) + val builder = KeyboardBuilder(this, KeyboardParams()) builder.load(keyboard.mId) keyboardParams = builder.mParams - val (width, height) = getEmojiKeyDimensions(keyboardParams!!, contextThemeWrapper) + val (width, height) = getEmojiKeyDimensions(keyboardParams!!, this) keyWidth = width keyHeight = height - emojiPageKeyboardView = EmojiPageKeyboardView(contextThemeWrapper, null) + emojiPageKeyboardView = EmojiPageKeyboardView(this, null) emojiPageKeyboardView!!.setKeyboard(keyboard) emojiPageKeyboardView!!.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) emojiPageKeyboardView!!.background = null - Settings.getValues().mColors.setBackground(emojiPageKeyboardView!!, ColorType.MAIN_BACKGROUND) + colors.setBackground(emojiPageKeyboardView!!, ColorType.MAIN_BACKGROUND) emojiPageKeyboardView!!.setPadding(0, 10, 0, 10) emojiPageKeyboardView!!.setEmojiViewCallback(object : EmojiViewCallback { From fcd91f49b15cbf501b9b21e864b483eeaf5cf8a1 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Thu, 10 Jul 2025 05:47:30 +0300 Subject: [PATCH 07/56] Minor fixes --- .../keyboard/emoji/EmojiSearchActivity.kt | 22 ++++++++++++------- .../helium314/keyboard/latin/LatinIME.java | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index d5e4b43dac..c9cc1d52d7 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -132,13 +132,16 @@ class EmojiSearchActivity : ComponentActivity() { ) { Column(modifier = Modifier.wrapContentHeight() .background(Color(colors.get(ColorType.MAIN_BACKGROUND))).onGloballyPositioned { + if (startup && imeVisible && isAlphaKeyboard()) { + search(searchText) + return@onGloballyPositioned + } if (!startup && !imeVisible) { imeClosed = true cancel() return@onGloballyPositioned } - if (!startup && (KeyboardSwitcher.getInstance().isShowingEmojiPalettes - || KeyboardSwitcher.getInstance().isShowingClipboardHistory)) { + if (!startup && !isAlphaKeyboard()) { cancel() return@onGloballyPositioned } @@ -210,10 +213,6 @@ class EmojiSearchActivity : ComponentActivity() { } } - override fun onEnterAnimationComplete() { - search(searchText) - } - override fun onStop() { val intent = Intent(this, LatinIME::class.java).setAction(EMOJI_SEARCH_DONE_ACTION) .putExtra(IME_CLOSED_KEY, imeClosed) @@ -268,14 +267,21 @@ class EmojiSearchActivity : ComponentActivity() { }) } - fun search(text: String) { - searchText = text + private fun isAlphaKeyboard(): Boolean = !(KeyboardSwitcher.getInstance().isShowingEmojiPalettes + || KeyboardSwitcher.getInstance().isShowingClipboardHistory) + + private fun search(text: String) { initDictionaryFacilitator(this) if (dictionaryFacilitator == null) { cancel() return } + if (!startup && text == searchText) { + return + } + + searchText = text startup = false val keyboard = emojiPageKeyboardView!!.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 3730d6ada0..7c726c2dcb 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1871,7 +1871,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { if (intent.getBooleanExtra(EmojiSearchActivity.IME_CLOSED_KEY, false)) { requestHideSelf(0); } else { - KeyboardSwitcher.getInstance().setEmojiKeyboard(); + mHandler.postDelayed(() -> KeyboardSwitcher.getInstance().setEmojiKeyboard(), 100); if (intent.hasExtra(EmojiSearchActivity.EMOJI_KEY)) { onTextInput(intent.getStringExtra(EmojiSearchActivity.EMOJI_KEY)); } From 2725df2c8a11fdcb7c23cce1f9bd2d132ae17761 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Fri, 11 Jul 2025 00:15:59 +0300 Subject: [PATCH 08/56] Minor fix Cosmetics --- .../keyboard/emoji/EmojiSearchActivity.kt | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index c9cc1d52d7..6e0e2bb0be 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -96,19 +96,21 @@ import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.prefs import helium314.keyboard.settings.CloseIcon import helium314.keyboard.settings.SearchIcon +import kotlin.properties.Delegates /** * This activity is displayed in a gap created for it above the keyboard and below the host app, and partly obscures the host app. */ class EmojiSearchActivity : ComponentActivity() { private val colors = Settings.getValues().mColors - private var startup: Boolean = true - private var emojiPageKeyboardView: EmojiPageKeyboardView? = null - private var keyboardParams: KeyboardParams? = null - private var keyWidth: Float? = null - private var keyHeight: Float? = null + private var enterAnimationComplete = false + private var startup = true + private lateinit var emojiPageKeyboardView: EmojiPageKeyboardView + private lateinit var keyboardParams: KeyboardParams + private var keyWidth by Delegates.notNull() + private var keyHeight by Delegates.notNull() private var pressedKey: Key? = null - private var imeClosed: Boolean = false + private var imeClosed = false @OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { @@ -132,7 +134,7 @@ class EmojiSearchActivity : ComponentActivity() { ) { Column(modifier = Modifier.wrapContentHeight() .background(Color(colors.get(ColorType.MAIN_BACKGROUND))).onGloballyPositioned { - if (startup && imeVisible && isAlphaKeyboard()) { + if (startup && enterAnimationComplete && imeVisible && isAlphaKeyboard()) { search(searchText) return@onGloballyPositioned } @@ -158,7 +160,7 @@ class EmojiSearchActivity : ComponentActivity() { color = Color(colors.get(ColorType.EMOJI_KEY_TEXT)), modifier = Modifier.fillMaxWidth().align(Alignment.CenterVertically)) } - AndroidView({ emojiPageKeyboardView!! }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) + AndroidView({ emojiPageKeyboardView }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) val focusRequester = remember { FocusRequester() } var text by remember { mutableStateOf(TextFieldValue(searchText, selection = TextRange(searchText.length))) } val textFieldColors = TextFieldDefaults.colors() @@ -213,16 +215,20 @@ class EmojiSearchActivity : ComponentActivity() { } } + override fun onEnterAnimationComplete() { + enterAnimationComplete = true + } + override fun onStop() { val intent = Intent(this, LatinIME::class.java).setAction(EMOJI_SEARCH_DONE_ACTION) .putExtra(IME_CLOSED_KEY, imeClosed) - if (pressedKey != null) { - intent.putExtra(EMOJI_KEY, if (pressedKey!!.code == KeyCode.MULTIPLE_CODE_POINTS) - pressedKey!!.getOutputText() + pressedKey?.let { + intent.putExtra(EMOJI_KEY, if (it.code == KeyCode.MULTIPLE_CODE_POINTS) + it.getOutputText() else - Character.toString(pressedKey!!.code)) + Character.toString(it.code)) - KeyboardSwitcher.getInstance().emojiPalettesView.addRecentKey(pressedKey) + KeyboardSwitcher.getInstance().emojiPalettesView.addRecentKey(it) } startService(intent) super.onStop() @@ -242,18 +248,18 @@ class EmojiSearchActivity : ComponentActivity() { val builder = KeyboardBuilder(this, KeyboardParams()) builder.load(keyboard.mId) keyboardParams = builder.mParams - val (width, height) = getEmojiKeyDimensions(keyboardParams!!, this) + val (width, height) = getEmojiKeyDimensions(keyboardParams, this) keyWidth = width keyHeight = height emojiPageKeyboardView = EmojiPageKeyboardView(this, null) - emojiPageKeyboardView!!.setKeyboard(keyboard) - emojiPageKeyboardView!!.layoutParams = + emojiPageKeyboardView.setKeyboard(keyboard) + emojiPageKeyboardView.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) - emojiPageKeyboardView!!.background = null - colors.setBackground(emojiPageKeyboardView!!, ColorType.MAIN_BACKGROUND) - emojiPageKeyboardView!!.setPadding(0, 10, 0, 10) + emojiPageKeyboardView.background = null + colors.setBackground(emojiPageKeyboardView, ColorType.MAIN_BACKGROUND) + emojiPageKeyboardView.setPadding(0, 10, 0, 10) - emojiPageKeyboardView!!.setEmojiViewCallback(object : EmojiViewCallback { + emojiPageKeyboardView.setEmojiViewCallback(object : EmojiViewCallback { override fun onPressKey(key: Key) { } @@ -283,7 +289,7 @@ class EmojiSearchActivity : ComponentActivity() { searchText = text startup = false - val keyboard = emojiPageKeyboardView!!.keyboard as DynamicGridKeyboard + val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() pressedKey = null dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { StringUtils.mightBeEmoji(it.word) }.forEach { @@ -291,14 +297,14 @@ class EmojiSearchActivity : ComponentActivity() { val popupSpec = getEmojiPopupSpec(emoji) val keyParams = Key.KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, Key.LABEL_FLAGS_FONT_NORMAL, keyboardParams) - keyParams.mAbsoluteWidth = keyWidth!! - keyParams.mAbsoluteHeight = keyHeight!! + keyParams.mAbsoluteWidth = keyWidth + keyParams.mAbsoluteHeight = keyHeight val key = keyParams.createKey() keyboard.addKeyLast(key) if (pressedKey == null && Settings.getValues().mAutoCorrectEnabled) pressedKey = key } - emojiPageKeyboardView!!.invalidate() + emojiPageKeyboardView.invalidate() } private fun cancel() { From 4a6a51d218c0f55943c7f26faecd40f0c5c3f604 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 12 Jul 2025 02:02:53 +0300 Subject: [PATCH 09/56] Minor fix --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 6e0e2bb0be..243bfac3ee 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -50,6 +50,7 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.lerp import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalContext @@ -132,8 +133,8 @@ class EmojiSearchActivity : ComponentActivity() { .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), verticalArrangement = Arrangement.Bottom ) { - Column(modifier = Modifier.wrapContentHeight() - .background(Color(colors.get(ColorType.MAIN_BACKGROUND))).onGloballyPositioned { + Column(modifier = Modifier.wrapContentHeight().background(Color(colors.get(ColorType.MAIN_BACKGROUND))) + .onGloballyPositioned { if (startup && enterAnimationComplete && imeVisible && isAlphaKeyboard()) { search(searchText) return@onGloballyPositioned @@ -187,6 +188,7 @@ class EmojiSearchActivity : ComponentActivity() { ), keyboardActions = KeyboardActions(onDone = { finish() }), singleLine = true, + cursorBrush = SolidColor(textFieldColors.cursorColor) ) { TextFieldDefaults.DecorationBox( value = text.text, From e4380111d8d942c42ebff953720b1f4aeed8a593 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 12 Jul 2025 02:37:02 +0300 Subject: [PATCH 10/56] Minor fix, license --- app/src/main/AndroidManifest.xml | 5 ++--- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 3 ++- app/src/main/java/helium314/keyboard/latin/LatinIME.java | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ebab05c10..1695bf9c5a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -76,9 +76,8 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only - diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 243bfac3ee..9bc511f4f9 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-3.0-only package helium314.keyboard.keyboard.emoji import android.R.string.cancel @@ -100,7 +101,7 @@ import helium314.keyboard.settings.SearchIcon import kotlin.properties.Delegates /** - * This activity is displayed in a gap created for it above the keyboard and below the host app, and partly obscures the host app. + * This activity is displayed in a gap created for it above the keyboard and below the host app, and disables the host app. */ class EmojiSearchActivity : ComponentActivity() { private val colors = Settings.getValues().mColors diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 7c726c2dcb..bea625d27c 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1862,7 +1862,8 @@ void launchSettings() { } public void launchEmojiSearch() { - startActivity(new Intent().setClass(this, EmojiSearchActivity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + startActivity(new Intent().setClass(this, EmojiSearchActivity.class) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_MULTIPLE_TASK)); } @Override From 251e5e8815a21d382d938aca641a44a1c060f292 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 12 Jul 2025 21:38:56 +0300 Subject: [PATCH 11/56] Minor fix --- .../keyboard/internal/keyboard_parser/floris/KeyCode.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt index b939872c31..c13d041734 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt @@ -53,7 +53,6 @@ object KeyCode { const val CLIPBOARD_CLEAR_HISTORY = -36 //const val CLIPBOARD_CLEAR_FULL_HISTORY = -37 //const val CLIPBOARD_CLEAR_PRIMARY_CLIP = -38 - const val SEARCH = -39 //const val COMPACT_LAYOUT_TO_LEFT = -111 //const val COMPACT_LAYOUT_TO_RIGHT = -112 @@ -175,6 +174,7 @@ object KeyCode { const val ALT_RIGHT = -10047 const val META_LEFT = -10048 const val META_RIGHT = -10049 + const val SEARCH = -10050 // Intents From 2445a236cc4510e346a41bef38476fa5fd702802 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Tue, 15 Jul 2025 02:02:59 +0300 Subject: [PATCH 12/56] Minor fixes --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 13 ++++--------- .../java/helium314/keyboard/latin/LatinIME.java | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 9bc511f4f9..253eedbf26 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -105,7 +105,6 @@ import kotlin.properties.Delegates */ class EmojiSearchActivity : ComponentActivity() { private val colors = Settings.getValues().mColors - private var enterAnimationComplete = false private var startup = true private lateinit var emojiPageKeyboardView: EmojiPageKeyboardView private lateinit var keyboardParams: KeyboardParams @@ -136,10 +135,6 @@ class EmojiSearchActivity : ComponentActivity() { ) { Column(modifier = Modifier.wrapContentHeight().background(Color(colors.get(ColorType.MAIN_BACKGROUND))) .onGloballyPositioned { - if (startup && enterAnimationComplete && imeVisible && isAlphaKeyboard()) { - search(searchText) - return@onGloballyPositioned - } if (!startup && !imeVisible) { imeClosed = true cancel() @@ -177,7 +172,8 @@ class EmojiSearchActivity : ComponentActivity() { BasicTextField( value = text, modifier = Modifier.fillMaxWidth().heightIn(20.dp, 30.dp).focusRequester(focusRequester), - textStyle = TextStyle(textDirection = TextDirection.Content, color = textFieldColors.unfocusedTextColor), + textStyle = TextStyle(textDirection = TextDirection.Content, + color = textFieldColors.unfocusedTextColor), onValueChange = { it: TextFieldValue -> text = it search(it.text) @@ -185,8 +181,7 @@ class EmojiSearchActivity : ComponentActivity() { enabled = true, keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done, - platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx))) - ), + platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx)))), keyboardActions = KeyboardActions(onDone = { finish() }), singleLine = true, cursorBrush = SolidColor(textFieldColors.cursorColor) @@ -219,7 +214,7 @@ class EmojiSearchActivity : ComponentActivity() { } override fun onEnterAnimationComplete() { - enterAnimationComplete = true + search(searchText) } override fun onStop() { diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index bea625d27c..c942b088cc 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1877,7 +1877,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { onTextInput(intent.getStringExtra(EmojiSearchActivity.EMOJI_KEY)); } } - return START_STICKY; + return START_NOT_STICKY; } return super.onStartCommand(intent, flags, startId); From 7e005d3d4ba8395f8ee8190cdf956e20afb80d95 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Fri, 18 Jul 2025 05:21:38 +0300 Subject: [PATCH 13/56] Use `hintLocales` --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 10 +++++----- .../keyboard/latin/inputlogic/InputLogic.java | 8 ++++---- .../keyboard/latin/utils/DictionaryInfoUtils.kt | 7 +++++++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 253eedbf26..6e1dc8ae93 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -64,6 +64,8 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.PlatformImeOptions import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.text.intl.LocaleList import androidx.compose.ui.text.style.TextDirection import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -110,6 +112,7 @@ class EmojiSearchActivity : ComponentActivity() { private lateinit var keyboardParams: KeyboardParams private var keyWidth by Delegates.notNull() private var keyHeight by Delegates.notNull() + private lateinit var hintLocales: LocaleList private var pressedKey: Key? = null private var imeClosed = false @@ -181,6 +184,7 @@ class EmojiSearchActivity : ComponentActivity() { enabled = true, keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done, + hintLocales = hintLocales, platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx)))), keyboardActions = KeyboardActions(onDone = { finish() }), singleLine = true, @@ -233,6 +237,7 @@ class EmojiSearchActivity : ComponentActivity() { } private fun init() { + hintLocales = LocaleList(DictionaryInfoUtils.getLocalesWithEmojiDicts(this).map { Locale(it.toLanguageTag()) }) val keyboardWidth = ResourceUtils.getKeyboardWidth(this, Settings.getValues()) val layoutSet = KeyboardLayoutSet.Builder(this, null).setSubtype(RichInputMethodSubtype.emojiSubtype) .setKeyboardGeometry(keyboardWidth, EmojiLayoutParams(resources).emojiKeyboardHeight).build() @@ -321,11 +326,6 @@ class EmojiSearchActivity : ComponentActivity() { private var dictionaryFacilitator: SingleDictionaryFacilitator? = null private var searchText: String = "" - fun isSupported(context: Context): Boolean { - initDictionaryFacilitator(context) - return dictionaryFacilitator != null - } - fun decodePrivateImeOptions(editorInfo: EditorInfo?): PrivateImeOptions = PrivateImeOptions( editorInfo?.privateImeOptions?.takeIf { it.startsWith(PRIVATE_IME_OPTIONS_PREFIX) } ?.substring(PRIVATE_IME_OPTIONS_PREFIX.length + 1)?.toInt() ?: 0) diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index e578ae332f..5e9af489fd 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -781,12 +781,12 @@ private void handleFunctionalEvent(final Event event, final InputTransaction inp mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME)); break; case KeyCode.SEARCH: - if (EmojiSearchActivity.Companion.isSupported(mLatinIME)) { - commitTyped(Settings.getValues(), LastComposedWord.NOT_A_SEPARATOR); - mLatinIME.launchEmojiSearch(); - } else { + if (DictionaryInfoUtils.getLocalesWithEmojiDicts(mLatinIME).isEmpty()) { // todo: open dictionary settings? onSettingsKeyPressed(); + } else { + commitTyped(Settings.getValues(), LastComposedWord.NOT_A_SEPARATOR); + mLatinIME.launchEmojiSearch(); } break; case KeyCode.SEND_INTENT_ONE, KeyCode.SEND_INTENT_TWO, KeyCode.SEND_INTENT_THREE: diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt index 05417fdb31..2ffccd8e21 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt @@ -8,6 +8,8 @@ package helium314.keyboard.latin.utils import android.content.Context import android.text.TextUtils import com.android.inputmethod.latin.utils.BinaryDictionaryUtils +import helium314.keyboard.latin.Dictionary +import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.common.LocaleUtils.constructLocale import helium314.keyboard.latin.common.loopOverCodePoints @@ -101,6 +103,11 @@ object DictionaryInfoUtils { return absoluteDirectoryName } + @JvmStatic + fun getLocalesWithEmojiDicts(context: Context): List = + RichInputMethodManager.Companion.getInstance().getMyEnabledInputMethodSubtypes(true) + .map { it.locale() }.filter { getCachedDictForLocaleAndType(it, Dictionary.TYPE_EMOJI, context) != null } + @JvmStatic fun getCachedDictForLocaleAndType(locale: Locale, type: String, context: Context): File? = getCachedDictsForLocale(locale, context).firstOrNull { it.name.substringBefore("_") == type } From 00b196c941c9cf9818747b53be9efede299d017e Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Fri, 18 Jul 2025 05:27:08 +0300 Subject: [PATCH 14/56] fix build --- .../java/helium314/keyboard/latin/inputlogic/InputLogic.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index 5e9af489fd..645fd8270e 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -49,6 +49,7 @@ import helium314.keyboard.latin.settings.SpacingAndPunctuations; import helium314.keyboard.latin.suggestions.SuggestionStripViewAccessor; import helium314.keyboard.latin.utils.AsyncResultHolder; +import helium314.keyboard.latin.utils.DictionaryInfoUtils; import helium314.keyboard.latin.utils.InputTypeUtils; import helium314.keyboard.latin.utils.IntentUtils; import helium314.keyboard.latin.utils.Log; From 763d24794ec5fcbd04ea35c4280f1ef2298a1908 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 19 Jul 2025 18:29:21 +0300 Subject: [PATCH 15/56] Cosmetics, doc --- .../keyboard/emoji/EmojiSearchActivity.kt | 36 +++++++++---------- .../helium314/keyboard/latin/LatinIME.java | 2 +- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 6e1dc8ae93..9f0e33e40b 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -108,11 +108,11 @@ import kotlin.properties.Delegates class EmojiSearchActivity : ComponentActivity() { private val colors = Settings.getValues().mColors private var startup = true + private lateinit var hintLocales: LocaleList private lateinit var emojiPageKeyboardView: EmojiPageKeyboardView private lateinit var keyboardParams: KeyboardParams private var keyWidth by Delegates.notNull() private var keyHeight by Delegates.notNull() - private lateinit var hintLocales: LocaleList private var pressedKey: Key? = null private var imeClosed = false @@ -126,12 +126,8 @@ class EmojiSearchActivity : ComponentActivity() { Surface(modifier = Modifier.fillMaxSize(), color = Color(0x80000000)) { val imeVisible = WindowInsets.isImeVisible val localDensity = LocalDensity.current - var heightPx by remember { - mutableIntStateOf(0) - } - var heightDp by remember { - mutableStateOf(0.dp) - } + var heightPx by remember { mutableIntStateOf(0) } + var heightDp by remember { mutableStateOf(0.dp) } Column(modifier = Modifier.fillMaxSize().clickable(onClick = { cancel() }) .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), verticalArrangement = Arrangement.Bottom @@ -163,21 +159,20 @@ class EmojiSearchActivity : ComponentActivity() { AndroidView({ emojiPageKeyboardView }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) val focusRequester = remember { FocusRequester() } var text by remember { mutableStateOf(TextFieldValue(searchText, selection = TextRange(searchText.length))) } - val textFieldColors = TextFieldDefaults.colors() - .copy(unfocusedContainerColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_BACKGROUND)), - unfocusedTextColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), - cursorColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), - unfocusedLeadingIconColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), - unfocusedTrailingIconColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), - unfocusedPlaceholderColor = lerp(Color(colors.get(ColorType.FUNCTIONAL_KEY_BACKGROUND)), - Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), 0.5f)) + val textFieldColors = TextFieldDefaults.colors().copy( + unfocusedContainerColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_BACKGROUND)), + unfocusedTextColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + cursorColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + unfocusedLeadingIconColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + unfocusedTrailingIconColor = Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), + unfocusedPlaceholderColor = lerp(Color(colors.get(ColorType.FUNCTIONAL_KEY_BACKGROUND)), + Color(colors.get(ColorType.FUNCTIONAL_KEY_TEXT)), 0.5f)) CompositionLocalProvider(LocalTextSelectionColors provides textFieldColors.textSelectionColors) { BasicTextField( value = text, modifier = Modifier.fillMaxWidth().heightIn(20.dp, 30.dp).focusRequester(focusRequester), - textStyle = TextStyle(textDirection = TextDirection.Content, - color = textFieldColors.unfocusedTextColor), - onValueChange = { it: TextFieldValue -> + textStyle = TextStyle(textDirection = TextDirection.Content, color = textFieldColors.unfocusedTextColor), + onValueChange = { text = it search(it.text) }, @@ -193,6 +188,11 @@ class EmojiSearchActivity : ComponentActivity() { TextFieldDefaults.DecorationBox( value = text.text, colors = textFieldColors, + + /** + * This is the reason for not using [androidx.compose.material3.TextField], + * which uses [TextFieldDefaults.contentPaddingWithoutLabel] + */ contentPadding = PaddingValues(2.dp), visualTransformation = VisualTransformation.None, innerTextField = it, diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index c942b088cc..4b44e33335 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1868,7 +1868,7 @@ public void launchEmojiSearch() { @Override public int onStartCommand(Intent intent, int flags, int startId) { - if (intent != null && EmojiSearchActivity.EMOJI_SEARCH_DONE_ACTION.equals(intent.getAction())) { + if (intent != null && EmojiSearchActivity.EMOJI_SEARCH_DONE_ACTION.equals(intent.getAction()) && ! isEmojiSearch()) { if (intent.getBooleanExtra(EmojiSearchActivity.IME_CLOSED_KEY, false)) { requestHideSelf(0); } else { From ee1ce7cbcdf3c5c48fa4d286d128276f56e7c8b7 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Tue, 22 Jul 2025 17:18:48 +0300 Subject: [PATCH 16/56] Fix crash on IME switch --- app/src/main/java/helium314/keyboard/latin/LatinIME.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 4b44e33335..35bae52fa9 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1877,6 +1877,8 @@ public int onStartCommand(Intent intent, int flags, int startId) { onTextInput(intent.getStringExtra(EmojiSearchActivity.EMOJI_KEY)); } } + + stopSelf(); // Allow the service to be destroyed on next IME switch return START_NOT_STICKY; } From a855413223a599cb4d165abcd547bda65609ae00 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 26 Jul 2025 16:30:32 +0300 Subject: [PATCH 17/56] Minor fix --- app/src/main/java/helium314/keyboard/latin/LatinIME.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 35bae52fa9..02b47e43ef 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1878,7 +1878,7 @@ public int onStartCommand(Intent intent, int flags, int startId) { } } - stopSelf(); // Allow the service to be destroyed on next IME switch + stopSelf(startId); // Allow the service to be destroyed when unbound return START_NOT_STICKY; } From 485783a2392173b365b9f1b6f00c61908ee55a9a Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Mon, 28 Jul 2025 23:52:13 +0300 Subject: [PATCH 18/56] Add timing logs, Prepare for NO_LOCALE_PER_APP --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 14 ++++++++++---- .../java/helium314/keyboard/latin/LatinIME.java | 1 + .../keyboard/latin/inputlogic/InputLogic.java | 1 - 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 9f0e33e40b..ed1528b9a0 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -96,6 +96,7 @@ import helium314.keyboard.latin.common.StringUtils import helium314.keyboard.latin.common.splitOnWhitespace import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.utils.DictionaryInfoUtils +import helium314.keyboard.latin.utils.Log import helium314.keyboard.latin.utils.ResourceUtils import helium314.keyboard.latin.utils.prefs import helium314.keyboard.settings.CloseIcon @@ -180,7 +181,7 @@ class EmojiSearchActivity : ComponentActivity() { keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done, hintLocales = hintLocales, - platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx)))), + platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx), this@EmojiSearchActivity))), keyboardActions = KeyboardActions(onDone = { finish() }), singleLine = true, cursorBrush = SolidColor(textFieldColors.cursorColor) @@ -218,7 +219,9 @@ class EmojiSearchActivity : ComponentActivity() { } override fun onEnterAnimationComplete() { + Log.d("emoji-search", "onEnterAnimationComplete") search(searchText) + Log.d("emoji-search", "initial search done") } override fun onStop() { @@ -237,6 +240,7 @@ class EmojiSearchActivity : ComponentActivity() { } private fun init() { + Log.d("emoji-search", "init start") hintLocales = LocaleList(DictionaryInfoUtils.getLocalesWithEmojiDicts(this).map { Locale(it.toLanguageTag()) }) val keyboardWidth = ResourceUtils.getKeyboardWidth(this, Settings.getValues()) val layoutSet = KeyboardLayoutSet.Builder(this, null).setSubtype(RichInputMethodSubtype.emojiSubtype) @@ -274,6 +278,7 @@ class EmojiSearchActivity : ComponentActivity() { override fun getDescription(emoji: String): String? = if (Settings.getValues().mShowEmojiDescriptions) dictionaryFacilitator?.getWordProperty(getEmojiNeutralVersion(emoji))?.mShortcutTargets[0]?.mWord else null }) + Log.d("emoji-search", "init end") } private fun isAlphaKeyboard(): Boolean = !(KeyboardSwitcher.getInstance().isShowingEmojiPalettes @@ -328,10 +333,11 @@ class EmojiSearchActivity : ComponentActivity() { fun decodePrivateImeOptions(editorInfo: EditorInfo?): PrivateImeOptions = PrivateImeOptions( editorInfo?.privateImeOptions?.takeIf { it.startsWith(PRIVATE_IME_OPTIONS_PREFIX) } - ?.substring(PRIVATE_IME_OPTIONS_PREFIX.length + 1)?.toInt() ?: 0) + ?.let { it.substring(PRIVATE_IME_OPTIONS_PREFIX.length + 1, it.indexOf(',')) }?.toInt() ?: 0) - private fun encodePrivateImeOptions(privateImeOptions: PrivateImeOptions) = - "$PRIVATE_IME_OPTIONS_PREFIX,${privateImeOptions.height}" + private fun encodePrivateImeOptions(privateImeOptions: PrivateImeOptions, context: Context) = + "$PRIVATE_IME_OPTIONS_PREFIX.${privateImeOptions.height}," + //todo: add ${context.packageName}.${Constants.ImeOption.NO_LOCALE_PER_APP} private fun initDictionaryFacilitator(context: Context) { val locale = RichInputMethodManager.getInstance().currentSubtype.locale diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 02b47e43ef..516004885e 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -1862,6 +1862,7 @@ void launchSettings() { } public void launchEmojiSearch() { + Log.d("emoji-search", "before activity launch"); startActivity(new Intent().setClass(this, EmojiSearchActivity.class) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_MULTIPLE_TASK)); } diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index 645fd8270e..3f9980a30c 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -25,7 +25,6 @@ import helium314.keyboard.event.InputTransaction; import helium314.keyboard.keyboard.Keyboard; import helium314.keyboard.keyboard.KeyboardSwitcher; -import helium314.keyboard.keyboard.emoji.EmojiSearchActivity; import helium314.keyboard.keyboard.internal.keyboard_parser.floris.KeyCode; import helium314.keyboard.latin.Dictionary; import helium314.keyboard.latin.DictionaryFacilitator; From 4d381c346867ee96d32ee6c87e200f93684d66a1 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Thu, 31 Jul 2025 01:33:47 +0300 Subject: [PATCH 19/56] Fix search startup instability, support orientation change --- app/src/main/AndroidManifest.xml | 2 +- .../keyboard/keyboard/KeyboardSwitcher.java | 5 +- .../keyboard/emoji/EmojiPalettesView.java | 5 +- .../keyboard/emoji/EmojiSearchActivity.kt | 49 ++++++++++++++----- .../helium314/keyboard/latin/LatinIME.java | 6 ++- 5 files changed, 50 insertions(+), 17 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1695bf9c5a..6dd5eb90a4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -78,7 +78,7 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only + android:windowSoftInputMode="adjustNothing|stateAlwaysVisible" android:configChanges="orientation|screenSize"/> () private lateinit var hintLocales: LocaleList private lateinit var emojiPageKeyboardView: EmojiPageKeyboardView private lateinit var keyboardParams: KeyboardParams @@ -125,22 +128,25 @@ class EmojiSearchActivity : ComponentActivity() { setContent { LocalContext.current.setTheme(KeyboardTheme.getKeyboardTheme(this).mStyleId) Surface(modifier = Modifier.fillMaxSize(), color = Color(0x80000000)) { - val imeVisible = WindowInsets.isImeVisible - val localDensity = LocalDensity.current - var heightPx by remember { mutableIntStateOf(0) } var heightDp by remember { mutableStateOf(0.dp) } Column(modifier = Modifier.fillMaxSize().clickable(onClick = { cancel() }) .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), verticalArrangement = Arrangement.Bottom ) { + val localDensity = LocalDensity.current + var heightPx by remember { mutableIntStateOf(0) } Column(modifier = Modifier.wrapContentHeight().background(Color(colors.get(ColorType.MAIN_BACKGROUND))) .onGloballyPositioned { - if (!startup && !imeVisible) { + val bottom = it.localToScreen(Offset(0f, it.size.height.toFloat())).y.toInt() + val imeVisible = bottom < screenHeight - 100 + || KeyboardSwitcher.getInstance().keyboardSwitchState != KeyboardSwitcher.KeyboardSwitchState.HIDDEN + if (imeVisible && isAlphaKeyboard()) imeOpened = true + if (imeOpened && !imeVisible) { imeClosed = true cancel() return@onGloballyPositioned } - if (!startup && !isAlphaKeyboard()) { + if (imeOpened && !isAlphaKeyboard()) { cancel() return@onGloballyPositioned } @@ -157,7 +163,9 @@ class EmojiSearchActivity : ComponentActivity() { color = Color(colors.get(ColorType.EMOJI_KEY_TEXT)), modifier = Modifier.fillMaxWidth().align(Alignment.CenterVertically)) } - AndroidView({ emojiPageKeyboardView }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) + key(emojiPageKeyboardView) { + AndroidView({ emojiPageKeyboardView }, modifier = Modifier.wrapContentHeight().fillMaxWidth()) + } val focusRequester = remember { FocusRequester() } var text by remember { mutableStateOf(TextFieldValue(searchText, selection = TextRange(searchText.length))) } val textFieldColors = TextFieldDefaults.colors().copy( @@ -181,7 +189,8 @@ class EmojiSearchActivity : ComponentActivity() { keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done, hintLocales = hintLocales, - platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx), this@EmojiSearchActivity))), + platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx), + this@EmojiSearchActivity))), keyboardActions = KeyboardActions(onDone = { finish() }), singleLine = true, cursorBrush = SolidColor(textFieldColors.cursorColor) @@ -224,6 +233,14 @@ class EmojiSearchActivity : ComponentActivity() { Log.d("emoji-search", "initial search done") } + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + init() + imeOpened = false + firstSearchDone = false + search(searchText) + } + override fun onStop() { val intent = Intent(this, LatinIME::class.java).setAction(EMOJI_SEARCH_DONE_ACTION) .putExtra(IME_CLOSED_KEY, imeClosed) @@ -241,6 +258,8 @@ class EmojiSearchActivity : ComponentActivity() { private fun init() { Log.d("emoji-search", "init start") + @Suppress("DEPRECATION") + screenHeight = windowManager.defaultDisplay.height hintLocales = LocaleList(DictionaryInfoUtils.getLocalesWithEmojiDicts(this).map { Locale(it.toLanguageTag()) }) val keyboardWidth = ResourceUtils.getKeyboardWidth(this, Settings.getValues()) val layoutSet = KeyboardLayoutSet.Builder(this, null).setSubtype(RichInputMethodSubtype.emojiSubtype) @@ -281,8 +300,8 @@ class EmojiSearchActivity : ComponentActivity() { Log.d("emoji-search", "init end") } - private fun isAlphaKeyboard(): Boolean = !(KeyboardSwitcher.getInstance().isShowingEmojiPalettes - || KeyboardSwitcher.getInstance().isShowingClipboardHistory) + private fun isAlphaKeyboard() = KeyboardSwitcher.getInstance().keyboardSwitchState !in + setOf(KeyboardSwitcher.KeyboardSwitchState.EMOJI, KeyboardSwitcher.KeyboardSwitchState.CLIPBOARD) private fun search(text: String) { initDictionaryFacilitator(this) @@ -291,12 +310,16 @@ class EmojiSearchActivity : ComponentActivity() { return } - if (!startup && text == searchText) { + if (firstSearchDone && text == searchText) { + return + } + + if (KeyboardSwitcher.getInstance().keyboard == null) { return } searchText = text - startup = false + firstSearchDone = true val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() pressedKey = null diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 516004885e..d629405aa8 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -869,6 +869,10 @@ public void setInputView(final View view) { mInputView = view; mInsetsUpdater = ViewOutlineProviderUtilsKt.setInsetsOutlineProvider(view); updateSoftInputWindowLayoutParameters(); + updateSuggestionStripView(view); + } + + public void updateSuggestionStripView(View view) { mSuggestionStripView = mSettings.getCurrent().mToolbarMode == ToolbarMode.HIDDEN || isEmojiSearch()? null : view.findViewById(R.id.suggestion_strip_view); if (hasSuggestionStripView()) { @@ -1616,7 +1620,7 @@ void showGesturePreviewAndSuggestionStrip(@NonNull final SuggestedWords suggeste dismissGestureFloatingPreviewText /* dismissDelayed */); } - private boolean hasSuggestionStripView() { + public boolean hasSuggestionStripView() { return null != mSuggestionStripView; } From 26972b01c9775005c8e8790d15efd49dbed1c837 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Thu, 31 Jul 2025 01:53:56 +0300 Subject: [PATCH 20/56] Fix failing tests --- .../main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java index d4d5d32de2..8a4e11ad66 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardSwitcher.java @@ -113,7 +113,7 @@ public void updateKeyboardTheme(@NonNull Context displayContext) { settings.loadSettings(displayContext, settings.getCurrent().mLocale, settings.getCurrent().mInputAttributes); if (mKeyboardView != null) mLatinIME.setInputView(onCreateInputView(displayContext, mIsHardwareAcceleratedDrawingEnabled)); - } else if (mLatinIME.hasSuggestionStripView() + } else if (mCurrentInputView != null && mLatinIME.hasSuggestionStripView() == (Settings.getValues().mToolbarMode == ToolbarMode.HIDDEN || mLatinIME.isEmojiSearch())) { mLatinIME.updateSuggestionStripView(mCurrentInputView); } From d1042dc21089c1674bad0dd88d5c132c4de1e7ce Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 9 Aug 2025 23:48:26 +0300 Subject: [PATCH 21/56] Minor improvements --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 1ae5be20b5..46ab78b3cd 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -139,8 +139,8 @@ class EmojiSearchActivity : ComponentActivity() { .onGloballyPositioned { val bottom = it.localToScreen(Offset(0f, it.size.height.toFloat())).y.toInt() val imeVisible = bottom < screenHeight - 100 - || KeyboardSwitcher.getInstance().keyboardSwitchState != KeyboardSwitcher.KeyboardSwitchState.HIDDEN - if (imeVisible && isAlphaKeyboard()) imeOpened = true + Log.d("emoji-search", "imeVisible: $imeVisible, imeOpened: $imeOpened, bottom: $bottom, " + + "keyboardState: ${KeyboardSwitcher.getInstance().keyboardSwitchState}") if (imeOpened && !imeVisible) { imeClosed = true cancel() @@ -150,6 +150,9 @@ class EmojiSearchActivity : ComponentActivity() { cancel() return@onGloballyPositioned } + if (imeVisible && isAlphaKeyboard()) { + imeOpened = true + } heightPx = it.size.height heightDp = with(localDensity) { it.size.height.toDp() } }) { @@ -315,6 +318,7 @@ class EmojiSearchActivity : ComponentActivity() { } if (KeyboardSwitcher.getInstance().keyboard == null) { + /** Avoid crash in [SingleDictionaryFacilitator.getSuggestions] */ return } From d58f7a24c77b3b3be313ee11d166d4caf2c54f52 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Fri, 15 Aug 2025 04:17:25 +0300 Subject: [PATCH 22/56] Minor fix --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 46ab78b3cd..607dee2d9b 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -136,7 +136,7 @@ class EmojiSearchActivity : ComponentActivity() { val localDensity = LocalDensity.current var heightPx by remember { mutableIntStateOf(0) } Column(modifier = Modifier.wrapContentHeight().background(Color(colors.get(ColorType.MAIN_BACKGROUND))) - .onGloballyPositioned { + .clickable(onClick = { }).onGloballyPositioned { val bottom = it.localToScreen(Offset(0f, it.size.height.toFloat())).y.toInt() val imeVisible = bottom < screenHeight - 100 Log.d("emoji-search", "imeVisible: $imeVisible, imeOpened: $imeOpened, bottom: $bottom, " + From cece5166557eeb89bb8220a1d20352a947212b99 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 16 Aug 2025 03:29:55 +0300 Subject: [PATCH 23/56] Minor fix --- app/build.gradle.kts | 2 +- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7f38a5b4b9..401cdab21e 100755 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -114,7 +114,7 @@ dependencies { // compose coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5") - implementation(platform("androidx.compose:compose-bom-beta:2025.06.01")) + implementation(platform("androidx.compose:compose-bom:2025.08.00")) implementation("androidx.compose.material3:material3") implementation("androidx.compose.ui:ui-tooling-preview") debugImplementation("androidx.compose.ui:ui-tooling") diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 607dee2d9b..b00ca81b15 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.Intent import android.content.res.Configuration import android.os.Bundle +import android.os.Handler import android.view.ViewGroup import android.view.inputmethod.EditorInfo import androidx.activity.ComponentActivity @@ -118,6 +119,7 @@ class EmojiSearchActivity : ComponentActivity() { private var keyWidth by Delegates.notNull() private var keyHeight by Delegates.notNull() private var pressedKey: Key? = null + private var imeVisible = false private var imeClosed = false @OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class) @@ -138,13 +140,17 @@ class EmojiSearchActivity : ComponentActivity() { Column(modifier = Modifier.wrapContentHeight().background(Color(colors.get(ColorType.MAIN_BACKGROUND))) .clickable(onClick = { }).onGloballyPositioned { val bottom = it.localToScreen(Offset(0f, it.size.height.toFloat())).y.toInt() - val imeVisible = bottom < screenHeight - 100 + imeVisible = bottom < screenHeight - 100 Log.d("emoji-search", "imeVisible: $imeVisible, imeOpened: $imeOpened, bottom: $bottom, " + "keyboardState: ${KeyboardSwitcher.getInstance().keyboardSwitchState}") if (imeOpened && !imeVisible) { - imeClosed = true - cancel() - return@onGloballyPositioned + Handler(this@EmojiSearchActivity.mainLooper).postDelayed({ + if (!imeVisible) { + Log.d("emoji-search", "IME closed") + imeClosed = true + cancel() + } + }, 200) } if (imeOpened && !isAlphaKeyboard()) { cancel() From 104a33ef5091d9244d6e0b2dcfd03c71e45b911e Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 16 Aug 2025 04:03:08 +0300 Subject: [PATCH 24/56] Minor fix --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index b00ca81b15..66bc290bb9 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -138,7 +138,7 @@ class EmojiSearchActivity : ComponentActivity() { val localDensity = LocalDensity.current var heightPx by remember { mutableIntStateOf(0) } Column(modifier = Modifier.wrapContentHeight().background(Color(colors.get(ColorType.MAIN_BACKGROUND))) - .clickable(onClick = { }).onGloballyPositioned { + .clickable(false) {}.onGloballyPositioned { val bottom = it.localToScreen(Offset(0f, it.size.height.toFloat())).y.toInt() imeVisible = bottom < screenHeight - 100 Log.d("emoji-search", "imeVisible: $imeVisible, imeOpened: $imeOpened, bottom: $bottom, " + From dd37915d8cf29a86d57027ab47b4bd523166c09a Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Thu, 21 Aug 2025 03:41:26 +0300 Subject: [PATCH 25/56] Another activity closing fix, Fix dynamic night color --- .../keyboard/emoji/EmojiSearchActivity.kt | 21 +++++++++++-------- .../helium314/keyboard/latin/common/Colors.kt | 2 +- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 66bc290bb9..2388ccd1f7 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -94,7 +94,7 @@ import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.RichInputMethodSubtype import helium314.keyboard.latin.SingleDictionaryFacilitator import helium314.keyboard.latin.common.ColorType -import helium314.keyboard.latin.common.StringUtils +import helium314.keyboard.latin.common.mightBeEmoji import helium314.keyboard.latin.common.splitOnWhitespace import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.utils.DictionaryInfoUtils @@ -122,6 +122,14 @@ class EmojiSearchActivity : ComponentActivity() { private var imeVisible = false private var imeClosed = false + private val closer = Runnable { + if (!imeVisible) { + Log.d("emoji-search", "IME closed") + imeClosed = true + cancel() + } + } + @OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -144,13 +152,7 @@ class EmojiSearchActivity : ComponentActivity() { Log.d("emoji-search", "imeVisible: $imeVisible, imeOpened: $imeOpened, bottom: $bottom, " + "keyboardState: ${KeyboardSwitcher.getInstance().keyboardSwitchState}") if (imeOpened && !imeVisible) { - Handler(this@EmojiSearchActivity.mainLooper).postDelayed({ - if (!imeVisible) { - Log.d("emoji-search", "IME closed") - imeClosed = true - cancel() - } - }, 200) + Handler(this@EmojiSearchActivity.mainLooper).postDelayed(closer, 200) } if (imeOpened && !isAlphaKeyboard()) { cancel() @@ -158,6 +160,7 @@ class EmojiSearchActivity : ComponentActivity() { } if (imeVisible && isAlphaKeyboard()) { imeOpened = true + Handler(this@EmojiSearchActivity.mainLooper).removeCallbacks(closer) } heightPx = it.size.height heightDp = with(localDensity) { it.size.height.toDp() } @@ -333,7 +336,7 @@ class EmojiSearchActivity : ComponentActivity() { val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() pressedKey = null - dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { StringUtils.mightBeEmoji(it.word) }.forEach { + dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { mightBeEmoji(it.word) }.forEach { val emoji = getEmojiDefaultVersion(it.word) val popupSpec = getEmojiPopupSpec(emoji) val keyParams = Key.KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, diff --git a/app/src/main/java/helium314/keyboard/latin/common/Colors.kt b/app/src/main/java/helium314/keyboard/latin/common/Colors.kt index 7081228280..26a366d0a6 100644 --- a/app/src/main/java/helium314/keyboard/latin/common/Colors.kt +++ b/app/src/main/java/helium314/keyboard/latin/common/Colors.kt @@ -281,7 +281,7 @@ class DynamicColors(context: Context, override val themeStyle: String, override KEY_ICON, POPUP_KEY_ICON, ONE_HANDED_MODE_BUTTON, EMOJI_CATEGORY, TOOL_BAR_KEY, FUNCTIONAL_KEY_TEXT -> keyText KEY_HINT_TEXT -> keyHintText SPACE_BAR_TEXT -> spaceBarText - FUNCTIONAL_KEY_BACKGROUND -> functionalKey + FUNCTIONAL_KEY_BACKGROUND -> if (!isNight) functionalKey else doubleAdjustedKeyBackground SPACE_BAR_BACKGROUND -> spaceBar MORE_SUGGESTIONS_WORD_BACKGROUND, MAIN_BACKGROUND -> background KEY_BACKGROUND -> keyBackground From 534191a6f9d384f267620380a8d663f5e15c3e0d Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 23 Aug 2025 05:14:11 +0300 Subject: [PATCH 26/56] Another activity closing fix --- .../keyboard/emoji/EmojiSearchActivity.kt | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 2388ccd1f7..4a8a1483b5 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -149,8 +149,8 @@ class EmojiSearchActivity : ComponentActivity() { .clickable(false) {}.onGloballyPositioned { val bottom = it.localToScreen(Offset(0f, it.size.height.toFloat())).y.toInt() imeVisible = bottom < screenHeight - 100 - Log.d("emoji-search", "imeVisible: $imeVisible, imeOpened: $imeOpened, bottom: $bottom, " + - "keyboardState: ${KeyboardSwitcher.getInstance().keyboardSwitchState}") + Log.d("emoji-search", "imeVisible: $imeVisible, firstSearchDone: $firstSearchDone, imeOpened: $imeOpened, " + + "bottom: $bottom, keyboardState: ${KeyboardSwitcher.getInstance().keyboardSwitchState}") if (imeOpened && !imeVisible) { Handler(this@EmojiSearchActivity.mainLooper).postDelayed(closer, 200) } @@ -158,7 +158,8 @@ class EmojiSearchActivity : ComponentActivity() { cancel() return@onGloballyPositioned } - if (imeVisible && isAlphaKeyboard()) { + if (imeVisible && firstSearchDone && isAlphaKeyboard()) { + Log.d("emoji-search", "IME opened in onGloballyPositioned") imeOpened = true Handler(this@EmojiSearchActivity.mainLooper).removeCallbacks(closer) } @@ -248,6 +249,7 @@ class EmojiSearchActivity : ComponentActivity() { override fun onConfigurationChanged(newConfig: Configuration) { super.onConfigurationChanged(newConfig) init() + imeVisible = false imeOpened = false firstSearchDone = false search(searchText) @@ -272,6 +274,7 @@ class EmojiSearchActivity : ComponentActivity() { Log.d("emoji-search", "init start") @Suppress("DEPRECATION") screenHeight = windowManager.defaultDisplay.height + Log.d("emoji-search", "screenHeight: $screenHeight") hintLocales = LocaleList(DictionaryInfoUtils.getLocalesWithEmojiDicts(this).map { Locale(it.toLanguageTag()) }) val keyboardWidth = ResourceUtils.getKeyboardWidth(this, Settings.getValues()) val layoutSet = KeyboardLayoutSet.Builder(this, null).setSubtype(RichInputMethodSubtype.emojiSubtype) @@ -331,8 +334,6 @@ class EmojiSearchActivity : ComponentActivity() { return } - searchText = text - firstSearchDone = true val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() pressedKey = null @@ -349,6 +350,13 @@ class EmojiSearchActivity : ComponentActivity() { pressedKey = key } emojiPageKeyboardView.invalidate() + + searchText = text + firstSearchDone = true + if (imeVisible && !imeOpened) { + Log.d("emoji-search", "IME opened in search") + imeOpened = true + } } private fun cancel() { From 885f45b83a161ed3d8c222c5784c463c94fdf47c Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 24 Sep 2025 04:40:47 +0300 Subject: [PATCH 27/56] Use `isEmoji` --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 4a8a1483b5..de08209a08 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -94,7 +94,7 @@ import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.RichInputMethodSubtype import helium314.keyboard.latin.SingleDictionaryFacilitator import helium314.keyboard.latin.common.ColorType -import helium314.keyboard.latin.common.mightBeEmoji +import helium314.keyboard.latin.common.isEmoji import helium314.keyboard.latin.common.splitOnWhitespace import helium314.keyboard.latin.settings.Settings import helium314.keyboard.latin.utils.DictionaryInfoUtils @@ -337,7 +337,7 @@ class EmojiSearchActivity : ComponentActivity() { val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() pressedKey = null - dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { mightBeEmoji(it.word) }.forEach { + dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { isEmoji(it.word) }.forEach { val emoji = getEmojiDefaultVersion(it.word) val popupSpec = getEmojiPopupSpec(emoji) val keyParams = Key.KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, From f7ec68f279bc9662b66f68fd73172323afd5a3fc Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 27 Sep 2025 20:07:14 +0300 Subject: [PATCH 28/56] Add todo --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index de08209a08..5d4f6b307f 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -337,6 +337,7 @@ class EmojiSearchActivity : ComponentActivity() { val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() pressedKey = null + //todo: change to suggestion.isEmoji() dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { isEmoji(it.word) }.forEach { val emoji = getEmojiDefaultVersion(it.word) val popupSpec = getEmojiPopupSpec(emoji) From 876c5e8fbbaad321cbd5e73c68624cf17d2dd547 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 1 Nov 2025 02:37:08 +0200 Subject: [PATCH 29/56] Cleanup --- .../keyboard/keyboard/emoji/EmojiPalettesView.java | 6 ++---- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 6 ++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index cc7281e208..a952f8839c 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -342,7 +342,7 @@ public void startEmojiPalettes(final KeyVisualAttributes keyVisualAttr, initDictionaryFacilitator(); } - public void addRecentKey(final Key key) { + void addRecentKey(final Key key) { if (Settings.getValues().mIncognitoModeEnabled) { // We do not want to log recent keys while being in incognito return; @@ -353,9 +353,7 @@ public void addRecentKey(final Key key) { } getRecentsKeyboard().addKeyFirst(key); - if (mPager != null) { - mPager.getAdapter().notifyItemChanged(mEmojiCategory.getRecentTabId()); - } + mPager.getAdapter().notifyItemChanged(mEmojiCategory.getRecentTabId()); } private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) { diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 5d4f6b307f..144c8eeb0d 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -202,8 +202,7 @@ class EmojiSearchActivity : ComponentActivity() { keyboardOptions = KeyboardOptions( imeAction = ImeAction.Done, hintLocales = hintLocales, - platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx), - this@EmojiSearchActivity))), + platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx)))), keyboardActions = KeyboardActions(onDone = { finish() }), singleLine = true, cursorBrush = SolidColor(textFieldColors.cursorColor) @@ -380,9 +379,8 @@ class EmojiSearchActivity : ComponentActivity() { editorInfo?.privateImeOptions?.takeIf { it.startsWith(PRIVATE_IME_OPTIONS_PREFIX) } ?.let { it.substring(PRIVATE_IME_OPTIONS_PREFIX.length + 1, it.indexOf(',')) }?.toInt() ?: 0) - private fun encodePrivateImeOptions(privateImeOptions: PrivateImeOptions, context: Context) = + private fun encodePrivateImeOptions(privateImeOptions: PrivateImeOptions) = "$PRIVATE_IME_OPTIONS_PREFIX.${privateImeOptions.height}," - //todo: add ${context.packageName}.${Constants.ImeOption.NO_LOCALE_PER_APP} private fun initDictionaryFacilitator(context: Context) { val locale = RichInputMethodManager.getInstance().currentSubtype.locale From b90fed331913e4d8808804855be205d595a3a987 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 5 Nov 2025 01:01:58 +0200 Subject: [PATCH 30/56] Fix main merge --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 144c8eeb0d..78b37d7ead 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -86,8 +86,8 @@ import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiDefaultVersi import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiKeyDimensions import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiNeutralVersion import helium314.keyboard.keyboard.internal.keyboard_parser.getEmojiPopupSpec -import helium314.keyboard.latin.Dictionary -import helium314.keyboard.latin.DictionaryFactory +import helium314.keyboard.latin.dictionary.Dictionary +import helium314.keyboard.latin.dictionary.DictionaryFactory import helium314.keyboard.latin.LatinIME import helium314.keyboard.latin.R import helium314.keyboard.latin.RichInputMethodManager From 3f55c095b9555a7a36994460d1050e541544fbed Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 5 Nov 2025 01:06:29 +0200 Subject: [PATCH 31/56] Fix main merge --- .../java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt index 13dbc87fa2..618bba11a6 100644 --- a/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt +++ b/app/src/main/java/helium314/keyboard/latin/utils/DictionaryInfoUtils.kt @@ -8,7 +8,7 @@ package helium314.keyboard.latin.utils import android.content.Context import android.text.TextUtils import com.android.inputmethod.latin.utils.BinaryDictionaryUtils -import helium314.keyboard.latin.Dictionary +import helium314.keyboard.latin.dictionary.Dictionary import helium314.keyboard.latin.RichInputMethodManager import helium314.keyboard.latin.common.FileUtils import helium314.keyboard.latin.common.LocaleUtils.constructLocale From 76f768cb1ccf436b9045e82fa4fc7407aa0732eb Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 5 Nov 2025 01:34:13 +0200 Subject: [PATCH 32/56] Switch to abc keyboard --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 78b37d7ead..80b83859ec 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -63,6 +63,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.PlatformImeOptions import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.VisualTransformation @@ -199,8 +200,7 @@ class EmojiSearchActivity : ComponentActivity() { search(it.text) }, enabled = true, - keyboardOptions = KeyboardOptions( - imeAction = ImeAction.Done, + keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done, hintLocales = hintLocales, platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx)))), keyboardActions = KeyboardActions(onDone = { finish() }), @@ -311,6 +311,7 @@ class EmojiSearchActivity : ComponentActivity() { override fun getDescription(emoji: String): String? = if (Settings.getValues().mShowEmojiDescriptions) dictionaryFacilitator?.getWordProperty(getEmojiNeutralVersion(emoji))?.mShortcutTargets[0]?.mWord else null }) + KeyboardSwitcher.getInstance().setAlphabetKeyboard() Log.d("emoji-search", "init end") } From 8876038747dffa031da0528febcdefe30dede2f6 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 5 Nov 2025 20:35:46 +0200 Subject: [PATCH 33/56] Fix autocorrect --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 80b83859ec..d9bc4055ce 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -119,6 +119,7 @@ class EmojiSearchActivity : ComponentActivity() { private lateinit var keyboardParams: KeyboardParams private var keyWidth by Delegates.notNull() private var keyHeight by Delegates.notNull() + private var firstKey: Key? = null private var pressedKey: Key? = null private var imeVisible = false private var imeClosed = false @@ -203,7 +204,10 @@ class EmojiSearchActivity : ComponentActivity() { keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Text, imeAction = ImeAction.Done, hintLocales = hintLocales, platformImeOptions = PlatformImeOptions(encodePrivateImeOptions(PrivateImeOptions(heightPx)))), - keyboardActions = KeyboardActions(onDone = { finish() }), + keyboardActions = KeyboardActions(onDone = { + if (Settings.getValues().mAutoCorrectEnabled) pressedKey = firstKey + finish() + }), singleLine = true, cursorBrush = SolidColor(textFieldColors.cursorColor) ) { @@ -336,6 +340,7 @@ class EmojiSearchActivity : ComponentActivity() { val keyboard = emojiPageKeyboardView.keyboard as DynamicGridKeyboard keyboard.removeAllKeys() + firstKey = null pressedKey = null //todo: change to suggestion.isEmoji() dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { isEmoji(it.word) }.forEach { @@ -347,8 +352,7 @@ class EmojiSearchActivity : ComponentActivity() { keyParams.mAbsoluteHeight = keyHeight val key = keyParams.createKey() keyboard.addKeyLast(key) - if (pressedKey == null && Settings.getValues().mAutoCorrectEnabled) - pressedKey = key + if (firstKey == null) firstKey = key } emojiPageKeyboardView.invalidate() @@ -361,7 +365,6 @@ class EmojiSearchActivity : ComponentActivity() { } private fun cancel() { - pressedKey = null finish() } From 7bc00c8cdb82874372ee74c2b405022f973abd70 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 15 Nov 2025 00:01:17 +0200 Subject: [PATCH 34/56] Disable inline emoji search if in full emoji search mode --- .../java/helium314/keyboard/latin/inputlogic/InputLogic.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index 268caeba9e..ee27be5012 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -2708,8 +2708,7 @@ private static boolean isValidInlineEmojiSearchPreviousChar(int charBeforeBefore } public void updateEmojiDictionary(Locale locale) { - //todo: disable if in full emoji search mode - if (Settings.getValues().mInlineEmojiSearch && Settings.getValues().needsToLookupSuggestions()) { + if (Settings.getValues().mInlineEmojiSearch && Settings.getValues().needsToLookupSuggestions() && ! mLatinIME.isEmojiSearch()) { if (mEmojiDictionaryFacilitator == null || ! mEmojiDictionaryFacilitator.isForLocale(locale)) { closeEmojiDictionary(); var dictFile = DictionaryInfoUtils.getCachedDictForLocaleAndType(locale, "emoji", mLatinIME); From 7ced3191f135b6f42429d44581791f809d6ece81 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Sat, 15 Nov 2025 19:51:35 +0200 Subject: [PATCH 35/56] Fix main merge --- .../layouts/emoji_bottom/emoji_bottom_row_with_action.json | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json index 4827b365d4..0f506a2bed 100644 --- a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json +++ b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json @@ -1,6 +1,7 @@ [ [ { "label": "alpha", "width": 0.15 }, + { "label": "search", "width": 0.15 }, { "label": "space", "width": -1 }, { "label": "delete", "width": 0.15 }, { "label": "action", "width": 0.15 } From 00461dfeb9e2651e41b4139d2f9c738f683451cf Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Mon, 17 Nov 2025 01:44:43 +0200 Subject: [PATCH 36/56] Cleanup --- .../helium314/keyboard/keyboard/emoji/EmojiPalettesView.java | 1 - .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index e501e0dd4b..d77f2fe93a 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -354,7 +354,6 @@ void addRecentKey(final Key key) { return; } getRecentsKeyboard().addKeyFirst(key); - mPager.getAdapter().notifyItemChanged(mEmojiCategory.getRecentTabId()); } diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index d9bc4055ce..d9ac20ece7 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -342,8 +342,7 @@ class EmojiSearchActivity : ComponentActivity() { keyboard.removeAllKeys() firstKey = null pressedKey = null - //todo: change to suggestion.isEmoji() - dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { isEmoji(it.word) }.forEach { + dictionaryFacilitator!!.getSuggestions(text.splitOnWhitespace()).filter { it.isEmoji }.forEach { val emoji = getEmojiDefaultVersion(it.word) val popupSpec = getEmojiPopupSpec(emoji) val keyParams = Key.KeyParams(emoji, emoji.getCode(), if (popupSpec != null) EMOJI_HINT_LABEL else null, popupSpec, From d108ef9a8554758102807e190baa5a639953784b Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 19 Nov 2025 01:49:41 +0200 Subject: [PATCH 37/56] Close dictionary on dictionary changes --- .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 9 ++++++++- app/src/main/java/helium314/keyboard/latin/LatinIME.java | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index d9ac20ece7..9d371bc041 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -313,7 +313,9 @@ class EmojiSearchActivity : ComponentActivity() { } override fun getDescription(emoji: String): String? = if (Settings.getValues().mShowEmojiDescriptions) - dictionaryFacilitator?.getWordProperty(getEmojiNeutralVersion(emoji))?.mShortcutTargets[0]?.mWord else null + dictionaryFacilitator?.getWordProperty(getEmojiNeutralVersion(emoji))?.let { + if (it.mHasShortcuts) it.mShortcutTargets[0]?.mWord else null + } else null }) KeyboardSwitcher.getInstance().setAlphabetKeyboard() Log.d("emoji-search", "init end") @@ -382,6 +384,11 @@ class EmojiSearchActivity : ComponentActivity() { editorInfo?.privateImeOptions?.takeIf { it.startsWith(PRIVATE_IME_OPTIONS_PREFIX) } ?.let { it.substring(PRIVATE_IME_OPTIONS_PREFIX.length + 1, it.indexOf(',')) }?.toInt() ?: 0) + fun closeDictionaryFacilitator() { + dictionaryFacilitator?.closeDictionaries() + dictionaryFacilitator = null + } + private fun encodePrivateImeOptions(privateImeOptions: PrivateImeOptions) = "$PRIVATE_IME_OPTIONS_PREFIX.${privateImeOptions.height}," diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 986dc0a939..ff63451a1c 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -667,6 +667,7 @@ private void resetDictionaryFacilitator(@NonNull final Locale locale) { mDictionaryFacilitator.resetDictionaries(this, mDictionaryFacilitator.getMainLocale(), settingsValues.mUseContactsDictionary, settingsValues.mUseAppsDictionary, settingsValues.mUsePersonalizedDicts, true, "", this); + EmojiSearchActivity.Companion.closeDictionaryFacilitator(); } // used for debug From c9cb50b2a367b83fd73cd35f4430753b94d022bd Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Tue, 25 Nov 2025 01:23:25 +0200 Subject: [PATCH 38/56] Fix for API < 30 --- app/src/main/AndroidManifest.xml | 2 +- .../keyboard/emoji/EmojiSearchActivity.kt | 29 ++++++++++--------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 322202c2e7..8dee1a1520 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -86,7 +86,7 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only + android:windowSoftInputMode="adjustResize|stateAlwaysVisible" android:configChanges="orientation|screenSize"/> Date: Wed, 26 Nov 2025 03:19:52 +0200 Subject: [PATCH 39/56] Fix landscape --- .../helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 772dd5e31c..7fa487197f 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -21,11 +21,11 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.exclude import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.safeDrawing import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.layout.wrapContentHeight @@ -143,7 +143,7 @@ class EmojiSearchActivity : ComponentActivity() { Surface(modifier = Modifier.fillMaxSize(), color = Color(0x80000000)) { var heightDp by remember { mutableStateOf(0.dp) } Column(modifier = Modifier.fillMaxSize().clickable(onClick = { cancel() }) - .windowInsetsPadding(WindowInsets.safeDrawing).offset(0.dp, heightDp), + .windowInsetsPadding(WindowInsets.safeDrawing.exclude(WindowInsets(bottom = heightDp))), verticalArrangement = Arrangement.Bottom ) { val localDensity = LocalDensity.current From d8dcff00b7f7e301d216e79b6a7243fd2922aea4 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Wed, 26 Nov 2025 23:54:20 +0200 Subject: [PATCH 40/56] Revert `config_emoji_keyboard_max_recents_key_count` -> `config_emoji_keyboard_max_recents_row_count` change, adding two factory methods to `DynamicGridKeyboard` --- .../keyboard/emoji/DynamicGridKeyboard.java | 14 ++++++++++++-- .../keyboard/keyboard/emoji/EmojiCategory.java | 12 ++++++------ .../keyboard/keyboard/emoji/EmojiSearchActivity.kt | 2 +- app/src/main/res/values-land/config.xml | 2 +- app/src/main/res/values-sw600dp-land/config.xml | 2 +- app/src/main/res/values-sw600dp/config.xml | 2 +- app/src/main/res/values-sw768dp-land/config.xml | 2 +- app/src/main/res/values-sw768dp/config.xml | 2 +- app/src/main/res/values/config.xml | 2 +- 9 files changed, 25 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java index 286174e497..7f4875a323 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java @@ -50,8 +50,18 @@ final class DynamicGridKeyboard extends Keyboard { private List mCachedGridKeys; private final ArrayList mEmptyColumnIndices = new ArrayList<>(4); - public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard, + public static DynamicGridKeyboard ofKeyCount(final SharedPreferences prefs, final Keyboard templateKeyboard, + final int maxKeyCount, final int categoryId, final int width) { + return new DynamicGridKeyboard(prefs, templateKeyboard, maxKeyCount, categoryId, width, false); + } + + public static DynamicGridKeyboard ofRowCount(final SharedPreferences prefs, final Keyboard templateKeyboard, final int maxRowCount, final int categoryId, final int width) { + return new DynamicGridKeyboard(prefs, templateKeyboard, maxRowCount, categoryId, width, true); + } + + private DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard, + final int maxCount, final int categoryId, final int width, boolean rowCount) { super(templateKeyboard); // todo: would be better to keep them final and not require width, but how to properly set width of the template keyboard? // an alternative would be to always create the templateKeyboard with full width @@ -69,7 +79,7 @@ public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templat mColumnsNum = mBaseWidth / mHorizontalStep; if (spacerWidth > 0) setSpacerColumns(spacerWidth); - mMaxKeyCount = maxRowCount * getOccupiedColumnCount(); + mMaxKeyCount = rowCount? maxCount * getOccupiedColumnCount() : maxCount; mIsRecents = categoryId == EmojiCategory.ID_RECENTS; mPrefs = prefs; } diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java index fd89e7b4d4..81327644b8 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java @@ -119,7 +119,7 @@ public int getPageCount() { private final SharedPreferences mPrefs; private final Resources mRes; private final Context mContext; - private final int mMaxRecentsRowCount; + private final int mMaxRecentsKeyCount; private final KeyboardLayoutSet mLayoutSet; private final HashMap mCategoryNameToIdMap = new HashMap<>(); private final int[] mCategoryTabIconId = new int[sCategoryName.length]; @@ -133,7 +133,7 @@ public EmojiCategory(final Context ctx, final KeyboardLayoutSet layoutSet, final mPrefs = KtxKt.prefs(ctx); mRes = ctx.getResources(); mContext = ctx; - mMaxRecentsRowCount = mRes.getInteger(R.integer.config_emoji_keyboard_max_recents_row_count); + mMaxRecentsKeyCount = mRes.getInteger(R.integer.config_emoji_keyboard_max_recents_key_count); mLayoutSet = layoutSet; for (int i = 0; i < sCategoryName.length; ++i) { mCategoryNameToIdMap.put(sCategoryName[i], i); @@ -292,9 +292,9 @@ public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { final int currentWidth = ResourceUtils.getKeyboardWidth(mContext, Settings.getValues()); if (categoryId == EmojiCategory.ID_RECENTS) { - final DynamicGridKeyboard kbd = new DynamicGridKeyboard(mPrefs, + final DynamicGridKeyboard kbd = DynamicGridKeyboard.ofKeyCount(mPrefs, mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - mMaxRecentsRowCount, categoryId, currentWidth); + mMaxRecentsKeyCount, categoryId, currentWidth); mCategoryKeyboardMap.put(categoryKeyboardMapKey, kbd); kbd.loadRecentKeys(mCategoryKeyboardMap.values()); return kbd; @@ -305,7 +305,7 @@ public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { final Key[][] sortedKeysPages = sortKeysGrouped( keyboard.getSortedKeys(), keyCountPerPage); for (int pageId = 0; pageId < sortedKeysPages.length; ++pageId) { - final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, + final DynamicGridKeyboard tempKeyboard = DynamicGridKeyboard.ofRowCount(mPrefs, mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), MAX_LINE_COUNT_PER_PAGE, categoryId, currentWidth); for (final Key emojiKey : sortedKeysPages[pageId]) { @@ -321,7 +321,7 @@ public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { } private int computeMaxKeyCountPerPage() { - final DynamicGridKeyboard tempKeyboard = new DynamicGridKeyboard(mPrefs, + final DynamicGridKeyboard tempKeyboard = DynamicGridKeyboard.ofKeyCount(mPrefs, mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), 0, 0, ResourceUtils.getKeyboardWidth(mContext, Settings.getValues())); return MAX_LINE_COUNT_PER_PAGE * tempKeyboard.getOccupiedColumnCount(); diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt index 7fa487197f..ddb8046e02 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiSearchActivity.kt @@ -287,7 +287,7 @@ class EmojiSearchActivity : ComponentActivity() { // Initialize default versions and popup specs layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_CATEGORY2) - val keyboard = DynamicGridKeyboard(prefs(), layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), + val keyboard = DynamicGridKeyboard.ofRowCount(prefs(), layoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), if (resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE) 1 else 2, KeyboardId.ELEMENT_EMOJI_CATEGORY16, keyboardWidth) val builder = KeyboardBuilder(this, KeyboardParams()) diff --git a/app/src/main/res/values-land/config.xml b/app/src/main/res/values-land/config.xml index 1ffb399990..e1d909847c 100644 --- a/app/src/main/res/values-land/config.xml +++ b/app/src/main/res/values-land/config.xml @@ -62,7 +62,7 @@ 41%p 78%p 78%p - 2 + 32 3 diff --git a/app/src/main/res/values-sw600dp-land/config.xml b/app/src/main/res/values-sw600dp-land/config.xml index bc5a17579f..448b73c0e1 100644 --- a/app/src/main/res/values-sw600dp-land/config.xml +++ b/app/src/main/res/values-sw600dp-land/config.xml @@ -52,7 +52,7 @@ 40%p 64%p 64%p - 3 + 36 4 diff --git a/app/src/main/res/values-sw600dp/config.xml b/app/src/main/res/values-sw600dp/config.xml index be55360d1f..3fac28c125 100644 --- a/app/src/main/res/values-sw600dp/config.xml +++ b/app/src/main/res/values-sw600dp/config.xml @@ -72,7 +72,7 @@ 28%p 78%p 78%p - 3 + 36 3 diff --git a/app/src/main/res/values-sw768dp-land/config.xml b/app/src/main/res/values-sw768dp-land/config.xml index c0fe32b58e..a315051013 100644 --- a/app/src/main/res/values-sw768dp-land/config.xml +++ b/app/src/main/res/values-sw768dp-land/config.xml @@ -50,5 +50,5 @@ 33%p 58%p 58%p - 3 + 39 diff --git a/app/src/main/res/values-sw768dp/config.xml b/app/src/main/res/values-sw768dp/config.xml index 642e8bf733..578de4d85b 100644 --- a/app/src/main/res/values-sw768dp/config.xml +++ b/app/src/main/res/values-sw768dp/config.xml @@ -67,5 +67,5 @@ 30%p 64%p 64%p - 3 + 39 diff --git a/app/src/main/res/values/config.xml b/app/src/main/res/values/config.xml index a2b97d8639..bc22125eb1 100644 --- a/app/src/main/res/values/config.xml +++ b/app/src/main/res/values/config.xml @@ -75,7 +75,7 @@ 30%p 78%p 78%p - 3 + 32 2 From 93c46ad2d36d076dabfc8268128f2a63ebfbadfc Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Thu, 27 Nov 2025 00:43:43 +0200 Subject: [PATCH 41/56] Hide search button if no emoji dictionary --- .../keyboard/keyboard/emoji/EmojiPalettesView.java | 2 ++ .../helium314/keyboard/latin/inputlogic/InputLogic.java | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index 83ba1d2384..f7d0b15f11 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -363,6 +363,8 @@ private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardA PointerTracker.switchTo(keyboardView); final KeyboardLayoutSet kls = KeyboardLayoutSet.Builder.buildEmojiClipBottomRow(getContext(), editorInfo); final Keyboard keyboard = kls.getKeyboard(KeyboardId.ELEMENT_EMOJI_BOTTOM_ROW); + var searchKey = keyboard.getKey(KeyCode.SEARCH); + if (searchKey != null) searchKey.setEnabled(! DictionaryInfoUtils.getLocalesWithEmojiDicts(getContext()).isEmpty()); keyboardView.setKeyboard(keyboard); } diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index 572bb5b29a..af358daaa1 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -797,13 +797,8 @@ private void handleFunctionalEvent(final Event event, final InputTransaction inp mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME)); break; case KeyCode.SEARCH: - if (DictionaryInfoUtils.getLocalesWithEmojiDicts(mLatinIME).isEmpty()) { - // todo: open dictionary settings? - onSettingsKeyPressed(); - } else { - commitTyped(Settings.getValues(), LastComposedWord.NOT_A_SEPARATOR); - mLatinIME.launchEmojiSearch(); - } + commitTyped(Settings.getValues(), LastComposedWord.NOT_A_SEPARATOR); + mLatinIME.launchEmojiSearch(); break; case KeyCode.SEND_INTENT_ONE, KeyCode.SEND_INTENT_TWO, KeyCode.SEND_INTENT_THREE: IntentUtils.handleSendIntentKey(mLatinIME, event.getKeyCode()); From ff13e47708918e9f09d91e0db0bb19febd45bc29 Mon Sep 17 00:00:00 2001 From: eranl <1707552+eranl@users.noreply.github.com> Date: Mon, 1 Dec 2025 03:21:32 +0200 Subject: [PATCH 42/56] Use `keyboard_state_selector` --- .../layouts/emoji_bottom/emoji_bottom_row.json | 2 +- .../emoji_bottom/emoji_bottom_row_with_action.json | 2 +- .../java/helium314/keyboard/keyboard/KeyboardId.java | 8 ++++++-- .../keyboard/keyboard/KeyboardLayoutSet.java | 3 +++ .../keyboard/keyboard/emoji/EmojiPalettesView.java | 2 -- .../internal/keyboard_parser/floris/KeyData.kt | 3 +++ .../main/java/helium314/keyboard/latin/LatinIME.java | 1 + .../keyboard/settings/dialogs/DictionaryDialog.kt | 12 +++++++++--- 8 files changed, 24 insertions(+), 9 deletions(-) diff --git a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json index 27d048e46c..190fb19e63 100644 --- a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json +++ b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json @@ -1,7 +1,7 @@ [ [ { "label": "alpha", "width": 0.15 }, - { "label": "search", "width": 0.15 }, + { "$": "keyboard_state_selector", "emojiSearchAvailable": { "label": "search", "width": 0.15 }}, { "label": "space", "width": -1 }, { "label": "delete", "width": 0.15 } ] diff --git a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json index 0f506a2bed..b199e1b3cf 100644 --- a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json +++ b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json @@ -1,7 +1,7 @@ [ [ { "label": "alpha", "width": 0.15 }, - { "label": "search", "width": 0.15 }, + { "$": "keyboard_state_selector", "emojiSearchAvailable": { "label": "search", "width": 0.15 }}, { "label": "space", "width": -1 }, { "label": "delete", "width": 0.15 }, { "label": "action", "width": 0.15 } diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java index 232ad66d51..9455cc09f0 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardId.java @@ -83,6 +83,7 @@ public final class KeyboardId { public final boolean mIsSplitLayout; public final boolean mOneHandedModeEnabled; public final KeyboardLayoutSet.InternalAction mInternalAction; + public final boolean mEmojiSearchAvailable; private final int mHashCode; @@ -103,6 +104,7 @@ public KeyboardId(final int elementId, final KeyboardLayoutSet.Params params) { mIsSplitLayout = params.mIsSplitLayoutEnabled; mOneHandedModeEnabled = params.mOneHandedModeEnabled; mInternalAction = params.mInternalAction; + mEmojiSearchAvailable = params.mEmojiSearchAvailable; mHashCode = computeHashCode(this); } @@ -228,7 +230,7 @@ public int hashCode() { @Override public String toString() { - return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s%s%s]", + return String.format(Locale.ROOT, "[%s %s:%s %dx%d %s %s%s%s%s%s%s%s%s%s%s%s%s%s]", elementIdToName(mElementId), mSubtype.getLocale(), mSubtype.getExtraValueOf(KEYBOARD_LAYOUT_SET), @@ -244,7 +246,9 @@ public String toString() { (mLanguageSwitchKeyEnabled ? " languageSwitchKeyEnabled" : ""), (mEmojiKeyEnabled ? " emojiKeyEnabled" : ""), (isMultiLine() ? " isMultiLine" : ""), - (mIsSplitLayout ? " isSplitLayout" : "") + (mIsSplitLayout ? " isSplitLayout" : ""), + (mInternalAction != null ? " internalAction=" + mInternalAction : ""), + (mEmojiSearchAvailable ? " emojiSearchAvailable" : "") ); } diff --git a/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayoutSet.java b/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayoutSet.java index 0a71574e59..6c0f5a5cf2 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayoutSet.java +++ b/app/src/main/java/helium314/keyboard/keyboard/KeyboardLayoutSet.java @@ -21,6 +21,7 @@ import helium314.keyboard.latin.RichInputMethodManager; import helium314.keyboard.latin.RichInputMethodSubtype; import helium314.keyboard.latin.settings.Settings; +import helium314.keyboard.latin.utils.DictionaryInfoUtils; import helium314.keyboard.latin.utils.InputTypeUtils; import helium314.keyboard.latin.utils.Log; import helium314.keyboard.latin.utils.ResourceUtils; @@ -99,6 +100,7 @@ public static final class Params { // and the required ProductionFlags are enabled. boolean mIsSplitLayoutEnabled; InternalAction mInternalAction; + boolean mEmojiSearchAvailable; } public static void onSystemLocaleChanged() { @@ -222,6 +224,7 @@ public Builder(final Context context, @Nullable final EditorInfo ei) { public static KeyboardLayoutSet buildEmojiClipBottomRow(final Context context, @Nullable final EditorInfo ei) { final Builder builder = new Builder(context, ei); builder.mParams.mMode = KeyboardId.MODE_TEXT; + builder.mParams.mEmojiSearchAvailable = ! DictionaryInfoUtils.getLocalesWithEmojiDicts(context).isEmpty(); final int width = ResourceUtils.getKeyboardWidth(context, Settings.getValues()); // actually the keyboard does not have full height, but at this point we use it to get correct key heights final int height = ResourceUtils.getKeyboardHeight(context.getResources(), Settings.getValues()); diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index f7d0b15f11..83ba1d2384 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -363,8 +363,6 @@ private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardA PointerTracker.switchTo(keyboardView); final KeyboardLayoutSet kls = KeyboardLayoutSet.Builder.buildEmojiClipBottomRow(getContext(), editorInfo); final Keyboard keyboard = kls.getKeyboard(KeyboardId.ELEMENT_EMOJI_BOTTOM_ROW); - var searchKey = keyboard.getKey(KeyCode.SEARCH); - if (searchKey != null) searchKey.setEnabled(! DictionaryInfoUtils.getLocalesWithEmojiDicts(getContext()).isEmpty()); keyboardView.setKeyboard(keyboard); } diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt index 7c8b0736d4..4e73ab6e0c 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyData.kt @@ -210,6 +210,7 @@ class KeyboardStateSelector( val moreSymbols: AbstractKeyData? = null, val alphabet: AbstractKeyData? = null, val default: AbstractKeyData? = null, + val emojiSearchAvailable: AbstractKeyData? = null, ) : AbstractKeyData { override fun compute(params: KeyboardParams): KeyData? { if (params.mId.mEmojiKeyEnabled) @@ -222,6 +223,8 @@ class KeyboardStateSelector( moreSymbols?.compute(params)?.let { return it } if (params.mId.isAlphabetKeyboard) alphabet?.compute(params)?.let { return it } + if (params.mId.mEmojiSearchAvailable) + emojiSearchAvailable?.compute(params)?.let { return it } return default?.compute(params) } diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 8a70ec199b..11a73f8d7d 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -668,6 +668,7 @@ private void resetDictionaryFacilitator(@NonNull final Locale locale) { mDictionaryFacilitator.resetDictionaries(this, mDictionaryFacilitator.getMainLocale(), settingsValues.mUseContactsDictionary, settingsValues.mUseAppsDictionary, settingsValues.mUsePersonalizedDicts, true, "", this); + mKeyboardSwitcher.setThemeNeedsReload(); EmojiPalettesView.closeDictionaryFacilitator(); EmojiSearchActivity.Companion.closeDictionaryFacilitator(); } diff --git a/app/src/main/java/helium314/keyboard/settings/dialogs/DictionaryDialog.kt b/app/src/main/java/helium314/keyboard/settings/dialogs/DictionaryDialog.kt index b4ff2e55b6..b2c771df9b 100644 --- a/app/src/main/java/helium314/keyboard/settings/dialogs/DictionaryDialog.kt +++ b/app/src/main/java/helium314/keyboard/settings/dialogs/DictionaryDialog.kt @@ -44,6 +44,7 @@ import java.io.File import java.util.Locale import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalResources +import helium314.keyboard.dictionarypack.DictionaryPackConstants @Composable fun DictionaryDialog( @@ -132,13 +133,18 @@ private fun DictionaryDetails(dict: File) { modifier = Modifier.padding(start = 10.dp, top = 0.dp, end = 10.dp, bottom = 12.dp) ) } - if (showDeleteDialog) + if (showDeleteDialog) { + val context = LocalContext.current ConfirmationDialog( onDismissRequest = { showDeleteDialog = false }, confirmButtonText = stringResource(R.string.remove), - onConfirmed = { dict.delete() }, - content = { Text(stringResource(R.string.remove_dictionary_message, type))} + onConfirmed = { + dict.delete() + context.sendBroadcast(Intent(DictionaryPackConstants.NEW_DICTIONARY_INTENT_ACTION)) + }, + content = { Text(stringResource(R.string.remove_dictionary_message, type)) } ) + } } @Preview From c7e9d46984d49c78c4572c0e0839beef3d0e7700 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 20:31:33 +0100 Subject: [PATCH 43/56] Avoid potential NPE when inserting emoji from search --- .../helium314/keyboard/keyboard/emoji/EmojiPalettesView.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java index 83ba1d2384..67d29c0733 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiPalettesView.java @@ -354,7 +354,8 @@ void addRecentKey(final Key key) { return; } getRecentsKeyboard().addKeyFirst(key); - mPager.getAdapter().notifyItemChanged(mEmojiCategory.getRecentTabId()); + if (initialized) + mPager.getAdapter().notifyItemChanged(mEmojiCategory.getRecentTabId()); } private void setupBottomRowKeyboard(final EditorInfo editorInfo, final KeyboardActionListener keyboardActionListener) { From 31e5afc783025a7b068355c9cd1f97ecdcc35df9 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 20:56:21 +0100 Subject: [PATCH 44/56] switch 3-line emoji keyboard to key count... --- .../java/helium314/keyboard/keyboard/emoji/EmojiCategory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java index 81327644b8..06ed06b93b 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/EmojiCategory.java @@ -305,9 +305,9 @@ public DynamicGridKeyboard getKeyboard(final int categoryId, final int id) { final Key[][] sortedKeysPages = sortKeysGrouped( keyboard.getSortedKeys(), keyCountPerPage); for (int pageId = 0; pageId < sortedKeysPages.length; ++pageId) { - final DynamicGridKeyboard tempKeyboard = DynamicGridKeyboard.ofRowCount(mPrefs, + final DynamicGridKeyboard tempKeyboard = DynamicGridKeyboard.ofKeyCount(mPrefs, mLayoutSet.getKeyboard(KeyboardId.ELEMENT_EMOJI_RECENTS), - MAX_LINE_COUNT_PER_PAGE, categoryId, currentWidth); + keyCountPerPage, categoryId, currentWidth); for (final Key emojiKey : sortedKeysPages[pageId]) { if (emojiKey == null) { break; From 2acf559ee82ec49d2c4412900d2d711f1d3b62ff Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 20:57:56 +0100 Subject: [PATCH 45/56] ... and make OccupiedHeight dynamic if we use key count prevents empty rows at the bottom of "normal" emoji view --- .../keyboard/keyboard/emoji/DynamicGridKeyboard.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java b/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java index 7f4875a323..4ec57359f9 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java +++ b/app/src/main/java/helium314/keyboard/keyboard/emoji/DynamicGridKeyboard.java @@ -43,6 +43,7 @@ final class DynamicGridKeyboard extends Keyboard { private final int mVerticalStep; private final int mColumnsNum; private final int mMaxKeyCount; + private final boolean mFixedRowCount; private final boolean mIsRecents; private final ArrayDeque mGridKeys = new ArrayDeque<>(); private final ArrayDeque mPendingKeys = new ArrayDeque<>(); @@ -61,7 +62,7 @@ public static DynamicGridKeyboard ofRowCount(final SharedPreferences prefs, fina } private DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard, - final int maxCount, final int categoryId, final int width, boolean rowCount) { + final int maxCount, final int categoryId, final int width, boolean fixedRowCount) { super(templateKeyboard); // todo: would be better to keep them final and not require width, but how to properly set width of the template keyboard? // an alternative would be to always create the templateKeyboard with full width @@ -79,7 +80,8 @@ private DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templa mColumnsNum = mBaseWidth / mHorizontalStep; if (spacerWidth > 0) setSpacerColumns(spacerWidth); - mMaxKeyCount = rowCount? maxCount * getOccupiedColumnCount() : maxCount; + mMaxKeyCount = fixedRowCount? maxCount * getOccupiedColumnCount() : maxCount; + mFixedRowCount = fixedRowCount; mIsRecents = categoryId == EmojiCategory.ID_RECENTS; mPrefs = prefs; } @@ -121,8 +123,10 @@ private Key getTemplateKey(final int code) { throw new RuntimeException("Can't find template key: code=" + code); } + // height is dynamic if we don't have a fixed row count int getOccupiedHeight() { - final int row = (mMaxKeyCount - 1) / getOccupiedColumnCount() + 1; + final int count = mFixedRowCount ? mMaxKeyCount : mGridKeys.size(); + final int row = (count - 1) / getOccupiedColumnCount() + 1; return row * mVerticalStep; } From 413bf801489a8918afc892842d35406a7943c012 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:24:00 +0100 Subject: [PATCH 46/56] add comment --- app/src/main/java/helium314/keyboard/latin/LatinIME.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/latin/LatinIME.java b/app/src/main/java/helium314/keyboard/latin/LatinIME.java index 262fe7fe2f..051371b759 100644 --- a/app/src/main/java/helium314/keyboard/latin/LatinIME.java +++ b/app/src/main/java/helium314/keyboard/latin/LatinIME.java @@ -671,7 +671,7 @@ private void resetDictionaryFacilitator(@NonNull final Locale locale) { mDictionaryFacilitator.resetDictionaries(this, mDictionaryFacilitator.getMainLocale(), settingsValues.mUseContactsDictionary, settingsValues.mUseAppsDictionary, settingsValues.mUsePersonalizedDicts, true, "", this); - mKeyboardSwitcher.setThemeNeedsReload(); + mKeyboardSwitcher.setThemeNeedsReload(); // necessary for emoji search EmojiPalettesView.closeDictionaryFacilitator(); EmojiSearchActivity.Companion.closeDictionaryFacilitator(); } From 54038dcf5db7a50367a1f529d7828fcee11d5209 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:34:05 +0100 Subject: [PATCH 47/56] rename search key --- .../keyboard/internal/keyboard_parser/floris/KeyCode.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt index de93965052..a47ac62c3b 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyCode.kt @@ -176,7 +176,7 @@ object KeyCode { const val ALT_RIGHT = -10047 const val META_LEFT = -10048 const val META_RIGHT = -10049 - const val SEARCH = -10050 + const val EMOJI_SEARCH = -10050 const val INLINE_EMOJI_SEARCH_DONE = -10051 @@ -201,7 +201,7 @@ object KeyCode { PAGE_DOWN, META, TAB, ESCAPE, INSERT, SLEEP, MEDIA_PLAY, MEDIA_PAUSE, MEDIA_PLAY_PAUSE, MEDIA_NEXT, MEDIA_PREVIOUS, VOL_UP, VOL_DOWN, MUTE, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, BACK, TIMESTAMP, CTRL_LEFT, CTRL_RIGHT, ALT_LEFT, ALT_RIGHT, META_LEFT, META_RIGHT, SEND_INTENT_ONE, SEND_INTENT_TWO, - SEND_INTENT_THREE, SEARCH, INLINE_EMOJI_SEARCH_DONE, META_LOCK + SEND_INTENT_THREE, EMOJI_SEARCH, INLINE_EMOJI_SEARCH_DONE, META_LOCK -> this // conversion From 418d1d78031f78c1f22fc7f9fc796ab0a512f8d7 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:36:32 +0100 Subject: [PATCH 48/56] rename key --- .../main/java/helium314/keyboard/latin/common/Constants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/latin/common/Constants.java b/app/src/main/java/helium314/keyboard/latin/common/Constants.java index e84d740a95..cb4eb408b7 100644 --- a/app/src/main/java/helium314/keyboard/latin/common/Constants.java +++ b/app/src/main/java/helium314/keyboard/latin/common/Constants.java @@ -233,7 +233,7 @@ public static String printableCode(final int code) { case KeyCode.SWITCH_ONE_HANDED_MODE: return "switchOneHandedMode"; case KeyCode.SPLIT_LAYOUT: return "splitLayout"; case KeyCode.NUMPAD: return "numpad"; - case KeyCode.SEARCH: return "search"; + case KeyCode.EMOJI_SEARCH: return "emojiSearch"; default: if (code < CODE_SPACE) return String.format("\\u%02X", code); if (code < 0x100) return String.format("%c", code); From 3e962511ee3ca7345fe9a378c1ee8b710a3758eb Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:37:20 +0100 Subject: [PATCH 49/56] rename key --- .../keyboard/keyboard/internal/KeyboardCodesSet.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java b/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java index 8b8d0a993c..9ce3265a0b 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/KeyboardCodesSet.java @@ -56,7 +56,7 @@ public static int getCode(final String name) { "key_start_onehanded", // keep name to avoid breaking custom layouts "key_stop_onehanded", // keep name to avoid breaking custom layouts "key_switch_onehanded", - "key_search" + "key_emoji_search" }; private static final int[] DEFAULT = { @@ -83,7 +83,7 @@ public static int getCode(final String name) { KeyCode.TOGGLE_ONE_HANDED_MODE, KeyCode.TOGGLE_ONE_HANDED_MODE, KeyCode.SWITCH_ONE_HANDED_MODE, - KeyCode.SEARCH + KeyCode.EMOJI_SEARCH }; static { From f832bb48706420d8dc04ed6f5f072f4e2613ddf3 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:37:59 +0100 Subject: [PATCH 50/56] rename key --- app/src/main/java/helium314/keyboard/keyboard/Key.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/Key.java b/app/src/main/java/helium314/keyboard/keyboard/Key.java index 1f6733e5ce..2585d50418 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/Key.java +++ b/app/src/main/java/helium314/keyboard/keyboard/Key.java @@ -1168,7 +1168,7 @@ public KeyParams( case KeyCode.SHIFT, Constants.CODE_ENTER, KeyCode.SHIFT_ENTER, KeyCode.ALPHA, Constants.CODE_SPACE, KeyCode.NUMPAD, KeyCode.SYMBOL, KeyCode.SYMBOL_ALPHA, KeyCode.LANGUAGE_SWITCH, KeyCode.EMOJI, KeyCode.CLIPBOARD, KeyCode.MOVE_START_OF_LINE, KeyCode.MOVE_END_OF_LINE, KeyCode.MOVE_START_OF_PAGE, KeyCode.MOVE_END_OF_PAGE, - KeyCode.SEARCH: + KeyCode.EMOJI_SEARCH: actionFlags |= ACTION_FLAGS_NO_KEY_PREVIEW; // no preview even if icon! } if (mCode == KeyCode.SETTINGS || mCode == KeyCode.LANGUAGE_SWITCH) From 96af52510be5eb093fbd3a758867f6b2fa9b74c9 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:40:57 +0100 Subject: [PATCH 51/56] rename key --- .../keyboard/internal/keyboard_parser/floris/KeyLabel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt index 03b821f80d..d31d9cc092 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/KeyLabel.kt @@ -41,7 +41,7 @@ object KeyLabel { const val TAB = "tab" const val ESCAPE = "esc" const val TIMESTAMP = "timestamp" - const val SEARCH = "search" + const val EMOJI_SEARCH = "emoji_search" /** to make sure a FlorisBoard label works when reading a JSON layout */ // resulting special labels should be names of FunctionalKey enum, case insensitive @@ -111,7 +111,7 @@ object KeyLabel { CTRL, ALT, FN, META, ESCAPE -> label.uppercase(Locale.US) TAB -> "!icon/tab_key|!code/${KeyCode.TAB}" TIMESTAMP -> "⌚" - SEARCH -> "!icon/search_key|!code/key_search" + EMOJI_SEARCH -> "!icon/search_key|!code/key_emoji_search" else -> if (label in toolbarKeyStrings.values) "!icon/$label|!code/${getCodeForToolbarKey(ToolbarKey.valueOf(label.uppercase(Locale.US)))}" else label From f0ec086ed6ba99bcff422c3bed2ed81a1ad92661 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:41:20 +0100 Subject: [PATCH 52/56] rename key --- app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json index 190fb19e63..cde4e61b4c 100644 --- a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json +++ b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row.json @@ -1,7 +1,7 @@ [ [ { "label": "alpha", "width": 0.15 }, - { "$": "keyboard_state_selector", "emojiSearchAvailable": { "label": "search", "width": 0.15 }}, + { "$": "keyboard_state_selector", "emojiSearchAvailable": { "label": "emoji_search", "width": 0.15 }}, { "label": "space", "width": -1 }, { "label": "delete", "width": 0.15 } ] From c0a5fc70e89f81e5695b46bd50be4bafc5669dc1 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:41:41 +0100 Subject: [PATCH 53/56] rename key --- .../layouts/emoji_bottom/emoji_bottom_row_with_action.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json index b199e1b3cf..831a5b84cd 100644 --- a/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json +++ b/app/src/main/assets/layouts/emoji_bottom/emoji_bottom_row_with_action.json @@ -1,7 +1,7 @@ [ [ { "label": "alpha", "width": 0.15 }, - { "$": "keyboard_state_selector", "emojiSearchAvailable": { "label": "search", "width": 0.15 }}, + { "$": "keyboard_state_selector", "emojiSearchAvailable": { "label": "emoji_search", "width": 0.15 }}, { "label": "space", "width": -1 }, { "label": "delete", "width": 0.15 }, { "label": "action", "width": 0.15 } From 2fa6e3d6ab632382c2b41e46ccafae300a154f72 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:42:50 +0100 Subject: [PATCH 54/56] rename key --- .../keyboard/accessibility/KeyCodeDescriptionMapper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt b/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt index 50060b0db4..64311e9313 100644 --- a/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt +++ b/app/src/main/java/helium314/keyboard/accessibility/KeyCodeDescriptionMapper.kt @@ -35,7 +35,7 @@ internal class KeyCodeDescriptionMapper private constructor() { put(KeyCode.ACTION_NEXT, R.string.spoken_description_action_next) put(KeyCode.ACTION_PREVIOUS, R.string.spoken_description_action_previous) put(KeyCode.EMOJI, R.string.spoken_description_emoji) - put(KeyCode.SEARCH, R.string.spoken_description_search) + put(KeyCode.EMOJI_SEARCH, R.string.spoken_description_search) // Because the upper-case and lower-case mappings of the following letters is depending on // the locale, the upper case descriptions should be defined here. The lower case // descriptions are handled in {@link #getSpokenLetterDescriptionId(Context,int)}. From 180e18d81b9f901b64c46ee18fe8ed3d59d15160 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:46:39 +0100 Subject: [PATCH 55/56] rename key --- .../java/helium314/keyboard/latin/inputlogic/InputLogic.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java index 09ad1e41e3..d155cbbe51 100644 --- a/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java +++ b/app/src/main/java/helium314/keyboard/latin/inputlogic/InputLogic.java @@ -804,7 +804,7 @@ private void handleFunctionalEvent(final Event event, final InputTransaction inp case KeyCode.TIMESTAMP: mLatinIME.onTextInput(TimestampKt.getTimestamp(mLatinIME)); break; - case KeyCode.SEARCH: + case KeyCode.EMOJI_SEARCH: commitTyped(Settings.getValues(), LastComposedWord.NOT_A_SEPARATOR); mLatinIME.launchEmojiSearch(); break; From ab67778eb18b2be446b07b7922a39634ef9a2c01 Mon Sep 17 00:00:00 2001 From: Helium314 Date: Sat, 21 Feb 2026 21:49:42 +0100 Subject: [PATCH 56/56] rename key --- .../keyboard/internal/keyboard_parser/floris/TextKeyData.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt index 5c5360fda6..2eab73d699 100644 --- a/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt +++ b/app/src/main/java/helium314/keyboard/keyboard/internal/keyboard_parser/floris/TextKeyData.kt @@ -405,7 +405,7 @@ sealed interface KeyData : AbstractKeyData { when (label) { // or use code? KeyLabel.SYMBOL_ALPHA, KeyLabel.SYMBOL, KeyLabel.ALPHA, KeyLabel.COMMA, KeyLabel.PERIOD, KeyLabel.DELETE, KeyLabel.COM, KeyLabel.LANGUAGE_SWITCH, KeyLabel.NUMPAD, KeyLabel.CTRL, KeyLabel.ALT, - KeyLabel.FN, KeyLabel.META, KeyLabel.SEARCH, toolbarKeyStrings[ToolbarKey.EMOJI] -> return Key.BACKGROUND_TYPE_FUNCTIONAL + KeyLabel.FN, KeyLabel.META, KeyLabel.EMOJI_SEARCH, toolbarKeyStrings[ToolbarKey.EMOJI] -> return Key.BACKGROUND_TYPE_FUNCTIONAL KeyLabel.SPACE, KeyLabel.ZWNJ -> return Key.BACKGROUND_TYPE_SPACEBAR KeyLabel.ACTION -> return Key.BACKGROUND_TYPE_ACTION KeyLabel.SHIFT -> return Key.BACKGROUND_TYPE_FUNCTIONAL