[WIP] EMOJI REACTION PICKER!!
Honestly I don't know why most of the things here work. It's mostly done, but it's missing a few key things I'd like to have, but either don't know how to do it or just didn't finish it yet. - add the button functionality to more views (i've only added it to the timeline - thread, search, conversations and whatsonot don't react to it) - add unicode emojis to tabs (because pleroma doesn't support custom emojis reactions lulz) - set first emoji as a group name - etc
This commit is contained in:
parent
09dce64a78
commit
93bef32825
|
@ -95,6 +95,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
private final SparkButton reblogButton;
|
||||
private final SparkButton favouriteButton;
|
||||
private final SparkButton bookmarkButton;
|
||||
private final ImageButton reactButton;
|
||||
private final ImageButton moreButton;
|
||||
private final ConstraintLayout mediaContainer;
|
||||
protected final MediaPreviewLayout mediaPreview;
|
||||
|
@ -151,6 +152,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
reblogButton = itemView.findViewById(R.id.status_inset);
|
||||
favouriteButton = itemView.findViewById(R.id.status_favourite);
|
||||
bookmarkButton = itemView.findViewById(R.id.status_bookmark);
|
||||
reactButton = itemView.findViewById(R.id.status_react);
|
||||
moreButton = itemView.findViewById(R.id.status_more);
|
||||
emojiReactionsView = itemView.findViewById(R.id.status_emoji_reactions);
|
||||
quoteView = itemView.findViewById(R.id.status_quote_view);
|
||||
|
@ -199,7 +201,7 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
mediaPreviewUnloaded = new ColorDrawable(MaterialColors.getColor(itemView, R.attr.colorBackgroundAccent));
|
||||
|
||||
TouchDelegateHelper.expandTouchSizeToFillRow((ViewGroup) itemView, CollectionsKt.listOfNotNull(replyButton, reblogButton, favouriteButton, bookmarkButton, moreButton));
|
||||
TouchDelegateHelper.expandTouchSizeToFillRow((ViewGroup) itemView, CollectionsKt.listOfNotNull(replyButton, reblogButton, favouriteButton, bookmarkButton, reactButton, moreButton));
|
||||
}
|
||||
|
||||
protected void setDisplayName(String name, List<Emoji> customEmojis, StatusDisplayOptions statusDisplayOptions) {
|
||||
|
@ -732,6 +734,15 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
|||
return true;
|
||||
});
|
||||
|
||||
if (reactButton != null) {
|
||||
reactButton.setOnClickListener(v -> {
|
||||
int position = getBindingAdapterPosition();
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
listener.openReactionPicker(v, position);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
moreButton.setOnClickListener(v -> {
|
||||
int position = getBindingAdapterPosition();
|
||||
if (position != RecyclerView.NO_POSITION) {
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.view.MenuItem
|
|||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import android.widget.PopupWindow
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.MenuProvider
|
||||
import androidx.lifecycle.Lifecycle
|
||||
|
@ -31,16 +32,14 @@ import androidx.lifecycle.ViewModelProvider
|
|||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.paging.LoadState
|
||||
import androidx.preference.PreferenceManager
|
||||
import androidx.recyclerview.widget.DividerItemDecoration
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.recyclerview.widget.SimpleItemAnimator
|
||||
import androidx.recyclerview.widget.*
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
|
||||
import at.connyduck.sparkbutton.helpers.Utils
|
||||
import autodispose2.androidx.lifecycle.autoDispose
|
||||
import com.google.android.material.color.MaterialColors
|
||||
import com.keylesspalace.tusky.BaseActivity
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.adapter.OnEmojiSelectedListener
|
||||
import com.keylesspalace.tusky.adapter.StatusBaseViewHolder
|
||||
import com.keylesspalace.tusky.appstore.EventHub
|
||||
import com.keylesspalace.tusky.appstore.PreferenceChangedEvent
|
||||
|
@ -70,6 +69,7 @@ import com.keylesspalace.tusky.util.hide
|
|||
import com.keylesspalace.tusky.util.show
|
||||
import com.keylesspalace.tusky.util.unsafeLazy
|
||||
import com.keylesspalace.tusky.util.viewBinding
|
||||
import com.keylesspalace.tusky.view.EmojiPicker
|
||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData
|
||||
import com.keylesspalace.tusky.viewdata.StatusViewData
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
|
@ -90,7 +90,8 @@ class TimelineFragment :
|
|||
Injectable,
|
||||
ReselectableFragment,
|
||||
RefreshableFragment,
|
||||
MenuProvider {
|
||||
MenuProvider,
|
||||
OnEmojiSelectedListener {
|
||||
|
||||
@Inject
|
||||
lateinit var viewModelFactory: ViewModelFactory
|
||||
|
@ -147,6 +148,25 @@ class TimelineFragment :
|
|||
/** The user's preferred reading order */
|
||||
private lateinit var readingOrder: ReadingOrder
|
||||
|
||||
private lateinit var emojiView : View
|
||||
private val emojiPicker : EmojiPicker by lazy {
|
||||
emojiView = layoutInflater.inflate(R.layout.emoji_picker, null)
|
||||
EmojiPicker(emojiView)
|
||||
}
|
||||
private val pickerDialog : PopupWindow by lazy {
|
||||
PopupWindow(requireContext())
|
||||
.apply {
|
||||
contentView = emojiView
|
||||
isFocusable = true
|
||||
setOnDismissListener {
|
||||
pickerCurrentStatusId = null
|
||||
}
|
||||
}
|
||||
}
|
||||
private var pickerCurrentStatusId : String? = null
|
||||
|
||||
private lateinit var statusDisplayOptions : StatusDisplayOptions
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
|
||||
|
@ -178,7 +198,7 @@ class TimelineFragment :
|
|||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
readingOrder = ReadingOrder.from(preferences.getString(PrefKeys.READING_ORDER, null))
|
||||
|
||||
val statusDisplayOptions = StatusDisplayOptions(
|
||||
statusDisplayOptions = StatusDisplayOptions(
|
||||
animateAvatars = preferences.getBoolean(PrefKeys.ANIMATE_GIF_AVATARS, false),
|
||||
mediaPreviewEnabled = accountManager.activeAccount!!.mediaPreviewEnabled,
|
||||
useAbsoluteTime = preferences.getBoolean(PrefKeys.ABSOLUTE_TIME_VIEW, false),
|
||||
|
@ -277,6 +297,12 @@ class TimelineFragment :
|
|||
}
|
||||
}
|
||||
|
||||
viewLifecycleOwner.lifecycleScope.launch {
|
||||
viewModel.emoji.collectLatest {
|
||||
emojiPicker.populateEmojis(it, this@TimelineFragment, statusDisplayOptions.animateEmojis)
|
||||
}
|
||||
}
|
||||
|
||||
if (actionButtonPresent()) {
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||
hideFab = preferences.getBoolean("fabHide", false)
|
||||
|
@ -460,6 +486,17 @@ class TimelineFragment :
|
|||
(activity as BaseActivity).startActivityWithSlideInAnimation(intent)
|
||||
}
|
||||
|
||||
override fun openReactionPicker(target: View, position: Int) {
|
||||
val statusId = adapter.peek(position)?.asStatusOrNull()?.id ?: return
|
||||
pickerCurrentStatusId = statusId
|
||||
pickerDialog.showAsDropDown(target)
|
||||
}
|
||||
|
||||
override fun onEmojiSelected(shortcode: String) {
|
||||
onEmojiReact(pickerCurrentStatusId!!, shortcode, true)
|
||||
pickerDialog.dismiss()
|
||||
}
|
||||
|
||||
override fun onShowFavs(position: Int) {
|
||||
val statusId = adapter.peek(position)?.asStatusOrNull()?.id ?: return
|
||||
val intent = newIntent(requireContext(), AccountListActivity.Type.FAVOURITED, statusId)
|
||||
|
|
|
@ -438,7 +438,7 @@ abstract class SFragment : Fragment(), Injectable {
|
|||
.show()
|
||||
}
|
||||
|
||||
open fun onEmojiReact(id: String, emoji: String, react: Boolean) {
|
||||
fun onEmojiReact(id: String, emoji: String, react: Boolean) {
|
||||
lifecycleScope.launch {
|
||||
val result = timelineCases.react(id, emoji, react).exceptionOrNull()
|
||||
if (result != null) {
|
||||
|
|
|
@ -72,4 +72,6 @@ public interface StatusActionListener extends LinkListener {
|
|||
void clearWarningAction(int position);
|
||||
|
||||
default void onEmojiReactMenu(@NonNull View view, @NonNull final EmojiReaction emoji, String statusId) {}
|
||||
|
||||
default void openReactionPicker(View target, int position) {}
|
||||
}
|
||||
|
|
|
@ -410,7 +410,7 @@
|
|||
android:contentDescription="@string/action_favourite"
|
||||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_bookmark"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_react"
|
||||
app:layout_constraintStart_toEndOf="@id/status_inset"
|
||||
app:layout_constraintTop_toTopOf="@id/status_inset"
|
||||
sparkbutton:activeImage="@drawable/ic_favourite_active_24dp"
|
||||
|
@ -430,6 +430,20 @@
|
|||
app:layout_constraintTop_toTopOf="@id/status_inset"
|
||||
tools:text="" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/status_react"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@string/action_react"
|
||||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/status_reply"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_bookmark"
|
||||
app:layout_constraintStart_toEndOf="@id/status_favourite"
|
||||
app:layout_constraintTop_toTopOf="@id/status_reply"
|
||||
app:srcCompat="@drawable/ic_emoji_24dp" />
|
||||
|
||||
<at.connyduck.sparkbutton.SparkButton
|
||||
android:id="@+id/status_bookmark"
|
||||
android:layout_width="52dp"
|
||||
|
@ -439,7 +453,7 @@
|
|||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_more"
|
||||
app:layout_constraintStart_toEndOf="@id/status_favourite"
|
||||
app:layout_constraintStart_toEndOf="@id/status_react"
|
||||
app:layout_constraintTop_toTopOf="@id/status_reply"
|
||||
sparkbutton:activeImage="@drawable/ic_bookmark_active_24dp"
|
||||
sparkbutton:iconSize="28dp"
|
||||
|
|
|
@ -425,7 +425,7 @@
|
|||
android:contentDescription="@string/action_favourite"
|
||||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_bookmark"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_react"
|
||||
app:layout_constraintStart_toEndOf="@id/status_inset"
|
||||
app:layout_constraintTop_toTopOf="@id/status_inset"
|
||||
sparkbutton:activeImage="@drawable/ic_favourite_active_24dp"
|
||||
|
@ -434,6 +434,19 @@
|
|||
sparkbutton:primaryColor="@color/tusky_orange"
|
||||
sparkbutton:secondaryColor="@color/tusky_orange_light" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/status_react"
|
||||
style="@style/TuskyImageButton"
|
||||
android:layout_width="52dp"
|
||||
android:layout_height="48dp"
|
||||
android:contentDescription="@string/action_react"
|
||||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_bookmark"
|
||||
app:layout_constraintStart_toEndOf="@id/status_favourite"
|
||||
app:layout_constraintTop_toTopOf="@id/status_favourite"
|
||||
app:srcCompat="@drawable/ic_emoji_24dp" />
|
||||
|
||||
<at.connyduck.sparkbutton.SparkButton
|
||||
android:id="@+id/status_bookmark"
|
||||
android:layout_width="52dp"
|
||||
|
@ -443,7 +456,7 @@
|
|||
android:importantForAccessibility="no"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/status_more"
|
||||
app:layout_constraintStart_toEndOf="@id/status_favourite"
|
||||
app:layout_constraintStart_toEndOf="@id/status_react"
|
||||
app:layout_constraintTop_toTopOf="@id/status_reply"
|
||||
sparkbutton:activeImage="@drawable/ic_bookmark_active_24dp"
|
||||
sparkbutton:iconSize="28dp"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<string name="admin">Admin</string>
|
||||
<string name="moderator">Moderator</string>
|
||||
|
||||
<string name="action_react">React</string>
|
||||
<string name="action_emoji_react">Add reaction</string>
|
||||
<string name="action_emoji_unreact">Remove reaction</string>
|
||||
<string name="action_emoji_reacted_by">Who reacted</string>
|
||||
|
|
Loading…
Reference in New Issue