Bug 1022102 - Polish search bar interaction and styling. r=eedens

This commit is contained in:
Margaret Leibovic 2014-07-18 16:49:32 -07:00
parent d2ee603161
commit 325dbd5865
16 changed files with 140 additions and 153 deletions

View File

@ -37,9 +37,6 @@ public class PreSearchFragment extends ListFragment {
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View headerView = getLayoutInflater(savedInstanceState)
.inflate(R.layout.search_stream_header, getListView(), false);
getListView().addHeaderView(headerView, null, false);
if (null == adapter) {
adapter = new ArrayAdapter<PreloadAgent.TmpItem>(getActivity(), R.layout.search_card,
R.id.card_title, PreloadAgent.ITEMS) {

View File

@ -5,6 +5,7 @@
package org.mozilla.search.autocomplete;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
@ -22,7 +23,6 @@ import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
@ -48,20 +48,21 @@ public class SearchFragment extends Fragment
// Maximum number of results returned by the suggestion client
private static final int SUGGESTION_MAX = 5;
private View mainView;
private FrameLayout backdropFrame;
private EditText searchBar;
private ListView suggestionDropdown;
private InputMethodManager inputMethodManager;
private AutoCompleteAdapter autoCompleteAdapter;
private SuggestClient suggestClient;
private SuggestionLoaderCallbacks suggestionLoaderCallbacks;
private State state;
private InputMethodManager inputMethodManager;
private AutoCompleteAdapter autoCompleteAdapter;
private enum State {
private View mainView;
private View searchBar;
private EditText editText;
private Button clearButton;
private ListView suggestionDropdown;
private State state = State.WAITING;
private static enum State {
WAITING, // The user is doing something else in the app.
RUNNING // The user is in search mode.
}
@ -70,20 +71,58 @@ public class SearchFragment extends Fragment
// Required empty public constructor
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// TODO: Don't hard-code this template string (bug 1039758)
final String template = "https://search.yahoo.com/sugg/ff?" +
"output=fxjson&appid=ffm&command=__searchTerms__&nresults=" + SUGGESTION_MAX;
suggestClient = new SuggestClient(activity, template, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
suggestionLoaderCallbacks = new SuggestionLoaderCallbacks();
inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
autoCompleteAdapter = new AutoCompleteAdapter(activity, this);
}
@Override
public void onDetach() {
super.onDetach();
suggestClient = null;
suggestionLoaderCallbacks = null;
inputMethodManager = null;
autoCompleteAdapter = null;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mainView = inflater.inflate(R.layout.search_auto_complete, container, false);
backdropFrame = (FrameLayout) mainView.findViewById(R.id.auto_complete_backdrop);
searchBar = (EditText) mainView.findViewById(R.id.auto_complete_search_bar);
suggestionDropdown = (ListView) mainView.findViewById(R.id.auto_complete_dropdown);
inputMethodManager =
(InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
// Intercept clicks on the main view to deactivate the search bar.
mainView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
transitionToWaiting();
}
});
searchBar = mainView.findViewById(R.id.search_bar);
editText = (EditText) mainView.findViewById(R.id.search_bar_edit_text);
final View.OnClickListener transitionToRunningListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
transitionToRunning();
}
};
searchBar.setOnClickListener(transitionToRunningListener);
editText.setOnClickListener(transitionToRunningListener);
// Attach a listener for the "search" key on the keyboard.
searchBar.addTextChangedListener(new TextWatcher() {
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@ -99,66 +138,44 @@ public class SearchFragment extends Fragment
getLoaderManager().restartLoader(LOADER_ID_SUGGESTION, args, suggestionLoaderCallbacks);
}
});
searchBar.setOnEditorActionListener(this);
searchBar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (v.hasFocus()) {
return;
}
transitionToRunning();
}
});
editText.setOnEditorActionListener(this);
final Button clearButton = (Button) mainView.findViewById(R.id.clear_button);
clearButton = (Button) mainView.findViewById(R.id.search_bar_clear_button);
clearButton.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v) {
searchBar.setText("");
editText.setText("");
}
});
backdropFrame.setOnClickListener(new BackdropClickListener());
autoCompleteAdapter = new AutoCompleteAdapter(getActivity(), this);
suggestionDropdown = (ListView) mainView.findViewById(R.id.auto_complete_dropdown);
suggestionDropdown.setAdapter(autoCompleteAdapter);
// This will hide the autocomplete box and background frame.
transitionToWaiting();
// Attach listener for tapping on a suggestion.
suggestionDropdown.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String query = (String) suggestionDropdown.getItemAtPosition(position);
final String query = (String) suggestionDropdown.getItemAtPosition(position);
startSearch(query);
}
});
// TODO: Don't hard-code this template string (bug 1039758)
final String template = "https://search.yahoo.com/sugg/ff?" +
"output=fxjson&appid=ffm&command=__searchTerms__&nresults=" + SUGGESTION_MAX;
suggestClient = new SuggestClient(getActivity(), template, SUGGESTION_TIMEOUT, SUGGESTION_MAX);
suggestionLoaderCallbacks = new SuggestionLoaderCallbacks();
return mainView;
}
@Override
public void onDestroyView() {
super.onDestroyView();
inputMethodManager = null;
mainView = null;
searchBar = null;
editText = null;
clearButton = null;
if (null != suggestionDropdown) {
suggestionDropdown.setOnItemClickListener(null);
suggestionDropdown.setAdapter(null);
suggestionDropdown = null;
}
autoCompleteAdapter = null;
suggestClient = null;
suggestionLoaderCallbacks = null;
}
/**
@ -178,8 +195,8 @@ public class SearchFragment extends Fragment
*/
private void startSearch(String queryString) {
if (getActivity() instanceof AcceptsSearchQuery) {
searchBar.setText(queryString);
searchBar.setSelection(queryString.length());
editText.setText(queryString);
editText.setSelection(queryString.length());
transitionToWaiting();
((AcceptsSearchQuery) getActivity()).onSearch(queryString);
} else {
@ -191,12 +208,13 @@ public class SearchFragment extends Fragment
if (state == State.WAITING) {
return;
}
searchBar.setFocusable(false);
searchBar.setFocusableInTouchMode(false);
searchBar.clearFocus();
inputMethodManager.hideSoftInputFromWindow(searchBar.getWindowToken(), 0);
setEditTextFocusable(false);
mainView.setClickable(false);
suggestionDropdown.setVisibility(View.GONE);
backdropFrame.setVisibility(View.GONE);
clearButton.setVisibility(View.GONE);
state = State.WAITING;
}
@ -204,20 +222,34 @@ public class SearchFragment extends Fragment
if (state == State.RUNNING) {
return;
}
searchBar.setFocusable(true);
searchBar.setFocusableInTouchMode(true);
searchBar.requestFocus();
inputMethodManager.showSoftInput(searchBar, InputMethodManager.SHOW_IMPLICIT);
setEditTextFocusable(true);
mainView.setClickable(true);
suggestionDropdown.setVisibility(View.VISIBLE);
backdropFrame.setVisibility(View.VISIBLE);
clearButton.setVisibility(View.VISIBLE);
state = State.RUNNING;
}
private void setEditTextFocusable(boolean focusable) {
editText.setFocusable(focusable);
editText.setFocusableInTouchMode(focusable);
if (focusable) {
editText.requestFocus();
inputMethodManager.showSoftInput(editText, InputMethodManager.SHOW_IMPLICIT);
} else {
editText.clearFocus();
inputMethodManager.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}
}
@Override
public void onJumpTap(String suggestion) {
searchBar.setText(suggestion);
editText.setText(suggestion);
// Move cursor to end of search input.
searchBar.setSelection(suggestion.length());
editText.setSelection(suggestion.length());
}
private class SuggestionLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<String>> {
@ -292,18 +324,4 @@ public class SearchFragment extends Fragment
suggestions = null;
}
}
/**
* Click handler for the backdrop. This should:
* - Remove focus from the search bar
* - Hide the keyboard
* - Hide the backdrop
* - Hide the suggestion box.
*/
private class BackdropClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
transitionToWaiting();
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 550 B

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 473 B

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 679 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -14,7 +14,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.mozilla.search.PostSearchFragment"
android:layout_marginTop="@dimen/webview_height_offset"
android:layout_marginTop="@dimen/search_bar_height"
android:id="@+id/postsearch"
/>
@ -22,14 +22,13 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.mozilla.search.PreSearchFragment"
android:layout_marginTop="@dimen/search_bar_height"
android:id="@+id/presearch"
/>
<fragment
android:layout_width="match_parent"
android:layout_height="match_parent"
android:name="org.mozilla.search.autocomplete.SearchFragment"
android:id="@+id/header_fragments"
/>
android:name="org.mozilla.search.autocomplete.SearchFragment"/>
</merge>

View File

@ -2,51 +2,49 @@
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".autocomplete.AutoCompleteFragment"
>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:clickable="false"
tools:context=".autocomplete.AutoCompleteFragment">
<FrameLayout
android:id="@+id/auto_complete_backdrop"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#a71f1f1f"
android:clickable="true"
android:focusable="true"/>
<LinearLayout
android:layout_width="fill_parent"
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/search_card_background"
android:orientation="vertical"
>
android:padding="10dp">
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/search_bar_edit_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="actionSearch"
android:inputType="textNoSuggestions|textVisiblePassword"
android:drawableLeft="@drawable/search_icon"
android:drawablePadding="10dp"
android:focusable="false"
android:focusableInTouchMode="false"
android:hint="@string/search_bar_hint"/>
<EditText
android:id="@+id/auto_complete_search_bar"
style="@style/AutoCompleteEditText"/>
<Button
android:id="@+id/search_bar_clear_button"
android:layout_width="14dp"
android:layout_height="14dp"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="10dp"
android:background="@drawable/search_clear"
android:visibility="gone"/>
<Button
android:id="@+id/clear_button"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="3dp"
android:background="@drawable/search_clear" />
</FrameLayout>
</FrameLayout>
<ListView
android:id="@+id/auto_complete_dropdown"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff"
android:visibility="gone"/>
<ListView
android:id="@+id/auto_complete_dropdown"
style="@style/AutoCompleteDropdown"/>
</LinearLayout>
</FrameLayout>
</LinearLayout>

View File

@ -1,12 +0,0 @@
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="100dp"
android:scaleType="centerCrop"
android:src="@drawable/search_header"
android:contentDescription="@string/search_header_image_content_description">
</ImageView>

View File

@ -6,7 +6,7 @@
<color name="transparent">#00FFFFFF</color>
<color name="highlight_orange">#FF9500</color>
<!-- card colors -->
<color name="card_background">#ffffff</color>

View File

@ -6,5 +6,5 @@
<!--This is used to offset the webview so that it is not covered-->
<!--by the search bar. If we change the height of the search bar-->
<!--then this will need to be updated.-->
<dimen name="webview_height_offset">55dp</dimen>
<dimen name="search_bar_height">55dp</dimen>
</resources>

View File

@ -13,19 +13,4 @@
<style name="BorderLessButton">
</style>
<style name="AutoCompleteDropdown">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:background">#fff</item>
<item name="android:layout_margin">10dp</item>
</style>
<style name="AutoCompleteEditText">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:imeOptions">actionSearch</item>
<item name="android:inputType">textNoSuggestions|textVisiblePassword</item>
</style>
</resources>

View File

@ -5,3 +5,4 @@
<!ENTITY search_jump_arrow '&#8598;'>
<!ENTITY search_app_name 'Firefox Search'>
<!ENTITY search_header_image_content_description 'Firefox Search Header Image'>
<!ENTITY search_bar_hint 'Search for anything'>

View File

@ -1,3 +1,4 @@
<string name="search_app_name">&search_app_name;</string>
<string name="search_jump_arrow">&search_jump_arrow;</string>
<string name="search_header_image_content_description">&search_header_image_content_description;</string>
<string name="search_bar_hint">&search_bar_hint;</string>