From bb463aa10ae98837f2164c6607f34497efe800c5 Mon Sep 17 00:00:00 2001 From: Grishka Date: Fri, 18 Feb 2022 01:50:00 +0300 Subject: [PATCH] Post actions --- mastodon/build.gradle | 2 +- .../api/requests/statuses/DeleteStatus.java | 10 +++ .../android/events/StatusDeletedEvent.java | 11 +++ .../fragments/AccountTimelineFragment.java | 16 ++++ .../fragments/BaseStatusListFragment.java | 5 ++ .../fragments/HomeTimelineFragment.java | 14 +++ .../android/fragments/ProfileFragment.java | 51 ++--------- .../android/fragments/SearchFragment.java | 16 ++++ .../android/fragments/StatusListFragment.java | 38 +++++++- .../android/fragments/ThreadFragment.java | 16 ++++ .../joinmastodon/android/model/Status.java | 2 +- .../displayitems/HeaderStatusDisplayItem.java | 25 ++++++ .../android/ui/utils/UiUtils.java | 88 +++++++++++++++++++ mastodon/src/main/res/menu/post.xml | 7 ++ mastodon/src/main/res/values/strings.xml | 4 + 15 files changed, 256 insertions(+), 49 deletions(-) create mode 100644 mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java create mode 100644 mastodon/src/main/java/org/joinmastodon/android/events/StatusDeletedEvent.java create mode 100644 mastodon/src/main/res/menu/post.xml diff --git a/mastodon/build.gradle b/mastodon/build.gradle index ef522185..5a523fa9 100644 --- a/mastodon/build.gradle +++ b/mastodon/build.gradle @@ -10,7 +10,7 @@ android { applicationId "org.joinmastodon.android" minSdk 23 targetSdk 31 - versionCode 1 + versionCode 2 versionName "0.1" } diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java new file mode 100644 index 00000000..edc8a70b --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/DeleteStatus.java @@ -0,0 +1,10 @@ +package org.joinmastodon.android.api.requests.statuses; + +import org.joinmastodon.android.api.MastodonAPIRequest; +import org.joinmastodon.android.model.Status; + +public class DeleteStatus extends MastodonAPIRequest{ + public DeleteStatus(String id){ + super(HttpMethod.DELETE, "/statuses/"+id, Status.class); + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/events/StatusDeletedEvent.java b/mastodon/src/main/java/org/joinmastodon/android/events/StatusDeletedEvent.java new file mode 100644 index 00000000..5ce18d40 --- /dev/null +++ b/mastodon/src/main/java/org/joinmastodon/android/events/StatusDeletedEvent.java @@ -0,0 +1,11 @@ +package org.joinmastodon.android.events; + +public class StatusDeletedEvent{ + public final String id; + public final String accountID; + + public StatusDeletedEvent(String id, String accountID){ + this.id=id; + this.accountID=accountID; + } +} diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/AccountTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/AccountTimelineFragment.java index 8f9827eb..dc0b4263 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/AccountTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/AccountTimelineFragment.java @@ -4,8 +4,12 @@ import android.app.Activity; import android.os.Bundle; import android.view.View; +import com.squareup.otto.Subscribe; + import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses; +import org.joinmastodon.android.events.StatusCountersUpdatedEvent; +import org.joinmastodon.android.events.StatusDeletedEvent; import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Status; import org.parceler.Parcels; @@ -65,4 +69,16 @@ public class AccountTimelineFragment extends StatusListFragment{ if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading) loadData(); } + + @Override + @Subscribe + public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){ + super.onStatusCountersUpdated(ev); + } + + @Override + @Subscribe + public void onStatusDeleted(StatusDeletedEvent ev){ + super.onStatusDeleted(ev); + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java index 5e3a12b4..88d43500 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java @@ -260,6 +260,7 @@ public abstract class BaseStatusListFragment exten RecyclerView.ViewHolder holder=parent.getChildViewHolder(child); if(holder instanceof FooterStatusDisplayItem.Holder){ float y=child.getY()+child.getHeight()-V.dp(.5f); + paint.setAlpha(Math.round(255*child.getAlpha())); c.drawLine(child.getX(), y, child.getX()+child.getWidth(), y, paint); } } @@ -467,6 +468,10 @@ public abstract class BaseStatusListFragment exten } } + public String getAccountID(){ + return accountID; + } + @Nullable protected I findItemOfType(String id, Class type){ for(StatusDisplayItem item:displayItems){ 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 76c87ce1..ea98ae9e 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTimelineFragment.java @@ -20,7 +20,9 @@ import org.joinmastodon.android.E; import org.joinmastodon.android.R; import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline; import org.joinmastodon.android.api.session.AccountSessionManager; +import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.events.StatusCreatedEvent; +import org.joinmastodon.android.events.StatusDeletedEvent; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.ui.utils.UiUtils; import org.parceler.Parcels; @@ -107,4 +109,16 @@ public class HomeTimelineFragment extends StatusListFragment{ Toolbar toolbar=getToolbar(); toolbar.addView(logo, new Toolbar.LayoutParams(Gravity.CENTER)); } + + @Override + @Subscribe + public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){ + super.onStatusCountersUpdated(ev); + } + + @Override + @Subscribe + public void onStatusDeleted(StatusDeletedEvent ev){ + super.onStatusDeleted(ev); + } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java index 482dd578..0d01f2a0 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java @@ -736,57 +736,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList } private void confirmToggleMuted(){ - new M3AlertDialogBuilder(getActivity()) - .setTitle(relationship.muting ? R.string.confirm_unmute_title : R.string.confirm_mute_title) - .setMessage(getString(relationship.muting ? R.string.confirm_unmute : R.string.confirm_mute, account.displayName)) - .setPositiveButton(relationship.muting ? R.string.do_unmute : R.string.do_mute, (dlg, i)->toggleMuted()) - .setNegativeButton(R.string.cancel, null) - .show(); + UiUtils.confirmToggleMuteUser(getActivity(), accountID, account, relationship.muting, this::updateRelationship); } private void confirmToggleBlocked(){ - new M3AlertDialogBuilder(getActivity()) - .setTitle(relationship.blocking ? R.string.confirm_unblock_title : R.string.confirm_block_title) - .setMessage(getString(relationship.blocking ? R.string.confirm_unblock : R.string.confirm_block, account.displayName)) - .setPositiveButton(relationship.blocking ? R.string.do_block : R.string.do_unblock, (dlg, i)->toggleBlocked()) - .setNegativeButton(R.string.cancel, null) - .show(); + UiUtils.confirmToggleBlockUser(getActivity(), accountID, account, relationship.blocking, this::updateRelationship); } - private void toggleMuted(){ - new SetAccountMuted(account.id, !relationship.muting) - .setCallback(new Callback<>(){ - @Override - public void onSuccess(Relationship result){ - relationship=result; - updateRelationship(); - } - - @Override - public void onError(ErrorResponse error){ - error.showToast(getActivity()); - } - }) - .wrapProgress(getActivity(), R.string.loading, false) - .exec(accountID); - } - - private void toggleBlocked(){ - new SetAccountBlocked(account.id, !relationship.blocking) - .setCallback(new Callback<>(){ - @Override - public void onSuccess(Relationship result){ - relationship=result; - updateRelationship(); - } - - @Override - public void onError(ErrorResponse error){ - error.showToast(getActivity()); - } - }) - .wrapProgress(getActivity(), R.string.loading, false) - .exec(accountID); + private void updateRelationship(Relationship r){ + relationship=r; + updateRelationship(); } @Override diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/SearchFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/SearchFragment.java index 6137a86c..4dccbe49 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/SearchFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/SearchFragment.java @@ -1,6 +1,10 @@ package org.joinmastodon.android.fragments; +import com.squareup.otto.Subscribe; + import org.joinmastodon.android.api.requests.trends.GetTrendingStatuses; +import org.joinmastodon.android.events.StatusCountersUpdatedEvent; +import org.joinmastodon.android.events.StatusDeletedEvent; import org.joinmastodon.android.model.Status; import java.util.List; @@ -18,4 +22,16 @@ public class SearchFragment extends StatusListFragment{ } }).exec(accountID); } + + @Override + @Subscribe + public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){ + super.onStatusCountersUpdated(ev); + } + + @Override + @Subscribe + public void onStatusDeleted(StatusDeletedEvent ev){ + super.onStatusDeleted(ev); + } } 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 b8d3209c..b4c802a7 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java +++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java @@ -1,14 +1,17 @@ package org.joinmastodon.android.fragments; import android.os.Bundle; +import android.util.Log; import com.squareup.otto.Subscribe; import org.joinmastodon.android.E; import org.joinmastodon.android.events.StatusCountersUpdatedEvent; +import org.joinmastodon.android.events.StatusDeletedEvent; import org.joinmastodon.android.model.Poll; import org.joinmastodon.android.model.Status; import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem; +import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.StatusDisplayItem; @@ -87,10 +90,43 @@ public abstract class StatusListFragment extends BaseStatusListFragment{ } } + @Subscribe + public void onStatusDeleted(StatusDeletedEvent ev){ + Log.i("11", "on status deleted!"); + if(!ev.accountID.equals(accountID)) + return; + Status status=getStatusByID(ev.id); + if(status==null) + return; + data.remove(status); + preloadedData.remove(status); + HeaderStatusDisplayItem item=findItemOfType(ev.id, HeaderStatusDisplayItem.class); + if(item==null) + return; + int index=displayItems.indexOf(item); + int lastIndex; + for(lastIndex=index;lastIndex{ + int id=menuItem.getItemId(); + if(id==R.id.delete){ + UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{}); + }else if(id==R.id.mute){ + UiUtils.confirmToggleMuteUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, false, r->{}); + }else if(id==R.id.block){ + UiUtils.confirmToggleBlockUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, false, r->{}); + }else if(id==R.id.report){ + } + return true; + }); + popup.show(); } } } diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java index 6d7bc654..0173d089 100644 --- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java +++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java @@ -17,22 +17,35 @@ import android.util.Log; import android.view.View; import android.widget.TextView; +import org.joinmastodon.android.E; import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.R; +import org.joinmastodon.android.api.requests.accounts.SetAccountBlocked; +import org.joinmastodon.android.api.requests.accounts.SetAccountMuted; +import org.joinmastodon.android.api.requests.statuses.DeleteStatus; +import org.joinmastodon.android.events.StatusDeletedEvent; import org.joinmastodon.android.fragments.ProfileFragment; +import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Emoji; +import org.joinmastodon.android.model.Relationship; +import org.joinmastodon.android.model.Status; +import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.text.CustomEmojiSpan; import java.time.Instant; import java.util.Arrays; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import java.util.stream.Collectors; import androidx.annotation.AttrRes; import androidx.annotation.ColorRes; +import androidx.annotation.StringRes; import androidx.browser.customtabs.CustomTabsIntent; import me.grishka.appkit.Nav; +import me.grishka.appkit.api.Callback; +import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.imageloader.ViewImageLoader; import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; import me.grishka.appkit.utils.V; @@ -172,4 +185,79 @@ public class UiUtils{ args.putString("profileAccountID", id); Nav.go((Activity)context, ProfileFragment.class, args); } + + public static void showConfirmationAlert(Context context, @StringRes int title, @StringRes int message, @StringRes int confirmButton, Runnable onConfirmed){ + showConfirmationAlert(context, context.getString(title), context.getString(message), context.getString(confirmButton), onConfirmed); + } + + public static void showConfirmationAlert(Context context, CharSequence title, CharSequence message, CharSequence confirmButton, Runnable onConfirmed){ + new M3AlertDialogBuilder(context) + .setTitle(title) + .setMessage(message) + .setPositiveButton(confirmButton, (dlg, i)->onConfirmed.run()) + .setNegativeButton(R.string.cancel, null) + .show(); + } + + public static void confirmToggleBlockUser(Activity activity, String accountID, Account account, boolean currentlyBlocked, Consumer resultCallback){ + showConfirmationAlert(activity, activity.getString(currentlyBlocked ? R.string.confirm_unblock_title : R.string.confirm_block_title), + activity.getString(currentlyBlocked ? R.string.confirm_unblock : R.string.confirm_block, account.displayName), + activity.getString(currentlyBlocked ? R.string.do_block : R.string.do_unblock), ()->{ + new SetAccountBlocked(account.id, !currentlyBlocked) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(Relationship result){ + resultCallback.accept(result); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(activity); + } + }) + .wrapProgress(activity, R.string.loading, false) + .exec(accountID); + }); + } + + public static void confirmToggleMuteUser(Activity activity, String accountID, Account account, boolean currentlyMuted, Consumer resultCallback){ + showConfirmationAlert(activity, activity.getString(currentlyMuted ? R.string.confirm_unmute_title : R.string.confirm_mute_title), + activity.getString(currentlyMuted ? R.string.confirm_unmute : R.string.confirm_mute, account.displayName), + activity.getString(currentlyMuted ? R.string.do_unmute : R.string.do_mute), ()->{ + new SetAccountMuted(account.id, !currentlyMuted) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(Relationship result){ + resultCallback.accept(result); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(activity); + } + }) + .wrapProgress(activity, R.string.loading, false) + .exec(accountID); + }); + } + + public static void confirmDeletePost(Activity activity, String accountID, Status status, Consumer resultCallback){ + showConfirmationAlert(activity, R.string.confirm_delete_title, R.string.confirm_delete, R.string.delete, ()->{ + new DeleteStatus(status.id) + .setCallback(new Callback<>(){ + @Override + public void onSuccess(Status result){ + resultCallback.accept(result); + E.post(new StatusDeletedEvent(status.id, accountID)); + } + + @Override + public void onError(ErrorResponse error){ + error.showToast(activity); + } + }) + .wrapProgress(activity, R.string.deleting, false) + .exec(accountID); + }); + } } diff --git a/mastodon/src/main/res/menu/post.xml b/mastodon/src/main/res/menu/post.xml new file mode 100644 index 00000000..1efd2ebc --- /dev/null +++ b/mastodon/src/main/res/menu/post.xml @@ -0,0 +1,7 @@ + + + + + + + \ 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 5d1d7f3b..d8670fe2 100644 --- a/mastodon/src/main/res/values/strings.xml +++ b/mastodon/src/main/res/values/strings.xml @@ -124,4 +124,8 @@ Blocked Vote Tap to reveal + Delete + Delete Post + Are you sure you want to delete this post? + Deleting… \ No newline at end of file