Mholloway has uploaded a new change for review. ( 
https://gerrit.wikimedia.org/r/344687 )

Change subject: Show an accurate message in the link preview when a page 
doesn't exist
......................................................................

Show an accurate message in the link preview when a page doesn't exist

Updates the link preview to show a "page does not exist" message when
appropriate.

Bug: T161008
Change-Id: I3b95431abb9305b191250ff527272d1869208c54
---
M app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
A app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewErrorView.java
M app/src/main/java/org/wikipedia/util/ThrowableUtil.java
A app/src/main/res/drawable/ic_portable_wifi_off_black_24px.xml
M app/src/main/res/layout/dialog_link_preview.xml
A app/src/main/res/layout/view_link_preview_error.xml
M app/src/main/res/values-qq/strings.xml
M app/src/main/res/values/strings.xml
8 files changed, 251 insertions(+), 54 deletions(-)


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

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 09154c2..c230ca3 100755
--- a/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
+++ b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewDialog.java
@@ -40,17 +40,20 @@
 import org.wikipedia.util.log.L;
 import org.wikipedia.views.ViewUtil;
 
+import java.net.UnknownHostException;
+
 import retrofit2.Call;
 import retrofit2.Response;
 
 import static org.wikipedia.util.L10nUtil.getStringForArticleLanguage;
 import static org.wikipedia.util.L10nUtil.setConditionalLayoutDirection;
+import static org.wikipedia.util.ThrowableUtil.is404;
+import static org.wikipedia.util.ThrowableUtil.isOffline;
 
 public class LinkPreviewDialog extends ExtendedBottomSheetDialogFragment
-        implements DialogInterface.OnDismissListener {
+        implements LinkPreviewErrorView.Callback, 
DialogInterface.OnDismissListener {
     public interface Callback {
-        void onLinkPreviewLoadPage(@NonNull PageTitle title, @NonNull 
HistoryEntry entry,
-                                   boolean inNewTab);
+        void onLinkPreviewLoadPage(@NonNull PageTitle title, @NonNull 
HistoryEntry entry, boolean inNewTab);
         void onLinkPreviewCopyLink(@NonNull PageTitle title);
         void onLinkPreviewAddToList(@NonNull PageTitle title);
         void onLinkPreviewShareLink(@NonNull PageTitle title);
@@ -60,7 +63,7 @@
 
     private LinearLayout dialogContainer;
     private View contentContainer;
-    private View offlineContainer;
+    private LinkPreviewErrorView errorContainer;
     private ProgressBar progressBar;
     private TextView extractText;
     private SimpleDraweeView thumbnailView;
@@ -88,8 +91,7 @@
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-                             Bundle savedInstanceState) {
+    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
Bundle savedInstanceState) {
         WikipediaApp app = WikipediaApp.getInstance();
         pageTitle = getArguments().getParcelable("title");
         entrySource = getArguments().getInt("entrySource");
@@ -98,7 +100,7 @@
         View rootView = inflater.inflate(R.layout.dialog_link_preview, 
container);
         dialogContainer = (LinearLayout) 
rootView.findViewById(R.id.dialog_link_preview_container);
         contentContainer = 
rootView.findViewById(R.id.dialog_link_preview_content_container);
-        offlineContainer = 
rootView.findViewById(R.id.dialog_link_preview_offline_container);
+        errorContainer = (LinkPreviewErrorView) 
rootView.findViewById(R.id.dialog_link_preview_error_container);
         progressBar = (ProgressBar) 
rootView.findViewById(R.id.link_preview_progress);
         toolbarView = rootView.findViewById(R.id.link_preview_toolbar);
         toolbarView.setOnClickListener(goToPageListener);
@@ -198,6 +200,28 @@
         }
     }
 
+    @Override
+    public void setOverlayButtonText(@NonNull String text) {
+        overlayView.setPrimaryButtonText(text);
+    }
+
+    @Override
+    public void setOverlayButtonCallback(@NonNull 
LinkPreviewOverlayView.Callback callback) {
+        overlayView.setCallback(callback);
+    }
+
+    @Override
+    public void onAddToList() {
+        if (callback() != null) {
+            callback().onLinkPreviewAddToList(pageTitle);
+        }
+    }
+
+    @Override
+    public void onDismiss() {
+        dismiss();
+    }
+
     private void loadContent() {
         PageClientFactory
                 .create(pageTitle.getWikiSite(), pageTitle.namespace())
@@ -205,7 +229,7 @@
                 .enqueue(linkPreviewNetworkOnLoadCallback);
     }
 
-    private void tryLoadingFromCache() {
+    private void tryLoadingFromCache(@Nullable final UnknownHostException 
offlineException) {
         L.v("Loading link preview from Saved Pages");
         new LoadSavedPageTask(pageTitle) {
             @Override public void onFinish(Page page) {
@@ -219,7 +243,11 @@
                 if (!isAdded()) {
                     return;
                 }
-                showPreviewOfflineNotice();
+                if (offlineException != null) {
+                    showError(offlineException);
+                } else {
+                    showError(caught);
+                }
                 L.e("Page summary cache request failed", caught);
             }
         }.execute();
@@ -230,14 +258,13 @@
         setPreviewContents(contents);
     }
 
-    private void showPreviewOfflineNotice() {
+    private void showError(@Nullable Throwable caught) {
         dialogContainer.setLayoutTransition(null);
         progressBar.setVisibility(View.GONE);
         contentContainer.setVisibility(View.GONE);
-        offlineContainer.setVisibility(View.VISIBLE);
-        
overlayView.setPrimaryButtonText(getResources().getString(R.string.button_add_to_reading_list));
         overlayView.showSecondaryButton(false);
-        overlayView.setCallback(new OverlayViewOfflineCallback());
+        errorContainer.setVisibility(View.VISIBLE);
+        errorContainer.setError(this, caught);
     }
 
     private void setPreviewContents(@NonNull LinkPreviewContents contents) {
@@ -258,15 +285,22 @@
             if (summary != null && !summary.hasError()) {
                 showPreview(new LinkPreviewContents(summary, 
pageTitle.getWikiSite()));
             } else {
-                tryLoadingFromCache();
+                tryLoadingFromCache(null);
                 logError(summary.hasError() ? summary.getError() : null,
                         "Page summary network request failed");
             }
         }
 
-        @Override public void onFailure(Call<PageSummary> call, Throwable t) {
-            tryLoadingFromCache();
-            L.e(t);
+        @Override public void onFailure(Call<PageSummary> call, Throwable 
caught) {
+            L.e(caught);
+            if (is404(getContext(), caught)) {
+                // If the page doesn't exist, show an error immediately 
without checking the cache.
+                showError(caught);
+            } else {
+                // If we're offline, check the cache but pass along the 
exception so that we show
+                // the correct error message if the page isn't found in the 
cache.
+                tryLoadingFromCache(isOffline(caught) ? (UnknownHostException) 
caught : null);
+            }
         }
     };
 
@@ -369,19 +403,6 @@
         @Override
         public void onSecondaryClick() {
             goToExternalMapsApp();
-        }
-    }
-
-    private class OverlayViewOfflineCallback implements 
LinkPreviewOverlayView.Callback {
-        @Override
-        public void onPrimaryClick() {
-            if (callback() != null) {
-                callback().onLinkPreviewAddToList(pageTitle);
-            }
-        }
-
-        @Override
-        public void onSecondaryClick() {
         }
     }
 
diff --git 
a/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewErrorView.java 
b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewErrorView.java
new file mode 100644
index 0000000..4d1e02d
--- /dev/null
+++ b/app/src/main/java/org/wikipedia/page/linkpreview/LinkPreviewErrorView.java
@@ -0,0 +1,151 @@
+package org.wikipedia.page.linkpreview;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.res.Resources;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.StringRes;
+import android.support.v4.content.ContextCompat;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.wikipedia.R;
+import org.wikipedia.util.ThrowableUtil;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class LinkPreviewErrorView extends LinearLayout {
+    @BindView(R.id.view_link_preview_error_icon) ImageView icon;
+    @BindView(R.id.view_link_preview_error_text) TextView textView;
+
+    interface Callback {
+        @NonNull Context getContext();
+        void setOverlayButtonText(@NonNull String text);
+        void setOverlayButtonCallback(@NonNull LinkPreviewOverlayView.Callback 
buttonCallback);
+        void onAddToList();
+        void onDismiss();
+    }
+
+    @Nullable private Callback callback;
+
+    public LinkPreviewErrorView(Context context) {
+        this(context, null);
+    }
+
+    public LinkPreviewErrorView(Context context, @Nullable AttributeSet attrs) 
{
+        this(context, attrs, 0);
+    }
+
+    public LinkPreviewErrorView(Context context, @Nullable AttributeSet attrs, 
int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    @TargetApi(21)
+    public LinkPreviewErrorView(Context context, AttributeSet attrs, int 
defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        inflate(context, R.layout.view_link_preview_error, this);
+        ButterKnife.bind(this);
+    }
+
+    public void setError(@NonNull Callback callback, @Nullable Throwable 
caught) {
+        this.callback = callback;
+        Context context = callback.getContext();
+        Resources resources = context.getResources();
+        ErrorType errorType = getErrorType(context, caught);
+        icon.setImageDrawable(ContextCompat.getDrawable(context, 
errorType.icon()));
+        textView.setText(resources.getString(errorType.text()));
+        
callback.setOverlayButtonText(resources.getString(errorType.buttonText()));
+        
callback.setOverlayButtonCallback(getCallbackForAction(errorType.buttonAction()));
+    }
+
+    @NonNull private LinkPreviewOverlayView.Callback 
getCallbackForAction(ButtonAction action) {
+        if (action == ButtonAction.ADD_TO_LIST) {
+            return new ButtonAddToListCallback();
+        }
+        if (action == ButtonAction.DISMISS) {
+            return new ButtonDismissCallback();
+        }
+        throw new IllegalArgumentException();
+    }
+
+    @NonNull private ErrorType getErrorType(@NonNull Context context, 
@Nullable Throwable caught) {
+        if (caught != null && ThrowableUtil.is404(context, caught)) {
+            return ErrorType.PAGE_MISSING;
+        }
+        if (caught != null && ThrowableUtil.isOffline(caught)) {
+            return ErrorType.OFFLINE;
+        }
+        return ErrorType.GENERIC;
+    }
+
+    private enum ErrorType {
+        OFFLINE(R.drawable.ic_portable_wifi_off_black_24px, 
R.string.dialog_link_preview_offline_notice,
+                R.string.button_add_to_reading_list, ButtonAction.ADD_TO_LIST) 
{
+        },
+
+        PAGE_MISSING(R.drawable.ic_error_black_24dp, 
R.string.error_page_does_not_exist,
+                R.string.view_link_preview_error_button_dismiss, 
ButtonAction.DISMISS),
+
+        GENERIC(R.drawable.ic_error_black_24dp, R.string.error_message_generic,
+                R.string.view_link_preview_error_button_dismiss, 
ButtonAction.DISMISS);
+
+        @DrawableRes private int icon;
+        @StringRes private int text;
+        @StringRes private int buttonText;
+        private ButtonAction buttonAction;
+
+        ErrorType(@DrawableRes int icon, @StringRes int text, @StringRes int 
buttonText, ButtonAction buttonAction) {
+            this.icon = icon;
+            this.text = text;
+            this.buttonText = buttonText;
+            this.buttonAction = buttonAction;
+        }
+
+        @DrawableRes int icon() {
+            return icon;
+        }
+
+        @StringRes int text() {
+            return text;
+        }
+
+        @StringRes int buttonText() {
+            return buttonText;
+        }
+
+        ButtonAction buttonAction() {
+            return buttonAction;
+        }
+    }
+
+    private class ButtonAddToListCallback implements 
LinkPreviewOverlayView.Callback {
+        @Override public void onPrimaryClick() {
+            if (callback != null) {
+                callback.onAddToList();
+            }
+        }
+
+        @Override public void onSecondaryClick() {
+        }
+    }
+
+    private class ButtonDismissCallback implements 
LinkPreviewOverlayView.Callback {
+        @Override public void onPrimaryClick() {
+            if (callback != null) {
+                callback.onDismiss();
+            }
+        }
+
+        @Override public void onSecondaryClick() {
+        }
+    }
+
+    private enum ButtonAction {
+        ADD_TO_LIST, DISMISS
+    }
+}
diff --git a/app/src/main/java/org/wikipedia/util/ThrowableUtil.java 
b/app/src/main/java/org/wikipedia/util/ThrowableUtil.java
index e8881f7..447bc30 100644
--- a/app/src/main/java/org/wikipedia/util/ThrowableUtil.java
+++ b/app/src/main/java/org/wikipedia/util/ThrowableUtil.java
@@ -11,6 +11,7 @@
 import org.wikipedia.R;
 import org.wikipedia.createaccount.CreateAccountException;
 import org.wikipedia.dataclient.mwapi.MwException;
+import org.wikipedia.dataclient.okhttp.HttpStatusException;
 import org.wikipedia.login.LoginClient;
 
 import java.net.UnknownHostException;
@@ -53,8 +54,10 @@
                                   getApiErrorMessage(context, (ApiException) 
inner));
         } else if (isNetworkError(e)) {
             result = new 
AppError(context.getString(R.string.error_network_error),
-                                  
context.getString(R.string.format_error_server_message,
-                                      inner.getLocalizedMessage()));
+                    context.getString(R.string.format_error_server_message,
+                            inner.getLocalizedMessage()));
+        } else if (e instanceof HttpStatusException) {
+            result = new AppError(e.getMessage(), 
Integer.toString(((HttpStatusException) e).code()));
         } else if (inner instanceof LoginClient.LoginFailedException
                 || inner instanceof CreateAccountException
                 || inner instanceof MwException) {
@@ -78,6 +81,10 @@
         return e.getDetail() != null && e.getDetail().contains("404");
     }
 
+    public static boolean isOffline(@NonNull Throwable caught) {
+        return caught instanceof UnknownHostException;
+    }
+
     private static boolean isNetworkError(@NonNull Throwable e) {
         return ThrowableUtil.throwableContainsException(e, 
HttpRequest.HttpRequestException.class)
                 || ThrowableUtil.throwableContainsException(e, 
UnknownHostException.class)
diff --git a/app/src/main/res/drawable/ic_portable_wifi_off_black_24px.xml 
b/app/src/main/res/drawable/ic_portable_wifi_off_black_24px.xml
new file mode 100644
index 0000000..98b6999
--- /dev/null
+++ b/app/src/main/res/drawable/ic_portable_wifi_off_black_24px.xml
@@ -0,0 +1,5 @@
+<vector android:autoMirrored="true" android:height="24dp"
+    android:viewportHeight="24.0" android:viewportWidth="24.0"
+    android:width="24dp" 
xmlns:android="http://schemas.android.com/apk/res/android";>
+    <path android:fillColor="#000000" 
android:pathData="M17.56,14.24c0.28,-0.69 0.44,-1.45 0.44,-2.24 0,-3.31 
-2.69,-6 -6,-6 -0.79,0 -1.55,0.16 -2.24,0.44l1.62,1.62c0.2,-0.03 0.41,-0.06 
0.62,-0.06 2.21,0 4,1.79 4,4 0,0.21 -0.02,0.42 
-0.05,0.63l1.61,1.61zM12,4c4.42,0 8,3.58 8,8 0,1.35 -0.35,2.62 
-0.95,3.74l1.47,1.47C21.46,15.69 22,13.91 22,12c0,-5.52 -4.48,-10 -10,-10 
-1.91,0 -3.69,0.55 -5.21,1.47l1.46,1.46C9.37,4.34 10.65,4 
12,4zM3.27,2.5L2,3.77l2.1,2.1C2.79,7.57 2,9.69 2,12c0,3.7 2.01,6.92 
4.99,8.65l1,-1.73C5.61,17.53 4,14.96 4,12c0,-1.76 0.57,-3.38 
1.53,-4.69l1.43,1.44C6.36,9.68 6,10.8 6,12c0,2.22 1.21,4.15 
3,5.19l1,-1.74c-1.19,-0.7 -2,-1.97 -2,-3.45 0,-0.65 0.17,-1.25 
0.44,-1.79l1.58,1.58L10,12c0,1.1 0.9,2 2,2l0.21,-0.02 0.01,0.01 
7.51,7.51L21,20.23 4.27,3.5l-1,-1z"/>
+</vector>
diff --git a/app/src/main/res/layout/dialog_link_preview.xml 
b/app/src/main/res/layout/dialog_link_preview.xml
index 17863f4..9c6cc46 100755
--- a/app/src/main/res/layout/dialog_link_preview.xml
+++ b/app/src/main/res/layout/dialog_link_preview.xml
@@ -94,31 +94,13 @@
                 android:layout_gravity="center_horizontal" />
         </LinearLayout>
 
-        <LinearLayout
-            android:id="@+id/dialog_link_preview_offline_container"
+        <org.wikipedia.page.linkpreview.LinkPreviewErrorView
+            android:id="@+id/dialog_link_preview_error_container"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:orientation="vertical"
             android:visibility="gone">
-            <ImageView
-                android:layout_width="72dp"
-                android:layout_height="72dp"
-                android:layout_margin="24dp"
-                android:layout_gravity="center_horizontal"
-                app:srcCompat="@drawable/ic_no_article"
-                android:tint="?attr/link_preview_offline_text_color"
-                android:contentDescription="@null"/>
-            <TextView
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginLeft="42dp"
-                android:layout_marginRight="42dp"
-                android:textSize="18sp"
-                android:textColor="?attr/link_preview_offline_text_color"
-                android:textAlignment="center"
-                android:lineSpacingMultiplier="1.2"
-                android:text="@string/dialog_link_preview_offline_notice"/>
-        </LinearLayout>
+
+        </org.wikipedia.page.linkpreview.LinkPreviewErrorView>
 
         <!-- Bottom padding for overlay button -->
         <View
diff --git a/app/src/main/res/layout/view_link_preview_error.xml 
b/app/src/main/res/layout/view_link_preview_error.xml
new file mode 100644
index 0000000..3fe5310
--- /dev/null
+++ b/app/src/main/res/layout/view_link_preview_error.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android";
+    xmlns:app="http://schemas.android.com/apk/res-auto";
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+    <ImageView
+        android:id="@+id/view_link_preview_error_icon"
+        android:layout_width="72dp"
+        android:layout_height="72dp"
+        android:layout_margin="24dp"
+        android:layout_gravity="center_horizontal"
+        app:srcCompat="@drawable/ic_error_black_24dp"
+        android:tint="?attr/link_preview_offline_text_color"
+        android:contentDescription="@null"/>
+    <TextView
+        android:id="@+id/view_link_preview_error_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="42dp"
+        android:layout_marginRight="42dp"
+        android:textSize="18sp"
+        android:textColor="?attr/link_preview_offline_text_color"
+        android:textAlignment="center"
+        android:lineSpacingMultiplier="1.2"
+        android:text="@string/error_message_generic"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/app/src/main/res/values-qq/strings.xml 
b/app/src/main/res/values-qq/strings.xml
index db76529..da9ffe8 100644
--- a/app/src/main/res/values-qq/strings.xml
+++ b/app/src/main/res/values-qq/strings.xml
@@ -369,6 +369,7 @@
   <string name="location_permissions_enable_action">Button label for 
requesting to turn on location permissions.</string>
   <string name="error_webview_updating">Error informing the user that the 
System WebView is being updated, meaning that the app cannot be launched right 
now, and that the user should try again in a moment.</string>
   <string name="multi_select_items_selected">Toolbar title shown when the user 
is selecting multiple items in a list. The \"%d\" symbol is replaced with the 
number of items currently selected.</string>
+  <string name="error_message_generic">Generic message informing the user that 
an error occurred</string>
   <string name="crash_report_dialog_title">Title of the dialog that pops up 
when the app crashes, asking user to send a report</string>
   <string name="crash_report_dialog_text">Text asking the user to send us a 
crash report</string>
   <string name="crash_report_dialog_dont_send_button">In the dialog that pops 
up when the app crashes, text for button that doesn\'t send a crash report.
diff --git a/app/src/main/res/values/strings.xml 
b/app/src/main/res/values/strings.xml
index 7dba702..0a1386f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -255,6 +255,9 @@
     <string name="location_permissions_enable_action">Turn on</string>
     <string name="error_webview_updating">The Android System WebView is 
currently being updated. Please try again in a moment.</string>
     <string name="multi_select_items_selected">%d selected</string>
+    <string name="error_message_generic">An error occurred</string>
+    <string name="view_link_preview_error_button_dismiss">Dismiss</string>
+    <string name="error_page_does_not_exist">This page does not exist</string>
 
     <!-- Crash reporter -->
     <string name="crash_report_dialog_title">Sorry, app crashed last 
time</string>

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3b95431abb9305b191250ff527272d1869208c54
Gerrit-PatchSet: 1
Gerrit-Project: apps/android/wikipedia
Gerrit-Branch: master
Gerrit-Owner: Mholloway <mhollo...@wikimedia.org>

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

Reply via email to