Mholloway has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/257695

Change subject: Implement Wiktionary definition dialog
......................................................................

Implement Wiktionary definition dialog

An implementation of Wiktionary popups based on the existing
SwipeableBottomDialog component. Adds a "define" option to the CAB menu
that triggers a definition dialog containing definition(s) from
Wiktionary.

Depends on mobile content service patch at
https://gerrit.wikimedia.org/r/#/c/255263/

TODO: Currently only works for English Wiktionary -- will work on
generalizing on the content service end.

TODO: Currently uses the Creative Commons icon as a placeholder in the
CAB menu on pre-Marshmallow versions while Kaity works on a "define" icon.

Bug: T118733
Bug: T118735
Change-Id: I461d84ab241c26d4c34649afd09eafea6f8b11e2
---
M app/src/main/java/org/wikipedia/page/PageActivityLongPressHandler.java
M app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
M app/src/main/java/org/wikipedia/page/snippet/ShareHandler.java
M app/src/main/java/org/wikipedia/savedpages/RefreshPagesHandler.java
R app/src/main/java/org/wikipedia/server/ContentServiceFactory.java
R app/src/main/java/org/wikipedia/server/restbase/RbContentService.java
A app/src/main/java/org/wikipedia/server/restbase/RbDefinition.java
R app/src/main/java/org/wikipedia/server/restbase/RbEndpointsCache.java
M app/src/main/java/org/wikipedia/util/PageLoadUtil.java
M app/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
A app/src/main/java/org/wikipedia/wiktionary/WiktionaryDialog.java
A app/src/main/res/layout/dialog_wiktionary.xml
A app/src/main/res/layout/dialog_wiktionary_overlay.xml
A app/src/main/res/layout/item_wiktionary_definition_with_examples.xml
A app/src/main/res/layout/item_wiktionary_definitions_list.xml
A app/src/main/res/layout/item_wiktionary_example.xml
M app/src/main/res/menu/menu_text_select.xml
M app/src/main/res/values-qq/strings.xml
M app/src/main/res/values/strings.xml
19 files changed, 514 insertions(+), 29 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/apps/android/wikipedia 
refs/changes/95/257695/1

diff --git 
a/app/src/main/java/org/wikipedia/page/PageActivityLongPressHandler.java 
b/app/src/main/java/org/wikipedia/page/PageActivityLongPressHandler.java
index 3b662dd..ef068b2 100644
--- a/app/src/main/java/org/wikipedia/page/PageActivityLongPressHandler.java
+++ b/app/src/main/java/org/wikipedia/page/PageActivityLongPressHandler.java
@@ -6,7 +6,7 @@
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.history.HistoryEntry;
 import org.wikipedia.server.PageService;
-import org.wikipedia.server.PageServiceFactory;
+import org.wikipedia.server.ContentServiceFactory;
 import org.wikipedia.savedpages.SaveOtherPageCallback;
 import org.wikipedia.util.ClipboardUtil;
 import org.wikipedia.util.FeedbackUtil;
@@ -72,6 +72,6 @@
     }
 
     private PageService getApiService(PageTitle title) {
-        return PageServiceFactory.create(title.getSite());
+        return ContentServiceFactory.create(title.getSite());
     }
 }
diff --git 
a/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java 
b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
index fd541cc..f3123c0 100755
--- a/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
+++ b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
@@ -15,7 +15,7 @@
 import org.wikipedia.page.gallery.GalleryCollectionFetchTask;
 import org.wikipedia.page.gallery.GalleryThumbnailScrollView;
 import org.wikipedia.savedpages.LoadSavedPageTask;
-import org.wikipedia.server.PageServiceFactory;
+import org.wikipedia.server.ContentServiceFactory;
 import org.wikipedia.server.PageSummary;
 import org.wikipedia.util.ApiUtil;
 import org.wikipedia.util.FeedbackUtil;
@@ -210,7 +210,7 @@
     }
 
     private void loadContent() {
-        PageServiceFactory.create(pageTitle.getSite()).pageSummary(
+        ContentServiceFactory.create(pageTitle.getSite()).pageSummary(
                 pageTitle.getPrefixedText(),
                 linkPreviewOnLoadCallback);
     }
diff --git a/app/src/main/java/org/wikipedia/page/snippet/ShareHandler.java 
b/app/src/main/java/org/wikipedia/page/snippet/ShareHandler.java
index 6f303fd..fa46ce1 100755
--- a/app/src/main/java/org/wikipedia/page/snippet/ShareHandler.java
+++ b/app/src/main/java/org/wikipedia/page/snippet/ShareHandler.java
@@ -29,6 +29,7 @@
 import org.wikipedia.page.PageActivity;
 import org.wikipedia.page.PageProperties;
 import org.wikipedia.page.PageFragment;
+import org.wikipedia.settings.Prefs;
 import org.wikipedia.tooltip.ToolTipUtil;
 import org.wikipedia.activity.ActivityUtil;
 import org.wikipedia.util.ClipboardUtil;
@@ -38,6 +39,7 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.wikipedia.util.log.L;
+import org.wikipedia.wiktionary.WiktionaryDialog;
 
 import java.util.Map;
 
@@ -51,7 +53,9 @@
     private static final String PAYLOAD_PURPOSE_KEY = "purpose";
     private static final String PAYLOAD_PURPOSE_SHARE = "share";
     private static final String PAYLOAD_PURPOSE_COPY = "copy";
+    private static final String PAYLOAD_PURPOSE_DEFINE = "define";
     private static final String PAYLOAD_TEXT_KEY = "text";
+    private static final String WIKTIONARY_DEFINITION_TAG = 
"wiktionary_definition_dialog";
 
     @ColorRes private static final int SHARE_TOOL_TIP_COLOR = 
R.color.blue_liberal;
 
@@ -85,6 +89,9 @@
                     case PAYLOAD_PURPOSE_COPY:
                         onCopyPayload(text);
                         break;
+                    case PAYLOAD_PURPOSE_DEFINE:
+                        onDefinePayload(text);
+                        break;
                     default:
                         L.d("Unknown purpose=" + purpose);
                 }
@@ -103,6 +110,16 @@
     private void onCopyPayload(String text) {
         copyText(text);
         showCopySnackbar();
+    }
+
+    private void onDefinePayload(String text) {
+        showWiktionaryDefinition(text);
+    }
+
+    private void showWiktionaryDefinition(String text) {
+        PageTitle title = activity.getCurPageFragment().getTitle();
+        WiktionaryDialog dialog = WiktionaryDialog.newInstance(title, text);
+        dialog.show(activity.getSupportFragmentManager(), 
WIKTIONARY_DEFINITION_TAG);
     }
 
     private void copyText(String text) {
@@ -189,10 +206,17 @@
             
WikipediaApp.getInstance().getOnboardingStateMachine().setShareTutorial();
         }
 
-        // Provide our own listeners for the copy and share buttons.
+        // Provide our own listeners for the copy, define, and share buttons.
         shareItem.setOnMenuItemClickListener(new 
RequestTextSelectOnMenuItemClickListener(PAYLOAD_PURPOSE_SHARE));
         MenuItem copyItem = menu.findItem(R.id.menu_text_select_copy);
         copyItem.setOnMenuItemClickListener(new 
RequestTextSelectOnMenuItemClickListener(PAYLOAD_PURPOSE_COPY));
+        MenuItem defineItem = menu.findItem(R.id.menu_text_select_define);
+        if (!Prefs.useRestBase()) {
+            defineItem.setVisible(false);
+            defineItem.setEnabled(false);
+        } else {
+            defineItem.setOnMenuItemClickListener(new 
RequestTextSelectOnMenuItemClickListener(PAYLOAD_PURPOSE_DEFINE));
+        }
 
         createFunnel();
         funnel.logHighlight();
diff --git 
a/app/src/main/java/org/wikipedia/savedpages/RefreshPagesHandler.java 
b/app/src/main/java/org/wikipedia/savedpages/RefreshPagesHandler.java
index 7f1bac6..8c7c8cd 100644
--- a/app/src/main/java/org/wikipedia/savedpages/RefreshPagesHandler.java
+++ b/app/src/main/java/org/wikipedia/savedpages/RefreshPagesHandler.java
@@ -4,7 +4,7 @@
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.page.PageTitle;
 import org.wikipedia.server.PageService;
-import org.wikipedia.server.PageServiceFactory;
+import org.wikipedia.server.ContentServiceFactory;
 import org.wikipedia.util.log.L;
 
 import android.app.ProgressDialog;
@@ -106,7 +106,7 @@
     }
 
     private PageService getApiService(PageTitle title) {
-        return PageServiceFactory.create(title.getSite());
+        return ContentServiceFactory.create(title.getSite());
     }
 
     private AlertDialog errorDialog;
diff --git a/app/src/main/java/org/wikipedia/server/PageServiceFactory.java 
b/app/src/main/java/org/wikipedia/server/ContentServiceFactory.java
similarity index 74%
rename from app/src/main/java/org/wikipedia/server/PageServiceFactory.java
rename to app/src/main/java/org/wikipedia/server/ContentServiceFactory.java
index d820d8d..29874be 100644
--- a/app/src/main/java/org/wikipedia/server/PageServiceFactory.java
+++ b/app/src/main/java/org/wikipedia/server/ContentServiceFactory.java
@@ -2,7 +2,7 @@
 
 import org.wikipedia.Site;
 import org.wikipedia.server.mwapi.MwPageService;
-import org.wikipedia.server.restbase.RbPageService;
+import org.wikipedia.server.restbase.RbContentService;
 import org.wikipedia.settings.RbSwitch;
 
 /**
@@ -10,15 +10,15 @@
  * MediaWiki PHP API and the new Nodejs Mobile Content Service hosted in the 
RESTBase
  * infrastructure.
  */
-public final class PageServiceFactory {
+public final class ContentServiceFactory {
     public static PageService create(Site site) {
         if (RbSwitch.INSTANCE.isRestBaseEnabled(site)) {
-            return new RbPageService(site);
+            return new RbContentService(site);
         } else {
             return new MwPageService(site);
         }
     }
 
-    private PageServiceFactory() {
+    private ContentServiceFactory() {
     }
 }
diff --git a/app/src/main/java/org/wikipedia/server/restbase/RbPageService.java 
b/app/src/main/java/org/wikipedia/server/restbase/RbContentService.java
similarity index 79%
rename from app/src/main/java/org/wikipedia/server/restbase/RbPageService.java
rename to app/src/main/java/org/wikipedia/server/restbase/RbContentService.java
index e3a8d1d..30ff1ca 100644
--- a/app/src/main/java/org/wikipedia/server/restbase/RbPageService.java
+++ b/app/src/main/java/org/wikipedia/server/restbase/RbContentService.java
@@ -20,13 +20,13 @@
 /**
  * Retrofit web service client for RESTBase Nodejs API.
  */
-public class RbPageService implements PageService {
-    private final RbPageEndpoints webService;
+public class RbContentService implements PageService {
+    private final RbEndpoints webService;
     private WikipediaZeroHandler responseHeaderHandler;
 
-    public RbPageService(final Site site) {
+    public RbContentService(final Site site) {
         responseHeaderHandler = 
WikipediaApp.getInstance().getWikipediaZeroHandler();
-        webService = RbPageEndpointsCache.INSTANCE.getRbPageEndpoints(site);
+        webService = RbEndpointsCache.INSTANCE.getRbEndpoints(site);
     }
 
     @Override
@@ -97,6 +97,26 @@
         });
     }
 
+    /* Not defined in the PageService interface since the Wiktionary 
definition endpoint exists only
+     * in the mobile content service, and does not concern the wholesale 
retrieval of the contents
+     * of a wiki page.
+     */
+    public void define(String title, final RbDefinition.Callback cb) {
+        webService.define(title, new Callback<RbDefinition>() {
+            @Override
+            public void success(RbDefinition definition, Response response) {
+                responseHeaderHandler.onHeaderCheck(response);
+                cb.success(definition, response);
+            }
+
+            @Override
+            public void failure(RetrofitError error) {
+                RbSwitch.INSTANCE.onRbRequestFailed(error);
+                cb.failure(error);
+            }
+        });
+    }
+
     /**
      * Optional boolean Retrofit parameter.
      * We don't want to send the query parameter at all when it's false since 
the presence of the parameter
@@ -110,9 +130,9 @@
     }
 
     /**
-     * Retrofit endpoints for MW API endpoints.
+     * Retrofit endpoints for mobile content service endpoints.
      */
-    interface RbPageEndpoints {
+    interface RbEndpoints {
         /**
          * Gets a page summary for a given title -- for link previews
          *
@@ -155,5 +175,14 @@
         @GET("/page/mobile-sections/{title}")
         void pageCombo(@Path("title") String title, @Query("noimages") Boolean 
noImages,
                        Callback<RbPageCombo> cb);
+
+
+        /**
+         * Gets selected Wiktionary content for a given title derived from 
user-selected text
+         *
+         * @param title the Wiktionary page title derived from user-selected 
Wikipedia article text
+         */
+        @GET("/definition/{title}")
+        void define(@Path("title") String title, Callback<RbDefinition> cb);
     }
 }
diff --git a/app/src/main/java/org/wikipedia/server/restbase/RbDefinition.java 
b/app/src/main/java/org/wikipedia/server/restbase/RbDefinition.java
new file mode 100644
index 0000000..53cdc2d
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/server/restbase/RbDefinition.java
@@ -0,0 +1,76 @@
+package org.wikipedia.server.restbase;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.google.gson.JsonObject;
+import com.google.gson.annotations.Expose;
+import com.google.gson.JsonArray;
+
+import org.wikipedia.util.log.L;
+
+import retrofit.RetrofitError;
+import retrofit.client.Response;
+
+public class RbDefinition {
+    @Expose static private RbServiceError error;
+
+    @Expose @Nullable private Usage[] usages;
+
+    @Nullable public Usage[] getUsages() {
+        return usages;
+    }
+
+    public boolean hasError() {
+        return error != null || usages == null;
+    }
+
+    public static void logError(String message) {
+        if (error != null) {
+            message += ": " + error.toString();
+        }
+        L.e(message);
+    }
+
+    public interface Callback {
+        void success(RbDefinition definition, Response response);
+
+        void failure(RetrofitError error);
+    }
+
+    public static class Usage {
+        @Expose private String partOfSpeech;
+        @Expose private Definition[] definitions;
+
+        public Usage(String partOfSpeech, Definition[] definitions) {
+            this.partOfSpeech = partOfSpeech;
+            this.definitions = definitions;
+        }
+
+        @NonNull public String getPartOfSpeech(){
+            return partOfSpeech;
+        }
+
+        @NonNull public Definition[] getDefinitions() {
+            return definitions;
+        }
+    }
+
+    public static class Definition {
+        @Expose private String definition;
+        @Expose private String[] examples;
+
+        public Definition(String definition, String[] examples) {
+            this.definition = definition;
+            this.examples = examples;
+        }
+
+        @NonNull public String getDefinition() {
+            return definition;
+        }
+
+        @Nullable public String[] getExamples() {
+            return examples;
+        }
+    }
+}
diff --git 
a/app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java 
b/app/src/main/java/org/wikipedia/server/restbase/RbEndpointsCache.java
similarity index 80%
rename from 
app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java
rename to app/src/main/java/org/wikipedia/server/restbase/RbEndpointsCache.java
index a2f6851..50bcb3e 100644
--- a/app/src/main/java/org/wikipedia/server/restbase/RbPageEndpointsCache.java
+++ b/app/src/main/java/org/wikipedia/server/restbase/RbEndpointsCache.java
@@ -18,16 +18,16 @@
  * It's good to cache the Retrofit web service since it's a memory intensive 
object.
  * Keep the same instance around as long as we're dealing with the same domain.
  */
-public final class RbPageEndpointsCache {
-    public static final RbPageEndpointsCache INSTANCE = new 
RbPageEndpointsCache();
+public final class RbEndpointsCache {
+    public static final RbEndpointsCache INSTANCE = new RbEndpointsCache();
 
     private Site site;
-    private RbPageService.RbPageEndpoints cachedWebService;
+    private RbContentService.RbEndpoints cachedWebService;
 
-    private RbPageEndpointsCache() {
+    private RbEndpointsCache() {
     }
 
-    public RbPageService.RbPageEndpoints getRbPageEndpoints(Site newSite) {
+    public RbContentService.RbEndpoints getRbEndpoints(Site newSite) {
         if (!newSite.equals(site)) {
             cachedWebService = createRbService(newSite);
             site = newSite;
@@ -35,8 +35,8 @@
         return cachedWebService;
     }
 
-    private RbPageService.RbPageEndpoints createRbService(final Site site) {
-        RbPageService.RbPageEndpoints webService;
+    private RbContentService.RbEndpoints createRbService(final Site site) {
+        RbContentService.RbEndpoints webService;
         final String domain = site.getApiDomain();
         final WikipediaApp app = WikipediaApp.getInstance();
         RestAdapter restAdapter = new RestAdapter.Builder()
@@ -63,7 +63,7 @@
                         .create()))
 
                 .build();
-        webService = restAdapter.create(RbPageService.RbPageEndpoints.class);
+        webService = restAdapter.create(RbContentService.RbEndpoints.class);
         return webService;
     }
 }
diff --git a/app/src/main/java/org/wikipedia/util/PageLoadUtil.java 
b/app/src/main/java/org/wikipedia/util/PageLoadUtil.java
index 4f3287a..24d02e5 100644
--- a/app/src/main/java/org/wikipedia/util/PageLoadUtil.java
+++ b/app/src/main/java/org/wikipedia/util/PageLoadUtil.java
@@ -4,13 +4,13 @@
 
 import org.wikipedia.Site;
 import org.wikipedia.server.PageService;
-import org.wikipedia.server.PageServiceFactory;
+import org.wikipedia.server.ContentServiceFactory;
 
 public final class PageLoadUtil {
 
     @NonNull
     public static PageService getApiService(Site site) {
-        return PageServiceFactory.create(site);
+        return ContentServiceFactory.create(site);
     }
 
     private PageLoadUtil() { }
diff --git 
a/app/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java 
b/app/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
index b9931a1..be356eb 100644
--- a/app/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
+++ b/app/src/main/java/org/wikipedia/widgets/WidgetProviderFeaturedPage.java
@@ -20,7 +20,7 @@
 import org.wikipedia.page.PageTitle;
 import org.wikipedia.server.PageLead;
 import org.wikipedia.server.PageService;
-import org.wikipedia.server.PageServiceFactory;
+import org.wikipedia.server.ContentServiceFactory;
 import org.wikipedia.staticdata.MainPageNameData;
 import org.wikipedia.util.log.L;
 
@@ -130,7 +130,7 @@
     }
 
     private PageService getApiService(PageTitle title) {
-        return PageServiceFactory.create(title.getSite());
+        return ContentServiceFactory.create(title.getSite());
     }
 
     private interface Callback {
diff --git a/app/src/main/java/org/wikipedia/wiktionary/WiktionaryDialog.java 
b/app/src/main/java/org/wikipedia/wiktionary/WiktionaryDialog.java
new file mode 100644
index 0000000..e27b603
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/wiktionary/WiktionaryDialog.java
@@ -0,0 +1,186 @@
+package org.wikipedia.wiktionary;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import org.wikipedia.R;
+import org.wikipedia.Site;
+import org.wikipedia.page.PageTitle;
+import org.wikipedia.page.linkpreview.SwipeableBottomDialog;
+import org.wikipedia.server.ContentServiceFactory;
+import org.wikipedia.server.PageService;
+import org.wikipedia.server.restbase.RbContentService;
+import org.wikipedia.server.restbase.RbDefinition;
+import org.wikipedia.util.FeedbackUtil;
+import org.wikipedia.util.log.L;
+
+import retrofit.RetrofitError;
+import retrofit.client.Response;
+
+import static org.wikipedia.util.L10nUtil.getStringForArticleLanguage;
+import static org.wikipedia.util.L10nUtil.setConditionalLayoutDirection;
+import static org.wikipedia.util.UriUtil.resolveProtocolRelativeUrl;
+import static org.wikipedia.util.UriUtil.visitInExternalBrowser;
+
+public class WiktionaryDialog extends SwipeableBottomDialog{
+    private static final String WIKTIONARY_DOMAIN = ".wiktionary.org";
+    private static final String PATH_WIKI = "/wiki/";
+    private static final String DOUBLE_SLASH = "//";
+
+    private ProgressBar progressBar;
+    private PageTitle pageTitle;
+    private String selectedText;
+    private RbDefinition currentDefinition;
+    private View rootView;
+
+    public static WiktionaryDialog newInstance(PageTitle title, String 
selectedText) {
+        WiktionaryDialog dialog = new WiktionaryDialog();
+        Bundle args = new Bundle();
+        args.putParcelable("title", title);
+        args.putString("selected_text", selectedText);
+        dialog.setArguments(args);
+        return dialog;
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setStyle(STYLE_NO_TITLE, R.style.LinkPreviewDialog);
+        setContentPeekHeight((int) 
getResources().getDimension(R.dimen.linkPreviewPeekHeight));
+    }
+
+    @Override
+    protected View inflateDialogView(LayoutInflater inflater, ViewGroup 
container) {
+        pageTitle = getArguments().getParcelable("title");
+        selectedText = getArguments().getString("selected_text");
+
+        rootView = inflater.inflate(R.layout.dialog_wiktionary, container);
+        progressBar = (ProgressBar) 
rootView.findViewById(R.id.dialog_wiktionary_progress);
+
+        View overlayRootView = addOverlay(inflater, 
R.layout.dialog_wiktionary_overlay);
+        Button fullDefinitionButton = (Button) 
overlayRootView.findViewById(R.id.wiktionary_full_definition_button);
+        
fullDefinitionButton.setOnClickListener(viewDefinitionButtonClickListener);
+        fullDefinitionButton.setText(getStringForArticleLanguage(pageTitle, 
R.string.wiktionary_full_definition));
+
+        TextView titleText = (TextView) 
rootView.findViewById(R.id.wiktionary_definition_dialog_title);
+        titleText.setText(selectedText);
+        setConditionalLayoutDirection(rootView, 
pageTitle.getSite().getLanguageCode());
+
+        // show the progress bar while we load content...
+        progressBar.setVisibility(View.VISIBLE);
+
+        loadDefinitions();
+
+        return rootView;
+    }
+
+    private void loadDefinitions() {
+        PageService contentService = ContentServiceFactory.create(new 
Site(pageTitle.getSite().getLanguageCode() + WIKTIONARY_DOMAIN));
+        if (contentService instanceof RbContentService) {
+            ((RbContentService) contentService).define(
+                    withUnderscores(selectedText),
+                    definitionOnLoadCallback);
+        } else {
+            FeedbackUtil.showMessage(getParentFragment().getActivity(),
+                    "Wiktionary definitions require mobile content service 
loading!");
+        }
+    }
+
+    private RbDefinition.Callback definitionOnLoadCallback = new 
RbDefinition.Callback() {
+        @Override
+        public void success(RbDefinition definition, Response response) {
+            if (!isAdded()) {
+                return;
+            }
+            L.v(response.getUrl());
+            if (!definition.hasError()) {
+                progressBar.setVisibility(View.GONE);
+                currentDefinition = definition;
+                layOutDefinitionsByUsage();
+            } else {
+                RbDefinition.logError("Wiktionary definition request failed");
+            }
+        }
+
+        @Override
+        public void failure(RetrofitError error) {
+            if (!isAdded()) {
+                return;
+            }
+            L.e("Wiktionary definition fetch error: " + error);
+        }
+    };
+
+    private void layOutDefinitionsByUsage() {
+        LayoutInflater inflater = LayoutInflater.from(getContext());
+        LinearLayout fullDefinitionsList = (LinearLayout) 
rootView.findViewById(R.id.wiktionary_definitions_by_part_of_speech);
+
+        RbDefinition.Usage[] usageList = currentDefinition.getUsages();
+        for (int i = 0; i < usageList.length; i++) {
+            View usageView = 
inflater.inflate(R.layout.item_wiktionary_definitions_list, (ViewGroup) 
rootView, false);
+            layOutUsage(usageList[i], usageView, inflater);
+            fullDefinitionsList.addView(usageView);
+        }
+    }
+
+    private void layOutUsage(RbDefinition.Usage currentUsage, View usageView, 
LayoutInflater inflater) {
+        TextView partOfSpeechView = (TextView) 
usageView.findViewById(R.id.wiktionary_part_of_speech);
+        partOfSpeechView.setText(currentUsage.getPartOfSpeech());
+
+        LinearLayout definitionsForPartOfSpeechList = (LinearLayout) 
usageView.findViewById(R.id.list_wiktionary_definitions_with_examples);
+        for (int i = 0; i < currentUsage.getDefinitions().length; i++) {
+            View definitionContainerView = 
inflater.inflate(R.layout.item_wiktionary_definition_with_examples, (ViewGroup) 
rootView, false);
+            layOutDefinitionWithExamples(currentUsage.getDefinitions()[i], 
definitionContainerView, inflater, i + 1);
+            definitionsForPartOfSpeechList.addView(definitionContainerView);
+        }
+    }
+
+    private void layOutDefinitionWithExamples(RbDefinition.Definition 
currentDefinition, View definitionContainerView, LayoutInflater inflater, int 
count) {
+        TextView definitionView = (TextView) 
definitionContainerView.findViewById(R.id.wiktionary_definition);
+        String definitionWithCount = getCounterString(count) + 
currentDefinition.getDefinition();
+        definitionView.setText(definitionWithCount);
+
+        LinearLayout examplesView = (LinearLayout) 
definitionContainerView.findViewById(R.id.wiktionary_examples);
+        if (currentDefinition.getExamples() != null) {
+            layoutExamples(currentDefinition.getExamples(), examplesView, 
inflater);
+        }
+    }
+
+    private String getCounterString(int count) {
+        return count + ". ";
+    }
+
+    private void layoutExamples(String[] examples, LinearLayout examplesView, 
LayoutInflater inflater) {
+        for (String example : examples) {
+            TextView exampleView = (TextView) 
inflater.inflate(R.layout.item_wiktionary_example, (ViewGroup) rootView, false);
+            exampleView.setText(example);
+            examplesView.addView(exampleView);
+        }
+    }
+
+    private String withUnderscores(String s) {
+        return s.replace(" ", "_");
+    }
+
+    private View.OnClickListener viewDefinitionButtonClickListener = new 
View.OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            sendViewDefinitionIntent();
+        }
+    };
+
+    private void sendViewDefinitionIntent() {
+        visitInExternalBrowser(getActivity(), constructWiktionaryUrl());
+    }
+
+    private Uri constructWiktionaryUrl() {
+        return Uri.parse(resolveProtocolRelativeUrl(DOUBLE_SLASH + 
pageTitle.getSite().getLanguageCode() + WIKTIONARY_DOMAIN + PATH_WIKI + 
withUnderscores(selectedText)));
+    }
+}
diff --git a/app/src/main/res/layout/dialog_wiktionary.xml 
b/app/src/main/res/layout/dialog_wiktionary.xml
new file mode 100644
index 0000000..81a21e0
--- /dev/null
+++ b/app/src/main/res/layout/dialog_wiktionary.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:tools="http://schemas.android.com/tools";
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="8dp"
+            android:background="@drawable/link_preview_top_shadow"/>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:minHeight="@dimen/linkPreviewPeekHeight"
+            android:background="?attr/link_preview_background_color"
+            android:orientation="vertical">
+
+            <TextView
+                android:id="@+id/wiktionary_definition_dialog_title"
+                android:clickable="false"
+                android:layout_width="match_parent"
+                android:layout_height="48dp"
+                android:gravity="center_vertical"
+                style="@style/RtlAwareTextView"
+                android:textColor="?attr/link_preview_text_color"
+                android:paddingLeft="16dp"
+                android:paddingRight="16dp"
+                android:textSize="20sp"
+                android:maxLines="1"
+                android:ellipsize="end"
+                tools:text="Lorem ipsum" />
+
+            <View
+                android:layout_width="match_parent"
+                android:layout_height="0.5dp"
+                android:layout_marginLeft="16dp"
+                android:layout_marginRight="16dp"
+                android:background="@color/list_separator_light"/>
+
+            <LinearLayout
+                android:id="@+id/wiktionary_definitions_by_part_of_speech"
+                android:orientation="vertical"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1"
+                android:paddingTop="4dp"
+                android:paddingLeft="16dp"
+                android:paddingRight="16dp"
+                android:clickable="false"/>
+
+            <View
+                android:id="@+id/wiktionary_dialog_bottom_padding"
+                android:layout_width="match_parent"
+                android:layout_height="48dp"
+                android:clickable="false"/>
+
+        </LinearLayout>
+
+    </LinearLayout>
+
+    <ProgressBar
+        android:id="@+id/dialog_wiktionary_progress"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"/>
+
+</FrameLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_wiktionary_overlay.xml 
b/app/src/main/res/layout/dialog_wiktionary_overlay.xml
new file mode 100644
index 0000000..90586cb
--- /dev/null
+++ b/app/src/main/res/layout/dialog_wiktionary_overlay.xml
@@ -0,0 +1,20 @@
+<?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:layout_gravity="bottom"
+    android:orientation="horizontal">
+    <Button
+        android:id="@+id/wiktionary_full_definition_button"
+        android:layout_width="0dp"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp"
+        android:textColor="?attr/link_color"
+        android:background="?attr/link_preview_button_background"
+        style="@style/Widget.AppCompat.Button.Borderless"
+        android:textSize="@dimen/abc_text_size_menu_material"
+        android:text="@string/wiktionary_full_definition"/>
+</LinearLayout>
\ No newline at end of file
diff --git 
a/app/src/main/res/layout/item_wiktionary_definition_with_examples.xml 
b/app/src/main/res/layout/item_wiktionary_definition_with_examples.xml
new file mode 100644
index 0000000..2edda48
--- /dev/null
+++ b/app/src/main/res/layout/item_wiktionary_definition_with_examples.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="?attr/link_preview_background_color"
+    android:clickable="false">
+    <TextView
+        android:id="@+id/wiktionary_definition"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textColor="?attr/link_preview_text_color"
+        android:lineSpacingMultiplier="1.3"
+        android:layout_marginTop="4dp"
+        android:layout_marginBottom="4dp"
+        android:background="?attr/link_preview_background_color"
+        android:clickable="false"/>
+    <LinearLayout
+        android:id="@+id/wiktionary_examples"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?attr/link_preview_background_color"
+        android:orientation="vertical"
+        android:clickable="false"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_wiktionary_definitions_list.xml 
b/app/src/main/res/layout/item_wiktionary_definitions_list.xml
new file mode 100644
index 0000000..454c51c
--- /dev/null
+++ b/app/src/main/res/layout/item_wiktionary_definitions_list.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    android:orientation="vertical"
+    android:background="?attr/link_preview_background_color"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <TextView
+        android:id="@+id/wiktionary_part_of_speech"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?attr/link_preview_background_color"
+        android:layout_marginTop="4dp"
+        android:layout_marginBottom="4dp"/>
+    <LinearLayout
+        android:id="@+id/list_wiktionary_definitions_with_examples"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:background="?attr/link_preview_background_color"
+        android:orientation="vertical"
+        android:clickable="false"/>
+    <View
+        android:id="@+id/definition_list_bottom_padding"
+        android:layout_width="match_parent"
+        android:layout_height="8dp"
+        android:background="?attr/link_preview_background_color"
+        android:clickable="false"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/layout/item_wiktionary_example.xml 
b/app/src/main/res/layout/item_wiktionary_example.xml
new file mode 100644
index 0000000..6041a25
--- /dev/null
+++ b/app/src/main/res/layout/item_wiktionary_example.xml
@@ -0,0 +1,13 @@
+<?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:paddingLeft="16dp"
+    android:paddingStart="16dp"
+    android:paddingRight="16dp"
+    android:paddingEnd="16dp"
+    android:paddingBottom="2dp"
+    android:textStyle="italic"
+    android:lineSpacingMultiplier="1.1"
+    android:clickable="false"
+    android:textColor="?attr/link_preview_text_color"/>
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_text_select.xml 
b/app/src/main/res/menu/menu_text_select.xml
index 2814456..8c15114 100644
--- a/app/src/main/res/menu/menu_text_select.xml
+++ b/app/src/main/res/menu/menu_text_select.xml
@@ -7,6 +7,11 @@
           android:icon="?actionModeCopyDrawable"
           app:showAsAction="ifRoom" />
 
+    <item android:id="@+id/menu_text_select_define"
+          android:title="@string/menu_text_select_define"
+          android:icon="@drawable/ic_license_cc"
+          app:showAsAction="ifRoom" />
+
     <item android:id="@+id/menu_text_select_share"
           android:title="@string/menu_text_select_share"
           android:icon="?actionModeShareDrawable"
diff --git a/app/src/main/res/values-qq/strings.xml 
b/app/src/main/res/values-qq/strings.xml
index 2558ffa..ad43865 100644
--- a/app/src/main/res/values-qq/strings.xml
+++ b/app/src/main/res/values-qq/strings.xml
@@ -67,6 +67,8 @@
   <string name="menu_long_press_copy_page">Menu item for copying a link to the 
system clipboard for pasting later.</string>
   <string name="menu_text_select_copy">Menu item caption for copying text to 
the system clipboard for pasting later.
 {{Identical|Copy}}</string>
+  <string name="menu_text_select_define">Menu item caption for launching a 
dialog containing Wiktionary definitions for the selected text.
+{{Identical|Copy}}</string>
   <string name="menu_text_select_share">Menu item caption for sharing text and 
images with other apps such as Email and Twitter.
 {{Identical|Share}}</string>
   <string name="nav_item_nearby">Entry in nav drawer for Nearby feature
@@ -298,6 +300,9 @@
   <string name="widget_name_search">Name of the Widget (as seen in the Android 
widget picker) for searching Wikipedia
 
 Followed by {{msg-wm|Wikipedia-android-strings-alpha update notification 
text}}.</string>
+
+  <string name="wiktionary_full_definition">Label for button on dialog 
containing selected content from Wiktionary, allowing the user to navigate to 
Wiktionary to view a word\'s full definition.</string>
+
   <string name="app_store_description">Description of the app as put up on the 
Google Play Store</string>
   <string name="alpha_update_notification_title">Title for notification when 
new alpha update is available.
   
diff --git a/app/src/main/res/values/strings.xml 
b/app/src/main/res/values/strings.xml
index d1be1ce..3317ed4 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -49,6 +49,7 @@
 
     <!-- Toolbar menu items -->
     <string name="menu_text_select_copy">Copy</string>
+    <string name="menu_text_select_define">Define</string>
     <string name="menu_text_select_share">Share</string>
 
     <!-- Nearby -->
@@ -217,6 +218,7 @@
     <string name="widget_name_featured_page">Wikipedia featured page</string>
     <string name="widget_title_featured_page">Today\'s featured page:</string>
     <string name="widget_name_search">Wikipedia search</string>
+    <string name="wiktionary_full_definition">Full definition</string>
 
     <string name="app_store_description" 
tools:ignore="PluralsCandidate,UnusedResources,StringFormatInvalid">Official 
Wikipedia App for Android. Wikipedia is the free encyclopedia containing more 
than 32 million articles in 280 languages, and is the most comprehensive and 
widely used reference work humans have ever compiled.
 

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I461d84ab241c26d4c34649afd09eafea6f8b11e2
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Mholloway <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to