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.admincentral;
35
36 import static info.magnolia.admincentral.ViewportLayout.View.*;
37
38 import info.magnolia.event.EventBus;
39 import info.magnolia.ui.api.event.AdmincentralEventBus;
40 import info.magnolia.ui.api.ioc.AdmincentralScoped;
41 import info.magnolia.ui.api.location.Location;
42 import info.magnolia.ui.api.location.LocationController;
43 import info.magnolia.ui.api.shell.CloseAppEvent;
44
45 import java.util.Arrays;
46 import java.util.Optional;
47 import java.util.stream.Stream;
48
49 import javax.inject.Inject;
50 import javax.inject.Named;
51
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 import com.vaadin.ui.Component;
56 import com.vaadin.ui.CssLayout;
57 import com.vaadin.ui.Layout;
58 import com.vaadin.ui.Panel;
59 import com.vaadin.ui.VerticalLayout;
60
61 import lombok.Getter;
62
63
64
65
66 @AdmincentralScoped
67 public class ViewportLayout extends CssLayout {
68
69 private static final Logger log = LoggerFactory.getLogger(ViewportLayout.class);
70
71 private static final String APP_VIEW_VISIBLE = "app-view-visible";
72 private static final String APP_VIEW_SLIDE_DOWN = "app-view-slide-down";
73 private static final String APP_VIEW_MOVE_DOWN = "app-view-move-down";
74 private static final String APP_VIEW_SLIDE_UP = "app-view-slide-up";
75 private static final String APP_VIEW_TO_FRONT = "app-view-to-front";
76
77 private static final String FIND_BAR_PANEL_SLIDE_DOWN = "find-bar-panel-slide-down";
78 private static final String FIND_BAR_PANEL_OPEN = "find-bar-panel-open";
79 private static final String FIND_BAR_PANEL_HIDDEN = "find-bar-panel-hidden";
80
81 private static final String STYLE_APPS_VIEWPORT = "apps-viewport";
82 private static final String STYLE_HEADER_APPS_VIEWPORT = "header-apps-viewport";
83
84 @Getter
85 private View activeView;
86
87 private final CssLayout appView;
88
89 private final CssLayout headerAppView;
90
91 @Getter
92 private final VerticalLayout appLauncherLayout;
93
94 @Getter
95 private final Layout findBarResultsLayout;
96 @Getter
97 private final Panel appLayout;
98
99 private final Panel tasksAppLayout;
100
101 private final Panel notificationAppLayout;
102
103 private final LocationController locationController;
104 private final EventBus eventBus;
105 private Location currentActiveAppLocation;
106
107 @Inject
108 public ViewportLayout(LocationController locationController, @Named(AdmincentralEventBus.NAME) EventBus eventBus) {
109
110 this.locationController = locationController;
111 this.eventBus = eventBus;
112
113 findBarResultsLayout = new CssLayout();
114 findBarResultsLayout.setWidth(100, Unit.PERCENTAGE);
115 findBarResultsLayout.addStyleName("findbar-results");
116
117 appLauncherLayout = new VerticalLayout();
118 appLauncherLayout.addStyleName("v-app-launcher");
119 appLauncherLayout.setSpacing(false);
120 appLauncherLayout.setMargin(false);
121 appLauncherLayout.setSizeFull();
122 Component findBarAndAppLauncher = new CssLayout(findBarResultsLayout, appLauncherLayout);
123 findBarAndAppLauncher.setWidth(100, Unit.PERCENTAGE);
124 findBarAndAppLauncher.addStyleName("findbarAndApplauncher");
125
126 appLayout = new Panel() {
127 @Override
128 public void setContent(Component content) {
129 super.setContent(content);
130 if (content != null) {
131 Optional.ofNullable(appView).ifPresent(v -> v.addStyleName(APP_VIEW_TO_FRONT));
132 } else {
133 Optional.ofNullable(appView).ifPresent(v -> v.removeStyleName(APP_VIEW_TO_FRONT));
134 }
135 }
136 };
137 appLayout.setSizeFull();
138 appLayout.addStyleName(STYLE_APPS_VIEWPORT);
139
140 CssLayout appOverlay = new CssLayout();
141 appOverlay.addStyleName("app-overlay");
142 appOverlay.setSizeFull();
143 appOverlay.addLayoutClickListener(event -> {
144 if (appLayout.getContent() != null) {
145 final View from = activeView != null ? activeView : APP_LAUNCHER;
146 updateView(from, APP);
147 }
148 });
149
150 appView = new CssLayout(appLayout, appOverlay) {
151 @Override
152 protected String getCss(Component c) {
153 return "z-index: " + (c == appLayout && (activeView == APP || appLayout.getContent() == null) ? 2 : 1);
154 }
155 };
156 appView.addStyleNames(STYLE_APPS_VIEWPORT);
157 appView.setSizeFull();
158
159 tasksAppLayout = new Panel();
160 tasksAppLayout.setSizeFull();
161 tasksAppLayout.addStyleName(STYLE_HEADER_APPS_VIEWPORT);
162
163 notificationAppLayout = new Panel();
164 notificationAppLayout.setSizeFull();
165 notificationAppLayout.addStyleName(STYLE_HEADER_APPS_VIEWPORT);
166
167 headerAppView = new CssLayout(tasksAppLayout, notificationAppLayout);
168 headerAppView.addStyleNames(STYLE_HEADER_APPS_VIEWPORT);
169 headerAppView.setSizeFull();
170
171 addComponents(findBarAndAppLauncher, appView, headerAppView);
172 addStyleName("viewportLayout");
173 setSizeFull();
174
175 updateView(NONE, FIND_BAR);
176 }
177
178 public void hideApp(String appName) {
179 View to;
180 View from;
181 Optional<View> appView = View.fromName(appName);
182 if (appView.isPresent() && appView.get().isHeaderView()) {
183 if (activeView.isFindBarActionView()) {
184 to = activeView;
185 } else if (currentActiveAppLocation != null) {
186 to = APP;
187 } else {
188 to = FIND_BAR;
189 }
190 from = appView.get();
191 } else {
192 setAppViewTransparent(true);
193 this.currentActiveAppLocation = null;
194 to = appLauncherLayout.getStyleName().contains(FIND_BAR_PANEL_OPEN) ? APP_LAUNCHER : FIND_BAR;
195 from = activeView;
196 }
197 if (to != from) {
198 updateView(from, to);
199 }
200 }
201
202 public void toggleAppLauncher() {
203 if (activeView == APP_LAUNCHER) {
204 if (appLayout.getContent() != null) {
205 updateView(activeView, APP);
206 }
207 } else {
208 if (activeView.isHeaderView()) {
209
210 activeView = APP_LAUNCHER;
211
212 eventBus.fireEvent(new CloseAppEvent());
213 } else {
214 updateView(activeView, APP_LAUNCHER);
215 }
216 }
217 }
218
219 public void toggleFindBar() {
220 if (activeView == FIND_BAR) {
221 if (appLayout.getContent() != null) {
222 updateView(activeView, APP);
223 }
224 } else {
225 if (activeView.isHeaderView()) {
226
227 activeView = FIND_BAR;
228
229 eventBus.fireEvent(new CloseAppEvent());
230 } else {
231 showFindBar();
232 }
233 }
234 }
235
236 public void showFindBar() {
237 if (activeView != FIND_BAR) {
238 updateView(activeView, FIND_BAR);
239 }
240 }
241
242 public void showApp(String appName) {
243
244 Optional<View> to = View.fromName(appName);
245 if (to.isPresent() && to.get().isHeaderView()) {
246 if (activeView != to.get()) {
247 updateView(activeView, to.get());
248 }
249 } else {
250 currentActiveAppLocation = locationController.getWhere();
251 showApp();
252 }
253 }
254
255 protected void showApp() {
256 if (activeView != APP) {
257 updateView(activeView, APP);
258 }
259 }
260
261 protected void disableAnimations() {
262 disableFindBarAnimation();
263 appView.removeStyleNames(APP_VIEW_SLIDE_UP, APP_VIEW_SLIDE_DOWN, APP_VIEW_MOVE_DOWN);
264 }
265
266 protected void disableFindBarAnimation() {
267 Arrays.asList(appLauncherLayout, findBarResultsLayout, headerAppView, notificationAppLayout, tasksAppLayout)
268 .forEach(v -> v.removeStyleNames(FIND_BAR_PANEL_SLIDE_DOWN, FIND_BAR_PANEL_OPEN, FIND_BAR_PANEL_HIDDEN));
269 }
270
271 public Panel getActiveAppView(Location location) {
272 if (location == null) {
273
274 return Arrays.asList(this.appLayout, tasksAppLayout, notificationAppLayout).stream()
275 .filter(layout -> layout.getContent() != null)
276 .findFirst().orElse(null);
277
278 } else {
279
280 Optional<View> currentAppView = View.fromName(location.getAppName());
281 if (currentAppView.isPresent() && currentAppView.get().isHeaderView()) {
282 switch (currentAppView.get()) {
283 case NOTIFICATIONS_APP:
284 return notificationAppLayout;
285 case TASK_APP:
286 return tasksAppLayout;
287 default:
288 return null;
289 }
290 } else {
291 this.currentActiveAppLocation = location;
292 return appLayout;
293 }
294 }
295 }
296
297 private void updateView(View from, View to) {
298
299 log.debug("switch from {} to {}", Optional.ofNullable(from).orElse(NONE), Optional.ofNullable(to).orElse(NONE));
300 disableAnimations();
301
302 boolean resetCurrentApp = false;
303
304 if (from.isFindBarActionView()) {
305
306 resetCurrentApp = switchFromFindBarAction(to);
307
308 } else if (from.isHeaderView()) {
309
310 resetCurrentApp = switchFromHeaderApp(to);
311
312 } else if (from == APP) {
313
314 switchFromApp(to);
315
316 } else {
317
318 hideHeaderAppView();
319
320 appView.addStyleNames(APP_VIEW_SLIDE_DOWN);
321
322 setAppViewTransparent(true);
323 }
324
325 activeView = to;
326
327 if (resetCurrentApp) {
328 Optional.ofNullable(currentActiveAppLocation).ifPresent(locationController::goTo);
329 }
330
331 }
332
333 private void switchFromApp(View to) {
334 if (to.isFindBarActionView()) {
335
336 openFindBarActionFromApp(to);
337
338 } else if (to.isHeaderView()) {
339
340 hideFindBarActionViews();
341
342 slideDownHeaderAppView(to);
343
344 appView.addStyleName(APP_VIEW_SLIDE_DOWN);
345 setAppViewTransparent(isAppViewHidden());
346 }
347 }
348
349 private boolean switchFromHeaderApp(View to) {
350 boolean resetCurrentApp = false;
351 if (to.isFindBarActionView()) {
352
353 openFindBarActionFromHeaderApp(to);
354
355 } else if (to == APP) {
356
357 hideHeaderAppView();
358
359 hideFindBarActionViews();
360
361 appView.addStyleName(APP_VIEW_SLIDE_UP);
362 setAppViewTransparent(false);
363
364 resetCurrentApp = true;
365
366 } else {
367
368 hideFindBarActionViews();
369
370 appView.addStyleName(APP_VIEW_MOVE_DOWN);
371 setAppViewTransparent(isAppViewHidden());
372
373 headerAppView.addStyleName(FIND_BAR_PANEL_OPEN);
374
375 swapHeaderAppViews(to);
376
377 }
378 return resetCurrentApp;
379 }
380
381 private boolean switchFromFindBarAction(View to) {
382 boolean resetCurrentApp = false;
383 if (to == APP) {
384
385 openAppFromFindBarActions(appLauncherLayout, findBarResultsLayout);
386
387
388
389 resetCurrentApp = currentActiveAppLocation != null &&
390 locationController.getWhere().getAppName().equals(currentActiveAppLocation.getAppName());
391
392 } else if (to.isFindBarActionView()) {
393
394 swapFindBarActionViews(to);
395
396 hideHeaderAppView();
397
398 appView.addStyleName(APP_VIEW_MOVE_DOWN);
399 setAppViewTransparent(isAppViewHidden());
400
401 } else if (to.isHeaderView()) {
402
403 hideFindBarActionViews();
404
405 slideDownHeaderAppView(to);
406
407 appView.addStyleName(APP_VIEW_MOVE_DOWN);
408 setAppViewTransparent(isAppViewHidden());
409
410 }
411 return resetCurrentApp;
412 }
413
414 private void openFindBarActionFromApp(View view) {
415
416 swapFindBarActionViews(view);
417
418 hideHeaderAppView();
419
420 appView.addStyleName(APP_VIEW_SLIDE_DOWN);
421
422
423 if (view == FIND_BAR) {
424 setAppViewTransparent(currentActiveAppLocation == null || isAppViewHidden());
425 }
426
427 }
428
429 private void openFindBarActionFromHeaderApp(View view) {
430
431 swapFindBarActionViews(view);
432
433 hideHeaderAppView();
434
435 appView.addStyleName(APP_VIEW_MOVE_DOWN);
436 setAppViewTransparent(isAppViewHidden());
437 }
438
439 private void openAppFromFindBarActions(Layout findbarLayoutToSlideUp, Layout findbarLayoutToHide) {
440
441 appView.addStyleName(APP_VIEW_SLIDE_UP);
442 setAppViewTransparent(false);
443
444 findbarLayoutToHide.addStyleName(FIND_BAR_PANEL_HIDDEN);
445
446 findbarLayoutToSlideUp.addStyleNames(FIND_BAR_PANEL_HIDDEN);
447
448 hideHeaderAppView();
449
450 }
451
452 private void swapFindBarActionViews(View activeFindBarActionView) {
453 appLauncherLayout.addStyleNames(activeFindBarActionView == APP_LAUNCHER ? new String[]{FIND_BAR_PANEL_OPEN, FIND_BAR_PANEL_SLIDE_DOWN} :
454 new String[]{FIND_BAR_PANEL_HIDDEN});
455
456 findBarResultsLayout.addStyleNames(activeFindBarActionView == FIND_BAR ? new String[]{FIND_BAR_PANEL_OPEN, FIND_BAR_PANEL_SLIDE_DOWN} :
457 new String[]{FIND_BAR_PANEL_HIDDEN});
458 }
459
460 private void hideFindBarActionViews() {
461 appLauncherLayout.addStyleName(FIND_BAR_PANEL_HIDDEN);
462
463 findBarResultsLayout.addStyleName(FIND_BAR_PANEL_HIDDEN);
464 }
465
466 private void swapHeaderAppViews(View activeHeaderAppView) {
467
468 tasksAppLayout.addStyleNames(activeHeaderAppView == TASK_APP ? new String[]{FIND_BAR_PANEL_SLIDE_DOWN, FIND_BAR_PANEL_OPEN} :
469 new String[]{FIND_BAR_PANEL_HIDDEN});
470
471 notificationAppLayout.addStyleNames(activeHeaderAppView == NOTIFICATIONS_APP ? new String[]{FIND_BAR_PANEL_SLIDE_DOWN, FIND_BAR_PANEL_OPEN} :
472 new String[]{FIND_BAR_PANEL_HIDDEN});
473 }
474
475 private void slideDownHeaderAppView(View view) {
476 headerAppView.addStyleNames(FIND_BAR_PANEL_SLIDE_DOWN, FIND_BAR_PANEL_OPEN);
477 swapHeaderAppViews(view);
478 }
479
480 private void hideHeaderAppView() {
481 headerAppView.addStyleName(FIND_BAR_PANEL_HIDDEN);
482 }
483
484 private boolean isAppViewHidden() {
485 return currentActiveAppLocation == null;
486 }
487
488 private void setAppViewTransparent(boolean transparent) {
489 if (transparent) {
490 appView.removeStyleName(APP_VIEW_VISIBLE);
491 } else {
492 appView.addStyleName(APP_VIEW_VISIBLE);
493 }
494 }
495
496
497
498
499 public enum View {
500
501 NONE("none"),
502 APP("app"),
503 FIND_BAR("find-bar"),
504 APP_LAUNCHER("app-launcher"),
505 TASK_APP("tasks-app"),
506 NOTIFICATIONS_APP("notifications");
507
508 String name;
509
510 View(String name) {
511 this.name = name;
512 }
513
514 static Optional<View> fromName(String name) {
515 return Stream.of(View.values())
516 .filter(v -> v.name.equals(name))
517 .findFirst();
518 }
519
520 boolean isFindBarActionView() {
521 return this == APP_LAUNCHER || this == FIND_BAR;
522 }
523
524 boolean isHeaderView() {
525 return this == TASK_APP || this == NOTIFICATIONS_APP;
526 }
527 }
528 }