chromium/chrome/browser/download/internal/android/java/src/org/chromium/chrome/browser/download/home/list/mutator/DateLabelAdder.java

// Copyright 2019 The Chromium Authors
// 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.mutator;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.chromium.chrome.browser.download.home.DownloadManagerUiConfig;
import org.chromium.chrome.browser.download.home.JustNowProvider;
import org.chromium.chrome.browser.download.home.list.ListItem;
import org.chromium.chrome.browser.download.home.list.ListItem.OfflineItemListItem;
import org.chromium.chrome.browser.download.home.list.ListItem.SectionHeaderType;
import org.chromium.components.browser_ui.util.date.CalendarUtils;
import org.chromium.components.offline_items_collection.OfflineItem;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Given a list of {@link ListItem}, returns a list that has date headers for each date.
 * Also adds Just Now header for recently completed items. Note that this class must be called on
 * the list before adding any other labels such as card header/footer/pagination etc.
 */
public class DateLabelAdder implements ListConsumer {
    private final DownloadManagerUiConfig mConfig;
    @Nullable private final JustNowProvider mJustNowProvider;
    private ListConsumer mListConsumer;

    public DateLabelAdder(
            DownloadManagerUiConfig config, @Nullable JustNowProvider justNowProvider) {
        mConfig = config;
        mJustNowProvider = justNowProvider;
    }

    @Override
    public ListConsumer setListConsumer(ListConsumer consumer) {
        mListConsumer = consumer;
        return mListConsumer;
    }

    @Override
    public void onListUpdated(List<ListItem> inputList) {
        if (mListConsumer == null) return;
        mListConsumer.onListUpdated(addLabels(inputList));
    }

    private List<ListItem> addLabels(List<ListItem> sortedList) {
        List<ListItem> listWithHeaders = new ArrayList<>();

        // Insert section headers to the list and output the new list with headers.
        OfflineItem previousItem = null;
        for (int i = 0; i < sortedList.size(); i++) {
            ListItem listItem = sortedList.get(i);
            if (!(listItem instanceof OfflineItemListItem)) continue;

            OfflineItem currentItem = ((OfflineItemListItem) listItem).item;
            maybeAddSectionHeader(listWithHeaders, currentItem, previousItem);
            listWithHeaders.add(listItem);
            previousItem = currentItem;
        }

        return listWithHeaders;
    }

    private void maybeAddSectionHeader(
            List<ListItem> listWithHeaders,
            @NonNull OfflineItem currentItem,
            @Nullable OfflineItem previousItem) {
        @SectionHeaderType int currentHeaderType = getSectionHeaderType(currentItem);
        @SectionHeaderType int previousHeaderType = getSectionHeaderType(previousItem);

        // Add a section header when starting a new section.
        if (currentHeaderType != previousHeaderType) {
            addSectionHeader(listWithHeaders, currentItem);
            return;
        }

        // For date time section, each day has a header.
        if (currentHeaderType == SectionHeaderType.DATE
                && startOfNewDay(currentItem, previousItem)) {
            addSectionHeader(listWithHeaders, currentItem);
            return;
        }
    }

    private void addSectionHeader(
            List<ListItem> listWithHeaders, @NonNull OfflineItem currentItem) {
        Date day = CalendarUtils.getStartOfDay(currentItem.creationTimeMs).getTime();
        ListItem.SectionHeaderListItem sectionHeaderItem =
                new ListItem.SectionHeaderListItem(
                        day.getTime(), getSectionHeaderType(currentItem));
        listWithHeaders.add(sectionHeaderItem);
    }

    private @SectionHeaderType int getSectionHeaderType(@Nullable OfflineItem offlineItem) {
        if (offlineItem == null) return SectionHeaderType.INVALID;

        // Just now section follows the scheduled for later section.
        boolean isJustNow = mJustNowProvider != null && mJustNowProvider.isJustNowItem(offlineItem);
        if (isJustNow) return SectionHeaderType.JUST_NOW;

        // Regular section that shows date as the section header.
        return SectionHeaderType.DATE;
    }

    private static boolean startOfNewDay(
            OfflineItem currentItem, @Nullable OfflineItem previousItem) {
        Date currentDay = CalendarUtils.getStartOfDay(currentItem.creationTimeMs).getTime();
        Date previousDay =
                previousItem == null
                        ? null
                        : CalendarUtils.getStartOfDay(previousItem.creationTimeMs).getTime();
        return !currentDay.equals(previousDay);
    }
}