Brion VIBBER has submitted this change and it was merged.

Change subject: Implement a rough ToC
......................................................................


Implement a rough ToC

- Accessed from overflow menu
- Tap each section to go to it
- Only section levels 1 and 2 are shown
- Also adds fadeIn & fadeOut utility methods

Change-Id: I475fefb3d0652cf96b1246489935528c7736d1c6
---
M wikipedia/assets/main.js
M wikipedia/res/layout/fragment_page.xml
A wikipedia/res/layout/header_toc_list.xml
A wikipedia/res/layout/item_toc_entry.xml
M wikipedia/res/menu/menu_page_actions.xml
M wikipedia/res/values/strings.xml
M wikipedia/src/main/java/org/wikipedia/Utils.java
A wikipedia/src/main/java/org/wikipedia/events/ShowToCEvent.java
M wikipedia/src/main/java/org/wikipedia/page/PageActionsHandler.java
M wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
A wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
12 files changed, 252 insertions(+), 14 deletions(-)

Approvals:
  Brion VIBBER: Verified; Looks good to me, approved



diff --git a/wikipedia/assets/main.js b/wikipedia/assets/main.js
index 208c530..c8b3ffd 100644
--- a/wikipedia/assets/main.js
+++ b/wikipedia/assets/main.js
@@ -11,6 +11,7 @@
 
         var title = document.createElement( "h1" );
         title.textContent = payload.title;
+        title.id = "heading_" + payload.section.id;
         document.getElementById( "content" ).appendChild( title );
 
         var content = document.createElement( "div" );
@@ -76,6 +77,13 @@
         bridge.sendMessage( "imagesListResponse", { "images": imageURLs });
     } );
 
+    bridge.registerListener( "scrollToSection", function ( payload ) {
+        // The 52 is for dealing with the search header
+        var scrollY = document.getElementById( "heading_" + 
payload.sectionID).offsetTop - 52;
+        window.scrollTo(0, scrollY);
+    });
+
+
     var actionHandlers = {
         "edit_section": function( el, event ) {
             bridge.sendMessage( 'editSectionClicked', { sectionID: 
el.getAttribute( 'data-id' ) } );
diff --git a/wikipedia/res/layout/fragment_page.xml 
b/wikipedia/res/layout/fragment_page.xml
index 6743479..1e9b487 100644
--- a/wikipedia/res/layout/fragment_page.xml
+++ b/wikipedia/res/layout/fragment_page.xml
@@ -17,6 +17,15 @@
         android:layout_height="match_parent"
         android:visibility="gone"
         />
+    <ListView
+            android:id="@+id/page_toc_list"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:visibility="gone"
+            android:background="@android:color/background_light"
+            android:divider="#ededed"
+            android:dividerHeight="0.5dp"
+            />
     <LinearLayout
             android:id="@+id/page_error"
             android:layout_width="match_parent"
diff --git a/wikipedia/res/layout/header_toc_list.xml 
b/wikipedia/res/layout/header_toc_list.xml
new file mode 100644
index 0000000..4ad6978
--- /dev/null
+++ b/wikipedia/res/layout/header_toc_list.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android";
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:fontFamily="serif"
+              android:padding="16dp"
+              android:textStyle="bold"
+              style="?android:textAppearanceLarge"
+        />
+
diff --git a/wikipedia/res/layout/item_toc_entry.xml 
b/wikipedia/res/layout/item_toc_entry.xml
new file mode 100644
index 0000000..f18d9b6
--- /dev/null
+++ b/wikipedia/res/layout/item_toc_entry.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="horizontal"
+        >
+    <View android:layout_width="0dp" android:layout_height="match_parent"
+          android:id="@+id/page_toc_filler"
+          />
+
+    <TextView
+            android:id="@+id/page_toc_item_text"
+            android:layout_height="wrap_content"
+            android:layout_width="0dp"
+            android:layout_weight="1"
+            android:layout_gravity="center_vertical"
+            android:layout_marginLeft="16dp"
+            android:layout_marginRight="16dp"
+            android:layout_marginTop="8dp"
+            android:layout_marginBottom="8dp"
+            style="?android:textAppearanceMedium"
+            />
+
+</LinearLayout>
diff --git a/wikipedia/res/menu/menu_page_actions.xml 
b/wikipedia/res/menu/menu_page_actions.xml
index 7e31994..960f798 100644
--- a/wikipedia/res/menu/menu_page_actions.xml
+++ b/wikipedia/res/menu/menu_page_actions.xml
@@ -1,7 +1,11 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <menu xmlns:android="http://schemas.android.com/apk/res/android";>
-
+    <item android:id="@+id/menu_show_toc"
+          android:title="@string/menu_show_toc"
+          android:enabled="false"
+          android:showAsAction="always"
+          />
     <item android:id="@+id/menu_other_languages"
           android:title="@string/menu_other_languages"
           android:enabled="false"
diff --git a/wikipedia/res/values/strings.xml b/wikipedia/res/values/strings.xml
index 0978fd9..994991f 100644
--- a/wikipedia/res/values/strings.xml
+++ b/wikipedia/res/values/strings.xml
@@ -51,4 +51,5 @@
     <string name="dialog_message_edit_failed">Edit failed!</string>
     <string name="dialog_message_edit_failed_retry">Retry</string>
     <string name="dialog_message_edit_failed_cancel">Cancel</string>
+    <string name="menu_show_toc">Table of Contents</string>
 </resources>
\ No newline at end of file
diff --git a/wikipedia/src/main/java/org/wikipedia/Utils.java 
b/wikipedia/src/main/java/org/wikipedia/Utils.java
index cf5f1f0..39fba22 100644
--- a/wikipedia/src/main/java/org/wikipedia/Utils.java
+++ b/wikipedia/src/main/java/org/wikipedia/Utils.java
@@ -39,21 +39,37 @@
      * @param newView The new view that should be faded in
      */
     public static void crossFade(final View curView, final View newView) {
-        newView.setAlpha(0f);
-        newView.setVisibility(View.VISIBLE);
-        newView.animate()
+        fadeIn(newView);
+        fadeOut(curView);
+    }
+
+    /**
+     * Fades in a view.
+     * @param view The currently invisible view to be faded in
+     */
+    public static void fadeIn(final View view) {
+        view.setAlpha(0f);
+        view.setVisibility(View.VISIBLE);
+        view.animate()
                 .alpha(1.0f)
                 .setDuration(WikipediaApp.MEDIUM_ANIMATION_DURATION)
-                .setListener(null);
+                .setListener(null)
+                .start();
+    }
 
-        curView.animate()
+    /**
+     * Fades out a view.
+     * @param view The currently visible view to be faded out
+     */
+    public static void fadeOut(final View view) {
+        view.animate()
                 .alpha(0f)
                 .setDuration(WikipediaApp.MEDIUM_ANIMATION_DURATION)
                 .setListener(new AnimatorListenerAdapter() {
                     @Override
                     public void onAnimationEnd(Animator animation) {
-                        curView.setVisibility(View.GONE);
-                        curView.setAlpha(1.0f);
+                        view.setVisibility(View.GONE);
+                        view.setAlpha(1.0f);
                     }
                 });
     }
diff --git a/wikipedia/src/main/java/org/wikipedia/events/ShowToCEvent.java 
b/wikipedia/src/main/java/org/wikipedia/events/ShowToCEvent.java
new file mode 100644
index 0000000..938384e
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/events/ShowToCEvent.java
@@ -0,0 +1,4 @@
+package org.wikipedia.events;
+
+public class ShowToCEvent {
+}
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageActionsHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageActionsHandler.java
index 3dea537..322a4ef 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActionsHandler.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActionsHandler.java
@@ -6,10 +6,7 @@
 import com.squareup.otto.Bus;
 import com.squareup.otto.Subscribe;
 import org.wikipedia.R;
-import org.wikipedia.events.PageStateChangeEvent;
-import org.wikipedia.events.SavePageEvent;
-import org.wikipedia.events.SharePageEvent;
-import org.wikipedia.events.ShowOtherLanguagesEvent;
+import org.wikipedia.events.*;
 
 public class PageActionsHandler implements PopupMenu.OnMenuItemClickListener {
     private final PopupMenu menu;
@@ -39,11 +36,13 @@
                 menu.getMenu().findItem(R.id.menu_save_page).setEnabled(false);
                 
menu.getMenu().findItem(R.id.menu_share_page).setEnabled(false);
                 
menu.getMenu().findItem(R.id.menu_other_languages).setEnabled(false);
+                menu.getMenu().findItem(R.id.menu_show_toc).setEnabled(false);
                 break;
             case PageViewFragment.STATE_COMPLETE_FETCH:
                 menu.getMenu().findItem(R.id.menu_save_page).setEnabled(true);
                 menu.getMenu().findItem(R.id.menu_share_page).setEnabled(true);
                 
menu.getMenu().findItem(R.id.menu_other_languages).setEnabled(true);
+                menu.getMenu().findItem(R.id.menu_show_toc).setEnabled(true);
                 break;
             default:
                 // How can this happen?!
@@ -63,6 +62,9 @@
             case R.id.menu_other_languages:
                 bus.post(new ShowOtherLanguagesEvent());
                 break;
+            case R.id.menu_show_toc:
+                bus.post(new ShowToCEvent());
+                break;
             default:
                 throw new RuntimeException("Unexpected menu item clicked");
         }
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
index 0c5f199..691d6a2 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageActivity.java
@@ -94,9 +94,14 @@
         startActivity(shareIntent);
     }
 
+    @Subscribe
+    public void onShowToCEvent(ShowToCEvent event) {
+        curPageFragment.showToC();
+    }
     @Override
     public void onBackPressed() {
-        if (!searchAriclesFragment.handleBackPressed()) {
+        if ((curPageFragment != null && !curPageFragment.handleBackPressed())
+                || searchAriclesFragment.handleBackPressed()) {
             if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
                 // Everything we could pop has been popped....
                 finish();
diff --git a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
index 59e1b28..3c45425 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragment.java
@@ -10,6 +10,7 @@
 import android.view.ViewGroup;
 import android.webkit.WebView;
 import android.widget.FrameLayout;
+import android.widget.ListView;
 import android.widget.ProgressBar;
 import android.widget.Toast;
 import org.json.JSONArray;
@@ -50,6 +51,8 @@
     private View networkError;
     private View retryButton;
 
+    private ListView tocList;
+
     private Page page;
     private HistoryEntry curEntry;
 
@@ -62,6 +65,8 @@
 
     private int scrollY;
     private int quickReturnBarId;
+
+    private View quickReturnBar;
 
     // Pass in the id rather than the View object itself for the quickReturn 
bar, to help it survive rotates
     public PageViewFragment(PageTitle title, HistoryEntry historyEntry, int 
quickReturnBarId) {
@@ -144,6 +149,8 @@
         loadProgress = (ProgressBar) 
parentView.findViewById(R.id.page_load_progress);
         networkError = parentView.findViewById(R.id.page_error);
         retryButton = parentView.findViewById(R.id.page_error_retry);
+        tocList = (ListView) parentView.findViewById(R.id.page_toc_list);
+        quickReturnBar = getActivity().findViewById(quickReturnBarId);
 
         if (savedInstanceState != null && 
savedInstanceState.containsKey(KEY_TITLE)) {
             title = savedInstanceState.getParcelable(KEY_TITLE);
@@ -184,7 +191,7 @@
             performActionForState(state);
         }
 
-        new QuickReturnHandler(webView, 
getActivity().findViewById(quickReturnBarId));
+        new QuickReturnHandler(webView, quickReturnBar);
 
         return parentView;
     }
@@ -317,4 +324,20 @@
             }
         }.execute();
     }
+
+    private ToCHandler tocHandler;
+    public void showToC() {
+        if (tocHandler == null) {
+            tocHandler = new ToCHandler(tocList, page, quickReturnBar, bridge);
+        }
+        tocHandler.show();
+    }
+
+    public boolean handleBackPressed() {
+        if (tocHandler != null && tocHandler.isVisible()) {
+            tocHandler.hide();
+            return true;
+        }
+        return false;
+    }
 }
diff --git a/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
new file mode 100644
index 0000000..dbbe617
--- /dev/null
+++ b/wikipedia/src/main/java/org/wikipedia/page/ToCHandler.java
@@ -0,0 +1,130 @@
+package org.wikipedia.page;
+
+import android.graphics.Color;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.wikipedia.*;
+
+import java.util.ArrayList;
+
+public class ToCHandler {
+    private final ListView tocList;
+    private final Page page;
+    private final View quickReturnBar;
+    private final CommunicationBridge bridge;
+
+    public ToCHandler(ListView tocList, Page page, View quickReturnBar, 
CommunicationBridge bridge) {
+        this.tocList = tocList;
+        this.page = page;
+        this.quickReturnBar = quickReturnBar;
+        this.bridge = bridge;
+    }
+
+    private void scrollToSection(Section section) {
+        JSONObject payload = new JSONObject();
+        try {
+            payload.put("sectionID", section.getId());
+        } catch (JSONException e) {
+            // This won't happen
+            throw new RuntimeException(e);
+        }
+
+        bridge.sendMessage("scrollToSection", payload);
+    }
+
+    public void show() {
+        if (tocList.getAdapter() == null) {
+            TextView headerView = (TextView) 
LayoutInflater.from(tocList.getContext()).inflate(R.layout.header_toc_list, 
null, false);
+            headerView.setText(page.getTitle().getDisplayText());
+            tocList.addHeaderView(headerView);
+            headerView.setOnClickListener(new View.OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    scrollToSection(page.getSections().get(0));
+                    hide();
+                }
+            });
+
+            tocList.setAdapter(new ToCAdapter(page));
+            tocList.setOnItemClickListener(new 
AdapterView.OnItemClickListener() {
+                @Override
+                public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
+                    Section section = (Section) 
parent.getAdapter().getItem(position);
+                    scrollToSection(section);
+                    hide();
+                }
+            });
+        }
+        Utils.ensureTranslationY(quickReturnBar, -quickReturnBar.getHeight());
+        Utils.fadeIn(tocList);
+    }
+
+    public void hide() {
+        Utils.fadeOut(tocList);
+        Utils.ensureTranslationY(quickReturnBar, 0);
+    }
+
+    public boolean isVisible() {
+        return tocList.getVisibility() == View.VISIBLE;
+    }
+
+    private static class ToCAdapter extends BaseAdapter {
+        private final ArrayList<Section> sections;
+        private final PageTitle title;
+
+
+        private ToCAdapter(Page page) {
+            sections = new ArrayList<Section>();
+            for (Section s : page.getSections()) {
+                if (s.getLevel() < 3 && !s.isLead()) {
+                    sections.add(s);
+                }
+            }
+            this.title = page.getTitle();
+        }
+
+        @Override
+        public int getCount() {
+            return sections.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return sections.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            if (convertView == null) {
+                convertView = 
LayoutInflater.from(parent.getContext()).inflate(R.layout.item_toc_entry, 
parent, false);
+            }
+            Section section = (Section) getItem(position);
+            TextView sectionHeading = (TextView) 
convertView.findViewById(R.id.page_toc_item_text);
+            View sectionFiller = 
convertView.findViewById(R.id.page_toc_filler);
+
+            LinearLayout.LayoutParams indentLayoutParameters = new 
LinearLayout.LayoutParams(sectionFiller.getLayoutParams());
+            indentLayoutParameters.width = (section.getLevel() - 1) * (int)(16 
* WikipediaApp.SCREEN_DENSITY);
+            sectionFiller.setLayoutParams(indentLayoutParameters);
+
+            sectionHeading.setText(section.getHeading());
+
+            if (section.getLevel() > 1) {
+                sectionHeading.setTextColor(Color.parseColor("#898989"));
+            } else {
+                sectionHeading.setTextColor(Color.parseColor("#333333"));
+            }
+            return convertView;
+        }
+    }
+}

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

Gerrit-MessageType: merged
Gerrit-Change-Id: I475fefb3d0652cf96b1246489935528c7736d1c6
Gerrit-PatchSet: 2
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Yuvipanda <yuvipa...@gmail.com>
Gerrit-Reviewer: Brion VIBBER <br...@wikimedia.org>

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

Reply via email to