Loading app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonStatusesService.java +14 −0 Original line number Diff line number Diff line Loading @@ -318,4 +318,18 @@ public interface MastodonStatusesService { @Header("Authorization") String token, @Path("id") String id ); @POST("statuses/{id}/react/{name}") Call<Void> addReaction( @Header("Authorization") String app_token, @Path("id") String id, @Path("name") String name ); @POST("statuses/{id}/unreact/{name}") Call<Void> removeReaction( @Header("Authorization") String app_token, @Path("id") String id, @Path("name") String name ); } app/src/main/java/app/fedilab/android/mastodon/client/entities/api/Status.java +2 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ public class Status implements Serializable, Cloneable { public boolean cached = false; @SerializedName("is_maths") public Boolean isMaths; @SerializedName("reactions") public List<Reaction> reactions; public Attachment art_attachment; public boolean isExpended = false; Loading app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ReactionAdapter.java +27 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import app.fedilab.android.mastodon.client.entities.api.Reaction; import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.ThemeHelper; import app.fedilab.android.mastodon.viewmodel.mastodon.AnnouncementsVM; import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM; import app.fedilab.android.mastodon.viewmodel.pleroma.ActionsVM; Loading @@ -46,18 +47,29 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti private final List<Reaction> reactions; private final String announcementId; private final boolean statusReaction; private final boolean isPleroma; private Context context; ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction, boolean isPleroma) { this.reactions = reactions; this.announcementId = announcementId; this.statusReaction = statusReaction; this.isPleroma = isPleroma; } ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction) { this.reactions = reactions; this.announcementId = announcementId; this.statusReaction = statusReaction; this.isPleroma = true; } ReactionAdapter(String announcementId, List<Reaction> reactions) { this.reactions = reactions; this.announcementId = announcementId; this.statusReaction = false; this.isPleroma = true; } @NonNull Loading Loading @@ -101,7 +113,7 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti } notifyItemChanged(position); }); } else { } else if (isPleroma) { ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class); holder.binding.reactionContainer.setOnClickListener(v -> { if (reaction.me) { Loading @@ -115,6 +127,20 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti } notifyItemChanged(position); }); } else { StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class); holder.binding.reactionContainer.setOnClickListener(v -> { if (reaction.me) { statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcementId, reaction.name); reaction.me = false; reaction.count -= 1; } else { statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcementId, reaction.name); reaction.me = true; reaction.count += 1; } notifyItemChanged(position); }); } } Loading app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java +108 −48 Original line number Diff line number Diff line Loading @@ -522,7 +522,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> holder.binding.quotedMessage.cardviewContainer.setVisibility(View.GONE); } if (currentAccount != null && currentAccount.api == Account.API.PLEROMA) { if (currentAccount != null && currentAccount.api == Account.API.PLEROMA || status.reactions != null) { if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) { holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE); ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions, true); Loading @@ -530,6 +530,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager); } else if (status.reactions != null && status.reactions.size() > 0) { holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE); ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.reactions, true, false); holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter); LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager); } else { holder.binding.layoutReactions.getRoot().setVisibility(View.GONE); holder.binding.layoutReactions.reactionsView.setAdapter(null); Loading @@ -542,9 +549,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> }).setOnEmojiClickListener((emoji, imageView) -> { String emojiStr = imageView.getUnicode(); boolean alreadyAdded = false; if (status.pleroma == null || status.pleroma.emoji_reactions == null) { return; } if (status.pleroma != null && status.pleroma.emoji_reactions != null) { for (Reaction reaction : status.pleroma.emoji_reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; Loading @@ -570,6 +575,32 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> } else { actionVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } else if (status.reactions != null) { for (Reaction reaction : status.reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; reaction.count = (reaction.count - 1); if (reaction.count == 0) { status.reactions.remove(reaction); } adapter.notifyItemChanged(holder.getBindingAdapterPosition()); break; } } if (!alreadyAdded) { Reaction reaction = new Reaction(); reaction.me = true; reaction.count = 1; reaction.name = emojiStr; status.reactions.add(0, reaction); adapter.notifyItemChanged(holder.getBindingAdapterPosition()); } if (alreadyAdded) { statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } else { statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } }) .build(holder.binding.layoutReactions.fakeEdittext); emojiPopup.toggle(); Loading @@ -594,6 +625,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> String url = emojis.get(BaseMainActivity.currentInstance).get(index).url; String static_url = emojis.get(BaseMainActivity.currentInstance).get(index).static_url; boolean alreadyAdded = false; if (status.pleroma != null && status.pleroma.emoji_reactions != null) { for (Reaction reaction : status.pleroma.emoji_reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; Loading Loading @@ -621,6 +653,34 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> } else { actionsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } else if (status.reactions != null) { for (Reaction reaction : status.reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; reaction.count = (reaction.count - 1); if (reaction.count == 0) { status.reactions.remove(reaction); } adapter.notifyItemChanged(holder.getBindingAdapterPosition()); break; } } if (!alreadyAdded) { Reaction reaction = new Reaction(); reaction.me = true; reaction.count = 1; reaction.name = emojiStr; reaction.url = url; reaction.static_url = static_url; status.reactions.add(0, reaction); adapter.notifyItemChanged(holder.getBindingAdapterPosition()); } if (alreadyAdded) { statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } else { statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } }); gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp); builder.setView(gridView); Loading app/src/main/java/app/fedilab/android/mastodon/viewmodel/mastodon/StatusesVM.java +44 −0 Original line number Diff line number Diff line Loading @@ -1292,4 +1292,48 @@ public class StatusesVM extends AndroidViewModel { }).start(); return voidMutableLiveData; } /** * React to a status with an emoji. * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id Local ID of an announcement * @param name Unicode emoji, or shortcode of custom emoji */ public void addReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) { MastodonStatusesService mastodonStatusesService = init(instance); new Thread(() -> { Call<Void> addReactionCall = mastodonStatusesService.addReaction(token, id, name); if (addReactionCall != null) { try { addReactionCall.execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } /** * Undo a react emoji to a status. * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id Local ID of an announcement * @param name Unicode emoji, or shortcode of custom emoji */ public void removeReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) { MastodonStatusesService mastodonStatusesService = init(instance); new Thread(() -> { Call<Void> removeReactionCall = mastodonStatusesService.removeReaction(token, id, name); if (removeReactionCall != null) { try { removeReactionCall.execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } } Loading
app/src/main/java/app/fedilab/android/mastodon/client/endpoints/MastodonStatusesService.java +14 −0 Original line number Diff line number Diff line Loading @@ -318,4 +318,18 @@ public interface MastodonStatusesService { @Header("Authorization") String token, @Path("id") String id ); @POST("statuses/{id}/react/{name}") Call<Void> addReaction( @Header("Authorization") String app_token, @Path("id") String id, @Path("name") String name ); @POST("statuses/{id}/unreact/{name}") Call<Void> removeReaction( @Header("Authorization") String app_token, @Path("id") String id, @Path("name") String name ); }
app/src/main/java/app/fedilab/android/mastodon/client/entities/api/Status.java +2 −0 Original line number Diff line number Diff line Loading @@ -109,6 +109,8 @@ public class Status implements Serializable, Cloneable { public boolean cached = false; @SerializedName("is_maths") public Boolean isMaths; @SerializedName("reactions") public List<Reaction> reactions; public Attachment art_attachment; public boolean isExpended = false; Loading
app/src/main/java/app/fedilab/android/mastodon/ui/drawer/ReactionAdapter.java +27 −1 Original line number Diff line number Diff line Loading @@ -34,6 +34,7 @@ import app.fedilab.android.mastodon.client.entities.api.Reaction; import app.fedilab.android.mastodon.helper.Helper; import app.fedilab.android.mastodon.helper.ThemeHelper; import app.fedilab.android.mastodon.viewmodel.mastodon.AnnouncementsVM; import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM; import app.fedilab.android.mastodon.viewmodel.pleroma.ActionsVM; Loading @@ -46,18 +47,29 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti private final List<Reaction> reactions; private final String announcementId; private final boolean statusReaction; private final boolean isPleroma; private Context context; ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction, boolean isPleroma) { this.reactions = reactions; this.announcementId = announcementId; this.statusReaction = statusReaction; this.isPleroma = isPleroma; } ReactionAdapter(String announcementId, List<Reaction> reactions, boolean statusReaction) { this.reactions = reactions; this.announcementId = announcementId; this.statusReaction = statusReaction; this.isPleroma = true; } ReactionAdapter(String announcementId, List<Reaction> reactions) { this.reactions = reactions; this.announcementId = announcementId; this.statusReaction = false; this.isPleroma = true; } @NonNull Loading Loading @@ -101,7 +113,7 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti } notifyItemChanged(position); }); } else { } else if (isPleroma) { ActionsVM actionVM = new ViewModelProvider((ViewModelStoreOwner) context).get(ActionsVM.class); holder.binding.reactionContainer.setOnClickListener(v -> { if (reaction.me) { Loading @@ -115,6 +127,20 @@ public class ReactionAdapter extends RecyclerView.Adapter<ReactionAdapter.Reacti } notifyItemChanged(position); }); } else { StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class); holder.binding.reactionContainer.setOnClickListener(v -> { if (reaction.me) { statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcementId, reaction.name); reaction.me = false; reaction.count -= 1; } else { statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, announcementId, reaction.name); reaction.me = true; reaction.count += 1; } notifyItemChanged(position); }); } } Loading
app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java +108 −48 Original line number Diff line number Diff line Loading @@ -522,7 +522,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> holder.binding.quotedMessage.cardviewContainer.setVisibility(View.GONE); } if (currentAccount != null && currentAccount.api == Account.API.PLEROMA) { if (currentAccount != null && currentAccount.api == Account.API.PLEROMA || status.reactions != null) { if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) { holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE); ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions, true); Loading @@ -530,6 +530,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager); } else if (status.reactions != null && status.reactions.size() > 0) { holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE); ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.reactions, true, false); holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter); LinearLayoutManager layoutManager = new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false); holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager); } else { holder.binding.layoutReactions.getRoot().setVisibility(View.GONE); holder.binding.layoutReactions.reactionsView.setAdapter(null); Loading @@ -542,9 +549,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> }).setOnEmojiClickListener((emoji, imageView) -> { String emojiStr = imageView.getUnicode(); boolean alreadyAdded = false; if (status.pleroma == null || status.pleroma.emoji_reactions == null) { return; } if (status.pleroma != null && status.pleroma.emoji_reactions != null) { for (Reaction reaction : status.pleroma.emoji_reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; Loading @@ -570,6 +575,32 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> } else { actionVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } else if (status.reactions != null) { for (Reaction reaction : status.reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; reaction.count = (reaction.count - 1); if (reaction.count == 0) { status.reactions.remove(reaction); } adapter.notifyItemChanged(holder.getBindingAdapterPosition()); break; } } if (!alreadyAdded) { Reaction reaction = new Reaction(); reaction.me = true; reaction.count = 1; reaction.name = emojiStr; status.reactions.add(0, reaction); adapter.notifyItemChanged(holder.getBindingAdapterPosition()); } if (alreadyAdded) { statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } else { statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } }) .build(holder.binding.layoutReactions.fakeEdittext); emojiPopup.toggle(); Loading @@ -594,6 +625,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> String url = emojis.get(BaseMainActivity.currentInstance).get(index).url; String static_url = emojis.get(BaseMainActivity.currentInstance).get(index).static_url; boolean alreadyAdded = false; if (status.pleroma != null && status.pleroma.emoji_reactions != null) { for (Reaction reaction : status.pleroma.emoji_reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; Loading Loading @@ -621,6 +653,34 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> } else { actionsVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } else if (status.reactions != null) { for (Reaction reaction : status.reactions) { if (reaction.name.compareTo(emojiStr) == 0 && reaction.me) { alreadyAdded = true; reaction.count = (reaction.count - 1); if (reaction.count == 0) { status.reactions.remove(reaction); } adapter.notifyItemChanged(holder.getBindingAdapterPosition()); break; } } if (!alreadyAdded) { Reaction reaction = new Reaction(); reaction.me = true; reaction.count = 1; reaction.name = emojiStr; reaction.url = url; reaction.static_url = static_url; status.reactions.add(0, reaction); adapter.notifyItemChanged(holder.getBindingAdapterPosition()); } if (alreadyAdded) { statusesVM.removeReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } else { statusesVM.addReaction(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id, emojiStr); } } }); gridView.setPadding(paddingDp, paddingDp, paddingDp, paddingDp); builder.setView(gridView); Loading
app/src/main/java/app/fedilab/android/mastodon/viewmodel/mastodon/StatusesVM.java +44 −0 Original line number Diff line number Diff line Loading @@ -1292,4 +1292,48 @@ public class StatusesVM extends AndroidViewModel { }).start(); return voidMutableLiveData; } /** * React to a status with an emoji. * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id Local ID of an announcement * @param name Unicode emoji, or shortcode of custom emoji */ public void addReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) { MastodonStatusesService mastodonStatusesService = init(instance); new Thread(() -> { Call<Void> addReactionCall = mastodonStatusesService.addReaction(token, id, name); if (addReactionCall != null) { try { addReactionCall.execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } /** * Undo a react emoji to a status. * * @param instance Instance domain of the active account * @param token Access token of the active account * @param id Local ID of an announcement * @param name Unicode emoji, or shortcode of custom emoji */ public void removeReaction(@NonNull String instance, String token, @NonNull String id, @NonNull String name) { MastodonStatusesService mastodonStatusesService = init(instance); new Thread(() -> { Call<Void> removeReactionCall = mastodonStatusesService.removeReaction(token, id, name); if (removeReactionCall != null) { try { removeReactionCall.execute(); } catch (Exception e) { e.printStackTrace(); } } }).start(); } }