Loading app/ui/src/main/java/com/fsck/k9/activity/ChooseFolder.java +134 −68 Original line number Diff line number Diff line Loading @@ -9,19 +9,27 @@ import java.util.List; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Filter; import android.widget.Filterable; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.SearchView; import android.widget.TextView; import com.fsck.k9.Account; import com.fsck.k9.Account.FolderMode; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.activity.FolderListFilter.FolderAdapter; import com.fsck.k9.controller.MessageReference; import com.fsck.k9.ui.R; import com.fsck.k9.controller.MessagingController; Loading @@ -29,6 +37,10 @@ import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.SimpleMessagingListener; import com.fsck.k9.mail.Folder; import com.fsck.k9.mailstore.LocalFolder; import com.fsck.k9.ui.folders.FolderIconProvider; import timber.log.Timber; import static java.util.Collections.emptyList; public class ChooseFolder extends K9ListActivity { Loading @@ -42,14 +54,14 @@ public class ChooseFolder extends K9ListActivity { public static final String RESULT_FOLDER_DISPLAY_NAME = "folderDisplayName"; String currentFolder; String mSelectFolder; Account mAccount; MessageReference mMessageReference; ArrayAdapter<FolderDisplayData> mAdapter; private String currentFolder; private String mSelectFolder; private Account mAccount; private MessageReference mMessageReference; private FolderListAdapter mAdapter; private ChooseFolderHandler mHandler = new ChooseFolderHandler(); boolean mHideCurrentFolder = true; boolean mShowDisplayableOnly = false; private boolean mHideCurrentFolder = true; private boolean mShowDisplayableOnly = false; /** * What folders to display.<br/> Loading @@ -59,13 +71,6 @@ public class ChooseFolder extends K9ListActivity { */ private Account.FolderMode mMode; /** * Current filter used by our ArrayAdapter.<br/> * Created on the fly and invalidated if a new * set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)} */ private FolderListFilter<String> mMyFilter = null; @Override public void onCreate(Bundle savedInstanceState) { Loading Loading @@ -95,18 +100,7 @@ public class ChooseFolder extends K9ListActivity { if (currentFolder == null) currentFolder = ""; mAdapter = new ArrayAdapter<FolderDisplayData>(this, android.R.layout.simple_list_item_1) { private Filter myFilter = null; @Override public Filter getFilter() { if (myFilter == null) { myFilter = new FolderListFilter<>(this); } return myFilter; } }; mAdapter = new FolderListAdapter(); setListAdapter(mAdapter); mMode = mAccount.getFolderTargetMode(); Loading @@ -115,7 +109,7 @@ public class ChooseFolder extends K9ListActivity { this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { FolderDisplayData folder = mAdapter.getItem(position); FolderInfoHolder folder = mAdapter.getItem(position); if (folder == null) { throw new AssertionError("Couldn't get item at adapter position " + position); } Loading Loading @@ -225,10 +219,6 @@ public class ChooseFolder extends K9ListActivity { private void setDisplayMode(FolderMode aMode) { mMode = aMode; // invalidate the current filter as it is working on an inval if (mMyFilter != null) { mMyFilter.invalidate(); } //re-populate the list MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener); } Loading Loading @@ -264,8 +254,8 @@ public class ChooseFolder extends K9ListActivity { } Account.FolderMode aMode = mMode; List<FolderDisplayData> newFolders = new ArrayList<>(); List<FolderDisplayData> topFolders = new ArrayList<>(); List<FolderInfoHolder> newFolders = new ArrayList<>(); List<FolderInfoHolder> topFolders = new ArrayList<>(); for (LocalFolder folder : folders) { String serverId = folder.getServerId(); Loading @@ -289,10 +279,7 @@ public class ChooseFolder extends K9ListActivity { continue; } long id = folder.getDatabaseId(); String name = folder.getName(); String displayName = buildDisplayName(account, serverId, name); FolderDisplayData folderDisplayData = new FolderDisplayData(id, serverId, displayName); FolderInfoHolder folderDisplayData = new FolderInfoHolder(folder, account); if (folder.isInTopGroup()) { topFolders.add(folderDisplayData); Loading @@ -301,9 +288,9 @@ public class ChooseFolder extends K9ListActivity { } } final Comparator<FolderDisplayData> comparator = new Comparator<FolderDisplayData>() { final Comparator<FolderInfoHolder> comparator = new Comparator<FolderInfoHolder>() { @Override public int compare(FolderDisplayData lhs, FolderDisplayData rhs) { public int compare(FolderInfoHolder lhs, FolderInfoHolder rhs) { int result = lhs.displayName.compareToIgnoreCase(rhs.displayName); return (result != 0) ? result : lhs.displayName.compareTo(rhs.displayName); } Loading @@ -312,7 +299,7 @@ public class ChooseFolder extends K9ListActivity { Collections.sort(topFolders, comparator); Collections.sort(newFolders, comparator); final List<FolderDisplayData> folderList = new ArrayList<>(newFolders.size() + topFolders.size()); final List<FolderInfoHolder> folderList = new ArrayList<>(newFolders.size() + topFolders.size()); folderList.addAll(topFolders); folderList.addAll(newFolders); Loading @@ -325,7 +312,7 @@ public class ChooseFolder extends K9ListActivity { */ try { int position = 0; for (FolderDisplayData folder : folderList) { for (FolderInfoHolder folder : folderList) { if (mSelectFolder != null) { /* * Never select EXTRA_CUR_FOLDER (mFolder) if EXTRA_SEL_FOLDER Loading @@ -347,16 +334,7 @@ public class ChooseFolder extends K9ListActivity { @Override public void run() { // Now we're in the UI-thread, we can safely change the contents of the adapter. mAdapter.clear(); mAdapter.addAll(folderList); mAdapter.notifyDataSetChanged(); /* * Only enable the text filter after the list has been * populated to avoid possible race conditions because our * FolderListFilter isn't really thread-safe. */ getListView().setTextFilterEnabled(true); mAdapter.setFolders(folderList); } }); } Loading @@ -367,29 +345,117 @@ public class ChooseFolder extends K9ListActivity { } }; private String buildDisplayName(Account account, String serverId, String name) { if (account.getInboxFolder().equals(serverId)) { return getString(R.string.special_mailbox_name_inbox); class FolderListAdapter extends BaseAdapter implements Filterable, FolderAdapter { private List<FolderInfoHolder> mFolders = emptyList(); private List<FolderInfoHolder> mFilteredFolders = emptyList(); private Filter mFilter = new FolderListFilter(this, mFolders); private FolderIconProvider folderIconProvider = new FolderIconProvider(getTheme()); private CharSequence filterText; public FolderInfoHolder getItem(long position) { return getItem((int)position); } @Override public FolderInfoHolder getItem(int position) { return mFilteredFolders.get(position); } @Override public long getItemId(int position) { return mFilteredFolders.get(position).folder.getDatabaseId(); } @Override public int getCount() { return mFilteredFolders.size(); } @Override public boolean isEnabled(int item) { return true; } @Override public boolean areAllItemsEnabled() { return true; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (position <= getCount()) { return getItemView(position, convertView, parent); } else { return name; Timber.e("getView with illegal position=%d called! count is only %d", position, getCount()); return null; } } public View getItemView(int itemPosition, View convertView, ViewGroup parent) { FolderInfoHolder folder = getItem(itemPosition); View view; if (convertView != null) { view = convertView; } else { view = View.inflate(ChooseFolder.this, R.layout.choose_folder_list_item, null); } static class FolderDisplayData { final long id; final String serverId; final String displayName; FolderViewHolder holder = (FolderViewHolder) view.getTag(); FolderDisplayData(long id, String serverId, String displayName) { this.id = id; this.serverId = serverId; this.displayName = displayName; if (holder == null) { holder = new FolderViewHolder(); holder.folderName = view.findViewById(R.id.folder_name); holder.folderIcon = view.findViewById(R.id.folder_icon); holder.folderListItemLayout = view.findViewById(R.id.folder_list_item_layout); view.setTag(holder); } if (folder == null) { return view; } holder.folderName.setText(folder.displayName); holder.folderIcon.setImageResource(folderIconProvider.getFolderIcon(folder.folder.getType())); if (K9.isWrapFolderNames()) { holder.folderName.setEllipsize(null); holder.folderName.setSingleLine(false); } else { holder.folderName.setEllipsize(TextUtils.TruncateAt.START); holder.folderName.setSingleLine(true); } return view; } @Override public boolean hasStableIds() { return true; } public Filter getFilter() { return mFilter; } @Override public String toString() { return displayName; public void setFilteredFolders(CharSequence filterText, List<FolderInfoHolder> folders) { this.filterText = filterText; mFilteredFolders = folders; notifyDataSetChanged(); } void setFolders(List<FolderInfoHolder> folders) { mFolders = folders; mFilter = new FolderListFilter(this, folders); mFilter.filter(filterText); } } static class FolderViewHolder { TextView folderName; ImageView folderIcon; LinearLayout folderListItemLayout; } } app/ui/src/main/java/com/fsck/k9/activity/FolderListFilter.java +22 −85 Original line number Diff line number Diff line Loading @@ -4,80 +4,41 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; import timber.log.Timber; import android.widget.ArrayAdapter; import android.widget.Filter; /** * Filter to search for occurrences of the search-expression in any place of the * folder-name instead of doing just a prefix-search. * * @author Marcus@Wolschon.biz * Filter to search for occurrences of the search-expression in any place of the folder name. */ public class FolderListFilter<T> extends Filter { /** * ArrayAdapter that contains the list of folders displayed in the * ListView. * This object is modified by {@link #publishResults} to reflect the * changes due to the filtering performed by {@link #performFiltering}. * This in turn will change the folders displayed in the ListView. */ private ArrayAdapter<T> mFolders; public class FolderListFilter extends Filter { private final FolderAdapter adapter; private final List<FolderInfoHolder> folders; /** * All folders. */ private List<T> mOriginalValues = null; /** * Create a filter for a list of folders. * * @param folders */ public FolderListFilter(final ArrayAdapter<T> folders) { this.mFolders = folders; public FolderListFilter(FolderAdapter adapter, List<FolderInfoHolder> folders) { this.adapter = adapter; this.folders = folders; } /** * Do the actual search. * {@inheritDoc} * * @see #publishResults(CharSequence, FilterResults) */ @Override protected FilterResults performFiltering(CharSequence searchTerm) { FilterResults results = new FilterResults(); // Copy the values from mFolders to mOriginalValues if this is the // first time this method is called. if (mOriginalValues == null) { int count = mFolders.getCount(); mOriginalValues = new ArrayList<>(count); for (int i = 0; i < count; i++) { mOriginalValues.add(mFolders.getItem(i)); } } Locale locale = Locale.getDefault(); if ((searchTerm == null) || (searchTerm.length() == 0)) { List<T> list = new ArrayList<>(mOriginalValues); if (searchTerm == null || searchTerm.length() == 0) { List<FolderInfoHolder> list = new ArrayList<>(folders); results.values = list; results.count = list.size(); } else { final String searchTermString = searchTerm.toString().toLowerCase(locale); final String[] words = searchTermString.split(" "); final int wordCount = words.length; String searchTermString = searchTerm.toString().toLowerCase(locale); String[] words = searchTermString.split(" "); final List<T> values = mOriginalValues; List<FolderInfoHolder> newValues = new ArrayList<>(); for (FolderInfoHolder folderInfoHolder : folders) { String valueText = folderInfoHolder.displayName.toLowerCase(locale); final List<T> newValues = new ArrayList<>(); for (final T value : values) { final String valueText = value.toString().toLowerCase(locale); for (int k = 0; k < wordCount; k++) { if (valueText.contains(words[k])) { newValues.add(value); for (String word : words) { if (valueText.contains(word)) { newValues.add(folderInfoHolder); break; } } Loading @@ -90,39 +51,15 @@ public class FolderListFilter<T> extends Filter { return results; } /** * Publish the results to the user-interface. * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { // Don't notify for every change mFolders.setNotifyOnChange(false); try { //noinspection unchecked final List<T> folders = (List<T>) results.values; mFolders.clear(); if (folders != null) { for (T folder : folders) { if (folder != null) { mFolders.add(folder); } } } else { Timber.w("FolderListFilter.publishResults - null search-result "); List<FolderInfoHolder> folders = (List<FolderInfoHolder>) results.values; adapter.setFilteredFolders(constraint, folders); } // Send notification that the data set changed now mFolders.notifyDataSetChanged(); } finally { // restore notification status mFolders.setNotifyOnChange(true); } } public void invalidate() { mOriginalValues = null; public interface FolderAdapter { void setFilteredFolders(CharSequence filterText, List<FolderInfoHolder> folders); } } app/ui/src/main/res/layout/choose_folder_list_item.xml 0 → 100644 +32 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/folder_list_item_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:minHeight="56dp" android:orientation="horizontal"> <ImageView android:id="@+id/folder_icon" android:layout_width="24dp" android:layout_height="24dp" android:layout_marginStart="16dp" android:layout_marginEnd="32dp" android:src="@drawable/ic_drafts_folder_light"/> <TextView android:id="@+id/folder_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="0dp" android:paddingTop="12dp" android:paddingEnd="16dp" android:paddingBottom="12dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorPrimary" tools:text="Folder name"/> </LinearLayout> Loading
app/ui/src/main/java/com/fsck/k9/activity/ChooseFolder.java +134 −68 Original line number Diff line number Diff line Loading @@ -9,19 +9,27 @@ import java.util.List; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.text.TextUtils; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.Filter; import android.widget.Filterable; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.SearchView; import android.widget.TextView; import com.fsck.k9.Account; import com.fsck.k9.Account.FolderMode; import com.fsck.k9.K9; import com.fsck.k9.Preferences; import com.fsck.k9.activity.FolderListFilter.FolderAdapter; import com.fsck.k9.controller.MessageReference; import com.fsck.k9.ui.R; import com.fsck.k9.controller.MessagingController; Loading @@ -29,6 +37,10 @@ import com.fsck.k9.controller.MessagingListener; import com.fsck.k9.controller.SimpleMessagingListener; import com.fsck.k9.mail.Folder; import com.fsck.k9.mailstore.LocalFolder; import com.fsck.k9.ui.folders.FolderIconProvider; import timber.log.Timber; import static java.util.Collections.emptyList; public class ChooseFolder extends K9ListActivity { Loading @@ -42,14 +54,14 @@ public class ChooseFolder extends K9ListActivity { public static final String RESULT_FOLDER_DISPLAY_NAME = "folderDisplayName"; String currentFolder; String mSelectFolder; Account mAccount; MessageReference mMessageReference; ArrayAdapter<FolderDisplayData> mAdapter; private String currentFolder; private String mSelectFolder; private Account mAccount; private MessageReference mMessageReference; private FolderListAdapter mAdapter; private ChooseFolderHandler mHandler = new ChooseFolderHandler(); boolean mHideCurrentFolder = true; boolean mShowDisplayableOnly = false; private boolean mHideCurrentFolder = true; private boolean mShowDisplayableOnly = false; /** * What folders to display.<br/> Loading @@ -59,13 +71,6 @@ public class ChooseFolder extends K9ListActivity { */ private Account.FolderMode mMode; /** * Current filter used by our ArrayAdapter.<br/> * Created on the fly and invalidated if a new * set of folders is chosen via {@link #onOptionsItemSelected(MenuItem)} */ private FolderListFilter<String> mMyFilter = null; @Override public void onCreate(Bundle savedInstanceState) { Loading Loading @@ -95,18 +100,7 @@ public class ChooseFolder extends K9ListActivity { if (currentFolder == null) currentFolder = ""; mAdapter = new ArrayAdapter<FolderDisplayData>(this, android.R.layout.simple_list_item_1) { private Filter myFilter = null; @Override public Filter getFilter() { if (myFilter == null) { myFilter = new FolderListFilter<>(this); } return myFilter; } }; mAdapter = new FolderListAdapter(); setListAdapter(mAdapter); mMode = mAccount.getFolderTargetMode(); Loading @@ -115,7 +109,7 @@ public class ChooseFolder extends K9ListActivity { this.getListView().setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { FolderDisplayData folder = mAdapter.getItem(position); FolderInfoHolder folder = mAdapter.getItem(position); if (folder == null) { throw new AssertionError("Couldn't get item at adapter position " + position); } Loading Loading @@ -225,10 +219,6 @@ public class ChooseFolder extends K9ListActivity { private void setDisplayMode(FolderMode aMode) { mMode = aMode; // invalidate the current filter as it is working on an inval if (mMyFilter != null) { mMyFilter.invalidate(); } //re-populate the list MessagingController.getInstance(getApplication()).listFolders(mAccount, false, mListener); } Loading Loading @@ -264,8 +254,8 @@ public class ChooseFolder extends K9ListActivity { } Account.FolderMode aMode = mMode; List<FolderDisplayData> newFolders = new ArrayList<>(); List<FolderDisplayData> topFolders = new ArrayList<>(); List<FolderInfoHolder> newFolders = new ArrayList<>(); List<FolderInfoHolder> topFolders = new ArrayList<>(); for (LocalFolder folder : folders) { String serverId = folder.getServerId(); Loading @@ -289,10 +279,7 @@ public class ChooseFolder extends K9ListActivity { continue; } long id = folder.getDatabaseId(); String name = folder.getName(); String displayName = buildDisplayName(account, serverId, name); FolderDisplayData folderDisplayData = new FolderDisplayData(id, serverId, displayName); FolderInfoHolder folderDisplayData = new FolderInfoHolder(folder, account); if (folder.isInTopGroup()) { topFolders.add(folderDisplayData); Loading @@ -301,9 +288,9 @@ public class ChooseFolder extends K9ListActivity { } } final Comparator<FolderDisplayData> comparator = new Comparator<FolderDisplayData>() { final Comparator<FolderInfoHolder> comparator = new Comparator<FolderInfoHolder>() { @Override public int compare(FolderDisplayData lhs, FolderDisplayData rhs) { public int compare(FolderInfoHolder lhs, FolderInfoHolder rhs) { int result = lhs.displayName.compareToIgnoreCase(rhs.displayName); return (result != 0) ? result : lhs.displayName.compareTo(rhs.displayName); } Loading @@ -312,7 +299,7 @@ public class ChooseFolder extends K9ListActivity { Collections.sort(topFolders, comparator); Collections.sort(newFolders, comparator); final List<FolderDisplayData> folderList = new ArrayList<>(newFolders.size() + topFolders.size()); final List<FolderInfoHolder> folderList = new ArrayList<>(newFolders.size() + topFolders.size()); folderList.addAll(topFolders); folderList.addAll(newFolders); Loading @@ -325,7 +312,7 @@ public class ChooseFolder extends K9ListActivity { */ try { int position = 0; for (FolderDisplayData folder : folderList) { for (FolderInfoHolder folder : folderList) { if (mSelectFolder != null) { /* * Never select EXTRA_CUR_FOLDER (mFolder) if EXTRA_SEL_FOLDER Loading @@ -347,16 +334,7 @@ public class ChooseFolder extends K9ListActivity { @Override public void run() { // Now we're in the UI-thread, we can safely change the contents of the adapter. mAdapter.clear(); mAdapter.addAll(folderList); mAdapter.notifyDataSetChanged(); /* * Only enable the text filter after the list has been * populated to avoid possible race conditions because our * FolderListFilter isn't really thread-safe. */ getListView().setTextFilterEnabled(true); mAdapter.setFolders(folderList); } }); } Loading @@ -367,29 +345,117 @@ public class ChooseFolder extends K9ListActivity { } }; private String buildDisplayName(Account account, String serverId, String name) { if (account.getInboxFolder().equals(serverId)) { return getString(R.string.special_mailbox_name_inbox); class FolderListAdapter extends BaseAdapter implements Filterable, FolderAdapter { private List<FolderInfoHolder> mFolders = emptyList(); private List<FolderInfoHolder> mFilteredFolders = emptyList(); private Filter mFilter = new FolderListFilter(this, mFolders); private FolderIconProvider folderIconProvider = new FolderIconProvider(getTheme()); private CharSequence filterText; public FolderInfoHolder getItem(long position) { return getItem((int)position); } @Override public FolderInfoHolder getItem(int position) { return mFilteredFolders.get(position); } @Override public long getItemId(int position) { return mFilteredFolders.get(position).folder.getDatabaseId(); } @Override public int getCount() { return mFilteredFolders.size(); } @Override public boolean isEnabled(int item) { return true; } @Override public boolean areAllItemsEnabled() { return true; } @Override public View getView(int position, View convertView, ViewGroup parent) { if (position <= getCount()) { return getItemView(position, convertView, parent); } else { return name; Timber.e("getView with illegal position=%d called! count is only %d", position, getCount()); return null; } } public View getItemView(int itemPosition, View convertView, ViewGroup parent) { FolderInfoHolder folder = getItem(itemPosition); View view; if (convertView != null) { view = convertView; } else { view = View.inflate(ChooseFolder.this, R.layout.choose_folder_list_item, null); } static class FolderDisplayData { final long id; final String serverId; final String displayName; FolderViewHolder holder = (FolderViewHolder) view.getTag(); FolderDisplayData(long id, String serverId, String displayName) { this.id = id; this.serverId = serverId; this.displayName = displayName; if (holder == null) { holder = new FolderViewHolder(); holder.folderName = view.findViewById(R.id.folder_name); holder.folderIcon = view.findViewById(R.id.folder_icon); holder.folderListItemLayout = view.findViewById(R.id.folder_list_item_layout); view.setTag(holder); } if (folder == null) { return view; } holder.folderName.setText(folder.displayName); holder.folderIcon.setImageResource(folderIconProvider.getFolderIcon(folder.folder.getType())); if (K9.isWrapFolderNames()) { holder.folderName.setEllipsize(null); holder.folderName.setSingleLine(false); } else { holder.folderName.setEllipsize(TextUtils.TruncateAt.START); holder.folderName.setSingleLine(true); } return view; } @Override public boolean hasStableIds() { return true; } public Filter getFilter() { return mFilter; } @Override public String toString() { return displayName; public void setFilteredFolders(CharSequence filterText, List<FolderInfoHolder> folders) { this.filterText = filterText; mFilteredFolders = folders; notifyDataSetChanged(); } void setFolders(List<FolderInfoHolder> folders) { mFolders = folders; mFilter = new FolderListFilter(this, folders); mFilter.filter(filterText); } } static class FolderViewHolder { TextView folderName; ImageView folderIcon; LinearLayout folderListItemLayout; } }
app/ui/src/main/java/com/fsck/k9/activity/FolderListFilter.java +22 −85 Original line number Diff line number Diff line Loading @@ -4,80 +4,41 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; import timber.log.Timber; import android.widget.ArrayAdapter; import android.widget.Filter; /** * Filter to search for occurrences of the search-expression in any place of the * folder-name instead of doing just a prefix-search. * * @author Marcus@Wolschon.biz * Filter to search for occurrences of the search-expression in any place of the folder name. */ public class FolderListFilter<T> extends Filter { /** * ArrayAdapter that contains the list of folders displayed in the * ListView. * This object is modified by {@link #publishResults} to reflect the * changes due to the filtering performed by {@link #performFiltering}. * This in turn will change the folders displayed in the ListView. */ private ArrayAdapter<T> mFolders; public class FolderListFilter extends Filter { private final FolderAdapter adapter; private final List<FolderInfoHolder> folders; /** * All folders. */ private List<T> mOriginalValues = null; /** * Create a filter for a list of folders. * * @param folders */ public FolderListFilter(final ArrayAdapter<T> folders) { this.mFolders = folders; public FolderListFilter(FolderAdapter adapter, List<FolderInfoHolder> folders) { this.adapter = adapter; this.folders = folders; } /** * Do the actual search. * {@inheritDoc} * * @see #publishResults(CharSequence, FilterResults) */ @Override protected FilterResults performFiltering(CharSequence searchTerm) { FilterResults results = new FilterResults(); // Copy the values from mFolders to mOriginalValues if this is the // first time this method is called. if (mOriginalValues == null) { int count = mFolders.getCount(); mOriginalValues = new ArrayList<>(count); for (int i = 0; i < count; i++) { mOriginalValues.add(mFolders.getItem(i)); } } Locale locale = Locale.getDefault(); if ((searchTerm == null) || (searchTerm.length() == 0)) { List<T> list = new ArrayList<>(mOriginalValues); if (searchTerm == null || searchTerm.length() == 0) { List<FolderInfoHolder> list = new ArrayList<>(folders); results.values = list; results.count = list.size(); } else { final String searchTermString = searchTerm.toString().toLowerCase(locale); final String[] words = searchTermString.split(" "); final int wordCount = words.length; String searchTermString = searchTerm.toString().toLowerCase(locale); String[] words = searchTermString.split(" "); final List<T> values = mOriginalValues; List<FolderInfoHolder> newValues = new ArrayList<>(); for (FolderInfoHolder folderInfoHolder : folders) { String valueText = folderInfoHolder.displayName.toLowerCase(locale); final List<T> newValues = new ArrayList<>(); for (final T value : values) { final String valueText = value.toString().toLowerCase(locale); for (int k = 0; k < wordCount; k++) { if (valueText.contains(words[k])) { newValues.add(value); for (String word : words) { if (valueText.contains(word)) { newValues.add(folderInfoHolder); break; } } Loading @@ -90,39 +51,15 @@ public class FolderListFilter<T> extends Filter { return results; } /** * Publish the results to the user-interface. * {@inheritDoc} */ @SuppressWarnings("unchecked") @Override protected void publishResults(CharSequence constraint, FilterResults results) { // Don't notify for every change mFolders.setNotifyOnChange(false); try { //noinspection unchecked final List<T> folders = (List<T>) results.values; mFolders.clear(); if (folders != null) { for (T folder : folders) { if (folder != null) { mFolders.add(folder); } } } else { Timber.w("FolderListFilter.publishResults - null search-result "); List<FolderInfoHolder> folders = (List<FolderInfoHolder>) results.values; adapter.setFilteredFolders(constraint, folders); } // Send notification that the data set changed now mFolders.notifyDataSetChanged(); } finally { // restore notification status mFolders.setNotifyOnChange(true); } } public void invalidate() { mOriginalValues = null; public interface FolderAdapter { void setFilteredFolders(CharSequence filterText, List<FolderInfoHolder> folders); } }
app/ui/src/main/res/layout/choose_folder_list_item.xml 0 → 100644 +32 −0 Original line number Diff line number Diff line <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/folder_list_item_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:minHeight="56dp" android:orientation="horizontal"> <ImageView android:id="@+id/folder_icon" android:layout_width="24dp" android:layout_height="24dp" android:layout_marginStart="16dp" android:layout_marginEnd="32dp" android:src="@drawable/ic_drafts_folder_light"/> <TextView android:id="@+id/folder_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingStart="0dp" android:paddingTop="12dp" android:paddingEnd="16dp" android:paddingBottom="12dp" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="?android:attr/textColorPrimary" tools:text="Folder name"/> </LinearLayout>