Merge branch 'openboard-team:master' into master

This commit is contained in:
Md. Rifat Hasan Jihan 2022-01-31 15:43:50 +06:00 committed by GitHub
commit 89a8041ce7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
198 changed files with 21867 additions and 593 deletions

40
.github/workflows/android-build.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: Build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Upload our APK
uses: actions/upload-artifact@v2.2.0
with:
name: APK
path: app/build/outputs/apk/release/app-release-unsigned.apk
- name: Upload lint report
uses: actions/upload-artifact@v2.2.0
with:
name: Lint report
path: app/build/reports/lint-results-debug.html

View file

@ -1,4 +1,10 @@
# OpenBoard # OpenBoard
[![Build](https://github.com/openboard-team/openboard/actions/workflows/android-build.yml/badge.svg)](https://github.com/openboard-team/openboard/actions/workflows/android-build.yml)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/openboard-team/openboard)](https://github.com/openboard-team/openboard/releases)
[![GitHub commits since latest release (by date)](https://img.shields.io/github/commits-since/openboard-team/openboard/latest)](https://github.com/openboard-team/openboard/commits/master)
[![Translation status](https://hosted.weblate.org/widgets/openboard/-/openboard/svg-badge.svg)](https://hosted.weblate.org/engage/openboard/)
<a href='https://f-droid.org/packages/org.dslul.openboard.inputmethod.latin'><img src='https://fdroid.gitlab.io/artwork/badge/get-it-on.png' alt='Get it on F-Droid' height='80'></a> <a href='https://f-droid.org/packages/org.dslul.openboard.inputmethod.latin'><img src='https://fdroid.gitlab.io/artwork/badge/get-it-on.png' alt='Get it on F-Droid' height='80'></a>
<a href='https://play.google.com/store/apps/details?id=org.dslul.openboard.inputmethod.latin&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png' height='80px'/></a> <a href='https://play.google.com/store/apps/details?id=org.dslul.openboard.inputmethod.latin&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1'><img alt='Get it on Google Play' src='https://play.google.com/intl/en_us/badges/static/images/badges/en_badge_web_generic.png' height='80px'/></a>
@ -12,14 +18,26 @@
Join [here](https://matrix.to/#/#openboard:matrix.org?via=matrix.org) Join [here](https://matrix.to/#/#openboard:matrix.org?via=matrix.org)
## Common issues ## Common issues
- Cannot open settings in MIUI - Cannot open settings in MIUI: See [issue #46](https://github.com/dslul/openboard/issues/46).
See https://github.com/dslul/openboard/issues/46
## Contribute ## Contribute
### Translation
You can help in translating OpenBoard in your language through our [Weblate project](https://hosted.weblate.org/engage/openboard/).
[![Translation status](https://hosted.weblate.org/widgets/openboard/-/openboard/horizontal-blue.svg)](https://hosted.weblate.org/engage/openboard/)
### How to create a dictionary ### How to create a dictionary
You can use [this tool](https://github.com/remi0s/aosp-dictionary-tools) to create a dictionary. You need a wordlist, as described [here](https://github.com/dslul/openboard/blob/master/dictionaries/sample.combined). The output .dict file must be put in [res/raw](https://github.com/dslul/openboard/tree/master/app/src/main/res/raw). You can use [this tool](https://github.com/remi0s/aosp-dictionary-tools) to create a dictionary. You need a wordlist, as described [here](dictionaries/sample.combined). The output .dict file must be put in [res/raw](app/src/main/res/raw).
### How to edit keyboard texts
Make your modifications in [tools/make-keyboard-text/src/main/resources](tools/make-keyboard-text/src/main/resources)/values-YOUR LOCALE.
Generate the new version of [KeyboardTextsTable.java](app/src/main/java/org/dslul/openboard/inputmethod/keyboard/internal/KeyboardTextsTable.java):
```sh
./gradlew tools:make-keyboard-text:makeText
```
### APK Development ### APK Development
@ -27,7 +45,7 @@ You can use [this tool](https://github.com/remi0s/aosp-dictionary-tools) to crea
Install java: Install java:
```sh ```sh
sudo pacman -S jdk8-openjdk jre8-openjdk jre8-openjdk-headless sudo pacman -S jdk11-openjdk jre11-openjdk jre11-openjdk-headless
``` ```
Install Android SDK: Install Android SDK:
@ -41,11 +59,6 @@ Configure your SDK location in your `~/.bash_profile` or `~/.bashrc`:
export ANDROID_SDK_ROOT=~/snap/androidsdk/current/AndroidSDK/ export ANDROID_SDK_ROOT=~/snap/androidsdk/current/AndroidSDK/
``` ```
Install the platform tools for your target android version:
```sh
androidsdk "platform-tools" "platforms;android-29"
```
Compile the project. This will install all dependencies, make sure to accept Compile the project. This will install all dependencies, make sure to accept
licenses when prompted. licenses when prompted.

View file

@ -9,8 +9,8 @@ android {
applicationId "org.dslul.openboard.inputmethod.latin" applicationId "org.dslul.openboard.inputmethod.latin"
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 31 targetSdkVersion 31
versionCode 15 versionCode 18
versionName '1.4.3' versionName '1.4.4'
} }
buildTypes { buildTypes {
@ -23,9 +23,6 @@ android {
} }
} }
aaptOptions {
noCompress 'dict'
}
externalNativeBuild { externalNativeBuild {
ndkBuild { ndkBuild {
@ -38,12 +35,16 @@ android {
} }
ndkVersion '21.3.6528147' ndkVersion '21.3.6528147'
androidResources {
noCompress 'dict'
}
} }
dependencies { dependencies {
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.core:core-ktx:1.5.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' // Replaces recyclerview:1.0.0 included by above dependency
implementation 'androidx.core:core-ktx:1.7.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.viewpager2:viewpager2:1.0.0' implementation 'androidx.viewpager2:viewpager2:1.0.0'
} }

View file

@ -0,0 +1,28 @@
package org.dslul.openboard.inputmethod.compat;
import android.annotation.TargetApi;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.os.Build;
public class ClipboardManagerCompat {
@TargetApi(Build.VERSION_CODES.P)
public static void clearPrimaryClip(ClipboardManager cm) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
cm.clearPrimaryClip();
} else {
cm.setPrimaryClip(ClipData.newPlainText("", ""));
}
}
@TargetApi(Build.VERSION_CODES.O)
public static Long getClipTimestamp(ClipData cd) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
return cd.getDescription().getTimestamp();
} else {
return null;
}
}
}

View file

@ -70,6 +70,7 @@ public final class KeyboardId {
public static final int ELEMENT_EMOJI_CATEGORY14 = 24; public static final int ELEMENT_EMOJI_CATEGORY14 = 24;
public static final int ELEMENT_EMOJI_CATEGORY15 = 25; public static final int ELEMENT_EMOJI_CATEGORY15 = 25;
public static final int ELEMENT_EMOJI_CATEGORY16 = 26; public static final int ELEMENT_EMOJI_CATEGORY16 = 26;
public static final int ELEMENT_CLIPBOARD = 27;
public final RichInputMethodSubtype mSubtype; public final RichInputMethodSubtype mSubtype;
public final int mWidth; public final int mWidth;
@ -255,6 +256,7 @@ public final class KeyboardId {
case ELEMENT_EMOJI_CATEGORY14: return "emojiCategory14"; case ELEMENT_EMOJI_CATEGORY14: return "emojiCategory14";
case ELEMENT_EMOJI_CATEGORY15: return "emojiCategory15"; case ELEMENT_EMOJI_CATEGORY15: return "emojiCategory15";
case ELEMENT_EMOJI_CATEGORY16: return "emojiCategory16"; case ELEMENT_EMOJI_CATEGORY16: return "emojiCategory16";
case ELEMENT_CLIPBOARD: return "clipboard";
default: return null; default: return null;
} }
} }

View file

@ -27,6 +27,7 @@ import android.view.inputmethod.EditorInfo;
import org.dslul.openboard.inputmethod.event.Event; import org.dslul.openboard.inputmethod.event.Event;
import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException; import org.dslul.openboard.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetException;
import org.dslul.openboard.inputmethod.keyboard.clipboard.ClipboardHistoryView;
import org.dslul.openboard.inputmethod.keyboard.emoji.EmojiPalettesView; import org.dslul.openboard.inputmethod.keyboard.emoji.EmojiPalettesView;
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardState; import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardState;
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardTextsSet; import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardTextsSet;
@ -53,6 +54,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
private View mMainKeyboardFrame; private View mMainKeyboardFrame;
private MainKeyboardView mKeyboardView; private MainKeyboardView mKeyboardView;
private EmojiPalettesView mEmojiPalettesView; private EmojiPalettesView mEmojiPalettesView;
private ClipboardHistoryView mClipboardHistoryView;
private LatinIME mLatinIME; private LatinIME mLatinIME;
private RichInputMethodManager mRichImm; private RichInputMethodManager mRichImm;
private boolean mIsHardwareAcceleratedDrawingEnabled; private boolean mIsHardwareAcceleratedDrawingEnabled;
@ -135,7 +137,7 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
} }
public void saveKeyboardState() { public void saveKeyboardState() {
if (getKeyboard() != null || isShowingEmojiPalettes()) { if (getKeyboard() != null || isShowingEmojiPalettes() || isShowingClipboardHistory()) {
mState.onSaveKeyboardState(); mState.onSaveKeyboardState();
} }
} }
@ -288,6 +290,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mMainKeyboardFrame.setVisibility(visibility); mMainKeyboardFrame.setVisibility(visibility);
mEmojiPalettesView.setVisibility(View.GONE); mEmojiPalettesView.setVisibility(View.GONE);
mEmojiPalettesView.stopEmojiPalettes(); mEmojiPalettesView.stopEmojiPalettes();
mClipboardHistoryView.setVisibility(View.GONE);
mClipboardHistoryView.stopClipboardHistory();
} }
// Implements {@link KeyboardState.SwitchActions}. // Implements {@link KeyboardState.SwitchActions}.
@ -308,10 +312,30 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mEmojiPalettesView.setVisibility(View.VISIBLE); mEmojiPalettesView.setVisibility(View.VISIBLE);
} }
// Implements {@link KeyboardState.SwitchActions}.
@Override
public void setClipboardKeyboard() {
if (DEBUG_ACTION) {
Log.d(TAG, "setClipboardKeyboard");
}
final Keyboard keyboard = mKeyboardLayoutSet.getKeyboard(KeyboardId.ELEMENT_ALPHABET);
mMainKeyboardFrame.setVisibility(View.GONE);
// The visibility of {@link #mKeyboardView} must be aligned with {@link #MainKeyboardFrame}.
// @see #getVisibleKeyboardView() and
// @see LatinIME#onComputeInset(android.inputmethodservice.InputMethodService.Insets)
mKeyboardView.setVisibility(View.GONE);
mClipboardHistoryView.startClipboardHistory(
mLatinIME.getClipboardHistoryManager(),
mKeyboardTextsSet.getText(KeyboardTextsSet.SWITCH_TO_ALPHA_KEY_LABEL),
mKeyboardView.getKeyVisualAttribute(), keyboard.mIconsSet);
mClipboardHistoryView.setVisibility(View.VISIBLE);
}
public enum KeyboardSwitchState { public enum KeyboardSwitchState {
HIDDEN(-1), HIDDEN(-1),
SYMBOLS_SHIFTED(KeyboardId.ELEMENT_SYMBOLS_SHIFTED), SYMBOLS_SHIFTED(KeyboardId.ELEMENT_SYMBOLS_SHIFTED),
EMOJI(KeyboardId.ELEMENT_EMOJI_RECENTS), EMOJI(KeyboardId.ELEMENT_EMOJI_RECENTS),
CLIPBOARD(KeyboardId.ELEMENT_CLIPBOARD),
OTHER(-1); OTHER(-1);
final int mKeyboardId; final int mKeyboardId;
@ -322,15 +346,16 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
} }
public KeyboardSwitchState getKeyboardSwitchState() { public KeyboardSwitchState getKeyboardSwitchState() {
boolean hidden = !isShowingEmojiPalettes() boolean hidden = !isShowingEmojiPalettes() && !isShowingClipboardHistory()
&& (mKeyboardLayoutSet == null && (mKeyboardLayoutSet == null
|| mKeyboardView == null || mKeyboardView == null
|| !mKeyboardView.isShown()); || !mKeyboardView.isShown());
KeyboardSwitchState state;
if (hidden) { if (hidden) {
return KeyboardSwitchState.HIDDEN; return KeyboardSwitchState.HIDDEN;
} else if (isShowingEmojiPalettes()) { } else if (isShowingEmojiPalettes()) {
return KeyboardSwitchState.EMOJI; return KeyboardSwitchState.EMOJI;
} else if (isShowingClipboardHistory()) {
return KeyboardSwitchState.CLIPBOARD;
} else if (isShowingKeyboardId(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)) { } else if (isShowingKeyboardId(KeyboardId.ELEMENT_SYMBOLS_SHIFTED)) {
return KeyboardSwitchState.SYMBOLS_SHIFTED; return KeyboardSwitchState.SYMBOLS_SHIFTED;
} }
@ -348,10 +373,15 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mLatinIME.startShowingInputView(true); mLatinIME.startShowingInputView(true);
if (toggleState == KeyboardSwitchState.EMOJI) { if (toggleState == KeyboardSwitchState.EMOJI) {
setEmojiKeyboard(); setEmojiKeyboard();
} else if (toggleState == KeyboardSwitchState.CLIPBOARD) {
setClipboardKeyboard();
} else { } else {
mEmojiPalettesView.stopEmojiPalettes(); mEmojiPalettesView.stopEmojiPalettes();
mEmojiPalettesView.setVisibility(View.GONE); mEmojiPalettesView.setVisibility(View.GONE);
mClipboardHistoryView.stopClipboardHistory();
mClipboardHistoryView.setVisibility(View.GONE);
mMainKeyboardFrame.setVisibility(View.VISIBLE); mMainKeyboardFrame.setVisibility(View.VISIBLE);
mKeyboardView.setVisibility(View.VISIBLE); mKeyboardView.setVisibility(View.VISIBLE);
setKeyboard(toggleState.mKeyboardId, toggleState); setKeyboard(toggleState.mKeyboardId, toggleState);
@ -429,8 +459,12 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
return mEmojiPalettesView != null && mEmojiPalettesView.isShown(); return mEmojiPalettesView != null && mEmojiPalettesView.isShown();
} }
public boolean isShowingClipboardHistory() {
return mClipboardHistoryView != null && mClipboardHistoryView.isShown();
}
public boolean isShowingMoreKeysPanel() { public boolean isShowingMoreKeysPanel() {
if (isShowingEmojiPalettes()) { if (isShowingEmojiPalettes() || isShowingClipboardHistory()) {
return false; return false;
} }
return mKeyboardView.isShowingMoreKeysPanel(); return mKeyboardView.isShowingMoreKeysPanel();
@ -439,6 +473,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
public View getVisibleKeyboardView() { public View getVisibleKeyboardView() {
if (isShowingEmojiPalettes()) { if (isShowingEmojiPalettes()) {
return mEmojiPalettesView; return mEmojiPalettesView;
} else if (isShowingClipboardHistory()) {
return mClipboardHistoryView;
} }
return mKeyboardView; return mKeyboardView;
} }
@ -455,6 +491,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
if (mEmojiPalettesView != null) { if (mEmojiPalettesView != null) {
mEmojiPalettesView.stopEmojiPalettes(); mEmojiPalettesView.stopEmojiPalettes();
} }
if (mClipboardHistoryView != null) {
mClipboardHistoryView.stopClipboardHistory();
}
} }
public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) { public View onCreateInputView(final boolean isHardwareAcceleratedDrawingEnabled) {
@ -467,8 +506,8 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate( mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
R.layout.input_view, null); R.layout.input_view, null);
mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame); mMainKeyboardFrame = mCurrentInputView.findViewById(R.id.main_keyboard_frame);
mEmojiPalettesView = mCurrentInputView.findViewById( mEmojiPalettesView = mCurrentInputView.findViewById(R.id.emoji_palettes_view);
R.id.emoji_palettes_view); mClipboardHistoryView = mCurrentInputView.findViewById(R.id.clipboard_history_view);
mKeyboardView = mCurrentInputView.findViewById(R.id.keyboard_view); mKeyboardView = mCurrentInputView.findViewById(R.id.keyboard_view);
mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled); mKeyboardView.setHardwareAcceleratedDrawingEnabled(isHardwareAcceleratedDrawingEnabled);
@ -476,6 +515,9 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled( mEmojiPalettesView.setHardwareAcceleratedDrawingEnabled(
isHardwareAcceleratedDrawingEnabled); isHardwareAcceleratedDrawingEnabled);
mEmojiPalettesView.setKeyboardActionListener(mLatinIME); mEmojiPalettesView.setKeyboardActionListener(mLatinIME);
mClipboardHistoryView.setHardwareAcceleratedDrawingEnabled(
isHardwareAcceleratedDrawingEnabled);
mClipboardHistoryView.setKeyboardActionListener(mLatinIME);
return mCurrentInputView; return mCurrentInputView;
} }

View file

@ -1082,7 +1082,7 @@ public final class PointerTracker implements PointerTrackerQueue.Element,
return; return;
} }
final int code = key.getCode(); final int code = key.getCode();
if (code == Constants.CODE_SPACE || code == Constants.CODE_LANGUAGE_SWITCH) { if (code == Constants.CODE_SPACE&&Settings.getInstance().getCurrent().mSpaceForLangChange || code == Constants.CODE_LANGUAGE_SWITCH) {
// Long pressing the space key invokes IME switcher dialog. // Long pressing the space key invokes IME switcher dialog.
if (sListener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) { if (sListener.onCustomRequest(Constants.CUSTOM_CODE_SHOW_INPUT_METHOD_PICKER)) {
cancelKeyTracking(); cancelKeyTracking();

View file

@ -0,0 +1,93 @@
package org.dslul.openboard.inputmethod.keyboard.clipboard
import android.graphics.Typeface
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import org.dslul.openboard.inputmethod.latin.ClipboardHistoryEntry
import org.dslul.openboard.inputmethod.latin.ClipboardHistoryManager
import org.dslul.openboard.inputmethod.latin.R
class ClipboardAdapter(
val clipboardLayoutParams: ClipboardLayoutParams,
val keyEventListener: OnKeyEventListener
) : RecyclerView.Adapter<ClipboardAdapter.ViewHolder>() {
var clipboardHistoryManager: ClipboardHistoryManager? = null
var pinnedIconResId = 0
var itemBackgroundId = 0
var itemTypeFace: Typeface? = null
var itemTextColor = 0
var itemTextSize = 0f
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.clipboard_entry_key, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.setContent(getItem(position))
}
private fun getItem(position: Int) = clipboardHistoryManager?.getHistoryEntry(position)
override fun getItemCount() = clipboardHistoryManager?.getHistorySize() ?: 0
inner class ViewHolder(
view: View
) : RecyclerView.ViewHolder(view), View.OnClickListener, View.OnTouchListener, View.OnLongClickListener {
private val pinnedIconView: ImageView
private val contentView: TextView
init {
view.apply {
setOnClickListener(this@ViewHolder)
setOnTouchListener(this@ViewHolder)
setOnLongClickListener(this@ViewHolder)
setBackgroundResource(itemBackgroundId)
}
pinnedIconView = view.findViewById<ImageView>(R.id.clipboard_entry_pinned_icon).apply {
visibility = View.GONE
setImageResource(pinnedIconResId)
}
contentView = view.findViewById<TextView>(R.id.clipboard_entry_content).apply {
typeface = itemTypeFace
setTextColor(itemTextColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, itemTextSize)
}
clipboardLayoutParams.setItemProperties(view)
}
fun setContent(historyEntry: ClipboardHistoryEntry?) {
itemView.tag = historyEntry?.id
contentView.text = historyEntry?.content
pinnedIconView.visibility = if (historyEntry?.isPinned == true) View.VISIBLE else View.GONE
}
override fun onTouch(view: View, event: MotionEvent): Boolean {
if (event.actionMasked != MotionEvent.ACTION_DOWN) {
return false
}
keyEventListener.onKeyDown(view.tag as Long)
return false
}
override fun onClick(view: View) {
keyEventListener.onKeyUp(view.tag as Long)
}
override fun onLongClick(view: View): Boolean {
clipboardHistoryManager?.toggleClipPinned(view.tag as Long)
return true
}
}
}

View file

@ -0,0 +1,78 @@
package org.dslul.openboard.inputmethod.keyboard.clipboard
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import androidx.recyclerview.widget.RecyclerView
class ClipboardHistoryRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
var placeholderView: View? = null
private val adapterDataObserver: AdapterDataObserver = object : AdapterDataObserver() {
override fun onChanged() {
checkAdapterContentChange()
}
override fun onItemRangeChanged(positionStart: Int, itemCount: Int) {
checkAdapterContentChange()
}
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
checkAdapterContentChange()
}
override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
checkAdapterContentChange()
}
}
private fun checkAdapterContentChange() {
if (placeholderView == null) return
val adapterIsEmpty = adapter == null || adapter?.itemCount == 0
if (this@ClipboardHistoryRecyclerView.visibility == VISIBLE && adapterIsEmpty) {
placeholderView!!.visibility = VISIBLE
this@ClipboardHistoryRecyclerView.visibility = INVISIBLE
} else if (this@ClipboardHistoryRecyclerView.visibility == INVISIBLE && !adapterIsEmpty) {
placeholderView!!.visibility = INVISIBLE
this@ClipboardHistoryRecyclerView.visibility = VISIBLE
}
}
override fun setAdapter(adapter: Adapter<*>?) {
this.adapter?.unregisterAdapterDataObserver(adapterDataObserver)
super.setAdapter(adapter)
checkAdapterContentChange()
adapter?.registerAdapterDataObserver(adapterDataObserver)
}
class BottomDividerItemDecoration(dividerHeight: Int, dividerColor: Int) : RecyclerView.ItemDecoration() {
private val paint = Paint()
init {
paint.color = dividerColor
paint.strokeWidth = dividerHeight.toFloat()
}
override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: State) {
super.onDrawOver(canvas, parent, state)
canvas.drawLine(parent.paddingLeft.toFloat(),
parent.height - paint.strokeWidth / 2,
parent.width.toFloat() - parent.paddingRight.toFloat(),
parent.height - paint.strokeWidth / 2 ,
paint
)
}
}
}

View file

@ -0,0 +1,226 @@
package org.dslul.openboard.inputmethod.keyboard.clipboard
import android.content.Context
import android.util.AttributeSet
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.StaggeredGridLayoutManager
import org.dslul.openboard.inputmethod.keyboard.KeyboardActionListener
import org.dslul.openboard.inputmethod.keyboard.internal.KeyDrawParams
import org.dslul.openboard.inputmethod.keyboard.internal.KeyVisualAttributes
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardIconsSet
import org.dslul.openboard.inputmethod.latin.ClipboardHistoryManager
import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.common.Constants
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils
class ClipboardHistoryView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet?,
defStyle: Int = R.attr.clipboardHistoryViewStyle
) : LinearLayout(context, attrs, defStyle), View.OnTouchListener, View.OnClickListener,
ClipboardHistoryManager.OnHistoryChangeListener, OnKeyEventListener {
private val clipboardLayoutParams = ClipboardLayoutParams(context.resources)
private val pinIconId: Int
private val dividerColor: Int
private val functionalKeyBackgroundId: Int
private val keyBackgroundId: Int
private lateinit var clipboardRecyclerView: ClipboardHistoryRecyclerView
private lateinit var placeholderView: TextView
private lateinit var alphabetKey: TextView
private lateinit var clearKey: ImageButton
private lateinit var clipboardAdapter: ClipboardAdapter
var keyboardActionListener: KeyboardActionListener? = null
var clipboardHistoryManager: ClipboardHistoryManager? = null
init {
val clipboardViewAttr = context.obtainStyledAttributes(attrs,
R.styleable.ClipboardHistoryView, defStyle, R.style.ClipboardHistoryView)
pinIconId = clipboardViewAttr.getResourceId(
R.styleable.ClipboardHistoryView_iconPinnedClip, 0)
dividerColor = clipboardViewAttr.getColor(
R.styleable.ClipboardHistoryView_dividerBackground, 0)
clipboardViewAttr.recycle()
val keyboardViewAttr = context.obtainStyledAttributes(attrs,
R.styleable.KeyboardView, defStyle, R.style.KeyboardView)
keyBackgroundId = keyboardViewAttr.getResourceId(
R.styleable.KeyboardView_keyBackground, 0)
functionalKeyBackgroundId = keyboardViewAttr.getResourceId(
R.styleable.KeyboardView_functionalKeyBackground, keyBackgroundId)
keyboardViewAttr.recycle()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
val res = context.resources
// The main keyboard expands to the entire this {@link KeyboardView}.
val width = (ResourceUtils.getDefaultKeyboardWidth(res)
+ paddingLeft + paddingRight)
val height = (ResourceUtils.getDefaultKeyboardHeight(res)
+ res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height)
+ paddingTop + paddingBottom)
setMeasuredDimension(width, height)
}
override fun onFinishInflate() {
super.onFinishInflate()
clipboardAdapter = ClipboardAdapter(clipboardLayoutParams, this).apply {
itemBackgroundId = keyBackgroundId
pinnedIconResId = pinIconId
}
placeholderView = findViewById(R.id.clipboard_empty_view)
clipboardRecyclerView = findViewById<ClipboardHistoryRecyclerView>(R.id.clipboard_list).apply {
val colCount = resources.getInteger(R.integer.config_clipboard_keyboard_col_count)
layoutManager = StaggeredGridLayoutManager(colCount, StaggeredGridLayoutManager.VERTICAL)
val dividerHeight = resources.getDimensionPixelSize(R.dimen.config_clipboard_divider_height)
addItemDecoration(ClipboardHistoryRecyclerView.BottomDividerItemDecoration(dividerHeight, dividerColor))
persistentDrawingCache = PERSISTENT_NO_CACHE
clipboardLayoutParams.setListProperties(this)
placeholderView = this@ClipboardHistoryView.placeholderView
}
findViewById<FrameLayout>(R.id.clipboard_action_bar)?.apply {
clipboardLayoutParams.setActionBarProperties(this)
}
alphabetKey = findViewById<TextView>(R.id.clipboard_keyboard_alphabet).apply {
tag = Constants.CODE_ALPHA_FROM_CLIPBOARD
setBackgroundResource(functionalKeyBackgroundId)
setOnTouchListener(this@ClipboardHistoryView)
setOnClickListener(this@ClipboardHistoryView)
}
clearKey = findViewById<ImageButton>(R.id.clipboard_clear).apply {
setOnTouchListener(this@ClipboardHistoryView)
setOnClickListener(this@ClipboardHistoryView)
}
}
private fun setupAlphabetKey(key: TextView?, label: String, params: KeyDrawParams) {
key?.apply {
text = label
typeface = params.mTypeface
setTextColor(params.mFunctionalTextColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize.toFloat())
}
}
private fun setupClipKey(params: KeyDrawParams) {
clipboardAdapter.apply {
itemBackgroundId = keyBackgroundId
itemTypeFace = params.mTypeface
itemTextColor = params.mTextColor
itemTextSize = params.mLabelSize.toFloat()
}
}
private fun setupClearKey(iconSet: KeyboardIconsSet) {
val resId = iconSet.getIconResourceId(KeyboardIconsSet.NAME_CLEAR_CLIPBOARD_KEY)
clearKey.setImageResource(resId)
}
fun setHardwareAcceleratedDrawingEnabled(enabled: Boolean) {
if (!enabled) return
// TODO: Should use LAYER_TYPE_SOFTWARE when hardware acceleration is off?
setLayerType(LAYER_TYPE_HARDWARE, null)
}
fun startClipboardHistory(
historyManager: ClipboardHistoryManager,
switchToAlphaLabel: String,
keyVisualAttr: KeyVisualAttributes?,
iconSet: KeyboardIconsSet
) {
historyManager.setHistoryChangeListener(this)
clipboardHistoryManager = historyManager
clipboardAdapter.clipboardHistoryManager = historyManager
val params = KeyDrawParams()
params.updateParams(clipboardLayoutParams.actionBarContentHeight, keyVisualAttr)
setupAlphabetKey(alphabetKey, switchToAlphaLabel, params)
setupClipKey(params)
setupClearKey(iconSet)
placeholderView.apply {
typeface = params.mTypeface
setTextColor(params.mTextColor)
setTextSize(TypedValue.COMPLEX_UNIT_PX, params.mLabelSize.toFloat() * 2)
}
clipboardRecyclerView.apply {
adapter = clipboardAdapter
}
}
fun stopClipboardHistory() {
clipboardRecyclerView.adapter = null
clipboardHistoryManager?.setHistoryChangeListener(null)
clipboardHistoryManager = null
clipboardAdapter.clipboardHistoryManager = null
}
override fun onTouch(view: View, event: MotionEvent): Boolean {
if (event.actionMasked != MotionEvent.ACTION_DOWN) {
return false
}
when (view) {
alphabetKey -> keyboardActionListener?.onPressKey(
Constants.CODE_ALPHA_FROM_CLIPBOARD, 0 /* repeatCount */,
true /* isSinglePointer */)
clearKey -> keyboardActionListener?.onPressKey(
Constants.CODE_UNSPECIFIED, 0 /* repeatCount */,
true /* isSinglePointer */)
}
// It's important to return false here. Otherwise, {@link #onClick} and touch-down visual
// feedback stop working.
return false
}
override fun onClick(view: View) {
when (view) {
alphabetKey -> {
keyboardActionListener?.onCodeInput(Constants.CODE_ALPHA_FROM_CLIPBOARD,
Constants.NOT_A_COORDINATE, Constants.NOT_A_COORDINATE,
false /* isKeyRepeat */)
keyboardActionListener?.onReleaseKey(Constants.CODE_ALPHA_FROM_CLIPBOARD,
false /* withSliding */)
}
clearKey -> {
clipboardHistoryManager?.clearHistory()
keyboardActionListener?.onReleaseKey(Constants.CODE_UNSPECIFIED,
false /* withSliding */)
}
}
}
override fun onKeyDown(clipId: Long) {
keyboardActionListener?.onPressKey(Constants.CODE_UNSPECIFIED, 0 /* repeatCount */,
true /* isSinglePointer */)
}
override fun onKeyUp(clipId: Long) {
val clipContent = clipboardHistoryManager?.getHistoryEntryContent(clipId)
keyboardActionListener?.onTextInput(clipContent?.content.toString())
keyboardActionListener?.onReleaseKey(Constants.CODE_UNSPECIFIED,
false /* withSliding */)
}
override fun onClipboardHistoryEntryAdded(at: Int) {
clipboardAdapter.notifyItemInserted(at)
clipboardRecyclerView.smoothScrollToPosition(at)
}
override fun onClipboardHistoryEntriesRemoved(position: Int, count: Int) {
clipboardAdapter.notifyItemRangeRemoved(position, count)
}
override fun onClipboardHistoryEntryMoved(from: Int, to: Int) {
clipboardAdapter.notifyItemMoved(from, to)
clipboardAdapter.notifyItemChanged(to)
if (to < from) clipboardRecyclerView.smoothScrollToPosition(to)
}
}

View file

@ -0,0 +1,68 @@
package org.dslul.openboard.inputmethod.keyboard.clipboard
import android.content.res.Resources
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
import androidx.recyclerview.widget.RecyclerView
import org.dslul.openboard.inputmethod.latin.R
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils
class ClipboardLayoutParams(res: Resources) {
private val keyVerticalGap: Int
private val keyHorizontalGap: Int
private val topPadding: Int
private val bottomPadding: Int
private val listHeight: Int
private val actionBarHeight: Int
companion object {
private const val DEFAULT_KEYBOARD_ROWS = 4
}
init {
val defaultKeyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res)
val suggestionStripHeight = res.getDimensionPixelSize(R.dimen.config_suggestions_strip_height)
val defaultKeyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res)
keyVerticalGap = res.getFraction(R.fraction.config_key_vertical_gap_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
bottomPadding = res.getFraction(R.fraction.config_keyboard_bottom_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
topPadding = res.getFraction(R.fraction.config_keyboard_top_padding_holo,
defaultKeyboardHeight, defaultKeyboardHeight).toInt()
keyHorizontalGap = res.getFraction(R.fraction.config_key_horizontal_gap_holo,
defaultKeyboardWidth, defaultKeyboardWidth).toInt()
actionBarHeight = (defaultKeyboardHeight - bottomPadding - topPadding) / DEFAULT_KEYBOARD_ROWS - keyVerticalGap / 2
listHeight = defaultKeyboardHeight + suggestionStripHeight - actionBarHeight - bottomPadding
}
fun setListProperties(recycler: RecyclerView) {
(recycler.layoutParams as FrameLayout.LayoutParams).apply {
height = listHeight
recycler.layoutParams = this
}
}
fun setActionBarProperties(layout: FrameLayout) {
(layout.layoutParams as LinearLayout.LayoutParams).apply {
height = actionBarHeight
layout.layoutParams = this
}
}
fun setItemProperties(view: View) {
(view.layoutParams as RecyclerView.LayoutParams).apply {
topMargin = keyHorizontalGap / 2
bottomMargin = keyVerticalGap / 2
marginStart = keyHorizontalGap / 2
marginEnd = keyHorizontalGap / 2
view.layoutParams = this
}
}
val actionBarContentHeight
get() = actionBarHeight
}

View file

@ -0,0 +1,9 @@
package org.dslul.openboard.inputmethod.keyboard.clipboard
interface OnKeyEventListener {
fun onKeyDown(clipId: Long)
fun onKeyUp(clipId: Long)
}

View file

@ -53,6 +53,8 @@ public final class KeyboardCodesSet {
"key_emoji", "key_emoji",
"key_alpha_from_emoji", "key_alpha_from_emoji",
"key_unspecified", "key_unspecified",
"key_clipboard",
"key_alpha_from_clipboard"
}; };
private static final int[] DEFAULT = { private static final int[] DEFAULT = {
@ -73,6 +75,8 @@ public final class KeyboardCodesSet {
Constants.CODE_EMOJI, Constants.CODE_EMOJI,
Constants.CODE_ALPHA_FROM_EMOJI, Constants.CODE_ALPHA_FROM_EMOJI,
Constants.CODE_UNSPECIFIED, Constants.CODE_UNSPECIFIED,
Constants.CODE_CLIPBOARD,
Constants.CODE_ALPHA_FROM_CLIPBOARD
}; };
static { static {

View file

@ -52,7 +52,6 @@ public final class KeyboardIconsSet {
public static final String NAME_PREVIOUS_KEY = "previous_key"; public static final String NAME_PREVIOUS_KEY = "previous_key";
public static final String NAME_TAB_KEY = "tab_key"; public static final String NAME_TAB_KEY = "tab_key";
public static final String NAME_SHORTCUT_KEY = "shortcut_key"; public static final String NAME_SHORTCUT_KEY = "shortcut_key";
public static final String NAME_CLIPBOARD_KEY = "clipboard_key";
public static final String NAME_INCOGNITO_KEY = "incognito_key"; public static final String NAME_INCOGNITO_KEY = "incognito_key";
public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled"; public static final String NAME_SHORTCUT_KEY_DISABLED = "shortcut_key_disabled";
public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key"; public static final String NAME_LANGUAGE_SWITCH_KEY = "language_switch_key";
@ -60,6 +59,9 @@ public final class KeyboardIconsSet {
public static final String NAME_ZWJ_KEY = "zwj_key"; public static final String NAME_ZWJ_KEY = "zwj_key";
public static final String NAME_EMOJI_ACTION_KEY = "emoji_action_key"; public static final String NAME_EMOJI_ACTION_KEY = "emoji_action_key";
public static final String NAME_EMOJI_NORMAL_KEY = "emoji_normal_key"; public static final String NAME_EMOJI_NORMAL_KEY = "emoji_normal_key";
public static final String NAME_CLIPBOARD_ACTION_KEY = "clipboard_action_key";
public static final String NAME_CLIPBOARD_NORMAL_KEY = "clipboard_normal_key";
public static final String NAME_CLEAR_CLIPBOARD_KEY = "clear_clipboard_key";
private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray(); private static final SparseIntArray ATTR_ID_TO_ICON_ID = new SparseIntArray();
@ -81,7 +83,6 @@ public final class KeyboardIconsSet {
NAME_PREVIOUS_KEY, R.styleable.Keyboard_iconPreviousKey, NAME_PREVIOUS_KEY, R.styleable.Keyboard_iconPreviousKey,
NAME_TAB_KEY, R.styleable.Keyboard_iconTabKey, NAME_TAB_KEY, R.styleable.Keyboard_iconTabKey,
NAME_SHORTCUT_KEY, R.styleable.Keyboard_iconShortcutKey, NAME_SHORTCUT_KEY, R.styleable.Keyboard_iconShortcutKey,
NAME_CLIPBOARD_KEY, R.styleable.Keyboard_iconClipboardKey,
NAME_INCOGNITO_KEY, R.styleable.Keyboard_iconIncognitoKey, NAME_INCOGNITO_KEY, R.styleable.Keyboard_iconIncognitoKey,
NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout, NAME_SPACE_KEY_FOR_NUMBER_LAYOUT, R.styleable.Keyboard_iconSpaceKeyForNumberLayout,
NAME_SHIFT_KEY_SHIFTED, R.styleable.Keyboard_iconShiftKeyShifted, NAME_SHIFT_KEY_SHIFTED, R.styleable.Keyboard_iconShiftKeyShifted,
@ -91,6 +92,9 @@ public final class KeyboardIconsSet {
NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey, NAME_ZWJ_KEY, R.styleable.Keyboard_iconZwjKey,
NAME_EMOJI_ACTION_KEY, R.styleable.Keyboard_iconEmojiActionKey, NAME_EMOJI_ACTION_KEY, R.styleable.Keyboard_iconEmojiActionKey,
NAME_EMOJI_NORMAL_KEY, R.styleable.Keyboard_iconEmojiNormalKey, NAME_EMOJI_NORMAL_KEY, R.styleable.Keyboard_iconEmojiNormalKey,
NAME_CLIPBOARD_ACTION_KEY, R.styleable.Keyboard_iconClipboardActionKey,
NAME_CLIPBOARD_NORMAL_KEY, R.styleable.Keyboard_iconClipboardNormalKey,
NAME_CLEAR_CLIPBOARD_KEY, R.styleable.Keyboard_iconClearClipboardKey,
}; };
private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2; private static int NUM_ICONS = NAMES_AND_ATTR_IDS.length / 2;

View file

@ -50,6 +50,7 @@ public final class KeyboardState {
void setAlphabetShiftLockedKeyboard(); void setAlphabetShiftLockedKeyboard();
void setAlphabetShiftLockShiftedKeyboard(); void setAlphabetShiftLockShiftedKeyboard();
void setEmojiKeyboard(); void setEmojiKeyboard();
void setClipboardKeyboard();
void setSymbolsKeyboard(); void setSymbolsKeyboard();
void setSymbolsShiftedKeyboard(); void setSymbolsShiftedKeyboard();
@ -81,10 +82,11 @@ public final class KeyboardState {
private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 5; private static final int SWITCH_STATE_MOMENTARY_ALPHA_SHIFT = 5;
private int mSwitchState = SWITCH_STATE_ALPHA; private int mSwitchState = SWITCH_STATE_ALPHA;
// TODO: Consolidate these two mode booleans into one integer to distinguish between alphabet, private static final int MODE_ALPHABET = 0;
// symbols, and emoji mode. private static final int MODE_SYMBOLS = 1;
private boolean mIsAlphabetMode; private static final int MODE_EMOJI = 2;
private boolean mIsEmojiMode; private static final int MODE_CLIPBOARD = 3;
private int mMode = MODE_ALPHABET;
private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState(); private AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState();
private boolean mIsSymbolShifted; private boolean mIsSymbolShifted;
private boolean mPrevMainKeyboardWasShiftLocked; private boolean mPrevMainKeyboardWasShiftLocked;
@ -99,9 +101,8 @@ public final class KeyboardState {
static final class SavedKeyboardState { static final class SavedKeyboardState {
public boolean mIsValid; public boolean mIsValid;
public boolean mIsAlphabetMode;
public boolean mIsAlphabetShiftLocked; public boolean mIsAlphabetShiftLocked;
public boolean mIsEmojiMode; public int mMode;
public int mShiftMode; public int mShiftMode;
@Override @Override
@ -109,13 +110,16 @@ public final class KeyboardState {
if (!mIsValid) { if (!mIsValid) {
return "INVALID"; return "INVALID";
} }
if (mIsAlphabetMode) { if (mMode == MODE_ALPHABET) {
return mIsAlphabetShiftLocked ? "ALPHABET_SHIFT_LOCKED" return mIsAlphabetShiftLocked ? "ALPHABET_SHIFT_LOCKED"
: "ALPHABET_" + shiftModeToString(mShiftMode); : "ALPHABET_" + shiftModeToString(mShiftMode);
} }
if (mIsEmojiMode) { if (mMode == MODE_EMOJI) {
return "EMOJI"; return "EMOJI";
} }
if (mMode == MODE_CLIPBOARD) {
return "CLIPBOARD";
}
return "SYMBOLS_" + shiftModeToString(mShiftMode); return "SYMBOLS_" + shiftModeToString(mShiftMode);
} }
} }
@ -152,9 +156,8 @@ public final class KeyboardState {
public void onSaveKeyboardState() { public void onSaveKeyboardState() {
final SavedKeyboardState state = mSavedKeyboardState; final SavedKeyboardState state = mSavedKeyboardState;
state.mIsAlphabetMode = mIsAlphabetMode; state.mMode = mMode;
state.mIsEmojiMode = mIsEmojiMode; if (mMode == MODE_ALPHABET) {
if (mIsAlphabetMode) {
state.mIsAlphabetShiftLocked = mAlphabetShiftState.isShiftLocked(); state.mIsAlphabetShiftLocked = mAlphabetShiftState.isShiftLocked();
state.mShiftMode = mAlphabetShiftState.isAutomaticShifted() ? AUTOMATIC_SHIFT state.mShiftMode = mAlphabetShiftState.isAutomaticShifted() ? AUTOMATIC_SHIFT
: (mAlphabetShiftState.isShiftedOrShiftLocked() ? MANUAL_SHIFT : UNSHIFT); : (mAlphabetShiftState.isShiftedOrShiftLocked() ? MANUAL_SHIFT : UNSHIFT);
@ -175,7 +178,7 @@ public final class KeyboardState {
+ " " + stateToString(autoCapsFlags, recapitalizeMode)); + " " + stateToString(autoCapsFlags, recapitalizeMode));
} }
mPrevMainKeyboardWasShiftLocked = state.mIsAlphabetShiftLocked; mPrevMainKeyboardWasShiftLocked = state.mIsAlphabetShiftLocked;
if (state.mIsAlphabetMode) { if (state.mMode == MODE_ALPHABET) {
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode); setAlphabetKeyboard(autoCapsFlags, recapitalizeMode);
setShiftLocked(state.mIsAlphabetShiftLocked); setShiftLocked(state.mIsAlphabetShiftLocked);
if (!state.mIsAlphabetShiftLocked) { if (!state.mIsAlphabetShiftLocked) {
@ -183,10 +186,14 @@ public final class KeyboardState {
} }
return; return;
} }
if (state.mIsEmojiMode) { if (state.mMode == MODE_EMOJI) {
setEmojiKeyboard(); setEmojiKeyboard();
return; return;
} }
if (state.mMode == MODE_CLIPBOARD) {
setClipboardKeyboard();
return;
}
// Symbol mode // Symbol mode
if (state.mShiftMode == MANUAL_SHIFT) { if (state.mShiftMode == MANUAL_SHIFT) {
setSymbolsShiftedKeyboard(); setSymbolsShiftedKeyboard();
@ -199,7 +206,7 @@ public final class KeyboardState {
if (DEBUG_INTERNAL_ACTION) { if (DEBUG_INTERNAL_ACTION) {
Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this); Log.d(TAG, "setShifted: shiftMode=" + shiftModeToString(shiftMode) + " " + this);
} }
if (!mIsAlphabetMode) return; if (mMode != MODE_ALPHABET) return;
final int prevShiftMode; final int prevShiftMode;
if (mAlphabetShiftState.isAutomaticShifted()) { if (mAlphabetShiftState.isAutomaticShifted()) {
prevShiftMode = AUTOMATIC_SHIFT; prevShiftMode = AUTOMATIC_SHIFT;
@ -238,7 +245,7 @@ public final class KeyboardState {
if (DEBUG_INTERNAL_ACTION) { if (DEBUG_INTERNAL_ACTION) {
Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this); Log.d(TAG, "setShiftLocked: shiftLocked=" + shiftLocked + " " + this);
} }
if (!mIsAlphabetMode) return; if (mMode != MODE_ALPHABET) return;
if (shiftLocked && (!mAlphabetShiftState.isShiftLocked() if (shiftLocked && (!mAlphabetShiftState.isShiftLocked()
|| mAlphabetShiftState.isShiftLockShifted())) { || mAlphabetShiftState.isShiftLockShifted())) {
mSwitchActions.setAlphabetShiftLockedKeyboard(); mSwitchActions.setAlphabetShiftLockedKeyboard();
@ -254,7 +261,7 @@ public final class KeyboardState {
Log.d(TAG, "toggleAlphabetAndSymbols: " Log.d(TAG, "toggleAlphabetAndSymbols: "
+ stateToString(autoCapsFlags, recapitalizeMode)); + stateToString(autoCapsFlags, recapitalizeMode));
} }
if (mIsAlphabetMode) { if (mMode == MODE_ALPHABET) {
mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked();
if (mPrevSymbolsKeyboardWasShifted) { if (mPrevSymbolsKeyboardWasShifted) {
setSymbolsShiftedKeyboard(); setSymbolsShiftedKeyboard();
@ -279,7 +286,7 @@ public final class KeyboardState {
Log.d(TAG, "resetKeyboardStateToAlphabet: " Log.d(TAG, "resetKeyboardStateToAlphabet: "
+ stateToString(autoCapsFlags, recapitalizeMode)); + stateToString(autoCapsFlags, recapitalizeMode));
} }
if (mIsAlphabetMode) return; if (mMode == MODE_ALPHABET) return;
mPrevSymbolsKeyboardWasShifted = mIsSymbolShifted; mPrevSymbolsKeyboardWasShifted = mIsSymbolShifted;
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode); setAlphabetKeyboard(autoCapsFlags, recapitalizeMode);
@ -303,8 +310,7 @@ public final class KeyboardState {
} }
mSwitchActions.setAlphabetKeyboard(); mSwitchActions.setAlphabetKeyboard();
mIsAlphabetMode = true; mMode = MODE_ALPHABET;
mIsEmojiMode = false;
mIsSymbolShifted = false; mIsSymbolShifted = false;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
mSwitchState = SWITCH_STATE_ALPHA; mSwitchState = SWITCH_STATE_ALPHA;
@ -316,7 +322,7 @@ public final class KeyboardState {
Log.d(TAG, "setSymbolsKeyboard"); Log.d(TAG, "setSymbolsKeyboard");
} }
mSwitchActions.setSymbolsKeyboard(); mSwitchActions.setSymbolsKeyboard();
mIsAlphabetMode = false; mMode = MODE_SYMBOLS;
mIsSymbolShifted = false; mIsSymbolShifted = false;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
// Reset alphabet shift state. // Reset alphabet shift state.
@ -329,7 +335,7 @@ public final class KeyboardState {
Log.d(TAG, "setSymbolsShiftedKeyboard"); Log.d(TAG, "setSymbolsShiftedKeyboard");
} }
mSwitchActions.setSymbolsShiftedKeyboard(); mSwitchActions.setSymbolsShiftedKeyboard();
mIsAlphabetMode = false; mMode = MODE_SYMBOLS;
mIsSymbolShifted = true; mIsSymbolShifted = true;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
// Reset alphabet shift state. // Reset alphabet shift state.
@ -341,8 +347,7 @@ public final class KeyboardState {
if (DEBUG_INTERNAL_ACTION) { if (DEBUG_INTERNAL_ACTION) {
Log.d(TAG, "setEmojiKeyboard"); Log.d(TAG, "setEmojiKeyboard");
} }
mIsAlphabetMode = false; mMode = MODE_EMOJI;
mIsEmojiMode = true;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE; mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
// Remember caps lock mode and reset alphabet shift state. // Remember caps lock mode and reset alphabet shift state.
mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked(); mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked();
@ -350,6 +355,18 @@ public final class KeyboardState {
mSwitchActions.setEmojiKeyboard(); mSwitchActions.setEmojiKeyboard();
} }
private void setClipboardKeyboard() {
if (DEBUG_INTERNAL_ACTION) {
Log.d(TAG, "setClipboardKeyboard");
}
mMode = MODE_CLIPBOARD;
mRecapitalizeMode = RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE;
// Remember caps lock mode and reset alphabet shift state.
mPrevMainKeyboardWasShiftLocked = mAlphabetShiftState.isShiftLocked();
mAlphabetShiftState.setShiftLocked(false);
mSwitchActions.setClipboardKeyboard();
}
public void onPressKey(final int code, final boolean isSinglePointer, final int autoCapsFlags, public void onPressKey(final int code, final boolean isSinglePointer, final int autoCapsFlags,
final int recapitalizeMode) { final int recapitalizeMode) {
if (DEBUG_EVENT) { if (DEBUG_EVENT) {
@ -379,7 +396,7 @@ public final class KeyboardState {
// As for #3, please note that it's required to check even when the auto caps mode is // As for #3, please note that it's required to check even when the auto caps mode is
// off because, for example, we may be in the #1 state within the manual temporary // off because, for example, we may be in the #1 state within the manual temporary
// shifted mode. // shifted mode.
if (!isSinglePointer && mIsAlphabetMode if (!isSinglePointer && mMode == MODE_ALPHABET
&& autoCapsFlags != TextUtils.CAP_MODE_CHARACTERS) { && autoCapsFlags != TextUtils.CAP_MODE_CHARACTERS) {
final boolean needsToResetAutoCaps = mAlphabetShiftState.isAutomaticShifted() final boolean needsToResetAutoCaps = mAlphabetShiftState.isAutomaticShifted()
|| (mAlphabetShiftState.isManualShifted() && mShiftKeyState.isReleasing()); || (mAlphabetShiftState.isManualShifted() && mShiftKeyState.isReleasing());
@ -463,7 +480,7 @@ public final class KeyboardState {
} }
private void updateAlphabetShiftState(final int autoCapsFlags, final int recapitalizeMode) { private void updateAlphabetShiftState(final int autoCapsFlags, final int recapitalizeMode) {
if (!mIsAlphabetMode) return; if (mMode != MODE_ALPHABET) return;
if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != recapitalizeMode) { if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != recapitalizeMode) {
// We are recapitalizing. Match the keyboard to the current recapitalize state. // We are recapitalizing. Match the keyboard to the current recapitalize state.
updateShiftStateForRecapitalize(recapitalizeMode); updateShiftStateForRecapitalize(recapitalizeMode);
@ -490,7 +507,7 @@ public final class KeyboardState {
if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) { if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) {
return; return;
} }
if (mIsAlphabetMode) { if (mMode == MODE_ALPHABET) {
mIsInDoubleTapShiftKey = mSwitchActions.isInDoubleTapShiftKeyTimeout(); mIsInDoubleTapShiftKey = mSwitchActions.isInDoubleTapShiftKeyTimeout();
if (!mIsInDoubleTapShiftKey) { if (!mIsInDoubleTapShiftKey) {
// This is first tap. // This is first tap.
@ -541,7 +558,7 @@ public final class KeyboardState {
// We are recapitalizing. We should match the keyboard state to the recapitalize // We are recapitalizing. We should match the keyboard state to the recapitalize
// state in priority. // state in priority.
updateShiftStateForRecapitalize(mRecapitalizeMode); updateShiftStateForRecapitalize(mRecapitalizeMode);
} else if (mIsAlphabetMode) { } else if (mMode == MODE_ALPHABET) {
final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked(); final boolean isShiftLocked = mAlphabetShiftState.isShiftLocked();
mIsInAlphabetUnshiftedFromShifted = false; mIsInAlphabetUnshiftedFromShifted = false;
if (mIsInDoubleTapShiftKey) { if (mIsInDoubleTapShiftKey) {
@ -629,7 +646,7 @@ public final class KeyboardState {
case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) { if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
// Detected only the mode change key has been pressed, and then released. // Detected only the mode change key has been pressed, and then released.
if (mIsAlphabetMode) { if (mMode == MODE_ALPHABET) {
mSwitchState = SWITCH_STATE_ALPHA; mSwitchState = SWITCH_STATE_ALPHA;
} else { } else {
mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
@ -644,8 +661,8 @@ public final class KeyboardState {
} }
break; break;
case SWITCH_STATE_SYMBOL_BEGIN: case SWITCH_STATE_SYMBOL_BEGIN:
if (mIsEmojiMode) { if (mMode == MODE_EMOJI || mMode == MODE_CLIPBOARD) {
// When in the Emoji keyboard, we don't want to switch back to the main layout even // When in the Emoji keyboard or clipboard one, we don't want to switch back to the main layout even
// after the user hits an emoji letter followed by an enter or a space. // after the user hits an emoji letter followed by an enter or a space.
break; break;
} }
@ -671,6 +688,10 @@ public final class KeyboardState {
setEmojiKeyboard(); setEmojiKeyboard();
} else if (code == Constants.CODE_ALPHA_FROM_EMOJI) { } else if (code == Constants.CODE_ALPHA_FROM_EMOJI) {
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode); setAlphabetKeyboard(autoCapsFlags, recapitalizeMode);
} else if (code == Constants.CODE_CLIPBOARD) {
setClipboardKeyboard();
} else if (code == Constants.CODE_ALPHA_FROM_CLIPBOARD) {
setAlphabetKeyboard(autoCapsFlags, recapitalizeMode);
} }
} }
@ -697,7 +718,7 @@ public final class KeyboardState {
@Override @Override
public String toString() { public String toString() {
return "[keyboard=" + (mIsAlphabetMode ? mAlphabetShiftState.toString() return "[keyboard=" + (mMode == MODE_ALPHABET ? mAlphabetShiftState.toString()
: (mIsSymbolShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS")) : (mIsSymbolShifted ? "SYMBOLS_SHIFTED" : "SYMBOLS"))
+ " shift=" + mShiftKeyState + " shift=" + mShiftKeyState
+ " symbol=" + mSymbolKeyState + " symbol=" + mSymbolKeyState

View file

@ -0,0 +1,13 @@
package org.dslul.openboard.inputmethod.latin
data class ClipboardHistoryEntry (
var id: Long,
val content: CharSequence,
var isPinned: Boolean = false
) : Comparable<ClipboardHistoryEntry> {
override fun compareTo(other: ClipboardHistoryEntry): Int {
val result = other.isPinned.compareTo(isPinned)
return if (result != 0) result else other.id.compareTo(id)
}
}

View file

@ -0,0 +1,174 @@
package org.dslul.openboard.inputmethod.latin
import android.content.ClipboardManager
import android.content.Context
import android.os.Build
import android.text.TextUtils
import android.util.Base64
import android.util.Log
import androidx.annotation.RequiresApi
import org.dslul.openboard.inputmethod.compat.ClipboardManagerCompat
import org.dslul.openboard.inputmethod.latin.utils.JsonUtils
import java.io.File
import java.lang.Exception
import java.util.*
class ClipboardHistoryManager(
private val latinIME: LatinIME
) : ClipboardManager.OnPrimaryClipChangedListener {
private lateinit var pinnedHistoryClipsFile: File
private lateinit var clipboardManager: ClipboardManager
private val historyEntries: MutableList<ClipboardHistoryEntry>
private var onHistoryChangeListener: OnHistoryChangeListener? = null
fun onCreate() {
pinnedHistoryClipsFile = File(latinIME.filesDir, PINNED_CLIPS_DATA_FILE_NAME)
clipboardManager = latinIME.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
fetchPrimaryClip()
clipboardManager.addPrimaryClipChangedListener(this)
startLoadPinnedClipsFromDisk()
}
fun onPinnedClipsAvailable(pinnedClips: List<ClipboardHistoryEntry>) {
historyEntries.addAll(pinnedClips)
sortHistoryEntries()
if (onHistoryChangeListener != null) {
pinnedClips.forEach {
onHistoryChangeListener?.onClipboardHistoryEntryAdded(historyEntries.indexOf(it))
}
}
}
fun onDestroy() {
clipboardManager.removePrimaryClipChangedListener(this)
}
override fun onPrimaryClipChanged() = fetchPrimaryClip()
private fun fetchPrimaryClip() {
val clipData = clipboardManager.primaryClip ?: return
if (clipData.itemCount == 0) return
clipData.getItemAt(0)?.let { clipItem ->
// Starting from API 30, onPrimaryClipChanged() can be called multiple times
// for the same clip. We can identify clips with their timestamps since API 26.
// We use that to prevent unwanted duplicates.
val id = ClipboardManagerCompat.getClipTimestamp(clipData)?.also { stamp ->
if (historyEntries.any { it.id == stamp }) return
} ?: System.currentTimeMillis()
val content = clipItem.coerceToText(latinIME)
if (TextUtils.isEmpty(content)) return
val entry = ClipboardHistoryEntry(id, content)
historyEntries.add(entry)
sortHistoryEntries()
val at = historyEntries.indexOf(entry)
onHistoryChangeListener?.onClipboardHistoryEntryAdded(at)
}
}
fun toggleClipPinned(clipId: Long) {
val from = historyEntries.indexOfFirst { it.id == clipId }
val historyEntry = historyEntries[from].apply {
id = System.currentTimeMillis()
isPinned = !isPinned
}
sortHistoryEntries()
val to = historyEntries.indexOf(historyEntry)
onHistoryChangeListener?.onClipboardHistoryEntryMoved(from, to)
startSavePinnedClipsToDisk()
}
fun clearHistory() {
ClipboardManagerCompat.clearPrimaryClip(clipboardManager)
val pos = historyEntries.indexOfFirst { !it.isPinned }
val count = historyEntries.count { !it.isPinned }
historyEntries.removeAll { !it.isPinned }
if (onHistoryChangeListener != null) {
onHistoryChangeListener?.onClipboardHistoryEntriesRemoved(pos, count)
}
}
private fun sortHistoryEntries() {
historyEntries.sort()
}
fun getHistorySize() = historyEntries.size
fun getHistoryEntry(position: Int) = historyEntries[position]
fun getHistoryEntryContent(id: Long) = historyEntries.first { it.id == id }
fun setHistoryChangeListener(l: OnHistoryChangeListener?) {
onHistoryChangeListener = l
}
private fun startLoadPinnedClipsFromDisk() {
object : Thread("$TAG-load") {
override fun run() {
loadFromDisk()
}
}.start()
}
private fun loadFromDisk() {
// Debugging
if (pinnedHistoryClipsFile.exists() && !pinnedHistoryClipsFile.canRead()) {
Log.w(TAG, "Attempt to read pinned clips file $pinnedHistoryClipsFile without permission")
}
var list = emptyList<ClipboardHistoryEntry>()
try {
if (pinnedHistoryClipsFile.exists()) {
val bytes = Base64.decode(pinnedHistoryClipsFile.readText(), Base64.DEFAULT)
list = JsonUtils.jsonBytesToHistoryEntryList(bytes)
}
} catch (e: Exception) {
Log.w(TAG, "Couldn't retrieve $pinnedHistoryClipsFile content", e)
}
latinIME.mHandler.postUpdateClipboardPinnedClips(list)
}
private fun startSavePinnedClipsToDisk() {
val localCopy = historyEntries.filter { it.isPinned }.map { it.copy() }
object : Thread("$TAG-save") {
override fun run() {
saveToDisk(localCopy)
}
}.start()
}
private fun saveToDisk(list: List<ClipboardHistoryEntry>) {
// Debugging
if (pinnedHistoryClipsFile.exists() && !pinnedHistoryClipsFile.canWrite()) {
Log.w(TAG, "Attempt to write pinned clips file $pinnedHistoryClipsFile without permission")
}
try {
pinnedHistoryClipsFile.createNewFile()
val jsonStr = JsonUtils.historyEntryListToJsonStr(list)
if (!TextUtils.isEmpty(jsonStr)) {
val rawText = Base64.encodeToString(jsonStr.encodeToByteArray(), Base64.DEFAULT)
pinnedHistoryClipsFile.writeText(rawText)
} else {
pinnedHistoryClipsFile.writeText("")
}
} catch (e: Exception) {
Log.w(TAG, "Couldn't write to $pinnedHistoryClipsFile", e)
}
}
interface OnHistoryChangeListener {
fun onClipboardHistoryEntryAdded(at: Int)
fun onClipboardHistoryEntriesRemoved(pos: Int, count: Int)
fun onClipboardHistoryEntryMoved(from: Int, to: Int)
}
companion object {
const val PINNED_CLIPS_DATA_FILE_NAME = "pinned_clips.data"
const val TAG = "ClipboardHistoryManager"
}
init {
historyEntries = LinkedList()
}
}

View file

@ -211,6 +211,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private GestureConsumer mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER; private GestureConsumer mGestureConsumer = GestureConsumer.NULL_GESTURE_CONSUMER;
private final ClipboardHistoryManager mClipboardHistoryManager = new ClipboardHistoryManager(this);
public final UIHandler mHandler = new UIHandler(this); public final UIHandler mHandler = new UIHandler(this);
public static final class UIHandler extends LeakGuardHandlerWrapper<LatinIME> { public static final class UIHandler extends LeakGuardHandlerWrapper<LatinIME> {
@ -226,8 +228,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
private static final int MSG_DEALLOCATE_MEMORY = 9; private static final int MSG_DEALLOCATE_MEMORY = 9;
private static final int MSG_RESUME_SUGGESTIONS_FOR_START_INPUT = 10; private static final int MSG_RESUME_SUGGESTIONS_FOR_START_INPUT = 10;
private static final int MSG_SWITCH_LANGUAGE_AUTOMATICALLY = 11; private static final int MSG_SWITCH_LANGUAGE_AUTOMATICALLY = 11;
private static final int MSG_UPDATE_CLIPBOARD_PINNED_CLIPS = 12;
// Update this when adding new messages // Update this when adding new messages
private static final int MSG_LAST = MSG_SWITCH_LANGUAGE_AUTOMATICALLY; private static final int MSG_LAST = MSG_UPDATE_CLIPBOARD_PINNED_CLIPS;
private static final int ARG1_NOT_GESTURE_INPUT = 0; private static final int ARG1_NOT_GESTURE_INPUT = 0;
private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1;
@ -324,6 +327,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
case MSG_SWITCH_LANGUAGE_AUTOMATICALLY: case MSG_SWITCH_LANGUAGE_AUTOMATICALLY:
latinIme.switchLanguage((InputMethodSubtype)msg.obj); latinIme.switchLanguage((InputMethodSubtype)msg.obj);
break; break;
case MSG_UPDATE_CLIPBOARD_PINNED_CLIPS:
@SuppressWarnings("unchecked")
List<ClipboardHistoryEntry> entries = (List<ClipboardHistoryEntry>) msg.obj;
latinIme.mClipboardHistoryManager.onPinnedClipsAvailable(entries);
break;
} }
} }
@ -446,6 +454,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
obtainMessage(MSG_SWITCH_LANGUAGE_AUTOMATICALLY, subtype).sendToTarget(); obtainMessage(MSG_SWITCH_LANGUAGE_AUTOMATICALLY, subtype).sendToTarget();
} }
public void postUpdateClipboardPinnedClips(final List<ClipboardHistoryEntry> clips) {
obtainMessage(MSG_UPDATE_CLIPBOARD_PINNED_CLIPS, clips).sendToTarget();
}
// Working variables for the following methods. // Working variables for the following methods.
private boolean mIsOrientationChanging; private boolean mIsOrientationChanging;
private boolean mPendingSuccessiveImsCallback; private boolean mPendingSuccessiveImsCallback;
@ -612,6 +624,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
mStatsUtilsManager.onCreate(this /* context */, mDictionaryFacilitator); mStatsUtilsManager.onCreate(this /* context */, mDictionaryFacilitator);
super.onCreate(); super.onCreate();
mClipboardHistoryManager.onCreate();
mHandler.onCreate(); mHandler.onCreate();
// TODO: Resolve mutual dependencies of {@link #loadSettings()} and // TODO: Resolve mutual dependencies of {@link #loadSettings()} and
@ -750,6 +763,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
@Override @Override
public void onDestroy() { public void onDestroy() {
mClipboardHistoryManager.onDestroy();
mDictionaryFacilitator.closeDictionaries(); mDictionaryFacilitator.closeDictionaries();
mSettings.onDestroy(); mSettings.onDestroy();
unregisterReceiver(mHideSoftInputReceiver); unregisterReceiver(mHideSoftInputReceiver);
@ -1226,6 +1240,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return; return;
} }
final int suggestionsHeight = (!mKeyboardSwitcher.isShowingEmojiPalettes() final int suggestionsHeight = (!mKeyboardSwitcher.isShowingEmojiPalettes()
&& !mKeyboardSwitcher.isShowingClipboardHistory()
&& mSuggestionStripView.getVisibility() == View.VISIBLE) && mSuggestionStripView.getVisibility() == View.VISIBLE)
? mSuggestionStripView.getHeight() : 0; ? mSuggestionStripView.getHeight() : 0;
final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - suggestionsHeight; final int visibleTopY = inputHeight - visibleKeyboardView.getHeight() - suggestionsHeight;
@ -1828,6 +1843,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
} }
}; };
public ClipboardHistoryManager getClipboardHistoryManager() {
return mClipboardHistoryManager;
}
void launchSettings() { void launchSettings() {
mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR); mInputLogic.commitTyped(mSettings.getCurrent(), LastComposedWord.NOT_A_SEPARATOR);
requestHideSelf(0); requestHideSelf(0);

View file

@ -242,11 +242,13 @@ public final class Constants {
public static final int CODE_ACTION_PREVIOUS = -9; public static final int CODE_ACTION_PREVIOUS = -9;
public static final int CODE_LANGUAGE_SWITCH = -10; public static final int CODE_LANGUAGE_SWITCH = -10;
public static final int CODE_EMOJI = -11; public static final int CODE_EMOJI = -11;
public static final int CODE_SHIFT_ENTER = -12; public static final int CODE_CLIPBOARD = -12;
public static final int CODE_SYMBOL_SHIFT = -13; public static final int CODE_SHIFT_ENTER = -13;
public static final int CODE_ALPHA_FROM_EMOJI = -14; public static final int CODE_SYMBOL_SHIFT = -14;
public static final int CODE_ALPHA_FROM_EMOJI = -15;
public static final int CODE_ALPHA_FROM_CLIPBOARD = -16;
// Code value representing the code is not specified. // Code value representing the code is not specified.
public static final int CODE_UNSPECIFIED = -15; public static final int CODE_UNSPECIFIED = -17;
public static boolean isLetterCode(final int code) { public static boolean isLetterCode(final int code) {
return code >= CODE_SPACE; return code >= CODE_SPACE;
@ -266,8 +268,10 @@ public final class Constants {
case CODE_ACTION_PREVIOUS: return "actionPrevious"; case CODE_ACTION_PREVIOUS: return "actionPrevious";
case CODE_LANGUAGE_SWITCH: return "languageSwitch"; case CODE_LANGUAGE_SWITCH: return "languageSwitch";
case CODE_EMOJI: return "emoji"; case CODE_EMOJI: return "emoji";
case CODE_CLIPBOARD: return "clipboard";
case CODE_SHIFT_ENTER: return "shiftEnter"; case CODE_SHIFT_ENTER: return "shiftEnter";
case CODE_ALPHA_FROM_EMOJI: return "alpha"; case CODE_ALPHA_FROM_EMOJI: return "alpha";
case CODE_ALPHA_FROM_CLIPBOARD: return "alpha";
case CODE_UNSPECIFIED: return "unspec"; case CODE_UNSPECIFIED: return "unspec";
case CODE_TAB: return "tab"; case CODE_TAB: return "tab";
case CODE_ENTER: return "enter"; case CODE_ENTER: return "enter";

View file

@ -692,6 +692,14 @@ public final class InputLogic {
// Note: Switching back from Emoji keyboard to the main keyboard is being // Note: Switching back from Emoji keyboard to the main keyboard is being
// handled in {@link KeyboardState#onEvent(Event,int)}. // handled in {@link KeyboardState#onEvent(Event,int)}.
break; break;
case Constants.CODE_CLIPBOARD:
// Note: Switching clipboard keyboard is being handled in
// {@link KeyboardState#onEvent(Event,int)}.
break;
case Constants.CODE_ALPHA_FROM_CLIPBOARD:
// Note: Switching back from clipboard keyboard to the main keyboard is being
// handled in {@link KeyboardState#onEvent(Event,int)}.
break;
case Constants.CODE_SHIFT_ENTER: case Constants.CODE_SHIFT_ENTER:
final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER, final Event tmpEvent = Event.createSoftwareKeypressEvent(Constants.CODE_ENTER,
event.getMKeyCode(), event.getMX(), event.getMY(), event.isKeyRepeat()); event.getMKeyCode(), event.getMX(), event.getMY(), event.isKeyRepeat());

View file

@ -22,6 +22,7 @@ import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
@ -95,8 +96,9 @@ public final class CustomInputStyleSettingsFragment extends PreferenceFragment
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
getPreferenceManager().setStorageDeviceProtected(); getPreferenceManager().setStorageDeviceProtected();
}
mPrefs = getPreferenceManager().getSharedPreferences(); mPrefs = getPreferenceManager().getSharedPreferences();
RichInputMethodManager.init(getActivity()); RichInputMethodManager.init(getActivity());
mRichImm = RichInputMethodManager.getInstance(); mRichImm = RichInputMethodManager.getInstance();

View file

@ -111,6 +111,8 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
public static final String PREF_SHOW_HINTS = "pref_show_hints"; public static final String PREF_SHOW_HINTS = "pref_show_hints";
public static final String PREF_SPACE_TO_CHANGE_LANG = "prefs_long_press_keyboard_to_change_lang";
// This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead. // This preference key is deprecated. Use {@link #PREF_SHOW_LANGUAGE_SWITCH_KEY} instead.
// This is being used only for the backward compatibility. // This is being used only for the backward compatibility.
private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY = private static final String PREF_SUPPRESS_LANGUAGE_SWITCH_KEY =

View file

@ -71,6 +71,7 @@ public class SettingsValues {
public final boolean mIncludesOtherImesInLanguageSwitchList; public final boolean mIncludesOtherImesInLanguageSwitchList;
public final boolean mShowsNumberRow; public final boolean mShowsNumberRow;
public final boolean mShowsHints; public final boolean mShowsHints;
public final boolean mSpaceForLangChange;
public final boolean mShowsLanguageSwitchKey; public final boolean mShowsLanguageSwitchKey;
public final boolean mShowsEmojiKey; public final boolean mShowsEmojiKey;
public final boolean mShowsClipboardKey; public final boolean mShowsClipboardKey;
@ -148,6 +149,7 @@ public class SettingsValues {
mIncludesOtherImesInLanguageSwitchList = !Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS || prefs.getBoolean(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false) /* forcibly */; mIncludesOtherImesInLanguageSwitchList = !Settings.ENABLE_SHOW_LANGUAGE_SWITCH_KEY_SETTINGS || prefs.getBoolean(Settings.PREF_INCLUDE_OTHER_IMES_IN_LANGUAGE_SWITCH_LIST, false) /* forcibly */;
mShowsNumberRow = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false); mShowsNumberRow = prefs.getBoolean(Settings.PREF_SHOW_NUMBER_ROW, false);
mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, true); mShowsHints = prefs.getBoolean(Settings.PREF_SHOW_HINTS, true);
mSpaceForLangChange = prefs.getBoolean(Settings.PREF_SPACE_TO_CHANGE_LANG, true);
mShowsLanguageSwitchKey = prefs.getBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, false); mShowsLanguageSwitchKey = prefs.getBoolean(Settings.PREF_SHOW_LANGUAGE_SWITCH_KEY, false);
mShowsEmojiKey = prefs.getBoolean(Settings.PREF_SHOW_EMOJI_KEY, false); mShowsEmojiKey = prefs.getBoolean(Settings.PREF_SHOW_EMOJI_KEY, false);
mShowsClipboardKey = prefs.getBoolean(Settings.PREF_SHOW_CLIPBOARD_KEY, false); mShowsClipboardKey = prefs.getBoolean(Settings.PREF_SHOW_CLIPBOARD_KEY, false);

View file

@ -21,6 +21,7 @@ import android.content.Context;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.ListPreference; import android.preference.ListPreference;
import android.preference.Preference; import android.preference.Preference;
@ -100,7 +101,9 @@ public abstract class SubScreenFragment extends PreferenceFragment
@Override @Override
public void onCreate(final Bundle savedInstanceState) { public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
getPreferenceManager().setStorageDeviceProtected(); getPreferenceManager().setStorageDeviceProtected();
}
mSharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() { mSharedPreferenceChangeListener = new OnSharedPreferenceChangeListener() {
@Override @Override
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) { public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {

View file

@ -40,6 +40,7 @@ import android.widget.TextView;
import org.dslul.openboard.inputmethod.accessibility.AccessibilityUtils; import org.dslul.openboard.inputmethod.accessibility.AccessibilityUtils;
import org.dslul.openboard.inputmethod.keyboard.Keyboard; import org.dslul.openboard.inputmethod.keyboard.Keyboard;
import org.dslul.openboard.inputmethod.keyboard.KeyboardSwitcher;
import org.dslul.openboard.inputmethod.keyboard.MainKeyboardView; import org.dslul.openboard.inputmethod.keyboard.MainKeyboardView;
import org.dslul.openboard.inputmethod.keyboard.MoreKeysPanel; import org.dslul.openboard.inputmethod.keyboard.MoreKeysPanel;
import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager; import org.dslul.openboard.inputmethod.latin.AudioAndHapticFeedbackManager;
@ -167,7 +168,7 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
R.styleable.Keyboard, defStyle, R.style.SuggestionStripView); R.styleable.Keyboard, defStyle, R.style.SuggestionStripView);
final Drawable iconVoice = keyboardAttr.getDrawable(R.styleable.Keyboard_iconShortcutKey); final Drawable iconVoice = keyboardAttr.getDrawable(R.styleable.Keyboard_iconShortcutKey);
final Drawable iconIncognito = keyboardAttr.getDrawable(R.styleable.Keyboard_iconIncognitoKey); final Drawable iconIncognito = keyboardAttr.getDrawable(R.styleable.Keyboard_iconIncognitoKey);
final Drawable iconClipboard = keyboardAttr.getDrawable(R.styleable.Keyboard_iconClipboardKey); final Drawable iconClipboard = keyboardAttr.getDrawable(R.styleable.Keyboard_iconClipboardNormalKey);
keyboardAttr.recycle(); keyboardAttr.recycle();
mVoiceKey.setImageDrawable(iconVoice); mVoiceKey.setImageDrawable(iconVoice);
mVoiceKey.setOnClickListener(this); mVoiceKey.setOnClickListener(this);
@ -442,12 +443,8 @@ public final class SuggestionStripView extends RelativeLayout implements OnClick
return; return;
} }
if (view == mClipboardKey) { if (view == mClipboardKey) {
CharSequence selectionSequence = mListener.getSelection(); final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance();
if (selectionSequence != null && selectionSequence.length() > 0 switcher.onToggleKeyboard(KeyboardSwitcher.KeyboardSwitchState.CLIPBOARD);
&& !Settings.getInstance().getCurrent().mInputAttributes.mIsPasswordField) {
ClipboardManager clipboardManager = (ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
clipboardManager.setPrimaryClip(ClipData.newPlainText(selectionSequence, selectionSequence));
}
return; return;
} }

View file

@ -20,6 +20,7 @@ import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.database.Cursor; import android.database.Cursor;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
@ -51,7 +52,9 @@ public class UserDictionaryList extends PreferenceFragment {
@Override @Override
public void onCreate(final Bundle icicle) { public void onCreate(final Bundle icicle) {
super.onCreate(icicle); super.onCreate(icicle);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
getPreferenceManager().setStorageDeviceProtected(); getPreferenceManager().setStorageDeviceProtected();
}
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity())); setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
} }

View file

@ -16,15 +16,20 @@
package org.dslul.openboard.inputmethod.latin.utils; package org.dslul.openboard.inputmethod.latin.utils;
import android.text.TextUtils;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import android.util.Log; import android.util.Log;
import org.dslul.openboard.inputmethod.latin.ClipboardHistoryEntry;
import java.io.ByteArrayInputStream;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader; import java.io.StringReader;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -33,6 +38,8 @@ public final class JsonUtils {
private static final String INTEGER_CLASS_NAME = Integer.class.getSimpleName(); private static final String INTEGER_CLASS_NAME = Integer.class.getSimpleName();
private static final String STRING_CLASS_NAME = String.class.getSimpleName(); private static final String STRING_CLASS_NAME = String.class.getSimpleName();
private static final String CLIPBOARD_HISTORY_ENTRY_ID_KEY = "id";
private static final String CLIPBOARD_HISTORY_ENTRY_CONTENT_KEY = "content";
private static final String EMPTY_STRING = ""; private static final String EMPTY_STRING = "";
@ -91,6 +98,63 @@ public final class JsonUtils {
return EMPTY_STRING; return EMPTY_STRING;
} }
public static List<ClipboardHistoryEntry> jsonBytesToHistoryEntryList(final byte[] bytes) {
final ArrayList<ClipboardHistoryEntry> list = new ArrayList<>();
final JsonReader reader = new JsonReader(new InputStreamReader(new ByteArrayInputStream(bytes)));
try {
reader.beginArray();
while (reader.hasNext()) {
reader.beginObject();
long id = 0;
String content = EMPTY_STRING;
while (reader.hasNext()) {
final String name = reader.nextName();
if (name.equals(CLIPBOARD_HISTORY_ENTRY_ID_KEY)) {
id = reader.nextLong();
} else if (name.equals(CLIPBOARD_HISTORY_ENTRY_CONTENT_KEY)) {
content = reader.nextString();
} else {
Log.w(TAG, "Invalid name: " + name);
reader.skipValue();
}
}
if (id > 0 && !TextUtils.isEmpty(content)) {
list.add(new ClipboardHistoryEntry(id, content, true));
}
reader.endObject();
}
reader.endArray();
return list;
} catch (final IOException e) {
} finally {
close(reader);
}
return Collections.emptyList();
}
public static String historyEntryListToJsonStr(final Collection<ClipboardHistoryEntry> entries) {
if (entries == null || entries.isEmpty()) {
return EMPTY_STRING;
}
final StringWriter sw = new StringWriter();
final JsonWriter writer = new JsonWriter(sw);
try {
writer.beginArray();
for (final ClipboardHistoryEntry e : entries) {
writer.beginObject();
writer.name(CLIPBOARD_HISTORY_ENTRY_ID_KEY).value(e.getId());
writer.name(CLIPBOARD_HISTORY_ENTRY_CONTENT_KEY).value(e.getContent().toString());
writer.endObject();
}
writer.endArray();
return sw.toString();
} catch (final IOException e) {
} finally {
close(writer);
}
return EMPTY_STRING;
}
private static void close(final Closeable closeable) { private static void close(final Closeable closeable) {
try { try {
if (closeable != null) { if (closeable != null) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 658 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 978 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 728 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 955 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 851 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 975 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 835 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 797 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/clipboard_entry_pinned_icon"
android:layout_width="@dimen/config_clipboard_pinned_icon_size"
android:layout_height="@dimen/config_clipboard_pinned_icon_size"
android:layout_marginVertical="8dp"
android:layout_marginStart="4dp"/>
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
We just need to ignore the system's audio and haptic feedback settings. -->
<TextView
android:id="@+id/clipboard_entry_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginTop="4dp"
android:layout_marginBottom="6dp"
android:layout_marginHorizontal="8dp"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:ellipsize="end"
android:maxLines="4"/>
</LinearLayout>

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<org.dslul.openboard.inputmethod.keyboard.clipboard.ClipboardHistoryView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical"
style="?attr/clipboardHistoryViewStyle">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/clipboard_empty_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="¯\\_(ツ)_/¯"/>
<org.dslul.openboard.inputmethod.keyboard.clipboard.ClipboardHistoryRecyclerView
android:id="@+id/clipboard_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</FrameLayout>
<FrameLayout
android:id="@+id/clipboard_action_bar"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1" >
<!-- TODO: Implement a KeyView and replace this. -->
<!-- Provide audio and haptic feedback by ourselves based on the keyboard settings.
We just need to ignore the system's audio and haptic feedback settings. -->
<TextView
android:id="@+id/clipboard_keyboard_alphabet"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginStart="2dp"
android:layout_marginTop="1dp"
android:layout_marginEnd="1dp"
android:layout_gravity="start|center_vertical"
android:paddingHorizontal="12dp"
android:gravity="center"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false" />
<ImageButton
android:id="@+id/clipboard_clear"
android:layout_width="@dimen/config_suggestions_strip_edge_key_width"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="2dp"
android:padding="8dp"
android:hapticFeedbackEnabled="false"
android:soundEffectsEnabled="false"
android:scaleType="fitCenter"
style="?attr/suggestionWordStyle" />
</FrameLayout>
</org.dslul.openboard.inputmethod.keyboard.clipboard.ClipboardHistoryView>

View file

@ -29,4 +29,7 @@
<include <include
android:id="@+id/emoji_palettes_view" android:id="@+id/emoji_palettes_view"
layout="@layout/emoji_palettes_view" /> layout="@layout/emoji_palettes_view" />
<include
android:id="@+id/clipboard_history_view"
layout="@layout/clipboard_history_view" />
</org.dslul.openboard.inputmethod.latin.InputView> </org.dslul.openboard.inputmethod.latin.InputView>

View file

@ -58,7 +58,6 @@
android:layout_width="@dimen/config_suggestions_strip_edge_key_width" android:layout_width="@dimen/config_suggestions_strip_edge_key_width"
android:scaleType="fitCenter" android:scaleType="fitCenter"
android:layout_height="fill_parent" android:layout_height="fill_parent"
android:contentDescription="@string/spoken_description_mic"
style="?attr/suggestionWordStyle" /> style="?attr/suggestionWordStyle" />
</LinearLayout> </LinearLayout>
</merge> </merge>

Binary file not shown.

View file

@ -82,4 +82,7 @@
<fraction name="config_emoji_keyboard_key_letter_size">70%p</fraction> <fraction name="config_emoji_keyboard_key_letter_size">70%p</fraction>
<fraction name="config_emoji_keyboard_key_label_size">70%p</fraction> <fraction name="config_emoji_keyboard_key_label_size">70%p</fraction>
<integer name="config_emoji_keyboard_max_recents_key_count">32</integer> <integer name="config_emoji_keyboard_max_recents_key_count">32</integer>
<!-- Clipboard keyboard -->
<integer name="config_clipboard_keyboard_col_count">3</integer>
</resources> </resources>

View file

@ -70,4 +70,7 @@
<fraction name="config_emoji_keyboard_key_letter_size">64%p</fraction> <fraction name="config_emoji_keyboard_key_letter_size">64%p</fraction>
<fraction name="config_emoji_keyboard_key_label_size">64%p</fraction> <fraction name="config_emoji_keyboard_key_label_size">64%p</fraction>
<integer name="config_emoji_keyboard_max_recents_key_count">36</integer> <integer name="config_emoji_keyboard_max_recents_key_count">36</integer>
<!-- Clipboard keyboard -->
<integer name="config_clipboard_keyboard_col_count">4</integer>
</resources> </resources>

View file

@ -87,4 +87,7 @@
<fraction name="config_emoji_keyboard_key_letter_size">78%p</fraction> <fraction name="config_emoji_keyboard_key_letter_size">78%p</fraction>
<fraction name="config_emoji_keyboard_key_label_size">78%p</fraction> <fraction name="config_emoji_keyboard_key_label_size">78%p</fraction>
<integer name="config_emoji_keyboard_max_recents_key_count">36</integer> <integer name="config_emoji_keyboard_max_recents_key_count">36</integer>
<!-- Clipboard keyboard -->
<integer name="config_clipboard_keyboard_col_count">3</integer>
</resources> </resources>

View file

@ -30,6 +30,8 @@
<attr name="mainKeyboardViewStyle" format="reference" /> <attr name="mainKeyboardViewStyle" format="reference" />
<!-- EmojiPalettesView style --> <!-- EmojiPalettesView style -->
<attr name="emojiPalettesViewStyle" format="reference" /> <attr name="emojiPalettesViewStyle" format="reference" />
<!-- ClipboardHistoryView style -->
<attr name="clipboardHistoryViewStyle" format="reference" />
<!-- MoreKeysKeyboard style --> <!-- MoreKeysKeyboard style -->
<attr name="moreKeysKeyboardStyle" format="reference" /> <attr name="moreKeysKeyboardStyle" format="reference" />
<!-- MoreKeysKeyboardView style --> <!-- MoreKeysKeyboardView style -->
@ -205,6 +207,11 @@
<attr name="iconEmojiCategory10Tab" format="reference" /> <attr name="iconEmojiCategory10Tab" format="reference" />
</declare-styleable> </declare-styleable>
<declare-styleable name="ClipboardHistoryView">
<attr name="dividerBackground" format="color" />
<attr name="iconPinnedClip" format="reference" />
</declare-styleable>
<declare-styleable name="SuggestionStripView"> <declare-styleable name="SuggestionStripView">
<attr name="suggestionStripOptions" format="integer"> <attr name="suggestionStripOptions" format="integer">
<!-- This should be aligned with <!-- This should be aligned with
@ -270,7 +277,6 @@
<attr name="iconPreviousKey" format="reference" /> <attr name="iconPreviousKey" format="reference" />
<attr name="iconTabKey" format="reference" /> <attr name="iconTabKey" format="reference" />
<attr name="iconShortcutKey" format="reference" /> <attr name="iconShortcutKey" format="reference" />
<attr name="iconClipboardKey" format="reference" />
<attr name="iconIncognitoKey" format="reference" /> <attr name="iconIncognitoKey" format="reference" />
<attr name="iconSpaceKeyForNumberLayout" format="reference" /> <attr name="iconSpaceKeyForNumberLayout" format="reference" />
<attr name="iconShiftKeyShifted" format="reference" /> <attr name="iconShiftKeyShifted" format="reference" />
@ -281,6 +287,9 @@
<attr name="iconImeKey" format="reference" /> <attr name="iconImeKey" format="reference" />
<attr name="iconEmojiActionKey" format="reference" /> <attr name="iconEmojiActionKey" format="reference" />
<attr name="iconEmojiNormalKey" format="reference" /> <attr name="iconEmojiNormalKey" format="reference" />
<attr name="iconClipboardActionKey" format="reference" />
<attr name="iconClipboardNormalKey" format="reference" />
<attr name="iconClearClipboardKey" format="reference" />
</declare-styleable> </declare-styleable>
<declare-styleable name="Keyboard_GridRows"> <declare-styleable name="Keyboard_GridRows">

View file

@ -136,6 +136,10 @@
<!-- Common configuration of Emoji keyboard --> <!-- Common configuration of Emoji keyboard -->
<dimen name="config_emoji_category_page_id_height">2dp</dimen> <dimen name="config_emoji_category_page_id_height">2dp</dimen>
<!-- Common configuration of clipboard keyboard -->
<dimen name="config_clipboard_divider_height">1.5dp</dimen>
<dimen name="config_clipboard_pinned_icon_size">18dp</dimen>
<!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. --> <!-- Inset used in Accessibility mode to avoid accidental key presses when a finger slides off the screen. -->
<dimen name="config_accessibility_edge_slop">8dp</dimen> <dimen name="config_accessibility_edge_slop">8dp</dimen>

View file

@ -93,6 +93,9 @@
<fraction name="config_emoji_keyboard_key_label_size">78%p</fraction> <fraction name="config_emoji_keyboard_key_label_size">78%p</fraction>
<integer name="config_emoji_keyboard_max_recents_key_count">32</integer> <integer name="config_emoji_keyboard_max_recents_key_count">32</integer>
<!-- Clipboard keyboard -->
<integer name="config_clipboard_keyboard_col_count">2</integer>
<!-- Key codes of hardware keys that can be used to toggle the Emoji layout. <!-- Key codes of hardware keys that can be used to toggle the Emoji layout.
Each array defines a comma-separated tuple containing: Each array defines a comma-separated tuple containing:
1. Key code constant from android.view.KeyEvent 1. Key code constant from android.view.KeyEvent

View file

@ -1,15 +1,31 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!--
!!!!! DO NOT EDIT THIS FILE !!!!!
This file is generated by tools/make-emoji-keys. The base template file is
tools/make-emoji-keys/src/main/resources/values/emoji-categories.tmpl
This file must be updated when any a new release of unicode comes out. Base data
can be found at https://unicode.org/Public/emoji/. Table must be defined in
tools/make-emoji-keys/src/main/resources/emoji/UNICODE_VERSION/emoji-test.txt.
To update this file, please run the following commands.
$ gradle :tools:make-emoji-keys:makeEmoji
The updated source file will be generated to the following path (this file).
app/src/main/res/values/emoji-categories.xml
Unicode version 14.0.
Platform compatibility up to API level 32.
-->
<!-- Note: This emoji code point list includes emojis from Unicode 13.1 supported
in Android up to platform level 30.
Emoji data generated from https://unicode.org/Public/emoji/13.1/emoji-test.txt.
Platform compatibility data from https://emojipedia.org/. -->
<resources> <resources>
<array <array
name="emoji_smileys_emotion" name="emoji_smileys_emotion"
format="string" format="string">
>
<item>1F600</item> <item>1F600</item>
<item>1F603</item> <item>1F603</item>
<item>1F604</item> <item>1F604</item>
@ -20,6 +36,7 @@
<item>1F602</item> <item>1F602</item>
<item>1F642||23</item> <item>1F642||23</item>
<item>1F643||23</item> <item>1F643||23</item>
<item>1FAE0||32</item>
<item>1F609</item> <item>1F609</item>
<item>1F60A</item> <item>1F60A</item>
<item>1F607</item> <item>1F607</item>
@ -40,17 +57,23 @@
<item>1F911||23</item> <item>1F911||23</item>
<item>1F917||23</item> <item>1F917||23</item>
<item>1F92D||26</item> <item>1F92D||26</item>
<item>1FAE2||32</item>
<item>1FAE3||32</item>
<item>1F92B||26</item> <item>1F92B||26</item>
<item>1F914||23</item> <item>1F914||23</item>
<item>1FAE1||32</item>
<item>1F910||23</item> <item>1F910||23</item>
<item>1F928||26</item> <item>1F928||26</item>
<item>1F610</item> <item>1F610</item>
<item>1F611</item> <item>1F611</item>
<item>1F636</item> <item>1F636</item>
<item>1FAE5||32</item>
<item>1F636,200D,1F32B,FE0F||31</item>
<item>1F60F</item> <item>1F60F</item>
<item>1F612</item> <item>1F612</item>
<item>1F644||23</item> <item>1F644||23</item>
<item>1F62C</item> <item>1F62C</item>
<item>1F62E,200D,1F4A8||31</item>
<item>1F925||24</item> <item>1F925||24</item>
<item>1F60C</item> <item>1F60C</item>
<item>1F614</item> <item>1F614</item>
@ -66,6 +89,8 @@
<item>1F975||28</item> <item>1F975||28</item>
<item>1F976||28</item> <item>1F976||28</item>
<item>1F974||28</item> <item>1F974||28</item>
<item>1F635</item>
<item>1F635,200D,1F4AB||31</item>
<item>1F92F||26</item> <item>1F92F||26</item>
<item>1F920||24</item> <item>1F920||24</item>
<item>1F973||28</item> <item>1F973||28</item>
@ -74,6 +99,7 @@
<item>1F913||23</item> <item>1F913||23</item>
<item>1F9D0||26</item> <item>1F9D0||26</item>
<item>1F615</item> <item>1F615</item>
<item>1FAE4||32</item>
<item>1F61F</item> <item>1F61F</item>
<item>1F641||23</item> <item>1F641||23</item>
<item>2639,FE0F||23</item> <item>2639,FE0F||23</item>
@ -82,6 +108,7 @@
<item>1F632</item> <item>1F632</item>
<item>1F633</item> <item>1F633</item>
<item>1F97A||28</item> <item>1F97A||28</item>
<item>1F979||32</item>
<item>1F626</item> <item>1F626</item>
<item>1F627</item> <item>1F627</item>
<item>1F628</item> <item>1F628</item>
@ -137,6 +164,8 @@
<item>1F49F</item> <item>1F49F</item>
<item>2763,FE0F||23</item> <item>2763,FE0F||23</item>
<item>1F494</item> <item>1F494</item>
<item>2764,FE0F,200D,1F525||31</item>
<item>2764,FE0F,200D,1FA79||31</item>
<item>2764,FE0F</item> <item>2764,FE0F</item>
<item>1F9E1||26</item> <item>1F9E1||26</item>
<item>1F49B</item> <item>1F49B</item>
@ -164,18 +193,22 @@
<array <array
name="emoji_people_body" name="emoji_people_body"
format="string" format="string">
>
<item>1F44B</item> <item>1F44B</item>
<item>1F91A||24</item> <item>1F91A||24</item>
<item>1F590,FE0F||23</item> <item>1F590,FE0F||23</item>
<item>270B</item> <item>270B</item>
<item>1F596||23</item> <item>1F596||23</item>
<item>1FAF1||32</item>
<item>1FAF2||32</item>
<item>1FAF3||32</item>
<item>1FAF4||32</item>
<item>1F44C</item> <item>1F44C</item>
<item>1F90C||30</item> <item>1F90C||30</item>
<item>1F90F||29</item> <item>1F90F||29</item>
<item>270C,FE0F</item> <item>270C,FE0F</item>
<item>1F91E||24</item> <item>1F91E||24</item>
<item>1FAF0||32</item>
<item>1F91F||26</item> <item>1F91F||26</item>
<item>1F918||23</item> <item>1F918||23</item>
<item>1F919||24</item> <item>1F919||24</item>
@ -185,6 +218,7 @@
<item>1F595||23</item> <item>1F595||23</item>
<item>1F447</item> <item>1F447</item>
<item>261D,FE0F</item> <item>261D,FE0F</item>
<item>1FAF5||32</item>
<item>1F44D</item> <item>1F44D</item>
<item>1F44E</item> <item>1F44E</item>
<item>270A</item> <item>270A</item>
@ -193,6 +227,7 @@
<item>1F91C||24</item> <item>1F91C||24</item>
<item>1F44F</item> <item>1F44F</item>
<item>1F64C</item> <item>1F64C</item>
<item>1FAF6||32</item>
<item>1F450</item> <item>1F450</item>
<item>1F932||26</item> <item>1F932||26</item>
<item>1F91D||24</item> <item>1F91D||24</item>
@ -202,8 +237,8 @@
<item>1F933||24</item> <item>1F933||24</item>
<item>1F4AA</item> <item>1F4AA</item>
<item>1F9BE||29</item> <item>1F9BE||29</item>
<item>1F9B5||28</item>
<item>1F9BF||29</item> <item>1F9BF||29</item>
<item>1F9B5||28</item>
<item>1F9B6||28</item> <item>1F9B6||28</item>
<item>1F442</item> <item>1F442</item>
<item>1F9BB||29</item> <item>1F9BB||29</item>
@ -217,25 +252,32 @@
<item>1F441,FE0F||23</item> <item>1F441,FE0F||23</item>
<item>1F445</item> <item>1F445</item>
<item>1F444</item> <item>1F444</item>
<item>1FAE6||32</item>
<item>1F476</item> <item>1F476</item>
<item>1F9D2||26</item> <item>1F9D2||26</item>
<item>1F466</item> <item>1F466</item>
<item>1F467</item> <item>1F467</item>
<item>1F9D1||26</item> <item>1F9D1||26</item>
<item>1F471</item>
<item>1F468</item> <item>1F468</item>
<item>1F9D4||26</item> <item>1F9D4||26</item>
<item>1F469</item> <item>1F9D4,200D,2642,FE0F||31</item>
<item>1F468,200D,1F9B1||28</item> <item>1F9D4,200D,2640,FE0F||31</item>
<item>1F469,200D,1F9B1||28</item>
<item>1F468,200D,1F9B0||28</item> <item>1F468,200D,1F9B0||28</item>
<item>1F469,200D,1F9B0||28</item> <item>1F468,200D,1F9B1||28</item>
<item>1F471</item>
<item>1F471,200D,2642,FE0F||25</item>
<item>1F471,200D,2640,FE0F||25</item>
<item>1F468,200D,1F9B2||28</item>
<item>1F469,200D,1F9B2||28</item>
<item>1F468,200D,1F9B3||28</item> <item>1F468,200D,1F9B3||28</item>
<item>1F468,200D,1F9B2||28</item>
<item>1F469</item>
<item>1F469,200D,1F9B0||28</item>
<item>1F9D1,200D,1F9B0||30</item>
<item>1F469,200D,1F9B1||28</item>
<item>1F9D1,200D,1F9B1||30</item>
<item>1F469,200D,1F9B3||28</item> <item>1F469,200D,1F9B3||28</item>
<item>1F9D1,200D,1F9B3||30</item>
<item>1F469,200D,1F9B2||28</item>
<item>1F9D1,200D,1F9B2||30</item>
<item>1F471,200D,2640,FE0F||25</item>
<item>1F471,200D,2642,FE0F||25</item>
<item>1F9D3||26</item> <item>1F9D3||26</item>
<item>1F474</item> <item>1F474</item>
<item>1F475</item> <item>1F475</item>
@ -269,36 +311,52 @@
<item>1F937||24</item> <item>1F937||24</item>
<item>1F937,200D,2642,FE0F||25</item> <item>1F937,200D,2642,FE0F||25</item>
<item>1F937,200D,2640,FE0F||25</item> <item>1F937,200D,2640,FE0F||25</item>
<item>1F9D1,200D,2695,FE0F||30</item>
<item>1F468,200D,2695,FE0F||25</item> <item>1F468,200D,2695,FE0F||25</item>
<item>1F469,200D,2695,FE0F||25</item> <item>1F469,200D,2695,FE0F||25</item>
<item>1F9D1,200D,1F393||30</item>
<item>1F468,200D,1F393||25</item> <item>1F468,200D,1F393||25</item>
<item>1F469,200D,1F393||25</item> <item>1F469,200D,1F393||25</item>
<item>1F9D1,200D,1F3EB||30</item>
<item>1F468,200D,1F3EB||25</item> <item>1F468,200D,1F3EB||25</item>
<item>1F469,200D,1F3EB||25</item> <item>1F469,200D,1F3EB||25</item>
<item>1F9D1,200D,2696,FE0F||30</item>
<item>1F468,200D,2696,FE0F||25</item> <item>1F468,200D,2696,FE0F||25</item>
<item>1F469,200D,2696,FE0F||25</item> <item>1F469,200D,2696,FE0F||25</item>
<item>1F9D1,200D,1F33E||30</item>
<item>1F468,200D,1F33E||25</item> <item>1F468,200D,1F33E||25</item>
<item>1F469,200D,1F33E||25</item> <item>1F469,200D,1F33E||25</item>
<item>1F9D1,200D,1F373||30</item>
<item>1F468,200D,1F373||25</item> <item>1F468,200D,1F373||25</item>
<item>1F469,200D,1F373||25</item> <item>1F469,200D,1F373||25</item>
<item>1F9D1,200D,1F527||30</item>
<item>1F468,200D,1F527||25</item> <item>1F468,200D,1F527||25</item>
<item>1F469,200D,1F527||25</item> <item>1F469,200D,1F527||25</item>
<item>1F9D1,200D,1F3ED||30</item>
<item>1F468,200D,1F3ED||25</item> <item>1F468,200D,1F3ED||25</item>
<item>1F469,200D,1F3ED||25</item> <item>1F469,200D,1F3ED||25</item>
<item>1F9D1,200D,1F4BC||30</item>
<item>1F468,200D,1F4BC||25</item> <item>1F468,200D,1F4BC||25</item>
<item>1F469,200D,1F4BC||25</item> <item>1F469,200D,1F4BC||25</item>
<item>1F9D1,200D,1F52C||30</item>
<item>1F468,200D,1F52C||25</item> <item>1F468,200D,1F52C||25</item>
<item>1F469,200D,1F52C||25</item> <item>1F469,200D,1F52C||25</item>
<item>1F9D1,200D,1F4BB||30</item>
<item>1F468,200D,1F4BB||25</item> <item>1F468,200D,1F4BB||25</item>
<item>1F469,200D,1F4BB||25</item> <item>1F469,200D,1F4BB||25</item>
<item>1F9D1,200D,1F3A4||30</item>
<item>1F468,200D,1F3A4||25</item> <item>1F468,200D,1F3A4||25</item>
<item>1F469,200D,1F3A4||25</item> <item>1F469,200D,1F3A4||25</item>
<item>1F9D1,200D,1F3A8||30</item>
<item>1F468,200D,1F3A8||25</item> <item>1F468,200D,1F3A8||25</item>
<item>1F469,200D,1F3A8||25</item> <item>1F469,200D,1F3A8||25</item>
<item>1F9D1,200D,2708,FE0F||30</item>
<item>1F468,200D,2708,FE0F||25</item> <item>1F468,200D,2708,FE0F||25</item>
<item>1F469,200D,2708,FE0F||25</item> <item>1F469,200D,2708,FE0F||25</item>
<item>1F9D1,200D,1F680||30</item>
<item>1F468,200D,1F680||25</item> <item>1F468,200D,1F680||25</item>
<item>1F469,200D,1F680||25</item> <item>1F469,200D,1F680||25</item>
<item>1F9D1,200D,1F692||30</item>
<item>1F468,200D,1F692||25</item> <item>1F468,200D,1F692||25</item>
<item>1F469,200D,1F692||25</item> <item>1F469,200D,1F692||25</item>
<item>1F46E</item> <item>1F46E</item>
@ -314,6 +372,7 @@
<item>1F477</item> <item>1F477</item>
<item>1F477,200D,2642,FE0F||25</item> <item>1F477,200D,2642,FE0F||25</item>
<item>1F477,200D,2640,FE0F||25</item> <item>1F477,200D,2640,FE0F||25</item>
<item>1FAC5||32</item>
<item>1F934||24</item> <item>1F934||24</item>
<item>1F478</item> <item>1F478</item>
<item>1F473</item> <item>1F473</item>
@ -328,6 +387,8 @@
<item>1F470,200D,2642,FE0F||30</item> <item>1F470,200D,2642,FE0F||30</item>
<item>1F470,200D,2640,FE0F||30</item> <item>1F470,200D,2640,FE0F||30</item>
<item>1F930||24</item> <item>1F930||24</item>
<item>1FAC3||32</item>
<item>1FAC4||32</item>
<item>1F931||26</item> <item>1F931||26</item>
<item>1F469,200D,1F37C||30</item> <item>1F469,200D,1F37C||30</item>
<item>1F468,200D,1F37C||30</item> <item>1F468,200D,1F37C||30</item>
@ -363,6 +424,7 @@
<item>1F9DF||26</item> <item>1F9DF||26</item>
<item>1F9DF,200D,2642,FE0F||26</item> <item>1F9DF,200D,2642,FE0F||26</item>
<item>1F9DF,200D,2640,FE0F||26</item> <item>1F9DF,200D,2640,FE0F||26</item>
<item>1F9CC||32</item>
<item>1F486</item> <item>1F486</item>
<item>1F486,200D,2642,FE0F||25</item> <item>1F486,200D,2642,FE0F||25</item>
<item>1F486,200D,2640,FE0F||25</item> <item>1F486,200D,2640,FE0F||25</item>
@ -378,10 +440,13 @@
<item>1F9CE||29</item> <item>1F9CE||29</item>
<item>1F9CE,200D,2642,FE0F||29</item> <item>1F9CE,200D,2642,FE0F||29</item>
<item>1F9CE,200D,2640,FE0F||29</item> <item>1F9CE,200D,2640,FE0F||29</item>
<item>1F9D1,200D,1F9AF||30</item>
<item>1F468,200D,1F9AF||29</item> <item>1F468,200D,1F9AF||29</item>
<item>1F469,200D,1F9AF||29</item> <item>1F469,200D,1F9AF||29</item>
<item>1F9D1,200D,1F9BC||30</item>
<item>1F468,200D,1F9BC||29</item> <item>1F468,200D,1F9BC||29</item>
<item>1F469,200D,1F9BC||29</item> <item>1F469,200D,1F9BC||29</item>
<item>1F9D1,200D,1F9BD||30</item>
<item>1F468,200D,1F9BD||29</item> <item>1F468,200D,1F9BD||29</item>
<item>1F469,200D,1F9BD||29</item> <item>1F469,200D,1F9BD||29</item>
<item>1F3C3</item> <item>1F3C3</item>
@ -448,59 +513,9 @@
<item>1F6C0</item> <item>1F6C0</item>
<item>1F6CC||23</item> <item>1F6CC||23</item>
<item>1F9D1,200D,1F91D,200D,1F9D1||29</item> <item>1F9D1,200D,1F91D,200D,1F9D1||29</item>
<!--<item>1F9D1,1F3FC,200D,1F91D,200D,1F9D1,1F3FB||29</item>
<item>1F9D1,1F3FD,200D,1F91D,200D,1F9D1,1F3FB||29</item>
<item>1F9D1,1F3FD,200D,1F91D,200D,1F9D1,1F3FC||29</item>
<item>1F9D1,1F3FE,200D,1F91D,200D,1F9D1,1F3FB||29</item>
<item>1F9D1,1F3FE,200D,1F91D,200D,1F9D1,1F3FC||29</item>
<item>1F9D1,1F3FE,200D,1F91D,200D,1F9D1,1F3FD||29</item>
<item>1F9D1,1F3FF,200D,1F91D,200D,1F9D1,1F3FB||29</item>
<item>1F9D1,1F3FF,200D,1F91D,200D,1F9D1,1F3FC||29</item>
<item>1F9D1,1F3FF,200D,1F91D,200D,1F9D1,1F3FD||29</item>
<item>1F9D1,1F3FF,200D,1F91D,200D,1F9D1,1F3FE||29</item>-->
<item>1F46D</item> <item>1F46D</item>
<!--<item>1F469,1F3FC,200D,1F91D,200D,1F469,1F3FB||29</item>
<item>1F469,1F3FD,200D,1F91D,200D,1F469,1F3FB||29</item>
<item>1F469,1F3FD,200D,1F91D,200D,1F469,1F3FC||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F469,1F3FB||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F469,1F3FC||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F469,1F3FD||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F469,1F3FB||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F469,1F3FC||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F469,1F3FD||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F469,1F3FE||29</item>-->
<item>1F46B</item> <item>1F46B</item>
<!--<item>1F469,1F3FB,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F469,1F3FB,200D,1F91D,200D,1F468,1F3FD||29</item>
<item>1F469,1F3FB,200D,1F91D,200D,1F468,1F3FE||29</item>
<item>1F469,1F3FB,200D,1F91D,200D,1F468,1F3FF||29</item>
<item>1F469,1F3FC,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F469,1F3FC,200D,1F91D,200D,1F468,1F3FD||29</item>
<item>1F469,1F3FC,200D,1F91D,200D,1F468,1F3FE||29</item>
<item>1F469,1F3FC,200D,1F91D,200D,1F468,1F3FF||29</item>
<item>1F469,1F3FD,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F469,1F3FD,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F469,1F3FD,200D,1F91D,200D,1F468,1F3FE||29</item>
<item>1F469,1F3FD,200D,1F91D,200D,1F468,1F3FF||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F468,1F3FD||29</item>
<item>1F469,1F3FE,200D,1F91D,200D,1F468,1F3FF||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F468,1F3FD||29</item>
<item>1F469,1F3FF,200D,1F91D,200D,1F468,1F3FE||29</item>-->
<item>1F46C</item> <item>1F46C</item>
<!--<item>1F468,1F3FC,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F468,1F3FD,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F468,1F3FD,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F468,1F3FE,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F468,1F3FE,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F468,1F3FE,200D,1F91D,200D,1F468,1F3FD||29</item>
<item>1F468,1F3FF,200D,1F91D,200D,1F468,1F3FB||29</item>
<item>1F468,1F3FF,200D,1F91D,200D,1F468,1F3FC||29</item>
<item>1F468,1F3FF,200D,1F91D,200D,1F468,1F3FD||29</item>
<item>1F468,1F3FF,200D,1F91D,200D,1F468,1F3FE||29</item>-->
<item>1F48F</item> <item>1F48F</item>
<item>1F469,200D,2764,FE0F,200D,1F48B,200D,1F468||26</item> <item>1F469,200D,2764,FE0F,200D,1F48B,200D,1F468||26</item>
<item>1F468,200D,2764,FE0F,200D,1F48B,200D,1F468||23</item> <item>1F468,200D,2764,FE0F,200D,1F48B,200D,1F468||23</item>
@ -544,18 +559,22 @@
<array <array
name="emoji_people_body_more" name="emoji_people_body_more"
format="string" format="string">
>
<item>1F44B,1F3FB||24;1F44B,1F3FC||24;1F44B,1F3FD||24;1F44B,1F3FE||24;1F44B,1F3FF||24</item> <item>1F44B,1F3FB||24;1F44B,1F3FC||24;1F44B,1F3FD||24;1F44B,1F3FE||24;1F44B,1F3FF||24</item>
<item>1F91A,1F3FB||24;1F91A,1F3FC||24;1F91A,1F3FD||24;1F91A,1F3FE||24;1F91A,1F3FF||24</item> <item>1F91A,1F3FB||24;1F91A,1F3FC||24;1F91A,1F3FD||24;1F91A,1F3FE||24;1F91A,1F3FF||24</item>
<item>1F590,1F3FB||24;1F590,1F3FC||24;1F590,1F3FD||24;1F590,1F3FE||24;1F590,1F3FF||24</item> <item>1F590,1F3FB||24;1F590,1F3FC||24;1F590,1F3FD||24;1F590,1F3FE||24;1F590,1F3FF||24</item>
<item>270B,1F3FB||24;270B,1F3FC||24;270B,1F3FD||24;270B,1F3FE||24;270B,1F3FF||24</item> <item>270B,1F3FB||24;270B,1F3FC||24;270B,1F3FD||24;270B,1F3FE||24;270B,1F3FF||24</item>
<item>1F596,1F3FB||24;1F596,1F3FC||24;1F596,1F3FD||24;1F596,1F3FE||24;1F596,1F3FF||24</item> <item>1F596,1F3FB||24;1F596,1F3FC||24;1F596,1F3FD||24;1F596,1F3FE||24;1F596,1F3FF||24</item>
<item>1FAF1,1F3FB||32;1FAF1,1F3FC||32;1FAF1,1F3FD||32;1FAF1,1F3FE||32;1FAF1,1F3FF||32</item>
<item>1FAF2,1F3FB||32;1FAF2,1F3FC||32;1FAF2,1F3FD||32;1FAF2,1F3FE||32;1FAF2,1F3FF||32</item>
<item>1FAF3,1F3FB||32;1FAF3,1F3FC||32;1FAF3,1F3FD||32;1FAF3,1F3FE||32;1FAF3,1F3FF||32</item>
<item>1FAF4,1F3FB||32;1FAF4,1F3FC||32;1FAF4,1F3FD||32;1FAF4,1F3FE||32;1FAF4,1F3FF||32</item>
<item>1F44C,1F3FB||24;1F44C,1F3FC||24;1F44C,1F3FD||24;1F44C,1F3FE||24;1F44C,1F3FF||24</item> <item>1F44C,1F3FB||24;1F44C,1F3FC||24;1F44C,1F3FD||24;1F44C,1F3FE||24;1F44C,1F3FF||24</item>
<item>1F90C,1F3FB||30;1F90C,1F3FC||30;1F90C,1F3FD||30;1F90C,1F3FE||30;1F90C,1F3FF||30</item> <item>1F90C,1F3FB||30;1F90C,1F3FC||30;1F90C,1F3FD||30;1F90C,1F3FE||30;1F90C,1F3FF||30</item>
<item>1F90F,1F3FB||29;1F90F,1F3FC||29;1F90F,1F3FD||29;1F90F,1F3FE||29;1F90F,1F3FF||29</item> <item>1F90F,1F3FB||29;1F90F,1F3FC||29;1F90F,1F3FD||29;1F90F,1F3FE||29;1F90F,1F3FF||29</item>
<item>270C,1F3FB||24;270C,1F3FC||24;270C,1F3FD||24;270C,1F3FE||24;270C,1F3FF||24</item> <item>270C,1F3FB||24;270C,1F3FC||24;270C,1F3FD||24;270C,1F3FE||24;270C,1F3FF||24</item>
<item>1F91E,1F3FB||24;1F91E,1F3FC||24;1F91E,1F3FD||24;1F91E,1F3FE||24;1F91E,1F3FF||24</item> <item>1F91E,1F3FB||24;1F91E,1F3FC||24;1F91E,1F3FD||24;1F91E,1F3FE||24;1F91E,1F3FF||24</item>
<item>1FAF0,1F3FB||32;1FAF0,1F3FC||32;1FAF0,1F3FD||32;1FAF0,1F3FE||32;1FAF0,1F3FF||32</item>
<item>1F91F,1F3FB||26;1F91F,1F3FC||26;1F91F,1F3FD||26;1F91F,1F3FE||26;1F91F,1F3FF||26</item> <item>1F91F,1F3FB||26;1F91F,1F3FC||26;1F91F,1F3FD||26;1F91F,1F3FE||26;1F91F,1F3FF||26</item>
<item>1F918,1F3FB||24;1F918,1F3FC||24;1F918,1F3FD||24;1F918,1F3FE||24;1F918,1F3FF||24</item> <item>1F918,1F3FB||24;1F918,1F3FC||24;1F918,1F3FD||24;1F918,1F3FE||24;1F918,1F3FF||24</item>
<item>1F919,1F3FB||24;1F919,1F3FC||24;1F919,1F3FD||24;1F919,1F3FE||24;1F919,1F3FF||24</item> <item>1F919,1F3FB||24;1F919,1F3FC||24;1F919,1F3FD||24;1F919,1F3FE||24;1F919,1F3FF||24</item>
@ -565,6 +584,7 @@
<item>1F595,1F3FB||24;1F595,1F3FC||24;1F595,1F3FD||24;1F595,1F3FE||24;1F595,1F3FF||24</item> <item>1F595,1F3FB||24;1F595,1F3FC||24;1F595,1F3FD||24;1F595,1F3FE||24;1F595,1F3FF||24</item>
<item>1F447,1F3FB||24;1F447,1F3FC||24;1F447,1F3FD||24;1F447,1F3FE||24;1F447,1F3FF||24</item> <item>1F447,1F3FB||24;1F447,1F3FC||24;1F447,1F3FD||24;1F447,1F3FE||24;1F447,1F3FF||24</item>
<item>261D,1F3FB||24;261D,1F3FC||24;261D,1F3FD||24;261D,1F3FE||24;261D,1F3FF||24</item> <item>261D,1F3FB||24;261D,1F3FC||24;261D,1F3FD||24;261D,1F3FE||24;261D,1F3FF||24</item>
<item>1FAF5,1F3FB||32;1FAF5,1F3FC||32;1FAF5,1F3FD||32;1FAF5,1F3FE||32;1FAF5,1F3FF||32</item>
<item>1F44D,1F3FB||24;1F44D,1F3FC||24;1F44D,1F3FD||24;1F44D,1F3FE||24;1F44D,1F3FF||24</item> <item>1F44D,1F3FB||24;1F44D,1F3FC||24;1F44D,1F3FD||24;1F44D,1F3FE||24;1F44D,1F3FF||24</item>
<item>1F44E,1F3FB||24;1F44E,1F3FC||24;1F44E,1F3FD||24;1F44E,1F3FE||24;1F44E,1F3FF||24</item> <item>1F44E,1F3FB||24;1F44E,1F3FC||24;1F44E,1F3FD||24;1F44E,1F3FE||24;1F44E,1F3FF||24</item>
<item>270A,1F3FB||24;270A,1F3FC||24;270A,1F3FD||24;270A,1F3FE||24;270A,1F3FF||24</item> <item>270A,1F3FB||24;270A,1F3FC||24;270A,1F3FD||24;270A,1F3FE||24;270A,1F3FF||24</item>
@ -573,17 +593,18 @@
<item>1F91C,1F3FB||24;1F91C,1F3FC||24;1F91C,1F3FD||24;1F91C,1F3FE||24;1F91C,1F3FF||24</item> <item>1F91C,1F3FB||24;1F91C,1F3FC||24;1F91C,1F3FD||24;1F91C,1F3FE||24;1F91C,1F3FF||24</item>
<item>1F44F,1F3FB||24;1F44F,1F3FC||24;1F44F,1F3FD||24;1F44F,1F3FE||24;1F44F,1F3FF||24</item> <item>1F44F,1F3FB||24;1F44F,1F3FC||24;1F44F,1F3FD||24;1F44F,1F3FE||24;1F44F,1F3FF||24</item>
<item>1F64C,1F3FB||24;1F64C,1F3FC||24;1F64C,1F3FD||24;1F64C,1F3FE||24;1F64C,1F3FF||24</item> <item>1F64C,1F3FB||24;1F64C,1F3FC||24;1F64C,1F3FD||24;1F64C,1F3FE||24;1F64C,1F3FF||24</item>
<item>1FAF6,1F3FB||32;1FAF6,1F3FC||32;1FAF6,1F3FD||32;1FAF6,1F3FE||32;1FAF6,1F3FF||32</item>
<item>1F450,1F3FB||24;1F450,1F3FC||24;1F450,1F3FD||24;1F450,1F3FE||24;1F450,1F3FF||24</item> <item>1F450,1F3FB||24;1F450,1F3FC||24;1F450,1F3FD||24;1F450,1F3FE||24;1F450,1F3FF||24</item>
<item>1F932,1F3FB||26;1F932,1F3FC||26;1F932,1F3FD||26;1F932,1F3FE||26;1F932,1F3FF||26</item> <item>1F932,1F3FB||26;1F932,1F3FC||26;1F932,1F3FD||26;1F932,1F3FE||26;1F932,1F3FF||26</item>
<item/> <item>1F91D,1F3FB||25;1F91D,1F3FC||25;1F91D,1F3FD||25;1F91D,1F3FE||25;1F91D,1F3FF||25</item>
<item>1F64F,1F3FB||24;1F64F,1F3FC||24;1F64F,1F3FD||24;1F64F,1F3FE||24;1F64F,1F3FF||24</item> <item>1F64F,1F3FB||24;1F64F,1F3FC||24;1F64F,1F3FD||24;1F64F,1F3FE||24;1F64F,1F3FF||24</item>
<item>270D,1F3FB||24;270D,1F3FC||24;270D,1F3FD||24;270D,1F3FE||24;270D,1F3FF||24</item> <item>270D,1F3FB||24;270D,1F3FC||24;270D,1F3FD||24;270D,1F3FE||24;270D,1F3FF||24</item>
<item>1F485,1F3FB||24;1F485,1F3FC||24;1F485,1F3FD||24;1F485,1F3FE||24;1F485,1F3FF||24</item> <item>1F485,1F3FB||24;1F485,1F3FC||24;1F485,1F3FD||24;1F485,1F3FE||24;1F485,1F3FF||24</item>
<item>1F933,1F3FB||24;1F933,1F3FC||24;1F933,1F3FD||24;1F933,1F3FE||24;1F933,1F3FF||24</item> <item>1F933,1F3FB||24;1F933,1F3FC||24;1F933,1F3FD||24;1F933,1F3FE||24;1F933,1F3FF||24</item>
<item>1F4AA,1F3FB||24;1F4AA,1F3FC||24;1F4AA,1F3FD||24;1F4AA,1F3FE||24;1F4AA,1F3FF||24;</item> <item>1F4AA,1F3FB||24;1F4AA,1F3FC||24;1F4AA,1F3FD||24;1F4AA,1F3FE||24;1F4AA,1F3FF||24</item>
<item/>
<item/> <item/>
<item>1F9B5,1F3FB||28;1F9B5,1F3FC||28;1F9B5,1F3FD||28;1F9B5,1F3FE||28;1F9B5,1F3FF||28</item> <item>1F9B5,1F3FB||28;1F9B5,1F3FC||28;1F9B5,1F3FD||28;1F9B5,1F3FE||28;1F9B5,1F3FF||28</item>
<item/>
<item>1F9B6,1F3FB||28;1F9B6,1F3FC||28;1F9B6,1F3FD||28;1F9B6,1F3FE||28;1F9B6,1F3FF||28</item> <item>1F9B6,1F3FB||28;1F9B6,1F3FC||28;1F9B6,1F3FD||28;1F9B6,1F3FE||28;1F9B6,1F3FF||28</item>
<item>1F442,1F3FB||24;1F442,1F3FC||24;1F442,1F3FD||24;1F442,1F3FE||24;1F442,1F3FF||24</item> <item>1F442,1F3FB||24;1F442,1F3FC||24;1F442,1F3FD||24;1F442,1F3FE||24;1F442,1F3FF||24</item>
<item>1F9BB,1F3FB||29;1F9BB,1F3FC||29;1F9BB,1F3FD||29;1F9BB,1F3FE||29;1F9BB,1F3FF||29</item> <item>1F9BB,1F3FB||29;1F9BB,1F3FC||29;1F9BB,1F3FD||29;1F9BB,1F3FE||29;1F9BB,1F3FF||29</item>
@ -597,25 +618,32 @@
<item/> <item/>
<item/> <item/>
<item/> <item/>
<item/>
<item>1F476,1F3FB||24;1F476,1F3FC||24;1F476,1F3FD||24;1F476,1F3FE||24;1F476,1F3FF||24</item> <item>1F476,1F3FB||24;1F476,1F3FC||24;1F476,1F3FD||24;1F476,1F3FE||24;1F476,1F3FF||24</item>
<item>1F9D2,1F3FB||26;1F9D2,1F3FC||26;1F9D2,1F3FD||26;1F9D2,1F3FE||26;1F9D2,1F3FF||26</item> <item>1F9D2,1F3FB||26;1F9D2,1F3FC||26;1F9D2,1F3FD||26;1F9D2,1F3FE||26;1F9D2,1F3FF||26</item>
<item>1F466,1F3FB||24;1F466,1F3FC||24;1F466,1F3FD||24;1F466,1F3FE||24;1F466,1F3FF||24</item> <item>1F466,1F3FB||24;1F466,1F3FC||24;1F466,1F3FD||24;1F466,1F3FE||24;1F466,1F3FF||24</item>
<item>1F467,1F3FB||24;1F467,1F3FC||24;1F467,1F3FD||24;1F467,1F3FE||24;1F467,1F3FF||24</item> <item>1F467,1F3FB||24;1F467,1F3FC||24;1F467,1F3FD||24;1F467,1F3FE||24;1F467,1F3FF||24</item>
<item>1F9D1,1F3FB||26;1F9D1,1F3FC||26;1F9D1,1F3FD||26;1F9D1,1F3FE||26;1F9D1,1F3FF||26</item> <item>1F9D1,1F3FB||26;1F9D1,1F3FC||26;1F9D1,1F3FD||26;1F9D1,1F3FE||26;1F9D1,1F3FF||26</item>
<item>1F471,1F3FB||24;1F471,1F3FC||24;1F471,1F3FD||24;1F471,1F3FE||24;1F471,1F3FF||24</item>
<item>1F468,1F3FB||24;1F468,1F3FC||24;1F468,1F3FD||24;1F468,1F3FE||24;1F468,1F3FF||24</item> <item>1F468,1F3FB||24;1F468,1F3FC||24;1F468,1F3FD||24;1F468,1F3FE||24;1F468,1F3FF||24</item>
<item>1F9D4,1F3FB||26;1F9D4,1F3FC||26;1F9D4,1F3FD||26;1F9D4,1F3FE||26;1F9D4,1F3FF||26</item> <item>1F9D4,1F3FB||26;1F9D4,1F3FC||26;1F9D4,1F3FD||26;1F9D4,1F3FE||26;1F9D4,1F3FF||26</item>
<item>1F469,1F3FB||24;1F469,1F3FC||24;1F469,1F3FD||24;1F469,1F3FE||24;1F469,1F3FF||24</item> <item>1F9D4,1F3FB,200D,2642,FE0F||31;1F9D4,1F3FC,200D,2642,FE0F||31;1F9D4,1F3FD,200D,2642,FE0F||31;1F9D4,1F3FE,200D,2642,FE0F||31;1F9D4,1F3FF,200D,2642,FE0F||31</item>
<item>1F468,1F3FB,200D,1F9B1||28;1F468,1F3FC,200D,1F9B1||28;1F468,1F3FD,200D,1F9B1||28;1F468,1F3FE,200D,1F9B1||28;1F468,1F3FF,200D,1F9B1||28</item> <item>1F9D4,1F3FB,200D,2640,FE0F||31;1F9D4,1F3FC,200D,2640,FE0F||31;1F9D4,1F3FD,200D,2640,FE0F||31;1F9D4,1F3FE,200D,2640,FE0F||31;1F9D4,1F3FF,200D,2640,FE0F||31</item>
<item>1F469,1F3FB,200D,1F9B1||28;1F469,1F3FC,200D,1F9B1||28;1F469,1F3FD,200D,1F9B1||28;1F469,1F3FE,200D,1F9B1||28;1F469,1F3FF,200D,1F9B1||28</item>
<item>1F468,1F3FB,200D,1F9B0||28;1F468,1F3FC,200D,1F9B0||28;1F468,1F3FD,200D,1F9B0||28;1F468,1F3FE,200D,1F9B0||28;1F468,1F3FF,200D,1F9B0||28</item> <item>1F468,1F3FB,200D,1F9B0||28;1F468,1F3FC,200D,1F9B0||28;1F468,1F3FD,200D,1F9B0||28;1F468,1F3FE,200D,1F9B0||28;1F468,1F3FF,200D,1F9B0||28</item>
<item>1F469,1F3FB,200D,1F9B0||28;1F469,1F3FC,200D,1F9B0||28;1F469,1F3FD,200D,1F9B0||28;1F469,1F3FE,200D,1F9B0||28;1F469,1F3FF,200D,1F9B0||28</item> <item>1F468,1F3FB,200D,1F9B1||28;1F468,1F3FC,200D,1F9B1||28;1F468,1F3FD,200D,1F9B1||28;1F468,1F3FE,200D,1F9B1||28;1F468,1F3FF,200D,1F9B1||28</item>
<item>1F471,1F3FB||24;1F471,1F3FC||24;1F471,1F3FD||24;1F471,1F3FE||24;1F471,1F3FF||24</item>
<item>1F471,1F3FB,200D,2642,FE0F||25;1F471,1F3FC,200D,2642,FE0F||25;1F471,1F3FD,200D,2642,FE0F||25;1F471,1F3FE,200D,2642,FE0F||25;1F471,1F3FF,200D,2642,FE0F||25</item>
<item>1F471,1F3FB,200D,2640,FE0F||25;1F471,1F3FC,200D,2640,FE0F||25;1F471,1F3FD,200D,2640,FE0F||25;1F471,1F3FE,200D,2640,FE0F||25;1F471,1F3FF,200D,2640,FE0F||25</item>
<item>1F468,1F3FB,200D,1F9B2||28;1F468,1F3FC,200D,1F9B2||28;1F468,1F3FD,200D,1F9B2||28;1F468,1F3FE,200D,1F9B2||28;1F468,1F3FF,200D,1F9B2||28</item>
<item>1F469,1F3FB,200D,1F9B2||28;1F469,1F3FC,200D,1F9B2||28;1F469,1F3FD,200D,1F9B2||28;1F469,1F3FE,200D,1F9B2||28;1F469,1F3FF,200D,1F9B2||28</item>
<item>1F468,1F3FB,200D,1F9B3||28;1F468,1F3FC,200D,1F9B3||28;1F468,1F3FD,200D,1F9B3||28;1F468,1F3FE,200D,1F9B3||28;1F468,1F3FF,200D,1F9B3||28</item> <item>1F468,1F3FB,200D,1F9B3||28;1F468,1F3FC,200D,1F9B3||28;1F468,1F3FD,200D,1F9B3||28;1F468,1F3FE,200D,1F9B3||28;1F468,1F3FF,200D,1F9B3||28</item>
<item>1F468,1F3FB,200D,1F9B2||28;1F468,1F3FC,200D,1F9B2||28;1F468,1F3FD,200D,1F9B2||28;1F468,1F3FE,200D,1F9B2||28;1F468,1F3FF,200D,1F9B2||28</item>
<item>1F469,1F3FB||24;1F469,1F3FC||24;1F469,1F3FD||24;1F469,1F3FE||24;1F469,1F3FF||24</item>
<item>1F469,1F3FB,200D,1F9B0||28;1F469,1F3FC,200D,1F9B0||28;1F469,1F3FD,200D,1F9B0||28;1F469,1F3FE,200D,1F9B0||28;1F469,1F3FF,200D,1F9B0||28</item>
<item>1F9D1,1F3FB,200D,1F9B0||30;1F9D1,1F3FC,200D,1F9B0||30;1F9D1,1F3FD,200D,1F9B0||30;1F9D1,1F3FE,200D,1F9B0||30;1F9D1,1F3FF,200D,1F9B0||30</item>
<item>1F469,1F3FB,200D,1F9B1||28;1F469,1F3FC,200D,1F9B1||28;1F469,1F3FD,200D,1F9B1||28;1F469,1F3FE,200D,1F9B1||28;1F469,1F3FF,200D,1F9B1||28</item>
<item>1F9D1,1F3FB,200D,1F9B1||30;1F9D1,1F3FC,200D,1F9B1||30;1F9D1,1F3FD,200D,1F9B1||30;1F9D1,1F3FE,200D,1F9B1||30;1F9D1,1F3FF,200D,1F9B1||30</item>
<item>1F469,1F3FB,200D,1F9B3||28;1F469,1F3FC,200D,1F9B3||28;1F469,1F3FD,200D,1F9B3||28;1F469,1F3FE,200D,1F9B3||28;1F469,1F3FF,200D,1F9B3||28</item> <item>1F469,1F3FB,200D,1F9B3||28;1F469,1F3FC,200D,1F9B3||28;1F469,1F3FD,200D,1F9B3||28;1F469,1F3FE,200D,1F9B3||28;1F469,1F3FF,200D,1F9B3||28</item>
<item>1F9D1,1F3FB,200D,1F9B3||30;1F9D1,1F3FC,200D,1F9B3||30;1F9D1,1F3FD,200D,1F9B3||30;1F9D1,1F3FE,200D,1F9B3||30;1F9D1,1F3FF,200D,1F9B3||30</item>
<item>1F469,1F3FB,200D,1F9B2||28;1F469,1F3FC,200D,1F9B2||28;1F469,1F3FD,200D,1F9B2||28;1F469,1F3FE,200D,1F9B2||28;1F469,1F3FF,200D,1F9B2||28</item>
<item>1F9D1,1F3FB,200D,1F9B2||30;1F9D1,1F3FC,200D,1F9B2||30;1F9D1,1F3FD,200D,1F9B2||30;1F9D1,1F3FE,200D,1F9B2||30;1F9D1,1F3FF,200D,1F9B2||30</item>
<item>1F471,1F3FB,200D,2640,FE0F||25;1F471,1F3FC,200D,2640,FE0F||25;1F471,1F3FD,200D,2640,FE0F||25;1F471,1F3FE,200D,2640,FE0F||25;1F471,1F3FF,200D,2640,FE0F||25</item>
<item>1F471,1F3FB,200D,2642,FE0F||25;1F471,1F3FC,200D,2642,FE0F||25;1F471,1F3FD,200D,2642,FE0F||25;1F471,1F3FE,200D,2642,FE0F||25;1F471,1F3FF,200D,2642,FE0F||25</item>
<item>1F9D3,1F3FB||26;1F9D3,1F3FC||26;1F9D3,1F3FD||26;1F9D3,1F3FE||26;1F9D3,1F3FF||26</item> <item>1F9D3,1F3FB||26;1F9D3,1F3FC||26;1F9D3,1F3FD||26;1F9D3,1F3FE||26;1F9D3,1F3FF||26</item>
<item>1F474,1F3FB||24;1F474,1F3FC||24;1F474,1F3FD||24;1F474,1F3FE||24;1F474,1F3FF||24</item> <item>1F474,1F3FB||24;1F474,1F3FC||24;1F474,1F3FD||24;1F474,1F3FE||24;1F474,1F3FF||24</item>
<item>1F475,1F3FB||24;1F475,1F3FC||24;1F475,1F3FD||24;1F475,1F3FE||24;1F475,1F3FF||24</item> <item>1F475,1F3FB||24;1F475,1F3FC||24;1F475,1F3FD||24;1F475,1F3FE||24;1F475,1F3FF||24</item>
@ -649,36 +677,52 @@
<item>1F937,1F3FB||24;1F937,1F3FC||24;1F937,1F3FD||24;1F937,1F3FE||24;1F937,1F3FF||24</item> <item>1F937,1F3FB||24;1F937,1F3FC||24;1F937,1F3FD||24;1F937,1F3FE||24;1F937,1F3FF||24</item>
<item>1F937,1F3FB,200D,2642,FE0F||25;1F937,1F3FC,200D,2642,FE0F||25;1F937,1F3FD,200D,2642,FE0F||25;1F937,1F3FE,200D,2642,FE0F||25;1F937,1F3FF,200D,2642,FE0F||25</item> <item>1F937,1F3FB,200D,2642,FE0F||25;1F937,1F3FC,200D,2642,FE0F||25;1F937,1F3FD,200D,2642,FE0F||25;1F937,1F3FE,200D,2642,FE0F||25;1F937,1F3FF,200D,2642,FE0F||25</item>
<item>1F937,1F3FB,200D,2640,FE0F||25;1F937,1F3FC,200D,2640,FE0F||25;1F937,1F3FD,200D,2640,FE0F||25;1F937,1F3FE,200D,2640,FE0F||25;1F937,1F3FF,200D,2640,FE0F||25</item> <item>1F937,1F3FB,200D,2640,FE0F||25;1F937,1F3FC,200D,2640,FE0F||25;1F937,1F3FD,200D,2640,FE0F||25;1F937,1F3FE,200D,2640,FE0F||25;1F937,1F3FF,200D,2640,FE0F||25</item>
<item>1F9D1,1F3FB,200D,2695,FE0F||30;1F9D1,1F3FC,200D,2695,FE0F||30;1F9D1,1F3FD,200D,2695,FE0F||30;1F9D1,1F3FE,200D,2695,FE0F||30;1F9D1,1F3FF,200D,2695,FE0F||30</item>
<item>1F468,1F3FB,200D,2695,FE0F||25;1F468,1F3FC,200D,2695,FE0F||25;1F468,1F3FD,200D,2695,FE0F||25;1F468,1F3FE,200D,2695,FE0F||25;1F468,1F3FF,200D,2695,FE0F||25</item> <item>1F468,1F3FB,200D,2695,FE0F||25;1F468,1F3FC,200D,2695,FE0F||25;1F468,1F3FD,200D,2695,FE0F||25;1F468,1F3FE,200D,2695,FE0F||25;1F468,1F3FF,200D,2695,FE0F||25</item>
<item>1F469,1F3FB,200D,2695,FE0F||25;1F469,1F3FC,200D,2695,FE0F||25;1F469,1F3FD,200D,2695,FE0F||25;1F469,1F3FE,200D,2695,FE0F||25;1F469,1F3FF,200D,2695,FE0F||25</item> <item>1F469,1F3FB,200D,2695,FE0F||25;1F469,1F3FC,200D,2695,FE0F||25;1F469,1F3FD,200D,2695,FE0F||25;1F469,1F3FE,200D,2695,FE0F||25;1F469,1F3FF,200D,2695,FE0F||25</item>
<item>1F9D1,1F3FB,200D,1F393||30;1F9D1,1F3FC,200D,1F393||30;1F9D1,1F3FD,200D,1F393||30;1F9D1,1F3FE,200D,1F393||30;1F9D1,1F3FF,200D,1F393||30</item>
<item>1F468,1F3FB,200D,1F393||25;1F468,1F3FC,200D,1F393||25;1F468,1F3FD,200D,1F393||25;1F468,1F3FE,200D,1F393||25;1F468,1F3FF,200D,1F393||25</item> <item>1F468,1F3FB,200D,1F393||25;1F468,1F3FC,200D,1F393||25;1F468,1F3FD,200D,1F393||25;1F468,1F3FE,200D,1F393||25;1F468,1F3FF,200D,1F393||25</item>
<item>1F469,1F3FB,200D,1F393||25;1F469,1F3FC,200D,1F393||25;1F469,1F3FD,200D,1F393||25;1F469,1F3FE,200D,1F393||25;1F469,1F3FF,200D,1F393||25</item> <item>1F469,1F3FB,200D,1F393||25;1F469,1F3FC,200D,1F393||25;1F469,1F3FD,200D,1F393||25;1F469,1F3FE,200D,1F393||25;1F469,1F3FF,200D,1F393||25</item>
<item>1F9D1,1F3FB,200D,1F3EB||30;1F9D1,1F3FC,200D,1F3EB||30;1F9D1,1F3FD,200D,1F3EB||30;1F9D1,1F3FE,200D,1F3EB||30;1F9D1,1F3FF,200D,1F3EB||30</item>
<item>1F468,1F3FB,200D,1F3EB||25;1F468,1F3FC,200D,1F3EB||25;1F468,1F3FD,200D,1F3EB||25;1F468,1F3FE,200D,1F3EB||25;1F468,1F3FF,200D,1F3EB||25</item> <item>1F468,1F3FB,200D,1F3EB||25;1F468,1F3FC,200D,1F3EB||25;1F468,1F3FD,200D,1F3EB||25;1F468,1F3FE,200D,1F3EB||25;1F468,1F3FF,200D,1F3EB||25</item>
<item>1F469,1F3FB,200D,1F3EB||25;1F469,1F3FC,200D,1F3EB||25;1F469,1F3FD,200D,1F3EB||25;1F469,1F3FE,200D,1F3EB||25;1F469,1F3FF,200D,1F3EB||25</item> <item>1F469,1F3FB,200D,1F3EB||25;1F469,1F3FC,200D,1F3EB||25;1F469,1F3FD,200D,1F3EB||25;1F469,1F3FE,200D,1F3EB||25;1F469,1F3FF,200D,1F3EB||25</item>
<item>1F9D1,1F3FB,200D,2696,FE0F||30;1F9D1,1F3FC,200D,2696,FE0F||30;1F9D1,1F3FD,200D,2696,FE0F||30;1F9D1,1F3FE,200D,2696,FE0F||30;1F9D1,1F3FF,200D,2696,FE0F||30</item>
<item>1F468,1F3FB,200D,2696,FE0F||25;1F468,1F3FC,200D,2696,FE0F||25;1F468,1F3FD,200D,2696,FE0F||25;1F468,1F3FE,200D,2696,FE0F||25;1F468,1F3FF,200D,2696,FE0F||25</item> <item>1F468,1F3FB,200D,2696,FE0F||25;1F468,1F3FC,200D,2696,FE0F||25;1F468,1F3FD,200D,2696,FE0F||25;1F468,1F3FE,200D,2696,FE0F||25;1F468,1F3FF,200D,2696,FE0F||25</item>
<item>1F469,1F3FB,200D,2696,FE0F||25;1F469,1F3FC,200D,2696,FE0F||25;1F469,1F3FD,200D,2696,FE0F||25;1F469,1F3FE,200D,2696,FE0F||25;1F469,1F3FF,200D,2696,FE0F||25</item> <item>1F469,1F3FB,200D,2696,FE0F||25;1F469,1F3FC,200D,2696,FE0F||25;1F469,1F3FD,200D,2696,FE0F||25;1F469,1F3FE,200D,2696,FE0F||25;1F469,1F3FF,200D,2696,FE0F||25</item>
<item>1F9D1,1F3FB,200D,1F33E||30;1F9D1,1F3FC,200D,1F33E||30;1F9D1,1F3FD,200D,1F33E||30;1F9D1,1F3FE,200D,1F33E||30;1F9D1,1F3FF,200D,1F33E||30</item>
<item>1F468,1F3FB,200D,1F33E||25;1F468,1F3FC,200D,1F33E||25;1F468,1F3FD,200D,1F33E||25;1F468,1F3FE,200D,1F33E||25;1F468,1F3FF,200D,1F33E||25</item> <item>1F468,1F3FB,200D,1F33E||25;1F468,1F3FC,200D,1F33E||25;1F468,1F3FD,200D,1F33E||25;1F468,1F3FE,200D,1F33E||25;1F468,1F3FF,200D,1F33E||25</item>
<item>1F469,1F3FB,200D,1F33E||25;1F469,1F3FC,200D,1F33E||25;1F469,1F3FD,200D,1F33E||25;1F469,1F3FE,200D,1F33E||25;1F469,1F3FF,200D,1F33E||25</item> <item>1F469,1F3FB,200D,1F33E||25;1F469,1F3FC,200D,1F33E||25;1F469,1F3FD,200D,1F33E||25;1F469,1F3FE,200D,1F33E||25;1F469,1F3FF,200D,1F33E||25</item>
<item>1F9D1,1F3FB,200D,1F373||30;1F9D1,1F3FC,200D,1F373||30;1F9D1,1F3FD,200D,1F373||30;1F9D1,1F3FE,200D,1F373||30;1F9D1,1F3FF,200D,1F373||30</item>
<item>1F468,1F3FB,200D,1F373||25;1F468,1F3FC,200D,1F373||25;1F468,1F3FD,200D,1F373||25;1F468,1F3FE,200D,1F373||25;1F468,1F3FF,200D,1F373||25</item> <item>1F468,1F3FB,200D,1F373||25;1F468,1F3FC,200D,1F373||25;1F468,1F3FD,200D,1F373||25;1F468,1F3FE,200D,1F373||25;1F468,1F3FF,200D,1F373||25</item>
<item>1F469,1F3FB,200D,1F373||25;1F469,1F3FC,200D,1F373||25;1F469,1F3FD,200D,1F373||25;1F469,1F3FE,200D,1F373||25;1F469,1F3FF,200D,1F373||25</item> <item>1F469,1F3FB,200D,1F373||25;1F469,1F3FC,200D,1F373||25;1F469,1F3FD,200D,1F373||25;1F469,1F3FE,200D,1F373||25;1F469,1F3FF,200D,1F373||25</item>
<item>1F9D1,1F3FB,200D,1F527||30;1F9D1,1F3FC,200D,1F527||30;1F9D1,1F3FD,200D,1F527||30;1F9D1,1F3FE,200D,1F527||30;1F9D1,1F3FF,200D,1F527||30</item>
<item>1F468,1F3FB,200D,1F527||25;1F468,1F3FC,200D,1F527||25;1F468,1F3FD,200D,1F527||25;1F468,1F3FE,200D,1F527||25;1F468,1F3FF,200D,1F527||25</item> <item>1F468,1F3FB,200D,1F527||25;1F468,1F3FC,200D,1F527||25;1F468,1F3FD,200D,1F527||25;1F468,1F3FE,200D,1F527||25;1F468,1F3FF,200D,1F527||25</item>
<item>1F469,1F3FB,200D,1F527||25;1F469,1F3FC,200D,1F527||25;1F469,1F3FD,200D,1F527||25;1F469,1F3FE,200D,1F527||25;1F469,1F3FF,200D,1F527||25</item> <item>1F469,1F3FB,200D,1F527||25;1F469,1F3FC,200D,1F527||25;1F469,1F3FD,200D,1F527||25;1F469,1F3FE,200D,1F527||25;1F469,1F3FF,200D,1F527||25</item>
<item>1F9D1,1F3FB,200D,1F3ED||30;1F9D1,1F3FC,200D,1F3ED||30;1F9D1,1F3FD,200D,1F3ED||30;1F9D1,1F3FE,200D,1F3ED||30;1F9D1,1F3FF,200D,1F3ED||30</item>
<item>1F468,1F3FB,200D,1F3ED||25;1F468,1F3FC,200D,1F3ED||25;1F468,1F3FD,200D,1F3ED||25;1F468,1F3FE,200D,1F3ED||25;1F468,1F3FF,200D,1F3ED||25</item> <item>1F468,1F3FB,200D,1F3ED||25;1F468,1F3FC,200D,1F3ED||25;1F468,1F3FD,200D,1F3ED||25;1F468,1F3FE,200D,1F3ED||25;1F468,1F3FF,200D,1F3ED||25</item>
<item>1F469,1F3FB,200D,1F3ED||25;1F469,1F3FC,200D,1F3ED||25;1F469,1F3FD,200D,1F3ED||25;1F469,1F3FE,200D,1F3ED||25;1F469,1F3FF,200D,1F3ED||25</item> <item>1F469,1F3FB,200D,1F3ED||25;1F469,1F3FC,200D,1F3ED||25;1F469,1F3FD,200D,1F3ED||25;1F469,1F3FE,200D,1F3ED||25;1F469,1F3FF,200D,1F3ED||25</item>
<item>1F9D1,1F3FB,200D,1F4BC||30;1F9D1,1F3FC,200D,1F4BC||30;1F9D1,1F3FD,200D,1F4BC||30;1F9D1,1F3FE,200D,1F4BC||30;1F9D1,1F3FF,200D,1F4BC||30</item>
<item>1F468,1F3FB,200D,1F4BC||25;1F468,1F3FC,200D,1F4BC||25;1F468,1F3FD,200D,1F4BC||25;1F468,1F3FE,200D,1F4BC||25;1F468,1F3FF,200D,1F4BC||25</item> <item>1F468,1F3FB,200D,1F4BC||25;1F468,1F3FC,200D,1F4BC||25;1F468,1F3FD,200D,1F4BC||25;1F468,1F3FE,200D,1F4BC||25;1F468,1F3FF,200D,1F4BC||25</item>
<item>1F469,1F3FB,200D,1F4BC||25;1F469,1F3FC,200D,1F4BC||25;1F469,1F3FD,200D,1F4BC||25;1F469,1F3FE,200D,1F4BC||25;1F469,1F3FF,200D,1F4BC||25</item> <item>1F469,1F3FB,200D,1F4BC||25;1F469,1F3FC,200D,1F4BC||25;1F469,1F3FD,200D,1F4BC||25;1F469,1F3FE,200D,1F4BC||25;1F469,1F3FF,200D,1F4BC||25</item>
<item>1F9D1,1F3FB,200D,1F52C||30;1F9D1,1F3FC,200D,1F52C||30;1F9D1,1F3FD,200D,1F52C||30;1F9D1,1F3FE,200D,1F52C||30;1F9D1,1F3FF,200D,1F52C||30</item>
<item>1F468,1F3FB,200D,1F52C||25;1F468,1F3FC,200D,1F52C||25;1F468,1F3FD,200D,1F52C||25;1F468,1F3FE,200D,1F52C||25;1F468,1F3FF,200D,1F52C||25</item> <item>1F468,1F3FB,200D,1F52C||25;1F468,1F3FC,200D,1F52C||25;1F468,1F3FD,200D,1F52C||25;1F468,1F3FE,200D,1F52C||25;1F468,1F3FF,200D,1F52C||25</item>
<item>1F469,1F3FB,200D,1F52C||25;1F469,1F3FC,200D,1F52C||25;1F469,1F3FD,200D,1F52C||25;1F469,1F3FE,200D,1F52C||25;1F469,1F3FF,200D,1F52C||25</item> <item>1F469,1F3FB,200D,1F52C||25;1F469,1F3FC,200D,1F52C||25;1F469,1F3FD,200D,1F52C||25;1F469,1F3FE,200D,1F52C||25;1F469,1F3FF,200D,1F52C||25</item>
<item>1F9D1,1F3FB,200D,1F4BB||30;1F9D1,1F3FC,200D,1F4BB||30;1F9D1,1F3FD,200D,1F4BB||30;1F9D1,1F3FE,200D,1F4BB||30;1F9D1,1F3FF,200D,1F4BB||30</item>
<item>1F468,1F3FB,200D,1F4BB||25;1F468,1F3FC,200D,1F4BB||25;1F468,1F3FD,200D,1F4BB||25;1F468,1F3FE,200D,1F4BB||25;1F468,1F3FF,200D,1F4BB||25</item> <item>1F468,1F3FB,200D,1F4BB||25;1F468,1F3FC,200D,1F4BB||25;1F468,1F3FD,200D,1F4BB||25;1F468,1F3FE,200D,1F4BB||25;1F468,1F3FF,200D,1F4BB||25</item>
<item>1F469,1F3FB,200D,1F4BB||25;1F469,1F3FC,200D,1F4BB||25;1F469,1F3FD,200D,1F4BB||25;1F469,1F3FE,200D,1F4BB||25;1F469,1F3FF,200D,1F4BB||25</item> <item>1F469,1F3FB,200D,1F4BB||25;1F469,1F3FC,200D,1F4BB||25;1F469,1F3FD,200D,1F4BB||25;1F469,1F3FE,200D,1F4BB||25;1F469,1F3FF,200D,1F4BB||25</item>
<item>1F9D1,1F3FB,200D,1F3A4||30;1F9D1,1F3FC,200D,1F3A4||30;1F9D1,1F3FD,200D,1F3A4||30;1F9D1,1F3FE,200D,1F3A4||30;1F9D1,1F3FF,200D,1F3A4||30</item>
<item>1F468,1F3FB,200D,1F3A4||25;1F468,1F3FC,200D,1F3A4||25;1F468,1F3FD,200D,1F3A4||25;1F468,1F3FE,200D,1F3A4||25;1F468,1F3FF,200D,1F3A4||25</item> <item>1F468,1F3FB,200D,1F3A4||25;1F468,1F3FC,200D,1F3A4||25;1F468,1F3FD,200D,1F3A4||25;1F468,1F3FE,200D,1F3A4||25;1F468,1F3FF,200D,1F3A4||25</item>
<item>1F469,1F3FB,200D,1F3A4||25;1F469,1F3FC,200D,1F3A4||25;1F469,1F3FD,200D,1F3A4||25;1F469,1F3FE,200D,1F3A4||25;1F469,1F3FF,200D,1F3A4||25</item> <item>1F469,1F3FB,200D,1F3A4||25;1F469,1F3FC,200D,1F3A4||25;1F469,1F3FD,200D,1F3A4||25;1F469,1F3FE,200D,1F3A4||25;1F469,1F3FF,200D,1F3A4||25</item>
<item>1F9D1,1F3FB,200D,1F3A8||30;1F9D1,1F3FC,200D,1F3A8||30;1F9D1,1F3FD,200D,1F3A8||30;1F9D1,1F3FE,200D,1F3A8||30;1F9D1,1F3FF,200D,1F3A8||30</item>
<item>1F468,1F3FB,200D,1F3A8||25;1F468,1F3FC,200D,1F3A8||25;1F468,1F3FD,200D,1F3A8||25;1F468,1F3FE,200D,1F3A8||25;1F468,1F3FF,200D,1F3A8||25</item> <item>1F468,1F3FB,200D,1F3A8||25;1F468,1F3FC,200D,1F3A8||25;1F468,1F3FD,200D,1F3A8||25;1F468,1F3FE,200D,1F3A8||25;1F468,1F3FF,200D,1F3A8||25</item>
<item>1F469,1F3FB,200D,1F3A8||25;1F469,1F3FC,200D,1F3A8||25;1F469,1F3FD,200D,1F3A8||25;1F469,1F3FE,200D,1F3A8||25;1F469,1F3FF,200D,1F3A8||25</item> <item>1F469,1F3FB,200D,1F3A8||25;1F469,1F3FC,200D,1F3A8||25;1F469,1F3FD,200D,1F3A8||25;1F469,1F3FE,200D,1F3A8||25;1F469,1F3FF,200D,1F3A8||25</item>
<item>1F9D1,1F3FB,200D,2708,FE0F||30;1F9D1,1F3FC,200D,2708,FE0F||30;1F9D1,1F3FD,200D,2708,FE0F||30;1F9D1,1F3FE,200D,2708,FE0F||30;1F9D1,1F3FF,200D,2708,FE0F||30</item>
<item>1F468,1F3FB,200D,2708,FE0F||25;1F468,1F3FC,200D,2708,FE0F||25;1F468,1F3FD,200D,2708,FE0F||25;1F468,1F3FE,200D,2708,FE0F||25;1F468,1F3FF,200D,2708,FE0F||25</item> <item>1F468,1F3FB,200D,2708,FE0F||25;1F468,1F3FC,200D,2708,FE0F||25;1F468,1F3FD,200D,2708,FE0F||25;1F468,1F3FE,200D,2708,FE0F||25;1F468,1F3FF,200D,2708,FE0F||25</item>
<item>1F469,1F3FB,200D,2708,FE0F||25;1F469,1F3FC,200D,2708,FE0F||25;1F469,1F3FD,200D,2708,FE0F||25;1F469,1F3FE,200D,2708,FE0F||25;1F469,1F3FF,200D,2708,FE0F||25</item> <item>1F469,1F3FB,200D,2708,FE0F||25;1F469,1F3FC,200D,2708,FE0F||25;1F469,1F3FD,200D,2708,FE0F||25;1F469,1F3FE,200D,2708,FE0F||25;1F469,1F3FF,200D,2708,FE0F||25</item>
<item>1F9D1,1F3FB,200D,1F680||30;1F9D1,1F3FC,200D,1F680||30;1F9D1,1F3FD,200D,1F680||30;1F9D1,1F3FE,200D,1F680||30;1F9D1,1F3FF,200D,1F680||30</item>
<item>1F468,1F3FB,200D,1F680||25;1F468,1F3FC,200D,1F680||25;1F468,1F3FD,200D,1F680||25;1F468,1F3FE,200D,1F680||25;1F468,1F3FF,200D,1F680||25</item> <item>1F468,1F3FB,200D,1F680||25;1F468,1F3FC,200D,1F680||25;1F468,1F3FD,200D,1F680||25;1F468,1F3FE,200D,1F680||25;1F468,1F3FF,200D,1F680||25</item>
<item>1F469,1F3FB,200D,1F680||25;1F469,1F3FC,200D,1F680||25;1F469,1F3FD,200D,1F680||25;1F469,1F3FE,200D,1F680||25;1F469,1F3FF,200D,1F680||25</item> <item>1F469,1F3FB,200D,1F680||25;1F469,1F3FC,200D,1F680||25;1F469,1F3FD,200D,1F680||25;1F469,1F3FE,200D,1F680||25;1F469,1F3FF,200D,1F680||25</item>
<item>1F9D1,1F3FB,200D,1F692||30;1F9D1,1F3FC,200D,1F692||30;1F9D1,1F3FD,200D,1F692||30;1F9D1,1F3FE,200D,1F692||30;1F9D1,1F3FF,200D,1F692||30</item>
<item>1F468,1F3FB,200D,1F692||25;1F468,1F3FC,200D,1F692||25;1F468,1F3FD,200D,1F692||25;1F468,1F3FE,200D,1F692||25;1F468,1F3FF,200D,1F692||25</item> <item>1F468,1F3FB,200D,1F692||25;1F468,1F3FC,200D,1F692||25;1F468,1F3FD,200D,1F692||25;1F468,1F3FE,200D,1F692||25;1F468,1F3FF,200D,1F692||25</item>
<item>1F469,1F3FB,200D,1F692||25;1F469,1F3FC,200D,1F692||25;1F469,1F3FD,200D,1F692||25;1F469,1F3FE,200D,1F692||25;1F469,1F3FF,200D,1F692||25</item> <item>1F469,1F3FB,200D,1F692||25;1F469,1F3FC,200D,1F692||25;1F469,1F3FD,200D,1F692||25;1F469,1F3FE,200D,1F692||25;1F469,1F3FF,200D,1F692||25</item>
<item>1F46E,1F3FB||24;1F46E,1F3FC||24;1F46E,1F3FD||24;1F46E,1F3FE||24;1F46E,1F3FF||24</item> <item>1F46E,1F3FB||24;1F46E,1F3FC||24;1F46E,1F3FD||24;1F46E,1F3FE||24;1F46E,1F3FF||24</item>
@ -694,6 +738,7 @@
<item>1F477,1F3FB||24;1F477,1F3FC||24;1F477,1F3FD||24;1F477,1F3FE||24;1F477,1F3FF||24</item> <item>1F477,1F3FB||24;1F477,1F3FC||24;1F477,1F3FD||24;1F477,1F3FE||24;1F477,1F3FF||24</item>
<item>1F477,1F3FB,200D,2642,FE0F||25;1F477,1F3FC,200D,2642,FE0F||25;1F477,1F3FD,200D,2642,FE0F||25;1F477,1F3FE,200D,2642,FE0F||25;1F477,1F3FF,200D,2642,FE0F||25</item> <item>1F477,1F3FB,200D,2642,FE0F||25;1F477,1F3FC,200D,2642,FE0F||25;1F477,1F3FD,200D,2642,FE0F||25;1F477,1F3FE,200D,2642,FE0F||25;1F477,1F3FF,200D,2642,FE0F||25</item>
<item>1F477,1F3FB,200D,2640,FE0F||25;1F477,1F3FC,200D,2640,FE0F||25;1F477,1F3FD,200D,2640,FE0F||25;1F477,1F3FE,200D,2640,FE0F||25;1F477,1F3FF,200D,2640,FE0F||25</item> <item>1F477,1F3FB,200D,2640,FE0F||25;1F477,1F3FC,200D,2640,FE0F||25;1F477,1F3FD,200D,2640,FE0F||25;1F477,1F3FE,200D,2640,FE0F||25;1F477,1F3FF,200D,2640,FE0F||25</item>
<item>1FAC5,1F3FB||32;1FAC5,1F3FC||32;1FAC5,1F3FD||32;1FAC5,1F3FE||32;1FAC5,1F3FF||32</item>
<item>1F934,1F3FB||24;1F934,1F3FC||24;1F934,1F3FD||24;1F934,1F3FE||24;1F934,1F3FF||24</item> <item>1F934,1F3FB||24;1F934,1F3FC||24;1F934,1F3FD||24;1F934,1F3FE||24;1F934,1F3FF||24</item>
<item>1F478,1F3FB||24;1F478,1F3FC||24;1F478,1F3FD||24;1F478,1F3FE||24;1F478,1F3FF||24</item> <item>1F478,1F3FB||24;1F478,1F3FC||24;1F478,1F3FD||24;1F478,1F3FE||24;1F478,1F3FF||24</item>
<item>1F473,1F3FB||24;1F473,1F3FC||24;1F473,1F3FD||24;1F473,1F3FE||24;1F473,1F3FF||24</item> <item>1F473,1F3FB||24;1F473,1F3FC||24;1F473,1F3FD||24;1F473,1F3FE||24;1F473,1F3FF||24</item>
@ -708,6 +753,8 @@
<item>1F470,1F3FB,200D,2642,FE0F||30;1F470,1F3FC,200D,2642,FE0F||30;1F470,1F3FD,200D,2642,FE0F||30;1F470,1F3FE,200D,2642,FE0F||30;1F470,1F3FF,200D,2642,FE0F||30</item> <item>1F470,1F3FB,200D,2642,FE0F||30;1F470,1F3FC,200D,2642,FE0F||30;1F470,1F3FD,200D,2642,FE0F||30;1F470,1F3FE,200D,2642,FE0F||30;1F470,1F3FF,200D,2642,FE0F||30</item>
<item>1F470,1F3FB,200D,2640,FE0F||30;1F470,1F3FC,200D,2640,FE0F||30;1F470,1F3FD,200D,2640,FE0F||30;1F470,1F3FE,200D,2640,FE0F||30;1F470,1F3FF,200D,2640,FE0F||30</item> <item>1F470,1F3FB,200D,2640,FE0F||30;1F470,1F3FC,200D,2640,FE0F||30;1F470,1F3FD,200D,2640,FE0F||30;1F470,1F3FE,200D,2640,FE0F||30;1F470,1F3FF,200D,2640,FE0F||30</item>
<item>1F930,1F3FB||24;1F930,1F3FC||24;1F930,1F3FD||24;1F930,1F3FE||24;1F930,1F3FF||24</item> <item>1F930,1F3FB||24;1F930,1F3FC||24;1F930,1F3FD||24;1F930,1F3FE||24;1F930,1F3FF||24</item>
<item>1FAC3,1F3FB||32;1FAC3,1F3FD||32;1FAC3,1F3FE||32;1FAC3,1F3FF||32</item>
<item>1FAC4,1F3FB||32;1FAC4,1F3FC||32;1FAC4,1F3FD||32;1FAC4,1F3FE||32;1FAC4,1F3FF||32</item>
<item>1F931,1F3FB||26;1F931,1F3FC||26;1F931,1F3FD||26;1F931,1F3FE||26;1F931,1F3FF||26</item> <item>1F931,1F3FB||26;1F931,1F3FC||26;1F931,1F3FD||26;1F931,1F3FE||26;1F931,1F3FF||26</item>
<item>1F469,1F3FB,200D,1F37C||30;1F469,1F3FC,200D,1F37C||30;1F469,1F3FD,200D,1F37C||30;1F469,1F3FE,200D,1F37C||30;1F469,1F3FF,200D,1F37C||30</item> <item>1F469,1F3FB,200D,1F37C||30;1F469,1F3FC,200D,1F37C||30;1F469,1F3FD,200D,1F37C||30;1F469,1F3FE,200D,1F37C||30;1F469,1F3FF,200D,1F37C||30</item>
<item>1F468,1F3FB,200D,1F37C||30;1F468,1F3FC,200D,1F37C||30;1F468,1F3FD,200D,1F37C||30;1F468,1F3FE,200D,1F37C||30;1F468,1F3FF,200D,1F37C||30</item> <item>1F468,1F3FB,200D,1F37C||30;1F468,1F3FC,200D,1F37C||30;1F468,1F3FD,200D,1F37C||30;1F468,1F3FE,200D,1F37C||30;1F468,1F3FF,200D,1F37C||30</item>
@ -743,6 +790,7 @@
<item/> <item/>
<item/> <item/>
<item/> <item/>
<item/>
<item>1F486,1F3FB||24;1F486,1F3FC||24;1F486,1F3FD||24;1F486,1F3FE||24;1F486,1F3FF||24</item> <item>1F486,1F3FB||24;1F486,1F3FC||24;1F486,1F3FD||24;1F486,1F3FE||24;1F486,1F3FF||24</item>
<item>1F486,1F3FB,200D,2642,FE0F||25;1F486,1F3FC,200D,2642,FE0F||25;1F486,1F3FD,200D,2642,FE0F||25;1F486,1F3FE,200D,2642,FE0F||25;1F486,1F3FF,200D,2642,FE0F||25</item> <item>1F486,1F3FB,200D,2642,FE0F||25;1F486,1F3FC,200D,2642,FE0F||25;1F486,1F3FD,200D,2642,FE0F||25;1F486,1F3FE,200D,2642,FE0F||25;1F486,1F3FF,200D,2642,FE0F||25</item>
<item>1F486,1F3FB,200D,2640,FE0F||25;1F486,1F3FC,200D,2640,FE0F||25;1F486,1F3FD,200D,2640,FE0F||25;1F486,1F3FE,200D,2640,FE0F||25;1F486,1F3FF,200D,2640,FE0F||25</item> <item>1F486,1F3FB,200D,2640,FE0F||25;1F486,1F3FC,200D,2640,FE0F||25;1F486,1F3FD,200D,2640,FE0F||25;1F486,1F3FE,200D,2640,FE0F||25;1F486,1F3FF,200D,2640,FE0F||25</item>
@ -758,10 +806,13 @@
<item>1F9CE,1F3FB||29;1F9CE,1F3FC||29;1F9CE,1F3FD||29;1F9CE,1F3FE||29;1F9CE,1F3FF||29</item> <item>1F9CE,1F3FB||29;1F9CE,1F3FC||29;1F9CE,1F3FD||29;1F9CE,1F3FE||29;1F9CE,1F3FF||29</item>
<item>1F9CE,1F3FB,200D,2642,FE0F||29;1F9CE,1F3FC,200D,2642,FE0F||29;1F9CE,1F3FD,200D,2642,FE0F||29;1F9CE,1F3FE,200D,2642,FE0F||29;1F9CE,1F3FF,200D,2642,FE0F||29</item> <item>1F9CE,1F3FB,200D,2642,FE0F||29;1F9CE,1F3FC,200D,2642,FE0F||29;1F9CE,1F3FD,200D,2642,FE0F||29;1F9CE,1F3FE,200D,2642,FE0F||29;1F9CE,1F3FF,200D,2642,FE0F||29</item>
<item>1F9CE,1F3FB,200D,2640,FE0F||29;1F9CE,1F3FC,200D,2640,FE0F||29;1F9CE,1F3FD,200D,2640,FE0F||29;1F9CE,1F3FE,200D,2640,FE0F||29;1F9CE,1F3FF,200D,2640,FE0F||29</item> <item>1F9CE,1F3FB,200D,2640,FE0F||29;1F9CE,1F3FC,200D,2640,FE0F||29;1F9CE,1F3FD,200D,2640,FE0F||29;1F9CE,1F3FE,200D,2640,FE0F||29;1F9CE,1F3FF,200D,2640,FE0F||29</item>
<item>1F9D1,1F3FB,200D,1F9AF||30;1F9D1,1F3FC,200D,1F9AF||30;1F9D1,1F3FD,200D,1F9AF||30;1F9D1,1F3FE,200D,1F9AF||30;1F9D1,1F3FF,200D,1F9AF||30</item>
<item>1F468,1F3FB,200D,1F9AF||29;1F468,1F3FC,200D,1F9AF||29;1F468,1F3FD,200D,1F9AF||29;1F468,1F3FE,200D,1F9AF||29;1F468,1F3FF,200D,1F9AF||29</item> <item>1F468,1F3FB,200D,1F9AF||29;1F468,1F3FC,200D,1F9AF||29;1F468,1F3FD,200D,1F9AF||29;1F468,1F3FE,200D,1F9AF||29;1F468,1F3FF,200D,1F9AF||29</item>
<item>1F469,1F3FB,200D,1F9AF||29;1F469,1F3FC,200D,1F9AF||29;1F469,1F3FD,200D,1F9AF||29;1F469,1F3FE,200D,1F9AF||29;1F469,1F3FF,200D,1F9AF||29</item> <item>1F469,1F3FB,200D,1F9AF||29;1F469,1F3FC,200D,1F9AF||29;1F469,1F3FD,200D,1F9AF||29;1F469,1F3FE,200D,1F9AF||29;1F469,1F3FF,200D,1F9AF||29</item>
<item>1F9D1,1F3FB,200D,1F9BC||30;1F9D1,1F3FC,200D,1F9BC||30;1F9D1,1F3FD,200D,1F9BC||30;1F9D1,1F3FE,200D,1F9BC||30;1F9D1,1F3FF,200D,1F9BC||30</item>
<item>1F468,1F3FB,200D,1F9BC||29;1F468,1F3FC,200D,1F9BC||29;1F468,1F3FD,200D,1F9BC||29;1F468,1F3FE,200D,1F9BC||29;1F468,1F3FF,200D,1F9BC||29</item> <item>1F468,1F3FB,200D,1F9BC||29;1F468,1F3FC,200D,1F9BC||29;1F468,1F3FD,200D,1F9BC||29;1F468,1F3FE,200D,1F9BC||29;1F468,1F3FF,200D,1F9BC||29</item>
<item>1F469,1F3FB,200D,1F9BC||29;1F469,1F3FC,200D,1F9BC||29;1F469,1F3FD,200D,1F9BC||29;1F469,1F3FE,200D,1F9BC||29;1F469,1F3FF,200D,1F9BC||29</item> <item>1F469,1F3FB,200D,1F9BC||29;1F469,1F3FC,200D,1F9BC||29;1F469,1F3FD,200D,1F9BC||29;1F469,1F3FE,200D,1F9BC||29;1F469,1F3FF,200D,1F9BC||29</item>
<item>1F9D1,1F3FB,200D,1F9BD||30;1F9D1,1F3FC,200D,1F9BD||30;1F9D1,1F3FD,200D,1F9BD||30;1F9D1,1F3FE,200D,1F9BD||30;1F9D1,1F3FF,200D,1F9BD||30</item>
<item>1F468,1F3FB,200D,1F9BD||29;1F468,1F3FC,200D,1F9BD||29;1F468,1F3FD,200D,1F9BD||29;1F468,1F3FE,200D,1F9BD||29;1F468,1F3FF,200D,1F9BD||29</item> <item>1F468,1F3FB,200D,1F9BD||29;1F468,1F3FC,200D,1F9BD||29;1F468,1F3FD,200D,1F9BD||29;1F468,1F3FE,200D,1F9BD||29;1F468,1F3FF,200D,1F9BD||29</item>
<item>1F469,1F3FB,200D,1F9BD||29;1F469,1F3FC,200D,1F9BD||29;1F469,1F3FD,200D,1F9BD||29;1F469,1F3FE,200D,1F9BD||29;1F469,1F3FF,200D,1F9BD||29</item> <item>1F469,1F3FB,200D,1F9BD||29;1F469,1F3FC,200D,1F9BD||29;1F469,1F3FD,200D,1F9BD||29;1F469,1F3FE,200D,1F9BD||29;1F469,1F3FF,200D,1F9BD||29</item>
<item>1F3C3,1F3FB||24;1F3C3,1F3FC||24;1F3C3,1F3FD||24;1F3C3,1F3FE||24;1F3C3,1F3FF||24</item> <item>1F3C3,1F3FB||24;1F3C3,1F3FC||24;1F3C3,1F3FD||24;1F3C3,1F3FE||24;1F3C3,1F3FF||24</item>
@ -827,65 +878,15 @@
<item>1F9D8,1F3FB,200D,2640,FE0F||26;1F9D8,1F3FC,200D,2640,FE0F||26;1F9D8,1F3FD,200D,2640,FE0F||26;1F9D8,1F3FE,200D,2640,FE0F||26;1F9D8,1F3FF,200D,2640,FE0F||26</item> <item>1F9D8,1F3FB,200D,2640,FE0F||26;1F9D8,1F3FC,200D,2640,FE0F||26;1F9D8,1F3FD,200D,2640,FE0F||26;1F9D8,1F3FE,200D,2640,FE0F||26;1F9D8,1F3FF,200D,2640,FE0F||26</item>
<item>1F6C0,1F3FB||24;1F6C0,1F3FC||24;1F6C0,1F3FD||24;1F6C0,1F3FE||24;1F6C0,1F3FF||24</item> <item>1F6C0,1F3FB||24;1F6C0,1F3FC||24;1F6C0,1F3FD||24;1F6C0,1F3FE||24;1F6C0,1F3FF||24</item>
<item>1F6CC,1F3FB||26;1F6CC,1F3FC||26;1F6CC,1F3FD||26;1F6CC,1F3FE||26;1F6CC,1F3FF||26</item> <item>1F6CC,1F3FB||26;1F6CC,1F3FC||26;1F6CC,1F3FD||26;1F6CC,1F3FE||26;1F6CC,1F3FF||26</item>
<item>1F9D1,1F3FB,200D,1F91D,200D,1F9D1,1F3FB||29;1F9D1,1F3FC,200D,1F91D,200D,1F9D1,1F3FC||29;1F9D1,1F3FD,200D,1F91D,200D,1F9D1,1F3FD||29;1F9D1,1F3FE,200D,1F91D,200D,1F9D1,1F3FE||29;1F9D1,1F3FF,200D,1F91D,200D,1F9D1,1F3FF||29</item>
<!--<item/>
<item/> <item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>-->
<item>1F46D,1F3FB||29;1F46D,1F3FC||29;1F46D,1F3FD||29;1F46D,1F3FE||29;1F46D,1F3FF||29</item> <item>1F46D,1F3FB||29;1F46D,1F3FC||29;1F46D,1F3FD||29;1F46D,1F3FE||29;1F46D,1F3FF||29</item>
<!--<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>-->
<item>1F46B,1F3FB||29;1F46B,1F3FC||29;1F46B,1F3FD||29;1F46B,1F3FE||29;1F46B,1F3FF||29</item> <item>1F46B,1F3FB||29;1F46B,1F3FC||29;1F46B,1F3FD||29;1F46B,1F3FE||29;1F46B,1F3FF||29</item>
<!--<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>-->
<item>1F46C,1F3FB||29;1F46C,1F3FC||29;1F46C,1F3FD||29;1F46C,1F3FE||29;1F46C,1F3FF||29</item> <item>1F46C,1F3FB||29;1F46C,1F3FC||29;1F46C,1F3FD||29;1F46C,1F3FE||29;1F46C,1F3FF||29</item>
<!--<item/> <item>1F48F,1F3FB||31;1F48F,1F3FC||31;1F48F,1F3FD||31;1F48F,1F3FE||31;1F48F,1F3FF||31</item>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>
<item/>-->
<item/>
<item/>
<item/> <item/>
<item/> <item/>
<item/> <item/>
<item>1F491,1F3FB||31;1F491,1F3FC||31;1F491,1F3FD||31;1F491,1F3FE||31;1F491,1F3FF||31</item>
<item/> <item/>
<item/> <item/>
<item/> <item/>
@ -1026,6 +1027,7 @@
<item>1F988||24</item> <item>1F988||24</item>
<item>1F419</item> <item>1F419</item>
<item>1F41A</item> <item>1F41A</item>
<item>1FAB8||32</item>
<item>1F40C</item> <item>1F40C</item>
<item>1F98B||24</item> <item>1F98B||24</item>
<item>1F41B</item> <item>1F41B</item>
@ -1045,6 +1047,7 @@
<item>1F490</item> <item>1F490</item>
<item>1F338</item> <item>1F338</item>
<item>1F4AE</item> <item>1F4AE</item>
<item>1FAB7||32</item>
<item>1F3F5,FE0F||23</item> <item>1F3F5,FE0F||23</item>
<item>1F339</item> <item>1F339</item>
<item>1F940||24</item> <item>1F940||24</item>
@ -1065,6 +1068,8 @@
<item>1F341</item> <item>1F341</item>
<item>1F342</item> <item>1F342</item>
<item>1F343</item> <item>1F343</item>
<item>1FAB9||32</item>
<item>1FABA||32</item>
</array> </array>
<array <array
@ -1103,6 +1108,7 @@
<item>1F9C5||29</item> <item>1F9C5||29</item>
<item>1F344</item> <item>1F344</item>
<item>1F95C||24</item> <item>1F95C||24</item>
<item>1FAD8||32</item>
<item>1F330</item> <item>1F330</item>
<item>1F35E</item> <item>1F35E</item>
<item>1F950||24</item> <item>1F950||24</item>
@ -1188,6 +1194,7 @@
<item>1F37B</item> <item>1F37B</item>
<item>1F942||24</item> <item>1F942||24</item>
<item>1F943||24</item> <item>1F943||24</item>
<item>1FAD7||32</item>
<item>1F964||26</item> <item>1F964||26</item>
<item>1F9CB||30</item> <item>1F9CB||30</item>
<item>1F9C3||29</item> <item>1F9C3||29</item>
@ -1198,6 +1205,7 @@
<item>1F374</item> <item>1F374</item>
<item>1F944||24</item> <item>1F944||24</item>
<item>1F52A</item> <item>1F52A</item>
<item>1FAD9||32</item>
<item>1F3FA||23</item> <item>1F3FA||23</item>
</array> </array>
@ -1265,6 +1273,7 @@
<item>1F309</item> <item>1F309</item>
<item>2668,FE0F</item> <item>2668,FE0F</item>
<item>1F3A0</item> <item>1F3A0</item>
<item>1F6DD||32</item>
<item>1F3A1</item> <item>1F3A1</item>
<item>1F3A2</item> <item>1F3A2</item>
<item>1F488</item> <item>1F488</item>
@ -1313,12 +1322,14 @@
<item>1F6E4,FE0F||23</item> <item>1F6E4,FE0F||23</item>
<item>1F6E2,FE0F||23</item> <item>1F6E2,FE0F||23</item>
<item>26FD</item> <item>26FD</item>
<item>1F6DE||32</item>
<item>1F6A8</item> <item>1F6A8</item>
<item>1F6A5</item> <item>1F6A5</item>
<item>1F6A6</item> <item>1F6A6</item>
<item>1F6D1||24</item> <item>1F6D1||24</item>
<item>1F6A7</item> <item>1F6A7</item>
<item>2693</item> <item>2693</item>
<item>1F6DF||32</item>
<item>26F5</item> <item>26F5</item>
<item>1F6F6||24</item> <item>1F6F6||24</item>
<item>1F6A4</item> <item>1F6A4</item>
@ -1423,8 +1434,7 @@
<array <array
name="emoji_activities" name="emoji_activities"
format="string" format="string">
>
<item>1F383</item> <item>1F383</item>
<item>1F384</item> <item>1F384</item>
<item>1F386</item> <item>1F386</item>
@ -1479,12 +1489,14 @@
<item>1F3BF</item> <item>1F3BF</item>
<item>1F6F7||26</item> <item>1F6F7||26</item>
<item>1F94C||26</item> <item>1F94C||26</item>
<item>1F3AF</item>
<item>1FA80||29</item> <item>1FA80||29</item>
<item>1FA81||29</item> <item>1FA81||29</item>
<item>1F3B1</item> <item>1F3B1</item>
<item>1F52E</item> <item>1F52E</item>
<item>1FA84||30</item> <item>1FA84||30</item>
<item>1F9FF||28</item> <item>1F9FF||28</item>
<item>1FAAC||32</item>
<item>1F3AE</item> <item>1F3AE</item>
<item>1F579,FE0F||23</item> <item>1F579,FE0F||23</item>
<item>1F3B0</item> <item>1F3B0</item>
@ -1492,6 +1504,7 @@
<item>1F9E9||28</item> <item>1F9E9||28</item>
<item>1F9F8||28</item> <item>1F9F8||28</item>
<item>1FA85||30</item> <item>1FA85||30</item>
<item>1FAA9||32</item>
<item>1FA86||30</item> <item>1FA86||30</item>
<item>2660,FE0F</item> <item>2660,FE0F</item>
<item>2665,FE0F</item> <item>2665,FE0F</item>
@ -1592,6 +1605,7 @@
<item>1F4DF</item> <item>1F4DF</item>
<item>1F4E0</item> <item>1F4E0</item>
<item>1F50B</item> <item>1F50B</item>
<item>1FAAB||32</item>
<item>1F50C</item> <item>1F50C</item>
<item>1F4BB</item> <item>1F4BB</item>
<item>1F5A5,FE0F||23</item> <item>1F5A5,FE0F||23</item>
@ -1703,6 +1717,7 @@
<item>1F6E0,FE0F||23</item> <item>1F6E0,FE0F||23</item>
<item>1F5E1,FE0F||23</item> <item>1F5E1,FE0F||23</item>
<item>2694,FE0F||23</item> <item>2694,FE0F||23</item>
<item>1F52B</item>
<item>1FA83||30</item> <item>1FA83||30</item>
<item>1F3F9||23</item> <item>1F3F9||23</item>
<item>1F6E1,FE0F||23</item> <item>1F6E1,FE0F||23</item>
@ -1731,7 +1746,9 @@
<item>1FA78||29</item> <item>1FA78||29</item>
<item>1F48A</item> <item>1F48A</item>
<item>1FA79||29</item> <item>1FA79||29</item>
<item>1FA7C||32</item>
<item>1FA7A||29</item> <item>1FA7A||29</item>
<item>1FA7B||32</item>
<item>1F6AA</item> <item>1F6AA</item>
<item>1F6D7||30</item> <item>1F6D7||30</item>
<item>1FA9E||30</item> <item>1FA9E||30</item>
@ -1752,6 +1769,7 @@
<item>1F9FB||28</item> <item>1F9FB||28</item>
<item>1FAA3||30</item> <item>1FAA3||30</item>
<item>1F9FC||28</item> <item>1F9FC||28</item>
<item>1FAE7||32</item>
<item>1FAA5||30</item> <item>1FAA5||30</item>
<item>1F9FD||28</item> <item>1F9FD||28</item>
<item>1F9EF||28</item> <item>1F9EF||28</item>
@ -1762,12 +1780,12 @@
<item>26B1,FE0F||23</item> <item>26B1,FE0F||23</item>
<item>1F5FF</item> <item>1F5FF</item>
<item>1FAA7||30</item> <item>1FAA7||30</item>
<item>1FAAA||32</item>
</array> </array>
<array <array
name="emoji_symbols" name="emoji_symbols"
format="string" format="string">
>
<item>1F3E7</item> <item>1F3E7</item>
<item>1F6AE</item> <item>1F6AE</item>
<item>1F6B0</item> <item>1F6B0</item>
@ -1871,11 +1889,14 @@
<item>2795</item> <item>2795</item>
<item>2796</item> <item>2796</item>
<item>2797</item> <item>2797</item>
<item>1F7F0||32</item>
<item>267E,FE0F||28</item> <item>267E,FE0F||28</item>
<item>203C,FE0F</item> <item>203C,FE0F</item>
<item>2049,FE0F</item> <item>2049,FE0F</item>
<item>2753</item>
<item>2754</item> <item>2754</item>
<item>2755</item> <item>2755</item>
<item>2757</item>
<item>3030,FE0F</item> <item>3030,FE0F</item>
<item>1F4B1</item> <item>1F4B1</item>
<item>1F4B2</item> <item>1F4B2</item>
@ -1897,9 +1918,47 @@
<item>2733,FE0F</item> <item>2733,FE0F</item>
<item>2734,FE0F</item> <item>2734,FE0F</item>
<item>2747,FE0F</item> <item>2747,FE0F</item>
<item>00A9,FE0F</item> <item>A9,FE0F</item>
<item>00AE,FE0F</item> <item>AE,FE0F</item>
<item>2122,FE0F</item> <item>2122,FE0F</item>
<item>1F1E6</item>
<item>1F1E7</item>
<item>1F1E8</item>
<item>1F1E9</item>
<item>1F1EA</item>
<item>1F1EB</item>
<item>1F1EC</item>
<item>1F1ED</item>
<item>1F1EE</item>
<item>1F1EF</item>
<item>1F1F0</item>
<item>1F1F1</item>
<item>1F1F2</item>
<item>1F1F3</item>
<item>1F1F4</item>
<item>1F1F5</item>
<item>1F1F6</item>
<item>1F1F7</item>
<item>1F1F8</item>
<item>1F1F9</item>
<item>1F1FA</item>
<item>1F1FB</item>
<item>1F1FC</item>
<item>1F1FD</item>
<item>1F1FE</item>
<item>1F1FF</item>
<item>23,FE0F,20E3||21</item>
<item>2A,FE0F,20E3||23</item>
<item>30,FE0F,20E3||21</item>
<item>31,FE0F,20E3||21</item>
<item>32,FE0F,20E3||21</item>
<item>33,FE0F,20E3||21</item>
<item>34,FE0F,20E3||21</item>
<item>35,FE0F,20E3||21</item>
<item>36,FE0F,20E3||21</item>
<item>37,FE0F,20E3||21</item>
<item>38,FE0F,20E3||21</item>
<item>39,FE0F,20E3||21</item>
<item>1F51F</item> <item>1F51F</item>
<item>1F520</item> <item>1F520</item>
<item>1F521</item> <item>1F521</item>
@ -1978,8 +2037,7 @@
<array <array
name="emoji_flags" name="emoji_flags"
format="string" format="string">
>
<item>1F3C1</item> <item>1F3C1</item>
<item>1F6A9</item> <item>1F6A9</item>
<item>1F38C</item> <item>1F38C</item>
@ -2243,8 +2301,7 @@
Do not remove these keys, because they are used as a template. --> Do not remove these keys, because they are used as a template. -->
<array <array
name="emoji_recents" name="emoji_recents"
format="string" format="string">
>
<!-- These code point should be aligned with {@link RecentsKeyboard#TEMPLATE_KEY_CODE_*. --> <!-- These code point should be aligned with {@link RecentsKeyboard#TEMPLATE_KEY_CODE_*. -->
<item>30</item> <item>30</item>
<item>31</item> <item>31</item>
@ -2252,8 +2309,7 @@
<array <array
name="emoji_emoticons" name="emoji_emoticons"
format="string" format="string">
>
<item>:-)</item> <item>:-)</item>
<item>;-)</item> <item>;-)</item>
<item>:-(</item> <item>:-(</item>

View file

@ -29,7 +29,6 @@
<item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item> <item name="iconSearchKey">@drawable/sym_keyboard_search_holo_dark</item>
<item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item> <item name="iconTabKey">@drawable/sym_keyboard_tab_holo_dark</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo_dark</item> <item name="iconShortcutKey">@drawable/sym_keyboard_voice_holo_dark</item>
<item name="iconClipboardKey">@drawable/sym_keyboard_clipboard_dark</item>
<item name="iconIncognitoKey">@drawable/sym_keyboard_incognito_dark</item> <item name="iconIncognitoKey">@drawable/sym_keyboard_incognito_dark</item>
<item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item> <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_holo_dark</item>
<item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item> <item name="iconShiftKeyShifted">@drawable/sym_keyboard_shift_locked_holo_dark</item>
@ -39,5 +38,8 @@
<item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item> <item name="iconZwjKey">@drawable/sym_keyboard_zwj_holo_dark</item>
<item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_holo_dark</item> <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_holo_dark</item>
<item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_holo_dark</item> <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_holo_dark</item>
<item name="iconClipboardActionKey">@drawable/sym_keyboard_clipboard_holo_dark</item>
<item name="iconClipboardNormalKey">@drawable/sym_keyboard_clipboard_holo_dark</item>
<item name="iconClearClipboardKey">@drawable/sym_keyboard_clear_clipboard_holo_dark</item>
</style> </style>
</resources> </resources>

View file

@ -36,7 +36,6 @@
<item name="iconPreviousKey">@drawable/sym_keyboard_previous_lxx_dark</item> <item name="iconPreviousKey">@drawable/sym_keyboard_previous_lxx_dark</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_voice_lxx_dark</item> <item name="iconShortcutKey">@drawable/sym_keyboard_voice_lxx_dark</item>
<item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_lxx_dark</item> <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_lxx_dark</item>
<item name="iconClipboardKey">@drawable/sym_keyboard_clipboard_dark</item>
<item name="iconIncognitoKey">@drawable/sym_keyboard_incognito_lxx_dark</item> <item name="iconIncognitoKey">@drawable/sym_keyboard_incognito_lxx_dark</item>
<item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_lxx_dark</item> <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_lxx_dark</item>
<item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_lxx_dark</item> <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_lxx_dark</item>
@ -44,5 +43,8 @@
<item name="iconZwjKey">@drawable/sym_keyboard_zwj_lxx_dark</item> <item name="iconZwjKey">@drawable/sym_keyboard_zwj_lxx_dark</item>
<item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_lxx_dark</item> <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
<item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_lxx_dark</item> <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
<item name="iconClipboardActionKey">@drawable/sym_keyboard_clipboard_lxx_dark</item>
<item name="iconClipboardNormalKey">@drawable/sym_keyboard_clipboard_lxx_dark</item>
<item name="iconClearClipboardKey">@drawable/sym_keyboard_clear_clipboard_lxx_dark</item>
</style> </style>
</resources> </resources>

View file

@ -36,7 +36,6 @@
<item name="iconPreviousKey">@drawable/sym_keyboard_previous_lxx_light</item> <item name="iconPreviousKey">@drawable/sym_keyboard_previous_lxx_light</item>
<item name="iconShortcutKey">@drawable/sym_keyboard_voice_lxx_light</item> <item name="iconShortcutKey">@drawable/sym_keyboard_voice_lxx_light</item>
<item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_lxx_light</item> <item name="iconShortcutKeyDisabled">@drawable/sym_keyboard_voice_off_lxx_light</item>
<item name="iconClipboardKey">@drawable/sym_keyboard_clipboard_light</item>
<item name="iconIncognitoKey">@drawable/sym_keyboard_incognito_lxx_light</item> <item name="iconIncognitoKey">@drawable/sym_keyboard_incognito_lxx_light</item>
<item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_lxx_light</item> <item name="iconSpaceKeyForNumberLayout">@drawable/sym_keyboard_space_lxx_light</item>
<item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_lxx_light</item> <item name="iconLanguageSwitchKey">@drawable/sym_keyboard_language_switch_lxx_light</item>
@ -44,5 +43,8 @@
<item name="iconZwjKey">@drawable/sym_keyboard_zwj_lxx_light</item> <item name="iconZwjKey">@drawable/sym_keyboard_zwj_lxx_light</item>
<item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_lxx_dark</item> <item name="iconEmojiActionKey">@drawable/sym_keyboard_smiley_lxx_dark</item>
<item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_lxx_light</item> <item name="iconEmojiNormalKey">@drawable/sym_keyboard_smiley_lxx_light</item>
<item name="iconClipboardActionKey">@drawable/sym_keyboard_clipboard_lxx_dark</item>
<item name="iconClipboardNormalKey">@drawable/sym_keyboard_clipboard_lxx_light</item>
<item name="iconClearClipboardKey">@drawable/sym_keyboard_clear_clipboard_lxx_light</item>
</style> </style>
</resources> </resources>

View file

@ -217,6 +217,9 @@
<!-- Description of the settings to show hints --> <!-- Description of the settings to show hints -->
<string name="show_hints_summary">Show long-press hints</string> <string name="show_hints_summary">Show long-press hints</string>
<!-- Title of the settings to disable long press space to change language -->
<string name="prefs_long_press_keyboard_to_change_lang">Long press to change lang</string>
<!-- Title of the settings to enable keyboard resizing --> <!-- Title of the settings to enable keyboard resizing -->
<string name="prefs_resize_keyboard">Enable keyboard resizing</string> <string name="prefs_resize_keyboard">Enable keyboard resizing</string>
<!-- Title of the settings for setting keyboard height --> <!-- Title of the settings for setting keyboard height -->

View file

@ -110,6 +110,7 @@
delete button, need themed {@link org.dslul.openboard.inputmethod.keyboard.KeyboardView} delete button, need themed {@link org.dslul.openboard.inputmethod.keyboard.KeyboardView}
attributes. --> attributes. -->
<style name="EmojiPalettesView" /> <style name="EmojiPalettesView" />
<style name="ClipboardHistoryView" />
<style name="MoreKeysKeyboard" /> <style name="MoreKeysKeyboard" />
<style name="MoreKeysKeyboardView" /> <style name="MoreKeysKeyboardView" />
<style name="SuggestionStripView" /> <style name="SuggestionStripView" />

View file

@ -25,6 +25,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.ICS</item> <item name="keyboardViewStyle">@style/KeyboardView.ICS</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.ICS</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.ICS</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.ICS</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.ICS</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.ICS</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.ICS</item>
<!-- Note: ICS theme uses the same style for both general more keys and action more keys. --> <!-- Note: ICS theme uses the same style for both general more keys and action more keys. -->
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.ICS</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.ICS</item>
@ -98,6 +99,13 @@
<item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_holo_dark</item> <item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_holo_dark</item>
<item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_holo_dark</item> <item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_holo_dark</item>
</style> </style>
<style
name="ClipboardHistoryView.ICS"
parent="MainKeyboardView.ICS"
>
<item name="iconPinnedClip">@drawable/ic_clipboard_pin_holo_dark</item>
<item name="dividerBackground">@color/emoji_tab_page_indicator_background_holo</item>
</style>
<style <style
name="MoreKeysKeyboard.ICS" name="MoreKeysKeyboard.ICS"
parent="Keyboard.ICS" parent="Keyboard.ICS"

View file

@ -25,6 +25,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.KLP</item> <item name="keyboardViewStyle">@style/KeyboardView.KLP</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.KLP</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.KLP</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.KLP</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.KLP</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.KLP</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.KLP</item>
<!-- Note: KLP theme uses the same style for both general more keys and action more keys. --> <!-- Note: KLP theme uses the same style for both general more keys and action more keys. -->
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.KLP</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.KLP</item>
@ -98,6 +99,11 @@
<item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_holo_dark</item> <item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_holo_dark</item>
<item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_holo_dark</item> <item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_holo_dark</item>
</style> </style>
<style
name="ClipboardHistoryView.KLP"
parent="ClipboardHistoryView.ICS"
>
</style>
<style <style
name="MoreKeysKeyboard.KLP" name="MoreKeysKeyboard.KLP"
parent="Keyboard.KLP" parent="Keyboard.KLP"

View file

@ -28,6 +28,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark_Amoled</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark_Amoled</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark_Amoled</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark_Amoled</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark_Amoled</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark_Amoled</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.LXX_Dark_Amoled</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark_Amoled</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark_Amoled</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Dark_Amoled</item> <item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Dark_Amoled</item>
</style> </style>
@ -65,6 +66,14 @@
<item name="keyBackground">@drawable/btn_keyboard_key_lxx_dark_amoled</item> <item name="keyBackground">@drawable/btn_keyboard_key_lxx_dark_amoled</item>
</style> </style>
<style
name="ClipboardHistoryView.LXX_Dark_Amoled"
parent="ClipboardHistoryView.LXX_Dark"
>
<item name="android:background">@color/background_amoled_black</item>
<item name="keyBackground">@drawable/btn_keyboard_key_lxx_dark_amoled</item>
</style>
<style <style
name="MoreKeysKeyboardView.LXX_Dark_Amoled" name="MoreKeysKeyboardView.LXX_Dark_Amoled"
parent="MoreKeysKeyboardView.LXX_Dark" parent="MoreKeysKeyboardView.LXX_Dark"

View file

@ -26,6 +26,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark_Border</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark_Border</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark_Border</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark_Border</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark_Border</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark_Border</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.LXX_Dark_Border</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark_Border</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark_Border</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Dark_Border</item> <item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Dark_Border</item>
</style> </style>
@ -65,6 +66,14 @@
<item name="spacebarBackground">@drawable/btn_keyboard_key_lxx_dark_border</item> <item name="spacebarBackground">@drawable/btn_keyboard_key_lxx_dark_border</item>
</style> </style>
<style
name="ClipboardHistoryView.LXX_Dark_Border"
parent="ClipboardHistoryView.LXX_Dark">
<item name="android:background">@drawable/keyboard_background_lxx_dark_border</item>
<item name="keyBackground">@drawable/btn_keyboard_key_lxx_dark_border</item>
<item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_lxx_dark_border</item>
</style>
<style <style
name="MoreKeysKeyboardView.LXX_Dark_Border" name="MoreKeysKeyboardView.LXX_Dark_Border"
parent="MoreKeysKeyboardView.LXX_Dark"> parent="MoreKeysKeyboardView.LXX_Dark">

View file

@ -28,6 +28,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Dark</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Dark</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Dark</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.LXX_Dark</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Dark</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Dark</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Dark</item>
<item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.LXX_Dark.Action</item> <item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.LXX_Dark.Action</item>
@ -99,6 +100,13 @@
<item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_lxx_dark</item> <item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_lxx_dark</item>
<item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_lxx_dark</item> <item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_lxx_dark</item>
</style> </style>
<style
name="ClipboardHistoryView.LXX_Dark"
parent="MainKeyboardView.LXX_Dark"
>
<item name="iconPinnedClip">@drawable/ic_clipboard_pin_lxx_dark</item>
<item name="dividerBackground">@color/emoji_tab_page_indicator_background_lxx_dark</item>
</style>
<style <style
name="MoreKeysKeyboard.LXX_Dark" name="MoreKeysKeyboard.LXX_Dark"
parent="Keyboard.LXX_Dark" parent="Keyboard.LXX_Dark"

View file

@ -25,6 +25,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Light_Border</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Light_Border</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Light_Border</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Light_Border</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Light_Border</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Light_Border</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.LXX_Light_Border</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Light_Border</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Light_Border</item>
<item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Light_Border</item> <item name="suggestionStripViewStyle">@style/SuggestionStripView.LXX_Light_Border</item>
</style> </style>
@ -62,6 +63,14 @@
<item name="spacebarBackground">@drawable/btn_keyboard_key_lxx_light_border</item> <item name="spacebarBackground">@drawable/btn_keyboard_key_lxx_light_border</item>
</style> </style>
<style
name="ClipboardHistoryView.LXX_Light_Border"
parent="ClipboardHistoryView.LXX_Light">
<item name="android:background">@drawable/keyboard_background_lxx_light_border</item>
<item name="keyBackground">@drawable/btn_keyboard_key_lxx_light_border</item>
<item name="functionalKeyBackground">@drawable/btn_keyboard_key_functional_lxx_light_border</item>
</style>
<style <style
name="MoreKeysKeyboardView.LXX_Light_Border" name="MoreKeysKeyboardView.LXX_Light_Border"
parent="MoreKeysKeyboardView.LXX_Light"> parent="MoreKeysKeyboardView.LXX_Light">

View file

@ -25,6 +25,7 @@
<item name="keyboardViewStyle">@style/KeyboardView.LXX_Light</item> <item name="keyboardViewStyle">@style/KeyboardView.LXX_Light</item>
<item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Light</item> <item name="mainKeyboardViewStyle">@style/MainKeyboardView.LXX_Light</item>
<item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Light</item> <item name="emojiPalettesViewStyle">@style/EmojiPalettesView.LXX_Light</item>
<item name="clipboardHistoryViewStyle">@style/ClipboardHistoryView.LXX_Light</item>
<item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Light</item> <item name="moreKeysKeyboardStyle">@style/MoreKeysKeyboard.LXX_Light</item>
<item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Light</item> <item name="moreKeysKeyboardViewStyle">@style/MoreKeysKeyboardView.LXX_Light</item>
<item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.LXX_Light.Action</item> <item name="moreKeysKeyboardViewForActionStyle">@style/MoreKeysKeyboardView.LXX_Light.Action</item>
@ -96,6 +97,13 @@
<item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_lxx_light</item> <item name="iconEmojiCategory9Tab">@drawable/ic_emoji_flags_lxx_light</item>
<item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_lxx_light</item> <item name="iconEmojiCategory10Tab">@drawable/ic_emoji_emoticons_lxx_light</item>
</style> </style>
<style
name="ClipboardHistoryView.LXX_Light"
parent="MainKeyboardView.LXX_Light"
>
<item name="iconPinnedClip">@drawable/ic_clipboard_pin_lxx_light</item>
<item name="dividerBackground">@color/emoji_tab_page_indicator_background_lxx_light</item>
</style>
<style <style
name="MoreKeysKeyboard.LXX_Light" name="MoreKeysKeyboard.LXX_Light"
parent="Keyboard.LXX_Light" parent="Keyboard.LXX_Light"

View file

@ -26,61 +26,61 @@
<key-style <key-style
latin:styleName="navigateNextMoreKeysStyle" latin:styleName="navigateNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!text/keyspec_action_next" /> latin:moreKeys="!text/keyspec_clipboard_action_key,!text/keyspec_action_next" />
<key-style <key-style
latin:styleName="navigatePreviousMoreKeysStyle" latin:styleName="navigatePreviousMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!text/keyspec_action_previous" /> latin:moreKeys="!text/keyspec_action_previous,!text/keyspec_clipboard_action_key" />
<key-style <key-style
latin:styleName="navigatePreviousNextMoreKeysStyle" latin:styleName="navigatePreviousNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_action_next" /> latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_clipboard_action_key,!text/keyspec_action_next" />
<key-style <key-style
latin:styleName="navigateEmojiMoreKeysStyle" latin:styleName="navigateEmojiMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!text/keyspec_emoji_action_key" /> latin:moreKeys="!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key" />
<key-style <key-style
latin:styleName="navigateEmojiNextMoreKeysStyle" latin:styleName="navigateEmojiNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!text/keyspec_action_next" /> latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key,!text/keyspec_action_next" />
<key-style <key-style
latin:styleName="navigateEmojiPreviousMoreKeysStyle" latin:styleName="navigateEmojiPreviousMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!text/keyspec_action_previous" /> latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key" />
<key-style <key-style
latin:styleName="navigateEmojiPreviousNextMoreKeysStyle" latin:styleName="navigateEmojiPreviousNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_emoji_action_key,!text/keyspec_action_previous,!text/keyspec_action_next" /> latin:moreKeys="!fixedColumnOrder!4,!needsDividers!,!text/keyspec_action_previous,!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key,!text/keyspec_action_next" />
</case> </case>
<default> <default>
<key-style <key-style
latin:styleName="navigateNextMoreKeysStyle" latin:styleName="navigateNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!icon/next_key|!code/key_action_next" /> latin:moreKeys="!text/keyspec_clipboard_action_key,!icon/next_key|!code/key_action_next" />
<key-style <key-style
latin:styleName="navigatePreviousMoreKeysStyle" latin:styleName="navigatePreviousMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!icon/previous_key|!code/key_action_previous" /> latin:moreKeys="!icon/previous_key|!code/key_action_previous,!text/keyspec_clipboard_action_key" />
<key-style <key-style
latin:styleName="navigatePreviousNextMoreKeysStyle" latin:styleName="navigatePreviousNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!icon/previous_key|!code/key_action_previous,!icon/next_key|!code/key_action_next" /> latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!icon/previous_key|!code/key_action_previous,!text/keyspec_clipboard_action_key,!icon/next_key|!code/key_action_next" />
<key-style <key-style
latin:styleName="navigateEmojiMoreKeysStyle" latin:styleName="navigateEmojiMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!text/keyspec_emoji_action_key" /> latin:moreKeys="!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key" />
<key-style <key-style
latin:styleName="navigateEmojiNextMoreKeysStyle" latin:styleName="navigateEmojiNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!icon/next_key|!code/key_action_next" /> latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key,!icon/next_key|!code/key_action_next" />
<key-style <key-style
latin:styleName="navigateEmojiPreviousMoreKeysStyle" latin:styleName="navigateEmojiPreviousMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!2,!needsDividers!,!text/keyspec_emoji_action_key,!icon/previous_key|!code/key_action_previous" /> latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!icon/previous_key|!code/key_action_previous,!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key" />
<key-style <key-style
latin:styleName="navigateEmojiPreviousNextMoreKeysStyle" latin:styleName="navigateEmojiPreviousNextMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint|preserveCase" latin:keyLabelFlags="hasPopupHint|preserveCase"
latin:moreKeys="!fixedColumnOrder!3,!needsDividers!,!text/keyspec_emoji_action_key,!icon/previous_key|!code/key_action_previous,!icon/next_key|!code/key_action_next" /> latin:moreKeys="!fixedColumnOrder!4,!needsDividers!,!icon/previous_key|!code/key_action_previous,!text/keyspec_clipboard_action_key,!text/keyspec_emoji_action_key,!icon/next_key|!code/key_action_next" />
</default> </default>
</switch> </switch>
</merge> </merge>

View file

@ -30,12 +30,41 @@
latin:styleName="settingsMoreKeysStyle" latin:styleName="settingsMoreKeysStyle"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
</case> </case>
<!-- clobberSettingsKey="false" --> <case
latin:emojiKeyEnabled="true"
latin:languageSwitchKeyEnabled="true"
>
<key-style
latin:styleName="settingsMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint"
latin:additionalMoreKeys="!text/keyspec_settings,!text/keyspec_clipboard_normal_key"
latin:backgroundType="functional" />
</case>
<case
latin:emojiKeyEnabled="false"
latin:languageSwitchKeyEnabled="true"
>
<key-style
latin:styleName="settingsMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint"
latin:additionalMoreKeys="!text/keyspec_settings,!text/keyspec_clipboard_normal_key,!text/keyspec_emoji_normal_key"
latin:backgroundType="functional" />
</case>
<case
latin:emojiKeyEnabled="true"
latin:languageSwitchKeyEnabled="false"
>
<key-style
latin:styleName="settingsMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint"
latin:additionalMoreKeys="!text/keyspec_settings,!icon/language_switch_key|!code/key_language_switch,!text/keyspec_clipboard_normal_key"
latin:backgroundType="functional" />
</case>
<default> <default>
<key-style <key-style
latin:styleName="settingsMoreKeysStyle" latin:styleName="settingsMoreKeysStyle"
latin:keyLabelFlags="hasPopupHint" latin:keyLabelFlags="hasPopupHint"
latin:additionalMoreKeys="!text/keyspec_settings,!icon/language_switch_key|!code/key_language_switch,!text/keyspec_emoji_normal_key" latin:additionalMoreKeys="!text/keyspec_settings,!icon/language_switch_key|!code/key_language_switch,!text/keyspec_clipboard_normal_key,!text/keyspec_emoji_normal_key"
latin:backgroundType="functional" /> latin:backgroundType="functional" />
</default> </default>
</switch> </switch>

View file

@ -34,6 +34,11 @@
android:summary="@string/show_hints_summary" android:summary="@string/show_hints_summary"
android:defaultValue="true" android:defaultValue="true"
android:persistent="true" /> android:persistent="true" />
<CheckBoxPreference
android:key="prefs_long_press_keyboard_to_change_lang"
android:title="@string/prefs_long_press_keyboard_to_change_lang"
android:persistent="true"
android:defaultValue="true" />
<CheckBoxPreference <CheckBoxPreference
android:key="pref_show_language_switch_key" android:key="pref_show_language_switch_key"
android:title="@string/show_language_switch_key" android:title="@string/show_language_switch_key"

View file

@ -1,13 +1,13 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
ext.kotlin_version = '1.4.30' ext.kotlin_version = '1.5.31'
repositories { repositories {
jcenter() jcenter()
google() google()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:4.2.1' classpath 'com.android.tools.build:gradle:7.0.4'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong

BIN
dictionaries/de_wordlist.combined.gz Normal file → Executable file

Binary file not shown.

View file

@ -0,0 +1,10 @@
1.4.4b:
- fix crash on older devices
- fix german words that appear in capital letters
1.4.4:
- add clipboard history
- fix bug preventing numpad from showing on tablets
- add Workman layout
- added dictionaries: Swedish, Danish, Hungarian
- bugfixes

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Before After
Before After

Some files were not shown because too many files have changed in this diff Show more