mirror of
https://github.com/mastodon/mastodon-android.git
synced 2024-12-22 22:48:18 +01:00
Post actions
This commit is contained in:
parent
371faf9bb2
commit
bb463aa10a
@ -10,7 +10,7 @@ android {
|
||||
applicationId "org.joinmastodon.android"
|
||||
minSdk 23
|
||||
targetSdk 31
|
||||
versionCode 1
|
||||
versionCode 2
|
||||
versionName "0.1"
|
||||
}
|
||||
|
||||
|
@ -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<Status>{
|
||||
public DeleteStatus(String id){
|
||||
super(HttpMethod.DELETE, "/statuses/"+id, Status.class);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -260,6 +260,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> 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<T extends DisplayItemsParent> exten
|
||||
}
|
||||
}
|
||||
|
||||
public String getAccountID(){
|
||||
return accountID;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected <I extends StatusDisplayItem> I findItemOfType(String id, Class<I> type){
|
||||
for(StatusDisplayItem item:displayItems){
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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<Status>{
|
||||
}
|
||||
}
|
||||
|
||||
@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<displayItems.size();lastIndex++){
|
||||
if(!displayItems.get(lastIndex).parentID.equals(ev.id))
|
||||
break;
|
||||
}
|
||||
displayItems.subList(index, lastIndex).clear();
|
||||
adapter.notifyItemRangeRemoved(index, lastIndex-index);
|
||||
}
|
||||
|
||||
protected Status getContentStatusByID(String id){
|
||||
Status s=getStatusByID(id);
|
||||
return s==null ? null : s.getContentStatus();
|
||||
}
|
||||
|
||||
protected Status getStatusByID(String id){
|
||||
for(Status s:data){
|
||||
if(s.id.equals(id)){
|
||||
return s.getContentStatus();
|
||||
return s;
|
||||
}
|
||||
}
|
||||
for(Status s:preloadedData){
|
||||
if(s.id.equals(id)){
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -5,8 +5,12 @@ import android.os.Bundle;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.view.View;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
|
||||
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
|
||||
import org.joinmastodon.android.events.StatusDeletedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.StatusContext;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@ -81,4 +85,16 @@ public class ThreadFragment extends StatusListFragment{
|
||||
if(!loaded)
|
||||
footerProgress.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Subscribe
|
||||
public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){
|
||||
super.onStatusCountersUpdated(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Subscribe
|
||||
public void onStatusDeleted(StatusDeletedEvent ev){
|
||||
super.onStatusDeleted(ev);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
|
||||
public Instant createdAt;
|
||||
@RequiredField
|
||||
public Account account;
|
||||
@RequiredField
|
||||
// @RequiredField
|
||||
public String content;
|
||||
@RequiredField
|
||||
public StatusPrivacy visibility;
|
||||
|
@ -8,13 +8,16 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
@ -143,7 +146,29 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
}
|
||||
|
||||
private void onMoreClick(View v){
|
||||
Account account=item.status.account;
|
||||
PopupMenu popup=new PopupMenu(v.getContext(), v);
|
||||
Menu menu=popup.getMenu();
|
||||
popup.getMenuInflater().inflate(R.menu.post, menu);
|
||||
if(!AccountSessionManager.getInstance().isSelf(item.parentFragment.getAccountID(), account))
|
||||
menu.findItem(R.id.delete).setVisible(false);
|
||||
menu.findItem(R.id.mute).setTitle(v.getResources().getString(/*relationship.muting ? R.string.unmute_user :*/ R.string.mute_user, account.displayName));
|
||||
menu.findItem(R.id.block).setTitle(v.getResources().getString(/*relationship.blocking ? R.string.unblock_user :*/ R.string.block_user, account.displayName));
|
||||
menu.findItem(R.id.report).setTitle(v.getResources().getString(R.string.report_user, account.displayName));
|
||||
popup.setOnMenuItemClickListener(menuItem->{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Relationship> 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<Relationship> 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<Status> 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
7
mastodon/src/main/res/menu/post.xml
Normal file
7
mastodon/src/main/res/menu/post.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/delete" android:title="@string/delete"/>
|
||||
<item android:id="@+id/mute" android:title="@string/mute_user"/>
|
||||
<item android:id="@+id/block" android:title="@string/block_user"/>
|
||||
<item android:id="@+id/report" android:title="@string/report_user"/>
|
||||
</menu>
|
@ -124,4 +124,8 @@
|
||||
<string name="button_blocked">Blocked</string>
|
||||
<string name="action_vote">Vote</string>
|
||||
<string name="tap_to_reveal">Tap to reveal</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="confirm_delete_title">Delete Post</string>
|
||||
<string name="confirm_delete">Are you sure you want to delete this post?</string>
|
||||
<string name="deleting">Deleting…</string>
|
||||
</resources>
|
Loading…
Reference in New Issue
Block a user