jenkins-bot has submitted this change and it was merged.

Change subject: Integrate Search fragment into overhaul.
......................................................................


Integrate Search fragment into overhaul.

Remaining things to do:
- Fill in all the callback functions to have the proper effect.
- Implement correct Back behavior.

Change-Id: I37aef4b3274d6b6ae019ac73d12d4db76ed9dd4a
---
M app/src/main/java/org/wikipedia/overhaul/OverhaulFragment.java
A app/src/main/java/org/wikipedia/search/OverhaulSearchFragment.java
M app/src/main/java/org/wikipedia/search/RecentSearchesFragment.java
M app/src/main/java/org/wikipedia/search/SearchArticlesFragment.java
M app/src/main/java/org/wikipedia/search/SearchResultsFragment.java
M app/src/main/java/org/wikipedia/views/ViewUtil.java
M app/src/main/res/layout/fragment_overhaul.xml
A app/src/main/res/layout/fragment_search_overhaul.xml
8 files changed, 790 insertions(+), 60 deletions(-)

Approvals:
  BearND: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/app/src/main/java/org/wikipedia/overhaul/OverhaulFragment.java 
b/app/src/main/java/org/wikipedia/overhaul/OverhaulFragment.java
index c2ebdc4..e4656f6 100644
--- a/app/src/main/java/org/wikipedia/overhaul/OverhaulFragment.java
+++ b/app/src/main/java/org/wikipedia/overhaul/OverhaulFragment.java
@@ -23,18 +23,23 @@
 import org.wikipedia.overhaul.navtab.NavTab;
 import org.wikipedia.overhaul.navtab.NavTabViewPagerAdapter;
 import org.wikipedia.page.PageTitle;
+import org.wikipedia.readinglist.AddToReadingListDialog;
 import org.wikipedia.readinglist.ReadingListsFragment;
+import org.wikipedia.search.OverhaulSearchFragment;
+import org.wikipedia.search.SearchResultsFragment;
 
 import butterknife.BindView;
 import butterknife.ButterKnife;
 import butterknife.Unbinder;
 
 public class OverhaulFragment extends Fragment implements 
FeedFragment.Callback,
-        NearbyFragment.Callback, HistoryFragment.Callback, 
ReadingListsFragment.Callback {
+        NearbyFragment.Callback, HistoryFragment.Callback, 
ReadingListsFragment.Callback,
+        OverhaulSearchFragment.Callback, SearchResultsFragment.Callback {
     @BindView(R.id.fragment_overhaul_view_pager) ViewPager viewPager;
     @BindView(R.id.view_nav_view_pager_tab_layout) TabLayout tabLayout;
     private Unbinder unbinder;
     private NavTabChangeListener pagerChangeListener = new 
NavTabChangeListener();
+    private OverhaulSearchFragment searchFragment;
 
     public interface Callback {
         void onTabChanged(@NonNull NavTab tab, @NonNull Fragment fragment);
@@ -57,6 +62,7 @@
         viewPager.setAdapter(new 
NavTabViewPagerAdapter(getChildFragmentManager()));
         tabLayout.setupWithViewPager(viewPager);
 
+        searchFragment = (OverhaulSearchFragment) 
getChildFragmentManager().findFragmentById(R.id.search_fragment);
         return view;
     }
 
@@ -68,7 +74,8 @@
     }
 
     @Override public void onFeedSearchRequested() {
-        // todo: [overhaul] search.
+        
searchFragment.setInvokeSource(OverhaulSearchFragment.InvokeSource.FEED_BAR);
+        searchFragment.openSearch();
     }
 
     @Override public void onFeedVoiceSearchRequested() {
@@ -145,4 +152,39 @@
                     ((NavTabViewPagerAdapter) 
viewPager.getAdapter()).getCurrentFragment());
         }
     }
+
+    @Override
+    public void onSearchResultCopyLink(@NonNull PageTitle title) {
+        // TODO: implement
+    }
+
+    @Override
+    public void onSearchResultAddToList(@NonNull PageTitle title, @NonNull 
AddToReadingListDialog.InvokeSource source) {
+        // TODO: implement
+    }
+
+    @Override
+    public void onSearchResultShareLink(@NonNull PageTitle title) {
+        // TODO: implement
+    }
+
+    @Override
+    public void onSearchProgressBar(boolean enabled) {
+        // TODO: implement
+    }
+
+    @Override
+    public void onSearchSelectPage(@NonNull HistoryEntry entry, boolean 
inNewTab) {
+        // TODO: implement
+    }
+
+    @Override
+    public void onSearchOpen() {
+        // TODO: implement
+    }
+
+    @Override
+    public void onSearchClose() {
+        // TODO: implement
+    }
 }
\ No newline at end of file
diff --git a/app/src/main/java/org/wikipedia/search/OverhaulSearchFragment.java 
b/app/src/main/java/org/wikipedia/search/OverhaulSearchFragment.java
new file mode 100644
index 0000000..a39c647
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/search/OverhaulSearchFragment.java
@@ -0,0 +1,504 @@
+package org.wikipedia.search;
+
+import android.content.DialogInterface;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v7.widget.SearchView;
+import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.squareup.otto.Subscribe;
+
+import org.wikipedia.BackPressedHandler;
+import org.wikipedia.R;
+import org.wikipedia.WikipediaApp;
+import org.wikipedia.activity.FragmentUtil;
+import org.wikipedia.analytics.SearchFunnel;
+import org.wikipedia.concurrency.SaneAsyncTask;
+import org.wikipedia.database.contract.SearchHistoryContract;
+import org.wikipedia.events.WikipediaZeroStateChangeEvent;
+import org.wikipedia.history.HistoryEntry;
+import org.wikipedia.model.EnumCode;
+import org.wikipedia.model.EnumCodeMap;
+import org.wikipedia.page.PageTitle;
+import org.wikipedia.settings.LanguagePreferenceDialog;
+import org.wikipedia.util.FeedbackUtil;
+import org.wikipedia.views.ViewUtil;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.Unbinder;
+
+public class OverhaulSearchFragment extends Fragment implements 
BackPressedHandler,
+        SearchResultsFragment.Parent, RecentSearchesFragment.Parent {
+    public enum InvokeSource implements EnumCode {
+        TOOLBAR(0),
+        WIDGET(1),
+        INTENT_SHARE(2),
+        INTENT_PROCESS_TEXT(3),
+        FEED_BAR(4),
+        VOICE(5);
+
+        private static final EnumCodeMap<InvokeSource> MAP = new 
EnumCodeMap<>(InvokeSource.class);
+
+        private final int code;
+
+        public static InvokeSource of(int code) {
+            return MAP.get(code);
+        }
+
+        @Override public int code() {
+            return code;
+        }
+
+        InvokeSource(int code) {
+            this.code = code;
+        }
+
+        public boolean fromIntent() {
+            return code == WIDGET.code() || code == INTENT_SHARE.code()
+                    || code == INTENT_PROCESS_TEXT.code();
+        }
+    }
+
+    public interface Callback {
+        void onSearchSelectPage(@NonNull HistoryEntry entry, boolean inNewTab);
+        void onSearchOpen();
+        void onSearchClose();
+    }
+
+    private static final String ARG_LAST_SEARCHED_TEXT = "lastSearchedText";
+    private static final String ARG_SEARCH_CURRENT_PANEL = 
"searchCurrentPanel";
+    private static final String ARG_INVOKE_SOURCE = "invokeSource";
+
+    private static final int PANEL_RECENT_SEARCHES = 0;
+    private static final int PANEL_SEARCH_RESULTS = 1;
+
+    @BindView(R.id.search_container) View searchContainer;
+    @BindView(R.id.search_toolbar) Toolbar toolbar;
+    @BindView(R.id.search_cab_view) SearchView searchView;
+    @BindView(R.id.search_progress_bar) ProgressBar progressBar;
+    @BindView(R.id.search_lang_button_container) View langButtonContainer;
+    @BindView(R.id.search_lang_button) TextView langButton;
+    private Unbinder unbinder;
+
+    private WikipediaApp app;
+    private EditText searchEditText;
+    private SearchFunnel funnel;
+    private InvokeSource invokeSource = InvokeSource.TOOLBAR;
+
+    /**
+     * Whether the Search fragment is currently showing.
+     */
+    private boolean isSearchActive = false;
+
+    /**
+     * The last search term that the user entered. This will be passed into
+     * the TitleSearch and FullSearch sub-fragments.
+     */
+    private String lastSearchedText;
+
+    private RecentSearchesFragment recentSearchesFragment;
+    private SearchResultsFragment searchResultsFragment;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        app = WikipediaApp.getInstance();
+        funnel = new SearchFunnel(WikipediaApp.getInstance(), 
SearchArticlesFragment.InvokeSource.of(invokeSource.code()));
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public View onCreateView(final LayoutInflater inflater, ViewGroup 
container, Bundle savedInstanceState) {
+        app = WikipediaApp.getInstance();
+        View view = inflater.inflate(R.layout.fragment_search_overhaul, 
container, false);
+        unbinder = ButterKnife.bind(this, view);
+
+        searchContainer.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                // Give the root container view an empty click handler, so 
that click events won't
+                // get passed down to any underlying views (e.g. a 
PageFragment on top of which
+                // this fragment is shown)
+            }
+        });
+
+        FragmentManager childFragmentManager = getChildFragmentManager();
+        recentSearchesFragment = 
(RecentSearchesFragment)childFragmentManager.findFragmentById(
+                R.id.search_panel_recent);
+        searchResultsFragment = 
(SearchResultsFragment)childFragmentManager.findFragmentById(
+                R.id.fragment_search_results);
+
+        // make sure we're hidden by default
+        searchContainer.setVisibility(View.GONE);
+
+        if (savedInstanceState != null) {
+            lastSearchedText = 
savedInstanceState.getString(ARG_LAST_SEARCHED_TEXT);
+            invokeSource = 
InvokeSource.of(savedInstanceState.getInt(ARG_INVOKE_SOURCE));
+            showPanel(savedInstanceState.getInt(ARG_SEARCH_CURRENT_PANEL));
+        }
+
+        initSearchView();
+        initLangButton();
+        return view;
+    }
+
+    @Override
+    public void onDestroyView() {
+        unbinder.unbind();
+        unbinder = null;
+        super.onDestroyView();
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putString(ARG_LAST_SEARCHED_TEXT, lastSearchedText);
+        outState.putInt(ARG_SEARCH_CURRENT_PANEL, getActivePanel());
+        outState.putInt(ARG_INVOKE_SOURCE, invokeSource.code());
+    }
+
+    @Override
+    @NonNull
+    public SearchFunnel getFunnel() {
+        return funnel;
+    }
+
+    public void setInvokeSource(InvokeSource source) {
+        invokeSource = source;
+    }
+
+    public boolean isLaunchedFromIntent() {
+        return invokeSource.fromIntent();
+    }
+
+    @Override
+    public void switchToSearch(@NonNull String queryText) {
+        startSearch(queryText, true);
+        searchView.setQuery(queryText, false);
+    }
+
+    /**
+     * Changes the search text box to contain a different string.
+     * @param text The text you want to make the search box display.
+     */
+    @Override
+    public void setSearchText(@NonNull CharSequence text) {
+        searchView.setQuery(text, false);
+    }
+
+    /**
+     * Show a particular panel, which can be one of:
+     * - PANEL_RECENT_SEARCHES
+     * - PANEL_SEARCH_RESULTS
+     * Automatically hides the previous panel.
+     * @param panel Which panel to show.
+     */
+    private void showPanel(int panel) {
+        switch (panel) {
+            case PANEL_RECENT_SEARCHES:
+                searchResultsFragment.hide();
+                recentSearchesFragment.show();
+                break;
+            case PANEL_SEARCH_RESULTS:
+                recentSearchesFragment.hide();
+                searchResultsFragment.show();
+                break;
+            default:
+                break;
+        }
+    }
+
+    private int getActivePanel() {
+        if (searchResultsFragment.isShowing()) {
+            return PANEL_SEARCH_RESULTS;
+        } else {
+            //otherwise, the recent searches must be showing:
+            return PANEL_RECENT_SEARCHES;
+        }
+    }
+
+    @Subscribe
+    public void onWikipediaZeroStateChangeEvent(WikipediaZeroStateChangeEvent 
event) {
+        updateZeroChrome();
+    }
+
+    /**
+     * Kick off a search, based on a given search term. Will automatically 
pass the search to
+     * Title search or Full search, based on which one is currently displayed.
+     * If the search term is empty, the "recent searches" view will be shown.
+     * @param term Phrase to search for.
+     * @param force Whether to "force" starting this search. If the search is 
not forced, the
+     *              search may be delayed by a small time, so that network 
requests are not sent
+     *              too often.  If the search is forced, the network request 
is sent immediately.
+     */
+    public void startSearch(String term, boolean force) {
+        if (!isSearchActive) {
+            openSearch();
+        }
+
+        if (TextUtils.isEmpty(term)) {
+            showPanel(PANEL_RECENT_SEARCHES);
+        } else if (getActivePanel() == PANEL_RECENT_SEARCHES) {
+            //start with title search...
+            showPanel(PANEL_SEARCH_RESULTS);
+        }
+
+        lastSearchedText = term;
+
+        searchResultsFragment.startSearch(term, force);
+    }
+
+    /**
+     * Activate the Search fragment.
+     */
+    public void openSearch() {
+        // create a new funnel every time Search is opened, to get a new 
session ID
+        funnel = new SearchFunnel(WikipediaApp.getInstance(), 
SearchArticlesFragment.InvokeSource.of(invokeSource.code()));
+        funnel.searchStart();
+        isSearchActive = true;
+        Callback callback = callback();
+        if (callback != null) {
+            callback.onSearchOpen();
+        }
+        // show ourselves
+        ViewUtil.fadeIn(searchContainer);
+
+        // if the current search string is empty, then it's a fresh start, so 
we'll show
+        // recent searches by default. Otherwise, the currently-selected panel 
should already
+        // be visible, so we don't need to do anything.
+        if (TextUtils.isEmpty(lastSearchedText)) {
+            showPanel(PANEL_RECENT_SEARCHES);
+        }
+
+        searchView.setIconified(false);
+        searchView.requestFocusFromTouch();
+        // if we already have a previous search query, then put it into the 
SearchView, and it will
+        // automatically trigger the showing of the corresponding search 
results.
+        if (isValidQuery(lastSearchedText)) {
+            searchView.setQuery(lastSearchedText, false);
+            searchEditText.selectAll();
+        }
+    }
+
+    public void closeSearch() {
+        isSearchActive = false;
+        Callback callback = callback();
+        if (callback != null) {
+            callback.onSearchClose();
+        }
+        // hide ourselves
+        ViewUtil.fadeOut(searchContainer);
+        addRecentSearch(lastSearchedText);
+    }
+
+    /**
+     * Determine whether the Search fragment is currently active.
+     * @return Whether the Search fragment is active.
+     */
+    public boolean isSearchActive() {
+        return isSearchActive;
+    }
+
+    @Override
+    public boolean onBackPressed() {
+        if (isSearchActive) {
+            closeSearch();
+            funnel.searchCancel();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void setProgressBarEnabled(boolean enabled) {
+        progressBar.setVisibility(enabled ? View.VISIBLE : View.GONE);
+    }
+
+    private void initSearchView() {
+        searchView.setOnQueryTextListener(searchQueryListener);
+        searchView.setOnCloseListener(searchCloseListener);
+
+        searchEditText = (EditText) searchView
+                
.findViewById(android.support.v7.appcompat.R.id.search_src_text);
+        // reset its background
+        searchEditText.setBackgroundColor(Color.TRANSPARENT);
+        // make the search frame match_parent
+        View searchEditFrame = searchView
+                
.findViewById(android.support.v7.appcompat.R.id.search_edit_frame);
+        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, 
ViewGroup.LayoutParams.MATCH_PARENT);
+        searchEditFrame.setLayoutParams(params);
+        // center the search text in it
+        searchEditText.setGravity(Gravity.CENTER_VERTICAL);
+        // remove focus line from search plate
+        View searchEditPlate = searchView
+                .findViewById(android.support.v7.appcompat.R.id.search_plate);
+        searchEditPlate.setBackgroundColor(Color.TRANSPARENT);
+
+        ImageView searchClose = (ImageView) searchView.findViewById(
+                android.support.v7.appcompat.R.id.search_close_btn);
+        FeedbackUtil.setToolbarButtonLongPressToast(searchClose);
+    }
+
+    private void initLangButton() {
+        langButton.setText(app.getAppOrSystemLanguageCode().toUpperCase());
+        formatLangButtonText();
+        langButtonContainer.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                showLangPreferenceDialog();
+            }
+        });
+        FeedbackUtil.setToolbarButtonLongPressToast(langButtonContainer);
+    }
+
+    /*
+    Update any UI elements related to WP Zero
+     */
+    private void updateZeroChrome() {
+        if (searchEditText != null) {
+            // setting the hint directly on the search EditText (instead of 
the SearchView)
+            // gets rid of the magnify icon, which we don't want.
+            
searchEditText.setHint(app.getWikipediaZeroHandler().isZeroEnabled() ? 
getString(
+                    R.string.zero_search_hint) : 
getString(R.string.search_hint));
+        }
+    }
+
+    private boolean isValidQuery(String queryText) {
+        return queryText != null && TextUtils.getTrimmedLength(queryText) > 0;
+    }
+
+    private final SearchView.OnQueryTextListener searchQueryListener = new 
SearchView.OnQueryTextListener() {
+        @Override
+        public boolean onQueryTextSubmit(String queryText) {
+            PageTitle firstResult = null;
+            if (getActivePanel() == PANEL_SEARCH_RESULTS) {
+                firstResult = searchResultsFragment.getFirstResult();
+            }
+            if (firstResult != null) {
+                navigateToTitle(firstResult, false, 0);
+                closeSearch();
+            }
+            return true;
+        }
+
+        @Override
+        public boolean onQueryTextChange(String queryText) {
+            startSearch(queryText.trim(), false);
+            return true;
+        }
+    };
+
+    private final SearchView.OnCloseListener searchCloseListener = new 
SearchView.OnCloseListener() {
+        @Override
+        public boolean onClose() {
+            closeSearch();
+            funnel.searchCancel();
+            return false;
+        }
+    };
+
+    @Override
+    public void navigateToTitle(@NonNull PageTitle title, boolean inNewTab, 
int position) {
+        if (!isAdded()) {
+            return;
+        }
+        funnel.searchClick(position);
+        HistoryEntry historyEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_SEARCH);
+        closeSearch();
+        Callback callback = callback();
+        if (callback != null) {
+            callback.onSearchSelectPage(historyEntry, inNewTab);
+        }
+    }
+
+    private void addRecentSearch(String title) {
+        if (isValidQuery(title)) {
+            new SaveRecentSearchTask(new RecentSearch(title)).execute();
+        }
+    }
+
+    private final class SaveRecentSearchTask extends SaneAsyncTask<Void> {
+        private final RecentSearch entry;
+        SaveRecentSearchTask(RecentSearch entry) {
+            this.entry = entry;
+        }
+
+        @Override
+        public Void performTask() throws Throwable {
+            app.getDatabaseClient(RecentSearch.class).upsert(entry, 
SearchHistoryContract.Query.SELECTION);
+            return null;
+        }
+
+        @Override
+        public void onFinish(Void result) {
+            super.onFinish(result);
+            recentSearchesFragment.updateList();
+        }
+
+        @Override
+        public void onCatch(Throwable caught) {
+            Log.w("SaveRecentSearchTask", "Caught " + caught.getMessage(), 
caught);
+        }
+    }
+
+    private void formatLangButtonText() {
+        final int langCodeStandardLength = 3;
+        final int langButtonTextMaxLength = 7;
+
+        // These values represent scaled pixels (sp)
+        final int langButtonTextSizeSmaller = 10;
+        final int langButtonTextSizeLarger = 13;
+
+        String langCode = app.getAppOrSystemLanguageCode();
+        if (langCode.length() > langCodeStandardLength) {
+            langButton.setTextSize(langButtonTextSizeSmaller);
+            if (langCode.length() > langButtonTextMaxLength) {
+                langButton.setText(langCode.substring(0, 
langButtonTextMaxLength).toUpperCase());
+            }
+            return;
+        }
+        langButton.setTextSize(langButtonTextSizeLarger);
+    }
+
+    @Nullable
+    private Callback callback() {
+        return FragmentUtil.getCallback(this, Callback.class);
+    }
+
+    public void showLangPreferenceDialog() {
+        LanguagePreferenceDialog langPrefDialog = new 
LanguagePreferenceDialog(getContext(), true);
+        langPrefDialog.setOnDismissListener(new 
DialogInterface.OnDismissListener() {
+            @Override
+            public void onDismiss(DialogInterface dialog) {
+                
langButton.setText(app.getAppOrSystemLanguageCode().toUpperCase());
+                formatLangButtonText();
+                if (!TextUtils.isEmpty(lastSearchedText)) {
+                    startSearch(lastSearchedText, true);
+                }
+            }
+        });
+        langPrefDialog.show();
+    }
+}
diff --git a/app/src/main/java/org/wikipedia/search/RecentSearchesFragment.java 
b/app/src/main/java/org/wikipedia/search/RecentSearchesFragment.java
index 57eddc2..23c3b77 100644
--- a/app/src/main/java/org/wikipedia/search/RecentSearchesFragment.java
+++ b/app/src/main/java/org/wikipedia/search/RecentSearchesFragment.java
@@ -1,14 +1,17 @@
 package org.wikipedia.search;
 
 import android.content.Context;
+import android.content.DialogInterface;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
+import android.support.annotation.NonNull;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.CursorLoader;
 import android.support.v4.content.Loader;
 import android.support.v4.widget.CursorAdapter;
+import android.support.v7.app.AlertDialog;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -18,13 +21,19 @@
 import android.widget.TextView;
 
 import org.wikipedia.R;
+import org.wikipedia.WikipediaApp;
 import org.wikipedia.database.contract.SearchHistoryContract;
+import org.wikipedia.util.FeedbackUtil;
 
 import static org.wikipedia.Constants.RECENT_SEARCHES_FRAGMENT_LOADER_ID;
 
 /** Displays a list of recent searches */
 public class RecentSearchesFragment extends Fragment implements 
LoaderManager.LoaderCallbacks<Cursor> {
-    private SearchArticlesFragment searchFragment;
+    public interface Parent {
+        void switchToSearch(@NonNull String text);
+    }
+
+    private Parent parentFragment;
     private View container;
     private ListView recentSearchesList;
     private RecentSearchesAdapter adapter;
@@ -33,10 +42,30 @@
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
Bundle savedInstanceState) {
         View rootView = inflater.inflate(R.layout.fragment_search_recent, 
container, false);
-        searchFragment = (SearchArticlesFragment) getParentFragment();
+        parentFragment = (Parent) getParentFragment();
         this.container = rootView.findViewById(R.id.recent_searches_container);
         recentSearchesList = (ListView) 
rootView.findViewById(R.id.recent_searches_list);
+
         deleteButton = (ImageView) 
rootView.findViewById(R.id.recent_searches_delete_button);
+        deleteButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                new AlertDialog.Builder(getContext())
+                        
.setMessage(getString(R.string.clear_recent_searches_confirm))
+                        .setPositiveButton(
+                                getString(R.string.yes),
+                                new DialogInterface.OnClickListener() {
+                                    @Override
+                                    public void onClick(DialogInterface 
dialog, int id) {
+                                        new 
DeleteAllRecentSearchesTask(WikipediaApp.getInstance()).execute();
+                                    }
+                                })
+                        .setNegativeButton(getString(R.string.no), null)
+                        .create().show();
+            }
+        });
+        FeedbackUtil.setToolbarButtonLongPressToast(deleteButton);
+
         return rootView;
     }
 
@@ -58,7 +87,7 @@
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
                 RecentSearch entry = (RecentSearch) view.getTag();
-                searchFragment.switchToSearch(entry.getText());
+                parentFragment.switchToSearch(entry.getText());
             }
         });
 
diff --git a/app/src/main/java/org/wikipedia/search/SearchArticlesFragment.java 
b/app/src/main/java/org/wikipedia/search/SearchArticlesFragment.java
index d7711a2..398166a 100644
--- a/app/src/main/java/org/wikipedia/search/SearchArticlesFragment.java
+++ b/app/src/main/java/org/wikipedia/search/SearchArticlesFragment.java
@@ -7,7 +7,6 @@
 import android.support.annotation.Nullable;
 import android.support.v4.app.Fragment;
 import android.support.v4.app.FragmentManager;
-import android.support.v7.app.AlertDialog;
 import android.support.v7.widget.SearchView;
 import android.text.TextUtils;
 import android.util.Log;
@@ -41,7 +40,8 @@
 
 import static org.wikipedia.util.DimenUtil.getContentTopOffsetPx;
 
-public class SearchArticlesFragment extends Fragment implements 
BackPressedHandler {
+public class SearchArticlesFragment extends Fragment implements 
BackPressedHandler,
+        SearchResultsFragment.Parent, RecentSearchesFragment.Parent {
     public enum InvokeSource implements EnumCode {
         TOOLBAR(0),
         WIDGET(1),
@@ -143,26 +143,6 @@
             }
         });
 
-        final View deleteButton = 
parentLayout.findViewById(R.id.recent_searches_delete_button);
-        deleteButton.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View view) {
-                new AlertDialog.Builder(getContext())
-                        
.setMessage(getString(R.string.clear_recent_searches_confirm))
-                        .setPositiveButton(
-                                getString(R.string.yes),
-                                new DialogInterface.OnClickListener() {
-                                    @Override
-                                    public void onClick(DialogInterface 
dialog, int id) {
-                                        new 
DeleteAllRecentSearchesTask(app).execute();
-                                    }
-                                })
-                        .setNegativeButton(getString(R.string.no), null)
-                        .create().show();
-            }
-        });
-        FeedbackUtil.setToolbarButtonLongPressToast(deleteButton);
-
         FragmentManager childFragmentManager = getChildFragmentManager();
         recentSearchesFragment = 
(RecentSearchesFragment)childFragmentManager.findFragmentById(
                 R.id.search_panel_recent);
@@ -194,6 +174,8 @@
         outState.putInt(ARG_INVOKE_SOURCE, invokeSource.code());
     }
 
+    @Override
+    @NonNull
     public SearchFunnel getFunnel() {
         return funnel;
     }
@@ -206,7 +188,8 @@
         return invokeSource.fromIntent();
     }
 
-    public void switchToSearch(String queryText) {
+    @Override
+    public void switchToSearch(@NonNull String queryText) {
         startSearch(queryText, true);
         searchView.setQuery(queryText, false);
     }
@@ -215,7 +198,8 @@
      * Changes the search text box to contain a different string.
      * @param text The text you want to make the search box display.
      */
-    public void setSearchText(CharSequence text) {
+    @Override
+    public void setSearchText(@NonNull CharSequence text) {
         searchView.setQuery(text, false);
     }
 
@@ -333,6 +317,10 @@
             return true;
         }
         return false;
+    }
+
+    @Override
+    public void setProgressBarEnabled(boolean enabled) {
     }
 
     private void setSearchViewEnabled(boolean enabled) {
@@ -460,7 +448,8 @@
         }
     };
 
-    public void navigateToTitle(PageTitle title, boolean inNewTab, int 
position) {
+    @Override
+    public void navigateToTitle(@NonNull PageTitle title, boolean inNewTab, 
int position) {
         if (!isAdded()) {
             return;
         }
diff --git a/app/src/main/java/org/wikipedia/search/SearchResultsFragment.java 
b/app/src/main/java/org/wikipedia/search/SearchResultsFragment.java
index 743a449..b2907e6 100644
--- a/app/src/main/java/org/wikipedia/search/SearchResultsFragment.java
+++ b/app/src/main/java/org/wikipedia/search/SearchResultsFragment.java
@@ -3,6 +3,7 @@
 import org.wikipedia.LongPressHandler;
 import org.wikipedia.ParcelableLruCache;
 import org.wikipedia.activity.FragmentUtil;
+import org.wikipedia.analytics.SearchFunnel;
 import org.wikipedia.history.HistoryEntry;
 import org.wikipedia.page.PageTitle;
 import org.wikipedia.R;
@@ -44,6 +45,13 @@
         void onSearchProgressBar(boolean enabled);
     }
 
+    public interface Parent {
+        void navigateToTitle(@NonNull PageTitle item, boolean inNewTab, int 
position);
+        void setSearchText(@NonNull CharSequence text);
+        @NonNull SearchFunnel getFunnel();
+        void setProgressBarEnabled(boolean enabled);
+    }
+
     private static final int BATCH_SIZE = 20;
     private static final int DELAY_MILLIS = 300;
     private static final int MESSAGE_SEARCH = 1;
@@ -54,7 +62,7 @@
      */
     private static final int NANO_TO_MILLI = 1_000_000;
 
-    private SearchArticlesFragment searchFragment;
+    private Parent parentFragment;
     private View searchResultsDisplay;
     private View searchResultsContainer;
     private ListView searchResultsList;
@@ -81,7 +89,7 @@
     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
Bundle savedInstanceState) {
         View rootView = inflater.inflate(R.layout.fragment_search_results, 
container, false);
         searchResultsDisplay = 
rootView.findViewById(R.id.search_results_display);
-        searchFragment = (SearchArticlesFragment) getParentFragment();
+        parentFragment = (Parent) getParentFragment();
 
         searchResultsContainer = 
rootView.findViewById(R.id.search_results_container);
         searchResultsList = (ListView) 
rootView.findViewById(R.id.search_results_list);
@@ -97,7 +105,7 @@
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
                 PageTitle item = ((SearchResult) 
getAdapter().getItem(position)).getPageTitle();
-                searchFragment.navigateToTitle(item, false, position);
+                parentFragment.navigateToTitle(item, false, position);
             }
         });
 
@@ -110,8 +118,8 @@
             public void onClick(View view) {
                 String suggestion = (String) searchSuggestion.getTag();
                 if (suggestion != null) {
-                    searchFragment.getFunnel().searchDidYouMean();
-                    searchFragment.setSearchText(suggestion);
+                    parentFragment.getFunnel().searchDidYouMean();
+                    parentFragment.setSearchText(suggestion);
                     startSearch(suggestion, true);
                 }
             }
@@ -230,7 +238,7 @@
                 if (!resultList.isEmpty()) {
                     // Calculate total time taken to display results, in 
milliseconds
                     final int timeToDisplay = (int) ((System.nanoTime() - 
startTime) / NANO_TO_MILLI);
-                    searchFragment.getFunnel().searchResults(false, 
resultList.size(), timeToDisplay);
+                    parentFragment.getFunnel().searchResults(false, 
resultList.size(), timeToDisplay);
                 }
 
                 updateProgressBar(false);
@@ -277,7 +285,7 @@
                 }
                 // Calculate total time taken to display results, in 
milliseconds
                 final int timeToDisplay = (int) ((System.nanoTime() - 
startTime) / NANO_TO_MILLI);
-                searchFragment.getFunnel().searchError(false, timeToDisplay);
+                parentFragment.getFunnel().searchError(false, timeToDisplay);
                 updateProgressBar(false);
 
                 searchErrorView.setVisibility(View.VISIBLE);
@@ -333,7 +341,7 @@
                 if (!resultList.isEmpty()) {
                     // Calculate total time taken to display results, in 
milliseconds
                     final int timeToDisplay = (int) ((System.nanoTime() - 
startTime) / NANO_TO_MILLI);
-                    searchFragment.getFunnel().searchResults(true, 
resultList.size(), timeToDisplay);
+                    parentFragment.getFunnel().searchResults(true, 
resultList.size(), timeToDisplay);
                 }
 
                 // append results to cache...
@@ -358,7 +366,7 @@
                 }
                 // Calculate total time taken to display results, in 
milliseconds
                 final int timeToDisplay = (int) ((System.nanoTime() - 
startTime) / NANO_TO_MILLI);
-                searchFragment.getFunnel().searchError(true, timeToDisplay);
+                parentFragment.getFunnel().searchError(true, timeToDisplay);
                 updateProgressBar(false);
 
                 // since this is a follow-up search just show a message
@@ -381,8 +389,10 @@
     }
 
     private void updateProgressBar(boolean enabled) {
+        parentFragment.setProgressBarEnabled(enabled);
         Callback callback = callback();
         if (callback != null) {
+            // TODO: remove this callback item after overhaul
             callback.onSearchProgressBar(enabled);
         }
     }
@@ -446,12 +456,12 @@
 
         @Override
         public void onOpenLink(PageTitle title, HistoryEntry entry) {
-            searchFragment.navigateToTitle(title, false, 
lastPositionRequested);
+            parentFragment.navigateToTitle(title, false, 
lastPositionRequested);
         }
 
         @Override
         public void onOpenInNewTab(PageTitle title, HistoryEntry entry) {
-            searchFragment.navigateToTitle(title, true, lastPositionRequested);
+            parentFragment.navigateToTitle(title, true, lastPositionRequested);
         }
     }
 
diff --git a/app/src/main/java/org/wikipedia/views/ViewUtil.java 
b/app/src/main/java/org/wikipedia/views/ViewUtil.java
index d0e65ea..e9fa710 100644
--- a/app/src/main/java/org/wikipedia/views/ViewUtil.java
+++ b/app/src/main/java/org/wikipedia/views/ViewUtil.java
@@ -1,5 +1,7 @@
 package org.wikipedia.views;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.annotation.TargetApi;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -120,5 +122,24 @@
         parent.addView(next, index);
     }
 
+    public static void fadeIn(@NonNull View view) {
+        view.setAlpha(0f);
+        view.setVisibility(View.VISIBLE);
+        view.animate().alpha(1f)
+                
.setDuration(view.getResources().getInteger(android.R.integer.config_shortAnimTime))
+                .setListener(null);
+    }
+
+    public static void fadeOut(@NonNull final View view) {
+        view.animate().alpha(0f)
+                
.setDuration(view.getResources().getInteger(android.R.integer.config_shortAnimTime))
+                .setListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                view.setVisibility(View.GONE);
+            }
+        });
+    }
+
     private ViewUtil() { }
 }
diff --git a/app/src/main/res/layout/fragment_overhaul.xml 
b/app/src/main/res/layout/fragment_overhaul.xml
index 6bba102..9ceee6a 100644
--- a/app/src/main/res/layout/fragment_overhaul.xml
+++ b/app/src/main/res/layout/fragment_overhaul.xml
@@ -1,27 +1,43 @@
 <?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:tools="http://schemas.android.com/tools";
     xmlns:app="http://schemas.android.com/apk/res-auto";
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <org.wikipedia.overhaul.navtab.NavTabLayout
-        android:id="@+id/view_nav_view_pager_tab_layout"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/view_nav_view_pager_tab_layout_height"
-        android:layout_alignParentBottom="true"
-        app:tabGravity="fill"
-        android:elevation="12dp"
-        android:background="@android:color/white"
-        app:tabIndicatorColor="@color/blue_liberal" />
 
-    <android.support.design.widget.CoordinatorLayout
-        android:id="@+id/fragment_overhaul_view_pager_container"
+    <RelativeLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+        <org.wikipedia.overhaul.navtab.NavTabLayout
+            android:id="@+id/view_nav_view_pager_tab_layout"
+            android:layout_width="match_parent"
+            
android:layout_height="@dimen/view_nav_view_pager_tab_layout_height"
+            android:layout_alignParentBottom="true"
+            app:tabGravity="fill"
+            android:elevation="12dp"
+            android:background="@android:color/white"
+            app:tabIndicatorColor="@color/blue_liberal" />
+
+        <android.support.design.widget.CoordinatorLayout
+            android:id="@+id/fragment_overhaul_view_pager_container"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_above="@id/view_nav_view_pager_tab_layout">
+            <org.wikipedia.readinglist.NoSwipeViewPager
+                android:id="@+id/fragment_overhaul_view_pager"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent" />
+        </android.support.design.widget.CoordinatorLayout>
+
+    </RelativeLayout>
+
+    <fragment
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_above="@id/view_nav_view_pager_tab_layout">
-        <org.wikipedia.readinglist.NoSwipeViewPager
-            android:id="@+id/fragment_overhaul_view_pager"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
-    </android.support.design.widget.CoordinatorLayout>
-</RelativeLayout>
+        android:id="@+id/search_fragment"
+        android:name="org.wikipedia.search.OverhaulSearchFragment"
+        android:layout="@id/view_nav_view_pager_tab_layout"
+        tools:layout="@layout/fragment_search_overhaul" />
+
+</FrameLayout>
diff --git a/app/src/main/res/layout/fragment_search_overhaul.xml 
b/app/src/main/res/layout/fragment_search_overhaul.xml
new file mode 100644
index 0000000..2443b21
--- /dev/null
+++ b/app/src/main/res/layout/fragment_search_overhaul.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:app="http://schemas.android.com/apk/res-auto";
+    xmlns:tools="http://schemas.android.com/tools";
+    android:id="@+id/search_container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <org.wikipedia.views.StatusBarBlankView
+        android:id="@+id/empty_status_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="@color/main_toolbar_background" />
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="?attr/actionBarSize"
+        android:background="@color/main_toolbar_background"
+        android:elevation="4dp">
+
+        <android.support.v7.widget.Toolbar
+            android:theme="@style/AppTheme.ToolbarTheme"
+            android:id="@+id/search_toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?attr/actionBarSize">
+
+            <LinearLayout
+                android:layout_width="match_parent"
+                android:layout_height="36dp"
+                android:layout_gravity="center_vertical"
+                android:layout_marginRight="4dp"
+                android:layout_marginEnd="4dp"
+                style="@style/AppTheme.SearchViewStyle">
+
+                <org.wikipedia.views.CabSearchView
+                    android:id="@+id/search_cab_view"
+                    android:layout_width="0dp"
+                    android:layout_height="36dp"
+                    android:layout_weight="1"
+                    android:layout_gravity="center_vertical"
+                    android:layout_marginLeft="8dp"
+                    android:layout_marginRight="8dp"
+                    android:layout_marginStart="8dp"
+                    android:layout_marginEnd="8dp"
+                    android:textSize="12sp"
+                    android:focusable="true"
+                    android:inputType="text"
+                    android:imeOptions="actionGo|flagNoExtractUi"
+                    app:cabEnabled="false" />
+
+                <FrameLayout
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:paddingTop="2dp"
+                    android:paddingBottom="2dp"
+                    android:paddingLeft="9dp"
+                    android:paddingRight="9dp"
+                    android:layout_marginRight="8dp"
+                    android:layout_marginEnd="8dp"
+                    android:id="@+id/search_lang_button_container"
+                    android:background="?attr/actionBarItemBackground"
+                    
android:contentDescription="@string/preference_title_language"
+                    android:clickable="true">
+                    <TextView
+                        android:id="@+id/search_lang_button"
+                        android:layout_width="30dp"
+                        android:layout_height="30dp"
+                        android:gravity="center"
+                        android:clickable="false"
+                        android:focusable="false"
+                        android:background="@drawable/lang_button_shape"
+                        style="@style/AppTheme.ActionModeStyle"
+                        android:textColor="@android:color/white" />
+                </FrameLayout>
+
+            </LinearLayout>
+
+        </android.support.v7.widget.Toolbar>
+
+        <ProgressBar
+            android:id="@+id/search_progress_bar"
+            style="@style/Widget.AppCompat.ProgressBar.Horizontal"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="-6.5dp"
+            android:layout_gravity="bottom"
+            android:elevation="4dp"
+            android:indeterminate="true"
+            android:indeterminateTint="@color/blue_progressive"
+            android:progressBackgroundTint="@color/blue_progressive_dark"
+            android:visibility="gone"
+            tools:visibility="visible"/>
+
+    </FrameLayout>
+
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="?attr/search_background_color">
+
+        <fragment
+            android:id="@+id/fragment_search_results"
+            android:name="org.wikipedia.search.SearchResultsFragment"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            tools:layout="@layout/fragment_search_results" />
+
+        <fragment
+            android:id="@+id/search_panel_recent"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:name="org.wikipedia.search.RecentSearchesFragment"
+            tools:layout="@layout/fragment_search_recent"/>
+
+    </FrameLayout>
+
+</LinearLayout>

-- 
To view, visit https://gerrit.wikimedia.org/r/302967
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I37aef4b3274d6b6ae019ac73d12d4db76ed9dd4a
Gerrit-PatchSet: 5
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Dbrant <dbr...@wikimedia.org>
Gerrit-Reviewer: BearND <bsitzm...@wikimedia.org>
Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org>
Gerrit-Reviewer: Dbrant <dbr...@wikimedia.org>
Gerrit-Reviewer: Mholloway <mhollo...@wikimedia.org>
Gerrit-Reviewer: Niedzielski <sniedziel...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to