Skip to content
This repository has been archived by the owner on Oct 28, 2024. It is now read-only.

Commit

Permalink
New emoji reaction button in footer
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacocococo committed Dec 27, 2023
1 parent f7dfebc commit c3b4217
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public class AccountLocalPreferences{
public boolean keepOnlyLatestNotification;
public boolean emojiReactionsEnabled;
public ShowEmojiReactions showEmojiReactions;
public NewEmojiReactionButton newEmojiReactionButton;
public ColorPreference color;
public ArrayList<Emoji> recentCustomEmoji;

Expand Down Expand Up @@ -73,6 +74,7 @@ public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
newEmojiReactionButton=NewEmojiReactionButton.valueOf(prefs.getString("newEmojiReactionButton", NewEmojiReactionButton.WITH_REACTIONS.name()));
color=prefs.contains("color") ? ColorPreference.valueOf(prefs.getString("color", null)) : null;
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
}
Expand Down Expand Up @@ -112,6 +114,7 @@ public void save(){
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
.putString("showEmojiReactions", showEmojiReactions.name())
.putString("newEmojiReactionButton", newEmojiReactionButton.name())
.putString("color", color!=null ? color.name() : null)
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
.apply();
Expand Down Expand Up @@ -146,4 +149,10 @@ public enum ShowEmojiReactions{
ONLY_OPENED,
ALWAYS
}

public enum NewEmojiReactionButton{
WITH_REACTIONS,
REPLACE_BOOKMARK,
REPLACE_SHARE
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,27 @@
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.polls.SubmitPollVote;
import org.joinmastodon.android.api.requests.statuses.AddStatusReaction;
import org.joinmastodon.android.api.requests.statuses.AkkomaTranslateStatus;
import org.joinmastodon.android.api.requests.statuses.DeleteStatusReaction;
import org.joinmastodon.android.api.requests.statuses.PleromaAddStatusReaction;
import org.joinmastodon.android.api.requests.statuses.PleromaDeleteStatusReaction;
import org.joinmastodon.android.api.requests.statuses.TranslateStatus;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AkkomaTranslation;
import org.joinmastodon.android.model.DisplayItemsParent;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Poll;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.Translation;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
Expand Down Expand Up @@ -943,6 +950,28 @@ private void updateTranslation(String itemID) {
}
}

public void addEmojiReaction(String itemID, Status status, String emoji, Emoji info) {
EmojiReactionsStatusDisplayItem.Holder holder=findHolderOfType(itemID, EmojiReactionsStatusDisplayItem.Holder.class);
if(holder!=null){
holder.addEmojiReaction(emoji, info);
return;
}

MastodonAPIRequest<Status> req=isInstanceAkkoma() ? new PleromaAddStatusReaction(status.id, emoji) : new AddStatusReaction(status.id, emoji);
req.setCallback(new Callback<>(){
@Override
public void onSuccess(Status result){
E.post(new EmojiReactionsUpdatedEvent(result.id, result.reactions, false, null));
}

@Override
public void onError(ErrorResponse error){
error.showToast(getContext());
}
});
req.exec(accountID);
}

public void rebuildAllDisplayItems(){
displayItems.clear();
for(T item:data){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

public class SettingsInstanceFragment extends BaseSettingsFragment<Void> implements HasAccountID{
private CheckableListItem<Void> contentTypesItem, emojiReactionsItem, localOnlyItem, glitchModeItem;
private ListItem<Void> defaultContentTypeItem, showEmojiReactionsItem;
private ListItem<Void> defaultContentTypeItem, showEmojiReactionsItem, newEmojiReactionButton;
private AccountLocalPreferences lp;

@Override
Expand All @@ -43,14 +43,16 @@ public void onCreate(Bundle savedInstanceState){
contentTypesItem=new CheckableListItem<>(R.string.sk_settings_content_types, R.string.sk_settings_content_types_explanation, CheckableListItem.Style.SWITCH, lp.contentTypesEnabled, R.drawable.ic_fluent_text_edit_style_24_regular, i->onContentTypeClick()),
defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick, 0, true),
emojiReactionsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions, R.string.sk_settings_emoji_reactions_explanation, CheckableListItem.Style.SWITCH, lp.emojiReactionsEnabled, R.drawable.ic_fluent_emoji_laugh_24_regular, i->onEmojiReactionsClick()),
showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, true),
showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, false),
newEmojiReactionButton=new ListItem<>(R.string.sk_settings_new_emoji_reaction_button, getNewEmojiReactionButton(), R.drawable.ic_fluent_emoji_add_24_regular, this::onNewEmojiReactionButtonClick, 0, true),
localOnlyItem=new CheckableListItem<>(R.string.sk_settings_support_local_only, R.string.sk_settings_local_only_explanation, CheckableListItem.Style.SWITCH, lp.localOnlySupported, R.drawable.ic_fluent_eye_24_regular, i->onLocalOnlyClick()),
glitchModeItem=new CheckableListItem<>(R.string.sk_settings_glitch_instance, R.string.sk_settings_glitch_mode_explanation, CheckableListItem.Style.SWITCH, lp.glitchInstance, R.drawable.ic_fluent_eye_24_filled, i->toggleCheckableItem(glitchModeItem))
));
contentTypesItem.checkedChangeListener=checked->onContentTypeClick();
defaultContentTypeItem.isEnabled=contentTypesItem.checked;
emojiReactionsItem.checkedChangeListener=checked->onEmojiReactionsClick();
showEmojiReactionsItem.isEnabled=emojiReactionsItem.checked;
newEmojiReactionButton.isEnabled=emojiReactionsItem.checked;
localOnlyItem.checkedChangeListener=checked->onLocalOnlyClick();
glitchModeItem.isEnabled=localOnlyItem.checked;
}
Expand Down Expand Up @@ -129,6 +131,22 @@ private void onShowEmojiReactionsClick(ListItem<?> item_){
.show();
}

private void onNewEmojiReactionButtonClick(ListItem<?> item_){
int selected=lp.newEmojiReactionButton.ordinal();
int[] newSelected={selected};
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_settings_new_emoji_reaction_button)
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_new_emoji_reaction_button_with_reactions, R.string.sk_settings_new_emoji_reaction_button_replace_bookmark, R.string.sk_settings_new_emoji_reaction_button_replace_share).mapToObj(this::getString).toArray(String[]::new),
selected, (dlg, item)->newSelected[0]=item)
.setPositiveButton(R.string.ok, (dlg, item)->{
lp.newEmojiReactionButton=AccountLocalPreferences.NewEmojiReactionButton.values()[newSelected[0]];
newEmojiReactionButton.subtitleRes=getNewEmojiReactionButton();
rebindItem(newEmojiReactionButton);
})
.setNegativeButton(R.string.cancel, null)
.show();
}

private @StringRes int getShowEmojiReactionsString(){
return switch(lp.showEmojiReactions){
case HIDE_EMPTY -> R.string.sk_settings_show_emoji_reactions_hide_empty;
Expand All @@ -137,10 +155,20 @@ private void onShowEmojiReactionsClick(ListItem<?> item_){
};
}

private @StringRes int getNewEmojiReactionButton(){
return switch(lp.newEmojiReactionButton){
case WITH_REACTIONS -> R.string.sk_settings_new_emoji_reaction_button_with_reactions;
case REPLACE_BOOKMARK -> R.string.sk_settings_new_emoji_reaction_button_replace_bookmark;
case REPLACE_SHARE -> R.string.sk_settings_new_emoji_reaction_button_replace_share;
};
}

private void onEmojiReactionsClick(){
toggleCheckableItem(emojiReactionsItem);
showEmojiReactionsItem.isEnabled=emojiReactionsItem.checked;
newEmojiReactionButton.isEnabled=emojiReactionsItem.checked;
rebindItem(showEmojiReactionsItem);
rebindItem(newEmojiReactionButton);
}

private void onLocalOnlyClick(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.joinmastodon.android.api.requests.statuses.DeleteStatusReaction;
import org.joinmastodon.android.api.requests.statuses.PleromaAddStatusReaction;
import org.joinmastodon.android.api.requests.statuses.PleromaDeleteStatusReaction;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
Expand Down Expand Up @@ -174,6 +175,9 @@ public void onBind(EmojiReactionsStatusDisplayItem item) {
item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null
? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24))
: null);
addButton.setVisibility(session.getLocalPreferences().newEmojiReactionButton != AccountLocalPreferences.NewEmojiReactionButton.WITH_REACTIONS
? View.GONE
: View.VISIBLE);
emojiKeyboard=new CustomEmojiPopupKeyboard(
(Activity) item.parentFragment.getContext(),
item.accountID,
Expand Down Expand Up @@ -213,7 +217,7 @@ public void onEmojiSelected(String emoji){
hideEmojiKeyboard();
}

private void addEmojiReaction(String emoji, Emoji info) {
public void addEmojiReaction(String emoji, Emoji info) {
int countBefore=item.status.reactions.size();
for(int i=0; i<item.status.reactions.size(); i++){
EmojiReaction r=item.status.reactions.get(i);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
Expand All @@ -16,17 +17,21 @@
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.CustomEmojiPopupKeyboard;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
Expand All @@ -52,10 +57,12 @@ public Type getType(){
return Type.FOOTER;
}

public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem> implements CustomEmojiPopupKeyboard.Listener {
private final TextView replies, boosts, favorites;
private final View reply, boost, favorite, share, bookmark;
private final View reply, boost, favorite, share, bookmark, react;
private final ImageView favIcon;
private CustomEmojiPopupKeyboard emojiKeyboard;
private final LinearLayout emojiKeyboardContainer;

private View touchingView = null;
private boolean longClickPerformed = false;
Expand Down Expand Up @@ -83,12 +90,15 @@ public Holder(Activity activity, ViewGroup parent){
boosts=findViewById(R.id.boost);
favorites=findViewById(R.id.favorite);

emojiKeyboardContainer = findViewById(R.id.footer_emoji_keyboard_container);

reply=findViewById(R.id.reply_btn);
boost=findViewById(R.id.boost_btn);
favorite=findViewById(R.id.favorite_btn);
share=findViewById(R.id.share_btn);
bookmark=findViewById(R.id.bookmark_btn);
favIcon=findViewById(R.id.favorite_icon);
react=findViewById(R.id.react_btn);

reply.setOnTouchListener(this::onButtonTouch);
reply.setOnClickListener(this::onReplyClick);
Expand All @@ -106,6 +116,9 @@ public Holder(Activity activity, ViewGroup parent){
bookmark.setOnClickListener(this::onBookmarkClick);
bookmark.setOnLongClickListener(this::onBookmarkLongClick);
bookmark.setAccessibilityDelegate(buttonAccessibilityDelegate);
react.setOnTouchListener(this::onButtonTouch);
react.setOnClickListener(this::onReactClick);
react.setAccessibilityDelegate(buttonAccessibilityDelegate);
share.setOnTouchListener(this::onButtonTouch);
share.setOnClickListener(this::onShareClick);
share.setOnLongClickListener(this::onShareLongClick);
Expand Down Expand Up @@ -144,6 +157,42 @@ public void onBind(FooterStatusDisplayItem item){
condenseBottom ? V.dp(-5) : 0);

itemView.requestLayout();

AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID);
if(!session.getLocalPreferences().emojiReactionsEnabled){
((FrameLayout) react.getParent()).setVisibility(View.GONE);
((FrameLayout) bookmark.getParent()).setVisibility(View.VISIBLE);
share.setVisibility(View.VISIBLE);
return;
}

AccountLocalPreferences.NewEmojiReactionButton newEmojiReactionButton = session.getLocalPreferences().newEmojiReactionButton;
if(newEmojiReactionButton == AccountLocalPreferences.NewEmojiReactionButton.WITH_REACTIONS){
((FrameLayout) react.getParent()).setVisibility(View.GONE);
}else{
((FrameLayout) react.getParent()).setVisibility(View.VISIBLE);
}
if(newEmojiReactionButton == AccountLocalPreferences.NewEmojiReactionButton.REPLACE_BOOKMARK){
((FrameLayout) bookmark.getParent()).setVisibility(View.GONE);
}else{
((FrameLayout) bookmark.getParent()).setVisibility(View.VISIBLE);
}
if(newEmojiReactionButton == AccountLocalPreferences.NewEmojiReactionButton.REPLACE_SHARE){
((FrameLayout) react.getParent()).setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0));
share.setVisibility(View.GONE);
}else{
((FrameLayout) react.getParent()).setLayoutParams(new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1));
share.setVisibility(View.VISIBLE);
}

emojiKeyboard=new CustomEmojiPopupKeyboard(
(Activity) item.parentFragment.getContext(),
item.accountID,
AccountSessionManager.getInstance().getCustomEmojis(session.domain),
session.domain, true);
emojiKeyboard.setListener(this);
emojiKeyboardContainer.removeAllViews();
emojiKeyboardContainer.addView(emojiKeyboard.getView());
}

private void bindText(TextView btn, long count){
Expand Down Expand Up @@ -351,6 +400,22 @@ private boolean onBookmarkLongClick(View v) {
return true;
}

private void onReactClick(View v){
emojiKeyboard.toggleKeyboardPopup(null);
if(!emojiKeyboard.isVisible()){
endEmojiReaction();
return;
}
DisplayMetrics displayMetrics = new DisplayMetrics();
int[] locationOnScreen = new int[2];
((Activity) v.getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
v.getLocationOnScreen(locationOnScreen);
double fromScreenTop = (double) locationOnScreen[1] / displayMetrics.heightPixels;
if (fromScreenTop > 0.75) {
item.parentFragment.scrollBy(0, (int) (displayMetrics.heightPixels * 0.3));
}
}

private void onShareClick(View v){
if(item.status.preview) return;
UiUtils.opacityIn(v);
Expand All @@ -366,6 +431,28 @@ private boolean onShareLongClick(View v){
return true;
}

@Override
public void onEmojiSelected(Emoji emoji) {
item.parentFragment.addEmojiReaction(getItemID(), item.status, emoji.shortcode, emoji);
endEmojiReaction();
}

@Override
public void onEmojiSelected(String emoji){
item.parentFragment.addEmojiReaction(getItemID(), item.status, emoji, null);
endEmojiReaction();
}

private void endEmojiReaction(){
if(emojiKeyboard.isVisible()) emojiKeyboard.toggleKeyboardPopup(null);
touchingView = null;
react.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
UiUtils.opacityIn(react);
}

@Override
public void onBackspace() {}

private int descriptionForId(int id){
if(id==R.id.reply_btn)
return R.string.button_reply;
Expand All @@ -375,6 +462,8 @@ private int descriptionForId(int id){
return R.string.button_favorite;
if(id==R.id.bookmark_btn)
return R.string.add_bookmark;
if(id==R.id.react_btn)
return R.string.sk_button_react;
if(id==R.id.share_btn)
return R.string.button_share;
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.joinmastodon.android.api.requests.announcements.DismissAnnouncement;
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
import org.joinmastodon.android.api.requests.statuses.GetStatusSourceText;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
Expand Down Expand Up @@ -506,16 +507,18 @@ private void updateOptionsMenu(){
MenuItem report=menu.findItem(R.id.report);
MenuItem follow=menu.findItem(R.id.follow);
MenuItem manageUserLists = menu.findItem(R.id.manage_user_lists);
/* disabled in megalodon: add/remove bookmark is already available through status footer

AccountLocalPreferences lp = AccountSessionManager.get(item.accountID).getLocalPreferences();
MenuItem bookmark=menu.findItem(R.id.bookmark);
bookmark.setVisible(false);
if(item.status!=null){
if(lp.newEmojiReactionButton==AccountLocalPreferences.NewEmojiReactionButton.REPLACE_BOOKMARK && item.status!=null){
bookmark.setVisible(true);
bookmark.setTitle(item.status.bookmarked ? R.string.remove_bookmark : R.string.add_bookmark);
}else{
bookmark.setVisible(false);
}
*/
MenuItem share=menu.findItem(R.id.share);
share.setVisible(lp.newEmojiReactionButton==AccountLocalPreferences.NewEmojiReactionButton.REPLACE_SHARE);

if(isPostScheduled || isOwnPost){
mute.setVisible(false);
block.setVisible(false);
Expand Down
Loading

0 comments on commit c3b4217

Please sign in to comment.