Merge pull request #232 from esensar/feature/229-emoji-categories

Add emoji categories to emoji list
This commit is contained in:
Tibor Kaputa 2023-08-30 15:39:13 +02:00 committed by GitHub
commit 25918d4660
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 232 additions and 22 deletions

View file

@ -6,39 +6,72 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.emoji2.text.EmojiCompat import androidx.emoji2.text.EmojiCompat
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.simplemobiletools.commons.databinding.DividerBinding
import com.simplemobiletools.commons.extensions.beInvisible
import com.simplemobiletools.keyboard.databinding.ItemEmojiBinding import com.simplemobiletools.keyboard.databinding.ItemEmojiBinding
import com.simplemobiletools.keyboard.helpers.EmojiData
class EmojisAdapter(val context: Context, var items: List<String>, val itemClick: (emoji: String) -> Unit) : RecyclerView.Adapter<EmojisAdapter.ViewHolder>() { class EmojisAdapter(val context: Context, private val items: List<Item>, val itemClick: (emoji: EmojiData) -> Unit) :
RecyclerView.Adapter<EmojisAdapter.ViewHolder>() {
private val layoutInflater = LayoutInflater.from(context) private val layoutInflater = LayoutInflater.from(context)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmojisAdapter.ViewHolder { override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmojisAdapter.ViewHolder {
return when (viewType) {
ITEM_TYPE_EMOJI -> {
val view = ItemEmojiBinding.inflate(layoutInflater, parent, false).root val view = ItemEmojiBinding.inflate(layoutInflater, parent, false).root
return ViewHolder(view) ViewHolder(view)
}
else -> {
val view = DividerBinding.inflate(layoutInflater, parent, false).root.apply { beInvisible() }
ViewHolder(view)
}
}
} }
override fun onBindViewHolder(holder: EmojisAdapter.ViewHolder, position: Int) { override fun onBindViewHolder(holder: EmojisAdapter.ViewHolder, position: Int) {
val item = items[position] val item = items[position]
if (item is Item.Emoji) {
holder.bindView(item) { itemView -> holder.bindView(item) { itemView ->
setupEmoji(itemView, item) setupEmoji(itemView, item)
} }
} }
}
override fun getItemViewType(position: Int): Int {
return if (items[position] is Item.Emoji) {
ITEM_TYPE_EMOJI
} else {
ITEM_TYPE_CATEGORY
}
}
override fun getItemCount() = items.size override fun getItemCount() = items.size
private fun setupEmoji(view: View, emoji: String) { private fun setupEmoji(view: View, emoji: Item.Emoji) {
val processed = EmojiCompat.get().process(emoji) val processed = EmojiCompat.get().process(emoji.value.emoji)
ItemEmojiBinding.bind(view).emojiValue.text = processed ItemEmojiBinding.bind(view).emojiValue.text = processed
} }
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bindView(emoji: String, callback: (itemView: View) -> Unit): View { fun bindView(emoji: Item.Emoji, callback: (itemView: View) -> Unit): View {
return itemView.apply { return itemView.apply {
callback(this) callback(this)
setOnClickListener { setOnClickListener {
itemClick.invoke(emoji) itemClick.invoke(emoji.value)
} }
} }
} }
} }
sealed interface Item {
data class Emoji(val value: EmojiData) : Item
data class Category(val value: String) : Item
}
companion object {
private const val ITEM_TYPE_EMOJI = 0
private const val ITEM_TYPE_CATEGORY = 1
}
} }

View file

@ -1,10 +1,11 @@
package com.simplemobiletools.keyboard.helpers package com.simplemobiletools.keyboard.helpers
import android.content.Context import android.content.Context
import com.simplemobiletools.keyboard.R
import org.json.JSONObject import org.json.JSONObject
import java.io.InputStream import java.io.InputStream
private var cachedEmojiData: MutableList<String>? = null private var cachedEmojiData: MutableList<EmojiData>? = null
val cachedVNTelexData: HashMap<String, String> = HashMap() val cachedVNTelexData: HashMap<String, String> = HashMap()
/** /**
@ -14,18 +15,21 @@ val cachedVNTelexData: HashMap<String, String> = HashMap()
* @param context The initiating view's context. * @param context The initiating view's context.
* @param path The path to the asset file. * @param path The path to the asset file.
*/ */
fun parseRawEmojiSpecsFile(context: Context, path: String): MutableList<String> { fun parseRawEmojiSpecsFile(context: Context, path: String): MutableList<EmojiData> {
if (cachedEmojiData != null) { if (cachedEmojiData != null) {
return cachedEmojiData!! return cachedEmojiData!!
} }
val emojis = mutableListOf<String>() val emojis = mutableListOf<EmojiData>()
var emojiEditorList: MutableList<String>? = null var emojiEditorList: MutableList<String>? = null
var category: String? = null
fun commitEmojiEditorList() { fun commitEmojiEditorList() {
emojiEditorList?.let { emojiEditorList?.let {
// add only the base emoji for now, ignore the variations // add only the base emoji for now, ignore the variations
emojis.add(it.first()) val base = it.first()
val variants = it.drop(1)
emojis.add(EmojiData(category ?: "none", base, variants))
} }
emojiEditorList = null emojiEditorList = null
} }
@ -36,6 +40,7 @@ fun parseRawEmojiSpecsFile(context: Context, path: String): MutableList<String>
// Comment line // Comment line
} else if (line.startsWith("[")) { } else if (line.startsWith("[")) {
commitEmojiEditorList() commitEmojiEditorList()
category = line.replace("[", "").replace("]", "")
} else if (line.trim().isEmpty()) { } else if (line.trim().isEmpty()) {
// Empty line // Empty line
continue continue
@ -84,3 +89,22 @@ fun parseRawJsonSpecsFile(context: Context, path: String): HashMap<String, Strin
} }
return cachedVNTelexData return cachedVNTelexData
} }
data class EmojiData(
val category: String,
val emoji: String,
val variants: List<String>
) {
fun getCategoryIcon(): Int =
when (category) {
"people_body" -> R.drawable.ic_emoji_category_people
"animals_nature" -> R.drawable.ic_emoji_category_animals
"food_drink" -> R.drawable.ic_emoji_category_food
"travel_places" -> R.drawable.ic_emoji_category_travel
"activities" -> R.drawable.ic_emoji_category_activities
"objects" -> R.drawable.ic_emoji_category_objects
"symbols" -> R.drawable.ic_emoji_category_symbols
"flags" -> R.drawable.ic_emoji_category_flags
else -> R.drawable.ic_emoji_category_smileys
}
}

View file

@ -7,6 +7,7 @@ import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.* import android.graphics.*
import android.graphics.Paint.Align import android.graphics.Paint.Align
import android.graphics.drawable.* import android.graphics.drawable.*
@ -19,6 +20,7 @@ import android.util.TypedValue
import android.view.* import android.view.*
import android.view.animation.AccelerateInterpolator import android.view.animation.AccelerateInterpolator
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.ImageButton
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.PopupWindow import android.widget.PopupWindow
import android.widget.TextView import android.widget.TextView
@ -29,6 +31,9 @@ import androidx.core.animation.doOnStart
import androidx.core.view.* import androidx.core.view.*
import androidx.emoji2.text.EmojiCompat import androidx.emoji2.text.EmojiCompat
import androidx.emoji2.text.EmojiCompat.EMOJI_SUPPORTED import androidx.emoji2.text.EmojiCompat.EMOJI_SUPPORTED
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
import androidx.recyclerview.widget.LinearLayoutManager
import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import com.simplemobiletools.commons.helpers.isPiePlus import com.simplemobiletools.commons.helpers.isPiePlus
@ -37,6 +42,7 @@ import com.simplemobiletools.keyboard.activities.ManageClipboardItemsActivity
import com.simplemobiletools.keyboard.activities.SettingsActivity import com.simplemobiletools.keyboard.activities.SettingsActivity
import com.simplemobiletools.keyboard.adapters.ClipsKeyboardAdapter import com.simplemobiletools.keyboard.adapters.ClipsKeyboardAdapter
import com.simplemobiletools.keyboard.adapters.EmojisAdapter import com.simplemobiletools.keyboard.adapters.EmojisAdapter
import com.simplemobiletools.keyboard.databinding.ItemEmojiCategoryBinding
import com.simplemobiletools.keyboard.databinding.KeyboardKeyPreviewBinding import com.simplemobiletools.keyboard.databinding.KeyboardKeyPreviewBinding
import com.simplemobiletools.keyboard.databinding.KeyboardPopupKeyboardBinding import com.simplemobiletools.keyboard.databinding.KeyboardPopupKeyboardBinding
import com.simplemobiletools.keyboard.databinding.KeyboardViewKeyboardBinding import com.simplemobiletools.keyboard.databinding.KeyboardViewKeyboardBinding
@ -1468,9 +1474,8 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
emojiPaletteLabel.setTextColor(textColor) emojiPaletteLabel.setTextColor(textColor)
emojiPaletteBottomBar.background = ColorDrawable(backgroundColor) emojiPaletteBottomBar.background = ColorDrawable(backgroundColor)
val bottomTextColor = textColor.darkenColor()
emojiPaletteModeChange.apply { emojiPaletteModeChange.apply {
setTextColor(bottomTextColor) setTextColor(textColor)
setOnClickListener { setOnClickListener {
vibrateIfNeeded() vibrateIfNeeded()
closeEmojiPalette() closeEmojiPalette()
@ -1478,7 +1483,7 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
} }
emojiPaletteBackspace.apply { emojiPaletteBackspace.apply {
applyColorFilter(bottomTextColor) applyColorFilter(textColor)
setOnTouchListener { _, event -> setOnTouchListener { _, event ->
when (event.action) { when (event.action) {
MotionEvent.ACTION_DOWN -> { MotionEvent.ACTION_DOWN -> {
@ -1529,8 +1534,8 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
} }
val emojis = fullEmojiList.filter { emoji -> val emojis = fullEmojiList.filter { emoji ->
systemFontPaint.hasGlyph(emoji) || (EmojiCompat.get().loadState == EmojiCompat.LOAD_STATE_SUCCEEDED && EmojiCompat.get() systemFontPaint.hasGlyph(emoji.emoji) || (EmojiCompat.get().loadState == EmojiCompat.LOAD_STATE_SUCCEEDED && EmojiCompat.get()
.getEmojiMatch(emoji, emojiCompatMetadataVersion) == EMOJI_SUPPORTED) .getEmojiMatch(emoji.emoji, emojiCompatMetadataVersion) == EMOJI_SUPPORTED)
} }
Handler(Looper.getMainLooper()).post { Handler(Looper.getMainLooper()).post {
@ -1546,19 +1551,80 @@ class MyKeyboardView @JvmOverloads constructor(context: Context, attrs: Attribut
} }
} }
private fun setupEmojiAdapter(emojis: List<String>) { private fun setupEmojiAdapter(emojis: List<EmojiData>) {
val categories = emojis.groupBy { it.category }
val allItems = mutableListOf<EmojisAdapter.Item>()
categories.entries.forEach { (category, emojis) ->
allItems.add(EmojisAdapter.Item.Category(category))
allItems.addAll(emojis.map(EmojisAdapter.Item::Emoji))
}
val checkIds = mutableMapOf<Int, String>()
keyboardViewBinding?.emojiCategoriesStrip?.apply {
weightSum = categories.count().toFloat()
val strip = this
removeAllViews()
categories.entries.forEach { (category, emojis) ->
ItemEmojiCategoryBinding.inflate(LayoutInflater.from(context), this, true).apply {
root.id = generateViewId()
checkIds[root.id] = category
root.setImageResource(emojis.first().getCategoryIcon())
root.layoutParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.MATCH_PARENT,
1f
)
root.setOnClickListener {
strip.children.filterIsInstance<ImageButton>().forEach {
it.imageTintList = ColorStateList.valueOf(mTextColor)
}
root.imageTintList = ColorStateList.valueOf(context.getProperPrimaryColor())
keyboardViewBinding?.emojisList?.stopScroll()
(keyboardViewBinding?.emojisList?.layoutManager as? GridLayoutManager)?.scrollToPositionWithOffset(
allItems.indexOfFirst { it is EmojisAdapter.Item.Category && it.value == category },
0
)
}
root.imageTintList = ColorStateList.valueOf(mTextColor)
}
}
}
keyboardViewBinding?.emojisList?.apply { keyboardViewBinding?.emojisList?.apply {
val emojiItemWidth = context.resources.getDimensionPixelSize(R.dimen.emoji_item_size) val emojiItemWidth = context.resources.getDimensionPixelSize(R.dimen.emoji_item_size)
val emojiTopBarElevation = context.resources.getDimensionPixelSize(R.dimen.emoji_top_bar_elevation).toFloat() val emojiTopBarElevation = context.resources.getDimensionPixelSize(R.dimen.emoji_top_bar_elevation).toFloat()
layoutManager = AutoGridLayoutManager(context, emojiItemWidth) layoutManager = AutoGridLayoutManager(context, emojiItemWidth).apply {
adapter = EmojisAdapter(context = context, items = emojis) { emoji -> spanSizeLookup = object : SpanSizeLookup() {
mOnKeyboardActionListener!!.onText(emoji) override fun getSpanSize(position: Int): Int =
if (allItems[position] is EmojisAdapter.Item.Category) {
spanCount
} else {
1
}
}
}
adapter = EmojisAdapter(context = context, items = allItems) { emoji ->
mOnKeyboardActionListener!!.onText(emoji.emoji)
vibrateIfNeeded() vibrateIfNeeded()
} }
clearOnScrollListeners()
onScroll { onScroll {
keyboardViewBinding!!.emojiPaletteTopBar.elevation = if (it > 4) emojiTopBarElevation else 0f keyboardViewBinding!!.emojiPaletteTopBar.elevation = if (it > 4) emojiTopBarElevation else 0f
(keyboardViewBinding?.emojisList?.layoutManager as? LinearLayoutManager)?.findFirstCompletelyVisibleItemPosition()?.also { firstVisibleIndex ->
allItems
.withIndex()
.lastOrNull { it.value is EmojisAdapter.Item.Category && it.index <= firstVisibleIndex }
?.also { activeCategory ->
val id = checkIds.entries.first { it.value == (activeCategory.value as EmojisAdapter.Item.Category).value }.key
keyboardViewBinding?.emojiCategoriesStrip?.children?.filterIsInstance<ImageButton>()?.forEach {
if (it.id == id) {
it.imageTintList = ColorStateList.valueOf(context.getProperPrimaryColor())
} else {
it.imageTintList = ColorStateList.valueOf(mTextColor)
}
}
}
}
} }
} }
} }

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19,5h-2V3H7v2H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H7v2h10v-2h-4v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM5,8V7h2v3.82C5.84,10.4 5,9.3 5,8zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z"/>
</vector>

View file

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21.94,4.88C21.76,4.35 21.25,4 20.68,4c-0.03,0 -0.06,0 -0.09,0H19.6l-0.31,-0.97C19.15,2.43 18.61,2 18,2h0c-0.61,0 -1.15,0.43 -1.29,1.04L16.4,4h-0.98c-0.03,0 -0.06,0 -0.09,0c-0.57,0 -1.08,0.35 -1.26,0.88c-0.19,0.56 0.04,1.17 0.56,1.48l0.87,0.52L15.1,8.12c-0.23,0.58 -0.04,1.25 0.45,1.62C15.78,9.91 16.06,10 16.33,10c0.31,0 0.61,-0.11 0.86,-0.32L18,8.98l0.81,0.7C19.06,9.89 19.36,10 19.67,10c0.27,0 0.55,-0.09 0.78,-0.26c0.5,-0.37 0.68,-1.04 0.45,-1.62l-0.39,-1.24l0.87,-0.52C21.89,6.05 22.12,5.44 21.94,4.88zM18,7c-0.55,0 -1,-0.45 -1,-1c0,-0.55 0.45,-1 1,-1s1,0.45 1,1C19,6.55 18.55,7 18,7z"/>
<path android:fillColor="@android:color/white" android:pathData="M13.49,10.51c-0.43,-0.43 -0.94,-0.73 -1.49,-0.93V8h-1v1.38c-0.11,-0.01 -0.23,-0.03 -0.34,-0.03c-1.02,0 -2.05,0.39 -2.83,1.17c-0.16,0.16 -0.3,0.34 -0.43,0.53L6,10.52c-1.56,-0.55 -3.28,0.27 -3.83,1.82c0,0 0,0 0,0c-0.27,0.75 -0.23,1.57 0.12,2.29c0.23,0.48 0.58,0.87 1,1.16c-0.38,1.35 -0.06,2.85 1,3.91c1.06,1.06 2.57,1.38 3.91,1c0.29,0.42 0.68,0.77 1.16,1C9.78,21.9 10.21,22 10.65,22c0.34,0 0.68,-0.06 1.01,-0.17c0,0 0,0 0,0c1.56,-0.55 2.38,-2.27 1.82,-3.85l-0.52,-1.37c0.18,-0.13 0.36,-0.27 0.53,-0.43c0.87,-0.87 1.24,-2.04 1.14,-3.17H16v-1h-1.59C14.22,11.46 13.92,10.95 13.49,10.51zM4.67,14.29c-0.25,-0.09 -0.45,-0.27 -0.57,-0.51s-0.13,-0.51 -0.04,-0.76c0.19,-0.52 0.76,-0.79 1.26,-0.61l3.16,1.19C7.33,14.2 5.85,14.71 4.67,14.29zM10.99,19.94c-0.25,0.09 -0.52,0.08 -0.76,-0.04c-0.24,-0.11 -0.42,-0.32 -0.51,-0.57c-0.42,-1.18 0.09,-2.65 0.7,-3.8l1.18,3.13C11.78,19.18 11.51,19.76 10.99,19.94zM12.2,14.6l-0.61,-1.61c0,-0.01 -0.01,-0.02 -0.02,-0.03c-0.02,-0.04 -0.04,-0.08 -0.06,-0.12c-0.02,-0.04 -0.04,-0.07 -0.07,-0.11c-0.03,-0.03 -0.06,-0.06 -0.09,-0.09c-0.03,-0.03 -0.06,-0.06 -0.09,-0.09c-0.03,-0.03 -0.07,-0.05 -0.11,-0.07c-0.04,-0.02 -0.07,-0.05 -0.12,-0.06c-0.01,0 -0.02,-0.01 -0.03,-0.02L9.4,11.8c0.36,-0.29 0.79,-0.46 1.26,-0.46c0.53,0 1.04,0.21 1.41,0.59C12.8,12.66 12.84,13.81 12.2,14.6z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M14.4,6L14,4H5v17h2v-7h5.6l0.4,2h7V6z"/>
</vector>

View file

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,3H9v2.4l1.81,1.45C10.93,6.94 11,7.09 11,7.24v4.26c0,0.28 -0.22,0.5 -0.5,0.5h-4C6.22,12 6,11.78 6,11.5V7.24c0,-0.15 0.07,-0.3 0.19,-0.39L8,5.4V3H4v10c0,2.21 1.79,4 4,4h6c2.21,0 4,-1.79 4,-4v-3h2c1.11,0 2,-0.9 2,-2V5C22,3.89 21.11,3 20,3zM20,8h-2V5h2V8z"/>
<path android:fillColor="@android:color/white" android:pathData="M4,19h16v2h-16z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,3c-0.46,0 -0.93,0.04 -1.4,0.14C7.84,3.67 5.64,5.9 5.12,8.66c-0.48,2.61 0.48,5.01 2.22,6.56C7.77,15.6 8,16.13 8,16.69V19c0,1.1 0.9,2 2,2h0.28c0.35,0.6 0.98,1 1.72,1s1.38,-0.4 1.72,-1H14c1.1,0 2,-0.9 2,-2v-2.31c0,-0.55 0.22,-1.09 0.64,-1.46C18.09,13.95 19,12.08 19,10C19,6.13 15.87,3 12,3zM14,19h-4v-1h4V19zM14,17h-4v-1h4V17zM12.5,11.41V14h-1v-2.59L9.67,9.59l0.71,-0.71L12,10.5l1.62,-1.62l0.71,0.71L12.5,11.41z"/>
</vector>

View file

@ -0,0 +1,6 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,4m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0"/>
<path android:fillColor="@android:color/white" android:pathData="M15.89,8.11C15.5,7.72 14.83,7 13.53,7c-0.21,0 -1.42,0 -2.54,0C8.24,6.99 6,4.75 6,2H4c0,3.16 2.11,5.84 5,6.71V22h2v-6h2v6h2V10.05L18.95,14l1.41,-1.41L15.89,8.11z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M11.99,2C6.47,2 2,6.48 2,12c0,5.52 4.47,10 9.99,10C17.52,22 22,17.52 22,12C22,6.48 17.52,2 11.99,2zM8.5,8C9.33,8 10,8.67 10,9.5S9.33,11 8.5,11S7,10.33 7,9.5S7.67,8 8.5,8zM12,18c-2.28,0 -4.22,-1.66 -5,-4h10C16.22,16.34 14.28,18 12,18zM15.5,11c-0.83,0 -1.5,-0.67 -1.5,-1.5S14.67,8 15.5,8S17,8.67 17,9.5S16.33,11 15.5,11z"/>
</vector>

View file

@ -0,0 +1,11 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M3,2h8v2h-8z"/>
<path android:fillColor="@android:color/white" android:pathData="M6,11l2,0l0,-4l3,0l0,-2l-8,0l0,2l3,0z"/>
<path android:fillColor="@android:color/white" android:pathData="M12.4036,20.1819l7.7781,-7.7781l1.4142,1.4142l-7.7781,7.7781z"/>
<path android:fillColor="@android:color/white" android:pathData="M14.5,14.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path android:fillColor="@android:color/white" android:pathData="M19.5,19.5m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
<path android:fillColor="@android:color/white" android:pathData="M15.5,11c1.38,0 2.5,-1.12 2.5,-2.5V4h3V2h-4v4.51C16.58,6.19 16.07,6 15.5,6C14.12,6 13,7.12 13,8.5C13,9.88 14.12,11 15.5,11z"/>
<path android:fillColor="@android:color/white" android:pathData="M9.74,15.96l-1.41,1.41l-0.71,-0.71l0.35,-0.35c0.98,-0.98 0.98,-2.56 0,-3.54c-0.49,-0.49 -1.13,-0.73 -1.77,-0.73c-0.64,0 -1.28,0.24 -1.77,0.73c-0.98,0.98 -0.98,2.56 0,3.54l0.35,0.35l-1.06,1.06c-0.98,0.98 -0.98,2.56 0,3.54C4.22,21.76 4.86,22 5.5,22s1.28,-0.24 1.77,-0.73l1.06,-1.06l1.41,1.41l1.41,-1.41l-1.41,-1.41l1.41,-1.41L9.74,15.96zM5.85,14.2c0.12,-0.12 0.26,-0.15 0.35,-0.15s0.23,0.03 0.35,0.15c0.19,0.2 0.19,0.51 0,0.71l-0.35,0.35L5.85,14.9C5.66,14.71 5.66,14.39 5.85,14.2zM5.85,19.85C5.73,19.97 5.59,20 5.5,20s-0.23,-0.03 -0.35,-0.15c-0.19,-0.19 -0.19,-0.51 0,-0.71l1.06,-1.06l0.71,0.71L5.85,19.85z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.3,16.9c0.4,-0.7 0.7,-1.5 0.7,-2.4c0,-2.5 -2,-4.5 -4.5,-4.5S11,12 11,14.5s2,4.5 4.5,4.5c0.9,0 1.7,-0.3 2.4,-0.7l3.2,3.2l1.4,-1.4L19.3,16.9zM15.5,17c-1.4,0 -2.5,-1.1 -2.5,-2.5s1.1,-2.5 2.5,-2.5s2.5,1.1 2.5,2.5S16.9,17 15.5,17zM12,20v2C6.48,22 2,17.52 2,12C2,6.48 6.48,2 12,2c4.84,0 8.87,3.44 9.8,8h-2.07c-0.64,-2.46 -2.4,-4.47 -4.73,-5.41V5c0,1.1 -0.9,2 -2,2h-2v2c0,0.55 -0.45,1 -1,1H8v2h2v3H9l-4.79,-4.79C4.08,10.79 4,11.38 4,12C4,16.41 7.59,20 12,20z"/>
</vector>

View file

@ -0,0 +1,8 @@
<com.simplemobiletools.commons.views.MyRecyclerView
android:id="@+id/emojis_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:padding="@dimen/small_margin"
android:scrollbars="vertical"
xmlns:android="http://schemas.android.com/apk/res/android" />

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/emoji_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/ripple_all_corners_medium"
android:gravity="center"
android:importantForAccessibility="no"
android:padding="@dimen/tiny_margin"
android:scaleType="centerInside"
android:src="@drawable/ic_emoji_category_activities" />

View file

@ -202,6 +202,18 @@
android:text="@string/abc" android:text="@string/abc"
android:textStyle="bold" /> android:textStyle="bold" />
<LinearLayout
android:id="@+id/emoji_categories_strip"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginStart="@dimen/medium_margin"
android:layout_marginEnd="@dimen/medium_margin"
android:layout_toStartOf="@+id/emoji_palette_backspace"
android:layout_toEndOf="@+id/emoji_palette_mode_change"
android:gravity="center"
android:orientation="horizontal" />
<ImageButton <ImageButton
android:id="@+id/emoji_palette_backspace" android:id="@+id/emoji_palette_backspace"
android:layout_width="@dimen/emoji_palette_btn_size" android:layout_width="@dimen/emoji_palette_btn_size"

View file

@ -9,6 +9,7 @@
<dimen name="vertical_correction">-10dp</dimen> <dimen name="vertical_correction">-10dp</dimen>
<dimen name="clip_pin_size">28dp</dimen> <dimen name="clip_pin_size">28dp</dimen>
<dimen name="emoji_item_size">46dp</dimen> <dimen name="emoji_item_size">46dp</dimen>
<dimen name="emoji_category_item_size">24dp</dimen>
<dimen name="emoji_top_bar_elevation">4dp</dimen> <dimen name="emoji_top_bar_elevation">4dp</dimen>
<dimen name="emoji_palette_btn_size">42dp</dimen> <dimen name="emoji_palette_btn_size">42dp</dimen>
<dimen name="suggestion_max_width">200dp</dimen> <dimen name="suggestion_max_width">200dp</dimen>
@ -17,4 +18,5 @@
<dimen name="preview_text_size">26sp</dimen> <dimen name="preview_text_size">26sp</dimen>
<dimen name="label_text_size">16sp</dimen> <!-- text size used at keys with longer labels, like "123" --> <dimen name="label_text_size">16sp</dimen> <!-- text size used at keys with longer labels, like "123" -->
<dimen name="emoji_text_size">28sp</dimen> <dimen name="emoji_text_size">28sp</dimen>
<dimen name="emoji_category_text_size">14sp</dimen>
</resources> </resources>