on 408540a help sign in
unity8/Shell.qml
841 lines 30 kB history raw
1/*
2 * Copyright (C) 2013 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
17import QtQuick 2.0
18import GSettings 1.0
19import Ubuntu.Application 0.1
20import Ubuntu.Components 0.1
21import Ubuntu.Gestures 0.1
22import LightDM 0.1 as LightDM
23import AccountsService 0.1
24import Powerd 0.1
25import "Dash"
26import "Greeter"
27import "Launcher"
28import "Panel"
29import "Hud"
30import "Components"
31import "Components/Math.js" as MathLocal
32import "Bottombar"
33import "SideStage"
34import "Notifications"
35import Unity.Notifications 1.0 as NotificationBackend
37FocusScope {
38 id: shell
40 // this is only here to select the width / height of the window if not running fullscreen
41 property bool tablet: false
42 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
43 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
45 property real edgeSize: units.gu(2)
46 property url defaultBackground: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
47 property url background
48 readonly property real panelHeight: panel.panelHeight
50 property bool dashShown: dash.shown
51 property bool stageScreenshotsReady: {
52 if (sideStage.shown) {
53 if (mainStage.applications.count > 0) {
54 return mainStage.usingScreenshots && sideStage.usingScreenshots;
55 } else {
56 return sideStage.usingScreenshots;
57 }
58 } else {
59 return mainStage.usingScreenshots;
60 }
61 }
63 property bool showEdgeDemo: false
64 property bool showEdgeDemoInGreeter: showEdgeDemo //AccountsService.getUserProperty("lightdm", "demo-edges")
66 function hideEdgeDemo() {
67 var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
68 AccountsService.setUserProperty(user, "demo-edges", false);
69 shell.showEdgeDemo = false;
70 }
71 function hideEdgeDemoInGreeter() {
72 //AccountsService.setUserProperty("lightdm", "demo-edges", false);
73 shell.showEdgeDemoInGreeter = false;
74 }
76 property ListModel searchHistory: SearchHistoryModel {}
78 property var applicationManager: ApplicationManagerWrapper {}
80 Component.onCompleted: {
81 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
83 applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
85 // FIXME: if application focused before shell starts, shell draws on top of it only.
86 // We should detect already running applications on shell start and bring them to the front.
87 applicationManager.unfocusCurrentApplication();
88 }
90 readonly property bool fullscreenMode: {
91 if (greeter.shown || lockscreen.shown) {
92 return false;
93 } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
94 return mainStage.switchingFromFullscreenToFullscreen;
95 } else if (applicationManager.mainStageFocusedApplication) {
96 return applicationManager.mainStageFocusedApplication.fullscreen;
97 } else {
98 return false;
99 }
100 }
102 Connections {
103 target: applicationManager
104 ignoreUnknownSignals: true
105 onFocusRequested: {
106 // TODO: this should be protected to only unlock for certain applications / certain usecases
107 // potentially only in connection with a notification
108 greeter.hide();
109 shell.activateApplication(desktopFile);
110 }
111 }
113 function activateApplication(desktopFile, argument) {
114 if (applicationManager) {
115 // For newly started applications, as it takes them time to draw their first frame
116 // we add a delay before we hide the animation screenshots to compensate.
117 var addDelay = !applicationManager.getApplicationFromDesktopFile(desktopFile);
119 var application;
120 application = applicationManager.activateApplication(desktopFile, argument);
121 if (application == null) {
122 return;
123 }
124 if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
125 mainStage.activateApplication(desktopFile, addDelay);
126 } else {
127 sideStage.activateApplication(desktopFile, addDelay);
128 }
129 stages.show();
130 }
131 }
133 GSettings {
134 id: backgroundSettings
135 schema.id: "org.gnome.desktop.background"
136 }
137 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
138 onGSettingsPictureChanged: {
139 shell.background = gSettingsPicture
140 }
142 // This is a dummy image that is needed to determine if the picture url
143 // in backgroundSettings points to a valid picture file.
144 // We can't do this with the real background image because setting a
145 // new source in onStatusChanged triggers a binding loop detection
146 // inside Image, which causes it not to render even though a valid source
147 // would be set. We don't mind about this image staying black and just
148 // use it for verification to populate the source for the real
149 // background image.
150 Image {
151 source: shell.background
152 height: 0
153 width: 0
154 sourceSize.height: 0
155 sourceSize.width: 0
156 onStatusChanged: {
157 if (status == Image.Error && source != shell.defaultBackground) {
158 shell.background = defaultBackground
159 }
160 }
161 }
163 VolumeControl {
164 id: volumeControl
165 }
167 Keys.onVolumeUpPressed: volumeControl.volumeUp()
168 Keys.onVolumeDownPressed: volumeControl.volumeDown()
170 Item {
171 id: underlay
172 objectName: "underlay"
173 anchors.fill: parent
175 // Whether the underlay is fully covered by opaque UI elements.
176 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
178 // Whether the user should see the topmost application surface (if there's one at all).
179 property bool applicationSurfaceShouldBeSeen:
180 (mainStage.applications && mainStage.applications.count > 0)
181 && (!stages.fullyHidden && !mainStage.usingScreenshots)
183 // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
184 // through the translucent parts of the shell surface.
185 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
187 CrossFadeImage {
188 id: backgroundImage
189 objectName: "backgroundImage"
191 anchors.fill: parent
192 source: shell.background
193 }
195 Rectangle {
196 anchors.fill: parent
197 color: "black"
198 opacity: dash.disappearingAnimationProgress
199 }
201 Dash {
202 id: dash
203 objectName: "dash"
205 available: !greeter.shown && !lockscreen.shown
206 hides: [stages, launcher, panel.indicators]
207 shown: disappearingAnimationProgress !== 1.0
208 enabled: disappearingAnimationProgress === 0.0 && !leftEdgeDemo.active && !topEdgeDemo.active && !finalEdgeDemo.active
209 // FIXME: unfocus all applications when going back to the dash
210 onEnabledChanged: {
211 if (enabled) {
212 shell.applicationManager.unfocusCurrentApplication()
213 }
214 }
216 anchors {
217 fill: parent
218 topMargin: panel.panelHeight
219 }
221 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
222 opacity: 1.0 - disappearingAnimationProgress
223 property real disappearingAnimationProgress: {
224 if (greeter.shown) {
225 return greeter.showProgress;
226 } else {
227 return stagesOuterContainer.showProgress;
228 }
229 }
231 // FIXME: only necessary because stagesOuterContainer.showProgress and
232 // greeterRevealer.animatedProgress are not animated
233 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
234 }
236 DemoOverlay {
237 id: topEdgeDemo
239 edge: "top"
240 title: i18n.tr("Top edge")
241 text: i18n.tr("Try swiping from the top edge to access the indicators")
242 anchors.fill: dash
243 visible: false
244 available: shell.showEdgeDemo
245 onSkip: shell.hideEdgeDemo()
247 Connections {
248 target: greeter
249 onShownChanged: if (!greeter.shown) topEdgeDemo.show()
250 }
252 Connections {
253 target: panel.indicators
254 onFullyOpenedChanged: if (panel.indicators.fullyOpened) topEdgeDemo.hideNow()
255 }
256 }
258 DemoOverlay {
259 id: leftEdgeDemo
261 edge: "left"
262 title: i18n.tr("Left edge")
263 text: i18n.tr("Swipe from the left to reveal the launcher for quick access to apps")
264 anchors.fill: dash
265 visible: false
266 available: shell.showEdgeDemo
267 onSkip: shell.hideEdgeDemo()
269 Connections {
270 target: bottomEdgeDemo
271 onActiveChanged: if (!bottomEdgeDemo.active) leftEdgeDemo.show()
272 }
274 Connections {
275 target: launcher
276 onStateChanged: if (launcher.state == "visible") leftEdgeDemo.hide()
277 }
278 }
279 }
281 Item {
282 id: stagesOuterContainer
284 width: parent.width
285 height: parent.height
286 x: launcher.progress
287 Behavior on x {SmoothedAnimation{velocity: 600}}
289 property real showProgress:
290 MathLocal.clamp(1 - (x + stages.x) / shell.width, 0, 1)
292 Showable {
293 id: stages
294 objectName: "stages"
296 x: width
298 property bool fullyShown: shown && x == 0 && parent.x == 0
299 property bool fullyHidden: !shown && x == width
300 available: !greeter.shown
301 hides: [launcher, panel.indicators]
302 shown: false
303 opacity: 1.0
304 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
305 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
307 width: parent.width
308 height: parent.height
310 // close the stages when no focused application remains
311 Connections {
312 target: shell.applicationManager
313 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
314 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
315 ignoreUnknownSignals: true
316 }
318 function closeIfNoApplications() {
319 if (!shell.applicationManager.mainStageFocusedApplication
320 && !shell.applicationManager.sideStageFocusedApplication
321 && shell.applicationManager.mainStageApplications.count == 0
322 && shell.applicationManager.sideStageApplications.count == 0) {
323 stages.hide();
324 }
325 }
327 // show the stages when an application gets the focus
328 Connections {
329 target: shell.applicationManager
330 onMainStageFocusedApplicationChanged: {
331 if (shell.applicationManager.mainStageFocusedApplication) {
332 mainStage.show();
333 stages.show();
334 }
335 }
336 onSideStageFocusedApplicationChanged: {
337 if (shell.applicationManager.sideStageFocusedApplication) {
338 sideStage.show();
339 stages.show();
340 }
341 }
342 ignoreUnknownSignals: true
343 }
345 Stage {
346 id: mainStage
348 anchors.fill: parent
349 fullyShown: stages.fullyShown
350 fullyHidden: stages.fullyHidden
351 shouldUseScreenshots: !fullyShown
352 rightEdgeEnabled: !sideStage.enabled
354 applicationManager: shell.applicationManager
355 rightEdgeDraggingAreaWidth: shell.edgeSize
356 normalApplicationY: shell.panelHeight
358 shown: true
359 function show() {
360 stages.show();
361 }
362 function hide() {
363 }
365 // FIXME: workaround the fact that focusing a main stage application
366 // raises its surface on top of all other surfaces including the ones
367 // that belong to side stage applications.
368 onFocusedApplicationChanged: {
369 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
370 shell.applicationManager.focusApplication(sideStage.focusedApplication);
371 }
372 }
373 }
375 SideStage {
376 id: sideStage
378 applicationManager: shell.applicationManager
379 rightEdgeDraggingAreaWidth: shell.edgeSize
380 normalApplicationY: shell.panelHeight
382 onShownChanged: {
383 if (!shown && mainStage.applications.count == 0) {
384 stages.hide();
385 }
386 }
387 // FIXME: when hiding the side stage, refocus the main stage
388 // application so that it goes in front of the side stage
389 // application and hides it
390 onFullyShownChanged: {
391 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
392 shell.applicationManager.focusApplication(mainStage.focusedApplication);
393 }
394 }
396 enabled: shell.width >= units.gu(60)
397 visible: enabled
398 fullyShown: stages.fullyShown && shown
399 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
400 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
402 available: !greeter.shown && !lockscreen.shown && enabled
403 hides: [launcher, panel.indicators]
404 shown: false
405 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
406 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
408 width: units.gu(40)
409 height: stages.height
410 handleExpanded: sideStageRevealer.pressed
411 }
413 Revealer {
414 id: sideStageRevealer
416 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
417 && sideStage.available
418 direction: Qt.RightToLeft
419 openedValue: parent.width - sideStage.width
420 hintDisplacement: units.gu(3)
421 /* The size of the sidestage handle needs to be bigger than the
422 typical size used for edge detection otherwise it is really
423 hard to grab.
424 */
425 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
426 closedValue: parent.width + sideStage.handleSizeCollapsed
427 target: sideStage
428 x: parent.width - width
429 width: sideStage.width + handleSize * 0.7
430 height: sideStage.height
431 orientation: Qt.Horizontal
432 }
434 DragHandle {
435 id: stagesDragHandle
437 anchors.top: parent.top
438 anchors.bottom: parent.bottom
439 anchors.right: parent.left
441 width: shell.edgeSize
442 direction: Direction.Leftwards
443 property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
445 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
446 // Make autocompletion impossible when !haveApps
447 edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
448 }
449 }
450 }
452 Lockscreen {
453 id: lockscreen
454 hides: [launcher, panel.indicators, hud]
455 shown: false
456 enabled: true
457 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
458 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
459 y: panel.panelHeight
460 x: required ? 0 : - width
461 width: parent.width
462 height: parent.height - panel.panelHeight
463 background: shell.background
465 onUnlocked: lockscreen.hide()
466 onCancel: greeter.show()
468 Component.onCompleted: {
469 if (LightDM.Users.count == 1) {
470 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
471 greeter.selected(0)
472 }
473 }
474 }
476 Connections {
477 target: LightDM.Greeter
479 onShowPrompt: {
480 if (LightDM.Users.count == 1) {
481 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
482 if (text == "PIN") {
483 lockscreen.alphaNumeric = false
484 } else {
485 lockscreen.alphaNumeric = true
486 }
487 lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
488 lockscreen.show();
489 }
490 }
491 }
493 Greeter {
494 id: greeter
495 objectName: "greeter"
497 available: true
498 hides: [launcher, panel.indicators, hud]
499 shown: true
501 y: panel.panelHeight
502 width: parent.width
503 height: parent.height - panel.panelHeight
505 dragHandleWidth: shell.edgeSize
507 onShownChanged: {
508 if (shown) {
509 lockscreen.reset();
510 // If there is only one user, we start authenticating with that one here.
511 // If there are more users, the Greeter will handle that
512 if (LightDM.Users.count == 1) {
513 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
514 greeter.selected(0);
515 }
516 greeter.forceActiveFocus();
517 }
518 }
520 onUnlocked: greeter.hide()
521 onSelected: {
522 // Update edge demo hint
523 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
524 shell.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
525 }
527 onLeftTeaserPressedChanged: {
528 if (leftTeaserPressed) {
529 launcher.tease();
530 }
531 }
533 DemoOverlay {
534 id: rightEdgeDemo
536 edge: "right"
537 title: i18n.tr("Right edge")
538 text: i18n.tr("Try swiping from the right edge to unlock the phone")
539 anchors.fill: parent
540 visible: shell.showEdgeDemoInGreeter
541 onSkip: {
542 shell.hideEdgeDemoInGreeter()
543 shell.hideEdgeDemo()
544 }
546 Connections {
547 target: greeter
549 function hide() {
550 if (rightEdgeDemo.active) {
551 rightEdgeDemo.hide()
552 shell.hideEdgeDemoInGreeter()
553 }
554 }
556 onUnlocked: hide()
557 onShownChanged: if (!greeter.shown) hide()
558 }
559 }
560 }
562 InputFilterArea {
563 anchors.fill: parent
564 blockInput: greeter.shown || lockscreen.shown
565 }
567 Connections {
568 id: powerConnection
569 target: Powerd
571 property var previousMainApp: null
572 property var previousSideApp: null
574 function setFocused(focused) {
575 if (!focused) {
576 // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
577 // the stage was actually shown
578 if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
579 if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
580 applicationManager.unfocusCurrentApplication();
581 } else {
582 if (powerConnection.previousMainApp) {
583 applicationManager.focusApplication(powerConnection.previousMainApp);
584 powerConnection.previousMainApp = null;
585 }
586 if (powerConnection.previousSideApp) {
587 applicationManager.focusApplication(powerConnection.previousSideApp);
588 powerConnection.previousSideApp = null;
589 }
590 }
591 }
593 onDisplayPowerStateChange: {
594 // We ignore any display-off signals when the proximity sensor
595 // is active. This usually indicates something like a phone call.
596 if (status == Powerd.Off && (flags & Powerd.UseProximity) == 0) {
597 powerConnection.setFocused(false);
598 greeter.show();
599 } else if (status == Powerd.On) {
600 powerConnection.setFocused(true);
601 }
602 }
603 }
605 Item {
606 id: overlay
608 anchors.fill: parent
610 Panel {
611 id: panel
612 anchors.fill: parent //because this draws indicator menus
613 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
614 indicators {
615 hides: [launcher]
616 available: !rightEdgeDemo.active && !leftEdgeDemo.active && !finalEdgeDemo.active
617 }
618 fullscreenMode: shell.fullscreenMode
619 searchVisible: !greeter.shown && !lockscreen.shown
621 InputFilterArea {
622 anchors.fill: parent
623 blockInput: panel.indicators.shown
624 }
626 DemoOverlay {
627 id: bottomEdgeDemo
629 edge: "bottom"
630 title: i18n.tr("Close")
631 text: i18n.tr("Swipe up again to close the settings screen")
632 anchors.fill: panel.indicators
633 visible: false
634 available: shell.showEdgeDemo
635 onSkip: shell.hideEdgeDemo()
637 Connections {
638 target: panel.indicators
639 onFullyOpenedChanged: if (panel.indicators.fullyOpened) bottomEdgeDemo.show()
640 onPartiallyOpenedChanged: if (!panel.indicators.partiallyOpened && !panel.indicators.fullyOpened) bottomEdgeDemo.hideNow()
641 }
642 }
643 }
645 Hud {
646 id: hud
648 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
649 height: parent.height
651 available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && !topEdgeDemo.active
652 shown: false
653 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
654 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
656 Connections {
657 target: shell.applicationManager
658 onMainStageFocusedApplicationChanged: hud.hide()
659 onSideStageFocusedApplicationChanged: hud.hide()
660 }
662 InputFilterArea {
663 anchors.fill: parent
664 blockInput: hud.shown
665 }
666 }
668 Revealer {
669 id: hudRevealer
671 enabled: hud.shown
672 width: hud.width
673 anchors.left: hud.left
674 height: parent.height
675 target: hud.revealerTarget
676 closedValue: height
677 openedValue: 0
678 direction: Qt.RightToLeft
679 orientation: Qt.Vertical
680 handleSize: hud.handleHeight
681 onCloseClicked: target.hide()
682 }
684 Bottombar {
685 theHud: hud
686 anchors.fill: parent
687 enabled: !panel.indicators.shown
688 applicationIsOnForeground: applicationManager.mainStageFocusedApplication
689 || applicationManager.sideStageFocusedApplication
690 }
692 InputFilterArea {
693 blockInput: launcher.shown
694 anchors {
695 top: parent.top
696 bottom: parent.bottom
697 left: parent.left
698 }
699 width: launcher.width
700 }
702 Launcher {
703 id: launcher
705 anchors.top: parent.top
706 anchors.bottom: parent.bottom
707 width: parent.width
708 dragAreaWidth: shell.edgeSize
709 available: (!greeter.shown || greeter.narrowMode) && !rightEdgeDemo.active && !topEdgeDemo.active && !bottomEdgeDemo.active && !finalEdgeDemo.active
710 onDashItemSelected: {
711 greeter.hide()
712 // Animate if moving between application and dash
713 if (!stages.shown) {
714 dash.setCurrentScope("home.scope", true, false)
715 } else {
716 dash.setCurrentScope("home.scope", false, false)
717 }
718 stages.hide();
719 }
720 onDash: {
721 if (stages.shown) {
722 dash.setCurrentScope("applications.scope", true, false)
723 stages.hide();
724 launcher.hide();
725 }
726 }
727 onLauncherApplicationSelected:{
728 greeter.hide()
729 shell.activateApplication(desktopFile)
730 }
731 onShownChanged: {
732 if (shown) {
733 panel.indicators.hide()
734 hud.hide()
735 }
736 }
737 }
739 Notifications {
740 id: notifications
742 model: NotificationBackend.Model
743 anchors {
744 top: parent.top
745 right: parent.right
746 bottom: parent.bottom
747 leftMargin: units.gu(1)
748 rightMargin: units.gu(1)
749 topMargin: panel.panelHeight + units.gu(1)
750 }
751 states: [
752 State {
753 name: "narrow"
754 when: overlay.width <= units.gu(60)
755 AnchorChanges { target: notifications; anchors.left: parent.left }
756 },
757 State {
758 name: "wide"
759 when: overlay.width > units.gu(60)
760 AnchorChanges { target: notifications; anchors.left: undefined }
761 PropertyChanges { target: notifications; width: units.gu(38) }
762 }
763 ]
764 }
765 }
767 DemoOverlay {
768 id: finalEdgeDemo
770 edge: "none"
771 title: i18n.tr("Well done")
772 text: i18n.tr("You have now mastered the edge gestures and can start using the phone")
773 skipText: i18n.tr("Finish")
774 anchors.fill: overlay
775 visible: false
776 available: shell.showEdgeDemo
777 onSkip: shell.hideEdgeDemo()
779 Connections {
780 target: leftEdgeDemo
781 onShownChanged: {
782 if (leftEdgeDemo.active && !leftEdgeDemo.shown) {
783 finalEdgeDemo.show();
784 launcher.hide();
785 }
786 }
787 }
788 }
790 focus: true
792 InputFilterArea {
793 anchors {
794 top: parent.top
795 bottom: parent.bottom
796 left: parent.left
797 }
798 width: shell.edgeSize
799 blockInput: true
800 }
802 InputFilterArea {
803 anchors {
804 top: parent.top
805 bottom: parent.bottom
806 right: parent.right
807 }
808 width: shell.edgeSize
809 blockInput: true
810 }
812 Binding {
813 target: i18n
814 property: "domain"
815 value: "unity8"
816 }
818 //FIXME: This should be handled in the input stack, keyboard shouldnt propagate
819 MouseArea {
820 anchors.bottom: parent.bottom
821 anchors.left: parent.left
822 anchors.right: parent.right
823 height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0
825 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
826 }
828 Label {
829 anchors.centerIn: parent
830 visible: applicationManager.fake
831 text: "EARLY ALPHA\nNOT READY FOR USE"
832 color: "lightgrey"
833 opacity: 0.2
834 font.weight: Font.Black
835 horizontalAlignment: Text.AlignHCenter
836 verticalAlignment: Text.AlignVCenter
837 fontSizeMode: Text.Fit
838 rotation: -45
839 scale: Math.min(parent.width, parent.height) / width
840 }