Author: yurize
Date: Tue May 1 19:14:21 2012
New Revision: 1332787
URL: http://svn.apache.org/viewvc?rev=1332787&view=rev
Log:
Adds saved state indicator.
https://reviews.apache.org/r/4937/
Added:
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/SavedStateIndicator.java
Modified:
incubator/wave/trunk/src/org/waveprotocol/box/server/gxp/TopBar.gxp
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StageTwoProvider.java
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StagesProvider.java
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/WebClient.java
incubator/wave/trunk/src/org/waveprotocol/wave/client/StageTwo.java
Modified: incubator/wave/trunk/src/org/waveprotocol/box/server/gxp/TopBar.gxp
URL:
http://svn.apache.org/viewvc/incubator/wave/trunk/src/org/waveprotocol/box/server/gxp/TopBar.gxp?rev=1332787&r1=1332786&r2=1332787&view=diff
==============================================================================
--- incubator/wave/trunk/src/org/waveprotocol/box/server/gxp/TopBar.gxp
(original)
+++ incubator/wave/trunk/src/org/waveprotocol/box/server/gxp/TopBar.gxp Tue May
1 19:14:21 2012
@@ -39,7 +39,8 @@
</gxp:if>
<gxp:if cond='username != null'>
<gxp:eval expr='username' /><span class="domain">@<gxp:eval
expr='domain' /></span> |
- <span id="netstatus" class="offline">Offline</span> |
+ <span id='unsavedStateContainer' style="width: 60px">Saved</span> |
+ <span id="netstatus" class="offline">Offline</span> |
<a href="/auth/signout?r=/">Sign out</a>
</gxp:if>
</div>
Added:
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/SavedStateIndicator.java
URL:
http://svn.apache.org/viewvc/incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/SavedStateIndicator.java?rev=1332787&view=auto
==============================================================================
---
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/SavedStateIndicator.java
(added)
+++
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/SavedStateIndicator.java
Tue May 1 19:14:21 2012
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2011 Google Inc. All Rights Reserved.
+ *
+ * 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 org.waveprotocol.box.webclient.client;
+
+import com.google.gwt.dom.client.Element;
+
+import org.waveprotocol.wave.client.scheduler.Scheduler;
+import org.waveprotocol.wave.client.scheduler.SchedulerInstance;
+import org.waveprotocol.wave.client.scheduler.TimerService;
+import org.waveprotocol.wave.concurrencycontrol.common.UnsavedDataListener;
+
+/**
+ * Simple saved state indicator.
+ *
+ * @author [email protected] (Daniel Danilatos)
+ * @author [email protected] (Yuri Zelikov)
+ */
+public class SavedStateIndicator implements UnsavedDataListener {
+
+ private enum SavedState {
+ SAVED("Saved"),
+ UNSAVED("Unsaved...");
+
+ final String message;
+
+ private SavedState(String message) {
+ this.message = message;
+ }
+ }
+
+ private static final int UPDATE_DELAY_MS = 300;
+
+ private final Scheduler.Task updateTask = new Scheduler.Task() {
+ @Override
+ public void execute() {
+ updateDisplay();
+ }
+ };
+
+ private final Element element;
+ private final TimerService scheduler;
+
+ private SavedState visibleSavedState = SavedState.SAVED;
+ private SavedState currentSavedState = null;
+
+ private static final String UNSAVED_HTML =
+ "<span style='color: red; text-align: center;'>" +
SavedState.UNSAVED.message
+ + "</span>";
+ private static final String SAVED_HTML =
+ "<span style='color: green; text-align: center;'>" +
SavedState.SAVED.message
+ + "</span>";
+
+ public SavedStateIndicator(Element element) {
+ this.element = element;
+ this.scheduler = SchedulerInstance.getLowPriorityTimer();
+ }
+
+ public void saved() {
+ maybeUpdateDisplay();
+ }
+
+ public void unsaved() {
+ maybeUpdateDisplay();
+ }
+
+ private void maybeUpdateDisplay() {
+ if (needsUpdating()) {
+ switch (currentSavedState) {
+ case SAVED:
+ scheduler.scheduleDelayed(updateTask, UPDATE_DELAY_MS);
+ break;
+ case UNSAVED:
+ updateDisplay();
+ break;
+ default:
+ throw new AssertionError("unknown " + currentSavedState);
+ }
+ } else {
+ scheduler.cancel(updateTask);
+ }
+ }
+
+ private boolean needsUpdating() {
+ return visibleSavedState != currentSavedState;
+ }
+
+ private void updateDisplay() {
+ visibleSavedState = currentSavedState;
+ String innerHtml = visibleSavedState == SavedState.SAVED ? SAVED_HTML :
UNSAVED_HTML;
+ element.setInnerHTML(innerHtml);
+ }
+
+ @Override
+ public void onUpdate(UnsavedDataInfo unsavedDataInfo) {
+ if (unsavedDataInfo.estimateUnacknowledgedSize() != 0) {
+ currentSavedState = SavedState.UNSAVED;
+ unsaved();
+ } else {
+ currentSavedState = SavedState.SAVED;
+ saved();
+ }
+ }
+
+ @Override
+ public void onClose(boolean everythingCommitted) {
+ if (everythingCommitted) {
+ saved();
+ } else {
+ unsaved();
+ }
+ }
+}
Modified:
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StageTwoProvider.java
URL:
http://svn.apache.org/viewvc/incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StageTwoProvider.java?rev=1332787&r1=1332786&r2=1332787&view=diff
==============================================================================
---
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StageTwoProvider.java
(original)
+++
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StageTwoProvider.java
Tue May 1 19:14:21 2012
@@ -19,6 +19,7 @@
package org.waveprotocol.box.webclient.client;
import com.google.common.base.Preconditions;
+import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Command;
import org.waveprotocol.wave.client.StageOne;
@@ -60,10 +61,12 @@ public class StageTwoProvider extends St
* @param waveId the id of the wave to open, or null to create a new wave
* @param channel communication channel
* @param idGenerator
+ * @param unsavedIndicatorElement
*/
public StageTwoProvider(StageOne stageOne, WaveRef waveRef,
RemoteViewServiceMultiplexer channel,
- boolean isNewWave, IdGenerator idGenerator, ProfileManager profiles) {
- super(stageOne);
+ boolean isNewWave, IdGenerator idGenerator, ProfileManager profiles,
+ Element unsavedIndicatorElement) {
+ super(stageOne, unsavedIndicatorElement);
Preconditions.checkArgument(stageOne != null);
Preconditions.checkArgument(waveRef != null);
Preconditions.checkArgument(waveRef.getWaveId() != null);
Modified:
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StagesProvider.java
URL:
http://svn.apache.org/viewvc/incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StagesProvider.java?rev=1332787&r1=1332786&r2=1332787&view=diff
==============================================================================
---
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StagesProvider.java
(original)
+++
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/StagesProvider.java
Tue May 1 19:14:21 2012
@@ -57,6 +57,7 @@ public class StagesProvider extends Stag
};
private final Element wavePanelElement;
+ private final Element unsavedIndicatorElement;
private final LogicalPanel rootPanel;
private final WaveRef waveRef;
private final RemoteViewServiceMultiplexer channel;
@@ -82,10 +83,12 @@ public class StagesProvider extends Stag
* @param isNewWave true if the wave is a new client-created wave
* @param idGenerator
*/
- public StagesProvider(Element wavePanelElement, LogicalPanel rootPanel,
WaveRef waveRef,
- RemoteViewServiceMultiplexer channel, IdGenerator idGenerator,
ProfileManager profiles,
- WaveStore store, boolean isNewWave, String localDomain) {
+ public StagesProvider(Element wavePanelElement, Element
unsavedIndicatorElement,
+ LogicalPanel rootPanel, WaveRef waveRef, RemoteViewServiceMultiplexer
channel,
+ IdGenerator idGenerator, ProfileManager profiles, WaveStore store,
boolean isNewWave,
+ String localDomain) {
this.wavePanelElement = wavePanelElement;
+ this.unsavedIndicatorElement = unsavedIndicatorElement;
this.rootPanel = rootPanel;
this.waveRef = waveRef;
this.channel = channel;
@@ -119,7 +122,7 @@ public class StagesProvider extends Stag
@Override
protected AsyncHolder<StageTwo> createStageTwoLoader(StageOne one) {
return haltIfClosed(new StageTwoProvider(
- this.one = one, waveRef, channel, isNewWave, idGenerator, profiles));
+ this.one = one, waveRef, channel, isNewWave, idGenerator, profiles,
unsavedIndicatorElement));
}
@Override
Modified:
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/WebClient.java
URL:
http://svn.apache.org/viewvc/incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/WebClient.java?rev=1332787&r1=1332786&r2=1332787&view=diff
==============================================================================
---
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/WebClient.java
(original)
+++
incubator/wave/trunk/src/org/waveprotocol/box/webclient/client/WebClient.java
Tue May 1 19:14:21 2012
@@ -34,6 +34,7 @@ import com.google.gwt.user.client.ui.Roo
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.UIObject;
+import org.waveprotocol.box.webclient.client.events.Log;
import org.waveprotocol.box.webclient.client.events.NetworkStatusEvent;
import org.waveprotocol.box.webclient.client.events.NetworkStatusEventHandler;
import org.waveprotocol.box.webclient.client.events.WaveCreationEvent;
@@ -48,7 +49,6 @@ import org.waveprotocol.box.webclient.se
import org.waveprotocol.box.webclient.search.SearchPresenter;
import org.waveprotocol.box.webclient.search.SimpleSearch;
import org.waveprotocol.box.webclient.search.WaveStore;
-import org.waveprotocol.box.webclient.client.events.Log;
import org.waveprotocol.box.webclient.widget.error.ErrorIndicatorPresenter;
import org.waveprotocol.box.webclient.widget.frame.FramedPanel;
import org.waveprotocol.box.webclient.widget.loading.LoadingIndicator;
@@ -301,9 +301,10 @@ public class WebClient implements EntryP
UIObject.setVisible(waveFrame.getElement(), true);
waveHolder.getElement().appendChild(loading);
Element holder =
waveHolder.getElement().appendChild(Document.get().createDivElement());
- StagesProvider wave = new StagesProvider(
- holder, waveHolder, waveRef, channel, idGenerator, profiles,
waveStore, isNewWave,
- Session.get().getDomain());
+ Element unsavedIndicator =
Document.get().getElementById("unsavedStateContainer");
+ StagesProvider wave =
+ new StagesProvider(holder, unsavedIndicator, waveHolder, waveRef,
channel, idGenerator,
+ profiles, waveStore, isNewWave, Session.get().getDomain());
this.wave = wave;
wave.load(new Command() {
@Override
Modified: incubator/wave/trunk/src/org/waveprotocol/wave/client/StageTwo.java
URL:
http://svn.apache.org/viewvc/incubator/wave/trunk/src/org/waveprotocol/wave/client/StageTwo.java?rev=1332787&r1=1332786&r2=1332787&view=diff
==============================================================================
--- incubator/wave/trunk/src/org/waveprotocol/wave/client/StageTwo.java
(original)
+++ incubator/wave/trunk/src/org/waveprotocol/wave/client/StageTwo.java Tue May
1 19:14:21 2012
@@ -19,6 +19,7 @@ import com.google.common.base.Preconditi
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.Command;
+import org.waveprotocol.box.webclient.client.SavedStateIndicator;
import org.waveprotocol.wave.client.account.ProfileManager;
import org.waveprotocol.wave.client.account.impl.ProfileManagerImpl;
import org.waveprotocol.wave.client.common.util.AsyncHolder;
@@ -85,6 +86,7 @@ import org.waveprotocol.wave.concurrency
import org.waveprotocol.wave.concurrencycontrol.channel.ViewChannelFactory;
import org.waveprotocol.wave.concurrencycontrol.channel.ViewChannelImpl;
import org.waveprotocol.wave.concurrencycontrol.channel.WaveViewService;
+import org.waveprotocol.wave.concurrencycontrol.common.UnsavedDataListener;
import
org.waveprotocol.wave.concurrencycontrol.common.UnsavedDataListenerFactory;
import org.waveprotocol.wave.model.conversation.ConversationBlip;
import org.waveprotocol.wave.model.conversation.ConversationThread;
@@ -237,8 +239,11 @@ public interface StageTwo {
private DiffController diffController;
private Reader reader;
- public DefaultProvider(StageOne stageOne) {
+ private final Element unsavedIndicatorElement;
+
+ public DefaultProvider(StageOne stageOne, Element unsavedIndicatorElement)
{
this.stageOne = stageOne;
+ this.unsavedIndicatorElement = unsavedIndicatorElement;
}
/**
@@ -525,7 +530,20 @@ public interface StageTwo {
.build();
ViewChannelFactory viewFactory =
ViewChannelImpl.factory(createWaveViewService(), logger);
- UnsavedDataListenerFactory unsyncedListeners =
UnsavedDataListenerFactory.NONE;
+ UnsavedDataListenerFactory unsyncedListeners = new
UnsavedDataListenerFactory() {
+
+ private final UnsavedDataListener listener = new SavedStateIndicator(
+ unsavedIndicatorElement);
+
+ @Override
+ public UnsavedDataListener create(WaveletId waveletId) {
+ return listener;
+ }
+
+ @Override
+ public void destroy(WaveletId waveletId) {
+ }
+ };
WaveletId udwId =
getIdGenerator().newUserDataWaveletId(getSignedInUser().getAddress());
final IdFilter filter = IdFilter.of(Collections.singleton(udwId),