Added search:

Added UI for search, normal SearchView + a bar at the top telling how many results were found.
Added filtering support for PostAdapter.
captchafix
Florens Douwes 11 years ago
parent eb7f854dbf
commit 0f34890000
  1. 4
      Clover/app/src/main/java/com/android/volley/RequestQueue.java
  2. 4
      Clover/app/src/main/java/com/mobeta/android/dslv/SimpleDragSortCursorAdapter.java
  3. 7
      Clover/app/src/main/java/org/floens/chan/core/loader/Loader.java
  4. 82
      Clover/app/src/main/java/org/floens/chan/ui/activity/BoardActivity.java
  5. 181
      Clover/app/src/main/java/org/floens/chan/ui/adapter/PostAdapter.java
  6. 87
      Clover/app/src/main/java/org/floens/chan/ui/fragment/ThreadFragment.java
  7. 36
      Clover/app/src/main/res/menu/base.xml
  8. 8
      Clover/app/src/main/res/values/strings.xml

@ -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)}. * {@link RequestQueue#cancelAll(RequestFilter)}.
*/ */
public interface 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 * @param filter The filtering function to use
*/ */
public void cancelAll(RequestFilter filter) { public void cancelAll(RequestFilter filter) {

@ -213,7 +213,7 @@ public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter {
* By default, the value will be treated as an image resource. If the value * 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. * 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. * retrieved from the database.
* *
* @param v * @param v
@ -234,7 +234,7 @@ public class SimpleDragSortCursorAdapter extends ResourceDragSortCursorAdapter {
* no existing ViewBinder or if the existing ViewBinder cannot handle * no existing ViewBinder or if the existing ViewBinder cannot handle
* binding to a TextView. * 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. * retrieved from the database.
* *
* @param v * @param v

@ -143,12 +143,13 @@ public class Loader {
clearTimer(); clearTimer();
if (loadable.isBoardMode()) { if (loadable.isBoardMode()) {
loadable.no++;
if (request != null) { if (request != null) {
request.cancel(); // finish the last board load first
return;
} }
loadable.no++;
request = getData(); request = getData();
} else if (loadable.isThreadMode()) { } else if (loadable.isThreadMode()) {
if (request != null) { if (request != null) {

@ -38,6 +38,7 @@ import android.view.ViewGroup.LayoutParams;
import android.widget.AdapterView; import android.widget.AdapterView;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.SearchView;
import android.widget.Spinner; import android.widget.Spinner;
import android.widget.TextView; 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.ChanPreferences;
import org.floens.chan.core.loader.Loader; import org.floens.chan.core.loader.Loader;
import org.floens.chan.core.manager.ThreadManager; 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.Loadable;
import org.floens.chan.core.model.Pin; import org.floens.chan.core.model.Pin;
import org.floens.chan.core.model.Post; import org.floens.chan.core.model.Post;
@ -68,6 +68,8 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
private boolean ignoreNextOnItemSelected = false; private boolean ignoreNextOnItemSelected = false;
private Spinner boardSpinner; private Spinner boardSpinner;
private BoardSpinnerAdapter spinnerAdapter; private BoardSpinnerAdapter spinnerAdapter;
private MenuItem searchMenuItem;
private boolean searchBoard;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -186,6 +188,38 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
super.onCreateOptionsMenu(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; 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); 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); return super.onPrepareOptionsMenu(menu);
} }
@ -485,6 +524,14 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
startLoadingBoard(boardLoadable); startLoadingBoard(boardLoadable);
} }
return true; 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: case android.R.id.home:
threadPane.openPane(); threadPane.openPane();
@ -517,7 +564,12 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
boardLoadable.mode = Loadable.Mode.BOARD; 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(); boardFragment.requestData();
updateActionBarState(); updateActionBarState();
@ -545,6 +597,32 @@ public class BoardActivity extends BaseActivity implements AdapterView.OnItemSel
updateActionBarState(); 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. * Handle opening from an external url.
* *

@ -19,12 +19,15 @@ package org.floens.chan.ui.adapter;
import android.content.Context; import android.content.Context;
import android.os.Handler; import android.os.Handler;
import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AbsListView; import android.widget.AbsListView;
import android.widget.BaseAdapter; import android.widget.BaseAdapter;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
@ -41,29 +44,46 @@ import org.floens.chan.utils.Utils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; 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_ITEM = 0;
private static final int VIEW_TYPE_STATUS = 1; private static final int VIEW_TYPE_STATUS = 1;
private final Object lock = new Object();
private final Context context; private final Context context;
private final ThreadManager threadManager;
private final AbsListView listView; private final AbsListView listView;
private final ThreadManager threadManager;
private final PostAdapterListener listener;
/**
* The list with the original data
*/
private final List<Post> sourceList = new ArrayList<>();
/**
* The list that is displayed (filtered)
*/
private final List<Post> displayList = new ArrayList<>();
private boolean endOfLine; private boolean endOfLine;
private final List<Post> postList = new ArrayList<>();
private int lastPostCount = 0; private int lastPostCount = 0;
private long lastViewedTime = 0; private long lastViewedTime = 0;
private String loadMessage = null; 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; context = activity;
this.threadManager = threadManager; this.threadManager = threadManager;
this.listView = listView; this.listView = listView;
this.listener = listener;
} }
@Override @Override
public int getCount() { public int getCount() {
return postList.size() + (showStatusView() ? 1 : 0); return displayList.size() + (showStatusView() ? 1 : 0);
} }
@Override @Override
@ -73,8 +93,8 @@ public class PostAdapter extends BaseAdapter {
@Override @Override
public int getItemViewType(int position) { public int getItemViewType(int position) {
if (showStatusView()) { if (position == getCount() - 1) {
return position == getCount() - 1 ? VIEW_TYPE_STATUS : VIEW_TYPE_ITEM; return showStatusView() ? VIEW_TYPE_STATUS : VIEW_TYPE_ITEM;
} else { } else {
return VIEW_TYPE_ITEM; return VIEW_TYPE_ITEM;
} }
@ -82,8 +102,9 @@ public class PostAdapter extends BaseAdapter {
@Override @Override
public Post getItem(int position) { public Post getItem(int position) {
if (position >= 0 && position < postList.size()) { int realPosition = position;
return postList.get(position); if (realPosition >= 0 && realPosition < displayList.size()) {
return displayList.get(realPosition);
} else { } else {
return null; return null;
} }
@ -102,7 +123,7 @@ public class PostAdapter extends BaseAdapter {
switch (getItemViewType(position)) { switch (getItemViewType(position)) {
case VIEW_TYPE_ITEM: { 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 = new PostView(context);
convertView.setTag(VIEW_TYPE_ITEM); convertView.setTag(VIEW_TYPE_ITEM);
} }
@ -120,42 +141,63 @@ public class PostAdapter extends BaseAdapter {
return null; return null;
} }
private void onGetBottomView() { public Filter getFilter() {
if (threadManager.getLoadable().isBoardMode() && !endOfLine) { return new Filter() {
// Try to load more posts @Override
threadManager.requestNextData(); protected FilterResults performFiltering(CharSequence constraintRaw) {
FilterResults results = new FilterResults();
if (TextUtils.isEmpty(constraintRaw)) {
ArrayList<Post> tmp;
synchronized (lock) {
tmp = new ArrayList<>(sourceList);
}
results.values = tmp;
} else {
List<Post> all;
synchronized (lock) {
all = new ArrayList<>(sourceList);
} }
if (lastPostCount != postList.size()) { List<Post> accepted = new ArrayList<>();
lastPostCount = postList.size(); String constraint = constraintRaw.toString().toLowerCase(Locale.ENGLISH);
lastViewedTime = Time.get();
for (Post post : all) {
if (post.comment.toString().toLowerCase(Locale.ENGLISH).contains(constraint)) {
accepted.add(post);
}
} }
if (Time.get(lastViewedTime) > 1000L) { results.values = accepted;
lastViewedTime = Time.get();
threadManager.bottomPostViewed();
} }
return results;
} }
private boolean showStatusView() { @Override
Loadable l = threadManager.getLoadable(); protected void publishResults(CharSequence constraint, final FilterResults results) {
if (l != null) { filter = constraint.toString();
if (l.isBoardMode()) { synchronized (lock) {
return true; displayList.clear();
} else if (l.isThreadMode() && threadManager.shouldWatch()) { displayList.addAll((List<Post>) results.values);
return true;
} else {
return false;
} }
} else { notifyDataSetChanged();
return false; listener.onFilterResults(filter, ((List<Post>) results.values).size(), TextUtils.isEmpty(filter));
} }
};
}
public void setFilter(String filter) {
getFilter().filter(filter);
notifyDataSetChanged();
} }
public void appendList(List<Post> list) { public void appendList(List<Post> list) {
synchronized (lock) {
boolean flag;
for (Post post : list) { for (Post post : list) {
boolean flag = true; flag = true;
for (Post own : postList) { for (Post own : sourceList) {
if (post.no == own.no) { if (post.no == own.no) {
flag = false; flag = false;
break; break;
@ -163,7 +205,15 @@ public class PostAdapter extends BaseAdapter {
} }
if (flag) { if (flag) {
postList.add(post); sourceList.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<Post> list) { public void setList(List<Post> list) {
postList.clear(); synchronized (lock) {
postList.addAll(list); sourceList.clear();
sourceList.addAll(list);
if (!isFiltering()) {
displayList.clear();
displayList.addAll(sourceList);
} else {
setFilter(filter);
}
}
notifyDataSetChanged(); notifyDataSetChanged();
} }
public List<Post> getList() { public List<Post> getList() {
return postList; return sourceList;
} }
public void setEndOfLine(boolean endOfLine) { public void setEndOfLine(boolean endOfLine) {
@ -190,8 +249,9 @@ public class PostAdapter extends BaseAdapter {
public void scrollToPost(int no) { public void scrollToPost(int no) {
notifyDataSetChanged(); notifyDataSetChanged();
for (int i = 0; i < postList.size(); i++) { synchronized (lock) {
if (postList.get(i).no == no) { for (int i = 0; i < displayList.size(); i++) {
if (displayList.get(i).no == no) {
if (Math.abs(i - listView.getFirstVisiblePosition()) > 20 || listView.getChildCount() == 0) { if (Math.abs(i - listView.getFirstVisiblePosition()) > 20 || listView.getChildCount() == 0) {
listView.setSelection(i); listView.setSelection(i);
} else { } else {
@ -203,6 +263,7 @@ public class PostAdapter extends BaseAdapter {
} }
} }
} }
}
public void setErrorMessage(String loadMessage) { public void setErrorMessage(String loadMessage) {
this.loadMessage = loadMessage; this.loadMessage = loadMessage;
@ -212,6 +273,40 @@ public class PostAdapter extends BaseAdapter {
return loadMessage; 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 { public class StatusView extends LinearLayout {
boolean detached = false; boolean detached = false;
@ -232,11 +327,14 @@ public class PostAdapter extends BaseAdapter {
public void init() { public void init() {
Loader loader = threadManager.getLoader(); Loader loader = threadManager.getLoader();
if (loader == null) if (loader == null || loader.getLoadable() == null)
return; return;
setGravity(Gravity.CENTER); setGravity(Gravity.CENTER);
Loadable loadable = loader.getLoadable();
if (loadable.isThreadMode()) {
if (threadManager.shouldWatch()) { if (threadManager.shouldWatch()) {
String error = getErrorMessage(); String error = getErrorMessage();
if (error != null) { if (error != null) {
@ -273,6 +371,9 @@ public class PostAdapter extends BaseAdapter {
Utils.setPressedDrawable(this); Utils.setPressedDrawable(this);
} else { } else {
setText("");
}
} else if (loadable.isBoardMode()) {
if (endOfLine) { if (endOfLine) {
setText(context.getString(R.string.thread_load_end_of_line)); setText(context.getString(R.string.thread_load_end_of_line));
} else { } else {

@ -18,9 +18,11 @@
package org.floens.chan.ui.fragment; package org.floens.chan.ui.fragment;
import android.app.Fragment; import android.app.Fragment;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.os.Bundle; import android.os.Bundle;
import android.util.AttributeSet;
import android.view.Gravity; import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
@ -29,6 +31,7 @@ import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener; import android.widget.AbsListView.OnScrollListener;
import android.widget.GridView; import android.widget.GridView;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView; import android.widget.ListView;
import android.widget.RelativeLayout; import android.widget.RelativeLayout;
import android.widget.TextView; import android.widget.TextView;
@ -52,7 +55,7 @@ import org.floens.chan.utils.Utils;
import java.util.List; 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 BaseActivity baseActivity;
private ThreadManager threadManager; private ThreadManager threadManager;
private Loadable loadable; private Loadable loadable;
@ -61,9 +64,13 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
private LoadView container; private LoadView container;
private AbsListView listView; private AbsListView listView;
private ImageView skip; private ImageView skip;
private FilterView filterView;
private SkipLogic skipLogic; private SkipLogic skipLogic;
private int highlightedPost = -1; private int highlightedPost = -1;
private ThreadManager.ViewMode viewMode = ThreadManager.ViewMode.LIST; private ThreadManager.ViewMode viewMode = ThreadManager.ViewMode.LIST;
private String lastFilter = "";
private boolean isFiltering = false;
public static ThreadFragment newInstance(BaseActivity activity) { public static ThreadFragment newInstance(BaseActivity activity) {
ThreadFragment fragment = new ThreadFragment(); ThreadFragment fragment = new ThreadFragment();
@ -112,6 +119,13 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
return threadManager.getLoader(); return threadManager.getLoader();
} }
public void setFilter(String filter) {
if (!filter.equals(lastFilter) && postAdapter != null) {
lastFilter = filter;
postAdapter.setFilter(filter);
}
}
@Override @Override
public void onDestroy() { public void onDestroy() {
super.onDestroy(); super.onDestroy();
@ -193,10 +207,17 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
if (postAdapter == null) { if (postAdapter == null) {
RelativeLayout compound = new RelativeLayout(baseActivity); 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) { if (viewMode == ThreadManager.ViewMode.LIST) {
ListView list = new ListView(baseActivity); ListView list = new ListView(baseActivity);
listView = list; listView = list;
postAdapter = new PostAdapter(baseActivity, threadManager, listView); postAdapter = new PostAdapter(baseActivity, threadManager, listView, this);
listView.setAdapter(postAdapter); listView.setAdapter(postAdapter);
list.setSelectionFromTop(loadable.listViewIndex, loadable.listViewTop); list.setSelectionFromTop(loadable.listViewIndex, loadable.listViewTop);
} else if (viewMode == ThreadManager.ViewMode.GRID) { } else if (viewMode == ThreadManager.ViewMode.GRID) {
@ -210,7 +231,7 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
grid.setVerticalSpacing(postGridSpacing); grid.setVerticalSpacing(postGridSpacing);
grid.setHorizontalSpacing(postGridSpacing); grid.setHorizontalSpacing(postGridSpacing);
listView = grid; listView = grid;
postAdapter = new PostAdapter(baseActivity, threadManager, listView); postAdapter = new PostAdapter(baseActivity, threadManager, listView, this);
listView.setAdapter(postAdapter); listView.setAdapter(postAdapter);
listView.setSelection(loadable.listViewIndex); listView.setSelection(loadable.listViewIndex);
} }
@ -218,25 +239,35 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
listView.setOnScrollListener(new OnScrollListener() { listView.setOnScrollListener(new OnScrollListener() {
@Override @Override
public void onScrollStateChanged(AbsListView view, int scrollState) { public void onScrollStateChanged(AbsListView view, int scrollState) {
if (!isFiltering) {
if (skipLogic != null) { if (skipLogic != null) {
skipLogic.onScrollStateChanged(view, scrollState); skipLogic.onScrollStateChanged(view, scrollState);
} }
} }
}
@Override @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (!isFiltering) {
if (loadable != null) { if (loadable != null) {
loadable.listViewIndex = view.getFirstVisiblePosition(); int index = view.getFirstVisiblePosition();
View v = view.getChildAt(0); View v = view.getChildAt(0);
loadable.listViewTop = (v == null) ? 0 : v.getTop(); int top = v == null ? 0 : v.getTop();
if (index != 0 || top != 0) {
loadable.listViewIndex = index;
loadable.listViewTop = top;
}
} }
if (skipLogic != null) { if (skipLogic != null) {
skipLogic.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); 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()) { if (loadable.isThreadMode()) {
skip = new ImageView(baseActivity); skip = new ImageView(baseActivity);
@ -292,6 +323,19 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
highlightedPost = -1; 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() { private void setEmpty() {
postAdapter = null; postAdapter = null;
@ -400,4 +444,35 @@ public class ThreadFragment extends Fragment implements ThreadManager.ThreadMana
up = false; 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);
}
}
} }

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?><!--
<!--
Clover - 4chan browser https://github.com/Floens/Clover/ Clover - 4chan browser https://github.com/Floens/Clover/
Copyright (C) 2014 Floens Copyright (C) 2014 Floens
@ -79,21 +78,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
android:title="@string/action_reload" /> android:title="@string/action_reload" />
<item <item
android:id="@+id/action_share" android:id="@+id/action_search"
android:actionViewClass="android.widget.SearchView"
android:orderInCategory="6" android:orderInCategory="6"
android:showAsAction="never|collapseActionView"
android:title="@string/action_search" />
<item
android:id="@+id/action_search_tablet"
android:orderInCategory="6"
android:showAsAction="never"
android:title="@string/action_search">
<menu>
<item
android:id="@+id/action_search_board"
android:title="@string/action_search_board" />
<item
android:id="@+id/action_search_thread"
android:title="@string/action_search_thread" />
</menu>
</item>
<item
android:id="@+id/action_share"
android:actionProviderClass="android.widget.ShareActionProvider"
android:orderInCategory="7"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/action_share" android:title="@string/action_share" />
android:actionProviderClass="android.widget.ShareActionProvider"/>
<item <item
android:id="@+id/action_open_browser" android:id="@+id/action_open_browser"
android:orderInCategory="7" android:orderInCategory="8"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/action_open_browser" /> android:title="@string/action_open_browser" />
<item <item
android:id="@+id/action_board_view_mode" android:id="@+id/action_board_view_mode"
android:orderInCategory="8" android:orderInCategory="9"
android:showAsAction="never" android:showAsAction="never"
android:title="@string/action_board_view_mode"> android:title="@string/action_board_view_mode">
<menu> <menu>

@ -41,6 +41,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="action_board_view_mode_list">List</string> <string name="action_board_view_mode_list">List</string>
<string name="action_board_view_mode_grid">Grid</string> <string name="action_board_view_mode_grid">Grid</string>
<string name="action_settings_advanced">Advanced</string> <string name="action_settings_advanced">Advanced</string>
<string name="action_search">Search</string>
<string name="action_search_board">Search board</string>
<string name="action_search_thread">Search thread</string>
<string name="search_hint">Search posts</string>
<string name="search_results">Found %1$s %2$s for "%3$s"</string>
<string name="open_unknown_title">Unsupported link</string> <string name="open_unknown_title">Unsupported link</string>
<string name="open_unknown">Clover can\'t open this link. Opening it in your browser instead.</string> <string name="open_unknown">Clover can\'t open this link. Opening it in your browser instead.</string>
@ -81,6 +87,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
<string name="multiple_replies">replies</string> <string name="multiple_replies">replies</string>
<string name="one_image">image</string> <string name="one_image">image</string>
<string name="multiple_images">images</string> <string name="multiple_images">images</string>
<string name="one_post">post</string>
<string name="multiple_posts">posts</string>
<string name="post_info">Info</string> <string name="post_info">Info</string>
<string-array name="post_options"> <string-array name="post_options">
<item>Quick reply</item> <item>Quick reply</item>

Loading…
Cancel
Save