com.google.livingstories.client.start.StartPage.java Source code

Java tutorial

Introduction

Here is the source code for com.google.livingstories.client.start.StartPage.java

Source

/**
 * Copyright 2010 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.livingstories.client.start;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Document;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.livingstories.client.ContentItemType;
import com.google.livingstories.client.BaseContentItem;
import com.google.livingstories.client.ClientMessageHolder;
import com.google.livingstories.client.EventContentItem;
import com.google.livingstories.client.LivingStory;
import com.google.livingstories.client.LivingStoryRpcService;
import com.google.livingstories.client.LivingStoryRpcServiceAsync;
import com.google.livingstories.client.NarrativeContentItem;
import com.google.livingstories.client.StartPageBundle;
import com.google.livingstories.client.lsp.views.ManagementLinks;
import com.google.livingstories.client.lsp.views.Resources;
import com.google.livingstories.client.util.DateUtil;
import com.google.livingstories.client.util.GlobalUtil;
import com.google.livingstories.client.util.HistoryManager;

import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * Living Story start page
 *
 * @author ericzhang@google.com (Eric Zhang), nehasingh@google.com (Neha Singh)
 */
public class StartPage implements EntryPoint {
    private final LivingStoryRpcServiceAsync livingStoryService = GWT.create(LivingStoryRpcService.class);
    private static final int ONE_MINUTE_MILLIS = 1000 * 60;
    private static final int ONE_HOUR_MILLIS = ONE_MINUTE_MILLIS * 60;
    private static final int ONE_DAY_MILLIS = ONE_HOUR_MILLIS * 24;
    private static final int ONE_WEEK_MILLIS = ONE_DAY_MILLIS * 7;
    private static final int MONTHS_PER_YEAR = 12;
    private static final int YEAR_CUTOFF = MONTHS_PER_YEAR;

    private VerticalPanel startPageWidget;

    @Override
    public void onModuleLoad() {
        // Inject the contents of the CSS file
        // TODO: extract start page styles into its own resource so this doesn't import
        // from the client/lsp/views package.
        Resources.INSTANCE.css().ensureInjected();

        RootPanel.get("managementLinks").add(new ManagementLinks());
        startPageWidget = new VerticalPanel();
        startPageWidget.setWidth("100%");
        RootPanel.get("storyList").add(startPageWidget);

        String title = ClientMessageHolder.consts.startPageTitle();
        Document doc = Document.get();
        doc.setTitle(title);
        doc.getElementById("logoImage").setAttribute("alt", title);

        livingStoryService.getStartPageBundle(new AsyncCallback<StartPageBundle>() {
            @Override
            public void onFailure(Throwable t) {
                startPageWidget.add(new Label(ClientMessageHolder.consts.startPageLoadFailed()));
            }

            @Override
            public void onSuccess(StartPageBundle bundle) {
                populate(bundle.getStories(), bundle.getStoryIdToUpdateMap());
            }
        });
    }

    private void populate(List<LivingStory> stories, Map<Long, List<BaseContentItem>> storyIdToUpdateMap) {
        for (LivingStory story : stories) {
            GlobalUtil.addIfNotNull(startPageWidget,
                    createStoryWidget(story, storyIdToUpdateMap.get(story.getId())));
        }
    }

    private Widget createStoryWidget(LivingStory story, List<BaseContentItem> updates) {
        if (updates.isEmpty()) {
            return null;
        }
        VerticalPanel panel = new VerticalPanel();
        panel.setWidth("100%");
        DOM.setStyleAttribute(panel.getElement(), "marginBottom", "15px");

        Anchor storyName = new Anchor(story.getTitle(), getStoryUrl(story));
        storyName.addStyleName("startPageStoryName");

        Label updateCount = getUpdateRecencyLabel(
                DateUtil.laterDate(updates.get(0).getTimestamp(), story.getLastChangeTimestamp()));
        updateCount.setWordWrap(false);

        HorizontalPanel header = new HorizontalPanel();
        header.setWidth("100%");
        header.addStyleName("sectionHeader");
        DOM.setStyleAttribute(header.getElement(), "marginBottom", "10px");
        header.setHorizontalAlignment(HorizontalPanel.ALIGN_LEFT);

        header.add(storyName);
        header.add(updateCount);
        header.setCellHorizontalAlignment(updateCount, HorizontalPanel.ALIGN_RIGHT);
        panel.add(header);

        for (BaseContentItem update : updates) {
            Anchor headline = null;
            if (update.getContentItemType() == ContentItemType.NARRATIVE) {
                NarrativeContentItem narrative = (NarrativeContentItem) update;
                headline = new Anchor(
                        narrative.getHeadline() + "<span class=\"greyFont\">&nbsp;-&nbsp;"
                                + narrative.getNarrativeType().toString(),
                        true, getStoryUrl(story) + getUpdateUrl(narrative));
            } else {
                EventContentItem event = (EventContentItem) update;
                headline = new Anchor(event.getEventUpdate(), true, getStoryUrl(story) + getUpdateUrl(event));
            }
            DOM.setStyleAttribute(headline.getElement(), "paddingLeft", "5px");
            panel.add(headline);

            Label dateLabel = new Label(DateUtil.formatDate(update.getDateSortKey()));
            dateLabel.addStyleName("greyFont");
            DOM.setStyleAttribute(dateLabel.getElement(), "padding", "0 0 13px 5px");

            panel.add(dateLabel);
        }

        Anchor viewAll = new Anchor(ClientMessageHolder.consts.startPageViewAll(), true, getStoryUrl(story));
        viewAll.setStylePrimaryName("startPageViewAll");
        panel.add(viewAll);

        return panel;
    }

    private String getStoryUrl(LivingStory story) {
        return "lsps/" + story.getUrl();
    }

    private String getUpdateUrl(BaseContentItem update) {
        return HistoryManager.getTokenStringForFocusedContentItem(update.getId());
    }

    private Label getUpdateRecencyLabel(Date lastUpdateTime) {
        Date now = new Date();

        long millisPassed = now.getTime() - lastUpdateTime.getTime();
        int monthsApart = fullMonthsApart(lastUpdateTime, now);

        String displayString;

        if (millisPassed < ONE_HOUR_MILLIS) {
            // "1 minute ago" is the most recent an update gets here.
            displayString = ClientMessageHolder.msgs
                    .nMinutesAgo(Math.max(intDiv(millisPassed, ONE_MINUTE_MILLIS), 1));
        } else if (millisPassed < ONE_DAY_MILLIS) {
            displayString = ClientMessageHolder.msgs.nHoursAgo(intDiv(millisPassed, ONE_HOUR_MILLIS));
        } else if (millisPassed < ONE_WEEK_MILLIS) {
            displayString = ClientMessageHolder.msgs.nDaysAgo(intDiv(millisPassed, ONE_DAY_MILLIS));
        } else if (monthsApart < 1) {
            displayString = ClientMessageHolder.msgs.nWeeksAgo(intDiv(millisPassed, ONE_WEEK_MILLIS));
        } else if (monthsApart < YEAR_CUTOFF) {
            displayString = ClientMessageHolder.msgs.nMonthsAgo(monthsApart);
        } else {
            displayString = ClientMessageHolder.msgs.nYearsAgo(monthsApart / MONTHS_PER_YEAR);
        }

        Label label = new Label(displayString);
        label.addStyleName("normalFontWeight");
        return label;
    }

    @SuppressWarnings("deprecation")
    /** returns the number of full months between d1 -- which should be the earlier date -- and d2 */
    private int fullMonthsApart(Date d1, Date d2) {
        int yearsApart = d2.getYear() - d1.getYear();
        int fullMonths = 12 * yearsApart;
        Date d1Modified = new Date(d1.getTime());
        d1Modified.setYear(d2.getYear());

        int monthsApart = d2.getMonth() - d1Modified.getMonth();

        fullMonths += monthsApart; // this could, effectively, be a subtraction
        d1Modified.setMonth(d2.getMonth());

        // if the day, hour, minute, etc.; components of d1Modified actually indicate it's after d2,
        // we've overcounted the number of full months by 1.
        if (d1Modified.compareTo(d2) > 0) {
            fullMonths--;
        }

        return fullMonths;
    }

    private int intDiv(long n, long d) {
        long ret = n / d;
        return ret > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) ret;
    }
}