1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.widget;
35
36 import info.magnolia.ui.vaadin.gwt.client.CloseButton;
37 import info.magnolia.ui.vaadin.gwt.client.FullScreenButton;
38 import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryCallback;
39 import info.magnolia.ui.vaadin.gwt.client.jquerywrapper.JQueryWrapper;
40 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.ShellState;
41 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.AppsTransitionDelegate;
42 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.MagnoliaSwipeRecognizer;
43 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.animation.FadeAnimation;
44 import info.magnolia.ui.vaadin.gwt.client.magnoliashell.viewport.animation.SlideAnimation;
45
46 import java.util.Iterator;
47
48 import com.google.gwt.dom.client.Style.Visibility;
49 import com.google.gwt.event.shared.HandlerRegistration;
50 import com.google.gwt.user.client.DOM;
51 import com.google.gwt.user.client.Element;
52 import com.google.gwt.user.client.Event;
53 import com.google.gwt.user.client.ui.RootPanel;
54 import com.google.gwt.user.client.ui.Widget;
55 import com.googlecode.mgwt.dom.client.event.touch.TouchCancelEvent;
56 import com.googlecode.mgwt.dom.client.event.touch.TouchCancelHandler;
57 import com.googlecode.mgwt.dom.client.event.touch.TouchEndEvent;
58 import com.googlecode.mgwt.dom.client.event.touch.TouchEndHandler;
59 import com.googlecode.mgwt.dom.client.recognizer.swipe.HasSwipeHandlers;
60 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeEndEvent;
61 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeEndHandler;
62 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeEvent;
63 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeEvent.DIRECTION;
64 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeMoveEvent;
65 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeMoveHandler;
66 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeStartEvent;
67 import com.googlecode.mgwt.dom.client.recognizer.swipe.SwipeStartHandler;
68 import com.googlecode.mgwt.ui.client.widget.touch.TouchDelegate;
69
70
71
72
73 public class AppsViewportWidget extends ViewportWidget<AppsTransitionDelegate> implements HasSwipeHandlers {
74
75 public static final String APP_INACTIVE_CLASS_NAME = "app-inactive";
76
77
78
79
80 public interface Listener {
81
82 void closeCurrentApp();
83
84 void activateApp(Widget appWidget);
85
86 };
87
88 private static final int SWIPE_OUT_THRESHOLD = 300;
89
90 private final AppPreloadern/gwt/client/magnoliashell/viewport/widget/AppPreloader.html#AppPreloader">AppPreloader preloader = new AppPreloader();
91
92 private boolean isAppClosing = false;
93
94 private boolean isCurtainVisible = false;
95
96 private Listener listener;
97
98 private final TouchDelegate/client/widget/touch/TouchDelegate.html#TouchDelegate">TouchDelegate delegate = new TouchDelegate(this);
99
100 private final FullScreenButtont/FullScreenButton.html#FullScreenButton">FullScreenButton fullScreenButton = new FullScreenButton();
101
102 private Element curtain = DOM.createDiv();
103
104
105
106
107
108 public boolean readyForAppSwipeOrShortcutNavigation() {
109 return ShellState.get().isAppStarted() && getWidgetCount() > 1 && !getTransitionDelegate().inProgress();
110 }
111
112 private void closeCurrentApp() {
113 if (!isAppClosing()) {
114 isAppClosing = true;
115 listener.closeCurrentApp();
116 isAppClosing = false;
117 }
118 }
119
120 private void toggleFullScreen() {
121 String cssClasses = RootPanel.get().getStyleName();
122 boolean isFullScreen = cssClasses.contains("fullscreen");
123
124 setFullScreen(!isFullScreen);
125 }
126
127 private CloseButton/gwt/client/CloseButton.html#CloseButton">CloseButton closeButton = new CloseButton();
128
129
130
131
132 public void setFullScreen(boolean isFullScreen) {
133
134 if (isFullScreen) {
135
136 RootPanel.get().addStyleName("fullscreen");
137
138 fullScreenButton.getElement().addClassName("icon-extend-header");
139 fullScreenButton.getElement().removeClassName("icon-collapse-header");
140 } else {
141
142
143 RootPanel.get().removeStyleName("fullscreen");
144
145 fullScreenButton.getElement().addClassName("icon-collapse-header");
146 fullScreenButton.getElement().removeClassName("icon-extend-header");
147 }
148 }
149
150 public AppsViewportWidget(final Listener listener) {
151 super();
152 this.listener = listener;
153 DOM.sinkEvents(getElement(), Event.ONCLICK);
154 curtain.setClassName("v-curtain v-curtain-green");
155 closeButton.addStyleDependentName("app");
156 delegate.addTouchEndHandler(new TouchEndHandler() {
157 @Override
158 public void onTouchEnd(TouchEndEvent event) {
159 Element target = event.getNativeEvent().getEventTarget().cast();
160 if (closeButton.getElement().isOrHasChild(target)) {
161 closeCurrentApp();
162 } else if (fullScreenButton.getElement().isOrHasChild(target)) {
163 toggleFullScreen();
164 }
165 }
166 });
167
168 bindTouchHandlers();
169
170 }
171
172 public void goToNextApp() {
173 if (getWidgetCount() > 1) {
174 processSwipe(-1);
175 switchToApp(DIRECTION.RIGHT_TO_LEFT);
176 }
177 }
178
179 public void goToPreviousApp() {
180 if (getWidgetCount() > 1) {
181 processSwipe(1);
182 switchToApp(DIRECTION.LEFT_TO_RIGHT);
183 }
184 }
185
186
187
188
189
190 public Widget getCurrentApp(){
191 if (getWidgetCount() < 1) {
192 return null;
193 }else{
194 for (int w=0; w < getWidgetCount(); w++){
195 Widget app = getWidget(w);
196 String style = app.getStyleName();
197 if (!app.getStyleName().contains("app-inactive")){
198 return app;
199 }
200 }
201 }
202
203 return null;
204 }
205
206 public Element getCurtain() {
207 return curtain;
208 }
209
210 public void setCurtainVisible(boolean visible) {
211 if (isCurtainVisible != visible) {
212 this.isCurtainVisible = visible;
213 getTransitionDelegate().setCurtainVisible(isCurtainVisible);
214 }
215 }
216
217
218 @Override
219 public void showChildNoTransition(Widget w) {
220 getElement().appendChild(closeButton.getElement());
221 getElement().appendChild(fullScreenButton.getElement());
222 Widget formerVisible = getVisibleChild();
223
224 if (formerVisible != null && !isAppClosing()) {
225 formerVisible.getElement().getStyle().setVisibility(Visibility.HIDDEN);
226 formerVisible.addStyleName(APP_INACTIVE_CLASS_NAME);
227 }
228 w.setVisible(true);
229 w.removeStyleName(APP_INACTIVE_CLASS_NAME);
230 w.getElement().getStyle().clearVisibility();
231 }
232
233 @Override
234 public void removeChild(Widget w) {
235 getTransitionDelegate().removeWidget(w);
236 getElement().removeChild(closeButton.getElement());
237 getElement().removeChild(fullScreenButton.getElement());
238 }
239
240 @Override
241 public void removeChildNoTransition(Widget w) {
242 super.removeChildNoTransition(w);
243 isAppClosing = false;
244 }
245
246 public boolean isAppClosing() {
247 return isAppClosing;
248 }
249
250
251 public void showAppPreloader(final String appName) {
252 preloader.setCaption(appName);
253 preloader.addStyleName("zoom-in");
254 RootPanel.get().add(preloader);
255 }
256
257 public boolean hasPreloader() {
258 return RootPanel.get().getWidgetIndex(preloader) >= 0;
259 }
260
261 public void removePreloader() {
262 final FadeAnimationient/magnoliashell/viewport/animation/FadeAnimation.html#FadeAnimation">FadeAnimation preloaderFadeOut = new FadeAnimation(0d, true);
263 preloaderFadeOut.addCallback(new JQueryCallback() {
264 @Override
265 public void execute(JQueryWrapper query) {
266 RootPanel.get().remove(preloader);
267 }
268 });
269 preloaderFadeOut.run(500, preloader.getElement());
270 }
271
272
273 private void bindTouchHandlers() {
274 DOM.sinkEvents(getElement(), Event.TOUCHEVENTS);
275 delegate.addTouchHandler(new MagnoliaSwipeRecognizer(delegate, SWIPE_OUT_THRESHOLD));
276 addSwipeStartHandler(new SwipeStartHandler() {
277 @Override
278 public void onSwipeStart(SwipeStartEvent event) {
279 processSwipe(event.getDistance() * (event.getDirection() == DIRECTION.LEFT_TO_RIGHT ? 1 : -1));
280 }
281 });
282
283 addSwipeMoveHandler(new SwipeMoveHandler() {
284 @Override
285 public void onSwipeMove(SwipeMoveEvent event) {
286 processSwipe(event.getDistance() * (event.getDirection() == SwipeEvent.DIRECTION.LEFT_TO_RIGHT ? 1 : -1));
287 }
288 });
289
290 addSwipeEndHandler(new SwipeEndHandler() {
291 @Override
292 public void onSwipeEnd(SwipeEndEvent event) {
293 if (getWidgetCount() > 1) {
294 final SwipeEvent.DIRECTION direction = event.getDirection();
295 if (event.isDistanceReached()) {
296 switchToApp(direction);
297 } else {
298 final Widget visibleChild = getVisibleChild();
299 final SlideAnimationlient/magnoliashell/viewport/animation/SlideAnimation.html#SlideAnimation">SlideAnimation slideAnimation = new SlideAnimation(false, true);
300 slideAnimation.setTargetValue(0);
301 slideAnimation.run(500, visibleChild.getElement());
302 slideAnimation.addCallback(new JQueryCallback() {
303 @Override
304 public void execute(JQueryWrapper query) {
305
306 dropZIndeces();
307 Widget next = getNextWidget();
308 Widget previous = getPreviousWidget();
309 if (next != null) {
310 next.getElement().getStyle().setVisibility(Visibility.HIDDEN);
311 }
312
313 if (previous != null) {
314 previous.getElement().getStyle().setVisibility(Visibility.HIDDEN);
315 }
316 }
317 });
318 }
319 }
320 }
321 });
322
323 delegate.addTouchCancelHandler(new TouchCancelHandler() {
324 @Override
325 public void onTouchCanceled(TouchCancelEvent event) {
326 dropZIndeces();
327 Widget next = getNextWidget();
328 Widget previous = getPreviousWidget();
329 if (next != null) {
330 next.getElement().getStyle().setVisibility(Visibility.HIDDEN);
331 }
332
333 if (previous != null) {
334 previous.getElement().getStyle().setVisibility(Visibility.HIDDEN);
335 }
336
337 getVisibleChild().getElement().getStyle().clearLeft();
338 }
339 });
340 }
341
342 private void switchToApp(final SwipeEvent.DIRECTION direction) {
343
344 final Widget newVisibleWidget = direction == DIRECTION.LEFT_TO_RIGHT ? getPreviousWidget() : getNextWidget();
345 SlideAnimationlient/magnoliashell/viewport/animation/SlideAnimation.html#SlideAnimation">SlideAnimation slideAnimation = new SlideAnimation(false, true);
346 slideAnimation.addCallback(new JQueryCallback() {
347 @Override
348 public void execute(JQueryWrapper query) {
349
350 showChild(newVisibleWidget);
351 dropZIndeces();
352 listener.activateApp(newVisibleWidget);
353 }
354 });
355
356 Element targetElement = getVisibleChild().getElement();
357 slideAnimation.setTargetValue(getOffsetWidth() * (direction == DIRECTION.LEFT_TO_RIGHT ? 1 : -1));
358 slideAnimation.run(450, targetElement);
359
360 if (direction == DIRECTION.RIGHT_TO_LEFT && getWidgetCount() > 2) {
361 final SlideAnimationell/viewport/animation/SlideAnimation.html#SlideAnimation">SlideAnimation slideNewVisibleToEdgeAnimation = new SlideAnimation(false, true);
362 slideNewVisibleToEdgeAnimation.setTargetValue(0);
363 slideNewVisibleToEdgeAnimation.run(500, newVisibleWidget.getElement());
364 }
365
366 }
367
368 private void processSwipe(int translationValue) {
369 if (getWidgetCount() > 1) {
370 JQueryWrapper.select(getVisibleChild()).setCss("-webkit-transform", "translate3d(" + translationValue + "px,0,0)");
371 showCandidateApp(translationValue);
372 }
373 }
374
375 private void showCandidateApp(int translationValue) {
376 final Widget nextWidget = getNextWidget();
377 final Widget previousWidget = getPreviousWidget();
378 boolean isNext = translationValue < 0;
379 if (isNext) {
380 nextWidget.getElement().getStyle().setZIndex(250);
381 getVisibleChild().getElement().getStyle().setZIndex(251);
382 } else {
383 previousWidget.getElement().getStyle().setZIndex(250);
384 getVisibleChild().getElement().getStyle().setZIndex(251);
385 }
386
387 if (isNext && getWidgetCount() > 2) {
388 JQueryWrapper.select(nextWidget).setCss("-webkit-transform", "translate3d(" + (translationValue + getVisibleChild().getOffsetWidth()) + "px,0,0)");
389 }
390
391 nextWidget.getElement().getStyle().setVisibility(isNext || nextWidget == previousWidget ? Visibility.VISIBLE : Visibility.HIDDEN);
392 previousWidget.getElement().getStyle().setVisibility(!isNext || nextWidget == previousWidget ? Visibility.VISIBLE : Visibility.HIDDEN);
393 }
394
395 private Widget getNextWidget() {
396 int index = getWidgetIndex(getVisibleChild());
397 return getWidget((index + 1) % getWidgetCount());
398 }
399
400 private Widget getPreviousWidget() {
401 int index = getWidgetIndex(getVisibleChild());
402 int count = getWidgetCount();
403 return getWidget((index + (count - 1)) % count);
404 }
405
406 private void dropZIndeces() {
407 final Iterator<Widget> it = iterator();
408 while (it.hasNext()) {
409 it.next().getElement().getStyle().clearZIndex();
410 }
411 }
412
413 @Override
414 public HandlerRegistration addSwipeStartHandler(SwipeStartHandler handler) {
415 return addHandler(handler, SwipeStartEvent.getType());
416 }
417
418 @Override
419 public HandlerRegistration addSwipeMoveHandler(SwipeMoveHandler handler) {
420 return addHandler(handler, SwipeMoveEvent.getType());
421 }
422
423 @Override
424 public HandlerRegistration addSwipeEndHandler(SwipeEndHandler handler) {
425 return addHandler(handler, SwipeEndEvent.getType());
426 }
427
428 }