Bug 1269027 - Add empty state for no synced devices. r=sebastian
authorChenxia Liu <liuche@mozilla.com>
Fri, 29 Apr 2016 15:38:19 -0700
changeset 362666 f410732bf7cf3cd523e68ff056a0a4c66b4fde94
parent 362665 5acbf0da132a32b5ce7873395f85866f178386bc
child 362667 9015ebea629332d283c11fdb8c525d5c1d20c8d2
push id17008
push userbgrinstead@mozilla.com
push dateMon, 02 May 2016 21:59:43 +0000
reviewerssebastian
bugs1269027
milestone49.0a1
Bug 1269027 - Add empty state for no synced devices. r=sebastian MozReview-Commit-ID: 2STg7zSgXF9
mobile/android/base/java/org/mozilla/gecko/home/CombinedHistoryAdapter.java
mobile/android/base/java/org/mozilla/gecko/home/CombinedHistoryPanel.java
mobile/android/base/resources/layout/history_sync_setup.xml
mobile/android/base/resources/layout/home_combined_history_panel.xml
mobile/android/base/resources/layout/remote_tabs_setup.xml
--- a/mobile/android/base/java/org/mozilla/gecko/home/CombinedHistoryAdapter.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/CombinedHistoryAdapter.java
@@ -10,17 +10,16 @@ import android.support.v7.widget.Recycle
 import android.database.Cursor;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.TextView;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.db.BrowserContract;
-import org.mozilla.gecko.db.RemoteTab;
 
 public class CombinedHistoryAdapter extends RecyclerView.Adapter<CombinedHistoryItem> implements CombinedHistoryRecyclerView.AdapterContextMenuBuilder {
     private static final int SYNCED_DEVICES_SMARTFOLDER_INDEX = 0;
 
     // Array for the time ranges in milliseconds covered by each section.
     static final HistorySectionsHelper.SectionDateRange[] sectionDateRangeArray = new HistorySectionsHelper.SectionDateRange[SectionHeader.values().length];
 
     // Semantic names for the time covered by each section
--- a/mobile/android/base/java/org/mozilla/gecko/home/CombinedHistoryPanel.java
+++ b/mobile/android/base/java/org/mozilla/gecko/home/CombinedHistoryPanel.java
@@ -5,16 +5,17 @@
 
 package org.mozilla.gecko.home;
 
 import android.accounts.Account;
 import android.app.AlertDialog;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.Intent;
 import android.database.Cursor;
 import android.os.Bundle;
 import android.support.v4.app.LoaderManager;
 import android.support.v4.content.Loader;
 import android.support.v4.widget.SwipeRefreshLayout;
 import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.RecyclerView;
 import android.text.SpannableStringBuilder;
@@ -24,28 +25,28 @@ import android.text.style.ClickableSpan;
 import android.text.style.UnderlineSpan;
 import android.util.Log;
 import android.view.ContextMenu;
 import android.view.LayoutInflater;
 import android.view.MenuInflater;
 import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewStub;
 import android.widget.Button;
 import android.widget.ImageView;
 import android.widget.TextView;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.EventDispatcher;
 import org.mozilla.gecko.GeckoAppShell;
 import org.mozilla.gecko.GeckoProfile;
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.RemoteClientsDialogFragment;
 import org.mozilla.gecko.fxa.FirefoxAccounts;
+import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.SyncStatusListener;
 import org.mozilla.gecko.restrictions.Restrictions;
 import org.mozilla.gecko.Telemetry;
 import org.mozilla.gecko.TelemetryContract;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.db.RemoteClient;
 import org.mozilla.gecko.restrictions.Restrictable;
 import org.mozilla.gecko.widget.DividerItemDecoration;
@@ -78,17 +79,18 @@ public class CombinedHistoryPanel extend
 
     // Child refresh layout view.
     protected SwipeRefreshLayout mRefreshLayout;
 
     // Sync listener that stops refreshing when a sync is completed.
     protected RemoteTabsSyncListener mSyncStatusListener;
 
     // Reference to the View to display when there are no results.
-    private View mEmptyView;
+    private View mHistoryEmptyView;
+    private View mClientsEmptyView;
 
     public interface OnPanelLevelChangeListener {
         enum PanelLevel {
         PARENT, CHILD
     }
 
         /**
          * Propagates level changes.
@@ -119,16 +121,20 @@ public class CombinedHistoryPanel extend
         super.onViewCreated(view, savedInstanceState);
 
         mRecyclerView = (CombinedHistoryRecyclerView) view.findViewById(R.id.combined_recycler_view);
         setUpRecyclerView();
 
         mRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh_layout);
         setUpRefreshLayout();
 
+        mClientsEmptyView = view.findViewById(R.id.home_clients_empty_view);
+        mHistoryEmptyView = view.findViewById(R.id.home_history_empty_view);
+        setUpEmptyViews();
+
         mPanelFooterButton = (Button) view.findViewById(R.id.clear_history_button);
         mPanelFooterButton.setOnClickListener(new OnFooterButtonClickListener());
     }
 
     private void setUpRecyclerView() {
         if (mPanelLevel == null) {
             mPanelLevel = OnPanelLevelChangeListener.PanelLevel.PARENT;
         }
@@ -148,16 +154,50 @@ public class CombinedHistoryPanel extend
         registerForContextMenu(mRecyclerView);
     }
 
     private void setUpRefreshLayout() {
         mRefreshLayout.setColorSchemeResources(R.color.fennec_ui_orange, R.color.action_orange);
         mRefreshLayout.setOnRefreshListener(new RemoteTabsRefreshListener());
     }
 
+    private void setUpEmptyViews() {
+        // Set up history empty view.
+        final ImageView emptyIcon = (ImageView) mHistoryEmptyView.findViewById(R.id.home_empty_image);
+        emptyIcon.setVisibility(View.GONE);
+
+        final TextView emptyText = (TextView) mHistoryEmptyView.findViewById(R.id.home_empty_text);
+        emptyText.setText(R.string.home_most_recent_empty);
+
+        final TextView emptyHint = (TextView) mHistoryEmptyView.findViewById(R.id.home_empty_hint);
+
+        if (!Restrictions.isAllowed(getActivity(), Restrictable.PRIVATE_BROWSING)) {
+            emptyHint.setVisibility(View.GONE);
+        } else {
+            final String hintText = getResources().getString(R.string.home_most_recent_emptyhint);
+            final SpannableStringBuilder hintBuilder = formatHintText(hintText);
+            if (hintBuilder != null) {
+                emptyHint.setText(hintBuilder);
+                emptyHint.setMovementMethod(LinkMovementMethod.getInstance());
+                emptyHint.setVisibility(View.VISIBLE);
+            }
+        }
+
+        // Set up Clients empty view.
+        final Button syncSetupButton = (Button) mClientsEmptyView.findViewById(R.id.sync_setup_button);
+        syncSetupButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View view) {
+                // This Activity will redirect to the correct Activity as needed.
+                final Intent intent = new Intent(FxAccountConstants.ACTION_FXA_GET_STARTED);
+                startActivity(intent);
+            }
+        });
+    }
+
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
         mCursorLoaderCallbacks = new CursorLoaderCallbacks();
     }
 
     @Override
     protected void load() {
@@ -248,34 +288,34 @@ public class CombinedHistoryPanel extend
         public boolean changeLevel(PanelLevel level) {
             if (level == mPanelLevel) {
                 return false;
             }
 
             mPanelLevel = level;
             switch (level) {
                 case PARENT:
-                    mRecyclerView.swapAdapter(mHistoryAdapter, false);
+                    mRecyclerView.swapAdapter(mHistoryAdapter, true);
                     break;
                 case CHILD:
                     mRecyclerView.swapAdapter(mClientsAdapter, true);
                     break;
             }
 
             updateEmptyView();
             updateButtonFromLevel();
             return true;
         }
     }
 
     private void updateButtonFromLevel() {
         switch (mPanelLevel) {
             case PARENT:
                 final boolean historyRestricted = !Restrictions.isAllowed(getActivity(), Restrictable.CLEAR_HISTORY);
-                if (historyRestricted || mHistoryAdapter.getItemCount() <= NUM_SMART_FOLDERS) {
+                if (historyRestricted || mHistoryAdapter.getItemCount() == NUM_SMART_FOLDERS) {
                     mPanelFooterButton.setVisibility(View.GONE);
                 } else {
                     mPanelFooterButton.setVisibility(View.VISIBLE);
                 }
                 break;
             case CHILD:
                 mPanelFooterButton.setVisibility(View.GONE);
                 break;
@@ -313,61 +353,35 @@ public class CombinedHistoryPanel extend
                 }
             });
 
             dialogBuilder.show();
         }
     }
 
     private void updateEmptyView() {
+        boolean showEmptyHistoryView = false;
+        boolean showEmptyClientsView = false;
         switch (mPanelLevel) {
             case PARENT:
-                final boolean showEmptyHistoryView = mHistoryAdapter.getItemCount() == NUM_SMART_FOLDERS && mClientsAdapter.getItemCount() == 1;
-                if (showEmptyHistoryView) {
-                    if (mEmptyView == null) {
-                        // Set empty panel view if it needs to be shown and hasn't been inflated.
-                        final ViewStub emptyViewStub = (ViewStub) getView().findViewById(R.id.home_empty_view_stub);
-                        mEmptyView = emptyViewStub.inflate();
-
-                        final ImageView emptyIcon = (ImageView) mEmptyView.findViewById(R.id.home_empty_image);
-                        emptyIcon.setImageResource(R.drawable.icon_most_recent_empty);
-
-                        final TextView emptyText = (TextView) mEmptyView.findViewById(R.id.home_empty_text);
-                        emptyText.setText(R.string.home_most_recent_empty);
-
-                        final TextView emptyHint = (TextView) mEmptyView.findViewById(R.id.home_empty_hint);
-
-                        if (!Restrictions.isAllowed(getActivity(), Restrictable.PRIVATE_BROWSING)) {
-                            emptyHint.setVisibility(View.GONE);
-                        } else {
-                            final String hintText = getResources().getString(R.string.home_most_recent_emptyhint);
-                            final SpannableStringBuilder hintBuilder = formatHintText(hintText);
-                            if (hintBuilder != null) {
-                                emptyHint.setText(hintBuilder);
-                                emptyHint.setMovementMethod(LinkMovementMethod.getInstance());
-                                emptyHint.setVisibility(View.VISIBLE);
-                            }
-                        }
-                    }
-                    mEmptyView.setVisibility(View.VISIBLE);
-                } else {
-                    if (mEmptyView != null) {
-                        mEmptyView.setVisibility(View.GONE);
-                    }
-                }
+                showEmptyHistoryView = mHistoryAdapter.getItemCount() == NUM_SMART_FOLDERS;
                 break;
 
             case CHILD:
-                // TODO: Bug 1262285
-                if (mEmptyView != null) {
-                    mEmptyView.setVisibility(View.GONE);
-                }
+                showEmptyClientsView = mClientsAdapter.getItemCount() == 1;
                 break;
         }
+
+        final boolean showEmptyView = showEmptyClientsView || showEmptyHistoryView;
+        mRecyclerView.setOverScrollMode(showEmptyView? View.OVER_SCROLL_NEVER : View.OVER_SCROLL_IF_CONTENT_SCROLLS);
+
+        mClientsEmptyView.setVisibility(showEmptyClientsView ? View.VISIBLE : View.GONE);
+        mHistoryEmptyView.setVisibility(showEmptyHistoryView ? View.VISIBLE : View.GONE);
     }
+
     /**
      * Make Span that is clickable, and underlined
      * between the string markers <code>FORMAT_S1</code> and
      * <code>FORMAT_S2</code>.
      *
      * @param text String to format
      * @return formatted SpannableStringBuilder, or null if there
      * is not any text to format.
rename from mobile/android/base/resources/layout/remote_tabs_setup.xml
rename to mobile/android/base/resources/layout/history_sync_setup.xml
--- a/mobile/android/base/resources/layout/remote_tabs_setup.xml
+++ b/mobile/android/base/resources/layout/history_sync_setup.xml
@@ -20,16 +20,16 @@
 
         <TextView
             style="@style/RemoteTabsPanelItem.TextAppearance"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="@string/fxaccount_getting_started_description" />
 
         <Button
-            android:id="@+id/remote_tabs_setup_get_started"
+            android:id="@+id/sync_setup_button"
             style="@style/RemoteTabsPanelItem.Button"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:text="@string/fxaccount_getting_started_get_started" />
     </LinearLayout>
 
 </ScrollView>
\ No newline at end of file
--- a/mobile/android/base/resources/layout/home_combined_history_panel.xml
+++ b/mobile/android/base/resources/layout/home_combined_history_panel.xml
@@ -3,39 +3,43 @@
    - 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/. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:layout_width="match_parent"
               android:layout_height="match_parent"
               android:orientation="vertical">
 
-    <ViewStub android:id="@+id/home_empty_view_stub"
-              android:layout="@layout/home_empty_panel"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"/>
-
-    <ViewStub android:id="@+id/home_sync_empty_view_stub"
-              android:layout="@layout/remote_tabs_setup"
-              android:layout_width="match_parent"
-              android:layout_height="match_parent"/>
-
     <android.support.v4.widget.SwipeRefreshLayout
             android:id="@+id/refresh_layout"
             android:layout_width="match_parent"
             android:layout_height="0dp"
             android:layout_weight="1">
 
         <org.mozilla.gecko.home.CombinedHistoryRecyclerView
                 android:id="@+id/combined_recycler_view"
-                android:layout_height="match_parent"
-                android:layout_width="match_parent"/>
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"/>
 
     </android.support.v4.widget.SwipeRefreshLayout>
 
+    <include android:id="@+id/home_history_empty_view"
+              layout="@layout/home_empty_panel"
+              android:layout_width="match_parent"
+              android:layout_height="0dp"
+              android:layout_weight="3"
+              android:visibility="gone"/>
+
+    <include android:id="@+id/home_clients_empty_view"
+              layout="@layout/history_sync_setup"
+              android:layout_width="match_parent"
+              android:layout_height="0dp"
+              android:layout_weight="3"
+              android:visibility="gone"/>
+
     <Button android:id="@+id/clear_history_button"
             style="@style/Widget.Home.ActionButton"
             android:text="@string/home_clear_history_button"
             android:layout_width="match_parent"
             android:layout_height="48dp"
             android:visibility="gone" />
 
 </LinearLayout>