Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(44)

Side by Side Diff: chrome/android/java/src/org/chromium/chrome/browser/widget/DateDividedAdapter.java

Issue 2670083002: [Download Home] Displaying offline page bundle per day (Closed)
Patch Set: comments Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.chrome.browser.widget; 5 package org.chromium.chrome.browser.widget;
6 6
7 import android.os.AsyncTask; 7 import android.os.AsyncTask;
8 import android.support.annotation.Nullable;
8 import android.support.v7.widget.RecyclerView; 9 import android.support.v7.widget.RecyclerView;
9 import android.support.v7.widget.RecyclerView.Adapter; 10 import android.support.v7.widget.RecyclerView.Adapter;
10 import android.support.v7.widget.RecyclerView.ViewHolder; 11 import android.support.v7.widget.RecyclerView.ViewHolder;
11 import android.text.format.DateUtils; 12 import android.text.format.DateUtils;
12 import android.util.Pair; 13 import android.util.Pair;
13 import android.view.LayoutInflater; 14 import android.view.LayoutInflater;
14 import android.view.View; 15 import android.view.View;
15 import android.view.ViewGroup; 16 import android.view.ViewGroup;
16 import android.widget.TextView; 17 import android.widget.TextView;
17 18
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 mTextView.setText(builder); 143 mTextView.setText(builder);
143 } 144 }
144 } 145 }
145 146
146 protected static class BasicViewHolder extends RecyclerView.ViewHolder { 147 protected static class BasicViewHolder extends RecyclerView.ViewHolder {
147 public BasicViewHolder(View itemView) { 148 public BasicViewHolder(View itemView) {
148 super(itemView); 149 super(itemView);
149 } 150 }
150 } 151 }
151 152
153 protected static class SubsectionHeaderViewHolder extends RecyclerView.ViewH older {
154 private View mView;
155
156 public SubsectionHeaderViewHolder(View itemView) {
157 super(itemView);
158 mView = itemView;
159 }
160
161 public View getView() {
162 return mView;
163 }
164 }
165
152 /** 166 /**
153 * A bucket of items with the same date. 167 * A bucket of items with the same date.
154 */ 168 */
155 protected static class ItemGroup { 169 public static class ItemGroup {
156 private final Date mDate; 170 private final Date mDate;
157 private final List<TimedItem> mItems = new ArrayList<>(); 171 private final List<TimedItem> mItems = new ArrayList<>();
158 172
159 /** Index of the header, relative to the full list. Must be set only on ce.*/ 173 /** Index of the header, relative to the full list. Must be set only on ce.*/
160 private int mIndex; 174 private int mIndex;
161 175
162 private boolean mIsSorted; 176 private boolean mIsSorted;
163 private boolean mIsListHeader; 177 private boolean mIsListHeader;
164 private boolean mIsListFooter; 178 private boolean mIsListFooter;
165 179
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
220 if (index == 0 || mIsListHeader || mIsListFooter) return null; 234 if (index == 0 || mIsListHeader || mIsListFooter) return null;
221 235
222 sortIfNeeded(); 236 sortIfNeeded();
223 return mItems.get(index - 1); 237 return mItems.get(index - 1);
224 } 238 }
225 239
226 /** 240 /**
227 * Rather than sorting the list each time a new item is added, the list is sorted when 241 * Rather than sorting the list each time a new item is added, the list is sorted when
228 * something requires a correct ordering of the items. 242 * something requires a correct ordering of the items.
229 */ 243 */
230 private void sortIfNeeded() { 244 protected void sortIfNeeded() {
231 if (mIsSorted) return; 245 if (mIsSorted) return;
232 mIsSorted = true; 246 mIsSorted = true;
233 247
234 Collections.sort(mItems, new Comparator<TimedItem>() { 248 Collections.sort(mItems, new Comparator<TimedItem>() {
235 @Override 249 @Override
236 public int compare(TimedItem lhs, TimedItem rhs) { 250 public int compare(TimedItem lhs, TimedItem rhs) {
237 // More recent items are listed first. Ideally we'd use Lon g.compare, but that 251 return compareItem(lhs, rhs);
238 // is an API level 19 call for some inexplicable reason.
239 long timeDelta = lhs.getTimestamp() - rhs.getTimestamp();
240 if (timeDelta > 0) {
241 return -1;
242 } else if (timeDelta == 0) {
243 return 0;
244 } else {
245 return 1;
246 }
247 } 252 }
248 }); 253 });
249 } 254 }
255
256 protected int compareItem(TimedItem lhs, TimedItem rhs) {
257 // More recent items are listed first. Ideally we'd use Long.compar e, but that
258 // is an API level 19 call for some inexplicable reason.
259 long timeDelta = lhs.getTimestamp() - rhs.getTimestamp();
260 if (timeDelta > 0) {
261 return -1;
262 } else if (timeDelta == 0) {
263 return 0;
264 } else {
265 return 1;
266 }
267 }
250 } 268 }
251 269
252 // Cached async tasks to get the two Calendar objects, which are used when c omparing dates. 270 // Cached async tasks to get the two Calendar objects, which are used when c omparing dates.
253 private static final AsyncTask<Void, Void, Calendar> sCal1 = createCalendar( ); 271 private static final AsyncTask<Void, Void, Calendar> sCal1 = createCalendar( );
254 private static final AsyncTask<Void, Void, Calendar> sCal2 = createCalendar( ); 272 private static final AsyncTask<Void, Void, Calendar> sCal2 = createCalendar( );
255 273
256 public static final int TYPE_FOOTER = -2; 274 public static final int TYPE_FOOTER = -2;
257 public static final int TYPE_HEADER = -1; 275 public static final int TYPE_HEADER = -1;
258 public static final int TYPE_DATE = 0; 276 public static final int TYPE_DATE = 0;
259 public static final int TYPE_NORMAL = 1; 277 public static final int TYPE_NORMAL = 1;
278 public static final int TYPE_SUBSECTION_HEADER = 2;
260 279
261 private int mSize; 280 private int mSize;
262 private boolean mHasListHeader; 281 private boolean mHasListHeader;
263 private boolean mHasListFooter; 282 private boolean mHasListFooter;
264 283
265 private SortedSet<ItemGroup> mGroups = new TreeSet<>(new Comparator<ItemGrou p>() { 284 private SortedSet<ItemGroup> mGroups = new TreeSet<>(new Comparator<ItemGrou p>() {
266 @Override 285 @Override
267 public int compare(ItemGroup lhs, ItemGroup rhs) { 286 public int compare(ItemGroup lhs, ItemGroup rhs) {
268 if (lhs == rhs) return 0; 287 if (lhs == rhs) return 0;
269 288
270 // There should only be at most one list header and one list footer in the SortedSet. 289 // There should only be at most one list header and one list footer in the SortedSet.
271 if (lhs.mIsListHeader || rhs.mIsListFooter) return -1; 290 if (lhs.mIsListHeader || rhs.mIsListFooter) return -1;
272 if (lhs.mIsListFooter || rhs.mIsListHeader) return 1; 291 if (lhs.mIsListFooter || rhs.mIsListHeader) return 1;
273 292
274 return compareDate(lhs.mDate, rhs.mDate); 293 return compareDate(lhs.mDate, rhs.mDate);
275 } 294 }
276 }); 295 });
277 296
278 /** 297 /**
279 * Creates a {@link ViewHolder} in the given view parent. 298 * Creates a {@link ViewHolder} in the given view parent.
280 * @see #onCreateViewHolder(ViewGroup, int) 299 * @see #onCreateViewHolder(ViewGroup, int)
281 */ 300 */
282 protected abstract ViewHolder createViewHolder(ViewGroup parent); 301 protected abstract ViewHolder createViewHolder(ViewGroup parent);
283 302
284 /** 303 /**
285 * Creates a {@link BasicViewHolder} in the given view parent for the header . 304 * Creates a {@link BasicViewHolder} in the given view parent for the header .
286 * @see #onCreateViewHolder(ViewGroup, int) 305 * @see #onCreateViewHolder(ViewGroup, int)
287 */ 306 */
307 @Nullable
288 protected BasicViewHolder createHeader(ViewGroup parent) { 308 protected BasicViewHolder createHeader(ViewGroup parent) {
289 return null; 309 return null;
290 } 310 }
291 311
292 /** 312 /**
293 * Creates a {@link BasicViewHolder} in the given view parent for the footer . 313 * Creates a {@link BasicViewHolder} in the given view parent for the footer .
294 * See {@link #onCreateViewHolder(ViewGroup, int)}. 314 * See {@link #onCreateViewHolder(ViewGroup, int)}.
295 */ 315 */
316 @Nullable
296 protected BasicViewHolder createFooter(ViewGroup parent) { 317 protected BasicViewHolder createFooter(ViewGroup parent) {
297 return null; 318 return null;
298 } 319 }
299 320
300 /** 321 /**
301 * Creates a {@link DateViewHolder} in the given view parent. 322 * Creates a {@link DateViewHolder} in the given view parent.
302 * @see #onCreateViewHolder(ViewGroup, int) 323 * @see #onCreateViewHolder(ViewGroup, int)
303 */ 324 */
304 protected DateViewHolder createDateViewHolder(ViewGroup parent) { 325 protected DateViewHolder createDateViewHolder(ViewGroup parent) {
305 return new DateViewHolder(LayoutInflater.from(parent.getContext()).infla te( 326 return new DateViewHolder(LayoutInflater.from(parent.getContext()).infla te(
306 getTimedItemViewResId(), parent, false)); 327 getTimedItemViewResId(), parent, false));
307 } 328 }
308 329
309 /** 330 /**
331 * Creates a {@link ViewHolder} for a subsection in the given view parent.
332 * @see #onCreateViewHolder(ViewGroup, int)
333 */
334 @Nullable
335 protected SubsectionHeaderViewHolder createSubsectionHeader(ViewGroup parent ) {
336 return null;
337 }
338
339 /**
340 * Helper function to determine whether an item is a subsection header.
341 * @param timedItem The item
Theresa 2017/02/17 23:56:35 nit: add a period at the end of this line
shaktisahu 2017/02/18 00:39:46 Done.
342 * @return Whether the item is a subsection header.
343 */
344 protected boolean isSubsectionHeader(TimedItem timedItem) {
345 return false;
346 }
347
348 /**
310 * Binds the {@link ViewHolder} with the given {@link TimedItem}. 349 * Binds the {@link ViewHolder} with the given {@link TimedItem}.
311 * @see #onBindViewHolder(ViewHolder, int) 350 * @see #onBindViewHolder(ViewHolder, int)
312 */ 351 */
313 protected abstract void bindViewHolderForTimedItem(ViewHolder viewHolder, Ti medItem item); 352 protected abstract void bindViewHolderForTimedItem(ViewHolder viewHolder, Ti medItem item);
314 353
315 /** 354 /**
355 * Binds the {@link SubsectionHeaderViewHolder} with the given {@link TimedI tem}.
356 * @see #onBindViewHolder(ViewHolder, int)
357 */
358 protected void bindViewHolderForSubsectionHeader(
359 SubsectionHeaderViewHolder holder, TimedItem timedItem) {}
360
361 /**
316 * Gets the resource id of the view showing the date header. 362 * Gets the resource id of the view showing the date header.
317 * Contract for subclasses: this view should be a {@link TextView}. 363 * Contract for subclasses: this view should be a {@link TextView}.
318 */ 364 */
319 protected abstract int getTimedItemViewResId(); 365 protected abstract int getTimedItemViewResId();
320 366
321 /** 367 /**
322 * Loads a list of {@link TimedItem}s to this adapter. Previous data will no t be removed. Call 368 * Loads a list of {@link TimedItem}s to this adapter. Previous data will no t be removed. Call
323 * {@link #clear(boolean)} to remove previous items. 369 * {@link #clear(boolean)} to remove previous items.
324 */ 370 */
325 public void loadItems(List<? extends TimedItem> timedItems) { 371 public void loadItems(List<? extends TimedItem> timedItems) {
326 for (TimedItem timedItem : timedItems) { 372 for (TimedItem timedItem : timedItems) {
327 Date date = new Date(timedItem.getTimestamp()); 373 Date date = new Date(timedItem.getTimestamp());
328 boolean found = false; 374 boolean found = false;
329 for (ItemGroup group : mGroups) { 375 for (ItemGroup group : mGroups) {
330 if (group.isSameDay(date)) { 376 if (group.isSameDay(date)) {
331 found = true; 377 found = true;
332 group.addItem(timedItem); 378 group.addItem(timedItem);
333 mSize++; 379 mSize++;
334 break; 380 break;
335 } 381 }
336 } 382 }
337 if (!found) { 383 if (!found) {
338 // Create a new ItemGroup with the date for the new item. This i ncreases the 384 // Create a new ItemGroup with the date for the new item. This i ncreases the
339 // size by two because we add new views for the date and the ite m itself. 385 // size by two because we add new views for the date and the ite m itself.
340 ItemGroup newGroup = new ItemGroup(timedItem.getTimestamp()); 386 ItemGroup newGroup = createGroup(timedItem.getTimestamp());
341 newGroup.addItem(timedItem); 387 newGroup.addItem(timedItem);
342 mGroups.add(newGroup); 388 mGroups.add(newGroup);
343 mSize += 2; 389 mSize += 2;
344 } 390 }
345 } 391 }
346 392
347 setGroupPositions(); 393 setGroupPositions();
348 notifyDataSetChanged(); 394 notifyDataSetChanged();
349 } 395 }
350 396
351 /** 397 /**
398 * Creates and returns an item group for a given day.
399 * @param timestamp A timestamp from which the date is determined.
400 * @return The item group.
401 */
402 protected ItemGroup createGroup(long timestamp) {
403 return new ItemGroup(timestamp);
404 }
405
406 /**
352 * Tells each group where they start in the list. 407 * Tells each group where they start in the list.
353 */ 408 */
354 private void setGroupPositions() { 409 private void setGroupPositions() {
355 int startIndex = 0; 410 int startIndex = 0;
356 for (ItemGroup group : mGroups) { 411 for (ItemGroup group : mGroups) {
357 group.resetPosition(); 412 group.resetPosition();
358 group.setPosition(startIndex); 413 group.setPosition(startIndex);
359 startIndex += group.size(); 414 startIndex += group.size();
360 } 415 }
361 } 416 }
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
450 */ 505 */
451 public Pair<Date, TimedItem> getItemAt(int position) { 506 public Pair<Date, TimedItem> getItemAt(int position) {
452 Pair<ItemGroup, Integer> pair = getGroupAt(position); 507 Pair<ItemGroup, Integer> pair = getGroupAt(position);
453 ItemGroup group = pair.first; 508 ItemGroup group = pair.first;
454 return new Pair<>(group.mDate, group.getItemAt(pair.second)); 509 return new Pair<>(group.mDate, group.getItemAt(pair.second));
455 } 510 }
456 511
457 @Override 512 @Override
458 public final int getItemViewType(int position) { 513 public final int getItemViewType(int position) {
459 Pair<ItemGroup, Integer> pair = getGroupAt(position); 514 Pair<ItemGroup, Integer> pair = getGroupAt(position);
515 ItemGroup group = pair.first;
460 if (pair.second == TYPE_HEADER) { 516 if (pair.second == TYPE_HEADER) {
461 return TYPE_HEADER; 517 return TYPE_HEADER;
462 } else if (pair.second == TYPE_FOOTER) { 518 } else if (pair.second == TYPE_FOOTER) {
463 return TYPE_FOOTER; 519 return TYPE_FOOTER;
464 } else if (pair.second == 0) { 520 } else if (pair.second == 0) {
465 return TYPE_DATE; 521 return TYPE_DATE;
522 } else if (isSubsectionHeader(group.getItemAt(pair.second))) {
523 return TYPE_SUBSECTION_HEADER;
466 } else { 524 } else {
467 return TYPE_NORMAL; 525 return TYPE_NORMAL;
468 } 526 }
469 } 527 }
470 528
471 @Override 529 @Override
472 public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, in t viewType) { 530 public final RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, in t viewType) {
473 if (viewType == TYPE_DATE) { 531 if (viewType == TYPE_DATE) {
474 return createDateViewHolder(parent); 532 return createDateViewHolder(parent);
475 } else if (viewType == TYPE_NORMAL) { 533 } else if (viewType == TYPE_NORMAL) {
476 return createViewHolder(parent); 534 return createViewHolder(parent);
477 } else if (viewType == TYPE_HEADER) { 535 } else if (viewType == TYPE_HEADER) {
478 return createHeader(parent); 536 return createHeader(parent);
479 } else if (viewType == TYPE_FOOTER) { 537 } else if (viewType == TYPE_FOOTER) {
480 return createFooter(parent); 538 return createFooter(parent);
539 } else if (viewType == TYPE_SUBSECTION_HEADER) {
540 return createSubsectionHeader(parent);
481 } 541 }
482 assert false; 542 assert false;
483 return null; 543 return null;
484 } 544 }
485 545
486 @Override 546 @Override
487 public final void onBindViewHolder(RecyclerView.ViewHolder holder, int posit ion) { 547 public final void onBindViewHolder(RecyclerView.ViewHolder holder, int posit ion) {
488 Pair<Date, TimedItem> pair = getItemAt(position); 548 Pair<Date, TimedItem> pair = getItemAt(position);
489 if (holder instanceof DateViewHolder) { 549 if (holder instanceof DateViewHolder) {
490 ((DateViewHolder) holder).setDate(pair.first); 550 ((DateViewHolder) holder).setDate(pair.first);
551 } else if (holder instanceof SubsectionHeaderViewHolder) {
552 bindViewHolderForSubsectionHeader((SubsectionHeaderViewHolder) holde r, pair.second);
491 } else if (!(holder instanceof BasicViewHolder)) { 553 } else if (!(holder instanceof BasicViewHolder)) {
492 bindViewHolderForTimedItem(holder, pair.second); 554 bindViewHolderForTimedItem(holder, pair.second);
493 } 555 }
494 } 556 }
495 557
496 @Override 558 @Override
497 public final int getItemCount() { 559 public final int getItemCount() {
498 return mSize; 560 return mSize;
499 } 561 }
500 562
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
556 long dayOfYear = calendar.get(Calendar.DAY_OF_YEAR); 618 long dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
557 long year = calendar.get(Calendar.YEAR); 619 long year = calendar.get(Calendar.YEAR);
558 return (year << 16) + dayOfYear; 620 return (year << 16) + dayOfYear;
559 } 621 }
560 622
561 /** 623 /**
562 * Compares two {@link Date}s. Note if you already have two {@link Calendar} objects, use 624 * Compares two {@link Date}s. Note if you already have two {@link Calendar} objects, use
563 * {@link #compareCalendar(Calendar, Calendar)} instead. 625 * {@link #compareCalendar(Calendar, Calendar)} instead.
564 * @return 0 if date1 and date2 are in the same day; 1 if date1 is before da te2; -1 otherwise. 626 * @return 0 if date1 and date2 are in the same day; 1 if date1 is before da te2; -1 otherwise.
565 */ 627 */
566 private static int compareDate(Date date1, Date date2) { 628 protected static int compareDate(Date date1, Date date2) {
567 Pair<Calendar, Calendar> pair = getCachedCalendars(); 629 Pair<Calendar, Calendar> pair = getCachedCalendars();
568 Calendar cal1 = pair.first, cal2 = pair.second; 630 Calendar cal1 = pair.first, cal2 = pair.second;
569 cal1.setTime(date1); 631 cal1.setTime(date1);
570 cal2.setTime(date2); 632 cal2.setTime(date2);
571 return compareCalendar(cal1, cal2); 633 return compareCalendar(cal1, cal2);
572 } 634 }
573 635
574 /** 636 /**
575 * @return 0 if cal1 and cal2 are in the same day; 1 if cal1 happens before cal2; -1 otherwise. 637 * @return 0 if cal1 and cal2 are in the same day; 1 if cal1 happens before cal2; -1 otherwise.
576 */ 638 */
(...skipping 30 matching lines...) Expand all
607 */ 669 */
608 private static AsyncTask<Void, Void, Calendar> createCalendar() { 670 private static AsyncTask<Void, Void, Calendar> createCalendar() {
609 return new AsyncTask<Void, Void, Calendar>() { 671 return new AsyncTask<Void, Void, Calendar>() {
610 @Override 672 @Override
611 protected Calendar doInBackground(Void... unused) { 673 protected Calendar doInBackground(Void... unused) {
612 return Calendar.getInstance(); 674 return Calendar.getInstance();
613 } 675 }
614 }.execute(); 676 }.execute();
615 } 677 }
616 } 678 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698