implement setting boost visibility

This commit is contained in:
sk 2022-12-22 11:03:42 -03:00 committed by LucasGGamerM
parent 42eacea4be
commit a2302ad318
9 changed files with 209 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.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import java.util.HashMap; import java.util.HashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -59,7 +60,7 @@ public class StatusInteractionController{
E.post(new StatusCountersUpdatedEvent(status)); 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()) if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread"); throw new IllegalStateException("Can only be called from main thread");
@ -67,7 +68,7 @@ public class StatusInteractionController{
if(current!=null){ if(current!=null){
current.cancel(); current.cancel();
} }
SetStatusReblogged req=(SetStatusReblogged) new SetStatusReblogged(status.id, reblogged) SetStatusReblogged req=(SetStatusReblogged) new SetStatusReblogged(status.id, reblogged, visibility)
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Status reblog){ 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.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
public class SetStatusReblogged extends MastodonAPIRequest<Status>{ 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); 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); 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; return items;
} }

View File

@ -1,9 +1,13 @@
package org.joinmastodon.android.ui.displayitems; package org.joinmastodon.android.ui.displayitems;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
@ -18,14 +22,18 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.ComposeFragment; import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy; import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels; import org.parceler.Parcels;
import java.util.function.Consumer;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.utils.CubicBezierInterpolator; import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
@ -166,21 +174,68 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void onBoostClick(View v){ private void onBoostClick(View v){
boost.setSelected(!item.status.reblogged); boost.setSelected(!item.status.reblogged);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, r->{ 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); v.startAnimation(opacityIn);
bindButton(boost, r.reblogsCount); bindButton(boost, r.reblogsCount);
});
} }
private boolean onBoostLongClick(View v){ private boolean onBoostLongClick(View v){
v.setAlpha(1); Context ctx = itemView.getContext();
v.setScaleX(1); View menu = LayoutInflater.from(ctx).inflate(R.layout.item_boost_menu, null);
v.setScaleY(1); 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(); Bundle args=new Bundle();
args.putString("account", item.accountID); args.putString("account", item.accountID);
args.putString("prefilledText", "\n\n" + item.status.url); args.putString("prefilledText", "\n\n" + item.status.url);
args.putInt("selectionStart", 0); args.putInt("selectionStart", 0);
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args); Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
});
dialog.show();
return true; return true;
} }

View File

@ -3,6 +3,7 @@ package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.MastodonApp.context; import static org.joinmastodon.android.MastodonApp.context;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.text.SpannableStringBuilder; import android.text.SpannableStringBuilder;
@ -14,6 +15,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Emoji; import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper; import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
@ -30,10 +32,13 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
private CharSequence text; private CharSequence text;
@DrawableRes @DrawableRes
private int icon; private int icon;
private StatusPrivacy visibility;
@DrawableRes
private int iconEnd;
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(); private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
private View.OnClickListener handleClick; 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); super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text); SpannableStringBuilder ssb=new SpannableStringBuilder(text);
HtmlParser.parseCustomEmoji(ssb, emojis); HtmlParser.parseCustomEmoji(ssb, emojis);
@ -43,6 +48,17 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
this.handleClick=handleClick; this.handleClick=handleClick;
TypedValue outValue = new TypedValue(); TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true); 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 @Override
@ -70,10 +86,18 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public void onBind(ReblogOrReplyLineStatusDisplayItem item){ public void onBind(ReblogOrReplyLineStatusDisplayItem item){
text.setText(item.text); 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); if(item.handleClick!=null) text.setOnClickListener(item.handleClick);
text.setEnabled(!item.inset); text.setEnabled(!item.inset);
text.setClickable(!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) if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N)
UiUtils.fixCompoundDrawableTintOnAndroid6(text); UiUtils.fixCompoundDrawableTintOnAndroid6(text);
} }

View File

@ -80,13 +80,13 @@ public abstract class StatusDisplayItem{
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", accountID); args.putString("account", accountID);
if(status.reblog!=null){ 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)); args.putParcelable("profileAccount", Parcels.wrap(status.account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args); Nav.go(fragment.getActivity(), ProfileFragment.class, args);
})); }));
}else if(status.inReplyToAccountId!=null && knownAccounts.containsKey(status.inReplyToAccountId)){ }else if(status.inReplyToAccountId!=null && knownAccounts.containsKey(status.inReplyToAccountId)){
Account account=Objects.requireNonNull(knownAccounts.get(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)); args.putParcelable("profileAccount", Parcels.wrap(account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args); Nav.go(fragment.getActivity(), ProfileFragment.class, args);
})); }));

View File

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
<path android:pathData="M10 2c4.418 0 8 3.582 8 8s-3.582 8-8 8-8-3.582-8-8 3.582-8 8-8zm0 1c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7zm3.358 4.646c0.174 0.174 0.193 0.443 0.058 0.638l-0.058 0.07-4.005 4.004c-0.173 0.174-0.442 0.193-0.637 0.058l-0.07-0.058-2-2c-0.195-0.195-0.195-0.511 0-0.707C6.82 9.478 7.09 9.46 7.284 9.594l0.07 0.057L9 11.298l3.651-3.652c0.196-0.195 0.512-0.195 0.707 0z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M21.78 3.28c0.293-0.293 0.293-0.767 0-1.06-0.293-0.293-0.768-0.293-1.06 0l-10 10-0.47 1.53 1.53-0.47 10-10zM6.25 3C4.455 3 3 4.455 3 6.25v11.5C3 19.545 4.455 21 6.25 21h11.5c1.795 0 3.25-1.455 3.25-3.25v-8C21 9.336 20.664 9 20.25 9S19.5 9.336 19.5 9.75v8c0 0.966-0.784 1.75-1.75 1.75H6.25c-0.966 0-1.75-0.784-1.75-1.75V6.25c0-0.966 0.784-1.75 1.75-1.75h8C14.664 4.5 15 4.164 15 3.75S14.664 3 14.25 3h-8z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingVertical="12dp">
<TextView
android:id="@+id/reblog_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:fontFamily="sans-serif-medium"
android:textColor="?android:colorAccent"
android:accessibilityHeading="true"
android:paddingVertical="12dp"
android:paddingHorizontal="24dp"
android:text="@string/sk_reblog_with_visibility" />
<TextView
android:id="@+id/delete_reblog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:paddingVertical="12dp"
android:paddingHorizontal="24dp"
android:gravity="center_vertical"
android:textSize="16sp"
android:textColor="?android:textColorPrimary"
android:drawablePadding="16dp"
android:background="?android:selectableItemBackground"
android:text="@string/sk_undo_reblog"
android:visibility="gone"
android:drawableStart="@drawable/ic_fluent_arrow_repeat_all_off_24_regular" />
<TextView
android:id="@+id/vis_public"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:paddingVertical="12dp"
android:paddingHorizontal="24dp"
android:gravity="center_vertical"
android:textSize="16sp"
android:textColor="?android:textColorPrimary"
android:drawablePadding="16dp"
android:background="?android:selectableItemBackground"
android:text="@string/visibility_public"
android:drawableStart="@drawable/ic_fluent_earth_24_regular" />
<TextView
android:id="@+id/vis_unlisted"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:paddingVertical="12dp"
android:paddingHorizontal="24dp"
android:gravity="center_vertical"
android:textSize="16sp"
android:textColor="?android:textColorPrimary"
android:drawablePadding="16dp"
android:background="?android:selectableItemBackground"
android:text="@string/sk_visibility_unlisted"
android:drawableStart="@drawable/ic_fluent_people_community_24_regular" />
<TextView
android:id="@+id/vis_followers"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:paddingVertical="12dp"
android:paddingHorizontal="24dp"
android:gravity="center_vertical"
android:textSize="16sp"
android:textColor="?android:textColorPrimary"
android:drawablePadding="16dp"
android:background="?android:selectableItemBackground"
android:text="@string/visibility_followers_only"
android:drawableStart="@drawable/ic_fluent_people_checkmark_24_regular" />
<View
android:id="@+id/separator"
android:layout_height="1dp"
android:layout_width="match_parent"
android:layout_marginVertical="8dp"
android:background="?colorPollVoted" />
<TextView
android:id="@+id/quote"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="36dp"
android:paddingVertical="12dp"
android:paddingHorizontal="24dp"
android:gravity="center_vertical"
android:textSize="16sp"
android:textColor="?android:textColorPrimary"
android:drawablePadding="16dp"
android:background="?android:selectableItemBackground"
android:text="@string/sk_quote_post"
android:drawableStart="@drawable/ic_fluent_compose_24_regular" />
</LinearLayout>