Commit bfc610d1 authored by David Trainor's avatar David Trainor Committed by Commit Bot

Implement the Download Manager list view

Add the class structure required to support the actual View in the new
download home code layout.  This adds the required adapters, model
change processors, view binders, etc..  Currently they all just inflate
to a TextView, but this is the rough structure the code will be in as
the Views get built out.

BUG=842345

Change-Id: I385ab70a7537254832f57ccb410bb75498a99545
Reviewed-on: https://chromium-review.googlesource.com/1072947
Commit-Queue: David Trainor <dtrainor@chromium.org>
Reviewed-by: default avatarMin Qin <qinmin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#562050}
parent fa655227
......@@ -24,6 +24,11 @@ public class DownloadManagerCoordinatorImpl {
context, OfflineContentAggregatorFactory.forProfile(profile));
}
/** Tears down this coordinator. */
public void destroy() {
mListCoordinator.destroy();
}
/**
* @return The {@link View} representing downloads home.
*/
......
......@@ -47,24 +47,17 @@ public final class CalendarUtils {
sCal1.setTimeInMillis(t1);
sCal2.setTimeInMillis(t2);
return compareCalendarDay(sCal1, sCal2) == 0;
return isSameDay(sCal1, sCal2);
}
/** @return Whether {@code cal1} and {@code cal2} have the same localized calendar day. */
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)
&& cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
}
private static void ensureCalendarsAreAvailable() {
if (sCal1 == null) sCal1 = CalendarFactory.get();
if (sCal2 == null) sCal2 = CalendarFactory.get();
}
private static int compareCalendarDay(Calendar cal1, Calendar cal2) {
boolean sameDay = cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)
&& cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR);
if (sameDay) {
return 0;
} else if (cal1.before(cal2)) {
return 1;
} else {
return -1;
}
}
}
\ No newline at end of file
......@@ -5,7 +5,6 @@
package org.chromium.chrome.browser.download.home.list;
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import org.chromium.chrome.browser.download.home.filter.FilterCoordinator;
......@@ -20,7 +19,7 @@ public class DateOrderedListCoordinator {
private final DateOrderedListModel mModel;
private final DateOrderedListMediator mMediator;
private final RecyclerView mView;
private final DateOrderedListView mView;
/** Creates an instance of a DateOrderedListCoordinator, which will visually represent
* {@code provider} as a list of items.
......@@ -30,15 +29,20 @@ public class DateOrderedListCoordinator {
public DateOrderedListCoordinator(Context context, OfflineContentProvider provider) {
mModel = new DateOrderedListModel();
mMediator = new DateOrderedListMediator(provider, mModel);
mView = new RecyclerView(context);
mView = new DateOrderedListView(context, mModel);
// Hook up the FilterCoordinator with our mediator.
mFilterCoordinator = new FilterCoordinator(context, mMediator.getFilterSource());
mFilterCoordinator.addObserver(filter -> mMediator.onFilterTypeSelected(filter));
}
/** Tears down this coordinator. */
public void destroy() {
mMediator.destroy();
}
/** @return The {@link View} representing downloads home. */
public View getView() {
return mView;
return mView.getView();
}
}
\ No newline at end of file
......@@ -53,6 +53,11 @@ class DateOrderedListMediator {
mListMutator = new DateOrderedListMutator(mSearchFilter, mModel);
}
/** Tears down this mediator. */
public void destroy() {
mSource.destroy();
}
/**
* To be called when this mediator should filter its content based on {@code filter}.
* @see TypeOfflineItemFilter#onFilterSelected(int)
......
......@@ -120,8 +120,17 @@ class DateOrderedListMutator implements OfflineItemFilterObserver {
private int getBestIndexFor(OfflineItem item) {
for (int i = 0; i < mModel.getItemCount(); i++) {
long timeStamp = mModel.getItemAt(i).date.getTime();
if (item.creationTimeMs < timeStamp) return i;
DateOrderedListModel.ListItem listItem = mModel.getItemAt(i);
// We need to compare different things depending on whether or not the ListItem is a
// header. If it is a header we want to compare the day, otherwise we want to compare
// the exact time.
boolean isHeader = listItem.item == null;
long itemTimestamp = isHeader
? CalendarUtils.getStartOfDay(item.creationTimeMs).getTimeInMillis()
: item.creationTimeMs;
if (itemTimestamp > listItem.date.getTime()) return i;
}
return mModel.getItemCount();
......
// 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.
package org.chromium.chrome.browser.download.home.list;
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import org.chromium.chrome.browser.modelutil.RecyclerViewModelChangeProcessor;
/**
* The View component of a DateOrderedList. This takes the DateOrderedListModel and creates the
* glue to display it on the screen.
*/
class DateOrderedListView {
private final DateOrderedListModel mModel;
private final RecyclerView mView;
/** Creates an instance of a {@link DateOrderedListView} representing {@code model}. */
public DateOrderedListView(Context context, DateOrderedListModel model) {
mModel = model;
DateOrderedListViewBinder viewBinder = new DateOrderedListViewBinder();
DateOrderedListViewAdapter adapter = new DateOrderedListViewAdapter(mModel, viewBinder);
RecyclerViewModelChangeProcessor<DateOrderedListModel, ViewHolder> modelChangeProcessor =
new RecyclerViewModelChangeProcessor<>(adapter);
mModel.addObserver(modelChangeProcessor);
mView = new RecyclerView(context);
mView.setHasFixedSize(true);
mView.getItemAnimator().setChangeDuration(0);
mView.setLayoutManager(
new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
mView.setAdapter(adapter);
}
/** @return The Android {@link View} representing this widget. */
public View getView() {
return mView;
}
}
\ No newline at end of file
// 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.
package org.chromium.chrome.browser.download.home.list;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import org.chromium.chrome.browser.download.home.list.DateOrderedListModel.ListItem;
import org.chromium.chrome.browser.download.home.list.DateOrderedListViewBinder.ViewType;
import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter;
import org.chromium.components.offline_items_collection.OfflineItemFilter;
import org.chromium.components.offline_items_collection.OfflineItemState;
/**
* A helper {@link RecyclerView.Adapter} implementation meant to glue a {@link DateOrderedListModel}
* to the right {@link ViewHolder} and {@link ViewBinder}.
*/
class DateOrderedListViewAdapter extends RecyclerViewAdapter<DateOrderedListModel, ViewHolder> {
/** Creates an instance of a {@link DateOrderedListViewAdapter}. */
public DateOrderedListViewAdapter(
DateOrderedListModel model, ViewBinder<DateOrderedListModel, ViewHolder> viewBinder) {
super(model, viewBinder);
setHasStableIds(true);
}
@Override
public long getItemId(int position) {
if (!hasStableIds()) return RecyclerView.NO_ID;
return mModel.getItemAt(position).stableId;
}
@Override
public @ViewType int getItemViewType(int position) {
ListItem item = mModel.getItemAt(position);
if (item.item == null) return DateOrderedListViewBinder.DATE;
if (item.item.state == OfflineItemState.IN_PROGRESS) {
return DateOrderedListViewBinder.IN_PROGRESS;
}
switch (item.item.filter) {
case OfflineItemFilter.FILTER_VIDEO:
return DateOrderedListViewBinder.VIDEO;
case OfflineItemFilter.FILTER_IMAGE:
return DateOrderedListViewBinder.IMAGE;
case OfflineItemFilter.FILTER_ALL:
case OfflineItemFilter.FILTER_PAGE:
case OfflineItemFilter.FILTER_AUDIO:
case OfflineItemFilter.FILTER_OTHER:
case OfflineItemFilter.FILTER_DOCUMENT:
default:
return DateOrderedListViewBinder.GENERIC;
}
}
}
\ No newline at end of file
// 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.
package org.chromium.chrome.browser.download.home.list;
import android.support.annotation.IntDef;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.ViewGroup;
import org.chromium.chrome.browser.modelutil.RecyclerViewAdapter.ViewBinder;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* A {@link ViewBinder} responsible for connecting a {@link DateOrderedListModel} with a underlying
* {@link ViewHolder}.
*/
class DateOrderedListViewBinder implements ViewBinder<DateOrderedListModel, ViewHolder> {
/** The potential types of list items that could be displayed. */
@Retention(RetentionPolicy.SOURCE)
@IntDef({DATE, IN_PROGRESS, GENERIC, VIDEO, IMAGE})
public @interface ViewType {}
public static final int DATE = 0;
public static final int IN_PROGRESS = 1;
public static final int GENERIC = 2;
public static final int VIDEO = 3;
public static final int IMAGE = 4;
// ViewBinder implementation.
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, @ViewType int viewType) {
switch (viewType) {
case DATE:
return new DateOrderedListViewHolder.DateViewHolder(parent);
case IN_PROGRESS:
return new DateOrderedListViewHolder.InProgressViewHolder(parent);
case GENERIC:
return new DateOrderedListViewHolder.GenericViewHolder(parent);
case VIDEO:
return new DateOrderedListViewHolder.VideoViewHolder(parent);
case IMAGE:
return new DateOrderedListViewHolder.ImageViewHolder(parent);
}
assert false;
return null;
}
@Override
public void onBindViewHolder(DateOrderedListModel model, ViewHolder holder, int position) {
if (holder instanceof DateOrderedListViewHolder) {
((DateOrderedListViewHolder) holder).bind(model.getItemAt(position));
}
}
}
\ No newline at end of file
// 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.
package org.chromium.chrome.browser.download.home.list;
import android.support.v7.widget.AppCompatTextView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import org.chromium.chrome.browser.download.home.list.DateOrderedListModel.ListItem;
/**
* A {@link ViewHolder} responsible for building and setting properties on the underlying Android
* {@link View}s for the Download Manager list.
*/
abstract class DateOrderedListViewHolder extends ViewHolder {
/** Creates an instance of a {@link DateOrderedListViewHolder}. */
public DateOrderedListViewHolder(View itemView) {
super(itemView);
}
/**
* Binds the currently held {@link View} to {@code item}.
* @param item The {@link ListItem} to visually represent in this {@link ViewHolder}.
*/
public abstract void bind(ListItem item);
/** A {@link ViewHolder} specifically meant to display a date header. */
public static class DateViewHolder extends DateOrderedListViewHolder {
public DateViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
}
// DateOrderedListViewHolder implementation.
@Override
public void bind(ListItem item) {
((TextView) itemView).setText(UiUtils.dateToHeaderString(item.date));
}
}
/** A {@link ViewHolder} specifically meant to display an in-progress {@code OfflineItem}. */
public static class InProgressViewHolder extends DateOrderedListViewHolder {
public InProgressViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
}
// DateOrderedListViewHolder implementation.
@Override
public void bind(ListItem item) {
((TextView) itemView).setText(item.item.title);
}
}
/** A {@link ViewHolder} specifically meant to display a generic {@code OfflineItem}. */
public static class GenericViewHolder extends DateOrderedListViewHolder {
public GenericViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
}
// DateOrderedListViewHolder implementation.
@Override
public void bind(ListItem item) {
((TextView) itemView).setText(item.item.title);
}
}
/** A {@link ViewHolder} specifically meant to display a video {@code OfflineItem}. */
public static class VideoViewHolder extends DateOrderedListViewHolder {
public VideoViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
}
// DateOrderedListViewHolder implementation.
@Override
public void bind(ListItem item) {
((TextView) itemView).setText(item.item.title);
}
}
/** A {@link ViewHolder} specifically meant to display an image {@code OfflineItem}. */
public static class ImageViewHolder extends DateOrderedListViewHolder {
public ImageViewHolder(ViewGroup parent) {
super(new AppCompatTextView(parent.getContext()));
}
// DateOrderedListViewHolder implementation.
@Override
public void bind(ListItem item) {
((TextView) itemView).setText(item.item.title);
}
}
}
\ No newline at end of file
// 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.
package org.chromium.chrome.browser.download.home.list;
import android.content.Context;
import android.text.format.DateUtils;
import org.chromium.base.ContextUtils;
import org.chromium.chrome.R;
import java.util.Calendar;
import java.util.Date;
/** A set of helper utility methods for the UI. */
public final class UiUtils {
private UiUtils() {}
/**
* Converts {@code date} into a string meant to be used as a list header.
* @param date The {@link Date} to convert.
* @return The {@link CharSequence} representing the header.
*/
public static CharSequence dateToHeaderString(Date date) {
Context context = ContextUtils.getApplicationContext();
Calendar calendar1 = CalendarFactory.get();
Calendar calendar2 = CalendarFactory.get();
calendar1.setTimeInMillis(System.currentTimeMillis());
calendar2.setTime(date);
StringBuilder builder = new StringBuilder();
if (CalendarUtils.isSameDay(calendar1, calendar2)) {
builder.append(context.getString(R.string.today)).append(" - ");
} else {
calendar1.add(Calendar.DATE, -1);
if (CalendarUtils.isSameDay(calendar1, calendar2)) {
builder.append(context.getString(R.string.yesterday)).append(" - ");
}
}
builder.append(DateUtils.formatDateTime(context, date.getTime(),
DateUtils.FORMAT_ABBREV_WEEKDAY | DateUtils.FORMAT_ABBREV_MONTH
| DateUtils.FORMAT_SHOW_YEAR));
return builder;
}
}
\ No newline at end of file
......@@ -10,7 +10,6 @@ import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.text.format.DateUtils;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
......@@ -20,6 +19,7 @@ import android.widget.TextView;
import org.chromium.base.Log;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.download.DownloadUtils;
import org.chromium.chrome.browser.download.home.list.UiUtils;
import org.chromium.chrome.browser.widget.DateDividedAdapter.ItemGroup;
import java.lang.annotation.Retention;
......@@ -178,29 +178,7 @@ public abstract class DateDividedAdapter extends Adapter<RecyclerView.ViewHolder
* @param date The date that this DateViewHolder should display.
*/
public void setDate(Date date) {
// Calender.getInstance() may take long time to run, so Calendar object should be reused
// as much as possible.
Pair<Calendar, Calendar> pair = getCachedCalendars();
Calendar cal1 = pair.first, cal2 = pair.second;
cal1.setTimeInMillis(System.currentTimeMillis());
cal2.setTime(date);
StringBuilder builder = new StringBuilder();
if (compareCalendar(cal1, cal2) == 0) {
builder.append(mTextView.getContext().getString(R.string.today));
builder.append(" - ");
} else {
// Set cal1 to yesterday.
cal1.add(Calendar.DATE, -1);
if (compareCalendar(cal1, cal2) == 0) {
builder.append(mTextView.getContext().getString(R.string.yesterday));
builder.append(" - ");
}
}
builder.append(DateUtils.formatDateTime(mTextView.getContext(), date.getTime(),
DateUtils.FORMAT_ABBREV_WEEKDAY | DateUtils.FORMAT_ABBREV_MONTH
| DateUtils.FORMAT_SHOW_YEAR));
mTextView.setText(builder);
mTextView.setText(UiUtils.dateToHeaderString(date));
}
}
......
......@@ -451,6 +451,11 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java",
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListModel.java",
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMutator.java",
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListView.java",
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListViewAdapter.java",
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListViewBinder.java",
"java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListViewHolder.java",
"java/src/org/chromium/chrome/browser/download/home/list/UiUtils.java",
"java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java",
"java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUi.java",
"java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorNotificationBridgeUiFactory.java",
......
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