Bug 1084062 - Support read/unread state in reading list UI. r=mhaigh

This commit is contained in:
Sebastian Kaspari 2015-08-14 10:17:40 +02:00
parent 9fac369f97
commit 879c49f81a
16 changed files with 121 additions and 3 deletions

View File

@ -415,7 +415,7 @@ public class BrowserContract {
public static final String DEFAULT_SORT_ORDER = CLIENT_LAST_MODIFIED + " DESC";
public static final String[] DEFAULT_PROJECTION = new String[] { _ID, URL, TITLE, EXCERPT, WORD_COUNT };
public static final String[] DEFAULT_PROJECTION = new String[] { _ID, URL, TITLE, EXCERPT, WORD_COUNT, IS_UNREAD };
// Minimum fields required to create a reading list item.
public static final String[] REQUIRED_FIELDS = { ReadingListItems.URL, ReadingListItems.TITLE };

View File

@ -189,6 +189,14 @@ public class LocalReadingListAccessor implements ReadingListAccessor {
cr.update(mReadingListUriWithProfile, values, ReadingListItems._ID + " = " + itemID, null);
}
@Override
public void markAsUnread(ContentResolver cr, long itemID) {
final ContentValues values = new ContentValues();
values.put(ReadingListItems.IS_UNREAD, 1);
cr.update(mReadingListUriWithProfile, values, ReadingListItems._ID + " = " + itemID, null);
}
@Override
public void updateContent(ContentResolver cr, long itemID, String resolvedTitle, String resolvedURL, String excerpt) {
final ContentValues values = new ContentValues();

View File

@ -37,6 +37,7 @@ public interface ReadingListAccessor {
void registerContentObserver(Context context, ContentObserver observer);
void markAsRead(ContentResolver cr, long itemID);
void markAsUnread(ContentResolver cr, long itemID);
void updateContent(ContentResolver cr, long itemID, String resolvedTitle, String resolvedURL, String excerpt);
void deleteItem(ContentResolver cr, long itemID);
}

View File

@ -73,6 +73,10 @@ class StubReadingListAccessor implements ReadingListAccessor {
public void markAsRead(ContentResolver cr, long itemID) {
}
@Override
public void markAsUnread(ContentResolver cr, long itemID) {
}
@Override
public void updateContent(ContentResolver cr, long itemID, String resolvedTitle, String resolvedURL, String excerpt) {
}

View File

@ -25,6 +25,7 @@ public class HomeContextMenuInfo extends AdapterContextMenuInfo {
public int historyId = -1;
public int bookmarkId = -1;
public int readingListItemId = -1;
public boolean isUnread;
public RemoveItemType itemType = null;
// Item type to be handled with "Remove" selection.

View File

@ -155,6 +155,9 @@ public abstract class HomeFragment extends Fragment {
if (!RestrictedProfiles.isAllowed(view.getContext(), Restriction.DISALLOW_PRIVATE_BROWSING)) {
menu.findItem(R.id.home_open_private_tab).setVisible(false);
}
menu.findItem(R.id.mark_read).setVisible(info.isInReadingList() && info.isUnread);
menu.findItem(R.id.mark_unread).setVisible(info.isInReadingList() && !info.isUnread);
}
@Override
@ -253,6 +256,22 @@ public abstract class HomeFragment extends Fragment {
return true;
}
if (itemId == R.id.mark_read) {
GeckoProfile
.get(context)
.getDB()
.getReadingListAccessor()
.markAsRead(context.getContentResolver(), info.id);
}
if (itemId == R.id.mark_unread) {
GeckoProfile
.get(context)
.getDB()
.getReadingListAccessor()
.markAsUnread(context.getContentResolver(), info.id);
}
return false;
}

View File

@ -90,6 +90,8 @@ public class ReadingListPanel extends HomeFragment {
// This item is a TwoLinePageRow, so we allow switch-to-tab.
mUrlOpenListener.onUrlOpen(url, EnumSet.of(OnUrlOpenListener.Flags.ALLOW_SWITCH_TO_TAB));
markAsRead(id);
}
});
@ -100,6 +102,7 @@ public class ReadingListPanel extends HomeFragment {
info.url = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.URL));
info.title = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.TITLE));
info.readingListItemId = cursor.getInt(cursor.getColumnIndexOrThrow(ReadingListItems._ID));
info.isUnread = cursor.getInt(cursor.getColumnIndexOrThrow(ReadingListItems.IS_UNREAD)) == 1;
info.itemType = RemoveItemType.READING_LIST;
return info;
}
@ -107,6 +110,15 @@ public class ReadingListPanel extends HomeFragment {
registerForContextMenu(mList);
}
private void markAsRead(long id) {
final Context context = getActivity();
GeckoProfile.get(context).getDB().getReadingListAccessor().markAsRead(
context.getContentResolver(),
id
);
}
@Override
public void onDestroyView() {
super.onDestroyView();

View File

@ -18,6 +18,7 @@ import android.database.Cursor;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@ -28,6 +29,7 @@ public class ReadingListRow extends LinearLayout {
private final TextView title;
private final TextView excerpt;
private final TextView readTime;
private final ImageView indicator;
// Average reading speed in words per minute.
private static final int AVERAGE_READING_SPEED = 250;
@ -50,6 +52,7 @@ public class ReadingListRow extends LinearLayout {
title = (TextView) findViewById(R.id.title);
excerpt = (TextView) findViewById(R.id.excerpt);
readTime = (TextView) findViewById(R.id.read_time);
indicator = (ImageView) findViewById(R.id.indicator);
}
public void updateFromCursor(Cursor cursor) {
@ -57,13 +60,19 @@ public class ReadingListRow extends LinearLayout {
return;
}
final boolean isUnread = cursor.getInt(cursor.getColumnIndexOrThrow(ReadingListItems.IS_UNREAD)) == 1;
final String url = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.URL));
final String titleText = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.TITLE));
title.setText(TextUtils.isEmpty(titleText) ? StringUtils.stripCommonSubdomains(StringUtils.stripScheme(url)) : titleText);
title.setTextAppearance(getContext(), isUnread ? R.style.Widget_ReadingListRow_Title_Unread : R.style.Widget_ReadingListRow_Title_Read);
final String excerptText = cursor.getString(cursor.getColumnIndexOrThrow(ReadingListItems.EXCERPT));
excerpt.setText(TextUtils.isEmpty(excerptText) ? url : excerptText);
excerpt.setTextAppearance(getContext(), isUnread ? R.style.Widget_ReadingListRow_Title_Unread : R.style.Widget_ReadingListRow_Title_Read);
indicator.setImageResource(isUnread ? R.drawable.reading_list_indicator_unread : R.drawable.reading_list_indicator_read);
/* Disabled until UX issues are fixed (see bug 1110461).
final int lengthIndex = cursor.getColumnIndexOrThrow(ReadingListItems.LENGTH);

View File

@ -391,6 +391,8 @@ size. -->
<!ENTITY contextmenu_top_sites_pin "Pin Site">
<!ENTITY contextmenu_top_sites_unpin "Unpin Site">
<!ENTITY contextmenu_add_search_engine "Add a Search Engine">
<!ENTITY contextmenu_mark_read "Mark as read">
<!ENTITY contextmenu_mark_unread "Mark as unread">
<!-- Localization note (doorhanger_login_no_username): This string is used in the save-login doorhanger
where normally a username would be displayed. In this case, no username was found, and this placeholder

View File

@ -0,0 +1,20 @@
<?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/. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval"
android:useLevel="false">
<stroke
android:width="1dp"
android:color="@color/disabled_grey" />
<solid
android:color="@android:color/white" />
<size
android:width="16dp"
android:height="16dp" />
</shape>

View File

@ -0,0 +1,14 @@
<?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/. -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/fennec_ui_orange"/>
<size
android:width="16dp"
android:height="16dp"/>
</shape>

View File

@ -5,11 +5,16 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<ImageView
android:id="@+id/indicator"
android:layout_width="64dp"
android:layout_height="match_parent"
android:scaleType="center" />
<LinearLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
android:paddingLeft="@dimen/reading_list_row_padding_left"
android:paddingRight="@dimen/reading_list_row_padding_right"
android:orientation="vertical"
android:gravity="center_vertical">

View File

@ -29,6 +29,12 @@
<item android:id="@+id/home_edit_bookmark"
android:title="@string/contextmenu_edit_bookmark"/>
<item android:id="@+id/mark_read"
android:title="@string/contextmenu_mark_read" />
<item android:id="@+id/mark_unread"
android:title="@string/contextmenu_mark_unread" />
<item android:id="@+id/home_remove"
android:title="@string/contextmenu_remove"/>

View File

@ -86,7 +86,6 @@
<!-- Reading list row on about:home -->
<dimen name="reading_list_row_height">128dp</dimen>
<dimen name="reading_list_row_padding_left">15dp</dimen>
<dimen name="reading_list_row_padding_right">10dp</dimen>
<!-- Remote Tabs static view top padding. Less in landscape on phones. -->

View File

@ -137,6 +137,14 @@
<item name="android:ellipsize">end</item>
</style>
<style name="Widget.ReadingListRow.Title.Read" parent="Widget.ReadingListRow.Title">
<item name="android:textColor">@color/disabled_grey</item>
</style>
<style name="Widget.ReadingListRow.Title.Unread" parent="Widget.ReadingListRow.Title">
<item name="android:textColor">@color/text_and_tabs_tray_grey</item>
</style>
<style name="Widget.ReadingListRow.Description">
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
<item name="android:maxLines">3</item>
@ -144,6 +152,14 @@
<item name="android:lineSpacingMultiplier">1.3</item>
</style>
<style name="Widget.ReadingListRow.Description.Read" parent="Widget.ReadingListRow.Description">
<item name="android:textColor">@color/disabled_grey</item>
</style>
<style name="Widget.ReadingListRow.Description.Unread" parent="Widget.ReadingListRow.Description">
<item name="android:textColor">@color/text_and_tabs_tray_grey</item>
</style>
<style name="Widget.ReadingListRow.ReadTime">
<item name="android:textColor">@color/fennec_ui_orange</item>
</style>

View File

@ -360,6 +360,8 @@
<string name="contextmenu_top_sites_pin">&contextmenu_top_sites_pin;</string>
<string name="contextmenu_top_sites_unpin">&contextmenu_top_sites_unpin;</string>
<string name="contextmenu_add_search_engine">&contextmenu_add_search_engine;</string>
<string name="contextmenu_mark_read">&contextmenu_mark_read;</string>
<string name="contextmenu_mark_unread">&contextmenu_mark_unread;</string>
<string name="doorhanger_login_no_username">&doorhanger_login_no_username;</string>
<string name="doorhanger_login_edit_title">&doorhanger_login_edit_title;</string>