Reporting
This commit is contained in:
parent
abae198e89
commit
86892e4103
|
@ -10,7 +10,7 @@ android {
|
|||
applicationId "org.joinmastodon.android"
|
||||
minSdk 23
|
||||
targetSdk 31
|
||||
versionCode 6
|
||||
versionCode 7
|
||||
versionName "0.1"
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/gray_800"/>
|
||||
<corners android:radius="10dp"/>
|
||||
<padding android:top="16dp" android:left="16dp" android:right="16dp" android:bottom="16dp"/>
|
||||
</shape>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="@color/gray_25"/>
|
||||
<corners android:radius="10dp"/>
|
||||
<padding android:top="16dp" android:left="16dp" android:right="16dp" android:bottom="16dp"/>
|
||||
</shape>
|
|
@ -0,0 +1,3 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M12 2c5.523 0 10 4.477 10 10s-4.477 10-10 10S2 17.523 2 12 6.477 2 12 2zm3.22 6.97l-4.47 4.47-1.97-1.97c-0.293-0.293-0.767-0.293-1.06 0-0.293 0.293-0.293 0.767 0 1.06l2.5 2.5c0.293 0.293 0.767 0.293 1.06 0l5-5c0.293-0.293 0.293-0.767 0-1.06-0.293-0.293-0.767-0.293-1.06 0z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
|
@ -0,0 +1,3 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
|
||||
<path android:pathData="M12 22.002c5.524 0 10.002-4.478 10.002-10.001 0-5.524-4.478-10.002-10.002-10.002-5.524 0-10.002 4.478-10.002 10.002 0 5.523 4.478 10.001 10.002 10.001zm0-1.5c-4.695 0-8.502-3.806-8.502-8.501 0-4.696 3.807-8.502 8.502-8.502s8.502 3.806 8.502 8.502c0 4.695-3.807 8.501-8.502 8.501z" android:fillColor="@color/fluent_default_icon_tint"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/ic_fluent_checkmark_circle_24_filled"/>
|
||||
<item android:drawable="@drawable/ic_fluent_radio_button_24_regular"/>
|
||||
</selector>
|
|
@ -0,0 +1,12 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<shape>
|
||||
<solid android:color="?android:colorBackground"/>
|
||||
<stroke android:width="6.5dp" android:color="@color/success_600"/>
|
||||
<corners android:radius="7dp"/>
|
||||
<size android:width="205dp" android:height="69dp"/>
|
||||
</shape>
|
||||
</item>
|
||||
<item android:drawable="@drawable/reported_text" android:gravity="center"/>
|
||||
</layer-list>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/button_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:windowBackground"
|
||||
android:outlineProvider="bounds"
|
||||
android:elevation="3dp"
|
||||
tools:showIn="@layout/fragment_report_choice">
|
||||
|
||||
<Button
|
||||
android:id="@+id/btn_next"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
style="?primaryLargeButtonStyle"
|
||||
android:text="@string/next" />
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/content_wrap"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<me.grishka.appkit.views.UsableRecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
<ViewStub android:layout="?emptyViewLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/empty"/>
|
||||
|
||||
</FrameLayout>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<me.grishka.appkit.views.UsableRecyclerView
|
||||
android:id="@+id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"
|
||||
android:background="?android:colorBackground"/>
|
||||
|
||||
<include layout="@layout/button_bar_one" />
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<include layout="@layout/item_list_header"/>
|
||||
|
||||
<EditText
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="16dp"
|
||||
android:hint="@string/report_comment_hint"
|
||||
android:inputType="textMultiLine|textCapSentences"
|
||||
android:gravity="top|start"
|
||||
android:minHeight="212dp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<include layout="@layout/button_bar_one"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,134 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="32dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:textAppearance="@style/m3_headline_medium"
|
||||
android:minHeight="36dp"
|
||||
android:gravity="center_vertical"
|
||||
tools:text="Title"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/ava_reported"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:clipToPadding="false">
|
||||
<ImageView
|
||||
android:id="@+id/avatar"
|
||||
android:layout_width="104dp"
|
||||
android:layout_height="104dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
tools:src="#0f0"/>
|
||||
<View
|
||||
android:id="@+id/reported_overlay"
|
||||
android:layout_width="205dp"
|
||||
android:layout_height="69dp"
|
||||
android:layout_gravity="center"
|
||||
android:elevation="2dp"
|
||||
android:background="@drawable/reported_overlay"/>
|
||||
</FrameLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="Subtitle"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/unfollow_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
tools:text="@string/unfollow_user"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/unfollow_btn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
style="?secondaryLargeButtonStyle"
|
||||
android:text="@string/unfollow"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/mute_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
tools:text="@string/mute_user"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:text="@string/mute_user_explain"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/mute_btn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
style="?secondaryLargeButtonStyle"
|
||||
android:text="@string/do_mute"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/block_title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
tools:text="@string/block_user"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
android:text="@string/block_user_explain"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/block_btn"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="4dp"
|
||||
style="?secondaryLargeButtonStyle"
|
||||
android:text="@string/do_block"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<include layout="@layout/button_bar_one"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<me.grishka.appkit.views.FragmentRootLinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:orientation="vertical"
|
||||
android:id="@+id/appkit_loader_root"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:background="?android:colorBackground">
|
||||
|
||||
<include layout="@layout/appkit_toolbar"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/appkit_loader_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<include layout="@layout/loading"
|
||||
android:id="@+id/loading"/>
|
||||
|
||||
<ViewStub android:layout="?errorViewLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/error"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/content_stub"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<include layout="@layout/button_bar_one"/>
|
||||
|
||||
</me.grishka.appkit.views.FragmentRootLinearLayout>
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingRight="16dp"
|
||||
android:paddingTop="32dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:textAppearance="@style/m3_headline_medium"
|
||||
android:minHeight="36dp"
|
||||
android:gravity="center_vertical"
|
||||
tools:text="Title"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="Subtitle"/>
|
||||
|
||||
</LinearLayout>
|
|
@ -0,0 +1,37 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/checkbox"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:tint="?android:textColorSecondary"
|
||||
android:src="@drawable/ic_round_checkbox"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/checkbox"
|
||||
android:layout_marginStart="16dp"
|
||||
android:textAppearance="@style/m3_title_medium"
|
||||
tools:text="Title"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@id/checkbox"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_marginStart="16dp"
|
||||
android:textAppearance="@style/m3_body_medium"
|
||||
android:textColor="?android:textColorSecondary"
|
||||
tools:text="Subtitle"/>
|
||||
|
||||
</RelativeLayout>
|
|
@ -16,6 +16,9 @@
|
|||
<attr name="colorTabInactive" format="color"/>
|
||||
<attr name="colorAccentLightest" format="color"/>
|
||||
|
||||
<attr name="primaryLargeButtonStyle" format="reference"/>
|
||||
<attr name="secondaryLargeButtonStyle" format="reference"/>
|
||||
|
||||
<declare-styleable name="MaxWidthFrameLayout">
|
||||
<attr name="android:maxWidth" format="dimension"/>
|
||||
</declare-styleable>
|
||||
|
|
|
@ -145,4 +145,31 @@
|
|||
<item quantity="one">Discussed %d time</item>
|
||||
<item quantity="other">Discussed %d times</item>
|
||||
</plurals>
|
||||
<string name="report_title">Report %s</string>
|
||||
<string name="report_choose_reason">Tell us what\'s going on with this post.</string>
|
||||
<string name="report_choose_reason_subtitle">Choose the best match</string>
|
||||
<string name="report_reason_personal">I don\'t like it</string>
|
||||
<string name="report_reason_personal_subtitle">It is not something you want to see</string>
|
||||
<string name="report_reason_spam">It\'s spam</string>
|
||||
<string name="report_reason_spam_subtitle">Malicious links, fake engagement, or repetitive replies</string>
|
||||
<string name="report_reason_violation">It violates server rules</string>
|
||||
<string name="report_reason_violation_subtitle">You are aware that it breaks specific rules</string>
|
||||
<string name="report_reason_other">It\'s something else</string>
|
||||
<string name="report_reason_other_subtitle">The issue does not fit into other categories</string>
|
||||
<string name="report_choose_rule">Which rules are being violated?</string>
|
||||
<string name="report_choose_rule_subtitle">Select all that apply</string>
|
||||
<string name="report_choose_posts">Are there any posts that back up this report?</string>
|
||||
<string name="report_choose_posts_subtitle">Optional. Select all that apply</string>
|
||||
<string name="report_comment_title">Is there anything else you think we should know?</string>
|
||||
<string name="report_comment_subtitle">Optional.</string>
|
||||
<string name="report_comment_hint">Additional comments</string>
|
||||
<string name="sending_report">Sending report…</string>
|
||||
<string name="report_sent_title">Thanks for reporting, we\'ll look into this.</string>
|
||||
<string name="report_sent_subtitle">While we review this, you can take action against %s.</string>
|
||||
<string name="unfollow_user">Unfollow %s</string>
|
||||
<string name="unfollow">Unfollow</string>
|
||||
<string name="mute_user_explain">You won\'t see their posts or reblogs in your home feed. They won\'t know they\'ve been muted.</string>
|
||||
<string name="block_user_explain">They will no longer be able to follow or see your posts, but thye can see if they\'ve been blocked.</string>
|
||||
<string name="report_personal_title">Don\'t want to see this?</string>
|
||||
<string name="report_personal_subtitle">When you see something you don\'t like on Mastodon, you can remove the person from your experience.</string>
|
||||
</resources>
|
|
@ -7,9 +7,12 @@
|
|||
<item name="appkitBackDrawable">@drawable/ic_fluent_arrow_left_24_regular</item>
|
||||
<item name="android:splitMotionEvents">false</item>
|
||||
<item name="android:windowBackground">?colorWindowBackground</item>
|
||||
<item name="android:editTextStyle">@style/Widget.Mastodon.EditText</item>
|
||||
|
||||
<item name="android:buttonStyle">@style/Widget.Mastodon.Button.Primary_DarkOnLight</item>
|
||||
<item name="secondaryButtonStyle">@style/Widget.Mastodon.Button.Secondary_DarkOnLight</item>
|
||||
<item name="primaryLargeButtonStyle">@style/Widget.Mastodon.Button.Large.Primary_DarkOnLight</item>
|
||||
<item name="secondaryLargeButtonStyle">@style/Widget.Mastodon.Button.Large.Secondary_DarkOnLight</item>
|
||||
<item name="android:colorAccent">@color/primary_700</item>
|
||||
<item name="android:colorPrimary">@color/gray_800</item>
|
||||
<item name="android:colorBackground">@color/gray_100</item>
|
||||
|
@ -34,6 +37,7 @@
|
|||
<item name="colorAccentLightest">@color/primary_100</item>
|
||||
|
||||
<item name="buttonBackground">@drawable/bg_button_primary_dark_on_light</item>
|
||||
<item name="android:editTextBackground">@drawable/bg_edittext_light</item>
|
||||
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
|
||||
|
@ -46,9 +50,12 @@
|
|||
<item name="appkitBackDrawable">@drawable/ic_fluent_arrow_left_24_regular</item>
|
||||
<item name="android:splitMotionEvents">false</item>
|
||||
<item name="android:windowBackground">?colorWindowBackground</item>
|
||||
<item name="android:editTextStyle">@style/Widget.Mastodon.EditText</item>
|
||||
|
||||
<item name="android:buttonStyle">@style/Widget.Mastodon.Button.Primary_LightOnDark</item>
|
||||
<item name="secondaryButtonStyle">@style/Widget.Mastodon.Button.Secondary_LightOnDark</item>
|
||||
<item name="primaryLargeButtonStyle">@style/Widget.Mastodon.Button.Large.Primary_LightOnDark</item>
|
||||
<item name="secondaryLargeButtonStyle">@style/Widget.Mastodon.Button.Large.Secondary_LightOnDark</item>
|
||||
<item name="android:colorAccent">@color/primary_600</item>
|
||||
<item name="android:colorPrimary">@color/gray_50</item>
|
||||
<item name="android:colorBackground">@color/gray_700</item>
|
||||
|
@ -75,6 +82,7 @@
|
|||
<item name="colorAccentLightest">@color/primary_100</item>
|
||||
|
||||
<item name="buttonBackground">@drawable/bg_button_primary_light_on_dark</item>
|
||||
<item name="android:editTextBackground">@drawable/bg_edittext_light</item>
|
||||
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">false</item>
|
||||
|
@ -114,6 +122,13 @@
|
|||
<item name="android:paddingRight">16dp</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.Button.Large">
|
||||
<item name="android:minHeight">56dp</item>
|
||||
<item name="android:paddingLeft">32dp</item>
|
||||
<item name="android:paddingRight">32dp</item>
|
||||
<item name="android:textAppearance">@style/m3_title_medium</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.Button.Primary_DarkOnLight">
|
||||
<item name="android:background">@drawable/bg_button_primary_dark_on_light</item>
|
||||
<item name="android:textColor">@color/button_text_primary_dark_on_light</item>
|
||||
|
@ -134,6 +149,32 @@
|
|||
<item name="android:textColor">@color/button_text_secondary_light_on_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.Button.Large.Primary_DarkOnLight">
|
||||
<item name="android:background">@drawable/bg_button_primary_dark_on_light</item>
|
||||
<item name="android:textColor">@color/button_text_primary_dark_on_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.Button.Large.Secondary_DarkOnLight">
|
||||
<item name="android:background">@drawable/bg_button_secondary_dark_on_light</item>
|
||||
<item name="android:textColor">@color/button_text_secondary_dark_on_light</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.Button.Large.Primary_LightOnDark">
|
||||
<item name="android:background">@drawable/bg_button_primary_light_on_dark</item>
|
||||
<item name="android:textColor">@color/button_text_primary_light_on_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.Button.Large.Secondary_LightOnDark">
|
||||
<item name="android:background">@drawable/bg_button_secondary_light_on_dark</item>
|
||||
<item name="android:textColor">@color/button_text_secondary_light_on_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Mastodon.EditText" parent="android:Widget.Material.Light.EditText">
|
||||
<item name="android:textColorHint">?android:textColorSecondary</item>
|
||||
<item name="android:elevation">2dp</item>
|
||||
<item name="android:textAppearance">@style/m3_body_large</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Mastodon.Dialog.Alert" parent="android:Theme.Material.Light.Dialog.Alert">
|
||||
<item name="android:windowTitleStyle">@style/alert_title</item>
|
||||
<item name="android:dialogPreferredPadding">24dp</item>
|
||||
|
@ -188,6 +229,7 @@
|
|||
<style name="m3_body_medium">
|
||||
<item name="android:textSize">14dp</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:lineSpacingExtra">4dp</item>
|
||||
</style>
|
||||
|
||||
<style name="m3_title_medium">
|
||||
|
@ -226,4 +268,10 @@
|
|||
<item name="android:textSize">24dp</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
</style>
|
||||
|
||||
<style name="m3_headline_medium">
|
||||
<item name="android:textSize">28dp</item>
|
||||
<item name="android:textColor">?android:textColorPrimary</item>
|
||||
<item name="android:lineSpacingExtra">3dp</item>
|
||||
</style>
|
||||
</resources>
|
Loading…
Reference in New Issue