Add reaction when favoriting post on Iceshrimp
This commit is contained in:
parent
86b6adf228
commit
3266a490be
|
@ -7,14 +7,23 @@ import org.joinmastodon.android.MastodonApp;
|
|||
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
|
||||
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
|
||||
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
|
||||
import org.joinmastodon.android.events.ReblogDeletedEvent;
|
||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||
import org.joinmastodon.android.model.Emoji;
|
||||
import org.joinmastodon.android.model.EmojiCategory;
|
||||
import org.joinmastodon.android.model.EmojiReaction;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.StatusPrivacy;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import me.grishka.appkit.api.Callback;
|
||||
|
@ -40,6 +49,9 @@ public class StatusInteractionController{
|
|||
if(!Looper.getMainLooper().isCurrentThread())
|
||||
throw new IllegalStateException("Can only be called from main thread");
|
||||
|
||||
AccountSession session=AccountSessionManager.get(accountID);
|
||||
Instance instance=session.getInstance().get();
|
||||
|
||||
SetStatusFavorited current=runningFavoriteRequests.remove(status.id);
|
||||
if(current!=null){
|
||||
current.cancel();
|
||||
|
@ -52,6 +64,7 @@ public class StatusInteractionController{
|
|||
result.favouritesCount = Math.max(0, status.favouritesCount + (favorited ? 1 : -1));
|
||||
cb.accept(result);
|
||||
if(updateCounters) E.post(new StatusCountersUpdatedEvent(result));
|
||||
if(instance.isIceshrimp()) E.post(new EmojiReactionsUpdatedEvent(status.id, result.reactions, false, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,12 +74,55 @@ public class StatusInteractionController{
|
|||
status.favourited=!favorited;
|
||||
cb.accept(status);
|
||||
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||
if(instance.isIceshrimp()) E.post(new EmojiReactionsUpdatedEvent(status.id, status.reactions, false, null));
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
runningFavoriteRequests.put(status.id, req);
|
||||
status.favourited=favorited;
|
||||
if(updateCounters) E.post(new StatusCountersUpdatedEvent(status));
|
||||
|
||||
String defaultReactionEmojiRaw=instance.configuration.reactions.defaultReaction;
|
||||
if(!instance.isIceshrimp() || defaultReactionEmojiRaw==null)
|
||||
return;
|
||||
|
||||
boolean reactionIsCustom=defaultReactionEmojiRaw.startsWith(":");
|
||||
String defaultReactionEmoji=reactionIsCustom ? defaultReactionEmojiRaw.substring(1, defaultReactionEmojiRaw.length()-1) : defaultReactionEmojiRaw;
|
||||
ArrayList<EmojiReaction> reactions=new ArrayList<>(status.reactions.size());
|
||||
for(EmojiReaction reaction:status.reactions){
|
||||
reactions.add(reaction.copy());
|
||||
}
|
||||
Optional<EmojiReaction> existingReaction=reactions.stream().filter(r->r.me).findFirst();
|
||||
Optional<EmojiReaction> existingDefaultReaction=reactions.stream().filter(r->r.name.equals(defaultReactionEmoji)).findFirst();
|
||||
if(existingReaction.isPresent() && !favorited){
|
||||
existingReaction.get().me=false;
|
||||
existingReaction.get().count--;
|
||||
existingReaction.get().pendingChange=true;
|
||||
}else if(existingDefaultReaction.isPresent() && favorited){
|
||||
existingDefaultReaction.get().count++;
|
||||
existingDefaultReaction.get().me=true;
|
||||
existingDefaultReaction.get().pendingChange=true;
|
||||
}else if(favorited){
|
||||
EmojiReaction reaction=null;
|
||||
if(reactionIsCustom){
|
||||
List<EmojiCategory> customEmojis=AccountSessionManager.getInstance().getCustomEmojis(session.domain);
|
||||
for(EmojiCategory category:customEmojis){
|
||||
for(Emoji emoji:category.emojis){
|
||||
if(emoji.shortcode.equals(defaultReactionEmoji)){
|
||||
reaction=EmojiReaction.of(emoji, session.self);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(reaction==null)
|
||||
reaction=EmojiReaction.of(defaultReactionEmoji, session.self);
|
||||
}else{
|
||||
reaction=EmojiReaction.of(defaultReactionEmoji, session.self);
|
||||
}
|
||||
reaction.pendingChange=true;
|
||||
reactions.add(reaction);
|
||||
}
|
||||
E.post(new EmojiReactionsUpdatedEvent(status.id, reactions, false, null));
|
||||
}
|
||||
|
||||
public void setReblogged(Status status, boolean reblogged, StatusPrivacy visibility, Consumer<Status> cb){
|
||||
|
|
|
@ -275,13 +275,17 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
|||
public void onEmojiReactionsChanged(EmojiReactionsUpdatedEvent ev){
|
||||
for(Notification n : data){
|
||||
if(n.status!=null && n.status.getContentStatus().id.equals(ev.id)){
|
||||
n.status.getContentStatus().update(ev);
|
||||
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
|
||||
for(int i=0; i<list.getChildCount(); i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==n.status.getContentStatus() && ev.viewHolder!=holder){
|
||||
reactions.rebind();
|
||||
}else if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(n.getID())){
|
||||
reactions.updateReactions(ev.reactions);
|
||||
}
|
||||
}
|
||||
n.status.getContentStatus().update(ev);
|
||||
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(n.getID())){
|
||||
text.rebind();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -286,13 +286,17 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
|||
public void onEmojiReactionsChanged(EmojiReactionsUpdatedEvent ev){
|
||||
for(Status s:data){
|
||||
if(s.getContentStatus().id.equals(ev.id)){
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==s.getContentStatus() && ev.viewHolder!=holder){
|
||||
reactions.updateReactions(ev.reactions);
|
||||
}
|
||||
}
|
||||
s.getContentStatus().update(ev);
|
||||
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==s.getContentStatus() && ev.viewHolder!=holder){
|
||||
reactions.rebind();
|
||||
}else if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(s.getID())){
|
||||
if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(s.getID())){
|
||||
text.rebind();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ public class EmojiReaction {
|
|||
public String staticUrl;
|
||||
|
||||
public transient ImageLoaderRequest request;
|
||||
public transient boolean pendingChange=false;
|
||||
|
||||
public String getUrl(boolean playGifs){
|
||||
String idealUrl=playGifs ? url : staticUrl;
|
||||
|
@ -60,4 +61,18 @@ public class EmojiReaction {
|
|||
accounts.add(self);
|
||||
accountIds.add(self.id);
|
||||
}
|
||||
|
||||
public EmojiReaction copy() {
|
||||
EmojiReaction r=new EmojiReaction();
|
||||
r.accounts=accounts;
|
||||
r.accountIds=accountIds;
|
||||
r.count=count;
|
||||
r.me=me;
|
||||
r.name=name;
|
||||
r.url=url;
|
||||
r.staticUrl=staticUrl;
|
||||
r.request=request;
|
||||
r.pendingChange=pendingChange;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,6 +227,7 @@ public class Instance extends BaseModel{
|
|||
@Parcel
|
||||
public static class ReactionsConfiguration {
|
||||
public int maxReactions;
|
||||
public String defaultReaction;
|
||||
}
|
||||
|
||||
@Parcel
|
||||
|
|
|
@ -47,6 +47,8 @@ import org.joinmastodon.android.ui.utils.TextDrawable;
|
|||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.EmojiReactionButton;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
|
@ -196,17 +198,23 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||
emojiKeyboard.setListener(this);
|
||||
space.setVisibility(View.GONE);
|
||||
root.addView(emojiKeyboard.getView());
|
||||
boolean hidden=item.isHidden();
|
||||
root.setVisibility(hidden ? View.GONE : View.VISIBLE);
|
||||
line.setVisibility(hidden ? View.GONE : View.VISIBLE);
|
||||
updateVisibility(item.isHidden(), true);
|
||||
imgLoader.updateImages();
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void updateVisibility(boolean hidden, boolean force){
|
||||
int visibility=hidden ? View.GONE : View.VISIBLE;
|
||||
if(!force && visibility==root.getVisibility())
|
||||
return;
|
||||
root.setVisibility(visibility);
|
||||
line.setVisibility(visibility);
|
||||
line.setPadding(
|
||||
list.getPaddingLeft(),
|
||||
hidden ? 0 : V.dp(8),
|
||||
list.getPaddingRight(),
|
||||
item.forAnnouncement ? V.dp(8) : 0
|
||||
);
|
||||
imgLoader.updateImages();
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void hideEmojiKeyboard(){
|
||||
|
@ -267,7 +275,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||
RecyclerView.SmoothScroller scroller=new LinearSmoothScroller(list.getContext());
|
||||
scroller.setTargetPosition(pos);
|
||||
list.getLayoutManager().startSmoothScroll(scroller);
|
||||
updateAddButtonClickable(false);
|
||||
updateMeReactionCount(false);
|
||||
}else{
|
||||
finalExisting.add(me);
|
||||
adapter.notifyItemChanged(item.status.reactions.indexOf(finalExisting));
|
||||
|
@ -297,8 +305,9 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||
}
|
||||
}
|
||||
|
||||
private void updateAddButtonClickable(boolean deleting) {
|
||||
meReactionCount+=deleting ? -1 : 1;
|
||||
private void updateAddButtonClickable() {
|
||||
if(instance==null || instance.configuration==null || instance.configuration.reactions==null || instance.configuration.reactions.maxReactions==0)
|
||||
return;
|
||||
boolean canReact=meReactionCount<instance.configuration.reactions.maxReactions;
|
||||
addButton.setClickable(canReact);
|
||||
|
||||
|
@ -310,6 +319,68 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||
anim.start();
|
||||
}
|
||||
|
||||
private void updateMeReactionCount(boolean deleting) {
|
||||
meReactionCount=Math.max(0, meReactionCount + (deleting ? -1 : 1));
|
||||
updateAddButtonClickable();
|
||||
}
|
||||
|
||||
public void updateReactions(List<EmojiReaction> reactions){
|
||||
for(int i=0;i<item.status.reactions.size();i++){
|
||||
EmojiReaction reaction=item.status.reactions.get(i);
|
||||
Optional<EmojiReaction> newReactionOptional=reactions.stream().filter(r->r.name.equals(reaction.name)).findFirst();
|
||||
if(newReactionOptional.isEmpty()){ // deleted reactions
|
||||
adapter.notifyItemRemoved(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
// changed reactions
|
||||
EmojiReaction newReaction=newReactionOptional.get();
|
||||
if(reaction.count!=newReaction.count || reaction.me!=newReaction.me || reaction.pendingChange!=newReaction.pendingChange){
|
||||
if(newReaction.pendingChange){
|
||||
View holderView=list.getChildAt(i);
|
||||
if(holderView!=null){
|
||||
EmojiReactionViewHolder reactionHolder=(EmojiReactionViewHolder) list.getChildViewHolder(holderView);
|
||||
item.setActionProgressVisible(reactionHolder, true);
|
||||
}
|
||||
}else{
|
||||
adapter.notifyItemChanged(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean pendingAddReaction=false;
|
||||
for(EmojiReaction reaction:reactions){
|
||||
if(item.status.reactions.stream().anyMatch(r->r.name.equals(reaction.name)))
|
||||
continue;
|
||||
|
||||
// new reactions
|
||||
if(reaction.pendingChange){
|
||||
pendingAddReaction=true;
|
||||
continue;
|
||||
}
|
||||
int pos=item.status.reactions.size();
|
||||
item.status.reactions.add(pos, reaction);
|
||||
adapter.notifyItemInserted(pos);
|
||||
RecyclerView.SmoothScroller scroller=new LinearSmoothScroller(list.getContext());
|
||||
scroller.setTargetPosition(pos);
|
||||
list.getLayoutManager().startSmoothScroll(scroller);
|
||||
}
|
||||
if(pendingAddReaction){
|
||||
progress.setVisibility(View.VISIBLE);
|
||||
addButton.setClickable(false);
|
||||
addButton.setAlpha(ALPHA_DISABLED);
|
||||
}else{
|
||||
progress.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
int newMeReactionCount=(int) reactions.stream().filter(r->r.me || r.pendingChange).count();
|
||||
if (newMeReactionCount!=meReactionCount){
|
||||
meReactionCount=newMeReactionCount;
|
||||
updateAddButtonClickable();
|
||||
}
|
||||
|
||||
updateVisibility(reactions.isEmpty() && item.hideEmpty, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImage(int index, Drawable image){
|
||||
View child=list.getChildAt(index);
|
||||
|
@ -386,6 +457,12 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||
|
||||
@Override
|
||||
public void onBind(Pair<EmojiReactionsStatusDisplayItem, EmojiReaction> item){
|
||||
if(item.second.pendingChange){
|
||||
itemView.setVisibility(View.GONE);
|
||||
return;
|
||||
}else{
|
||||
itemView.setVisibility(View.VISIBLE);
|
||||
}
|
||||
item.first.setActionProgressVisible(this, false);
|
||||
EmojiReactionsStatusDisplayItem parent=item.first;
|
||||
EmojiReaction reaction=item.second;
|
||||
|
@ -435,7 +512,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
|||
|
||||
Instance instance=parent.parentFragment.getInstance().get();
|
||||
if(instance.configuration!=null && instance.configuration.reactions!=null && instance.configuration.reactions.maxReactions!=0){
|
||||
adapter.parentHolder.updateAddButtonClickable(deleting);
|
||||
adapter.parentHolder.updateMeReactionCount(deleting);
|
||||
}
|
||||
if(instance.isIceshrimp() && status!=null){
|
||||
parent.parentFragment.onFavoriteChanged(status, adapter.parentHolder.getItemID());
|
||||
|
|
Loading…
Reference in New Issue