Dbrant has uploaded a new change for review.

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

Change subject: [WIP] Link Previews: TNG
......................................................................

[WIP] Link Previews: TNG

For entertainment only! Please hold off on commenting/reviewing for now.

Change-Id: I8326dba91d76b821d5c58550e20544c55d432808
---
M wikipedia/build.gradle
A wikipedia/res/drawable-xxhdpi/checkerboard.png
M wikipedia/res/layout/dialog_link_preview.xml
D wikipedia/res/layout/dialog_link_preview_2.xml
A wikipedia/res/layout/dialog_link_preview_container.xml
A wikipedia/res/layout/item_gallery_thumbnail.xml
A wikipedia/res/menu/menu_link_preview.xml
M wikipedia/res/values/colors.xml
M wikipedia/res/values/strings.xml
M wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
M wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
M wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
A 
wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryCollectionWithThumbFetchTask.java
M wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryItem.java
A 
wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryThumbnailScrollView.java
M wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
M 
wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
M wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
M wikipedia/src/main/java/org/wikipedia/page/linkpreview/PreviewFetchTask.java
A 
wikipedia/src/main/java/org/wikipedia/page/linkpreview/SwipeableBottomDialog.java
M wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
21 files changed, 596 insertions(+), 353 deletions(-)


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

diff --git a/wikipedia/build.gradle b/wikipedia/build.gradle
index d0dd470..a6bb1cd 100644
--- a/wikipedia/build.gradle
+++ b/wikipedia/build.gradle
@@ -115,6 +115,7 @@
 
     compile 'com.android.support:appcompat-v7:22.2.1' // includes support-v4
     compile 'com.android.support:design:22.2.1'
+    compile 'com.android.support:recyclerview-v7:22.1.1'
     compile 'com.android.support:percent:22.2.0'
     compile 'com.squareup.okhttp:okhttp-urlconnection:2.4.0'
     compile 'com.squareup.okhttp:okhttp:2.4.0'
diff --git a/wikipedia/res/drawable-xxhdpi/checkerboard.png 
b/wikipedia/res/drawable-xxhdpi/checkerboard.png
new file mode 100644
index 0000000..e47fd46
--- /dev/null
+++ b/wikipedia/res/drawable-xxhdpi/checkerboard.png
Binary files differ
diff --git a/wikipedia/res/layout/dialog_link_preview.xml 
b/wikipedia/res/layout/dialog_link_preview.xml
index 37db72c..83c7c4f 100755
--- a/wikipedia/res/layout/dialog_link_preview.xml
+++ b/wikipedia/res/layout/dialog_link_preview.xml
@@ -3,36 +3,56 @@
 <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="256dp"
-    android:orientation="horizontal"
+    android:layout_height="wrap_content"
     android:background="?attr/window_background_color">
 
     <LinearLayout
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:background="@color/link_preview_background_light"
         android:orientation="vertical">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
+            android:background="@color/link_preview_toolbar_light"
             android:orientation="horizontal">
+            <ImageView
+                android:id="@+id/link_preview_image"
+                android:layout_width="72dp"
+                android:layout_height="72dp"
+                android:src="@drawable/ic_pageimage_placeholder"
+                android:contentDescription="@null"
+                android:scaleType="centerCrop"/>
             <TextView
                 android:id="@+id/link_preview_title"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
                 android:layout_weight="1"
+                android:layout_gravity="center_vertical"
                 style="@style/RtlAwareTextView"
-                android:paddingTop="18dp"
-                android:paddingBottom="12dp"
-                android:paddingLeft="12dp"
-                android:paddingRight="12dp"
+                android:padding="12dp"
                 android:textSize="18sp"
                 android:fontFamily="serif"
                 android:lineSpacingMultiplier="0.8"
                 android:maxLines="2"
                 android:ellipsize="end"
-                android:textColor="?attr/link_color"
+                android:textColor="@android:color/white"
                 tools:text="Lorem ipsum"/>
+
+            <LinearLayout
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center_vertical">
+                <ImageView
+                    android:id="@+id/link_preview_overflow_button"
+                    android:layout_width="48dp"
+                    android:layout_height="48dp"
+                    android:clickable="true"
+                    android:padding="12dp"
+                    android:src="@drawable/ic_more_vert" />
+            </LinearLayout>
+
         </LinearLayout>
 
         <TextView
@@ -42,47 +62,33 @@
             android:visibility="gone"
             tools:text="Lorem ipsum"/>
 
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="0.5dp"
-            android:background="@color/list_separator_light"/>
-
-        <LinearLayout
+        <FrameLayout
             android:id="@+id/link_preview_container"
             android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1"
-            android:orientation="horizontal"
-            android:padding="6dp"
-            android:background="?attr/window_background_color">
-
+            android:layout_height="wrap_content">
             <TextView
                 android:id="@+id/link_preview_extract"
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="6"
+                android:layout_width="match_parent"
+                android:layout_height="200dp"
                 style="@style/RtlAwareTextView"
-                android:paddingStart="6dp"
-                android:paddingLeft="6dp"
-                android:paddingEnd="6dp"
-                android:paddingRight="6dp"
+                android:padding="12dp"
                 android:textSize="16sp"
+                android:textColor="@color/link_preview_text_light"
                 tools:text="Lorem ipsum"/>
+        </FrameLayout>
 
-            <FrameLayout
-                android:layout_width="0dp"
-                android:layout_height="match_parent"
-                android:layout_weight="4">
-                <ImageView
-                    android:id="@+id/link_preview_image"
-                    android:layout_width="match_parent"
-                    android:layout_height="match_parent"
-                    android:src="?attr/lead_image_drawable"
-                    android:contentDescription="@null"
-                    android:scaleType="centerCrop"/>
-            </FrameLayout>
+        <org.wikipedia.page.gallery.GalleryThumbnailScrollView
+            android:id="@+id/link_preview_thumbnail_gallery"
+            android:layout_width="match_parent"
+            android:layout_height="96dp"
+            android:visibility="gone"/>
 
-        </LinearLayout>
+        <Button
+            android:id="@+id/link_preview_go_button"
+            android:layout_width="match_parent"
+            android:layout_height="48dp"
+            style="@style/ButtonProgressive"
+            android:text="Continue to article"/>
 
     </LinearLayout>
 
diff --git a/wikipedia/res/layout/dialog_link_preview_2.xml 
b/wikipedia/res/layout/dialog_link_preview_2.xml
deleted file mode 100755
index 8470700..0000000
--- a/wikipedia/res/layout/dialog_link_preview_2.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
-    xmlns:tools="http://schemas.android.com/tools";
-    android:layout_width="match_parent"
-    android:layout_height="256dp"
-    android:orientation="vertical">
-
-    <FrameLayout
-        android:id="@+id/link_preview_container"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <ImageView
-            android:id="@+id/link_preview_image"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="@color/actionbar_background"
-            android:contentDescription="@null"
-            android:scaleType="centerCrop"/>
-        <View
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:background="@drawable/link_preview_gradient"/>
-
-        <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_marginTop="@dimen/activity_vertical_margin"
-            android:layout_marginBottom="@dimen/activity_vertical_margin"
-            android:layout_marginLeft="@dimen/activity_horizontal_margin"
-            android:layout_marginRight="@dimen/activity_horizontal_margin"
-            android:layout_marginStart="@dimen/activity_horizontal_margin"
-            android:layout_marginEnd="@dimen/activity_horizontal_margin"
-            android:orientation="vertical">
-
-            <LinearLayout
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:orientation="vertical">
-                <TextView
-                    android:id="@+id/link_preview_title"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    style="@style/RtlAwareTextView"
-                    android:layout_gravity="center_vertical"
-                    android:paddingBottom="8dp"
-                    android:textSize="26sp"
-                    android:lineSpacingMultiplier="0.8"
-                    android:maxLines="2"
-                    android:ellipsize="end"
-                    android:textColor="@android:color/white"
-                    tools:text="Lorem ipsum"/>
-                <TextView
-                    android:id="@+id/link_preview_description"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    style="@style/RtlAwareTextView"
-                    android:layout_marginTop="-8dp"
-                    android:paddingBottom="2dp"
-                    android:textSize="12sp"
-                    android:lineSpacingMultiplier="0.9"
-                    android:maxLines="2"
-                    android:ellipsize="end"
-                    android:textColor="@android:color/white"
-                    tools:text="Lorem ipsum"/>
-
-            </LinearLayout>
-
-            <TextView
-                android:id="@+id/link_preview_extract"
-                android:layout_width="match_parent"
-                android:layout_height="0dp"
-                android:layout_weight="1"
-                style="@style/RtlAwareTextView"
-                android:paddingTop="8dp"
-                android:textColor="@android:color/white"
-                android:textSize="16sp"
-                tools:text="Lorem ipsum"/>
-
-        </LinearLayout>
-
-        <ProgressBar
-            android:id="@+id/link_preview_progress"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"/>
-
-    </FrameLayout>
-</LinearLayout>
\ No newline at end of file
diff --git a/wikipedia/res/layout/dialog_link_preview_container.xml 
b/wikipedia/res/layout/dialog_link_preview_container.xml
new file mode 100644
index 0000000..02067ed
--- /dev/null
+++ b/wikipedia/res/layout/dialog_link_preview_container.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<ListView xmlns:android="http://schemas.android.com/apk/res/android";
+    android:id="@+id/link_preview_container_list"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:scrollbars="none"
+    android:overScrollMode="never"
+    android:listSelector="@null"
+    android:divider="@null"
+    android:dividerHeight="0dp"
+    />
diff --git a/wikipedia/res/layout/item_gallery_thumbnail.xml 
b/wikipedia/res/layout/item_gallery_thumbnail.xml
new file mode 100644
index 0000000..d8204f7
--- /dev/null
+++ b/wikipedia/res/layout/item_gallery_thumbnail.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
+
+    <ImageView
+        android:id="@+id/gallery_thumbnail_image"
+        android:layout_width="96dp"
+        android:layout_height="96dp"
+        android:src="@drawable/checkerboard"
+        android:scaleType="centerCrop"
+        android:contentDescription="@null" />
+
+</FrameLayout>
diff --git a/wikipedia/res/menu/menu_link_preview.xml 
b/wikipedia/res/menu/menu_link_preview.xml
new file mode 100644
index 0000000..f31cd48
--- /dev/null
+++ b/wikipedia/res/menu/menu_link_preview.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android";>
+    <item android:id="@+id/menu_save_page"
+        android:title="@string/menu_save_page"
+          />
+    <item android:id="@+id/menu_share_page"
+        android:title="@string/menu_share_page"
+        />
+    <item android:id="@+id/menu_copy_url"
+        android:title="@string/menu_copy_link_address"
+        />
+</menu>
\ No newline at end of file
diff --git a/wikipedia/res/values/colors.xml b/wikipedia/res/values/colors.xml
index a5847d7..aa1efa1 100644
--- a/wikipedia/res/values/colors.xml
+++ b/wikipedia/res/values/colors.xml
@@ -50,6 +50,9 @@
     <color name="tab_shadow_light">#ffc0c0c0</color>
     <color name="toc_button_light">#ff009688</color>
     <color name="tool_tip_default_light">@android:color/black</color>
+    <color name="link_preview_toolbar_light">#404040</color>
+    <color name="link_preview_background_light">#f0f0f0</color>
+    <color name="link_preview_text_light">#505050</color>
 
     <color name="link_dark">#ff2B6FB2</color>
     <color name="button_dark">#ff2B6FB2</color>
diff --git a/wikipedia/res/values/strings.xml b/wikipedia/res/values/strings.xml
index 7a1bcc0..5c4496b 100644
--- a/wikipedia/res/values/strings.xml
+++ b/wikipedia/res/values/strings.xml
@@ -295,4 +295,5 @@
     <string name="error_unknown">An unknown error occurred.</string>
     <string name="format_error_server_message">Message: \"%s\"</string>
     <string name="format_error_server_code">Code: \"%s\"</string>
+    <string name="menu_copy_link_address">Copy link address</string>
 </resources>
diff --git a/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java 
b/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
index 60d25fa..559b9c1 100644
--- a/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/history/HistoryFragment.java
@@ -30,6 +30,8 @@
 import org.wikipedia.R;
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.page.PageActivity;
+import org.wikipedia.page.PageTitle;
+import org.wikipedia.page.linkpreview.LinkPreviewDialog;
 import org.wikipedia.pageimages.PageImage;
 
 import java.text.DateFormat;
@@ -110,9 +112,16 @@
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
                 if (actionMode == null) {
-                    HistoryEntry oldEntry = (HistoryEntry) view.getTag();
-                    HistoryEntry newEntry = new 
HistoryEntry(oldEntry.getTitle(), HistoryEntry.SOURCE_HISTORY);
-                    
((PageActivity)getActivity()).displayNewPage(oldEntry.getTitle(), newEntry);
+                    PageTitle title = ((HistoryEntry) 
view.getTag()).getTitle();
+                    LinkPreviewDialog dialog = 
LinkPreviewDialog.newInstance(title);
+                    dialog.setOnNavigateListener(new 
LinkPreviewDialog.OnNavigateListener() {
+                        @Override
+                        public void onNavigate(PageTitle title) {
+                            HistoryEntry newEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_HISTORY);
+                            
((PageActivity)getActivity()).displayNewPage(title, newEntry);
+                        }
+                    });
+                    dialog.show(getActivity().getSupportFragmentManager(), 
"link_preview_dialog");
                 }
             }
         });
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java 
b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
index 6661146..cba4a50 100755
--- a/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/PageViewFragmentInternal.java
@@ -40,6 +40,7 @@
 import org.wikipedia.views.WikiErrorView;
 
 import android.annotation.TargetApi;
+import android.app.Activity;
 import android.content.Intent;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -172,6 +173,10 @@
 
     public PageTitle getTitle() {
         return model.getTitle();
+    }
+
+    public PageTitle getTitleOriginal() {
+        return model.getTitleOriginal();
     }
 
     public Page getPage() {
@@ -431,9 +436,14 @@
             ((PageActivity) getActivity()).displayNewPage(title, historyEntry);
             new LinkPreviewFunnel(app, title).logNavigate();
         } else {
-            // For version values 1 or 2, pass the value to the 
LinkPreviewDialog, which will use
-            // the value to adjust its prototype layout.
-            LinkPreviewDialog dialog = LinkPreviewDialog.newInstance(title, 
app.getLinkPreviewVersion());
+            LinkPreviewDialog dialog = LinkPreviewDialog.newInstance(title);
+            dialog.setOnNavigateListener(new 
LinkPreviewDialog.OnNavigateListener() {
+                @Override
+                public void onNavigate(PageTitle title) {
+                    HistoryEntry historyEntry = new HistoryEntry(title, 
HistoryEntry.SOURCE_INTERNAL_LINK);
+                    ((PageActivity) getActivity()).displayNewPage(title, 
historyEntry);
+                }
+            });
             dialog.show(getActivity().getSupportFragmentManager(), 
"link_preview_dialog");
         }
     }
@@ -624,7 +634,8 @@
                     String href = 
Utils.decodeURL(messagePayload.getString("href"));
                     if (href.startsWith("/wiki/")) {
                         PageTitle imageTitle = 
model.getTitle().getSite().titleForInternalLink(href);
-                        showImageGallery(imageTitle, false);
+                        GalleryActivity.showGallery(getActivity(), 
model.getTitleOriginal(),
+                                imageTitle, false);
                     } else {
                         linkHandler.onUrlClick(href);
                     }
@@ -638,7 +649,8 @@
             public void onMessage(String messageType, JSONObject 
messagePayload) {
                 try {
                     String href = 
Utils.decodeURL(messagePayload.getString("href"));
-                    showImageGallery(new PageTitle(href, 
model.getTitle().getSite()), false);
+                    GalleryActivity.showGallery(getActivity(), 
model.getTitleOriginal(),
+                            new PageTitle(href, model.getTitle().getSite()), 
false);
                 } catch (JSONException e) {
                     ACRA.getErrorReporter().handleException(e);
                 }
@@ -816,19 +828,6 @@
             return;
         }
         tocHandler.scrollToSection(sectionAnchor);
-    }
-
-    /**
-     * Launch the image gallery activity, and start with the provided image.
-     * @param imageTitle Image with which to begin the gallery.
-     */
-    public void showImageGallery(PageTitle imageTitle, boolean fromLeadImage) {
-        Intent galleryIntent = new Intent();
-        galleryIntent.setClass(getActivity(), GalleryActivity.class);
-        galleryIntent.putExtra(GalleryActivity.EXTRA_IMAGETITLE, imageTitle);
-        galleryIntent.putExtra(GalleryActivity.EXTRA_PAGETITLE, 
model.getTitleOriginal());
-        galleryIntent.putExtra(GalleryActivity.EXTRA_FROM_LEAD_IMAGE, 
fromLeadImage);
-        getActivity().startActivityForResult(galleryIntent, 
PageActivity.ACTIVITY_REQUEST_GALLERY);
     }
 
     public void onPageLoadComplete() {
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
index 7b316e7..512f065 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryActivity.java
@@ -20,6 +20,7 @@
 import org.wikipedia.util.GradientUtil;
 import org.wikipedia.views.ViewUtil;
 
+import android.app.Activity;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -218,6 +219,20 @@
         });
     }
 
+    /**
+     * Launch the image gallery activity, and start with the provided image.
+     * @param imageTitle Image with which to begin the gallery.
+     */
+    public static void showGallery(Activity activity, PageTitle pageTitle, 
PageTitle imageTitle,
+                                   boolean fromLeadImage) {
+        Intent galleryIntent = new Intent();
+        galleryIntent.setClass(activity, GalleryActivity.class);
+        galleryIntent.putExtra(EXTRA_IMAGETITLE, imageTitle);
+        galleryIntent.putExtra(EXTRA_PAGETITLE, pageTitle);
+        galleryIntent.putExtra(EXTRA_FROM_LEAD_IMAGE, fromLeadImage);
+        activity.startActivityForResult(galleryIntent, 
PageActivity.ACTIVITY_REQUEST_GALLERY);
+    }
+
     private class GalleryPageChangeListener implements 
ViewPager.OnPageChangeListener {
         private int currentPosition = -1;
         @Override
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryCollectionWithThumbFetchTask.java
 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryCollectionWithThumbFetchTask.java
new file mode 100644
index 0000000..d3e04c0
--- /dev/null
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryCollectionWithThumbFetchTask.java
@@ -0,0 +1,42 @@
+package org.wikipedia.page.gallery;
+
+import org.json.JSONObject;
+import org.mediawiki.api.json.Api;
+import org.mediawiki.api.json.RequestBuilder;
+import org.wikipedia.WikipediaApp;
+import org.wikipedia.page.PageQueryTask;
+import org.wikipedia.page.PageTitle;
+import org.wikipedia.Site;
+import java.util.Map;
+
+public abstract class GalleryCollectionWithThumbFetchTask extends 
PageQueryTask<GalleryItem> {
+    private static final String MAX_ITEM_COUNT = "256";
+
+    public GalleryCollectionWithThumbFetchTask(Api api, Site site, PageTitle 
title) {
+        super(LOW_CONCURRENCY, api, site, title);
+    }
+
+    @Override
+    public void buildQueryParams(RequestBuilder builder) {
+        builder.param("prop", "imageinfo")
+               .param("iiprop", "dimensions|mime|url")
+               .param("generator", "images")
+               .param("iiurlwidth", 
Integer.toString(WikipediaApp.PREFERRED_THUMB_SIZE))
+               .param("iiurlheight", 
Integer.toString(WikipediaApp.PREFERRED_THUMB_SIZE))
+               .param("redirects", "")
+               .param("gimlimit", MAX_ITEM_COUNT);
+    }
+
+    @Override
+    public GalleryItem processPage(int pageId, PageTitle pageTitle, JSONObject 
pageData) throws Throwable {
+        return new GalleryItem(pageData);
+    }
+
+    @Override
+    public void onFinish(Map<PageTitle, GalleryItem> result) {
+        GalleryCollection collection = new GalleryCollection(result);
+        onGalleryResult(collection);
+    }
+
+    abstract void onGalleryResult(GalleryCollection result);
+}
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryItem.java 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryItem.java
index 445a5b0..6b0a677 100644
--- a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryItem.java
+++ b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryItem.java
@@ -78,6 +78,7 @@
     public GalleryItem(JSONObject json) throws JSONException {
         this.json = json;
         this.name = json.getString("title");
+        this.metadata = new HashMap<>();
         JSONObject objinfo;
         if (json.has("imageinfo")) {
             objinfo = (JSONObject)json.getJSONArray("imageinfo").get(0);
@@ -96,17 +97,20 @@
                 }
             }
         } else {
-            throw new JSONException("Response did not contain required info.");
+            width = 0;
+            height = 0;
+            thumbUrl = null;
+            mimeType = "*/*";
+            return;
         }
         if (TextUtils.isEmpty(url)) {
             this.url = objinfo.optString("url", "");
         }
-        this.mimeType = objinfo.getString("mime");
-        this.thumbUrl = objinfo.optString("thumburl", "");
-        this.width = objinfo.getInt("width");
-        this.height = objinfo.getInt("height");
-        this.metadata = new HashMap<>();
-        this.license = new ImageLicense("", "", "");
+        mimeType = objinfo.getString("mime");
+        thumbUrl = objinfo.optString("thumburl", "");
+        width = objinfo.getInt("width");
+        height = objinfo.getInt("height");
+        license = new ImageLicense("", "", "");
         JSONObject extmetadata = objinfo.optJSONObject("extmetadata");
         if (extmetadata != null) {
             Iterator<String> keys = extmetadata.keys();
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryThumbnailScrollView.java
 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryThumbnailScrollView.java
new file mode 100644
index 0000000..b9c0155
--- /dev/null
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/gallery/GalleryThumbnailScrollView.java
@@ -0,0 +1,128 @@
+package org.wikipedia.page.gallery;
+
+import org.wikipedia.R;
+import org.wikipedia.WikipediaApp;
+import org.wikipedia.page.PageTitle;
+import org.wikipedia.util.FeedbackUtil;
+
+import android.content.Context;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+
+import com.squareup.picasso.Picasso;
+
+public class GalleryThumbnailScrollView extends RecyclerView {
+    private static final String TAG = "ThumbnailGallery";
+
+    private Context mContext;
+    private PageTitle mPageTitle;
+    private GalleryCollection mCollection;
+    private GalleryViewListener mListener;
+
+    private OnClickListener mItemClickListener = new OnClickListener() {
+        @Override
+        public void onClick(View v) {
+            if (mListener != null) {
+                GalleryItem item = (GalleryItem) v.getTag();
+                mListener.onGalleryItemClicked(new PageTitle(item.getName(), 
mPageTitle.getSite()));
+            }
+        }
+    };
+
+    public GalleryThumbnailScrollView(Context context) {
+        this(context, null);
+    }
+
+    public GalleryThumbnailScrollView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public GalleryThumbnailScrollView(Context context, AttributeSet attrs, int 
defStyle) {
+        super(context, attrs, defStyle);
+        this.mContext = context;
+        setLayoutManager(new LinearLayoutManager(context, 
LinearLayoutManager.HORIZONTAL, false));
+    }
+
+    public interface GalleryViewListener {
+        void onGalleryLoaded();
+        void onGalleryItemClicked(PageTitle imageTitle);
+    }
+
+    public void setGalleryViewListener(GalleryViewListener listener) {
+        mListener = listener;
+    }
+
+    public void loadGallery(PageTitle title) {
+        mPageTitle = title;
+        new 
GalleryCollectionWithThumbFetchTask(WikipediaApp.getInstance().getAPIForSite(mPageTitle.getSite()),
+                mPageTitle.getSite(), mPageTitle) {
+            @Override
+            public void onGalleryResult(GalleryCollection result) {
+                mCollection = result;
+                setAdapter(new GalleryViewAdapter());
+                if (mListener != null) {
+                    mListener.onGalleryLoaded();
+                }
+            }
+            @Override
+            public void onCatch(Throwable caught) {
+                Log.e(TAG, "Failed to fetch gallery collection.", caught);
+                FeedbackUtil.showError(getRootView(), caught);
+            }
+        }.execute();
+    }
+
+    public int getItemCount() {
+        return mCollection != null ? mCollection.getItemList().size() : 0;
+    }
+
+    private class GalleryItemHolder extends ViewHolder {
+        private final ImageView mImageView;
+        private GalleryItem mGalleryItem;
+
+        public GalleryItemHolder(View itemView) {
+            super(itemView);
+            mImageView = (ImageView) 
itemView.findViewById(R.id.gallery_thumbnail_image);
+        }
+
+        public void bindItem(GalleryItem item) {
+            mGalleryItem = item;
+            mImageView.setOnClickListener(mItemClickListener);
+            mImageView.setTag(mGalleryItem);
+            if (WikipediaApp.getInstance().isImageDownloadEnabled()
+                    && !TextUtils.isEmpty(mGalleryItem.getThumbUrl())) {
+                Picasso.with(mContext)
+                        .load(mGalleryItem.getThumbUrl())
+                        .placeholder(R.drawable.checkerboard)
+                        .error(R.drawable.checkerboard)
+                        .into(mImageView);
+            }
+        }
+    }
+
+    private final class GalleryViewAdapter extends 
RecyclerView.Adapter<GalleryItemHolder> {
+        @Override
+        public int getItemCount() {
+            return mCollection.getItemList().size();
+        }
+
+        @Override
+        public GalleryItemHolder onCreateViewHolder(ViewGroup parent, int pos) 
{
+            View view = LayoutInflater.from(mContext)
+                    .inflate(R.layout.item_gallery_thumbnail, parent, false);
+            return new GalleryItemHolder(view);
+        }
+
+        @Override
+        public void onBindViewHolder(GalleryItemHolder holder, int pos) {
+            holder.bindItem(mCollection.getItemList().get(pos));
+        }
+    }
+}
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java 
b/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
index 658feb6..6505604 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.java
@@ -33,6 +33,7 @@
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.bridge.CommunicationBridge;
 import org.wikipedia.page.PageViewFragmentInternal;
+import org.wikipedia.page.gallery.GalleryActivity;
 import org.wikipedia.util.ApiUtil;
 import org.wikipedia.util.DimenUtil;
 import org.wikipedia.util.GradientUtil;
@@ -148,7 +149,8 @@
                         PageTitle imageTitle = new PageTitle("File:" + 
imageName,
                                                              
parentFragment.getTitle()
                                                                            
.getSite());
-                        parentFragment.showImageGallery(imageTitle, true);
+                        
GalleryActivity.showGallery(parentFragment.getActivity(),
+                                parentFragment.getTitleOriginal(), imageTitle, 
false);
                     }
                     return true;
                 }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
index 25165ef..8b11a49 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewContents.java
@@ -1,17 +1,10 @@
 package org.wikipedia.page.linkpreview;
 
-import android.text.TextUtils;
-
 import org.wikipedia.page.PageTitle;
 import org.wikipedia.Site;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.wikipedia.Utils;
-
-import java.text.BreakIterator;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
 
 public class LinkPreviewContents {
 
@@ -20,20 +13,28 @@
         return title;
     }
 
-    private final List<String> extract;
-    public List<String> getExtract() {
+    private final String leadImageName;
+    public String getLeadImageName() {
+        return leadImageName;
+    }
+
+    private final String extract;
+    public String getExtract() {
         return extract;
     }
 
     public LinkPreviewContents(JSONObject json, Site site) throws 
JSONException {
         title = new PageTitle(json.getString("title"), site);
-        extract = getSentences(json.getString("extract"), site);
+        // replace newlines in the extract with double newlines, so that 
they'll show up
+        // as paragraph breaks when displayed in a TextView.
+        extract = json.getString("extract").replace("\n", "\n\n");
         if (json.has("thumbnail")) {
             
title.setThumbUrl(json.getJSONObject("thumbnail").optString("source"));
         }
         if (json.has("terms") && 
json.getJSONObject("terms").has("description")) {
             
title.setDescription(Utils.capitalizeFirstChar(json.getJSONObject("terms").getJSONArray("description").optString(0)));
         }
+        leadImageName = json.has("pageimage") ? "File:" + 
json.optString("pageimage") : null;
     }
 
     /**
@@ -77,39 +78,4 @@
         return (level == 0) ? outStr.toString() : text;
     }
 
-    /**
-     * Split a block of text into sentences, taking into account the language 
in which
-     * the text is assumed to be.
-     * @param text Text to be transformed into sentences.
-     * @param site Site that will provide the language of the given text.
-     * @return List of sentences.
-     */
-    public static List<String> getSentences(String text, Site site) {
-        List<String> sentenceList = new ArrayList<>();
-        BreakIterator iterator = BreakIterator.getSentenceInstance(new 
Locale(site.getLanguageCode()));
-        // feed the text into the iterator, with line breaks removed:
-        text = text.replaceAll("(\r|\n)", "");
-        iterator.setText(text);
-        int start = iterator.first();
-        int end = iterator.next();
-        while (end != BreakIterator.DONE) {
-            String sentence = text.substring(start, end).trim();
-            if (!TextUtils.isEmpty(sentence)) {
-                if (sentenceList.size() == 0) {
-                    // if it's the first sentence, then remove parentheses 
from it.
-                    sentenceList.add(removeParens(sentence));
-                } else {
-                    sentenceList.add(sentence);
-                }
-            }
-            start = end;
-            end = iterator.next();
-        }
-        // if we couldn't detect any sentences using the BreakIterator, then 
just return the
-        // original text as a single sentence.
-        if (sentenceList.size() == 0) {
-            sentenceList.add(text);
-        }
-        return sentenceList;
-    }
 }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
index 0b917c7..f73f860 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
@@ -2,136 +2,131 @@
 
 import org.wikipedia.page.PageTitle;
 import org.wikipedia.R;
-import org.wikipedia.Utils;
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.analytics.LinkPreviewFunnel;
-import org.wikipedia.history.HistoryEntry;
-import org.wikipedia.page.PageActivity;
+import org.wikipedia.page.gallery.GalleryActivity;
+import org.wikipedia.page.gallery.GalleryThumbnailScrollView;
 import org.wikipedia.util.ApiUtil;
 import org.wikipedia.util.FeedbackUtil;
 
 import com.squareup.picasso.Callback;
 import com.squareup.picasso.Picasso;
-import android.app.Dialog;
 import android.content.DialogInterface;
 import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.os.Bundle;
-import android.support.annotation.NonNull;
-import android.support.v4.app.DialogFragment;
-import android.support.v4.view.GestureDetectorCompat;
-import android.text.Spannable;
+import android.support.v7.widget.PopupMenu;
 import android.text.TextUtils;
-import android.text.method.ScrollingMovementMethod;
-import android.text.method.Touch;
 import android.util.Log;
-import android.view.GestureDetector;
-import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
+import android.view.MenuItem;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
-import android.view.Window;
-import android.view.WindowManager;
-import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
+import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.LinearLayout;
 import android.widget.ProgressBar;
 import android.widget.TextView;
+
 import java.util.Map;
 
-public class LinkPreviewDialog extends DialogFragment implements 
DialogInterface.OnDismissListener {
+public class LinkPreviewDialog extends SwipeableBottomDialog implements 
DialogInterface.OnDismissListener {
     private static final String TAG = "LinkPreviewDialog";
-    private static final int DIALOG_HEIGHT = 196;
-
-    // TODO: remove when we finalize the layout to be used.
-    private int layoutToggle;
+    private static final int MAX_PEEK_HEIGHT = 320;
 
     private boolean navigateSuccess = false;
 
     private View previewContainer;
     private ProgressBar progressBar;
     private TextView titleText;
-    private TextView descriptionText;
     private TextView extractText;
     private ImageView previewImage;
+    private GalleryThumbnailScrollView thumbnailGallery;
 
     private WikipediaApp app;
     private PageTitle pageTitle;
 
     private LinkPreviewFunnel funnel;
+    private LinkPreviewContents contents;
+    private OnNavigateListener onNavigateListener;
 
-    private GestureDetectorCompat gestureDetector;
-
-    public static LinkPreviewDialog newInstance(PageTitle title, int 
layoutToggle) {
+    public static LinkPreviewDialog newInstance(PageTitle title) {
         LinkPreviewDialog dialog = new LinkPreviewDialog();
         Bundle args = new Bundle();
         args.putParcelable("title", title);
-        args.putInt("layoutToggle", layoutToggle);
         dialog.setArguments(args);
+        dialog.setDialogPeekHeight(MAX_PEEK_HEIGHT);
         return dialog;
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
Bundle savedInstanceState) {
-        layoutToggle = getArguments().getInt("layoutToggle");
-        View rootView = inflater.inflate(layoutToggle == 1 ? 
R.layout.dialog_link_preview : R.layout.dialog_link_preview_2, container);
+    protected View inflateDialogView(LayoutInflater inflater, ViewGroup 
container) {
+        app = WikipediaApp.getInstance();
+        pageTitle = getArguments().getParcelable("title");
+
+        View rootView = inflater.inflate(R.layout.dialog_link_preview, 
container);
+
         previewContainer = rootView.findViewById(R.id.link_preview_container);
         progressBar = (ProgressBar) 
rootView.findViewById(R.id.link_preview_progress);
         titleText = (TextView) rootView.findViewById(R.id.link_preview_title);
-        previewImage = (ImageView) 
rootView.findViewById(R.id.link_preview_image);
-
-        descriptionText = (TextView) 
rootView.findViewById(R.id.link_preview_description);
+        titleText.setText(pageTitle.getDisplayText());
         if (!ApiUtil.hasLollipop()) {
-            LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) 
descriptionText.getLayoutParams();
-            final float marginScale = 0.7f;
-            params.topMargin = (int) (params.topMargin * marginScale);
-            descriptionText.setLayoutParams(params);
+            final int bottomPadding = (int)(8 * app.getScreenDensity());
+            titleText.setPadding(titleText.getPaddingLeft(), 
titleText.getPaddingTop(),
+                    titleText.getPaddingRight(), titleText.getPaddingBottom() 
+ bottomPadding);
         }
 
+        previewImage = (ImageView) 
rootView.findViewById(R.id.link_preview_image);
         extractText = (TextView) 
rootView.findViewById(R.id.link_preview_extract);
-        extractText.setMovementMethod(new ScrollingMovementMethod() {
-            private float startX;
-            private float startY;
-            private float touchSlop = 
ViewConfiguration.get(getDialog().getContext()).getScaledTouchSlop();
 
-            @Override
-            public boolean onTouchEvent(@NonNull TextView widget, @NonNull 
Spannable buffer, @NonNull MotionEvent event) {
-                switch (event.getAction()) {
-                    case MotionEvent.ACTION_DOWN:
-                        startX = event.getX();
-                        startY = event.getY();
-                        break;
-                    case MotionEvent.ACTION_UP:
-                        if (Math.abs(event.getX() - startX) <= touchSlop
-                                && Math.abs(event.getY() - startY) <= 
touchSlop) {
-                            goToLinkedPage();
-                        }
-                        break;
-                    default:
-                        break;
+        thumbnailGallery = (GalleryThumbnailScrollView) 
rootView.findViewById(R.id.link_preview_thumbnail_gallery);
+        if (app.isImageDownloadEnabled()) {
+            thumbnailGallery.loadGallery(pageTitle);
+            thumbnailGallery.setGalleryViewListener(new 
GalleryThumbnailScrollView.GalleryViewListener() {
+                @Override
+                public void onGalleryLoaded() {
+                    if (thumbnailGallery.getItemCount() > 2) {
+                        thumbnailGallery.setVisibility(View.VISIBLE);
+                    }
                 }
-                return Touch.onTouchEvent(widget, buffer, event);
+
+                @Override
+                public void onGalleryItemClicked(PageTitle imageTitle) {
+                    GalleryActivity.showGallery(getActivity(), pageTitle, 
imageTitle, false);
+                }
+            });
+        }
+
+        previewImage.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                if (contents != null && 
!TextUtils.isEmpty(contents.getTitle().getThumbUrl())) {
+                    GalleryActivity.showGallery(getActivity(), pageTitle, new 
PageTitle(contents.getLeadImageName(), pageTitle.getSite()), false);
+                }
             }
         });
 
-        rootView.setOnTouchListener(new View.OnTouchListener() {
+        View goButton = rootView.findViewById(R.id.link_preview_go_button);
+        goButton.setOnClickListener(new View.OnClickListener() {
             @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                gestureDetector.onTouchEvent(event);
-                return true;
+            public void onClick(View v) {
+                goToLinkedPage();
+            }
+        });
+
+        final View overflowButton = 
rootView.findViewById(R.id.link_preview_overflow_button);
+        overflowButton.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                PopupMenu popupMenu = new PopupMenu(getActivity(), 
overflowButton);
+                popupMenu.inflate(R.menu.menu_link_preview);
+                popupMenu.setOnMenuItemClickListener(menuListener);
+                popupMenu.show();
             }
         });
 
         // show the progress bar while we load content...
         progressBar.setVisibility(View.VISIBLE);
 
-        pageTitle = getArguments().getParcelable("title");
-
         // and kick off the task to load all the things...
-        app = WikipediaApp.getInstance();
         new PreviewFetchTask(app.getAPIForSite(pageTitle.getSite()), 
pageTitle) {
             @Override
             public void onFinish(Map<PageTitle, LinkPreviewContents> result) {
@@ -140,7 +135,8 @@
                 }
                 progressBar.setVisibility(View.GONE);
                 if (result.size() > 0) {
-                    layoutPreview((LinkPreviewContents) 
result.values().toArray()[0]);
+                    contents = (LinkPreviewContents) 
result.values().toArray()[0];
+                    layoutPreview();
                 } else {
                     FeedbackUtil.showMessage(getActivity(), 
R.string.error_network_error);
                     dismiss();
@@ -158,24 +154,50 @@
             }
         }.execute();
 
-        LinearLayout.LayoutParams lp = new 
LinearLayout.LayoutParams(inflater.getContext().getResources().getDisplayMetrics().widthPixels,
 (int)(inflater.getContext().getResources().getDisplayMetrics().density * 
DIALOG_HEIGHT));
-        previewContainer.setLayoutParams(lp);
-
         funnel = new LinkPreviewFunnel(app, pageTitle);
         funnel.logLinkClick();
 
         return rootView;
     }
 
+    public interface OnNavigateListener {
+        void onNavigate(PageTitle title);
+    }
+
+    public void setOnNavigateListener(OnNavigateListener listener) {
+        onNavigateListener = listener;
+    }
+
     public void goToLinkedPage() {
-        HistoryEntry historyEntry = new HistoryEntry(pageTitle, 
HistoryEntry.SOURCE_INTERNAL_LINK);
         navigateSuccess = true;
         funnel.logNavigate();
         if (getDialog() != null) {
             getDialog().dismiss();
         }
-        ((PageActivity) getActivity()).displayNewPage(pageTitle, historyEntry);
+        if (onNavigateListener != null) {
+            onNavigateListener.onNavigate(pageTitle);
+        }
     }
+
+    PopupMenu.OnMenuItemClickListener menuListener = new 
PopupMenu.OnMenuItemClickListener() {
+        @Override
+        public boolean onMenuItemClick(MenuItem item) {
+            switch (item.getItemId()) {
+                case R.id.menu_save_page:
+
+                    return true;
+                case R.id.menu_share_page:
+
+                    return true;
+                case R.id.menu_copy_url:
+
+                    return true;
+                default:
+                    break;
+            }
+            return false;
+        }
+    };
 
     @Override
     public void onDismiss(DialogInterface dialogInterface) {
@@ -185,86 +207,25 @@
         }
     }
 
-    @NonNull
-    @Override
-    public Dialog onCreateDialog(Bundle savedInstanceState) {
-        Dialog dialog = super.onCreateDialog(savedInstanceState);
-        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
-        dialog.getWindow().getAttributes().windowAnimations = 
R.style.DialogAnimation;
-
-        dialog.getWindow().setBackgroundDrawable(new 
ColorDrawable(Color.TRANSPARENT));
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
-        lp.copyFrom(dialog.getWindow().getAttributes());
-        lp.gravity = Gravity.BOTTOM;
-        dialog.getWindow().setAttributes(lp);
-
-        gestureDetector = new GestureDetectorCompat(dialog.getContext(), new 
PreviewGestureListener());
-        return dialog;
-    }
-
-    private class PreviewGestureListener extends 
GestureDetector.SimpleOnGestureListener {
-        private final float flingThreshold = 100f;
-        @Override
-        public boolean onSingleTapConfirmed(MotionEvent e) {
-            goToLinkedPage();
-            return true;
-        }
-
-        @Override
-        public boolean onFling(MotionEvent event1, MotionEvent event2, float 
velocityX, float velocityY) {
-            Log.d(TAG, "onFling: x: " + velocityX + ", y: " + velocityY);
-            if (velocityY > flingThreshold) {
-                dismiss();
-            } else if (velocityY < -flingThreshold) {
-                goToLinkedPage();
-            }
-            return true;
-        }
-    }
-
-    private void layoutPreview(final LinkPreviewContents contents) {
+    private void layoutPreview() {
         previewContainer.setVisibility(View.VISIBLE);
-        titleText.setText(contents.getTitle().getDisplayText());
-        if (descriptionText.getVisibility() != View.GONE) {
-            if (TextUtils.isEmpty(contents.getTitle().getDescription())) {
-                descriptionText.setVisibility(View.GONE);
-            } else {
-                descriptionText.setText(contents.getTitle().getDescription());
-                descriptionText.setVisibility(View.VISIBLE);
-            }
+        if (contents.getExtract().length() > 0) {
+            extractText.setText(contents.getExtract());
         }
-        if (contents.getExtract().size() > 0) {
-            // By default, use only a single sentence for the preview...
-            extractText.setText(contents.getExtract().get(0));
-            extractText.post(new Runnable() {
-                @Override
-                public void run() {
-                    final int minLineCount = 4;
-                    // ...however, if the extract text turns out to be smaller 
than x lines,
-                    // then add one more sentence to it!
-                    if (extractText.getLineCount() < minLineCount
-                            && contents.getExtract().size() > 1) {
-                        extractText.setText(contents.getExtract().get(0) + " " 
+ contents.getExtract().get(1));
-                    }
-                }
-            });
-        }
+
+        FrameLayout.LayoutParams extractLayoutParams = 
(FrameLayout.LayoutParams) extractText.getLayoutParams();
+        extractLayoutParams.height = ViewGroup.LayoutParams.WRAP_CONTENT;
+        extractText.setLayoutParams(extractLayoutParams);
+
         if (!TextUtils.isEmpty(contents.getTitle().getThumbUrl()) && 
app.isImageDownloadEnabled()) {
             Picasso.with(getActivity())
                     .load(contents.getTitle().getThumbUrl())
-                    .placeholder(layoutToggle == 1 ? 
Utils.getThemedAttributeId(getActivity(), R.attr.lead_image_drawable) : 
R.drawable.link_preview_gradient)
-                    .error(Utils.getThemedAttributeId(getActivity(), 
R.attr.lead_image_drawable))
+                    .placeholder(R.drawable.ic_pageimage_placeholder)
+                    .error(R.drawable.ic_pageimage_placeholder)
                     .into(previewImage, new Callback() {
                         @Override
                         public void onSuccess() {
-                            if (!isAdded()) {
-                                return;
-                            }
-                            // and perform a subtle Ken Burns animation...
-                            Animation anim = 
AnimationUtils.loadAnimation(getActivity(),
-                                    R.anim.lead_image_zoom);
-                            anim.setFillAfter(true);
-                            previewImage.startAnimation(anim);
+                            previewImage.setBackgroundColor(Color.WHITE);
                         }
 
                         @Override
@@ -273,5 +234,4 @@
                     });
         }
     }
-
 }
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/PreviewFetchTask.java 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/PreviewFetchTask.java
index b059c4b..11865a3 100755
--- 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/PreviewFetchTask.java
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/PreviewFetchTask.java
@@ -3,6 +3,7 @@
 import org.json.JSONObject;
 import org.mediawiki.api.json.Api;
 import org.mediawiki.api.json.RequestBuilder;
+import org.wikipedia.WikipediaApp;
 import org.wikipedia.page.PageQueryTask;
 import org.wikipedia.page.PageTitle;
 
@@ -23,10 +24,11 @@
         // TODO: implement better sentence parsing in our future web service.
         builder.param("prop", "extracts|pageimages|pageterms")
                .param("redirects", "true")
-               .param("exchars", "512")
+               //.param("exchars", "4096")
+               .param("exsentences", "5")
                .param("explaintext", "true")
-               .param("piprop", "thumbnail")
-               .param("pithumbsize", "640")
+               .param("piprop", "thumbnail|name")
+               .param("pithumbsize", 
Integer.toString(WikipediaApp.PREFERRED_THUMB_SIZE))
                .param("wbptterms", "description");
     }
 
diff --git 
a/wikipedia/src/main/java/org/wikipedia/page/linkpreview/SwipeableBottomDialog.java
 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/SwipeableBottomDialog.java
new file mode 100644
index 0000000..32c9b04
--- /dev/null
+++ 
b/wikipedia/src/main/java/org/wikipedia/page/linkpreview/SwipeableBottomDialog.java
@@ -0,0 +1,147 @@
+package org.wikipedia.page.linkpreview;
+
+import org.wikipedia.R;
+import org.wikipedia.WikipediaApp;
+
+import android.app.Dialog;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.FrameLayout;
+import android.widget.ListView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class SwipeableBottomDialog extends DialogFragment {
+    private int dialogPeekHeight;
+
+    private ListView dialogListView;
+    private List<View> dialogViews;
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
Bundle savedInstanceState) {
+        WikipediaApp app = WikipediaApp.getInstance();
+        int displayWidth = 
inflater.getContext().getResources().getDisplayMetrics().widthPixels;
+        int displayHeight = 
inflater.getContext().getResources().getDisplayMetrics().heightPixels;
+        int dialogHeight = (int) (dialogPeekHeight * app.getScreenDensity());
+
+        View rootView = 
inflater.inflate(R.layout.dialog_link_preview_container, container);
+        rootView.setLayoutParams(new FrameLayout.LayoutParams(displayWidth, 
displayHeight));
+
+        View emptyViewDismissTrigger = new View(inflater.getContext());
+        emptyViewDismissTrigger.setLayoutParams(new 
ListView.LayoutParams(displayWidth, 1));
+
+        View emptyViewTop = new View(inflater.getContext());
+        emptyViewTop.setLayoutParams(new ListView.LayoutParams(displayWidth, 
dialogHeight));
+        emptyViewTop.setClickable(true);
+        emptyViewTop.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismiss();
+            }
+        });
+
+        View emptyViewMiddle = new View(inflater.getContext());
+        emptyViewMiddle.setLayoutParams(new 
ListView.LayoutParams(displayWidth, displayHeight - dialogHeight));
+        emptyViewMiddle.setClickable(true);
+        emptyViewMiddle.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismiss();
+            }
+        });
+
+        View dialogView = inflateDialogView(inflater, container);
+
+        dialogViews = new ArrayList<>();
+        dialogViews.add(emptyViewDismissTrigger);
+        dialogViews.add(emptyViewTop);
+        dialogViews.add(emptyViewMiddle);
+        dialogViews.add(dialogView);
+
+        dialogListView = (ListView) 
rootView.findViewById(R.id.link_preview_container_list);
+        dialogListView.setAdapter(new SwipeableAdapter());
+        dialogListView.setSelection(dialogViews.indexOf(emptyViewMiddle));
+        dialogView.post(new Runnable() {
+            @Override
+            public void run() {
+                dialogListView.setOnScrollListener(new 
AbsListView.OnScrollListener() {
+                    @Override
+                    public void onScrollStateChanged(AbsListView view, int 
scrollState) {
+                        // don't need this
+                    }
+
+                    @Override
+                    public void onScroll(AbsListView view, int 
firstVisibleItem, int visibleItemCount, int totalItemCount) {
+                        if (firstVisibleItem == 0) {
+                            dismiss();
+                        }
+                    }
+                });
+            }
+        });
+
+        return rootView;
+    }
+
+    protected abstract View inflateDialogView(LayoutInflater inflater, 
ViewGroup container);
+
+    @NonNull
+    @Override
+    public Dialog onCreateDialog(Bundle savedInstanceState) {
+        Dialog dialog = super.onCreateDialog(savedInstanceState);
+        dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
+        dialog.getWindow().getAttributes().windowAnimations = 
R.style.DialogAnimation;
+        dialog.getWindow().setBackgroundDrawable(new 
ColorDrawable(Color.TRANSPARENT));
+        return dialog;
+    }
+
+    @Override
+    public void onStart() {
+        super.onStart();
+        Dialog dialog = getDialog();
+        if (dialog != null)
+        {
+            dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
+                    ViewGroup.LayoutParams.MATCH_PARENT);
+        }
+    }
+
+    public void setDialogPeekHeight(int height) {
+        dialogPeekHeight = height;
+    }
+
+    private final class SwipeableAdapter extends BaseAdapter {
+        private SwipeableAdapter() {
+        }
+
+        @Override
+        public int getCount() {
+            return dialogViews.size();
+        }
+
+        @Override
+        public Object getItem(int position) {
+            return dialogViews.get(position);
+        }
+
+        @Override
+        public long getItemId(int position) {
+            return position;
+        }
+
+        @Override
+        public View getView(int position, View convertView, ViewGroup parent) {
+            return dialogViews.get(position);
+        }
+    }
+}
diff --git 
a/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java 
b/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
index 81c8029..e2a5ca7 100644
--- a/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
+++ b/wikipedia/src/main/java/org/wikipedia/search/SearchResultsFragment.java
@@ -8,6 +8,7 @@
 import org.wikipedia.WikipediaApp;
 import org.wikipedia.page.PageActivity;
 import org.wikipedia.util.FeedbackUtil;
+import org.wikipedia.page.linkpreview.LinkPreviewDialog;
 import org.wikipedia.views.WikiErrorView;
 import org.wikipedia.views.WikiListView;
 
@@ -114,7 +115,14 @@
             @Override
             public void onItemClick(AdapterView<?> parent, View view, int 
position, long id) {
                 PageTitle item = (PageTitle) 
searchResultsList.getAdapter().getItem(position);
-                searchFragment.navigateToTitle(item, false);
+                LinkPreviewDialog dialog = LinkPreviewDialog.newInstance(item);
+                dialog.setOnNavigateListener(new 
LinkPreviewDialog.OnNavigateListener() {
+                    @Override
+                    public void onNavigate(PageTitle title) {
+                        searchFragment.navigateToTitle(title, false);
+                    }
+                });
+                dialog.show(getActivity().getSupportFragmentManager(), 
"link_preview_dialog");
             }
         });
 

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

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

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

Reply via email to