on xenial help sign in
First pass at new greeter teasing
c868dfcMichael Terry
qml/Greeter/Greeter.qml+99−40
@@ -31,7 +31,7 @@ Showable {
31 property real showProgress: MathUtils.clamp((width + x) / width, 0, 1)
31 property real showProgress: MathUtils.clamp((width + x) / width, 0, 1)
32
32
33 showAnimation: StandardAnimation { property: "x"; to: 0 }
33 showAnimation: StandardAnimation { property: "x"; to: 0 }
34− hideAnimation: StandardAnimation { property: "x"; to: -width }
34+ hideAnimation: __leftHideAnimation
35
35
36 property alias dragHandleWidth: dragHandle.width
36 property alias dragHandleWidth: dragHandle.width
37 property alias model: greeterContentLoader.model
37 property alias model: greeterContentLoader.model
@@ -40,20 +40,24 @@ Showable {
40 readonly property bool narrowMode: !multiUser && height > width
40 readonly property bool narrowMode: !multiUser && height > width
41 readonly property bool multiUser: LightDM.Users.count > 1
41 readonly property bool multiUser: LightDM.Users.count > 1
42
42
43− readonly property bool leftTeaserPressed: greeterContentLoader.status == Loader.Ready &&
44− greeterContentLoader.item.leftTeaserPressed
45− readonly property bool rightTeaserPressed: greeterContentLoader.status == Loader.Ready &&
46− greeterContentLoader.item.rightTeaserPressed
47−
48 readonly property int currentIndex: greeterContentLoader.currentIndex
43 readonly property int currentIndex: greeterContentLoader.currentIndex
49
44
45+ property var __leftHideAnimation: StandardAnimation { property: "x"; to: -width }
46+ property var __rightHideAnimation: StandardAnimation { property: "x"; to: width }
47+
50 signal selected(int uid)
48 signal selected(int uid)
51 signal unlocked(int uid)
49 signal unlocked(int uid)
50+ signal tease()
52
51
53− onRightTeaserPressedChanged: {
52+ function hideRight() {
54− if (rightTeaserPressed && (!locked || narrowMode) && x == 0) {
53+ hideAnimation = __rightHideAnimation
55− teasingTimer.start();
54+ hide()
56− }
55+ }
56+
57+ Connections {
58+ target: __rightHideAnimation
59+ // Reset hide animation to default once we're finished with it
60+ onRunningChanged: if (!__rightHideAnimation.running) greeter.hideAnimation = __leftHideAnimation
57 }
61 }
58
62
59 Loader {
63 Loader {
@@ -82,45 +86,100 @@ Showable {
82 }
86 }
83 }
87 }
84
88
85− Timer {
89+ onTease: showLabelAnimation.start()
86− id: teasingTimer
90+
87− interval: 200
91+ UbuntuShape {
92+ id: swipeHint
93+ color: "#222222"
94+
95+ visible: greeter.shown
96+ width: swipeLabel.width + units.gu(2)
97+ height: swipeLabel.height + units.gu(2)
98+ property real baseOpacity: 0.6
99+ opacity: 0.0
100+
101+ anchors.horizontalCenter: parent.horizontalCenter
102+ anchors.bottom: parent.bottom
103+ anchors.bottomMargin: units.gu(5)
104+
105+ Label {
106+ id: swipeLabel
107+ anchors.centerIn: parent
108+ text: i18n.tr("Swipe to unlock")
109+ color: "white"
110+ }
88 }
111 }
89
112
90− states: [
113+ SequentialAnimation {
91− State {
114+ id: showLabelAnimation
92− name: "teasing"
115+
93− when: teasingTimer.running
116+ PropertyAnimation {
94− PropertyChanges {
95− target: greeter
117+ target: swipeHint
96− x: -dragHandle.hintDisplacement
118+ property: "opacity"
97− }
119+ from: 0.0
120+ to: swipeHint.baseOpacity
121+ duration: UbuntuAnimation.SlowDuration
98 }
122 }
99− ]
123+ PropertyAnimation {
100− transitions: [
101− Transition {
102− from: "*"
103− to: "*"
104− NumberAnimation {
105− target: greeter
106− property: "x"
107− duration: 300
124+ duration: 10000
108− easing.type: Easing.OutCubic
109− }
110 }
125 }
111− ]
126+ PropertyAnimation {
127+ target: swipeHint
128+ property: "opacity"
129+ from: swipeHint.baseOpacity
130+ to: 0.0
131+ duration: UbuntuAnimation.SlowDuration
132+ }
133+ }
112
134
113− DragHandle {
135+ // Bi-directional revealer
136+ DraggingArea {
114 id: dragHandle
137 id: dragHandle
138+ anchors.fill: greeterContentLoader
139+ enabled: greeter.narrowMode || !greeter.locked
140+ orientation: Qt.Horizontal
141+ propagateComposedEvents: true
115
142
116− anchors.top: parent.top
143+ Component.onCompleted: {
117− anchors.bottom: parent.bottom
144+ // set evaluators to baseline of dragValue == 0
118− anchors.right: parent.right
145+ leftEvaluator.reset()
146+ rightEvaluator.reset()
147+ }
119
148
120− hintDisplacement: units.gu(2)
149+ function maybeTease() {
150+ if ((!greeter.locked || greeter.narrowMode) && greeter.x == 0)
151+ greeter.tease();
152+ }
121
153
122− enabled: greeter.narrowMode || !greeter.locked
154+ onPressAndHold: maybeTease()
155+ onClicked: maybeTease()
123
156
157+ onDragEnd: {
158+ if (rightEvaluator.shouldAutoComplete())
159+ greeter.hideRight()
160+ else if (leftEvaluator.shouldAutoComplete())
161+ greeter.hide();
162+ else
163+ greeter.show(); // undo drag
164+ }
165+
166+ onDragValueChanged: {
167+ // dragValue is kept as a "step" value since we do this x adjusting on the fly
168+ greeter.x += dragValue
169+ }
170+
171+ EdgeDragEvaluator {
172+ id: rightEvaluator
173+ trackedPosition: dragHandle.dragValue + greeter.x
174+ maxDragDistance: parent.width
175+ direction: Direction.Rightwards
176+ }
177+
178+ EdgeDragEvaluator {
179+ id: leftEvaluator
180+ trackedPosition: dragHandle.dragValue + greeter.x
181+ maxDragDistance: parent.width
124− direction: Direction.Leftwards
182+ direction: Direction.Leftwards
183+ }
125 }
184 }
126}
185}
qml/Greeter/GreeterContent.qml−9
@@ -25,10 +25,6 @@ MouseArea {
25 anchors.fill: parent
25 anchors.fill: parent
26
26
27 property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
27 property bool ready: background.source == "" || background.status == Image.Ready || background.status == Image.Error
28− property bool leftTeaserPressed: teasingMouseArea.pressed &&
29− teasingMouseArea.mouseX < teasingMouseArea.width / 2
30− property bool rightTeaserPressed: teasingMouseArea.pressed &&
31− teasingMouseArea.mouseX > teasingMouseArea.width / 2
32
28
33 signal selected(int uid)
29 signal selected(int uid)
34 signal unlocked(int uid)
30 signal unlocked(int uid)
@@ -74,11 +70,6 @@ MouseArea {
74 opacity: 0.4
70 opacity: 0.4
75 }
71 }
76
72
77− MouseArea {
78− id: teasingMouseArea
79− anchors.fill: parent
80− }
81−
82 Loader {
73 Loader {
83 id: loginLoader
74 id: loginLoader
84 objectName: "loginLoader"
75 objectName: "loginLoader"
qml/Shell.qml+77−77
@@ -211,16 +211,10 @@ FocusScope {
211
211
212 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
212 contentScale: 1.0 - 0.2 * disappearingAnimationProgress
213 opacity: 1.0 - disappearingAnimationProgress
213 opacity: 1.0 - disappearingAnimationProgress
214− property real disappearingAnimationProgress: {
214+ property real disappearingAnimationProgress: stagesOuterContainer.showProgress
215− if (greeter.shown) {
216− return greeter.showProgress;
217− } else {
218− return stagesOuterContainer.showProgress;
219− }
220− }
221
215
222− // FIXME: only necessary because stagesOuterContainer.showProgress and
216+ // FIXME: only necessary because stagesOuterContainer.showProgress
223− // greeterRevealer.animatedProgress are not animated
217+ // is not animated
224 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
218 Behavior on disappearingAnimationProgress { SmoothedAnimation { velocity: 5 }}
225 }
219 }
226 }
220 }
@@ -453,90 +447,94 @@ FocusScope {
453 }
447 }
454 }
448 }
455
449
456− Greeter {
450+ Item {
457− id: greeter
451+ // Just a tiny wrapper to adjust greeter's x without messing with its own dragging
458− objectName: "greeter"
452+ width: parent.width
453+ height: parent.height
454+ x: launcher.progress
455+ Behavior on x {SmoothedAnimation{velocity: 600}}
459
456
460− available: true
457+ Greeter {
461− hides: [launcher, panel.indicators, hud]
458+ id: greeter
462− shown: true
459+ objectName: "greeter"
463
460
464− defaultBackground: shell.background
461+ available: true
462+ hides: [launcher, panel.indicators, hud]
463+ shown: true
465
464
466− y: panel.panelHeight
465+ defaultBackground: shell.background
467− width: parent.width
468− height: parent.height - panel.panelHeight
469
466
470− dragHandleWidth: shell.edgeSize
467+ y: panel.panelHeight
468+ width: parent.width
469+ height: parent.height - panel.panelHeight
471
470
472− property var previousMainApp: null
471+ dragHandleWidth: shell.edgeSize
473− property var previousSideApp: null
474
472
475− function removeApplicationFocus() {
473+ property var previousMainApp: null
476− greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
474+ property var previousSideApp: null
477− greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
478− applicationManager.unfocusCurrentApplication();
479− }
480
475
481− function restoreApplicationFocus() {
476+ function removeApplicationFocus() {
482− if (greeter.previousMainApp) {
477+ greeter.previousMainApp = applicationManager.mainStageFocusedApplication;
483− applicationManager.focusApplication(greeter.previousMainApp);
478+ greeter.previousSideApp = applicationManager.sideStageFocusedApplication;
484− greeter.previousMainApp = null;
479+ applicationManager.unfocusCurrentApplication();
485 }
480 }
486− if (greeter.previousSideApp) {
487− applicationManager.focusApplication(greeter.previousSideApp);
488− greeter.previousSideApp = null;
489− }
490− }
491
481
492− onShownChanged: {
482+ function restoreApplicationFocus() {
493− if (shown) {
483+ if (greeter.previousMainApp) {
494− lockscreen.reset();
484+ applicationManager.focusApplication(greeter.previousMainApp);
495− // If there is only one user, we start authenticating with that one here.
485+ greeter.previousMainApp = null;
496− // If there are more users, the Greeter will handle that
486+ }
497− if (LightDM.Users.count == 1) {
487+ if (greeter.previousSideApp) {
498− LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
488+ applicationManager.focusApplication(greeter.previousSideApp);
489+ greeter.previousSideApp = null;
499 }
490 }
500− greeter.forceActiveFocus();
501− removeApplicationFocus();
502− } else {
503− restoreApplicationFocus();
504 }
491 }
505− }
506
492
507− onUnlocked: greeter.hide()
493+ onShownChanged: {
508− onSelected: {
494+ if (shown) {
509− // Update launcher items for new user
495+ lockscreen.reset();
496+ // If there is only one user, we start authenticating with that one here.
497+ // If there are more users, the Greeter will handle that
498+ if (LightDM.Users.count == 1) {
510− var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
499+ LightDM.Greeter.authenticate(LightDM.Users.data(0, LightDM.UserRoles.NameRole));
511− AccountsService.user = user;
500+ }
512− LauncherModel.setUser(user);
501+ greeter.forceActiveFocus();
502+ removeApplicationFocus();
503+ } else {
504+ restoreApplicationFocus();
505+ }
513− }
506+ }
514
507
515− onLeftTeaserPressedChanged: {
508+ onUnlocked: greeter.hide()
516− if (leftTeaserPressed) {
509+ onSelected: {
517− launcher.tease();
510+ // Update launcher items for new user
511+ var user = LightDM.Users.data(uid, LightDM.UserRoles.NameRole);
512+ AccountsService.user = user;
513+ LauncherModel.setUser(user);
518 }
514 }
519− }
520
515
516+ onTease: launcher.tease() //launcher.state = "visible"
517+
521− Connections {
518+ Connections {
522− target: applicationManager
519+ target: applicationManager
523− ignoreUnknownSignals: true
520+ ignoreUnknownSignals: true
524− // If any app is focused when greeter is open, it's due to a user action
521+ // If any app is focused when greeter is open, it's due to a user action
525− // like a snap decision (say, an incoming call).
522+ // like a snap decision (say, an incoming call).
526− // TODO: these should be protected to only unlock for certain applications / certain usecases
523+ // TODO: these should be protected to only unlock for certain applications / certain usecases
527− // potentially only in connection with a notification.
524+ // potentially only in connection with a notification.
528− onMainStageFocusedApplicationChanged: {
525+ onMainStageFocusedApplicationChanged: {
529− if (greeter.shown && applicationManager.mainStageFocusedApplication) {
526+ if (greeter.shown && applicationManager.mainStageFocusedApplication) {
530− greeter.previousMainApp = null // make way for new focused app
527+ greeter.previousMainApp = null // make way for new focused app
531− greeter.previousSideApp = null
528+ greeter.previousSideApp = null
532− greeter.hide()
529+ greeter.hide()
530+ }
533 }
531 }
534− }
535− onSideStageFocusedApplicationChanged: {
532+ onSideStageFocusedApplicationChanged: {
536− if (greeter.shown && applicationManager.sideStageFocusedApplication) {
533+ if (greeter.shown && applicationManager.sideStageFocusedApplication) {
537− greeter.previousMainApp = null // make way for new focused app
534+ greeter.previousMainApp = null // make way for new focused app
538− greeter.previousSideApp = null
535+ greeter.previousSideApp = null
539− greeter.hide()
536+ greeter.hide()
537+ }
540 }
538 }
541 }
539 }
542 }
540 }
@@ -681,6 +679,8 @@ FocusScope {
681 stages.hide();
679 stages.hide();
682 launcher.hide();
680 launcher.hide();
683 }
681 }
682+ if (greeter.shown)
683+ greeter.hideRight();
684 }
684 }
685 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("applications.scope", false, true)
685 onDashSwipeChanged: if (dashSwipe && stages.shown) dash.setCurrentScope("applications.scope", false, true)
686 onLauncherApplicationSelected:{
686 onLauncherApplicationSelected:{