on xenial help sign in
Add new right-edge screen, not fully finished yet
commita4e916605e762b2a64e9d3a8a3ba9113f9de032b authorMichael Terry <michael.terry@canonical.com> dateTue 6 Jan 2015, 09:46 (12 years ago) parent8160336
16 files changed+443−120
qml/Shell.qml+2−2 qml/Stages/ApplicationWindow.qml+14−1 qml/Stages/PhoneStage.qml+54−31 qml/Stages/TransformedSpreadDelegate.qml+27−21 qml/Tutorial/Tick.qml+29 qml/Tutorial/Tutorial.qml+1−1 qml/Tutorial/TutorialBottomFinish.qml+3−9 qml/Tutorial/TutorialContent.qml+15−2 qml/Tutorial/TutorialLeftFinish.qml+3−9 qml/Tutorial/TutorialPage.qml+49−44 qml/Tutorial/TutorialRight.qml+219 qml/Tutorial/graphics/camera.png qml/Tutorial/graphics/dialer.jpg qml/Tutorial/graphics/facebook.png qml/Tutorial/graphics/gallery.png tests/qmltests/Tutorial/tst_Tutorial.qml+27
qml/Shell.qml+2−2
@@ -297,12 +297,12 @@ Item {
297297 Binding {
298298 target: applicationsDisplayLoader.item
299299 property: "interactive"
300− value: tutorial.stagesEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
300+ value: tutorial.spreadEnabled && !greeter.shown && !lockscreen.shown && panel.indicators.fullyClosed && launcher.progress == 0 && !notifications.useModal
301301 }
302302 Binding {
303303 target: applicationsDisplayLoader.item
304304 property: "spreadEnabled"
305− value: tutorial.stagesEnabled && !greeter.hasLockedApp
305+ value: tutorial.spreadEnabled && !greeter.hasLockedApp
306306 }
307307 Binding {
308308 target: applicationsDisplayLoader.item
qml/Stages/ApplicationWindow.qml+14−1
@@ -43,6 +43,7 @@ Item {
4343 readonly property color splashColor: root.application ? root.application.splashColor : "#00000000"
4444 readonly property color splashColorHeader: root.application ? root.application.splashColorHeader : "#00000000"
4545 readonly property color splashColorFooter: root.application ? root.application.splashColorFooter : "#00000000"
46+ readonly property url defaultScreenshot: root.application ? root.application.defaultScreenshot : ""
4647
4748 // Whether the Application had a surface before but lost it.
4849 property bool hadSurface: sessionContainer.surfaceContainer.hadSurface
@@ -72,7 +73,7 @@ Item {
7273 Image {
7374 id: screenshotImage
7475 objectName: "screenshotImage"
75− source: ""
76+ source: d.defaultScreenshot
7677 anchors.fill: parent
7778 antialiasing: !root.interactive
7879
@@ -123,6 +124,7 @@ Item {
123124 }
124125
125126 StateGroup {
127+ id: stateGroup
126128 objectName: "applicationWindowStateGroup"
127129 states: [
128130 State {
@@ -215,6 +217,17 @@ Item {
215217 PropertyAction { target: screenshotImage; property: "source"; value: "" }
216218 }
217219 },
220+ Transition {
221+ from: "splashScreen"; to: "screenshot"
222+ SequentialAnimation {
223+ PropertyAction { target: screenshotImage
224+ property: "visible"; value: true }
225+ UbuntuNumberAnimation { target: screenshotImage; property: "opacity";
226+ from: 0.0; to: 1.0
227+ duration: UbuntuAnimation.BriskDuration }
228+ PropertyAction { target: splashLoader; property: "active"; value: false }
229+ }
230+ },
218231 Transition {
219232 from: "surface"; to: "void"
220233 SequentialAnimation {
qml/Stages/PhoneStage.qml+54−31
@@ -32,6 +32,18 @@ Rectangle {
3232 property bool spreadEnabled: true // If false, animations and right edge will be disabled
3333 property real inverseProgress: 0 // This is the progress for left edge drags, in pixels.
3434 property int orientation: Qt.PortraitOrientation
35+ property QtObject applicationManager: ApplicationManager
36+ property bool focusFirstApp: true // If false, focused app will appear on right edge like other apps
37+ property bool altTabEnabled: true
38+ property real startScale: 1.1
39+ property real endScale: 0.7
40+
41+ // How far left the stage has been dragged
42+ readonly property real dragProgress: spreadRepeater.count > 0 ? -spreadRepeater.itemAt(0).xTranslate : 0
43+
44+ readonly property alias dragging: spreadDragArea.dragging
45+
46+ signal opened()
3547
3648 color: "#111111"
3749
@@ -52,30 +64,30 @@ Rectangle {
5264 if (inverseProgress == 0 && priv.oldInverseProgress > 0) {
5365 // left edge drag released. Minimum distance is given by design.
5466 if (priv.oldInverseProgress > units.gu(22)) {
55− ApplicationManager.focusApplication("unity8-dash");
67+ applicationManager.focusApplication("unity8-dash");
5668 }
5769 }
5870 priv.oldInverseProgress = inverseProgress;
5971 }
6072
6173 Connections {
62− target: ApplicationManager
74+ target: applicationManager
6375
6476 onFocusRequested: {
6577 if (spreadView.phase > 0) {
6678 spreadView.snapTo(priv.indexOf(appId));
6779 } else {
68− ApplicationManager.focusApplication(appId);
80+ applicationManager.focusApplication(appId);
6981 }
7082 }
7183
7284 onApplicationAdded: {
7385 if (spreadView.phase == 2) {
74− spreadView.snapTo(ApplicationManager.count - 1);
86+ spreadView.snapTo(applicationManager.count - 1);
7587 } else {
7688 spreadView.phase = 0;
7789 spreadView.contentX = -spreadView.shift;
78− ApplicationManager.focusApplication(appId);
90+ applicationManager.focusApplication(appId);
7991 }
8092 }
8193
@@ -90,9 +102,9 @@ Rectangle {
90102 }
91103
92104 function focusTopMostApp() {
93− if (ApplicationManager.count > 0) {
94− var topmostApp = ApplicationManager.get(0);
95− ApplicationManager.focusApplication(topmostApp.appId);
105+ if (applicationManager.count > 0) {
106+ var topmostApp = applicationManager.get(0);
107+ applicationManager.focusApplication(topmostApp.appId);
96108 }
97109 }
98110 }
@@ -100,8 +112,9 @@ Rectangle {
100112 QtObject {
101113 id: priv
102114
103− property string focusedAppId: ApplicationManager.focusedApplicationId
104− property var focusedApplication: ApplicationManager.findApplication(focusedAppId)
115+ readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
116+ property string focusedAppId: applicationManager.focusedApplicationId
117+ property var focusedApplication: applicationManager.findApplication(focusedAppId)
105118 property var focusedAppDelegate: null
106119
107120 property real oldInverseProgress: 0
@@ -110,8 +123,8 @@ Rectangle {
110123 onFocusedAppIdChanged: focusedAppDelegate = spreadRepeater.itemAt(0);
111124
112125 function indexOf(appId) {
113− for (var i = 0; i < ApplicationManager.count; i++) {
114− if (ApplicationManager.get(i).appId == appId) {
126+ for (var i = 0; i < applicationManager.count; i++) {
127+ if (applicationManager.get(i).appId == appId) {
115128 return i;
116129 }
117130 }
@@ -197,10 +210,17 @@ Rectangle {
197210 // Add 1 pixel to make sure we definitely hit positionMarker4 even with rounding errors of the animation.
198211 snapAnimation.targetContentX = width * positionMarker4 + 1 - shift;
199212 snapAnimation.start();
213+ root.opened();
200214 }
201215 }
202216 function snapTo(index) {
203− if (ApplicationManager.count <= index) {
217+ if (!root.altTabEnabled) {
218+ // Reset to start instead
219+ snapAnimation.targetContentX = -shift;
220+ snapAnimation.start();
221+ return;
222+ }
223+ if (applicationManager.count <= index) {
204224 // In case we're trying to snap to some non existing app, lets snap back to the first one
205225 index = 0;
206226 }
@@ -215,7 +235,7 @@ Rectangle {
215235 snapAnimation.start();
216236 }
217237
218− // In case the ApplicationManager already holds an app when starting up we're missing animations
238+ // In case the applicationManager already holds an app when starting up we're missing animations
219239 // Make sure we end up in the same state
220240 Component.onCompleted: {
221241 spreadView.contentX = -spreadView.shift
@@ -235,7 +255,7 @@ Rectangle {
235255 ScriptAction {
236256 script: {
237257 if (spreadView.selectedIndex >= 0) {
238− ApplicationManager.focusApplication(ApplicationManager.get(spreadView.selectedIndex).appId);
258+ applicationManager.focusApplication(applicationManager.get(spreadView.selectedIndex).appId);
239259
240260 spreadView.selectedIndex = -1;
241261 spreadView.phase = 0;
@@ -250,7 +270,7 @@ Rectangle {
250270 // This width controls how much the spread can be flicked left/right. It's composed of:
251271 // tileDistance * app count (with a minimum of 3 apps, in order to also allow moving 1 and 2 apps a bit)
252272 // + some constant value (still scales with the screen width) which looks good and somewhat fills the screen
253− width: Math.max(3, ApplicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
273+ width: Math.max(3, applicationManager.count) * spreadView.tileDistance + (spreadView.width - spreadView.tileDistance) * 1.5
254274 height: parent.height
255275 Behavior on width {
256276 enabled: spreadView.closingIndex >= 0
@@ -265,20 +285,22 @@ Rectangle {
265285 x: spreadView.contentX
266286
267287 onClicked: {
268− spreadView.snapTo(0);
288+ if (root.altTabEnabled) {
289+ spreadView.snapTo(0);
290+ }
269291 }
270292
271293 Repeater {
272294 id: spreadRepeater
273295 objectName: "spreadRepeater"
274− model: ApplicationManager
296+ model: applicationManager
275297 delegate: TransformedSpreadDelegate {
276298 id: appDelegate
277299 objectName: "appDelegate" + index
278300 startAngle: 45
279301 endAngle: 5
280− startScale: 1.1
281− endScale: 0.7
302+ startScale: root.startScale
303+ endScale: root.endScale
282304 startDistance: spreadView.tileDistance
283305 endDistance: units.gu(.5)
284306 width: spreadView.width
@@ -286,11 +308,12 @@ Rectangle {
286308 selected: spreadView.selectedIndex == index
287309 otherSelected: spreadView.selectedIndex >= 0 && !selected
288310 interactive: !spreadView.interactive && spreadView.phase === 0
289− && spreadView.shiftedContentX === 0 && root.interactive && index === 0
290− swipeToCloseEnabled: spreadView.interactive && !snapAnimation.running
311+ && spreadView.shiftedContentX === 0 && root.interactive && isFocused
312+ swipeToCloseEnabled: spreadView.interactive && root.interactive && !snapAnimation.running
291313 maximizedAppTopMargin: root.maximizedAppTopMargin
292314 dropShadow: spreadView.active ||
293315 (priv.focusedAppDelegate && priv.focusedAppDelegate.x !== 0)
316+ focusFirstApp: root.focusFirstApp
294317
295318 readonly property bool isDash: model.appId == "unity8-dash"
296319
@@ -298,7 +321,7 @@ Rectangle {
298321
299322 x: {
300323 // focused app is always positioned at 0 except when following left edge drag
301− if (index == 0) {
324+ if (isFocused) {
302325 if (!isDash && root.inverseProgress > 0) {
303326 return root.inverseProgress;
304327 }
@@ -309,10 +332,10 @@ Rectangle {
309332 }
310333
311334 // Otherwise line up for the spread
312− return spreadView.width + (index - 1) * spreadView.tileDistance;
335+ return spreadView.width + spreadIndex * spreadView.tileDistance;
313336 }
314337
315− application: ApplicationManager.get(index)
338+ application: applicationManager.get(index)
316339 closeable: !isDash
317340
318341 property real behavioredIndex: index
@@ -350,7 +373,7 @@ Rectangle {
350373 progress: {
351374 var tileProgress = (spreadView.shiftedContentX - behavioredIndex * spreadView.tileDistance) / spreadView.width;
352375 // Tile 1 needs to move directly from the beginning...
353− if (behavioredIndex == 1 && spreadView.phase < 2) {
376+ if (root.focusFirstApp && behavioredIndex == 1 && spreadView.phase < 2) {
354377 tileProgress += spreadView.tileDistance / spreadView.width;
355378 }
356379 // Limiting progress to ~0 and 1.7 to avoid binding calculations when tiles are not
@@ -365,7 +388,7 @@ Rectangle {
365388
366389 // This mostly is the same as progress, just adds the snapping to phase 1 for tiles 0 and 1
367390 animatedProgress: {
368− if (spreadView.phase == 0 && index < 2) {
391+ if (spreadView.phase == 0 && index <= priv.firstSpreadIndex) {
369392 if (progress < spreadView.positionMarker1) {
370393 return progress;
371394 } else if (progress < spreadView.positionMarker1 + 0.05){
@@ -390,11 +413,11 @@ Rectangle {
390413 }
391414
392415 onClicked: {
393− if (spreadView.phase == 2) {
394− if (ApplicationManager.focusedApplicationId == ApplicationManager.get(index).appId) {
416+ if (root.altTabEnabled && spreadView.phase == 2) {
417+ if (applicationManager.focusedApplicationId == applicationManager.get(index).appId) {
395418 spreadView.snapTo(index);
396419 } else {
397− ApplicationManager.requestFocusApplication(ApplicationManager.get(index).appId);
420+ applicationManager.requestFocusApplication(applicationManager.get(index).appId);
398421 }
399422 }
400423 }
@@ -409,7 +432,7 @@ Rectangle {
409432
410433 onClosed: {
411434 spreadView.closingIndex = index;
412− ApplicationManager.stopApplication(ApplicationManager.get(index).appId);
435+ applicationManager.stopApplication(applicationManager.get(index).appId);
413436 }
414437 }
415438 }
qml/Stages/TransformedSpreadDelegate.qml+27−21
@@ -46,6 +46,18 @@ SpreadDelegate {
4646 property real startDistance: units.gu(5)
4747 property real endDistance: units.gu(.5)
4848
49+ // Whether first app is displayed entirely vs just on the spread edge
50+ property bool focusFirstApp: true
51+
52+ // Whether this delegate is displayed to the user outside of the spread
53+ readonly property bool isFocused: focusFirstApp && index === 0
54+
55+ // Adjusted index for any spread animation calculations
56+ readonly property int spreadIndex: index - (focusFirstApp ? 1 : 0)
57+
58+ // How far left this delegate has been translated
59+ readonly property alias xTranslate: priv.xTranslate
60+
4961 onSelectedChanged: {
5062 if (selected) {
5163 priv.snapshot();
@@ -63,8 +75,8 @@ SpreadDelegate {
6375 Connections {
6476 target: spreadView
6577 onPhaseChanged: {
66− if (spreadView.phase == 1) {
67− if (index == 0) {
78+ if (root.focusFirstApp && spreadView.phase == 1) {
79+ if (index === 0) {
6880 priv.phase2startTranslate = priv.easingAnimation(0, spreadView.positionMarker4, 0, -spreadView.width, spreadView.positionMarker4) + spreadView.width;
6981 priv.phase2startAngle = priv.easingAnimation(0, spreadView.positionMarker4, root.startAngle, root.endAngle, spreadView.positionMarker4);
7082 priv.phase2startScale = priv.easingAnimation(0, spreadView.positionMarker4, root.startScale, root.endScale, spreadView.positionMarker4);
@@ -134,7 +146,7 @@ SpreadDelegate {
134146 }
135147
136148 if (otherSelected) {
137− if (spreadView.phase < 2 && index == 0) {
149+ if (spreadView.phase < 2 && root.isFocused) {
138150 return linearAnimation(selectedProgress, 0, selectedXTranslate,
139151 selectedXTranslate - spreadView.tileDistance, root.progress);
140152 }
@@ -142,8 +154,7 @@ SpreadDelegate {
142154 return selectedXTranslate;
143155 }
144156
145− switch (index) {
146− case 0:
157+ if (root.focusFirstApp && index === 0) {
147158 if (spreadView.phase == 0) {
148159 return Math.min(0, linearAnimation(0, spreadView.positionMarker2,
149160 0, -spreadView.width * .25, root.animatedProgress));
@@ -153,11 +164,10 @@ SpreadDelegate {
153164 } else if (!priv.isSelected){ // phase 2
154165 // Apply the same animation as with the rest but add spreadView.width to align it with the others.
155166 return -easingCurve.value * spreadView.width + spreadView.width;
156− } else if (priv.isSelected) {
167+ } else {
157168 return linearAnimation(selectedProgress, 0, selectedXTranslate, 0, root.progress);
158169 }
159−
160− case 1:
170+ } else if (root.focusFirstApp && index === 1) {
161171 if (spreadView.phase == 0 && !priv.isSelected) {
162172 return linearAnimation(0, spreadView.positionMarker2,
163173 0, -spreadView.width * spreadView.snapPosition, root.animatedProgress);
@@ -170,13 +180,13 @@ SpreadDelegate {
170180
171181 if (priv.isSelected) {
172182 // Distance to left edge
173− var targetTranslate = -spreadView.width - ((index - 1) * root.startDistance);
183+ var targetTranslate = -spreadView.width - (root.spreadIndex * root.startDistance);
174184 return linearAnimation(selectedProgress, 0,
175185 selectedXTranslate, targetTranslate, root.progress);
176186 }
177187
178188 // Fix it at the right edge...
179− var rightEdgeOffset = -((index - 1) * root.startDistance);
189+ var rightEdgeOffset = -(root.spreadIndex * root.startDistance);
180190 // ...and use our easing to move them to the left. Stop a bit earlier for each tile
181191 var animatedEndDistance = linearAnimation(0, 2, root.endDistance, 0, root.progress);
182192 return -easingCurve.value * spreadView.width + (index * animatedEndDistance) + rightEdgeOffset;
@@ -194,8 +204,7 @@ SpreadDelegate {
194204 if (priv.isSelected) {
195205 return linearAnimation(selectedProgress, 0, selectedAngle, 0, root.progress);
196206 }
197− switch (index) {
198− case 0:
207+ if (root.focusFirstApp && index === 0) {
199208 if (spreadView.phase == 0) {
200209 return Math.max(0, linearAnimation(0, spreadView.positionMarker2,
201210 0, root.tile0SnapAngle, root.animatedProgress));
@@ -203,7 +212,7 @@ SpreadDelegate {
203212 return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
204213 root.tile0SnapAngle, phase2startAngle, root.progress);
205214 }
206− case 1:
215+ } else if (root.focusFirstApp && index === 1) {
207216 if (spreadView.phase == 0) {
208217 return linearAnimation(0, spreadView.positionMarker2, root.startAngle,
209218 root.startAngle * (1-spreadView.snapPosition), root.animatedProgress);
@@ -227,15 +236,14 @@ SpreadDelegate {
227236 return linearAnimation(selectedProgress, 0, selectedScale, 1, root.progress);
228237 }
229238
230− switch (index) {
231− case 0:
239+ if (root.focusFirstApp && index === 0) {
232240 if (spreadView.phase == 0) {
233241 return 1;
234242 } else if (spreadView.phase == 1) {
235243 return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
236244 1, phase2startScale, root.progress);
237245 }
238− case 1:
246+ } else if (root.focusFirstApp && index === 1) {
239247 if (spreadView.phase == 0) {
240248 var targetScale = tile1StartScale - ((tile1StartScale - 1) * spreadView.snapPosition);
241249 return linearAnimation(0, spreadView.positionMarker2,
@@ -254,7 +262,7 @@ SpreadDelegate {
254262 return linearAnimation (selectedProgress, Math.max(0, selectedProgress - .5),
255263 selectedOpacity, 0, root.progress);
256264 }
257− if (index == 0) {
265+ if (root.isFocused) {
258266 switch (spreadView.phase) {
259267 case 0:
260268 return linearAnimation(0, spreadView.positionMarker2, 1, .7, root.animatedProgress);
@@ -272,16 +280,14 @@ SpreadDelegate {
272280 return linearAnimation(selectedProgress, 0, selectedTopMarginProgress, 0, root.progress);
273281 }
274282
275− switch (index) {
276− case 0:
283+ if (root.focusFirstApp && index === 0) {
277284 if (spreadView.phase == 0) {
278285 return 0;
279286 } else if (spreadView.phase == 1) {
280287 return linearAnimation(spreadView.positionMarker2, spreadView.positionMarker4,
281288 0, priv.phase2startTopMarginProgress, root.progress);
282289 }
283− break;
284− case 1:
290+ } else if (root.focusFirstApp && index === 1) {
285291 if (spreadView.phase == 0) {
286292 return 0;
287293 } else if (spreadView.phase == 1) {
qml/Tutorial/Tick.qmlnew file+29
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright (C) 2015 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+import Ubuntu.Components 1.1
19+
20+MouseArea {
21+ implicitHeight: tick.height
22+ implicitWidth: tick.width
23+ Image {
24+ id: tick
25+ source: Qt.resolvedUrl("graphics/tick.png")
26+ height: units.gu(6.5)
27+ width: units.gu(6.5)
28+ }
29+}
qml/Tutorial/Tutorial.qml+1−1
@@ -30,7 +30,7 @@ Item {
3030 property Item overlay
3131
3232 readonly property bool launcherEnabled: loader.item ? loader.item.launcherEnabled : true
33− readonly property bool stagesEnabled: loader.item ? loader.item.stagesEnabled : true
33+ readonly property bool spreadEnabled: loader.item ? loader.item.spreadEnabled : true
3434 readonly property bool panelEnabled: loader.item ? loader.item.panelEnabled : true
3535 readonly property bool panelContentEnabled: loader.item ? loader.item.panelContentEnabled : true
3636 readonly property bool running: loader.item ? loader.item.running : false
qml/Tutorial/TutorialBottomFinish.qml+3−9
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.3
1818import Ubuntu.Components 1.1
19+import "." as LocalComponents
1920
2021TutorialPage {
2122 id: root
@@ -26,21 +27,14 @@ TutorialPage {
2627
2728 foreground {
2829 children: [
29− Image {
30+ LocalComponents.Tick {
3031 objectName: "tick"
3132 anchors {
3233 horizontalCenter: parent.horizontalCenter
3334 top: parent.top
3435 topMargin: root.textBottom + units.gu(3)
3536 }
36− source: Qt.resolvedUrl("graphics/tick.png")
37− height: units.gu(6.5)
38− width: units.gu(6.5)
39−
40− MouseArea {
41− anchors.fill: parent
42− onClicked: root.hide()
43− }
37+ onClicked: root.hide()
4438 }
4539 ]
4640 }
qml/Tutorial/TutorialContent.qml+15−2
@@ -27,7 +27,7 @@ Item {
2727
2828 readonly property bool launcherEnabled: !running ||
2929 (!paused && loader.target === leftComponent)
30− readonly property bool stagesEnabled: !running
30+ readonly property bool spreadEnabled: !running
3131 readonly property bool panelEnabled: !running
3232 readonly property bool panelContentEnabled: !running
3333 readonly property bool running: loader.sourceComponent !== null
@@ -126,11 +126,24 @@ Item {
126126
127127 onFinished: {
128128 root.launcher.hide();
129− loader.load(bottomComponent);
129+ loader.load(rightComponent);
130130 }
131131 }
132132 }
133133
134+ Component {
135+ id: rightComponent
136+ TutorialRight {
137+ objectName: "tutorialRight"
138+ parent: root.stages
139+ anchors.fill: parent
140+ edgeSize: root.edgeSize
141+ panel: root.panel
142+
143+ onFinished: loader.load(bottomComponent)
144+ }
145+ }
146+
134147 Component {
135148 id: bottomComponent
136149 TutorialBottom {
qml/Tutorial/TutorialLeftFinish.qml+3−9
@@ -16,6 +16,7 @@
1616
1717import QtQuick 2.3
1818import Ubuntu.Components 1.1
19+import "." as LocalComponents
1920
2021TutorialPage {
2122 id: root
@@ -26,21 +27,14 @@ TutorialPage {
2627
2728 foreground {
2829 children: [
29− Image {
30+ LocalComponents.Tick {
3031 objectName: "tick"
3132 anchors {
3233 horizontalCenter: parent.horizontalCenter
3334 top: parent.top
3435 topMargin: root.textBottom + units.gu(3)
3536 }
36− source: Qt.resolvedUrl("graphics/tick.png")
37− height: units.gu(6.5)
38− width: units.gu(6.5)
39−
40− MouseArea {
41− anchors.fill: parent
42− onClicked: root.hide()
43− }
37+ onClicked: root.hide()
4438 }
4539 ]
4640 }
qml/Tutorial/TutorialPage.qml+49−44
@@ -55,8 +55,8 @@ Showable {
5555 property real textXOffset: 0
5656 property real textYOffset: 0
5757
58− // Foreground opacity
59− property real foregroundOpacity: 1
58+ // Foreground text opacity
59+ property real textOpacity: 1
6060
6161 signal finished()
6262
@@ -125,53 +125,58 @@ Showable {
125125 Item {
126126 id: foreground
127127 anchors.fill: parent
128− opacity: root.foregroundOpacity < 1 ? root.foregroundOpacity : root._foregroundHideOpacity
129−
130− Label {
131− id: titleLabel
132− anchors {
133− top: parent.verticalCenter
134− topMargin: d.verticalOffset + root.textYOffset
135− left: parent.left
136− leftMargin: d.sideMargin + d.textXOffset
128+ opacity: root._foregroundHideOpacity
129+
130+ Item {
131+ anchors.fill: parent
132+ opacity: root.textOpacity
133+
134+ Label {
135+ id: titleLabel
136+ anchors {
137+ top: parent.verticalCenter
138+ topMargin: d.verticalOffset + root.textYOffset
139+ left: parent.left
140+ leftMargin: d.sideMargin + d.textXOffset
141+ }
142+ width: parent.width - d.sideMargin * 2
143+ horizontalAlignment: Text.AlignLeft
144+ wrapMode: Text.Wrap
145+ font.weight: Font.Light
146+ font.pixelSize: units.gu(3.5)
137147 }
138− width: parent.width - d.sideMargin * 2
139− horizontalAlignment: Text.AlignLeft
140− wrapMode: Text.Wrap
141− font.weight: Font.Light
142− font.pixelSize: units.gu(3.5)
143− }
144148
145− Label {
146− id: textLabel
147− anchors {
148− top: titleLabel.bottom
149− topMargin: units.gu(2)
150− left: parent.left
151− leftMargin: d.sideMargin + d.textXOffset
149+ Label {
150+ id: textLabel
151+ anchors {
152+ top: titleLabel.bottom
153+ topMargin: units.gu(2)
154+ left: parent.left
155+ leftMargin: d.sideMargin + d.textXOffset
156+ }
157+ width: (parent.width - d.sideMargin * 2) * (fullTextWidth ? 1 : 0.66)
158+ horizontalAlignment: Text.AlignLeft
159+ wrapMode: Text.Wrap
160+ font.weight: Font.Light
161+ font.pixelSize: units.gu(2.5)
152162 }
153− width: (parent.width - d.sideMargin * 2) * (fullTextWidth ? 1 : 0.66)
154− horizontalAlignment: Text.AlignLeft
155− wrapMode: Text.Wrap
156− font.weight: Font.Light
157− font.pixelSize: units.gu(2.5)
158− }
159163
160− Label {
161− id: errorLabel
162− objectName: "errorLabel"
163− anchors {
164− top: parent.verticalCenter
165− topMargin: d.verticalOffset + root.textYOffset
166− left: parent.left
167− leftMargin: d.sideMargin + d.textXOffset
164+ Label {
165+ id: errorLabel
166+ objectName: "errorLabel"
167+ anchors {
168+ top: parent.verticalCenter
169+ topMargin: d.verticalOffset + root.textYOffset
170+ left: parent.left
171+ leftMargin: d.sideMargin + d.textXOffset
172+ }
173+ width: parent.width - d.sideMargin * 2
174+ horizontalAlignment: Text.AlignLeft
175+ wrapMode: Text.Wrap
176+ font.weight: Font.Light
177+ font.pixelSize: units.gu(3.5)
178+ opacity: 0
168179 }
169− width: parent.width - d.sideMargin * 2
170− horizontalAlignment: Text.AlignLeft
171− wrapMode: Text.Wrap
172− font.weight: Font.Light
173− font.pixelSize: units.gu(3.5)
174− opacity: 0
175180 }
176181
177182 // A place for subclasses to add extra widgets
qml/Tutorial/TutorialRight.qmlnew file+219
@@ -0,0 +1,219 @@
1+/*
2+ * Copyright (C) 2014 Canonical, Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.3
18+import Ubuntu.Components 1.1
19+import Ubuntu.Gestures 0.1
20+import Unity.Application 0.1
21+import "../Components"
22+import "../Stages"
23+import "." as LocalComponents
24+
25+TutorialPage {
26+ id: root
27+
28+ property var panel
29+ property alias edgeSize: stage.dragAreaWidth
30+
31+ title: i18n.tr("To view open apps")
32+ text: i18n.tr("Long swipe from the right edge.")
33+ errorText: i18n.tr("You almost got it!") + "\n" + i18n.tr("Try again.")
34+
35+ textOpacity: 1 - slider.percent
36+
37+ SequentialAnimation {
38+ paused: root.paused
39+ running: false // !slider.active
40+ loops: Animation.Infinite
41+
42+ UbuntuNumberAnimation {
43+ target: stage
44+ property: "x"
45+ to: -units.gu(2)
46+ duration: UbuntuAnimation.SleepyDuration
47+ }
48+ UbuntuNumberAnimation {
49+ target: stage
50+ property: "x"
51+ to: 0
52+ duration: UbuntuAnimation.SleepyDuration
53+ }
54+ }
55+
56+ foreground {
57+ children: [
58+ LocalComponents.Slider {
59+ id: slider
60+ anchors {
61+ right: parent.right
62+ top: parent.top
63+ topMargin: root.textBottom + units.gu(3)
64+ }
65+ rotation: 180
66+ offset: stage.dragProgress - stage.x
67+ active: stage.dragging
68+ },
69+
70+ // Just assume PhoneStage for now. The tablet version of the right-edge
71+ // tutorial is still being spec'd by the design team.
72+ PhoneStage {
73+ id: stage
74+ anchors.top: parent.top
75+ x: 0
76+ width: parent.width
77+ height: parent.height
78+ applicationManager: fakeAppManager
79+ color: "transparent"
80+ interactive: false
81+ altTabEnabled: false
82+ focusFirstApp: false
83+ startScale: 0.9
84+ endScale: 0.6
85+
86+ onOpened: {
87+ overlay.show();
88+ root.textOpacity = 0;
89+ slider.visible = false;
90+ }
91+
92+ onDraggingChanged: {
93+ if (!dragging && !overlay.shown) {
94+ root.showError();
95+ }
96+ }
97+ },
98+
99+ Showable {
100+ id: overlay
101+ objectName: "overlay"
102+ anchors.fill: parent
103+
104+ opacity: 0
105+ shown: false
106+ showAnimation: UbuntuNumberAnimation { property: "opacity"; to: 1 }
107+
108+ Label {
109+ anchors.top: parent.top
110+ anchors.topMargin: root.panel.panelHeight + units.gu(2)
111+ anchors.left: parent.left
112+ anchors.leftMargin: units.gu(2)
113+ anchors.right: parent.right
114+ anchors.rightMargin: units.gu(2)
115+ wrapMode: Text.Wrap
116+ horizontalAlignment: Text.AlignHCenter
117+ fontSize: "large"
118+ text: i18n.tr("View all your running tasks.")
119+ }
120+
121+ LocalComponents.Tick {
122+ objectName: "tick"
123+ anchors.bottom: bottomOverlayText.top
124+ anchors.bottomMargin: units.gu(1)
125+ anchors.horizontalCenter: bottomOverlayText.horizontalCenter
126+ onClicked: root.hide()
127+ }
128+
129+ Label {
130+ id: bottomOverlayText
131+ anchors.bottom: parent.bottom
132+ anchors.bottomMargin: units.gu(2)
133+ anchors.left: parent.left
134+ anchors.leftMargin: units.gu(2)
135+ anchors.right: parent.right
136+ anchors.rightMargin: units.gu(2)
137+ wrapMode: Text.Wrap
138+ horizontalAlignment: Text.AlignHCenter
139+ fontSize: "small"
140+ text: i18n.tr("Tap here to continue.")
141+ }
142+ }
143+ ]
144+ }
145+
146+ ListModel {
147+ id: fakeAppManager
148+
149+ readonly property string focusedApplicationId: "facebook"
150+
151+ function focusApplication(appId) {}
152+ function requestFocusApplication(appId) {}
153+ function findApplication(appId) {return null;}
154+
155+ signal applicationAdded(string appId)
156+ signal applicationRemoved(string appId)
157+ signal focusRequested(string appId)
158+
159+ ListElement {
160+ appId: "facebook"
161+ fullscreen: false
162+ name: ""
163+ icon: ""
164+ state: ApplicationInfoInterface.Stopped
165+ splashTitle: ""
166+ splashImage: ""
167+ splashShowHeader: false
168+ splashColor: "transparent"
169+ splashColorHeader: "transparent"
170+ splashColorFooter: "transparent"
171+ defaultScreenshot: "../Tutorial/graphics/facebook.png"
172+ }
173+
174+ ListElement {
175+ appId: "camera"
176+ fullscreen: false
177+ name: ""
178+ icon: ""
179+ state: ApplicationInfoInterface.Stopped
180+ splashTitle: ""
181+ splashImage: ""
182+ splashShowHeader: false
183+ splashColor: "transparent"
184+ splashColorHeader: "transparent"
185+ splashColorFooter: "transparent"
186+ defaultScreenshot: "../Tutorial/graphics/camera.png"
187+ }
188+
189+ ListElement {
190+ appId: "gallery"
191+ fullscreen: false
192+ name: ""
193+ icon: ""
194+ state: ApplicationInfoInterface.Stopped
195+ splashTitle: ""
196+ splashImage: ""
197+ splashShowHeader: false
198+ splashColor: "transparent"
199+ splashColorHeader: "transparent"
200+ splashColorFooter: "transparent"
201+ defaultScreenshot: "../Tutorial/graphics/gallery.png"
202+ }
203+
204+ ListElement {
205+ appId: "dialer"
206+ fullscreen: false
207+ name: ""
208+ icon: ""
209+ state: ApplicationInfoInterface.Stopped
210+ splashTitle: ""
211+ splashImage: ""
212+ splashShowHeader: false
213+ splashColor: "transparent"
214+ splashColorHeader: "transparent"
215+ splashColorFooter: "transparent"
216+ defaultScreenshot: "../Tutorial/graphics/dialer.jpg"
217+ }
218+ }
219+}
qml/Tutorial/graphics/camera.pngnew file

Binary file not shown.

qml/Tutorial/graphics/dialer.jpgnew file

Binary file not shown.

qml/Tutorial/graphics/facebook.pngnew file

Binary file not shown.

qml/Tutorial/graphics/gallery.pngnew file

Binary file not shown.

tests/qmltests/Tutorial/tst_Tutorial.qml+27
@@ -211,6 +211,33 @@ Item {
211211 var tick = findChild(page, "tick");
212212 tap(tick);
213213
214+ page = waitForPage("tutorialRight");
215+ checkTopEdge();
216+ checkLeftEdge();
217+ checkBottomEdge();
218+ if (name === "tutorialRight") return page;
219+ touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
220+ var overlay = findChild(page, "overlay");
221+ tryCompare(overlay, "shown", true);
222+ var tick = findChild(page, "tick");
223+ tap(tick);
224+
225+ var page = waitForPage("tutorialBottom");
226+ checkTopEdge();
227+ checkLeftEdge();
228+ checkRightEdge();
229+ if (name === "tutorialBottom") return page;
230+ touchFlick(shell, halfWidth, shell.height, halfWidth, halfHeight);
231+
232+ var page = waitForPage("tutorialBottomFinish");
233+ checkTopEdge();
234+ checkLeftEdge();
235+ checkRightEdge();
236+ checkBottomEdge();
237+ if (name === "tutorialBottomFinish") return page;
238+ var tick = findChild(page, "tick");
239+ tap(tick);
240+
214241 checkFinished();
215242 return null;
216243 }