on 577fe5b help sign in
unity8/Shell.qml
840 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 Unity.Launcher 0.1
23import LightDM 0.1 as LightDM
24import AccountsService 0.1
25import Powerd 0.1
26import "Dash"
27import "Greeter"
28import "Launcher"
29import "Panel"
30import "Hud"
31import "Components"
32import "Components/Math.js" as MathLocal
33import "Bottombar"
34import "SideStage"
35import "Notifications"
36import Unity.Notifications 1.0 as NotificationBackend
38FocusScope {
39 id: shell
41 // this is only here to select the width / height of the window if not running fullscreen
42 property bool tablet: false
43 width: tablet ? units.gu(160) : applicationArguments.hasGeometry() ? applicationArguments.width() : units.gu(40)
44 height: tablet ? units.gu(100) : applicationArguments.hasGeometry() ? applicationArguments.height() : units.gu(71)
46 property real edgeSize: units.gu(2)
47 property url defaultBackground: shell.width >= units.gu(60) ? "graphics/tablet_background.jpg" : "graphics/phone_background.jpg"
48 property url background
49 readonly property real panelHeight: panel.panelHeight
51 property bool dashShown: dash.shown
52 property bool stageScreenshotsReady: {
53 if (sideStage.shown) {
54 if (mainStage.applications.count > 0) {
55 return mainStage.usingScreenshots && sideStage.usingScreenshots;
56 } else {
57 return sideStage.usingScreenshots;
58 }
59 } else {
60 return mainStage.usingScreenshots;
61 }
62 }
64 property bool showEdgeDemo: false
65 property bool showEdgeDemoInGreeter: showEdgeDemo //AccountsService.getUserProperty("lightdm", "demo-edges")
67 function hideEdgeDemo() {
68 var user = LightDM.Users.data(greeter.currentIndex, LightDM.UserRoles.NameRole);
69 AccountsService.setUserProperty(user, "demo-edges", false);
70 shell.showEdgeDemo = false;
71 }
72 function hideEdgeDemoInGreeter() {
73 //AccountsService.setUserProperty("lightdm", "demo-edges", false);
74 shell.showEdgeDemoInGreeter = false;
75 }
77 property ListModel searchHistory: SearchHistoryModel {}
79 property var applicationManager: ApplicationManagerWrapper {}
81 Component.onCompleted: {
82 Theme.name = "Ubuntu.Components.Themes.SuruGradient"
84 applicationManager.sideStageEnabled = Qt.binding(function() { return sideStage.enabled })
86 // FIXME: if application focused before shell starts, shell draws on top of it only.
87 // We should detect already running applications on shell start and bring them to the front.
88 applicationManager.unfocusCurrentApplication();
89 }
91 readonly property bool fullscreenMode: {
92 if (greeter.shown || lockscreen.shown) {
93 return false;
94 } else if (mainStage.usingScreenshots) { // Window Manager animating so want to re-evaluate fullscreen mode
95 return mainStage.switchingFromFullscreenToFullscreen;
96 } else if (applicationManager.mainStageFocusedApplication) {
97 return applicationManager.mainStageFocusedApplication.fullscreen;
98 } else {
99 return false;
100 }
101 }
103 Connections {
104 target: applicationManager
105 ignoreUnknownSignals: true
106 onFocusRequested: {
107 // TODO: this should be protected to only unlock for certain applications / certain usecases
108 // potentially only in connection with a notification
109 greeter.hide();
110 shell.activateApplication(desktopFile);
111 }
112 }
114 function activateApplication(desktopFile, argument) {
115 if (applicationManager) {
116 // For newly started applications, as it takes them time to draw their first frame
117 // we add a delay before we hide the animation screenshots to compensate.
118 var addDelay = !applicationManager.getApplicationFromDesktopFile(desktopFile);
120 var application;
121 application = applicationManager.activateApplication(desktopFile, argument);
122 if (application == null) {
123 return;
124 }
125 if (application.stage == ApplicationInfo.MainStage || !sideStage.enabled) {
126 mainStage.activateApplication(desktopFile, addDelay);
127 } else {
128 sideStage.activateApplication(desktopFile, addDelay);
129 }
130 stages.show();
131 }
132 }
134 GSettings {
135 id: backgroundSettings
136 schema.id: "org.gnome.desktop.background"
137 }
138 property url gSettingsPicture: backgroundSettings.pictureUri != undefined && backgroundSettings.pictureUri.length > 0 ? backgroundSettings.pictureUri : shell.defaultBackground
139 onGSettingsPictureChanged: {
140 shell.background = gSettingsPicture
141 }
143 // This is a dummy image that is needed to determine if the picture url
144 // in backgroundSettings points to a valid picture file.
145 // We can't do this with the real background image because setting a
146 // new source in onStatusChanged triggers a binding loop detection
147 // inside Image, which causes it not to render even though a valid source
148 // would be set. We don't mind about this image staying black and just
149 // use it for verification to populate the source for the real
150 // background image.
151 Image {
152 source: shell.background
153 height: 0
154 width: 0
155 sourceSize.height: 0
156 sourceSize.width: 0
157 onStatusChanged: {
158 if (status == Image.Error && source != shell.defaultBackground) {
159 shell.background = defaultBackground
160 }
161 }
162 }
164 VolumeControl {
165 id: volumeControl
166 }
168 Keys.onVolumeUpPressed: volumeControl.volumeUp()
169 Keys.onVolumeDownPressed: volumeControl.volumeDown()
171 Item {
172 id: underlay
173 objectName: "underlay"
174 anchors.fill: parent
176 // Whether the underlay is fully covered by opaque UI elements.
177 property bool fullyCovered: panel.indicators.fullyOpened && shell.width <= panel.indicatorsMenuWidth
179 // Whether the user should see the topmost application surface (if there's one at all).
180 property bool applicationSurfaceShouldBeSeen:
181 (mainStage.applications && mainStage.applications.count > 0)
182 && (!stages.fullyHidden && !mainStage.usingScreenshots)
184 // NB! Application surfaces are stacked behing the shell one. So they can only be seen by the user
185 // through the translucent parts of the shell surface.
186 visible: !fullyCovered && !applicationSurfaceShouldBeSeen
188 CrossFadeImage {
189 id: backgroundImage
190 objectName: "backgroundImage"
192 anchors.fill: parent
193 source: shell.background
194 }
196 Rectangle {
197 anchors.fill: parent
198 color: "black"
199 opacity: dash.disappearingAnimationProgress
200 }
202 Dash {
203 id: dash
204 objectName: "dash"
206 available: !greeter.shown && !lockscreen.shown
207 hides: [stages, launcher, panel.indicators]
208 shown: disappearingAnimationProgress !== 1.0
209 enabled: disappearingAnimationProgress === 0.0 && !leftEdgeDemo.active && !topEdgeDemo.active && !finalEdgeDemo.active
210 // FIXME: unfocus all applications when going back to the dash
211 onEnabledChanged: {
212 if (enabled) {
213 shell.applicationManager.unfocusCurrentApplication()
214 }
215 }
217 anchors {
218 fill: parent
219 topMargin: panel.panelHeight
220 }
222 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
223 opacity: 1.0 - disappearingAnimationProgress
224 property real disappearingAnimationProgress: {
225 if (greeter.shown) {
226 return greeter.showProgress;
227 } else {
228 return stagesOuterContainer.showProgress;
229 }
230 }
232 // FIXME: only necessary because stagesOuterContainer.showProgress and
233 // greeterRevealer.animatedProgress are not animated
234 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
235 }
237 DemoOverlay {
238 id: topEdgeDemo
240 edge: "top"
241 title: i18n.tr("Top edge")
242 text: i18n.tr("Try swiping from the top edge to access the indicators")
243 anchors.fill: dash
244 visible: false
245 enabled: shell.showEdgeDemo
246 onSkip: shell.hideEdgeDemo()
248 Connections {
249 target: greeter
250 onShownChanged: if (!greeter.shown) topEdgeDemo.visible = true
251 }
253 Connections {
254 target: panel.indicators
255 onFullyOpenedChanged: if (panel.indicators.fullyOpened) topEdgeDemo.enabled = false
256 }
257 }
259 DemoOverlay {
260 id: leftEdgeDemo
262 edge: "left"
263 title: i18n.tr("Left edge")
264 text: i18n.tr("Swipe from the left to reveal the launcher for quick access to apps")
265 anchors.fill: dash
266 visible: false
267 enabled: shell.showEdgeDemo
268 onSkip: shell.hideEdgeDemo()
270 Connections {
271 target: bottomEdgeDemo
272 onActiveChanged: if (!bottomEdgeDemo.active) leftEdgeDemo.visible = true
273 }
275 Connections {
276 target: launcher
277 onProgressChanged: if (launcher.progress >= 1.0) leftEdgeDemo.enabled = false
278 }
279 }
280 }
282 Item {
283 id: stagesOuterContainer
285 width: parent.width
286 height: parent.height
287 x: launcher.progress
288 Behavior on x {SmoothedAnimation{velocity: 600}}
290 property real showProgress:
291 MathLocal.clamp(1 - (x + stages.x) / shell.width, 0, 1)
293 Showable {
294 id: stages
295 objectName: "stages"
297 x: width
299 property bool fullyShown: shown && x == 0 && parent.x == 0
300 property bool fullyHidden: !shown && x == width
301 available: !greeter.shown
302 hides: [launcher, panel.indicators]
303 shown: false
304 opacity: 1.0
305 showAnimation: StandardAnimation { property: "x"; duration: 350; to: 0; easing.type: Easing.OutCubic }
306 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: width; easing.type: Easing.OutCubic }
308 width: parent.width
309 height: parent.height
311 // close the stages when no focused application remains
312 Connections {
313 target: shell.applicationManager
314 onMainStageFocusedApplicationChanged: stages.closeIfNoApplications()
315 onSideStageFocusedApplicationChanged: stages.closeIfNoApplications()
316 ignoreUnknownSignals: true
317 }
319 function closeIfNoApplications() {
320 if (!shell.applicationManager.mainStageFocusedApplication
321 && !shell.applicationManager.sideStageFocusedApplication
322 && shell.applicationManager.mainStageApplications.count == 0
323 && shell.applicationManager.sideStageApplications.count == 0) {
324 stages.hide();
325 }
326 }
328 // show the stages when an application gets the focus
329 Connections {
330 target: shell.applicationManager
331 onMainStageFocusedApplicationChanged: {
332 if (shell.applicationManager.mainStageFocusedApplication) {
333 mainStage.show();
334 stages.show();
335 }
336 }
337 onSideStageFocusedApplicationChanged: {
338 if (shell.applicationManager.sideStageFocusedApplication) {
339 sideStage.show();
340 stages.show();
341 }
342 }
343 ignoreUnknownSignals: true
344 }
346 Stage {
347 id: mainStage
349 anchors.fill: parent
350 fullyShown: stages.fullyShown
351 fullyHidden: stages.fullyHidden
352 shouldUseScreenshots: !fullyShown
353 rightEdgeEnabled: !sideStage.enabled
355 applicationManager: shell.applicationManager
356 rightEdgeDraggingAreaWidth: shell.edgeSize
357 normalApplicationY: shell.panelHeight
359 shown: true
360 function show() {
361 stages.show();
362 }
363 function hide() {
364 }
366 // FIXME: workaround the fact that focusing a main stage application
367 // raises its surface on top of all other surfaces including the ones
368 // that belong to side stage applications.
369 onFocusedApplicationChanged: {
370 if (focusedApplication && sideStage.focusedApplication && sideStage.fullyShown) {
371 shell.applicationManager.focusApplication(sideStage.focusedApplication);
372 }
373 }
374 }
376 SideStage {
377 id: sideStage
379 applicationManager: shell.applicationManager
380 rightEdgeDraggingAreaWidth: shell.edgeSize
381 normalApplicationY: shell.panelHeight
383 onShownChanged: {
384 if (!shown && mainStage.applications.count == 0) {
385 stages.hide();
386 }
387 }
388 // FIXME: when hiding the side stage, refocus the main stage
389 // application so that it goes in front of the side stage
390 // application and hides it
391 onFullyShownChanged: {
392 if (!fullyShown && stages.fullyShown && sideStage.focusedApplication != null) {
393 shell.applicationManager.focusApplication(mainStage.focusedApplication);
394 }
395 }
397 enabled: shell.width >= units.gu(60)
398 visible: enabled
399 fullyShown: stages.fullyShown && shown
400 && sideStage[sideStageRevealer.boundProperty] == sideStageRevealer.openedValue
401 shouldUseScreenshots: !fullyShown || mainStage.usingScreenshots || sideStageRevealer.pressed
403 available: !greeter.shown && !lockscreen.shown && enabled
404 hides: [launcher, panel.indicators]
405 shown: false
406 showAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.openedValue; easing.type: Easing.OutQuint }
407 hideAnimation: StandardAnimation { property: "x"; duration: 350; to: sideStageRevealer.closedValue; easing.type: Easing.OutQuint }
409 width: units.gu(40)
410 height: stages.height
411 handleExpanded: sideStageRevealer.pressed
412 }
414 Revealer {
415 id: sideStageRevealer
417 enabled: mainStage.applications.count > 0 && sideStage.applications.count > 0
418 && sideStage.available
419 direction: Qt.RightToLeft
420 openedValue: parent.width - sideStage.width
421 hintDisplacement: units.gu(3)
422 /* The size of the sidestage handle needs to be bigger than the
423 typical size used for edge detection otherwise it is really
424 hard to grab.
425 */
426 handleSize: sideStage.shown ? units.gu(4) : shell.edgeSize
427 closedValue: parent.width + sideStage.handleSizeCollapsed
428 target: sideStage
429 x: parent.width - width
430 width: sideStage.width + handleSize * 0.7
431 height: sideStage.height
432 orientation: Qt.Horizontal
433 }
435 DragHandle {
436 id: stagesDragHandle
438 anchors.top: parent.top
439 anchors.bottom: parent.bottom
440 anchors.right: parent.left
442 width: shell.edgeSize
443 direction: Direction.Leftwards
444 property bool haveApps: mainStage.applications.count > 0 || sideStage.applications.count > 0
446 maxTotalDragDistance: haveApps ? parent.width : parent.width * 0.7
447 // Make autocompletion impossible when !haveApps
448 edgeDragEvaluator.minDragDistance: haveApps ? maxTotalDragDistance * 0.1 : Number.MAX_VALUE
449 }
450 }
451 }
453 Lockscreen {
454 id: lockscreen
455 hides: [launcher, panel.indicators, hud]
456 shown: false
457 enabled: true
458 showAnimation: StandardAnimation { property: "opacity"; to: 1 }
459 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
460 y: panel.panelHeight
461 x: required ? 0 : - width
462 width: parent.width
463 height: parent.height - panel.panelHeight
464 background: shell.background
466 onUnlocked: lockscreen.hide()
467 onCancel: greeter.show()
469 Component.onCompleted: {
470 if (LightDM.Users.count == 1) {
471 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole))
472 greeter.selected(0)
473 }
474 }
475 }
477 Connections {
478 target: LightDM.Greeter
480 onShowPrompt: {
481 if (LightDM.Users.count == 1) {
482 // TODO: There's no better way for now to determine if its a PIN or a passphrase.
483 if (text == "PIN") {
484 lockscreen.alphaNumeric = false
485 } else {
486 lockscreen.alphaNumeric = true
487 }
488 lockscreen.placeholderText = i18n.tr("Please enter %1").arg(text);
489 lockscreen.show();
490 }
491 }
492 }
494 Greeter {
495 id: greeter
496 objectName: "greeter"
498 available: true
499 hides: [launcher, panel.indicators, hud]
500 shown: true
502 y: panel.panelHeight
503 width: parent.width
504 height: parent.height - panel.panelHeight
506 dragHandleWidth: shell.edgeSize
508 onShownChanged: {
509 if (shown) {
510 lockscreen.reset();
511 // If there is only one user, we start authenticating with that one here.
512 // If there are more users, the Greeter will handle that
513 if (LightDM.Users.count == 1) {
514 LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
515 greeter.selected(0);
516 }
517 greeter.forceActiveFocus();
518 }
519 }
521 onUnlocked: greeter.hide()
522 onSelected: {
523 // Update edge demo hint
524 var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole)
525 shell.showEdgeDemo = AccountsService.getUserProperty(user, "demo-edges")
526 // Update launcher items for new user
527 LauncherModel.setUser(user);
528 }
530 onLeftTeaserPressedChanged: {
531 if (leftTeaserPressed) {
532 launcher.tease();
533 }
534 }
536 DemoOverlay {
537 id: rightEdgeDemo
539 edge: "right"
540 title: i18n.tr("Right edge")
541 text: i18n.tr("Try swiping from the right edge to unlock the phone")
542 anchors.fill: parent
543 visible: shell.showEdgeDemoInGreeter
544 onSkip: {
545 shell.hideEdgeDemoInGreeter()
546 shell.hideEdgeDemo()
547 }
549 Connections {
550 target: greeter
552 function hide() {
553 if (rightEdgeDemo.active) {
554 rightEdgeDemo.enabled = false
555 shell.hideEdgeDemoInGreeter()
556 }
557 }
559 onUnlocked: hide()
560 onShownChanged: if (!greeter.shown) hide()
561 }
562 }
563 }
565 InputFilterArea {
566 anchors.fill: parent
567 blockInput: greeter.shown || lockscreen.shown
568 }
570 Connections {
571 id: powerConnection
572 target: Powerd
574 property var previousMainApp: null
575 property var previousSideApp: null
577 function setFocused(focused) {
578 if (!focused) {
579 // FIXME: *FocusedApplication are not updated when unfocused, hence the need to check whether
580 // the stage was actually shown
581 if (mainStage.fullyShown) powerConnection.previousMainApp = applicationManager.mainStageFocusedApplication;
582 if (sideStage.fullyShown) powerConnection.previousSideApp = applicationManager.sideStageFocusedApplication;
583 applicationManager.unfocusCurrentApplication();
584 } else {
585 if (powerConnection.previousMainApp) {
586 applicationManager.focusApplication(powerConnection.previousMainApp);
587 powerConnection.previousMainApp = null;
588 }
589 if (powerConnection.previousSideApp) {
590 applicationManager.focusApplication(powerConnection.previousSideApp);
591 powerConnection.previousSideApp = null;
592 }
593 }
594 }
596 onPowerStateChange: {
597 if (state == 0) { // suspend
598 powerConnection.setFocused(false);
599 greeter.show();
600 } else if (state == 1) { // active
601 powerConnection.setFocused(true);
602 }
603 }
604 }
606 Item {
607 id: overlay
609 anchors.fill: parent
611 Panel {
612 id: panel
613 anchors.fill: parent //because this draws indicator menus
614 indicatorsMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
615 indicators {
616 hides: [launcher]
617 available: !rightEdgeDemo.active && !leftEdgeDemo.active && !finalEdgeDemo.active
618 }
619 fullscreenMode: shell.fullscreenMode
620 searchVisible: !greeter.shown && !lockscreen.shown
622 InputFilterArea {
623 anchors.fill: parent
624 blockInput: panel.indicators.shown
625 }
627 DemoOverlay {
628 id: bottomEdgeDemo
630 edge: "bottom"
631 title: i18n.tr("Close")
632 text: i18n.tr("Swipe up again to close the settings screen")
633 anchors.fill: panel.indicators
634 visible: false
635 enabled: shell.showEdgeDemo
636 onSkip: shell.hideEdgeDemo()
638 Connections {
639 target: panel.indicators
640 onFullyOpenedChanged: if (panel.indicators.fullyOpened) bottomEdgeDemo.visible = true
641 onPartiallyOpenedChanged: if (!panel.indicators.partiallyOpened && !panel.indicators.fullyOpened) bottomEdgeDemo.enabled = false
642 }
643 }
644 }
646 Hud {
647 id: hud
649 width: parent.width > units.gu(60) ? units.gu(40) : parent.width
650 height: parent.height
652 available: !greeter.shown && !panel.indicators.shown && !lockscreen.shown && !topEdgeDemo.active
653 shown: false
654 showAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: 0; easing.type: Easing.Linear }
655 hideAnimation: StandardAnimation { property: "y"; duration: hud.showableAnimationDuration; to: hudRevealer.closedValue; easing.type: Easing.Linear }
657 Connections {
658 target: shell.applicationManager
659 onMainStageFocusedApplicationChanged: hud.hide()
660 onSideStageFocusedApplicationChanged: hud.hide()
661 }
663 InputFilterArea {
664 anchors.fill: parent
665 blockInput: hud.shown
666 }
667 }
669 Revealer {
670 id: hudRevealer
672 enabled: hud.shown
673 width: hud.width
674 anchors.left: hud.left
675 height: parent.height
676 target: hud.revealerTarget
677 closedValue: height
678 openedValue: 0
679 direction: Qt.RightToLeft
680 orientation: Qt.Vertical
681 handleSize: hud.handleHeight
682 onCloseClicked: target.hide()
683 }
685 Bottombar {
686 theHud: hud
687 anchors.fill: parent
688 enabled: !panel.indicators.shown
689 applicationIsOnForeground: applicationManager.mainStageFocusedApplication
690 || applicationManager.sideStageFocusedApplication
691 }
693 InputFilterArea {
694 blockInput: launcher.shown
695 anchors {
696 top: parent.top
697 bottom: parent.bottom
698 left: parent.left
699 }
700 width: launcher.width
701 }
703 Launcher {
704 id: launcher
706 anchors.top: parent.top
707 anchors.bottom: parent.bottom
708 width: parent.width
709 dragAreaWidth: shell.edgeSize
710 available: (!greeter.shown || greeter.narrowMode) && !rightEdgeDemo.active && !topEdgeDemo.active && !bottomEdgeDemo.active && !finalEdgeDemo.active
711 onDashItemSelected: {
712 greeter.hide()
713 // Animate if moving between application and dash
714 if (!stages.shown) {
715 dash.setCurrentScope("home.scope", true, false)
716 } else {
717 dash.setCurrentScope("home.scope", false, false)
718 }
719 stages.hide();
720 }
721 onDash: {
722 if (stages.shown) {
723 dash.setCurrentScope("applications.scope", true, false)
724 stages.hide();
725 launcher.hide();
726 }
727 }
728 onLauncherApplicationSelected:{
729 greeter.hide()
730 shell.activateApplication(desktopFile)
731 }
732 onShownChanged: {
733 if (shown) {
734 panel.indicators.hide()
735 hud.hide()
736 }
737 }
738 }
740 Notifications {
741 id: notifications
743 model: NotificationBackend.Model
744 anchors {
745 top: parent.top
746 right: parent.right
747 bottom: parent.bottom
748 leftMargin: units.gu(1)
749 rightMargin: units.gu(1)
750 topMargin: panel.panelHeight + units.gu(1)
751 }
752 states: [
753 State {
754 name: "narrow"
755 when: overlay.width <= units.gu(60)
756 AnchorChanges { target: notifications; anchors.left: parent.left }
757 },
758 State {
759 name: "wide"
760 when: overlay.width > units.gu(60)
761 AnchorChanges { target: notifications; anchors.left: undefined }
762 PropertyChanges { target: notifications; width: units.gu(38) }
763 }
764 ]
765 }
766 }
768 DemoOverlay {
769 id: finalEdgeDemo
771 edge: "none"
772 title: i18n.tr("Well done")
773 text: i18n.tr("You have now mastered the edge gestures and can start using the phone")
774 skipText: i18n.tr("Finish")
775 anchors.fill: overlay
776 visible: false
777 enabled: shell.showEdgeDemo
778 onSkip: {
779 launcher.hide();
780 shell.hideEdgeDemo();
781 }
783 Connections {
784 target: leftEdgeDemo
785 onActiveChanged: if (!leftEdgeDemo.active) finalEdgeDemo.visible = true
786 }
787 }
789 focus: true
791 InputFilterArea {
792 anchors {
793 top: parent.top
794 bottom: parent.bottom
795 left: parent.left
796 }
797 width: shell.edgeSize
798 blockInput: true
799 }
801 InputFilterArea {
802 anchors {
803 top: parent.top
804 bottom: parent.bottom
805 right: parent.right
806 }
807 width: shell.edgeSize
808 blockInput: true
809 }
811 Binding {
812 target: i18n
813 property: "domain"
814 value: "unity8"
815 }
817 //FIXME: This should be handled in the input stack, keyboard shouldnt propagate
818 MouseArea {
819 anchors.bottom: parent.bottom
820 anchors.left: parent.left
821 anchors.right: parent.right
822 height: shell.applicationManager ? shell.applicationManager.keyboardHeight : 0
824 enabled: shell.applicationManager && shell.applicationManager.keyboardVisible
825 }
827 Label {
828 anchors.centerIn: parent
829 visible: applicationManager.fake
830 text: "EARLY ALPHA\nNOT READY FOR USE"
831 color: "lightgrey"
832 opacity: 0.2
833 font.weight: Font.Black
834 horizontalAlignment: Text.AlignHCenter
835 verticalAlignment: Text.AlignVCenter
836 fontSizeMode: Text.Fit
837 rotation: -45
838 scale: Math.min(parent.width, parent.height) / width
839 }