package org.activityinfo.ui.client.page.app;
/*
* #%L
* ActivityInfo Server
* %%
* Copyright (C) 2009 - 2013 UNICEF
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.extjs.gxt.ui.client.event.Listener;
import com.extjs.gxt.ui.client.widget.MessageBox;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.http.client.*;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.Widget;
import org.activityinfo.i18n.shared.I18N;
import org.activityinfo.legacy.shared.Log;
import org.activityinfo.ui.client.ClientContext;
import org.activityinfo.ui.client.EventBus;
import org.activityinfo.ui.client.SessionUtil;
import org.activityinfo.ui.client.inject.ClientSideAuthProvider;
import org.activityinfo.ui.client.local.LocalController;
import org.activityinfo.ui.client.local.LocalStateChangeEvent;
import org.activityinfo.ui.client.local.LocalStateChangeEvent.State;
import org.activityinfo.ui.client.local.capability.LocalCapabilityProfile;
import org.activityinfo.ui.client.local.sync.SyncCompleteEvent;
import org.activityinfo.ui.client.local.sync.SyncStatusEvent;
import org.activityinfo.ui.client.page.NavigationEvent;
import org.activityinfo.ui.client.page.NavigationHandler;
import java.util.Date;
public class SettingsPopup extends PopupPanel {
public static final int WIDTH = 250;
private static SettingsPopupUiBinder uiBinder = GWT.create(SettingsPopupUiBinder.class);
interface SettingsPopupUiBinder extends UiBinder<Widget, SettingsPopup> {
}
@UiField SpanElement versionLabel;
@UiField SpanElement emailLabel;
@UiField SpanElement versionStatus;
@UiField SpanElement appCacheStatus;
@UiField Label refreshLink;
@UiField Label logoutLink;
@UiField Label userProfileLink;
@UiField Label offlineInstallLabel;
@UiField Label offlineStatusLabel;
@UiField Label lastSyncedLabel;
Date lastSyncTime = null;
@UiField DivElement syncRow;
@UiField Label syncNowLabel;
private boolean syncing = false;
private EventBus eventBus;
private LocalStateChangeEvent.State state = State.CHECKING;
private LocalController offlineController;
private LocalCapabilityProfile offlineCapabilityProfile = GWT.create(LocalCapabilityProfile.class);
public SettingsPopup(EventBus eventBus, LocalController offlineController) {
this.eventBus = eventBus;
this.offlineController = offlineController;
setWidget(uiBinder.createAndBindUi(this));
setAutoHideEnabled(true);
setAutoHideOnHistoryEventsEnabled(true);
setWidth(WIDTH + "px");
versionLabel.setInnerText(ClientContext.getVersion());
emailLabel.setInnerText(new ClientSideAuthProvider().get().getEmail());
syncRow.getStyle().setDisplay(Display.NONE);
eventBus.addListener(SyncStatusEvent.TYPE, new Listener<SyncStatusEvent>() {
@Override
public void handleEvent(SyncStatusEvent be) {
offlineStatusLabel.setText(be.getTask() + " " + ((int) (be.getPercentComplete())) + "%");
syncing = true;
}
});
eventBus.addListener(SyncCompleteEvent.TYPE, new Listener<SyncCompleteEvent>() {
@Override
public void handleEvent(SyncCompleteEvent event) {
syncing = false;
syncRow.getStyle().setDisplay(Display.BLOCK);
lastSyncTime = event.getTime();
updateLastSyncLabel();
}
});
eventBus.addListener(LocalStateChangeEvent.TYPE, new Listener<LocalStateChangeEvent>() {
@Override
public void handleEvent(LocalStateChangeEvent be) {
onOfflineStatusChange(be.getState());
}
});
onOfflineStatusChange(offlineController.getState());
}
@Override
public void show() {
sendUpdateRequest();
updateLastSyncLabel();
if (!syncing) {
offlineStatusLabel.setText("");
}
super.show();
}
/**
* Queries the server for the latest deployed version.
*/
private void sendUpdateRequest() {
versionStatus.setInnerText(I18N.CONSTANTS.versionChecking());
appCacheStatus.setInnerText("");
refreshLink.setVisible(false);
RequestBuilder request = new RequestBuilder(RequestBuilder.GET, "/commit.id");
request.setCallback(new RequestCallback() {
@Override
public void onResponseReceived(Request request, Response response) {
if (response.getStatusCode() != 200) {
versionStatus.setInnerText(I18N.CONSTANTS.versionConnectionProblem());
} else if (response.getText().startsWith(ClientContext.getCommitId())) {
versionStatus.setInnerText(I18N.CONSTANTS.versionLatest());
} else {
versionStatus.setInnerText(I18N.CONSTANTS.versionUpdateAvailable());
refreshLink.setVisible(true);
}
}
@Override
public void onError(Request request, Throwable exception) {
versionStatus.setInnerText(I18N.CONSTANTS.versionConnectionProblem());
}
});
try {
request.send();
} catch (RequestException e) {
versionStatus.setInnerText(I18N.CONSTANTS.versionConnectionProblem());
Log.debug("Problem fetching latest version", e);
}
}
@UiHandler("refreshLink")
public void onRefreshLink(ClickEvent e) {
}
@UiHandler("logoutLink")
public void onLogoutClicked(ClickEvent e) {
SessionUtil.logout();
}
@UiHandler("userProfileLink")
public void onUserProfileLink(ClickEvent e) {
eventBus.fireEvent(new NavigationEvent(NavigationHandler.NAVIGATION_REQUESTED, new UserProfilePage.State()));
super.hide();
}
@UiHandler("offlineInstallLabel")
public void onOfflineInstallClicked(ClickEvent e) {
switch (state) {
case UNINSTALLED:
if (offlineCapabilityProfile.isOfflineModeSupported()) {
offlineController.install();
} else {
MessageBox.info("Offline Mode not supported",
offlineCapabilityProfile.getInstallInstructions(),
null);
}
}
}
@UiHandler("syncNowLabel")
public void onSyncNowClicked(ClickEvent e) {
offlineController.synchronize();
}
private void onOfflineStatusChange(State state) {
this.state = state;
offlineStatusLabel.setText("");
switch (state) {
case UNINSTALLED:
offlineInstallLabel.setText(I18N.CONSTANTS.installOffline());
syncRow.getStyle().setDisplay(Display.NONE);
break;
case INSTALLING:
offlineInstallLabel.setText("");
syncRow.getStyle().setDisplay(Display.NONE);
break;
case INSTALLED:
offlineInstallLabel.setText(I18N.CONSTANTS.reinstallOfflineMode());
syncRow.getStyle().setDisplay(Display.BLOCK);
lastSyncTime = offlineController.getLastSyncTime();
updateLastSyncLabel();
}
}
private void updateLastSyncLabel() {
if (lastSyncTime != null) {
lastSyncedLabel.setText(I18N.MESSAGES.lastSynced(formatLastSyncTime(lastSyncTime)));
}
}
private String formatLastSyncTime(Date time) {
long now = new Date().getTime();
long last = time.getTime();
long secondsAgo = (now - last) / 1000;
if (secondsAgo <= 60) {
return I18N.CONSTANTS.relativeTimeMinAgo();
}
long minutesAgo = secondsAgo / 60;
if (minutesAgo <= 60) {
return I18N.MESSAGES.minutesAgo((int) minutesAgo);
}
long hoursAgo = minutesAgo / 60;
if (hoursAgo <= 48) {
return I18N.MESSAGES.hoursAgo((int) hoursAgo);
}
long daysAgo = hoursAgo / 24;
return I18N.MESSAGES.daysAgo((int) daysAgo);
}
}