Toot actions
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
package org.joinmastodon.android.api;
|
||||
|
||||
import android.os.Looper;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.MastodonApp;
|
||||
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 java.util.HashMap;
|
||||
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
|
||||
public class StatusInteractionController{
|
||||
private final String accountID;
|
||||
private final HashMap<String, SetStatusFavorited> runningFavoriteRequests=new HashMap<>();
|
||||
private final HashMap<String, SetStatusReblogged> runningReblogRequests=new HashMap<>();
|
||||
|
||||
public StatusInteractionController(String accountID){
|
||||
this.accountID=accountID;
|
||||
}
|
||||
|
||||
public void setFavorited(Status status, boolean favorited){
|
||||
if(!Looper.getMainLooper().isCurrentThread())
|
||||
throw new IllegalStateException("Can only be called from main thread");
|
||||
|
||||
SetStatusFavorited current=runningFavoriteRequests.remove(status.id);
|
||||
if(current!=null){
|
||||
current.cancel();
|
||||
}
|
||||
SetStatusFavorited req=(SetStatusFavorited) new SetStatusFavorited(status.id, favorited)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Status result){
|
||||
runningFavoriteRequests.remove(status.id);
|
||||
E.post(new StatusCountersUpdatedEvent(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
runningFavoriteRequests.remove(status.id);
|
||||
error.showToast(MastodonApp.context);
|
||||
status.favourited=!favorited;
|
||||
if(favorited)
|
||||
status.favouritesCount--;
|
||||
else
|
||||
status.favouritesCount++;
|
||||
E.post(new StatusCountersUpdatedEvent(status));
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
runningFavoriteRequests.put(status.id, req);
|
||||
status.favourited=favorited;
|
||||
if(favorited)
|
||||
status.favouritesCount++;
|
||||
else
|
||||
status.favouritesCount--;
|
||||
}
|
||||
|
||||
public void setReblogged(Status status, boolean reblogged){
|
||||
if(!Looper.getMainLooper().isCurrentThread())
|
||||
throw new IllegalStateException("Can only be called from main thread");
|
||||
|
||||
SetStatusReblogged current=runningReblogRequests.remove(status.id);
|
||||
if(current!=null){
|
||||
current.cancel();
|
||||
}
|
||||
SetStatusReblogged req=(SetStatusReblogged) new SetStatusReblogged(status.id, reblogged)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Status result){
|
||||
runningReblogRequests.remove(status.id);
|
||||
E.post(new StatusCountersUpdatedEvent(result));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
runningReblogRequests.remove(status.id);
|
||||
error.showToast(MastodonApp.context);
|
||||
status.reblogged=!reblogged;
|
||||
if(reblogged)
|
||||
status.reblogsCount--;
|
||||
else
|
||||
status.reblogsCount++;
|
||||
E.post(new StatusCountersUpdatedEvent(status));
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
runningReblogRequests.put(status.id, req);
|
||||
status.reblogged=reblogged;
|
||||
if(reblogged)
|
||||
status.reblogsCount++;
|
||||
else
|
||||
status.reblogsCount--;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.joinmastodon.android.api.requests.statuses;
|
||||
|
||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
|
||||
public class SetStatusFavorited extends MastodonAPIRequest<Status>{
|
||||
public SetStatusFavorited(String id, boolean favorited){
|
||||
super(HttpMethod.POST, "/statuses/"+id+"/"+(favorited ? "favourite" : "unfavourite"), Status.class);
|
||||
setRequestBody(new Object());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.joinmastodon.android.api.requests.statuses;
|
||||
|
||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
|
||||
public class SetStatusReblogged extends MastodonAPIRequest<Status>{
|
||||
public SetStatusReblogged(String id, boolean reblogged){
|
||||
super(HttpMethod.POST, "/statuses/"+id+"/"+(reblogged ? "reblog" : "unreblog"), Status.class);
|
||||
setRequestBody(new Object());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.joinmastodon.android.api.session;
|
||||
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.StatusInteractionController;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Application;
|
||||
import org.joinmastodon.android.model.Token;
|
||||
@@ -13,6 +14,7 @@ public class AccountSession{
|
||||
public Application app;
|
||||
public long infoLastUpdated;
|
||||
private transient MastodonAPIController apiController;
|
||||
private transient StatusInteractionController statusInteractionController;
|
||||
|
||||
AccountSession(Token token, Account self, Application app, String domain, int tootCharLimit){
|
||||
this.token=token;
|
||||
@@ -34,4 +36,10 @@ public class AccountSession{
|
||||
apiController=new MastodonAPIController(this);
|
||||
return apiController;
|
||||
}
|
||||
|
||||
public StatusInteractionController getStatusInteractionController(){
|
||||
if(statusInteractionController==null)
|
||||
statusInteractionController=new StatusInteractionController(getID());
|
||||
return statusInteractionController;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.joinmastodon.android.events;
|
||||
|
||||
import org.joinmastodon.android.model.Status;
|
||||
|
||||
public class StatusCountersUpdatedEvent{
|
||||
public String id;
|
||||
public int favorites, reblogs;
|
||||
public boolean favorited, reblogged;
|
||||
|
||||
public StatusCountersUpdatedEvent(Status s){
|
||||
id=s.id;
|
||||
favorites=s.favouritesCount;
|
||||
reblogs=s.reblogsCount;
|
||||
favorited=s.favourited;
|
||||
reblogged=s.reblogged;
|
||||
}
|
||||
}
|
||||
@@ -79,18 +79,6 @@ public class HomeTimelineFragment extends StatusListFragment{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
E.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(){
|
||||
super.onDestroy();
|
||||
E.unregister(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusCreated(StatusCreatedEvent ev){
|
||||
prependItems(Collections.singletonList(ev.status));
|
||||
|
||||
@@ -1,12 +1,56 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
E.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(){
|
||||
super.onDestroy();
|
||||
E.unregister(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){
|
||||
for(Status s:data){
|
||||
if(s.getContentStatus().id.equals(ev.id)){
|
||||
s.update(ev);
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof FooterStatusDisplayItem.Holder && ((FooterStatusDisplayItem.Holder) holder).getItem().status==s.getContentStatus()){
|
||||
((FooterStatusDisplayItem.Holder) holder).rebind();
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
for(Status s:preloadedData){
|
||||
if(s.id.equals(ev.id)){
|
||||
s.update(ev);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.joinmastodon.android.model;
|
||||
|
||||
import org.joinmastodon.android.api.ObjectValidationException;
|
||||
import org.joinmastodon.android.api.RequiredField;
|
||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.List;
|
||||
@@ -111,4 +112,15 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
||||
public String getID(){
|
||||
return id;
|
||||
}
|
||||
|
||||
public void update(StatusCountersUpdatedEvent ev){
|
||||
favouritesCount=ev.favorites;
|
||||
reblogsCount=ev.reblogs;
|
||||
favourited=ev.favorited;
|
||||
reblogged=ev.reblogged;
|
||||
}
|
||||
|
||||
public Status getContentStatus(){
|
||||
return reblog!=null ? reblog : this;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.StatusPrivacy;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
@@ -17,7 +21,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
private final Status status;
|
||||
public final Status status;
|
||||
private final String accountID;
|
||||
|
||||
public FooterStatusDisplayItem(String parentID, Status status, String accountID){
|
||||
@@ -43,9 +47,13 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
share=findViewById(R.id.share);
|
||||
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N){
|
||||
UiUtils.fixCompoundDrawableTintOnAndroid6(reply, R.color.text_secondary);
|
||||
UiUtils.fixCompoundDrawableTintOnAndroid6(boost, R.color.text_secondary);
|
||||
UiUtils.fixCompoundDrawableTintOnAndroid6(favorite, R.color.text_secondary);
|
||||
UiUtils.fixCompoundDrawableTintOnAndroid6(boost, R.color.boost_icon);
|
||||
UiUtils.fixCompoundDrawableTintOnAndroid6(favorite, R.color.favorite_icon);
|
||||
}
|
||||
reply.setOnClickListener(this::onReplyClick);
|
||||
boost.setOnClickListener(this::onBoostClick);
|
||||
favorite.setOnClickListener(this::onFavoriteClick);
|
||||
share.setOnClickListener(this::onShareClick);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,6 +61,10 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
bindButton(reply, item.status.repliesCount);
|
||||
bindButton(boost, item.status.reblogsCount);
|
||||
bindButton(favorite, item.status.favouritesCount);
|
||||
boost.setSelected(item.status.reblogged);
|
||||
favorite.setSelected(item.status.favourited);
|
||||
boost.setEnabled(item.status.visibility==StatusPrivacy.PUBLIC || item.status.visibility==StatusPrivacy.UNLISTED
|
||||
|| (item.status.visibility==StatusPrivacy.PRIVATE && item.status.account.id.equals(AccountSessionManager.getInstance().getAccount(item.accountID).self.id)));
|
||||
}
|
||||
|
||||
private void bindButton(TextView btn, int count){
|
||||
@@ -64,5 +76,28 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
btn.setCompoundDrawablePadding(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void onReplyClick(View v){
|
||||
|
||||
}
|
||||
|
||||
private void onBoostClick(View v){
|
||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged);
|
||||
boost.setSelected(item.status.reblogged);
|
||||
bindButton(boost, item.status.reblogsCount);
|
||||
}
|
||||
|
||||
private void onFavoriteClick(View v){
|
||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited);
|
||||
favorite.setSelected(item.status.favourited);
|
||||
bindButton(favorite, item.status.favouritesCount);
|
||||
}
|
||||
|
||||
private void onShareClick(View v){
|
||||
Intent intent=new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_TEXT, item.status.url);
|
||||
v.getContext().startActivity(Intent.createChooser(intent, v.getContext().getString(R.string.share_toot_title)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public abstract class StatusDisplayItem{
|
||||
public static ArrayList<StatusDisplayItem> buildItems(Fragment fragment, Status status, String accountID, DisplayItemsParent parentObject){
|
||||
String parentID=parentObject.getID();
|
||||
ArrayList<StatusDisplayItem> items=new ArrayList<>();
|
||||
Status statusForContent=status.reblog==null ? status : status.reblog;
|
||||
Status statusForContent=status.getContentStatus();
|
||||
if(status.reblog!=null){
|
||||
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment.getString(R.string.user_boosted, status.account.displayName)));
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public abstract class StatusDisplayItem{
|
||||
photoIndex++;
|
||||
}
|
||||
}
|
||||
items.add(new FooterStatusDisplayItem(parentID, status, accountID));
|
||||
items.add(new FooterStatusDisplayItem(parentID, statusForContent, accountID));
|
||||
return items;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user