Reporting
This commit is contained in:
@@ -22,12 +22,17 @@ public class GetAccountStatuses extends MastodonAPIRequest<List<Status>>{
|
||||
case DEFAULT -> addQueryParameter("exclude_replies", "true");
|
||||
case INCLUDE_REPLIES -> {}
|
||||
case MEDIA -> addQueryParameter("only_media", "true");
|
||||
case NO_REBLOGS -> {
|
||||
addQueryParameter("exclude_replies", "true");
|
||||
addQueryParameter("exclude_reblogs", "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Filter{
|
||||
DEFAULT,
|
||||
INCLUDE_REPLIES,
|
||||
MEDIA
|
||||
MEDIA,
|
||||
NO_REBLOGS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package org.joinmastodon.android.api.requests.reports;
|
||||
|
||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||
import org.joinmastodon.android.model.ReportReason;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class SendReport extends MastodonAPIRequest<Object>{
|
||||
public SendReport(String accountID, ReportReason reason, List<String> statusIDs, List<String> ruleIDs, String comment, boolean forward){
|
||||
super(HttpMethod.POST, "/reports", Object.class);
|
||||
Body b=new Body();
|
||||
b.accountId=accountID;
|
||||
b.statusIds=statusIDs;
|
||||
b.comment=comment;
|
||||
b.forward=forward;
|
||||
b.category=reason;
|
||||
b.ruleIds=ruleIDs;
|
||||
setRequestBody(b);
|
||||
}
|
||||
|
||||
private static class Body{
|
||||
public String accountId;
|
||||
public List<String> statusIds;
|
||||
public String comment;
|
||||
public boolean forward;
|
||||
public ReportReason category;
|
||||
public List<String> ruleIds;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ 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.Instance;
|
||||
import org.joinmastodon.android.model.Token;
|
||||
|
||||
public class AccountSession{
|
||||
@@ -13,16 +14,19 @@ public class AccountSession{
|
||||
public int tootCharLimit;
|
||||
public Application app;
|
||||
public long infoLastUpdated;
|
||||
public long instanceLastUpdated;
|
||||
public Instance instance;
|
||||
private transient MastodonAPIController apiController;
|
||||
private transient StatusInteractionController statusInteractionController;
|
||||
|
||||
AccountSession(Token token, Account self, Application app, String domain, int tootCharLimit){
|
||||
AccountSession(Token token, Account self, Application app, String domain, int tootCharLimit, Instance instance){
|
||||
this.token=token;
|
||||
this.self=self;
|
||||
this.domain=domain;
|
||||
this.app=app;
|
||||
this.tootCharLimit=tootCharLimit;
|
||||
infoLastUpdated=System.currentTimeMillis();
|
||||
this.instance=instance;
|
||||
instanceLastUpdated=infoLastUpdated=System.currentTimeMillis();
|
||||
}
|
||||
|
||||
AccountSession(){}
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Application;
|
||||
@@ -84,7 +85,7 @@ public class AccountSessionManager{
|
||||
}
|
||||
|
||||
public void addAccount(Instance instance, Token token, Account self, Application app){
|
||||
AccountSession session=new AccountSession(token, self, app, instance.uri, instance.maxTootChars);
|
||||
AccountSession session=new AccountSession(token, self, app, instance.uri, instance.maxTootChars, instance);
|
||||
sessions.put(session.getID(), session);
|
||||
lastActiveAccountID=session.getID();
|
||||
writeAccountsFile();
|
||||
@@ -212,7 +213,7 @@ public class AccountSessionManager{
|
||||
HashSet<String> domains=new HashSet<>();
|
||||
for(AccountSession session:sessions.values()){
|
||||
domains.add(session.domain.toLowerCase());
|
||||
if(now-session.infoLastUpdated>24L*3600_000L){
|
||||
if(now-session.infoLastUpdated>24L*3600_000L || now-session.instanceLastUpdated>24L*360_000L*3L){
|
||||
updateSessionLocalInfo(session);
|
||||
}
|
||||
}
|
||||
@@ -247,6 +248,21 @@ public class AccountSessionManager{
|
||||
}
|
||||
})
|
||||
.exec(session.getID());
|
||||
new GetInstance()
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Instance result){
|
||||
session.instance=result;
|
||||
session.instanceLastUpdated=System.currentTimeMillis();
|
||||
writeAccountsFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
|
||||
}
|
||||
})
|
||||
.exec(session.getID());
|
||||
}
|
||||
|
||||
private void updateCustomEmojis(String domain){
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.joinmastodon.android.events;
|
||||
|
||||
public class FinishReportFragmentsEvent{
|
||||
public final String reportAccountID;
|
||||
|
||||
public FinishReportFragmentsEvent(String reportAccountID){
|
||||
this.reportAccountID=reportAccountID;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public abstract class BaseReportChoiceFragment extends ToolbarFragment{
|
||||
private UsableRecyclerView list;
|
||||
private MergeRecyclerAdapter adapter;
|
||||
private Button btn;
|
||||
private View buttonBar;
|
||||
protected ArrayList<Item> items=new ArrayList<>();
|
||||
protected boolean isMultipleChoice;
|
||||
protected ArrayList<String> selectedIDs=new ArrayList<>();
|
||||
protected String accountID;
|
||||
protected Account reportAccount;
|
||||
protected Status reportStatus;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
E.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(){
|
||||
E.unregister(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
setNavigationBarColor(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground));
|
||||
accountID=getArguments().getString("account");
|
||||
reportAccount=Parcels.unwrap(getArguments().getParcelable("reportAccount"));
|
||||
reportStatus=Parcels.unwrap(getArguments().getParcelable("status"));
|
||||
setTitle(getString(R.string.report_title, reportAccount.acct));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||
View view=inflater.inflate(R.layout.fragment_report_choice, container, false);
|
||||
|
||||
list=view.findViewById(R.id.list);
|
||||
list.setLayoutManager(new LinearLayoutManager(getActivity()));
|
||||
populateItems();
|
||||
Item header=getHeaderItem();
|
||||
View headerView=inflater.inflate(R.layout.item_list_header, list, false);
|
||||
TextView title=headerView.findViewById(R.id.title);
|
||||
TextView subtitle=headerView.findViewById(R.id.subtitle);
|
||||
title.setText(header.title);
|
||||
subtitle.setText(header.subtitle);
|
||||
|
||||
adapter=new MergeRecyclerAdapter();
|
||||
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||
adapter.addAdapter(new ItemsAdapter());
|
||||
list.setAdapter(adapter);
|
||||
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 16, 16, DividerItemDecoration.NOT_FIRST));
|
||||
|
||||
btn=view.findViewById(R.id.btn_next);
|
||||
btn.setEnabled(!selectedIDs.isEmpty());
|
||||
btn.setOnClickListener(v->onButtonClick());
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
protected abstract Item getHeaderItem();
|
||||
protected abstract void populateItems();
|
||||
protected abstract void onButtonClick();
|
||||
|
||||
@Override
|
||||
public void onApplyWindowInsets(WindowInsets insets){
|
||||
if(Build.VERSION.SDK_INT>=27){
|
||||
int inset=insets.getSystemWindowInsetBottom();
|
||||
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
|
||||
}else{
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||
}
|
||||
}
|
||||
|
||||
protected static class Item{
|
||||
public String title, subtitle, id;
|
||||
|
||||
public Item(String title, String subtitle, String id){
|
||||
this.title=title;
|
||||
this.subtitle=subtitle;
|
||||
this.id=id;
|
||||
}
|
||||
}
|
||||
|
||||
private class ItemsAdapter extends RecyclerView.Adapter<ItemViewHolder>{
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return new ItemViewHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ItemViewHolder holder, int position){
|
||||
holder.bind(items.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount(){
|
||||
return items.size();
|
||||
}
|
||||
}
|
||||
|
||||
private class ItemViewHolder extends BindableViewHolder<Item> implements UsableRecyclerView.Clickable{
|
||||
private final TextView title, subtitle;
|
||||
private final ImageView checkbox;
|
||||
|
||||
public ItemViewHolder(){
|
||||
super(getActivity(), R.layout.item_report_choice, list);
|
||||
title=findViewById(R.id.title);
|
||||
subtitle=findViewById(R.id.subtitle);
|
||||
checkbox=findViewById(R.id.checkbox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBind(Item item){
|
||||
title.setText(item.title);
|
||||
if(TextUtils.isEmpty(item.subtitle)){
|
||||
subtitle.setVisibility(View.GONE);
|
||||
}else{
|
||||
subtitle.setVisibility(View.VISIBLE);
|
||||
subtitle.setText(item.subtitle);
|
||||
}
|
||||
checkbox.setSelected(selectedIDs.contains(item.id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(){
|
||||
if(isMultipleChoice){
|
||||
if(selectedIDs.contains(item.id))
|
||||
selectedIDs.remove(item.id);
|
||||
else
|
||||
selectedIDs.add(item.id);
|
||||
rebind();
|
||||
}else{
|
||||
if(!selectedIDs.contains(item.id)){
|
||||
if(!selectedIDs.isEmpty()){
|
||||
String prev=selectedIDs.remove(0);
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
|
||||
if(holder instanceof ItemViewHolder && ((ItemViewHolder) holder).getItem().id.equals(prev)){
|
||||
((ItemViewHolder) holder).rebind();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
selectedIDs.add(item.id);
|
||||
rebind();
|
||||
}
|
||||
}
|
||||
btn.setEnabled(!selectedIDs.isEmpty());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
protected PhotoViewer currentPhotoViewer;
|
||||
protected HashMap<String, Account> knownAccounts=new HashMap<>();
|
||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||
protected Rect tmpRect=new Rect();
|
||||
|
||||
public BaseStatusListFragment(){
|
||||
super(20);
|
||||
@@ -259,7 +260,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
}
|
||||
});
|
||||
list.addItemDecoration(new RecyclerView.ItemDecoration(){
|
||||
private Rect tmpRect=new Rect();
|
||||
private Paint paint=new Paint();
|
||||
{
|
||||
paint.setColor(UiUtils.getThemeColor(getActivity(), R.attr.colorPollVoted));
|
||||
@@ -276,11 +276,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
RecyclerView.ViewHolder siblingHolder=parent.getChildViewHolder(bottomSibling);
|
||||
if(holder instanceof StatusDisplayItem.Holder && siblingHolder instanceof StatusDisplayItem.Holder
|
||||
&& !((StatusDisplayItem.Holder<?>) holder).getItemID().equals(((StatusDisplayItem.Holder<?>) siblingHolder).getItemID())){
|
||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
||||
float y=tmpRect.bottom-V.dp(.5f);
|
||||
paint.setAlpha(Math.round(255*child.getAlpha()));
|
||||
c.drawLine(0, y, parent.getWidth(), y, paint);
|
||||
drawDivider(child, bottomSibling, holder, siblingHolder, parent, c, paint);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,6 +394,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void drawDivider(View child, View bottomSibling, RecyclerView.ViewHolder holder, RecyclerView.ViewHolder siblingHolder, RecyclerView parent, Canvas c, Paint paint){
|
||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
||||
float y=tmpRect.bottom-V.dp(.5f);
|
||||
paint.setAlpha(Math.round(255*child.getAlpha()));
|
||||
c.drawLine(0, y, parent.getWidth(), y, paint);
|
||||
}
|
||||
|
||||
public abstract void onItemClick(String id);
|
||||
|
||||
protected void updatePoll(String itemID, Poll poll){
|
||||
@@ -494,7 +498,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
status.spoilerRevealed=true;
|
||||
TextStatusDisplayItem.Holder text=findHolderOfType(itemID, TextStatusDisplayItem.Holder.class);
|
||||
if(text!=null)
|
||||
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition());
|
||||
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition()+getMainAdapterOffset());
|
||||
HeaderStatusDisplayItem.Holder header=findHolderOfType(itemID, HeaderStatusDisplayItem.Holder.class);
|
||||
if(header!=null)
|
||||
header.rebind();
|
||||
@@ -509,7 +513,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
if(!TextUtils.isEmpty(status.spoilerText)){
|
||||
TextStatusDisplayItem.Holder text=findHolderOfType(holder.getItemID(), TextStatusDisplayItem.Holder.class);
|
||||
if(text!=null){
|
||||
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition());
|
||||
adapter.notifyItemChanged(text.getAbsoluteAdapterPosition()+getMainAdapterOffset());
|
||||
}
|
||||
}
|
||||
holder.rebind();
|
||||
@@ -609,7 +613,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
@NonNull
|
||||
@Override
|
||||
public BindableViewHolder<StatusDisplayItem> onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
|
||||
return (BindableViewHolder<StatusDisplayItem>) StatusDisplayItem.createViewHolder(StatusDisplayItem.Type.values()[viewType], getActivity(), parent);
|
||||
return (BindableViewHolder<StatusDisplayItem>) StatusDisplayItem.createViewHolder(StatusDisplayItem.Type.values()[viewType & (~0x80000000)], getActivity(), parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -625,7 +629,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position){
|
||||
return displayItems.get(position).getType().ordinal();
|
||||
return displayItems.get(position).getType().ordinal() | 0x80000000;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -476,6 +476,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
confirmToggleMuted();
|
||||
}else if(id==R.id.block){
|
||||
confirmToggleBlocked();
|
||||
}else if(id==R.id.report){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("reportAccount", Parcels.wrap(account));
|
||||
Nav.go(getActivity(), ReportReasonChoiceFragment.class, args);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.ImageStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
||||
|
||||
private Button btn;
|
||||
private View buttonBar;
|
||||
private ArrayList<String> selectedIDs=new ArrayList<>();
|
||||
private String accountID;
|
||||
private Account reportAccount;
|
||||
private Status reportStatus;
|
||||
private SparseIntArray knownDisplayItemHeights=new SparseIntArray();
|
||||
private HashSet<String> postsWithKnownNonHeaderHeights=new HashSet<>();
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
setListLayoutId(R.layout.fragment_content_report_posts);
|
||||
setLayout(R.layout.fragment_report_posts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
setNavigationBarColor(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground));
|
||||
accountID=getArguments().getString("account");
|
||||
reportAccount=Parcels.unwrap(getArguments().getParcelable("reportAccount"));
|
||||
reportStatus=Parcels.unwrap(getArguments().getParcelable("status"));
|
||||
if(reportStatus!=null)
|
||||
selectedIDs.add(reportStatus.id);
|
||||
setTitle(getString(R.string.report_title, reportAccount.acct));
|
||||
loadData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
currentRequest=new GetAccountStatuses(reportAccount.id, offset>0 ? getMaxID() : null, null, count, GetAccountStatuses.Filter.NO_REBLOGS)
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(String id){
|
||||
if(selectedIDs.contains(id))
|
||||
selectedIDs.remove(id);
|
||||
else
|
||||
selectedIDs.add(id);
|
||||
list.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
btn=view.findViewById(R.id.btn_next);
|
||||
btn.setEnabled(!selectedIDs.isEmpty());
|
||||
btn.setOnClickListener(this::onButtonClick);
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
|
||||
list.addItemDecoration(new RecyclerView.ItemDecoration(){
|
||||
private Drawable uncheckedIcon=getResources().getDrawable(R.drawable.ic_fluent_radio_button_24_regular, getActivity().getTheme()).mutate();
|
||||
private Drawable checkedIcon=getResources().getDrawable(R.drawable.ic_fluent_checkmark_circle_24_filled, getActivity().getTheme()).mutate();
|
||||
{
|
||||
int color=UiUtils.getThemeColor(getActivity(), android.R.attr.textColorSecondary);
|
||||
checkedIcon.setTint(color);
|
||||
uncheckedIcon.setTint(color);
|
||||
checkedIcon.setBounds(0, 0, checkedIcon.getIntrinsicWidth(), checkedIcon.getIntrinsicHeight());
|
||||
uncheckedIcon.setBounds(0, 0, uncheckedIcon.getIntrinsicWidth(), uncheckedIcon.getIntrinsicHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
|
||||
if(holder.getAbsoluteAdapterPosition()==0)
|
||||
return;
|
||||
outRect.left=V.dp(40);
|
||||
if(holder instanceof ImageStatusDisplayItem.Holder){
|
||||
ImageStatusDisplayItem.Holder<ImageStatusDisplayItem> imgHolder=(ImageStatusDisplayItem.Holder<ImageStatusDisplayItem>) holder;
|
||||
String siblingID;
|
||||
if(holder.getAbsoluteAdapterPosition()<parent.getAdapter().getItemCount()-1){
|
||||
siblingID=displayItems.get(holder.getAbsoluteAdapterPosition()-getMainAdapterOffset()+1).parentID;
|
||||
}else{
|
||||
siblingID=null;
|
||||
}
|
||||
outRect.left+=V.dp(16);
|
||||
outRect.right=V.dp(16);
|
||||
if(!imgHolder.getItemID().equals(siblingID) || imgHolder.getItem().thisTile.startRow+imgHolder.getItem().thisTile.rowSpan==imgHolder.getItem().tiledLayout.rowSizes.length)
|
||||
outRect.bottom=V.dp(16);
|
||||
}else if(holder instanceof AudioStatusDisplayItem.Holder){
|
||||
outRect.bottom=V.dp(16);
|
||||
}else if(holder instanceof LinkCardStatusDisplayItem.Holder){
|
||||
outRect.bottom=V.dp(16);
|
||||
outRect.left+=V.dp(16);
|
||||
outRect.right=V.dp(16);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
|
||||
// 1st pass: update item heights
|
||||
for(int i=0;i<parent.getChildCount();i++){
|
||||
View child=parent.getChildAt(i);
|
||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||
if(holder instanceof StatusDisplayItem.Holder){
|
||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||
String id=((StatusDisplayItem.Holder<?>) holder).getItemID();
|
||||
int height=tmpRect.height();
|
||||
if(holder instanceof ImageStatusDisplayItem.Holder){
|
||||
ImageStatusDisplayItem.Holder<ImageStatusDisplayItem> imgHolder=(ImageStatusDisplayItem.Holder<ImageStatusDisplayItem>) holder;
|
||||
if(imgHolder.getItem().thisTile.startCol+imgHolder.getItem().thisTile.colSpan<imgHolder.getItem().tiledLayout.columnSizes.length)
|
||||
height=0;
|
||||
}
|
||||
if(!(holder instanceof HeaderStatusDisplayItem.Holder) && !(holder instanceof ReblogOrReplyLineStatusDisplayItem.Holder))
|
||||
postsWithKnownNonHeaderHeights.add(id);
|
||||
knownDisplayItemHeights.put(holder.getAbsoluteAdapterPosition(), height);
|
||||
}
|
||||
}
|
||||
// 2nd pass: draw checkboxes
|
||||
String lastPostID=null;
|
||||
for(int i=0;i<parent.getChildCount();i++){
|
||||
View child=parent.getChildAt(i);
|
||||
RecyclerView.ViewHolder holder=parent.getChildViewHolder(child);
|
||||
if(holder instanceof StatusDisplayItem.Holder){
|
||||
String postID=((StatusDisplayItem.Holder<?>) holder).getItemID();
|
||||
if(!postID.equals(lastPostID)){
|
||||
lastPostID=postID;
|
||||
if(!postsWithKnownNonHeaderHeights.contains(postID))
|
||||
continue; // We don't know full height of this post yet
|
||||
int postHeight=0;
|
||||
int heightOffset=0;
|
||||
for(int j=holder.getAbsoluteAdapterPosition()-getMainAdapterOffset();j<displayItems.size();j++){
|
||||
StatusDisplayItem item=displayItems.get(j);
|
||||
if(!item.parentID.equals(postID))
|
||||
break;
|
||||
postHeight+=knownDisplayItemHeights.get(j+getMainAdapterOffset());
|
||||
}
|
||||
for(int j=holder.getAbsoluteAdapterPosition()-getMainAdapterOffset()-1;j>=0;j--){
|
||||
StatusDisplayItem item=displayItems.get(j);
|
||||
if(!item.parentID.equals(postID))
|
||||
break;
|
||||
int itemHeight=knownDisplayItemHeights.get(j+getMainAdapterOffset());
|
||||
postHeight+=itemHeight;
|
||||
heightOffset+=itemHeight;
|
||||
}
|
||||
int y=Math.round(child.getY())+postHeight/2-heightOffset;
|
||||
Drawable check=selectedIDs.contains(postID) ? checkedIcon : uncheckedIcon;
|
||||
c.save();
|
||||
c.translate(V.dp(16), y-check.getIntrinsicHeight()/2f);
|
||||
check.draw(c);
|
||||
c.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMainAdapterOffset(){
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecyclerView.Adapter getAdapter(){
|
||||
View headerView=getActivity().getLayoutInflater().inflate(R.layout.item_list_header, list, false);
|
||||
TextView title=headerView.findViewById(R.id.title);
|
||||
TextView subtitle=headerView.findViewById(R.id.subtitle);
|
||||
title.setText(R.string.report_choose_posts);
|
||||
subtitle.setText(R.string.report_choose_posts_subtitle);
|
||||
|
||||
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
|
||||
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
|
||||
adapter.addAdapter(super.getAdapter());
|
||||
return adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<StatusDisplayItem> buildDisplayItems(Status s){
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false);
|
||||
}
|
||||
|
||||
protected void drawDivider(View child, View bottomSibling, RecyclerView.ViewHolder holder, RecyclerView.ViewHolder siblingHolder, RecyclerView parent, Canvas c, Paint paint){
|
||||
parent.getDecoratedBoundsWithMargins(child, tmpRect);
|
||||
tmpRect.offset(0, Math.round(child.getTranslationY()));
|
||||
float y=tmpRect.bottom-V.dp(.5f);
|
||||
paint.setAlpha(Math.round(255*child.getAlpha()));
|
||||
c.drawLine(V.dp(16), y, parent.getWidth()-V.dp(16), y, paint);
|
||||
}
|
||||
|
||||
private void onButtonClick(View v){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
|
||||
args.putStringArrayList("statusIDs", selectedIDs);
|
||||
args.putStringArrayList("ruleIDs", getArguments().getStringArrayList("ruleIDs"));
|
||||
args.putString("reason", getArguments().getString("reason"));
|
||||
Nav.go(getActivity(), ReportCommentFragment.class, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyWindowInsets(WindowInsets insets){
|
||||
if(Build.VERSION.SDK_INT>=27){
|
||||
int inset=insets.getSystemWindowInsetBottom();
|
||||
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
|
||||
}else{
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
|
||||
if(ev.reportAccountID.equals(reportAccount.id))
|
||||
Nav.finish(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.reports.SendReport;
|
||||
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.ReportReason;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class ReportCommentFragment extends ToolbarFragment{
|
||||
private String accountID;
|
||||
private Account reportAccount;
|
||||
private Button btn;
|
||||
private View buttonBar;
|
||||
private EditText commentEdit;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
E.register(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy(){
|
||||
E.unregister(this);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
setNavigationBarColor(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground));
|
||||
accountID=getArguments().getString("account");
|
||||
reportAccount=Parcels.unwrap(getArguments().getParcelable("reportAccount"));
|
||||
setTitle(getString(R.string.report_title, reportAccount.acct));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||
View view=inflater.inflate(R.layout.fragment_report_comment, container, false);
|
||||
|
||||
TextView title=view.findViewById(R.id.title);
|
||||
TextView subtitle=view.findViewById(R.id.subtitle);
|
||||
title.setText(R.string.report_comment_title);
|
||||
subtitle.setText(R.string.report_comment_subtitle);
|
||||
|
||||
btn=view.findViewById(R.id.btn_next);
|
||||
btn.setOnClickListener(this::onButtonClick);
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
commentEdit=view.findViewById(R.id.text);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), android.R.attr.colorBackground));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyWindowInsets(WindowInsets insets){
|
||||
if(Build.VERSION.SDK_INT>=27){
|
||||
int inset=insets.getSystemWindowInsetBottom();
|
||||
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
|
||||
}else{
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||
}
|
||||
}
|
||||
|
||||
private void onButtonClick(View v){
|
||||
ReportReason reason=ReportReason.valueOf(getArguments().getString("reason"));
|
||||
ArrayList<String> statusIDs=getArguments().getStringArrayList("statusIDs");
|
||||
ArrayList<String> ruleIDs=getArguments().getStringArrayList("ruleIDs");
|
||||
new SendReport(reportAccount.id, reason, statusIDs, ruleIDs, commentEdit.getText().toString(), false)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Object result){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
|
||||
args.putString("reason", reason.name());
|
||||
Nav.go(getActivity(), ReportDoneFragment.class, args);
|
||||
buttonBar.postDelayed(()->E.post(new FinishReportFragmentsEvent(reportAccount.id)), 500);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
error.showToast(getActivity());
|
||||
}
|
||||
})
|
||||
.wrapProgress(getActivity(), R.string.sending_report, false)
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
|
||||
if(ev.reportAccountID.equals(reportAccount.id))
|
||||
Nav.finish(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||
import org.joinmastodon.android.api.requests.reports.SendReport;
|
||||
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
import org.joinmastodon.android.model.ReportReason;
|
||||
import org.joinmastodon.android.ui.OutlineProviders;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.ToolbarFragment;
|
||||
import me.grishka.appkit.imageloader.ViewImageLoader;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class ReportDoneFragment extends ToolbarFragment{
|
||||
private String accountID;
|
||||
private Account reportAccount;
|
||||
private Button btn;
|
||||
private View buttonBar;
|
||||
private ReportReason reason;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
setNavigationBarColor(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground));
|
||||
accountID=getArguments().getString("account");
|
||||
reportAccount=Parcels.unwrap(getArguments().getParcelable("reportAccount"));
|
||||
reason=ReportReason.valueOf(getArguments().getString("reason"));
|
||||
setTitle(getString(R.string.report_title, reportAccount.acct));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||
View view=inflater.inflate(R.layout.fragment_report_done, container, false);
|
||||
|
||||
TextView title=view.findViewById(R.id.title);
|
||||
TextView subtitle=view.findViewById(R.id.subtitle);
|
||||
if(reason==ReportReason.PERSONAL){
|
||||
title.setText(R.string.report_personal_title);
|
||||
subtitle.setText(R.string.report_personal_subtitle);
|
||||
}else{
|
||||
title.setText(R.string.report_sent_title);
|
||||
subtitle.setText(getString(R.string.report_sent_subtitle, '@'+reportAccount.acct));
|
||||
}
|
||||
|
||||
btn=view.findViewById(R.id.btn_next);
|
||||
btn.setOnClickListener(this::onButtonClick);
|
||||
buttonBar=view.findViewById(R.id.button_bar);
|
||||
btn.setText(R.string.done);
|
||||
|
||||
if(reason!=ReportReason.PERSONAL){
|
||||
View doneOverlay=view.findViewById(R.id.reported_overlay);
|
||||
doneOverlay.setOutlineProvider(OutlineProviders.roundedRect(7));
|
||||
ImageView ava=view.findViewById(R.id.avatar);
|
||||
ava.setOutlineProvider(OutlineProviders.roundedRect(24));
|
||||
ava.setClipToOutline(true);
|
||||
ViewImageLoader.load(ava, null, new UrlImageLoaderRequest(reportAccount.avatar));
|
||||
doneOverlay.setScaleX(1.5f);
|
||||
doneOverlay.setScaleY(1.5f);
|
||||
doneOverlay.setAlpha(0f);
|
||||
doneOverlay.animate().scaleX(1f).scaleY(1f).alpha(1f).rotation(8.79f).setDuration(300).setStartDelay(300).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||
}else{
|
||||
view.findViewById(R.id.ava_reported).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
TextView unfollowTitle=view.findViewById(R.id.unfollow_title);
|
||||
TextView muteTitle=view.findViewById(R.id.mute_title);
|
||||
TextView blockTitle=view.findViewById(R.id.block_title);
|
||||
|
||||
unfollowTitle.setText(getString(R.string.unfollow_user, '@'+reportAccount.acct));
|
||||
muteTitle.setText(getString(R.string.mute_user, '@'+reportAccount.acct));
|
||||
blockTitle.setText(getString(R.string.block_user, '@'+reportAccount.acct));
|
||||
|
||||
view.findViewById(R.id.unfollow_btn).setOnClickListener(v->onUnfollowClick());
|
||||
view.findViewById(R.id.mute_btn).setOnClickListener(v->onMuteClick());
|
||||
view.findViewById(R.id.block_btn).setOnClickListener(v->onBlockClick());
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState){
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), android.R.attr.colorBackground));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplyWindowInsets(WindowInsets insets){
|
||||
if(Build.VERSION.SDK_INT>=27){
|
||||
int inset=insets.getSystemWindowInsetBottom();
|
||||
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
|
||||
}else{
|
||||
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
|
||||
}
|
||||
}
|
||||
|
||||
private void onButtonClick(View v){
|
||||
Nav.finish(this);
|
||||
}
|
||||
|
||||
private void onUnfollowClick(){
|
||||
new SetAccountFollowed(reportAccount.id, false)
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(Relationship result){
|
||||
Nav.finish(ReportDoneFragment.this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
error.showToast(getActivity());
|
||||
}
|
||||
})
|
||||
.wrapProgress(getActivity(), R.string.loading, false)
|
||||
.exec(accountID);
|
||||
}
|
||||
|
||||
private void onMuteClick(){
|
||||
UiUtils.confirmToggleMuteUser(getActivity(), accountID, reportAccount, false, rel->Nav.finish(this));
|
||||
}
|
||||
|
||||
private void onBlockClick(){
|
||||
UiUtils.confirmToggleBlockUser(getActivity(), accountID, reportAccount, false, rel->Nav.finish(this));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
||||
import org.joinmastodon.android.model.ReportReason;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
|
||||
public class ReportReasonChoiceFragment extends BaseReportChoiceFragment{
|
||||
@Override
|
||||
protected Item getHeaderItem(){
|
||||
return new Item(getString(R.string.report_choose_reason), getString(R.string.report_choose_reason_subtitle), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populateItems(){
|
||||
items.add(new Item(getString(R.string.report_reason_personal), getString(R.string.report_reason_personal_subtitle), ReportReason.PERSONAL.name()));
|
||||
items.add(new Item(getString(R.string.report_reason_spam), getString(R.string.report_reason_spam_subtitle), ReportReason.SPAM.name()));
|
||||
items.add(new Item(getString(R.string.report_reason_violation), getString(R.string.report_reason_violation_subtitle), ReportReason.VIOLATION.name()));
|
||||
items.add(new Item(getString(R.string.report_reason_other), getString(R.string.report_reason_other_subtitle), ReportReason.OTHER.name()));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onButtonClick(){
|
||||
ReportReason reason=ReportReason.valueOf(selectedIDs.get(0));
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("status", Parcels.wrap(reportStatus));
|
||||
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
|
||||
args.putString("reason", reason.name());
|
||||
switch(reason){
|
||||
case PERSONAL -> {
|
||||
Nav.go(getActivity(), ReportDoneFragment.class, args);
|
||||
content.postDelayed(()->Nav.finish(this), 500);
|
||||
}
|
||||
case SPAM, OTHER -> Nav.go(getActivity(), ReportAddPostsChoiceFragment.class, args);
|
||||
case VIOLATION -> Nav.go(getActivity(), ReportRuleChoiceFragment.class, args);
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
|
||||
if(ev.reportAccountID.equals(reportAccount.id))
|
||||
Nav.finish(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
|
||||
public class ReportRuleChoiceFragment extends BaseReportChoiceFragment{
|
||||
@Override
|
||||
protected Item getHeaderItem(){
|
||||
return new Item(getString(R.string.report_choose_rule), getString(R.string.report_choose_rule_subtitle), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void populateItems(){
|
||||
isMultipleChoice=true;
|
||||
Instance inst=AccountSessionManager.getInstance().getAccount(accountID).instance;
|
||||
if(inst!=null && inst.rules!=null){
|
||||
for(Instance.Rule rule:inst.rules){
|
||||
items.add(new Item(rule.text, null, rule.id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onButtonClick(){
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", accountID);
|
||||
args.putParcelable("status", Parcels.wrap(reportStatus));
|
||||
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
|
||||
args.putString("reason", getArguments().getString("reason"));
|
||||
args.putStringArrayList("ruleIDs", selectedIDs);
|
||||
Nav.go(getActivity(), ReportAddPostsChoiceFragment.class, args);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
|
||||
if(ev.reportAccountID.equals(reportAccount.id))
|
||||
Nav.finish(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.joinmastodon.android.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
public enum ReportReason{
|
||||
PERSONAL,
|
||||
@SerializedName("spam")
|
||||
SPAM,
|
||||
@SerializedName("violation")
|
||||
VIOLATION,
|
||||
@SerializedName("other")
|
||||
OTHER
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import android.view.View;
|
||||
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import androidx.annotation.AttrRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@@ -15,13 +17,21 @@ import me.grishka.appkit.utils.V;
|
||||
public class DividerItemDecoration extends RecyclerView.ItemDecoration{
|
||||
private Paint paint=new Paint();
|
||||
private int paddingStart, paddingEnd;
|
||||
private Predicate<RecyclerView.ViewHolder> drawDividerPredicate;
|
||||
|
||||
public static final Predicate<RecyclerView.ViewHolder> NOT_FIRST=vh->vh.getAbsoluteAdapterPosition()>0;
|
||||
|
||||
public DividerItemDecoration(Context context, @AttrRes int color, float thicknessDp, int paddingStartDp, int paddingEndDp){
|
||||
this(context, color, thicknessDp, paddingStartDp, paddingEndDp, null);
|
||||
}
|
||||
|
||||
public DividerItemDecoration(Context context, @AttrRes int color, float thicknessDp, int paddingStartDp, int paddingEndDp, Predicate<RecyclerView.ViewHolder> drawDividerPredicate){
|
||||
paint.setColor(UiUtils.getThemeColor(context, color));
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeWidth(V.dp(thicknessDp));
|
||||
paddingStart=V.dp(paddingStartDp);
|
||||
paddingEnd=V.dp(paddingEndDp);
|
||||
this.drawDividerPredicate=drawDividerPredicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,7 +43,7 @@ public class DividerItemDecoration extends RecyclerView.ItemDecoration{
|
||||
for(int i=0;i<parent.getChildCount();i++){
|
||||
View child=parent.getChildAt(i);
|
||||
int pos=parent.getChildAdapterPosition(child);
|
||||
if(pos<totalItems-1){
|
||||
if(pos<totalItems-1 && (drawDividerPredicate==null || drawDividerPredicate.test(parent.getChildViewHolder(child)))){
|
||||
float y=Math.round(child.getY()+child.getHeight()-paint.getStrokeWidth()/2f);
|
||||
paint.setAlpha(Math.round(255f*child.getAlpha()));
|
||||
c.drawLine(padLeft+child.getX(), y, child.getX()+child.getWidth()-padRight, y, paint);
|
||||
|
||||
@@ -94,7 +94,7 @@ public class PhotoLayoutHelper{
|
||||
};
|
||||
}
|
||||
}else if(cnt==3){
|
||||
if(/*(ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) &&*/ orients.equals("www")){ // 2nd and 3rd photos are on the next line
|
||||
if(/*(ratios.get(0) > 1.2 * maxRatio || avgRatio > 1.5 * maxRatio) &&*/ orients.equals("www") || true){ // 2nd and 3rd photos are on the next line
|
||||
float hCover=Math.min(maxW/ratios.get(0), (maxH-marginH)*0.66f);
|
||||
float w2=((maxW-marginW)/2);
|
||||
float h=Math.min(maxH-hCover-marginH, Math.min(w2/ratios.get(1), w2/ratios.get(2)));
|
||||
|
||||
@@ -19,6 +19,7 @@ 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.fragments.ReportReasonChoiceFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -121,7 +122,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
name.setText(item.parsedName);
|
||||
username.setText('@'+item.user.acct);
|
||||
timestamp.setText(UiUtils.formatRelativeTimestamp(itemView.getContext(), item.createdAt));
|
||||
visibility.setVisibility(item.hasVisibilityToggle ? View.VISIBLE : View.GONE);
|
||||
visibility.setVisibility(item.hasVisibilityToggle && !item.inset ? View.VISIBLE : View.GONE);
|
||||
if(item.hasVisibilityToggle){
|
||||
visibility.setImageResource(item.status.spoilerRevealed ? R.drawable.ic_visibility_off : R.drawable.ic_visibility);
|
||||
}
|
||||
@@ -133,6 +134,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
extraText.setText(item.extraText);
|
||||
}
|
||||
more.setVisibility(item.inset ? View.GONE : View.VISIBLE);
|
||||
avatar.setClickable(!item.inset);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,7 +180,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
}else if(id==R.id.block){
|
||||
UiUtils.confirmToggleBlockUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, false, r->{});
|
||||
}else if(id==R.id.report){
|
||||
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", item.parentFragment.getAccountID());
|
||||
args.putParcelable("status", Parcels.wrap(item.status));
|
||||
args.putParcelable("reportAccount", Parcels.wrap(item.status.account));
|
||||
Nav.go(item.parentFragment.getActivity(), ReportReasonChoiceFragment.class, args);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user