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