Commit 1073af05 authored by David Trainor's avatar David Trainor Committed by Commit Bot

Download Home - Build new prefetch view

This is the initial implementation of a prefetch view item for the new
download home UI.  This change includes the following:
- Builds out the ViewHolder that can handle thumbnails (automatically
processes it and pushes it to the view).
- Builds out the ViewHolder that can handle a 3-dot menu (automatically
handles the callback information).
- Adds the initial XML for the prefetched item.

BUG=849584

Change-Id: I965df4b6bdffc73f084f2f18c15588488b4beb0f
Reviewed-on: https://chromium-review.googlesource.com/1087319
Commit-Queue: David Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarMin Qin <qinmin@chromium.org>
Reviewed-by: default avatarShakti Sahu <shaktisahu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#565079}
parent 717c1c29
...@@ -110,6 +110,7 @@ android_resources("chrome_java_resources") { ...@@ -110,6 +110,7 @@ android_resources("chrome_java_resources") {
"//third_party/android_media:android_media_resources", "//third_party/android_media:android_media_resources",
"//third_party/android_tools:android_support_design_java", "//third_party/android_tools:android_support_design_java",
"//third_party/android_tools:android_support_v7_appcompat_java", "//third_party/android_tools:android_support_v7_appcompat_java",
"//third_party/android_tools:android_support_v7_gridlayout_java",
"//third_party/android_tools:android_support_v7_recyclerview_java", "//third_party/android_tools:android_support_v7_recyclerview_java",
] ]
custom_package = "org.chromium.chrome" custom_package = "org.chromium.chrome"
......
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2018 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<android.support.v7.widget.GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="114dp"
android:clickable="true"
android:background="@android:color/white"
app:columnCount="4"
app:rowCount="4">
<ImageView
android:id="@+id/thumbnail"
android:layout_width="114dp"
android:layout_height="114dp"
android:layout_marginEnd="9dp"
android:scaleType="fitCenter"
android:background="@color/google_grey_100"
app:layout_column="0"
app:layout_row="0"
app:layout_rowSpan="4"
tools:ignore="ContentDescription" />
<Space
android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_gravity="fill"
app:layout_column="0"
app:layout_row="3"
app:layout_columnSpan="4" />
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:minHeight="40dp"
android:maxLines="2"
android:ellipsize="end"
android:textAppearance="@style/BlackBodyDefault"
android:textAlignment="viewStart"
app:layout_column="1"
app:layout_row="0"
app:layout_columnSpan="2"
app:layout_gravity="fill_horizontal" />
<TextView
android:id="@+id/caption"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="@style/BlackCaption"
android:textAlignment="viewStart"
app:layout_column="1"
app:layout_row="1"
app:layout_columnSpan="3"
app:layout_gravity="fill_horizontal" />
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="@style/BlackCaption"
android:textAlignment="viewStart"
app:layout_column="1"
app:layout_row="2"
app:layout_gravity="center_vertical" />
<ImageView
android:layout_width="12dp"
android:layout_height="12dp"
android:layout_marginStart="4dp"
android:src="@drawable/offline_pin_round"
android:scaleType="centerInside"
android:tint="@color/black_alpha_65"
app:layout_column="2"
app:layout_row="2"
app:layout_columnSpan="2"
app:layout_gravity="start|center_vertical"
tools:ignore="ContentDescription" />
<include layout="@layout/list_menu_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:paddingTop="12dp"
app:layout_column="3"
app:layout_row="0" />
</android.support.v7.widget.GridLayout>
\ No newline at end of file
...@@ -573,4 +573,8 @@ ...@@ -573,4 +573,8 @@
<!-- Download manager dimensions --> <!-- Download manager dimensions -->
<dimen name="download_manager_image_width">150dp</dimen> <dimen name="download_manager_image_width">150dp</dimen>
<dimen name="download_manager_image_padding">1dp</dimen> <dimen name="download_manager_image_padding">1dp</dimen>
<dimen name="download_manager_generic_thumbnail_size">48dp</dimen>
<dimen name="download_manager_prefetch_thumbnail_size">114dp</dimen>
<dimen name="download_manager_prefetch_horizontal_margin">16dp</dimen>
<dimen name="download_manager_prefetch_vertical_margin">12dp</dimen>
</resources> </resources>
...@@ -73,7 +73,7 @@ public class OfflineContentProviderGlue implements OfflineContentProvider.Observ ...@@ -73,7 +73,7 @@ public class OfflineContentProviderGlue implements OfflineContentProvider.Observ
if (LegacyHelpers.isLegacyDownload(item.id)) { if (LegacyHelpers.isLegacyDownload(item.id)) {
mDownloadProvider.removeItem(item); mDownloadProvider.removeItem(item);
} else { } else {
mProvider.openItem(item.id); mProvider.removeItem(item.id);
} }
} }
......
...@@ -27,6 +27,8 @@ class DateOrderedListView { ...@@ -27,6 +27,8 @@ class DateOrderedListView {
private final int mImageWidthPx; private final int mImageWidthPx;
private final int mImagePaddingPx; private final int mImagePaddingPx;
private final int mPrefetchVerticalPaddingPx;
private final int mPrefetchHorizontalPaddingPx;
private final RecyclerView mView; private final RecyclerView mView;
...@@ -38,6 +40,10 @@ class DateOrderedListView { ...@@ -38,6 +40,10 @@ class DateOrderedListView {
context.getResources().getDimensionPixelSize(R.dimen.download_manager_image_width); context.getResources().getDimensionPixelSize(R.dimen.download_manager_image_width);
mImagePaddingPx = context.getResources().getDimensionPixelOffset( mImagePaddingPx = context.getResources().getDimensionPixelOffset(
R.dimen.download_manager_image_padding); R.dimen.download_manager_image_padding);
mPrefetchHorizontalPaddingPx = context.getResources().getDimensionPixelSize(
R.dimen.download_manager_prefetch_horizontal_margin);
mPrefetchVerticalPaddingPx = context.getResources().getDimensionPixelSize(
R.dimen.download_manager_prefetch_vertical_margin);
DateOrderedListViewBinder listViewBinder = new DateOrderedListViewBinder(); DateOrderedListViewBinder listViewBinder = new DateOrderedListViewBinder();
DateOrderedListViewAdapter adapter = new DateOrderedListViewAdapter(mModel, listViewBinder); DateOrderedListViewAdapter adapter = new DateOrderedListViewAdapter(mModel, listViewBinder);
...@@ -107,6 +113,12 @@ class DateOrderedListView { ...@@ -107,6 +113,12 @@ class DateOrderedListView {
outRect.top = mImagePaddingPx; outRect.top = mImagePaddingPx;
outRect.bottom = mImagePaddingPx; outRect.bottom = mImagePaddingPx;
break; break;
case ListUtils.PREFETCH:
outRect.left = mPrefetchHorizontalPaddingPx;
outRect.right = mPrefetchHorizontalPaddingPx;
outRect.top = mPrefetchVerticalPaddingPx / 2;
outRect.bottom = mPrefetchVerticalPaddingPx / 2;
break;
} }
} }
} }
......
...@@ -23,13 +23,15 @@ class DateOrderedListViewBinder implements ViewBinder<DecoratedListItemModel, Li ...@@ -23,13 +23,15 @@ class DateOrderedListViewBinder implements ViewBinder<DecoratedListItemModel, Li
case ListUtils.IN_PROGRESS: case ListUtils.IN_PROGRESS:
return new ListItemViewHolder.InProgressViewHolder(parent); return new ListItemViewHolder.InProgressViewHolder(parent);
case ListUtils.GENERIC: case ListUtils.GENERIC:
return new ListItemViewHolder.GenericViewHolder(parent); return ListItemViewHolder.GenericViewHolder.create(parent);
case ListUtils.VIDEO: case ListUtils.VIDEO:
return new ListItemViewHolder.VideoViewHolder(parent); return new ListItemViewHolder.VideoViewHolder(parent);
case ListUtils.IMAGE: case ListUtils.IMAGE:
return new ListItemViewHolder.ImageViewHolder(parent); return new ListItemViewHolder.ImageViewHolder(parent);
case ListUtils.CUSTOM_VIEW: case ListUtils.CUSTOM_VIEW:
return new ListItemViewHolder.CustomViewHolder(parent); return new ListItemViewHolder.CustomViewHolder(parent);
case ListUtils.PREFETCH:
return ListItemViewHolder.PrefetchViewHolder.create(parent);
} }
assert false; assert false;
......
...@@ -4,21 +4,24 @@ ...@@ -4,21 +4,24 @@
package org.chromium.chrome.browser.download.home.list; package org.chromium.chrome.browser.download.home.list;
import android.graphics.drawable.BitmapDrawable; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.support.annotation.CallSuper; import android.support.annotation.CallSuper;
import android.support.v7.widget.AppCompatTextView; import android.support.v7.widget.AppCompatTextView;
import android.support.v7.widget.RecyclerView.ViewHolder; import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams; import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.chromium.base.ApiCompatibilityUtils; import org.chromium.chrome.R;
import org.chromium.chrome.browser.download.home.list.ListItem.DateListItem; import org.chromium.chrome.browser.download.home.list.ListItem.DateListItem;
import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem; import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem;
import org.chromium.chrome.browser.download.home.list.ListItem.ViewListItem; import org.chromium.chrome.browser.download.home.list.ListItem.ViewListItem;
import org.chromium.chrome.browser.widget.ListMenuButton;
import org.chromium.chrome.browser.widget.ListMenuButton.Item;
import org.chromium.components.offline_items_collection.ContentId; import org.chromium.components.offline_items_collection.ContentId;
import org.chromium.components.offline_items_collection.OfflineItemVisuals; import org.chromium.components.offline_items_collection.OfflineItemVisuals;
import org.chromium.components.offline_items_collection.VisualsCallback; import org.chromium.components.offline_items_collection.VisualsCallback;
...@@ -93,8 +96,15 @@ abstract class ListItemViewHolder extends ViewHolder { ...@@ -93,8 +96,15 @@ abstract class ListItemViewHolder extends ViewHolder {
/** A {@link ViewHolder} specifically meant to display a generic {@code OfflineItem}. */ /** A {@link ViewHolder} specifically meant to display a generic {@code OfflineItem}. */
public static class GenericViewHolder extends ThumbnailAwareViewHolder { public static class GenericViewHolder extends ThumbnailAwareViewHolder {
public GenericViewHolder(ViewGroup parent) { public static GenericViewHolder create(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext())); View view = new AppCompatTextView(parent.getContext());
int imageSize = parent.getContext().getResources().getDimensionPixelSize(
R.dimen.download_manager_generic_thumbnail_size);
return new GenericViewHolder(view, imageSize);
}
private GenericViewHolder(View view, int thumbnailSizePx) {
super(view, thumbnailSizePx, thumbnailSizePx);
} }
// ListItemViewHolder implementation. // ListItemViewHolder implementation.
...@@ -104,17 +114,6 @@ abstract class ListItemViewHolder extends ViewHolder { ...@@ -104,17 +114,6 @@ abstract class ListItemViewHolder extends ViewHolder {
OfflineItemListItem offlineItem = (OfflineItemListItem) item; OfflineItemListItem offlineItem = (OfflineItemListItem) item;
((TextView) itemView).setText(offlineItem.item.title); ((TextView) itemView).setText(offlineItem.item.title);
} }
@Override
void onVisualsChanged(OfflineItemVisuals visuals) {
Drawable drawable = null;
if (visuals != null && visuals.icon != null) {
drawable = new BitmapDrawable(itemView.getResources(), visuals.icon);
}
ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds(
(TextView) itemView, drawable, null, null, null);
}
} }
/** A {@link ViewHolder} specifically meant to display a video {@code OfflineItem}. */ /** A {@link ViewHolder} specifically meant to display a video {@code OfflineItem}. */
...@@ -132,51 +131,131 @@ abstract class ListItemViewHolder extends ViewHolder { ...@@ -132,51 +131,131 @@ abstract class ListItemViewHolder extends ViewHolder {
} }
/** A {@link ViewHolder} specifically meant to display an image {@code OfflineItem}. */ /** A {@link ViewHolder} specifically meant to display an image {@code OfflineItem}. */
public static class ImageViewHolder extends ThumbnailAwareViewHolder { public static class ImageViewHolder extends ListItemViewHolder {
public ImageViewHolder(ViewGroup parent) { public ImageViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext())); super(new AppCompatTextView(parent.getContext()));
} }
// ListItemViewHolder implementation.
@Override
public void bind(ListPropertyModel properties, ListItem item) {
OfflineItemListItem offlineItem = (OfflineItemListItem) item;
((TextView) itemView).setText(offlineItem.item.title);
}
}
/** A {@link ViewHolder} specifically meant to display a prefetch item. */
public static class PrefetchViewHolder extends ThumbnailAwareViewHolder {
private final TextView mTitle;
private final TextView mCaption;
private final TextView mTimestamp;
/** Creates a new instance of a {@link PrefetchViewHolder}. */
public static PrefetchViewHolder create(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.download_manager_prefetch_item, null);
int imageSize = parent.getContext().getResources().getDimensionPixelSize(
R.dimen.download_manager_prefetch_thumbnail_size);
return new PrefetchViewHolder(view, imageSize);
}
private PrefetchViewHolder(View view, int thumbnailSizePx) {
super(view, thumbnailSizePx, thumbnailSizePx);
mTitle = (TextView) itemView.findViewById(R.id.title);
mCaption = (TextView) itemView.findViewById(R.id.caption);
mTimestamp = (TextView) itemView.findViewById(R.id.timestamp);
}
// ThumbnailAwareViewHolder implementation. // ThumbnailAwareViewHolder implementation.
@Override @Override
public void bind(ListPropertyModel properties, ListItem item) { public void bind(ListPropertyModel properties, ListItem item) {
super.bind(properties, item); super.bind(properties, item);
OfflineItemListItem offlineItem = (OfflineItemListItem) item; OfflineItemListItem offlineItem = (OfflineItemListItem) item;
((TextView) itemView).setText(offlineItem.item.title);
mTitle.setText(offlineItem.item.title);
mCaption.setText(UiUtils.generatePrefetchCaption(offlineItem.item));
mTimestamp.setText(UiUtils.generatePrefetchTimestamp(offlineItem.date));
itemView.setOnClickListener(
v -> properties.getOpenCallback().onResult(offlineItem.item));
}
} }
/** Helper {@link ViewHolder} that handles showing a 3-dot menu with preset actions. */
private static class MoreButtonViewHolder
extends ListItemViewHolder implements ListMenuButton.Delegate {
private final ListMenuButton mMore;
private Runnable mShareCallback;
private Runnable mDeleteCallback;
/** Creates a new instance of a {@link MoreButtonViewHolder}. */
public MoreButtonViewHolder(View view) {
super(view);
mMore = (ListMenuButton) view.findViewById(R.id.more);
if (mMore != null) mMore.setDelegate(this);
}
// ListItemViewHolder implementation.
@CallSuper
@Override
public void bind(ListPropertyModel properties, ListItem item) {
OfflineItemListItem offlineItem = (OfflineItemListItem) item;
mShareCallback = () -> properties.getShareCallback().onResult(offlineItem.item);
mDeleteCallback = () -> properties.getRemoveCallback().onResult(offlineItem.item);
}
// ListMenuButton.Delegate implementation.
@Override @Override
void onVisualsChanged(OfflineItemVisuals visuals) { public Item[] getItems() {
Drawable drawable = null; return new Item[] {new Item(itemView.getContext(), R.string.share, true),
if (visuals != null && visuals.icon != null) { new Item(itemView.getContext(), R.string.delete, true)};
drawable = new BitmapDrawable(itemView.getResources(), visuals.icon);
} }
ApiCompatibilityUtils.setCompoundDrawablesRelativeWithIntrinsicBounds( @Override
(TextView) itemView, drawable, null, null, null); public void onItemSelected(Item item) {
if (item.getTextId() == R.string.share) {
if (mShareCallback != null) mShareCallback.run();
} else if (item.getTextId() == R.string.delete) {
if (mDeleteCallback != null) mDeleteCallback.run();
}
} }
} }
/** Helper {@link ViewHolder} that handles querying for thumbnails if necessary. */ /** Helper {@link ViewHolder} that handles querying for thumbnails if necessary. */
private abstract static class ThumbnailAwareViewHolder private abstract static class ThumbnailAwareViewHolder
extends ListItemViewHolder implements VisualsCallback { extends MoreButtonViewHolder implements VisualsCallback {
private static final int TEST_IMAGE_SIZE_PX = 100; private final int mThumbnailWidthPx;
private final int mThumbnailHeightPx;
private final ImageView mThumbnail;
/** Track whether or not the result of a query came back while we were making it. */ /** Track whether or not the result of a query came back while we were making it. */
private boolean mQueryFinished; private boolean mQueryFinished;
private ContentId mQueryId; private ContentId mQueryId;
private Runnable mQueryCancelRunnable; private Runnable mQueryCancelRunnable;
public ThumbnailAwareViewHolder(View view) { /**
* Creates a new instance of a {@link ThumbnailAwareViewHolder}.
* @param view The root {@link View} for this holder.
* @param thumbnailWidthPx The desired width of the thumbnail that will be retrieved.
* @param thumbnailHeightPx The desired height of the thumbnail that will be retrieved.
*/
public ThumbnailAwareViewHolder(View view, int thumbnailWidthPx, int thumbnailHeightPx) {
super(view); super(view);
}
abstract void onVisualsChanged(OfflineItemVisuals visuals); mThumbnailWidthPx = thumbnailWidthPx;
mThumbnailHeightPx = thumbnailHeightPx;
mThumbnail = (ImageView) view.findViewById(R.id.thumbnail);
}
// ListItemViewHolder implementation. // MoreButtonViewHolder implementation.
@Override @Override
@CallSuper @CallSuper
public void bind(ListPropertyModel properties, ListItem item) { public void bind(ListPropertyModel properties, ListItem item) {
super.bind(properties, item);
OfflineItemListItem offlineItem = (OfflineItemListItem) item; OfflineItemListItem offlineItem = (OfflineItemListItem) item;
if (mThumbnail == null) return;
if (offlineItem.item.id.equals(mQueryId)) return; if (offlineItem.item.id.equals(mQueryId)) return;
if (mQueryId != null) onVisualsChanged(null); if (mQueryId != null) onVisualsChanged(null);
...@@ -185,7 +264,7 @@ abstract class ListItemViewHolder extends ViewHolder { ...@@ -185,7 +264,7 @@ abstract class ListItemViewHolder extends ViewHolder {
mQueryId = offlineItem.item.id; mQueryId = offlineItem.item.id;
mQueryFinished = false; mQueryFinished = false;
mQueryCancelRunnable = properties.getVisualsProvider().getVisuals( mQueryCancelRunnable = properties.getVisualsProvider().getVisuals(
offlineItem.item, TEST_IMAGE_SIZE_PX, TEST_IMAGE_SIZE_PX, this); offlineItem.item, mThumbnailWidthPx, mThumbnailHeightPx, this);
// Handle reentrancy case. // Handle reentrancy case.
if (mQueryFinished) mQueryCancelRunnable = null; if (mQueryFinished) mQueryCancelRunnable = null;
...@@ -199,5 +278,11 @@ abstract class ListItemViewHolder extends ViewHolder { ...@@ -199,5 +278,11 @@ abstract class ListItemViewHolder extends ViewHolder {
mQueryFinished = true; mQueryFinished = true;
onVisualsChanged(visuals); onVisualsChanged(visuals);
} }
private void onVisualsChanged(OfflineItemVisuals visuals) {
Bitmap bitmap = null;
if (visuals != null && visuals.icon != null) bitmap = visuals.icon;
mThumbnail.setImageBitmap(bitmap);
}
} }
} }
\ No newline at end of file
...@@ -19,7 +19,7 @@ import java.lang.annotation.RetentionPolicy; ...@@ -19,7 +19,7 @@ import java.lang.annotation.RetentionPolicy;
class ListUtils { class ListUtils {
/** The potential types of list items that could be displayed. */ /** The potential types of list items that could be displayed. */
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@IntDef({DATE, IN_PROGRESS, GENERIC, VIDEO, IMAGE, CUSTOM_VIEW}) @IntDef({DATE, IN_PROGRESS, GENERIC, VIDEO, IMAGE, CUSTOM_VIEW, PREFETCH})
public @interface ViewType {} public @interface ViewType {}
public static final int DATE = 0; public static final int DATE = 0;
public static final int IN_PROGRESS = 1; public static final int IN_PROGRESS = 1;
...@@ -27,6 +27,7 @@ class ListUtils { ...@@ -27,6 +27,7 @@ class ListUtils {
public static final int VIDEO = 3; public static final int VIDEO = 3;
public static final int IMAGE = 4; public static final int IMAGE = 4;
public static final int CUSTOM_VIEW = 5; public static final int CUSTOM_VIEW = 5;
public static final int PREFETCH = 6;
private ListUtils() {} private ListUtils() {}
...@@ -43,6 +44,7 @@ class ListUtils { ...@@ -43,6 +44,7 @@ class ListUtils {
if (item instanceof OfflineItemListItem) { if (item instanceof OfflineItemListItem) {
OfflineItemListItem offlineItem = (OfflineItemListItem) item; OfflineItemListItem offlineItem = (OfflineItemListItem) item;
if (offlineItem.item.isSuggested) return ListUtils.PREFETCH;
if (offlineItem.item.state == OfflineItemState.IN_PROGRESS) { if (offlineItem.item.state == OfflineItemState.IN_PROGRESS) {
return ListUtils.IN_PROGRESS; return ListUtils.IN_PROGRESS;
} }
......
...@@ -9,11 +9,15 @@ import android.text.format.DateUtils; ...@@ -9,11 +9,15 @@ import android.text.format.DateUtils;
import org.chromium.base.ContextUtils; import org.chromium.base.ContextUtils;
import org.chromium.chrome.R; import org.chromium.chrome.R;
import org.chromium.chrome.browser.download.DownloadUtils;
import org.chromium.chrome.browser.util.MathUtils;
import org.chromium.components.offline_items_collection.OfflineItem; import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.OfflineItemFilter; import org.chromium.components.offline_items_collection.OfflineItemFilter;
import org.chromium.components.url_formatter.UrlFormatter;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.concurrent.TimeUnit;
/** A set of helper utility methods for the UI. */ /** A set of helper utility methods for the UI. */
public final class UiUtils { public final class UiUtils {
...@@ -50,6 +54,45 @@ public final class UiUtils { ...@@ -50,6 +54,45 @@ public final class UiUtils {
return builder; return builder;
} }
/**
* Converts {@code date} to a string meant to be used as a prefetched item timestamp.
* @param date The {@link Date} to convert.
* @return The {@link CharSequence} representing the timestamp.
*/
public static CharSequence generatePrefetchTimestamp(Date date) {
Context context = ContextUtils.getApplicationContext();
Calendar calendar1 = CalendarFactory.get();
Calendar calendar2 = CalendarFactory.get();
calendar1.setTimeInMillis(System.currentTimeMillis());
calendar2.setTime(date);
if (CalendarUtils.isSameDay(calendar1, calendar2)) {
int hours =
(int) MathUtils.clamp(TimeUnit.MILLISECONDS.toHours(calendar1.getTimeInMillis()
- calendar2.getTimeInMillis()),
1, 23);
return context.getResources().getQuantityString(
R.plurals.download_manager_n_hours, hours, hours);
} else {
return DateUtils.formatDateTime(context, date.getTime(), DateUtils.FORMAT_SHOW_YEAR);
}
}
/**
* Generates a caption for a prefetched item.
* @param item The {@link OfflineItem} to generate a caption for.
* @return The {@link CharSequence} representing the caption.
*/
public static CharSequence generatePrefetchCaption(OfflineItem item) {
Context context = ContextUtils.getApplicationContext();
String displaySize = DownloadUtils.getStringForBytes(context, item.totalSizeBytes);
String displayUrl = UrlFormatter.formatUrlForSecurityDisplayOmitScheme(item.pageUrl);
return context.getString(
R.string.download_manager_prefetch_caption, displayUrl, displaySize);
}
/** @return Whether or not {@code item} can show a thumbnail in the UI. */ /** @return Whether or not {@code item} can show a thumbnail in the UI. */
public static boolean canHaveThumbnails(OfflineItem item) { public static boolean canHaveThumbnails(OfflineItem item) {
switch (item.filter) { switch (item.filter) {
......
...@@ -2333,6 +2333,12 @@ To obtain new licenses, connect to the internet and play your downloaded content ...@@ -2333,6 +2333,12 @@ To obtain new licenses, connect to the internet and play your downloaded content
<message name="IDS_DOWNLOAD_MANAGER_PREFETCH_TAB" desc="Tab text for showing downloaded popular content."> <message name="IDS_DOWNLOAD_MANAGER_PREFETCH_TAB" desc="Tab text for showing downloaded popular content.">
Popular Content Popular Content
</message> </message>
<message name="IDS_DOWNLOAD_MANAGER_PREFETCH_CAPTION" desc="Text containing the prefetched article description.">
<ph name="DESCRIPTION">%1$s<ex>www.example.com</ex></ph> - <ph name="FILE_SIZE">%2$s<ex>1.56 MB</ex></ph>
</message>
<message name="IDS_DOWNLOAD_MANAGER_N_HOURS" desc="How many hours ago an item was downloaded (if downloaded on the same day). [ICU Syntax]">
{HOURS, plural, =1 {# hr} other {# hrs}}
</message>
<!-- Browsing History UI --> <!-- Browsing History UI -->
<message name="IDS_HISTORY_MANAGER_EMPTY" desc="Indicates that there are no browsing history items."> <message name="IDS_HISTORY_MANAGER_EMPTY" desc="Indicates that there are no browsing history items.">
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment