Merge lp:~mterry/unity8/skip-spread-tutorial-on-desktop into lp:unity8

Proposed by Michael Terry on 2015-03-23
Status: Merged
Approved by: Albert Astals Cid on 2015-04-02
Approved revision: 1697
Merged at revision: 1716
Proposed branch: lp:~mterry/unity8/skip-spread-tutorial-on-desktop
Merge into: lp:unity8
Diff against target: 381 lines (+130/-49)
8 files modified
qml/Shell.qml (+9/-0)
qml/Tutorial/Tutorial.qml (+7/-0)
qml/Tutorial/TutorialContent.qml (+9/-1)
tests/mocks/GSettings.1.0/fake_gsettings.cpp (+64/-28)
tests/mocks/GSettings.1.0/fake_gsettings.h (+16/-6)
tests/mocks/GSettings.1.0/plugin.cpp (+0/-6)
tests/qmltests/Tutorial/tst_Tutorial.qml (+22/-5)
tests/qmltests/tst_Shell.qml (+3/-3)
To merge this branch: bzr merge lp:~mterry/unity8/skip-spread-tutorial-on-desktop
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) 2015-04-01 Approve on 2015-04-02
PS Jenkins bot continuous-integration Approve on 2015-03-26
Michael Zanetti (community) 2015-03-23 Needs Fixing on 2015-03-26
Review via email: mp+253866@code.launchpad.net

Commit Message

Skip parts of the edge tutorial that require a touch device (like spread and bottom edge).

For now, we just use "desktop-mode" to imply "no-touch-device". In the future, presumably Design will provide different tutorial layouts for the various device modes we support. For now, they have only blessed a phone version. So I just skip the problematic parts.

Description of the Change

Skip parts of the edge tutorial that require a touch device (like spread and bottom edge).

For now, we just use "desktop-mode" to imply "no-touch-device". In the future, presumably Design will provide different tutorial layouts for the various device modes we support. For now, they have only blessed a phone version. So I just skip the problematic parts.

This was a relatively simple change. But adding a baby test for this (mostly so that when we fix how modes work in Shell.qml, we'll know to update this code due to the newly-broken test) involved a bit of yak shaving.

So... our mock GSettings support is awful. In an ideal world, we'd compile the schemas unity8 provides, point GSettings at them (plus the system ones), and then run GSettings with the memory backend so nothing gets saved to disk. That would avoid the need for a mock entirely.

But for convenience of keeping this tiny branch tiny, I tried to fix the mock we have:

- Fixed a reversed-logic check that prevented id() or path() from being set on any GSettings object (and causing warnings to be printed in test logs all the time about 'GSettings.schema.id may only be set on construction')

- I stopped exposing GSettingsController as an object for Qml. This used to be used by tests to modify all existing GSettings objects, wherever they are. But the test code now directly modifies the Shell's GSettings object. So this class was unused. And I'm not thrilled anyway with exposing a special object that only lives in mocks. If we want to change GSettings, we can make our own object or modify an existing one.

- I moved the property storage from each GSettings to the singleton GSettingsController instance. This way if you change one GSettings object, each other object will notice (and especially, so that if you create a GSettings object after another one was set, they agree in values).

- I validate the schema.id value when setting/getting from GSettings, just for sanity checking.

- I provide a default value of "Staged" for com.canonical.Unity8.usageMode. Without this, we were getting the non-inverted launcher (i.e. the desktop version with the home button at the top) in tests and ./run.sh -f. Fixing this required me to change a test's coordinates that dealt with the home button (which is why you see that odd 0.8/0.2 change in tst_Shell.qml).

To post a comment you must log in.
Michael Zanetti (mzanetti) wrote :

two tiny inline comments, and add the checklist please.

review: Needs Fixing
Michael Terry (mterry) wrote :

 * Are there any related MPs required for this MP to build/function as expected? Please list.
 No

 * Did you perform an exploratory manual test run of your code change and any related functionality?
 Yes

 * Did you make sure that your branch does not contain spurious tags?
 Yes

 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
 NA

 * If you changed the UI, has there been a design review?
 NA

1697. By Michael Terry on 2015-03-26

Review nits

Michael Terry (mterry) wrote :

Both comments addressed.

Albert Astals Cid (aacid) wrote :

I'd maybe had named that useEdgeDragArea as "useDesktopTutorial", but one can argue about naming forever on these things so not important

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass?
*IT DID* :o

 * Did you make sure that the branch does not contain spurious tags?
Yes

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qml/Shell.qml'
2--- qml/Shell.qml 2015-03-10 14:25:12 +0000
3+++ qml/Shell.qml 2015-03-26 13:30:45 +0000
4@@ -591,6 +591,15 @@
5 overlay: overlay
6 edgeSize: shell.edgeSize
7
8+ // EdgeDragAreas don't work with mice. So to avoid trapping the user,
9+ // we'll tell the tutorial to avoid using them on the Desktop. The
10+ // Desktop doesn't use the same spread design anyway. The tutorial is
11+ // all a bit of a placeholder on non-phone form factors right now.
12+ // When the design team gives us more guidance, we can do something
13+ // more clever here.
14+ // TODO: use DeviceConfiguration instead of checking source
15+ useEdgeDragArea: applicationsDisplayLoader.source != Qt.resolvedUrl("Stages/DesktopStage.qml")
16+
17 onFinished: {
18 AccountsService.demoEdges = false;
19 active = false; // for immediate response / if AS is having problems
20
21=== modified file 'qml/Tutorial/Tutorial.qml'
22--- qml/Tutorial/Tutorial.qml 2015-01-06 19:50:14 +0000
23+++ qml/Tutorial/Tutorial.qml 2015-03-26 13:30:45 +0000
24@@ -23,6 +23,7 @@
25 property alias active: loader.active
26 property bool paused
27 property real edgeSize
28+ property bool useEdgeDragArea
29
30 property Item launcher
31 property Item panel
32@@ -62,6 +63,12 @@
33
34 Binding {
35 target: loader.item
36+ property: "useEdgeDragArea"
37+ value: root.useEdgeDragArea
38+ }
39+
40+ Binding {
41+ target: loader.item
42 property: "launcher"
43 value: root.launcher
44 }
45
46=== modified file 'qml/Tutorial/TutorialContent.qml'
47--- qml/Tutorial/TutorialContent.qml 2015-01-06 19:13:58 +0000
48+++ qml/Tutorial/TutorialContent.qml 2015-03-26 13:30:45 +0000
49@@ -34,6 +34,7 @@
50
51 property bool paused: false
52 property real edgeSize
53+ property bool useEdgeDragArea
54
55 signal finished()
56
57@@ -81,10 +82,17 @@
58 anchors.fill: parent
59 textXOffset: root.launcher.panelWidth
60 paused: !shown || root.paused
61+ text: root.useEdgeDragArea ? i18n.tr("Tap here to continue.") : i18n.tr("Click here to finish.")
62
63 onFinished: {
64 root.launcher.hide();
65- tutorialRight.show();
66+ if (root.useEdgeDragArea) {
67+ tutorialRight.show();
68+ } else {
69+ // Last two screens use EdgeDragArea (right edge spread and
70+ // bottom edge). So just end tutorial here.
71+ root.finish();
72+ }
73 }
74 }
75
76
77=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.cpp'
78--- tests/mocks/GSettings.1.0/fake_gsettings.cpp 2013-08-15 08:11:04 +0000
79+++ tests/mocks/GSettings.1.0/fake_gsettings.cpp 2015-03-26 13:30:45 +0000
80@@ -20,7 +20,9 @@
81
82 GSettingsControllerQml* GSettingsControllerQml::s_controllerInstance = 0;
83
84-GSettingsControllerQml::GSettingsControllerQml() {
85+GSettingsControllerQml::GSettingsControllerQml()
86+ : m_usageMode("Staged")
87+{
88 }
89
90 GSettingsControllerQml::~GSettingsControllerQml() {
91@@ -34,17 +36,29 @@
92 return s_controllerInstance;
93 }
94
95-void GSettingsControllerQml::registerSettingsObject(GSettingsQml *obj) {
96- m_registeredGSettings.append(obj);
97-}
98-
99-void GSettingsControllerQml::unRegisterSettingsObject(GSettingsQml *obj) {
100- m_registeredGSettings.removeOne(obj);
101-}
102-
103-void GSettingsControllerQml::setPictureUri(const QString &str) {
104- Q_FOREACH (GSettingsQml *obj, m_registeredGSettings) {
105- obj->setPictureUri(str);
106+QString GSettingsControllerQml::pictureUri() const
107+{
108+ return m_pictureUri;
109+}
110+
111+void GSettingsControllerQml::setPictureUri(const QString &str)
112+{
113+ if (str != m_pictureUri) {
114+ m_pictureUri = str;
115+ Q_EMIT pictureUriChanged(m_pictureUri);
116+ }
117+}
118+
119+QString GSettingsControllerQml::usageMode() const
120+{
121+ return m_usageMode;
122+}
123+
124+void GSettingsControllerQml::setUsageMode(const QString &usageMode)
125+{
126+ if (usageMode != m_usageMode) {
127+ m_usageMode = usageMode;
128+ Q_EMIT usageModeChanged(m_usageMode);
129 }
130 }
131
132@@ -56,7 +70,7 @@
133 }
134
135 void GSettingsSchemaQml::setId(const QByteArray &id) {
136- if (m_id.isEmpty()) {
137+ if (!m_id.isEmpty()) {
138 qWarning("GSettings.schema.id may only be set on construction");
139 return;
140 }
141@@ -69,7 +83,7 @@
142 }
143
144 void GSettingsSchemaQml::setPath(const QByteArray &path) {
145- if (m_path.isEmpty()) {
146+ if (!m_path.isEmpty()) {
147 qWarning("GSettings.schema.path may only be set on construction");
148 return;
149 }
150@@ -77,26 +91,48 @@
151 m_path = path;
152 }
153
154-GSettingsQml::GSettingsQml(QObject *parent): QObject(parent) {
155+GSettingsQml::GSettingsQml(QObject *parent)
156+ : QObject(parent)
157+{
158 m_schema = new GSettingsSchemaQml(this);
159- GSettingsControllerQml::instance()->registerSettingsObject(this);
160-}
161-
162-GSettingsQml::~GSettingsQml() {
163- GSettingsControllerQml::instance()->unRegisterSettingsObject(this);
164+ connect(GSettingsControllerQml::instance(), SIGNAL(pictureUriChanged(const QString &)),
165+ this, SIGNAL(pictureUriChanged(const QString &)));
166+ connect(GSettingsControllerQml::instance(), SIGNAL(usageModeChanged(const QString &)),
167+ this, SIGNAL(usageModeChanged(const QString &)));
168 }
169
170 GSettingsSchemaQml * GSettingsQml::schema() const {
171 return m_schema;
172 }
173
174-QString GSettingsQml::pictureUri() const {
175- return m_pictureUri;
176-}
177-
178-void GSettingsQml::setPictureUri(const QString &str) {
179- if (str != m_pictureUri) {
180- m_pictureUri = str;
181- Q_EMIT pictureUriChanged(m_pictureUri);
182+QString GSettingsQml::pictureUri() const
183+{
184+ if (m_schema->id() == "org.gnome.desktop.background") {
185+ return GSettingsControllerQml::instance()->pictureUri();
186+ } else {
187+ return "";
188+ }
189+}
190+
191+void GSettingsQml::setPictureUri(const QString &str)
192+{
193+ if (m_schema->id() == "org.gnome.desktop.background") {
194+ GSettingsControllerQml::instance()->setPictureUri(str);
195+ }
196+}
197+
198+QString GSettingsQml::usageMode() const
199+{
200+ if (m_schema->id() == "com.canonical.Unity8") {
201+ return GSettingsControllerQml::instance()->usageMode();
202+ } else {
203+ return "";
204+ }
205+}
206+
207+void GSettingsQml::setUsageMode(const QString &usageMode)
208+{
209+ if (m_schema->id() == "com.canonical.Unity8") {
210+ GSettingsControllerQml::instance()->setUsageMode(usageMode);
211 }
212 }
213
214=== modified file 'tests/mocks/GSettings.1.0/fake_gsettings.h'
215--- tests/mocks/GSettings.1.0/fake_gsettings.h 2014-08-26 08:14:44 +0000
216+++ tests/mocks/GSettings.1.0/fake_gsettings.h 2015-03-26 13:30:45 +0000
217@@ -46,25 +46,26 @@
218
219 Q_PROPERTY(GSettingsSchemaQml* schema READ schema NOTIFY schemaChanged)
220 Q_PROPERTY(QString pictureUri READ pictureUri WRITE setPictureUri NOTIFY pictureUriChanged)
221+ Q_PROPERTY(QString usageMode READ usageMode WRITE setUsageMode NOTIFY usageModeChanged)
222
223 public:
224 GSettingsQml(QObject *parent = nullptr);
225- ~GSettingsQml();
226
227 GSettingsSchemaQml * schema() const;
228 QString pictureUri() const;
229+ QString usageMode() const;
230
231 void setPictureUri(const QString &str);
232+ void setUsageMode(const QString &usageMode);
233
234 Q_SIGNALS:
235 void schemaChanged();
236 void pictureUriChanged(const QString&);
237+ void usageModeChanged(const QString&);
238
239 private:
240 GSettingsSchemaQml* m_schema;
241
242- QString m_pictureUri;
243-
244 friend class GSettingsSchemaQml;
245 };
246
247@@ -76,13 +77,22 @@
248 static GSettingsControllerQml* instance();
249 ~GSettingsControllerQml();
250
251- void registerSettingsObject(GSettingsQml *obj);
252- void unRegisterSettingsObject(GSettingsQml *obj);
253- Q_INVOKABLE void setPictureUri(const QString &str);
254+ QString pictureUri() const;
255+ void setPictureUri(const QString &str);
256+
257+ QString usageMode() const;
258+ void setUsageMode(const QString &usageMode);
259+
260+Q_SIGNALS:
261+ void pictureUriChanged(const QString&);
262+ void usageModeChanged(const QString&);
263
264 private:
265 GSettingsControllerQml();
266
267+ QString m_pictureUri;
268+ QString m_usageMode;
269+
270 static GSettingsControllerQml* s_controllerInstance;
271 QList<GSettingsQml *> m_registeredGSettings;
272 };
273
274=== modified file 'tests/mocks/GSettings.1.0/plugin.cpp'
275--- tests/mocks/GSettings.1.0/plugin.cpp 2013-08-23 11:56:44 +0000
276+++ tests/mocks/GSettings.1.0/plugin.cpp 2015-03-26 13:30:45 +0000
277@@ -19,14 +19,8 @@
278
279 #include <QtQml/qqml.h>
280
281-static QObject* controllerProvider(QQmlEngine* /* engine */, QJSEngine* /* scriptEngine */)
282-{
283- return GSettingsControllerQml::instance();
284-}
285-
286 void FakeGSettingsQmlPlugin::registerTypes(const char *uri)
287 {
288- qmlRegisterSingletonType<GSettingsControllerQml>(uri, 1, 0, "GSettingsController", controllerProvider);
289 qmlRegisterType<GSettingsQml>(uri, 1, 0, "GSettings");
290 qmlRegisterUncreatableType<GSettingsSchemaQml>(uri, 1, 0, "GSettingsSchema",
291 "GSettingsSchema can only be used inside of a GSettings component");
292
293=== modified file 'tests/qmltests/Tutorial/tst_Tutorial.qml'
294--- tests/qmltests/Tutorial/tst_Tutorial.qml 2015-02-05 21:13:16 +0000
295+++ tests/qmltests/Tutorial/tst_Tutorial.qml 2015-03-26 13:30:45 +0000
296@@ -17,6 +17,7 @@
297 import QtQuick 2.0
298 import QtTest 1.0
299 import AccountsService 0.1
300+import GSettings 1.0
301 import LightDM 0.1 as LightDM
302 import Ubuntu.Components 1.1
303 import Unity.Application 0.1
304@@ -45,6 +46,11 @@
305 }
306 }
307
308+ GSettings {
309+ id: unity8Settings
310+ schema.id: "com.canonical.Unity8"
311+ }
312+
313 Component.onCompleted: {
314 // must set the mock mode before loading the Shell
315 LightDM.Greeter.mockMode = "single-pin";
316@@ -112,6 +118,7 @@
317
318 function init() {
319 tryCompare(shell, "enabled", true); // enabled by greeter when ready
320+ unity8Settings.usageMode = "Staged";
321 AccountsService.demoEdges = false;
322 AccountsService.demoEdges = true;
323 swipeAwayGreeter();
324@@ -185,17 +192,19 @@
325 }
326
327 function checkRightEdge() {
328- touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
329+ if (unity8Settings.usageMode === "Staged") {
330+ touchFlick(shell, shell.width, halfHeight, halfWidth, halfHeight);
331
332- var stage = findChild(shell, "stage");
333- var spreadView = findChild(stage, "spreadView");
334- tryCompare(spreadView, "phase", 0);
335+ var stage = findChild(shell, "stage");
336+ var spreadView = findChild(stage, "spreadView");
337+ tryCompare(spreadView, "phase", 0);
338+ }
339 }
340
341 function checkBottomEdge() {
342 // Can't actually check effect of swipe, since dash isn't really loaded
343 var applicationsDisplayLoader = findChild(shell, "applicationsDisplayLoader");
344- tryCompare(applicationsDisplayLoader.item, "interactive", false);
345+ tryCompare(applicationsDisplayLoader, "interactive", false);
346 }
347
348 function checkFinished() {
349@@ -256,6 +265,14 @@
350 goToPage(null);
351 }
352
353+ function test_walkthroughOnDesktop() {
354+ unity8Settings.usageMode = "Windowed";
355+ var page = goToPage("tutorialLeftFinish");
356+ var tick = findChild(page, "tick");
357+ tap(tick);
358+ checkFinished();
359+ }
360+
361 function test_launcherShortDrag() {
362 // goToPage does a normal launcher pull. But here we want to test
363 // just barely pulling the launcher out and letting go (i.e. not
364
365=== modified file 'tests/qmltests/tst_Shell.qml'
366--- tests/qmltests/tst_Shell.qml 2015-03-18 10:16:42 +0000
367+++ tests/qmltests/tst_Shell.qml 2015-03-26 13:30:45 +0000
368@@ -1084,11 +1084,11 @@
369 {
370 var buttonShowDashHome = findChild(launcher, "buttonShowDashHome");
371 var startPos = buttonShowDashHome.mapToItem(shell,
372+ buttonShowDashHome.width * 0.2,
373+ buttonShowDashHome.height * 0.8);
374+ var endPos = buttonShowDashHome.mapToItem(shell,
375 buttonShowDashHome.width * 0.8,
376 buttonShowDashHome.height * 0.2);
377- var endPos = buttonShowDashHome.mapToItem(shell,
378- buttonShowDashHome.width * 0.2,
379- buttonShowDashHome.height * 0.8);
380 touchFlick(shell, startPos.x, startPos.y, endPos.x, endPos.y);
381 }
382

Subscribers

People subscribed via source and target branches