@@ -30,13 +30,13 @@ Item {
3030 property bool keyboardVisible
3131 property var lastInputTimestamp
3232
33− readonly property bool launcherEnabled: !running || tutorialLeft.shown
34− readonly property bool spreadEnabled: !running || tutorialRight.shown
35− readonly property bool panelEnabled: !running || tutorialTop.shown
36− readonly property bool running: tutorialLeft.shown
37− || tutorialTop.shown
38− || tutorialRight.shown
39− || tutorialBottom.shown
33+ readonly property bool launcherEnabled: !running || tutorialLeftLoader.shown
34+ readonly property bool spreadEnabled: !running || tutorialRightLoader.shown
35+ readonly property bool panelEnabled: !running || tutorialTopLoader.shown
36+ readonly property bool running: tutorialLeftLoader.shown
37+ || tutorialTopLoader.shown
38+ || tutorialRightLoader.shown
39+ || tutorialBottomLoader.shown
4040
4141 signal finished()
4242
@@ -59,123 +59,186 @@ Item {
5959 ? ApplicationManager.findApplication(ApplicationManager.focusedApplicationId)
6060 : null
6161
62− property bool endPointsFinished: tutorialRight.skipped && tutorialBottom.skipped
62+ function haveShown(tutorialId) {
63+ return AccountsService.demoEdgesCompleted.indexOf(tutorialId) != -1;
64+ }
65+
66+ property bool endPointsFinished: tutorialRightLoader.skipped &&
67+ tutorialBottomLoader.skipped
6368 onEndPointsFinishedChanged: if (endPointsFinished) root.finish()
6469 }
6570
66− TutorialLeft {
67− id: tutorialLeft
68− objectName: "tutorialLeft"
71+ Loader {
72+ id: tutorialLeftLoader
73+ objectName: "tutorialLeftLoader"
6974 anchors.fill: parent
70− launcher: root.launcher
71− hides: [launcher, panel.indicators]
72− paused: root.paused
73−
74− readonly property bool skipped: !d.mobileScenario ||
75− AccountsService.demoEdgesCompleted.indexOf("left") != -1
76− isReady: !skipped && !paused && !keyboardVisible
77−
78− // Use an idle timer here, because when constructed, all our isReady variables will be false.
79− // Qml needs a moment to copy their values from Tutorial.qml. So we idle it and recheck.
80− Timer {
81− id: tutorialLeftTimer
82− interval: 0
83− onTriggered: if (tutorialLeft.isReady && !tutorialLeft.shown) tutorialLeft.show()
84− }
8575
86− onSkippedChanged: if (skipped && shown) hide()
87− onIsReadyChanged: if (isReady && !shown) tutorialLeftTimer.start()
88− onFinished: AccountsService.markDemoEdgeCompleted("left")
76+ readonly property bool skipped: !d.mobileScenario || d.haveShown("left")
77+ readonly property bool shown: item && item.shown
78+ active: !skipped || (item && item.visible)
79+ onSkippedChanged: if (skipped && shown) item.hide()
80+
81+ sourceComponent: TutorialLeft {
82+ id: tutorialLeft
83+ objectName: "tutorialLeft"
84+ anchors.fill: parent
85+ launcher: root.launcher
86+ hides: [launcher, panel.indicators]
87+ paused: root.paused
88+
89+ isReady: !tutorialLeftLoader.skipped && !paused && !keyboardVisible
90+
91+ // Use an idle timer here, because when constructed, all our isReady variables will be false.
92+ // Qml needs a moment to copy their values from Tutorial.qml. So we idle it and recheck.
93+ Timer {
94+ id: tutorialLeftTimer
95+ interval: 0
96+ onTriggered: if (tutorialLeft.isReady && !tutorialLeft.shown) tutorialLeft.show()
97+ }
98+
99+ onIsReadyChanged: if (isReady && !shown) tutorialLeftTimer.start()
100+ onFinished: AccountsService.markDemoEdgeCompleted("left")
101+ }
89102 }
90103
91− TutorialTop {
92− id: tutorialTop
93− objectName: "tutorialTop"
104+ Loader {
105+ id: tutorialTopLoader
106+ objectName: "tutorialTopLoader"
94107 anchors.fill: parent
95− panel: root.panel
96− hides: [launcher, panel.indicators]
97− paused: root.paused
98108
99− readonly property bool skipped: !d.mobileScenario ||
100− AccountsService.demoEdgesCompleted.indexOf("top") != -1
101− isReady: tutorialLeft.skipped && !skipped && !paused && !keyboardVisible &&
102− !tutorialBottom.shown && !tutorialBottom.mightShow
103−
104− // We fire 30s after left edge tutorial, with at least 3s of inactivity
109+ readonly property bool skipped: !d.mobileScenario || d.haveShown("top")
110+ readonly property bool shown: item && item.shown
111+ active: !skipped || (item && item.visible)
112+ onSkippedChanged: if (skipped && shown) item.hide()
113+
114+ sourceComponent: TutorialTop {
115+ id: tutorialTop
116+ objectName: "tutorialTop"
117+ anchors.fill: parent
118+ panel: root.panel
119+ hides: [launcher, panel.indicators]
120+ paused: root.paused
121+
122+ isReady: tutorialLeftLoader.skipped && !tutorialTopLoader.skipped &&
123+ !paused && !keyboardVisible &&
124+ !tutorialBottomLoader.shown && !tutorialBottomLoader.mightShow
125+
126+ // We fire 30s after left edge tutorial, with at least 3s of inactivity
127+
128+ InactivityTimer {
129+ id: tutorialTopInactivityTimer
130+ lastInputTimestamp: root.lastInputTimestamp
131+ page: parent
132+ }
105133
106− InactivityTimer {
107− id: tutorialTopInactivityTimer
108− lastInputTimestamp: root.lastInputTimestamp
109− page: parent
110− }
134+ Timer {
135+ id: tutorialTopTimer
136+ objectName: "tutorialTopTimer"
137+ interval: 27000
138+ onTriggered: tutorialTopInactivityTimer.start()
139+ }
111140
112− Timer {
113− id: tutorialTopTimer
114− objectName: "tutorialTopTimer"
115− interval: 27000
116− onTriggered: tutorialTopInactivityTimer.start()
141+ onIsReadyChanged: if (isReady && !shown) tutorialTopTimer.start()
142+ onFinished: AccountsService.markDemoEdgeCompleted("top")
117143 }
118−
119− onSkippedChanged: if (skipped && shown) hide()
120− onIsReadyChanged: if (isReady && !shown) tutorialTopTimer.start()
121− onFinished: AccountsService.markDemoEdgeCompleted("top")
122144 }
123145
124− TutorialRight {
125− id: tutorialRight
126− objectName: "tutorialRight"
146+ Loader {
147+ id: tutorialRightLoader
148+ objectName: "tutorialRightLoader"
127149 anchors.fill: parent
128− stage: root.stage
129− usageScenario: root.usageScenario
130− hides: [launcher, panel.indicators]
131− paused: root.paused
132−
133− readonly property bool skipped: AccountsService.demoEdgesCompleted.indexOf("right") != -1
134− isReady: tutorialTop.skipped && !skipped && !paused && !keyboardVisible &&
135− !tutorialBottom.shown && !tutorialBottom.mightShow &&
136− ApplicationManager.count >= 3
137−
138− InactivityTimer {
139− id: tutorialRightInactivityTimer
140− objectName: "tutorialRightInactivityTimer"
141− lastInputTimestamp: root.lastInputTimestamp
142− page: parent
143− }
144150
145− Connections {
146− target: d
147− onFocusedAppChanged: {
148− if (tutorialRight.isReady && !tutorialRight.shown && d.focusedApp
149− && d.focusedApp.state === ApplicationInfoInterface.Starting) {
150− tutorialRight.show();
151+ readonly property bool skipped: d.haveShown("right")
152+ readonly property bool shown: item && item.shown
153+ active: !skipped || (item && item.visible)
154+ onSkippedChanged: if (skipped && shown) item.hide()
155+
156+ sourceComponent: TutorialRight {
157+ id: tutorialRight
158+ objectName: "tutorialRight"
159+ anchors.fill: parent
160+ stage: root.stage
161+ usageScenario: root.usageScenario
162+ hides: [launcher, panel.indicators]
163+ paused: root.paused
164+
165+ isReady: tutorialTopLoader.skipped && !tutorialRightLoader.skipped &&
166+ !paused && !keyboardVisible &&
167+ !tutorialBottomLoader.shown && !tutorialBottomLoader.mightShow &&
168+ ApplicationManager.count >= 3
169+
170+ InactivityTimer {
171+ id: tutorialRightInactivityTimer
172+ objectName: "tutorialRightInactivityTimer"
173+ lastInputTimestamp: root.lastInputTimestamp
174+ page: parent
175+ }
176+
177+ Connections {
178+ target: d
179+ onFocusedAppChanged: {
180+ if (tutorialRight.isReady && !tutorialRight.shown && d.focusedApp
181+ && d.focusedApp.state === ApplicationInfoInterface.Starting) {
182+ tutorialRight.show();
183+ }
151184 }
152185 }
153− }
154186
155− onSkippedChanged: if (skipped && shown) hide()
156− onIsReadyChanged: if (isReady && !shown) tutorialRightInactivityTimer.start()
157− onFinished: AccountsService.markDemoEdgeCompleted("right")
187+ onIsReadyChanged: if (isReady && !shown) tutorialRightInactivityTimer.start()
188+ onFinished: AccountsService.markDemoEdgeCompleted("right")
189+ }
158190 }
159191
160− TutorialBottom {
161− id: tutorialBottom
162− objectName: "tutorialBottom"
192+ Loader {
193+ id: tutorialBottomLoader
194+ objectName: "tutorialBottomLoader"
163195 anchors.fill: parent
164− hides: [launcher, panel.indicators]
165− paused: root.paused
166− usageScenario: root.usageScenario
167− stage: root.stage
168− application: d.focusedApp
169−
170− readonly property bool skipped: !d.mobileScenario ||
171− AccountsService.demoEdgesCompleted.indexOf("bottom") != -1
172− readonly property bool mightShow: !skipped && d.focusedApp && canShowForApp(d.focusedApp.appId)
173− isReady: !skipped && !paused && !keyboardVisible &&
174− !tutorialTop.shown && !tutorialRight.shown &&
175− mightShow && d.focusedApp.state === ApplicationInfoInterface.Running
176−
177− onSkippedChanged: if (skipped && shown) hide()
178− onIsReadyChanged: if (isReady && !shown) show()
179− onFinished: AccountsService.markDemoEdgeCompleted("bottom")
196+
197+ // See TutorialBottom.qml for an explanation of why we only support
198+ // certain apps.
199+ readonly property var supportedApps: ["address-book-app",
200+ "com.ubuntu.calculator_calculator",
201+ "com.ubuntu.clock_clock",
202+ "dialer-app",
203+ "messaging-app"]
204+ readonly property bool skipped: {
205+ if (!d.mobileScenario) {
206+ return true;
207+ }
208+ for (var i = 0; i < supportedApps.length; i++) {
209+ if (!d.haveShown("bottom-" + supportedApps[i])) {
210+ return false;
211+ }
212+ }
213+ return true;
214+ }
215+ readonly property bool shown: item && item.shown
216+ readonly property bool haveShownFocusedApp: d.focusedApp &&
217+ d.haveShown("bottom-" + d.focusedApp.appId)
218+ readonly property bool mightShow: !skipped && d.focusedApp &&
219+ supportedApps.indexOf(d.focusedApp.appId) !== -1 &&
220+ !haveShownFocusedApp
221+ active: !skipped || (item && item.visible)
222+ onHaveShownFocusedAppChanged: if (haveShownFocusedApp && shown) hide()
223+ onSkippedChanged: if (skipped && shown) item.hide()
224+
225+ sourceComponent: TutorialBottom {
226+ id: tutorialBottom
227+ objectName: "tutorialBottom"
228+ anchors.fill: parent
229+ hides: [launcher, panel.indicators]
230+ paused: root.paused
231+ usageScenario: root.usageScenario
232+ stage: root.stage
233+ application: d.focusedApp
234+
235+ isReady: !tutorialBottomLoader.skipped && !paused && !keyboardVisible &&
236+ !tutorialTopLoader.shown && !tutorialRightLoader.shown &&
237+ tutorialBottomLoader.mightShow &&
238+ d.focusedApp.state === ApplicationInfoInterface.Running
239+
240+ onIsReadyChanged: if (isReady && !shown) show()
241+ onFinished: AccountsService.markDemoEdgeCompleted("bottom-" + d.focusedApp.appId)
242+ }
180243 }
181244}