From 0f348900005dc7edc38cfc688d2ce52e15f28a19 Mon Sep 17 00:00:00 2001 From: Florens Douwes Date: Wed, 30 Jul 2014 13:23:13 +0200 Subject: [PATCH] Added search: Added UI for search, normal SearchView + a bar at the top telling how many results were found. Added filtering support for PostAdapter. --- .../java/com/android/volley/RequestQueue.java | 4 +- .../dslv/SimpleDragSortCursorAdapter.java | 4 +- .../org/floens/chan/core/loader/Loader.java | 7 +- .../floens/chan/ui/activity/BaseActivity.java | 14 +- .../chan/ui/activity/BoardActivity.java | 82 +++++- .../floens/chan/ui/adapter/PostAdapter.java | 275 ++++++++++++------ .../chan/ui/fragment/ThreadFragment.java | 101 ++++++- Clover/app/src/main/res/menu/base.xml | 60 ++-- Clover/app/src/main/res/values/strings.xml | 8 + 9 files changed, 420 insertions(+), 135 deletions(-) diff --git a/Clover/app/src/main/java/com/android/volley/RequestQueue.java b/Clover/app/src/main/java/com/android/volley/RequestQueue.java index 5c0e7afb..e9360293 100644 --- a/Clover/app/src/main/java/com/android/volley/RequestQueue.java +++ b/Clover/app/src/main/java/com/android/volley/RequestQueue.java @@ -171,7 +171,7 @@ public class RequestQueue { } /** - * A simple predicate or filter interface for Requests, for use by + * A simple predicate or setFilter interface for Requests, for use by * {@link RequestQueue#cancelAll(RequestFilter)}. */ public interface RequestFilter { @@ -179,7 +179,7 @@ public class RequestQueue { } /** - * Cancels all requests in this queue for which the given filter applies. + * Cancels all requests in this queue for which the given setFilter applies. * @param filter The filtering function to use */ public void cancelAll(RequestFilter filter) { diff --git a/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java b/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java index 3a9116e5..c01ecb61 100644 --- a/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java +++ b/Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java @@ -213,7 +213,7 @@ public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter { * By default, the value will be treated as an image resource. If the value * cannot be used as an image resource, the value is used as an image Uri. * - * Intended to be overridden by Adapters that need to filter strings + * Intended to be overridden by Adapters that need to setFilter strings * retrieved from the database. * * @param v @@ -234,7 +234,7 @@ public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter { * no existing ViewBinder or if the existing ViewBinder cannot handle * binding to a TextView. * - * Intended to be overridden by Adapters that need to filter strings + * Intended to be overridden by Adapters that need to setFilter strings * retrieved from the database. * * @param v diff --git a/Clover/app/src/main/java/org/floens/chan/core/loader/Loader.java b/Clover/app/src/main/java/org/floens/chan/core/loader/Loader.java index 27d8943c..5150e2aa 100644 --- a/Clover/app/src/main/java/org/floens/chan/core/loader/Loader.java +++ b/Clover/app/src/main/java/org/floens/chan/core/loader/Loader.java @@ -143,12 +143,13 @@ public class Loader { clearTimer(); if (loadable.isBoardMode()) { - loadable.no++; - if (request != null) { - request.cancel(); + // finish the last board load first + return; } + loadable.no++; + request = getData(); } else if (loadable.isThreadMode()) { if (request != null) { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java index 6d402a56..5c6becce 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/BaseActivity.java @@ -240,13 +240,13 @@ public abstract class BaseActivity extends Activity implements PanelSlideListene private void onPinLongPress(final Pin pin) { new AlertDialog.Builder(this) - .setNegativeButton(R.string.drawer_pinned_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - // Delete pin - removePin(pin); - } - }).setPositiveButton(R.string.drawer_pinned_change_title, new DialogInterface.OnClickListener() { + .setNegativeButton(R.string.drawer_pinned_delete, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + // Delete pin + removePin(pin); + } + }).setPositiveButton(R.string.drawer_pinned_change_title, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // Change pin title diff --git a/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java b/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java index ac30861c..b24c5e73 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java @@ -38,6 +38,7 @@ import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; import android.widget.BaseAdapter; import android.widget.FrameLayout; +import android.widget.SearchView; import android.widget.Spinner; import android.widget.TextView; @@ -47,7 +48,6 @@ import org.floens.chan.chan.ChanUrls; import org.floens.chan.core.ChanPreferences; import org.floens.chan.core.loader.Loader; import org.floens.chan.core.manager.ThreadManager; -import org.floens.chan.core.manager.WatchManager; import org.floens.chan.core.model.Loadable; import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Post; @@ -68,6 +68,8 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel private boolean ignoreNextOnItemSelected = false; private Spinner boardSpinner; private BoardSpinnerAdapter spinnerAdapter; + private MenuItem searchMenuItem; + private boolean searchBoard; @Override protected void onCreate(Bundle savedInstanceState) { @@ -186,6 +188,38 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); + searchMenuItem = menu.findItem(R.id.action_search); + + SearchView searchView = (SearchView) searchMenuItem.getActionView(); + searchView.setQueryHint(getString(R.string.search_hint)); + searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { + @Override + public boolean onQueryTextSubmit(String query) { + doSearch(query); + return false; + } + + @Override + public boolean onQueryTextChange(String newText) { + doSearch(newText); + return false; + } + }); + searchMenuItem.setOnActionExpandListener(new MenuItem.OnActionExpandListener() { + @Override + public boolean onMenuItemActionExpand(MenuItem item) { + return true; + } + + @Override + public boolean onMenuItemActionCollapse(MenuItem item) { + threadFragment.setFilter(""); + boardFragment.setFilter(""); + + return true; + } + }); + return true; } @@ -411,6 +445,11 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel menu.findItem(R.id.action_board_view_mode_grid).setChecked(true); } + setMenuItemEnabled(menu.findItem(R.id.action_search), slidable); + setMenuItemEnabled(menu.findItem(R.id.action_search_tablet), !slidable); + + showSearch(false); + return super.onPrepareOptionsMenu(menu); } @@ -485,6 +524,14 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel startLoadingBoard(boardLoadable); } return true; + case R.id.action_search_board: + showSearch(true); + searchBoard = true; + return true; + case R.id.action_search_thread: + showSearch(true); + searchBoard = false; + return true; case android.R.id.home: threadPane.openPane(); @@ -517,7 +564,12 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel boardLoadable.mode = Loadable.Mode.BOARD; } - boardFragment.bindLoadable(loadable); + // Force catalog mode when using grid + if (boardFragment.getViewMode() == ThreadManager.ViewMode.GRID) { + boardLoadable.mode = Loadable.Mode.CATALOG; + } + + boardFragment.bindLoadable(boardLoadable); boardFragment.requestData(); updateActionBarState(); @@ -545,6 +597,32 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel updateActionBarState(); } + private void showSearch(boolean show) { + if (searchMenuItem != null) { + if (show) { + searchMenuItem.expandActionView(); + } else { + searchMenuItem.collapseActionView(); + } + } + } + + private void doSearch(String filter) { + if (threadPane.isSlideable()) { + if (threadPane.isOpen()) { + boardFragment.setFilter(filter); + } else { + threadFragment.setFilter(filter); + } + } else { + if (searchBoard) { + boardFragment.setFilter(filter); + } else { + threadFragment.setFilter(filter); + } + } + } + /** * Handle opening from an external url. * diff --git a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java index 713d17ce..5bc6d957 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java @@ -19,12 +19,15 @@ package org.floens.chan.ui.adapter; import android.content.Context; import android.os.Handler; +import android.text.TextUtils; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseAdapter; +import android.widget.Filter; +import android.widget.Filterable; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.TextView; @@ -41,29 +44,46 @@ import org.floens.chan.utils.Utils; import java.util.ArrayList; import java.util.List; +import java.util.Locale; -public class PostAdapter extends BaseAdapter { +public class PostAdapter extends BaseAdapter implements Filterable { private static final int VIEW_TYPE_ITEM = 0; private static final int VIEW_TYPE_STATUS = 1; + private final Object lock = new Object(); + private final Context context; - private final ThreadManager threadManager; private final AbsListView listView; + + private final ThreadManager threadManager; + private final PostAdapterListener listener; + + /** + * The list with the original data + */ + private final List sourceList = new ArrayList<>(); + + /** + * The list that is displayed (filtered) + */ + private final List displayList = new ArrayList<>(); + private boolean endOfLine; - private final List postList = new ArrayList<>(); private int lastPostCount = 0; private long lastViewedTime = 0; private String loadMessage = null; + private String filter = ""; - public PostAdapter(Context activity, ThreadManager threadManager, AbsListView listView) { + public PostAdapter(Context activity, ThreadManager threadManager, AbsListView listView, PostAdapterListener listener) { context = activity; this.threadManager = threadManager; this.listView = listView; + this.listener = listener; } @Override public int getCount() { - return postList.size() + (showStatusView() ? 1 : 0); + return displayList.size() + (showStatusView() ? 1 : 0); } @Override @@ -73,8 +93,8 @@ public class PostAdapter extends BaseAdapter { @Override public int getItemViewType(int position) { - if (showStatusView()) { - return position == getCount() - 1 ? VIEW_TYPE_STATUS : VIEW_TYPE_ITEM; + if (position == getCount() - 1) { + return showStatusView() ? VIEW_TYPE_STATUS : VIEW_TYPE_ITEM; } else { return VIEW_TYPE_ITEM; } @@ -82,8 +102,9 @@ public class PostAdapter extends BaseAdapter { @Override public Post getItem(int position) { - if (position >= 0 && position < postList.size()) { - return postList.get(position); + int realPosition = position; + if (realPosition >= 0 && realPosition < displayList.size()) { + return displayList.get(realPosition); } else { return null; } @@ -102,7 +123,7 @@ public class PostAdapter extends BaseAdapter { switch (getItemViewType(position)) { case VIEW_TYPE_ITEM: { - if (convertView == null || convertView.getTag() == null && (Integer) convertView.getTag() != VIEW_TYPE_ITEM) { + if (convertView == null || convertView.getTag() == null || (Integer) convertView.getTag() != VIEW_TYPE_ITEM) { convertView = new PostView(context); convertView.setTag(VIEW_TYPE_ITEM); } @@ -120,50 +141,79 @@ public class PostAdapter extends BaseAdapter { return null; } - private void onGetBottomView() { - if (threadManager.getLoadable().isBoardMode() && !endOfLine) { - // Try to load more posts - threadManager.requestNextData(); - } + public Filter getFilter() { + return new Filter() { + @Override + protected FilterResults performFiltering(CharSequence constraintRaw) { + FilterResults results = new FilterResults(); - if (lastPostCount != postList.size()) { - lastPostCount = postList.size(); - lastViewedTime = Time.get(); - } + if (TextUtils.isEmpty(constraintRaw)) { + ArrayList tmp; + synchronized (lock) { + tmp = new ArrayList<>(sourceList); + } + results.values = tmp; + } else { + List all; + synchronized (lock) { + all = new ArrayList<>(sourceList); + } - if (Time.get(lastViewedTime) > 1000L) { - lastViewedTime = Time.get(); - threadManager.bottomPostViewed(); - } - } + List accepted = new ArrayList<>(); + String constraint = constraintRaw.toString().toLowerCase(Locale.ENGLISH); - private boolean showStatusView() { - Loadable l = threadManager.getLoadable(); - if (l != null) { - if (l.isBoardMode()) { - return true; - } else if (l.isThreadMode() && threadManager.shouldWatch()) { - return true; - } else { - return false; + for (Post post : all) { + if (post.comment.toString().toLowerCase(Locale.ENGLISH).contains(constraint)) { + accepted.add(post); + } + } + + results.values = accepted; + } + + return results; } - } else { - return false; - } + + @Override + protected void publishResults(CharSequence constraint, final FilterResults results) { + filter = constraint.toString(); + synchronized (lock) { + displayList.clear(); + displayList.addAll((List) results.values); + } + notifyDataSetChanged(); + listener.onFilterResults(filter, ((List) results.values).size(), TextUtils.isEmpty(filter)); + } + }; + } + + public void setFilter(String filter) { + getFilter().filter(filter); + notifyDataSetChanged(); } public void appendList(List list) { - for (Post post : list) { - boolean flag = true; - for (Post own : postList) { - if (post.no == own.no) { - flag = false; - break; + synchronized (lock) { + boolean flag; + for (Post post : list) { + flag = true; + for (Post own : sourceList) { + if (post.no == own.no) { + flag = false; + break; + } + } + + if (flag) { + sourceList.add(post); } } - if (flag) { - postList.add(post); + if (!isFiltering()) { + displayList.clear(); + displayList.addAll(sourceList); + } else { + setFilter(filter); } } @@ -171,14 +221,23 @@ public class PostAdapter extends BaseAdapter { } public void setList(List list) { - postList.clear(); - postList.addAll(list); + synchronized (lock) { + sourceList.clear(); + sourceList.addAll(list); + + if (!isFiltering()) { + displayList.clear(); + displayList.addAll(sourceList); + } else { + setFilter(filter); + } + } notifyDataSetChanged(); } public List getList() { - return postList; + return sourceList; } public void setEndOfLine(boolean endOfLine) { @@ -190,16 +249,18 @@ public class PostAdapter extends BaseAdapter { public void scrollToPost(int no) { notifyDataSetChanged(); - for (int i = 0; i < postList.size(); i++) { - if (postList.get(i).no == no) { - if (Math.abs(i - listView.getFirstVisiblePosition()) > 20 || listView.getChildCount() == 0) { - listView.setSelection(i); - } else { - ScrollerRunnable r = new ScrollerRunnable(listView); - r.start(i); - } + synchronized (lock) { + for (int i = 0; i < displayList.size(); i++) { + if (displayList.get(i).no == no) { + if (Math.abs(i - listView.getFirstVisiblePosition()) > 20 || listView.getChildCount() == 0) { + listView.setSelection(i); + } else { + ScrollerRunnable r = new ScrollerRunnable(listView); + r.start(i); + } - break; + break; + } } } } @@ -212,6 +273,40 @@ public class PostAdapter extends BaseAdapter { return loadMessage; } + private void onGetBottomView() { + if (threadManager.getLoadable().isBoardMode() && !endOfLine) { + // Try to load more posts + threadManager.requestNextData(); + } + + if (lastPostCount != sourceList.size()) { + lastPostCount = sourceList.size(); + lastViewedTime = Time.get(); + } + + if (Time.get(lastViewedTime) > 1000L) { + lastViewedTime = Time.get(); + threadManager.bottomPostViewed(); + } + } + + private boolean showStatusView() { + Loadable l = threadManager.getLoadable(); + if (l != null) { + return l.isBoardMode() || l.isThreadMode(); + } else { + return false; + } + } + + private boolean isFiltering() { + return !TextUtils.isEmpty(filter); + } + + public interface PostAdapterListener { + public void onFilterResults(String filter, int count, boolean all); + } + public class StatusView extends LinearLayout { boolean detached = false; @@ -232,47 +327,53 @@ public class PostAdapter extends BaseAdapter { public void init() { Loader loader = threadManager.getLoader(); - if (loader == null) + if (loader == null || loader.getLoadable() == null) return; setGravity(Gravity.CENTER); - if (threadManager.shouldWatch()) { - String error = getErrorMessage(); - if (error != null) { - setText(error); - } else { - long time = loader.getTimeUntilLoadMore() / 1000L; - if (time == 0) { - setText("Loading"); - } else { - setText("Loading in " + time); - } - } + Loadable loadable = loader.getLoadable(); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - if (!detached) { - notifyDataSetChanged(); + if (loadable.isThreadMode()) { + if (threadManager.shouldWatch()) { + String error = getErrorMessage(); + if (error != null) { + setText(error); + } else { + long time = loader.getTimeUntilLoadMore() / 1000L; + if (time == 0) { + setText("Loading"); + } else { + setText("Loading in " + time); } } - }, 1000); - - setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - Loader loader = threadManager.getLoader(); - if (loader != null) { - loader.requestMoreDataAndResetTimer(); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + if (!detached) { + notifyDataSetChanged(); + } } + }, 1000); - notifyDataSetChanged(); - } - }); + setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + Loader loader = threadManager.getLoader(); + if (loader != null) { + loader.requestMoreDataAndResetTimer(); + } - Utils.setPressedDrawable(this); - } else { + notifyDataSetChanged(); + } + }); + + Utils.setPressedDrawable(this); + } else { + setText(""); + } + } else if (loadable.isBoardMode()) { if (endOfLine) { setText(context.getString(R.string.thread_load_end_of_line)); } else { diff --git a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java index 66c404e9..ea0e55b8 100644 --- a/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java +++ b/Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java @@ -18,9 +18,11 @@ package org.floens.chan.ui.fragment; import android.app.Fragment; +import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; import android.os.Bundle; +import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; @@ -29,6 +31,7 @@ import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.GridView; import android.widget.ImageView; +import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.TextView; @@ -52,7 +55,7 @@ import org.floens.chan.utils.Utils; import java.util.List; -public class ThreadFragment extends Fragment implements ThreadManager.ThreadManagerListener { +public class ThreadFragment extends Fragment implements ThreadManager.ThreadManagerListener, PostAdapter.PostAdapterListener { private BaseActivity baseActivity; private ThreadManager threadManager; private Loadable loadable; @@ -61,9 +64,13 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana private LoadView container; private AbsListView listView; private ImageView skip; + private FilterView filterView; + private SkipLogic skipLogic; private int highlightedPost = -1; private ThreadManager.ViewMode viewMode = ThreadManager.ViewMode.LIST; + private String lastFilter = ""; + private boolean isFiltering = false; public static ThreadFragment newInstance(BaseActivity activity) { ThreadFragment fragment = new ThreadFragment(); @@ -112,6 +119,13 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana return threadManager.getLoader(); } + public void setFilter(String filter) { + if (!filter.equals(lastFilter) && postAdapter != null) { + lastFilter = filter; + postAdapter.setFilter(filter); + } + } + @Override public void onDestroy() { super.onDestroy(); @@ -193,10 +207,17 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana if (postAdapter == null) { RelativeLayout compound = new RelativeLayout(baseActivity); + LinearLayout listViewContainer = new LinearLayout(baseActivity); + listViewContainer.setOrientation(LinearLayout.VERTICAL); + + filterView = new FilterView(baseActivity); + filterView.setVisibility(View.GONE); + listViewContainer.addView(filterView, Utils.MATCH_WRAP_PARAMS); + if (viewMode == ThreadManager.ViewMode.LIST) { ListView list = new ListView(baseActivity); listView = list; - postAdapter = new PostAdapter(baseActivity, threadManager, listView); + postAdapter = new PostAdapter(baseActivity, threadManager, listView, this); listView.setAdapter(postAdapter); list.setSelectionFromTop(loadable.listViewIndex, loadable.listViewTop); } else if (viewMode == ThreadManager.ViewMode.GRID) { @@ -210,7 +231,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana grid.setVerticalSpacing(postGridSpacing); grid.setHorizontalSpacing(postGridSpacing); listView = grid; - postAdapter = new PostAdapter(baseActivity, threadManager, listView); + postAdapter = new PostAdapter(baseActivity, threadManager, listView, this); listView.setAdapter(postAdapter); listView.setSelection(loadable.listViewIndex); } @@ -218,25 +239,35 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana listView.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { - if (skipLogic != null) { - skipLogic.onScrollStateChanged(view, scrollState); + if (!isFiltering) { + if (skipLogic != null) { + skipLogic.onScrollStateChanged(view, scrollState); + } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { - if (loadable != null) { - loadable.listViewIndex = view.getFirstVisiblePosition(); - View v = view.getChildAt(0); - loadable.listViewTop = (v == null) ? 0 : v.getTop(); - } - if (skipLogic != null) { - skipLogic.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); + if (!isFiltering) { + if (loadable != null) { + int index = view.getFirstVisiblePosition(); + View v = view.getChildAt(0); + int top = v == null ? 0 : v.getTop(); + if (index != 0 || top != 0) { + loadable.listViewIndex = index; + loadable.listViewTop = top; + } + } + if (skipLogic != null) { + skipLogic.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); + } } } }); - compound.addView(listView, Utils.MATCH_PARAMS); + listViewContainer.addView(listView, Utils.MATCH_PARAMS); + + compound.addView(listViewContainer, Utils.MATCH_PARAMS); if (loadable.isThreadMode()) { skip = new ImageView(baseActivity); @@ -292,6 +323,19 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana highlightedPost = -1; } + public void onFilterResults(String filter, int count, boolean all) { + isFiltering = !all; + + if (filterView != null) { + if (all) { + filterView.setVisibility(View.GONE); + } else { + filterView.setVisibility(View.VISIBLE); + filterView.setText(filter, count); + } + } + } + private void setEmpty() { postAdapter = null; @@ -400,4 +444,35 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana up = false; } } + + public class FilterView extends LinearLayout { + private TextView textView; + + public FilterView(Context activity) { + super(activity); + init(); + } + + public FilterView(Context activity, AttributeSet attr) { + super(activity, attr); + init(); + } + + public FilterView(Context activity, AttributeSet attr, int style) { + super(activity, attr, style); + init(); + } + + private void init() { + textView = new TextView(getContext()); + textView.setGravity(Gravity.CENTER); + addView(textView, new LayoutParams(LayoutParams.MATCH_PARENT, Utils.dp(48))); + } + + private void setText(String filter, int count) { + String posts = getContext().getString(count == 1 ? R.string.one_post : R.string.multiple_posts); + String text = getContext().getString(R.string.search_results, Integer.toString(count), posts, filter); + textView.setText(text); + } + } } diff --git a/Clover/app/src/main/res/menu/base.xml b/Clover/app/src/main/res/menu/base.xml index a51d47c5..4ea26940 100644 --- a/Clover/app/src/main/res/menu/base.xml +++ b/Clover/app/src/main/res/menu/base.xml @@ -1,5 +1,4 @@ - -