Reporting M3 redesign

This commit is contained in:
Grishka 2023-05-22 17:08:04 +03:00
parent 34a2af8429
commit bd7157c172
75 changed files with 2371 additions and 488 deletions

View File

@ -9,7 +9,7 @@ android {
applicationId "org.joinmastodon.android"
minSdk 23
targetSdk 33
versionCode 54
versionCode 55
versionName "1.3.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "ur-rIN", "vi-rVN", "zh-rCN", "zh-rTW"

View File

@ -5,14 +5,9 @@ import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@ -31,18 +26,15 @@ import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.SpoilerStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.MediaGridLayout;
import org.joinmastodon.android.utils.TypedObjectPool;
import java.util.ArrayList;
@ -268,7 +260,11 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
private Rect tmpRect=new Rect();
@Override
public void getSelectorBounds(View view, Rect outRect){
list.getDecoratedBoundsWithMargins(view, outRect);
if(((UsableRecyclerView) list).isIncludeMarginsInItemHitbox()){
list.getDecoratedBoundsWithMargins(view, outRect);
}else{
outRect.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
}
RecyclerView.ViewHolder holder=list.getChildViewHolder(view);
if(holder instanceof StatusDisplayItem.Holder){
if(((StatusDisplayItem.Holder<?>) holder).getItem().getType()==StatusDisplayItem.Type.GAP){
@ -430,6 +426,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
displayItems.subList(index+1, index+1+spoilerItem.contentItems.size()).clear();
adapter.notifyItemRangeRemoved(index+1, spoilerItem.contentItems.size());
}
list.invalidateItemDecorations();
}
public void onGapClick(GapStatusDisplayItem.Holder item){}
@ -557,6 +554,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
return attachmentViewsPool;
}
protected void onModifyItemViewHolder(BindableViewHolder<StatusDisplayItem> holder){}
protected class DisplayItemsAdapter extends UsableRecyclerView.Adapter<BindableViewHolder<StatusDisplayItem>> implements ImageLoaderRecyclerAdapter{
public DisplayItemsAdapter(){
@ -566,7 +565,9 @@ 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 & (~0x80000000)], getActivity(), parent);
BindableViewHolder<StatusDisplayItem> holder=(BindableViewHolder<StatusDisplayItem>) StatusDisplayItem.createViewHolder(StatusDisplayItem.Type.values()[viewType & (~0x80000000)], getActivity(), parent);
onModifyItemViewHolder(holder);
return holder;
}
@Override

View File

@ -4,6 +4,7 @@ import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
@ -34,4 +35,9 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
})
.exec(accountID);
}
@Override
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
// no-op
}
}

View File

@ -584,6 +584,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("reportAccount", Parcels.wrap(account));
args.putParcelable("relationship", Parcels.wrap(relationship));
Nav.go(getActivity(), ReportReasonChoiceFragment.class, args);
}else if(id==R.id.open_in_browser){
UiUtils.launchWebBrowser(getActivity(), account.url);

View File

@ -108,13 +108,7 @@ public class AccountActivationFragment extends ToolbarFragment{
@Override
public void onApplyWindowInsets(WindowInsets insets){
if(Build.VERSION.SDK_INT>=27){
int inset=insets.getSystemWindowInsetBottom();
contentView.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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(contentView, insets));
}
@Override

View File

@ -151,13 +151,7 @@ public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
private void loadServerPrivacyPolicy(){

View File

@ -20,6 +20,7 @@ import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.catalog.CatalogInstance;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
@ -330,13 +331,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
@Override

View File

@ -111,13 +111,7 @@ public class InstanceRulesFragment extends ToolbarFragment{
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
private class ItemsAdapter extends RecyclerView.Adapter<ItemViewHolder>{

View File

@ -130,13 +130,7 @@ public class OnboardingFollowSuggestionsFragment extends BaseRecyclerFragment<Pa
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
@Override

View File

@ -161,13 +161,7 @@ public class OnboardingProfileSetupFragment extends ToolbarFragment implements R
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
private View makeFieldsRow(){

View File

@ -366,13 +366,7 @@ public class SignupFragment extends ToolbarFragment{
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
private void onGoBackLinkClick(LinkSpan span){

View File

@ -1,15 +1,13 @@
package org.joinmastodon.android.fragments.report;
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.ProgressBar;
import android.widget.TextView;
import org.joinmastodon.android.E;
@ -23,14 +21,9 @@ 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 MastodonToolbarFragment{
@ -38,12 +31,13 @@ public abstract class BaseReportChoiceFragment extends MastodonToolbarFragment{
private MergeRecyclerAdapter adapter;
private Button btn;
private View buttonBar;
protected ArrayList<Item> items=new ArrayList<>();
protected ArrayList<ChoiceItem> items=new ArrayList<>();
protected boolean isMultipleChoice;
protected ArrayList<String> selectedIDs=new ArrayList<>();
protected String accountID;
protected Account reportAccount;
protected Status reportStatus;
protected ProgressBar progressBar;
@Override
public void onCreate(Bundle savedInstanceState){
@ -75,122 +69,33 @@ public abstract class BaseReportChoiceFragment extends MastodonToolbarFragment{
list=view.findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(getActivity()));
populateItems();
Item header=getHeaderItem();
ChoiceItem 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);
TextView stepCounter=headerView.findViewById(R.id.step_counter);
title.setText(header.title);
subtitle.setText(header.subtitle);
stepCounter.setText(getString(R.string.step_x_of_n, getStepNumber(), 3));
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);
progressBar=view.findViewById(R.id.top_progress);
adapter=new MergeRecyclerAdapter();
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
adapter.addAdapter(new ChoiceItemsAdapter(getActivity(), isMultipleChoice, items, list, selectedIDs, btn::setEnabled));
list.setAdapter(adapter);
return view;
}
protected abstract Item getHeaderItem();
protected abstract ChoiceItem getHeaderItem();
protected abstract void populateItems();
protected abstract void onButtonClick();
protected abstract int getStepNumber();
@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 ivh && ivh.getItem().id.equals(prev)){
ivh.rebind();
break;
}
}
}
selectedIDs.add(item.id);
rebind();
}
}
btn.setEnabled(!selectedIDs.isEmpty());
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
}

View File

@ -0,0 +1,11 @@
package org.joinmastodon.android.fragments.report;
class ChoiceItem{
public String title, subtitle, id;
public ChoiceItem(String title, String subtitle, String id){
this.title=title;
this.subtitle=subtitle;
this.id=id;
}
}

View File

@ -0,0 +1,85 @@
package org.joinmastodon.android.fragments.report;
import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RadioButton;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.ui.views.CheckableLinearLayout;
import java.util.ArrayList;
import java.util.function.Consumer;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
class ChoiceItemViewHolder extends BindableViewHolder<ChoiceItem> implements UsableRecyclerView.Clickable{
private final TextView title, subtitle;
private final View checkbox;
private final CheckableLinearLayout view;
private final boolean isMultipleChoice;
private final RecyclerView list;
private final ArrayList<String> selectedIDs;
private final Consumer<Boolean> buttonEnabledSetter;
public ChoiceItemViewHolder(Context context, boolean isMultipleChoice, RecyclerView list, ArrayList<String> selectedIDs, Consumer<Boolean> buttonEnabledSetter){
super(context, R.layout.item_report_choice, list);
this.buttonEnabledSetter=buttonEnabledSetter;
this.isMultipleChoice=isMultipleChoice;
this.list=list;
this.selectedIDs=selectedIDs;
title=findViewById(R.id.title);
subtitle=findViewById(R.id.subtitle);
checkbox=findViewById(R.id.checkbox);
CompoundButton cb=isMultipleChoice ? new CheckBox(context) : new RadioButton(context);
checkbox.setBackground(cb.getButtonDrawable());
view=(CheckableLinearLayout) itemView;
}
@Override
public void onBind(ChoiceItem item){
title.setText(item.title);
if(TextUtils.isEmpty(item.subtitle)){
subtitle.setVisibility(View.GONE);
view.setMinimumHeight(V.dp(56));
}else{
subtitle.setVisibility(View.VISIBLE);
subtitle.setText(item.subtitle);
view.setMinimumHeight(V.dp(72));
}
view.setChecked(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 ChoiceItemViewHolder ivh && ivh.getItem().id.equals(prev)){
ivh.rebind();
break;
}
}
}
selectedIDs.add(item.id);
rebind();
}
}
buttonEnabledSetter.accept(!selectedIDs.isEmpty());
}
}

View File

@ -0,0 +1,46 @@
package org.joinmastodon.android.fragments.report;
import android.content.Context;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.function.Consumer;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.views.UsableRecyclerView;
class ChoiceItemsAdapter extends RecyclerView.Adapter<ChoiceItemViewHolder>{
private final Context context;
private final boolean isMultipleChoice;
private final ArrayList<ChoiceItem> items;
private final RecyclerView list;
private final ArrayList<String> selectedIDs;
private final Consumer<Boolean> buttonEnabledSetter;
public ChoiceItemsAdapter(Context context, boolean isMultipleChoice, ArrayList<ChoiceItem> items, RecyclerView list, ArrayList<String> selectedIDs, Consumer<Boolean> buttonEnabledSetter){
this.context=context;
this.isMultipleChoice=isMultipleChoice;
this.items=items;
this.list=list;
this.selectedIDs=selectedIDs;
this.buttonEnabledSetter=buttonEnabledSetter;
}
@NonNull
@Override
public ChoiceItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
return new ChoiceItemViewHolder(context, isMultipleChoice, list, selectedIDs, buttonEnabledSetter);
}
@Override
public void onBindViewHolder(@NonNull ChoiceItemViewHolder holder, int position){
holder.bind(items.get(position));
}
@Override
public int getItemCount(){
return items.size();
}
}

View File

@ -4,13 +4,11 @@ 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.ProgressBar;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
@ -22,37 +20,34 @@ import org.joinmastodon.android.events.FinishReportFragmentsEvent;
import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.PhotoLayoutHelper;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.CheckableHeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
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 androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.BindableViewHolder;
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){
@ -72,13 +67,15 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
@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)
if(reportStatus!=null){
selectedIDs.add(reportStatus.id);
setTitle(getString(R.string.report_title, reportAccount.acct));
setTitle(R.string.report_title_post);
}else{
setTitle(getString(R.string.report_title, reportAccount.acct));
}
loadData();
}
@ -88,6 +85,9 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
for(Status s:result){
s.sensitive=true;
}
onDataLoaded(result, !result.isEmpty());
}
})
@ -100,8 +100,10 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
selectedIDs.remove(id);
else
selectedIDs.add(id);
list.invalidate();
btn.setEnabled(!selectedIDs.isEmpty());
CheckableHeaderStatusDisplayItem.Holder holder=findHolderOfType(id, CheckableHeaderStatusDisplayItem.Holder.class);
if(holder!=null)
holder.rebind();
}
@Override
@ -110,88 +112,27 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
btn=view.findViewById(R.id.btn_next);
btn.setEnabled(!selectedIDs.isEmpty());
btn.setOnClickListener(this::onButtonClick);
view.findViewById(R.id.btn_back).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)
if(holder.getAbsoluteAdapterPosition()==0 || holder instanceof CheckableHeaderStatusDisplayItem.Holder)
return;
outRect.left=V.dp(40);
if(holder instanceof AudioStatusDisplayItem.Holder){
outRect.bottom=V.dp(16);
}else if(holder instanceof LinkCardStatusDisplayItem.Holder){
}else if(holder instanceof LinkCardStatusDisplayItem.Holder || holder instanceof MediaGridStatusDisplayItem.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 sdiHolder){
parent.getDecoratedBoundsWithMargins(child, tmpRect);
String id=sdiHolder.getItemID();
int height=tmpRect.height();
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<?> sdiHolder){
String postID=sdiHolder.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();
}
}
}
}
});
ProgressBar topProgress=view.findViewById(R.id.top_progress);
topProgress.setProgress(getArguments().containsKey("ruleIDs") ? 50 : 33);
}
@Override
@ -204,10 +145,8 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
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);
TextView stepCounter=headerView.findViewById(R.id.step_counter);
title.setText(R.string.report_choose_posts);
subtitle.setText(R.string.report_choose_posts_subtitle);
stepCounter.setText(getString(R.string.step_x_of_n, 2, 3));
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
@ -216,17 +155,14 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
}
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));
if(reportStatus!=null)
args.putBoolean("fromPost", true);
if(v.getId()==R.id.btn_next){
args.putStringArrayList("statusIDs", selectedIDs);
}else{
@ -237,18 +173,13 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
}
args.putStringArrayList("ruleIDs", getArguments().getStringArrayList("ruleIDs"));
args.putString("reason", getArguments().getString("reason"));
args.putParcelable("relationship", getArguments().getParcelable("relationship"));
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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
@Subscribe
@ -261,4 +192,32 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
protected boolean wantsOverlaySystemNavigation(){
return false;
}
@Override
protected boolean wantsElevationOnScrollEffect(){
return false;
}
@Override
protected List<StatusDisplayItem> buildDisplayItems(Status s){
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, StatusDisplayItem.FLAG_INSET | StatusDisplayItem.FLAG_NO_FOOTER | StatusDisplayItem.FLAG_CHECKABLE | StatusDisplayItem.FLAG_MEDIA_FORCE_HIDDEN);
}
@Override
protected void onModifyItemViewHolder(BindableViewHolder<StatusDisplayItem> holder){
if((Object)holder instanceof MediaGridStatusDisplayItem.Holder h){
View layout=h.getLayout();
layout.setOutlineProvider(OutlineProviders.roundedRect(8));
layout.setClipToOutline(true);
View overlay=h.getSensitiveOverlay();
overlay.setOutlineProvider(OutlineProviders.roundedRect(8));
overlay.setClipToOutline(true);
}else if((Object)holder instanceof CheckableHeaderStatusDisplayItem.Holder h){
h.setIsChecked(this::isChecked);
}
}
private boolean isChecked(CheckableHeaderStatusDisplayItem.Holder holder){
return selectedIDs.contains(holder.getItem().parentID);
}
}

View File

@ -1,14 +1,16 @@
package org.joinmastodon.android.fragments.report;
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.EditText;
import android.widget.ProgressBar;
import android.widget.Switch;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
@ -16,6 +18,7 @@ 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.api.session.AccountSessionManager;
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
import org.joinmastodon.android.fragments.MastodonToolbarFragment;
import org.joinmastodon.android.model.Account;
@ -28,8 +31,6 @@ 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 MastodonToolbarFragment{
private String accountID;
@ -37,6 +38,8 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
private Button btn;
private View buttonBar;
private EditText commentEdit;
private Switch forwardSwitch;
private View forwardBtn;
@Override
public void onCreate(Bundle savedInstanceState){
@ -54,10 +57,12 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
@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));
if(getArguments().getBoolean("fromPost", false))
setTitle(R.string.report_title_post);
else
setTitle(getString(R.string.report_title, reportAccount.acct));
}
@ -67,16 +72,23 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
TextView title=view.findViewById(R.id.title);
TextView subtitle=view.findViewById(R.id.subtitle);
TextView stepCounter=view.findViewById(R.id.step_counter);
title.setText(R.string.report_comment_title);
subtitle.setVisibility(View.GONE);
stepCounter.setText(getString(R.string.step_x_of_n, 3, 3));
btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(this::onButtonClick);
view.findViewById(R.id.btn_back).setOnClickListener(this::onButtonClick);
buttonBar=view.findViewById(R.id.button_bar);
commentEdit=view.findViewById(R.id.text);
forwardSwitch=view.findViewById(R.id.forward_switch);
forwardBtn=view.findViewById(R.id.forward_report);
forwardBtn.setOnClickListener(v->forwardSwitch.toggle());
String myDomain=AccountSessionManager.getInstance().getAccount(accountID).domain;
if(!TextUtils.isEmpty(reportAccount.getDomain()) && !myDomain.equalsIgnoreCase(reportAccount.getDomain())){
TextView forwardTitle=view.findViewById(R.id.forward_title);
forwardTitle.setText(getString(R.string.forward_report_to_server, reportAccount.getDomain()));
}else{
forwardBtn.setVisibility(View.GONE);
}
return view;
}
@ -84,25 +96,21 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), android.R.attr.colorBackground));
ProgressBar topProgress=view.findViewById(R.id.top_progress);
topProgress.setProgress(getArguments().containsKey("ruleIDs") ? 75 : 66);
}
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
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, v.getId()==R.id.btn_back ? null : commentEdit.getText().toString(), true)
new SendReport(reportAccount.id, reason, statusIDs, ruleIDs, v.getId()==R.id.btn_back ? null : commentEdit.getText().toString(), forwardSwitch.isChecked())
.setCallback(new Callback<>(){
@Override
public void onSuccess(Object result){
@ -110,6 +118,8 @@ public class ReportCommentFragment extends MastodonToolbarFragment{
args.putString("account", accountID);
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
args.putString("reason", reason.name());
args.putBoolean("fromPost", getArguments().getBoolean("fromPost", false));
args.putParcelable("relationship", getArguments().getParcelable("relationship"));
Nav.go(getActivity(), ReportDoneFragment.class, args);
buttonBar.postDelayed(()->E.post(new FinishReportFragmentsEvent(reportAccount.id)), 500);
}

View File

@ -1,12 +1,14 @@
package org.joinmastodon.android.fragments.report;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.os.Build;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.animation.PathInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@ -23,10 +25,13 @@ import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
import androidx.annotation.DrawableRes;
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
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;
@ -38,6 +43,13 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
private Button btn;
private View buttonBar;
private ReportReason reason;
private TextView unfollowTitle;
private TextView muteTitle;
private TextView blockTitle;
private View unfollowBtn;
private View muteBtn;
private View blockBtn;
private Relationship relationship;
@Override
public void onCreate(Bundle savedInstanceState){
@ -52,10 +64,13 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
accountID=getArguments().getString("account");
reportAccount=Parcels.unwrap(getArguments().getParcelable("reportAccount"));
reason=ReportReason.valueOf(getArguments().getString("reason"));
setTitle(getString(R.string.report_title, reportAccount.acct));
relationship=Parcels.unwrap(getArguments().getParcelable("relationship"));
if(getArguments().getBoolean("fromPost", false))
setTitle(R.string.report_title_post);
else
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);
@ -64,10 +79,18 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
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);
if(relationship!=null && relationship.blocking){
subtitle.setText(R.string.report_personal_already_blocked);
}else{
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));
if(relationship!=null && relationship.blocking){
subtitle.setText(R.string.report_sent_already_blocked);
}else{
subtitle.setText(getString(R.string.report_sent_subtitle, '@'+reportAccount.acct));
}
}
btn=view.findViewById(R.id.btn_next);
@ -76,31 +99,65 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
btn.setText(R.string.done);
if(reason!=ReportReason.PERSONAL){
View doneOverlay=view.findViewById(R.id.reported_overlay);
doneOverlay.setOutlineProvider(OutlineProviders.roundedRect(7));
TextView stamp=view.findViewById(R.id.reported_stamp);
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();
stamp.setAlpha(0f);
stamp.setTranslationX(V.dp(148));
stamp.setTranslationY(V.dp(-296));
stamp.setScaleX(3.5f);
stamp.setScaleY(3.5f);
ObjectAnimator alpha=ObjectAnimator.ofFloat(stamp, View.ALPHA, 1f).setDuration(400);
alpha.setInterpolator(new PathInterpolator(0.16f, 1, 0.3f, 1));
alpha.start();
setupSpringAnimation(new SpringAnimation(stamp, DynamicAnimation.TRANSLATION_X, 0f));
setupSpringAnimation(new SpringAnimation(stamp, DynamicAnimation.TRANSLATION_Y, 0f));
setupSpringAnimation(new SpringAnimation(stamp, DynamicAnimation.SCALE_X, 1f));
setupSpringAnimation(new SpringAnimation(stamp, DynamicAnimation.SCALE_Y, 1f));
}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=view.findViewById(R.id.unfollow_title);
muteTitle=view.findViewById(R.id.mute_title);
blockTitle=view.findViewById(R.id.block_title);
unfollowBtn=view.findViewById(R.id.unfollow_btn);
muteBtn=view.findViewById(R.id.mute_btn);
blockBtn=view.findViewById(R.id.block_btn);
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));
setIconToButton(R.drawable.ic_person_remove_20px, unfollowTitle);
setIconToButton(R.drawable.ic_block_20px, blockTitle);
setIconToButton(R.drawable.ic_volume_off_20px, muteTitle);
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());
unfollowBtn.setOnClickListener(v->onUnfollowClick());
muteBtn.setOnClickListener(v->onMuteClick());
blockBtn.setOnClickListener(v->onBlockClick());
if(relationship!=null){
if(relationship.blocking){
muteBtn.setVisibility(View.GONE);
view.findViewById(R.id.mute_explanation).setVisibility(View.GONE);
unfollowBtn.setVisibility(View.GONE);
view.findViewById(R.id.unfollow_explanation).setVisibility(View.GONE);
blockBtn.setVisibility(View.GONE);
view.findViewById(R.id.block_explanation).setVisibility(View.GONE);
}else{
if(relationship.muting){
muteBtn.setVisibility(View.GONE);
view.findViewById(R.id.mute_explanation).setVisibility(View.GONE);
}
if(!relationship.following){
unfollowBtn.setVisibility(View.GONE);
view.findViewById(R.id.unfollow_explanation).setVisibility(View.GONE);
}
}
}
return view;
}
@ -108,18 +165,11 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
@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()));
}
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
private void onButtonClick(View v){
@ -131,8 +181,13 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
.setCallback(new Callback<>(){
@Override
public void onSuccess(Relationship result){
Nav.finish(ReportDoneFragment.this);
E.post(new RemoveAccountPostsEvent(accountID, reportAccount.id, true));
unfollowTitle.setTextColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSecondaryContainer));
unfollowTitle.setText(getString(R.string.unfollowed_user, '@'+reportAccount.acct));
setIconToButton(R.drawable.ic_check_24px, unfollowTitle);
unfollowBtn.setBackgroundResource(R.drawable.bg_button_m3_tonal);
unfollowBtn.setClickable(false);
unfollowBtn.setFocusable(false);
}
@Override
@ -145,10 +200,50 @@ public class ReportDoneFragment extends MastodonToolbarFragment{
}
private void onMuteClick(){
UiUtils.confirmToggleMuteUser(getActivity(), accountID, reportAccount, false, rel->Nav.finish(this));
UiUtils.confirmToggleMuteUser(getActivity(), accountID, reportAccount, false, rel->{
muteTitle.setTextColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSecondaryContainer));
muteTitle.setText(getString(R.string.muted_user, '@'+reportAccount.acct));
setIconToButton(R.drawable.ic_check_24px, muteTitle);
muteBtn.setBackgroundResource(R.drawable.bg_button_m3_tonal);
muteBtn.setClickable(false);
muteBtn.setFocusable(false);
});
}
private void onBlockClick(){
UiUtils.confirmToggleBlockUser(getActivity(), accountID, reportAccount, false, rel->Nav.finish(this));
UiUtils.confirmToggleBlockUser(getActivity(), accountID, reportAccount, false, rel->{
blockTitle.setTextColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSecondaryContainer));
blockTitle.setText(getString(R.string.blocked_user, '@'+reportAccount.acct));
setIconToButton(R.drawable.ic_check_24px, blockTitle);
blockBtn.setBackgroundResource(R.drawable.bg_button_m3_tonal);
blockBtn.setClickable(false);
blockBtn.setFocusable(false);
if(unfollowBtn.isClickable())
unfollowBtn.setEnabled(false);
if(muteBtn.isClickable())
muteBtn.setEnabled(false);
});
}
@Override
protected int getNavigationIconDrawableResource(){
return R.drawable.ic_baseline_close_24;
}
@Override
public boolean wantsCustomNavigationIcon(){
return true;
}
private void setIconToButton(@DrawableRes int icon, TextView button){
Drawable d=getResources().getDrawable(icon, getActivity().getTheme()).mutate();
d.setBounds(0, 0, V.dp(18), V.dp(18));
d.setTintList(button.getTextColors());
button.setCompoundDrawablesRelative(d, null, null, null);
}
private void setupSpringAnimation(SpringAnimation anim){
anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY).setStiffness(500);
anim.start();
}
}

View File

@ -1,36 +1,106 @@
package org.joinmastodon.android.fragments.report;
import android.app.Activity;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowInsets;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.ReportReason;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.displayitems.LinkCardStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
import me.grishka.appkit.Nav;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
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 class ReportReasonChoiceFragment extends StatusListFragment{
private MergeRecyclerAdapter mergeAdapter;
private Button btn;
private View buttonBar;
protected ArrayList<ChoiceItem> items=new ArrayList<>();
protected boolean isMultipleChoice;
protected ArrayList<String> selectedIDs=new ArrayList<>();
protected Account reportAccount;
protected Status reportStatus;
protected ProgressBar progressBar;
private Relationship relationship;
public class ReportReasonChoiceFragment extends BaseReportChoiceFragment{
@Override
protected Item getHeaderItem(){
return new Item(reportStatus!=null ? getString(R.string.report_choose_reason) : getString(R.string.report_choose_reason_account, reportAccount.acct), getString(R.string.report_choose_reason_subtitle), null);
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(true);
setListLayoutId(R.layout.fragment_content_report_posts);
setLayout(R.layout.fragment_report_posts);
E.register(this);
}
@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()));
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"));
if(reportStatus!=null){
Status hiddenStatus=new Status(reportStatus);
hiddenStatus.spoilerText=getString(R.string.post_hidden);
onDataLoaded(Collections.singletonList(hiddenStatus));
setTitle(R.string.report_title_post);
}else{
onDataLoaded(Collections.emptyList());
setTitle(getString(R.string.report_title, reportAccount.acct));
}
relationship=Parcels.unwrap(getArguments().getParcelable("relationship"));
if(relationship==null && reportStatus==null)
loadRelationships(Collections.singleton(reportAccount.id));
items.add(new ChoiceItem(getString(R.string.report_reason_personal), getString(R.string.report_reason_personal_subtitle), ReportReason.PERSONAL.name()));
items.add(new ChoiceItem(getString(R.string.report_reason_spam), getString(R.string.report_reason_spam_subtitle), ReportReason.SPAM.name()));
Instance inst=AccountSessionManager.getInstance().getInstanceInfo(AccountSessionManager.getInstance().getAccount(accountID).domain);
if(inst!=null && inst.rules!=null && !inst.rules.isEmpty()){
items.add(new Item(getString(R.string.report_reason_violation), getString(R.string.report_reason_violation_subtitle), ReportReason.VIOLATION.name()));
items.add(new ChoiceItem(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()));
items.add(new ChoiceItem(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();
@ -38,6 +108,8 @@ public class ReportReasonChoiceFragment extends BaseReportChoiceFragment{
args.putParcelable("status", Parcels.wrap(reportStatus));
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
args.putString("reason", reason.name());
args.putBoolean("fromPost", reportStatus!=null);
args.putParcelable("relationship", Parcels.wrap(relationship));
switch(reason){
case PERSONAL -> {
Nav.go(getActivity(), ReportDoneFragment.class, args);
@ -48,14 +120,146 @@ public class ReportReasonChoiceFragment extends BaseReportChoiceFragment{
}
}
@Override
protected int getStepNumber(){
return 1;
}
@Subscribe
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
if(ev.reportAccountID.equals(reportAccount.id))
Nav.finish(this);
}
@Override
public void onApplyWindowInsets(WindowInsets insets){
super.onApplyWindowInsets(UiUtils.applyBottomInsetToFixedView(buttonBar, insets));
}
@Override
protected void doLoadData(int offset, int count){
}
@Override
protected RecyclerView.Adapter getAdapter(){
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
LayoutInflater inflater=getActivity().getLayoutInflater();
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(reportStatus!=null ? getString(R.string.report_choose_reason) : getString(R.string.report_choose_reason_account, reportAccount.acct));
subtitle.setText(getString(R.string.report_choose_reason_subtitle));
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
adapter.addAdapter(super.getAdapter());
adapter.addAdapter(new ChoiceItemsAdapter(getActivity(), isMultipleChoice, items, list, selectedIDs, btn::setEnabled));
return mergeAdapter=adapter;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
btn=view.findViewById(R.id.btn_next);
btn.setEnabled(!selectedIDs.isEmpty());
btn.setOnClickListener(v->onButtonClick());
buttonBar=view.findViewById(R.id.button_bar);
progressBar=view.findViewById(R.id.top_progress);
progressBar.setProgress(5);
super.onViewCreated(view, savedInstanceState);
((UsableRecyclerView)list).setIncludeMarginsInItemHitbox(false);
if(reportStatus!=null){
list.addItemDecoration(new RecyclerView.ItemDecoration(){
@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 instanceof LinkCardStatusDisplayItem.Holder || holder instanceof MediaGridStatusDisplayItem.Holder){
outRect.left=V.dp(16);
outRect.right=V.dp(16);
}
}
});
list.addItemDecoration(new RecyclerView.ItemDecoration(){
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
{
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(V.dp(1));
paint.setColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OutlineVariant));
}
@Override
public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
int firstPos=list.getChildAdapterPosition(list.getChildAt(0));
int lastPos=-1;
for(int i=list.getChildCount()-1;i>=0;i--){
lastPos=list.getChildAdapterPosition(list.getChildAt(i));
if(lastPos!=-1)
break;
}
int postStart=mergeAdapter.getPositionForAdapter(adapter);
if(lastPos<postStart || firstPos>postStart+displayItems.size()){
return;
}
float top=V.dp(-12);
float bottom=parent.getHeight()+V.dp(12);
for(int i=0;i<parent.getChildCount();i++){
View child=parent.getChildAt(i);
int pos=parent.getChildAdapterPosition(child);
if(pos==postStart)
top=child.getY();
if(pos==postStart+displayItems.size())
bottom=child.getY()-V.dp(16);
}
float off=paint.getStrokeWidth()/2f;
c.drawRoundRect(V.dp(16)-off, top-off, parent.getWidth()-V.dp(16)+off, bottom+off, V.dp(12), V.dp(12), paint);
}
@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 instanceof StatusDisplayItem.Holder<?>){
outRect.left=outRect.right=V.dp(16);
}
int index=holder.getAbsoluteAdapterPosition()-mergeAdapter.getPositionForAdapter(adapter);
if(index==displayItems.size()){
outRect.top=V.dp(32);
}
}
});
}
}
@Override
protected boolean wantsOverlaySystemNavigation(){
return false;
}
@Override
protected boolean wantsElevationOnScrollEffect(){
return false;
}
@Override
protected List<StatusDisplayItem> buildDisplayItems(Status s){
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, StatusDisplayItem.FLAG_INSET | StatusDisplayItem.FLAG_NO_FOOTER);
}
@Override
protected void onModifyItemViewHolder(BindableViewHolder<StatusDisplayItem> holder){
if((Object)holder instanceof MediaGridStatusDisplayItem.Holder h){
View layout=h.getLayout();
layout.setOutlineProvider(OutlineProviders.roundedRect(8));
layout.setClipToOutline(true);
View overlay=h.getSensitiveOverlay();
overlay.setOutlineProvider(OutlineProviders.roundedRect(8));
overlay.setClipToOutline(true);
}
}
@Override
public void putRelationship(String id, Relationship rel){
super.putRelationship(id, rel);
if(id.equals(reportAccount.id))
relationship=rel;
}
}

View File

@ -1,6 +1,7 @@
package org.joinmastodon.android.fragments.report;
import android.os.Bundle;
import android.view.View;
import com.squareup.otto.Subscribe;
@ -14,8 +15,8 @@ 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);
protected ChoiceItem getHeaderItem(){
return new ChoiceItem(getString(R.string.report_choose_rule), getString(R.string.report_choose_rule_subtitle), null);
}
@Override
@ -24,7 +25,7 @@ public class ReportRuleChoiceFragment extends BaseReportChoiceFragment{
Instance inst=AccountSessionManager.getInstance().getInstanceInfo(AccountSessionManager.getInstance().getAccount(accountID).domain);
if(inst!=null && inst.rules!=null){
for(Instance.Rule rule:inst.rules){
items.add(new Item(rule.text, null, rule.id));
items.add(new ChoiceItem(rule.text, null, rule.id));
}
}
}
@ -37,17 +38,19 @@ public class ReportRuleChoiceFragment extends BaseReportChoiceFragment{
args.putParcelable("reportAccount", Parcels.wrap(reportAccount));
args.putString("reason", getArguments().getString("reason"));
args.putStringArrayList("ruleIDs", selectedIDs);
args.putParcelable("relationship", getArguments().getParcelable("relationship"));
Nav.go(getActivity(), ReportAddPostsChoiceFragment.class, args);
}
@Override
protected int getStepNumber(){
return 1;
}
@Subscribe
public void onFinishReportFragments(FinishReportFragmentsEvent ev){
if(ev.reportAccountID.equals(reportAccount.id))
Nav.finish(this);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
progressBar.setProgress(25);
}
}

View File

@ -1,7 +1,9 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
@Parcel
public class Relationship extends BaseModel{
@RequiredField
public String id;

View File

@ -59,6 +59,41 @@ public class Status extends BaseModel implements DisplayItemsParent{
public transient boolean hasGapAfter;
private transient String strippedText;
public Status(){}
public Status(Status other){
this.id=other.id;
this.uri=other.uri;
this.createdAt=other.createdAt;
this.account=other.account;
this.content=other.content;
this.visibility=other.visibility;
this.sensitive=other.sensitive;
this.spoilerText=other.spoilerText;
this.mediaAttachments=other.mediaAttachments;
this.application=other.application;
this.mentions=other.mentions;
this.tags=other.tags;
this.emojis=other.emojis;
this.reblogsCount=other.reblogsCount;
this.favouritesCount=other.favouritesCount;
this.repliesCount=other.repliesCount;
this.editedAt=other.editedAt;
this.url=other.url;
this.inReplyToId=other.inReplyToId;
this.inReplyToAccountId=other.inReplyToAccountId;
this.reblog=other.reblog;
this.poll=other.poll;
this.card=other.card;
this.language=other.language;
this.text=other.text;
this.favourited=other.favourited;
this.reblogged=other.reblogged;
this.muted=other.muted;
this.bookmarked=other.bookmarked;
this.pinned=other.pinned;
}
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();

View File

@ -0,0 +1,51 @@
package org.joinmastodon.android.ui.displayitems;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.views.CheckableRelativeLayout;
import java.time.Instant;
import java.util.function.Predicate;
public class CheckableHeaderStatusDisplayItem extends HeaderStatusDisplayItem{
public CheckableHeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, String extraText){
super(parentID, user, createdAt, parentFragment, accountID, status, extraText);
}
@Override
public Type getType(){
return Type.HEADER_CHECKABLE;
}
public static class Holder extends HeaderStatusDisplayItem.Holder{
private final View checkbox;
private final CheckableRelativeLayout view;
private Predicate<Holder> isChecked;
public Holder(Activity activity, ViewGroup parent){
super(activity, R.layout.display_item_header_checkable, parent);
checkbox=findViewById(R.id.checkbox);
view=(CheckableRelativeLayout) itemView;
checkbox.setBackground(new CheckBox(activity).getButtonDrawable());
}
@Override
public void onBind(HeaderStatusDisplayItem item){
super.onBind(item);
if(isChecked!=null){
view.setChecked(isChecked.test(this));
}
}
public void setIsChecked(Predicate<Holder> isChecked){
this.isChecked=isChecked;
}
}
}

View File

@ -3,18 +3,16 @@ package org.joinmastodon.android.ui.displayitems;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Outline;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
@ -43,6 +41,7 @@ import java.time.Instant;
import java.util.Collections;
import java.util.List;
import androidx.annotation.LayoutRes;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.APIRequest;
import me.grishka.appkit.api.Callback;
@ -114,7 +113,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
private APIRequest<?> currentRelationshipRequest;
public Holder(Activity activity, ViewGroup parent){
super(activity, R.layout.display_item_header, parent);
this(activity, R.layout.display_item_header, parent);
}
protected Holder(Activity activity, @LayoutRes int layout, ViewGroup parent){
super(activity, layout, parent);
name=findViewById(R.id.name);
timeAndUsername=findViewById(R.id.time_and_username);
avatar=findViewById(R.id.avatar);
@ -165,6 +168,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
args.putString("account", item.parentFragment.getAccountID());
args.putParcelable("status", Parcels.wrap(item.status));
args.putParcelable("reportAccount", Parcels.wrap(item.status.account));
args.putParcelable("relationship", Parcels.wrap(relationship));
Nav.go(item.parentFragment.getActivity(), ReportReasonChoiceFragment.class, args);
}else if(id==R.id.open_in_browser){
UiUtils.launchWebBrowser(activity, item.status.url);

View File

@ -48,6 +48,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
private final ArrayList<ImageLoaderRequest> requests=new ArrayList<>();
public final Status status;
public boolean sensitiveRevealed;
public String sensitiveTitle;
public MediaGridStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, PhotoLayoutHelper.TiledLayoutResult tiledLayout, List<Attachment> attachments, Status status){
super(parentID, parentFragment);
@ -103,6 +104,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
private final LayerDrawable sensitiveOverlayBG;
private static final ColorDrawable drawableForWhenThereIsNoBlurhash=new ColorDrawable(0xffffffff);
private final TextView hideSensitiveButton;
private final TextView sensitiveText;
private int altTextIndex=-1;
private Animator altTextAnimator;
@ -112,7 +114,6 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
wrapper=(FrameLayout)itemView;
layout=new MediaGridLayout(activity);
wrapper.addView(layout);
wrapper.setPadding(0, 0, 0, V.dp(8));
wrapper.setClipToPadding(false);
overlays=new MaxWidthFrameLayout(activity);
@ -136,15 +137,20 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
activity.getLayoutInflater().inflate(R.layout.overlay_image_sensitive, overlays);
sensitiveOverlay=findViewById(R.id.sensitive_overlay);
sensitiveOverlayBG=(LayerDrawable) sensitiveOverlay.getBackground();
sensitiveOverlayBG=(LayerDrawable) sensitiveOverlay.getBackground().mutate();
sensitiveOverlayBG.setDrawableByLayerId(R.id.left_drawable, new SpoilerStripesDrawable(false));
sensitiveOverlayBG.setDrawableByLayerId(R.id.right_drawable, new SpoilerStripesDrawable(true));
sensitiveOverlay.setBackground(sensitiveOverlayBG);
sensitiveOverlay.setOnClickListener(v->revealSensitive());
hideSensitiveButton.setOnClickListener(v->hideSensitive());
sensitiveText=findViewById(R.id.sensitive_text);
}
@Override
public void onBind(MediaGridStatusDisplayItem item){
wrapper.setPadding(0, 0, 0, item.inset ? 0 : V.dp(8));
if(altTextAnimator!=null)
altTextAnimator.cancel();
@ -190,6 +196,10 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
layout.setVisibility(View.VISIBLE);
}
hideSensitiveButton.setVisibility(item.status.sensitive ? View.VISIBLE : View.GONE);
if(!TextUtils.isEmpty(item.sensitiveTitle))
sensitiveText.setText(item.sensitiveTitle);
else
sensitiveText.setText(R.string.sensitive_content_explain);
}
@Override
@ -346,5 +356,13 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
item.sensitiveRevealed=false;
V.setVisibilityAnimated(sensitiveOverlay, View.VISIBLE, ()->layout.setVisibility(View.INVISIBLE));
}
public MediaGridLayout getLayout(){
return layout;
}
public View getSensitiveOverlay(){
return sensitiveOverlay;
}
}
}

View File

@ -33,6 +33,11 @@ public abstract class StatusDisplayItem{
public boolean inset;
public int index;
public static final int FLAG_INSET=1;
public static final int FLAG_NO_FOOTER=1 << 1;
public static final int FLAG_CHECKABLE=1 << 2;
public static final int FLAG_MEDIA_FORCE_HIDDEN=1 << 3;
public StatusDisplayItem(String parentID, BaseStatusListFragment parentFragment){
this.parentID=parentID;
this.parentFragment=parentFragment;
@ -51,6 +56,7 @@ public abstract class StatusDisplayItem{
public static BindableViewHolder<? extends StatusDisplayItem> createViewHolder(Type type, Activity activity, ViewGroup parent){
return switch(type){
case HEADER -> new HeaderStatusDisplayItem.Holder(activity, parent);
case HEADER_CHECKABLE -> new CheckableHeaderStatusDisplayItem.Holder(activity, parent);
case REBLOG_OR_REPLY_LINE -> new ReblogOrReplyLineStatusDisplayItem.Holder(activity, parent);
case TEXT -> new TextStatusDisplayItem.Holder(activity, parent);
case AUDIO -> new AudioStatusDisplayItem.Holder(activity, parent);
@ -70,6 +76,15 @@ public abstract class StatusDisplayItem{
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter){
int flags=0;
if(inset)
flags|=FLAG_INSET;
if(!addFooter)
flags|=FLAG_NO_FOOTER;
return buildItems(fragment, status, accountID, parentObject, knownAccounts, flags);
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, int flags){
String parentID=parentObject.getID();
ArrayList<StatusDisplayItem> items=new ArrayList<>();
Status statusForContent=status.getContentStatus();
@ -80,7 +95,10 @@ public abstract class StatusDisplayItem{
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.in_reply_to, account.displayName), account.emojis, R.drawable.ic_reply_20px));
}
HeaderStatusDisplayItem header;
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null));
if((flags & FLAG_CHECKABLE)!=0)
items.add(header=new CheckableHeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null));
else
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null));
ArrayList<StatusDisplayItem> contentItems;
if(!TextUtils.isEmpty(statusForContent.spoilerText)){
@ -99,7 +117,10 @@ public abstract class StatusDisplayItem{
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream().filter(att->att.type.isImage()).collect(Collectors.toList());
if(!imageAttachments.isEmpty()){
PhotoLayoutHelper.TiledLayoutResult layout=PhotoLayoutHelper.processThumbs(imageAttachments);
contentItems.add(new MediaGridStatusDisplayItem(parentID, fragment, layout, imageAttachments, statusForContent));
MediaGridStatusDisplayItem mediaGrid=new MediaGridStatusDisplayItem(parentID, fragment, layout, imageAttachments, statusForContent);
if((flags & FLAG_MEDIA_FORCE_HIDDEN)!=0)
mediaGrid.sensitiveTitle=fragment.getString(R.string.media_hidden);
contentItems.add(mediaGrid);
}
for(Attachment att:statusForContent.mediaAttachments){
if(att.type==Attachment.Type.AUDIO){
@ -112,12 +133,13 @@ public abstract class StatusDisplayItem{
if(statusForContent.card!=null && statusForContent.mediaAttachments.isEmpty() && TextUtils.isEmpty(statusForContent.spoilerText)){
contentItems.add(new LinkCardStatusDisplayItem(parentID, fragment, statusForContent));
}
if(addFooter){
if((flags & FLAG_NO_FOOTER)==0){
items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID));
if(status.hasGapAfter && !(fragment instanceof ThreadFragment))
items.add(new GapStatusDisplayItem(parentID, fragment));
}
int i=1;
boolean inset=(flags & FLAG_INSET)!=0;
for(StatusDisplayItem item:items){
item.inset=inset;
item.index=i++;
@ -156,7 +178,8 @@ public abstract class StatusDisplayItem{
EXTENDED_FOOTER,
MEDIA_GRID,
SPOILER,
SECTION_HEADER
SECTION_HEADER,
HEADER_CHECKABLE
}
public static abstract class Holder<T extends StatusDisplayItem> extends BindableViewHolder<T> implements UsableRecyclerView.DisableableClickable{

View File

@ -35,6 +35,7 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.PopupMenu;
@ -740,4 +741,13 @@ public class UiUtils{
ta.recycle();
return d;
}
public static WindowInsets applyBottomInsetToFixedView(View view, WindowInsets insets){
if(Build.VERSION.SDK_INT>=27){
int inset=insets.getSystemWindowInsetBottom();
view.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(40)) : 0);
return insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0);
}
return insets;
}
}

View File

@ -228,6 +228,7 @@ public class AccountViewHolder extends BindableViewHolder<AccountViewModel> impl
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("reportAccount", Parcels.wrap(account));
args.putParcelable("relationship", Parcels.wrap(relationship));
Nav.go(fragment.getActivity(), ReportReasonChoiceFragment.class, args);
}else if(id==R.id.open_in_browser){
UiUtils.launchWebBrowser(fragment.getActivity(), account.url);

View File

@ -2,6 +2,7 @@ package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Checkable;
import android.widget.LinearLayout;
@ -47,4 +48,11 @@ public class CheckableLinearLayout extends LinearLayout implements Checkable{
}
return drawableState;
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info){
super.onInitializeAccessibilityNodeInfo(info);
info.setCheckable(true);
info.setChecked(checked);
}
}

View File

@ -0,0 +1,58 @@
package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.util.AttributeSet;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Checkable;
import android.widget.RelativeLayout;
public class CheckableRelativeLayout extends RelativeLayout implements Checkable{
private boolean checked;
private static final int[] CHECKED_STATE_SET = {
android.R.attr.state_checked
};
public CheckableRelativeLayout(Context context){
this(context, null);
}
public CheckableRelativeLayout(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public CheckableRelativeLayout(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
}
@Override
public void setChecked(boolean checked){
this.checked=checked;
refreshDrawableState();
}
@Override
public boolean isChecked(){
return checked;
}
@Override
public void toggle(){
setChecked(!checked);
}
@Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);
if (isChecked()) {
mergeDrawableStates(drawableState, CHECKED_STATE_SET);
}
return drawableState;
}
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info){
super.onInitializeAccessibilityNodeInfo(info);
info.setCheckable(true);
info.setChecked(checked);
}
}

View File

@ -0,0 +1,83 @@
package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.Switch;
import java.lang.reflect.Field;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.grishka.appkit.utils.V;
public class M3Switch extends Switch{
private boolean ignoreRequestLayout;
private DummyDrawable dummyDrawable=new DummyDrawable();
public M3Switch(Context context){
super(context);
}
public M3Switch(Context context, AttributeSet attrs){
super(context, attrs);
}
public M3Switch(Context context, AttributeSet attrs, int defStyleAttr){
super(context, attrs, defStyleAttr);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
ignoreRequestLayout=true;
Drawable prevThumbDrawable=getThumbDrawable();
setThumbDrawable(dummyDrawable);
ignoreRequestLayout=false;
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
ignoreRequestLayout=true;
setThumbDrawable(prevThumbDrawable);
ignoreRequestLayout=false;
try{
Field fld=Switch.class.getDeclaredField("mThumbWidth");
fld.setAccessible(true);
fld.set(this, V.dp(32));
}catch(Exception ignore){}
}
@Override
public void requestLayout(){
if(ignoreRequestLayout)
return;
super.requestLayout();
}
private static class DummyDrawable extends Drawable{
@Override
public void draw(@NonNull Canvas canvas){
}
@Override
public void setAlpha(int alpha){
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter){
}
@Override
public int getOpacity(){
return 0;
}
@Override
public int getIntrinsicWidth(){
return V.dp(26);
}
}
}

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- State Disabled, Unchecked -->
<item
android:alpha="@dimen/m3_comp_switch_disabled_unselected_icon_opacity"
android:color="@macro/m3_comp_switch_disabled_unselected_icon_color"
android:state_enabled="false" android:state_checked="false"/>
<!-- State Disabled, Checked -->
<item
android:alpha="@dimen/m3_comp_switch_disabled_selected_icon_opacity"
android:color="@macro/m3_comp_switch_disabled_selected_icon_color"
android:state_enabled="false" android:state_checked="true"/>
<!-- State Checked -->
<item android:color="@macro/m3_comp_switch_selected_icon_color" android:state_checked="true"/>
<!-- State Unchecked -->
<item android:color="@macro/m3_comp_switch_unselected_icon_color"/>
</selector>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- State Disabled, Unchecked -->
<item
android:alpha="@dimen/m3_comp_switch_disabled_unselected_handle_opacity"
android:color="@macro/m3_comp_switch_disabled_unselected_handle_color"
android:state_enabled="false" android:state_checked="false"/>
<!-- State Disabled, Checked -->
<item
android:alpha="@dimen/m3_comp_switch_disabled_selected_handle_opacity"
android:color="@macro/m3_comp_switch_disabled_selected_handle_color"
android:state_enabled="false" android:state_checked="true"/>
<!-- State Checked, Pressed -->
<item android:color="@macro/m3_comp_switch_selected_pressed_handle_color" android:state_checked="true" android:state_pressed="true"/>
<!-- State Checked -->
<item android:color="@macro/m3_comp_switch_selected_handle_color" android:state_checked="true"/>
<!-- State Unchecked, Pressed -->
<item android:color="@macro/m3_comp_switch_unselected_pressed_handle_color" android:state_pressed="true"/>
<!-- State Unchecked -->
<item android:color="@macro/m3_comp_switch_unselected_handle_color"/>
</selector>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@android:color/transparent" android:state_checked="true"/>
<item
android:alpha="@dimen/m3_comp_switch_disabled_track_opacity"
android:color="@macro/m3_comp_switch_disabled_unselected_track_outline_color"
android:state_enabled="false"/>
<item android:color="@macro/m3_comp_switch_unselected_track_outline_color"/>
</selector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:alpha="@dimen/m3_comp_switch_disabled_track_opacity"
android:color="@macro/m3_comp_switch_disabled_unselected_track_color"
android:state_enabled="false" android:state_checked="false"/>
<item android:alpha="@dimen/m3_comp_switch_disabled_track_opacity"
android:color="@macro/m3_comp_switch_disabled_selected_track_color"
android:state_enabled="false" android:state_checked="true"/>
<item android:color="@macro/m3_comp_switch_selected_track_color" android:state_checked="true"/>
<item android:color="@macro/m3_comp_switch_unselected_track_color"/>
</selector>

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="?colorWhite"/>
</shape>
</item>
<item android:gravity="top" android:height="0.5dp">
<shape>
<solid android:color="?colorM3OutlineVariant"/>
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="?colorM3PrimaryContainer"/>
<stroke android:width="4dp" android:color="?colorM3OnPrimaryContainer"/>
<corners android:radius="6dp"/>
</shape>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@android:color/white"
android:pathData="M10,18Q8.354,18 6.896,17.375Q5.438,16.75 4.344,15.656Q3.25,14.562 2.625,13.104Q2,11.646 2,10Q2,8.333 2.625,6.885Q3.25,5.438 4.344,4.344Q5.438,3.25 6.896,2.625Q8.354,2 10,2Q11.667,2 13.115,2.625Q14.562,3.25 15.656,4.344Q16.75,5.438 17.375,6.885Q18,8.333 18,10Q18,11.646 17.375,13.104Q16.75,14.562 15.656,15.656Q14.562,16.75 13.115,17.375Q11.667,18 10,18ZM10,16.5Q12.708,16.5 14.604,14.604Q16.5,12.708 16.5,10Q16.5,8.854 16.125,7.833Q15.75,6.812 15.083,5.979L5.979,15.083Q6.812,15.75 7.833,16.125Q8.854,16.5 10,16.5ZM4.917,14.021 L14.021,4.917Q13.188,4.25 12.167,3.875Q11.146,3.5 10,3.5Q7.292,3.5 5.396,5.396Q3.5,7.292 3.5,10Q3.5,11.146 3.875,12.167Q4.25,13.188 4.917,14.021Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M9.55,18 L3.85,12.3 5.275,10.875 9.55,15.15 18.725,5.975 20.15,7.4Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@android:color/white"
android:pathData="M13.292,9.312V7.562H18.333V9.312ZM7.542,9.979Q6.125,9.979 5.167,9.021Q4.208,8.062 4.208,6.646Q4.208,5.229 5.167,4.271Q6.125,3.312 7.542,3.312Q8.958,3.312 9.917,4.271Q10.875,5.229 10.875,6.646Q10.875,8.062 9.917,9.021Q8.958,9.979 7.542,9.979ZM0.833,16.667V14.271Q0.833,13.542 1.208,12.958Q1.583,12.375 2.188,12.083Q3.479,11.458 4.833,11.146Q6.188,10.833 7.562,10.833Q8.938,10.833 10.302,11.156Q11.667,11.479 12.938,12.083Q13.542,12.375 13.906,12.958Q14.271,13.542 14.271,14.271V16.667ZM2.583,14.917H12.521V14.271Q12.521,14.042 12.417,13.896Q12.312,13.75 12.146,13.667Q11.042,13.167 9.875,12.875Q8.708,12.583 7.562,12.583Q6.417,12.583 5.25,12.865Q4.083,13.146 2.979,13.667Q2.792,13.729 2.688,13.885Q2.583,14.042 2.583,14.271ZM7.542,8.229Q8.229,8.229 8.677,7.781Q9.125,7.333 9.125,6.646Q9.125,5.958 8.677,5.51Q8.229,5.062 7.542,5.062Q6.854,5.062 6.406,5.51Q5.958,5.958 5.958,6.646Q5.958,7.333 6.406,7.781Q6.854,8.229 7.542,8.229ZM7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646Q7.542,6.646 7.542,6.646ZM7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Q7.562,12.583 7.562,12.583Z"/>
</vector>

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:fillColor="@android:color/white"
android:pathData="M15.812,18.604 L13.729,16.521Q13.229,16.812 12.667,17.021Q12.104,17.229 11.5,17.354V15.583Q11.75,15.521 11.979,15.427Q12.208,15.333 12.438,15.229L9.75,12.542V16.646L5.479,12.5H2.271V7.458H4.667L1.312,4.104L2.562,2.854L17.042,17.354ZM16.292,14.104 L15.021,12.833Q15.375,12.188 15.573,11.469Q15.771,10.75 15.771,9.979Q15.771,8 14.583,6.448Q13.396,4.896 11.5,4.375V2.604Q14.167,3.125 15.844,5.198Q17.521,7.271 17.521,9.979Q17.521,11.104 17.208,12.156Q16.896,13.208 16.292,14.104ZM7.229,10ZM13.375,11.188 L11.5,9.312V6.708Q12.458,7.146 13.021,8.031Q13.583,8.917 13.583,9.979Q13.583,10.292 13.531,10.594Q13.479,10.896 13.375,11.188ZM9.75,7.542 L7.604,5.396 9.75,3.312ZM8,12.5V10.792L6.417,9.208H4.021V10.75H6.167Z"/>
</vector>

View File

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:width="@dimen/mtrl_switch_thumb_size"
android:height="@dimen/mtrl_switch_thumb_size"
tools:ignore="NewApi">
<item
android:id="@+id/pressed"
android:drawable="@drawable/mtrl_switch_thumb_pressed"
android:state_pressed="true" />
<item
android:id="@+id/checked"
android:drawable="@drawable/mtrl_switch_thumb_checked"
android:state_checked="true" />
<item
android:id="@+id/with_icon"
android:drawable="@drawable/mtrl_switch_thumb_checked"
app:state_with_icon="true" />
<item
android:id="@+id/unchecked"
android:drawable="@drawable/mtrl_switch_thumb_unchecked" />
<transition
android:fromId="@+id/pressed"
android:toId="@+id/checked"
android:drawable="@drawable/mtrl_switch_thumb_pressed_checked" />
<transition
android:fromId="@+id/pressed"
android:toId="@+id/with_icon"
android:drawable="@drawable/mtrl_switch_thumb_pressed_checked" />
<transition
android:fromId="@+id/pressed"
android:toId="@+id/unchecked"
android:drawable="@drawable/mtrl_switch_thumb_pressed_unchecked" />
<transition
android:fromId="@+id/checked"
android:toId="@+id/pressed"
android:drawable="@drawable/mtrl_switch_thumb_checked_pressed" />
<transition
android:fromId="@+id/checked"
android:toId="@+id/unchecked"
android:drawable="@drawable/mtrl_switch_thumb_checked_unchecked" />
<transition
android:fromId="@+id/with_icon"
android:toId="@+id/pressed"
android:drawable="@drawable/mtrl_switch_thumb_checked_pressed" />
<transition
android:fromId="@+id/unchecked"
android:toId="@+id/pressed"
android:drawable="@drawable/mtrl_switch_thumb_unchecked_pressed" />
<transition
android:fromId="@+id/unchecked"
android:toId="@+id/checked"
android:drawable="@drawable/mtrl_switch_thumb_unchecked_checked" />
</animated-selector>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="@dimen/mtrl_switch_thumb_size"
android:height="@dimen/mtrl_switch_thumb_size"
android:viewportHeight="@integer/mtrl_switch_thumb_viewport_size"
android:viewportWidth="@integer/mtrl_switch_thumb_viewport_size"
tools:ignore="NewApi">
<group
android:name="@string/mtrl_switch_thumb_group_name"
android:pivotX="@integer/mtrl_switch_thumb_viewport_center_coordinate"
android:pivotY="@integer/mtrl_switch_thumb_viewport_center_coordinate">
<path
android:name="@string/mtrl_switch_thumb_path_name"
android:fillColor="#FFFFFFFF"
android:pathData="@string/mtrl_switch_thumb_path_checked" />
</group>
</vector>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/mtrl_switch_thumb_checked"
tools:ignore="NewApi">
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@integer/mtrl_switch_thumb_pressed_duration"
android:interpolator="@interpolator/m3_sys_motion_easing_standard"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_checked"
android:valueTo="@string/mtrl_switch_thumb_path_pressed"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/mtrl_switch_thumb_checked"
tools:ignore="NewApi">
<set
android:interpolator="@interpolator/m3_sys_motion_easing_emphasized"
android:shareInterpolator="true">
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@integer/mtrl_switch_thumb_pre_morphing_duration"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_checked"
android:valueTo="@string/mtrl_switch_thumb_path_morphing"
android:valueType="pathType" />
</aapt:attr>
</target>
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:startOffset="@integer/mtrl_switch_thumb_pre_morphing_duration"
android:duration="@integer/mtrl_switch_thumb_post_morphing_duration"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_morphing"
android:valueTo="@string/mtrl_switch_thumb_path_unchecked"
android:valueType="pathType" />
</aapt:attr>
</target>
</set>
</animated-vector>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="@dimen/mtrl_switch_thumb_size"
android:height="@dimen/mtrl_switch_thumb_size"
android:viewportHeight="@integer/mtrl_switch_thumb_viewport_size"
android:viewportWidth="@integer/mtrl_switch_thumb_viewport_size"
tools:ignore="NewApi">
<group
android:name="@string/mtrl_switch_thumb_group_name"
android:pivotX="@integer/mtrl_switch_thumb_viewport_center_coordinate"
android:pivotY="@integer/mtrl_switch_thumb_viewport_center_coordinate">
<path
android:name="@string/mtrl_switch_thumb_path_name"
android:fillColor="#ffffffff"
android:pathData="@string/mtrl_switch_thumb_path_pressed" />
</group>
</vector>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/mtrl_switch_thumb_pressed"
tools:ignore="NewApi">
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@integer/mtrl_switch_thumb_pressed_duration"
android:interpolator="@interpolator/m3_sys_motion_easing_standard"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_pressed"
android:valueTo="@string/mtrl_switch_thumb_path_checked"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/mtrl_switch_thumb_pressed"
tools:ignore="NewApi">
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@integer/mtrl_switch_thumb_pressed_duration"
android:interpolator="@interpolator/m3_sys_motion_easing_emphasized"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_pressed"
android:valueTo="@string/mtrl_switch_thumb_path_unchecked"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="@dimen/mtrl_switch_thumb_size"
android:height="@dimen/mtrl_switch_thumb_size"
android:viewportHeight="@integer/mtrl_switch_thumb_viewport_size"
android:viewportWidth="@integer/mtrl_switch_thumb_viewport_size"
tools:ignore="NewApi">
<group
android:name="@string/mtrl_switch_thumb_group_name"
android:pivotX="@integer/mtrl_switch_thumb_viewport_center_coordinate"
android:pivotY="@integer/mtrl_switch_thumb_viewport_center_coordinate">
<path
android:name="@string/mtrl_switch_thumb_path_name"
android:fillColor="#FFFFFFFF"
android:pathData="@string/mtrl_switch_thumb_path_unchecked" />
</group>
</vector>

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/mtrl_switch_thumb_unchecked"
tools:ignore="NewApi">
<set
android:interpolator="@interpolator/m3_sys_motion_easing_emphasized"
android:shareInterpolator="true">
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@integer/mtrl_switch_thumb_post_morphing_duration"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_unchecked"
android:valueTo="@string/mtrl_switch_thumb_path_morphing"
android:valueType="pathType" />
</aapt:attr>
</target>
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:startOffset="@integer/mtrl_switch_thumb_post_morphing_duration"
android:duration="@integer/mtrl_switch_thumb_pre_morphing_duration"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_morphing"
android:valueTo="@string/mtrl_switch_thumb_path_checked"
android:valueType="pathType" />
</aapt:attr>
</target>
</set>
</animated-vector>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
xmlns:tools="http://schemas.android.com/tools"
android:drawable="@drawable/mtrl_switch_thumb_unchecked"
tools:ignore="NewApi">
<target android:name="@string/mtrl_switch_thumb_path_name">
<aapt:attr name="android:animation">
<objectAnimator
android:duration="@integer/mtrl_switch_thumb_pressed_duration"
android:interpolator="@interpolator/m3_sys_motion_easing_standard"
android:propertyName="pathData"
android:valueFrom="@string/mtrl_switch_thumb_path_unchecked"
android:valueTo="@string/mtrl_switch_thumb_path_pressed"
android:valueType="pathType" />
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="@dimen/mtrl_switch_track_width"
android:height="@dimen/mtrl_switch_track_height"
android:viewportWidth="@integer/mtrl_switch_track_viewport_width"
android:viewportHeight="@integer/mtrl_switch_track_viewport_height"
tools:ignore="NewApi">
<path
android:name="track"
android:fillColor="#FFFFFFFF"
android:pathData="@string/mtrl_switch_track_path" />
</vector>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:width="@dimen/mtrl_switch_track_width"
android:height="@dimen/mtrl_switch_track_height"
android:viewportWidth="@integer/mtrl_switch_track_viewport_width"
android:viewportHeight="@integer/mtrl_switch_track_viewport_height"
tools:ignore="NewApi">
<path
android:name="outline"
android:strokeColor="?attr/colorM3Outline"
android:strokeWidth="2"
android:pathData="@string/mtrl_switch_track_decoration_path" />
</vector>

View File

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:pathData="@string/m3_sys_motion_easing_emphasized_path_data" />

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="@dimen/m3_sys_motion_easing_emphasized_accelerate_control_x1"
android:controlY1="@dimen/m3_sys_motion_easing_emphasized_accelerate_control_y1"
android:controlX2="@dimen/m3_sys_motion_easing_emphasized_accelerate_control_x2"
android:controlY2="@dimen/m3_sys_motion_easing_emphasized_accelerate_control_y2"/>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="@dimen/m3_sys_motion_easing_emphasized_decelerate_control_x1"
android:controlY1="@dimen/m3_sys_motion_easing_emphasized_decelerate_control_y1"
android:controlX2="@dimen/m3_sys_motion_easing_emphasized_decelerate_control_x2"
android:controlY2="@dimen/m3_sys_motion_easing_emphasized_decelerate_control_y2"/>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="@dimen/m3_sys_motion_easing_linear_control_x1"
android:controlY1="@dimen/m3_sys_motion_easing_linear_control_y1"
android:controlX2="@dimen/m3_sys_motion_easing_linear_control_x2"
android:controlY2="@dimen/m3_sys_motion_easing_linear_control_y2"/>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="@dimen/m3_sys_motion_easing_standard_control_x1"
android:controlY1="@dimen/m3_sys_motion_easing_standard_control_y1"
android:controlX2="@dimen/m3_sys_motion_easing_standard_control_x2"
android:controlY2="@dimen/m3_sys_motion_easing_standard_control_y2"/>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="@dimen/m3_sys_motion_easing_standard_accelerate_control_x1"
android:controlY1="@dimen/m3_sys_motion_easing_standard_accelerate_control_y1"
android:controlX2="@dimen/m3_sys_motion_easing_standard_accelerate_control_x2"
android:controlY2="@dimen/m3_sys_motion_easing_standard_accelerate_control_y2"/>

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
android:controlX1="@dimen/m3_sys_motion_easing_standard_decelerate_control_x1"
android:controlY1="@dimen/m3_sys_motion_easing_standard_decelerate_control_y1"
android:controlX2="@dimen/m3_sys_motion_easing_standard_decelerate_control_x2"
android:controlY2="@dimen/m3_sys_motion_easing_standard_decelerate_control_y2"/>

View File

@ -4,17 +4,15 @@
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"
android:background="@drawable/bg_m3_bottom_bar"
tools:showIn="@layout/fragment_report_choice">
<Button
android:id="@+id/btn_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="40dp"
android:layout_margin="16dp"
style="?primaryLargeButtonStyle"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/next" />
</FrameLayout>

View File

@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<org.joinmastodon.android.ui.views.CheckableRelativeLayout 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:paddingTop="16dp"
android:paddingRight="16dp"
android:paddingLeft="16dp"
android:clipToPadding="false">
<View
android:id="@+id/checkbox"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="-4dp"
android:layout_marginTop="-8dp"
android:layout_marginEnd="12dp"
android:duplicateParentState="true"/>
<ImageView
android:id="@+id/more"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="-2dp"
android:layout_marginEnd="-2dp"
android:background="?android:selectableItemBackgroundBorderless"
android:scaleType="center"
android:tint="?colorM3OnSurfaceVariant"
android:contentDescription="@string/more_options"
android:src="@drawable/ic_more_vert_20px" />
<ImageView
android:id="@+id/avatar"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_toEndOf="@id/checkbox"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp" />
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
android:id="@+id/name_wrap"
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_toEndOf="@id/avatar"
android:layout_toStartOf="@id/more"
android:layout_marginEnd="8dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/m3_title_medium"
android:textColor="?colorM3OnSurface"
android:gravity="start|center_vertical"
tools:text="Eugen" />
<TextView
android:id="@+id/extra_text"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_marginStart="8dp"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/m3_title_medium"
android:fontFamily="sans-serif"
android:textAlignment="viewStart"
android:textColor="?colorM3OnSurface"
tools:text="boosted your cat picture" />
</org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout>
<TextView
android:id="@+id/time_and_username"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_below="@id/name_wrap"
android:layout_toEndOf="@id/avatar"
android:singleLine="true"
android:ellipsize="end"
android:textAppearance="@style/m3_title_small"
android:gravity="center_vertical"
android:textColor="?colorM3OnSurfaceVariant"
tools:text="9h ago · \@Gargron@mastodon.social"/>
</org.joinmastodon.android.ui.views.CheckableRelativeLayout>

View File

@ -3,13 +3,22 @@
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/top_progress"
android:layout_width="match_parent"
android:layout_height="4dp"
android:indeterminate="false"
android:indeterminateOnly="false"
android:max="100"
android:progressDrawable="@drawable/m3_progress"/>
<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"/>
android:background="?colorM3Surface"/>
<include layout="@layout/button_bar_one" />

View File

@ -1,9 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/top_progress"
android:layout_width="match_parent"
android:layout_height="4dp"
android:indeterminate="false"
android:indeterminateOnly="false"
android:max="100"
android:progressDrawable="@drawable/m3_progress"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
@ -16,20 +27,74 @@
<include layout="@layout/item_list_header"/>
<EditText
android:id="@+id/text"
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
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"/>
android:paddingTop="4dp"
android:paddingBottom="12dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<EditText
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="8dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textMultiLine|textCapSentences"
android:hint="@string/report_comment_hint"/>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<RelativeLayout
android:id="@+id/forward_report"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:paddingHorizontal="16dp"
android:paddingVertical="12dp"
android:background="?android:selectableItemBackground">
<org.joinmastodon.android.ui.views.M3Switch
android:id="@+id/forward_switch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginStart="16dp"
android:checked="true"/>
<TextView
android:id="@+id/forward_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@id/forward_switch"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:minHeight="24dp"
android:gravity="center_vertical"
tools:text="Forward to %s"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/forward_title"
android:layout_alignLeft="@id/forward_title"
android:layout_alignRight="@id/forward_title"
android:textAppearance="@style/m3_body_medium"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/forward_report_explanation"/>
</RelativeLayout>
</LinearLayout>
</ScrollView>
<include layout="@layout/button_bar_two"/>
<include layout="@layout/button_bar_one"/>
</LinearLayout>

View File

@ -5,6 +5,16 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/top_progress"
android:layout_width="match_parent"
android:layout_height="4dp"
android:indeterminate="false"
android:indeterminateOnly="false"
android:max="100"
android:progress="100"
android:progressDrawable="@drawable/m3_progress"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
@ -20,110 +30,162 @@
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:layout_marginHorizontal="-16dp"
android:paddingHorizontal="16dp"
android:layout_marginTop="-32dp"
android:paddingTop="32dp"
android:clipToPadding="false">
<ImageView
android:id="@+id/avatar"
android:layout_width="104dp"
android:layout_height="104dp"
android:layout_width="96dp"
android:layout_height="96dp"
android:layout_gravity="center_horizontal"
android:importantForAccessibility="no"
tools:src="#0f0"/>
<View
android:id="@+id/reported_overlay"
android:layout_width="205dp"
android:layout_height="69dp"
<TextView
android:id="@+id/reported_stamp"
android:layout_width="wrap_content"
android:layout_height="45dp"
android:layout_gravity="center"
android:elevation="2dp"
android:background="@drawable/reported_overlay"/>
android:background="@drawable/bg_reported_stamp"
android:elevation="1dp"
android:gravity="center"
android:includeFontPadding="false"
android:outlineProvider="background"
android:paddingHorizontal="12dp"
android:rotation="-10"
android:text="@string/reported"
android:textAllCaps="true"
android:textColor="?colorM3OnPrimaryContainer"
android:fontFamily="sans-serif-condensed"
android:textStyle="bold"
android:letterSpacing="-0.03"
android:singleLine="true"
android:maxWidth="300dp"
android:textSize="28dp" />
</FrameLayout>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textAppearance="@style/m3_headline_medium"
android:minHeight="36dp"
android:gravity="center_vertical"
android:textColor="?colorM3OnSurface"
tools:text="Title"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:textAppearance="@style/m3_title_medium"
android:textColor="?android:textColorSecondary"
android:textColor="?colorM3OnSurfaceVariant"
android:minHeight="24dp"
android:gravity="center_vertical"
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
<FrameLayout
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"/>
android:layout_height="40dp"
android:background="@drawable/bg_button_m3_outlined">
<TextView
android:id="@+id/unfollow_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:foreground="@null"
android:drawablePadding="8dp"
android:clickable="false"
android:focusable="false"
tools:text="@string/unfollow_user"
android:duplicateParentState="true"
style="@style/Widget.Mastodon.M3.Button.Outlined"/>
</FrameLayout>
<TextView
android:id="@+id/mute_title"
android:id="@+id/unfollow_explanation"
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"/>
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:layout_marginHorizontal="8dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/report_unfollow_explanation"/>
<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
<FrameLayout
android:id="@+id/block_btn"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/bg_button_m3_outlined">
<TextView
android:id="@+id/block_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:foreground="@null"
android:drawablePadding="8dp"
android:clickable="false"
android:focusable="false"
tools:text="@string/block_user"
android:duplicateParentState="true"
style="@style/Widget.Mastodon.M3.Button.Outlined"/>
</FrameLayout>
<TextView
android:id="@+id/block_explanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
style="?secondaryLargeButtonStyle"
android:text="@string/do_block"/>
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:layout_marginHorizontal="8dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/block_user_explain"/>
<FrameLayout
android:id="@+id/mute_btn"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@drawable/bg_button_m3_outlined">
<TextView
android:id="@+id/mute_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@null"
android:foreground="@null"
android:drawablePadding="8dp"
android:clickable="false"
android:focusable="false"
tools:text="@string/mute_user"
android:duplicateParentState="true"
style="@style/Widget.Mastodon.M3.Button.Outlined"/>
</FrameLayout>
<TextView
android:id="@+id/mute_explanation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:layout_marginHorizontal="8dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/mute_user_explain"/>
</LinearLayout>

View File

@ -6,10 +6,19 @@
android:orientation="vertical"
android:id="@+id/appkit_loader_root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?android:colorBackground">
android:background="?colorM3Surface">
<include layout="@layout/appkit_toolbar"/>
<ProgressBar
android:id="@+id/top_progress"
android:layout_width="match_parent"
android:layout_height="4dp"
android:indeterminate="false"
android:indeterminateOnly="false"
android:max="100"
android:progressDrawable="@drawable/m3_progress"/>
<FrameLayout
android:id="@+id/appkit_loader_content"
android:layout_width="match_parent"
@ -32,6 +41,6 @@
</FrameLayout>
<include layout="@layout/button_bar_two"/>
<include layout="@layout/button_bar_one"/>
</me.grishka.appkit.views.FragmentRootLinearLayout>

View File

@ -4,28 +4,19 @@
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/step_counter"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:textAppearance="@style/m3_title_medium"
android:textColor="?android:textColorSecondary"
tools:text="@string/step_x_of_n"/>
android:paddingHorizontal="16dp"
android:paddingTop="14dp"
android:paddingBottom="16dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginBottom="8dp"
android:textAppearance="@style/m3_headline_medium"
android:minHeight="36dp"
android:gravity="center_vertical"
android:textColor="?colorM3OnSurface"
tools:text="Title"/>
<TextView
@ -33,7 +24,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_medium"
android:textColor="?android:textColorSecondary"
android:textColor="?colorM3OnSurfaceVariant"
android:minHeight="24dp"
android:gravity="center_vertical"
tools:text="Subtitle"/>
</LinearLayout>

View File

@ -1,39 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<org.joinmastodon.android.ui.views.CheckableLinearLayout 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">
android:orientation="horizontal"
android:paddingVertical="8dp"
android:paddingEnd="24dp"
android:gravity="center_vertical">
<ImageView
<View
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"/>
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginHorizontal="12dp"
android:duplicateParentState="true"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<org.joinmastodon.android.ui.views.LinkedTextView
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"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:textSize="16sp"
android:minHeight="24dp"
android:gravity="center_vertical"
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"
android:textColor="?colorM3OnSurfaceVariant"
android:textSize="14sp"
android:minHeight="20dp"
android:gravity="center_vertical"
tools:text="Subtitle"/>
</RelativeLayout>
</LinearLayout>
</org.joinmastodon.android.ui.views.CheckableLinearLayout>

View File

@ -28,12 +28,13 @@
android:ellipsize="end"
tools:text="@string/theme_true_black"/>
<Switch
<org.joinmastodon.android.ui.views.M3Switch
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginEnd="12dp"
android:duplicateParentState="false"
android:focusable="false"
android:clickable="false"/>

View File

@ -18,6 +18,7 @@
android:src="@drawable/ic_visibility_off_24px"/>
<TextView
android:id="@+id/sensitive_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"

View File

@ -44,6 +44,7 @@
<attr name="colorM3OnErrorContainer" format="color"/>
<attr name="colorM3PrimaryInverse" format="color"/>
<attr name="colorSensitiveOverlay" format="color"/>
<attr name="colorWhite" format="color"/>
<attr name="primaryLargeButtonStyle" format="reference"/>
<attr name="secondaryLargeButtonStyle" format="reference"/>

View File

@ -0,0 +1,115 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- MaterialSwitch-specific state to represent presence of a thumb icon. -->
<attr name="state_with_icon" format="boolean" />
<!-- Generated from token set (md.comp.switch) in context (platform=android, audience=3p). -->
<!-- Enabled - Icon -->
<macro name="m3_comp_switch_selected_icon_color">?attr/colorM3OnPrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_icon_color">?attr/colorM3SurfaceVariant</macro>
<!-- Enabled - Track -->
<dimen name="m3_comp_switch_track_height">32dp</dimen>
<dimen name="m3_comp_switch_track_width">52dp</dimen>
<macro name="m3_comp_switch_unselected_track_outline_color">?attr/colorM3Outline</macro>
<macro name="m3_comp_switch_selected_track_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_unselected_track_color">?attr/colorM3SurfaceVariant</macro>
<!-- Enabled - Handle -->
<macro name="m3_comp_switch_selected_handle_color">?attr/colorM3OnPrimary</macro>
<macro name="m3_comp_switch_unselected_handle_color">?attr/colorM3Outline</macro>
<!-- Disabled - Icon -->
<macro name="m3_comp_switch_disabled_selected_icon_color">?attr/colorM3OnSurface</macro>
<item name="m3_comp_switch_disabled_selected_icon_opacity" format="float" type="dimen">0.38</item>
<macro name="m3_comp_switch_disabled_unselected_icon_color">?attr/colorM3SurfaceVariant</macro>
<item name="m3_comp_switch_disabled_unselected_icon_opacity" format="float" type="dimen">0.38</item>
<!-- Disabled - Track -->
<item name="m3_comp_switch_disabled_track_opacity" format="float" type="dimen">0.12</item>
<macro name="m3_comp_switch_disabled_selected_track_color">?attr/colorM3OnSurface</macro>
<macro name="m3_comp_switch_disabled_unselected_track_color">?attr/colorM3SurfaceVariant</macro>
<macro name="m3_comp_switch_disabled_unselected_track_outline_color">?attr/colorM3OnSurface</macro>
<!-- Disabled - Handle -->
<item name="m3_comp_switch_disabled_unselected_handle_opacity" format="float" type="dimen">0.38</item>
<item name="m3_comp_switch_disabled_selected_handle_opacity" format="float" type="dimen">1</item>
<macro name="m3_comp_switch_disabled_selected_handle_color">?attr/colorM3Surface</macro>
<macro name="m3_comp_switch_disabled_unselected_handle_color">?attr/colorM3OnSurface</macro>
<!-- Hovered - Icon -->
<macro name="m3_comp_switch_selected_hover_icon_color">?attr/colorM3OnPrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_hover_icon_color">?attr/colorM3SurfaceVariant</macro>
<!-- Hovered - Track -->
<macro name="m3_comp_switch_selected_hover_track_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_selected_hover_state_layer_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_unselected_hover_track_color">?attr/colorM3SurfaceVariant</macro>
<macro name="m3_comp_switch_unselected_hover_track_outline_color">?attr/colorM3Outline</macro>
<macro name="m3_comp_switch_unselected_hover_state_layer_color">?attr/colorM3OnSurface</macro>
<!-- Hovered - Handle -->
<macro name="m3_comp_switch_selected_hover_handle_color">?attr/colorM3PrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_hover_handle_color">?attr/colorM3OnSurfaceVariant</macro>
<!-- Focused - Icon -->
<macro name="m3_comp_switch_selected_focus_icon_color">?attr/colorM3OnPrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_focus_icon_color">?attr/colorM3SurfaceVariant</macro>
<!-- Focused - Track -->
<macro name="m3_comp_switch_selected_focus_track_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_selected_focus_state_layer_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_unselected_focus_track_color">?attr/colorM3SurfaceVariant</macro>
<macro name="m3_comp_switch_unselected_focus_track_outline_color">?attr/colorM3Outline</macro>
<macro name="m3_comp_switch_unselected_focus_state_layer_color">?attr/colorM3OnSurface</macro>
<!-- Focused - Handle -->
<macro name="m3_comp_switch_selected_focus_handle_color">?attr/colorM3PrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_focus_handle_color">?attr/colorM3OnSurfaceVariant</macro>
<!-- Pressed (rippple) - Icon -->
<macro name="m3_comp_switch_selected_pressed_icon_color">?attr/colorM3OnPrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_pressed_icon_color">?attr/colorM3SurfaceVariant</macro>
<!-- Pressed (rippple) - Track -->
<macro name="m3_comp_switch_selected_pressed_track_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_selected_pressed_state_layer_color">?attr/colorM3Primary</macro>
<macro name="m3_comp_switch_unselected_pressed_track_color">?attr/colorM3SurfaceVariant</macro>
<macro name="m3_comp_switch_unselected_pressed_track_outline_color">?attr/colorM3Outline</macro>
<macro name="m3_comp_switch_unselected_pressed_state_layer_color">?attr/colorM3OnSurface</macro>
<!-- Pressed (rippple) - Handle -->
<macro name="m3_comp_switch_selected_pressed_handle_color">?attr/colorM3PrimaryContainer</macro>
<macro name="m3_comp_switch_unselected_pressed_handle_color">?attr/colorM3OnSurfaceVariant</macro>
<dimen name="mtrl_switch_thumb_size">32dp</dimen>
<dimen name="mtrl_switch_track_width">@dimen/m3_comp_switch_track_width</dimen>
<dimen name="mtrl_switch_track_height">@dimen/m3_comp_switch_track_height</dimen>
<dimen name="mtrl_switch_text_padding">16dp</dimen>
<!-- Below path data are used to morph the thumb shape between different
states. All of them start from the orientation of 270 degrees, draw 90
degrees clockwise, draw a horizontal line (may have zero length if it's a
circle), draw 180 degrees clockwise, draw another horizontal line (may
have zero length if it's a circle), and then draw the final 90 degrees to
finish a circle or a capsule. -->
<!-- Path data to draw a larger thumb circle when the thumb is pressed. -->
<string name="mtrl_switch_thumb_path_pressed" translatable="false">M2,16 A14,14 0 0,1 16,2 H16 A14,14 0 0,1 16,30 H16 A14,14 0 0,1 2,16</string>
<!-- Path data to draw a thumb circle when the switch is checked. -->
<string name="mtrl_switch_thumb_path_checked" translatable="false">M4,16 A12,12 0 0,1 16,4 H16 A12,12 0 0,1 16,28 H16 A12,12 0 0,1 4,16</string>
<!-- Path data to draw a smaller thumb circle when the switch is unchecked. -->
<string name="mtrl_switch_thumb_path_unchecked" translatable="false">M8,16 A8,8 0 0,1 16,8 H16 A8,8 0 0,1 16,24 H16 A8,8 0 0,1 8,16</string>
<!-- Path data to draw a morphed thumb circle when the switch's checked state is changing. -->
<string name="mtrl_switch_thumb_path_morphing" translatable="false">M0,16 A11,11 0 0,1 11,5 H21 A11,11 0 0,1 21,27 H11 A11,11 0 0,1 0,16</string>
<string name="mtrl_switch_thumb_group_name" translatable="false">circle_group</string>
<string name="mtrl_switch_thumb_path_name" translatable="false">circle</string>
<!-- Path data to draw the switch track. -->
<string name="mtrl_switch_track_path" translatable="false">M0,16 A16,16 0 0,1 16,0 H36 A16,16 0 0,1 36,32 H16 A16,16 0 0,1 0,16</string>
<!-- Path data to draw the switch track decor. -->
<string name="mtrl_switch_track_decoration_path" translatable="false">M1,16 A15,15 0 0,1 16,1 H36 A15,15 0 0,1 36,31 H16 A15,15 0 0,1 1,16</string>
<!-- Note: The following duration values are different from the design spec,
since the thumb position animation duration is hard-coded in
SwitchCompat and we have no way to override it. Therefore the
following values are set according to the position animation
duration (250ms). -->
<integer name="mtrl_switch_thumb_motion_duration">@integer/m3_sys_motion_duration_medium1</integer>
<integer name="mtrl_switch_thumb_pre_morphing_duration">@integer/m3_sys_motion_duration_short2</integer>
<integer name="mtrl_switch_thumb_post_morphing_duration">@integer/m3_sys_motion_duration_short3</integer>
<integer name="mtrl_switch_thumb_pressed_duration">@integer/m3_sys_motion_duration_short2</integer>
<integer name="mtrl_switch_thumb_viewport_size">32</integer>
<integer name="mtrl_switch_thumb_viewport_center_coordinate">16</integer>
<integer name="mtrl_switch_track_viewport_width">52</integer>
<integer name="mtrl_switch_track_viewport_height">32</integer>
</resources>

View File

@ -8,7 +8,7 @@
<string name="next">Next</string>
<string name="loading_instance">Retrieving server info…</string>
<string name="error">Error</string>
<string name="not_a_mastodon_instance">%s doesn\'t appear to be a Mastodon server.</string>
<string name="not_a_mastodon_instance">%s doesnt appear to be a Mastodon server.</string>
<string name="ok">OK</string>
<string name="preparing_auth">Preparing for authentication…</string>
<string name="finishing_auth">Finishing authentication…</string>
@ -150,16 +150,16 @@
<item quantity="other">Discussed %d times</item>
</plurals>
<string name="report_title">Report %s</string>
<string name="report_choose_reason">What\'s wrong with this post?</string>
<string name="report_choose_reason_account">What\'s wrong with %s?</string>
<string name="report_choose_reason">Whats wrong with this post?</string>
<string name="report_choose_reason_account">Whats wrong with %s?</string>
<string name="report_choose_reason_subtitle">Select the best match</string>
<string name="report_reason_personal">I don\'t like it</string>
<string name="report_reason_personal">I dont 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">Its 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">Its 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>
@ -168,14 +168,14 @@
<string name="report_comment_title">Is there anything else we should know?</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="report_sent_title">Thanks for reporting, well 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 boosts 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 they 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>
<string name="mute_user_explain">You will not see their posts. They can still follow you and see your posts and will not know that they are muted.</string>
<string name="block_user_explain">You will not see their posts. They will not be able to see your posts or follow you. They will be able to tell that they are blocked.</string>
<string name="report_personal_title">Dont want to see this?</string>
<string name="report_personal_subtitle">Here are your options for controlling what you see on Mastodon:</string>
<string name="back">Back</string>
<string name="instance_catalog_title">Mastodon is made of users on different servers.</string>
<string name="instance_catalog_subtitle">Pick a server based on your interests, region, or a general purpose one. You can still connect with everyone, regardless of server.</string>
@ -205,12 +205,12 @@
<string name="category_tech">Tech</string>
<string name="confirm_email_title">Check Your Inbox</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Tap the link we sent you to verify %s. We\'ll wait right here.</string>
<string name="confirm_email_didnt_get">Didn\'t get a link?</string>
<string name="confirm_email_subtitle">Tap the link we sent you to verify %s. Well wait right here.</string>
<string name="confirm_email_didnt_get">Didnt get a link?</string>
<string name="resend">Resend</string>
<string name="open_email_app">Open email app</string>
<string name="resent_email">Confirmation email sent</string>
<string name="compose_hint">Type or paste what\'s on your mind</string>
<string name="compose_hint">Type or paste whats on your mind</string>
<string name="content_warning">Content warning</string>
<string name="add_image_description">Add image description…</string>
<string name="retry_upload">Retry upload</string>
@ -235,8 +235,8 @@
<string name="choose_account">Choose account</string>
<string name="err_not_logged_in">Please log into Mastodon first</string>
<plurals name="cant_add_more_than_x_attachments">
<item quantity="one">You can\'t add more than %d media attachment</item>
<item quantity="other">You can\'t add more than %d media attachments</item>
<item quantity="one">You cant add more than %d media attachment</item>
<item quantity="other">You cant add more than %d media attachments</item>
</plurals>
<string name="media_attachment_unsupported_type">File %s is of an unsupported type</string>
<string name="media_attachment_too_big">File %1$s exceeds the size limit of %2$s MB</string>
@ -269,8 +269,7 @@
<string name="media_cache_cleared">Media cache cleared</string>
<string name="confirm_log_out">Log out of %s?</string>
<string name="sensitive_content_explain">The author marked this media as sensitive.</string>
<string name="media_hidden">Tap to reveal</string>
<string name="avatar_description">Go to %s\'s profile</string>
<string name="avatar_description">Go to %ss profile</string>
<string name="more_options">More options</string>
<string name="reveal_content">Reveal content</string>
<string name="hide_content">Hide content</string>
@ -289,7 +288,7 @@
<string name="media_viewer">Media viewer</string>
<string name="follow_user">Follow %s</string>
<string name="unfollowed_user">Unfollowed %s</string>
<string name="followed_user">You\'re now following %s</string>
<string name="followed_user">Youre now following %s</string>
<string name="following_user_requested">Requested to follow %s</string>
<string name="open_in_browser">Open in browser</string>
<string name="hide_boosts_from_user">Hide boosts from %s</string>
@ -307,7 +306,7 @@
<string name="error_saving_file">Error saving file</string>
<string name="file_saved">File saved</string>
<string name="downloading">Downloading…</string>
<string name="no_app_to_handle_action">There\'s no app to handle this action</string>
<string name="no_app_to_handle_action">Theres no app to handle this action</string>
<string name="local_timeline">Community</string>
<string name="trending_posts_info_banner">These are the posts gaining traction in your corner of Mastodon.</string>
<string name="trending_hashtags_info_banner">These are the hashtags gaining traction in your corner of Mastodon.</string>
@ -401,7 +400,7 @@
<string name="login_title">Welcome Back</string>
<string name="login_subtitle">Log in with the server where you created your account.</string>
<string name="server_url">Server URL</string>
<string name="signup_random_server_explain">We\'ll pick a server based on your language if you continue without making a selection.</string>
<string name="signup_random_server_explain">Well pick a server based on your language if you continue without making a selection.</string>
<string name="server_filter_any_language">Any Language</string>
<string name="server_filter_instant_signup">Instant Sign-up</string>
<string name="server_filter_manual_review">Manual Review</string>
@ -414,7 +413,7 @@
<string name="server_filter_region_oceania">Oceania</string>
<string name="not_accepting_new_members">Not accepting new members</string>
<string name="category_special_interests">Special Interests</string>
<string name="signup_passwords_dont_match">Passwords don\'t match</string>
<string name="signup_passwords_dont_match">Passwords dont match</string>
<string name="pick_server_for_me">Pick for me</string>
<string name="profile_add_row">Add row</string>
<string name="profile_setup">Profile setup</string>
@ -423,14 +422,14 @@
<string name="popular_on_mastodon">Popular on Mastodon</string>
<string name="follow_all">Follow all</string>
<string name="server_rules_disagree">Disagree</string>
<string name="privacy_policy_explanation">TL;DR: We don\'t collect or process anything.</string>
<string name="privacy_policy_explanation">TL;DR: We dont collect or process anything.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Disagree with %s</string>
<string name="profile_bio">Bio</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Following users…</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s doesn\'t allow signups from %2$s. Try a different one or &lt;a>pick a different server&lt;/a>.</string>
<string name="signup_email_domain_blocked">%1$s doesnt allow signups from %2$s. Try a different one or &lt;a>pick a different server&lt;/a>.</string>
<string name="signup_username_taken">This username is taken.</string>
<string name="spoiler_show">Show anyway</string>
<string name="spoiler_hide">Re-hide</string>
@ -482,7 +481,7 @@
<string name="edit_post">Edit post</string>
<string name="no_verified_link">No verified link</string>
<string name="compose_autocomplete_emoji_empty">Browse emoji</string>
<string name="compose_autocomplete_users_empty">Find who you\'re looking for</string>
<string name="compose_autocomplete_users_empty">Find who youre looking for</string>
<string name="no_search_results">Could not find anything for these search terms</string>
<string name="language">Language</string>
<string name="language_default">Default</string>
@ -490,4 +489,17 @@
<string name="language_detecting">Detecting language</string>
<string name="language_cant_detect">Unable to detect language</string>
<string name="language_detected">Detected</string>
<string name="media_hidden">Media hidden</string>
<string name="post_hidden">Post hidden</string>
<string name="report_title_post">Report post</string>
<string name="forward_report_explanation">The account is from another server. Send an anonymized copy of this report there as well?</string>
<!-- %s is the server domain -->
<string name="forward_report_to_server">Forward to %s</string>
<!-- Shown on the "stamp" on the screen that appears after you report a post/user. Please keep the translation short, preferably a single word -->
<string name="reported">Reported</string>
<string name="report_unfollow_explanation">To not see their posts in your home feed anymore, unfollow them.</string>
<string name="muted_user">Muted %s</string>
<string name="report_sent_already_blocked">Youve already blocked this user, so theres nothing else you need to do while we review your report.</string>
<string name="report_personal_already_blocked">Youve already blocked this user, so theres nothing else you need to do.\n\nThanks for helping keep Mastodon a safe place for everyone!</string>
<string name="blocked_user">Blocked %s</string>
</resources>

View File

@ -37,6 +37,7 @@
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
<item name="android:popupMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
<item name="android:actionOverflowMenuStyle">@style/Widget.Mastodon.PopupMenu</item>
<item name="android:switchStyle">@style/Widget.Mastodon.M3.Switch</item>
<!-- M3 colors -->
<item name="colorM3Primary">@color/m3_sys_light_primary</item>
@ -66,6 +67,7 @@
<item name="colorM3ErrorContainer">#F9DEDC</item>
<item name="colorM3OnErrorContainer">#410E0B</item>
<item name="colorM3PrimaryInverse">@color/m3_sys_dark_primary</item>
<item name="colorWhite">#FFF</item>
<item name="colorWindowBackground">?colorM3Background</item>
<item name="android:statusBarColor">?colorM3Background</item>
@ -143,6 +145,7 @@
<item name="colorM3ErrorContainer">#8C1D18</item>
<item name="colorM3OnErrorContainer">#F9DEDC</item>
<item name="colorM3PrimaryInverse">@color/m3_sys_light_primary</item>
<item name="colorWhite">#000</item>
<item name="colorWindowBackground">?colorM3Background</item>
<item name="android:statusBarColor">?colorM3Background</item>
@ -358,6 +361,19 @@
<item name="android:disabledAlpha">0</item>
</style>
<style name="Widget.Mastodon.M3.Switch" parent="">
<item name="android:thumb">@drawable/mtrl_switch_thumb</item>
<item name="android:track">@drawable/mtrl_switch_track</item>
<item name="android:foreground">@drawable/mtrl_switch_track_decoration</item>
<!-- <item name="android:paddingLeft">-10dp</item>-->
<item name="android:thumbTint">@color/mtrl_switch_thumb_tint</item>
<item name="android:trackTint">@color/mtrl_switch_track_tint</item>
<item name="android:foregroundTint">@color/mtrl_switch_track_decoration_tint</item>
<!-- <item name="android:textOn"></item>-->
<!-- <item name="android:textOff"></item>-->
<item name="android:showText">false</item>
</style>
<style name="alert_title">
<item name="android:textColor">?android:textColorPrimary</item>
<item name="android:textSize">24dp</item>

View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2022 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<!-- AUTOGENERATED FILE. DO NOT MODIFY. -->
<!-- Version: v0.162 -->
<resources>
<!-- Generated from token set (md.sys.motion) in context (platform=android, audience=3p). -->
<!-- Easing -->
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_emphasized" translatable="false">path(M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1)</string>
<!-- Vector path used in <pathInterpolator> resources. -->
<string name="m3_sys_motion_easing_emphasized_path_data" translatable="false">M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1</string>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_emphasized_accelerate" translatable="false">cubic-bezier(0.3, 0, 0.8, 0.2)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_emphasized_accelerate_control_x1" format="float" type="dimen">0.3</item>
<item name="m3_sys_motion_easing_emphasized_accelerate_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_emphasized_accelerate_control_x2" format="float" type="dimen">0.8</item>
<item name="m3_sys_motion_easing_emphasized_accelerate_control_y2" format="float" type="dimen">0.2</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_emphasized_decelerate" translatable="false">cubic-bezier(0.1, 0.7, 0.1, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_emphasized_decelerate_control_x1" format="float" type="dimen">0.1</item>
<item name="m3_sys_motion_easing_emphasized_decelerate_control_y1" format="float" type="dimen">0.7</item>
<item name="m3_sys_motion_easing_emphasized_decelerate_control_x2" format="float" type="dimen">0.1</item>
<item name="m3_sys_motion_easing_emphasized_decelerate_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_standard" translatable="false">cubic-bezier(0.2, 0, 0, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_standard_control_x1" format="float" type="dimen">0.2</item>
<item name="m3_sys_motion_easing_standard_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_standard_control_x2" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_standard_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_standard_accelerate" translatable="false">cubic-bezier(0.3, 0, 1, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_standard_accelerate_control_x1" format="float" type="dimen">0.3</item>
<item name="m3_sys_motion_easing_standard_accelerate_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_standard_accelerate_control_x2" format="float" type="dimen">1</item>
<item name="m3_sys_motion_easing_standard_accelerate_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_standard_decelerate" translatable="false">cubic-bezier(0, 0, 0, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_standard_decelerate_control_x1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_standard_decelerate_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_standard_decelerate_control_x2" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_standard_decelerate_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_legacy" translatable="false">cubic-bezier(0.4, 0, 0.2, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_legacy_control_x1" format="float" type="dimen">0.4</item>
<item name="m3_sys_motion_easing_legacy_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_legacy_control_x2" format="float" type="dimen">0.2</item>
<item name="m3_sys_motion_easing_legacy_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_legacy_accelerate" translatable="false">cubic-bezier(0.4, 0, 1, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_legacy_accelerate_control_x1" format="float" type="dimen">0.4</item>
<item name="m3_sys_motion_easing_legacy_accelerate_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_legacy_accelerate_control_x2" format="float" type="dimen">1</item>
<item name="m3_sys_motion_easing_legacy_accelerate_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_legacy_decelerate" translatable="false">cubic-bezier(0, 0, 0.2, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_legacy_decelerate_control_x1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_legacy_decelerate_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_legacy_decelerate_control_x2" format="float" type="dimen">0.2</item>
<item name="m3_sys_motion_easing_legacy_decelerate_control_y2" format="float" type="dimen">1</item>
<!-- Easing string used in Material's MotionUtils class. -->
<string name="m3_sys_motion_easing_linear" translatable="false">cubic-bezier(0, 0, 1, 1)</string>
<!-- Control points used in <pathInterpolator> resources. -->
<item name="m3_sys_motion_easing_linear_control_x1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_linear_control_y1" format="float" type="dimen">0</item>
<item name="m3_sys_motion_easing_linear_control_x2" format="float" type="dimen">1</item>
<item name="m3_sys_motion_easing_linear_control_y2" format="float" type="dimen">1</item>
<!-- Duration -->
<integer name="m3_sys_motion_duration_short1">50</integer>
<integer name="m3_sys_motion_duration_short2">100</integer>
<integer name="m3_sys_motion_duration_short3">150</integer>
<integer name="m3_sys_motion_duration_short4">200</integer>
<integer name="m3_sys_motion_duration_medium1">250</integer>
<integer name="m3_sys_motion_duration_medium2">300</integer>
<integer name="m3_sys_motion_duration_medium3">350</integer>
<integer name="m3_sys_motion_duration_medium4">400</integer>
<integer name="m3_sys_motion_duration_long1">450</integer>
<integer name="m3_sys_motion_duration_long2">500</integer>
<integer name="m3_sys_motion_duration_long3">550</integer>
<integer name="m3_sys_motion_duration_long4">600</integer>
<integer name="m3_sys_motion_duration_extra_long1">700</integer>
<integer name="m3_sys_motion_duration_extra_long2">800</integer>
<integer name="m3_sys_motion_duration_extra_long3">900</integer>
<integer name="m3_sys_motion_duration_extra_long4">1000</integer>
<!-- Style -->
<!-- Linear motion path. -->
<integer name="m3_sys_motion_path">0</integer>
</resources>