From 97ffa142680f08e057ca5558148ea1c10703a6d8 Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 6 Mar 2020 21:04:14 +0300 Subject: [PATCH] emoji_reactions: general refactoring, implement emoji_reactions_by --- .../tusky/AccountListActivity.kt | 16 ++++- .../adapter/EmojiReactionViewHolder.java | 39 +++++++++++ .../tusky/adapter/EmojiReactionsAdapter.java | 70 +++++++++++++++++++ .../tusky/adapter/StatusBaseViewHolder.java | 18 ++++- .../adapter/StatusDetailedViewHolder.java | 57 --------------- .../tusky/fragment/AccountListFragment.kt | 49 ++++++++++--- .../tusky/fragment/SFragment.java | 29 ++++++++ .../tusky/fragment/ViewThreadFragment.java | 10 +-- .../interfaces/StatusActionListener.java | 4 +- .../tusky/network/MastodonApi.kt | 31 ++++---- app/src/main/res/menu/emoji_reaction_more.xml | 13 ++++ app/src/main/res/values/husky.xml | 11 ++- 12 files changed, 254 insertions(+), 93 deletions(-) create mode 100644 app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionViewHolder.java create mode 100644 app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionsAdapter.java create mode 100644 app/src/main/res/menu/emoji_reaction_more.xml diff --git a/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt b/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt index 6cf3367e..8f9a3435 100644 --- a/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/AccountListActivity.kt @@ -37,7 +37,8 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector { MUTES, FOLLOW_REQUESTS, REBLOGGED, - FAVOURITED + FAVOURITED, + REACTED } override fun onCreate(savedInstanceState: Bundle?) { @@ -46,6 +47,7 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector { val type = intent.getSerializableExtra(EXTRA_TYPE) as Type val id: String? = intent.getStringExtra(EXTRA_ID) + val emoji: String? = intent.getStringExtra(EXTRA_EMOJI) setSupportActionBar(toolbar) supportActionBar?.apply { @@ -57,6 +59,7 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector { Type.FOLLOWS -> setTitle(R.string.title_follows) Type.REBLOGGED -> setTitle(R.string.title_reblogged_by) Type.FAVOURITED -> setTitle(R.string.title_favourited_by) + Type.REACTED -> setTitle(R.string.title_emoji_reacted_by) } setDisplayHomeAsUpEnabled(true) setDisplayShowHomeEnabled(true) @@ -64,7 +67,7 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector { supportFragmentManager .beginTransaction() - .replace(R.id.fragment_container, AccountListFragment.newInstance(type, id)) + .replace(R.id.fragment_container, AccountListFragment.newInstance(type, id, emoji)) .commit() } @@ -83,13 +86,20 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector { companion object { private const val EXTRA_TYPE = "type" private const val EXTRA_ID = "id" + private const val EXTRA_EMOJI = "emoji" @JvmStatic - fun newIntent(context: Context, type: Type, id: String? = null): Intent { + fun newIntent(context: Context, type: Type, id: String?, emoji: String?): Intent { return Intent(context, AccountListActivity::class.java).apply { putExtra(EXTRA_TYPE, type) putExtra(EXTRA_ID, id) + putExtra(EXTRA_EMOJI, emoji) } } + + @JvmStatic + fun newIntent(context: Context, type: Type, id: String? = null): Intent { + return newIntent(context, type, id, null) + } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionViewHolder.java new file mode 100644 index 00000000..32753917 --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionViewHolder.java @@ -0,0 +1,39 @@ +package com.keylesspalace.tusky.adapter; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.emoji.widget.EmojiAppCompatButton; +import androidx.recyclerview.widget.RecyclerView; +import com.google.android.flexbox.FlexboxLayoutManager; + +import com.keylesspalace.tusky.R; +import com.keylesspalace.tusky.entity.Status; +import com.keylesspalace.tusky.entity.EmojiReaction; +import com.keylesspalace.tusky.interfaces.StatusActionListener; +import com.keylesspalace.tusky.util.CardViewMode; +import com.keylesspalace.tusky.util.LinkHelper; +import com.keylesspalace.tusky.util.StatusDisplayOptions; +import com.keylesspalace.tusky.viewdata.StatusViewData; + +import java.text.DateFormat; +import java.util.List; +import java.util.Date; + +public class EmojiReactionViewHolder extends RecyclerView.ViewHolder { + public EmojiAppCompatButton emojiReaction; + EmojiReactionViewHolder(View view) { + super(view); + emojiReaction = view.findViewById(R.id.status_emoji_reaction); + } +} + diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionsAdapter.java b/app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionsAdapter.java new file mode 100644 index 00000000..62ee1c4a --- /dev/null +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/EmojiReactionsAdapter.java @@ -0,0 +1,70 @@ +package com.keylesspalace.tusky.adapter; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; +import android.widget.Toast; +import android.util.Log; + +import androidx.annotation.Nullable; +import androidx.emoji.widget.EmojiAppCompatButton; +import androidx.recyclerview.widget.RecyclerView; + +import com.keylesspalace.tusky.R; +import com.keylesspalace.tusky.entity.Status; +import com.keylesspalace.tusky.entity.EmojiReaction; +import com.keylesspalace.tusky.interfaces.StatusActionListener; +import com.keylesspalace.tusky.util.CardViewMode; +import com.keylesspalace.tusky.util.LinkHelper; +import com.keylesspalace.tusky.util.StatusDisplayOptions; +import com.keylesspalace.tusky.viewdata.StatusViewData; + +import java.text.DateFormat; +import java.util.List; +import java.util.Date; + + +public class EmojiReactionsAdapter extends RecyclerView.Adapter { + private final List reactions; + private final StatusActionListener listener; + private final String statusId; + + EmojiReactionsAdapter(final List reactions, final StatusActionListener listener, final String statusId) { + this.reactions = reactions; + this.listener = listener; + this.statusId = statusId; + } + + @Override + public EmojiReactionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.item_emoji_reaction, parent, false); + return new EmojiReactionViewHolder(view); + } + + @Override + public void onBindViewHolder(EmojiReactionViewHolder holder, int position) { + EmojiReaction reaction = reactions.get(position); + String str = reaction.getName() + " " + reaction.getCount(); + + // no custom emoji yet! + holder.emojiReaction.setText(str); + holder.emojiReaction.setActivated(reaction.getMe()); + holder.emojiReaction.setOnClickListener(v -> { + listener.onEmojiReactMenu(v, reaction, statusId, position); + }); + } + + // total number of rows + @Override + public int getItemCount() { + return reactions.size(); + } +} + diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java index d0969630..1a4ec534 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusBaseViewHolder.java @@ -28,6 +28,7 @@ import com.bumptech.glide.Glide; import com.bumptech.glide.load.resource.bitmap.CenterCrop; import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners; import com.google.android.material.button.MaterialButton; +import com.google.android.flexbox.FlexboxLayoutManager; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.entity.Attachment; import com.keylesspalace.tusky.entity.Attachment.Focus; @@ -35,6 +36,7 @@ import com.keylesspalace.tusky.entity.Attachment.MetaData; import com.keylesspalace.tusky.entity.Card; import com.keylesspalace.tusky.entity.Emoji; import com.keylesspalace.tusky.entity.Status; +import com.keylesspalace.tusky.entity.EmojiReaction; import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.util.CardViewMode; import com.keylesspalace.tusky.util.CustomEmojiHelper; @@ -112,6 +114,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { private int avatarRadius24dp; private final Drawable mediaPreviewUnloaded; + + private RecyclerView emojiReactionsView; protected StatusBaseViewHolder(View itemView) { super(itemView); @@ -125,7 +129,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { favouriteButton = itemView.findViewById(R.id.status_favourite); bookmarkButton = itemView.findViewById(R.id.status_bookmark); moreButton = itemView.findViewById(R.id.status_more); - + emojiReactionsView = itemView.findViewById(R.id.status_emoji_reactions); + float INCREASE_HORIZONTAL_HIT_AREA = 20.0f; ViewExtensionsKt.increaseHitArea(replyButton, 0.0f, INCREASE_HORIZONTAL_HIT_AREA); @@ -700,6 +705,15 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { }) .show(); } + + private void setEmojiReactions(@Nullable List reactions, final StatusActionListener listener, final String statusId) { + if(emojiReactionsView != null && reactions != null && reactions.size() > 0) { + emojiReactionsView.setVisibility(View.VISIBLE); + FlexboxLayoutManager lm = new FlexboxLayoutManager(emojiReactionsView.getContext()); + emojiReactionsView.setLayoutManager(lm); + emojiReactionsView.setAdapter(new EmojiReactionsAdapter(reactions, listener, statusId)); + } + } public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener, StatusDisplayOptions statusDisplayOptions) { @@ -752,6 +766,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder { setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(), status.getMentions(), status.getStatusEmojis(), status.getPoll(), statusDisplayOptions, listener); setDescriptionForStatus(status, statusDisplayOptions); + + setEmojiReactions(status.getEmojiReactions(), listener, status.getId()); // Workaround for RecyclerView 1.0.0 / androidx.core 1.0.0 // RecyclerView tries to set AccessibilityDelegateCompat to null diff --git a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java index eb19103f..fcbc43f2 100644 --- a/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java +++ b/app/src/main/java/com/keylesspalace/tusky/adapter/StatusDetailedViewHolder.java @@ -33,14 +33,12 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder { private TextView reblogs; private TextView favourites; private View infoDivider; - private RecyclerView emojiReactionsView; StatusDetailedViewHolder(View view) { super(view); reblogs = view.findViewById(R.id.status_reblogs); favourites = view.findViewById(R.id.status_favourites); infoDivider = view.findViewById(R.id.status_info_divider); - emojiReactionsView = view.findViewById(R.id.status_emoji_reactions); } @Override @@ -108,60 +106,6 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder { } } - private class EmojiReactionViewHolder extends RecyclerView.ViewHolder { - public EmojiAppCompatButton emojiReaction; - EmojiReactionViewHolder(View view) { - super(view); - emojiReaction = view.findViewById(R.id.status_emoji_reaction); - } - } - - private class EmojiReactionsAdapter extends RecyclerView.Adapter { - private List reactions; - - EmojiReactionsAdapter(List reactions) { - this.reactions = reactions; - - } - - @Override - public EmojiReactionViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.item_emoji_reaction, parent, false); - return new EmojiReactionViewHolder(view); - } - - @Override - public void onBindViewHolder(EmojiReactionViewHolder holder, int position) { - EmojiReaction reaction = reactions.get(position); - String str = reaction.getName() + " " + reaction.getCount(); - - // no custom emoji yet! - holder.emojiReaction.setText(str); - holder.emojiReaction.setActivated(reaction.getMe()); - holder.emojiReaction.setOnClickListener(v -> {}); - } - - // total number of rows - @Override - public int getItemCount() { - return reactions.size(); - } - } - - private void setEmojiReactions(@Nullable List reactions) { - if(reactions != null) { - emojiReactionsView.setVisibility(View.VISIBLE); - FlexboxLayoutManager lm = new FlexboxLayoutManager(emojiReactionsView.getContext()); - // lm.setFlexDirection(FlexDirection.COLUMN); - // StaggeredGridLayoutManager.HORIZONTAL); - // lm.setGapStrategy(StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS); - emojiReactionsView.setLayoutManager(lm); - emojiReactionsView.setAdapter(new EmojiReactionsAdapter(reactions)); - //emojiReactionsView.setLayoutManager StaggeredGridLayoutManager - } - } - @Override protected void setupWithStatus(final StatusViewData.Concrete status, final StatusActionListener listener, @@ -173,7 +117,6 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder { setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener); setApplication(status.getApplication()); - setEmojiReactions(status.getEmojiReactions()); View.OnLongClickListener longClickListener = view -> { TextView textView = (TextView) view; ClipboardManager clipboard = (ClipboardManager) view.getContext().getSystemService(Context.CLIPBOARD_SERVICE); diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt index 62ba853e..3d689c6b 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/AccountListFragment.kt @@ -31,8 +31,7 @@ import com.keylesspalace.tusky.BaseActivity import com.keylesspalace.tusky.R import com.keylesspalace.tusky.adapter.* import com.keylesspalace.tusky.di.Injectable -import com.keylesspalace.tusky.entity.Account -import com.keylesspalace.tusky.entity.Relationship +import com.keylesspalace.tusky.entity.* import com.keylesspalace.tusky.interfaces.AccountActionListener import com.keylesspalace.tusky.network.MastodonApi import com.keylesspalace.tusky.util.HttpHeaderLink @@ -58,6 +57,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { private lateinit var type: Type private var id: String? = null + private var emojiReaction: String? = null private lateinit var scrollListener: EndlessOnScrollListener private lateinit var adapter: AccountAdapter @@ -68,6 +68,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { super.onCreate(savedInstanceState) type = arguments?.getSerializable(ARG_TYPE) as Type id = arguments?.getString(ARG_ID) + emojiReaction = arguments?.getString(ARG_EMOJI) } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { @@ -273,11 +274,22 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { val statusId = requireId(type, id) api.statusFavouritedBy(statusId, fromId) } + Type.REACTED -> { + // HACKHACK: make compiler happy + val statusId = requireId(type, id) + api.statusFavouritedBy(statusId, fromId) + } } } - - private fun requireId(type: Type, id: String?): String { - return requireNotNull(id) { "id must not be null for type "+type.name } + + private fun requireId(type: Type, id: String?, name: String = "id"): String { + return requireNotNull(id) { name+" must not be null for type "+type.name } + } + + private fun getEmojiReactionFetchCall(): Single>> { + val statusId = requireId(type, id) + val emoji = requireId(type, emojiReaction, "emoji") + return api.statusReactedBy(statusId, emoji) } private fun fetchAccounts(fromId: String? = null) { @@ -289,8 +301,25 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { if (fromId != null) { recyclerView.post { adapter.setBottomLoading(true) } } + + if(type == Type.REACTED) { + getEmojiReactionFetchCall() + .observeOn(AndroidSchedulers.mainThread()) + .autoDispose(from(this, Lifecycle.Event.ON_DESTROY)) + .subscribe({ response -> + val emojiReaction = response.body() - getFetchCallByListType(fromId) + if (response.isSuccessful && emojiReaction != null && emojiReaction.size > 0 && emojiReaction.get(0).accounts != null) { + val linkHeader = response.headers()["Link"] + onFetchAccountsSuccess(emojiReaction.get(0).accounts!!, linkHeader) + } else { + onFetchAccountsFailure(Exception(response.message())) + } + }, {throwable -> + onFetchAccountsFailure(throwable) + }) + } else { + getFetchCallByListType(fromId) .observeOn(AndroidSchedulers.mainThread()) .autoDispose(from(this, Lifecycle.Event.ON_DESTROY)) .subscribe({ response -> @@ -305,7 +334,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { }, {throwable -> onFetchAccountsFailure(throwable) }) - + } } private fun onFetchAccountsSuccess(accounts: List, linkHeader: String?) { @@ -361,12 +390,14 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable { private const val TAG = "AccountList" // logging tag private const val ARG_TYPE = "type" private const val ARG_ID = "id" + private const val ARG_EMOJI = "emoji" - fun newInstance(type: Type, id: String? = null): AccountListFragment { + fun newInstance(type: Type, id: String? = null, emoji: String? = null): AccountListFragment { return AccountListFragment().apply { - arguments = Bundle(2).apply { + arguments = Bundle(3).apply { putSerializable(ARG_TYPE, type) putString(ARG_ID, id) + putString(ARG_EMOJI, emoji) } } } diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java index f963ab52..3395c396 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/SFragment.java @@ -43,6 +43,7 @@ import androidx.lifecycle.Lifecycle; import com.keylesspalace.tusky.BaseActivity; import com.keylesspalace.tusky.BottomSheetActivity; import com.keylesspalace.tusky.MainActivity; +import com.keylesspalace.tusky.AccountListActivity; import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.PostLookupFallbackBehavior; import com.keylesspalace.tusky.ViewMediaActivity; @@ -57,6 +58,7 @@ import com.keylesspalace.tusky.entity.Attachment; import com.keylesspalace.tusky.entity.Filter; import com.keylesspalace.tusky.entity.PollOption; import com.keylesspalace.tusky.entity.Status; +import com.keylesspalace.tusky.entity.EmojiReaction; import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.network.TimelineCases; import com.keylesspalace.tusky.viewdata.AttachmentViewData; @@ -172,6 +174,33 @@ public abstract class SFragment extends BaseFragment implements Injectable { Intent intent = ComposeActivity.startIntent(getContext(), composeOptions); getActivity().startActivity(intent); } + + protected void emojiReactMenu(@NonNull final String statusId, @NonNull final EmojiReaction reaction, View view, final int position) { + PopupMenu popup = new PopupMenu(getContext(), view); + + popup.inflate(R.menu.emoji_reaction_more); + Menu menu = popup.getMenu(); + menu.findItem(R.id.emoji_react).setVisible(!reaction.getMe()); + menu.findItem(R.id.emoji_unreact).setVisible(reaction.getMe()); + + popup.setOnMenuItemClickListener(item -> { + switch (item.getItemId()) { + case R.id.emoji_react: + // TODO + return true; + case R.id.emoji_unreact: + // TODO + return true; + case R.id.emoji_reacted_by: + Intent intent = AccountListActivity.newIntent(getContext(), AccountListActivity.Type.REACTED, statusId, reaction.getName()); + ((BaseActivity) getActivity()).startActivityWithSlideInAnimation(intent); + + return true; + } + return false; + }); + popup.show(); + } protected void more(@NonNull final Status status, View view, final int position) { final String id = status.getActionableId(); diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java index 2903894f..efcc4757 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java @@ -52,10 +52,7 @@ import com.keylesspalace.tusky.appstore.ReblogEvent; import com.keylesspalace.tusky.appstore.StatusComposedEvent; import com.keylesspalace.tusky.appstore.StatusDeletedEvent; import com.keylesspalace.tusky.di.Injectable; -import com.keylesspalace.tusky.entity.Filter; -import com.keylesspalace.tusky.entity.Poll; -import com.keylesspalace.tusky.entity.Status; -import com.keylesspalace.tusky.entity.StatusContext; +import com.keylesspalace.tusky.entity.*; import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.util.CardViewMode; @@ -747,4 +744,9 @@ public final class ViewThreadFragment extends SFragment implements protected void refreshAfterApplyingFilters() { onRefresh(); } + + @Override + public void onEmojiReactMenu(@NonNull View view, final EmojiReaction emoji, final String statusId, final int position) { + super.emojiReactMenu(statusId, emoji, view, position); + } } diff --git a/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java b/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java index 719d20c2..00fd4794 100644 --- a/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java +++ b/app/src/main/java/com/keylesspalace/tusky/interfaces/StatusActionListener.java @@ -18,6 +18,7 @@ package com.keylesspalace.tusky.interfaces; import android.view.View; import java.util.List; +import com.keylesspalace.tusky.entity.EmojiReaction; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -64,6 +65,7 @@ public interface StatusActionListener extends LinkListener { void onVoteInPoll(int position, @NonNull List choices); default void onMute(int position, boolean isMuted) {} - default void onEmojiReact(final boolean react, final String emoji, final int position) {}; + // default void onEmojiReact(final boolean react, final String emoji, final int position) {}; + default void onEmojiReactMenu(@NonNull View view, final EmojiReaction emoji, final String statusId, final int position) {}; } diff --git a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt index 9487591e..119867fb 100644 --- a/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt +++ b/app/src/main/java/com/keylesspalace/tusky/network/MastodonApi.kt @@ -588,19 +588,20 @@ interface MastodonApi { fun getNodeinfo(@Url url: String) : Single @PUT("api/v1/pleroma/statuses/{id}/reactions/{emoji}") - fun reactWithEmoji( - @Path("id") statusId: String, - @Path("emoji") emoji: String - ): Single - - @DELETE("api/v1/pleroma/statuses/{id}/reactions/{emoji}") - fun unreactWithEmoji( - @Path("id") statusId: String, - @Path("emoji") emoji: String - ): Single - - @GET("api/v1/pleroma/statuses/{id}/reactions") - fun statusReactedBy( - @Path("id") statusId: String - ): Single> + fun reactWithEmoji( + @Path("id") statusId: String, + @Path("emoji") emoji: String + ): Single + + @DELETE("api/v1/pleroma/statuses/{id}/reactions/{emoji}") + fun unreactWithEmoji( + @Path("id") statusId: String, + @Path("emoji") emoji: String + ): Single + + @GET("api/v1/pleroma/statuses/{id}/reactions/{emoji}") + fun statusReactedBy( + @Path("id") statusId: String, + @Path("emoji") emoji: String + ): Single>> } diff --git a/app/src/main/res/menu/emoji_reaction_more.xml b/app/src/main/res/menu/emoji_reaction_more.xml new file mode 100644 index 00000000..906afdd1 --- /dev/null +++ b/app/src/main/res/menu/emoji_reaction_more.xml @@ -0,0 +1,13 @@ + + + + + + + diff --git a/app/src/main/res/values/husky.xml b/app/src/main/res/values/husky.xml index e05ed178..1619f96f 100644 --- a/app/src/main/res/values/husky.xml +++ b/app/src/main/res/values/husky.xml @@ -2,8 +2,13 @@ Reply to Markdown - Mute conversation - Unmute conversation + Mute conversation + Unmute conversation + Add reaction + Remove reaction + Who reacted + + Emoji reacted by Application name Application website @@ -13,7 +18,7 @@ File size exceeds instance limits - %s reacted to your post with %s + %s reacted with %s to your post Emoji Reactions Notifications about new emoji reactions