Bug 889351 - Show more details in reading list row. r=lucasr
authorMargaret Leibovic <margaret.leibovic@gmail.com>
Mon, 13 Oct 2014 15:09:34 -0400
changeset 210158 f2e6554750681528b0aff8a11af81f71d6aad46b
parent 210157 e23264b514a20c4d241397b36f3730c1258e2c16
child 210159 2939a2996f46e060418b5b98162c9e194ff425a4
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerslucasr
bugs889351
milestone35.0a1
Bug 889351 - Show more details in reading list row. r=lucasr
mobile/android/base/home/ReadingListRow.java
mobile/android/base/locales/en-US/android_strings.dtd
mobile/android/base/resources/layout/reading_list_item_row.xml
mobile/android/base/resources/layout/reading_list_row_view.xml
mobile/android/base/resources/values-v16/styles.xml
mobile/android/base/resources/values/styles.xml
mobile/android/base/strings.xml.in
--- a/mobile/android/base/home/ReadingListRow.java
+++ b/mobile/android/base/home/ReadingListRow.java
@@ -3,40 +3,85 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 package org.mozilla.gecko.home;
 
 import org.mozilla.gecko.R;
 import org.mozilla.gecko.Tab;
 import org.mozilla.gecko.Tabs;
+import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
 import org.mozilla.gecko.home.TwoLinePageRow;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
 import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class ReadingListRow extends LinearLayout {
+
+    private final Resources resources;
 
-public class ReadingListRow extends TwoLinePageRow {
+    private final TextView title;
+    private final TextView excerpt;
+    private final TextView readTime;
+
+    // Average reading speed in words per minute.
+    private static final int AVERAGE_READING_SPEED = 250;
+
+    // Length of average word.
+    private static final float AVERAGE_WORD_LENGTH = 5.1f;
+
 
     public ReadingListRow(Context context) {
         this(context, null);
     }
 
     public ReadingListRow(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        LayoutInflater.from(context).inflate(R.layout.reading_list_row_view, this);
+
+        setOrientation(LinearLayout.VERTICAL);
+
+        resources = context.getResources();
+
+        title = (TextView) findViewById(R.id.title);
+        excerpt = (TextView) findViewById(R.id.excerpt);
+        readTime = (TextView) findViewById(R.id.read_time);
     }
 
-    @Override
-    protected void updateDisplayedUrl() {
-        String pageUrl = getUrl();
+    public void updateFromCursor(Cursor cursor) {
+        if (cursor == null) {
+            return;
+        }
 
-        boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate();
-        Tab tab = Tabs.getInstance().getFirstReaderTabForUrl(pageUrl, isPrivate);
+        final int titleIndex = cursor.getColumnIndexOrThrow(ReadingListItems.TITLE);
+        title.setText(cursor.getString(titleIndex));
 
-        if (tab != null) {
-            setUrl(R.string.switch_to_tab);
-            setSwitchToTabIcon(R.drawable.ic_url_bar_tab);
+        final int excerptIndex = cursor.getColumnIndexOrThrow(ReadingListItems.EXCERPT);
+        excerpt.setText(cursor.getString(excerptIndex));
+
+        final int lengthIndex = cursor.getColumnIndexOrThrow(ReadingListItems.LENGTH);
+        final int minutes = getEstimatedReadTime(cursor.getInt(lengthIndex));
+        if (minutes <= 60) {
+            readTime.setText(resources.getString(R.string.reading_list_time_minutes, minutes));
         } else {
-            setUrl(pageUrl);
-            setSwitchToTabIcon(NO_ICON);
+            readTime.setText(resources.getString(R.string.reading_list_time_over_an_hour));
         }
     }
 
+    /**
+     * Calculates the estimated time to read an article based on its length.
+     *
+     * @param length of the article (in characters)
+     * @return estimated time to read the article (in minutes)
+     */
+    private static int getEstimatedReadTime(int length) {
+        final int minutes = (int) Math.ceil((length / AVERAGE_WORD_LENGTH) / AVERAGE_READING_SPEED);
+
+        // Minimum of one minute.
+        return Math.max(minutes, 1);
+    }
 }
--- a/mobile/android/base/locales/en-US/android_strings.dtd
+++ b/mobile/android/base/locales/en-US/android_strings.dtd
@@ -359,16 +359,22 @@ size. -->
 <!ENTITY site_settings_cancel       "Cancel">
 <!ENTITY site_settings_clear        "Clear">
 <!ENTITY site_settings_no_settings  "There are no settings to clear.">
 
 <!ENTITY reading_list_added "Page added to your Reading List">
 <!ENTITY reading_list_failed "Failed to add page to your Reading List">
 <!ENTITY reading_list_duplicate "Page already in your Reading List">
 
+<!-- Localization note (reading_list_time_minutes) : This string is used in the "Reading List"
+     panel on the home page to give the user an estimate of how many minutes it will take to
+     read an article. The word "minute" should be abbreviated if possible. -->
+<!ENTITY reading_list_time_minutes "&formatD;min">
+<!ENTITY reading_list_time_over_an_hour "Over an hour">
+
 <!-- Localization note : These strings are used as alternate text for accessibility.
      They are not visible in the UI. -->
 <!ENTITY page_action_dropmarker_description "Additional Actions">
 
 <!ENTITY masterpassword_create_title "Create Master Password">
 <!ENTITY masterpassword_remove_title "Remove Master Password">
 <!ENTITY masterpassword_password "Password">
 <!ENTITY masterpassword_confirm "Confirm password">
--- a/mobile/android/base/resources/layout/reading_list_item_row.xml
+++ b/mobile/android/base/resources/layout/reading_list_item_row.xml
@@ -1,10 +1,10 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!-- This Source Code Form is subject to the terms of the Mozilla Public
    - License, v. 2.0. If a copy of the MPL was not distributed with this
    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
 
 <org.mozilla.gecko.home.ReadingListRow xmlns:android="http://schemas.android.com/apk/res/android"
                                        style="@style/Widget.BookmarkItemView"
                                        android:layout_width="match_parent"
-                                       android:layout_height="@dimen/page_row_height"
-                                       android:minHeight="@dimen/page_row_height"/>
+                                       android:layout_height="wrap_content"
+                                       android:padding="10dp"/>
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/resources/layout/reading_list_row_view.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- This Source Code Form is subject to the terms of the Mozilla Public
+   - License, v. 2.0. If a copy of the MPL was not distributed with this
+   - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="horizontal">
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="0dip"
+            android:layout_height="match_parent"
+            android:layout_weight="1"
+            style="@style/Widget.ReadingListRow.Title" />
+
+        <TextView
+            android:id="@+id/read_time"
+            android:layout_width="wrap_content"
+            android:layout_height="match_parent"
+            style="@style/Widget.ReadingListRow.ReadTime" />
+
+    </LinearLayout>
+
+    <TextView
+        android:id="@+id/excerpt"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        style="@style/Widget.ReadingListRow.Description" />
+
+</merge>
--- a/mobile/android/base/resources/values-v16/styles.xml
+++ b/mobile/android/base/resources/values-v16/styles.xml
@@ -12,16 +12,22 @@
     <style name="TextAppearance.Widget.Home.ItemTitle" parent="TextAppearance.Medium">
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
 
     <style name="TextAppearance.Widget.Home.PageTitle" parent="TextAppearance.Medium">
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
 
+    <style name="Widget.ReadingListRow.ReadTime">
+        <item name="android:textStyle">italic</item>
+        <item name="android:textColor">#FF9400</item>
+        <item name="android:fontFamily">sans-serif-condensed</item>
+    </style>
+
     <style name="OnboardStartTextAppearance.Subtext">
         <item name="android:textSize">18sp</item>
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
     <style name="TextAppearance.UrlBar.Title" parent="TextAppearance.Small">
         <item name="android:textSize">15sp</item>
         <item name="android:fontFamily">sans-serif-light</item>
     </style>
--- a/mobile/android/base/resources/values/styles.xml
+++ b/mobile/android/base/resources/values/styles.xml
@@ -122,16 +122,35 @@
 
     <style name="Widget.TwoLinePageRow.Url">
         <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
         <item name="android:includeFontPadding">false</item>
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">middle</item>
     </style>
 
+    <style name="Widget.ReadingListRow" />
+
+    <style name="Widget.ReadingListRow.Title">
+        <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemTitle</item>
+        <item name="android:maxLines">2</item>
+        <item name="android:ellipsize">end</item>
+    </style>
+
+    <style name="Widget.ReadingListRow.Description">
+        <item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
+        <item name="android:maxLines">4</item>
+        <item name="android:ellipsize">end</item>
+    </style>
+
+    <style name="Widget.ReadingListRow.ReadTime">
+        <item name="android:textStyle">italic</item>
+        <item name="android:textColor">@color/text_color_highlight</item>
+    </style>
+
     <style name="Widget.BookmarkFolderView" parent="Widget.TwoLinePageRow.Title">
         <item name="android:singleLine">true</item>
         <item name="android:ellipsize">none</item>
         <item name="android:paddingLeft">10dip</item>
         <item name="android:drawablePadding">10dip</item>
         <item name="android:drawableLeft">@drawable/bookmark_folder</item>
     </style>
 
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -293,16 +293,18 @@
   <string name="site_settings_title">&site_settings_title3;</string>
   <string name="site_settings_cancel">&site_settings_cancel;</string>
   <string name="site_settings_clear">&site_settings_clear;</string>
   <string name="site_settings_no_settings">&site_settings_no_settings;</string>
 
   <string name="reading_list_added">&reading_list_added;</string>
   <string name="reading_list_failed">&reading_list_failed;</string>
   <string name="reading_list_duplicate">&reading_list_duplicate;</string>
+  <string name="reading_list_time_minutes">&reading_list_time_minutes;</string>
+  <string name="reading_list_time_over_an_hour">&reading_list_time_over_an_hour;</string>
 
   <string name="page_action_dropmarker_description">&page_action_dropmarker_description;</string>
 
   <string name="contextmenu_open_new_tab">&contextmenu_open_new_tab;</string>
   <string name="contextmenu_open_private_tab">&contextmenu_open_private_tab;</string>
   <string name="contextmenu_remove">&contextmenu_remove;</string>
   <string name="contextmenu_add_to_launcher">&contextmenu_add_to_launcher;</string>
   <string name="contextmenu_share">&contextmenu_share;</string>