Group emojis in the picker

This commit is contained in:
fruye 2022-12-04 14:44:59 +01:00
parent 0f55cb0388
commit 2f79b4f8b2
6 changed files with 124 additions and 31 deletions

View File

@ -31,10 +31,15 @@ class EmojiAdapter(
private val animate: Boolean
) : RecyclerView.Adapter<BindingHolder<ItemEmojiButtonBinding>>() {
private val emojiList: List<Emoji> = emojiList.filter { emoji -> emoji.visibleInPicker == null || emoji.visibleInPicker }
private val groupedEmojiList = emojiList.filter { emoji -> emoji.visibleInPicker ?: true }
.sortedBy { it.shortcode.lowercase(Locale.ROOT) }
.groupBy { emoji -> emoji.category.orEmpty() }
.toList().sortedBy { it.first.lowercase(Locale.ROOT) }.toTypedArray()
private var currentEmojiList: List<Emoji> = groupedEmojiList.firstOrNull()?.second ?: emptyList()
override fun getItemCount() = emojiList.size
override fun getItemCount() = currentEmojiList.size
fun getGroupedEmojiList() = groupedEmojiList
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingHolder<ItemEmojiButtonBinding> {
val binding = ItemEmojiButtonBinding.inflate(LayoutInflater.from(parent.context), parent, false)
@ -42,7 +47,7 @@ class EmojiAdapter(
}
override fun onBindViewHolder(holder: BindingHolder<ItemEmojiButtonBinding>, position: Int) {
val emoji = emojiList[position]
val emoji = currentEmojiList[position]
val emojiImageView = holder.binding.root
if (animate) {
@ -63,6 +68,11 @@ class EmojiAdapter(
emojiImageView.contentDescription = emoji.shortcode
TooltipCompat.setTooltipText(emojiImageView, emoji.shortcode)
}
fun changeGroup(index: Int) {
currentEmojiList = groupedEmojiList[index].second
notifyDataSetChanged()
}
}
interface OnEmojiSelectedListener {

View File

@ -33,7 +33,6 @@ import com.google.android.material.color.MaterialColors
import com.keylesspalace.tusky.BottomSheetActivity
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.StatusListActivity
import com.keylesspalace.tusky.adapter.EmojiAdapter
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
import com.keylesspalace.tusky.databinding.ActivityAnnouncementsBinding
import com.keylesspalace.tusky.di.Injectable
@ -69,17 +68,8 @@ class AnnouncementsActivity :
private lateinit var adapter: AnnouncementAdapter
private val picker by unsafeLazy { EmojiPicker(this) }
private val pickerDialog by unsafeLazy {
PopupWindow(this)
.apply {
contentView = picker
isFocusable = true
setOnDismissListener {
currentAnnouncementId = null
}
}
}
private lateinit var emojiPicker : EmojiPicker
private lateinit var pickerDialog : PopupWindow
private var currentAnnouncementId: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
@ -110,6 +100,17 @@ class AnnouncementsActivity :
binding.announcementsList.adapter = adapter
val emojiPopupView = layoutInflater.inflate(R.layout.emoji_picker, null)
emojiPicker = EmojiPicker(emojiPopupView)
pickerDialog = PopupWindow(this)
.apply {
contentView = emojiPopupView
isFocusable = true
setOnDismissListener {
currentAnnouncementId = null
}
}
viewModel.announcements.observe(this) {
when (it) {
is Success -> {
@ -138,7 +139,7 @@ class AnnouncementsActivity :
}
viewModel.emojis.observe(this) {
picker.adapter = EmojiAdapter(it, this, animateEmojis)
emojiPicker.populateEmojis(it, this, animateEmojis)
}
viewModel.load()

View File

@ -72,6 +72,7 @@ import com.canhub.cropper.options
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.color.MaterialColors
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.tabs.TabLayout
import com.keylesspalace.tusky.BaseActivity
import com.keylesspalace.tusky.BuildConfig
import com.keylesspalace.tusky.R
@ -111,6 +112,7 @@ import com.keylesspalace.tusky.util.show
import com.keylesspalace.tusky.util.unsafeLazy
import com.keylesspalace.tusky.util.viewBinding
import com.keylesspalace.tusky.util.visible
import com.keylesspalace.tusky.view.EmojiPicker
import com.mikepenz.iconics.IconicsDrawable
import com.mikepenz.iconics.typeface.library.googlematerial.GoogleMaterial
import com.mikepenz.iconics.utils.colorInt
@ -149,6 +151,7 @@ class ComposeActivity :
private lateinit var emojiBehavior: BottomSheetBehavior<*>
private lateinit var scheduleBehavior: BottomSheetBehavior<*>
private lateinit var previewBehavior: BottomSheetBehavior<*>
private lateinit var emojiPicker: EmojiPicker
/** The account that is being used to compose the status */
private lateinit var activeAccount: AccountEntity
@ -511,7 +514,8 @@ class ComposeActivity :
composeOptionsBehavior = BottomSheetBehavior.from(binding.composeOptionsBottomSheet)
addMediaBehavior = BottomSheetBehavior.from(binding.addMediaBottomSheet)
scheduleBehavior = BottomSheetBehavior.from(binding.composeScheduleView)
emojiBehavior = BottomSheetBehavior.from(binding.emojiView)
emojiBehavior = BottomSheetBehavior.from(binding.emojiPicker)
emojiPicker = EmojiPicker(binding.emojiPicker);
previewBehavior = BottomSheetBehavior.from(binding.previewScroll)
enableButton(binding.composeEmojiButton, clickable = false, colorActive = false)
@ -1296,7 +1300,7 @@ class ComposeActivity :
private fun setEmojiList(emojiList: List<Emoji>?) {
if (emojiList != null) {
val animateEmojis = preferences.getBoolean(PrefKeys.ANIMATE_CUSTOM_EMOJIS, false)
binding.emojiView.adapter = EmojiAdapter(emojiList, this@ComposeActivity, animateEmojis)
emojiPicker.populateEmojis(emojiList, this@ComposeActivity, animateEmojis)
enableButton(binding.composeEmojiButton, true, emojiList.isNotEmpty())
}
}

View File

@ -1,17 +1,45 @@
package com.keylesspalace.tusky.view
import android.content.Context
import android.util.AttributeSet
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.tabs.TabLayout
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.adapter.EmojiAdapter
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
import com.keylesspalace.tusky.entity.Emoji
class EmojiPicker @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : RecyclerView(context, attrs) {
class EmojiPicker constructor(view: View) {
private val emojiView : RecyclerView
private val tabs : TabLayout
init {
clipToPadding = false
layoutManager = GridLayoutManager(context, 3, GridLayoutManager.HORIZONTAL, false)
emojiView = view.findViewById(R.id.emojiView)
emojiView.apply {
layoutManager = GridLayoutManager(view.context, 3, GridLayoutManager.HORIZONTAL, false)
clipToPadding = false
}
tabs = view.findViewById(R.id.emojiCategoryTabLayout)
}
fun populateEmojis(emojis: List<Emoji>, onEmojiSelectedListener: OnEmojiSelectedListener, animateEmojis: Boolean) {
emojiView.adapter = EmojiAdapter(emojis, onEmojiSelectedListener, animateEmojis)
val emojiAdapter = emojiView.adapter as EmojiAdapter
emojiAdapter.getGroupedEmojiList().forEach { (category, _) ->
val newTab = tabs.newTab()
newTab.text = if (category.isEmpty()) "Unsorted" else category.removePrefix("pack:") // pleroma prefixes categories with "pack:".. why though?
tabs.addTab(newTab)
}
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
emojiAdapter.changeGroup(tab.position)
}
override fun onTabUnselected(tab: TabLayout.Tab?) { }
override fun onTabReselected(tab: TabLayout.Tab?) { }
})
}
}

View File

@ -236,19 +236,37 @@
android:textSize="?attr/status_text_medium" />
</LinearLayout>
<com.keylesspalace.tusky.view.EmojiPicker
android:id="@+id/emojiView"
<LinearLayout
android:id="@+id/emojiPicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:orientation="vertical"
android:elevation="12dp"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="60dp"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" >
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/emojiView"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/emojiCategoryTabLayout"
style="@style/TuskyTabAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:tabGravity="center"
app:tabIndicatorGravity="top"
app:tabMode="scrollable"
app:tabTextAppearance="@style/TuskyTabAppearance" />
</LinearLayout>
<com.keylesspalace.tusky.components.compose.view.ComposeOptionsView
android:id="@+id/composeOptionsBottomSheet"

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:orientation="vertical"
android:elevation="12dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/emojiView"
android:paddingStart="16dp"
android:paddingEnd="16dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/emojiCategoryTabLayout"
style="@style/TuskyTabAppearance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
app:tabGravity="center"
app:tabIndicatorGravity="top"
app:tabMode="scrollable"
app:tabTextAppearance="@style/TuskyTabAppearance" />
</LinearLayout>