Merge lp:~macslow/unity8/swipe-dismiss-snap-decisions into lp:unity8
- swipe-dismiss-snap-decisions
- Merge into trunk
Status: | Merged | ||||||||
---|---|---|---|---|---|---|---|---|---|
Approved by: | Michał Sawicz | ||||||||
Approved revision: | 1285 | ||||||||
Merged at revision: | 1599 | ||||||||
Proposed branch: | lp:~macslow/unity8/swipe-dismiss-snap-decisions | ||||||||
Merge into: | lp:unity8 | ||||||||
Diff against target: |
1554 lines (+836/-252) 15 files modified
qml/Notifications/Notification.qml (+36/-6) qml/Notifications/Notifications.qml (+2/-6) tests/mocks/Unity/Notifications/CMakeLists.txt (+2/-1) tests/mocks/Unity/Notifications/MockActionModel.cpp (+6/-4) tests/mocks/Unity/Notifications/MockActionModel.h (+4/-2) tests/mocks/Unity/Notifications/MockNotification.cpp (+156/-4) tests/mocks/Unity/Notifications/MockNotification.h (+63/-5) tests/mocks/Unity/Notifications/MockNotificationModel.cpp (+172/-0) tests/mocks/Unity/Notifications/MockNotificationModel.h (+72/-0) tests/mocks/Unity/Notifications/plugin.cpp (+5/-3) tests/mocks/Unity/Notifications/plugin.h (+1/-2) tests/qmltests/Notifications/Notification.qml (+31/-0) tests/qmltests/Notifications/tst_Notifications.qml (+271/-213) tests/qmltests/Notifications/tst_OptionToggle.qml (+11/-6) tests/qmltests/Notifications/tst_SwipeToAct.qml (+4/-0) |
||||||||
To merge this branch: | bzr merge lp:~macslow/unity8/swipe-dismiss-snap-decisions | ||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michał Sawicz | tests | Approve | |
PS Jenkins bot (community) | continuous-integration | Approve | |
Albert Astals Cid (community) | Approve | ||
Michael Zanetti (community) | Abstain | ||
Antti Kaijanmäki (community) | Needs Information | ||
Review via email: mp+233347@code.launchpad.net |
Commit message
Allow swipe-to-dismiss for contracted snap-decision notifications, interactive notifications and ephemeral notifications.
Description of the change
Allow swipe-to-dismiss for contracted snap-decision notifications, interactive notifications and ephemeral notifications.
For the reviewers convenience, here's a video of the branch in action: https:/
* 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?
Not applicable.
* If you changed the UI, has there been a design review?
Yes.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1230
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1233
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1234
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1235
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1331
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
Text conflict in qml/Notificatio
1 conflicts encountered.
Albert Astals Cid (aacid) wrote : | # |
Text conflict in qml/Notificatio
Text conflict in tests/qmltests/
2 conflicts encountered.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1236
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1236
http://
Executed test runs:
UNSTABLE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Antti Kaijanmäki (kaijanmaki) wrote : | # |
+ readonly property bool draggable: state == "contracted" || notification.type !== Notification.
Does this cover pin-unlock dialog as well? I don't have the code at hand right now to check if it's type is set to Notification.
Mirco Müller (macslow) wrote : | # |
> + readonly property bool draggable: state == "contracted" ||
> notification.type !== Notification.
>
>
> Does this cover pin-unlock dialog as well? I don't have the code at hand right
> now to check if it's type is set to Notification.
> becomes draggable.
No, that won't happen. A SIM-unlock "dialog" is an expanded (or non-contractable) snap-decision, thus it cannot be dragged.
Albert Astals Cid (aacid) wrote : | # |
file://
if (data.type !== Notification.
^
file://
if (data.type !== Notification.
Albert Astals Cid (aacid) wrote : | # |
make testNotifications fails here
Mirco Müller (macslow) wrote : | # |
> make testNotifications fails here
Like discussed on IRC, I can't reproduce your reported failures. Everything works and passes as expected.
Albert Astals Cid (aacid) wrote : | # |
> > make testNotifications fails here
>
> Like discussed on IRC, I can't reproduce your reported failures. Everything
> works and passes as expected.
Barring that for some reasons test don't pass for me the rest looks good, if everyone else wants to take over these two days i'm out, feel free :)
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1241
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
I can reproduce the test failures Albert reported. Sometimes it seems that a swipe to remove removes 2 notifications instead of just one. I can also reproduce that manually with tryNotifications.
Michael Zanetti (mzanetti) wrote : | # |
Seems fixing the FIXME in Notifications.
Michael Zanetti (mzanetti) wrote : | # |
hmm.. sorry, after reverting the debug prints in the test it fails again here...
Michael Zanetti (mzanetti) wrote : | # |
Test passing fine now.
Albert Astals Cid (aacid) wrote : | # |
I think relying on the JS->C++ binding ignoring the extra parameter to call an invokable function with less parameters is a bit too much
Albert Astals Cid (aacid) wrote : | # |
* Did you perform an exploratory manual test run of the code change and any related functionality?
Yes
* Did CI run pass?
Waiting for it to finish
* Did you make sure that the branch does not contain spurious tags?
Yes
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1282
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1282
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Albert Astals Cid (aacid) wrote : | # |
qmluitests failed on CI for some reason byt they all passed fine so i'm going to top approve anyway
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1282
http://
Executed test runs:
FAILURE: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) wrote : | # |
There's a failing test I'm afraid:
FAIL! : qmltestrunner:
Actual (): 3
Expected (): 2
Loc: [/home/
Mirco Müller (macslow) wrote : | # |
Looking into it.
- 1284. By Mirco Müller
-
Merge with trunk.
Mirco Müller (macslow) wrote : | # |
I've updated my system, re-merged this branch with lp:unity8 trunk and recompiled everything, but still can't reproduce this failure. All notification-
- 1285. By Mirco Müller
-
Make sure all rendering operations are completed before doing the swipe-dismiss-
checks, thus the tests also pass on very slow (jenkins) systems.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1285
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1285
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michał Sawicz (saviq) : | # |
Preview Diff
1 | === modified file 'qml/Notifications/Notification.qml' |
2 | --- qml/Notifications/Notification.qml 2014-11-07 14:31:12 +0000 |
3 | +++ qml/Notifications/Notification.qml 2015-02-06 15:16:01 +0000 |
4 | @@ -40,6 +40,7 @@ |
5 | property bool fullscreen: false |
6 | property int maxHeight |
7 | property int margins |
8 | + readonly property bool draggable: (type === Notification.SnapDecision && state === "contracted") || type === Notification.Interactive || type === Notification.Ephemeral |
9 | readonly property bool darkOnBright: panel.indicators.shown || type === Notification.SnapDecision |
10 | readonly property color red: "#fc4949" |
11 | readonly property color green: "#3fb24f" |
12 | @@ -52,7 +53,7 @@ |
13 | implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0 |
14 | |
15 | color: (type === Notification.Confirmation && notificationList.useModal && !greeter.shown) || darkOnBright ? sdLightGrey : Qt.rgba(0.132, 0.117, 0.109, 0.97) |
16 | - opacity: 1 // FIXME: 1 because of LP: #1354406 workaround, has to be 0 really |
17 | + opacity: 1 - (x / notification.width) // FIXME: non-zero initially because of LP: #1354406 workaround, we want this to start at 0 upon creation eventually |
18 | |
19 | state: { |
20 | var result = ""; |
21 | @@ -80,18 +81,28 @@ |
22 | id: sound |
23 | objectName: "sound" |
24 | audioRole: MediaPlayer.alert |
25 | - source: hints["suppress-sound"] != "true" && hints["sound-file"] != undefined ? hints["sound-file"] : "" |
26 | + source: hints["suppress-sound"] !== "true" && hints["sound-file"] !== undefined ? hints["sound-file"] : "" |
27 | } |
28 | |
29 | // FIXME: using onCompleted because of LP: #1354406 workaround, has to be onOpacityChanged really |
30 | Component.onCompleted: { |
31 | - if (opacity == 1.0 && hints["suppress-sound"] != "true" && sound.source != "") { |
32 | + if (opacity == 1.0 && hints["suppress-sound"] !== "true" && sound.source !== "") { |
33 | sound.play(); |
34 | } |
35 | } |
36 | |
37 | + Behavior on x { |
38 | + id: normalXBehavior |
39 | + |
40 | + enabled: draggable |
41 | + UbuntuNumberAnimation { |
42 | + duration: UbuntuAnimation.FastDuration |
43 | + easing.type: Easing.OutBounce |
44 | + } |
45 | + } |
46 | + |
47 | onHintsChanged: { |
48 | - if (type === Notification.Confirmation && opacity == 1.0 && hints["suppress-sound"] != "true" && sound.source != "") { |
49 | + if (type === Notification.Confirmation && opacity == 1.0 && hints["suppress-sound"] !== "true" && sound.source !== "") { |
50 | sound.play(); |
51 | } |
52 | } |
53 | @@ -146,6 +157,12 @@ |
54 | opacity: parent.opacity |
55 | } |
56 | |
57 | + onXChanged: { |
58 | + if (draggable && notification.x > 0.75 * notification.width) { |
59 | + notification.notification.close() |
60 | + } |
61 | + } |
62 | + |
63 | Item { |
64 | id: contents |
65 | anchors.fill: fullscreen ? nonShapedBack : shapedBack |
66 | @@ -169,7 +186,7 @@ |
67 | actions: paths.actions |
68 | menuObjectPath: paths.menuObjectPath |
69 | onNameOwnerChanged: { |
70 | - if (lastNameOwner != "" && nameOwner == "" && notification.notification != undefined) { |
71 | + if (lastNameOwner !== "" && nameOwner === "" && notification.notification !== undefined) { |
72 | notification.notification.close() |
73 | } |
74 | lastNameOwner = nameOwner |
75 | @@ -181,6 +198,12 @@ |
76 | |
77 | anchors.fill: parent |
78 | objectName: "interactiveArea" |
79 | + |
80 | + drag.target: draggable ? notification : undefined |
81 | + drag.axis: Drag.XAxis |
82 | + drag.minimumX: 0 |
83 | + drag.maximumX: notification.width |
84 | + |
85 | onClicked: { |
86 | if (notification.type == Notification.Interactive) { |
87 | notification.notification.invokeAction(actionRepeater.itemAt(0).actionId) |
88 | @@ -188,6 +211,13 @@ |
89 | notificationList.currentIndex = index; |
90 | } |
91 | } |
92 | + onReleased: { |
93 | + if (notification.x < notification.width / 2) { |
94 | + notification.x = 0 |
95 | + } else { |
96 | + notification.x = notification.width |
97 | + } |
98 | + } |
99 | } |
100 | |
101 | Column { |
102 | @@ -447,7 +477,7 @@ |
103 | right: parent.right |
104 | margins: contentSpacing |
105 | } |
106 | - visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0 && !oneOverTwoCase.visible |
107 | + visible: notification.type === Notification.SnapDecision && actionRepeater.count > 0 && !oneOverTwoCase.visible |
108 | spacing: units.gu(2) |
109 | layoutDirection: Qt.RightToLeft |
110 | |
111 | |
112 | === modified file 'qml/Notifications/Notifications.qml' |
113 | --- qml/Notifications/Notifications.qml 2014-12-19 14:51:35 +0000 |
114 | +++ qml/Notifications/Notifications.qml 2015-02-06 15:16:01 +0000 |
115 | @@ -41,15 +41,11 @@ |
116 | property bool topmostIsFullscreen: false |
117 | spacing: topmostIsFullscreen ? 0 : units.gu(.5) |
118 | |
119 | - // FIXME: This doesn't make any sense and results in a binding loop |
120 | - currentIndex: (currentIndex < 1 && count > 1) ? 1 : -1 |
121 | + currentIndex: count > 1 ? 1 : -1 |
122 | |
123 | delegate: Notification { |
124 | objectName: "notification" + index |
125 | - anchors { |
126 | - left: parent.left |
127 | - right: parent.right |
128 | - } |
129 | + width: parent.width |
130 | type: model.type |
131 | hints: model.hints |
132 | iconSource: model.icon |
133 | |
134 | === modified file 'tests/mocks/Unity/Notifications/CMakeLists.txt' |
135 | --- tests/mocks/Unity/Notifications/CMakeLists.txt 2014-10-23 22:01:57 +0000 |
136 | +++ tests/mocks/Unity/Notifications/CMakeLists.txt 2015-02-06 15:16:01 +0000 |
137 | @@ -4,7 +4,8 @@ |
138 | |
139 | set(MockNotificationsPlugin_SOURCES |
140 | plugin.cpp |
141 | - MockNotificationTypes.cpp |
142 | + MockNotification.cpp |
143 | + MockNotificationModel.cpp |
144 | MockActionModel.cpp |
145 | ) |
146 | |
147 | |
148 | === modified file 'tests/mocks/Unity/Notifications/MockActionModel.cpp' |
149 | --- tests/mocks/Unity/Notifications/MockActionModel.cpp 2014-10-23 22:01:57 +0000 |
150 | +++ tests/mocks/Unity/Notifications/MockActionModel.cpp 2015-02-06 15:16:01 +0000 |
151 | @@ -1,5 +1,5 @@ |
152 | /* |
153 | - * Copyright 2014 Canonical Ltd. |
154 | + * Copyright 2015 Canonical Ltd. |
155 | * |
156 | * This program is free software; you can redistribute it and/or modify |
157 | * it under the terms of the GNU Lesser General Public License as published by |
158 | @@ -25,8 +25,6 @@ |
159 | }; |
160 | |
161 | ActionModel::ActionModel(QObject *parent) : QStringListModel(parent), p(new ActionModelPrivate) { |
162 | - insertAction("ok_id", "Ok"); |
163 | - insertAction("cancel_id", "Cancel"); |
164 | } |
165 | |
166 | ActionModel::~ActionModel() { |
167 | @@ -66,7 +64,11 @@ |
168 | return data(index(row, 0), role); |
169 | } |
170 | |
171 | -void ActionModel::insertAction(const QString &id, const QString &label) { |
172 | +void ActionModel::append(const QString &id, const QString &label) { |
173 | p->ids.push_back(id); |
174 | p->labels.push_back(label); |
175 | } |
176 | + |
177 | +int ActionModel::getCount() const { |
178 | + return p->labels.size(); |
179 | +} |
180 | |
181 | === modified file 'tests/mocks/Unity/Notifications/MockActionModel.h' |
182 | --- tests/mocks/Unity/Notifications/MockActionModel.h 2014-10-23 22:01:57 +0000 |
183 | +++ tests/mocks/Unity/Notifications/MockActionModel.h 2015-02-06 15:16:01 +0000 |
184 | @@ -1,5 +1,5 @@ |
185 | /* |
186 | - * Copyright 2014 Canonical Ltd. |
187 | + * Copyright 2015 Canonical Ltd. |
188 | * |
189 | * This program is free software; you can redistribute it and/or modify |
190 | * it under the terms of the GNU Lesser General Public License as published by |
191 | @@ -26,6 +26,7 @@ |
192 | |
193 | class ActionModel : public QStringListModel { |
194 | Q_OBJECT |
195 | + Q_PROPERTY(int count READ getCount) |
196 | |
197 | public: |
198 | ActionModel(QObject *parent=nullptr); |
199 | @@ -42,7 +43,8 @@ |
200 | }; |
201 | Q_INVOKABLE QVariant data(int row, int role) const; |
202 | |
203 | - void insertAction(const QString &id, const QString &label); |
204 | + Q_INVOKABLE void append(const QString &id, const QString &label); |
205 | + int getCount() const; |
206 | |
207 | private: |
208 | QScopedPointer<ActionModelPrivate> p; |
209 | |
210 | === renamed file 'tests/mocks/Unity/Notifications/MockNotificationTypes.cpp' => 'tests/mocks/Unity/Notifications/MockNotification.cpp' |
211 | --- tests/mocks/Unity/Notifications/MockNotificationTypes.cpp 2014-10-23 22:01:57 +0000 |
212 | +++ tests/mocks/Unity/Notifications/MockNotification.cpp 2015-02-06 15:16:01 +0000 |
213 | @@ -1,5 +1,5 @@ |
214 | /* |
215 | - * Copyright 2014 Canonical Ltd. |
216 | + * Copyright 2015 Canonical Ltd. |
217 | * |
218 | * This program is free software; you can redistribute it and/or modify |
219 | * it under the terms of the GNU Lesser General Public License as published by |
220 | @@ -17,10 +17,162 @@ |
221 | * Mirco Mueller <mirco.mueller@canonical.com> |
222 | */ |
223 | |
224 | -#include "MockNotificationTypes.h" |
225 | - |
226 | -MockNotification::MockNotification(QObject *parent) : QObject(parent) { |
227 | +#include "MockNotification.h" |
228 | + |
229 | +#include <QDebug> |
230 | + |
231 | +struct MockNotificationPrivate { |
232 | + int id; |
233 | + QString summary; |
234 | + QString body; |
235 | + int value; |
236 | + MockNotification::Type type; |
237 | + QString icon; |
238 | + QString secondaryIcon; |
239 | + QStringList actions; |
240 | + ActionModel* actionsModel; |
241 | + QVariantMap hints; |
242 | +}; |
243 | + |
244 | +MockNotification::MockNotification(QObject *parent) : QObject(parent), p(new MockNotificationPrivate()) { |
245 | + p->actionsModel = new ActionModel(); |
246 | } |
247 | |
248 | MockNotification::~MockNotification() { |
249 | } |
250 | + |
251 | +QString MockNotification::getSummary() const { |
252 | + return p->summary; |
253 | +} |
254 | + |
255 | +void MockNotification::setSummary(const QString &summary) { |
256 | + if(p->summary != summary) { |
257 | + p->summary = summary; |
258 | + Q_EMIT summaryChanged(p->summary); |
259 | + Q_EMIT dataChanged(p->id); |
260 | + } |
261 | +} |
262 | + |
263 | +QString MockNotification::getBody() const { |
264 | + return p->body; |
265 | +} |
266 | + |
267 | +void MockNotification::setBody(const QString &body) { |
268 | + if(p->body != body) { |
269 | + p->body = body; |
270 | + Q_EMIT bodyChanged(p->body); |
271 | + Q_EMIT dataChanged(p->id); |
272 | + } |
273 | +} |
274 | + |
275 | +int MockNotification::getID() const { |
276 | + return p->id; |
277 | +} |
278 | + |
279 | +void MockNotification::setID(const int id) { |
280 | + p->id = id; |
281 | +} |
282 | + |
283 | +int MockNotification::getValue() const { |
284 | + return p->value; |
285 | +} |
286 | + |
287 | +void MockNotification::setValue(int value) { |
288 | + if(p->value != value) { |
289 | + p->value = value; |
290 | + Q_EMIT valueChanged(p->value); |
291 | + Q_EMIT dataChanged(p->id); |
292 | + } |
293 | +} |
294 | + |
295 | +QString MockNotification::getIcon() const { |
296 | + return p->icon; |
297 | +} |
298 | + |
299 | +void MockNotification::setIcon(const QString &icon) { |
300 | + if (icon.startsWith(" ") || icon.size() == 0) { |
301 | + p->icon = nullptr; |
302 | + } |
303 | + else { |
304 | + p->icon = icon; |
305 | + |
306 | + if (icon.indexOf("/") == -1) { |
307 | + p->icon.prepend("image://theme/"); |
308 | + } |
309 | + } |
310 | + |
311 | + Q_EMIT iconChanged(p->icon); |
312 | + Q_EMIT dataChanged(p->id); |
313 | +} |
314 | + |
315 | +QString MockNotification::getSecondaryIcon() const { |
316 | + return p->secondaryIcon; |
317 | +} |
318 | + |
319 | +void MockNotification::setSecondaryIcon(const QString &secondaryIcon) { |
320 | + if (secondaryIcon.startsWith(" ") || secondaryIcon.size() == 0) { |
321 | + p->secondaryIcon = nullptr; |
322 | + } |
323 | + else { |
324 | + p->secondaryIcon = secondaryIcon; |
325 | + |
326 | + if (secondaryIcon.indexOf("/") == -1) { |
327 | + p->secondaryIcon.prepend("image://theme/"); |
328 | + } |
329 | + } |
330 | + |
331 | + Q_EMIT secondaryIconChanged(p->secondaryIcon); |
332 | + Q_EMIT dataChanged(p->id); |
333 | +} |
334 | + |
335 | +MockNotification::Type MockNotification::getType() const { |
336 | + return p->type; |
337 | +} |
338 | + |
339 | +void MockNotification::setType(Type type) { |
340 | + if(p->type != type) { |
341 | + p->type = type; |
342 | + Q_EMIT typeChanged(p->type); |
343 | + } |
344 | +} |
345 | + |
346 | +ActionModel* MockNotification::getActions() const { |
347 | + return p->actionsModel; |
348 | +} |
349 | + |
350 | +void MockNotification::setActions(const QStringList &actions) { |
351 | + if(p->actions != actions) { |
352 | + p->actions = actions; |
353 | + Q_EMIT actionsChanged(p->actions); |
354 | + |
355 | + for (int i = 0; i < p->actions.size(); i += 2) { |
356 | + p->actionsModel->append(p->actions[i], p->actions[i+1]); |
357 | + } |
358 | + } |
359 | +} |
360 | + |
361 | +QVariantMap MockNotification::getHints() const { |
362 | + return p->hints; |
363 | +} |
364 | + |
365 | +void MockNotification::setHints(const QVariantMap& hints) { |
366 | + if (p->hints != hints) { |
367 | + p->hints = hints; |
368 | + Q_EMIT hintsChanged(p->hints); |
369 | + } |
370 | +} |
371 | + |
372 | +void MockNotification::invokeAction(const QString &action) { |
373 | + for(int i=0; i<p->actions.size(); i++) { |
374 | + if(p->actions[i] == action) { |
375 | + Q_EMIT actionInvoked(action); |
376 | + qDebug() << "Info: invoked action" << action; |
377 | + return; |
378 | + } |
379 | + } |
380 | + fprintf(stderr, "Error: tried to invoke action not in actionList.\n"); |
381 | +} |
382 | + |
383 | +void MockNotification::close() { |
384 | + Q_EMIT completed(p->id); |
385 | +} |
386 | |
387 | === renamed file 'tests/mocks/Unity/Notifications/MockNotificationTypes.h' => 'tests/mocks/Unity/Notifications/MockNotification.h' |
388 | --- tests/mocks/Unity/Notifications/MockNotificationTypes.h 2014-10-23 22:01:57 +0000 |
389 | +++ tests/mocks/Unity/Notifications/MockNotification.h 2015-02-06 15:16:01 +0000 |
390 | @@ -1,5 +1,5 @@ |
391 | /* |
392 | - * Copyright 2014 Canonical Ltd. |
393 | + * Copyright 2015 Canonical Ltd. |
394 | * |
395 | * This program is free software; you can redistribute it and/or modify |
396 | * it under the terms of the GNU Lesser General Public License as published by |
397 | @@ -17,20 +17,78 @@ |
398 | * Mirco Mueller <mirco.mueller@canonical.com> |
399 | */ |
400 | |
401 | -#ifndef MOCK_NOTIFICATION_TYPES_H |
402 | -#define MOCK_NOTIFICATION_TYPES_H |
403 | +#ifndef MOCK_NOTIFICATION_H |
404 | +#define MOCK_NOTIFICATION_H |
405 | |
406 | +#include "MockActionModel.h" |
407 | #include <QObject> |
408 | +#include <QString> |
409 | +#include <QStringList> |
410 | +#include <QScopedPointer> |
411 | + |
412 | +struct MockNotificationPrivate; |
413 | |
414 | class MockNotification : public QObject { |
415 | Q_OBJECT |
416 | Q_ENUMS(Type) |
417 | + Q_PROPERTY(QString summary READ getSummary WRITE setSummary NOTIFY summaryChanged) |
418 | + Q_PROPERTY(QString body READ getBody WRITE setBody NOTIFY bodyChanged) |
419 | + Q_PROPERTY(int nid READ getID WRITE setID NOTIFY idChanged) |
420 | + Q_PROPERTY(int value READ getValue WRITE setValue NOTIFY valueChanged) |
421 | + Q_PROPERTY(QString icon READ getIcon WRITE setIcon NOTIFY iconChanged) |
422 | + Q_PROPERTY(QString secondaryIcon READ getSecondaryIcon WRITE setSecondaryIcon NOTIFY secondaryIconChanged) |
423 | + Q_PROPERTY(Type type READ getType WRITE setType NOTIFY typeChanged) |
424 | + Q_PROPERTY(QStringList rawActions WRITE setActions) |
425 | + Q_PROPERTY(ActionModel* actions READ getActions NOTIFY actionsChanged) |
426 | + Q_PROPERTY(QVariantMap hints READ getHints WRITE setHints NOTIFY hintsChanged) |
427 | + |
428 | +private: |
429 | + QScopedPointer<MockNotificationPrivate> p; |
430 | + |
431 | +public: |
432 | + enum Urgency { Low, Normal, Critical }; |
433 | + enum Type { PlaceHolder, Confirmation, Ephemeral, Interactive, SnapDecision }; |
434 | + |
435 | +Q_SIGNALS: |
436 | + void summaryChanged(const QString &summary); |
437 | + void bodyChanged(const QString &body); |
438 | + void idChanged(const int id); |
439 | + void valueChanged(int value); |
440 | + void iconChanged(const QString &icon); |
441 | + void secondaryIconChanged(const QString &secondaryIcon); |
442 | + void typeChanged(Type type); |
443 | + void actionsChanged(const QStringList &actions); |
444 | + void hintsChanged(const QVariantMap& hints); |
445 | + |
446 | + void dataChanged(int nid); |
447 | + void completed(int nid); |
448 | + void actionInvoked(const QString &action); |
449 | |
450 | public: |
451 | MockNotification(QObject *parent=nullptr); |
452 | virtual ~MockNotification(); |
453 | |
454 | - enum Type { PlaceHolder, Confirmation, Ephemeral, Interactive, SnapDecision }; |
455 | + QString getSummary() const; |
456 | + void setSummary(const QString &summary); |
457 | + QString getBody() const; |
458 | + void setBody(const QString &body); |
459 | + int getID() const; |
460 | + void setID(const int id); |
461 | + int getValue() const; |
462 | + void setValue(int value); |
463 | + QString getIcon() const; |
464 | + void setIcon(const QString &icon); |
465 | + QString getSecondaryIcon() const; |
466 | + void setSecondaryIcon(const QString &secondaryIcon); |
467 | + Type getType() const; |
468 | + void setType(Type type); |
469 | + ActionModel* getActions() const; |
470 | + void setActions(const QStringList &actions); |
471 | + QVariantMap getHints() const; |
472 | + void setHints(const QVariantMap& hints); |
473 | + |
474 | + Q_INVOKABLE void invokeAction(const QString &action); |
475 | + Q_INVOKABLE void close(); |
476 | }; |
477 | |
478 | -#endif // MOCK_NOTIFICATION_TYPES_H |
479 | +#endif // MOCK_NOTIFICATION_H |
480 | |
481 | === added file 'tests/mocks/Unity/Notifications/MockNotificationModel.cpp' |
482 | --- tests/mocks/Unity/Notifications/MockNotificationModel.cpp 1970-01-01 00:00:00 +0000 |
483 | +++ tests/mocks/Unity/Notifications/MockNotificationModel.cpp 2015-02-06 15:16:01 +0000 |
484 | @@ -0,0 +1,172 @@ |
485 | +/* |
486 | + * Copyright 2015 Canonical Ltd. |
487 | + * |
488 | + * This program is free software; you can redistribute it and/or modify |
489 | + * it under the terms of the GNU Lesser General Public License as published by |
490 | + * the Free Software Foundation; version 3. |
491 | + * |
492 | + * This program is distributed in the hope that it will be useful, |
493 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
494 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
495 | + * GNU Lesser General Public License for more details. |
496 | + * |
497 | + * You should have received a copy of the GNU Lesser General Public License |
498 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
499 | + * |
500 | + * Authors: |
501 | + * Mirco Mueller <mirco.mueller@canonical.com> |
502 | + */ |
503 | + |
504 | +#include "MockNotificationModel.h" |
505 | +#include "MockNotification.h" |
506 | + |
507 | +#include <unity/shell/notifications/ModelInterface.h> |
508 | + |
509 | +#include <QTimer> |
510 | +#include <QList> |
511 | +#include <QVector> |
512 | +#include <QMap> |
513 | +#include <QStringListModel> |
514 | +#include <QQmlEngine> |
515 | + |
516 | +using namespace unity::shell::notifications; |
517 | + |
518 | +MockNotificationModel::MockNotificationModel(QObject *parent) : QAbstractListModel(parent) { |
519 | +} |
520 | + |
521 | +MockNotificationModel::~MockNotificationModel() { |
522 | +} |
523 | + |
524 | +int MockNotificationModel::rowCount(const QModelIndex &parent) const { |
525 | + return m_queue.size(); |
526 | +} |
527 | + |
528 | +int MockNotificationModel::getCount() const { |
529 | + return m_queue.size(); |
530 | +} |
531 | + |
532 | +QVariant MockNotificationModel::data(const QModelIndex &index, int role) const { |
533 | + if (!index.isValid()) |
534 | + return QVariant(); |
535 | + |
536 | + switch(role) { |
537 | + case ModelInterface::RoleType: |
538 | + return QVariant(m_queue[index.row()]->getType()); |
539 | + |
540 | + case ModelInterface::RoleId: |
541 | + return QVariant(m_queue[index.row()]->getID()); |
542 | + |
543 | + case ModelInterface::RoleSummary: |
544 | + return QVariant(m_queue[index.row()]->getSummary()); |
545 | + |
546 | + case ModelInterface::RoleBody: |
547 | + return QVariant(m_queue[index.row()]->getBody()); |
548 | + |
549 | + case ModelInterface::RoleValue: |
550 | + return QVariant(m_queue[index.row()]->getValue()); |
551 | + |
552 | + case ModelInterface::RoleIcon: |
553 | + return QVariant(m_queue[index.row()]->getIcon()); |
554 | + |
555 | + case ModelInterface::RoleSecondaryIcon: |
556 | + return QVariant(m_queue[index.row()]->getSecondaryIcon()); |
557 | + |
558 | + case ModelInterface::RoleActions: |
559 | + return QVariant::fromValue(m_queue[index.row()]->getActions()); |
560 | + |
561 | + case ModelInterface::RoleHints: |
562 | + return QVariant(m_queue[index.row()]->getHints()); |
563 | + |
564 | + case ModelInterface::RoleNotification: |
565 | + return QVariant::fromValue(m_queue[index.row()]); |
566 | + |
567 | + default: |
568 | + return QVariant(); |
569 | + } |
570 | +} |
571 | + |
572 | +void MockNotificationModel::append(MockNotification* n) { |
573 | + int location = m_queue.size(); |
574 | + QModelIndex insertionPoint = QModelIndex(); |
575 | + beginInsertRows(insertionPoint, location, location); |
576 | + m_queue.insert(location, n); |
577 | + endInsertRows(); |
578 | +} |
579 | + |
580 | +MockNotification* MockNotificationModel::getNotification(int id) const { |
581 | + for(int i=0; i < m_queue.size(); i++) { |
582 | + if(m_queue[i]->getID() == id) { |
583 | + return m_queue[i]; |
584 | + } |
585 | + } |
586 | + |
587 | + return nullptr; |
588 | +} |
589 | + |
590 | +void MockNotificationModel::remove(const int id) { |
591 | + for(int i = 0; i < m_queue.size(); i++) { |
592 | + if(m_queue[i]->getID() == id) { |
593 | + removeInternal(i); |
594 | + return; |
595 | + } |
596 | + } |
597 | +} |
598 | + |
599 | +void MockNotificationModel::removeSecond() { |
600 | + if(m_queue.size() < 2) |
601 | + return; |
602 | + removeInternal(1); |
603 | +} |
604 | + |
605 | +void MockNotificationModel::removeInternal(int loc) { |
606 | + QModelIndex deletePoint = QModelIndex(); |
607 | + beginRemoveRows(deletePoint, loc, loc); |
608 | + m_queue.erase(m_queue.begin() + loc); |
609 | + endRemoveRows(); |
610 | +} |
611 | + |
612 | +MockNotification* MockNotificationModel::getRaw(const int notificationId) const { |
613 | + for(int i = 0; i < m_queue.size(); i++) { |
614 | + if(m_queue[i]->getID() == notificationId) { |
615 | + MockNotification* n = m_queue[i]; |
616 | + return n; |
617 | + } |
618 | + } |
619 | + |
620 | + return nullptr; |
621 | +} |
622 | + |
623 | +int MockNotificationModel::queued() const { |
624 | + return m_queue.size(); |
625 | +} |
626 | + |
627 | +QHash<int, QByteArray> MockNotificationModel::roleNames() const { |
628 | + QHash<int, QByteArray> roles; |
629 | + |
630 | + roles.insert(ModelInterface::RoleType, "type"); |
631 | + roles.insert(ModelInterface::RoleUrgency, "urgency"); |
632 | + roles.insert(ModelInterface::RoleId, "id"); |
633 | + roles.insert(ModelInterface::RoleSummary, "summary"); |
634 | + roles.insert(ModelInterface::RoleBody, "body"); |
635 | + roles.insert(ModelInterface::RoleValue, "value"); |
636 | + roles.insert(ModelInterface::RoleIcon, "icon"); |
637 | + roles.insert(ModelInterface::RoleSecondaryIcon, "secondaryIcon"); |
638 | + roles.insert(ModelInterface::RoleActions, "actions"); |
639 | + roles.insert(ModelInterface::RoleHints, "hints"); |
640 | + roles.insert(ModelInterface::RoleNotification, "notification"); |
641 | + |
642 | + return roles; |
643 | +} |
644 | + |
645 | +void MockNotificationModel::onCompleted(int id) { |
646 | + remove(id); |
647 | +} |
648 | + |
649 | +void MockNotificationModel::onDataChanged(int id) { |
650 | + for(int i = 0; i < m_queue.size(); i++) { |
651 | + if(m_queue[i]->getID() == id) { |
652 | + Q_EMIT dataChanged(index(i, 0), index(i, 0)); |
653 | + break; |
654 | + } |
655 | + } |
656 | +} |
657 | |
658 | === added file 'tests/mocks/Unity/Notifications/MockNotificationModel.h' |
659 | --- tests/mocks/Unity/Notifications/MockNotificationModel.h 1970-01-01 00:00:00 +0000 |
660 | +++ tests/mocks/Unity/Notifications/MockNotificationModel.h 2015-02-06 15:16:01 +0000 |
661 | @@ -0,0 +1,72 @@ |
662 | +/* |
663 | + * Copyright 2015 Canonical Ltd. |
664 | + * |
665 | + * This program is free software; you can redistribute it and/or modify |
666 | + * it under the terms of the GNU Lesser General Public License as published by |
667 | + * the Free Software Foundation; version 3. |
668 | + * |
669 | + * This program is distributed in the hope that it will be useful, |
670 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
671 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
672 | + * GNU Lesser General Public License for more details. |
673 | + * |
674 | + * You should have received a copy of the GNU Lesser General Public License |
675 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
676 | + * |
677 | + * Authors: |
678 | + * Mirco Mueller <mirco.mueller@canonical.com> |
679 | + */ |
680 | + |
681 | +#ifndef MOCK_NOTIFICATION_MODEL_H |
682 | +#define MOCK_NOTIFICATION_MODEL_H |
683 | + |
684 | +#include <QAbstractListModel> |
685 | +#include <QSharedPointer> |
686 | +#include <QScopedPointer> |
687 | +#include "MockNotification.h" |
688 | + |
689 | +class MockNotification; |
690 | + |
691 | +class MockNotificationModel : public QAbstractListModel { |
692 | + Q_OBJECT |
693 | + Q_PROPERTY(int count READ getCount) |
694 | + |
695 | +public: |
696 | + MockNotificationModel(QObject *parent=nullptr); |
697 | + virtual ~MockNotificationModel(); |
698 | + |
699 | + virtual int rowCount(const QModelIndex &parent) const; |
700 | + virtual QVariant data(const QModelIndex &index, int role) const; |
701 | + virtual QHash<int, QByteArray> roleNames() const; |
702 | + |
703 | + Q_INVOKABLE void append(MockNotification* n); |
704 | + MockNotification* getNotification(int id) const; |
705 | + |
706 | + // getRaw() is only meant to be used from QML, since QML cannot handle |
707 | + // QSharedPointers... on C++-side only use getNotification() |
708 | + Q_INVOKABLE MockNotification* getRaw(const int notificationId) const; |
709 | + |
710 | + Q_INVOKABLE int queued() const; |
711 | + Q_INVOKABLE void remove(const int id); |
712 | + Q_INVOKABLE void removeSecond(); |
713 | + |
714 | + int getCount() const; |
715 | + |
716 | +Q_SIGNALS: |
717 | + void actionInvoked(const QString &action); |
718 | + |
719 | +public Q_SLOTS: |
720 | + void onCompleted(int id); |
721 | + |
722 | +private Q_SLOTS: |
723 | + void onDataChanged(int id); |
724 | + |
725 | +Q_SIGNALS: |
726 | + void queueSizeChanged(int newSize); |
727 | + |
728 | +private: |
729 | + QList<MockNotification*> m_queue; |
730 | + void removeInternal(int loc); |
731 | +}; |
732 | + |
733 | +#endif |
734 | |
735 | === modified file 'tests/mocks/Unity/Notifications/plugin.cpp' |
736 | --- tests/mocks/Unity/Notifications/plugin.cpp 2014-10-23 22:01:57 +0000 |
737 | +++ tests/mocks/Unity/Notifications/plugin.cpp 2015-02-06 15:16:01 +0000 |
738 | @@ -1,5 +1,5 @@ |
739 | /* |
740 | - * Copyright 2014 Canonical Ltd. |
741 | + * Copyright 2015 Canonical Ltd. |
742 | * |
743 | * This program is free software; you can redistribute it and/or modify |
744 | * it under the terms of the GNU Lesser General Public License as published by |
745 | @@ -19,13 +19,15 @@ |
746 | |
747 | #include "plugin.h" |
748 | #include "MockActionModel.h" |
749 | -#include "MockNotificationTypes.h" |
750 | +#include "MockNotification.h" |
751 | +#include "MockNotificationModel.h" |
752 | |
753 | #include <QtQml/qqml.h> |
754 | |
755 | void TestNotificationPlugin::registerTypes(const char* uri) |
756 | { |
757 | // @uri Unity.Notifications |
758 | - qmlRegisterUncreatableType<MockNotification>(uri, 1, 0, "Notification", "Notification objects can only be created by the plugin"); |
759 | + qmlRegisterType<MockNotification>(uri, 1, 0, "Notification"); |
760 | + qmlRegisterType<MockNotificationModel>(uri, 1, 0, "NotificationModel"); |
761 | qmlRegisterType<ActionModel>(uri, 1, 0, "ActionModel"); |
762 | } |
763 | |
764 | === modified file 'tests/mocks/Unity/Notifications/plugin.h' |
765 | --- tests/mocks/Unity/Notifications/plugin.h 2014-10-23 22:01:57 +0000 |
766 | +++ tests/mocks/Unity/Notifications/plugin.h 2015-02-06 15:16:01 +0000 |
767 | @@ -1,5 +1,5 @@ |
768 | /* |
769 | - * Copyright 2014 Canonical Ltd. |
770 | + * Copyright 2015 Canonical Ltd. |
771 | * |
772 | * This program is free software; you can redistribute it and/or modify |
773 | * it under the terms of the GNU Lesser General Public License as published by |
774 | @@ -17,7 +17,6 @@ |
775 | * Mirco Mueller <mirco.mueller@canonical.com> |
776 | */ |
777 | |
778 | - |
779 | #ifndef TESTNOTIFICATION_PLUGIN_H |
780 | #define TESTNOTIFICATION_PLUGIN_H |
781 | |
782 | |
783 | === added file 'tests/qmltests/Notifications/Notification.qml' |
784 | --- tests/qmltests/Notifications/Notification.qml 1970-01-01 00:00:00 +0000 |
785 | +++ tests/qmltests/Notifications/Notification.qml 2015-02-06 15:16:01 +0000 |
786 | @@ -0,0 +1,31 @@ |
787 | +/* |
788 | + * Copyright 2015 Canonical Ltd. |
789 | + * |
790 | + * This program is free software; you can redistribute it and/or modify |
791 | + * it under the terms of the GNU Lesser General Public License as published by |
792 | + * the Free Software Foundation; version 3. |
793 | + * |
794 | + * This program is distributed in the hope that it will be useful, |
795 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
796 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
797 | + * GNU Lesser General Public License for more details. |
798 | + * |
799 | + * You should have received a copy of the GNU Lesser General Public License |
800 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
801 | + * |
802 | + * Authors: |
803 | + * Mirco Mueller <mirco.mueller@canonical.com> |
804 | + */ |
805 | + |
806 | +import Unity.Notifications 1.0 |
807 | + |
808 | +Notification { |
809 | + nid: 0 |
810 | + type: Notification.PlaceHolder |
811 | + summary: "" |
812 | + body: "" |
813 | + icon: "" |
814 | + secondaryIcon: "" |
815 | + value: 0 |
816 | + rawActions: [] |
817 | +} |
818 | |
819 | === modified file 'tests/qmltests/Notifications/tst_Notifications.qml' |
820 | --- tests/qmltests/Notifications/tst_Notifications.qml 2015-01-09 09:15:45 +0000 |
821 | +++ tests/qmltests/Notifications/tst_Notifications.qml 2015-02-06 15:16:01 +0000 |
822 | @@ -1,17 +1,20 @@ |
823 | /* |
824 | - * Copyright (C) 2013 Canonical, Ltd. |
825 | + * Copyright 2015 Canonical Ltd. |
826 | * |
827 | * This program is free software; you can redistribute it and/or modify |
828 | - * it under the terms of the GNU General Public License as published by |
829 | + * it under the terms of the GNU Lesser General Public License as published by |
830 | * the Free Software Foundation; version 3. |
831 | * |
832 | * This program is distributed in the hope that it will be useful, |
833 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
834 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
835 | - * GNU General Public License for more details. |
836 | + * GNU Lesser General Public License for more details. |
837 | * |
838 | - * You should have received a copy of the GNU General Public License |
839 | + * You should have received a copy of the GNU Lesser General Public License |
840 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
841 | + * |
842 | + * Authors: |
843 | + * Mirco Mueller <mirco.mueller@canonical.com> |
844 | */ |
845 | |
846 | import QtQuick 2.0 |
847 | @@ -24,146 +27,134 @@ |
848 | import QtMultimedia 5.0 |
849 | |
850 | Item { |
851 | + id: foobar |
852 | + |
853 | width: notificationsRect.width + interactiveControls.width |
854 | height: notificationsRect.height |
855 | + property int index: 0 |
856 | |
857 | Row { |
858 | id: rootRow |
859 | |
860 | - Component { |
861 | - id: mockNotification |
862 | - |
863 | - QtObject { |
864 | - function invokeAction(actionId) { |
865 | - mockModel.actionInvoked(actionId) |
866 | - } |
867 | - } |
868 | - } |
869 | - |
870 | - ListModel { |
871 | + NotificationModel { |
872 | id: mockModel |
873 | - dynamicRoles: true |
874 | - |
875 | - signal actionInvoked(string actionId) |
876 | - |
877 | - function getRaw(id) { |
878 | - return mockNotification.createObject(mockModel) |
879 | - } |
880 | |
881 | // add the default/PlaceHolder notification to the model |
882 | Component.onCompleted: { |
883 | - var n = { |
884 | - type: Notification.PlaceHolder, |
885 | - hints: {}, |
886 | - summary: "", |
887 | - body: "", |
888 | - icon: "", |
889 | - secondaryIcon: "", |
890 | - actions: [] |
891 | - } |
892 | - |
893 | + var component = Qt.createComponent("Notification.qml") |
894 | + var n = component.createObject("notification", {"nid": index++, |
895 | + "type": Notification.PlaceHolder, |
896 | + "hints": {}, |
897 | + "summary": "", |
898 | + "body": "", |
899 | + "icon": "", |
900 | + "secondaryIcon": "", |
901 | + "rawActions": []}) |
902 | + n.completed.connect(mockModel.onCompleted) |
903 | append(n) |
904 | } |
905 | } |
906 | |
907 | function add2over1SnapDecisionNotification() { |
908 | - var n = { |
909 | - type: Notification.SnapDecision, |
910 | - hints: {"x-canonical-private-affirmative-tint": "true"}, |
911 | - summary: "Theatre at Ferria Stadium", |
912 | - body: "at Ferria Stadium in Bilbao, Spain\n07578545317", |
913 | - icon: "", |
914 | - secondaryIcon: "", |
915 | - actions: [{ id: "ok_id", label: "Ok"}, |
916 | - { id: "snooze_id", label: "Snooze"}, |
917 | - { id: "view_id", label: "View"}] |
918 | - } |
919 | - |
920 | + var component = Qt.createComponent("Notification.qml") |
921 | + var n = component.createObject("notification", {"nid": index++, |
922 | + "type": Notification.SnapDecision, |
923 | + "hints": {"x-canonical-private-affirmative-tint": "true"}, |
924 | + "summary": "Theatre at Ferria Stadium", |
925 | + "body": "at Ferria Stadium in Bilbao, Spain\n07578545317", |
926 | + "icon": "", |
927 | + "secondaryIcon": "", |
928 | + "rawActions": ["ok_id", "Ok", |
929 | + "snooze_id", "Snooze", |
930 | + "view_id", "View"]}) |
931 | + n.completed.connect(mockModel.onCompleted) |
932 | mockModel.append(n) |
933 | } |
934 | |
935 | function addEphemeralNotification() { |
936 | - var n = { |
937 | - type: Notification.Ephemeral, |
938 | - summary: "Cole Raby", |
939 | - body: "I did not expect it to be that late.", |
940 | - icon: "../graphics/avatars/amanda.png", |
941 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
942 | - actions: [] |
943 | - } |
944 | - |
945 | + var component = Qt.createComponent("Notification.qml") |
946 | + var n = component.createObject("notification", {"nid": index++, |
947 | + "type": Notification.Ephemeral, |
948 | + "hints": {}, |
949 | + "summary": "Cole Raby", |
950 | + "body": "I did not expect it to be that late.", |
951 | + "icon": "../graphics/avatars/amanda.png", |
952 | + "secondaryIcon": "../graphics/applicationIcons/facebook.png", |
953 | + "rawActions": ["reply_id", "Dummy"]}) |
954 | + n.completed.connect(mockModel.onCompleted) |
955 | mockModel.append(n) |
956 | } |
957 | |
958 | function addEphemeralNonShapedIconNotification() { |
959 | - var n = { |
960 | - type: Notification.Ephemeral, |
961 | - hints: {"x-canonical-non-shaped-icon": "true"}, |
962 | - summary: "Contacts", |
963 | - body: "Synchronised contacts-database with cloud-storage.", |
964 | - icon: "../graphics/applicationIcons/contacts-app.png", |
965 | - secondaryIcon: "", |
966 | - actions: [] |
967 | - } |
968 | - |
969 | + var component = Qt.createComponent("Notification.qml") |
970 | + var n = component.createObject("notification", {"nid": index++, |
971 | + "type": Notification.Ephemeral, |
972 | + "hints": {"x-canonical-non-shaped-icon": "true"}, |
973 | + "summary": "Contacts", |
974 | + "body": "Synchronised contacts-database with cloud-storage.", |
975 | + "icon": "../graphics/applicationIcons/contacts-app.png", |
976 | + "secondaryIcon": "", |
977 | + "rawActions": ["reply_id", "Dummy"]}) |
978 | + n.completed.connect(mockModel.onCompleted) |
979 | mockModel.append(n) |
980 | } |
981 | |
982 | function addEphemeralIconSummaryNotification() { |
983 | - var n = { |
984 | - type: Notification.Ephemeral, |
985 | - hints: {"x-canonical-non-shaped-icon": "false"}, |
986 | - summary: "Photo upload completed", |
987 | - body: "", |
988 | - icon: "../graphics/applicationIcons/facebook.png", |
989 | - secondaryIcon: "", |
990 | - actions: [] |
991 | - } |
992 | - |
993 | + var component = Qt.createComponent("Notification.qml") |
994 | + var n = component.createObject("notification", {"nid": index++, |
995 | + "type": Notification.Ephemeral, |
996 | + "hints": {"x-canonical-non-shaped-icon": "false"}, |
997 | + "summary": "Photo upload completed", |
998 | + "body": "", |
999 | + "icon": "../graphics/applicationIcons/facebook.png", |
1000 | + "secondaryIcon": "", |
1001 | + "rawActions": ["reply_id", "Dummy"]}) |
1002 | + n.completed.connect(mockModel.onCompleted) |
1003 | mockModel.append(n) |
1004 | } |
1005 | |
1006 | function addInteractiveNotification() { |
1007 | - var n = { |
1008 | - type: Notification.Interactive, |
1009 | - summary: "Interactive notification", |
1010 | - body: "This is a notification that can be clicked", |
1011 | - icon: "../graphics/avatars/anna_olsson.png", |
1012 | - secondaryIcon: "", |
1013 | - actions: [{ id: "reply_id", label: "Dummy"}], |
1014 | - } |
1015 | - |
1016 | + var component = Qt.createComponent("Notification.qml") |
1017 | + var n = component.createObject("notification", {"nid": index++, |
1018 | + "type": Notification.Interactive, |
1019 | + "hints": {}, |
1020 | + "summary": "Interactive notification", |
1021 | + "body": "This is a notification that can be clicked", |
1022 | + "icon": "../graphics/avatars/anna_olsson.png", |
1023 | + "secondaryIcon": "", |
1024 | + "rawActions": ["reply_id", "Dummy"]}) |
1025 | + n.completed.connect(mockModel.onCompleted) |
1026 | mockModel.append(n) |
1027 | } |
1028 | |
1029 | function addConfirmationNotification() { |
1030 | - var n = { |
1031 | - type: Notification.Confirmation, |
1032 | - hints: {"x-canonical-non-shaped-icon": "true"}, |
1033 | - summary: "Confirmation notification", |
1034 | - body: "", |
1035 | - icon: "image://theme/audio-volume-medium", |
1036 | - secondaryIcon: "", |
1037 | - value: 50, |
1038 | - actions: [], |
1039 | - } |
1040 | - |
1041 | + var component = Qt.createComponent("Notification.qml") |
1042 | + var n = component.createObject("notification", {"nid": index++, |
1043 | + "type": Notification.Confirmation, |
1044 | + "hints": {"x-canonical-non-shaped-icon": "true"}, |
1045 | + "summary": "Confirmation notification", |
1046 | + "body": "", |
1047 | + "icon": "image://theme/audio-volume-medium", |
1048 | + "secondaryIcon": "", |
1049 | + "value": 50, |
1050 | + "rawActions": ["reply_id", "Dummy"]}) |
1051 | + n.completed.connect(mockModel.onCompleted) |
1052 | mockModel.append(n) |
1053 | } |
1054 | |
1055 | function add2ndConfirmationNotification() { |
1056 | - var n = { |
1057 | - type: Notification.Confirmation, |
1058 | - hints: {"x-canonical-non-shaped-icon": "true", |
1059 | - "x-canonical-value-bar-tint": "true"}, |
1060 | - summary: "Confirmation notification", |
1061 | - body: "High Volume", |
1062 | - icon: "image://theme/audio-volume-high", |
1063 | - secondaryIcon: "", |
1064 | - value: 85, |
1065 | - actions: [], |
1066 | - } |
1067 | - |
1068 | + var component = Qt.createComponent("Notification.qml") |
1069 | + var n = component.createObject("notification", {"nid": index++, |
1070 | + "type": Notification.Confirmation, |
1071 | + "hints": {"x-canonical-non-shaped-icon": "true", |
1072 | + "x-canonical-value-bar-tint": "true"}, |
1073 | + "summary": "Confirmation notification", |
1074 | + "body": "High Volume", |
1075 | + "icon": "image://theme/audio-volume-high", |
1076 | + "secondaryIcon": "", |
1077 | + "value": 85, |
1078 | + "rawActions": ["reply_id", "Dummy"]}) |
1079 | + n.completed.connect(mockModel.onCompleted) |
1080 | mockModel.append(n) |
1081 | } |
1082 | |
1083 | @@ -174,8 +165,9 @@ |
1084 | } |
1085 | |
1086 | function remove1stNotification() { |
1087 | - if (mockModel.count > 1) |
1088 | - mockModel.remove(1) |
1089 | + if (mockModel.count > 1) { |
1090 | + mockModel.removeSecond() |
1091 | + } |
1092 | } |
1093 | |
1094 | Rectangle { |
1095 | @@ -273,41 +265,122 @@ |
1096 | name: "NotificationRendererTest" |
1097 | when: windowShown |
1098 | |
1099 | + property list<Notification> nlist: [ |
1100 | + Notification { |
1101 | + nid: 1 |
1102 | + type: Notification.Ephemeral |
1103 | + summary: "Photo upload completed" |
1104 | + body: "" |
1105 | + icon: "../graphics/applicationIcons/facebook.png" |
1106 | + secondaryIcon: "" |
1107 | + value: 0 |
1108 | + rawActions: [] |
1109 | + }, |
1110 | + Notification { |
1111 | + nid: 2 |
1112 | + type: Notification.Ephemeral |
1113 | + hints: {"x-canonical-private-affirmative-tint": "false", |
1114 | + "sound-file": "dummy.ogg", |
1115 | + "suppress-sound": "true"} |
1116 | + summary: "New comment successfully published" |
1117 | + body: "" |
1118 | + icon: "" |
1119 | + secondaryIcon: "../graphics/applicationIcons/facebook.png" |
1120 | + value: 0 |
1121 | + rawActions: [] |
1122 | + }, |
1123 | + Notification { |
1124 | + nid: 3 |
1125 | + type: Notification.Interactive |
1126 | + hints: {"x-canonical-private-affirmative-tint": "false", |
1127 | + "sound-file": "dummy.ogg"} |
1128 | + summary: "Interactive notification" |
1129 | + body: "This is a notification that can be clicked" |
1130 | + icon: "../graphics/avatars/amanda.png" |
1131 | + secondaryIcon: "" |
1132 | + value: 0 |
1133 | + rawActions: ["reply_id", "Dummy"] |
1134 | + }, |
1135 | + Notification { |
1136 | + nid: 4 |
1137 | + type: Notification.SnapDecision |
1138 | + hints: {"x-canonical-private-affirmative-tint": "false", |
1139 | + "sound-file": "dummy.ogg"} |
1140 | + summary: "Bro Coly" |
1141 | + body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet." |
1142 | + icon: "../graphics/avatars/anna_olsson.png" |
1143 | + secondaryIcon: "" |
1144 | + value: 0 |
1145 | + rawActions: ["accept_id", "Accept", |
1146 | + "reject_id", "Reject"] |
1147 | + }, |
1148 | + Notification { |
1149 | + nid: 5 |
1150 | + type: Notification.Ephemeral |
1151 | + hints: {"x-canonical-private-affirmative-tint": "false", |
1152 | + "sound-file": "dummy.ogg"} |
1153 | + summary: "Cole Raby" |
1154 | + body: "I did not expect it to be that late." |
1155 | + icon: "../graphics/avatars/funky.png" |
1156 | + secondaryIcon: "../graphics/applicationIcons/facebook.png" |
1157 | + value: 0 |
1158 | + rawActions: [] |
1159 | + }, |
1160 | + Notification { |
1161 | + nid: 6 |
1162 | + type: Notification.Ephemeral |
1163 | + hints: {"x-canonical-private-affirmative-tint": "false", |
1164 | + "x-canonical-non-shaped-icon": "true"} |
1165 | + summary: "Contacts" |
1166 | + body: "Synchronised contacts-database with cloud-storage." |
1167 | + icon: "image://theme/contacts-app" |
1168 | + secondaryIcon: "" |
1169 | + value: 0 |
1170 | + rawActions: [] |
1171 | + }, |
1172 | + Notification { |
1173 | + nid: 7 |
1174 | + type: Notification.Confirmation |
1175 | + hints: {"x-canonical-non-shaped-icon": "true"} |
1176 | + summary: "" |
1177 | + body: "" |
1178 | + icon: "image://theme/audio-volume-medium" |
1179 | + secondaryIcon: "" |
1180 | + value: 50 |
1181 | + rawActions: [] |
1182 | + }, |
1183 | + Notification { |
1184 | + nid: 8 |
1185 | + type: Notification.Confirmation |
1186 | + hints: {"x-canonical-non-shaped-icon": "true", |
1187 | + "x-canonical-value-bar-tint" : "true"} |
1188 | + summary: "" |
1189 | + body: "High Volume" |
1190 | + icon: "image://theme/audio-volume-high" |
1191 | + secondaryIcon: "" |
1192 | + value: 85 |
1193 | + rawActions: [] |
1194 | + }, |
1195 | + Notification { |
1196 | + nid: 9 |
1197 | + type: Notification.SnapDecision |
1198 | + hints: {"x-canonical-private-affirmative-tint": "true"} |
1199 | + summary: "Theatre at Ferria Stadium" |
1200 | + body: "at Ferria Stadium in Bilbao, Spain\n07578545317" |
1201 | + icon: "" |
1202 | + secondaryIcon: "" |
1203 | + value: 0 |
1204 | + rawActions: ["ok_id", "Ok", |
1205 | + "snooze_id", "Snooze", |
1206 | + "view_id", "View"] |
1207 | + } |
1208 | + ] |
1209 | + |
1210 | function test_NotificationRenderer_data() { |
1211 | return [ |
1212 | { |
1213 | - tag: "2-over-1 Snap Decision with button-tint", |
1214 | - type: Notification.SnapDecision, |
1215 | - hints: {"x-canonical-private-affirmative-tint": "true"}, |
1216 | - summary: "Theatre at Ferria Stadium", |
1217 | - body: "at Ferria Stadium in Bilbao, Spain\n07578545317", |
1218 | - icon: "", |
1219 | - secondaryIcon: "", |
1220 | - actions: [{ id: "ok_id", label: "Ok"}, |
1221 | - { id: "snooze_id", label: "Snooze"}, |
1222 | - { id: "view_id", label: "View"}], |
1223 | - summaryVisible: true, |
1224 | - bodyVisible: true, |
1225 | - iconVisible: false, |
1226 | - centeredIconVisible: false, |
1227 | - shaped: false, |
1228 | - secondaryIconVisible: false, |
1229 | - buttonRowVisible: false, |
1230 | - buttonTinted: true, |
1231 | - hasSound: false, |
1232 | - valueVisible: false, |
1233 | - valueLabelVisible: false, |
1234 | - valueTinted: false |
1235 | - }, |
1236 | - { |
1237 | tag: "Ephemeral notification - icon-summary layout", |
1238 | - type: Notification.Ephemeral, |
1239 | - hints: {}, |
1240 | - summary: "Photo upload completed", |
1241 | - body: "", |
1242 | - icon: "../graphics/applicationIcons/facebook.png", |
1243 | - secondaryIcon: "", |
1244 | - actions: [], |
1245 | + n: nlist[0], |
1246 | summaryVisible: true, |
1247 | bodyVisible: false, |
1248 | iconVisible: true, |
1249 | @@ -323,15 +396,7 @@ |
1250 | }, |
1251 | { |
1252 | tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout", |
1253 | - type: Notification.Ephemeral, |
1254 | - hints: {"x-canonical-private-affirmative-tint": "false", |
1255 | - "sound-file": "dummy.ogg", |
1256 | - "suppress-sound": "true"}, |
1257 | - summary: "New comment successfully published", |
1258 | - body: "", |
1259 | - icon: "", |
1260 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
1261 | - actions: [], |
1262 | + n: nlist[1], |
1263 | summaryVisible: true, |
1264 | bodyVisible: false, |
1265 | interactiveAreaEnabled: false, |
1266 | @@ -348,14 +413,7 @@ |
1267 | }, |
1268 | { |
1269 | tag: "Interactive notification", |
1270 | - type: Notification.Interactive, |
1271 | - hints: {"x-canonical-private-affirmative-tint": "false", |
1272 | - "sound-file": "dummy.ogg"}, |
1273 | - summary: "Interactive notification", |
1274 | - body: "This is a notification that can be clicked", |
1275 | - icon: "../graphics/avatars/amanda.png", |
1276 | - secondaryIcon: "", |
1277 | - actions: [{ id: "reply_id", label: "Dummy"}], |
1278 | + n: nlist[2], |
1279 | summaryVisible: true, |
1280 | bodyVisible: true, |
1281 | iconVisible: true, |
1282 | @@ -371,15 +429,7 @@ |
1283 | }, |
1284 | { |
1285 | tag: "Snap Decision without secondary icon and no button-tint", |
1286 | - type: Notification.SnapDecision, |
1287 | - hints: {"x-canonical-private-affirmative-tint": "false", |
1288 | - "sound-file": "dummy.ogg"}, |
1289 | - summary: "Bro Coly", |
1290 | - body: "At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.", |
1291 | - icon: "../graphics/avatars/anna_olsson.png", |
1292 | - secondaryIcon: "", |
1293 | - actions: [{ id: "accept_id", label: "Accept"}, |
1294 | - { id: "reject_id", label: "Reject"}], |
1295 | + n: nlist[3], |
1296 | summaryVisible: true, |
1297 | bodyVisible: true, |
1298 | iconVisible: true, |
1299 | @@ -395,14 +445,7 @@ |
1300 | }, |
1301 | { |
1302 | tag: "Ephemeral notification", |
1303 | - type: Notification.Ephemeral, |
1304 | - hints: {"x-canonical-private-affirmative-tint": "false", |
1305 | - "sound-file": "dummy.ogg"}, |
1306 | - summary: "Cole Raby", |
1307 | - body: "I did not expect it to be that late.", |
1308 | - icon: "../graphics/avatars/funky.png", |
1309 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
1310 | - actions: [], |
1311 | + n: nlist[4], |
1312 | summaryVisible: true, |
1313 | bodyVisible: true, |
1314 | iconVisible: true, |
1315 | @@ -418,14 +461,7 @@ |
1316 | }, |
1317 | { |
1318 | tag: "Ephemeral notification with non-shaped icon", |
1319 | - type: Notification.Ephemeral, |
1320 | - hints: {"x-canonical-private-affirmative-tint": "false", |
1321 | - "x-canonical-non-shaped-icon": "true"}, |
1322 | - summary: "Contacts", |
1323 | - body: "Synchronised contacts-database with cloud-storage.", |
1324 | - icon: "image://theme/contacts-app", |
1325 | - secondaryIcon: "", |
1326 | - actions: [], |
1327 | + n: nlist[5], |
1328 | summaryVisible: true, |
1329 | bodyVisible: true, |
1330 | iconVisible: true, |
1331 | @@ -441,14 +477,7 @@ |
1332 | }, |
1333 | { |
1334 | tag: "Confirmation notification with value", |
1335 | - type: Notification.Confirmation, |
1336 | - hints: {"x-canonical-non-shaped-icon": "true"}, |
1337 | - summary: "", |
1338 | - body: "", |
1339 | - icon: "image://theme/audio-volume-medium", |
1340 | - secondaryIcon: "", |
1341 | - value: 50, |
1342 | - actions: [], |
1343 | + n: nlist[6], |
1344 | summaryVisible: false, |
1345 | bodyVisible: false, |
1346 | iconVisible: false, |
1347 | @@ -464,15 +493,7 @@ |
1348 | }, |
1349 | { |
1350 | tag: "Confirmation notification with value, label and tint", |
1351 | - type: Notification.Confirmation, |
1352 | - hints: {"x-canonical-non-shaped-icon": "true", |
1353 | - "x-canonical-value-bar-tint" : "true"}, |
1354 | - summary: "", |
1355 | - body: "High Volume", |
1356 | - icon: "image://theme/audio-volume-high", |
1357 | - secondaryIcon: "", |
1358 | - value: 85, |
1359 | - actions: [], |
1360 | + n: nlist[7], |
1361 | summaryVisible: false, |
1362 | bodyVisible: false, |
1363 | iconVisible: false, |
1364 | @@ -485,6 +506,22 @@ |
1365 | valueVisible: true, |
1366 | valueLabelVisible: true, |
1367 | valueTinted: true |
1368 | + }, |
1369 | + { |
1370 | + tag: "2-over-1 Snap Decision with button-tint", |
1371 | + n: nlist[8], |
1372 | + summaryVisible: true, |
1373 | + bodyVisible: true, |
1374 | + iconVisible: false, |
1375 | + centeredIconVisible: false, |
1376 | + shaped: false, |
1377 | + secondaryIconVisible: false, |
1378 | + buttonRowVisible: false, |
1379 | + buttonTinted: true, |
1380 | + hasSound: false, |
1381 | + valueVisible: false, |
1382 | + valueLabelVisible: false, |
1383 | + valueTinted: false |
1384 | } |
1385 | ] |
1386 | } |
1387 | @@ -509,8 +546,14 @@ |
1388 | } |
1389 | |
1390 | function test_NotificationRenderer(data) { |
1391 | + // make sure the clicks on mocked notifications can be checked against by "actionSpy" (mimicking the NotificationServer component) |
1392 | + data.n.actionInvoked.connect(mockModel.actionInvoked) |
1393 | + |
1394 | + // hook up notification's completed-signal with model's onCompleted-slot, so that remove() (model) happens on close() (notification) |
1395 | + data.n.completed.connect(mockModel.onCompleted) |
1396 | + |
1397 | // populate model with some mock notifications |
1398 | - mockModel.append(data) |
1399 | + mockModel.append(data.n) |
1400 | |
1401 | // make sure the view is properly updated before going on |
1402 | notifications.forceLayout(); |
1403 | @@ -548,9 +591,9 @@ |
1404 | |
1405 | // test input does not fall through |
1406 | mouseClick(notification) |
1407 | - if(data.type == Notification.Interactive) { |
1408 | + if(data.n.type === Notification.Interactive) { |
1409 | actionSpy.wait() |
1410 | - compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action") |
1411 | + compare(actionSpy.signalArguments[0][0], data.n.actions.data(0, ActionModel.RoleActionId), "got wrong id for interactive action") |
1412 | } |
1413 | compare(clickThroughSpy.count, 0, "click on notification fell through") |
1414 | |
1415 | @@ -559,17 +602,19 @@ |
1416 | compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect") |
1417 | compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect") |
1418 | |
1419 | - var audioItem = findInvisibleChild(notification, "sound") |
1420 | - compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state") |
1421 | + if (data.hasSound) { |
1422 | + var audioItem = findInvisibleChild(notification, "sound") |
1423 | + compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state") |
1424 | + } |
1425 | |
1426 | if(data.buttonRowVisible) { |
1427 | var buttonCancel = findChild(buttonRow, "notify_button1") |
1428 | var buttonAccept = findChild(buttonRow, "notify_button0") |
1429 | |
1430 | // only test the left/cancel-button if two actions have been passed in |
1431 | - if (data.actions.length == 2) { |
1432 | + if (data.n.actions.count === 2) { |
1433 | tryCompareFunction(function() { mouseClick(buttonCancel); return actionSpy.signalArguments.length > 0; }, true); |
1434 | - compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action") |
1435 | + compare(actionSpy.signalArguments[0][0], data.n.actions.data(1, ActionModel.RoleActionId), "got wrong id for negative action") |
1436 | actionSpy.clear() |
1437 | } |
1438 | |
1439 | @@ -578,36 +623,49 @@ |
1440 | |
1441 | // click the positive/right button |
1442 | tryCompareFunction(function() { mouseClick(buttonAccept); return actionSpy.signalArguments.length > 0; }, true); |
1443 | - compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action") |
1444 | + compare(actionSpy.signalArguments[0][0], data.n.actions.data(0, ActionModel.RoleActionId), "got wrong id positive action") |
1445 | actionSpy.clear() |
1446 | - waitForRendering (notification) |
1447 | |
1448 | // check if there's a ComboButton created due to more actions being passed |
1449 | - if (data.actions.length > 2) { |
1450 | + if (data.n.actions.count > 3) { |
1451 | var comboButton = findChild(notification, "notify_button2") |
1452 | - tryCompareFunction(function() { return comboButton.expanded == false; }, true); |
1453 | + tryCompareFunction(function() { return comboButton.expanded === false; }, true); |
1454 | |
1455 | // click to expand |
1456 | - tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true); |
1457 | + tryCompareFunction(function() { mouseClick(comboButton, comboButton.width / 2, comboButton.height / 2); return comboButton.expanded === true; }, true); |
1458 | |
1459 | // try clicking on choices in expanded comboList |
1460 | var choiceButton1 = findChild(notification, "notify_button3") |
1461 | tryCompareFunction(function() { mouseClick(choiceButton1); return actionSpy.signalArguments.length > 0; }, true); |
1462 | - compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1") |
1463 | + compare(actionSpy.signalArguments[0][0], data.n.actions.data(3, ActionModel.RoleActionId), "got wrong id choice action 1") |
1464 | actionSpy.clear() |
1465 | |
1466 | var choiceButton2 = findChild(notification, "notify_button4") |
1467 | tryCompareFunction(function() { mouseClick(choiceButton2); return actionSpy.signalArguments.length > 0; }, true); |
1468 | - compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2") |
1469 | + compare(actionSpy.signalArguments[0][0], data.n.actions.data(4, ActionModel.RoleActionId), "got wrong id choice action 2") |
1470 | actionSpy.clear() |
1471 | |
1472 | // click to collapse |
1473 | - //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true); |
1474 | + tryCompareFunction(function() { mouseClick(comboButton, comboButton.width / 2, comboButton.height / 2); return comboButton.expanded == false; }, true); |
1475 | } else { |
1476 | mouseClick(buttonCancel) |
1477 | - compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action") |
1478 | + compare(actionSpy.signalArguments[0][0], data.n.actions.data(1, ActionModel.RoleActionId), "got wrong id for negative action") |
1479 | } |
1480 | } |
1481 | + |
1482 | + // swipe-to-dismiss check |
1483 | + waitForRendering(notification) |
1484 | + var before = mockModel.count |
1485 | + var dragStart = notification.width * 0.25; |
1486 | + var dragEnd = notification.width; |
1487 | + var dragY = notification.height / 2; |
1488 | + touchFlick(notification, dragStart, dragY, dragEnd, dragY) |
1489 | + waitForRendering(notification) |
1490 | + if ((data.n.type === Notification.SnapDecision && notification.state === "expanded") || data.n.type === Notification.Confirmation) { |
1491 | + tryCompare(mockModel, "count", before) |
1492 | + } else { |
1493 | + tryCompare(mockModel, "count", before - 1) |
1494 | + } |
1495 | } |
1496 | } |
1497 | } |
1498 | |
1499 | === modified file 'tests/qmltests/Notifications/tst_OptionToggle.qml' |
1500 | --- tests/qmltests/Notifications/tst_OptionToggle.qml 2015-01-09 09:15:45 +0000 |
1501 | +++ tests/qmltests/Notifications/tst_OptionToggle.qml 2015-02-06 15:16:01 +0000 |
1502 | @@ -1,17 +1,20 @@ |
1503 | /* |
1504 | - * Copyright (C) 2014 Canonical, Ltd. |
1505 | + * Copyright 2015 Canonical Ltd. |
1506 | * |
1507 | * This program is free software; you can redistribute it and/or modify |
1508 | - * it under the terms of the GNU General Public License as published by |
1509 | + * it under the terms of the GNU Lesser General Public License as published by |
1510 | * the Free Software Foundation; version 3. |
1511 | * |
1512 | * This program is distributed in the hope that it will be useful, |
1513 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1514 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1515 | - * GNU General Public License for more details. |
1516 | + * GNU Lesser General Public License for more details. |
1517 | * |
1518 | - * You should have received a copy of the GNU General Public License |
1519 | + * You should have received a copy of the GNU Lesser General Public License |
1520 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1521 | + * |
1522 | + * Authors: |
1523 | + * Mirco Mueller <mirco.mueller@canonical.com> |
1524 | */ |
1525 | |
1526 | import QtQuick 2.0 |
1527 | @@ -235,8 +238,10 @@ |
1528 | compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect") |
1529 | compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect") |
1530 | |
1531 | - var audioItem = findInvisibleChild(notification, "sound") |
1532 | - compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state") |
1533 | + if (data.hasSound) { |
1534 | + var audioItem = findInvisibleChild(notification, "sound") |
1535 | + compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state") |
1536 | + } |
1537 | |
1538 | if(data.buttonRowVisible) { |
1539 | var buttonCancel = findChild(buttonRow, "notify_button1") |
1540 | |
1541 | === modified file 'tests/qmltests/Notifications/tst_SwipeToAct.qml' |
1542 | --- tests/qmltests/Notifications/tst_SwipeToAct.qml 2015-01-09 09:15:45 +0000 |
1543 | +++ tests/qmltests/Notifications/tst_SwipeToAct.qml 2015-02-06 15:16:01 +0000 |
1544 | @@ -218,6 +218,10 @@ |
1545 | // populate model with some mock notifications |
1546 | mockModel.append(data) |
1547 | |
1548 | + // add actions to action-model to test against |
1549 | + myActionModel.append("ok_id", "Ok") |
1550 | + myActionModel.append("cancel_id", "Cancel") |
1551 | + |
1552 | // make sure the view is properly updated before going on |
1553 | notifications.forceLayout(); |
1554 | waitForRendering(notifications); |
FAILED: Continuous integration, rev:1089 /code.launchpad .net/~macslow/ unity8/ swipe-dismiss- snap-decisions/ +merge/ 233347/ +edit-commit- message
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https:/
http:// jenkins. qa.ubuntu. com/job/ unity8- ci/4230/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- utopic- touch/4444 jenkins. qa.ubuntu. com/job/ unity-phablet- qmluitests- utopic/ 1231 jenkins. qa.ubuntu. com/job/ unity8- utopic- amd64-ci/ 1324 jenkins. qa.ubuntu. com/job/ unity8- utopic- i386-ci/ 1324 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- mako/4219 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5696 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- utopic- armhf/5696/ artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 12647
Executed test runs:
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/unity8- ci/4230/ rebuild
http://