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

Setting to replace bookmark/share buttons with new emoji reaction in footer #955

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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