Commit 3f30b24d authored by Shakti Sahu's avatar Shakti Sahu Committed by Commit Bot

Download Home : Implement in-progress list item and spinning progress bar

UX: https://docs.google.com/presentation/d/14pBMf4Qrhd_a4qF6KdXJJfAZYLdmv_JN0gL8GC4SWAU/edit?ts=5b2c34ff#slide=id.g3d18eff084_2_13

Bug: 863717
Change-Id: I682470f7e0eb66d874fbc82b9ccfae19bb1a7090
Reviewed-on: https://chromium-review.googlesource.com/1139022Reviewed-by: default avatarTheresa <twellington@chromium.org>
Reviewed-by: default avatarMin Qin <qinmin@chromium.org>
Commit-Queue: Shakti Sahu <shaktisahu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#575813}
parent a33f42a2
<?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. -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/progress">
<rotate
android:fromDegrees="180"
android:toDegrees="180" >
<shape
android:innerRadius="16dp"
android:thickness="2dp"
android:useLevel="true"
android:shape="ring">
<gradient
android:startColor="@color/modern_grey_800"
android:endColor="@color/modern_grey_800"
android:type="sweep" />
</shape>
</rotate>
</item>
</layer-list>
\ No newline at end of file
<?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. -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:id="@android:id/background">
<shape
android:shape="oval">
<solid android:color="@color/google_grey_300" />
</shape>
</item>
</layer-list>
\ No newline at end of file
......@@ -30,24 +30,16 @@
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
style="@style/DownloadItemText"
android:layout_marginTop="11dp"
android:maxLines="1"
android:ellipsize="end"
android:textAppearance="@style/BlackTitle1"
android:textAlignment="viewStart"
app:layout_column="1"
app:layout_row="0"
app:layout_gravity="fill_horizontal" />
<TextView
android:id="@+id/caption"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:maxLines="1"
android:ellipsize="end"
style="@style/DownloadItemText"
android:textAppearance="@style/BlackHint2"
android:textAlignment="viewStart"
app:layout_column="1"
app:layout_row="1"
app:layout_gravity="fill_horizontal" />
......
<?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="wrap_content"
android:minHeight="64dp"
android:clickable="true"
android:background="@android:color/white"
app:columnCount="3"
app:rowCount="2">
<ImageView
android:layout_width="36dp"
android:layout_height="36dp"
app:layout_gravity="center"
app:layout_column="0"
app:layout_row="0"
app:layout_rowSpan="2"
tools:ignore="ContentDescription"
android:background="@drawable/download_circular_progress_bar_background"
android:layout_centerInParent="true"/>
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
app:layout_gravity="center"
style="?android:attr/progressBarStyleHorizontal"
app:layout_column="0"
app:layout_row="0"
app:layout_rowSpan="2"
android:max="100"
android:progress="0"
android:progressDrawable="@drawable/download_circular_progress_bar"/>
<org.chromium.chrome.browser.widget.TintedImageButton
android:id="@+id/pause_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_gravity="center"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/download_notification_pause_button"
android:src="@drawable/ic_pause_white_24dp"
app:chrometint="@color/google_grey_600"
app:layout_column="0"
app:layout_row="0"
app:layout_rowSpan="2"/>
<TextView
android:id="@+id/title"
style="@style/DownloadItemText"
android:layout_marginTop="11dp"
android:textAppearance="@style/BlackTitle1"
app:layout_column="1"
app:layout_row="0"
app:layout_gravity="fill_horizontal" />
<TextView
android:id="@+id/caption"
style="@style/DownloadItemText"
android:textAppearance="@style/BlackHint2"
app:layout_column="1"
app:layout_row="1"
app:layout_gravity="fill_horizontal" />
<org.chromium.chrome.browser.widget.TintedImageButton
android:id="@+id/cancel_button"
android:layout_width="48dp"
android:layout_height="48dp"
app:layout_column="2"
app:layout_row="0"
app:layout_rowSpan="2"
app:layout_gravity="center_vertical"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/download_notification_cancel_button"
android:src="@drawable/btn_close"
app:chrometint="@color/google_grey_600" />
</android.support.v7.widget.GridLayout>
\ No newline at end of file
......@@ -707,6 +707,15 @@
<item name="android:text">@string/prefetch_badge_new</item>
</style>
<!-- Download Home V2 -->
<style name="DownloadItemText">
<item name="android:layout_width">0dp</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:maxLines">1</item>
<item name="android:ellipsize">end</item>
<item name="android:singleLine">true</item>
</style>
<!-- Data Reduction -->
<style name="DataUsageBreakdownColumnLabel">
<item name="android:layout_height">wrap_content</item>
......
......@@ -18,17 +18,21 @@ import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.download.DownloadUtils;
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.ViewListItem;
import org.chromium.chrome.browser.widget.ListMenuButton;
import org.chromium.chrome.browser.widget.ListMenuButton.Item;
import org.chromium.chrome.browser.widget.TintedImageButton;
import org.chromium.chrome.browser.widget.TintedImageView;
import org.chromium.components.offline_items_collection.ContentId;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.OfflineItemState;
import org.chromium.components.offline_items_collection.OfflineItemVisuals;
import org.chromium.components.offline_items_collection.VisualsCallback;
......@@ -54,7 +58,7 @@ abstract class ListItemViewHolder extends ViewHolder {
case ListUtils.ViewType.DATE:
return DateViewHolder.create(parent);
case ListUtils.ViewType.IN_PROGRESS:
return new InProgressViewHolder(parent);
return InProgressViewHolder.create(parent);
case ListUtils.ViewType.GENERIC:
return GenericViewHolder.create(parent);
case ListUtils.ViewType.VIDEO:
......@@ -126,16 +130,77 @@ abstract class ListItemViewHolder extends ViewHolder {
/** A {@link ViewHolder} specifically meant to display an in-progress {@code OfflineItem}. */
public static class InProgressViewHolder extends ListItemViewHolder {
/** Creates a new {@link InProgressViewHolder} instance. */
public InProgressViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
private final ProgressBar mProgressBar;
private final TextView mTitle;
private final TextView mCaption;
private final TintedImageButton mPauseResumeButton;
private final TintedImageButton mCancelButton;
/**
* Creates a new {@link InProgressViewHolder} instance.
*/
public static InProgressViewHolder create(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.download_manager_in_progress_item, null);
return new InProgressViewHolder(view);
}
/**
* Creates a new {@link InProgressViewHolder} instance.
*/
public InProgressViewHolder(View view) {
super(view);
mProgressBar = view.findViewById(R.id.progress_bar);
mTitle = view.findViewById(R.id.title);
mCaption = view.findViewById(R.id.caption);
mPauseResumeButton = view.findViewById(R.id.pause_button);
mCancelButton = view.findViewById(R.id.cancel_button);
}
// ListItemViewHolder implementation.
@Override
public void bind(ListPropertyModel properties, ListItem item) {
OfflineItemListItem offlineItem = (OfflineItemListItem) item;
((TextView) itemView).setText(offlineItem.item.title);
mTitle.setText(offlineItem.item.title);
mCancelButton.setOnClickListener(
v -> properties.getCancelCallback().onResult(offlineItem.item));
if (offlineItem.item.state == OfflineItemState.PAUSED) {
mPauseResumeButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
mPauseResumeButton.setContentDescription(itemView.getContext().getString(
R.string.download_notification_resume_button));
} else {
mPauseResumeButton.setImageResource(R.drawable.ic_pause_white_24dp);
mPauseResumeButton.setContentDescription(itemView.getContext().getString(
R.string.download_notification_pause_button));
}
// TODO(shaktisahu): Create status string for the new specs.
mCaption.setText(
DownloadUtils.getProgressTextForNotification(offlineItem.item.progress));
mPauseResumeButton.setOnClickListener(view -> {
if (offlineItem.item.state == OfflineItemState.PAUSED) {
properties.getResumeCallback().onResult(offlineItem.item);
} else {
properties.getPauseCallback().onResult(offlineItem.item);
}
});
boolean showIndeterminate = offlineItem.item.progress.isIndeterminate()
&& offlineItem.item.state != OfflineItemState.PAUSED
&& offlineItem.item.state != OfflineItemState.PENDING;
if (showIndeterminate) {
mProgressBar.setIndeterminate(true);
mProgressBar.setIndeterminateDrawable(
itemView.getContext().getResources().getDrawable(
R.drawable.download_circular_progress_bar));
} else {
mProgressBar.setIndeterminate(false);
}
if (!offlineItem.item.progress.isIndeterminate()) {
mProgressBar.setProgress(offlineItem.item.progress.getPercentage());
}
}
}
......@@ -217,7 +282,9 @@ abstract class ListItemViewHolder extends ViewHolder {
}
}
/** A {@link ViewHolder} specifically meant to display a video {@code OfflineItem}. */
/**
* A {@link ViewHolder} specifically meant to display a video {@code OfflineItem}.
*/
public static class VideoViewHolder extends ListItemViewHolder {
public VideoViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
......@@ -263,13 +330,17 @@ abstract class ListItemViewHolder extends ViewHolder {
}
}
/** A {@link ViewHolder} specifically meant to display a prefetch item. */
/**
* 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}. */
/**
* 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);
......@@ -305,7 +376,9 @@ abstract class ListItemViewHolder extends ViewHolder {
}
}
/** Helper {@link ViewHolder} that handles showing a 3-dot menu with preset actions. */
/**
* 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;
......@@ -313,7 +386,9 @@ abstract class ListItemViewHolder extends ViewHolder {
private Runnable mShareCallback;
private Runnable mDeleteCallback;
/** Creates a new instance of a {@link MoreButtonViewHolder}. */
/**
* Creates a new instance of a {@link MoreButtonViewHolder}.
*/
public MoreButtonViewHolder(View view) {
super(view);
mMore = (ListMenuButton) view.findViewById(R.id.more);
......@@ -346,24 +421,36 @@ abstract class ListItemViewHolder extends ViewHolder {
}
}
/** 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
extends MoreButtonViewHolder implements VisualsCallback {
private final ImageView mThumbnail;
/** The {@link ContentId} of the associated thumbnail/request if any. */
/**
* The {@link ContentId} of the associated thumbnail/request if any.
*/
private @Nullable ContentId mId;
/** A {@link Runnable} to cancel an outstanding thumbnail request if any. */
/**
* A {@link Runnable} to cancel an outstanding thumbnail request if any.
*/
private @Nullable Runnable mCancellable;
/** Whether or not a request is outstanding to support synchronous responses. */
/**
* Whether or not a request is outstanding to support synchronous responses.
*/
private boolean mIsRequesting;
/** The ideal width of the queried thumbnail. */
/**
* The ideal width of the queried thumbnail.
*/
private int mWidthPx;
/** The ideal height of the queried thumbnail. */
/**
* The ideal height of the queried thumbnail.
*/
private int mHeightPx;
/**
......@@ -431,4 +518,4 @@ abstract class ListItemViewHolder extends ViewHolder {
*/
abstract void onVisualsChanged(ImageView view, @Nullable OfflineItemVisuals visuals);
}
}
\ No newline at end of file
}
......@@ -47,7 +47,11 @@ class ListUtils {
OfflineItemListItem offlineItem = (OfflineItemListItem) item;
if (offlineItem.item.isSuggested) return ViewType.PREFETCH;
if (offlineItem.item.state == OfflineItemState.IN_PROGRESS) {
if (offlineItem.item.state == OfflineItemState.IN_PROGRESS
|| offlineItem.item.state == OfflineItemState.PAUSED
|| offlineItem.item.state == OfflineItemState.INTERRUPTED
|| offlineItem.item.state == OfflineItemState.PENDING
|| offlineItem.item.state == OfflineItemState.FAILED) {
return ViewType.IN_PROGRESS;
}
......@@ -84,4 +88,4 @@ class ListUtils {
public static int getSpanSize(ListItem item, int spanCount) {
return getViewTypeForItem(item) == ViewType.IMAGE ? 1 : spanCount;
}
}
\ No newline at end of file
}
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