progress indicator for emoji reactions

This commit is contained in:
sk 2023-08-23 23:38:12 +02:00
parent 4920bf63e3
commit 647e3e5e85
2 changed files with 92 additions and 39 deletions

View File

@ -1,6 +1,7 @@
package org.joinmastodon.android.ui.displayitems; package org.joinmastodon.android.ui.displayitems;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@ -10,13 +11,13 @@ import android.util.DisplayMetrics;
import android.util.Pair; import android.util.Pair;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.E; import org.joinmastodon.android.E;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
@ -40,6 +41,7 @@ import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.CustomEmojiPopupKeyboard; import org.joinmastodon.android.ui.CustomEmojiPopupKeyboard;
import org.joinmastodon.android.ui.utils.TextDrawable; import org.joinmastodon.android.ui.utils.TextDrawable;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ProgressBarButton;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
@ -95,17 +97,34 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
hidden=status.reactions.isEmpty() && hideAdd; hidden=status.reactions.isEmpty() && hideAdd;
} }
private MastodonAPIRequest<?> createRequest(String name, boolean delete, Runnable cb){ // borrowed from ProfileFragment
private void setActionProgressVisible(Holder.EmojiReactionViewHolder vh, boolean visible){
if(vh==null) return;
vh.progress.setVisibility(visible ? View.VISIBLE : View.GONE);
if(visible)
vh.progress.setIndeterminateTintList(vh.btn.getTextColors());
vh.btn.setClickable(!visible);
}
private MastodonAPIRequest<?> createRequest(String name, int count, boolean delete, Holder.EmojiReactionViewHolder vh, Runnable cb){
setActionProgressVisible(vh, true);
boolean ak=parentFragment.isInstanceAkkoma(); boolean ak=parentFragment.isInstanceAkkoma();
boolean keepSpinning=delete && count == 1;
if(forAnnouncement){ if(forAnnouncement){
MastodonAPIRequest<Object> req=delete MastodonAPIRequest<Object> req=delete
? new DeleteAnnouncementReaction(status.id, name) ? new DeleteAnnouncementReaction(status.id, name)
: new AddAnnouncementReaction(status.id, name); : new AddAnnouncementReaction(status.id, name);
return req.setCallback(new Callback<>(){ return req.setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Object result){ cb.run(); } public void onSuccess(Object result){
if(!keepSpinning) setActionProgressVisible(vh, false);
cb.run();
}
@Override @Override
public void onError(ErrorResponse error){ error.showToast(parentFragment.getContext()); } public void onError(ErrorResponse error){
setActionProgressVisible(vh, false);
error.showToast(parentFragment.getContext());
}
}); });
}else{ }else{
MastodonAPIRequest<Status> req=delete MastodonAPIRequest<Status> req=delete
@ -113,9 +132,15 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
: (ak ? new PleromaAddStatusReaction(status.id, name) : new AddStatusReaction(status.id, name)); : (ak ? new PleromaAddStatusReaction(status.id, name) : new AddStatusReaction(status.id, name));
return req.setCallback(new Callback<>(){ return req.setCallback(new Callback<>(){
@Override @Override
public void onSuccess(Status result){ cb.run(); } public void onSuccess(Status result){
if(!keepSpinning) setActionProgressVisible(vh, false);
cb.run();
}
@Override @Override
public void onError(ErrorResponse error){ error.showToast(parentFragment.getContext()); } public void onError(ErrorResponse error){
setActionProgressVisible(vh, false);
error.showToast(parentFragment.getContext());
}
}); });
} }
} }
@ -188,25 +213,24 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
private void addEmojiReaction(String emoji, Emoji info) { private void addEmojiReaction(String emoji, Emoji info) {
if(item.status.reactions.stream().filter(r->r.name.equals(emoji) && r.me).findAny().isPresent()) return; if(item.status.reactions.stream().filter(r->r.name.equals(emoji) && r.me).findAny().isPresent()) return;
item.createRequest(emoji, false, ()->{ Account me=AccountSessionManager.get(item.accountID).self;
Account me=AccountSessionManager.get(item.accountID).self; EmojiReaction existing=null;
boolean found=false; for(int i=0; i<item.status.reactions.size(); i++){
for(int i=0; i<item.status.reactions.size(); i++){ EmojiReaction r=item.status.reactions.get(i);
EmojiReaction r=item.status.reactions.get(i); if(r.name.equals(emoji)){
if(r.name.equals(emoji)){ existing=r;
found=true; r.add(me);
r.add(me); adapter.notifyItemChanged(i);
adapter.notifyItemChanged(i); break;
break;
}
} }
if(!found){ }
item.status.reactions.add(info!=null ? EmojiReaction.of(info, me) : EmojiReaction.of(emoji, me)); if(existing==null){
adapter.notifyItemRangeInserted(item.status.reactions.size() - 1, 1); item.status.reactions.add(0, info!=null ? EmojiReaction.of(info, me) : EmojiReaction.of(emoji, me));
} adapter.notifyItemRangeInserted(0, 1);
E.post(new StatusCountersUpdatedEvent(item.status, adapter.parentHolder)); }
}).exec(item.accountID); E.post(new StatusCountersUpdatedEvent(item.status, adapter.parentHolder));
item.createRequest(emoji, existing==null ? 1 : existing.count, false, null, ()->{}).exec(item.accountID);
} }
@Override @Override
@ -252,14 +276,14 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
@NonNull @NonNull
@Override @Override
public EmojiReactionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){ public EmojiReactionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout frame=new FrameLayout(parent.getContext()); // FrameLayout frame=new FrameLayout(parent.getContext());
frame.setPaddingRelative(0, 0, V.dp(8), 0); // frame.setPaddingRelative(0, 0, V.dp(8), 0);
Button btn=new Button(parent.getContext(), null, 0, R.style.Widget_Mastodon_M3_Button_Outlined_Icon); // Button btn=new Button(parent.getContext(), null, 0, R.style.Widget_Mastodon_M3_Button_Outlined_Icon);
btn.setCompoundDrawableTintList(null); // btn.setCompoundDrawableTintList(null);
btn.setBackgroundResource(R.drawable.bg_button_m3_tonal); // btn.setBackgroundResource(R.drawable.bg_button_m3_tonal);
btn.setCompoundDrawables(item.placeholder, null, null, null); // btn.setCompoundDrawables(item.placeholder, null, null, null);
frame.addView(btn); // frame.addView(btn);
return new EmojiReactionViewHolder(frame); return new EmojiReactionViewHolder(parent.getContext(), list);
} }
@Override @Override
@ -285,11 +309,13 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
} }
private static class EmojiReactionViewHolder extends BindableViewHolder<Pair<EmojiReactionsStatusDisplayItem, EmojiReaction>> implements ImageLoaderViewHolder{ private static class EmojiReactionViewHolder extends BindableViewHolder<Pair<EmojiReactionsStatusDisplayItem, EmojiReaction>> implements ImageLoaderViewHolder{
private final Button btn; private final ProgressBarButton btn;
private final ProgressBar progress;
public EmojiReactionViewHolder(@NonNull View itemView){ public EmojiReactionViewHolder(Context context, RecyclerView list){
super(itemView); super(context, R.layout.item_emoji_reaction, list);
btn=(Button) ((FrameLayout) itemView).getChildAt(0); btn=findViewById(R.id.btn);
progress=findViewById(R.id.progress);
} }
@Override @Override
@ -306,6 +332,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
@Override @Override
public void onBind(Pair<EmojiReactionsStatusDisplayItem, EmojiReaction> item){ public void onBind(Pair<EmojiReactionsStatusDisplayItem, EmojiReaction> item){
item.first.setActionProgressVisible(this, false);
EmojiReactionsStatusDisplayItem parent=item.first; EmojiReactionsStatusDisplayItem parent=item.first;
EmojiReaction reaction=item.second; EmojiReaction reaction=item.second;
btn.setText(UiUtils.abbreviateNumber(reaction.count)); btn.setText(UiUtils.abbreviateNumber(reaction.count));
@ -322,9 +349,8 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
btn.setSelected(reaction.me); btn.setSelected(reaction.me);
btn.setOnClickListener(e->{ btn.setOnClickListener(e->{
boolean deleting=reaction.me; boolean deleting=reaction.me;
parent.createRequest(reaction.name, deleting, ()->{ parent.createRequest(reaction.name, reaction.count, deleting, this, ()->{
EmojiReactionsAdapter adapter = (EmojiReactionsAdapter) getBindingAdapter(); EmojiReactionsAdapter adapter = (EmojiReactionsAdapter) getBindingAdapter();
for(int i=0; i<parent.status.reactions.size(); i++){ for(int i=0; i<parent.status.reactions.size(); i++){
EmojiReaction r=parent.status.reactions.get(i); EmojiReaction r=parent.status.reactions.get(i);
if(!r.name.equals(reaction.name)) continue; if(!r.name.equals(reaction.name)) continue;

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:orientation="vertical"
android:paddingEnd="8dp"
tools:ignore="RtlSymmetry">
<ProgressBar
android:id="@+id/progress"
style="?android:progressBarStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:elevation="10dp"
android:indeterminate="true"
android:outlineProvider="none"
android:visibility="gone"/>
<org.joinmastodon.android.ui.views.ProgressBarButton
android:id="@+id/btn"
style="@style/Widget.Mastodon.M3.Button.Outlined.Icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTint="@null"
android:drawableStart="@drawable/image_placeholder"
android:background="@drawable/bg_button_m3_tonal"/>
</FrameLayout>