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