on xenial help sign in
More work, add new WideView test
e806e8cMichael Terry
qml/Greeter/CoverPage.qml+23−39
@@ -15,8 +15,6 @@
15 */
15 */
16
16
17import QtQuick 2.3
17import QtQuick 2.3
18−import AccountsService 0.1
19−import LightDM 0.1 as LightDM
20import Ubuntu.Components 1.1
18import Ubuntu.Components 1.1
21import Ubuntu.Gestures 0.1
19import Ubuntu.Gestures 0.1
22import "../Components"
20import "../Components"
@@ -29,7 +27,7 @@ Showable {
29 property alias background: greeterBackground.source
27 property alias background: greeterBackground.source
30 property real backgroundTopMargin
28 property real backgroundTopMargin
31 property bool ready: greeterBackground.source == "" || greeterBackground.status == Image.Ready || greeterBackground.status == Image.Error
29 property bool ready: greeterBackground.source == "" || greeterBackground.status == Image.Ready || greeterBackground.status == Image.Error
32− property int currentIndex
30+ property var infographicModel
33 property bool draggable: true
31 property bool draggable: true
34
32
35 property alias infographics: infographics
33 property alias infographics: infographics
@@ -39,20 +37,24 @@ Showable {
39 signal tease()
37 signal tease()
40
38
41 function hideRight() {
39 function hideRight() {
42− if (shown) {
40+ d.forceRightOnNextHideAnimation = true;
43− hideAnimation = d.rightHideAnimation;
44− hide();
41+ hide();
45− }
46 }
42 }
47
43
48− property real dragOffset
44+ QtObject {
49− x: launcherOffset + dragOffset
45+ id: d
46+ property bool forceRightOnNextHideAnimation: false
47+ }
50
48
51− function startTease() {
49+ prepareToHide: function () {
52− tease();
50+ hideTranslation.to = root.x > 0 || d.forceRightOnNextHideAnimation ? root.width : -root.width;
53− showLabelAnimation.start();
51+ d.forceRightOnNextHideAnimation = false;
54 }
52 }
55
53
54+ // We don't directly bind "x" because that's owned by the DragHandle. So
55+ // instead, we can get a little extra horizontal push by using transforms.
56+ transform: Translate { x: draggable ? launcherOffset : 0 }
57+
56 DragHandle {
58 DragHandle {
57 id: dragHandle
59 id: dragHandle
58 anchors.fill: parent
60 anchors.fill: parent
@@ -60,11 +62,10 @@ Showable {
60 enabled: root.draggable
62 enabled: root.draggable
61 direction: Direction.Horizontal
63 direction: Direction.Horizontal
62
64
63− onTapped: root.startTease()
64−
65 onDraggingChanged: {
65 onDraggingChanged: {
66 if (dragging) {
66 if (dragging) {
67− root.startTease();
67+ root.tease();
68+ showLabelAnimation.start();
68 }
69 }
69 }
70 }
70 }
71 }
@@ -99,24 +100,7 @@ Showable {
99 id: infographics
100 id: infographics
100 objectName: "infographics"
101 objectName: "infographics"
101 height: parent.height
102 height: parent.height
102− model: LightDM.Infographic
103+ model: root.infographicModel
103−
104− property string selectedUser: LightDM.Users.data(root.currentIndex, LightDM.UserRoles.NameRole)
105−
106− Component.onCompleted: {
107− LightDM.Infographic.readyForDataChange();
108− }
109−
110− Binding {
111− target: LightDM.Infographic
112− property: "username"
113− value: AccountsService.statsWelcomeScreen ? infographics.selectedUser : ""
114− }
115−
116− Connections {
117− target: i18n
118− onLanguageChanged: LightDM.Infographic.readyForDataChange()
119− }
120
104
121 anchors {
105 anchors {
122 verticalCenter: parent.verticalCenter
106 verticalCenter: parent.verticalCenter
@@ -183,10 +167,10 @@ Showable {
183 }
167 }
184
168
185 if (enabled) {
169 if (enabled) {
186− if (root.dragOffset > 0) {
170+ if (root.x > 0) {
187− value = Qt.binding(function() { return greeter.width; })
171+ value = Qt.binding(function() { return root.width; })
188 } else {
172 } else {
189− value = Qt.binding(function() { return -greeter.width; })
173+ value = Qt.binding(function() { return -root.width; })
190 }
174 }
191 }
175 }
192
176
@@ -197,7 +181,7 @@ Showable {
197
181
198 target: root
182 target: root
199 when: __enabled
183 when: __enabled
200− property: "dragOffset"
184+ property: "x"
201 }
185 }
202
186
203 hideAnimation: SequentialAnimation {
187 hideAnimation: SequentialAnimation {
@@ -205,7 +189,7 @@ Showable {
205 objectName: "hideAnimation"
189 objectName: "hideAnimation"
206 StandardAnimation {
190 StandardAnimation {
207 id: hideTranslation
191 id: hideTranslation
208− property: "dragOffset"
192+ property: "x"
209 target: root
193 target: root
210 }
194 }
211 PropertyAction { target: root; property: "visible"; value: false }
195 PropertyAction { target: root; property: "visible"; value: false }
@@ -218,7 +202,7 @@ Showable {
218 PropertyAction { target: root; property: "visible"; value: true }
202 PropertyAction { target: root; property: "visible"; value: true }
219 PropertyAction { target: positionLock; property: "enabled"; value: false }
203 PropertyAction { target: positionLock; property: "enabled"; value: false }
220 StandardAnimation {
204 StandardAnimation {
221− property: "dragOffset"
205+ property: "x"
222 target: root
206 target: root
223 to: 0
207 to: 0
224 duration: UbuntuAnimation.FastDuration
208 duration: UbuntuAnimation.FastDuration
qml/Greeter/Greeter.qml+67−20
@@ -23,7 +23,7 @@ import Unity.Launcher 0.1
23import "../Components"
23import "../Components"
24
24
25Showable {
25Showable {
26− id: greeter
26+ id: root
27 created: loader.status == Loader.Ready
27 created: loader.status == Loader.Ready
28
28
29 property real dragHandleLeftMargin: 0
29 property real dragHandleLeftMargin: 0
@@ -95,15 +95,9 @@ Showable {
95 d.startUnlock(true);
95 d.startUnlock(true);
96 }
96 }
97
97
98− prepareToHide: function () {
99− hideTranslation.to = greeter.x > 0 || d.forceRightOnNextHideAnimation ? greeter.width : -greeter.width;
100− d.forceRightOnNextHideAnimation = false;
101− }
102−
103 QtObject {
98 QtObject {
104 id: d
99 id: d
105
100
106− property bool forceRightOnNextHideAnimation: false
107 readonly property bool multiUser: LightDM.Users.count > 1
101 readonly property bool multiUser: LightDM.Users.count > 1
108 property int currentIndex
102 property int currentIndex
109 property int delayMinutes
103 property int delayMinutes
@@ -188,15 +182,16 @@ Showable {
188
182
189 anchors.fill: parent
183 anchors.fill: parent
190
184
191− source: greeter.required ? ((!d.multiUser && !tabletMode) ? "NarrowGreeter.qml"
185+ source: root.required ? ((!d.multiUser && !tabletMode) ? "NarrowView.qml"
192− : "WideGreeter.qml")
186+ : "WideView.qml")
193− : ""
187+ : ""
194
188
195 onLoaded: {
189 onLoaded: {
196 loader.item.reset();
190 loader.item.reset();
197− greeter.lockedApp = "";
191+ root.lockedApp = "";
198− greeter.forceActiveFocus();
192+ root.forceActiveFocus();
199 d.selectUser(d.currentIndex);
193 d.selectUser(d.currentIndex);
194+ LightDM.InfoGraphic.readyForDataChange();
200 }
195 }
201
196
202 Connections {
197 Connections {
@@ -204,13 +199,18 @@ Showable {
204 onSelected: {
199 onSelected: {
205 d.selectUser(index);
200 d.selectUser(index);
206 }
201 }
207− onUnlocked: {
202+ onResponded: {
203+ if (root.locked) {
204+ LightDM.Greeter.respond(response);
205+ } else {
208− d.login()
206+ d.login();
207+ }
209 }
208 }
210− onTease: greeter.tease()
209+ onTease: root.tease()
210+ onEmergencyCall: root.emergencyCall()
211 onRequiredChanged: {
211 onRequiredChanged: {
212 if (!loader.item.required) {
212 if (!loader.item.required) {
213− greeter.hide();
213+ root.hide();
214 }
214 }
215 }
215 }
216 }
216 }
@@ -218,7 +218,7 @@ Showable {
218 Binding {
218 Binding {
219 target: loader.item
219 target: loader.item
220 property: "backgroundTopMargin"
220 property: "backgroundTopMargin"
221− value: -greeter.y
221+ value: -root.y
222 }
222 }
223
223
224 Binding {
224 Binding {
@@ -230,7 +230,7 @@ Showable {
230 Binding {
230 Binding {
231 target: loader.item
231 target: loader.item
232 property: "dragHandleLeftMargin"
232 property: "dragHandleLeftMargin"
233− value: greeter.dragHandleLeftMargin
233+ value: root.dragHandleLeftMargin
234 }
234 }
235
235
236 Binding {
236 Binding {
@@ -238,13 +238,49 @@ Showable {
238 property: "delayMinutes"
238 property: "delayMinutes"
239 value: d.delayMinutes
239 value: d.delayMinutes
240 }
240 }
241+
242+ Binding {
243+ target: loader.item
244+ property: "background"
245+ value: root.background
246+ }
247+
248+ Binding {
249+ target: loader.item
250+ property: "locked"
251+ value: root.locked
252+ }
253+
254+ Binding {
255+ target: loader.item
256+ property: "currentIndex"
257+ value: d.currentIndex
258+ }
259+
260+ Binding {
261+ target: loader.item
262+ property: "currentUser"
263+ value: LightDM.Users.data(d.currentIndex, LightDM.UserRoles.NameRole)
264+ }
265+
266+ Binding {
267+ target: loader.item
268+ property: "userModel"
269+ value: LightDM.Users
270+ }
271+
272+ Binding {
273+ target: loader.item
274+ property: "infographicModel"
275+ value: LightDM.Infographic
276+ }
241 }
277 }
242
278
243 Connections {
279 Connections {
244 target: LightDM.Greeter
280 target: LightDM.Greeter
245
281
246 onShowGreeter: {
282 onShowGreeter: {
247− greeter.show();
283+ root.show();
248 loader.item.reset();
284 loader.item.reset();
249 d.selectUser(d.currentIndex);
285 d.selectUser(d.currentIndex);
250 }
286 }
@@ -331,6 +367,17 @@ Showable {
331 Binding {
367 Binding {
332 target: LightDM.Greeter
368 target: LightDM.Greeter
333 property: "active"
369 property: "active"
334− value: greeter.active
370+ value: root.active
371+ }
372+
373+ Binding {
374+ target: LightDM.Infographic
375+ property: "username"
376+ value: AccountsService.statsWelcomeScreen ? LightDM.Users.data(d.currentIndex, LightDM.UserRoles.NameRole) : ""
377+ }
378+
379+ Connections {
380+ target: i18n
381+ onLanguageChanged: LightDM.Infographic.readyForDataChange()
335 }
382 }
336}
383}
qml/Greeter/LoginList.qml+24−34
@@ -16,35 +16,35 @@
16
16
17import QtQuick 2.3
17import QtQuick 2.3
18import Ubuntu.Components 1.1
18import Ubuntu.Components 1.1
19−import LightDM 0.1 as LightDM
20import "../Components"
19import "../Components"
21
20
22Item {
21Item {
23 id: root
22 id: root
24
23
25− property alias userList: userList
26 property alias model: userList.model
24 property alias model: userList.model
27− property alias currentIndex: userList.currentIndex
25+ property int currentIndex
26+ property bool locked
28
27
29 readonly property int numAboveBelow: 4
28 readonly property int numAboveBelow: 4
30 readonly property int cellHeight: units.gu(5)
29 readonly property int cellHeight: units.gu(5)
31 readonly property int highlightedHeight: units.gu(10)
30 readonly property int highlightedHeight: units.gu(10)
32 readonly property int moveDuration: 200
31 readonly property int moveDuration: 200
32+ readonly property string currentUser: userList.currentItem.username
33 property bool wasPrompted: false
33 property bool wasPrompted: false
34
34
35− signal selected(int uid)
35+ signal selected(int index)
36− signal unlocked()
36+ signal responded(string response)
37
37
38 function tryToUnlock() {
38 function tryToUnlock() {
39− if (LightDM.Greeter.promptless) {
39+ if (wasPrompted) {
40− if (LightDM.Greeter.authenticated) {
40+ passwordInput.forceActiveFocus();
41− root.unlocked()
42− } else {
41+ } else {
42+ if (root.locked) {
43− root.resetAuthentication()
43+ root.resetAuthentication();
44 root.selected(currentIndex);
44 root.selected(currentIndex);
45+ } else {
46+ root.responded("");
45 }
47 }
46− } else {
47− passwordInput.forceActiveFocus()
48 }
48 }
49 }
49 }
50
50
@@ -106,18 +106,10 @@ Item {
106
106
107 readonly property bool movingInternally: moveTimer.running || userList.moving
107 readonly property bool movingInternally: moveTimer.running || userList.moving
108
108
109+ currentIndex: root.currentIndex
109 onCurrentIndexChanged: {
110 onCurrentIndexChanged: {
110− if (LightDM.Greeter.authenticationUser != userList.model.data(currentIndex, LightDM.UserRoles.NameRole)) {
111− root.resetAuthentication();
111+ root.resetAuthentication();
112− root.selected(currentIndex);
112+ moveTimer.start();
113− }
114− }
115−
116− onMovingInternallyChanged: {
117− // Only emit the selected signal once we stop moving to avoid frequent background changes
118− if (!movingInternally) {
119− root.selected(userList.currentIndex);
120− }
121 }
113 }
122
114
123 delegate: Item {
115 delegate: Item {
@@ -126,6 +118,7 @@ Item {
126
118
127 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)
119 readonly property bool belowHighlight: (userList.currentIndex < 0 && index > 0) || (userList.currentIndex >= 0 && index > userList.currentIndex)
128 readonly property int belowOffset: root.highlightedHeight - root.cellHeight
120 readonly property int belowOffset: root.highlightedHeight - root.cellHeight
121+ readonly property string username: name
129
122
130 opacity: {
123 opacity: {
131 // The goal here is to make names less and less opaque as they
124 // The goal here is to make names less and less opaque as they
@@ -173,11 +166,8 @@ Item {
173 topMargin: parent.belowHighlight ? parent.belowOffset : 0
166 topMargin: parent.belowHighlight ? parent.belowOffset : 0
174 }
167 }
175 height: parent.height
168 height: parent.height
176− enabled: userList.currentIndex !== index
169+ enabled: userList.currentIndex !== index && parent.opacity > 0
177− onClicked: {
170+ onClicked: root.selected(index)
178− moveTimer.start();
179− userList.currentIndex = index;
180− }
181
171
182 Behavior on anchors.topMargin { NumberAnimation { duration: root.moveDuration; easing.type: Easing.InOutQuad; } }
172 Behavior on anchors.topMargin { NumberAnimation { duration: root.moveDuration; easing.type: Easing.InOutQuad; } }
183 }
173 }
@@ -230,9 +220,9 @@ Item {
230 opacity: userList.movingInternally ? 0 : 1
220 opacity: userList.movingInternally ? 0 : 1
231
221
232 property string promptText
222 property string promptText
233− placeholderText: LightDM.Greeter.promptless ? (LightDM.Greeter.authenticated ? i18n.tr("Tap to unlock")
223+ placeholderText: root.wasPrompted ? promptText
234− : i18n.tr("Retry"))
224+ : (root.locked ? i18n.tr("Retry")
235− : promptText
225+ : i18n.tr("Tap to unlock"))
236
226
237 Behavior on opacity {
227 Behavior on opacity {
238 NumberAnimation { duration: 100 }
228 NumberAnimation { duration: 100 }
@@ -243,7 +233,7 @@ Item {
243 return;
233 return;
244 root.focus = true; // so that it can handle Escape presses for us
234 root.focus = true; // so that it can handle Escape presses for us
245 enabled = false;
235 enabled = false;
246− LightDM.Greeter.respond(text);
236+ root.responded(text);
247 }
237 }
248 Keys.onEscapePressed: {
238 Keys.onEscapePressed: {
249 root.resetAuthentication();
239 root.resetAuthentication();
@@ -256,7 +246,7 @@ Item {
256 rightMargin: units.gu(2)
246 rightMargin: units.gu(2)
257 verticalCenter: parent.verticalCenter
247 verticalCenter: parent.verticalCenter
258 }
248 }
259− visible: LightDM.Greeter.promptless
249+ visible: !root.wasPrompted
260 source: "graphics/icon_arrow.png"
250 source: "graphics/icon_arrow.png"
261 }
251 }
262
252
@@ -280,7 +270,7 @@ Item {
280 id: passwordMouseArea
270 id: passwordMouseArea
281 objectName: "passwordMouseArea"
271 objectName: "passwordMouseArea"
282 anchors.fill: passwordInput
272 anchors.fill: passwordInput
283− enabled: LightDM.Greeter.promptless
273+ enabled: !root.wasPrompted
284 onClicked: root.tryToUnlock()
274 onClicked: root.tryToUnlock()
285 }
275 }
286
276
qml/Greeter/NarrowGreeter.qml → qml/Greeter/NarrowView.qmlrenamed+16−23
@@ -16,7 +16,6 @@
16
16
17import QtQuick 2.3
17import QtQuick 2.3
18import AccountsService 0.1
18import AccountsService 0.1
19−import LightDM 0.1 as LightDM
20import Ubuntu.Components 1.1
19import Ubuntu.Components 1.1
21import "../Components"
20import "../Components"
22
21
@@ -28,12 +27,17 @@ Item {
28 property int currentIndex // unused
27 property int currentIndex // unused
29 property alias delayMinutes: lockscreen.delayMinutes
28 property alias delayMinutes: lockscreen.delayMinutes
30 property alias backgroundTopMargin: coverPage.backgroundTopMargin
29 property alias backgroundTopMargin: coverPage.backgroundTopMargin
30+ property url background
31+ property bool locked
32+ property var userModel // unused
33+ property alias infographicModel: coverPage.infographicModel
31− property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
34+ readonly property bool fullyShown: coverPage.showProgress === 1 || lockscreen.shown
32− property bool required: coverPage.required || lockscreen.required
35+ readonly property bool required: coverPage.required || lockscreen.required
33
36
34 signal selected(int index)
37 signal selected(int index)
35− signal unlocked()
38+ signal responded(string response)
36 signal tease()
39 signal tease()
40+ signal emergencyCall()
37
41
38 function showMessage(html) {
42 function showMessage(html) {
39 // TODO
43 // TODO
@@ -73,9 +77,7 @@ Item {
73 }
77 }
74
78
75 function tryToUnlock(toTheRight) {
79 function tryToUnlock(toTheRight) {
76− if (!LightDM.Greeter.authenticated) {
77− lockscreen.maybeShow();
80+ lockscreen.maybeShow();
78− }
79 if (toTheRight) {
81 if (toTheRight) {
80 coverPage.hideRight();
82 coverPage.hideRight();
81 } else {
83 } else {
@@ -96,7 +98,7 @@ Item {
96 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
98 hideAnimation: StandardAnimation { property: "opacity"; to: 0 }
97 anchors.fill: parent
99 anchors.fill: parent
98 visible: required
100 visible: required
99− background: greeter.background
101+ background: root.background
100 darkenBackground: 0.4
102 darkenBackground: 0.4
101 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
103 alphaNumeric: AccountsService.passwordDisplayHint === AccountsService.Keyboard
102 minPinLength: 4
104 minPinLength: 4
@@ -111,21 +113,12 @@ Item {
111 i18n.tr("Please re-enter") :
113 i18n.tr("Please re-enter") :
112 i18n.tr("Sorry, incorrect passcode")
114 i18n.tr("Sorry, incorrect passcode")
113
115
114− // FIXME: We *should* show emergency dialer if there is a SIM present,
115− // regardless of whether the side stage is enabled. But right now,
116− // the assumption is that narrow screens are phones which have SIMs
117− // and wider screens are tablets which don't. When we do allow this
118− // on devices with a side stage and a SIM, work should be done to
119− // ensure that the main stage is disabled while the dialer is present
120− // in the side stage. See the FIXME in the stage loader in Shell.qml.
121− showEmergencyCallButton: !greeter.tabletMode
122−
123− onEntered: LightDM.Greeter.respond(passphrase)
116+ onEntered: root.responded(passphrase)
124 onCancel: coverPage.show()
117 onCancel: coverPage.show()
125− onEmergencyCall: greeter.emergencyCall()
118+ onEmergencyCall: root.emergencyCall()
126
119
127 function maybeShow() {
120 function maybeShow() {
128− if (!greeter.forcedUnlock) {
121+ if (root.locked) {
129 showNow();
122 showNow();
130 }
123 }
131 }
124 }
@@ -142,7 +135,7 @@ Item {
142 objectName: "coverPage"
135 objectName: "coverPage"
143 height: parent.height
136 height: parent.height
144 width: parent.width
137 width: parent.width
145− background: greeter.background
138+ background: root.background
146 onTease: root.tease()
139 onTease: root.tease()
147
140
148 onShowProgressChanged: {
141 onShowProgressChanged: {
@@ -151,10 +144,10 @@ Item {
151 }
144 }
152
145
153 if (showProgress === 0) {
146 if (showProgress === 0) {
154− if (greeter.locked) {
147+ if (root.locked) {
155 lockscreen.clear(false); // to reset focus if necessary
148 lockscreen.clear(false); // to reset focus if necessary
156 } else {
149 } else {
157− root.unlocked();
150+ root.responded("");
158 }
151 }
159 }
152 }
160 }
153 }
qml/Greeter/WideGreeter.qml → qml/Greeter/WideView.qmlrenamed+29−26
@@ -15,7 +15,6 @@
15 */
15 */
16
16
17import QtQuick 2.3
17import QtQuick 2.3
18−import LightDM 0.1 as LightDM
19import Ubuntu.Components 1.1
18import Ubuntu.Components 1.1
20
19
21Item {
20Item {
@@ -26,12 +25,17 @@ Item {
26 property alias currentIndex: loginList.currentIndex
25 property alias currentIndex: loginList.currentIndex
27 property int delayMinutes // TODO
26 property int delayMinutes // TODO
28 property alias backgroundTopMargin: coverPage.backgroundTopMargin
27 property alias backgroundTopMargin: coverPage.backgroundTopMargin
28+ property alias background: coverPage.background
29+ property bool locked
30+ property alias userModel: loginList.model
31+ property alias infographicModel: coverPage.infographicModel
29− property bool fullyShown: coverPage.showProgress === 1
32+ readonly property bool fullyShown: coverPage.showProgress === 1
30− property bool required: coverPage.required
33+ readonly property bool required: coverPage.required
31
34
32 signal selected(int index)
35 signal selected(int index)
33− signal unlocked()
36+ signal responded(string response)
34 signal tease()
37 signal tease()
38+ signal emergencyCall() // UNUSED
35
39
36 function showMessage(html) {
40 function showMessage(html) {
37 loginList.showMessage(html);
41 loginList.showMessage(html);
@@ -60,15 +64,15 @@ Item {
60 }
64 }
61
65
62 function tryToUnlock(toTheRight) {
66 function tryToUnlock(toTheRight) {
63− if (LightDM.Greeter.authenticated) {
67+ if (root.locked) {
68+ coverPage.show();
69+ loginList.tryToUnlock();
70+ } else {
64 if (toTheRight) {
71 if (toTheRight) {
65 coverPage.hideRight();
72 coverPage.hideRight();
66 } else {
73 } else {
67 coverPage.hide();
74 coverPage.hide();
68 }
75 }
69− } else {
70− coverPage.show();
71− loginList.tryToUnlock();
72 }
76 }
73 }
77 }
74
78
@@ -87,8 +91,7 @@ Item {
87 objectName: "coverPage"
91 objectName: "coverPage"
88 height: parent.height
92 height: parent.height
89 width: parent.width
93 width: parent.width
90− background: greeter.background
91− draggable: !greeter.locked
94+ draggable: !root.locked
92
95
93 infographics {
96 infographics {
94 height: 0.75 * parent.height
97 height: 0.75 * parent.height
@@ -98,27 +101,27 @@ Item {
98 onTease: root.tease()
101 onTease: root.tease()
99
102
100 onShowProgressChanged: {
103 onShowProgressChanged: {
101− if (showProgress === 0 && !greeter.locked) {
104+ if (showProgress === 0 && !root.locked) {
102− root.unlocked();
105+ root.responded("");
103 }
106 }
104 }
107 }
105− }
106
108
107− LoginList {
109+ LoginList {
108− id: loginList
110+ id: loginList
109− objectName: "loginList"
111+ objectName: "loginList"
110
112
111− anchors {
113+ anchors {
112− left: parent.left
114+ left: parent.left
113− leftMargin: Math.min(parent.width * 0.16, units.gu(20))
115+ leftMargin: Math.min(parent.width * 0.16, units.gu(20))
114− verticalCenter: parent.verticalCenter
116+ verticalCenter: parent.verticalCenter
115− }
117+ }
116− width: units.gu(29)
118+ width: units.gu(29)
117− height: parent.height
119+ height: parent.height
118
120
119− model: LightDM.Users
121+ locked: root.locked
120
122
121− onSelected: root.selected(uid)
123+ onSelected: root.selected(index)
122− onUnlocked: coverPage.hide()
124+ onResponded: root.responded(response)
125+ }
123 }
126 }
124}
127}
tests/qmltests/CMakeLists.txt+1
@@ -65,6 +65,7 @@ add_qml_test(Greeter MultiGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DI
65add_qml_test(Greeter SingleGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
65add_qml_test(Greeter SingleGreeter ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/single")
66add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
66add_qml_test(Greeter Infographics ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
67add_qml_test(Greeter Clock ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
67add_qml_test(Greeter Clock ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel")
68+add_qml_test(Greeter WideView ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
68add_qml_test(Launcher Launcher)
69add_qml_test(Launcher Launcher)
69add_qml_test(Notifications Notifications)
70add_qml_test(Notifications Notifications)
70add_qml_test(Notifications VisualSnapDecisionsQueue)
71add_qml_test(Notifications VisualSnapDecisionsQueue)
tests/qmltests/Greeter/tst_WideView.qmlnew file+299
@@ -0,0 +1,299 @@
1+/*
2+ * Copyright 2014 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+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import ".."
20+import "../../../qml/Greeter"
21+import LightDM 0.1 as LightDM
22+import Ubuntu.Components 0.1
23+import Unity.Test 0.1 as UT
24+
25+Item {
26+ id: root
27+ width: units.gu(120)
28+ height: units.gu(80)
29+
30+ Row {
31+ anchors.fill: parent
32+ Loader {
33+ id: loader
34+ width: root.width - controls.width
35+ height: parent.height
36+
37+ property bool itemDestroyed: false
38+ sourceComponent: Component {
39+ WideView {
40+ background: Qt.resolvedUrl("../../../qml/graphics/tablet_background.jpg")
41+ userModel: LightDM.Users
42+ infographicModel: LightDM.Infographic
43+
44+ launcherOffset: parseFloat(launcherOffsetField.text)
45+ currentIndex: parseInt(currentIndexField.text, 10)
46+ delayMinutes: parseInt(delayMinutesField.text, 10)
47+ backgroundTopMargin: parseFloat(backgroundTopMarginField.text)
48+ locked: lockedCheckBox.checked
49+
50+ Component.onDestruction: {
51+ loader.itemDestroyed = true
52+ }
53+
54+ onSelected: {
55+ currentIndexField.text = index;
56+ }
57+ }
58+ }
59+ }
60+
61+ Rectangle {
62+ id: controls
63+ color: "white"
64+ width: units.gu(40)
65+ height: parent.height
66+
67+ Column {
68+ anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) }
69+ spacing: units.gu(1)
70+
71+ Row {
72+ Button {
73+ text: "Show Last Chance"
74+ onClicked: loader.item.showLastChance()
75+ }
76+ }
77+ Row {
78+ Button {
79+ text: "Hide"
80+ onClicked: loader.item.hide()
81+ }
82+ }
83+ Row {
84+ Button {
85+ text: "Reset"
86+ onClicked: loader.item.reset()
87+ }
88+ }
89+ Row {
90+ Button {
91+ text: "Show Message"
92+ onClicked: loader.item.showMessage(messageField.text)
93+ }
94+ TextField {
95+ id: messageField
96+ width: units.gu(10)
97+ text: ""
98+ }
99+ }
100+ Row {
101+ Button {
102+ text: "Show Prompt"
103+ onClicked: loader.item.showPrompt(promptField.text, isSecretCheckBox.checked, isDefaultPromptCheckBox.checked)
104+ }
105+ TextField {
106+ id: promptField
107+ width: units.gu(10)
108+ text: ""
109+ }
110+ CheckBox {
111+ id: isSecretCheckBox
112+ }
113+ Label {
114+ text: "secret"
115+ }
116+ CheckBox {
117+ id: isDefaultPromptCheckBox
118+ }
119+ Label {
120+ text: "default"
121+ }
122+ }
123+ Row {
124+ Button {
125+ text: "Authenticated"
126+ onClicked: loader.item.authenticated(successCheckBox.checked)
127+ }
128+ CheckBox {
129+ id: successCheckBox
130+ }
131+ Label {
132+ text: "success"
133+ }
134+ }
135+ Row {
136+ Button {
137+ text: "Try To Unlock"
138+ onClicked: loader.item.tryToUnlock(toTheRightCheckBox.checked)
139+ }
140+ CheckBox {
141+ id: toTheRightCheckBox
142+ }
143+ Label {
144+ text: "toTheRight"
145+ }
146+ }
147+ Row {
148+ TextField {
149+ id: launcherOffsetField
150+ width: units.gu(10)
151+ text: "0"
152+ }
153+ Label {
154+ text: "launcherOffset"
155+ }
156+ }
157+ Row {
158+ TextField {
159+ id: currentIndexField
160+ width: units.gu(10)
161+ text: "0"
162+ }
163+ Label {
164+ text: "currentIndex"
165+ }
166+ }
167+ Row {
168+ TextField {
169+ id: delayMinutesField
170+ width: units.gu(10)
171+ text: "0"
172+ }
173+ Label {
174+ text: "delayMinutes"
175+ }
176+ }
177+ Row {
178+ TextField {
179+ id: backgroundTopMarginField
180+ width: units.gu(10)
181+ text: "0"
182+ }
183+ Label {
184+ text: "backgroundTopMargin"
185+ }
186+ }
187+ Row {
188+ CheckBox {
189+ id: lockedCheckBox
190+ }
191+ Label {
192+ text: "locked"
193+ }
194+ }
195+ Row {
196+ Label {
197+ text: "selected: " + selectedSpy.count
198+ }
199+ }
200+ Row {
201+ Label {
202+ text: "responded: " + respondedSpy.count
203+ }
204+ }
205+ Row {
206+ Label {
207+ text: "teased: " + teaseSpy.count
208+ }
209+ }
210+ Row {
211+ Label {
212+ text: "emergency: " + emergencySpy.count
213+ }
214+ }
215+ Row {
216+ Button {
217+ text: "Reload View"
218+ onClicked: {
219+ loader.active = false;
220+ loader.active = true;
221+ }
222+ }
223+ }
224+ }
225+ }
226+ }
227+
228+ SignalSpy {
229+ id: selectedSpy
230+ target: loader.item
231+ signalName: "selected"
232+ }
233+
234+ SignalSpy {
235+ id: respondedSpy
236+ target: loader.item
237+ signalName: "responded"
238+ }
239+
240+ SignalSpy {
241+ id: teaseSpy
242+ target: loader.item
243+ signalName: "tease"
244+ }
245+
246+ SignalSpy {
247+ id: emergencySpy
248+ target: loader.item
249+ signalName: "emergencyCall"
250+ }
251+
252+ UT.UnityTestCase {
253+ name: "WideView"
254+ when: windowShown
255+
256+ property Item view: loader.status === Loader.Ready ? loader.item : null
257+
258+ function init() {
259+ view.currentIndex = 0; // break binding with text field
260+ selectedSpy.clear();
261+ respondedSpy.clear();
262+ teaseSpy.clear();
263+ emergencySpy.clear();
264+ }
265+
266+ function cleanup() {
267+ loader.itemDestroyed = false;
268+ loader.active = false;
269+ tryCompare(loader, "status", Loader.Null);
270+ tryCompare(loader, "item", null);
271+ tryCompare(loader, "itemDestroyed", true);
272+ loader.active = true;
273+ tryCompare(loader, "status", Loader.Ready);
274+ }
275+
276+ function test_tease() {
277+ tap(view, 1, 1);
278+ compare(teaseSpy.count, 1);
279+ }
280+
281+ function test_selected() {
282+ var delegate = findChild(view, "username2");
283+ tap(delegate);
284+ compare(selectedSpy.count, 1);
285+ compare(selectedSpy.signalArguments[0][0], 2);
286+ compare(view.currentIndex, 0); // confirm we didn't change
287+ }
288+
289+ function test_responded() {
290+ view.showPrompt("Prompt", true, true);
291+ var passwordInput = findChild(view, "passwordInput");
292+ tap(passwordInput);
293+ typeString("password");
294+ keyClick(Qt.Key_Enter);
295+ compare(respondedSpy.count, 1);
296+ compare(respondedSpy.signalArguments[0][0], "password");
297+ }
298+ }
299+}