1 package com.android.documentsui.sorting;
2 
3 import static com.android.documentsui.base.SharedMinimal.TAG;
4 
5 import android.app.Dialog;
6 import android.content.Context;
7 import android.os.Bundle;
8 import android.util.Log;
9 import android.view.View;
10 import android.view.ViewGroup;
11 import android.widget.AdapterView;
12 import android.widget.ArrayAdapter;
13 import android.widget.CheckedTextView;
14 import android.widget.FrameLayout;
15 import android.widget.ListView;
16 
17 import androidx.annotation.StringRes;
18 import androidx.fragment.app.DialogFragment;
19 import androidx.fragment.app.FragmentManager;
20 
21 import com.android.documentsui.R;
22 import com.android.documentsui.sorting.SortDimension.SortDirection;
23 import com.android.documentsui.sorting.SortModel.SortDimensionId;
24 
25 import com.google.android.material.bottomsheet.BottomSheetBehavior;
26 import com.google.android.material.bottomsheet.BottomSheetDialog;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 
31 public class SortListFragment extends DialogFragment {
32 
33     private static final String TAG_MODEL = "sorting_model";
34     private static final String TAG_SORTING_LIST = "sorting_list";
35 
36     private SortModel mModel;
37     private List<SortItem> mSortingList;
38 
show(FragmentManager fm, SortModel model)39     public static void show(FragmentManager fm, SortModel model) {
40         if (fm.isStateSaved()) {
41             Log.w(TAG, "Skip show sort dialog because state saved");
42             return;
43         }
44 
45         if (fm.findFragmentByTag(TAG_SORTING_LIST) == null) {
46             SortListFragment fragment = new SortListFragment();
47             Bundle args = new Bundle();
48             args.putParcelable(TAG_MODEL, model);
49             fragment.setArguments(args);
50             fragment.show(fm, TAG_SORTING_LIST);
51         }
52     }
53 
SortListFragment()54     public SortListFragment() {
55         super();
56     }
57 
onItemClicked(AdapterView<?> parent, View view, int position, long id)58     private void onItemClicked (AdapterView<?> parent, View view, int position, long id) {
59         SortItem item = mSortingList.get(position);
60         mModel.sortByUser(item.id, item.direction);
61         getDialog().dismiss();
62     }
63 
setupSortingList()64     private void setupSortingList() {
65         mSortingList = new ArrayList<>();
66         for (int i = 0; i < mModel.getSize(); ++i) {
67             SortDimension dimension = mModel.getDimensionAt(i);
68             if (dimension.getSortCapability() != SortDimension.SORT_CAPABILITY_NONE) {
69                 switch (dimension.getId()) {
70                     case SortModel.SORT_DIMENSION_ID_TITLE:
71                     case SortModel.SORT_DIMENSION_ID_FILE_TYPE:
72                         addBothDirectionDimension(dimension, true);
73                         break;
74                     case SortModel.SORT_DIMENSION_ID_DATE:
75                     case SortModel.SORT_DIMENSION_ID_SIZE:
76                         addBothDirectionDimension(dimension, false);
77                         break;
78                     default:
79                         mSortingList.add(new SortItem(dimension));
80                         break;
81                 }
82             }
83         }
84     }
85 
addBothDirectionDimension(SortDimension source, boolean ascendingFirst)86     private void addBothDirectionDimension(SortDimension source, boolean ascendingFirst) {
87         SortItem ascending = new SortItem(source.getId(),
88                 SortDimension.SORT_DIRECTION_ASCENDING,
89                 getSheetLabelId(source, SortDimension.SORT_DIRECTION_ASCENDING));
90         SortItem descending = new SortItem(source.getId(),
91                 SortDimension.SORT_DIRECTION_DESCENDING,
92                 getSheetLabelId(source, SortDimension.SORT_DIRECTION_DESCENDING));
93         mSortingList.add(ascendingFirst ? ascending : descending);
94         mSortingList.add(ascendingFirst ? descending : ascending);
95     }
96 
getSheetLabelId(SortDimension dimension, @SortDirection int direction)97     public static @StringRes int getSheetLabelId(SortDimension dimension, @SortDirection int direction) {
98         boolean isAscending = direction == SortDimension.SORT_DIRECTION_ASCENDING;
99         switch (dimension.getId()) {
100             case SortModel.SORT_DIMENSION_ID_TITLE:
101                 return isAscending ? R.string.sort_dimension_name_ascending :
102                         R.string.sort_dimension_name_descending;
103             case SortModel.SORT_DIMENSION_ID_DATE:
104                 return isAscending ? R.string.sort_dimension_date_ascending :
105                         R.string.sort_dimension_date_descending;
106             case SortModel.SORT_DIMENSION_ID_FILE_TYPE:
107                 return isAscending ? R.string.sort_dimension_file_type_ascending :
108                         R.string.sort_dimension_file_type_descending;
109             case SortModel.SORT_DIMENSION_ID_SIZE:
110                 return isAscending ? R.string.sort_dimension_size_ascending :
111                         R.string.sort_dimension_size_descending;
112             default:
113                 return dimension.getLabelId();
114         }
115     }
116 
117     @Override
onCreateDialog(Bundle savedInstanceState)118     public Dialog onCreateDialog(Bundle savedInstanceState) {
119         if (savedInstanceState == null) {
120             Bundle args = getArguments();
121             mModel = args.getParcelable(TAG_MODEL);
122         } else {
123             mModel = savedInstanceState.getParcelable(TAG_MODEL);
124         }
125         setupSortingList();
126 
127         BottomSheetDialog dialog =
128                 new BottomSheetDialog(getContext());
129         dialog.setContentView(R.layout.dialog_sorting);
130 
131         // Workaround for solve issue about dialog not full expanded when landscape.
132         FrameLayout bottomSheet = (FrameLayout)
133                 dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
134         BottomSheetBehavior.from(bottomSheet)
135                 .setState(BottomSheetBehavior.STATE_EXPANDED);
136 
137         ListView listView = dialog.findViewById(R.id.sorting_dialog_list);
138 
139         listView.setAdapter(new SortingListAdapter(getContext(), mSortingList));
140         listView.setOnItemClickListener(this::onItemClicked);
141 
142         return dialog;
143     }
144 
145     @Override
onSaveInstanceState(Bundle outState)146     public void onSaveInstanceState(Bundle outState) {
147         super.onSaveInstanceState(outState);
148         outState.putParcelable(TAG_MODEL, mModel);
149     }
150 
151     private class SortingListAdapter extends ArrayAdapter<SortItem> {
152 
SortingListAdapter(Context context, List<SortItem> list)153         public SortingListAdapter(Context context, List<SortItem> list) {
154             super(context, R.layout.sort_list_item, list);
155         }
156 
157         @Override
getView(int position, View convertView, ViewGroup parent)158         public View getView(int position, View convertView, ViewGroup parent) {
159             View view = super.getView(position, convertView, parent);
160             final SortItem item = getItem(position);
161             final CheckedTextView text = view.findViewById(android.R.id.text1);
162             text.setText(getString(item.labelId));
163 
164             boolean selected = item.id == mModel.getSortedDimensionId()
165                     && item.direction == mModel.getCurrentSortDirection();
166             text.setChecked(selected);
167             return view;
168         }
169     }
170 
171     private static class SortItem {
172 
173         @SortDimensionId final int id;
174         @SortDirection final int direction;
175         @StringRes final int labelId;
176 
SortItem(SortDimension dimension)177         SortItem(SortDimension dimension) {
178             id = dimension.getId();
179             direction = dimension.getDefaultSortDirection();
180             labelId = dimension.getLabelId();
181         }
182 
SortItem(@ortDimensionId int id, @SortDirection int direction, @StringRes int labelId)183         SortItem(@SortDimensionId int id, @SortDirection int direction, @StringRes int labelId) {
184             this.id = id;
185             this.direction = direction;
186             this.labelId = labelId;
187         }
188     }
189 }
190