on xenial help sign in
Refactor and redesign edge tutorial
commit8cebdc79d0f96d94aa7c67767370cb9c71169f43 authorMichael Terry <michael.terry@canonical.com> dateMon 27 Oct 2014, 20:15 (12 years ago) parent0e59683
13 files changed+759−515
qml/Components/EdgeDemo.qml−238 qml/Components/EdgeDemoOverlay.qml−273 qml/Shell.qml+6−4 qml/Tutorial/Arrow.qml+45 qml/Tutorial/Bar.qml+99 qml/Tutorial/Tutorial.qml+206 qml/Tutorial/TutorialIntro.qml+25 qml/Tutorial/TutorialLeft.qml+43 qml/Tutorial/TutorialLeftFinish.qml+24 qml/Tutorial/TutorialPage.qml+228 qml/Tutorial/TutorialTop.qml+42 qml/Tutorial/TutorialTopFinish.qml+41 qml/Tutorial/graphics/arrow-down.png
qml/Components/EdgeDemo.qmldeleted−238
@@ -1,238 +0,0 @@
1−/*
2− * Copyright (C) 2013 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 AccountsService 0.1
18−import LightDM 0.1 as LightDM
19−import QtQuick 2.0
20−
21−Item {
22− id: demo
23−
24− property Item greeter
25− property Item launcher
26− property Item indicators
27− property Item stages
28−
29− property bool launcherEnabled: true
30− property bool stagesEnabled: true
31− property bool panelEnabled: true
32− property bool panelContentEnabled: true
33− property bool running: !launcherEnabled || !stagesEnabled || !panelEnabled || !panelContentEnabled
34−
35− property bool paused: false
36−
37− onPausedChanged: {
38− if (d.rightEdgeDemo) d.rightEdgeDemo.paused = paused
39− if (d.topEdgeDemo) d.topEdgeDemo.paused = paused
40− if (d.bottomEdgeDemo) d.bottomEdgeDemo.paused = paused
41− if (d.leftEdgeDemo) d.leftEdgeDemo.paused = paused
42− if (d.finalEdgeDemo) d.finalEdgeDemo.paused = paused
43− }
44−
45− function hideEdgeDemoInShell() {
46− AccountsService.demoEdges = false;
47− stopDemo();
48− }
49−
50− function hideEdgeDemoInGreeter() {
51− // TODO: AccountsService.demoEdges = false as lightdm user
52− }
53−
54− function hideEdgeDemos() {
55− hideEdgeDemoInGreeter();
56− hideEdgeDemoInShell();
57− }
58−
59− function stopDemo() {
60− launcherEnabled = true
61− stagesEnabled = true
62− panelEnabled = true
63− panelContentEnabled = true
64− if (d.rightEdgeDemo) d.rightEdgeDemo.destroy()
65− if (d.topEdgeDemo) d.topEdgeDemo.destroy()
66− if (d.bottomEdgeDemo) d.bottomEdgeDemo.destroy()
67− if (d.leftEdgeDemo) d.leftEdgeDemo.destroy()
68− if (d.finalEdgeDemo) d.finalEdgeDemo.destroy()
69− }
70−
71− function startDemo() {
72− if (!d.overlay) {
73− d.overlay = Qt.createComponent("EdgeDemoOverlay.qml")
74− }
75−
76− launcherEnabled = false;
77− stagesEnabled = false;
78− panelEnabled = false;
79− panelContentEnabled = false;
80−
81− // Begin with either greeter or top, depending on which is visible
82− if (greeter && greeter.shown) {
83− startRightEdgeDemo()
84− } else {
85− startTopEdgeDemo()
86− }
87− }
88−
89− QtObject {
90− id: d
91− property Component overlay
92− property QtObject rightEdgeDemo
93− property QtObject topEdgeDemo
94− property QtObject bottomEdgeDemo
95− property QtObject leftEdgeDemo
96− property QtObject finalEdgeDemo
97− property bool showEdgeDemo: AccountsService.demoEdges
98− property bool showEdgeDemoInGreeter: AccountsService.demoEdges // TODO: AccountsService.demoEdges as lightdm user
99−
100− onShowEdgeDemoChanged: {
101− stopDemo()
102− if (d.showEdgeDemo) {
103− startDemo()
104− }
105− }
106− }
107−
108− function startRightEdgeDemo() {
109− if (demo.greeter) {
110− d.rightEdgeDemo = d.overlay.createObject(demo.greeter, {
111− "edge": "right",
112− "title": i18n.tr("Right edge"),
113− "text": i18n.tr("Try swiping from the right edge to unlock the phone"),
114− "anchors.fill": demo.greeter,
115− });
116− }
117− if (d.rightEdgeDemo) {
118− d.rightEdgeDemo.onSkip.connect(demo.hideEdgeDemos)
119− } else {
120− stopDemo();
121− }
122− }
123−
124− Connections {
125− target: demo.greeter
126−
127− function hide() {
128− if (d.rightEdgeDemo && d.rightEdgeDemo.available) {
129− d.rightEdgeDemo.hide()
130− hideEdgeDemoInGreeter()
131− startTopEdgeDemo()
132− }
133− }
134−
135− onUnlocked: hide()
136− onShownChanged: if (!greeter.shown) hide()
137− }
138−
139− function startTopEdgeDemo() {
140− demo.panelEnabled = true;
141− if (demo.stages) {
142− d.topEdgeDemo = d.overlay.createObject(demo.stages, {
143− "edge": "top",
144− "title": i18n.tr("Top edge"),
145− "text": i18n.tr("Try swiping from the top edge to access the indicators"),
146− "anchors.fill": demo.stages,
147− });
148− }
149− if (d.topEdgeDemo) {
150− d.topEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
151− } else {
152− stopDemo();
153− }
154− }
155−
156− Connections {
157− target: demo.indicators
158− onFullyOpenedChanged: {
159− if (d.topEdgeDemo && d.topEdgeDemo.available && demo.indicators.fullyOpened) {
160− d.topEdgeDemo.hideNow()
161− startBottomEdgeDemo()
162− }
163− }
164− }
165−
166− function startBottomEdgeDemo() {
167− if (demo.indicators) {
168− d.bottomEdgeDemo = d.overlay.createObject(demo.indicators, {
169− "edge": "bottom",
170− "title": i18n.tr("Close"),
171− "text": i18n.tr("Swipe up again to close the settings screen"),
172− "anchors.fill": demo.indicators.content,
173− });
174− }
175− if (d.bottomEdgeDemo) {
176− d.bottomEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
177− } else {
178− stopDemo();
179− }
180− }
181−
182− Connections {
183− target: demo.indicators
184− onPartiallyOpenedChanged: {
185− if (d.bottomEdgeDemo && d.bottomEdgeDemo.available && !demo.indicators.partiallyOpened && !demo.indicators.fullyOpened) {
186− d.bottomEdgeDemo.hideNow()
187− startLeftEdgeDemo()
188− }
189− }
190− }
191−
192− function startLeftEdgeDemo() {
193− demo.panelEnabled = false;
194− demo.launcherEnabled = true;
195− if (demo.stages) {
196− d.leftEdgeDemo = d.overlay.createObject(demo.stages, {
197− "edge": "left",
198− "title": i18n.tr("Left edge"),
199− "text": i18n.tr("Swipe from the left to reveal the launcher for quick access to apps"),
200− "anchors.fill": demo.stages,
201− });
202− }
203− if (d.leftEdgeDemo) {
204− d.leftEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
205− } else {
206− stopDemo();
207− }
208− }
209−
210− Connections {
211− target: demo.launcher
212− onStateChanged: {
213− if (d.leftEdgeDemo && d.leftEdgeDemo.available && launcher.state == "visible") {
214− d.leftEdgeDemo.hide()
215− launcher.hide()
216− startFinalEdgeDemo()
217− }
218− }
219− }
220−
221− function startFinalEdgeDemo() {
222− demo.launcherEnabled = false;
223− if (demo.stages) {
224− d.finalEdgeDemo = d.overlay.createObject(demo.stages, {
225− "edge": "none",
226− "title": i18n.tr("Well done"),
227− "text": i18n.tr("You have now mastered the edge gestures and can start using the phone<br><br>Tap on the screen to start"),
228− "anchors.fill": demo.stages,
229− "showSkip": false,
230− });
231− }
232− if (d.finalEdgeDemo) {
233− d.finalEdgeDemo.onSkip.connect(demo.hideEdgeDemoInShell)
234− } else {
235− stopDemo();
236− }
237− }
238−}
qml/Components/EdgeDemoOverlay.qmldeleted−273
@@ -1,273 +0,0 @@
1−/*
2− * Copyright (C) 2013 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 Powerd 0.1
18−import QtQuick 2.0
19−import QtGraphicalEffects 1.0
20−import Unity.Application 0.1
21−import Ubuntu.Components 0.1
22−
23−Showable {
24− id: overlay
25−
26− /*
27− * Valid values are "left", "right", "top", "bottom", or "none".
28− */
29− property string edge: "top"
30−
31− /*
32− * This is the header displayed, like "Right edge".
33− */
34− property alias title: titleLabel.text
35−
36− /*
37− * This is the block of text displayed below the header.
38− */
39− property alias text: textLabel.text
40−
41− /*
42− * This is the text for the skip button.
43− */
44− property alias skipText: skipLabel.text
45−
46− /*
47− * This is the visible status of the skip button.
48− */
49− property alias showSkip: skipLabel.visible
50−
51− /*
52− * Whether this demo is running currently.
53− */
54− readonly property bool active: available && visible
55−
56− /*
57− * Whether animations are paused.
58− */
59− property alias paused: wholeAnimation.paused
60−
61− /*
62− * Whether animations are running.
63− */
64− readonly property alias running: wholeAnimation.running
65−
66− signal skip()
67−
68− function doSkip() {
69− d.skipOnHide = true;
70− hide();
71− }
72−
73− function hideNow() {
74− overlay.visible = false;
75− overlay.available = false;
76− if (d.skipOnHide) {
77− overlay.skip();
78− }
79− }
80−
81− showAnimation: StandardAnimation {
82− property: "opacity"
83− to: 1
84− onRunningChanged: if (running) overlay.visible = true
85− }
86− hideAnimation: StandardAnimation {
87− property: "opacity"
88− to: 0
89− duration: UbuntuAnimation.BriskDuration
90− onRunningChanged: if (!running) overlay.hideNow()
91− }
92−
93− QtObject {
94− id: d
95− property bool skipOnHide: false
96− property int edgeMargin: units.gu(4)
97− }
98−
99− Rectangle {
100− objectName: "backgroundShade"
101−
102− anchors.fill: parent
103− color: "black"
104− opacity: 0.8
105− visible: overlay.active
106−
107− MouseArea {
108− objectName: "backgroundShadeMouseArea"
109−
110− anchors.fill: parent
111− enabled: overlay.edge == "none" && overlay.opacity == 1.0
112− onClicked: overlay.doSkip()
113− }
114− }
115−
116− Item {
117− id: hintGroup
118− x: 0
119− y: 0
120− width: parent.width
121− height: parent.height
122− visible: overlay.active
123−
124− Column {
125− id: labelGroup
126− spacing: units.gu(3)
127−
128− anchors {
129− margins: d.edgeMargin
130− left: parent.left
131− top: overlay.edge == "bottom" ? undefined : parent.top
132− bottom: overlay.edge == "bottom" ? parent.bottom : undefined
133− }
134−
135− Label {
136− id: titleLabel
137− fontSize: "x-large"
138− width: units.gu(25)
139− wrapMode: Text.WordWrap
140− }
141−
142− Label {
143− id: textLabel
144− width: units.gu(25)
145− wrapMode: Text.WordWrap
146− }
147−
148− Label {
149− id: skipLabel
150− objectName: "skipLabel"
151− text: i18n.tr("Skip intro")
152− color: UbuntuColors.orange
153− fontSize: "small"
154−
155− Icon {
156− anchors.left: parent.right
157− anchors.verticalCenter: parent.verticalCenter
158− height: units.dp(12)
159− width: units.dp(12)
160− name: "chevron"
161− color: UbuntuColors.orange
162− }
163−
164− MouseArea {
165− // Make clickable area bigger than just the link because
166− // otherwise, the edge demo will feel hard to dismiss.
167− anchors.fill: parent
168− anchors.margins: -units.gu(5)
169− onClicked: overlay.doSkip()
170− }
171− }
172− }
173−
174− LinearGradient {
175− id: edgeHint
176− property int size: 1
177− cached: false
178− visible: overlay.edge != "none"
179− gradient: Gradient {
180− GradientStop {
181− position: 0.0
182− color: Qt.hsla(16.0/360.0, 0.83, 0.47, 0.4) // UbuntuColors.orange, but transparent
183− }
184− GradientStop {
185− position: 1.0
186− color: "transparent"
187− }
188− }
189− anchors.fill: parent
190− start: {
191− if (overlay.edge == "right") {
192− return Qt.point(width, 0);
193− } else if (overlay.edge == "left") {
194− return Qt.point(0, 0);
195− } else if (overlay.edge == "top") {
196− return Qt.point(0, 0);
197− } else {
198− return Qt.point(0, height);
199− }
200− }
201− end: {
202− if (overlay.edge == "right") {
203− return Qt.point(width - size, 0);
204− } else if (overlay.edge == "left") {
205− return Qt.point(size, 0);
206− } else if (overlay.edge == "top") {
207− return Qt.point(0, size);
208− } else {
209− return Qt.point(0, height - size);
210− }
211− }
212− }
213− }
214−
215− SequentialAnimation {
216− id: wholeAnimation
217− objectName: "wholeAnimation"
218− running: overlay.active
219−
220− ParallelAnimation {
221− id: fadeInAnimation
222−
223− StandardAnimation {
224− target: labelGroup
225− property: {
226− if (overlay.edge == "right" || overlay.edge == "left") {
227− return "anchors.leftMargin";
228− } else if (overlay.edge == "bottom") {
229− return "anchors.bottomMargin";
230− } else {
231− return "anchors.topMargin";
232− }
233− }
234− from: {
235− if (overlay.edge == "right") {
236− return d.edgeMargin + units.gu(3)
237− } else {
238− return d.edgeMargin - units.gu(3)
239− }
240− }
241− to: d.edgeMargin
242− duration: overlay.edge == "none" ? 0 : UbuntuAnimation.SleepyDuration
243− }
244− StandardAnimation {
245− target: overlay
246− property: "opacity"
247− from: 0.0
248− to: 1.0
249− duration: UbuntuAnimation.SleepyDuration
250− }
251− }
252−
253− SequentialAnimation {
254− id: hintAnimation
255− loops: Animation.Infinite
256− property string prop: (overlay.edge == "left" || overlay.edge == "right") ? "x" : "y"
257− property double endVal: units.dp(5) * ((overlay.edge == "left" || overlay.edge == "top") ? 1 : -1)
258− property double maxGlow: units.dp(20)
259− property int duration: overlay.edge == "none" ? 0 : UbuntuAnimation.SleepyDuration
260−
261− ParallelAnimation {
262− StandardAnimation { target: hintGroup; property: hintAnimation.prop; from: 0; to: hintAnimation.endVal; duration: hintAnimation.duration }
263− StandardAnimation { target: edgeHint; property: "size"; from: 1; to: hintAnimation.maxGlow; duration: hintAnimation.duration }
264− }
265−
266− // Undo the above
267− ParallelAnimation {
268− StandardAnimation { target: hintGroup; property: hintAnimation.prop; from: hintAnimation.endVal; to: 0; duration: hintAnimation.duration }
269− StandardAnimation { target: edgeHint; property: "size"; from: hintAnimation.maxGlow; to: 1; duration: hintAnimation.duration }
270− }
271− }
272− }
273−}
qml/Shell.qml+6−4
@@ -36,6 +36,7 @@ import "Panel"
3636import "Components"
3737import "Notifications"
3838import "Stages"
39+import "Tutorial"
3940import Unity.Notifications 1.0 as NotificationBackend
4041import Unity.Session 0.1
4142import Unity.DashCommunicator 0.1
@@ -756,15 +757,16 @@ Item {
756757 scale: Math.min(parent.width, parent.height) / width
757758 }
758759
759− EdgeDemo {
760+ Tutorial {
760761 id: edgeDemo
761762 objectName: "edgeDemo"
762− z: alphaDisclaimerLabel.z + 10
763− paused: Powerd.status === Powerd.Off // Saves power
764− greeter: greeter
763+ visible: AccountsService.demoEdges
764+ paused: Powerd.status === Powerd.Off || LightDM.Greeter.active
765765 launcher: launcher
766766 indicators: panel.indicators
767767 stages: stages
768+
769+ onFinished: AccountsService.demoEdges = false
768770 }
769771
770772 Connections {
qml/Tutorial/Arrow.qmlnew file+45
@@ -0,0 +1,45 @@
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+
20+Image {
21+ // Valid values are: down, up, right, left
22+ property string direction
23+
24+ readonly property real offset: units.gu(6)
25+
26+ ////
27+
28+ visible: direction !== ""
29+ source: Qt.resolvedUrl("graphics/arrow-down.png")
30+
31+ rotation: {
32+ if (direction === "up") {
33+ return 180;
34+ } else if (direction === "left") {
35+ return 90;
36+ } else if (direction === "right") {
37+ return -90;
38+ } else {
39+ return 0;
40+ }
41+ }
42+
43+ height: units.gu(9)
44+ sourceSize.height: height
45+}
qml/Tutorial/Bar.qmlnew file+99
@@ -0,0 +1,99 @@
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 QtGraphicalEffects 1.0
18+import QtQuick 2.3
19+import Ubuntu.Components 1.1
20+import "../Components"
21+
22+Item {
23+ id: root
24+
25+ // Valid values are: down, up, right, left
26+ property string direction
27+
28+ property bool animating: true
29+
30+ readonly property real offset: edgeHint.size / 4
31+
32+ ////
33+
34+ visible: direction !== ""
35+ implicitHeight: direction === "down" || direction === "up" ? hintAnimation.maxGlow : 0
36+ implicitWidth: direction === "left" || direction === "right" ? hintAnimation.maxGlow : 0
37+
38+ LinearGradient {
39+ id: edgeHint
40+ property int size: 1
41+ cached: false
42+ gradient: Gradient {
43+ GradientStop {
44+ position: 0.0
45+ color: Qt.hsla(16.0/360.0, 0.83, 0.47, 0.4) // UbuntuColors.orange, but transparent
46+ }
47+ GradientStop {
48+ position: 1.0
49+ color: "transparent"
50+ }
51+ }
52+ anchors.fill: parent
53+ start: {
54+ if (root.direction == "left") {
55+ return Qt.point(width, 0);
56+ } else if (root.direction == "right") {
57+ return Qt.point(0, 0);
58+ } else if (root.direction == "down") {
59+ return Qt.point(0, 0);
60+ } else {
61+ return Qt.point(0, height);
62+ }
63+ }
64+ end: {
65+ if (root.direction == "left") {
66+ return Qt.point(width - size, 0);
67+ } else if (root.direction == "right") {
68+ return Qt.point(size, 0);
69+ } else if (root.direction == "down") {
70+ return Qt.point(0, size);
71+ } else {
72+ return Qt.point(0, height - size);
73+ }
74+ }
75+ }
76+
77+ SequentialAnimation {
78+ id: hintAnimation
79+ loops: Animation.Infinite
80+ running: root.animating && root.visible
81+ property double maxGlow: units.dp(20)
82+ property int duration: UbuntuAnimation.SleepyDuration
83+
84+ StandardAnimation {
85+ target: edgeHint
86+ property: "size"
87+ to: hintAnimation.maxGlow
88+ duration: hintAnimation.duration
89+ }
90+
91+ // Undo the above
92+ StandardAnimation {
93+ target: edgeHint
94+ property: "size"
95+ to: 1
96+ duration: hintAnimation.duration
97+ }
98+ }
99+}
qml/Tutorial/Tutorial.qmlnew file+206
@@ -0,0 +1,206 @@
1+/*
2+ * Copyright (C) 2013,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+
20+Item {
21+ id: root
22+
23+ property Item launcher
24+ property Item indicators
25+ property Item stages
26+
27+ readonly property bool launcherEnabled: loader.sourceComponent === leftComponent ||
28+ loader.sourceComponent === leftFinishComponent
29+ readonly property bool stagesEnabled: !running
30+ readonly property bool panelEnabled: loader.sourceComponent === topComponent ||
31+ loader.sourceComponent === topFinishComponent
32+ readonly property bool panelContentEnabled: !running
33+ readonly property bool running: loader.sourceComponent !== null
34+
35+ property bool paused: false
36+
37+ signal finished()
38+
39+ ////
40+
41+ visible: false
42+ onVisibleChanged: {
43+ d.stop();
44+ if (visible) {
45+ d.start();
46+ }
47+ }
48+
49+ QtObject {
50+ id: d
51+ property int pageTotal: 2
52+
53+ function stop() {
54+ loader.sourceComponent = null;
55+ }
56+
57+ function start() {
58+ loader.load(introComponent);
59+ }
60+ }
61+
62+ Connections {
63+ target: root.indicators
64+
65+ onFullyOpenedChanged: {
66+ if (loader.sourceComponent === topComponent &&
67+ root.indicators.fullyOpened) {
68+ loader.load(topFinishComponent);
69+ }
70+ }
71+
72+ onPartiallyOpenedChanged: {
73+ if (loader.sourceComponent === topFinishComponent &&
74+ !root.indicators.partiallyOpened &&
75+ !root.indicators.fullyOpened) {
76+ loader.load(leftComponent);
77+ }
78+ }
79+ }
80+
81+ Connections {
82+ target: root.launcher
83+
84+ onProgressChanged: {
85+ if (loader.sourceComponent === leftComponent &&
86+ launcher.progress > 0) {
87+ loader.load(leftFinishComponent);
88+ }
89+ }
90+
91+ onShownChanged: {
92+ // This stanza is necessary because user might have dragged launcher
93+ // far enough to trigger the progress check above, but then dragged
94+ // it back into its original position.
95+ if (loader.sourceComponent === leftFinishComponent &&
96+ !launcher.shown) {
97+ loader.load(null);
98+ }
99+ }
100+
101+ onStateChanged: {
102+ if ((loader.sourceComponent === leftComponent || // happens if user didn't drag past launcher
103+ loader.sourceComponent === leftFinishComponent) &&
104+ launcher.state === "visible") {
105+ loader.load(null);
106+ launcher.hide();
107+ }
108+ }
109+ }
110+
111+ Loader {
112+ id: loader
113+
114+ property Component next: null
115+
116+ function load(comp) {
117+ if (loader.item) {
118+ next = comp;
119+ loader.item.hide();
120+ } else {
121+ loader.sourceComponent = comp;
122+ }
123+ }
124+
125+ Connections {
126+ target: loader.item
127+ onFinished: {
128+ loader.sourceComponent = loader.next;
129+ if (loader.next != null) {
130+ loader.next = null;
131+ } else {
132+ root.finished();
133+ }
134+ }
135+ }
136+
137+ Binding {
138+ target: loader.item
139+ property: "paused"
140+ value: root.paused
141+ }
142+
143+ Binding {
144+ target: loader.item
145+ property: "pageTotal"
146+ value: d.pageTotal
147+ }
148+ }
149+
150+ Component {
151+ id: introComponent
152+ TutorialIntro {
153+ parent: root.stages
154+ anchors.fill: parent
155+ backgroundFadesOut: false
156+
157+ Timer {
158+ interval: 3500
159+ running: !root.paused
160+ onTriggered: loader.load(topComponent)
161+ }
162+ }
163+ }
164+
165+ Component {
166+ id: topComponent
167+ TutorialTop {
168+ parent: root.stages
169+ anchors.fill: parent
170+ anchors.topMargin: root.indicators.panelHeight
171+ pageNumber: 1
172+ backgroundFadesIn: false
173+ }
174+ }
175+
176+ Component {
177+ id: topFinishComponent
178+ TutorialTopFinish {
179+ parent: root.indicators
180+ anchors.bottom: parent ? parent.content.bottom : undefined
181+ anchors.left: parent ? parent.content.left : undefined
182+ anchors.right: parent ? parent.content.right : undefined
183+ height: root.stages.height
184+ }
185+ }
186+
187+ Component {
188+ id: leftComponent
189+ TutorialLeft {
190+ parent: root.stages
191+ anchors.fill: parent
192+ pageNumber: 2
193+ backgroundFadesOut: false
194+ }
195+ }
196+
197+ Component {
198+ id: leftFinishComponent
199+ TutorialLeftFinish {
200+ parent: root.stages
201+ anchors.fill: parent
202+ textXOffset: root.launcher.panelWidth
203+ backgroundFadesIn: false
204+ }
205+ }
206+}
qml/Tutorial/TutorialIntro.qmlnew file+25
@@ -0,0 +1,25 @@
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+
20+TutorialPage {
21+ id: root
22+
23+ title: i18n.tr("Quick tips")
24+ text: i18n.tr("The following tips are designed to help you learn how to use your phone…")
25+}
qml/Tutorial/TutorialLeft.qmlnew file+43
@@ -0,0 +1,43 @@
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+
20+TutorialPage {
21+ id: root
22+
23+ title: i18n.tr("Left edge")
24+ text: i18n.tr("Swipe from the <b>left edge</b> to see your <b>favorite apps</b> in the <b>Launcher</b>.")
25+
26+ bar {
27+ direction: "right"
28+ }
29+
30+ foreground {
31+ children: [
32+ Arrow {
33+ direction: "right"
34+ anchors {
35+ left: parent.left
36+ leftMargin: offset + bar.offset
37+ top: parent.top
38+ topMargin: offset
39+ }
40+ }
41+ ]
42+ }
43+}
qml/Tutorial/TutorialLeftFinish.qmlnew file+24
@@ -0,0 +1,24 @@
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+
20+TutorialPage {
21+ id: root
22+
23+ text: i18n.tr("<b>Release</b> to hide the <b>Launcher</b> again.")
24+}
qml/Tutorial/TutorialPage.qmlnew file+228
@@ -0,0 +1,228 @@
1+/*
2+ * Copyright (C) 2013,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 "../Components"
20+
21+Showable {
22+ id: overlay
23+
24+ // Valid values are "left", "right", "top", "bottom", or "none"
25+ property string edge: "none"
26+
27+ // This is the header displayed, like "Right edge"
28+ property alias title: titleLabel.text
29+
30+ // This is the block of text displayed below the header
31+ property alias text: textLabel.text
32+
33+ // This is the text for the skip button
34+ property string skipText: i18n.tr("Skip tutorial")
35+
36+ // Whether this demo is running currently
37+ readonly property bool active: available && visible
38+
39+ // Whether animations are paused
40+ property bool paused
41+
42+ // Which page number this overlay represents, 1-indexed
43+ property int pageNumber
44+
45+ // How many pages there are total
46+ property int pageTotal
47+
48+ // Whether whole page (background + foreground) or just the foreground fades in
49+ property bool backgroundFadesIn: true
50+
51+ // Whether whole page (background + foreground) or just the foreground fades out
52+ property bool backgroundFadesOut: true
53+
54+ // An integrated glowing Bar class
55+ property alias bar: bar
56+
57+ // The foreground Item, add children to it that you want to fade in
58+ property alias foreground: foregroundExtra
59+
60+ // X/Y offsets for text
61+ property real textXOffset: 0
62+ property real textYOffset: 0
63+
64+ signal finished()
65+
66+ ////
67+
68+ shown: false
69+ Component.onCompleted: show()
70+
71+ property alias _foregroundOpacity: foreground.opacity
72+
73+ showAnimation: StandardAnimation {
74+ property: root.backgroundFadesIn ? "opacity" : "_foregroundOpacity"
75+ from: 0
76+ to: 1
77+ duration: root.backgroundFadesIn ? UbuntuAnimation.SleepyDuration : UbuntuAnimation.BriskDuration
78+ }
79+
80+ hideAnimation: StandardAnimation {
81+ property: root.backgroundFadesOut ? "opacity" : "_foregroundOpacity"
82+ to: 0
83+ duration: UbuntuAnimation.BriskDuration
84+ onRunningChanged: {
85+ if (!running) {
86+ overlay.finished();
87+ }
88+ }
89+ }
90+
91+ QtObject {
92+ id: d
93+
94+ property real sideMargin: units.gu(6)
95+ property real verticalOffset: -units.gu(3)
96+ property real buttonMargin: units.gu(2)
97+ property real paginationOffset: units.gu(12)
98+
99+ property real fadeInOffset: {
100+ if (showAnimation.running) {
101+ var opacity = root[root.showAnimation.property]
102+ return (1 - opacity) * units.gu(3);
103+ } else {
104+ return 0;
105+ }
106+ }
107+
108+ property real xLabelOffset: {
109+ if (bar.direction === "right") {
110+ return bar.offset - fadeInOffset + root.textXOffset;
111+ } else if (bar.direction === "left") {
112+ return -bar.offset + fadeInOffset + root.textXOffset;
113+ } else {
114+ return root.textXOffset;
115+ }
116+ }
117+ property real yLabelOffset: {
118+ if (bar.direction === "down") {
119+ return bar.offset - fadeInOffset + root.textYOffset;
120+ } else if (bar.direction === "up") {
121+ return -bar.offset + fadeInOffset + root.textYOffset;
122+ } else {
123+ return root.textYOffset;
124+ }
125+ }
126+ }
127+
128+ MouseArea { // eat any errant presses
129+ anchors.fill: parent
130+ }
131+
132+ Rectangle {
133+ anchors.fill: parent
134+ color: "black"
135+ opacity: 0.8
136+ }
137+
138+ Item {
139+ id: foreground
140+ anchors.fill: parent
141+
142+ Label {
143+ id: titleLabel
144+ anchors {
145+ bottom: textLabel.top
146+ bottomMargin: units.gu(2)
147+ horizontalCenter: parent.horizontalCenter
148+ horizontalCenterOffset: d.xLabelOffset - root.textXOffset / 2
149+ }
150+ width: parent.width - d.sideMargin * 2 - root.textXOffset
151+ horizontalAlignment: Text.AlignHCenter
152+ wrapMode: Text.Wrap
153+ font.pixelSize: units.gu(4)
154+ text: root.title
155+ }
156+
157+ Label {
158+ id: textLabel
159+ anchors {
160+ top: parent.verticalCenter
161+ topMargin: d.verticalOffset + d.yLabelOffset
162+ horizontalCenter: parent.horizontalCenter
163+ horizontalCenterOffset: d.xLabelOffset - root.textXOffset / 2
164+ }
165+ width: parent.width - d.sideMargin * 2 - root.textXOffset
166+ horizontalAlignment: Text.AlignHCenter
167+ wrapMode: Text.Wrap
168+ text: root.text
169+ }
170+
171+ Row {
172+ visible: overlay.pageNumber > 0
173+ spacing: units.gu(0.5)
174+ anchors {
175+ bottom: parent.bottom
176+ bottomMargin: d.paginationOffset
177+ horizontalCenter: parent.horizontalCenter
178+ }
179+ Repeater {
180+ model: overlay.pageTotal
181+ Image {
182+ height: units.gu(1)
183+ width: height
184+ source: (index === overlay.pageNumber - 1) ?
185+ "../Dash/graphics/pagination_dot_on.png" :
186+ "../Dash/graphics/pagination_dot_off.png"
187+ }
188+ }
189+ }
190+
191+ MouseArea {
192+ visible: overlay.pageNumber > 0
193+ enabled: visible
194+ anchors {
195+ bottom: parent.bottom
196+ right: parent.right
197+ }
198+ implicitHeight: skipLabel.height + d.buttonMargin * 2
199+ implicitWidth: skipLabel.width + d.buttonMargin * 2
200+
201+ Label {
202+ id: skipLabel
203+ anchors.centerIn: parent
204+ // Translators: This is the arrow for "Skip tutorial" buttons
205+ text: i18n.tr("%1 〉").arg(overlay.skipText)
206+ }
207+
208+ onClicked: overlay.hide()
209+ }
210+
211+ Bar {
212+ id: bar
213+ animating: !root.paused
214+ anchors {
215+ top: direction === "up" ? undefined : parent.top
216+ bottom: direction === "down" ? undefined : parent.bottom
217+ left: direction === "left" ? undefined : parent.left
218+ right: direction === "right" ? undefined : parent.right
219+ }
220+ }
221+
222+ // A place for subclasses to add extra widgets
223+ Item {
224+ id: foregroundExtra
225+ anchors.fill: parent
226+ }
227+ }
228+}
qml/Tutorial/TutorialTop.qmlnew file+42
@@ -0,0 +1,42 @@
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+
20+TutorialPage {
21+ id: root
22+
23+ title: i18n.tr("Top edge")
24+ text: i18n.tr("<b>Swipe down</b> from the <b>top edge</b> to see <b>settings and notifications</b>.")
25+
26+ bar {
27+ direction: "down"
28+ }
29+
30+ foreground {
31+ children: [
32+ Arrow {
33+ direction: "down"
34+ anchors {
35+ top: parent.top
36+ topMargin: offset + bar.offset
37+ horizontalCenter: parent.horizontalCenter
38+ }
39+ }
40+ ]
41+ }
42+}
qml/Tutorial/TutorialTopFinish.qmlnew file+41
@@ -0,0 +1,41 @@
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+
20+TutorialPage {
21+ id: root
22+
23+ text: i18n.tr("<b>Swipe up</b> again to close the <b>Settings</b> menu.")
24+
25+ bar {
26+ direction: "up"
27+ }
28+
29+ foreground {
30+ children: [
31+ Arrow {
32+ direction: "up"
33+ anchors {
34+ bottom: parent.bottom
35+ bottomMargin: offset + bar.offset
36+ horizontalCenter: parent.horizontalCenter
37+ }
38+ }
39+ ]
40+ }
41+}
qml/Tutorial/graphics/arrow-down.pngnew file

Binary file not shown.