diff --git a/docs-android/app/build.gradle b/docs-android/app/build.gradle index 8fc77c04..c9195ab8 100644 --- a/docs-android/app/build.gradle +++ b/docs-android/app/build.gradle @@ -3,7 +3,7 @@ buildscript { mavenCentral() } dependencies { - classpath 'com.android.tools.build:gradle:1.2.2' + classpath 'com.android.tools.build:gradle:1.2.3' } } apply plugin: 'com.android.application' diff --git a/docs-android/app/src/main/AndroidManifest.xml b/docs-android/app/src/main/AndroidManifest.xml index 0f669078..ff234698 100644 --- a/docs-android/app/src/main/AndroidManifest.xml +++ b/docs-android/app/src/main/AndroidManifest.xml @@ -26,7 +26,8 @@ + android:launchMode="singleTop" + android:windowSoftInputMode="adjustNothing"> diff --git a/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java b/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java index 496bc7e2..3d0e49c7 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java +++ b/docs-android/app/src/main/java/com/sismics/docs/activity/MainActivity.java @@ -21,6 +21,7 @@ import android.widget.TextView; import com.androidquery.util.AQUtility; import com.sismics.docs.R; import com.sismics.docs.adapter.TagListAdapter; +import com.sismics.docs.event.AdvancedSearchEvent; import com.sismics.docs.event.SearchEvent; import com.sismics.docs.fragment.SearchFragment; import com.sismics.docs.listener.JsonHttpResponseHandler; @@ -138,6 +139,8 @@ public class MainActivity extends AppCompatActivity { }); handleIntent(getIntent()); + + EventBus.getDefault().register(this); } @Override @@ -259,8 +262,18 @@ public class MainActivity extends AppCompatActivity { drawerLayout.closeDrawers(); } + /** + * An advanced search event has been fired. + * + * @param event Advanced search event + */ + public void onEventMainThread(AdvancedSearchEvent event) { + searchQuery(event.getQuery()); + } + @Override protected void onDestroy() { + EventBus.getDefault().unregister(this); if(isTaskRoot()) { int cacheSizeMb = PreferenceUtil.getIntegerPreference(this, PreferenceUtil.PREF_CACHE_SIZE, 10); AQUtility.cleanCacheAsync(this, cacheSizeMb * 1000000, cacheSizeMb * 1000000); diff --git a/docs-android/app/src/main/java/com/sismics/docs/event/AdvancedSearchEvent.java b/docs-android/app/src/main/java/com/sismics/docs/event/AdvancedSearchEvent.java new file mode 100644 index 00000000..c463f28e --- /dev/null +++ b/docs-android/app/src/main/java/com/sismics/docs/event/AdvancedSearchEvent.java @@ -0,0 +1,31 @@ +package com.sismics.docs.event; + +/** + * Advanced search event. + * + * @author bgamard. + */ +public class AdvancedSearchEvent { + /** + * Search query. + */ + private String query; + + /** + * Create an advanced search event. + * + * @param query Query + */ + public AdvancedSearchEvent(String query) { + this.query = query; + } + + /** + * Getter of query. + * + * @return query + */ + public String getQuery() { + return query; + } +} diff --git a/docs-android/app/src/main/java/com/sismics/docs/fragment/SearchFragment.java b/docs-android/app/src/main/java/com/sismics/docs/fragment/SearchFragment.java index b0d3ff52..93ead327 100644 --- a/docs-android/app/src/main/java/com/sismics/docs/fragment/SearchFragment.java +++ b/docs-android/app/src/main/java/com/sismics/docs/fragment/SearchFragment.java @@ -8,14 +8,19 @@ import android.support.annotation.NonNull; import android.support.v4.app.DialogFragment; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowManager; +import android.widget.CheckBox; +import android.widget.EditText; import android.widget.Spinner; import com.sismics.docs.R; import com.sismics.docs.adapter.LanguageAdapter; import com.sismics.docs.adapter.TagAutoCompleteAdapter; -import com.sismics.docs.event.SearchEvent; +import com.sismics.docs.event.AdvancedSearchEvent; +import com.sismics.docs.ui.view.DatePickerView; import com.sismics.docs.ui.view.TagsCompleteTextView; import com.sismics.docs.util.PreferenceUtil; +import com.sismics.docs.util.SearchQueryBuilder; import org.json.JSONArray; import org.json.JSONObject; @@ -49,8 +54,13 @@ public class SearchFragment extends DialogFragment { // Setup the view LayoutInflater inflater = getActivity().getLayoutInflater(); View view = inflater.inflate(R.layout.search_dialog, null); - Spinner languageSpinner = (Spinner) view.findViewById(R.id.languageSpinner); - TagsCompleteTextView tagsEditText = (TagsCompleteTextView) view.findViewById(R.id.tagsEditText); + final EditText searchEditText = (EditText) view.findViewById(R.id.searchEditText); + final EditText fulltextEditText = (EditText) view.findViewById(R.id.fulltextEditText); + final CheckBox sharedCheckbox = (CheckBox) view.findViewById(R.id.sharedCheckbox); + final Spinner languageSpinner = (Spinner) view.findViewById(R.id.languageSpinner); + final DatePickerView beforeDatePicker = (DatePickerView) view.findViewById(R.id.beforeDatePicker); + final DatePickerView afterDatePicker = (DatePickerView) view.findViewById(R.id.afterDatePicker); + final TagsCompleteTextView tagsEditText = (TagsCompleteTextView) view.findViewById(R.id.tagsEditText); // Language spinner LanguageAdapter languageAdapter = new LanguageAdapter(getActivity(), true); @@ -77,7 +87,32 @@ public class SearchFragment extends DialogFragment { builder.setView(view) .setPositiveButton(R.string.search, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int id) { - EventBus.getDefault().post(new SearchEvent(null)); + // Build the simple criterias + SearchQueryBuilder queryBuilder = new SearchQueryBuilder() + .simpleSearch(searchEditText.getText().toString()) + .shared(sharedCheckbox.isChecked()) + .language(((LanguageAdapter.Language) languageSpinner.getSelectedItem()).getId()) + .before(beforeDatePicker.getDate()) + .after(afterDatePicker.getDate()); + + // Fulltext criteria + String fulltextCriteria = fulltextEditText.getText().toString(); + if (!fulltextCriteria.trim().isEmpty()) { + String[] criterias = fulltextCriteria.split(" "); + for (String criteria : criterias) { + queryBuilder.fulltextSearch(criteria); + } + } + + // Tags criteria + for (Object object : tagsEditText.getObjects()) { + JSONObject tag = (JSONObject) object; + queryBuilder.tag(tag.optString("name")); + } + + // Send the advanced search event + EventBus.getDefault().post(new AdvancedSearchEvent(queryBuilder.build())); + getDialog().cancel(); } }) @@ -86,6 +121,8 @@ public class SearchFragment extends DialogFragment { getDialog().cancel(); } }); - return builder.create(); + Dialog dialog = builder.create(); + dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); + return dialog; } } diff --git a/docs-android/app/src/main/java/com/sismics/docs/util/SearchQueryBuilder.java b/docs-android/app/src/main/java/com/sismics/docs/util/SearchQueryBuilder.java new file mode 100644 index 00000000..54ab1f94 --- /dev/null +++ b/docs-android/app/src/main/java/com/sismics/docs/util/SearchQueryBuilder.java @@ -0,0 +1,151 @@ +package com.sismics.docs.util; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Search query builder. + * + * @author bgamard. + */ +public class SearchQueryBuilder { + /** + * The query. + */ + private StringBuilder query; + + /** + * Search separator. + */ + private static String SEARCH_SEPARATOR = " "; + + /** + * Search date format. + */ + private SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + + /** + * Build a query. + */ + public SearchQueryBuilder() { + query = new StringBuilder(); + } + + /** + * Add a simple search criteria. + * + * @param simpleSearch Simple search criteria + * @return The builder + */ + public SearchQueryBuilder simpleSearch(String simpleSearch) { + if (isValid(simpleSearch)) { + query.append(SEARCH_SEPARATOR).append(simpleSearch); + } + return this; + } + + /** + * Add a fulltext search criteria. + * + * @param fulltextSearch Fulltext search criteria + * @return The builder + */ + public SearchQueryBuilder fulltextSearch(String fulltextSearch) { + if (isValid(fulltextSearch)) { + query.append(SEARCH_SEPARATOR) + .append("full:") + .append(fulltextSearch); + } + return this; + } + + /** + * Add a language criteria. + * + * @param language Language criteria + * @return The builder + */ + public SearchQueryBuilder language(String language) { + if (isValid(language)) { + query.append(SEARCH_SEPARATOR) + .append("lang:") + .append(language); + } + return this; + } + + /** + * Add a shared criteria. + * + * @param shared Shared criteria + * @return The builder + */ + public SearchQueryBuilder shared(boolean shared) { + if (shared) { + query.append(SEARCH_SEPARATOR).append("shared:yes"); + } + return this; + } + + /** + * Add a tag criteria. + * + * @param tag Tag criteria + * @return The builder + */ + public SearchQueryBuilder tag(String tag) { + query.append(SEARCH_SEPARATOR) + .append("tag:") + .append(tag); + return this; + } + + /** + * Add a before date criteria. + * + * @param before Before date criteria + * @return The builder + */ + public SearchQueryBuilder before(Date before) { + if (before != null) { + query.append(SEARCH_SEPARATOR) + .append("before:") + .append(DATE_FORMAT.format(before)); + } + return this; + } + + /** + * Add an after date criteria. + * + * @param after After date criteria + * @return The builder + */ + public SearchQueryBuilder after(Date after) { + if (after != null) { + query.append(SEARCH_SEPARATOR) + .append("after:") + .append(DATE_FORMAT.format(after)); + } + return this; + } + + /** + * Build the query. + * + * @return The query + */ + public String build() { + return query.toString(); + } + + /** + * Return true if the search criteria is valid. + * + * @param criteria Search criteria + * @return True if the search criteria is valid + */ + private boolean isValid(String criteria) { + return criteria != null && !criteria.trim().isEmpty(); + } +}