/******************************************************************************* * Copyright 2011 Antti Havanko * * This file is part of Motiver.fi. * Motiver.fi is licensed under one open source license and one commercial license. * * Commercial license: This is the appropriate option if you want to use Motiver.fi in * commercial purposes. Contact license@motiver.fi for licensing options. * * Open source license: This is the appropriate option if you are creating an open source * application with a license compatible with the GNU GPL license v3. Although the GPLv3 has * many terms, the most important is that you must provide the source code of your application * to your users so they can be free to modify your application for their own needs. ******************************************************************************/ package com.delect.motiver.client.view.mobile; import java.util.Date; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.i18n.client.DateTimeFormat; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Widget; import com.google.gwt.user.datepicker.client.CalendarUtil; import com.delect.motiver.client.AppController; import com.delect.motiver.client.StringConstants; import com.delect.motiver.client.presenter.DateWeekSelectorPresenter; import com.delect.motiver.client.presenter.DateWeekSelectorPresenter.DateWeekSelectorHandler; import com.delect.motiver.shared.util.CommonUtils; import com.extjs.gxt.ui.client.Style.Orientation; import com.extjs.gxt.ui.client.event.BaseEvent; import com.extjs.gxt.ui.client.event.ComponentEvent; import com.extjs.gxt.ui.client.event.DomEvent; import com.extjs.gxt.ui.client.event.Events; import com.extjs.gxt.ui.client.event.Listener; import com.extjs.gxt.ui.client.util.Margins; import com.extjs.gxt.ui.client.widget.DatePicker; import com.extjs.gxt.ui.client.widget.Info; import com.extjs.gxt.ui.client.widget.LayoutContainer; import com.extjs.gxt.ui.client.widget.Popup; import com.extjs.gxt.ui.client.widget.Text; import com.extjs.gxt.ui.client.widget.layout.RowData; import com.extjs.gxt.ui.client.widget.layout.RowLayout; /** * * Date selector panel with X days */ public class DateWeekSelectorView extends DateWeekSelectorPresenter.DateWeekSelectorDisplay { /** * How many days are shown in week calendar. */ public static final int TOTAL_DAY_COUNT = 7; private Date dateSelected = new Date(); //date variables private Date dateStart = new Date(); private Date dateStartLast = null; private DateWeekSelectorHandler handler; private boolean isSliding = false; //mouse slide variables private int lastX = 0; private int lastY = 0; private boolean[] markers; private HorizontalPanel panelDays = new HorizontalPanel(); private Popup popup; private boolean slideOn = false; private boolean slidePrev = false; final DateTimeFormat fmt2 = DateTimeFormat.getFormat("d.M.YYYY"); //date formats final DateTimeFormat fmtDate = DateTimeFormat.getFormat("d"); final DateTimeFormat fmtDay = DateTimeFormat.getFormat("E"); final Text linkSelectDate = new Text(); long timeAni = 0; final String todayStr = fmt2.format(new Date()); public DateWeekSelectorView() { this.setLayout(new RowLayout()); this.setStyleName("panel-calendarweek"); panelDays.setWidth("100%"); panelDays.setSpacing(5); this.add(panelDays, new RowData(-1, -1)); //links LayoutContainer panelLinks = new LayoutContainer(); panelLinks.setLayout(new RowLayout(Orientation.HORIZONTAL)); panelLinks.setHeight(18); //today Text linkToday = new Text(AppController.Lang.Today()); linkToday.setStyleName("link"); linkToday.addListener(Events.OnClick, new Listener<BaseEvent>() { @Override public void handleEvent(BaseEvent be) { dateSelected = new Date(); dateStartLast = dateStart; if(dateSelected.getTime() == 0) { return; } //call handler handler.dateSelected(dateStart, dateSelected); } }); panelLinks.add(linkToday, new RowData(-1, -1, new Margins(0, 10, 0, 0))); //date selection linkSelectDate.setStyleName("link"); linkSelectDate.setText(AppController.Lang.SelectDate()); linkSelectDate.addListener(Events.OnClick, new Listener<BaseEvent>() { @Override public void handleEvent(BaseEvent be) { if(popup != null && popup.isVisible()) { popup.hide(); } popup = new Popup(); final DatePicker picker = new DatePicker(); picker.setValue(dateSelected); picker.addListener(Events.Select, new Listener<ComponentEvent>() { public void handleEvent(ComponentEvent be) { dateSelected = picker.getValue(); dateStartLast = dateStart; if(dateSelected.getTime() == 0) { return; } if(popup != null && popup.isVisible()) { popup.hide(); } //call handler handler.dateSelected(dateStart, dateSelected); } }); popup.add(picker); popup.show(linkSelectDate); } }); panelLinks.add(linkSelectDate); this.add(panelLinks, new RowData(-1, -1, new Margins(5, 0, 0, 5))); } @Override public Widget asWidget() { //disable text selection this.setStyleAttribute("-webkit-user-select", "none"); //set slide listeners (change dates when sliding left/right) this.addListener(Events.OnMouseDown, new Listener<DomEvent>() { @Override public void handleEvent(DomEvent be) { lastX = be.getClientX(); lastY = be.getClientY(); slideOn = true; } }); this.addListener(Events.OnMouseUp, new Listener<DomEvent>() { @Override public void handleEvent(DomEvent be) { slideOn = false; } }); this.addListener(Events.OnMouseMove, new Listener<DomEvent>() { @Override public void handleEvent(DomEvent be) { if(!slideOn) { return; } final int x = be.getClientX(); final int y = be.getClientY(); if(lastX > 0 && lastY > 0 && x > 0 && y > 0) { //slide to right if(x - lastX > StringConstants.SLIDE_MIN_X) { slideOn = false; showPrevDates(); } //slide to left else if(lastX - x > StringConstants.SLIDE_MIN_X) { slideOn = false; showNextDates(); } } } }); initDaysPanel(); return this; } @Override public void onStop() { if(popup != null && popup.isVisible()) { popup.hide(); } } @Override public void refreshView() { slidePrev = (dateStart.getTime() < dateStartLast.getTime()); //scroll animation if(this.isRendered()) { //init panel 21 times final DateTimeFormat fmt = DateTimeFormat.getFormat("yyyy-MM-dd"); if( !fmt.format(dateStartLast).equals(fmt.format(dateStart))) { isSliding = true; animatePanel(dateStartLast, dateStart); } else { initDaysPanel(); } } else { initDaysPanel(); } } @Override public void setDate(Date dateStart) { this.dateStart = dateStart; if(dateStartLast == null) { dateStartLast = this.dateStart; } } @Override public void setDateSelected(Date date) { dateSelected = date; } @Override public void setHandler(DateWeekSelectorHandler handler) { this.handler = handler; } /** * Sets markers (if day has data) to each day * @param markers */ @Override public void setMarkers(boolean[] markers) { this.markers = markers; if(!isSliding) { initDaysPanel(); } } /** * Inits days panel until we are in correct day * @param dateStartLast2 */ private void animatePanel(final Date d, final Date dateEnd) { Timer timer = new Timer() { @Override public void run() { //scroll speed based on datediff int speed = 1; int diff = Math.abs(CalendarUtil.getDaysBetween(d, dateEnd)); if(diff <= 14) { speed = 1; } else if(diff <= 21) { speed = 2; } else if(diff <= 35) { speed = 5; } else if(diff <= 70) { speed = 10; } else { speed = 25; } if(slidePrev) { dateStart = new Date( (d.getTime() / 1000 - 3600 * 24 * speed) * 1000 ); } else { dateStart = new Date( (d.getTime() / 1000 + 3600 * 24 * speed) * 1000 ); } initDaysPanel(); //if more days final DateTimeFormat fmt = DateTimeFormat.getFormat("yyyy-MM-dd"); if( !fmt.format(dateStart).equals(fmt.format(dateEnd))) { animatePanel(dateStart, dateEnd); } else { isSliding = false; initDaysPanel(); //refresh one more time, so event handler are set } } }; long days = 0; if(slidePrev) { days = (d.getTime() - dateEnd.getTime()) / (1000 * 3600 * 24); } else { days = (dateEnd.getTime() - d.getTime()) / (1000 * 3600 * 24); } int del = 15; if(days > 0 && days < 6) { del += (6 - days) * 35; } else if(days > 16 && days < 22) { del += (days - 16) * 35; } //run timer timer.schedule(del); } /** * Inits days panel */ private void initDaysPanel() { timeAni = System.currentTimeMillis(); panelDays.clear(); //set last start date dateStartLast = dateStart; try { //find prev monday long mon = dateStart.getTime() / 1000; final String selStr = fmt2.format(dateSelected); //left arrow HTML lLeft = new HTML("<div><</div>"); lLeft.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { showPrevDates(); } }); lLeft.setStyleName("panel-calendarweek-day-left"); panelDays.add(lLeft); panelDays.setCellWidth(lLeft, "2.5%"); Date d = new Date(mon * 1000); //load cells for(int i=0; i < TOTAL_DAY_COUNT; i++) { final long sec = d.getTime() / 1000; String dStr = fmtDate.format(d); if(dStr.length() == 1) { dStr = " " + dStr; } //day of week dStr += "<br>" + fmtDay.format(d); dStr = "<div>" + dStr + "</div>"; //add day HTML l = new HTML(dStr); l.setTitle(AppController.Lang.ShowDate() + ": " + CommonUtils.getDateString(d, true, false)); //styles //if selected if(fmt2.format(d).equals(selStr)) { l.setStyleName("panel-calendarweek-day-sel"); } //if workouts (only when not sliding) else if(!isSliding && markers != null && markers.length > i && markers[i]) { l.setStyleName("panel-calendarweek-day-workout"); } else { l.setStyleName("panel-calendarweek-day"); } //add these only when not in "animation" if(!isSliding) { l.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { dateSelected = new Date(sec * 1000); dateStartLast = dateStart; if(dateSelected.getTime() == 0) { return; } handler.dateSelected(dateStart, dateSelected); } }); } panelDays.add(l); panelDays.setCellWidth(l, "13.5%"); //add day CalendarUtil.addDaysToDate(d, 1); } //right arrow HTML lRight = new HTML("<div>></div>"); lRight.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { showNextDates(); } }); lRight.setStyleName("panel-calendarweek-day-right"); panelDays.add(lRight); panelDays.setCellWidth(lRight, "2.5%"); } catch (Exception e) { Info.display("error", e.getMessage()); } } /** * Shows next three weeks */ protected void showNextDates() { if(!isSliding) { dateStartLast = dateStart; //change both dates dateStart = new Date(dateStart.getTime() + 1000 * 3600 * 24 * 21); dateSelected = new Date(dateSelected.getTime() + 1000 * 3600 * 24 * 21); handler.dateSelected(dateStart, dateSelected); } } /** * Shows previous three weeks */ protected void showPrevDates() { if(!isSliding) { dateStartLast = dateStart; //change both dates dateStart = new Date(dateStart.getTime() - 1000 * 3600 * 24 * 21); dateSelected = new Date(dateSelected.getTime() - 1000 * 3600 * 24 * 21); handler.dateSelected(dateStart, dateSelected); } } @Override public int getTotalDays() { return TOTAL_DAY_COUNT; } }