Android: Searching

This commit is contained in:
jendib 2014-11-23 00:49:56 +01:00
parent c610364ef7
commit 1773998ca0
16 changed files with 253 additions and 56 deletions

View File

@ -102,6 +102,7 @@
<orderEntry type="library" exported="" name="support-annotations-21.0.2" level="project" />
<orderEntry type="library" exported="" name="imagezoom-1.0.5" level="project" />
<orderEntry type="library" exported="" name="support-v4-21.0.2" level="project" />
<orderEntry type="library" exported="" name="eventbus-2.4.0" level="project" />
<orderEntry type="library" exported="" name="android-query.0.26.8" level="project" />
<orderEntry type="library" exported="" name="appcompat-v7-21.0.2" level="project" />
<orderEntry type="library" exported="" name="android-async-http-1.4.6" level="project" />

View File

@ -35,4 +35,5 @@ dependencies {
compile 'com.android.support:recyclerview-v7:21.0.0'
compile 'com.loopj.android:android-async-http:1.4.6'
compile 'it.sephiroth.android.library.imagezoom:imagezoom:1.0.5'
compile 'de.greenrobot:eventbus:2.4.0'
}

View File

@ -27,12 +27,19 @@
android:label="@string/app_name"
android:logo="@drawable/ic_launcher"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="@xml/searchable" />
</activity>
<activity
android:name=".activity.DocumentActivity"
android:label=""
android:logo="@drawable/ic_launcher">
</activity>
<provider android:name=".provider.RecentSuggestionsProvider"
android:exported="false"
android:authorities="com.sismics.docs.provider.RecentSuggestionsProvider" />
</application>
</manifest>

View File

@ -23,7 +23,6 @@ public class MainApplication extends Application {
// TODO Fullscreen preview
// TODO Sharing
// TODO Error feedback
// TODO Searching
// TODO Printing
super.onCreate();

View File

@ -1,18 +1,28 @@
package com.sismics.docs.activity;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.SearchView;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import com.sismics.docs.R;
import com.sismics.docs.event.SearchEvent;
import com.sismics.docs.model.application.ApplicationContext;
import com.sismics.docs.provider.RecentSuggestionsProvider;
import org.json.JSONObject;
import de.greenrobot.event.EventBus;
/**
* Main activity.
@ -21,8 +31,8 @@ import com.sismics.docs.model.application.ApplicationContext;
*/
public class MainActivity extends ActionBarActivity {
private ListView drawerList;
private ActionBarDrawerToggle drawerToggle;
private MenuItem searchItem;
@Override
protected void onCreate(final Bundle args) {
@ -38,19 +48,8 @@ public class MainActivity extends ActionBarActivity {
// Setup the activity
setContentView(R.layout.main_activity);
// Cache view references
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerList = (ListView) findViewById(R.id.drawer_list);
// Drawer item click listener
drawerList.setOnItemClickListener(new ListView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
}
});
if (drawerLayout != null) {
// Enable ActionBar app icon to behave as action to toggle nav drawer
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
@ -61,7 +60,15 @@ public class MainActivity extends ActionBarActivity {
drawerToggle = new ActionBarDrawerToggle(this, drawerLayout,
R.string.drawer_open, R.string.drawer_close);
drawerLayout.setDrawerListener(drawerToggle);
}
// Fill the drawer user info
JSONObject userInfo = ApplicationContext.getInstance().getUserInfo();
TextView usernameTextView = (TextView) findViewById(R.id.usernameTextView);
usernameTextView.setText(userInfo.optString("username"));
TextView emailTextView = (TextView) findViewById(R.id.emailTextView);
emailTextView.setText(userInfo.optString("email"));
handleIntent(getIntent());
}
@Override
@ -70,7 +77,7 @@ public class MainActivity extends ActionBarActivity {
case android.R.id.home:
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (drawerToggle != null && drawerToggle.onOptionsItemSelected(item)) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
return true;
@ -83,24 +90,69 @@ public class MainActivity extends ActionBarActivity {
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
if (drawerToggle != null) {
// Sync the toggle state after onRestoreInstanceState has occurred.
drawerToggle.syncState();
}
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (drawerToggle != null) {
// Pass any configuration change to the drawer toggle
drawerToggle.onConfigurationChanged(newConfig);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main_activity, menu);
// Get the SearchView and set the searchable configuration
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchItem = menu.findItem(R.id.action_search);
SearchView searchView = (SearchView) searchItem.getActionView();
searchView.setSearchableInfo(searchManager.getSearchableInfo(getComponentName()));
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
EventBus.getDefault().post(new SearchEvent(null));
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("drawerItemSelected", drawerList.getCheckedItemPosition());
protected void onNewIntent(Intent intent) {
setIntent(intent);
handleIntent(intent);
}
/**
* Handle the incoming intent.
*
* @param intent Intent
*/
private void handleIntent(Intent intent) {
// Intent is consumed
setIntent(null);
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
// Perform a search query
String query = intent.getStringExtra(SearchManager.QUERY);
// Collapse the SearchView
if (searchItem != null) {
searchItem.collapseActionView();
}
// Save the query
SearchRecentSuggestions suggestions = new SearchRecentSuggestions(this, RecentSuggestionsProvider.AUTHORITY, RecentSuggestionsProvider.MODE);
suggestions.saveRecentQuery(query, null);
EventBus.getDefault().post(new SearchEvent(query));
}
}
}

View File

@ -88,14 +88,21 @@ public class DocListAdapter extends RecyclerView.Adapter<DocListAdapter.ViewHold
return documents.optJSONObject(position);
}
/**
* Clear the documents.
*/
public void clearDocuments() {
documents = new JSONArray();
notifyDataSetChanged();
}
/**
* Add documents to display.
*
* @param documents Documents
* @param reset Reset the list
*/
public void addDocuments(JSONArray documents, boolean reset) {
if (this.documents == null || reset) {
public void addDocuments(JSONArray documents) {
if (this.documents == null) {
this.documents = new JSONArray();
}

View File

@ -0,0 +1,31 @@
package com.sismics.docs.event;
/**
* Search event.
*
* @author bgamard.
*/
public class SearchEvent {
/**
* Search query.
*/
private String query;
/**
* Create a search event.
*
* @param query Query
*/
public SearchEvent(String query) {
this.query = query;
}
/**
* Getter of query.
*
* @return query
*/
public String getQuery() {
return query;
}
}

View File

@ -14,12 +14,15 @@ import com.sismics.docs.DividerItemDecoration;
import com.sismics.docs.R;
import com.sismics.docs.activity.DocumentActivity;
import com.sismics.docs.adapter.DocListAdapter;
import com.sismics.docs.event.SearchEvent;
import com.sismics.docs.listener.RecyclerItemClickListener;
import com.sismics.docs.resource.DocumentResource;
import org.apache.http.Header;
import org.json.JSONObject;
import de.greenrobot.event.EventBus;
/**
* @author bgamard.
*/
@ -27,12 +30,16 @@ public class DocListFragment extends Fragment {
/**
* Documents adapter.
*/
DocListAdapter adapter;
private DocListAdapter adapter;
/**
* Search query.
*/
private String query;
// Infinite scrolling things
private boolean loading = true;
private int previousTotal = 0;
int firstVisibleItem, visibleItemCount, totalItemCount;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -69,9 +76,9 @@ public class DocListFragment extends Fragment {
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
visibleItemCount = recyclerView.getChildCount();
totalItemCount = layoutManager.getItemCount();
firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
int visibleItemCount = recyclerView.getChildCount();
int totalItemCount = layoutManager.getItemCount();
int firstVisibleItem = layoutManager.findFirstVisibleItemPosition();
if (loading) {
if (totalItemCount > previousTotal) {
@ -80,26 +87,54 @@ public class DocListFragment extends Fragment {
}
}
if (!loading && totalItemCount - visibleItemCount <= firstVisibleItem + 3) {
loadDocuments();
loadDocuments(false);
loading = true;
}
}
});
// Grab the documents
loadDocuments();
loadDocuments(true);
EventBus.getDefault().register(this);
return view;
}
@Override
public void onDestroyView() {
EventBus.getDefault().unregister(this);
super.onDestroyView();
}
/**
* A search event has been fired.
*
* @param event Search event
*/
public void onEvent(SearchEvent event) {
query = event.getQuery();
loadDocuments(true);
}
/**
* Refresh the document list.
*
* @param reset If true, reload the documents
*/
private void loadDocuments() {
DocumentResource.list(getActivity(), adapter.getItemCount(), new JsonHttpResponseHandler() {
private void loadDocuments(final boolean reset) {
if (reset) {
loading = true;
previousTotal = 0;
adapter.clearDocuments();
if (getView() != null) {
getView().findViewById(R.id.progressBar).setVisibility(View.VISIBLE);
}
}
DocumentResource.list(getActivity(), reset ? 0 : adapter.getItemCount(), query, new JsonHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, JSONObject response) {
adapter.addDocuments(response.optJSONArray("documents"), false);
adapter.addDocuments(response.optJSONArray("documents"));
if (getView() != null) {
getView().findViewById(R.id.progressBar).setVisibility(View.GONE);
}

View File

@ -0,0 +1,17 @@
package com.sismics.docs.provider;
import android.content.SearchRecentSuggestionsProvider;
/**
* Search recent suggestions provider.
*
* @author bgamard.
*/
public class RecentSuggestionsProvider extends SearchRecentSuggestionsProvider {
public final static String AUTHORITY = "com.sismics.docs.provider.RecentSuggestionsProvider";
public final static int MODE = DATABASE_MODE_QUERIES;
public RecentSuggestionsProvider() {
setupSuggestions(AUTHORITY, MODE);
}
}

View File

@ -15,9 +15,11 @@ public class DocumentResource extends BaseResource {
* GET /document/list.
*
* @param context Context
* @param offset Offset
* @param query Search query
* @param responseHandler Callback
*/
public static void list(Context context, int offset, JsonHttpResponseHandler responseHandler) {
public static void list(Context context, int offset, String query, JsonHttpResponseHandler responseHandler) {
init(context);
RequestParams params = new RequestParams();
@ -25,6 +27,7 @@ public class DocumentResource extends BaseResource {
params.put("offset", offset);
params.put("sort_column", 3);
params.put("asc", false);
params.put("search", query);
client.get(getApiUrl(context) + "/document/list", params, responseHandler);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -18,12 +18,40 @@
android:layout_height="match_parent"
android:layout_gravity="start"
android:gravity="center"
android:orientation="vertical">
android:orientation="vertical"
android:background="#fff"
android:elevation="5dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#aaa"
android:padding="12dp"
android:orientation="vertical"
android:elevation="4dp">
<TextView
android:id="@+id/usernameTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:fontFamily="sans-serif"/>
<TextView
android:id="@+id/emailTextView"
android:layout_marginTop="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#fff"
android:fontFamily="sans-serif-light"/>
</LinearLayout>
<ListView
android:id="@+id/drawer_list"
android:layout_weight="1"
android:id="@+id/tagListView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="0dp"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp" />

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/action_search"
android:title="@string/action_search"
app:showAsAction="ifRoom"
app:actionViewClass="android.support.v7.widget.SearchView" />
</menu>

View File

@ -30,5 +30,6 @@
<string name="downloading_file">Downloading file number %1s</string>
<string name="download_document">Download all files</string>
<string name="downloading_document">Downloading document</string>
<string name="action_search">Search documents</string>
</resources>

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/app_name"
android:hint="@string/action_search"
android:searchSuggestAuthority="com.sismics.docs.provider.RecentSuggestionsProvider"
android:searchSuggestSelection=" ?">
</searchable>