diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java b/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java new file mode 100644 index 00000000..7836ad95 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/StatusInteractionController.java @@ -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 runningFavoriteRequests=new HashMap<>(); + private final HashMap 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--; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/SetStatusFavorited.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/SetStatusFavorited.java new file mode 100644 index 00000000..f019c444 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/SetStatusFavorited.java @@ -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{ + public SetStatusFavorited(String id, boolean favorited){ + super(HttpMethod.POST, "/statuses/"+id+"/"+(favorited ? "favourite" : "unfavourite"), Status.class); + setRequestBody(new Object()); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/SetStatusReblogged.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/SetStatusReblogged.java new file mode 100644 index 00000000..a28aed7b --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/SetStatusReblogged.java @@ -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{ + public SetStatusReblogged(String id, boolean reblogged){ + super(HttpMethod.POST, "/statuses/"+id+"/"+(reblogged ? "reblog" : "unreblog"), Status.class); + setRequestBody(new Object()); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java index 793f8ea4..c69702f4 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java +++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java @@ -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; + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/StatusCountersUpdatedEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/StatusCountersUpdatedEvent.java new file mode 100644 index 00000000..5eb4190d --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/events/StatusCountersUpdatedEvent.java @@ -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; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java index 0030799b..aa8ef1f4 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -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)); diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java index aad8f070..f4306014 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java @@ -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{ protected List 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 buildItems(Fragment fragment, Status status, String accountID, DisplayItemsParent parentObject){ String parentID=parentObject.getID(); ArrayList 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; } diff --git a/mastodon/src/main/res/color/boost_icon.xml b/mastodon/src/main/res/color/boost_icon.xml new file mode 100644 index 00000000..8599aeaa --- /dev/null +++ b/mastodon/src/main/res/color/boost_icon.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/color/favorite_icon.xml b/mastodon/src/main/res/color/favorite_icon.xml new file mode 100644 index 00000000..9ad6f01b --- /dev/null +++ b/mastodon/src/main/res/color/favorite_icon.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_boost.xml b/mastodon/src/main/res/drawable/ic_boost.xml new file mode 100644 index 00000000..ab9a6b77 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_boost.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/mastodon/src/main/res/drawable/ic_fluent_arrow_repeat_all_off_24_regular.xml b/mastodon/src/main/res/drawable/ic_fluent_arrow_repeat_all_off_24_regular.xml new file mode 100644 index 00000000..fea8a97e --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_arrow_repeat_all_off_24_regular.xml @@ -0,0 +1,3 @@ + + + diff --git a/mastodon/src/main/res/drawable/ic_fluent_star_24_selector.xml b/mastodon/src/main/res/drawable/ic_fluent_star_24_selector.xml new file mode 100644 index 00000000..a4b89d10 --- /dev/null +++ b/mastodon/src/main/res/drawable/ic_fluent_star_24_selector.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mastodon/src/main/res/layout/display_item_footer.xml b/mastodon/src/main/res/layout/display_item_footer.xml index 388e6564..77d520ea 100644 --- a/mastodon/src/main/res/layout/display_item_footer.xml +++ b/mastodon/src/main/res/layout/display_item_footer.xml @@ -12,7 +12,7 @@ android:layout_width="wrap_content" android:layout_height="24dp" android:minWidth="56dp"> - - @@ -56,14 +57,15 @@ android:layout_width="wrap_content" android:layout_height="24dp" android:minWidth="56dp"> - diff --git a/mastodon/src/main/res/values/colors.xml b/mastodon/src/main/res/values/colors.xml index 7b1cfb9e..49d380bf 100644 --- a/mastodon/src/main/res/values/colors.xml +++ b/mastodon/src/main/res/values/colors.xml @@ -20,4 +20,8 @@ @color/gray_500 #E9EDF2 #282C37 + #80667085 + + #FF9F0A + #79BD9A \ No newline at end of file diff --git a/mastodon/src/main/res/values/strings.xml b/mastodon/src/main/res/values/strings.xml index 95c7e8d7..30988b32 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -25,4 +25,6 @@ %dm %dh %dd + + Share toot \ No newline at end of file