emoji_reactions: general refactoring, implement emoji_reactions_by
This commit is contained in:
parent
0257cd3b07
commit
97ffa14268
|
@ -37,7 +37,8 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
|
||||||
MUTES,
|
MUTES,
|
||||||
FOLLOW_REQUESTS,
|
FOLLOW_REQUESTS,
|
||||||
REBLOGGED,
|
REBLOGGED,
|
||||||
FAVOURITED
|
FAVOURITED,
|
||||||
|
REACTED
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -46,6 +47,7 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
|
||||||
|
|
||||||
val type = intent.getSerializableExtra(EXTRA_TYPE) as Type
|
val type = intent.getSerializableExtra(EXTRA_TYPE) as Type
|
||||||
val id: String? = intent.getStringExtra(EXTRA_ID)
|
val id: String? = intent.getStringExtra(EXTRA_ID)
|
||||||
|
val emoji: String? = intent.getStringExtra(EXTRA_EMOJI)
|
||||||
|
|
||||||
setSupportActionBar(toolbar)
|
setSupportActionBar(toolbar)
|
||||||
supportActionBar?.apply {
|
supportActionBar?.apply {
|
||||||
|
@ -57,6 +59,7 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
|
||||||
Type.FOLLOWS -> setTitle(R.string.title_follows)
|
Type.FOLLOWS -> setTitle(R.string.title_follows)
|
||||||
Type.REBLOGGED -> setTitle(R.string.title_reblogged_by)
|
Type.REBLOGGED -> setTitle(R.string.title_reblogged_by)
|
||||||
Type.FAVOURITED -> setTitle(R.string.title_favourited_by)
|
Type.FAVOURITED -> setTitle(R.string.title_favourited_by)
|
||||||
|
Type.REACTED -> setTitle(R.string.title_emoji_reacted_by)
|
||||||
}
|
}
|
||||||
setDisplayHomeAsUpEnabled(true)
|
setDisplayHomeAsUpEnabled(true)
|
||||||
setDisplayShowHomeEnabled(true)
|
setDisplayShowHomeEnabled(true)
|
||||||
|
@ -64,7 +67,7 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
|
||||||
|
|
||||||
supportFragmentManager
|
supportFragmentManager
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.replace(R.id.fragment_container, AccountListFragment.newInstance(type, id))
|
.replace(R.id.fragment_container, AccountListFragment.newInstance(type, id, emoji))
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,13 +86,20 @@ class AccountListActivity : BaseActivity(), HasAndroidInjector {
|
||||||
companion object {
|
companion object {
|
||||||
private const val EXTRA_TYPE = "type"
|
private const val EXTRA_TYPE = "type"
|
||||||
private const val EXTRA_ID = "id"
|
private const val EXTRA_ID = "id"
|
||||||
|
private const val EXTRA_EMOJI = "emoji"
|
||||||
|
|
||||||
@JvmStatic
|
@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 {
|
return Intent(context, AccountListActivity::class.java).apply {
|
||||||
putExtra(EXTRA_TYPE, type)
|
putExtra(EXTRA_TYPE, type)
|
||||||
putExtra(EXTRA_ID, id)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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<EmojiReactionViewHolder> {
|
||||||
|
private final List<EmojiReaction> reactions;
|
||||||
|
private final StatusActionListener listener;
|
||||||
|
private final String statusId;
|
||||||
|
|
||||||
|
EmojiReactionsAdapter(final List<EmojiReaction> 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import com.bumptech.glide.Glide;
|
||||||
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
|
||||||
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners;
|
import com.bumptech.glide.load.resource.bitmap.GranularRoundedCorners;
|
||||||
import com.google.android.material.button.MaterialButton;
|
import com.google.android.material.button.MaterialButton;
|
||||||
|
import com.google.android.flexbox.FlexboxLayoutManager;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.entity.Attachment;
|
import com.keylesspalace.tusky.entity.Attachment;
|
||||||
import com.keylesspalace.tusky.entity.Attachment.Focus;
|
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.Card;
|
||||||
import com.keylesspalace.tusky.entity.Emoji;
|
import com.keylesspalace.tusky.entity.Emoji;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
|
import com.keylesspalace.tusky.entity.EmojiReaction;
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.util.CardViewMode;
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
import com.keylesspalace.tusky.util.CustomEmojiHelper;
|
||||||
|
@ -112,6 +114,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
private int avatarRadius24dp;
|
private int avatarRadius24dp;
|
||||||
|
|
||||||
private final Drawable mediaPreviewUnloaded;
|
private final Drawable mediaPreviewUnloaded;
|
||||||
|
|
||||||
|
private RecyclerView emojiReactionsView;
|
||||||
|
|
||||||
protected StatusBaseViewHolder(View itemView) {
|
protected StatusBaseViewHolder(View itemView) {
|
||||||
super(itemView);
|
super(itemView);
|
||||||
|
@ -125,7 +129,8 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
favouriteButton = itemView.findViewById(R.id.status_favourite);
|
favouriteButton = itemView.findViewById(R.id.status_favourite);
|
||||||
bookmarkButton = itemView.findViewById(R.id.status_bookmark);
|
bookmarkButton = itemView.findViewById(R.id.status_bookmark);
|
||||||
moreButton = itemView.findViewById(R.id.status_more);
|
moreButton = itemView.findViewById(R.id.status_more);
|
||||||
|
emojiReactionsView = itemView.findViewById(R.id.status_emoji_reactions);
|
||||||
|
|
||||||
float INCREASE_HORIZONTAL_HIT_AREA = 20.0f;
|
float INCREASE_HORIZONTAL_HIT_AREA = 20.0f;
|
||||||
|
|
||||||
ViewExtensionsKt.increaseHitArea(replyButton, 0.0f, INCREASE_HORIZONTAL_HIT_AREA);
|
ViewExtensionsKt.increaseHitArea(replyButton, 0.0f, INCREASE_HORIZONTAL_HIT_AREA);
|
||||||
|
@ -700,6 +705,15 @@ public abstract class StatusBaseViewHolder extends RecyclerView.ViewHolder {
|
||||||
})
|
})
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setEmojiReactions(@Nullable List<EmojiReaction> 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,
|
public void setupWithStatus(StatusViewData.Concrete status, final StatusActionListener listener,
|
||||||
StatusDisplayOptions statusDisplayOptions) {
|
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);
|
setSpoilerAndContent(status.isExpanded(), status.getContent(), status.getSpoilerText(), status.getMentions(), status.getStatusEmojis(), status.getPoll(), statusDisplayOptions, listener);
|
||||||
|
|
||||||
setDescriptionForStatus(status, statusDisplayOptions);
|
setDescriptionForStatus(status, statusDisplayOptions);
|
||||||
|
|
||||||
|
setEmojiReactions(status.getEmojiReactions(), listener, status.getId());
|
||||||
|
|
||||||
// Workaround for RecyclerView 1.0.0 / androidx.core 1.0.0
|
// Workaround for RecyclerView 1.0.0 / androidx.core 1.0.0
|
||||||
// RecyclerView tries to set AccessibilityDelegateCompat to null
|
// RecyclerView tries to set AccessibilityDelegateCompat to null
|
||||||
|
|
|
@ -33,14 +33,12 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
private TextView reblogs;
|
private TextView reblogs;
|
||||||
private TextView favourites;
|
private TextView favourites;
|
||||||
private View infoDivider;
|
private View infoDivider;
|
||||||
private RecyclerView emojiReactionsView;
|
|
||||||
|
|
||||||
StatusDetailedViewHolder(View view) {
|
StatusDetailedViewHolder(View view) {
|
||||||
super(view);
|
super(view);
|
||||||
reblogs = view.findViewById(R.id.status_reblogs);
|
reblogs = view.findViewById(R.id.status_reblogs);
|
||||||
favourites = view.findViewById(R.id.status_favourites);
|
favourites = view.findViewById(R.id.status_favourites);
|
||||||
infoDivider = view.findViewById(R.id.status_info_divider);
|
infoDivider = view.findViewById(R.id.status_info_divider);
|
||||||
emojiReactionsView = view.findViewById(R.id.status_emoji_reactions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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<EmojiReactionViewHolder> {
|
|
||||||
private List<EmojiReaction> reactions;
|
|
||||||
|
|
||||||
EmojiReactionsAdapter(List<EmojiReaction> 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<EmojiReaction> 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
|
@Override
|
||||||
protected void setupWithStatus(final StatusViewData.Concrete status,
|
protected void setupWithStatus(final StatusViewData.Concrete status,
|
||||||
final StatusActionListener listener,
|
final StatusActionListener listener,
|
||||||
|
@ -173,7 +117,6 @@ class StatusDetailedViewHolder extends StatusBaseViewHolder {
|
||||||
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
setReblogAndFavCount(status.getReblogsCount(), status.getFavouritesCount(), listener);
|
||||||
|
|
||||||
setApplication(status.getApplication());
|
setApplication(status.getApplication());
|
||||||
setEmojiReactions(status.getEmojiReactions());
|
|
||||||
View.OnLongClickListener longClickListener = view -> {
|
View.OnLongClickListener longClickListener = view -> {
|
||||||
TextView textView = (TextView) view;
|
TextView textView = (TextView) view;
|
||||||
ClipboardManager clipboard = (ClipboardManager) view.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
ClipboardManager clipboard = (ClipboardManager) view.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
|
||||||
|
|
|
@ -31,8 +31,7 @@ import com.keylesspalace.tusky.BaseActivity
|
||||||
import com.keylesspalace.tusky.R
|
import com.keylesspalace.tusky.R
|
||||||
import com.keylesspalace.tusky.adapter.*
|
import com.keylesspalace.tusky.adapter.*
|
||||||
import com.keylesspalace.tusky.di.Injectable
|
import com.keylesspalace.tusky.di.Injectable
|
||||||
import com.keylesspalace.tusky.entity.Account
|
import com.keylesspalace.tusky.entity.*
|
||||||
import com.keylesspalace.tusky.entity.Relationship
|
|
||||||
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
import com.keylesspalace.tusky.interfaces.AccountActionListener
|
||||||
import com.keylesspalace.tusky.network.MastodonApi
|
import com.keylesspalace.tusky.network.MastodonApi
|
||||||
import com.keylesspalace.tusky.util.HttpHeaderLink
|
import com.keylesspalace.tusky.util.HttpHeaderLink
|
||||||
|
@ -58,6 +57,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
|
|
||||||
private lateinit var type: Type
|
private lateinit var type: Type
|
||||||
private var id: String? = null
|
private var id: String? = null
|
||||||
|
private var emojiReaction: String? = null
|
||||||
|
|
||||||
private lateinit var scrollListener: EndlessOnScrollListener
|
private lateinit var scrollListener: EndlessOnScrollListener
|
||||||
private lateinit var adapter: AccountAdapter
|
private lateinit var adapter: AccountAdapter
|
||||||
|
@ -68,6 +68,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
type = arguments?.getSerializable(ARG_TYPE) as Type
|
type = arguments?.getSerializable(ARG_TYPE) as Type
|
||||||
id = arguments?.getString(ARG_ID)
|
id = arguments?.getString(ARG_ID)
|
||||||
|
emojiReaction = arguments?.getString(ARG_EMOJI)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||||
|
@ -273,11 +274,22 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
val statusId = requireId(type, id)
|
val statusId = requireId(type, id)
|
||||||
api.statusFavouritedBy(statusId, fromId)
|
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 {
|
private fun requireId(type: Type, id: String?, name: String = "id"): String {
|
||||||
return requireNotNull(id) { "id must not be null for type "+type.name }
|
return requireNotNull(id) { name+" must not be null for type "+type.name }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getEmojiReactionFetchCall(): Single<Response<List<EmojiReaction>>> {
|
||||||
|
val statusId = requireId(type, id)
|
||||||
|
val emoji = requireId(type, emojiReaction, "emoji")
|
||||||
|
return api.statusReactedBy(statusId, emoji)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchAccounts(fromId: String? = null) {
|
private fun fetchAccounts(fromId: String? = null) {
|
||||||
|
@ -289,8 +301,25 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
if (fromId != null) {
|
if (fromId != null) {
|
||||||
recyclerView.post { adapter.setBottomLoading(true) }
|
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())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.autoDispose(from(this, Lifecycle.Event.ON_DESTROY))
|
.autoDispose(from(this, Lifecycle.Event.ON_DESTROY))
|
||||||
.subscribe({ response ->
|
.subscribe({ response ->
|
||||||
|
@ -305,7 +334,7 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
}, {throwable ->
|
}, {throwable ->
|
||||||
onFetchAccountsFailure(throwable)
|
onFetchAccountsFailure(throwable)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onFetchAccountsSuccess(accounts: List<Account>, linkHeader: String?) {
|
private fun onFetchAccountsSuccess(accounts: List<Account>, linkHeader: String?) {
|
||||||
|
@ -361,12 +390,14 @@ class AccountListFragment : BaseFragment(), AccountActionListener, Injectable {
|
||||||
private const val TAG = "AccountList" // logging tag
|
private const val TAG = "AccountList" // logging tag
|
||||||
private const val ARG_TYPE = "type"
|
private const val ARG_TYPE = "type"
|
||||||
private const val ARG_ID = "id"
|
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 {
|
return AccountListFragment().apply {
|
||||||
arguments = Bundle(2).apply {
|
arguments = Bundle(3).apply {
|
||||||
putSerializable(ARG_TYPE, type)
|
putSerializable(ARG_TYPE, type)
|
||||||
putString(ARG_ID, id)
|
putString(ARG_ID, id)
|
||||||
|
putString(ARG_EMOJI, emoji)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import androidx.lifecycle.Lifecycle;
|
||||||
import com.keylesspalace.tusky.BaseActivity;
|
import com.keylesspalace.tusky.BaseActivity;
|
||||||
import com.keylesspalace.tusky.BottomSheetActivity;
|
import com.keylesspalace.tusky.BottomSheetActivity;
|
||||||
import com.keylesspalace.tusky.MainActivity;
|
import com.keylesspalace.tusky.MainActivity;
|
||||||
|
import com.keylesspalace.tusky.AccountListActivity;
|
||||||
import com.keylesspalace.tusky.R;
|
import com.keylesspalace.tusky.R;
|
||||||
import com.keylesspalace.tusky.PostLookupFallbackBehavior;
|
import com.keylesspalace.tusky.PostLookupFallbackBehavior;
|
||||||
import com.keylesspalace.tusky.ViewMediaActivity;
|
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.Filter;
|
||||||
import com.keylesspalace.tusky.entity.PollOption;
|
import com.keylesspalace.tusky.entity.PollOption;
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
import com.keylesspalace.tusky.entity.Status;
|
||||||
|
import com.keylesspalace.tusky.entity.EmojiReaction;
|
||||||
import com.keylesspalace.tusky.network.MastodonApi;
|
import com.keylesspalace.tusky.network.MastodonApi;
|
||||||
import com.keylesspalace.tusky.network.TimelineCases;
|
import com.keylesspalace.tusky.network.TimelineCases;
|
||||||
import com.keylesspalace.tusky.viewdata.AttachmentViewData;
|
import com.keylesspalace.tusky.viewdata.AttachmentViewData;
|
||||||
|
@ -172,6 +174,33 @@ public abstract class SFragment extends BaseFragment implements Injectable {
|
||||||
Intent intent = ComposeActivity.startIntent(getContext(), composeOptions);
|
Intent intent = ComposeActivity.startIntent(getContext(), composeOptions);
|
||||||
getActivity().startActivity(intent);
|
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) {
|
protected void more(@NonNull final Status status, View view, final int position) {
|
||||||
final String id = status.getActionableId();
|
final String id = status.getActionableId();
|
||||||
|
|
|
@ -52,10 +52,7 @@ import com.keylesspalace.tusky.appstore.ReblogEvent;
|
||||||
import com.keylesspalace.tusky.appstore.StatusComposedEvent;
|
import com.keylesspalace.tusky.appstore.StatusComposedEvent;
|
||||||
import com.keylesspalace.tusky.appstore.StatusDeletedEvent;
|
import com.keylesspalace.tusky.appstore.StatusDeletedEvent;
|
||||||
import com.keylesspalace.tusky.di.Injectable;
|
import com.keylesspalace.tusky.di.Injectable;
|
||||||
import com.keylesspalace.tusky.entity.Filter;
|
import com.keylesspalace.tusky.entity.*;
|
||||||
import com.keylesspalace.tusky.entity.Poll;
|
|
||||||
import com.keylesspalace.tusky.entity.Status;
|
|
||||||
import com.keylesspalace.tusky.entity.StatusContext;
|
|
||||||
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
import com.keylesspalace.tusky.interfaces.StatusActionListener;
|
||||||
import com.keylesspalace.tusky.network.MastodonApi;
|
import com.keylesspalace.tusky.network.MastodonApi;
|
||||||
import com.keylesspalace.tusky.util.CardViewMode;
|
import com.keylesspalace.tusky.util.CardViewMode;
|
||||||
|
@ -747,4 +744,9 @@ public final class ViewThreadFragment extends SFragment implements
|
||||||
protected void refreshAfterApplyingFilters() {
|
protected void refreshAfterApplyingFilters() {
|
||||||
onRefresh();
|
onRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEmojiReactMenu(@NonNull View view, final EmojiReaction emoji, final String statusId, final int position) {
|
||||||
|
super.emojiReactMenu(statusId, emoji, view, position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package com.keylesspalace.tusky.interfaces;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import com.keylesspalace.tusky.entity.EmojiReaction;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
@ -64,6 +65,7 @@ public interface StatusActionListener extends LinkListener {
|
||||||
void onVoteInPoll(int position, @NonNull List<Integer> choices);
|
void onVoteInPoll(int position, @NonNull List<Integer> choices);
|
||||||
|
|
||||||
default void onMute(int position, boolean isMuted) {}
|
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) {};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -588,19 +588,20 @@ interface MastodonApi {
|
||||||
fun getNodeinfo(@Url url: String) : Single<NodeInfo>
|
fun getNodeinfo(@Url url: String) : Single<NodeInfo>
|
||||||
|
|
||||||
@PUT("api/v1/pleroma/statuses/{id}/reactions/{emoji}")
|
@PUT("api/v1/pleroma/statuses/{id}/reactions/{emoji}")
|
||||||
fun reactWithEmoji(
|
fun reactWithEmoji(
|
||||||
@Path("id") statusId: String,
|
@Path("id") statusId: String,
|
||||||
@Path("emoji") emoji: String
|
@Path("emoji") emoji: String
|
||||||
): Single<Status>
|
): Single<Status>
|
||||||
|
|
||||||
@DELETE("api/v1/pleroma/statuses/{id}/reactions/{emoji}")
|
@DELETE("api/v1/pleroma/statuses/{id}/reactions/{emoji}")
|
||||||
fun unreactWithEmoji(
|
fun unreactWithEmoji(
|
||||||
@Path("id") statusId: String,
|
@Path("id") statusId: String,
|
||||||
@Path("emoji") emoji: String
|
@Path("emoji") emoji: String
|
||||||
): Single<Status>
|
): Single<Status>
|
||||||
|
|
||||||
@GET("api/v1/pleroma/statuses/{id}/reactions")
|
@GET("api/v1/pleroma/statuses/{id}/reactions/{emoji}")
|
||||||
fun statusReactedBy(
|
fun statusReactedBy(
|
||||||
@Path("id") statusId: String
|
@Path("id") statusId: String,
|
||||||
): Single<List<EmojiReaction>>
|
@Path("emoji") emoji: String
|
||||||
|
): Single<Response<List<EmojiReaction>>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item
|
||||||
|
android:id="@+id/emoji_react"
|
||||||
|
android:title="@string/action_emoji_react" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/emoji_unreact"
|
||||||
|
android:title="@string/action_emoji_unreact" />
|
||||||
|
<item
|
||||||
|
android:id="@+id/emoji_reacted_by"
|
||||||
|
android:title="@string/action_emoji_reacted_by" />
|
||||||
|
</menu>
|
||||||
|
|
|
@ -2,8 +2,13 @@
|
||||||
|
|
||||||
<string name="action_reply_to">Reply to</string>
|
<string name="action_reply_to">Reply to</string>
|
||||||
<string name="action_markdown">Markdown</string>
|
<string name="action_markdown">Markdown</string>
|
||||||
<string name="action_mute_conversation">Mute conversation</string>
|
<string name="action_mute_conversation">Mute conversation</string>
|
||||||
<string name="action_unmute_conversation">Unmute conversation</string>
|
<string name="action_unmute_conversation">Unmute conversation</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>
|
||||||
|
|
||||||
|
<string name="title_emoji_reacted_by">Emoji reacted by</string>
|
||||||
|
|
||||||
<string name="hint_appname">Application name</string>
|
<string name="hint_appname">Application name</string>
|
||||||
<string name="hint_website">Application website</string>
|
<string name="hint_website">Application website</string>
|
||||||
|
@ -13,7 +18,7 @@
|
||||||
|
|
||||||
<string name="error_media_upload_size">File size exceeds instance limits</string>
|
<string name="error_media_upload_size">File size exceeds instance limits</string>
|
||||||
|
|
||||||
<string name="notification_emoji_format">%s reacted to your post with %s</string>
|
<string name="notification_emoji_format">%s reacted with %s to your post</string>
|
||||||
<string name="notification_emoji_name">Emoji Reactions</string>
|
<string name="notification_emoji_name">Emoji Reactions</string>
|
||||||
<string name="notification_emoji_description">Notifications about new emoji reactions</string>
|
<string name="notification_emoji_description">Notifications about new emoji reactions</string>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue