Merge lp:~mterry/unity8/tutorial-refactor into lp:unity8
- tutorial-refactor
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Terry | ||||
Approved revision: | 1403 | ||||
Merged at revision: | 1603 | ||||
Proposed branch: | lp:~mterry/unity8/tutorial-refactor | ||||
Merge into: | lp:unity8 | ||||
Prerequisite: | lp:~dandrader/unity8/fixSurfaceActiveFocus | ||||
Diff against target: |
2307 lines (+1144/-811) 20 files modified
debian/unity8.install (+1/-0) qml/CMakeLists.txt (+3/-2) qml/Components/EdgeDemo.qml (+0/-254) qml/Components/EdgeDemoOverlay.qml (+0/-273) qml/Launcher/Launcher.qml (+13/-7) qml/Shell.qml (+33/-23) qml/Tutorial/Arrow.qml (+56/-0) qml/Tutorial/Slider.qml (+117/-0) qml/Tutorial/Tutorial.qml (+85/-0) qml/Tutorial/TutorialContent.qml (+130/-0) qml/Tutorial/TutorialLeft.qml (+91/-0) qml/Tutorial/TutorialLeftFinish.qml (+47/-0) qml/Tutorial/TutorialPage.qml (+240/-0) tests/autopilot/unity8/shell/emulators/tutorial.py (+16/-102) tests/autopilot/unity8/shell/fixture_setup.py (+6/-6) tests/autopilot/unity8/shell/tests/test_tutorial.py (+17/-18) tests/qmltests/CMakeLists.txt (+1/-1) tests/qmltests/Components/tst_EdgeDemoOverlay.qml (+0/-123) tests/qmltests/Tutorial/tst_Tutorial.qml (+286/-0) tests/qmltests/tst_TabletShell.qml (+2/-2) |
||||
To merge this branch: | bzr merge lp:~mterry/unity8/tutorial-refactor | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Pending | |
Andrea Cimitan | Pending | ||
Review via email: mp+249359@code.launchpad.net |
This proposal supersedes a proposal from 2014-10-28.
Commit message
Redesign tutorial to match latest spec (just removing obsolete pages and redesigning look, no new pages yet)
Specifically, both the greeter and top-edge pages are dropped. Design decided they were self-explanatory enough that they didn't need to be part of the tutorial (in an effort to make it shorter).
The tutorial is still missing right-edge and bottom-edge pages. But since those are new, I am going to do them as a separate branch. This branch is just about trimming the tutorial and redesigning the look and feel.
This leaves us with a very short tutorial right now, but I'm OK with that. It will get longer in a moment with my next tutorial branch.
I did a whole refactor of the tutorial code while here. I didn't like the old way I had done it (too procedural rather than declarative).
I've also taken this opportunity to sync our technical name for the tutorial (edge demo) to what Design calls it (tutorial).
Description of the change
Redesign tutorial to match latest spec (just removing obsolete pages and redesigning look, no new pages yet)
Specifically, both the greeter and top-edge pages are dropped. Design decided they were self-explanatory enough that they didn't need to be part of the tutorial (in an effort to make it shorter).
The tutorial is still missing right-edge and bottom-edge pages. But since those are new, I am going to do them as a separate branch. This branch is just about trimming the tutorial and redesigning the look and feel.
This leaves us with a very short tutorial right now, but I'm OK with that. It will get longer in a moment with my next tutorial branch.
I did a whole refactor of the tutorial code while here. I didn't like the old way I had done it (too procedural rather than declarative).
I've also taken this opportunity to sync our technical name for the tutorial (edge demo) to what Design calls it (tutorial).
Here is the spec from Design:
https:/
== Checklist ==
* Are there any related MPs required for this MP to build/function as expected? Please list.
No
* Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
* Did you make sure that your branch does not contain spurious tags?
Yes
* If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
I'm in that team
* If you changed the UI, has there been a design review?
Yes-ish, they saw an earlier version, will get final approval.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1372
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1373
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1374
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Shell.qml
Conflict adding file qml/Tutorial. Moved existing file to qml/Tutorial.moved.
Text conflict in qml/Tutorial/
3 conflicts encountered.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1377
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1379
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1379
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Text conflict in qml/Shell.qml
1 conflicts encountered.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1380
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1382
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1383
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1384
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1385
http://
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1386
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1387
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1388
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1391
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1391
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
I've triggered a rebuild, don't think the failures are because of this branch.
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
Ha! That was bad timing. I've cancelled the rebuild :D
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1391
http://
Executed test runs:
SUCCESS: http://
None: http://
SUCCESS: http://
SUCCESS: http://
None: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : Posted in a previous version of this proposal | # |
And my cancelled build appears as failed :/
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1391
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1392
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Andrea Cimitan (cimi) wrote : Posted in a previous version of this proposal | # |
I tested this few times in a row, until I found my launcher stuck 2px on screen when hidden (like always on screen 2px).
Might be some of the changes to Launcher.qml
another small thing, more a question, you added both chevron and tick png, but while for tick you used gridUnit, you used pixels for chevron... should both scale or not?
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
I'll look at the 2px-launcher problem.
As for gridUnit vs pixels... Arrow.qml mentions the size of the "chevron.png" source image in pixels, but for its actual height/width, it scales to whatever size the Arrow object is. So they both scale fine, I believe.
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, fixed the launcher sometimes being left exposed. Thanks for the catch!
Andrea Cimitan (cimi) wrote : Posted in a previous version of this proposal | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
y
* Did CI run pass? If not, please explain why.
y
* Did you make sure that the branch does not contain spurious tags?
y
thanks, no issues I noticed now!
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1393
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
I'm going to wait to top-approve this, because design is still doing some minor tweaks (color tweaks, size of text, etc)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1395
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1396
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1397
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1398
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1399
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1400
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Michael Terry (mterry) wrote : Posted in a previous version of this proposal | # |
OK, so this got updated with a couple minor design tweaks and a fix for the autopilot tests. Design has signed off on this version. And the autopilot passes now (well, you can't see it here yet -- I just kicked a rebuild, but you can see it in https:/
So I'm inclined to top-approve again if there isn't an objection.
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:1400
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1400
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PASSED: Continuous integration, rev:1402
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'debian/unity8.install' |
2 | --- debian/unity8.install 2014-11-14 22:40:00 +0000 |
3 | +++ debian/unity8.install 2015-02-11 17:00:33 +0000 |
4 | @@ -10,5 +10,6 @@ |
5 | usr/share/unity8/Panel |
6 | usr/share/unity8/Shell.qml |
7 | usr/share/unity8/Stages |
8 | +usr/share/unity8/Tutorial |
9 | usr/share/unity8/Wizard |
10 | usr/share/url-dispatcher/urls/unity8-dash.url-dispatcher |
11 | |
12 | === modified file 'qml/CMakeLists.txt' |
13 | --- qml/CMakeLists.txt 2014-11-14 23:30:10 +0000 |
14 | +++ qml/CMakeLists.txt 2015-02-11 17:00:33 +0000 |
15 | @@ -9,10 +9,11 @@ |
16 | Dash |
17 | graphics |
18 | Greeter |
19 | + Launcher |
20 | + Notifications |
21 | Panel |
22 | - Launcher |
23 | Stages |
24 | - Notifications |
25 | + Tutorial |
26 | Wizard |
27 | ) |
28 | |
29 | |
30 | === removed file 'qml/Components/EdgeDemo.qml' |
31 | --- qml/Components/EdgeDemo.qml 2014-11-19 19:05:35 +0000 |
32 | +++ qml/Components/EdgeDemo.qml 1970-01-01 00:00:00 +0000 |
33 | @@ -1,254 +0,0 @@ |
34 | -/* |
35 | - * Copyright (C) 2013 Canonical, Ltd. |
36 | - * |
37 | - * This program is free software; you can redistribute it and/or modify |
38 | - * it under the terms of the GNU General Public License as published by |
39 | - * the Free Software Foundation; version 3. |
40 | - * |
41 | - * This program is distributed in the hope that it will be useful, |
42 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
43 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
44 | - * GNU General Public License for more details. |
45 | - * |
46 | - * You should have received a copy of the GNU General Public License |
47 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
48 | - */ |
49 | - |
50 | -import AccountsService 0.1 |
51 | -import LightDM 0.1 as LightDM |
52 | -import QtQuick 2.0 |
53 | -import Ubuntu.Components 1.1 |
54 | - |
55 | -Item { |
56 | - id: demo |
57 | - |
58 | - property Item greeter |
59 | - property Item launcher |
60 | - property Item panel |
61 | - property Item stages |
62 | - |
63 | - property bool launcherEnabled: true |
64 | - property bool stagesEnabled: true |
65 | - property bool panelEnabled: true |
66 | - property bool panelContentEnabled: true |
67 | - property bool running: !launcherEnabled || !stagesEnabled || !panelEnabled || !panelContentEnabled |
68 | - |
69 | - property bool paused: false |
70 | - |
71 | - onPausedChanged: { |
72 | - if (d.rightEdgeDemo) d.rightEdgeDemo.paused = paused |
73 | - if (d.topEdgeDemo) d.topEdgeDemo.paused = paused |
74 | - if (d.bottomEdgeDemo) d.bottomEdgeDemo.paused = paused |
75 | - if (d.leftEdgeDemo) d.leftEdgeDemo.paused = paused |
76 | - if (d.finalEdgeDemo) d.finalEdgeDemo.paused = paused |
77 | - } |
78 | - |
79 | - function hideEdgeDemoInShell() { |
80 | - AccountsService.demoEdges = false; |
81 | - stopDemo(); |
82 | - } |
83 | - |
84 | - function hideEdgeDemoInGreeter() { |
85 | - // TODO: AccountsService.demoEdges = false as lightdm user |
86 | - } |
87 | - |
88 | - function hideEdgeDemos() { |
89 | - hideEdgeDemoInGreeter(); |
90 | - hideEdgeDemoInShell(); |
91 | - } |
92 | - |
93 | - function stopDemo() { |
94 | - launcherEnabled = true |
95 | - stagesEnabled = true |
96 | - panelEnabled = true |
97 | - panelContentEnabled = true |
98 | - |
99 | - // Use a tiny delay for these destroy() calls because if a lot is |
100 | - // happening at once (like creating and being destroyed in same event |
101 | - // loop, as might happen when answering a call while demo is open), |
102 | - // the destroy() call will be ignored. |
103 | - if (d.rightEdgeDemo) d.rightEdgeDemo.destroy(1); |
104 | - if (d.topEdgeDemo) d.topEdgeDemo.destroy(1); |
105 | - if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy(1); |
106 | - if (d.leftEdgeDemo) d.leftEdgeDemo.destroy(1); |
107 | - if (d.finalEdgeDemo) d.finalEdgeDemo.destroy(1); |
108 | - } |
109 | - |
110 | - function startDemo() { |
111 | - if (!d.overlay) { |
112 | - d.overlay = Qt.createComponent("EdgeDemoOverlay.qml") |
113 | - } |
114 | - |
115 | - launcherEnabled = false; |
116 | - stagesEnabled = false; |
117 | - panelEnabled = false; |
118 | - panelContentEnabled = false; |
119 | - |
120 | - // Begin with either greeter or top, depending on which is visible |
121 | - if (greeter && greeter.shown) { |
122 | - startRightEdgeDemo() |
123 | - } else { |
124 | - startTopEdgeDemo() |
125 | - } |
126 | - } |
127 | - |
128 | - QtObject { |
129 | - id: d |
130 | - property Component overlay |
131 | - property QtObject rightEdgeDemo |
132 | - property QtObject topEdgeDemo |
133 | - property QtObject bottomEdgeDemo |
134 | - property QtObject leftEdgeDemo |
135 | - property QtObject finalEdgeDemo |
136 | - property bool showEdgeDemo: AccountsService.demoEdges |
137 | - property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user |
138 | - |
139 | - function restartDemo() { |
140 | - stopDemo() |
141 | - if (d.showEdgeDemo) { |
142 | - startDemo() |
143 | - } |
144 | - } |
145 | - |
146 | - onShowEdgeDemoChanged: restartDemo() |
147 | - } |
148 | - |
149 | - Connections { |
150 | - target: i18n |
151 | - onLanguageChanged: d.restartDemo() |
152 | - } |
153 | - |
154 | - function startRightEdgeDemo() { |
155 | - if (demo.greeter) { |
156 | - d.rightEdgeDemo = d.overlay.createObject(demo.greeter, { |
157 | - "edge": "right", |
158 | - "title": i18n.tr("Right edge"), |
159 | - "text": i18n.tr("Try swiping from the right edge to unlock the phone"), |
160 | - "anchors.fill": demo.greeter, |
161 | - }); |
162 | - } |
163 | - if (d.rightEdgeDemo) { |
164 | - d.rightEdgeDemo.onSkip.connect(demo.hideEdgeDemos) |
165 | - } else { |
166 | - stopDemo(); |
167 | - } |
168 | - } |
169 | - |
170 | - Connections { |
171 | - target: demo.greeter |
172 | - |
173 | - function hide() { |
174 | - if (d.rightEdgeDemo && d.rightEdgeDemo.available) { |
175 | - d.rightEdgeDemo.hide() |
176 | - hideEdgeDemoInGreeter() |
177 | - startTopEdgeDemo() |
178 | - } |
179 | - } |
180 | - |
181 | - onUnlocked: hide() |
182 | - onShownChanged: if (!greeter.shown) hide() |
183 | - } |
184 | - |
185 | - function startTopEdgeDemo() { |
186 | - demo.panelEnabled = true; |
187 | - if (demo.stages) { |
188 | - d.topEdgeDemo = d.overlay.createObject(demo.panel, { |
189 | - "edge": "top", |
190 | - "title": i18n.tr("Top edge"), |
191 | - "text": i18n.tr("Try swiping from the top edge to access the indicators"), |
192 | - "anchors.fill": demo.panel, |
193 | - }); |
194 | - } |
195 | - if (d.topEdgeDemo) { |
196 | - d.topEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell) |
197 | - } else { |
198 | - stopDemo(); |
199 | - } |
200 | - } |
201 | - |
202 | - Connections { |
203 | - target: demo.panel.indicators |
204 | - onFullyOpenedChanged: { |
205 | - if (d.topEdgeDemo && d.topEdgeDemo.available && demo.panel.indicators.fullyOpened) { |
206 | - d.topEdgeDemo.hideNow() |
207 | - startBottomEdgeDemo() |
208 | - } |
209 | - } |
210 | - } |
211 | - |
212 | - function startBottomEdgeDemo() { |
213 | - if (demo.panel.indicators) { |
214 | - d.bottomEdgeDemo = d.overlay.createObject(demo.panel.indicators, { |
215 | - "edge": "bottom", |
216 | - "title": i18n.tr("Close"), |
217 | - "text": i18n.tr("Swipe up again to close the settings screen"), |
218 | - "anchors.fill": demo.panel.indicators, |
219 | - }); |
220 | - } |
221 | - if (d.bottomEdgeDemo) { |
222 | - d.bottomEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell) |
223 | - } else { |
224 | - stopDemo(); |
225 | - } |
226 | - } |
227 | - |
228 | - Connections { |
229 | - target: demo.panel.indicators |
230 | - onPartiallyOpenedChanged: { |
231 | - if (d.bottomEdgeDemo && |
232 | - d.bottomEdgeDemo.available && |
233 | - !demo.panel.indicators.partiallyOpened && |
234 | - !demo.panel.indicators.fullyOpened) { |
235 | - d.bottomEdgeDemo.hideNow() |
236 | - startLeftEdgeDemo() |
237 | - } |
238 | - } |
239 | - } |
240 | - |
241 | - function startLeftEdgeDemo() { |
242 | - demo.panelEnabled = false; |
243 | - demo.launcherEnabled = true; |
244 | - if (demo.stages) { |
245 | - d.leftEdgeDemo = d.overlay.createObject(demo.stages, { |
246 | - "edge": "left", |
247 | - "title": i18n.tr("Left edge"), |
248 | - "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"), |
249 | - "anchors.fill": demo.stages, |
250 | - }); |
251 | - } |
252 | - if (d.leftEdgeDemo) { |
253 | - d.leftEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell) |
254 | - } else { |
255 | - stopDemo(); |
256 | - } |
257 | - } |
258 | - |
259 | - Connections { |
260 | - target: demo.launcher |
261 | - onStateChanged: { |
262 | - if (d.leftEdgeDemo && d.leftEdgeDemo.available && launcher.state == "visible") { |
263 | - d.leftEdgeDemo.hide() |
264 | - launcher.hide() |
265 | - startFinalEdgeDemo() |
266 | - } |
267 | - } |
268 | - } |
269 | - |
270 | - function startFinalEdgeDemo() { |
271 | - demo.launcherEnabled = false; |
272 | - if (demo.stages) { |
273 | - d.finalEdgeDemo = d.overlay.createObject(demo.stages, { |
274 | - "edge": "none", |
275 | - "title": i18n.tr("Well done"), |
276 | - "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap on the screen to start"), |
277 | - "anchors.fill": demo.stages, |
278 | - "showSkip": false, |
279 | - }); |
280 | - } |
281 | - if (d.finalEdgeDemo) { |
282 | - d.finalEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell) |
283 | - } else { |
284 | - stopDemo(); |
285 | - } |
286 | - } |
287 | -} |
288 | |
289 | === removed file 'qml/Components/EdgeDemoOverlay.qml' |
290 | --- qml/Components/EdgeDemoOverlay.qml 2014-07-01 23:45:28 +0000 |
291 | +++ qml/Components/EdgeDemoOverlay.qml 1970-01-01 00:00:00 +0000 |
292 | @@ -1,273 +0,0 @@ |
293 | -/* |
294 | - * Copyright (C) 2013 Canonical, Ltd. |
295 | - * |
296 | - * This program is free software; you can redistribute it and/or modify |
297 | - * it under the terms of the GNU General Public License as published by |
298 | - * the Free Software Foundation; version 3. |
299 | - * |
300 | - * This program is distributed in the hope that it will be useful, |
301 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
302 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
303 | - * GNU General Public License for more details. |
304 | - * |
305 | - * You should have received a copy of the GNU General Public License |
306 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
307 | - */ |
308 | - |
309 | -import Powerd 0.1 |
310 | -import QtQuick 2.0 |
311 | -import QtGraphicalEffects 1.0 |
312 | -import Unity.Application 0.1 |
313 | -import Ubuntu.Components 0.1 |
314 | - |
315 | -Showable { |
316 | - id: overlay |
317 | - |
318 | - /* |
319 | - * Valid values are "left", "right", "top", "bottom", or "none". |
320 | - */ |
321 | - property string edge: "top" |
322 | - |
323 | - /* |
324 | - * This is the header displayed, like "Right edge". |
325 | - */ |
326 | - property alias title: titleLabel.text |
327 | - |
328 | - /* |
329 | - * This is the block of text displayed below the header. |
330 | - */ |
331 | - property alias text: textLabel.text |
332 | - |
333 | - /* |
334 | - * This is the text for the skip button. |
335 | - */ |
336 | - property alias skipText: skipLabel.text |
337 | - |
338 | - /* |
339 | - * This is the visible status of the skip button. |
340 | - */ |
341 | - property alias showSkip: skipLabel.visible |
342 | - |
343 | - /* |
344 | - * Whether this demo is running currently. |
345 | - */ |
346 | - readonly property bool active: available && visible |
347 | - |
348 | - /* |
349 | - * Whether animations are paused. |
350 | - */ |
351 | - property alias paused: wholeAnimation.paused |
352 | - |
353 | - /* |
354 | - * Whether animations are running. |
355 | - */ |
356 | - readonly property alias running: wholeAnimation.running |
357 | - |
358 | - signal skip() |
359 | - |
360 | - function doSkip() { |
361 | - d.skipOnHide = true; |
362 | - hide(); |
363 | - } |
364 | - |
365 | - function hideNow() { |
366 | - overlay.visible = false; |
367 | - overlay.available = false; |
368 | - if (d.skipOnHide) { |
369 | - overlay.skip(); |
370 | - } |
371 | - } |
372 | - |
373 | - showAnimation: StandardAnimation { |
374 | - property: "opacity" |
375 | - to: 1 |
376 | - onRunningChanged: if (running) overlay.visible = true |
377 | - } |
378 | - hideAnimation: StandardAnimation { |
379 | - property: "opacity" |
380 | - to: 0 |
381 | - duration: UbuntuAnimation.BriskDuration |
382 | - onRunningChanged: if (!running) overlay.hideNow() |
383 | - } |
384 | - |
385 | - QtObject { |
386 | - id: d |
387 | - property bool skipOnHide: false |
388 | - property int edgeMargin: units.gu(4) |
389 | - } |
390 | - |
391 | - Rectangle { |
392 | - objectName: "backgroundShade" |
393 | - |
394 | - anchors.fill: parent |
395 | - color: "black" |
396 | - opacity: 0.8 |
397 | - visible: overlay.active |
398 | - |
399 | - MouseArea { |
400 | - objectName: "backgroundShadeMouseArea" |
401 | - |
402 | - anchors.fill: parent |
403 | - enabled: overlay.edge == "none" && overlay.opacity == 1.0 |
404 | - onClicked: overlay.doSkip() |
405 | - } |
406 | - } |
407 | - |
408 | - Item { |
409 | - id: hintGroup |
410 | - x: 0 |
411 | - y: 0 |
412 | - width: parent.width |
413 | - height: parent.height |
414 | - visible: overlay.active |
415 | - |
416 | - Column { |
417 | - id: labelGroup |
418 | - spacing: units.gu(3) |
419 | - |
420 | - anchors { |
421 | - margins: d.edgeMargin |
422 | - left: parent.left |
423 | - top: overlay.edge == "bottom" ? undefined : parent.top |
424 | - bottom: overlay.edge == "bottom" ? parent.bottom : undefined |
425 | - } |
426 | - |
427 | - Label { |
428 | - id: titleLabel |
429 | - fontSize: "x-large" |
430 | - width: units.gu(25) |
431 | - wrapMode: Text.WordWrap |
432 | - } |
433 | - |
434 | - Label { |
435 | - id: textLabel |
436 | - width: units.gu(25) |
437 | - wrapMode: Text.WordWrap |
438 | - } |
439 | - |
440 | - Label { |
441 | - id: skipLabel |
442 | - objectName: "skipLabel" |
443 | - text: i18n.tr("Skip intro") |
444 | - color: UbuntuColors.orange |
445 | - fontSize: "small" |
446 | - |
447 | - Icon { |
448 | - anchors.left: parent.right |
449 | - anchors.verticalCenter: parent.verticalCenter |
450 | - height: units.dp(12) |
451 | - width: units.dp(12) |
452 | - name: "chevron" |
453 | - color: UbuntuColors.orange |
454 | - } |
455 | - |
456 | - MouseArea { |
457 | - // Make clickable area bigger than just the link because |
458 | - // otherwise, the edge demo will feel hard to dismiss. |
459 | - anchors.fill: parent |
460 | - anchors.margins: -units.gu(5) |
461 | - onClicked: overlay.doSkip() |
462 | - } |
463 | - } |
464 | - } |
465 | - |
466 | - LinearGradient { |
467 | - id: edgeHint |
468 | - property int size: 1 |
469 | - cached: false |
470 | - visible: overlay.edge != "none" |
471 | - gradient: Gradient { |
472 | - GradientStop { |
473 | - position: 0.0 |
474 | - color: Qt.hsla(16.0/360.0, 0.83, 0.47, 0.4) // UbuntuColors.orange, but transparent |
475 | - } |
476 | - GradientStop { |
477 | - position: 1.0 |
478 | - color: "transparent" |
479 | - } |
480 | - } |
481 | - anchors.fill: parent |
482 | - start: { |
483 | - if (overlay.edge == "right") { |
484 | - return Qt.point(width, 0); |
485 | - } else if (overlay.edge == "left") { |
486 | - return Qt.point(0, 0); |
487 | - } else if (overlay.edge == "top") { |
488 | - return Qt.point(0, 0); |
489 | - } else { |
490 | - return Qt.point(0, height); |
491 | - } |
492 | - } |
493 | - end: { |
494 | - if (overlay.edge == "right") { |
495 | - return Qt.point(width - size, 0); |
496 | - } else if (overlay.edge == "left") { |
497 | - return Qt.point(size, 0); |
498 | - } else if (overlay.edge == "top") { |
499 | - return Qt.point(0, size); |
500 | - } else { |
501 | - return Qt.point(0, height - size); |
502 | - } |
503 | - } |
504 | - } |
505 | - } |
506 | - |
507 | - SequentialAnimation { |
508 | - id: wholeAnimation |
509 | - objectName: "wholeAnimation" |
510 | - running: overlay.active |
511 | - |
512 | - ParallelAnimation { |
513 | - id: fadeInAnimation |
514 | - |
515 | - StandardAnimation { |
516 | - target: labelGroup |
517 | - property: { |
518 | - if (overlay.edge == "right" || overlay.edge == "left") { |
519 | - return "anchors.leftMargin"; |
520 | - } else if (overlay.edge == "bottom") { |
521 | - return "anchors.bottomMargin"; |
522 | - } else { |
523 | - return "anchors.topMargin"; |
524 | - } |
525 | - } |
526 | - from: { |
527 | - if (overlay.edge == "right") { |
528 | - return d.edgeMargin + units.gu(3) |
529 | - } else { |
530 | - return d.edgeMargin - units.gu(3) |
531 | - } |
532 | - } |
533 | - to: d.edgeMargin |
534 | - duration: overlay.edge == "none" ? 0 : UbuntuAnimation.SleepyDuration |
535 | - } |
536 | - StandardAnimation { |
537 | - target: overlay |
538 | - property: "opacity" |
539 | - from: 0.0 |
540 | - to: 1.0 |
541 | - duration: UbuntuAnimation.SleepyDuration |
542 | - } |
543 | - } |
544 | - |
545 | - SequentialAnimation { |
546 | - id: hintAnimation |
547 | - loops: Animation.Infinite |
548 | - property string prop: (overlay.edge == "left" || overlay.edge == "right") ? "x" : "y" |
549 | - property double endVal: units.dp(5) * ((overlay.edge == "left" || overlay.edge == "top") ? 1 : -1) |
550 | - property double maxGlow: units.dp(20) |
551 | - property int duration: overlay.edge == "none" ? 0 : UbuntuAnimation.SleepyDuration |
552 | - |
553 | - ParallelAnimation { |
554 | - StandardAnimation { target: hintGroup; property: hintAnimation.prop; from: 0; to: hintAnimation.endVal; duration: hintAnimation.duration } |
555 | - StandardAnimation { target: edgeHint; property: "size"; from: 1; to: hintAnimation.maxGlow; duration: hintAnimation.duration } |
556 | - } |
557 | - |
558 | - // Undo the above |
559 | - ParallelAnimation { |
560 | - StandardAnimation { target: hintGroup; property: hintAnimation.prop; from: hintAnimation.endVal; to: 0; duration: hintAnimation.duration } |
561 | - StandardAnimation { target: edgeHint; property: "size"; from: hintAnimation.maxGlow; to: 1; duration: hintAnimation.duration } |
562 | - } |
563 | - } |
564 | - } |
565 | -} |
566 | |
567 | === modified file 'qml/Launcher/Launcher.qml' |
568 | --- qml/Launcher/Launcher.qml 2014-12-11 13:24:26 +0000 |
569 | +++ qml/Launcher/Launcher.qml 2015-02-11 17:00:33 +0000 |
570 | @@ -26,6 +26,7 @@ |
571 | property bool autohideEnabled: false |
572 | property bool available: true // can be used to disable all interactions |
573 | property alias inverted: panel.inverted |
574 | + property bool shadeBackground: true // can be used to disable background shade when launcher is visible |
575 | |
576 | property int panelWidth: units.gu(8) |
577 | property int dragAreaWidth: units.gu(1) |
578 | @@ -33,6 +34,10 @@ |
579 | property real progress: dragArea.dragging && dragArea.touchX > panelWidth ? |
580 | (width * (dragArea.touchX-panelWidth) / (width - panelWidth)) : 0 |
581 | |
582 | + readonly property bool dragging: dragArea.dragging |
583 | + readonly property real dragDistance: dragArea.dragging ? dragArea.touchX : 0 |
584 | + readonly property real visibleWidth: panel.width + panel.x |
585 | + |
586 | readonly property bool shown: panel.x > -panel.width |
587 | |
588 | // emitted when an application is selected |
589 | @@ -154,7 +159,7 @@ |
590 | |
591 | MouseArea { |
592 | id: launcherDragArea |
593 | - enabled: root.state == "visible" |
594 | + enabled: root.available && root.state == "visible" |
595 | anchors.fill: panel |
596 | anchors.rightMargin: -units.gu(2) |
597 | drag { |
598 | @@ -180,7 +185,7 @@ |
599 | right: parent.right |
600 | bottom: parent.bottom |
601 | } |
602 | - enabled: root.state == "visible" |
603 | + enabled: root.shadeBackground && root.state == "visible" |
604 | onPressed: { |
605 | root.state = "" |
606 | } |
607 | @@ -190,7 +195,7 @@ |
608 | id: backgroundShade |
609 | anchors.fill: parent |
610 | color: "black" |
611 | - opacity: root.state == "visible" ? 0.6 : 0 |
612 | + opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0 |
613 | |
614 | Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } } |
615 | } |
616 | @@ -198,14 +203,14 @@ |
617 | LauncherPanel { |
618 | id: panel |
619 | objectName: "launcherPanel" |
620 | - enabled: root.available |
621 | + enabled: root.available && root.state == "visible" |
622 | width: root.panelWidth |
623 | anchors { |
624 | top: parent.top |
625 | bottom: parent.bottom |
626 | } |
627 | x: -width |
628 | - visible: x > -width || dragArea.status === DirectionalDragArea.Undecided |
629 | + visible: root.x > 0 || x > -width || dragArea.status === DirectionalDragArea.Undecided |
630 | model: LauncherModel |
631 | |
632 | property bool animate: true |
633 | @@ -247,6 +252,7 @@ |
634 | direction: Direction.Rightwards |
635 | |
636 | enabled: root.available |
637 | + x: -root.x // so if launcher is adjusted relative to screen, we stay put (like tutorial does when teasing) |
638 | width: root.dragAreaWidth |
639 | height: root.height |
640 | |
641 | @@ -260,7 +266,7 @@ |
642 | // would appear right next to the user's finger out of nowhere. |
643 | // Instead, we make the panel go towards the user's finger in several |
644 | // steps. ie., in an animated way. |
645 | - var targetPanelX = Math.min(0, touchX - panel.width) |
646 | + var targetPanelX = Math.min(0, touchX - panel.width) - root.x |
647 | var delta = targetPanelX - panel.x |
648 | // the trick is not to go all the way (1.0) as it would cause a sudden jump |
649 | panel.x += 0.4 * delta |
650 | @@ -292,7 +298,7 @@ |
651 | name: "visible" |
652 | PropertyChanges { |
653 | target: panel |
654 | - x: 0 |
655 | + x: -root.x // so we never go past panelWidth, even when teased by tutorial |
656 | } |
657 | }, |
658 | State { |
659 | |
660 | === modified file 'qml/Shell.qml' |
661 | --- qml/Shell.qml 2015-02-11 17:00:33 +0000 |
662 | +++ qml/Shell.qml 2015-02-11 17:00:33 +0000 |
663 | @@ -36,6 +36,7 @@ |
664 | import "Components" |
665 | import "Notifications" |
666 | import "Stages" |
667 | +import "Tutorial" |
668 | import "Wizard" |
669 | import Unity.Notifications 1.0 as NotificationBackend |
670 | import Unity.Session 0.1 |
671 | @@ -62,7 +63,7 @@ |
672 | |
673 | readonly property bool locked: LightDM.Greeter.active && !LightDM.Greeter.authenticated && !forcedUnlock |
674 | readonly property alias hasLockedApp: greeter.hasLockedApp |
675 | - readonly property bool forcedUnlock: edgeDemo.running |
676 | + readonly property bool forcedUnlock: tutorial.running |
677 | onForcedUnlockChanged: if (forcedUnlock) lockscreen.hide() |
678 | |
679 | property bool sideStageEnabled: shell.width >= units.gu(100) |
680 | @@ -161,7 +162,7 @@ |
681 | |
682 | ScreenGrabber { |
683 | id: screenGrabber |
684 | - z: edgeDemo.z + 10 |
685 | + z: dialogs.z + 10 |
686 | enabled: Powerd.status === Powerd.On |
687 | } |
688 | |
689 | @@ -252,14 +253,16 @@ |
690 | } |
691 | |
692 | onApplicationAdded: { |
693 | - if (greeter.shown && appId != "unity8-dash") { |
694 | - greeter.startUnlock() |
695 | + if (appId != "unity8-dash") { |
696 | + if (greeter.shown) { |
697 | + greeter.startUnlock(); |
698 | + } |
699 | |
700 | // If this happens on first boot, we may be in edge |
701 | // tutorial or wizard while receiving a call. But a call |
702 | // is more important than wizard so just bail out of those. |
703 | - if (edgeDemo.running) { |
704 | - edgeDemo.hideEdgeDemos(); |
705 | + if (tutorial.running) { |
706 | + tutorial.finish(); |
707 | wizard.hide(); |
708 | } |
709 | } |
710 | @@ -287,7 +290,7 @@ |
711 | source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml" |
712 | : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml" |
713 | |
714 | - property bool interactive: edgeDemo.stagesEnabled |
715 | + property bool interactive: tutorial.stagesEnabled |
716 | && !greeter.shown |
717 | && !lockscreen.shown |
718 | && panel.indicators.fullyClosed |
719 | @@ -320,7 +323,7 @@ |
720 | Binding { |
721 | target: applicationsDisplayLoader.item |
722 | property: "spreadEnabled" |
723 | - value: edgeDemo.stagesEnabled && !greeter.hasLockedApp |
724 | + value: tutorial.stagesEnabled && !greeter.hasLockedApp |
725 | } |
726 | Binding { |
727 | target: applicationsDisplayLoader.item |
728 | @@ -653,9 +656,13 @@ |
729 | LauncherModel.setUser(user); |
730 | } |
731 | |
732 | - onTapped: launcher.tease() |
733 | + onTapped: { |
734 | + if (!tutorial.running) { |
735 | + launcher.tease(); |
736 | + } |
737 | + } |
738 | onDraggingChanged: { |
739 | - if (dragging) { |
740 | + if (dragging && !tutorial.running) { |
741 | launcher.tease(); |
742 | } |
743 | } |
744 | @@ -693,7 +700,7 @@ |
745 | |
746 | onStatusChanged: { |
747 | if (Powerd.status === Powerd.Off && reason !== Powerd.Proximity && |
748 | - !callManager.hasCalls && !edgeDemo.running) { |
749 | + !callManager.hasCalls && !tutorial.running) { |
750 | // We don't want to simply call greeter.showNow() here, because |
751 | // that will take too long. Qt will delay button event |
752 | // handling until the greeter is done loading and may think the |
753 | @@ -709,7 +716,7 @@ |
754 | } |
755 | |
756 | function showHome() { |
757 | - if (edgeDemo.running) { |
758 | + if (tutorial.running) { |
759 | return |
760 | } |
761 | |
762 | @@ -751,8 +758,8 @@ |
763 | anchors.fill: parent //because this draws indicator menus |
764 | indicators { |
765 | hides: [launcher] |
766 | - available: edgeDemo.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp |
767 | - contentEnabled: edgeDemo.panelContentEnabled |
768 | + available: tutorial.panelEnabled && (!shell.locked || AccountsService.enableIndicatorsWhileLocked) && !greeter.hasLockedApp |
769 | + contentEnabled: tutorial.panelContentEnabled |
770 | width: parent.width > units.gu(60) ? units.gu(40) : parent.width |
771 | |
772 | minimizedPanelHeight: units.gu(3) |
773 | @@ -785,8 +792,9 @@ |
774 | anchors.bottom: parent.bottom |
775 | width: parent.width |
776 | dragAreaWidth: shell.edgeSize |
777 | - available: edgeDemo.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp |
778 | + available: tutorial.launcherEnabled && (!shell.locked || AccountsService.enableLauncherWhileLocked) && !greeter.hasLockedApp |
779 | inverted: usageModeSettings.usageMode === "Staged" |
780 | + shadeBackground: !tutorial.running |
781 | |
782 | onShowDashHome: showHome() |
783 | onDash: showDash() |
784 | @@ -799,7 +807,7 @@ |
785 | if (greeter.hasLockedApp) { |
786 | greeter.startUnlock() |
787 | } |
788 | - if (!edgeDemo.running) |
789 | + if (!tutorial.running) |
790 | shell.activateApplication(appId) |
791 | } |
792 | onShownChanged: { |
793 | @@ -872,15 +880,17 @@ |
794 | } |
795 | } |
796 | |
797 | - EdgeDemo { |
798 | - id: edgeDemo |
799 | - objectName: "edgeDemo" |
800 | - z: dialogs.z + 10 |
801 | - paused: Powerd.status === Powerd.Off || wizard.active // Saves power |
802 | - greeter: greeter |
803 | + Tutorial { |
804 | + id: tutorial |
805 | + objectName: "tutorial" |
806 | + active: AccountsService.demoEdges |
807 | + paused: LightDM.Greeter.active |
808 | launcher: launcher |
809 | panel: panel |
810 | stages: stages |
811 | + overlay: overlay |
812 | + |
813 | + onFinished: AccountsService.demoEdges = false |
814 | } |
815 | |
816 | Connections { |
817 | @@ -890,7 +900,7 @@ |
818 | |
819 | Rectangle { |
820 | id: shutdownFadeOutRectangle |
821 | - z: edgeDemo.z + 10 |
822 | + z: screenGrabber.z + 10 |
823 | enabled: false |
824 | visible: false |
825 | color: "black" |
826 | |
827 | === added directory 'qml/Tutorial' |
828 | === added file 'qml/Tutorial/Arrow.qml' |
829 | --- qml/Tutorial/Arrow.qml 1970-01-01 00:00:00 +0000 |
830 | +++ qml/Tutorial/Arrow.qml 2015-02-11 17:00:33 +0000 |
831 | @@ -0,0 +1,56 @@ |
832 | +/* |
833 | + * Copyright (C) 2014 Canonical, Ltd. |
834 | + * |
835 | + * This program is free software; you can redistribute it and/or modify |
836 | + * it under the terms of the GNU General Public License as published by |
837 | + * the Free Software Foundation; version 3. |
838 | + * |
839 | + * This program is distributed in the hope that it will be useful, |
840 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
841 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
842 | + * GNU General Public License for more details. |
843 | + * |
844 | + * You should have received a copy of the GNU General Public License |
845 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
846 | + */ |
847 | + |
848 | +import QtQuick 2.3 |
849 | +import Ubuntu.Components 1.1 |
850 | + |
851 | +Item { |
852 | + id: root |
853 | + |
854 | + property alias color: circle.color |
855 | + |
856 | + // Will make whole arrow darker |
857 | + property real darkenBy: 0 |
858 | + |
859 | + property alias chevronOpacity: chevron.opacity |
860 | + |
861 | + //// |
862 | + |
863 | + Rectangle { |
864 | + id: circle |
865 | + anchors.fill: parent |
866 | + radius: width / 2 |
867 | + } |
868 | + |
869 | + Image { |
870 | + id: chevron |
871 | + anchors.centerIn: parent |
872 | + source: Qt.resolvedUrl("graphics/chevron.png") |
873 | + fillMode: Image.PreserveAspectFit |
874 | + sourceSize.width: 152 |
875 | + sourceSize.height: 152 |
876 | + width: parent.width / 2 |
877 | + height: parent.height / 2 |
878 | + } |
879 | + |
880 | + Rectangle { |
881 | + id: darkCircle |
882 | + anchors.fill: parent |
883 | + radius: width / 2 |
884 | + color: "black" |
885 | + opacity: root.darkenBy |
886 | + } |
887 | +} |
888 | |
889 | === added file 'qml/Tutorial/Slider.qml' |
890 | --- qml/Tutorial/Slider.qml 1970-01-01 00:00:00 +0000 |
891 | +++ qml/Tutorial/Slider.qml 2015-02-11 17:00:33 +0000 |
892 | @@ -0,0 +1,117 @@ |
893 | +/* |
894 | + * Copyright (C) 2014 Canonical, Ltd. |
895 | + * |
896 | + * This program is free software; you can redistribute it and/or modify |
897 | + * it under the terms of the GNU General Public License as published by |
898 | + * the Free Software Foundation; version 3. |
899 | + * |
900 | + * This program is distributed in the hope that it will be useful, |
901 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
902 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
903 | + * GNU General Public License for more details. |
904 | + * |
905 | + * You should have received a copy of the GNU General Public License |
906 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
907 | + */ |
908 | + |
909 | +import QtQuick 2.3 |
910 | +import Ubuntu.Components 1.1 |
911 | + |
912 | +Item { |
913 | + id: root |
914 | + |
915 | + // Whether this slider is short or long |
916 | + property bool shortSwipe |
917 | + |
918 | + // How far the user has slid |
919 | + property real offset |
920 | + |
921 | + // Set to true when slider is being used |
922 | + property bool active |
923 | + |
924 | + // How far in percentage terms |
925 | + readonly property real percent: d.slideOffset / target.x |
926 | + |
927 | + QtObject { |
928 | + id: d |
929 | + readonly property color trayColor: "#424141" |
930 | + readonly property real margin: units.gu(0.5) |
931 | + readonly property real arrowSize: root.height - margin * 2 |
932 | + readonly property real dotSize: units.dp(1) |
933 | + readonly property real slideOffset: Math.min(root.offset - offscreenOffset, target.x) |
934 | + readonly property real offscreenOffset: units.gu(2) |
935 | + } |
936 | + |
937 | + implicitWidth: shortSwipe ? units.gu(15) : units.gu(27.5) |
938 | + implicitHeight: units.gu(6.5) |
939 | + |
940 | + Rectangle { |
941 | + color: d.trayColor |
942 | + anchors.fill: parent |
943 | + anchors.rightMargin: clipBox.width - 1 |
944 | + } |
945 | + |
946 | + // We want to have a circular border around the target. But we can't just |
947 | + // do a radius on two of a rectangle's corners. So we clip a full circle. |
948 | + Item { |
949 | + id: clipBox |
950 | + |
951 | + clip: true |
952 | + anchors.top: parent.top |
953 | + anchors.bottom: parent.bottom |
954 | + anchors.right: parent.right |
955 | + width: parent.height / 2 |
956 | + |
957 | + Rectangle { |
958 | + color: d.trayColor |
959 | + anchors.top: parent.top |
960 | + anchors.bottom: parent.bottom |
961 | + anchors.right: parent.right |
962 | + width: parent.width * 2 |
963 | + radius: parent.width |
964 | + } |
965 | + } |
966 | + |
967 | + Arrow { |
968 | + id: target |
969 | + width: d.arrowSize |
970 | + height: d.arrowSize |
971 | + color: "#73000000" |
972 | + chevronOpacity: 0.52 |
973 | + anchors.right: parent.right |
974 | + anchors.rightMargin: d.margin |
975 | + anchors.verticalCenter: parent.verticalCenter |
976 | + } |
977 | + |
978 | + Row { |
979 | + anchors.left: handle.horizontalCenter |
980 | + anchors.right: target.horizontalCenter |
981 | + anchors.verticalCenter: parent.verticalCenter |
982 | + |
983 | + layoutDirection: Qt.RightToLeft |
984 | + spacing: d.dotSize * 2 |
985 | + |
986 | + Repeater { |
987 | + model: parent.width / (parent.spacing + d.dotSize) |
988 | + Rectangle { |
989 | + anchors.verticalCenter: parent ? parent.verticalCenter : undefined |
990 | + height: d.dotSize |
991 | + width: height |
992 | + radius: width |
993 | + color: "white" |
994 | + opacity: 0.2 |
995 | + } |
996 | + } |
997 | + } |
998 | + |
999 | + Arrow { |
1000 | + id: handle |
1001 | + width: d.arrowSize |
1002 | + height: d.arrowSize |
1003 | + color: UbuntuColors.orange |
1004 | + darkenBy: root.active ? 0.5 : 0 |
1005 | + anchors.left: parent.left |
1006 | + anchors.leftMargin: d.slideOffset |
1007 | + anchors.verticalCenter: parent.verticalCenter |
1008 | + } |
1009 | +} |
1010 | |
1011 | === added file 'qml/Tutorial/Tutorial.qml' |
1012 | --- qml/Tutorial/Tutorial.qml 1970-01-01 00:00:00 +0000 |
1013 | +++ qml/Tutorial/Tutorial.qml 2015-02-11 17:00:33 +0000 |
1014 | @@ -0,0 +1,85 @@ |
1015 | +/* |
1016 | + * Copyright (C) 2014 Canonical, Ltd. |
1017 | + * |
1018 | + * This program is free software; you can redistribute it and/or modify |
1019 | + * it under the terms of the GNU General Public License as published by |
1020 | + * the Free Software Foundation; version 3. |
1021 | + * |
1022 | + * This program is distributed in the hope that it will be useful, |
1023 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1024 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1025 | + * GNU General Public License for more details. |
1026 | + * |
1027 | + * You should have received a copy of the GNU General Public License |
1028 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1029 | + */ |
1030 | + |
1031 | +import QtQuick 2.3 |
1032 | +import Ubuntu.Components 1.1 |
1033 | + |
1034 | +Item { |
1035 | + id: root |
1036 | + |
1037 | + property alias active: loader.active |
1038 | + property bool paused |
1039 | + |
1040 | + property Item launcher |
1041 | + property Item panel |
1042 | + property Item stages |
1043 | + property Item overlay |
1044 | + |
1045 | + readonly property bool launcherEnabled: loader.item ? loader.item.launcherEnabled : true |
1046 | + readonly property bool stagesEnabled: loader.item ? loader.item.stagesEnabled : true |
1047 | + readonly property bool panelEnabled: loader.item ? loader.item.panelEnabled : true |
1048 | + readonly property bool panelContentEnabled: loader.item ? loader.item.panelContentEnabled : true |
1049 | + readonly property bool running: loader.item ? loader.item.running : false |
1050 | + |
1051 | + function finish() { |
1052 | + if (loader.item) { |
1053 | + loader.item.finish(); |
1054 | + } |
1055 | + } |
1056 | + |
1057 | + signal finished() |
1058 | + |
1059 | + Loader { |
1060 | + id: loader |
1061 | + anchors.fill: parent |
1062 | + source: "TutorialContent.qml" |
1063 | + |
1064 | + Binding { |
1065 | + target: loader.item |
1066 | + property: "paused" |
1067 | + value: root.paused |
1068 | + } |
1069 | + |
1070 | + Binding { |
1071 | + target: loader.item |
1072 | + property: "launcher" |
1073 | + value: root.launcher |
1074 | + } |
1075 | + |
1076 | + Binding { |
1077 | + target: loader.item |
1078 | + property: "panel" |
1079 | + value: root.panel |
1080 | + } |
1081 | + |
1082 | + Binding { |
1083 | + target: loader.item |
1084 | + property: "stages" |
1085 | + value: root.stages |
1086 | + } |
1087 | + |
1088 | + Binding { |
1089 | + target: loader.item |
1090 | + property: "overlay" |
1091 | + value: root.overlay |
1092 | + } |
1093 | + |
1094 | + Connections { |
1095 | + target: loader.item |
1096 | + onFinished: root.finished() |
1097 | + } |
1098 | + } |
1099 | +} |
1100 | |
1101 | === added file 'qml/Tutorial/TutorialContent.qml' |
1102 | --- qml/Tutorial/TutorialContent.qml 1970-01-01 00:00:00 +0000 |
1103 | +++ qml/Tutorial/TutorialContent.qml 2015-02-11 17:00:33 +0000 |
1104 | @@ -0,0 +1,130 @@ |
1105 | +/* |
1106 | + * Copyright (C) 2013,2014 Canonical, Ltd. |
1107 | + * |
1108 | + * This program is free software; you can redistribute it and/or modify |
1109 | + * it under the terms of the GNU General Public License as published by |
1110 | + * the Free Software Foundation; version 3. |
1111 | + * |
1112 | + * This program is distributed in the hope that it will be useful, |
1113 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1114 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1115 | + * GNU General Public License for more details. |
1116 | + * |
1117 | + * You should have received a copy of the GNU General Public License |
1118 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1119 | + */ |
1120 | + |
1121 | +import QtQuick 2.3 |
1122 | +import Ubuntu.Components 1.1 |
1123 | + |
1124 | +Item { |
1125 | + id: root |
1126 | + |
1127 | + property Item launcher |
1128 | + property Item panel |
1129 | + property Item stages |
1130 | + property Item overlay |
1131 | + |
1132 | + readonly property bool launcherEnabled: !running || |
1133 | + (!paused && loader.target === leftComponent) |
1134 | + readonly property bool stagesEnabled: !running |
1135 | + readonly property bool panelEnabled: !running |
1136 | + readonly property bool panelContentEnabled: !running |
1137 | + readonly property bool running: loader.sourceComponent !== null |
1138 | + |
1139 | + property bool paused: false |
1140 | + |
1141 | + signal finished() |
1142 | + |
1143 | + function finish() { |
1144 | + d.stop(); |
1145 | + finished(); |
1146 | + } |
1147 | + |
1148 | + //// |
1149 | + |
1150 | + Component.onCompleted: { |
1151 | + d.start(); |
1152 | + } |
1153 | + |
1154 | + QtObject { |
1155 | + id: d |
1156 | + |
1157 | + function stop() { |
1158 | + loader.sourceComponent = null; |
1159 | + } |
1160 | + |
1161 | + function start() { |
1162 | + loader.load(leftComponent); |
1163 | + } |
1164 | + } |
1165 | + |
1166 | + Loader { |
1167 | + id: loader |
1168 | + objectName: "tutorialLoader" |
1169 | + |
1170 | + property Component target: { |
1171 | + if (next) { |
1172 | + return next; |
1173 | + } else if (loader.item && loader.item.shown) { |
1174 | + return sourceComponent; |
1175 | + } else { |
1176 | + return null; |
1177 | + } |
1178 | + } |
1179 | + |
1180 | + property Component next: null |
1181 | + |
1182 | + function load(comp) { |
1183 | + if (loader.item) { |
1184 | + next = comp; |
1185 | + loader.item.hide(); |
1186 | + } else { |
1187 | + loader.sourceComponent = comp; |
1188 | + } |
1189 | + } |
1190 | + |
1191 | + Connections { |
1192 | + target: loader.item |
1193 | + onFinished: { |
1194 | + loader.sourceComponent = loader.next; |
1195 | + if (loader.next != null) { |
1196 | + loader.next = null; |
1197 | + } else { |
1198 | + root.finished(); |
1199 | + } |
1200 | + } |
1201 | + } |
1202 | + |
1203 | + Binding { |
1204 | + target: loader.item |
1205 | + property: "paused" |
1206 | + value: root.paused |
1207 | + } |
1208 | + } |
1209 | + |
1210 | + Component { |
1211 | + id: leftComponent |
1212 | + TutorialLeft { |
1213 | + objectName: "tutorialLeft" |
1214 | + parent: root.stages |
1215 | + anchors.fill: parent |
1216 | + launcher: root.launcher |
1217 | + |
1218 | + onFinished: loader.load(leftFinishComponent) |
1219 | + } |
1220 | + } |
1221 | + |
1222 | + Component { |
1223 | + id: leftFinishComponent |
1224 | + TutorialLeftFinish { |
1225 | + objectName: "tutorialLeftFinish" |
1226 | + parent: root.stages |
1227 | + anchors.fill: parent |
1228 | + textXOffset: root.launcher.panelWidth |
1229 | + backgroundFadesOut: true |
1230 | + |
1231 | + onFinished: root.launcher.hide() |
1232 | + } |
1233 | + } |
1234 | +} |
1235 | |
1236 | === added file 'qml/Tutorial/TutorialLeft.qml' |
1237 | --- qml/Tutorial/TutorialLeft.qml 1970-01-01 00:00:00 +0000 |
1238 | +++ qml/Tutorial/TutorialLeft.qml 2015-02-11 17:00:33 +0000 |
1239 | @@ -0,0 +1,91 @@ |
1240 | +/* |
1241 | + * Copyright (C) 2014 Canonical, Ltd. |
1242 | + * |
1243 | + * This program is free software; you can redistribute it and/or modify |
1244 | + * it under the terms of the GNU General Public License as published by |
1245 | + * the Free Software Foundation; version 3. |
1246 | + * |
1247 | + * This program is distributed in the hope that it will be useful, |
1248 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1249 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1250 | + * GNU General Public License for more details. |
1251 | + * |
1252 | + * You should have received a copy of the GNU General Public License |
1253 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1254 | + */ |
1255 | + |
1256 | +import QtQuick 2.3 |
1257 | +import Ubuntu.Components 1.1 |
1258 | +import "." as LocalComponents |
1259 | + |
1260 | +TutorialPage { |
1261 | + id: root |
1262 | + |
1263 | + property var launcher |
1264 | + |
1265 | + title: i18n.tr("Open the launcher") |
1266 | + text: i18n.tr("Short swipe from the left edge.") |
1267 | + |
1268 | + textXOffset: root.launcher.x + root.launcher.visibleWidth |
1269 | + |
1270 | + Connections { |
1271 | + target: root.launcher |
1272 | + |
1273 | + onStateChanged: { |
1274 | + if (root.launcher.state === "visible") { |
1275 | + finishTimer.start(); |
1276 | + } |
1277 | + } |
1278 | + |
1279 | + onDash: { |
1280 | + finishTimer.stop(); |
1281 | + root.showError(); |
1282 | + root.launcher.hide(); |
1283 | + } |
1284 | + } |
1285 | + |
1286 | + SequentialAnimation { |
1287 | + id: teaseAnimation |
1288 | + paused: running && root.paused |
1289 | + running: !slider.active && root.launcher.visibleWidth === 0 && root.shown |
1290 | + loops: Animation.Infinite |
1291 | + |
1292 | + UbuntuNumberAnimation { |
1293 | + target: root.launcher |
1294 | + property: "x" |
1295 | + to: units.gu(2) |
1296 | + duration: UbuntuAnimation.SleepyDuration |
1297 | + } |
1298 | + UbuntuNumberAnimation { |
1299 | + target: root.launcher |
1300 | + property: "x" |
1301 | + to: 0 |
1302 | + duration: UbuntuAnimation.SleepyDuration |
1303 | + } |
1304 | + } |
1305 | + |
1306 | + Timer { |
1307 | + id: finishTimer |
1308 | + interval: 1 |
1309 | + onTriggered: { |
1310 | + root.hide(); |
1311 | + root.launcher.x = 0; // make sure to reset launcher before we go |
1312 | + } |
1313 | + } |
1314 | + |
1315 | + foreground { |
1316 | + children: [ |
1317 | + LocalComponents.Slider { |
1318 | + id: slider |
1319 | + anchors { |
1320 | + left: parent.left |
1321 | + top: parent.top |
1322 | + topMargin: root.textBottom + units.gu(3) |
1323 | + } |
1324 | + offset: root.launcher.x + root.launcher.visibleWidth + root.launcher.progress |
1325 | + active: root.launcher.dragging |
1326 | + shortSwipe: true |
1327 | + } |
1328 | + ] |
1329 | + } |
1330 | +} |
1331 | |
1332 | === added file 'qml/Tutorial/TutorialLeftFinish.qml' |
1333 | --- qml/Tutorial/TutorialLeftFinish.qml 1970-01-01 00:00:00 +0000 |
1334 | +++ qml/Tutorial/TutorialLeftFinish.qml 2015-02-11 17:00:33 +0000 |
1335 | @@ -0,0 +1,47 @@ |
1336 | +/* |
1337 | + * Copyright (C) 2014 Canonical, Ltd. |
1338 | + * |
1339 | + * This program is free software; you can redistribute it and/or modify |
1340 | + * it under the terms of the GNU General Public License as published by |
1341 | + * the Free Software Foundation; version 3. |
1342 | + * |
1343 | + * This program is distributed in the hope that it will be useful, |
1344 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1345 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1346 | + * GNU General Public License for more details. |
1347 | + * |
1348 | + * You should have received a copy of the GNU General Public License |
1349 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1350 | + */ |
1351 | + |
1352 | +import QtQuick 2.3 |
1353 | +import Ubuntu.Components 1.1 |
1354 | + |
1355 | +TutorialPage { |
1356 | + id: root |
1357 | + |
1358 | + title: i18n.tr("These are the shortcuts to favorite apps") |
1359 | + text: i18n.tr("Tap here to finish.") |
1360 | + fullTextWidth: true |
1361 | + |
1362 | + foreground { |
1363 | + children: [ |
1364 | + Image { |
1365 | + objectName: "tick" |
1366 | + anchors { |
1367 | + horizontalCenter: parent.horizontalCenter |
1368 | + top: parent.top |
1369 | + topMargin: root.textBottom + units.gu(3) |
1370 | + } |
1371 | + source: Qt.resolvedUrl("graphics/tick.png") |
1372 | + height: units.gu(6.5) |
1373 | + width: units.gu(6.5) |
1374 | + |
1375 | + MouseArea { |
1376 | + anchors.fill: parent |
1377 | + onClicked: root.hide() |
1378 | + } |
1379 | + } |
1380 | + ] |
1381 | + } |
1382 | +} |
1383 | |
1384 | === added file 'qml/Tutorial/TutorialPage.qml' |
1385 | --- qml/Tutorial/TutorialPage.qml 1970-01-01 00:00:00 +0000 |
1386 | +++ qml/Tutorial/TutorialPage.qml 2015-02-11 17:00:33 +0000 |
1387 | @@ -0,0 +1,240 @@ |
1388 | +/* |
1389 | + * Copyright (C) 2013,2014 Canonical, Ltd. |
1390 | + * |
1391 | + * This program is free software; you can redistribute it and/or modify |
1392 | + * it under the terms of the GNU General Public License as published by |
1393 | + * the Free Software Foundation; version 3. |
1394 | + * |
1395 | + * This program is distributed in the hope that it will be useful, |
1396 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1397 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1398 | + * GNU General Public License for more details. |
1399 | + * |
1400 | + * You should have received a copy of the GNU General Public License |
1401 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1402 | + */ |
1403 | + |
1404 | +import QtQuick 2.3 |
1405 | +import Ubuntu.Components 1.1 |
1406 | +import "../Components" |
1407 | + |
1408 | +Showable { |
1409 | + id: root |
1410 | + |
1411 | + // This is the header displayed, like "Right edge" |
1412 | + property alias title: titleLabel.text |
1413 | + |
1414 | + // This is the block of text displayed below the header |
1415 | + property alias text: textLabel.text |
1416 | + |
1417 | + // Whether animations are paused |
1418 | + property bool paused |
1419 | + |
1420 | + // Whether to give the text the full width that the title has |
1421 | + property bool fullTextWidth |
1422 | + |
1423 | + // Whether whole page (background + foreground) or just the foreground fades in |
1424 | + property bool backgroundFadesIn: false |
1425 | + |
1426 | + // Whether whole page (background + foreground) or just the foreground fades out |
1427 | + property bool backgroundFadesOut: false |
1428 | + |
1429 | + // The foreground Item, add children to it that you want to fade in |
1430 | + property alias foreground: foregroundExtra |
1431 | + |
1432 | + // The text label bottom, so you can position elements relative to it |
1433 | + readonly property real textBottom: Math.max(textLabel.y + textLabel.height, errorTextLabel.y + errorTextLabel.height) |
1434 | + |
1435 | + // The MouseArea that eats events (so you can adjust size as you will) |
1436 | + property alias mouseArea: mouseArea |
1437 | + |
1438 | + // X/Y offsets for text |
1439 | + property real textXOffset: 0 |
1440 | + property real textYOffset: 0 |
1441 | + |
1442 | + // Foreground opacity |
1443 | + property real foregroundOpacity: 1 |
1444 | + |
1445 | + signal finished() |
1446 | + |
1447 | + function showError() { |
1448 | + errorTimer.start(); |
1449 | + } |
1450 | + |
1451 | + //// |
1452 | + |
1453 | + shown: false |
1454 | + Component.onCompleted: show() |
1455 | + |
1456 | + property real _foregroundHideOpacity |
1457 | + |
1458 | + showAnimation: StandardAnimation { |
1459 | + property: root.backgroundFadesIn ? "opacity" : "_foregroundHideOpacity" |
1460 | + from: 0 |
1461 | + to: 1 |
1462 | + duration: root.backgroundFadesIn ? UbuntuAnimation.SleepyDuration : UbuntuAnimation.BriskDuration |
1463 | + } |
1464 | + |
1465 | + hideAnimation: StandardAnimation { |
1466 | + property: root.backgroundFadesOut ? "opacity" : "_foregroundHideOpacity" |
1467 | + to: 0 |
1468 | + duration: UbuntuAnimation.BriskDuration |
1469 | + onRunningChanged: { |
1470 | + if (!running) { |
1471 | + root.finished(); |
1472 | + } |
1473 | + } |
1474 | + } |
1475 | + |
1476 | + QtObject { |
1477 | + id: d |
1478 | + |
1479 | + readonly property real sideMargin: units.gu(5.5) |
1480 | + readonly property real verticalOffset: -units.gu(9) |
1481 | + readonly property real textXOffset: Math.max(0, root.textXOffset - sideMargin + units.gu(2)) |
1482 | + |
1483 | + property real fadeInOffset: { |
1484 | + if (showAnimation.running) { |
1485 | + var opacity = root[root.showAnimation.property] |
1486 | + return (1 - opacity) * units.gu(3); |
1487 | + } else { |
1488 | + return 0; |
1489 | + } |
1490 | + } |
1491 | + } |
1492 | + |
1493 | + Timer { |
1494 | + id: errorTimer |
1495 | + interval: 3500 |
1496 | + } |
1497 | + |
1498 | + MouseArea { // eat any errant presses |
1499 | + id: mouseArea |
1500 | + anchors.fill: parent |
1501 | + } |
1502 | + |
1503 | + Rectangle { |
1504 | + anchors.fill: parent |
1505 | + color: "black" |
1506 | + opacity: 0.82 |
1507 | + } |
1508 | + |
1509 | + Item { |
1510 | + id: foreground |
1511 | + anchors.fill: parent |
1512 | + opacity: root.foregroundOpacity < 1 ? root.foregroundOpacity : root._foregroundHideOpacity |
1513 | + |
1514 | + Label { |
1515 | + id: titleLabel |
1516 | + anchors { |
1517 | + top: parent.verticalCenter |
1518 | + topMargin: d.verticalOffset + root.textYOffset |
1519 | + left: parent.left |
1520 | + leftMargin: d.sideMargin + d.textXOffset |
1521 | + } |
1522 | + width: parent.width - d.sideMargin * 2 |
1523 | + horizontalAlignment: Text.AlignLeft |
1524 | + wrapMode: Text.Wrap |
1525 | + font.weight: Font.Light |
1526 | + font.pixelSize: units.gu(3.5) |
1527 | + } |
1528 | + |
1529 | + Label { |
1530 | + id: textLabel |
1531 | + anchors { |
1532 | + top: titleLabel.bottom |
1533 | + topMargin: units.gu(2) |
1534 | + left: parent.left |
1535 | + leftMargin: d.sideMargin + d.textXOffset |
1536 | + } |
1537 | + width: (parent.width - d.sideMargin * 2) * (fullTextWidth ? 1 : 0.66) |
1538 | + horizontalAlignment: Text.AlignLeft |
1539 | + wrapMode: Text.Wrap |
1540 | + font.weight: Font.Light |
1541 | + font.pixelSize: units.gu(2.5) |
1542 | + } |
1543 | + |
1544 | + // We use two separate labels like this rather than just changing |
1545 | + // the text of the above labels because we want to know where to place |
1546 | + // sliders (via root.textBottom) without having that place change |
1547 | + // as the text changes length. |
1548 | + Label { |
1549 | + id: errorTitleLabel |
1550 | + objectName: "errorTitleLabel" |
1551 | + anchors { |
1552 | + top: titleLabel.top |
1553 | + left: titleLabel.left |
1554 | + } |
1555 | + width: titleLabel.width |
1556 | + horizontalAlignment: titleLabel.horizontalAlignment |
1557 | + wrapMode: titleLabel.wrapMode |
1558 | + font.weight: titleLabel.font.weight |
1559 | + font.pixelSize: titleLabel.font.pixelSize |
1560 | + opacity: 0 |
1561 | + text: i18n.tr("You almost got it!") |
1562 | + } |
1563 | + |
1564 | + Label { |
1565 | + id: errorTextLabel |
1566 | + objectName: "errorTextLabel" |
1567 | + anchors { |
1568 | + top: errorTitleLabel.bottom |
1569 | + topMargin: textLabel.anchors.topMargin |
1570 | + left: textLabel.left |
1571 | + } |
1572 | + width: textLabel.width |
1573 | + horizontalAlignment: textLabel.horizontalAlignment |
1574 | + wrapMode: textLabel.wrapMode |
1575 | + font.weight: textLabel.font.weight |
1576 | + font.pixelSize: textLabel.font.pixelSize |
1577 | + opacity: 0 |
1578 | + text: i18n.tr("Try again.") |
1579 | + } |
1580 | + |
1581 | + // A place for subclasses to add extra widgets |
1582 | + Item { |
1583 | + id: foregroundExtra |
1584 | + anchors.fill: parent |
1585 | + } |
1586 | + } |
1587 | + |
1588 | + states: State { |
1589 | + name: "errorState" |
1590 | + when: errorTimer.running |
1591 | + PropertyChanges { target: titleLabel; opacity: 0 } |
1592 | + PropertyChanges { target: textLabel; opacity: 0 } |
1593 | + PropertyChanges { target: errorTitleLabel; opacity: 1 } |
1594 | + PropertyChanges { target: errorTextLabel; opacity: 1 } |
1595 | + } |
1596 | + |
1597 | + transitions: Transition { |
1598 | + to: "errorState" |
1599 | + reversible: true |
1600 | + SequentialAnimation { |
1601 | + ParallelAnimation { |
1602 | + StandardAnimation { |
1603 | + target: titleLabel |
1604 | + property: "opacity" |
1605 | + duration: UbuntuAnimation.BriskDuration |
1606 | + } |
1607 | + StandardAnimation { |
1608 | + target: textLabel |
1609 | + property: "opacity" |
1610 | + duration: UbuntuAnimation.BriskDuration |
1611 | + } |
1612 | + } |
1613 | + ParallelAnimation { |
1614 | + StandardAnimation { |
1615 | + target: errorTitleLabel |
1616 | + property: "opacity" |
1617 | + duration: UbuntuAnimation.BriskDuration |
1618 | + } |
1619 | + StandardAnimation { |
1620 | + target: errorTextLabel |
1621 | + property: "opacity" |
1622 | + duration: UbuntuAnimation.BriskDuration |
1623 | + } |
1624 | + } |
1625 | + } |
1626 | + } |
1627 | +} |
1628 | |
1629 | === added directory 'qml/Tutorial/graphics' |
1630 | === added file 'qml/Tutorial/graphics/chevron.png' |
1631 | Binary files qml/Tutorial/graphics/chevron.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/chevron.png 2015-02-11 17:00:33 +0000 differ |
1632 | === added file 'qml/Tutorial/graphics/tick.png' |
1633 | Binary files qml/Tutorial/graphics/tick.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/tick.png 2015-02-11 17:00:33 +0000 differ |
1634 | === renamed file 'tests/autopilot/unity8/shell/emulators/edges_demo.py' => 'tests/autopilot/unity8/shell/emulators/tutorial.py' |
1635 | --- tests/autopilot/unity8/shell/emulators/edges_demo.py 2014-12-16 16:32:40 +0000 |
1636 | +++ tests/autopilot/unity8/shell/emulators/tutorial.py 2015-02-11 17:00:33 +0000 |
1637 | @@ -29,112 +29,26 @@ |
1638 | logger = logging.getLogger(__name__) |
1639 | |
1640 | |
1641 | -class RightEdgeDemoOverlay( |
1642 | - ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
1643 | - |
1644 | - @classmethod |
1645 | - def validate_dbus_object(cls, path, state): |
1646 | - name = introspection.get_classname_from_path(path) |
1647 | - if name == b'EdgeDemoOverlay': |
1648 | - if state['edge'][1] == 'right': |
1649 | - return True |
1650 | - return False |
1651 | - |
1652 | - @autopilot.logging.log_action(logger.info) |
1653 | - def swipe(self): |
1654 | - """Swipe to the left to complete this demo step.""" |
1655 | - x, y, width, height = self.globalRect |
1656 | - start_x = x + width |
1657 | - stop_x = x |
1658 | - start_y = stop_y = y + height // 2 |
1659 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1660 | - return self.get_root_instance().wait_select_single( |
1661 | - edge='top', active=True) |
1662 | - |
1663 | - |
1664 | -class TopEdgeDemoOverlay( |
1665 | - ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
1666 | - |
1667 | - @classmethod |
1668 | - def validate_dbus_object(cls, path, state): |
1669 | - name = introspection.get_classname_from_path(path) |
1670 | - if name == b'EdgeDemoOverlay': |
1671 | - if state['edge'][1] == 'top': |
1672 | - return True |
1673 | - return False |
1674 | - |
1675 | - @autopilot.logging.log_action(logger.info) |
1676 | - def swipe(self): |
1677 | - """Swipe to the bottom to complete this demo step.""" |
1678 | - x, y, width, height = self.globalRect |
1679 | - start_x = stop_x = x + width // 2 |
1680 | - start_y = y |
1681 | - stop_y = y + height |
1682 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1683 | - return self.get_root_instance().wait_select_single( |
1684 | - edge='bottom', active=True) |
1685 | - |
1686 | - |
1687 | -class BottomEdgeDemoOverlay( |
1688 | - ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
1689 | - |
1690 | - @classmethod |
1691 | - def validate_dbus_object(cls, path, state): |
1692 | - name = introspection.get_classname_from_path(path) |
1693 | - if name == b'EdgeDemoOverlay': |
1694 | - if state['edge'][1] == 'bottom': |
1695 | - return True |
1696 | - return False |
1697 | - |
1698 | - @autopilot.logging.log_action(logger.info) |
1699 | - def swipe(self): |
1700 | - """Swipe to the top to complete this demo step.""" |
1701 | - x, y, width, height = self.globalRect |
1702 | - start_x = stop_x = x + width // 2 |
1703 | - start_y = y + height |
1704 | - stop_y = y |
1705 | - self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1706 | - return self.get_root_instance().wait_select_single( |
1707 | - edge='left', active=True) |
1708 | - |
1709 | - |
1710 | -class LeftEdgeDemoOverlay( |
1711 | - ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
1712 | - |
1713 | - @classmethod |
1714 | - def validate_dbus_object(cls, path, state): |
1715 | - name = introspection.get_classname_from_path(path) |
1716 | - if name == b'EdgeDemoOverlay': |
1717 | - if state['edge'][1] == 'left': |
1718 | - return True |
1719 | - return False |
1720 | - |
1721 | - @autopilot.logging.log_action(logger.info) |
1722 | - def swipe(self): |
1723 | - """Swipe to the right to complete this demo step.""" |
1724 | +class TutorialPage( |
1725 | + ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
1726 | + |
1727 | + @classmethod |
1728 | + def validate_dbus_object(cls, path, state): |
1729 | + name = introspection.get_classname_from_path(path) |
1730 | + return name == b'TutorialPage' or name == b'TutorialLeft' |
1731 | + |
1732 | + @autopilot.logging.log_action(logger.info) |
1733 | + def short_swipe_right(self): |
1734 | x, y, width, height = self.globalRect |
1735 | start_x = x |
1736 | - stop_x = x + width |
1737 | + stop_x = x + width // 3 |
1738 | start_y = stop_y = y + height // 2 |
1739 | self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1740 | - return self.get_root_instance().wait_select_single( |
1741 | - edge='none', active=True) |
1742 | - |
1743 | - |
1744 | -class FinalEdgeDemoOverlay( |
1745 | - ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase): |
1746 | - |
1747 | - @classmethod |
1748 | - def validate_dbus_object(cls, path, state): |
1749 | - name = introspection.get_classname_from_path(path) |
1750 | - if name == b'EdgeDemoOverlay': |
1751 | - if state['edge'][1] == 'none': |
1752 | - return True |
1753 | - return False |
1754 | + self.shown.wait_for(False) |
1755 | |
1756 | @autopilot.logging.log_action(logger.info) |
1757 | - def tap_to_start(self): |
1758 | - """Tap to finish the demo and start using the Ubuntu Touch.""" |
1759 | - time.sleep(1) |
1760 | - self.pointing_device.click_object(self) |
1761 | + def tap(self): |
1762 | + """Tap the tick button to complete this step.""" |
1763 | + button = self.select_single(objectName="tick") |
1764 | + self.pointing_device.click_object(button) |
1765 | self.shown.wait_for(False) |
1766 | |
1767 | === modified file 'tests/autopilot/unity8/shell/fixture_setup.py' |
1768 | --- tests/autopilot/unity8/shell/fixture_setup.py 2014-12-16 16:32:40 +0000 |
1769 | +++ tests/autopilot/unity8/shell/fixture_setup.py 2015-02-11 17:00:33 +0000 |
1770 | @@ -54,7 +54,7 @@ |
1771 | return ld_library_path |
1772 | |
1773 | |
1774 | -class EdgesDemo(fixtures.Fixture): |
1775 | +class Tutorial(fixtures.Fixture): |
1776 | |
1777 | def __init__(self, enable): |
1778 | super().__init__() |
1779 | @@ -62,12 +62,12 @@ |
1780 | |
1781 | def setUp(self): |
1782 | super().setUp() |
1783 | - original_state = self._is_edges_demo_enabled() |
1784 | + original_state = self._is_tutorial_enabled() |
1785 | if self.enable != original_state: |
1786 | - self.addCleanup(self._set_edges_demo, original_state) |
1787 | - self._set_edges_demo(self.enable) |
1788 | + self.addCleanup(self._set_tutorial, original_state) |
1789 | + self._set_tutorial(self.enable) |
1790 | |
1791 | - def _is_edges_demo_enabled(self): |
1792 | + def _is_tutorial_enabled(self): |
1793 | command = [ |
1794 | 'dbus-send', '--system', '--print-reply', |
1795 | '--dest=org.freedesktop.Accounts', |
1796 | @@ -79,7 +79,7 @@ |
1797 | output = subprocess.check_output(command, universal_newlines=True) |
1798 | return True if output.count('true') else False |
1799 | |
1800 | - def _set_edges_demo(self, value): |
1801 | + def _set_tutorial(self, value): |
1802 | value_string = 'true' if value else 'false' |
1803 | command = [ |
1804 | 'dbus-send', '--system', '--print-reply', |
1805 | |
1806 | === renamed file 'tests/autopilot/unity8/shell/tests/test_edges_demo.py' => 'tests/autopilot/unity8/shell/tests/test_tutorial.py' |
1807 | --- tests/autopilot/unity8/shell/tests/test_edges_demo.py 2015-01-21 13:50:14 +0000 |
1808 | +++ tests/autopilot/unity8/shell/tests/test_tutorial.py 2015-02-11 17:00:33 +0000 |
1809 | @@ -24,28 +24,27 @@ |
1810 | fixture_setup, |
1811 | tests |
1812 | ) |
1813 | -# unused import to load the edge emulators custom proxy objects. |
1814 | -from unity8.shell.emulators import edges_demo # NOQA |
1815 | - |
1816 | - |
1817 | -class EdgesDemoTestCase(tests.UnityTestCase): |
1818 | +# unused import to load the tutorial emulators custom proxy objects. |
1819 | +from unity8.shell.emulators import tutorial # NOQA |
1820 | + |
1821 | + |
1822 | +class TutorialTestCase(tests.UnityTestCase): |
1823 | |
1824 | def setUp(self): |
1825 | - super(EdgesDemoTestCase, self).setUp() |
1826 | + super(TutorialTestCase, self).setUp() |
1827 | self._qml_mock_enabled = False |
1828 | self._data_dirs_mock_enabled = False |
1829 | |
1830 | - self.useFixture(fixture_setup.EdgesDemo(True)) |
1831 | + self.useFixture(fixture_setup.Tutorial(True)) |
1832 | self.unity = self.launch_unity() |
1833 | |
1834 | - def test_complete_edge_demo(self): |
1835 | - edge_demo = self.unity.select_single('EdgeDemo') |
1836 | - self.assertThat(edge_demo.running, Eventually(Equals(True))) |
1837 | - right_edge_overlay = self.unity.wait_select_single( |
1838 | - edge='right', active=True) |
1839 | - top_edge_overlay = right_edge_overlay.swipe() |
1840 | - bottom_edge_overlay = top_edge_overlay.swipe() |
1841 | - left_edge_overlay = bottom_edge_overlay.swipe() |
1842 | - final_overlay = left_edge_overlay.swipe() |
1843 | - final_overlay.tap_to_start() |
1844 | - self.assertThat(edge_demo.running, Eventually(Equals(False))) |
1845 | + def test_complete_tutorial(self): |
1846 | + greeter = self.main_window.get_greeter() |
1847 | + tutorial = self.unity.select_single('Tutorial') |
1848 | + self.assertThat(tutorial.running, Eventually(Equals(True))) |
1849 | + greeter.swipe() |
1850 | + page = self.unity.wait_select_single(objectName='tutorialLeft') |
1851 | + page.short_swipe_right() |
1852 | + page = self.unity.wait_select_single(objectName='tutorialLeftFinish') |
1853 | + page.tap() |
1854 | + self.assertThat(tutorial.running, Eventually(Equals(False))) |
1855 | |
1856 | === modified file 'tests/qmltests/CMakeLists.txt' |
1857 | --- tests/qmltests/CMakeLists.txt 2015-02-11 17:00:33 +0000 |
1858 | +++ tests/qmltests/CMakeLists.txt 2015-02-11 17:00:33 +0000 |
1859 | @@ -25,7 +25,6 @@ |
1860 | add_qml_test(Components Carousel) |
1861 | add_qml_test(Components Dialogs) |
1862 | add_qml_test(Components DraggingArea) |
1863 | -add_qml_test(Components EdgeDemoOverlay) |
1864 | add_qml_test(Components LazyImage) |
1865 | add_qml_test(Components Lockscreen) |
1866 | add_qml_test(Components Rating) |
1867 | @@ -91,4 +90,5 @@ |
1868 | add_qml_test(Stages TabletStage) |
1869 | add_qml_test(Stages WindowMoveResizeArea) |
1870 | add_qml_test(Stages Splash) |
1871 | +add_qml_test(Tutorial Tutorial) |
1872 | add_qml_test(Wizard Wizard) |
1873 | |
1874 | === removed file 'tests/qmltests/Components/tst_EdgeDemoOverlay.qml' |
1875 | --- tests/qmltests/Components/tst_EdgeDemoOverlay.qml 2013-12-17 16:04:47 +0000 |
1876 | +++ tests/qmltests/Components/tst_EdgeDemoOverlay.qml 1970-01-01 00:00:00 +0000 |
1877 | @@ -1,123 +0,0 @@ |
1878 | -/* |
1879 | - * Copyright 2013 Canonical Ltd. |
1880 | - * |
1881 | - * This program is free software; you can redistribute it and/or modify |
1882 | - * it under the terms of the GNU General Public License as published by |
1883 | - * the Free Software Foundation; version 3. |
1884 | - * |
1885 | - * This program is distributed in the hope that it will be useful, |
1886 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1887 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1888 | - * GNU General Public License for more details. |
1889 | - * |
1890 | - * You should have received a copy of the GNU General Public License |
1891 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1892 | - */ |
1893 | - |
1894 | -import QtQuick 2.0 |
1895 | -import QtTest 1.0 |
1896 | -import Unity.Test 0.1 as UT |
1897 | -import "../../../qml/Components" |
1898 | - |
1899 | -Item { |
1900 | - id: root |
1901 | - width: boxWidth * 3 |
1902 | - height: boxHeight * 2 |
1903 | - |
1904 | - property int boxWidth: 250 |
1905 | - property int boxHeight: 250 |
1906 | - |
1907 | - EdgeDemoOverlay { |
1908 | - id: top |
1909 | - edge: "top" |
1910 | - title: "Top" |
1911 | - text: "Displayed on top left" |
1912 | - anchors.left: parent.left |
1913 | - anchors.top: parent.top |
1914 | - width: boxWidth |
1915 | - height: boxHeight |
1916 | - } |
1917 | - |
1918 | - EdgeDemoOverlay { |
1919 | - id: right |
1920 | - edge: "right" |
1921 | - title: "Right" |
1922 | - text: "Displayed on top right" |
1923 | - anchors.right: parent.right |
1924 | - anchors.top: parent.top |
1925 | - width: boxWidth |
1926 | - height: boxHeight |
1927 | - } |
1928 | - |
1929 | - EdgeDemoOverlay { |
1930 | - id: left |
1931 | - edge: "left" |
1932 | - title: "Left" |
1933 | - text: "Displayed on bottom right" |
1934 | - anchors.right: parent.right |
1935 | - anchors.bottom: parent.bottom |
1936 | - width: boxWidth |
1937 | - height: boxHeight |
1938 | - available: false |
1939 | - } |
1940 | - |
1941 | - EdgeDemoOverlay { |
1942 | - id: bottom |
1943 | - edge: "bottom" |
1944 | - title: "Bottom" |
1945 | - text: "Displayed on bottom left" |
1946 | - anchors.left: parent.left |
1947 | - anchors.bottom: parent.bottom |
1948 | - width: boxWidth |
1949 | - height: boxHeight |
1950 | - } |
1951 | - |
1952 | - EdgeDemoOverlay { |
1953 | - id: none |
1954 | - edge: "none" |
1955 | - title: "None" |
1956 | - text: "Displayed on top middle" |
1957 | - anchors.horizontalCenter: parent.horizontalCenter |
1958 | - anchors.top: parent.top |
1959 | - width: boxWidth |
1960 | - height: boxHeight |
1961 | - } |
1962 | - |
1963 | - SignalSpy { |
1964 | - id: signalSpy |
1965 | - } |
1966 | - |
1967 | - UT.UnityTestCase { |
1968 | - name: "EdgeDemoOverlay" |
1969 | - when: windowShown |
1970 | - |
1971 | - function test_animations() { |
1972 | - compare(right.running, true) |
1973 | - |
1974 | - compare(left.running, false) |
1975 | - left.available = true |
1976 | - compare(left.running, true) |
1977 | - } |
1978 | - |
1979 | - function test_skip() { |
1980 | - signalSpy.target = bottom |
1981 | - signalSpy.signalName = "skip" |
1982 | - signalSpy.clear() |
1983 | - var bottomSkip = findChild(bottom, "skipLabel") |
1984 | - mousePress(bottomSkip, 1, 1) |
1985 | - mouseRelease(bottomSkip, 1, 1) |
1986 | - signalSpy.wait() |
1987 | - compare(bottom.available, false) |
1988 | - |
1989 | - // Test that the 'none' edge skips anywhere |
1990 | - signalSpy.target = none |
1991 | - signalSpy.clear() |
1992 | - var backgroundShade = findChild(none, "backgroundShadeMouseArea") |
1993 | - tryCompare(backgroundShade, "enabled", true) |
1994 | - mousePress(backgroundShade, 1, 1) |
1995 | - mouseRelease(backgroundShade, 1, 1) |
1996 | - signalSpy.wait() |
1997 | - compare(none.available, false) |
1998 | - } |
1999 | - } |
2000 | -} |
2001 | |
2002 | === added directory 'tests/qmltests/Tutorial' |
2003 | === added file 'tests/qmltests/Tutorial/tst_Tutorial.qml' |
2004 | --- tests/qmltests/Tutorial/tst_Tutorial.qml 1970-01-01 00:00:00 +0000 |
2005 | +++ tests/qmltests/Tutorial/tst_Tutorial.qml 2015-02-11 17:00:33 +0000 |
2006 | @@ -0,0 +1,286 @@ |
2007 | +/* |
2008 | + * Copyright (C) 2013,2014 Canonical, Ltd. |
2009 | + * |
2010 | + * This program is free software; you can redistribute it and/or modify |
2011 | + * it under the terms of the GNU General Public License as published by |
2012 | + * the Free Software Foundation; version 3. |
2013 | + * |
2014 | + * This program is distributed in the hope that it will be useful, |
2015 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2016 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2017 | + * GNU General Public License for more details. |
2018 | + * |
2019 | + * You should have received a copy of the GNU General Public License |
2020 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2021 | + */ |
2022 | + |
2023 | +import QtQuick 2.0 |
2024 | +import QtTest 1.0 |
2025 | +import AccountsService 0.1 |
2026 | +import LightDM 0.1 as LightDM |
2027 | +import Ubuntu.Components 1.1 |
2028 | +import Unity.Application 0.1 |
2029 | +import Unity.Test 0.1 as UT |
2030 | + |
2031 | +import "../../../qml" |
2032 | + |
2033 | +Item { |
2034 | + id: root |
2035 | + width: shellLoader.width + buttons.width |
2036 | + height: shellLoader.height |
2037 | + |
2038 | + QtObject { |
2039 | + id: applicationArguments |
2040 | + |
2041 | + function hasGeometry() { |
2042 | + return false; |
2043 | + } |
2044 | + |
2045 | + function width() { |
2046 | + return 0; |
2047 | + } |
2048 | + |
2049 | + function height() { |
2050 | + return 0; |
2051 | + } |
2052 | + } |
2053 | + |
2054 | + Component.onCompleted: { |
2055 | + // must set the mock mode before loading the Shell |
2056 | + LightDM.Greeter.mockMode = "single-pin"; |
2057 | + LightDM.Users.mockMode = "single-pin"; |
2058 | + shellLoader.active = true; |
2059 | + } |
2060 | + |
2061 | + Row { |
2062 | + spacing: 0 |
2063 | + anchors.fill: parent |
2064 | + |
2065 | + Loader { |
2066 | + id: shellLoader |
2067 | + |
2068 | + active: false |
2069 | + width: units.gu(40) |
2070 | + height: units.gu(71) |
2071 | + |
2072 | + property bool itemDestroyed: false |
2073 | + sourceComponent: Component { |
2074 | + Shell { |
2075 | + property string indicatorProfile: "phone" |
2076 | + |
2077 | + Component.onDestruction: { |
2078 | + shellLoader.itemDestroyed = true; |
2079 | + } |
2080 | + } |
2081 | + } |
2082 | + } |
2083 | + |
2084 | + Rectangle { |
2085 | + id: buttons |
2086 | + color: "white" |
2087 | + width: units.gu(30) |
2088 | + height: shellLoader.height |
2089 | + |
2090 | + Column { |
2091 | + anchors { left: parent.left; right: parent.right; top: parent.top; margins: units.gu(1) } |
2092 | + spacing: units.gu(1) |
2093 | + Row { |
2094 | + anchors { left: parent.left; right: parent.right } |
2095 | + Button { |
2096 | + text: "Restart Tutorial" |
2097 | + onClicked: { |
2098 | + if (shellLoader.status !== Loader.Ready) |
2099 | + return; |
2100 | + |
2101 | + AccountsService.demoEdges = false; |
2102 | + AccountsService.demoEdges = true; |
2103 | + } |
2104 | + } |
2105 | + } |
2106 | + } |
2107 | + } |
2108 | + } |
2109 | + |
2110 | + UT.UnityTestCase { |
2111 | + id: testCase |
2112 | + name: "Tutorial" |
2113 | + when: windowShown |
2114 | + |
2115 | + property Item shell: shellLoader.status === Loader.Ready ? shellLoader.item : null |
2116 | + property real halfWidth: shell ? shell.width / 2 : 0 |
2117 | + property real halfHeight: shell ? shell.height / 2 : 0 |
2118 | + |
2119 | + function init() { |
2120 | + tryCompare(shell, "enabled", true); // enabled by greeter when ready |
2121 | + swipeAwayGreeter(); |
2122 | + AccountsService.demoEdges = false; |
2123 | + AccountsService.demoEdges = true; |
2124 | + } |
2125 | + |
2126 | + function cleanup() { |
2127 | + shellLoader.itemDestroyed = false; |
2128 | + |
2129 | + shellLoader.active = false; |
2130 | + |
2131 | + tryCompare(shellLoader, "status", Loader.Null); |
2132 | + tryCompare(shellLoader, "item", null); |
2133 | + // Loader.status might be Loader.Null and Loader.item might be null but the Loader |
2134 | + // item might still be alive. So if we set Loader.active back to true |
2135 | + // again right now we will get the very same Shell instance back. So no reload |
2136 | + // actually took place. Likely because Loader waits until the next event loop |
2137 | + // iteration to do its work. So to ensure the reload, we will wait until the |
2138 | + // Shell instance gets destroyed. |
2139 | + tryCompare(shellLoader, "itemDestroyed", true); |
2140 | + |
2141 | + // kill all (fake) running apps |
2142 | + killApps(); |
2143 | + |
2144 | + // reload our test subject to get it in a fresh state once again |
2145 | + shellLoader.active = true; |
2146 | + |
2147 | + tryCompare(shellLoader, "status", Loader.Ready); |
2148 | + removeTimeConstraintsFromDirectionalDragAreas(shellLoader.item); |
2149 | + } |
2150 | + |
2151 | + function killApps() { |
2152 | + while (ApplicationManager.count > 1) { |
2153 | + var appIndex = ApplicationManager.get(0).appId == "unity8-dash" ? 1 : 0 |
2154 | + ApplicationManager.stopApplication(ApplicationManager.get(appIndex).appId); |
2155 | + } |
2156 | + compare(ApplicationManager.count, 1) |
2157 | + } |
2158 | + |
2159 | + function swipeAwayGreeter() { |
2160 | + var greeter = findChild(shell, "greeter"); |
2161 | + tryCompare(greeter, "showProgress", 1); |
2162 | + |
2163 | + touchFlick(shell, halfWidth, halfHeight, shell.width, halfHeight); |
2164 | + |
2165 | + // wait until the animation has finished |
2166 | + tryCompare(greeter, "showProgress", 0); |
2167 | + waitForRendering(greeter); |
2168 | + } |
2169 | + |
2170 | + function waitForPage(name) { |
2171 | + tryCompareFunction(function() { return findChild(shell, name) !== null; }, true); |
2172 | + waitForRendering(findChild(shell, name)); |
2173 | + var page = findChild(shell, name); |
2174 | + tryCompare(page, "shown", true); |
2175 | + tryCompare(page.showAnimation, "running", false); |
2176 | + return page; |
2177 | + } |
2178 | + |
2179 | + function checkTopEdge() { |
2180 | + touchFlick(shell, halfWidth, 0, halfWidth, halfHeight); |
2181 | + |
2182 | + var panel = findChild(shell, "panel"); |
2183 | + tryCompare(panel.indicators, "fullyClosed", true); |
2184 | + } |
2185 | + |
2186 | + function checkLeftEdge() { |
2187 | + touchFlick(shell, 0, halfHeight, halfWidth, halfHeight); |
2188 | + |
2189 | + var launcher = findChild(shell, "launcher"); |
2190 | + tryCompare(launcher, "state", ""); |
2191 | + } |
2192 | + |
2193 | + function checkRightEdge() { |
2194 | + touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight); |
2195 | + |
2196 | + var stage = findChild(shell, "stage"); |
2197 | + var spreadView = findChild(stage, "spreadView"); |
2198 | + tryCompare(spreadView, "phase", 0); |
2199 | + } |
2200 | + |
2201 | + function checkBottomEdge() { |
2202 | + // Can't actually check effect of swipe, since dash isn't really loaded |
2203 | + var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader"); |
2204 | + tryCompare(applicationsDisplayLoader.item, "interactive", false); |
2205 | + } |
2206 | + |
2207 | + function checkFinished() { |
2208 | + tryCompare(AccountsService, "demoEdges", false); |
2209 | + |
2210 | + var tutorial = findChild(shell, "tutorial"); |
2211 | + tryCompare(tutorial, "running", false); |
2212 | + |
2213 | + var launcher = findChild(shell, "launcher"); |
2214 | + tryCompare(launcher, "shown", false); |
2215 | + } |
2216 | + |
2217 | + function goToPage(name) { |
2218 | + var page = waitForPage("tutorialLeft"); |
2219 | + checkTopEdge(); |
2220 | + checkRightEdge(); |
2221 | + checkBottomEdge(); |
2222 | + if (name === "tutorialLeft") return page; |
2223 | + touchFlick(shell, 0, halfHeight, halfWidth, halfHeight); |
2224 | + |
2225 | + page = waitForPage("tutorialLeftFinish"); |
2226 | + if (name === "tutorialLeftFinish") return page; |
2227 | + var tick = findChild(page, "tick"); |
2228 | + tap(tick); |
2229 | + |
2230 | + checkFinished(); |
2231 | + return null; |
2232 | + } |
2233 | + |
2234 | + function test_walkthrough() { |
2235 | + goToPage(null); |
2236 | + } |
2237 | + |
2238 | + function test_launcherShortDrag() { |
2239 | + // goToPage does a normal launcher pull. But here we want to test |
2240 | + // just barely pulling the launcher out and letting go (i.e. not |
2241 | + // triggering the "progress" property of Launcher). |
2242 | + |
2243 | + var left = goToPage("tutorialLeft"); |
2244 | + |
2245 | + // Make sure we don't do anything if we don't pull the launcher |
2246 | + // out much. |
2247 | + var launcher = findChild(shell, "launcher"); |
2248 | + touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.4, halfHeight); |
2249 | + tryCompare(launcher, "state", ""); // should remain hidden |
2250 | + tryCompare(left, "shown", true); // and we should still be on left |
2251 | + |
2252 | + // Now drag out but not past launcher itself |
2253 | + touchFlick(shell, 0, halfHeight, launcher.panelWidth * 0.9, halfHeight); |
2254 | + |
2255 | + waitForPage("tutorialLeftFinish"); |
2256 | + } |
2257 | + |
2258 | + function test_launcherLongDrag() { |
2259 | + // goToPage does a normal launcher pull. But here we want to test |
2260 | + // a full pull across the page. |
2261 | + |
2262 | + var left = goToPage("tutorialLeft"); |
2263 | + |
2264 | + var launcher = findChild(shell, "launcher"); |
2265 | + touchFlick(shell, 0, halfHeight, shell.width, halfHeight); |
2266 | + |
2267 | + var errorTextLabel = findChild(left, "errorTextLabel"); |
2268 | + var errorTitleLabel = findChild(left, "errorTitleLabel"); |
2269 | + tryCompare(launcher, "state", ""); // launcher goes away |
2270 | + tryCompare(left, "shown", true); // still on left page |
2271 | + tryCompare(errorTextLabel, "opacity", 1); // show error |
2272 | + tryCompare(errorTitleLabel, "opacity", 1); // show error |
2273 | + } |
2274 | + |
2275 | + function test_launcherDragBack() { |
2276 | + // goToPage does a full launcher pull. But here we test pulling |
2277 | + // all the way out, then dragging back into place. |
2278 | + |
2279 | + var left = goToPage("tutorialLeft"); |
2280 | + touchFlick(shell, 0, halfHeight, halfWidth, halfHeight, true, false); |
2281 | + touchFlick(shell, halfWidth, halfHeight, 0, halfHeight, false, true); |
2282 | + |
2283 | + tryCompare(left, "shown", true); // and we should still be on left |
2284 | + } |
2285 | + |
2286 | + function test_interrupted() { |
2287 | + goToPage("tutorialLeft"); |
2288 | + ApplicationManager.startApplication("dialer-app"); |
2289 | + checkFinished(); |
2290 | + } |
2291 | + } |
2292 | +} |
2293 | |
2294 | === modified file 'tests/qmltests/tst_TabletShell.qml' |
2295 | --- tests/qmltests/tst_TabletShell.qml 2015-01-20 11:50:19 +0000 |
2296 | +++ tests/qmltests/tst_TabletShell.qml 2015-02-11 17:00:33 +0000 |
2297 | @@ -303,8 +303,8 @@ |
2298 | selectUser(data.user) |
2299 | |
2300 | AccountsService.demoEdges = data.demo |
2301 | - var edgeDemo = findChild(shell, "edgeDemo") |
2302 | - tryCompare(edgeDemo, "running", data.demo) |
2303 | + var tutorial = findChild(shell, "tutorial"); |
2304 | + tryCompare(tutorial, "running", data.demo); |
2305 | |
2306 | swipeFromLeftEdge(shell.width * 0.75) |
2307 | wait(500) // to give time to handle dash() signal from Launcher |
FAILED: Continuous integration, rev:1371 jenkins. qa.ubuntu. com/job/ unity8- ci/4776/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/6263/ console jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- utopic/ 1762 jenkins. qa.ubuntu. com/job/ unity8- utopic- amd64-ci/ 1872 jenkins. qa.ubuntu. com/job/ unity8- utopic- i386-ci/ 1870 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/5877/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/7515 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/7515/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 15144
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/4776/ rebuild
http://