Merge lp:~mterry/unity8/tutorial-new-screens into lp:unity8
- tutorial-new-screens
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Michael Zanetti | ||||
Approved revision: | 1410 | ||||
Merged at revision: | 1604 | ||||
Proposed branch: | lp:~mterry/unity8/tutorial-new-screens | ||||
Merge into: | lp:unity8 | ||||
Prerequisite: | lp:~mterry/unity8/tutorial-refactor | ||||
Diff against target: |
1549 lines (+769/-226) 16 files modified
qml/Shell.qml (+7/-3) qml/Stages/ApplicationWindow.qml (+14/-1) qml/Stages/PhoneStage.qml (+62/-34) qml/Stages/TransformedSpreadDelegate.qml (+27/-21) qml/Tutorial/Slider.qml (+8/-2) qml/Tutorial/Tick.qml (+29/-0) qml/Tutorial/Tutorial.qml (+8/-1) qml/Tutorial/TutorialBottom.qml (+104/-0) qml/Tutorial/TutorialBottomFinish.qml (+41/-0) qml/Tutorial/TutorialContent.qml (+69/-75) qml/Tutorial/TutorialLeftFinish.qml (+4/-10) qml/Tutorial/TutorialPage.qml (+79/-74) qml/Tutorial/TutorialRight.qml (+223/-0) tests/autopilot/unity8/shell/emulators/tutorial.py (+24/-4) tests/autopilot/unity8/shell/tests/test_tutorial.py (+7/-0) tests/qmltests/Tutorial/tst_Tutorial.qml (+63/-1) |
||||
To merge this branch: | bzr merge lp:~mterry/unity8/tutorial-new-screens | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Michael Zanetti (community) | Approve | ||
Review via email:
|
Commit message
Add new right-edge and bottom-edge screens to the first-boot edge tutorial
Description of the change
Add new right-edge and bottom-edge screens to the first-boot edge tutorial.
I redesigned TutorialContent a bit to not use a loader, but pre-load everything. This prevented a delay between the Left and Right edge screens as it loads the fake app images. We already have a loader in Tutorial.qml, so I felt the second layer was unnecessary.
I also have added bits here and there to PhoneStage in order to support the right-edge tutorial screen.
Design spec here: https:/
To test, install the debs from this MP and run the following: phablet-config edges-intro --enable; adb reboot
== Checklist ==
* Are there any related MPs required for this MP to build/function as expected? Please list.
Yes, the pre-requisite linked to this MP
* 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?
NA
* If you changed the UI, has there been a design review?
TBD

PS Jenkins bot (ps-jenkins) wrote : | # |
- 1394. By Michael Terry
-
Merge from refactor branch
- 1395. By Michael Terry
-
Robustify waiting for demoEdgesChanged signal by not doing it

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1394
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 : | # |
PASSED: Continuous integration, rev:1395
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://
- 1396. By Michael Terry
-
Merge from -refactor branch
- 1397. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1397
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 : | # |
FAILED: Continuous integration, rev:1397
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 Zanetti (mzanetti) wrote : | # |
I tested the spread, still seems to work fine. I'm a bit worried that doing changes in the spread in the future might break the welcome wizard as its not totally obvious why your changes would be required if one only looks at the real right edge spread. I guess it would be beneficial to add some tests that verify your changes keep working. What do you think?

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1397
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://

MichaĆ Sawicz (saviq) wrote : | # |
There seem to be somewhat legitimate (if flaky) qmltest failures, please investigate.

Albert Astals Cid (aacid) wrote : | # |
qmltestrunner.
- 1398. By Michael Terry
-
Merge from -refactor
- 1399. By Michael Terry
-
Add a couple tests

Michael Terry (mterry) wrote : | # |
@mzanetti, I've added a test that pokes and prods some spread values to make sure that they are what we expect (like the first app delegate having x==shell.width instead of 0 for example).
It's hard to test the new spread mode fully because it modifies how the transforms are applied as mostly a visual thing. What I really want to be able to write is a "does it look right?" test, with maybe some Mike AI that knows the correct answer. But ah well. Checking some values will have to do for now.

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1398
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 : | # |
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://
- 1400. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1400
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://
- 1401. By Michael Terry
-
Merge from -refactor
- 1402. By Michael Terry
-
Updated fake screenshots
- 1403. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1403
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://
- 1404. By Michael Terry
-
Update facebook.png from design

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1404
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1405. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1405
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 : | # |
Text conflict in qml/Shell.qml
1 conflicts encountered.
- 1406. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1406
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://
- 1407. By Michael Terry
-
Make spread pages slightly smaller

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1407
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1408. By Michael Terry
-
Merge from -refactor
- 1409. By Michael Terry
-
Add tease to bottom edge slider

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1409
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://

Michael Zanetti (mzanetti) wrote : | # |
there's an outdated comment now, see inline comment

Michael Terry (mterry) wrote : | # |
Naw, I think that comment is still fine. I replied inline. But I'm happy to change if you disagree.

Michael Zanetti (mzanetti) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
yes
* Did CI run pass? If not, please explain why.
no. ci seems to have crashed. I've just triggered a rebuild. Michael, please check if jenkins is fine with this branch before we land it.
* Did you make sure that the branch does not contain spurious tags?
yes

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1409
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://

Michael Zanetti (mzanetti) wrote : | # |
ok, Jenkins built fine now. Failing qml tests don't seem to be related to this branch. However, Autopilot seems to have issues. I think at least this test is broken by this branch:
unity8.
Please also check if the other AP failures are related.
- 1410. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1410
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 : | # |
This is from Olga reviewing the latest code here:
"We reviewed the new implementation and you have the go ahead. :)
Looks brilliant! :D"
So that's a +1 from design. Just need to confirm fixed AP tests and we're good.

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1410
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://

Michael Zanetti (mzanetti) wrote : | # |
ok. last test run looks good.
- 1411. By Michael Terry
-
Merge from -refactor
- 1412. By Michael Terry
-
Merge from -refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1410
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 : | # |
FAILED: Continuous integration, rev:1412
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://
- 1413. By Michael Terry
-
Merge from tutorial-refactor

PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1412
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 'qml/Shell.qml' |
2 | --- qml/Shell.qml 2015-02-11 16:32:24 +0000 |
3 | +++ qml/Shell.qml 2015-02-11 16:32:25 +0000 |
4 | @@ -290,7 +290,7 @@ |
5 | source: usageModeSettings.usageMode === "Windowed" ? "Stages/DesktopStage.qml" |
6 | : tabletMode ? "Stages/TabletStage.qml" : "Stages/PhoneStage.qml" |
7 | |
8 | - property bool interactive: tutorial.stagesEnabled |
9 | + property bool interactive: tutorial.spreadEnabled |
10 | && !greeter.shown |
11 | && !lockscreen.shown |
12 | && panel.indicators.fullyClosed |
13 | @@ -323,7 +323,7 @@ |
14 | Binding { |
15 | target: applicationsDisplayLoader.item |
16 | property: "spreadEnabled" |
17 | - value: tutorial.stagesEnabled && !greeter.hasLockedApp |
18 | + value: tutorial.spreadEnabled && !greeter.hasLockedApp |
19 | } |
20 | Binding { |
21 | target: applicationsDisplayLoader.item |
22 | @@ -889,8 +889,12 @@ |
23 | panel: panel |
24 | stages: stages |
25 | overlay: overlay |
26 | + edgeSize: shell.edgeSize |
27 | |
28 | - onFinished: AccountsService.demoEdges = false |
29 | + onFinished: { |
30 | + AccountsService.demoEdges = false; |
31 | + active = false; // for immediate response / if AS is having problems |
32 | + } |
33 | } |
34 | |
35 | Connections { |
36 | |
37 | === modified file 'qml/Stages/ApplicationWindow.qml' |
38 | --- qml/Stages/ApplicationWindow.qml 2015-02-11 16:32:24 +0000 |
39 | +++ qml/Stages/ApplicationWindow.qml 2015-02-11 16:32:25 +0000 |
40 | @@ -43,6 +43,7 @@ |
41 | readonly property color splashColor: root.application ? root.application.splashColor : "#00000000" |
42 | readonly property color splashColorHeader: root.application ? root.application.splashColorHeader : "#00000000" |
43 | readonly property color splashColorFooter: root.application ? root.application.splashColorFooter : "#00000000" |
44 | + readonly property url defaultScreenshot: root.application ? root.application.defaultScreenshot : "" |
45 | |
46 | // Whether the Application had a surface before but lost it. |
47 | property bool hadSurface: sessionContainer.surfaceContainer.hadSurface |
48 | @@ -72,7 +73,7 @@ |
49 | Image { |
50 | id: screenshotImage |
51 | objectName: "screenshotImage" |
52 | - source: "" |
53 | + source: d.defaultScreenshot |
54 | anchors.fill: parent |
55 | antialiasing: !root.interactive |
56 | |
57 | @@ -125,6 +126,7 @@ |
58 | } |
59 | |
60 | StateGroup { |
61 | + id: stateGroup |
62 | objectName: "applicationWindowStateGroup" |
63 | states: [ |
64 | State { |
65 | @@ -218,6 +220,17 @@ |
66 | } |
67 | }, |
68 | Transition { |
69 | + from: "splashScreen"; to: "screenshot" |
70 | + SequentialAnimation { |
71 | + PropertyAction { target: screenshotImage |
72 | + property: "visible"; value: true } |
73 | + UbuntuNumberAnimation { target: screenshotImage; property: "opacity"; |
74 | + from: 0.0; to: 1.0 |
75 | + duration: UbuntuAnimation.BriskDuration } |
76 | + PropertyAction { target: splashLoader; property: "active"; value: false } |
77 | + } |
78 | + }, |
79 | + Transition { |
80 | from: "surface"; to: "void" |
81 | SequentialAnimation { |
82 | PropertyAction { target: sessionContainer.surfaceContainer; property: "visible"; value: false } |
83 | |
84 | === modified file 'qml/Stages/PhoneStage.qml' |
85 | --- qml/Stages/PhoneStage.qml 2015-02-11 16:32:24 +0000 |
86 | +++ qml/Stages/PhoneStage.qml 2015-02-11 16:32:25 +0000 |
87 | @@ -32,6 +32,21 @@ |
88 | property bool spreadEnabled: true // If false, animations and right edge will be disabled |
89 | property real inverseProgress: 0 // This is the progress for left edge drags, in pixels. |
90 | property int orientation: Qt.PortraitOrientation |
91 | + property QtObject applicationManager: ApplicationManager |
92 | + property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps |
93 | + property bool altTabEnabled: true |
94 | + property real startScale: 1.1 |
95 | + property real endScale: 0.7 |
96 | + |
97 | + // How far left the stage has been dragged |
98 | + readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0 |
99 | + |
100 | + readonly property alias dragging: spreadDragArea.dragging |
101 | + |
102 | + // Only used by the tutorial right now, when it is teasing the right edge |
103 | + property real dragAreaOverlap |
104 | + |
105 | + signal opened() |
106 | |
107 | color: "#111111" |
108 | |
109 | @@ -52,30 +67,30 @@ |
110 | if (inverseProgress == 0 && priv.oldInverseProgress > 0) { |
111 | // left edge drag released. Minimum distance is given by design. |
112 | if (priv.oldInverseProgress > units.gu(22)) { |
113 | - ApplicationManager.requestFocusApplication("unity8-dash"); |
114 | + applicationManager.requestFocusApplication("unity8-dash"); |
115 | } |
116 | } |
117 | priv.oldInverseProgress = inverseProgress; |
118 | } |
119 | |
120 | Connections { |
121 | - target: ApplicationManager |
122 | + target: applicationManager |
123 | |
124 | onFocusRequested: { |
125 | if (spreadView.phase > 0) { |
126 | spreadView.snapTo(priv.indexOf(appId)); |
127 | } else { |
128 | - ApplicationManager.focusApplication(appId); |
129 | + applicationManager.focusApplication(appId); |
130 | } |
131 | } |
132 | |
133 | onApplicationAdded: { |
134 | if (spreadView.phase == 2) { |
135 | - spreadView.snapTo(ApplicationManager.count - 1); |
136 | + spreadView.snapTo(applicationManager.count - 1); |
137 | } else { |
138 | spreadView.phase = 0; |
139 | spreadView.contentX = -spreadView.shift; |
140 | - ApplicationManager.focusApplication(appId); |
141 | + applicationManager.focusApplication(appId); |
142 | } |
143 | } |
144 | |
145 | @@ -90,9 +105,9 @@ |
146 | } |
147 | |
148 | function focusTopMostApp() { |
149 | - if (ApplicationManager.count > 0) { |
150 | - var topmostApp = ApplicationManager.get(0); |
151 | - ApplicationManager.focusApplication(topmostApp.appId); |
152 | + if (applicationManager.count > 0) { |
153 | + var topmostApp = applicationManager.get(0); |
154 | + applicationManager.focusApplication(topmostApp.appId); |
155 | } |
156 | } |
157 | } |
158 | @@ -100,20 +115,21 @@ |
159 | QtObject { |
160 | id: priv |
161 | |
162 | - property string focusedAppId: ApplicationManager.focusedApplicationId |
163 | - property var focusedApplication: ApplicationManager.findApplication(focusedAppId) |
164 | + readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0 |
165 | + property string focusedAppId: applicationManager.focusedApplicationId |
166 | + property var focusedApplication: applicationManager.findApplication(focusedAppId) |
167 | property var focusedAppDelegate: null |
168 | |
169 | property real oldInverseProgress: 0 |
170 | - property bool animateX: true |
171 | + property bool animateX: false |
172 | |
173 | onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0); |
174 | |
175 | onFocusedAppDelegateChanged: focusedAppDelegate.focus = true; |
176 | |
177 | function indexOf(appId) { |
178 | - for (var i = 0; i < ApplicationManager.count; i++) { |
179 | - if (ApplicationManager.get(i).appId == appId) { |
180 | + for (var i = 0; i < applicationManager.count; i++) { |
181 | + if (applicationManager.get(i).appId == appId) { |
182 | return i; |
183 | } |
184 | } |
185 | @@ -133,7 +149,7 @@ |
186 | |
187 | // This indicates when the spreadView is active. That means, all the animations |
188 | // are activated and tiles need to line up for the spread. |
189 | - readonly property bool active: shiftedContentX > 0 || spreadDragArea.status === DirectionalDragArea.Recognized |
190 | + readonly property bool active: shiftedContentX > 0 || spreadDragArea.status === DirectionalDragArea.Recognized || !root.focusFirstApp |
191 | |
192 | // The flickable needs to fill the screen in order to get touch events all over. |
193 | // However, we don't want to the user to be able to scroll back all the way. For |
194 | @@ -199,10 +215,17 @@ |
195 | // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation. |
196 | snapAnimation.targetContentX = width * positionMarker4 + 1 - shift; |
197 | snapAnimation.start(); |
198 | + root.opened(); |
199 | } |
200 | } |
201 | function snapTo(index) { |
202 | - if (ApplicationManager.count <= index) { |
203 | + if (!root.altTabEnabled) { |
204 | + // Reset to start instead |
205 | + snapAnimation.targetContentX = -shift; |
206 | + snapAnimation.start(); |
207 | + return; |
208 | + } |
209 | + if (applicationManager.count <= index) { |
210 | // In case we're trying to snap to some non existing app, lets snap back to the first one |
211 | index = 0; |
212 | } |
213 | @@ -217,10 +240,12 @@ |
214 | snapAnimation.start(); |
215 | } |
216 | |
217 | - // In case the ApplicationManager already holds an app when starting up we're missing animations |
218 | + // In case the applicationManager already holds an app when starting up we're missing animations |
219 | // Make sure we end up in the same state |
220 | Component.onCompleted: { |
221 | spreadView.contentX = -spreadView.shift |
222 | + priv.animateX = true; |
223 | + snapAnimation.complete(); |
224 | } |
225 | |
226 | SequentialAnimation { |
227 | @@ -237,7 +262,7 @@ |
228 | ScriptAction { |
229 | script: { |
230 | if (spreadView.selectedIndex >= 0) { |
231 | - ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId); |
232 | + applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId); |
233 | |
234 | spreadView.selectedIndex = -1; |
235 | spreadView.phase = 0; |
236 | @@ -252,7 +277,7 @@ |
237 | // This width controls how much the spread can be flicked left/right. It's composed of: |
238 | // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit) |
239 | // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen |
240 | - width: Math.max(3, ApplicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5 |
241 | + width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5 |
242 | height: parent.height |
243 | Behavior on width { |
244 | enabled: spreadView.closingIndex >= 0 |
245 | @@ -267,20 +292,22 @@ |
246 | x: spreadView.contentX |
247 | |
248 | onClicked: { |
249 | - spreadView.snapTo(0); |
250 | + if (root.altTabEnabled) { |
251 | + spreadView.snapTo(0); |
252 | + } |
253 | } |
254 | |
255 | Repeater { |
256 | id: spreadRepeater |
257 | objectName: "spreadRepeater" |
258 | - model: ApplicationManager |
259 | + model: applicationManager |
260 | delegate: TransformedSpreadDelegate { |
261 | id: appDelegate |
262 | objectName: "appDelegate" + index |
263 | startAngle: 45 |
264 | endAngle: 5 |
265 | - startScale: 1.1 |
266 | - endScale: 0.7 |
267 | + startScale: root.startScale |
268 | + endScale: root.endScale |
269 | startDistance: spreadView.tileDistance |
270 | endDistance: units.gu(.5) |
271 | width: spreadView.width |
272 | @@ -288,11 +315,12 @@ |
273 | selected: spreadView.selectedIndex == index |
274 | otherSelected: spreadView.selectedIndex >= 0 && !selected |
275 | interactive: !spreadView.interactive && spreadView.phase === 0 |
276 | - && spreadView.shiftedContentX === 0 && root.interactive && index === 0 |
277 | - swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running |
278 | + && spreadView.shiftedContentX === 0 && root.interactive && isFocused |
279 | + swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running |
280 | maximizedAppTopMargin: root.maximizedAppTopMargin |
281 | dropShadow: spreadView.active || |
282 | (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0) |
283 | + focusFirstApp: root.focusFirstApp |
284 | |
285 | readonly property bool isDash: model.appId == "unity8-dash" |
286 | |
287 | @@ -300,7 +328,7 @@ |
288 | |
289 | x: { |
290 | // focused app is always positioned at 0 except when following left edge drag |
291 | - if (index == 0) { |
292 | + if (isFocused) { |
293 | if (!isDash && root.inverseProgress > 0 && spreadView.phase === 0) { |
294 | return root.inverseProgress; |
295 | } |
296 | @@ -311,10 +339,10 @@ |
297 | } |
298 | |
299 | // Otherwise line up for the spread |
300 | - return spreadView.width + (index - 1) * spreadView.tileDistance; |
301 | + return spreadView.width + spreadIndex * spreadView.tileDistance; |
302 | } |
303 | |
304 | - application: ApplicationManager.get(index) |
305 | + application: applicationManager.get(index) |
306 | closeable: !isDash |
307 | |
308 | property real behavioredIndex: index |
309 | @@ -352,7 +380,7 @@ |
310 | progress: { |
311 | var tileProgress = (spreadView.shiftedContentX - behavioredIndex * spreadView.tileDistance) / spreadView.width; |
312 | // Tile 1 needs to move directly from the beginning... |
313 | - if (behavioredIndex == 1 && spreadView.phase < 2) { |
314 | + if (root.focusFirstApp && behavioredIndex == 1 && spreadView.phase < 2) { |
315 | tileProgress += spreadView.tileDistance / spreadView.width; |
316 | } |
317 | // Limiting progress to ~0 and 1.7 to avoid binding calculations when tiles are not |
318 | @@ -367,7 +395,7 @@ |
319 | |
320 | // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1 |
321 | animatedProgress: { |
322 | - if (spreadView.phase == 0 && index < 2) { |
323 | + if (spreadView.phase == 0 && index <= priv.firstSpreadIndex) { |
324 | if (progress < spreadView.positionMarker1) { |
325 | return progress; |
326 | } else if (progress < spreadView.positionMarker1 + 0.05){ |
327 | @@ -392,11 +420,11 @@ |
328 | } |
329 | |
330 | onClicked: { |
331 | - if (spreadView.phase == 2) { |
332 | - if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) { |
333 | + if (root.altTabEnabled && spreadView.phase == 2) { |
334 | + if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) { |
335 | spreadView.snapTo(index); |
336 | } else { |
337 | - ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId); |
338 | + applicationManager.requestFocusApplication(applicationManager.get(index).appId); |
339 | } |
340 | } |
341 | } |
342 | @@ -411,7 +439,7 @@ |
343 | |
344 | onClosed: { |
345 | spreadView.closingIndex = index; |
346 | - ApplicationManager.stopApplication(ApplicationManager.get(index).appId); |
347 | + applicationManager.stopApplication(applicationManager.get(index).appId); |
348 | } |
349 | } |
350 | } |
351 | @@ -424,7 +452,7 @@ |
352 | direction: Direction.Leftwards |
353 | enabled: (spreadView.phase != 2 && root.spreadEnabled) || dragging |
354 | |
355 | - anchors { top: parent.top; right: parent.right; bottom: parent.bottom } |
356 | + anchors { top: parent.top; right: parent.right; bottom: parent.bottom; rightMargin: -root.dragAreaOverlap } |
357 | width: root.dragAreaWidth |
358 | |
359 | property var gesturePoints: new Array() |
360 | |
361 | === modified file 'qml/Stages/TransformedSpreadDelegate.qml' |
362 | --- qml/Stages/TransformedSpreadDelegate.qml 2014-12-01 12:09:28 +0000 |
363 | +++ qml/Stages/TransformedSpreadDelegate.qml 2015-02-11 16:32:25 +0000 |
364 | @@ -46,6 +46,18 @@ |
365 | property real startDistance: units.gu(5) |
366 | property real endDistance: units.gu(.5) |
367 | |
368 | + // Whether first app is displayed entirely vs just on the spread edge |
369 | + property bool focusFirstApp: true |
370 | + |
371 | + // Whether this delegate is displayed to the user outside of the spread |
372 | + readonly property bool isFocused: focusFirstApp && index === 0 |
373 | + |
374 | + // Adjusted index for any spread animation calculations |
375 | + readonly property int spreadIndex: index - (focusFirstApp ? 1 : 0) |
376 | + |
377 | + // How far left this delegate has been translated |
378 | + readonly property alias xTranslate: priv.xTranslate |
379 | + |
380 | onSelectedChanged: { |
381 | if (selected) { |
382 | priv.snapshot(); |
383 | @@ -63,8 +75,8 @@ |
384 | Connections { |
385 | target: spreadView |
386 | onPhaseChanged: { |
387 | - if (spreadView.phase == 1) { |
388 | - if (index == 0) { |
389 | + if (root.focusFirstApp && spreadView.phase == 1) { |
390 | + if (index === 0) { |
391 | priv.phase2startTranslate = priv.easingAnimation(0, spreadView.positionMarker4, 0, -spreadView.width, spreadView.positionMarker4) + spreadView.width; |
392 | priv.phase2startAngle = priv.easingAnimation(0, spreadView.positionMarker4, root.startAngle, root.endAngle, spreadView.positionMarker4); |
393 | priv.phase2startScale = priv.easingAnimation(0, spreadView.positionMarker4, root.startScale, root.endScale, spreadView.positionMarker4); |
394 | @@ -134,7 +146,7 @@ |
395 | } |
396 | |
397 | if (otherSelected) { |
398 | - if (spreadView.phase < 2 && index == 0) { |
399 | + if (spreadView.phase < 2 && root.isFocused) { |
400 | return linearAnimation(selectedProgress, 0, selectedXTranslate, |
401 | selectedXTranslate - spreadView.tileDistance, root.progress); |
402 | } |
403 | @@ -142,8 +154,7 @@ |
404 | return selectedXTranslate; |
405 | } |
406 | |
407 | - switch (index) { |
408 | - case 0: |
409 | + if (root.focusFirstApp && index === 0) { |
410 | if (spreadView.phase == 0) { |
411 | return Math.min(0, linearAnimation(0, spreadView.positionMarker2, |
412 | 0, -spreadView.width * .25, root.animatedProgress)); |
413 | @@ -153,11 +164,10 @@ |
414 | } else if (!priv.isSelected){ // phase 2 |
415 | // Apply the same animation as with the rest but add spreadView.width to align it with the others. |
416 | return -easingCurve.value * spreadView.width + spreadView.width; |
417 | - } else if (priv.isSelected) { |
418 | + } else { |
419 | return linearAnimation(selectedProgress, 0, selectedXTranslate, 0, root.progress); |
420 | } |
421 | - |
422 | - case 1: |
423 | + } else if (root.focusFirstApp && index === 1) { |
424 | if (spreadView.phase == 0 && !priv.isSelected) { |
425 | return linearAnimation(0, spreadView.positionMarker2, |
426 | 0, -spreadView.width * spreadView.snapPosition, root.animatedProgress); |
427 | @@ -170,13 +180,13 @@ |
428 | |
429 | if (priv.isSelected) { |
430 | // Distance to left edge |
431 | - var targetTranslate = -spreadView.width - ((index - 1) * root.startDistance); |
432 | + var targetTranslate = -spreadView.width - (root.spreadIndex * root.startDistance); |
433 | return linearAnimation(selectedProgress, 0, |
434 | selectedXTranslate, targetTranslate, root.progress); |
435 | } |
436 | |
437 | // Fix it at the right edge... |
438 | - var rightEdgeOffset = -((index - 1) * root.startDistance); |
439 | + var rightEdgeOffset = -(root.spreadIndex * root.startDistance); |
440 | // ...and use our easing to move them to the left. Stop a bit earlier for each tile |
441 | var animatedEndDistance = linearAnimation(0, 2, root.endDistance, 0, root.progress); |
442 | return -easingCurve.value * spreadView.width + (index * animatedEndDistance) + rightEdgeOffset; |
443 | @@ -194,8 +204,7 @@ |
444 | if (priv.isSelected) { |
445 | return linearAnimation(selectedProgress, 0, selectedAngle, 0, root.progress); |
446 | } |
447 | - switch (index) { |
448 | - case 0: |
449 | + if (root.focusFirstApp && index === 0) { |
450 | if (spreadView.phase == 0) { |
451 | return Math.max(0, linearAnimation(0, spreadView.positionMarker2, |
452 | 0, root.tile0SnapAngle, root.animatedProgress)); |
453 | @@ -203,7 +212,7 @@ |
454 | return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
455 | root.tile0SnapAngle, phase2startAngle, root.progress); |
456 | } |
457 | - case 1: |
458 | + } else if (root.focusFirstApp && index === 1) { |
459 | if (spreadView.phase == 0) { |
460 | return linearAnimation(0, spreadView.positionMarker2, root.startAngle, |
461 | root.startAngle * (1-spreadView.snapPosition), root.animatedProgress); |
462 | @@ -227,15 +236,14 @@ |
463 | return linearAnimation(selectedProgress, 0, selectedScale, 1, root.progress); |
464 | } |
465 | |
466 | - switch (index) { |
467 | - case 0: |
468 | + if (root.focusFirstApp && index === 0) { |
469 | if (spreadView.phase == 0) { |
470 | return 1; |
471 | } else if (spreadView.phase == 1) { |
472 | return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
473 | 1, phase2startScale, root.progress); |
474 | } |
475 | - case 1: |
476 | + } else if (root.focusFirstApp && index === 1) { |
477 | if (spreadView.phase == 0) { |
478 | var targetScale = tile1StartScale - ((tile1StartScale - 1) * spreadView.snapPosition); |
479 | return linearAnimation(0, spreadView.positionMarker2, |
480 | @@ -254,7 +262,7 @@ |
481 | return linearAnimation (selectedProgress, Math.max(0, selectedProgress - .5), |
482 | selectedOpacity, 0, root.progress); |
483 | } |
484 | - if (index == 0) { |
485 | + if (root.isFocused) { |
486 | switch (spreadView.phase) { |
487 | case 0: |
488 | return linearAnimation(0, spreadView.positionMarker2, 1, .7, root.animatedProgress); |
489 | @@ -272,16 +280,14 @@ |
490 | return linearAnimation(selectedProgress, 0, selectedTopMarginProgress, 0, root.progress); |
491 | } |
492 | |
493 | - switch (index) { |
494 | - case 0: |
495 | + if (root.focusFirstApp && index === 0) { |
496 | if (spreadView.phase == 0) { |
497 | return 0; |
498 | } else if (spreadView.phase == 1) { |
499 | return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4, |
500 | 0, priv.phase2startTopMarginProgress, root.progress); |
501 | } |
502 | - break; |
503 | - case 1: |
504 | + } else if (root.focusFirstApp && index === 1) { |
505 | if (spreadView.phase == 0) { |
506 | return 0; |
507 | } else if (spreadView.phase == 1) { |
508 | |
509 | === modified file 'qml/Tutorial/Slider.qml' |
510 | --- qml/Tutorial/Slider.qml 2015-02-11 16:32:24 +0000 |
511 | +++ qml/Tutorial/Slider.qml 2015-02-11 16:32:25 +0000 |
512 | @@ -38,7 +38,7 @@ |
513 | readonly property real margin: units.gu(0.5) |
514 | readonly property real arrowSize: root.height - margin * 2 |
515 | readonly property real dotSize: units.dp(1) |
516 | - readonly property real slideOffset: Math.min(root.offset - offscreenOffset, target.x) |
517 | + readonly property real slideOffset: MathUtils.clamp(root.offset - offscreenOffset, -offscreenOffset, target.x) |
518 | readonly property real offscreenOffset: units.gu(2) |
519 | } |
520 | |
521 | @@ -111,7 +111,13 @@ |
522 | color: UbuntuColors.orange |
523 | darkenBy: root.active ? 0.5 : 0 |
524 | anchors.left: parent.left |
525 | - anchors.leftMargin: d.slideOffset |
526 | + // We use a Translate transform rather than anchors.leftMargin because |
527 | + // the latter has weird performance problems on the TutorialRight page. |
528 | + transform: [ |
529 | + Translate { |
530 | + x: d.slideOffset |
531 | + } |
532 | + ] |
533 | anchors.verticalCenter: parent.verticalCenter |
534 | } |
535 | } |
536 | |
537 | === added file 'qml/Tutorial/Tick.qml' |
538 | --- qml/Tutorial/Tick.qml 1970-01-01 00:00:00 +0000 |
539 | +++ qml/Tutorial/Tick.qml 2015-02-11 16:32:25 +0000 |
540 | @@ -0,0 +1,29 @@ |
541 | +/* |
542 | + * Copyright (C) 2015 Canonical, Ltd. |
543 | + * |
544 | + * This program is free software; you can redistribute it and/or modify |
545 | + * it under the terms of the GNU General Public License as published by |
546 | + * the Free Software Foundation; version 3. |
547 | + * |
548 | + * This program is distributed in the hope that it will be useful, |
549 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
550 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
551 | + * GNU General Public License for more details. |
552 | + * |
553 | + * You should have received a copy of the GNU General Public License |
554 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
555 | + */ |
556 | + |
557 | +import QtQuick 2.3 |
558 | +import Ubuntu.Components 1.1 |
559 | + |
560 | +MouseArea { |
561 | + implicitHeight: tick.height |
562 | + implicitWidth: tick.width |
563 | + Image { |
564 | + id: tick |
565 | + source: Qt.resolvedUrl("graphics/tick.png") |
566 | + height: units.gu(6.5) |
567 | + width: units.gu(6.5) |
568 | + } |
569 | +} |
570 | |
571 | === modified file 'qml/Tutorial/Tutorial.qml' |
572 | --- qml/Tutorial/Tutorial.qml 2015-02-11 16:32:24 +0000 |
573 | +++ qml/Tutorial/Tutorial.qml 2015-02-11 16:32:25 +0000 |
574 | @@ -22,6 +22,7 @@ |
575 | |
576 | property alias active: loader.active |
577 | property bool paused |
578 | + property real edgeSize |
579 | |
580 | property Item launcher |
581 | property Item panel |
582 | @@ -29,7 +30,7 @@ |
583 | property Item overlay |
584 | |
585 | readonly property bool launcherEnabled: loader.item ? loader.item.launcherEnabled : true |
586 | - readonly property bool stagesEnabled: loader.item ? loader.item.stagesEnabled : true |
587 | + readonly property bool spreadEnabled: loader.item ? loader.item.spreadEnabled : true |
588 | readonly property bool panelEnabled: loader.item ? loader.item.panelEnabled : true |
589 | readonly property bool panelContentEnabled: loader.item ? loader.item.panelContentEnabled : true |
590 | readonly property bool running: loader.item ? loader.item.running : false |
591 | @@ -55,6 +56,12 @@ |
592 | |
593 | Binding { |
594 | target: loader.item |
595 | + property: "edgeSize" |
596 | + value: root.edgeSize |
597 | + } |
598 | + |
599 | + Binding { |
600 | + target: loader.item |
601 | property: "launcher" |
602 | value: root.launcher |
603 | } |
604 | |
605 | === added file 'qml/Tutorial/TutorialBottom.qml' |
606 | --- qml/Tutorial/TutorialBottom.qml 1970-01-01 00:00:00 +0000 |
607 | +++ qml/Tutorial/TutorialBottom.qml 2015-02-11 16:32:25 +0000 |
608 | @@ -0,0 +1,104 @@ |
609 | +/* |
610 | + * Copyright (C) 2014 Canonical, Ltd. |
611 | + * |
612 | + * This program is free software; you can redistribute it and/or modify |
613 | + * it under the terms of the GNU General Public License as published by |
614 | + * the Free Software Foundation; version 3. |
615 | + * |
616 | + * This program is distributed in the hope that it will be useful, |
617 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
618 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
619 | + * GNU General Public License for more details. |
620 | + * |
621 | + * You should have received a copy of the GNU General Public License |
622 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
623 | + */ |
624 | + |
625 | +import QtQuick 2.3 |
626 | +import Ubuntu.Components 1.1 |
627 | +import Ubuntu.Gestures 0.1 |
628 | +import "../Components" |
629 | +import "." as LocalComponents |
630 | + |
631 | +TutorialPage { |
632 | + id: root |
633 | + |
634 | + property alias edgeSize: dragArea.height |
635 | + |
636 | + title: i18n.tr("Open special menus") |
637 | + text: i18n.tr("Swipe up from the bottom edge.") |
638 | + fullTextWidth: true |
639 | + |
640 | + SequentialAnimation { |
641 | + id: teaseAnimation |
642 | + paused: running && root.paused |
643 | + running: !dragArea.useTouchY && slider.dragOffset === 0 |
644 | + loops: Animation.Infinite |
645 | + |
646 | + UbuntuNumberAnimation { |
647 | + target: slider |
648 | + property: "teaseOffset" |
649 | + to: units.gu(1) |
650 | + duration: UbuntuAnimation.SleepyDuration |
651 | + } |
652 | + UbuntuNumberAnimation { |
653 | + target: slider |
654 | + property: "teaseOffset" |
655 | + to: 0 |
656 | + duration: UbuntuAnimation.SleepyDuration |
657 | + } |
658 | + } |
659 | + |
660 | + foreground { |
661 | + children: [ |
662 | + LocalComponents.Slider { |
663 | + id: slider |
664 | + anchors { |
665 | + bottom: parent.bottom |
666 | + bottomMargin: width / 2 - height / 2 |
667 | + horizontalCenter: parent.horizontalCenter |
668 | + } |
669 | + rotation: -90 |
670 | + offset: teaseOffset + dragOffset |
671 | + active: dragArea.dragging |
672 | + |
673 | + property real teaseOffset |
674 | + property real dragOffset: dragArea.useTouchY ? -dragArea.touchY : 0 |
675 | + |
676 | + Behavior on dragOffset { |
677 | + id: offsetAnimation |
678 | + UbuntuNumberAnimation {} |
679 | + } |
680 | + } |
681 | + ] |
682 | + } |
683 | + |
684 | + EdgeDragArea { |
685 | + id: dragArea |
686 | + direction: Direction.Upwards |
687 | + anchors { |
688 | + bottom: parent.bottom |
689 | + left: parent.left |
690 | + right: parent.right |
691 | + } |
692 | + |
693 | + property bool useTouchY |
694 | + |
695 | + onDraggingChanged: { |
696 | + if (!dragging) { |
697 | + if (slider.percent >= 0.85) { |
698 | + root.hide(); |
699 | + } else if (slider.percent >= 0.15) { |
700 | + root.showError(); |
701 | + } |
702 | + } |
703 | + |
704 | + // We use a separate vars here rather than just directly looking at |
705 | + // 'dragging' because we want to preserve our 'slider.offset' |
706 | + // value during the above percent check. Now that we made it, |
707 | + // we can have 'slider.offset' go back to zero. |
708 | + offsetAnimation.enabled = !dragging; |
709 | + useTouchY = dragging; |
710 | + } |
711 | + } |
712 | +} |
713 | |
714 | === added file 'qml/Tutorial/TutorialBottomFinish.qml' |
715 | --- qml/Tutorial/TutorialBottomFinish.qml 1970-01-01 00:00:00 +0000 |
716 | +++ qml/Tutorial/TutorialBottomFinish.qml 2015-02-11 16:32:25 +0000 |
717 | @@ -0,0 +1,41 @@ |
718 | +/* |
719 | + * Copyright (C) 2014 Canonical, Ltd. |
720 | + * |
721 | + * This program is free software; you can redistribute it and/or modify |
722 | + * it under the terms of the GNU General Public License as published by |
723 | + * the Free Software Foundation; version 3. |
724 | + * |
725 | + * This program is distributed in the hope that it will be useful, |
726 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
727 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
728 | + * GNU General Public License for more details. |
729 | + * |
730 | + * You should have received a copy of the GNU General Public License |
731 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
732 | + */ |
733 | + |
734 | +import QtQuick 2.3 |
735 | +import Ubuntu.Components 1.1 |
736 | +import "." as LocalComponents |
737 | + |
738 | +TutorialPage { |
739 | + id: root |
740 | + |
741 | + title: i18n.tr("This action does different things for different apps") |
742 | + text: i18n.tr("Tap here to finish.") |
743 | + fullTextWidth: true |
744 | + |
745 | + foreground { |
746 | + children: [ |
747 | + LocalComponents.Tick { |
748 | + objectName: "tick" |
749 | + anchors { |
750 | + horizontalCenter: parent.horizontalCenter |
751 | + top: parent.top |
752 | + topMargin: root.textBottom + units.gu(3) |
753 | + } |
754 | + onClicked: root.hide() |
755 | + } |
756 | + ] |
757 | + } |
758 | +} |
759 | |
760 | === modified file 'qml/Tutorial/TutorialContent.qml' |
761 | --- qml/Tutorial/TutorialContent.qml 2015-02-11 16:32:24 +0000 |
762 | +++ qml/Tutorial/TutorialContent.qml 2015-02-11 16:32:25 +0000 |
763 | @@ -26,13 +26,14 @@ |
764 | property Item overlay |
765 | |
766 | readonly property bool launcherEnabled: !running || |
767 | - (!paused && loader.target === leftComponent) |
768 | - readonly property bool stagesEnabled: !running |
769 | + (!paused && tutorialLeft.shown) |
770 | + readonly property bool spreadEnabled: !running |
771 | readonly property bool panelEnabled: !running |
772 | readonly property bool panelContentEnabled: !running |
773 | - readonly property bool running: loader.sourceComponent !== null |
774 | + readonly property alias running: d.running |
775 | |
776 | property bool paused: false |
777 | + property real edgeSize |
778 | |
779 | signal finished() |
780 | |
781 | @@ -50,81 +51,74 @@ |
782 | QtObject { |
783 | id: d |
784 | |
785 | + property bool running |
786 | + |
787 | function stop() { |
788 | - loader.sourceComponent = null; |
789 | + running = false; |
790 | } |
791 | |
792 | function start() { |
793 | - loader.load(leftComponent); |
794 | - } |
795 | - } |
796 | - |
797 | - Loader { |
798 | - id: loader |
799 | - objectName: "tutorialLoader" |
800 | - |
801 | - property Component target: { |
802 | - if (next) { |
803 | - return next; |
804 | - } else if (loader.item && loader.item.shown) { |
805 | - return sourceComponent; |
806 | - } else { |
807 | - return null; |
808 | - } |
809 | - } |
810 | - |
811 | - property Component next: null |
812 | - |
813 | - function load(comp) { |
814 | - if (loader.item) { |
815 | - next = comp; |
816 | - loader.item.hide(); |
817 | - } else { |
818 | - loader.sourceComponent = comp; |
819 | - } |
820 | - } |
821 | - |
822 | - Connections { |
823 | - target: loader.item |
824 | - onFinished: { |
825 | - loader.sourceComponent = loader.next; |
826 | - if (loader.next != null) { |
827 | - loader.next = null; |
828 | - } else { |
829 | - root.finished(); |
830 | - } |
831 | - } |
832 | - } |
833 | - |
834 | - Binding { |
835 | - target: loader.item |
836 | - property: "paused" |
837 | - value: root.paused |
838 | - } |
839 | - } |
840 | - |
841 | - Component { |
842 | - id: leftComponent |
843 | - TutorialLeft { |
844 | - objectName: "tutorialLeft" |
845 | - parent: root.stages |
846 | - anchors.fill: parent |
847 | - launcher: root.launcher |
848 | - |
849 | - onFinished: loader.load(leftFinishComponent) |
850 | - } |
851 | - } |
852 | - |
853 | - Component { |
854 | - id: leftFinishComponent |
855 | - TutorialLeftFinish { |
856 | - objectName: "tutorialLeftFinish" |
857 | - parent: root.stages |
858 | - anchors.fill: parent |
859 | - textXOffset: root.launcher.panelWidth |
860 | - backgroundFadesOut: true |
861 | - |
862 | - onFinished: root.launcher.hide() |
863 | - } |
864 | + running = true; |
865 | + tutorialLeft.show(); |
866 | + } |
867 | + } |
868 | + |
869 | + TutorialLeft { |
870 | + id: tutorialLeft |
871 | + objectName: "tutorialLeft" |
872 | + parent: root.stages |
873 | + anchors.fill: parent |
874 | + launcher: root.launcher |
875 | + paused: !shown || root.paused |
876 | + |
877 | + onFinished: tutorialLeftFinish.show() |
878 | + } |
879 | + |
880 | + TutorialLeftFinish { |
881 | + id: tutorialLeftFinish |
882 | + objectName: "tutorialLeftFinish" |
883 | + parent: root.stages |
884 | + anchors.fill: parent |
885 | + textXOffset: root.launcher.panelWidth |
886 | + paused: !shown || root.paused |
887 | + |
888 | + onFinished: { |
889 | + root.launcher.hide(); |
890 | + tutorialRight.show(); |
891 | + } |
892 | + } |
893 | + |
894 | + TutorialRight { |
895 | + id: tutorialRight |
896 | + objectName: "tutorialRight" |
897 | + parent: root.stages |
898 | + anchors.fill: parent |
899 | + edgeSize: root.edgeSize |
900 | + panel: root.panel |
901 | + paused: !shown || root.paused |
902 | + |
903 | + onFinished: tutorialBottom.show() |
904 | + } |
905 | + |
906 | + TutorialBottom { |
907 | + id: tutorialBottom |
908 | + objectName: "tutorialBottom" |
909 | + parent: root.stages |
910 | + anchors.fill: parent |
911 | + edgeSize: root.edgeSize |
912 | + paused: !shown || root.paused |
913 | + |
914 | + onFinished: tutorialBottomFinish.show() |
915 | + } |
916 | + |
917 | + TutorialBottomFinish { |
918 | + id: tutorialBottomFinish |
919 | + objectName: "tutorialBottomFinish" |
920 | + parent: root.stages |
921 | + anchors.fill: parent |
922 | + backgroundFadesOut: true |
923 | + paused: !shown || root.paused |
924 | + |
925 | + onFinished: root.finish() |
926 | } |
927 | } |
928 | |
929 | === modified file 'qml/Tutorial/TutorialLeftFinish.qml' |
930 | --- qml/Tutorial/TutorialLeftFinish.qml 2015-02-11 16:32:24 +0000 |
931 | +++ qml/Tutorial/TutorialLeftFinish.qml 2015-02-11 16:32:25 +0000 |
932 | @@ -16,31 +16,25 @@ |
933 | |
934 | import QtQuick 2.3 |
935 | import Ubuntu.Components 1.1 |
936 | +import "." as LocalComponents |
937 | |
938 | TutorialPage { |
939 | id: root |
940 | |
941 | title: i18n.tr("These are the shortcuts to favorite apps") |
942 | - text: i18n.tr("Tap here to finish.") |
943 | + text: i18n.tr("Tap here to continue.") |
944 | fullTextWidth: true |
945 | |
946 | foreground { |
947 | children: [ |
948 | - Image { |
949 | + LocalComponents.Tick { |
950 | objectName: "tick" |
951 | anchors { |
952 | horizontalCenter: parent.horizontalCenter |
953 | top: parent.top |
954 | topMargin: root.textBottom + units.gu(3) |
955 | } |
956 | - source: Qt.resolvedUrl("graphics/tick.png") |
957 | - height: units.gu(6.5) |
958 | - width: units.gu(6.5) |
959 | - |
960 | - MouseArea { |
961 | - anchors.fill: parent |
962 | - onClicked: root.hide() |
963 | - } |
964 | + onClicked: root.hide() |
965 | } |
966 | ] |
967 | } |
968 | |
969 | === modified file 'qml/Tutorial/TutorialPage.qml' |
970 | --- qml/Tutorial/TutorialPage.qml 2015-02-11 16:32:24 +0000 |
971 | +++ qml/Tutorial/TutorialPage.qml 2015-02-11 16:32:25 +0000 |
972 | @@ -52,8 +52,8 @@ |
973 | property real textXOffset: 0 |
974 | property real textYOffset: 0 |
975 | |
976 | - // Foreground opacity |
977 | - property real foregroundOpacity: 1 |
978 | + // Foreground text opacity |
979 | + property real textOpacity: 1 |
980 | |
981 | signal finished() |
982 | |
983 | @@ -63,8 +63,8 @@ |
984 | |
985 | //// |
986 | |
987 | + visible: false |
988 | shown: false |
989 | - Component.onCompleted: show() |
990 | |
991 | property real _foregroundHideOpacity |
992 | |
993 | @@ -73,16 +73,16 @@ |
994 | from: 0 |
995 | to: 1 |
996 | duration: root.backgroundFadesIn ? UbuntuAnimation.SleepyDuration : UbuntuAnimation.BriskDuration |
997 | + onStarted: root.visible = true |
998 | } |
999 | |
1000 | hideAnimation: StandardAnimation { |
1001 | property: root.backgroundFadesOut ? "opacity" : "_foregroundHideOpacity" |
1002 | to: 0 |
1003 | duration: UbuntuAnimation.BriskDuration |
1004 | - onRunningChanged: { |
1005 | - if (!running) { |
1006 | - root.finished(); |
1007 | - } |
1008 | + onStopped: { |
1009 | + root.visible = false; |
1010 | + root.finished(); |
1011 | } |
1012 | } |
1013 | |
1014 | @@ -122,73 +122,78 @@ |
1015 | Item { |
1016 | id: foreground |
1017 | anchors.fill: parent |
1018 | - opacity: root.foregroundOpacity < 1 ? root.foregroundOpacity : root._foregroundHideOpacity |
1019 | - |
1020 | - Label { |
1021 | - id: titleLabel |
1022 | - anchors { |
1023 | - top: parent.verticalCenter |
1024 | - topMargin: d.verticalOffset + root.textYOffset |
1025 | - left: parent.left |
1026 | - leftMargin: d.sideMargin + d.textXOffset |
1027 | - } |
1028 | - width: parent.width - d.sideMargin * 2 |
1029 | - horizontalAlignment: Text.AlignLeft |
1030 | - wrapMode: Text.Wrap |
1031 | - font.weight: Font.Light |
1032 | - font.pixelSize: units.gu(3.5) |
1033 | - } |
1034 | - |
1035 | - Label { |
1036 | - id: textLabel |
1037 | - anchors { |
1038 | - top: titleLabel.bottom |
1039 | - topMargin: units.gu(2) |
1040 | - left: parent.left |
1041 | - leftMargin: d.sideMargin + d.textXOffset |
1042 | - } |
1043 | - width: (parent.width - d.sideMargin * 2) * (fullTextWidth ? 1 : 0.66) |
1044 | - horizontalAlignment: Text.AlignLeft |
1045 | - wrapMode: Text.Wrap |
1046 | - font.weight: Font.Light |
1047 | - font.pixelSize: units.gu(2.5) |
1048 | - } |
1049 | - |
1050 | - // We use two separate labels like this rather than just changing |
1051 | - // the text of the above labels because we want to know where to place |
1052 | - // sliders (via root.textBottom) without having that place change |
1053 | - // as the text changes length. |
1054 | - Label { |
1055 | - id: errorTitleLabel |
1056 | - objectName: "errorTitleLabel" |
1057 | - anchors { |
1058 | - top: titleLabel.top |
1059 | - left: titleLabel.left |
1060 | - } |
1061 | - width: titleLabel.width |
1062 | - horizontalAlignment: titleLabel.horizontalAlignment |
1063 | - wrapMode: titleLabel.wrapMode |
1064 | - font.weight: titleLabel.font.weight |
1065 | - font.pixelSize: titleLabel.font.pixelSize |
1066 | - opacity: 0 |
1067 | - text: i18n.tr("You almost got it!") |
1068 | - } |
1069 | - |
1070 | - Label { |
1071 | - id: errorTextLabel |
1072 | - objectName: "errorTextLabel" |
1073 | - anchors { |
1074 | - top: errorTitleLabel.bottom |
1075 | - topMargin: textLabel.anchors.topMargin |
1076 | - left: textLabel.left |
1077 | - } |
1078 | - width: textLabel.width |
1079 | - horizontalAlignment: textLabel.horizontalAlignment |
1080 | - wrapMode: textLabel.wrapMode |
1081 | - font.weight: textLabel.font.weight |
1082 | - font.pixelSize: textLabel.font.pixelSize |
1083 | - opacity: 0 |
1084 | - text: i18n.tr("Try again.") |
1085 | + opacity: root._foregroundHideOpacity |
1086 | + |
1087 | + Item { |
1088 | + anchors.fill: parent |
1089 | + opacity: root.textOpacity |
1090 | + |
1091 | + Label { |
1092 | + id: titleLabel |
1093 | + anchors { |
1094 | + top: parent.verticalCenter |
1095 | + topMargin: d.verticalOffset + root.textYOffset |
1096 | + left: parent.left |
1097 | + leftMargin: d.sideMargin + d.textXOffset |
1098 | + } |
1099 | + width: parent.width - d.sideMargin * 2 |
1100 | + horizontalAlignment: Text.AlignLeft |
1101 | + wrapMode: Text.Wrap |
1102 | + font.weight: Font.Light |
1103 | + font.pixelSize: units.gu(3.5) |
1104 | + } |
1105 | + |
1106 | + Label { |
1107 | + id: textLabel |
1108 | + anchors { |
1109 | + top: titleLabel.bottom |
1110 | + topMargin: units.gu(2) |
1111 | + left: parent.left |
1112 | + leftMargin: d.sideMargin + d.textXOffset |
1113 | + } |
1114 | + width: (parent.width - d.sideMargin * 2) * (fullTextWidth ? 1 : 0.66) |
1115 | + horizontalAlignment: Text.AlignLeft |
1116 | + wrapMode: Text.Wrap |
1117 | + font.weight: Font.Light |
1118 | + font.pixelSize: units.gu(2.5) |
1119 | + } |
1120 | + |
1121 | + // We use two separate labels like this rather than just changing |
1122 | + // the text of the above labels because we want to know where to place |
1123 | + // sliders (via root.textBottom) without having that place change |
1124 | + // as the text changes length. |
1125 | + Label { |
1126 | + id: errorTitleLabel |
1127 | + objectName: "errorTitleLabel" |
1128 | + anchors { |
1129 | + top: titleLabel.top |
1130 | + left: titleLabel.left |
1131 | + } |
1132 | + width: titleLabel.width |
1133 | + horizontalAlignment: titleLabel.horizontalAlignment |
1134 | + wrapMode: titleLabel.wrapMode |
1135 | + font.weight: titleLabel.font.weight |
1136 | + font.pixelSize: titleLabel.font.pixelSize |
1137 | + opacity: 0 |
1138 | + text: i18n.tr("You almost got it!") |
1139 | + } |
1140 | + |
1141 | + Label { |
1142 | + id: errorTextLabel |
1143 | + objectName: "errorTextLabel" |
1144 | + anchors { |
1145 | + top: errorTitleLabel.bottom |
1146 | + topMargin: textLabel.anchors.topMargin |
1147 | + left: textLabel.left |
1148 | + } |
1149 | + width: textLabel.width |
1150 | + horizontalAlignment: textLabel.horizontalAlignment |
1151 | + wrapMode: textLabel.wrapMode |
1152 | + font.weight: textLabel.font.weight |
1153 | + font.pixelSize: textLabel.font.pixelSize |
1154 | + opacity: 0 |
1155 | + text: i18n.tr("Try again.") |
1156 | + } |
1157 | } |
1158 | |
1159 | // A place for subclasses to add extra widgets |
1160 | |
1161 | === added file 'qml/Tutorial/TutorialRight.qml' |
1162 | --- qml/Tutorial/TutorialRight.qml 1970-01-01 00:00:00 +0000 |
1163 | +++ qml/Tutorial/TutorialRight.qml 2015-02-11 16:32:25 +0000 |
1164 | @@ -0,0 +1,223 @@ |
1165 | +/* |
1166 | + * Copyright (C) 2014 Canonical, Ltd. |
1167 | + * |
1168 | + * This program is free software; you can redistribute it and/or modify |
1169 | + * it under the terms of the GNU General Public License as published by |
1170 | + * the Free Software Foundation; version 3. |
1171 | + * |
1172 | + * This program is distributed in the hope that it will be useful, |
1173 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1174 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1175 | + * GNU General Public License for more details. |
1176 | + * |
1177 | + * You should have received a copy of the GNU General Public License |
1178 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1179 | + */ |
1180 | + |
1181 | +import QtQuick 2.3 |
1182 | +import Ubuntu.Components 1.1 |
1183 | +import Ubuntu.Gestures 0.1 |
1184 | +import Unity.Application 0.1 |
1185 | +import "../Components" |
1186 | +import "../Stages" |
1187 | +import "." as LocalComponents |
1188 | + |
1189 | +TutorialPage { |
1190 | + id: root |
1191 | + |
1192 | + property var panel |
1193 | + property alias edgeSize: stage.dragAreaWidth |
1194 | + |
1195 | + title: i18n.tr("To view open apps") |
1196 | + text: i18n.tr("Long swipe from the right edge.") |
1197 | + |
1198 | + textOpacity: 1 - slider.percent |
1199 | + |
1200 | + SequentialAnimation { |
1201 | + id: teaseAnimation |
1202 | + paused: running && root.paused |
1203 | + running: !stage.dragging && stage.dragProgress === 0 |
1204 | + loops: Animation.Infinite |
1205 | + |
1206 | + UbuntuNumberAnimation { |
1207 | + target: stage |
1208 | + property: "x" |
1209 | + to: -stage.dragAreaOverlap |
1210 | + duration: UbuntuAnimation.SleepyDuration |
1211 | + } |
1212 | + UbuntuNumberAnimation { |
1213 | + target: stage |
1214 | + property: "x" |
1215 | + to: 0 |
1216 | + duration: UbuntuAnimation.SleepyDuration |
1217 | + } |
1218 | + } |
1219 | + |
1220 | + foreground { |
1221 | + children: [ |
1222 | + LocalComponents.Slider { |
1223 | + id: slider |
1224 | + anchors { |
1225 | + right: parent.right |
1226 | + top: parent.top |
1227 | + topMargin: root.textBottom + units.gu(3) |
1228 | + } |
1229 | + rotation: 180 |
1230 | + offset: stage.dragProgress - stage.x |
1231 | + active: stage.dragging |
1232 | + }, |
1233 | + |
1234 | + // Just assume PhoneStage for now. The tablet version of the right-edge |
1235 | + // tutorial is still being spec'd by the design team. |
1236 | + PhoneStage { |
1237 | + id: stage |
1238 | + objectName: "stage" |
1239 | + anchors.top: parent.top |
1240 | + width: parent.width |
1241 | + height: parent.height |
1242 | + applicationManager: fakeAppManager |
1243 | + color: "transparent" |
1244 | + interactive: false |
1245 | + altTabEnabled: false |
1246 | + focusFirstApp: false |
1247 | + startScale: 0.8 |
1248 | + endScale: 0.6 |
1249 | + dragAreaOverlap: units.gu(2) |
1250 | + |
1251 | + onOpened: { |
1252 | + overlay.show(); |
1253 | + root.textOpacity = 0; |
1254 | + slider.visible = false; |
1255 | + } |
1256 | + |
1257 | + onDraggingChanged: { |
1258 | + if (!dragging) { |
1259 | + if (!overlay.shown) { |
1260 | + root.showError(); |
1261 | + } |
1262 | + teaseAnimation.complete(); |
1263 | + } |
1264 | + } |
1265 | + }, |
1266 | + |
1267 | + Showable { |
1268 | + id: overlay |
1269 | + objectName: "overlay" |
1270 | + anchors.fill: parent |
1271 | + |
1272 | + opacity: 0 |
1273 | + shown: false |
1274 | + showAnimation: UbuntuNumberAnimation { property: "opacity"; to: 1 } |
1275 | + |
1276 | + Label { |
1277 | + anchors.top: parent.top |
1278 | + anchors.topMargin: root.panel.panelHeight + units.gu(2) |
1279 | + anchors.left: parent.left |
1280 | + anchors.leftMargin: units.gu(2) |
1281 | + anchors.right: parent.right |
1282 | + anchors.rightMargin: units.gu(2) |
1283 | + wrapMode: Text.Wrap |
1284 | + horizontalAlignment: Text.AlignHCenter |
1285 | + fontSize: "large" |
1286 | + text: i18n.tr("View all your running tasks.") |
1287 | + } |
1288 | + |
1289 | + LocalComponents.Tick { |
1290 | + objectName: "tick" |
1291 | + anchors.bottom: bottomOverlayText.top |
1292 | + anchors.bottomMargin: units.gu(1) |
1293 | + anchors.horizontalCenter: bottomOverlayText.horizontalCenter |
1294 | + onClicked: root.hide() |
1295 | + } |
1296 | + |
1297 | + Label { |
1298 | + id: bottomOverlayText |
1299 | + anchors.bottom: parent.bottom |
1300 | + anchors.bottomMargin: units.gu(2) |
1301 | + anchors.left: parent.left |
1302 | + anchors.leftMargin: units.gu(2) |
1303 | + anchors.right: parent.right |
1304 | + anchors.rightMargin: units.gu(2) |
1305 | + wrapMode: Text.Wrap |
1306 | + horizontalAlignment: Text.AlignHCenter |
1307 | + fontSize: "small" |
1308 | + text: i18n.tr("Tap here to continue.") |
1309 | + } |
1310 | + } |
1311 | + ] |
1312 | + } |
1313 | + |
1314 | + ListModel { |
1315 | + id: fakeAppManager |
1316 | + |
1317 | + readonly property string focusedApplicationId: "facebook" |
1318 | + |
1319 | + function focusApplication(appId) {} |
1320 | + function requestFocusApplication(appId) {} |
1321 | + function findApplication(appId) {return null;} |
1322 | + |
1323 | + signal applicationAdded(string appId) |
1324 | + signal applicationRemoved(string appId) |
1325 | + signal focusRequested(string appId) |
1326 | + |
1327 | + ListElement { |
1328 | + appId: "facebook" |
1329 | + fullscreen: false |
1330 | + name: "" |
1331 | + icon: "" |
1332 | + state: ApplicationInfoInterface.Stopped |
1333 | + splashTitle: "" |
1334 | + splashImage: "" |
1335 | + splashShowHeader: false |
1336 | + splashColor: "transparent" |
1337 | + splashColorHeader: "transparent" |
1338 | + splashColorFooter: "transparent" |
1339 | + defaultScreenshot: "../Tutorial/graphics/facebook.png" |
1340 | + } |
1341 | + |
1342 | + ListElement { |
1343 | + appId: "camera" |
1344 | + fullscreen: false |
1345 | + name: "" |
1346 | + icon: "" |
1347 | + state: ApplicationInfoInterface.Stopped |
1348 | + splashTitle: "" |
1349 | + splashImage: "" |
1350 | + splashShowHeader: false |
1351 | + splashColor: "transparent" |
1352 | + splashColorHeader: "transparent" |
1353 | + splashColorFooter: "transparent" |
1354 | + defaultScreenshot: "../Tutorial/graphics/camera.png" |
1355 | + } |
1356 | + |
1357 | + ListElement { |
1358 | + appId: "gallery" |
1359 | + fullscreen: false |
1360 | + name: "" |
1361 | + icon: "" |
1362 | + state: ApplicationInfoInterface.Stopped |
1363 | + splashTitle: "" |
1364 | + splashImage: "" |
1365 | + splashShowHeader: false |
1366 | + splashColor: "transparent" |
1367 | + splashColorHeader: "transparent" |
1368 | + splashColorFooter: "transparent" |
1369 | + defaultScreenshot: "../Tutorial/graphics/gallery.png" |
1370 | + } |
1371 | + |
1372 | + ListElement { |
1373 | + appId: "dialer" |
1374 | + fullscreen: false |
1375 | + name: "" |
1376 | + icon: "" |
1377 | + state: ApplicationInfoInterface.Stopped |
1378 | + splashTitle: "" |
1379 | + splashImage: "" |
1380 | + splashShowHeader: false |
1381 | + splashColor: "transparent" |
1382 | + splashColorHeader: "transparent" |
1383 | + splashColorFooter: "transparent" |
1384 | + defaultScreenshot: "../Tutorial/graphics/dialer.png" |
1385 | + } |
1386 | + } |
1387 | +} |
1388 | |
1389 | === added file 'qml/Tutorial/graphics/camera.png' |
1390 | Binary files qml/Tutorial/graphics/camera.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/camera.png 2015-02-11 16:32:25 +0000 differ |
1391 | === added file 'qml/Tutorial/graphics/dialer.png' |
1392 | Binary files qml/Tutorial/graphics/dialer.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/dialer.png 2015-02-11 16:32:25 +0000 differ |
1393 | === added file 'qml/Tutorial/graphics/facebook.png' |
1394 | Binary files qml/Tutorial/graphics/facebook.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/facebook.png 2015-02-11 16:32:25 +0000 differ |
1395 | === added file 'qml/Tutorial/graphics/gallery.png' |
1396 | Binary files qml/Tutorial/graphics/gallery.png 1970-01-01 00:00:00 +0000 and qml/Tutorial/graphics/gallery.png 2015-02-11 16:32:25 +0000 differ |
1397 | === modified file 'tests/autopilot/unity8/shell/emulators/tutorial.py' |
1398 | --- tests/autopilot/unity8/shell/emulators/tutorial.py 2015-02-11 16:32:24 +0000 |
1399 | +++ tests/autopilot/unity8/shell/emulators/tutorial.py 2015-02-11 16:32:25 +0000 |
1400 | @@ -35,20 +35,40 @@ |
1401 | @classmethod |
1402 | def validate_dbus_object(cls, path, state): |
1403 | name = introspection.get_classname_from_path(path) |
1404 | - return name == b'TutorialPage' or name == b'TutorialLeft' |
1405 | + return name in (b'TutorialPage', b'TutorialLeft', |
1406 | + b'TutorialLeftFinish', b'TutorialRight', |
1407 | + b'TutorialBottom', b'TutorialBottomFinish') |
1408 | |
1409 | @autopilot.logging.log_action(logger.info) |
1410 | def short_swipe_right(self): |
1411 | + self.shown.wait_for(True) |
1412 | x, y, width, height = self.globalRect |
1413 | start_x = x |
1414 | stop_x = x + width // 3 |
1415 | start_y = stop_y = y + height // 2 |
1416 | self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1417 | - self.shown.wait_for(False) |
1418 | + |
1419 | + @autopilot.logging.log_action(logger.info) |
1420 | + def swipe_left(self): |
1421 | + self.shown.wait_for(True) |
1422 | + x, y, width, height = self.globalRect |
1423 | + start_x = width |
1424 | + stop_x = x |
1425 | + start_y = stop_y = y + height // 2 |
1426 | + self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1427 | + |
1428 | + @autopilot.logging.log_action(logger.info) |
1429 | + def swipe_up(self): |
1430 | + self.shown.wait_for(True) |
1431 | + x, y, width, height = self.globalRect |
1432 | + start_y = height |
1433 | + stop_y = y |
1434 | + start_x = stop_x = x + width // 2 |
1435 | + self.pointing_device.drag(start_x, start_y, stop_x, stop_y) |
1436 | |
1437 | @autopilot.logging.log_action(logger.info) |
1438 | def tap(self): |
1439 | """Tap the tick button to complete this step.""" |
1440 | - button = self.select_single(objectName="tick") |
1441 | + self.shown.wait_for(True) |
1442 | + button = self.wait_select_single(objectName="tick") |
1443 | self.pointing_device.click_object(button) |
1444 | - self.shown.wait_for(False) |
1445 | |
1446 | === modified file 'tests/autopilot/unity8/shell/tests/test_tutorial.py' |
1447 | --- tests/autopilot/unity8/shell/tests/test_tutorial.py 2015-02-11 16:32:24 +0000 |
1448 | +++ tests/autopilot/unity8/shell/tests/test_tutorial.py 2015-02-11 16:32:25 +0000 |
1449 | @@ -47,4 +47,11 @@ |
1450 | page.short_swipe_right() |
1451 | page = self.unity.wait_select_single(objectName='tutorialLeftFinish') |
1452 | page.tap() |
1453 | + page = self.unity.wait_select_single(objectName='tutorialRight') |
1454 | + page.swipe_left() |
1455 | + page.tap() |
1456 | + page = self.unity.wait_select_single(objectName='tutorialBottom') |
1457 | + page.swipe_up() |
1458 | + page = self.unity.wait_select_single(objectName='tutorialBottomFinish') |
1459 | + page.tap() |
1460 | self.assertThat(tutorial.running, Eventually(Equals(False))) |
1461 | |
1462 | === modified file 'tests/qmltests/Tutorial/tst_Tutorial.qml' |
1463 | --- tests/qmltests/Tutorial/tst_Tutorial.qml 2015-02-11 16:32:24 +0000 |
1464 | +++ tests/qmltests/Tutorial/tst_Tutorial.qml 2015-02-11 16:32:25 +0000 |
1465 | @@ -162,7 +162,6 @@ |
1466 | } |
1467 | |
1468 | function waitForPage(name) { |
1469 | - tryCompareFunction(function() { return findChild(shell, name) !== null; }, true); |
1470 | waitForRendering(findChild(shell, name)); |
1471 | var page = findChild(shell, name); |
1472 | tryCompare(page, "shown", true); |
1473 | @@ -221,6 +220,33 @@ |
1474 | var tick = findChild(page, "tick"); |
1475 | tap(tick); |
1476 | |
1477 | + page = waitForPage("tutorialRight"); |
1478 | + checkTopEdge(); |
1479 | + checkLeftEdge(); |
1480 | + checkBottomEdge(); |
1481 | + if (name === "tutorialRight") return page; |
1482 | + touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight); |
1483 | + var overlay = findChild(page, "overlay"); |
1484 | + tryCompare(overlay, "shown", true); |
1485 | + var tick = findChild(page, "tick"); |
1486 | + tap(tick); |
1487 | + |
1488 | + var page = waitForPage("tutorialBottom"); |
1489 | + checkTopEdge(); |
1490 | + checkLeftEdge(); |
1491 | + checkRightEdge(); |
1492 | + if (name === "tutorialBottom") return page; |
1493 | + touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight); |
1494 | + |
1495 | + var page = waitForPage("tutorialBottomFinish"); |
1496 | + checkTopEdge(); |
1497 | + checkLeftEdge(); |
1498 | + checkRightEdge(); |
1499 | + checkBottomEdge(); |
1500 | + if (name === "tutorialBottomFinish") return page; |
1501 | + var tick = findChild(page, "tick"); |
1502 | + tap(tick); |
1503 | + |
1504 | checkFinished(); |
1505 | return null; |
1506 | } |
1507 | @@ -277,6 +303,42 @@ |
1508 | tryCompare(left, "shown", true); // and we should still be on left |
1509 | } |
1510 | |
1511 | + function test_spread() { |
1512 | + // Unfortunately, most of what we want to test of the spread is |
1513 | + // "did it render correctly?" but that's hard to test. So instead, |
1514 | + // just poke and prod it a little bit to see if some of the values |
1515 | + // we'd expect to be correct, are so. |
1516 | + |
1517 | + var right = goToPage("tutorialRight"); |
1518 | + var stage = findChild(right, "stage"); |
1519 | + var delegate0 = findChild(right, "appDelegate0"); |
1520 | + |
1521 | + tryCompare(stage, "dragProgress", 0); |
1522 | + touchFlick(shell, shell.width, halfHeight, shell.width * 0.8, halfHeight, true, false); |
1523 | + verify(stage.dragProgress > 0); |
1524 | + compare(stage.dragProgress, -delegate0.xTranslate); |
1525 | + touchFlick(shell, shell.width * 0.8, halfHeight, shell.width, halfHeight, false, true); |
1526 | + tryCompare(stage, "dragProgress", 0); |
1527 | + |
1528 | + tryCompare(delegate0, "x", shell.width); |
1529 | + |
1530 | + var screenshotImage = findChild(right, "screenshotImage"); |
1531 | + tryCompare(screenshotImage, "source", Qt.resolvedUrl("../../../qml/Tutorial/graphics/facebook.png")); |
1532 | + tryCompare(screenshotImage, "visible", true); |
1533 | + } |
1534 | + |
1535 | + function test_bottomShortDrag() { |
1536 | + var bottom = goToPage("tutorialBottom"); |
1537 | + |
1538 | + touchFlick(shell, halfWidth, shell.height, halfWidth, shell.height * 0.8); |
1539 | + |
1540 | + var errorTextLabel = findChild(bottom, "errorTextLabel"); |
1541 | + var errorTitleLabel = findChild(bottom, "errorTitleLabel"); |
1542 | + tryCompare(bottom, "shown", true); // still on bottom page |
1543 | + tryCompare(errorTextLabel, "opacity", 1); // show error |
1544 | + tryCompare(errorTitleLabel, "opacity", 1); // show error |
1545 | + } |
1546 | + |
1547 | function test_interrupted() { |
1548 | goToPage("tutorialLeft"); |
1549 | ApplicationManager.startApplication("dialer-app"); |
FAILED: Continuous integration, rev:1393 jenkins. qa.ubuntu. com/job/ unity8- ci/5080/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 676 jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- vivid/244 jenkins. qa.ubuntu. com/job/ unity8- vivid-amd64- ci/245 jenkins. qa.ubuntu. com/job/ unity8- vivid-i386- ci/245 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- vivid-mako/ 581 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 674 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 674/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 16850
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: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/5080/ rebuild
http://