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