implement setting boost visibility

This commit is contained in:
sk
2022-12-22 15:03:42 +01:00
parent ed02733524
commit 86ab6f7b3d
10 changed files with 212 additions and 21 deletions

View File

@@ -9,6 +9,7 @@ import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import java.util.HashMap;
import java.util.function.Consumer;
@@ -59,7 +60,7 @@ public class StatusInteractionController{
E.post(new StatusCountersUpdatedEvent(status));
}
public void setReblogged(Status status, boolean reblogged, Consumer<Status> cb){
public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer<Status> cb){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");
@@ -67,7 +68,7 @@ public class StatusInteractionController{
if(current!=null){
current.cancel();
}
SetStatusReblogged req=(SetStatusReblogged) new SetStatusReblogged(status.id, reblogged)
SetStatusReblogged req=(SetStatusReblogged) new SetStatusReblogged(status.id, reblogged, visibility)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Status reblog){

View File

@@ -2,10 +2,17 @@ package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
public class SetStatusReblogged extends MastodonAPIRequest<Status>{
public SetStatusReblogged(String id, boolean reblogged){
public SetStatusReblogged(String id, boolean reblogged, StatusPrivacy visibility){
super(HttpMethod.POST, "/statuses/"+id+"/"+(reblogged ? "reblog" : "unreblog"), Status.class);
setRequestBody(new Object());
Request req = new Request();
req.visibility = visibility;
setRequestBody(req);
}
public static class Request {
public StatusPrivacy visibility;
}
}

View File

@@ -139,7 +139,7 @@ public class StatusEditHistoryFragment extends StatusListFragment{
action=getString(R.string.edit_multiple_changed);
}
}
items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" · "+date, Collections.emptyList(), 0, null));
items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" · "+date, Collections.emptyList(), 0, null, null));
}
return items;
}

View File

@@ -1,9 +1,13 @@
package org.joinmastodon.android.ui.displayitems;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
@@ -18,14 +22,18 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
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.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
import java.util.function.Consumer;
import me.grishka.appkit.Nav;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
@@ -166,21 +174,68 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void onBoostClick(View v){
boost.setSelected(!item.status.reblogged);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, r->{
v.startAnimation(opacityIn);
bindButton(boost, r.reblogsCount);
});
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r));
}
private void boostConsumer(View v, Status r) {
v.startAnimation(opacityIn);
bindButton(boost, r.reblogsCount);
}
private boolean onBoostLongClick(View v){
v.setAlpha(1);
v.setScaleX(1);
v.setScaleY(1);
Bundle args=new Bundle();
args.putString("account", item.accountID);
args.putString("prefilledText", "\n\n" + item.status.url);
args.putInt("selectionStart", 0);
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
Context ctx = itemView.getContext();
View menu = LayoutInflater.from(ctx).inflate(R.layout.item_boost_menu, null);
Dialog dialog = new M3AlertDialogBuilder(ctx).setView(menu).create();
AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID);
Consumer<StatusPrivacy> doReblog = (visibility) -> {
v.startAnimation(opacityOut);
session.getStatusInteractionController()
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
dialog.dismiss();
};
View separator = menu.findViewById(R.id.separator);
TextView reblogHeader = menu.findViewById(R.id.reblog_header);
TextView undoReblog = menu.findViewById(R.id.delete_reblog);
TextView itemPublic = menu.findViewById(R.id.vis_public);
TextView itemUnlisted = menu.findViewById(R.id.vis_unlisted);
TextView itemFollowers = menu.findViewById(R.id.vis_followers);
undoReblog.setVisibility(item.status.reblogged ? View.VISIBLE : View.GONE);
separator.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
reblogHeader.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
itemPublic.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PUBLIC) ? View.GONE : View.VISIBLE);
itemUnlisted.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) ? View.GONE : View.VISIBLE);
itemFollowers.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PRIVATE) ? View.GONE : View.VISIBLE);
Drawable checkMark = ctx.getDrawable(R.drawable.ic_fluent_checkmark_circle_20_regular);
Drawable publicDrawable = ctx.getDrawable(R.drawable.ic_fluent_earth_24_regular);
Drawable unlistedDrawable = ctx.getDrawable(R.drawable.ic_fluent_people_community_24_regular);
Drawable followersDrawable = ctx.getDrawable(R.drawable.ic_fluent_people_checkmark_24_regular);
StatusPrivacy defaultVisibility = session.preferences.postingDefaultVisibility;
itemPublic.setCompoundDrawablesWithIntrinsicBounds(publicDrawable, null, StatusPrivacy.PUBLIC.equals(defaultVisibility) ? checkMark : null, null);
itemUnlisted.setCompoundDrawablesWithIntrinsicBounds(unlistedDrawable, null, StatusPrivacy.UNLISTED.equals(defaultVisibility) ? checkMark : null, null);
itemFollowers.setCompoundDrawablesWithIntrinsicBounds(followersDrawable, null, StatusPrivacy.PRIVATE.equals(defaultVisibility) ? checkMark : null, null);
undoReblog.setOnClickListener(c->doReblog.accept(null));
itemPublic.setOnClickListener(c->doReblog.accept(StatusPrivacy.PUBLIC));
itemUnlisted.setOnClickListener(c->doReblog.accept(StatusPrivacy.UNLISTED));
itemFollowers.setOnClickListener(c->doReblog.accept(StatusPrivacy.PRIVATE));
menu.findViewById(R.id.quote).setOnClickListener(c->{
dialog.dismiss();
v.startAnimation(opacityIn);
Bundle args=new Bundle();
args.putString("account", item.accountID);
args.putString("prefilledText", "\n\n" + item.status.url);
args.putInt("selectionStart", 0);
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
});
dialog.show();
return true;
}

View File

@@ -3,6 +3,7 @@ package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.MastodonApp.context;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.SpannableStringBuilder;
@@ -14,6 +15,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils;
@@ -30,10 +32,13 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
private CharSequence text;
@DrawableRes
private int icon;
private StatusPrivacy visibility;
@DrawableRes
private int iconEnd;
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
private View.OnClickListener handleClick;
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, @Nullable View.OnClickListener handleClick){
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick){
super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
HtmlParser.parseCustomEmoji(ssb, emojis);
@@ -43,6 +48,17 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
this.handleClick=handleClick;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
updateVisibility(visibility);
}
public void updateVisibility(StatusPrivacy visibility) {
this.visibility = visibility;
this.iconEnd = visibility != null ? switch (visibility) {
case PUBLIC -> R.drawable.ic_fluent_earth_20_regular;
case UNLISTED -> R.drawable.ic_fluent_people_community_20_regular;
case PRIVATE -> R.drawable.ic_fluent_people_checkmark_20_regular;
default -> 0;
} : 0;
}
@Override
@@ -70,10 +86,18 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
@Override
public void onBind(ReblogOrReplyLineStatusDisplayItem item){
text.setText(item.text);
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, 0, 0);
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, item.iconEnd, 0);
if(item.handleClick!=null) text.setOnClickListener(item.handleClick);
text.setEnabled(!item.inset);
text.setClickable(!item.inset);
Context ctx = itemView.getContext();
int visibilityText = item.visibility != null ? switch (item.visibility) {
case PUBLIC -> R.string.visibility_public;
case UNLISTED -> R.string.sk_visibility_unlisted;
case PRIVATE -> R.string.visibility_followers_only;
default -> 0;
} : 0;
if (visibilityText != 0) text.setContentDescription(item.text + "." + ctx.getString(R.string.post_visibility) + " " + ctx.getString(visibilityText));
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
UiUtils.fixCompoundDrawableTintOnAndroid6(text);
}

View File

@@ -81,13 +81,13 @@ public abstract class StatusDisplayItem{
Bundle args=new Bundle();
args.putString("account", accountID);
if(status.reblog!=null){
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20_filled, i->{
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20_filled, status.visibility, i->{
args.putParcelable("profileAccount", Parcels.wrap(status.account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
}));
}else if(status.inReplyToAccountId!=null && knownAccounts.containsKey(status.inReplyToAccountId)){
Account account=Objects.requireNonNull(knownAccounts.get(status.inReplyToAccountId));
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.in_reply_to, account.displayName), account.emojis, R.drawable.ic_fluent_arrow_reply_20_filled, i->{
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.in_reply_to, account.displayName), account.emojis, R.drawable.ic_fluent_arrow_reply_20_filled, null, i->{
args.putParcelable("profileAccount", Parcels.wrap(account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
}));