Update input logic to better handle combined emoji

This commit is contained in:
Aleksandras Kostarevas 2024-03-18 16:00:20 -05:00
parent 9410e5a825
commit 536460cfd4
7 changed files with 73 additions and 5 deletions

View File

@ -23474,5 +23474,27 @@
]
, "unicode_version": "11.0"
, "ios_version": "12.1"
},
{
"emoji": ":)"
, "description": "smiley"
, "category": "ASCII"
, "aliases": [
]
, "tags": [
]
, "unicode_version": ""
, "ios_version": ""
}
, {
"emoji": ":3"
, "description": "cat face"
, "category": "ASCII"
, "aliases": [
]
, "tags": [
]
, "unicode_version": ""
, "ios_version": ""
}
]

View File

@ -37,14 +37,17 @@ import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import androidx.savedstate.findViewTreeSavedStateRegistryOwner
import androidx.savedstate.setViewTreeSavedStateRegistryOwner
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.futo.inputmethod.latin.SuggestedWords.SuggestedWordInfo
import org.futo.inputmethod.latin.common.Constants
import org.futo.inputmethod.latin.uix.BasicThemeProvider
import org.futo.inputmethod.latin.uix.DynamicThemeProvider
import org.futo.inputmethod.latin.uix.DynamicThemeProviderOwner
import org.futo.inputmethod.latin.uix.EmojiTracker.unuseEmoji
import org.futo.inputmethod.latin.uix.EmojiTracker.useEmoji
import org.futo.inputmethod.latin.uix.SUGGESTION_BLACKLIST
import org.futo.inputmethod.latin.uix.THEME_KEY
@ -542,7 +545,17 @@ class LatinIME : InputMethodService(), LifecycleOwner, ViewModelStoreOwner, Save
fun rememberEmojiSuggestion(suggestion: SuggestedWordInfo) {
if(suggestion.mKindAndFlags == SuggestedWordInfo.KIND_EMOJI_SUGGESTION) {
lifecycleScope.launch {
useEmoji(suggestion.mWord)
withContext(Dispatchers.Default) {
useEmoji(suggestion.mWord)
}
}
}
}
fun onEmojiDeleted(emoji: String) {
lifecycleScope.launch {
withContext(Dispatchers.Default) {
unuseEmoji(emoji)
}
}
}

View File

@ -2048,4 +2048,8 @@ public class LatinIMELegacy implements KeyboardActionListener,
public LanguageModelFacilitator getLanguageModelFacilitator() {
return ((LatinIME)(mInputMethodService)).getLanguageModelFacilitator();
}
public void onCodePointDeleted(String textBeforeCursor) {
((LatinIME)(mInputMethodService)).onEmojiDeleted(textBeforeCursor);
}
}

View File

@ -60,6 +60,7 @@ import org.futo.inputmethod.latin.utils.StatsUtils;
import org.futo.inputmethod.latin.utils.TextRange;
import org.futo.inputmethod.latin.xlm.LanguageModelFacilitator;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Locale;
import java.util.TreeSet;
@ -1072,6 +1073,7 @@ public final class InputLogic {
// like the smiley key or the .com key.
mConnection.deleteTextBeforeCursor(mEnteredText.length());
StatsUtils.onDeleteMultiCharInput(mEnteredText.length());
mLatinIMELegacy.onCodePointDeleted(mEnteredText);
mEnteredText = null;
// If we have mEnteredText, then we know that mHasUncommittedTypedChars == false.
// In addition we know that spaceState is false, and that we should not be
@ -1159,8 +1161,26 @@ public final class InputLogic {
// TODO: Add a new StatsUtils method onBackspaceWhenNoText()
return;
}
final int lengthToDelete =
String textDeleted = new String(Character.toChars(codePointBeforeCursor));
int lengthToDelete =
Character.isSupplementaryCodePoint(codePointBeforeCursor) ? 2 : 1;
// Handle emoji sequences (flags, etc)
CharSequence textBeforeCursor = mConnection.getTextBeforeCursor(8, 0);
if (textBeforeCursor != null && textBeforeCursor.length() > 0) {
BreakIterator breakIterator = BreakIterator.getCharacterInstance();
breakIterator.setText(textBeforeCursor.toString());
int end = breakIterator.last();
int start = breakIterator.previous();
if (start != BreakIterator.DONE) {
lengthToDelete = end - start;
textDeleted = textBeforeCursor.subSequence(start, end).toString();
}
}
Log.d(TAG, "lengthToDelete=" + lengthToDelete + ", textDeleted=" + textDeleted);
mConnection.deleteTextBeforeCursor(lengthToDelete);
int totalDeletedLength = lengthToDelete;
if (mDeleteCount > Constants.DELETE_ACCELERATE_AT) {
@ -1179,6 +1199,9 @@ public final class InputLogic {
}
}
StatsUtils.onBackspacePressed(totalDeletedLength);
if(codePointBeforeCursor >= 0x1F600)
mLatinIMELegacy.onCodePointDeleted(textDeleted);
}
}
if (!hasUnlearnedWordBeingDeleted) {

View File

@ -25,7 +25,7 @@ object EmojiTracker {
suspend fun Context.unuseEmoji(emoji: String) {
dataStore.edit {
val split = (it[lastUsedEmoji] ?: "").split("<|>")
val idxToRemove = split.indexOfFirst { v -> v == emoji }
val idxToRemove = split.indexOfFirst { v -> v == emoji || v.trim() == emoji.trim() }
it[lastUsedEmoji] = split.filterIndexed { i, _ -> i != idxToRemove}.joinToString("<|>")
}
}

View File

@ -113,8 +113,10 @@ class EmojiGridAdapter(
fun bindEmoji(
emoji: EmojiItem,
onClick: (EmojiItem) -> Unit,
onSelectSkinTone: (PopupInfo) -> Unit
onSelectSkinTone: (PopupInfo) -> Unit,
color: Int
) {
emojiView.setTextColor(color)
emojiView.emoji = emoji
emojiView.setOnClickListener {
it.sendAccessibilityEvent(AccessibilityEvent.TYPE_ANNOUNCEMENT)
@ -153,7 +155,7 @@ class EmojiGridAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val item = data[position]
if(item is EmojiItemItem && holder is EmojiViewHolder) {
holder.bindEmoji(item.emoji, onClick, onSelectSkinTone)
holder.bindEmoji(item.emoji, onClick, onSelectSkinTone, contentColor.toArgb())
}else if(item is CategoryItem && holder is CategoryViewHolder) {
holder.bind(item)
}

View File

@ -67,6 +67,10 @@ class EmojiView @JvmOverloads constructor(
)
}
fun setTextColor(color: Int) {
textPaint.color = color
}
private val offscreenCanvasBitmap: Bitmap = with(textPaint.fontMetricsInt) {
val size = bottom - top
Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)