Merge lp:~unity-team/unity8/rtm-14.09-staging into lp:unity8/rtm-14.09
- rtm-14.09-staging
- Merge into rtm-14.09
Status: | Merged |
---|---|
Approved by: | kevin gunn |
Approved revision: | no longer in the source branch. |
Merged at revision: | 1397 |
Proposed branch: | lp:~unity-team/unity8/rtm-14.09-staging |
Merge into: | lp:unity8/rtm-14.09 |
Diff against target: |
4113 lines (+2365/-788) 51 files modified
debian/changelog (+37/-0) debian/unity8-private.install (+1/-0) libs/UbuntuGestures/DebugHelpers.cpp (+1/-1) plugins/CMakeLists.txt (+1/-0) plugins/ScreenGrabber/CMakeLists.txt (+13/-0) plugins/ScreenGrabber/ScreenGrabber.qmltypes (+17/-0) plugins/ScreenGrabber/plugin.cpp (+28/-0) plugins/ScreenGrabber/plugin.h (+33/-0) plugins/ScreenGrabber/qmldir (+3/-0) plugins/ScreenGrabber/screengrabber.cpp (+94/-0) plugins/ScreenGrabber/screengrabber.h (+42/-0) plugins/Ubuntu/Gestures/TouchDispatcher.cpp (+43/-0) plugins/Ubuntu/Gestures/TouchDispatcher.h (+3/-0) plugins/Unity/Launcher/dbusinterface.cpp (+2/-2) plugins/Unity/Launcher/desktopfilehandler.cpp (+2/-0) po/unity8.pot (+51/-47) po/update-unity-pot (+1/-0) qml/Components/Dialogs.qml (+1/-1) qml/Components/ScreenGrabber.qml (+72/-0) qml/Components/VolumeKeyFilter.qml (+63/-0) qml/Greeter/Greeter.qml (+1/-1) qml/Greeter/Infographics.qml (+20/-15) qml/Notifications/Notification.qml (+22/-3) qml/Notifications/SwipeToAct.qml (+309/-0) qml/Panel/IndicatorPage.qml (+12/-1) qml/Panel/Indicators/MenuItemFactory.qml (+36/-8) qml/Shell.qml (+15/-5) tests/autopilot/unity8/shell/tests/test_notifications.py (+0/-51) tests/mocks/QtMultimedia/QtMultimedia.qmltypes (+10/-0) tests/mocks/QtMultimedia/audio.cpp (+10/-0) tests/mocks/QtMultimedia/audio.h (+12/-0) tests/mocks/Unity/Notifications/CMakeLists.txt (+15/-1) tests/mocks/Unity/Notifications/MockActionModel.cpp (+72/-0) tests/mocks/Unity/Notifications/MockActionModel.h (+51/-0) tests/mocks/Unity/Notifications/MockNotificationTypes.cpp (+26/-0) tests/mocks/Unity/Notifications/MockNotificationTypes.h (+36/-0) tests/mocks/Unity/Notifications/notification.js (+0/-23) tests/mocks/Unity/Notifications/plugin.cpp (+31/-0) tests/mocks/Unity/Notifications/plugin.h (+35/-0) tests/mocks/Unity/Notifications/qmldir (+2/-1) tests/plugins/Ubuntu/Gestures/GestureTest.cpp (+6/-0) tests/plugins/Ubuntu/Gestures/GestureTest.h (+2/-0) tests/plugins/Ubuntu/Gestures/tst_TouchDispatcher.cpp (+59/-0) tests/plugins/Unity/Launcher/launchermodeltest.cpp (+2/-2) tests/qmltests/CMakeLists.txt (+1/-0) tests/qmltests/Greeter/tst_SingleGreeter.qml (+72/-29) tests/qmltests/Notifications/tst_Notifications.qml (+595/-587) tests/qmltests/Notifications/tst_SwipeToAct.qml (+276/-0) tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml (+17/-1) tests/qmltests/Panel/tst_IndicatorPage.qml (+54/-9) tests/qmltests/tst_ShellWithPin.qml (+58/-0) |
To merge this branch: | bzr merge lp:~unity-team/unity8/rtm-14.09-staging |
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
kevin gunn (community) | Approve | ||
Review via email: mp+240664@code.launchpad.net |
Commit message
[ Albert Astals ]
* Fix i18n (LP: #1389165)
[ Michael Zanetti ]
* Fix DBusVariant conversion for launcher emblems (LP: #1387261)
* Fix desktop file encoding in launcher (LP: #1387083)
[ Alberto Aguirre ]
* Add audioRole to QtMultimedia mock
* Add a plugin to take screenshots on vol up + vol down
[ Nick Dedekind ]
* Reset current item selection on deleted. (LP: #1378462)
* Added timer to re-assert server value after indicator menu item
activation. (LP: #1336715)
[ Mirco Müller ]
* Added dedicated swipe-to-act button for snap-decisions, which avoids
accidental taps/button-
[ Michael Terry ]
* Don't lock phone if user tries to switch back to an active call.
(LP: #1388156)
[ Daniel d'Andrada ]
* TouchDispatcher: synthesize MouseButtonDblClick events (LP: #1388359)
Description of the change
- 1397. By Michael Terry
-
[ Albert Astals ]
* Fix i18n (LP: #1389165)[ Michael Zanetti ]
* Fix DBusVariant conversion for launcher emblems (LP: #1387261)
* Fix desktop file encoding in launcher (LP: #1387083)[ Alberto Aguirre ]
* Add audioRole to QtMultimedia mock
* Add a plugin to take screenshots on vol up + vol down[ Nick Dedekind ]
* Reset current item selection on deleted. (LP: #1378462)
* Added timer to re-assert server value after indicator menu item
activation. (LP: #1336715)[ Mirco Müller ]
* Added dedicated swipe-to-act button for snap-decisions, which avoids
accidental taps/button-presses. (LP: #1358343) [ Michael Terry ]
* Don't lock phone if user tries to switch back to an active call.
(LP: #1388156)[ Daniel d'Andrada ]
* TouchDispatcher: synthesize MouseButtonDblClick events (LP: #1388359) Fixes: 1336715, 1358343, 1378462, 1387083, 1387261, 1388156, 1388359, 1389165
Preview Diff
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2014-10-30 21:43:43 +0000 |
3 | +++ debian/changelog 2014-11-05 14:37:57 +0000 |
4 | @@ -1,3 +1,40 @@ |
5 | +unity8 (8.01.1-0ubuntu1) UNRELEASED; urgency=medium |
6 | + |
7 | + [ Albert Astals ] |
8 | + * Fix i18n (LP: #1389165) |
9 | + |
10 | + [ Michael Zanetti ] |
11 | + * Fix DBusVariant conversion for launcher emblems (LP: #1387261) |
12 | + * Fix desktop file encoding in launcher (LP: #1387083) |
13 | + |
14 | + [ Alberto Aguirre ] |
15 | + * Add audioRole to QtMultimedia mock |
16 | + * Add a plugin to take screenshots on vol up + vol down |
17 | + |
18 | + [ Nick Dedekind ] |
19 | + * Reset current item selection on deleted. (LP: #1378462) |
20 | + * Added timer to re-assert server value after indicator menu item |
21 | + activation. (LP: #1336715) |
22 | + |
23 | + [ Mirco Müller ] |
24 | + * Added dedicated swipe-to-act button for snap-decisions, which avoids |
25 | + accidental taps/button-presses. (LP: #1358343) |
26 | + |
27 | + [ Michael Terry ] |
28 | + * Don't lock phone if user tries to switch back to an active call. |
29 | + (LP: #1388156) |
30 | + |
31 | + [ Daniel d'Andrada ] |
32 | + * TouchDispatcher: synthesize MouseButtonDblClick events (LP: |
33 | + #1388359) |
34 | + |
35 | + [ Michał Sawicz ] |
36 | + * Bump the version above the version synced from vivid, otherwise |
37 | + train will generate a lower-than-archive version number. |
38 | + * fix positive/negative answer order on the new swipe notification |
39 | + |
40 | + -- Michał Sawicz <michal.sawicz@canonical.com> Wed, 05 Nov 2014 02:37:24 +0100 |
41 | + |
42 | unity8 (8.01+15.04.20141030-0ubuntu1) vivid; urgency=medium |
43 | |
44 | [ Michael Terry ] |
45 | |
46 | === modified file 'debian/unity8-private.install' |
47 | --- debian/unity8-private.install 2014-10-06 15:45:25 +0000 |
48 | +++ debian/unity8-private.install 2014-11-05 14:37:57 +0000 |
49 | @@ -6,6 +6,7 @@ |
50 | usr/lib/*/unity8/qml/Lights |
51 | usr/lib/*/unity8/qml/Powerd |
52 | usr/lib/*/unity8/qml/SessionBroadcast |
53 | +usr/lib/*/unity8/qml/ScreenGrabber |
54 | usr/lib/*/unity8/qml/Ubuntu |
55 | usr/lib/*/unity8/qml/Unity |
56 | usr/lib/*/unity8/qml/Utils |
57 | |
58 | === modified file 'libs/UbuntuGestures/DebugHelpers.cpp' |
59 | --- libs/UbuntuGestures/DebugHelpers.cpp 2014-10-17 11:01:53 +0000 |
60 | +++ libs/UbuntuGestures/DebugHelpers.cpp 2014-11-05 14:37:57 +0000 |
61 | @@ -83,7 +83,7 @@ |
62 | message.append("MouseButtonDblClick "); |
63 | break; |
64 | case QEvent::MouseMove: |
65 | - message.append("MouseButtonMove "); |
66 | + message.append("MouseMove "); |
67 | break; |
68 | default: |
69 | message.append("INVALID_MOUSE_EVENT_TYPE "); |
70 | |
71 | === modified file 'plugins/CMakeLists.txt' |
72 | --- plugins/CMakeLists.txt 2014-09-29 09:43:18 +0000 |
73 | +++ plugins/CMakeLists.txt 2014-11-05 14:37:57 +0000 |
74 | @@ -18,6 +18,7 @@ |
75 | add_subdirectory(Dash) |
76 | add_subdirectory(Powerd) |
77 | add_subdirectory(SessionBroadcast) |
78 | +add_subdirectory(ScreenGrabber) |
79 | add_subdirectory(Ubuntu) |
80 | add_subdirectory(Unity) |
81 | add_subdirectory(Utils) |
82 | |
83 | === added directory 'plugins/ScreenGrabber' |
84 | === added file 'plugins/ScreenGrabber/CMakeLists.txt' |
85 | --- plugins/ScreenGrabber/CMakeLists.txt 1970-01-01 00:00:00 +0000 |
86 | +++ plugins/ScreenGrabber/CMakeLists.txt 2014-11-05 14:37:57 +0000 |
87 | @@ -0,0 +1,13 @@ |
88 | +include_directories( |
89 | + ${CMAKE_CURRENT_BINARY_DIR} |
90 | +) |
91 | + |
92 | +set(SCREENGRABBERSOURCES |
93 | + screengrabber.cpp |
94 | + plugin.cpp |
95 | +) |
96 | + |
97 | +add_library(ScreenGrabber-qml MODULE ${SCREENGRABBERSOURCES}) |
98 | +qt5_use_modules(ScreenGrabber-qml Qml Gui Quick Concurrent) |
99 | + |
100 | +add_unity8_plugin(ScreenGrabber 0.1 ScreenGrabber TARGETS ScreenGrabber-qml) |
101 | |
102 | === added file 'plugins/ScreenGrabber/ScreenGrabber.qmltypes' |
103 | --- plugins/ScreenGrabber/ScreenGrabber.qmltypes 1970-01-01 00:00:00 +0000 |
104 | +++ plugins/ScreenGrabber/ScreenGrabber.qmltypes 2014-11-05 14:37:57 +0000 |
105 | @@ -0,0 +1,17 @@ |
106 | +import QtQuick.tooling 1.1 |
107 | + |
108 | +// This file describes the plugin-supplied types contained in the library. |
109 | +// It is used for QML tooling purposes only. |
110 | +// |
111 | +// This file was auto-generated by: |
112 | +// 'qmlplugindump -nonrelocatable ScreenGrabber 0.1 plugins' |
113 | + |
114 | +Module { |
115 | + Component { |
116 | + name: "ScreenGrabber" |
117 | + prototype: "QObject" |
118 | + exports: ["ScreenGrabber/ScreenGrabber 0.1"] |
119 | + exportMetaObjectRevisions: [0] |
120 | + Method { name: "captureAndSave" } |
121 | + } |
122 | +} |
123 | |
124 | === added file 'plugins/ScreenGrabber/plugin.cpp' |
125 | --- plugins/ScreenGrabber/plugin.cpp 1970-01-01 00:00:00 +0000 |
126 | +++ plugins/ScreenGrabber/plugin.cpp 2014-11-05 14:37:57 +0000 |
127 | @@ -0,0 +1,28 @@ |
128 | +/* |
129 | + * Copyright (C) 2014 Canonical, Ltd. |
130 | + * |
131 | + * This program is free software; you can redistribute it and/or modify |
132 | + * it under the terms of the GNU General Public License as published by |
133 | + * the Free Software Foundation; version 3. |
134 | + * |
135 | + * This program is distributed in the hope that it will be useful, |
136 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
137 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
138 | + * GNU General Public License for more details. |
139 | + * |
140 | + * You should have received a copy of the GNU General Public License |
141 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
142 | + * |
143 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
144 | + */ |
145 | + |
146 | +#include "plugin.h" |
147 | +#include "screengrabber.h" |
148 | + |
149 | +#include <QtQml/qqml.h> |
150 | + |
151 | +void ScreenGrabberPlugin::registerTypes(const char *uri) |
152 | +{ |
153 | + Q_ASSERT(uri == QLatin1String("ScreenGrabber")); |
154 | + qmlRegisterType<ScreenGrabber>(uri, 0, 1, "ScreenGrabber"); |
155 | +} |
156 | |
157 | === added file 'plugins/ScreenGrabber/plugin.h' |
158 | --- plugins/ScreenGrabber/plugin.h 1970-01-01 00:00:00 +0000 |
159 | +++ plugins/ScreenGrabber/plugin.h 2014-11-05 14:37:57 +0000 |
160 | @@ -0,0 +1,33 @@ |
161 | +/* |
162 | + * Copyright (C) 2014 Canonical, Ltd. |
163 | + * |
164 | + * This program is free software; you can redistribute it and/or modify |
165 | + * it under the terms of the GNU General Public License as published by |
166 | + * the Free Software Foundation; version 3. |
167 | + * |
168 | + * This program is distributed in the hope that it will be useful, |
169 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
170 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
171 | + * GNU General Public License for more details. |
172 | + * |
173 | + * You should have received a copy of the GNU General Public License |
174 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
175 | + * |
176 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
177 | + */ |
178 | + |
179 | +#ifndef SCREENGRABBER_PLUGIN_H |
180 | +#define SCREENGRABBER_PLUGIN_H |
181 | + |
182 | +#include <QtQml/QQmlExtensionPlugin> |
183 | + |
184 | +class ScreenGrabberPlugin : public QQmlExtensionPlugin |
185 | +{ |
186 | + Q_OBJECT |
187 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
188 | + |
189 | +public: |
190 | + void registerTypes(const char *uri); |
191 | +}; |
192 | + |
193 | +#endif // SCREENGRABBER_PLUGIN_H |
194 | |
195 | === added file 'plugins/ScreenGrabber/qmldir' |
196 | --- plugins/ScreenGrabber/qmldir 1970-01-01 00:00:00 +0000 |
197 | +++ plugins/ScreenGrabber/qmldir 2014-11-05 14:37:57 +0000 |
198 | @@ -0,0 +1,3 @@ |
199 | +module ScreenGrabber |
200 | +plugin ScreenGrabber-qml |
201 | +typeinfo ScreenGrabber.qmltypes |
202 | |
203 | === added file 'plugins/ScreenGrabber/screengrabber.cpp' |
204 | --- plugins/ScreenGrabber/screengrabber.cpp 1970-01-01 00:00:00 +0000 |
205 | +++ plugins/ScreenGrabber/screengrabber.cpp 2014-11-05 14:37:57 +0000 |
206 | @@ -0,0 +1,94 @@ |
207 | +/* |
208 | + * Copyright (C) 2014 Canonical, Ltd. |
209 | + * |
210 | + * This program is free software; you can redistribute it and/or modify |
211 | + * it under the terms of the GNU General Public License as published by |
212 | + * the Free Software Foundation; version 3. |
213 | + * |
214 | + * This program is distributed in the hope that it will be useful, |
215 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
216 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
217 | + * GNU General Public License for more details. |
218 | + * |
219 | + * You should have received a copy of the GNU General Public License |
220 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
221 | + * |
222 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
223 | + */ |
224 | + |
225 | +#include "screengrabber.h" |
226 | + |
227 | +#include <QDir> |
228 | +#include <QDateTime> |
229 | +#include <QStandardPaths> |
230 | +#include <QtGui/QImage> |
231 | +#include <QtGui/QGuiApplication> |
232 | +#include <QtQuick/QQuickWindow> |
233 | +#include <QtConcurrent/QtConcurrentRun> |
234 | + |
235 | +#include <QDebug> |
236 | + |
237 | +void saveScreenshot(QImage screenshot, QString filename, QString format, int quality) |
238 | +{ |
239 | + if (!screenshot.save(filename, format.toLatin1().data(), quality)) |
240 | + qWarning() << "ScreenShotter: failed to save snapshot!"; |
241 | +} |
242 | + |
243 | +ScreenGrabber::ScreenGrabber(QObject *parent) |
244 | + : QObject(parent), |
245 | + screenshotQuality(0) |
246 | +{ |
247 | + QDir screenshotsDir(QStandardPaths::displayName(QStandardPaths::PicturesLocation)); |
248 | + screenshotsDir.mkdir("Screenshots"); |
249 | + screenshotsDir.cd("Screenshots"); |
250 | + if (screenshotsDir.exists()) |
251 | + { |
252 | + fileNamePrefix = screenshotsDir.absolutePath(); |
253 | + fileNamePrefix.append("/screenshot"); |
254 | + } |
255 | + else |
256 | + { |
257 | + qWarning() << "ScreenShotter: failed to create directory at: " << screenshotsDir.absolutePath(); |
258 | + } |
259 | +} |
260 | + |
261 | +void ScreenGrabber::captureAndSave() |
262 | +{ |
263 | + if (fileNamePrefix.isEmpty()) |
264 | + { |
265 | + qWarning() << "ScreenShotter: no directory to save screenshot"; |
266 | + return; |
267 | + } |
268 | + |
269 | + const QWindowList windows = QGuiApplication::topLevelWindows(); |
270 | + if (windows.empty()) |
271 | + { |
272 | + qWarning() << "ScreenShotter: no top level windows found!"; |
273 | + return; |
274 | + } |
275 | + |
276 | + QQuickWindow *main_window = qobject_cast<QQuickWindow *>(windows[0]); |
277 | + if (!main_window) |
278 | + { |
279 | + qWarning() << "ScreenShotter: can only take screenshots of QQuickWindows"; |
280 | + return; |
281 | + } |
282 | + |
283 | + QImage screenshot = main_window->grabWindow(); |
284 | + QtConcurrent::run(saveScreenshot, screenshot, makeFileName(), getFormat(), screenshotQuality); |
285 | +} |
286 | + |
287 | +QString ScreenGrabber::makeFileName() |
288 | +{ |
289 | + QString fileName(fileNamePrefix); |
290 | + fileName.append(QDateTime::currentDateTime().toString("yyyymmdd_hhmmsszzz")); |
291 | + fileName.append("."); |
292 | + fileName.append(getFormat()); |
293 | + return fileName; |
294 | +} |
295 | + |
296 | +QString ScreenGrabber::getFormat() |
297 | +{ |
298 | + //TODO: This should be configurable (perhaps through gsettings?) |
299 | + return "png"; |
300 | +} |
301 | |
302 | === added file 'plugins/ScreenGrabber/screengrabber.h' |
303 | --- plugins/ScreenGrabber/screengrabber.h 1970-01-01 00:00:00 +0000 |
304 | +++ plugins/ScreenGrabber/screengrabber.h 2014-11-05 14:37:57 +0000 |
305 | @@ -0,0 +1,42 @@ |
306 | +/* |
307 | + * Copyright (C) 2014 Canonical, Ltd. |
308 | + * |
309 | + * This program is free software; you can redistribute it and/or modify |
310 | + * it under the terms of the GNU General Public License as published by |
311 | + * the Free Software Foundation; version 3. |
312 | + * |
313 | + * This program is distributed in the hope that it will be useful, |
314 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
315 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
316 | + * GNU General Public License for more details. |
317 | + * |
318 | + * You should have received a copy of the GNU General Public License |
319 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
320 | + * |
321 | + * Authors: Alberto Aguirre <alberto.aguirre@canonical.com> |
322 | + */ |
323 | + |
324 | +#ifndef SNAPSHOTTER_H |
325 | +#define SNAPSHOTTER_H |
326 | + |
327 | +#include <QObject> |
328 | +#include <QString> |
329 | + |
330 | +class ScreenGrabber: public QObject |
331 | +{ |
332 | + Q_OBJECT |
333 | + |
334 | +public: |
335 | + explicit ScreenGrabber(QObject *parent = 0); |
336 | + |
337 | +public Q_SLOTS: |
338 | + void captureAndSave(); |
339 | + |
340 | +private: |
341 | + QString makeFileName(); |
342 | + QString getFormat(); |
343 | + QString fileNamePrefix; |
344 | + int screenshotQuality; |
345 | +}; |
346 | + |
347 | +#endif |
348 | |
349 | === modified file 'plugins/Ubuntu/Gestures/TouchDispatcher.cpp' |
350 | --- plugins/Ubuntu/Gestures/TouchDispatcher.cpp 2014-10-20 14:24:30 +0000 |
351 | +++ plugins/Ubuntu/Gestures/TouchDispatcher.cpp 2014-11-05 14:37:57 +0000 |
352 | @@ -16,7 +16,9 @@ |
353 | |
354 | #include "TouchDispatcher.h" |
355 | |
356 | +#include <QGuiApplication> |
357 | #include <QScopedPointer> |
358 | +#include <QStyleHints> |
359 | |
360 | #pragma GCC diagnostic push |
361 | #pragma GCC diagnostic ignored "-pedantic" |
362 | @@ -32,6 +34,7 @@ |
363 | TouchDispatcher::TouchDispatcher() |
364 | : m_status(NoActiveTouch) |
365 | , m_touchMouseId(-1) |
366 | + , m_touchMousePressTimestamp(0) |
367 | { |
368 | } |
369 | |
370 | @@ -148,6 +151,18 @@ |
371 | #endif |
372 | m_status = DeliveringMouseEvents; |
373 | m_touchMouseId = targetTouchPoints.at(0).id(); |
374 | + |
375 | + if (checkIfDoubleClicked(timestamp)) { |
376 | + QScopedPointer<QMouseEvent> doubleClickEvent( |
377 | + touchToMouseEvent(QEvent::MouseButtonDblClick, targetTouchPoints.at(0), timestamp, |
378 | + modifiers, false /* transformNeeded */)); |
379 | + #if TOUCHDISPATCHER_DEBUG |
380 | + qDebug() << "[TouchDispatcher] dispatching" << qPrintable(mouseEventToString(doubleClickEvent.data())) |
381 | + << "to" << m_targetItem.data(); |
382 | + #endif |
383 | + QCoreApplication::sendEvent(targetItem, doubleClickEvent.data()); |
384 | + } |
385 | + |
386 | } else { |
387 | #if TOUCHDISPATCHER_DEBUG |
388 | qDebug() << "[TouchDispatcher] Item rejected the QMouseEvent."; |
389 | @@ -322,3 +337,31 @@ |
390 | //QGuiApplicationPrivate::setMouseEventSource(me, Qt::MouseEventSynthesizedByQt); |
391 | return me; |
392 | } |
393 | + |
394 | +/* |
395 | + Copied from qquickwindow.cpp which has: |
396 | + Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies) |
397 | + Under GPL 3.0 license. |
398 | +*/ |
399 | +bool TouchDispatcher::checkIfDoubleClicked(ulong newPressEventTimestamp) |
400 | +{ |
401 | + bool doubleClicked; |
402 | + |
403 | + if (m_touchMousePressTimestamp == 0) { |
404 | + // just initialize the variable |
405 | + m_touchMousePressTimestamp = newPressEventTimestamp; |
406 | + doubleClicked = false; |
407 | + } else { |
408 | + ulong timeBetweenPresses = newPressEventTimestamp - m_touchMousePressTimestamp; |
409 | + ulong doubleClickInterval = static_cast<ulong>(qApp->styleHints()-> |
410 | + mouseDoubleClickInterval()); |
411 | + doubleClicked = timeBetweenPresses < doubleClickInterval; |
412 | + if (doubleClicked) { |
413 | + m_touchMousePressTimestamp = 0; |
414 | + } else { |
415 | + m_touchMousePressTimestamp = newPressEventTimestamp; |
416 | + } |
417 | + } |
418 | + |
419 | + return doubleClicked; |
420 | +} |
421 | |
422 | === modified file 'plugins/Ubuntu/Gestures/TouchDispatcher.h' |
423 | --- plugins/Ubuntu/Gestures/TouchDispatcher.h 2014-10-17 11:01:53 +0000 |
424 | +++ plugins/Ubuntu/Gestures/TouchDispatcher.h 2014-11-05 14:37:57 +0000 |
425 | @@ -71,6 +71,8 @@ |
426 | QMouseEvent *touchToMouseEvent(QEvent::Type type, const QTouchEvent::TouchPoint &p, |
427 | ulong timestamp, Qt::KeyboardModifiers modifiers, bool transformNeeded = true); |
428 | |
429 | + bool checkIfDoubleClicked(ulong newPressEventTimestamp); |
430 | + |
431 | QPointer<QQuickItem> m_targetItem; |
432 | |
433 | enum { |
434 | @@ -81,6 +83,7 @@ |
435 | } m_status; |
436 | |
437 | int m_touchMouseId; |
438 | + ulong m_touchMousePressTimestamp; |
439 | }; |
440 | |
441 | #endif // UBUNTU_TOUCH_DISPATCHER_H |
442 | |
443 | === modified file 'plugins/Unity/Launcher/dbusinterface.cpp' |
444 | --- plugins/Unity/Launcher/dbusinterface.cpp 2014-10-09 21:29:00 +0000 |
445 | +++ plugins/Unity/Launcher/dbusinterface.cpp 2014-11-05 14:37:57 +0000 |
446 | @@ -171,13 +171,13 @@ |
447 | } |
448 | } else if (message.member() == "Set") { |
449 | if (message.arguments()[1].toString() == "count") { |
450 | - int newCount = message.arguments()[2].toInt(); |
451 | + int newCount = message.arguments()[2].value<QDBusVariant>().variant().toInt(); |
452 | if (!item || newCount != item->count()) { |
453 | Q_EMIT countChanged(appid, newCount); |
454 | notifyPropertyChanged("com.canonical.Unity.Launcher.Item", encodeAppId(appid), "count", QVariant(newCount)); |
455 | } |
456 | } else if (message.arguments()[1].toString() == "countVisible") { |
457 | - bool newVisible = message.arguments()[2].toBool(); |
458 | + bool newVisible = message.arguments()[2].value<QDBusVariant>().variant().toBool(); |
459 | if (!item || newVisible != item->countVisible()) { |
460 | Q_EMIT countVisibleChanged(appid, newVisible); |
461 | notifyPropertyChanged("com.canonical.Unity.Launcher.Item", encodeAppId(appid), "countVisible", newVisible); |
462 | |
463 | === modified file 'plugins/Unity/Launcher/desktopfilehandler.cpp' |
464 | --- plugins/Unity/Launcher/desktopfilehandler.cpp 2014-09-30 16:48:28 +0000 |
465 | +++ plugins/Unity/Launcher/desktopfilehandler.cpp 2014-11-05 14:37:57 +0000 |
466 | @@ -106,6 +106,7 @@ |
467 | } |
468 | |
469 | QSettings settings(m_filename, QSettings::IniFormat); |
470 | + settings.setIniCodec("UTF-8"); |
471 | settings.beginGroup("Desktop Entry"); |
472 | |
473 | // First try to find Name[xx_YY] and Name[xx] in .desktop file |
474 | @@ -138,6 +139,7 @@ |
475 | } |
476 | |
477 | QSettings settings(m_filename, QSettings::IniFormat); |
478 | + settings.setIniCodec("UTF-8"); |
479 | settings.beginGroup("Desktop Entry"); |
480 | QString iconString = settings.value("Icon").toString(); |
481 | QString pathString = settings.value("Path").toString(); |
482 | |
483 | === modified file 'po/unity8.pot' |
484 | --- po/unity8.pot 2014-10-07 08:41:28 +0000 |
485 | +++ po/unity8.pot 2014-11-05 14:37:57 +0000 |
486 | @@ -8,7 +8,7 @@ |
487 | msgstr "" |
488 | "Project-Id-Version: unity8\n" |
489 | "Report-Msgid-Bugs-To: \n" |
490 | -"POT-Creation-Date: 2014-10-07 11:37+0300\n" |
491 | +"POT-Creation-Date: 2014-10-31 10:36+0100\n" |
492 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
493 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
494 | "Language-Team: LANGUAGE <LL@li.org>\n" |
495 | @@ -50,59 +50,59 @@ |
496 | msgstr[0] "" |
497 | msgstr[1] "" |
498 | |
499 | -#: qml/Components/Dialogs.qml:70 |
500 | +#: qml/Components/Dialogs.qml:74 |
501 | msgid "Log out" |
502 | msgstr "" |
503 | |
504 | -#: qml/Components/Dialogs.qml:71 |
505 | +#: qml/Components/Dialogs.qml:75 |
506 | msgid "Are you sure you want to log out?" |
507 | msgstr "" |
508 | |
509 | -#: qml/Components/Dialogs.qml:73 qml/Components/Dialogs.qml:97 |
510 | -#: qml/Components/Dialogs.qml:122 |
511 | +#: qml/Components/Dialogs.qml:77 qml/Components/Dialogs.qml:101 |
512 | +#: qml/Components/Dialogs.qml:126 |
513 | msgid "No" |
514 | msgstr "" |
515 | |
516 | -#: qml/Components/Dialogs.qml:80 qml/Components/Dialogs.qml:104 |
517 | -#: qml/Components/Dialogs.qml:129 |
518 | +#: qml/Components/Dialogs.qml:84 qml/Components/Dialogs.qml:108 |
519 | +#: qml/Components/Dialogs.qml:133 |
520 | msgid "Yes" |
521 | msgstr "" |
522 | |
523 | -#: qml/Components/Dialogs.qml:94 |
524 | +#: qml/Components/Dialogs.qml:98 |
525 | msgid "Shut down" |
526 | msgstr "" |
527 | |
528 | -#: qml/Components/Dialogs.qml:95 |
529 | +#: qml/Components/Dialogs.qml:99 |
530 | msgid "Are you sure you want to shut down?" |
531 | msgstr "" |
532 | |
533 | -#: qml/Components/Dialogs.qml:119 |
534 | +#: qml/Components/Dialogs.qml:123 |
535 | msgid "Reboot" |
536 | msgstr "" |
537 | |
538 | -#: qml/Components/Dialogs.qml:120 |
539 | +#: qml/Components/Dialogs.qml:124 |
540 | msgid "Are you sure you want to reboot?" |
541 | msgstr "" |
542 | |
543 | -#: qml/Components/Dialogs.qml:144 |
544 | +#: qml/Components/Dialogs.qml:148 |
545 | msgid "Power" |
546 | msgstr "" |
547 | |
548 | -#: qml/Components/Dialogs.qml:145 |
549 | +#: qml/Components/Dialogs.qml:149 |
550 | msgid "" |
551 | "Are you sure you would like\n" |
552 | "to power off?" |
553 | msgstr "" |
554 | |
555 | -#: qml/Components/Dialogs.qml:147 |
556 | +#: qml/Components/Dialogs.qml:151 |
557 | msgid "Power off" |
558 | msgstr "" |
559 | |
560 | -#: qml/Components/Dialogs.qml:157 |
561 | +#: qml/Components/Dialogs.qml:161 |
562 | msgid "Restart" |
563 | msgstr "" |
564 | |
565 | -#: qml/Components/Dialogs.qml:167 |
566 | +#: qml/Components/Dialogs.qml:171 |
567 | msgid "Cancel" |
568 | msgstr "" |
569 | |
570 | @@ -134,29 +134,33 @@ |
571 | msgid "Swipe up again to close the settings screen" |
572 | msgstr "" |
573 | |
574 | -#: qml/Components/EdgeDemo.qml:198 |
575 | +#: qml/Components/EdgeDemo.qml:201 |
576 | msgid "Left edge" |
577 | msgstr "" |
578 | |
579 | -#: qml/Components/EdgeDemo.qml:199 |
580 | +#: qml/Components/EdgeDemo.qml:202 |
581 | msgid "Swipe from the left to reveal the launcher for quick access to apps" |
582 | msgstr "" |
583 | |
584 | -#: qml/Components/EdgeDemo.qml:226 |
585 | +#: qml/Components/EdgeDemo.qml:229 |
586 | msgid "Well done" |
587 | msgstr "" |
588 | |
589 | -#: qml/Components/EdgeDemo.qml:227 |
590 | +#: qml/Components/EdgeDemo.qml:230 |
591 | msgid "" |
592 | "You have now mastered the edge gestures and can start using the " |
593 | "phone<br><br>Tap on the screen to start" |
594 | msgstr "" |
595 | |
596 | -#: qml/Components/Lockscreen.qml:220 |
597 | +#: qml/Components/Lockscreen.qml:223 |
598 | +msgid "Return to Call" |
599 | +msgstr "" |
600 | + |
601 | +#: qml/Components/Lockscreen.qml:223 |
602 | msgid "Emergency Call" |
603 | msgstr "" |
604 | |
605 | -#: qml/Components/Lockscreen.qml:252 |
606 | +#: qml/Components/Lockscreen.qml:255 |
607 | msgid "OK" |
608 | msgstr "" |
609 | |
610 | @@ -213,15 +217,15 @@ |
611 | msgid "Release to refresh…" |
612 | msgstr "" |
613 | |
614 | -#: qml/Dash/ScopesOverview.qml:206 |
615 | +#: qml/Dash/ScopesOverview.qml:215 |
616 | msgid "Manage Scopes" |
617 | msgstr "" |
618 | |
619 | -#: qml/Dash/ScopesOverview.qml:428 |
620 | +#: qml/Dash/ScopesOverview.qml:437 |
621 | msgid "Done" |
622 | msgstr "" |
623 | |
624 | -#: qml/Dash/ScopesOverview.qml:454 |
625 | +#: qml/Dash/ScopesOverview.qml:463 |
626 | msgid "Store" |
627 | msgstr "" |
628 | |
629 | @@ -233,7 +237,7 @@ |
630 | msgid "All" |
631 | msgstr "" |
632 | |
633 | -#: qml/Greeter/Greeter.qml:157 |
634 | +#: qml/Greeter/Greeter.qml:174 |
635 | msgid "Unlock" |
636 | msgstr "" |
637 | |
638 | @@ -261,39 +265,39 @@ |
639 | msgid "Show password" |
640 | msgstr "" |
641 | |
642 | -#: qml/Panel/ActiveCallHint.qml:77 |
643 | +#: qml/Panel/ActiveCallHint.qml:79 |
644 | msgid "Tap to return to call..." |
645 | msgstr "" |
646 | |
647 | -#: qml/Panel/ActiveCallHint.qml:90 |
648 | +#: qml/Panel/ActiveCallHint.qml:92 |
649 | msgid "Conference" |
650 | msgstr "" |
651 | |
652 | -#: qml/Panel/Indicators/MenuItemFactory.qml:600 |
653 | +#: qml/Panel/Indicators/MenuItemFactory.qml:615 |
654 | msgid "Nothing is playing" |
655 | msgstr "" |
656 | |
657 | -#: qml/Panel/Indicators/MenuItemFactory.qml:748 |
658 | +#: qml/Panel/Indicators/MenuItemFactory.qml:763 |
659 | msgid "In queue…" |
660 | msgstr "" |
661 | |
662 | -#: qml/Panel/Indicators/MenuItemFactory.qml:752 |
663 | +#: qml/Panel/Indicators/MenuItemFactory.qml:767 |
664 | msgid "Downloading" |
665 | msgstr "" |
666 | |
667 | -#: qml/Panel/Indicators/MenuItemFactory.qml:754 |
668 | +#: qml/Panel/Indicators/MenuItemFactory.qml:769 |
669 | msgid "Paused, tap to resume" |
670 | msgstr "" |
671 | |
672 | -#: qml/Panel/Indicators/MenuItemFactory.qml:756 |
673 | +#: qml/Panel/Indicators/MenuItemFactory.qml:771 |
674 | msgid "Canceled" |
675 | msgstr "" |
676 | |
677 | -#: qml/Panel/Indicators/MenuItemFactory.qml:758 |
678 | +#: qml/Panel/Indicators/MenuItemFactory.qml:773 |
679 | msgid "Finished" |
680 | msgstr "" |
681 | |
682 | -#: qml/Panel/Indicators/MenuItemFactory.qml:760 |
683 | +#: qml/Panel/Indicators/MenuItemFactory.qml:775 |
684 | msgid "Failed, tap to retry" |
685 | msgstr "" |
686 | |
687 | @@ -305,55 +309,55 @@ |
688 | msgid "Roaming" |
689 | msgstr "" |
690 | |
691 | -#: qml/Shell.qml:346 |
692 | +#: qml/Shell.qml:381 |
693 | msgid "Enter passphrase" |
694 | msgstr "" |
695 | |
696 | -#: qml/Shell.qml:347 |
697 | +#: qml/Shell.qml:382 |
698 | msgid "Sorry, incorrect passphrase" |
699 | msgstr "" |
700 | |
701 | -#: qml/Shell.qml:348 |
702 | +#: qml/Shell.qml:383 |
703 | msgid "Please re-enter" |
704 | msgstr "" |
705 | |
706 | -#: qml/Shell.qml:350 |
707 | +#: qml/Shell.qml:385 |
708 | msgid "Enter passcode" |
709 | msgstr "" |
710 | |
711 | -#: qml/Shell.qml:351 |
712 | +#: qml/Shell.qml:386 |
713 | msgid "Sorry, incorrect passcode" |
714 | msgstr "" |
715 | |
716 | -#: qml/Shell.qml:354 |
717 | +#: qml/Shell.qml:389 |
718 | #, qt-format |
719 | msgid "Enter %1" |
720 | msgstr "" |
721 | |
722 | -#: qml/Shell.qml:355 |
723 | +#: qml/Shell.qml:390 |
724 | #, qt-format |
725 | msgid "Sorry, incorrect %1" |
726 | msgstr "" |
727 | |
728 | -#: qml/Shell.qml:390 |
729 | +#: qml/Shell.qml:431 |
730 | msgid "Sorry, incorrect passphrase." |
731 | msgstr "" |
732 | |
733 | -#: qml/Shell.qml:391 |
734 | +#: qml/Shell.qml:432 |
735 | msgid "Sorry, incorrect passcode." |
736 | msgstr "" |
737 | |
738 | -#: qml/Shell.qml:392 |
739 | +#: qml/Shell.qml:433 |
740 | msgid "This will be your last attempt." |
741 | msgstr "" |
742 | |
743 | -#: qml/Shell.qml:394 |
744 | +#: qml/Shell.qml:435 |
745 | msgid "" |
746 | "If passphrase is entered incorrectly, your phone will conduct a factory " |
747 | "reset and all personal data will be deleted." |
748 | msgstr "" |
749 | |
750 | -#: qml/Shell.qml:395 |
751 | +#: qml/Shell.qml:436 |
752 | msgid "" |
753 | "If passcode is entered incorrectly, your phone will conduct a factory reset " |
754 | "and all personal data will be deleted." |
755 | |
756 | === modified file 'po/update-unity-pot' |
757 | --- po/update-unity-pot 2014-07-07 11:15:37 +0000 |
758 | +++ po/update-unity-pot 2014-11-05 14:37:57 +0000 |
759 | @@ -21,6 +21,7 @@ |
760 | --add-comments=TRANSLATORS \ |
761 | --keyword=tr \ |
762 | --keyword=tr:1,2 \ |
763 | + --keyword=dtr:2 \ |
764 | --package-name="unity8" \ |
765 | --copyright-holder="Canonical Ltd." \ |
766 | --from-code="UTF-8" |
767 | |
768 | === modified file 'qml/Components/Dialogs.qml' |
769 | --- qml/Components/Dialogs.qml 2014-10-15 20:35:42 +0000 |
770 | +++ qml/Components/Dialogs.qml 2014-11-05 14:37:57 +0000 |
771 | @@ -26,7 +26,7 @@ |
772 | |
773 | // Explicitly use the right domain for this widget because it might be used |
774 | // in other applications like the welcome wizard. |
775 | - property string domain: "unity8" |
776 | + readonly property string domain: "unity8" |
777 | |
778 | function onPowerKeyPressed() { |
779 | // FIXME: event.isAutoRepeat is always false on Nexus 4. |
780 | |
781 | === added file 'qml/Components/ScreenGrabber.qml' |
782 | --- qml/Components/ScreenGrabber.qml 1970-01-01 00:00:00 +0000 |
783 | +++ qml/Components/ScreenGrabber.qml 2014-11-05 14:37:57 +0000 |
784 | @@ -0,0 +1,72 @@ |
785 | +/* |
786 | + * Copyright (C) 2014 Canonical, Ltd. |
787 | + * |
788 | + * This program is free software; you can redistribute it and/or modify |
789 | + * it under the terms of the GNU General Public License as published by |
790 | + * the Free Software Foundation; version 3. |
791 | + * |
792 | + * This program is distributed in the hope that it will be useful, |
793 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
794 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
795 | + * GNU General Public License for more details. |
796 | + * |
797 | + * You should have received a copy of the GNU General Public License |
798 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
799 | + */ |
800 | + |
801 | +import QtQuick 2.0 |
802 | +import QtMultimedia 5.0 |
803 | +import ScreenGrabber 0.1 |
804 | + |
805 | +Rectangle { |
806 | + id: root |
807 | + enabled: true |
808 | + visible: false |
809 | + color: "white" |
810 | + anchors.fill: parent |
811 | + opacity: 0.0 |
812 | + |
813 | + ScreenGrabber { |
814 | + id: screenGrabber |
815 | + objectName: "screenGrabber" |
816 | + } |
817 | + |
818 | + Audio { |
819 | + id: shutterSound |
820 | + audioRole: MediaPlayer.alert |
821 | + source: "/system/media/audio/ui/camera_click.ogg" |
822 | + } |
823 | + |
824 | + function capture() { |
825 | + if (!enabled) |
826 | + return; |
827 | + |
828 | + visible = true; |
829 | + shutterSound.stop(); |
830 | + shutterSound.play(); |
831 | + fadeIn.start(); |
832 | + } |
833 | + |
834 | + NumberAnimation on opacity { |
835 | + id: fadeIn |
836 | + from: 0.0 |
837 | + to: 1.0 |
838 | + onStopped: { |
839 | + if (visible) { |
840 | + fadeOut.start(); |
841 | + } |
842 | + } |
843 | + } |
844 | + |
845 | + NumberAnimation on opacity { |
846 | + id: fadeOut |
847 | + from: 1.0 |
848 | + to: 0.0 |
849 | + onStopped: { |
850 | + if (visible) { |
851 | + screenGrabber.captureAndSave(); |
852 | + visible = false; |
853 | + } |
854 | + } |
855 | + } |
856 | +} |
857 | |
858 | === added file 'qml/Components/VolumeKeyFilter.qml' |
859 | --- qml/Components/VolumeKeyFilter.qml 1970-01-01 00:00:00 +0000 |
860 | +++ qml/Components/VolumeKeyFilter.qml 2014-11-05 14:37:57 +0000 |
861 | @@ -0,0 +1,63 @@ |
862 | +/* |
863 | + * Copyright (C) 2014 Canonical, Ltd. |
864 | + * |
865 | + * This program is free software; you can redistribute it and/or modify |
866 | + * it under the terms of the GNU General Public License as published by |
867 | + * the Free Software Foundation; version 3. |
868 | + * |
869 | + * This program is distributed in the hope that it will be useful, |
870 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
871 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
872 | + * GNU General Public License for more details. |
873 | + * |
874 | + * You should have received a copy of the GNU General Public License |
875 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
876 | + */ |
877 | + |
878 | +import QtQuick 2.0 |
879 | +/*! |
880 | + \brief A filter for volume keys |
881 | + |
882 | +A filter which treats volume keys as single tri-state key with the states: |
883 | +VolumeUp Pressed, VolumeDown Pressed or Volume Up+Down pressed |
884 | +*/ |
885 | +QtObject { |
886 | + id: root |
887 | + |
888 | + signal volumeUpPressed() |
889 | + signal volumeDownPressed() |
890 | + signal bothVolumeKeysPressed() |
891 | + |
892 | + property bool volumeUpKeyPressed: false |
893 | + property bool volumeDownKeyPressed: false |
894 | + property bool aVolumeKeyWasReleased: true |
895 | + |
896 | + function onKeyPressed(key) { |
897 | + if (key == Qt.Key_VolumeUp) |
898 | + volumeUpKeyPressed = true; |
899 | + else if (key == Qt.Key_VolumeDown) |
900 | + volumeDownKeyPressed = true; |
901 | + |
902 | + if (volumeDownKeyPressed && volumeUpKeyPressed) { |
903 | + //avoids sending a signal repeatedly if both keys are held |
904 | + //instead one of the keys must have been previously released |
905 | + if (aVolumeKeyWasReleased) |
906 | + bothVolumeKeysPressed(); |
907 | + aVolumeKeyWasReleased = false; |
908 | + } else if (volumeDownKeyPressed) { |
909 | + volumeDownPressed(); |
910 | + } else if (volumeUpKeyPressed) { |
911 | + volumeUpPressed(); |
912 | + } |
913 | + } |
914 | + |
915 | + function onKeyReleased(key) { |
916 | + if (key == Qt.Key_VolumeUp) { |
917 | + volumeUpKeyPressed = false; |
918 | + aVolumeKeyWasReleased = true; |
919 | + } else if (key == Qt.Key_VolumeDown) { |
920 | + volumeDownKeyPressed = false; |
921 | + aVolumeKeyWasReleased = true; |
922 | + } |
923 | + } |
924 | +} |
925 | |
926 | === modified file 'qml/Greeter/Greeter.qml' |
927 | --- qml/Greeter/Greeter.qml 2014-10-17 11:01:53 +0000 |
928 | +++ qml/Greeter/Greeter.qml 2014-11-05 14:37:57 +0000 |
929 | @@ -132,7 +132,7 @@ |
930 | TouchGate { |
931 | targetItem: dragHandle |
932 | anchors.fill: targetItem |
933 | - enabled: targetITem.enabled |
934 | + enabled: targetItem.enabled |
935 | } |
936 | |
937 | Loader { |
938 | |
939 | === modified file 'qml/Greeter/Infographics.qml' |
940 | --- qml/Greeter/Infographics.qml 2014-07-29 13:47:33 +0000 |
941 | +++ qml/Greeter/Infographics.qml 2014-11-05 14:37:57 +0000 |
942 | @@ -26,8 +26,15 @@ |
943 | |
944 | property int animDuration: 10 |
945 | |
946 | - property bool __useDotAnimation: true |
947 | - property int __circleModifier: __useDotAnimation ? 1 : 2 |
948 | + QtObject { |
949 | + id: d |
950 | + objectName: "infographicPrivate" |
951 | + property bool useDotAnimation: true |
952 | + property int circleModifier: useDotAnimation ? 1 : 2 |
953 | + property bool animating: dotHideAnimTimer.running |
954 | + || dotShowAnimTimer.running |
955 | + || circleChangeAnimTimer.running |
956 | + } |
957 | |
958 | Connections { |
959 | target: model |
960 | @@ -46,7 +53,7 @@ |
961 | dotHideAnimTimer.stop() |
962 | notification.hideAnim.stop() |
963 | |
964 | - if (__useDotAnimation) { |
965 | + if (d.useDotAnimation) { |
966 | dotShowAnimTimer.startFromBeginning() |
967 | } |
968 | notification.showAnim.start() |
969 | @@ -57,7 +64,7 @@ |
970 | circleChangeAnimTimer.stop() |
971 | notification.showAnim.stop() |
972 | |
973 | - if (__useDotAnimation) { |
974 | + if (d.useDotAnimation) { |
975 | dotHideAnimTimer.startFromBeginning() |
976 | } else { |
977 | circleChangeAnimTimer.startFromBeginning() |
978 | @@ -148,21 +155,21 @@ |
979 | property: "opacity" |
980 | to: pastCircle.circleOpacity |
981 | easing.type: Easing.OutCurve |
982 | - duration: circleChangeAnimTimer.interval * __circleModifier |
983 | + duration: circleChangeAnimTimer.interval * d.circleModifier |
984 | } |
985 | PropertyAnimation { |
986 | target: pastCircle |
987 | property: "scale" |
988 | to: modelData |
989 | easing.type: Easing.OutCurve |
990 | - duration: circleChangeAnimTimer.interval * __circleModifier |
991 | + duration: circleChangeAnimTimer.interval * d.circleModifier |
992 | } |
993 | ColorAnimation { |
994 | target: pastCircle |
995 | property: "color" |
996 | to: Gradient.threeColorByIndex(index, count, infographic.model.secondColor) |
997 | easing.type: Easing.OutCurve |
998 | - duration: circleChangeAnimTimer.interval * __circleModifier |
999 | + duration: circleChangeAnimTimer.interval * d.circleModifier |
1000 | } |
1001 | } |
1002 | } |
1003 | @@ -209,21 +216,21 @@ |
1004 | property: "opacity" |
1005 | to: presentCircle.circleOpacity |
1006 | easing.type: Easing.OutCurve |
1007 | - duration: circleChangeAnimTimer.interval * __circleModifier |
1008 | + duration: circleChangeAnimTimer.interval * d.circleModifier |
1009 | } |
1010 | PropertyAnimation { |
1011 | target: presentCircle |
1012 | property: "scale" |
1013 | to: modelData |
1014 | easing.type: Easing.OutCurve |
1015 | - duration: circleChangeAnimTimer.interval * __circleModifier |
1016 | + duration: circleChangeAnimTimer.interval * d.circleModifier |
1017 | } |
1018 | ColorAnimation { |
1019 | target: presentCircle |
1020 | property: "color" |
1021 | to: Gradient.threeColorByIndex(index, infographic.model.currentDay, infographic.model.firstColor) |
1022 | easing.type: Easing.OutCurve |
1023 | - duration: circleChangeAnimTimer.interval * __circleModifier |
1024 | + duration: circleChangeAnimTimer.interval * d.circleModifier |
1025 | } |
1026 | } |
1027 | } |
1028 | @@ -385,7 +392,7 @@ |
1029 | from: notification.baseOpacity |
1030 | to: 0.0 |
1031 | duration: notification.duration * dots.count |
1032 | - onStopped: if (!__useDotAnimation) infographic.model.readyForDataChange() |
1033 | + onStopped: if (!d.useDotAnimation) infographic.model.readyForDataChange() |
1034 | } |
1035 | } |
1036 | } |
1037 | @@ -394,10 +401,8 @@ |
1038 | anchors.fill: dataCircle |
1039 | |
1040 | onDoubleClicked: { |
1041 | - if (!dotHideAnimTimer.running && |
1042 | - !dotShowAnimTimer.running && |
1043 | - !circleChangeAnimTimer.running) { |
1044 | - __useDotAnimation = false |
1045 | + if (!d.animating) { |
1046 | + d.useDotAnimation = false |
1047 | infographic.model.nextDataSource() |
1048 | } |
1049 | } |
1050 | |
1051 | === modified file 'qml/Notifications/Notification.qml' |
1052 | --- qml/Notifications/Notification.qml 2014-10-30 21:42:32 +0000 |
1053 | +++ qml/Notifications/Notification.qml 2014-11-05 14:37:57 +0000 |
1054 | @@ -398,7 +398,7 @@ |
1055 | |
1056 | spacing: contentSpacing |
1057 | |
1058 | - visible: notification.type == Notification.SnapDecision && oneOverTwoRepeaterTop.count == 3 |
1059 | + visible: notification.type === Notification.SnapDecision && oneOverTwoRepeaterTop.count === 3 |
1060 | |
1061 | Repeater { |
1062 | id: oneOverTwoRepeaterTop |
1063 | @@ -468,22 +468,41 @@ |
1064 | spacing: units.gu(2) |
1065 | layoutDirection: Qt.RightToLeft |
1066 | |
1067 | + Loader { |
1068 | + id: notifySwipeButtonLoader |
1069 | + active: notification.hints["x-canonical-snap-decisions-swipe"] === "true" |
1070 | + |
1071 | + sourceComponent: SwipeToAct { |
1072 | + objectName: "notify_swipe_button" |
1073 | + width: buttonRow.width |
1074 | + leftIconName: "call-end" |
1075 | + rightIconName: "call-start" |
1076 | + onRightTriggered: { |
1077 | + notification.notification.invokeAction(notification.actions.data(0, ActionModel.RoleActionId)) |
1078 | + } |
1079 | + |
1080 | + onLeftTriggered: { |
1081 | + notification.notification.invokeAction(notification.actions.data(1, ActionModel.RoleActionId)) |
1082 | + } |
1083 | + } |
1084 | + } |
1085 | + |
1086 | Repeater { |
1087 | id: actionRepeater |
1088 | - |
1089 | model: notification.actions |
1090 | delegate: Loader { |
1091 | id: loader |
1092 | |
1093 | property string actionId: id |
1094 | property string actionLabel: label |
1095 | + active: !notifySwipeButtonLoader.active |
1096 | |
1097 | Component { |
1098 | id: actionButton |
1099 | |
1100 | Button { |
1101 | objectName: "notify_button" + index |
1102 | - width: buttonRow.width / 2 - spacing*2 |
1103 | + width: buttonRow.width / 2 - spacing * 2 |
1104 | text: loader.actionLabel |
1105 | color: { |
1106 | var result = sdDarkGrey; |
1107 | |
1108 | === added file 'qml/Notifications/SwipeToAct.qml' |
1109 | --- qml/Notifications/SwipeToAct.qml 1970-01-01 00:00:00 +0000 |
1110 | +++ qml/Notifications/SwipeToAct.qml 2014-11-05 14:37:57 +0000 |
1111 | @@ -0,0 +1,309 @@ |
1112 | +/* |
1113 | + * Copyright (C) 2014 Canonical, Ltd. |
1114 | + * |
1115 | + * This program is free software; you can redistribute it and/or modify |
1116 | + * it under the terms of the GNU General Public License as published by |
1117 | + * the Free Software Foundation; version 3. |
1118 | + * |
1119 | + * This program is distributed in the hope that it will be useful, |
1120 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1121 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1122 | + * GNU General Public License for more details. |
1123 | + * |
1124 | + * You should have received a copy of the GNU General Public License |
1125 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1126 | + */ |
1127 | + |
1128 | +import QtQuick 2.3 |
1129 | +import Ubuntu.Components 1.1 |
1130 | +import QtGraphicalEffects 1.0 |
1131 | + |
1132 | +Item { |
1133 | + id: swipeToAct |
1134 | + |
1135 | + width: parent.width |
1136 | + height: childrenRect.height |
1137 | + |
1138 | + signal leftTriggered() |
1139 | + signal rightTriggered() |
1140 | + |
1141 | + property string leftIconName |
1142 | + property string rightIconName |
1143 | + readonly property double sliderHeight: units.gu(6) |
1144 | + readonly property double gap: units.gu(1) |
1145 | + readonly property double halfWay: mouseArea.drag.maximumX / 2 |
1146 | + |
1147 | + Rectangle { |
1148 | + id: gradient |
1149 | + width: parent.width * 5 |
1150 | + height: sliderHeight |
1151 | + visible: false |
1152 | + LinearGradient { |
1153 | + anchors.fill: parent |
1154 | + start: Qt.point(parent.x, parent.y) |
1155 | + end: Qt.point(parent.width, parent.y) |
1156 | + gradient: Gradient { |
1157 | + GradientStop { position: 0.0; color: UbuntuColors.red } |
1158 | + GradientStop { position: 0.2; color: UbuntuColors.red } |
1159 | + GradientStop { position: 0.4; color: "#dddddd" } |
1160 | + GradientStop { position: 0.6; color: "#dddddd" } |
1161 | + GradientStop { position: 0.8; color: UbuntuColors.green } |
1162 | + GradientStop { position: 1.0; color: UbuntuColors.green } |
1163 | + } |
1164 | + } |
1165 | + } |
1166 | + |
1167 | + ShaderEffectSource { |
1168 | + id: effectSourceGradient |
1169 | + sourceItem: gradient |
1170 | + width: gradient.width |
1171 | + height: gradient.height |
1172 | + sourceRect: Qt.rect(0.4 * gradient.width * (slider.x / halfWay), 0, mask.width, mask.height) |
1173 | + visible: false |
1174 | + hideSource: true |
1175 | + } |
1176 | + |
1177 | + UbuntuShape { |
1178 | + id: mask |
1179 | + color: "black" |
1180 | + width: parent.width |
1181 | + height: sliderHeight |
1182 | + borderSource: "none" |
1183 | + visible: false |
1184 | + } |
1185 | + |
1186 | + ShaderEffectSource { |
1187 | + id: effectSourceMask |
1188 | + sourceItem: mask |
1189 | + width: mask.width |
1190 | + height: mask.height |
1191 | + visible: false |
1192 | + hideSource: true |
1193 | + } |
1194 | + |
1195 | + ShaderEffect { |
1196 | + width: parent.width |
1197 | + height: sliderHeight |
1198 | + property variant mask: effectSourceMask |
1199 | + property variant gradient: effectSourceGradient |
1200 | + vertexShader: " |
1201 | + uniform highp mat4 qt_Matrix; |
1202 | + attribute highp vec4 qt_Vertex; |
1203 | + attribute highp vec2 qt_MultiTexCoord0; |
1204 | + varying highp vec2 coord; |
1205 | + void main() { |
1206 | + coord = qt_MultiTexCoord0; |
1207 | + gl_Position = qt_Matrix * qt_Vertex; |
1208 | + }" |
1209 | + fragmentShader: " |
1210 | + varying highp vec2 coord; |
1211 | + uniform sampler2D mask; |
1212 | + uniform sampler2D gradient; |
1213 | + void main() { |
1214 | + lowp vec4 texMask = texture2D(mask, coord); |
1215 | + lowp vec4 texGradient = texture2D(gradient, coord); |
1216 | + gl_FragColor = texGradient.rgba * texMask.a ; |
1217 | + }" |
1218 | + |
1219 | + Row { |
1220 | + id: row |
1221 | + anchors.fill: parent |
1222 | + spacing: gap |
1223 | + anchors.margins: gap |
1224 | + |
1225 | + UbuntuShape { |
1226 | + id: leftShape |
1227 | + states: [ |
1228 | + State { |
1229 | + name: "normal" |
1230 | + PropertyChanges { |
1231 | + target: leftShape |
1232 | + color: UbuntuColors.red |
1233 | + } |
1234 | + PropertyChanges { |
1235 | + target: innerLeftShape |
1236 | + color: UbuntuColors.red |
1237 | + visible: false |
1238 | + } |
1239 | + }, |
1240 | + State { |
1241 | + name: "selected" |
1242 | + PropertyChanges { |
1243 | + target: leftShape |
1244 | + color: "white" |
1245 | + } |
1246 | + PropertyChanges { |
1247 | + target: innerLeftShape |
1248 | + color: UbuntuColors.red |
1249 | + visible: true |
1250 | + } |
1251 | + } |
1252 | + ] |
1253 | + state: "normal" |
1254 | + height: units.gu(4) |
1255 | + width: units.gu(7) |
1256 | + borderSource: "none" |
1257 | + opacity: slider.x <= halfWay ? 1.0 : 1.0 - ((slider.x - halfWay) / halfWay) |
1258 | + UbuntuShape { |
1259 | + id: innerLeftShape |
1260 | + anchors.centerIn: parent |
1261 | + borderSource: "none" |
1262 | + width: parent.width - units.gu(.5) |
1263 | + height: parent.height - units.gu(.5) |
1264 | + } |
1265 | + Icon { |
1266 | + anchors.centerIn: parent |
1267 | + width: units.gu(2) |
1268 | + height: units.gu(2) |
1269 | + name: leftIconName |
1270 | + color: "white" |
1271 | + } |
1272 | + } |
1273 | + |
1274 | + Rectangle { |
1275 | + id: leftSpacer |
1276 | + width: (row.width - (leftShape.width + slider.width + rightShape.width + 4 * row.spacing)) / 2 |
1277 | + height: units.gu(4) |
1278 | + opacity: 0 |
1279 | + } |
1280 | + |
1281 | + UbuntuShape { |
1282 | + id: slider |
1283 | + objectName: "slider" |
1284 | + |
1285 | + Behavior on x { |
1286 | + UbuntuNumberAnimation { |
1287 | + duration: UbuntuAnimation.FastDuration |
1288 | + easing.type: Easing.OutBounce |
1289 | + } |
1290 | + } |
1291 | + |
1292 | + Behavior on opacity { |
1293 | + UbuntuNumberAnimation { |
1294 | + duration: UbuntuAnimation.FastDuration |
1295 | + } |
1296 | + } |
1297 | + |
1298 | + onOpacityChanged: { |
1299 | + if (opacity === 0) { |
1300 | + if (rightShape.state === "selected") { |
1301 | + rightTriggered() |
1302 | + } |
1303 | + if (leftShape.state === "selected") { |
1304 | + leftTriggered() |
1305 | + } |
1306 | + } |
1307 | + } |
1308 | + |
1309 | + z: 1 |
1310 | + color: "white" |
1311 | + height: units.gu(4) |
1312 | + width: units.gu(7) |
1313 | + borderSource: "none" |
1314 | + Row { |
1315 | + anchors.fill: parent |
1316 | + spacing: 2 * gap |
1317 | + anchors.leftMargin: units.gu(.5) |
1318 | + anchors.rightMargin: units.gu(.5) |
1319 | + Icon { |
1320 | + anchors.verticalCenter: parent.verticalCenter |
1321 | + name: "back" |
1322 | + width: units.gu(2) |
1323 | + height: units.gu(2) |
1324 | + } |
1325 | + Icon { |
1326 | + anchors.verticalCenter: parent.verticalCenter |
1327 | + name: "next" |
1328 | + width: units.gu(2) |
1329 | + height: units.gu(2) |
1330 | + } |
1331 | + } |
1332 | + } |
1333 | + |
1334 | + Rectangle { |
1335 | + id: rightSpacer |
1336 | + width: leftSpacer.width |
1337 | + height: units.gu(4) |
1338 | + opacity: 0 |
1339 | + } |
1340 | + |
1341 | + UbuntuShape { |
1342 | + id: rightShape |
1343 | + states: [ |
1344 | + State { |
1345 | + name: "normal" |
1346 | + PropertyChanges { |
1347 | + target: rightShape |
1348 | + color: UbuntuColors.green |
1349 | + } |
1350 | + PropertyChanges { |
1351 | + target: innerRightShape |
1352 | + color: UbuntuColors.green |
1353 | + visible: false |
1354 | + } |
1355 | + }, |
1356 | + State { |
1357 | + name: "selected" |
1358 | + PropertyChanges { |
1359 | + target: rightShape |
1360 | + color: "white" |
1361 | + } |
1362 | + PropertyChanges { |
1363 | + target: innerRightShape |
1364 | + color: UbuntuColors.green |
1365 | + visible: true |
1366 | + } |
1367 | + } |
1368 | + ] |
1369 | + state: "normal" |
1370 | + height: units.gu(4) |
1371 | + width: units.gu(7) |
1372 | + borderSource: "none" |
1373 | + opacity: slider.x >= halfWay ? 1.0 : slider.x / halfWay |
1374 | + UbuntuShape { |
1375 | + id: innerRightShape |
1376 | + anchors.centerIn: parent |
1377 | + borderSource: "none" |
1378 | + width: parent.width - units.gu(.5) |
1379 | + height: parent.height - units.gu(.5) |
1380 | + } |
1381 | + Icon { |
1382 | + anchors.centerIn: parent |
1383 | + width: units.gu(2) |
1384 | + height: units.gu(2) |
1385 | + name: rightIconName |
1386 | + color: "white" |
1387 | + } |
1388 | + } |
1389 | + } |
1390 | + |
1391 | + MouseArea { |
1392 | + id: mouseArea |
1393 | + objectName: "swipeMouseArea" |
1394 | + |
1395 | + anchors.fill: row |
1396 | + drag.target: slider |
1397 | + drag.axis: Drag.XAxis |
1398 | + drag.minimumX: 0 |
1399 | + drag.maximumX: row.width - slider.width |
1400 | + |
1401 | + onReleased: { |
1402 | + if (slider.x !== drag.minimumX || slider.x !== drag.maximumX) { |
1403 | + slider.x = halfWay |
1404 | + } |
1405 | + if (slider.x === drag.minimumX) { |
1406 | + slider.x = drag.minimumX |
1407 | + slider.opacity = 0 |
1408 | + enabled = false |
1409 | + leftShape.state = "selected" |
1410 | + } |
1411 | + if (slider.x === drag.maximumX) { |
1412 | + slider.x = drag.maximumX |
1413 | + slider.opacity = 0 |
1414 | + enabled = false |
1415 | + rightShape.state = "selected" |
1416 | + } |
1417 | + } |
1418 | + } |
1419 | + } |
1420 | +} |
1421 | |
1422 | === modified file 'qml/Panel/IndicatorPage.qml' |
1423 | --- qml/Panel/IndicatorPage.qml 2014-10-23 11:59:22 +0000 |
1424 | +++ qml/Panel/IndicatorPage.qml 2014-11-05 14:37:57 +0000 |
1425 | @@ -25,6 +25,7 @@ |
1426 | //const |
1427 | property string title: rootActionState.title |
1428 | property alias highlightFollowsCurrentItem : mainMenu.highlightFollowsCurrentItem |
1429 | + readonly property alias factory: _factory |
1430 | |
1431 | Indicators.UnityMenuModelStack { |
1432 | id: menuStack |
1433 | @@ -117,6 +118,16 @@ |
1434 | } |
1435 | } |
1436 | |
1437 | + Connections { |
1438 | + target: mainMenu.model ? mainMenu.model : null |
1439 | + onRowsAboutToBeRemoved: { |
1440 | + // track current item deletion. |
1441 | + if (mainMenu.selectedIndex >= first && mainMenu.selectedIndex <= last) { |
1442 | + mainMenu.selectedIndex = -1; |
1443 | + } |
1444 | + } |
1445 | + } |
1446 | + |
1447 | delegate: Loader { |
1448 | id: loader |
1449 | objectName: "menuItem" + index |
1450 | @@ -164,7 +175,7 @@ |
1451 | } |
1452 | |
1453 | MenuItemFactory { |
1454 | - id: factory |
1455 | + id: _factory |
1456 | rootModel: main.menuModel ? main.menuModel : null |
1457 | menuModel: mainMenu.model ? mainMenu.model : null |
1458 | } |
1459 | |
1460 | === modified file 'qml/Panel/Indicators/MenuItemFactory.qml' |
1461 | --- qml/Panel/Indicators/MenuItemFactory.qml 2014-10-06 16:22:57 +0000 |
1462 | +++ qml/Panel/Indicators/MenuItemFactory.qml 2014-11-05 14:37:57 +0000 |
1463 | @@ -290,12 +290,26 @@ |
1464 | checked: serverChecked |
1465 | highlightWhenPressed: false |
1466 | |
1467 | - onServerCheckedChanged: { |
1468 | - // value can be changed by menu, so a binding won't work. |
1469 | - checked = serverChecked; |
1470 | - } |
1471 | + onServerCheckedChanged: updateFromServer() |
1472 | onTriggered: { |
1473 | menuModel.activate(menuIndex); |
1474 | + resyncTimer.restart(); |
1475 | + } |
1476 | + |
1477 | + // value can be changed by menu, so a binding won't work. |
1478 | + function updateFromServer() { |
1479 | + resyncTimer.stop(); |
1480 | + if (checked != serverChecked) { |
1481 | + checked = serverChecked; |
1482 | + } |
1483 | + } |
1484 | + |
1485 | + // Server value is not guaranteed to change to what we expect from an activation. |
1486 | + // In this case, we need to re-assert that we are presenting the UI with the set backend value. |
1487 | + Timer { |
1488 | + id: resyncTimer |
1489 | + interval: 1500 |
1490 | + onTriggered: updateFromServer() |
1491 | } |
1492 | } |
1493 | } |
1494 | @@ -315,12 +329,26 @@ |
1495 | checked: serverChecked |
1496 | highlightWhenPressed: false |
1497 | |
1498 | - onServerCheckedChanged: { |
1499 | - // value can be changed by menu, so a binding won't work. |
1500 | - checked = serverChecked; |
1501 | - } |
1502 | + onServerCheckedChanged: updateFromServer() |
1503 | onTriggered: { |
1504 | menuModel.activate(menuIndex); |
1505 | + resyncTimer.restart(); |
1506 | + } |
1507 | + |
1508 | + // value can be changed by menu, so a binding won't work. |
1509 | + function updateFromServer() { |
1510 | + resyncTimer.stop(); |
1511 | + if (checked != serverChecked) { |
1512 | + checked = serverChecked; |
1513 | + } |
1514 | + } |
1515 | + |
1516 | + // Server value is not guaranteed to change to what we expect from an activation. |
1517 | + // In this case, we need to re-assert that we are presenting the UI with the set backend value. |
1518 | + Timer { |
1519 | + id: resyncTimer |
1520 | + interval: 1500 |
1521 | + onTriggered: updateFromServer() |
1522 | } |
1523 | } |
1524 | } |
1525 | |
1526 | === modified file 'qml/Shell.qml' |
1527 | --- qml/Shell.qml 2014-10-30 21:43:18 +0000 |
1528 | +++ qml/Shell.qml 2014-11-05 14:37:57 +0000 |
1529 | @@ -133,23 +133,32 @@ |
1530 | objectName: "dashCommunicator" |
1531 | } |
1532 | |
1533 | + ScreenGrabber { |
1534 | + id: screenGrabber |
1535 | + z: edgeDemo.z + 10 |
1536 | + enabled: Powerd.status === Powerd.On |
1537 | + } |
1538 | + |
1539 | Binding { |
1540 | target: ApplicationManager |
1541 | property: "forceDashActive" |
1542 | value: launcher.shown || launcher.dashSwipe |
1543 | } |
1544 | |
1545 | + VolumeKeyFilter { |
1546 | + id: volumeKeyFilter |
1547 | + onVolumeDownPressed: volumeControl.volumeDown() |
1548 | + onVolumeUpPressed: volumeControl.volumeUp() |
1549 | + onBothVolumeKeysPressed: screenGrabber.capture() |
1550 | + } |
1551 | |
1552 | WindowKeysFilter { |
1553 | - // Handle but do not filter out volume keys |
1554 | - Keys.onVolumeUpPressed: { volumeControl.volumeUp(); event.accepted = false; } |
1555 | - Keys.onVolumeDownPressed: { volumeControl.volumeDown(); event.accepted = false; } |
1556 | - |
1557 | Keys.onPressed: { |
1558 | if (event.key == Qt.Key_PowerOff || event.key == Qt.Key_PowerDown) { |
1559 | dialogs.onPowerKeyPressed(); |
1560 | event.accepted = true; |
1561 | } else { |
1562 | + volumeKeyFilter.onKeyPressed(event.key); |
1563 | event.accepted = false; |
1564 | } |
1565 | } |
1566 | @@ -159,6 +168,7 @@ |
1567 | dialogs.onPowerKeyReleased(); |
1568 | event.accepted = true; |
1569 | } else { |
1570 | + volumeKeyFilter.onKeyReleased(event.key); |
1571 | event.accepted = false; |
1572 | } |
1573 | } |
1574 | @@ -175,7 +185,7 @@ |
1575 | target: ApplicationManager |
1576 | onFocusRequested: { |
1577 | if (greeter.narrowMode) { |
1578 | - if (appId === "dialer-app" && callManager.hasCalls) { |
1579 | + if (appId === "dialer-app" && callManager.hasCalls && shell.locked) { |
1580 | // If we are in the middle of a call, make dialer lockedApp and show it. |
1581 | // This can happen if user backs out of dialer back to greeter, then |
1582 | // launches dialer again. |
1583 | |
1584 | === modified file 'tests/autopilot/unity8/shell/tests/test_notifications.py' |
1585 | --- tests/autopilot/unity8/shell/tests/test_notifications.py 2014-10-30 21:43:06 +0000 |
1586 | +++ tests/autopilot/unity8/shell/tests/test_notifications.py 2014-11-05 14:37:57 +0000 |
1587 | @@ -157,57 +157,6 @@ |
1588 | |
1589 | self.assert_notification_action_id_was_called('action_id') |
1590 | |
1591 | - def test_sd_incoming_call(self): |
1592 | - """Rejecting a call should make notification expand and |
1593 | - offer more options.""" |
1594 | - unity_proxy = self.launch_unity() |
1595 | - unlock_unity(unity_proxy) |
1596 | - |
1597 | - summary = "Incoming call" |
1598 | - body = "Frank Zappa\n+44 (0)7736 027340" |
1599 | - icon_path = self._get_icon_path('avatars/anna_olsson.png') |
1600 | - hints = [ |
1601 | - ("x-canonical-secondary-icon", "incoming-call"), |
1602 | - ("x-canonical-snap-decisions", "true"), |
1603 | - ("x-canonical-private-affirmative-tint", "true"), |
1604 | - ("x-canonical-private-rejection-tint", "true"), |
1605 | - ] |
1606 | - |
1607 | - actions = [ |
1608 | - ('action_accept', 'Hold + Answer'), |
1609 | - ('action_decline_1', 'End + Answer'), |
1610 | - ('action_decline_2', 'Decline'), |
1611 | - ('action_decline_3', 'message:I missed your call - can you call me now?'), |
1612 | - ('action_decline_4', 'message:I\'m running late. I\'m on my way.'), |
1613 | - ('action_decline_5', 'message:I\'m busy at the moment. I\'ll call later.'), |
1614 | - ('action_decline_6', 'edit:Custom'), |
1615 | - ] |
1616 | - |
1617 | - self._create_interactive_notification( |
1618 | - summary, |
1619 | - body, |
1620 | - icon_path, |
1621 | - "NORMAL", |
1622 | - actions, |
1623 | - hints |
1624 | - ) |
1625 | - |
1626 | - notify_list = self._get_notifications_list() |
1627 | - get_notification = lambda: notify_list.wait_select_single( |
1628 | - 'Notification', objectName='notification1') |
1629 | - notification = get_notification() |
1630 | - self._assert_notification(notification, summary, body, True, True, 1.0) |
1631 | - notification.pointing_device.click_object( |
1632 | - notification.select_single(objectName="combobutton_dropdown")) |
1633 | - self.assertThat( |
1634 | - notification.select_single(objectName="notify_button2").expanded, |
1635 | - Eventually(Equals(True))) |
1636 | - time.sleep(2) |
1637 | - notification.pointing_device.click_object( |
1638 | - notification.select_single(objectName="notify_button4")) |
1639 | - self.assert_notification_action_id_was_called("action_decline_4") |
1640 | - |
1641 | - |
1642 | def test_sd_one_over_two_layout(self): |
1643 | """Snap-decision with three actions should use one-over two button layout.""" |
1644 | unity_proxy = self.launch_unity() |
1645 | |
1646 | === modified file 'tests/mocks/QtMultimedia/QtMultimedia.qmltypes' |
1647 | --- tests/mocks/QtMultimedia/QtMultimedia.qmltypes 2014-06-26 07:47:57 +0000 |
1648 | +++ tests/mocks/QtMultimedia/QtMultimedia.qmltypes 2014-11-05 14:37:57 +0000 |
1649 | @@ -20,11 +20,21 @@ |
1650 | "StoppedState": 2 |
1651 | } |
1652 | } |
1653 | + Enum { |
1654 | + name: "AudioRole" |
1655 | + values: { |
1656 | + "AlarmRole": 0, |
1657 | + "AlertRole": 1, |
1658 | + "MultimediaRole": 2, |
1659 | + "PhoneRole": 3 |
1660 | + } |
1661 | + } |
1662 | Property { name: "source"; type: "QUrl" } |
1663 | Property { name: "playbackState"; type: "PlaybackState"; isReadonly: true } |
1664 | Property { name: "position"; type: "int"; isReadonly: true } |
1665 | Property { name: "duration"; type: "int"; isReadonly: true } |
1666 | Property { name: "errorString"; type: "string"; isReadonly: true } |
1667 | + Property { name: "audioRole"; type: "AudioRole" } |
1668 | Signal { |
1669 | name: "sourceChanged" |
1670 | Parameter { name: "source"; type: "QUrl" } |
1671 | |
1672 | === modified file 'tests/mocks/QtMultimedia/audio.cpp' |
1673 | --- tests/mocks/QtMultimedia/audio.cpp 2014-09-12 14:51:55 +0000 |
1674 | +++ tests/mocks/QtMultimedia/audio.cpp 2014-11-05 14:37:57 +0000 |
1675 | @@ -105,3 +105,13 @@ |
1676 | stop(); |
1677 | } |
1678 | } |
1679 | + |
1680 | +Audio::AudioRole Audio::audioRole() const |
1681 | +{ |
1682 | + return Audio::MultimediaRole; |
1683 | +} |
1684 | + |
1685 | +void Audio::setAudioRole(Audio::AudioRole audioRole) |
1686 | +{ |
1687 | + Q_UNUSED(audioRole); |
1688 | +} |
1689 | |
1690 | === modified file 'tests/mocks/QtMultimedia/audio.h' |
1691 | --- tests/mocks/QtMultimedia/audio.h 2013-11-14 12:12:05 +0000 |
1692 | +++ tests/mocks/QtMultimedia/audio.h 2014-11-05 14:37:57 +0000 |
1693 | @@ -27,11 +27,13 @@ |
1694 | { |
1695 | Q_OBJECT |
1696 | Q_ENUMS(PlaybackState) |
1697 | + Q_ENUMS(AudioRole) |
1698 | Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) |
1699 | Q_PROPERTY(PlaybackState playbackState READ playbackState NOTIFY playbackStateChanged) |
1700 | Q_PROPERTY(int position READ position NOTIFY positionChanged) |
1701 | Q_PROPERTY(int duration READ duration NOTIFY durationChanged) |
1702 | Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged) |
1703 | + Q_PROPERTY(AudioRole audioRole READ audioRole WRITE setAudioRole) |
1704 | public: |
1705 | enum PlaybackState { |
1706 | PlayingState, |
1707 | @@ -39,6 +41,13 @@ |
1708 | StoppedState |
1709 | }; |
1710 | |
1711 | + enum AudioRole { |
1712 | + AlarmRole, |
1713 | + AlertRole, |
1714 | + MultimediaRole, |
1715 | + PhoneRole |
1716 | + }; |
1717 | + |
1718 | explicit Audio(QObject *parent = 0); |
1719 | |
1720 | QUrl source() const; |
1721 | @@ -52,6 +61,9 @@ |
1722 | |
1723 | QString errorString() const; |
1724 | |
1725 | + AudioRole audioRole() const; |
1726 | + void setAudioRole(AudioRole audioRole); |
1727 | + |
1728 | public Q_SLOTS: |
1729 | void pause(); |
1730 | void play(); |
1731 | |
1732 | === modified file 'tests/mocks/Unity/Notifications/CMakeLists.txt' |
1733 | --- tests/mocks/Unity/Notifications/CMakeLists.txt 2014-05-02 23:27:02 +0000 |
1734 | +++ tests/mocks/Unity/Notifications/CMakeLists.txt 2014-11-05 14:37:57 +0000 |
1735 | @@ -1,1 +1,15 @@ |
1736 | -add_unity8_mock(Unity.Notifications 1.0 Unity/Notifications) |
1737 | +include_directories( |
1738 | + ${CMAKE_CURRENT_SOURCE_DIR} |
1739 | +) |
1740 | + |
1741 | +set(MockNotificationsPlugin_SOURCES |
1742 | + plugin.cpp |
1743 | + MockNotificationTypes.cpp |
1744 | + MockActionModel.cpp |
1745 | +) |
1746 | + |
1747 | +add_library(MockNotificationsPlugin MODULE ${MockNotificationsPlugin_SOURCES}) |
1748 | + |
1749 | +qt5_use_modules(MockNotificationsPlugin Core Quick) |
1750 | + |
1751 | +add_unity8_mock(Unity.Notifications 1.0 Unity/Notifications TARGETS MockNotificationsPlugin) |
1752 | |
1753 | === added file 'tests/mocks/Unity/Notifications/MockActionModel.cpp' |
1754 | --- tests/mocks/Unity/Notifications/MockActionModel.cpp 1970-01-01 00:00:00 +0000 |
1755 | +++ tests/mocks/Unity/Notifications/MockActionModel.cpp 2014-11-05 14:37:57 +0000 |
1756 | @@ -0,0 +1,72 @@ |
1757 | +/* |
1758 | + * Copyright 2014 Canonical Ltd. |
1759 | + * |
1760 | + * This program is free software; you can redistribute it and/or modify |
1761 | + * it under the terms of the GNU Lesser General Public License as published by |
1762 | + * the Free Software Foundation; version 3. |
1763 | + * |
1764 | + * This program is distributed in the hope that it will be useful, |
1765 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1766 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1767 | + * GNU Lesser General Public License for more details. |
1768 | + * |
1769 | + * You should have received a copy of the GNU Lesser General Public License |
1770 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1771 | + * |
1772 | + * Authors: |
1773 | + * Mirco Mueller <mirco.mueller@canonical.com> |
1774 | + */ |
1775 | + |
1776 | +#include "MockActionModel.h" |
1777 | + |
1778 | +struct ActionModelPrivate { |
1779 | + QList<QString> labels; |
1780 | + QList<QString> ids; |
1781 | +}; |
1782 | + |
1783 | +ActionModel::ActionModel(QObject *parent) : QStringListModel(parent), p(new ActionModelPrivate) { |
1784 | + insertAction("ok_id", "Ok"); |
1785 | + insertAction("cancel_id", "Cancel"); |
1786 | +} |
1787 | + |
1788 | +ActionModel::~ActionModel() { |
1789 | +} |
1790 | + |
1791 | +int ActionModel::rowCount(const QModelIndex &index) const { |
1792 | + return p->labels.size(); |
1793 | +} |
1794 | + |
1795 | +QVariant ActionModel::data(const QModelIndex &index, int role) const { |
1796 | + if (!index.isValid()) |
1797 | + return QVariant(); |
1798 | + |
1799 | + switch(role) { |
1800 | + case RoleActionLabel: |
1801 | + return QVariant(p->labels[index.row()]); |
1802 | + |
1803 | + case RoleActionId: |
1804 | + return QVariant(p->ids[index.row()]); |
1805 | + |
1806 | + default: |
1807 | + return QVariant(); |
1808 | + } |
1809 | +} |
1810 | + |
1811 | +QHash<int, QByteArray> ActionModel::roleNames() const { |
1812 | + QHash<int, QByteArray> roles; |
1813 | + |
1814 | + roles.insert(RoleActionLabel, "label"); |
1815 | + roles.insert(RoleActionId, "id"); |
1816 | + |
1817 | + return roles; |
1818 | +} |
1819 | + |
1820 | +Q_INVOKABLE QVariant ActionModel::data(int row, int role) const |
1821 | +{ |
1822 | + return data(index(row, 0), role); |
1823 | +} |
1824 | + |
1825 | +void ActionModel::insertAction(const QString &id, const QString &label) { |
1826 | + p->ids.push_back(id); |
1827 | + p->labels.push_back(label); |
1828 | +} |
1829 | |
1830 | === added file 'tests/mocks/Unity/Notifications/MockActionModel.h' |
1831 | --- tests/mocks/Unity/Notifications/MockActionModel.h 1970-01-01 00:00:00 +0000 |
1832 | +++ tests/mocks/Unity/Notifications/MockActionModel.h 2014-11-05 14:37:57 +0000 |
1833 | @@ -0,0 +1,51 @@ |
1834 | +/* |
1835 | + * Copyright 2014 Canonical Ltd. |
1836 | + * |
1837 | + * This program is free software; you can redistribute it and/or modify |
1838 | + * it under the terms of the GNU Lesser General Public License as published by |
1839 | + * the Free Software Foundation; version 3. |
1840 | + * |
1841 | + * This program is distributed in the hope that it will be useful, |
1842 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1843 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1844 | + * GNU Lesser General Public License for more details. |
1845 | + * |
1846 | + * You should have received a copy of the GNU Lesser General Public License |
1847 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1848 | + * |
1849 | + * Authors: |
1850 | + * Mirco Mueller <mirco.mueller@canonical.com> |
1851 | + */ |
1852 | + |
1853 | +#ifndef MOCK_ACTION_MODEL_H |
1854 | +#define MOCK_ACTION_MODEL_H |
1855 | + |
1856 | +#include <QStringListModel> |
1857 | + |
1858 | +struct ActionModelPrivate; |
1859 | + |
1860 | +class ActionModel : public QStringListModel { |
1861 | + Q_OBJECT |
1862 | + |
1863 | +public: |
1864 | + ActionModel(QObject *parent=nullptr); |
1865 | + virtual ~ActionModel(); |
1866 | + |
1867 | + virtual int rowCount(const QModelIndex &index) const; |
1868 | + virtual QVariant data(const QModelIndex &index, int role) const; |
1869 | + virtual QHash<int, QByteArray> roleNames() const; |
1870 | + |
1871 | + Q_ENUMS(ActionsRoles) |
1872 | + enum ActionsRoles { |
1873 | + RoleActionLabel = Qt::UserRole + 1, |
1874 | + RoleActionId = Qt::UserRole + 2 |
1875 | + }; |
1876 | + Q_INVOKABLE QVariant data(int row, int role) const; |
1877 | + |
1878 | + void insertAction(const QString &id, const QString &label); |
1879 | + |
1880 | +private: |
1881 | + QScopedPointer<ActionModelPrivate> p; |
1882 | +}; |
1883 | + |
1884 | +#endif // MOCK_ACTION_MODEL_H |
1885 | |
1886 | === added file 'tests/mocks/Unity/Notifications/MockNotificationTypes.cpp' |
1887 | --- tests/mocks/Unity/Notifications/MockNotificationTypes.cpp 1970-01-01 00:00:00 +0000 |
1888 | +++ tests/mocks/Unity/Notifications/MockNotificationTypes.cpp 2014-11-05 14:37:57 +0000 |
1889 | @@ -0,0 +1,26 @@ |
1890 | +/* |
1891 | + * Copyright 2014 Canonical Ltd. |
1892 | + * |
1893 | + * This program is free software; you can redistribute it and/or modify |
1894 | + * it under the terms of the GNU Lesser General Public License as published by |
1895 | + * the Free Software Foundation; version 3. |
1896 | + * |
1897 | + * This program is distributed in the hope that it will be useful, |
1898 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1899 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1900 | + * GNU Lesser General Public License for more details. |
1901 | + * |
1902 | + * You should have received a copy of the GNU Lesser General Public License |
1903 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1904 | + * |
1905 | + * Authors: |
1906 | + * Mirco Mueller <mirco.mueller@canonical.com> |
1907 | + */ |
1908 | + |
1909 | +#include "MockNotificationTypes.h" |
1910 | + |
1911 | +MockNotification::MockNotification(QObject *parent) : QObject(parent) { |
1912 | +} |
1913 | + |
1914 | +MockNotification::~MockNotification() { |
1915 | +} |
1916 | |
1917 | === added file 'tests/mocks/Unity/Notifications/MockNotificationTypes.h' |
1918 | --- tests/mocks/Unity/Notifications/MockNotificationTypes.h 1970-01-01 00:00:00 +0000 |
1919 | +++ tests/mocks/Unity/Notifications/MockNotificationTypes.h 2014-11-05 14:37:57 +0000 |
1920 | @@ -0,0 +1,36 @@ |
1921 | +/* |
1922 | + * Copyright 2014 Canonical Ltd. |
1923 | + * |
1924 | + * This program is free software; you can redistribute it and/or modify |
1925 | + * it under the terms of the GNU Lesser General Public License as published by |
1926 | + * the Free Software Foundation; version 3. |
1927 | + * |
1928 | + * This program is distributed in the hope that it will be useful, |
1929 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1930 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1931 | + * GNU Lesser General Public License for more details. |
1932 | + * |
1933 | + * You should have received a copy of the GNU Lesser General Public License |
1934 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1935 | + * |
1936 | + * Authors: |
1937 | + * Mirco Mueller <mirco.mueller@canonical.com> |
1938 | + */ |
1939 | + |
1940 | +#ifndef MOCK_NOTIFICATION_TYPES_H |
1941 | +#define MOCK_NOTIFICATION_TYPES_H |
1942 | + |
1943 | +#include <QObject> |
1944 | + |
1945 | +class MockNotification : public QObject { |
1946 | + Q_OBJECT |
1947 | + Q_ENUMS(Type) |
1948 | + |
1949 | +public: |
1950 | + MockNotification(QObject *parent=nullptr); |
1951 | + virtual ~MockNotification(); |
1952 | + |
1953 | + enum Type { PlaceHolder, Confirmation, Ephemeral, Interactive, SnapDecision }; |
1954 | +}; |
1955 | + |
1956 | +#endif // MOCK_NOTIFICATION_TYPES_H |
1957 | |
1958 | === removed file 'tests/mocks/Unity/Notifications/notification.js' |
1959 | --- tests/mocks/Unity/Notifications/notification.js 2013-06-19 10:24:31 +0000 |
1960 | +++ tests/mocks/Unity/Notifications/notification.js 1970-01-01 00:00:00 +0000 |
1961 | @@ -1,23 +0,0 @@ |
1962 | -/* |
1963 | - * Copyright (C) 2013 Canonical, Ltd. |
1964 | - * |
1965 | - * This program is free software; you can redistribute it and/or modify |
1966 | - * it under the terms of the GNU General Public License as published by |
1967 | - * the Free Software Foundation; version 3. |
1968 | - * |
1969 | - * This program is distributed in the hope that it will be useful, |
1970 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1971 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1972 | - * GNU General Public License for more details. |
1973 | - * |
1974 | - * You should have received a copy of the GNU General Public License |
1975 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1976 | - */ |
1977 | - |
1978 | -.pragma library |
1979 | - |
1980 | -var Confirmation = 0; |
1981 | -var Ephemeral = 1; |
1982 | -var Interactive = 2; |
1983 | -var SnapDecision = 3; |
1984 | -var PlaceHolder = 4; |
1985 | |
1986 | === added file 'tests/mocks/Unity/Notifications/plugin.cpp' |
1987 | --- tests/mocks/Unity/Notifications/plugin.cpp 1970-01-01 00:00:00 +0000 |
1988 | +++ tests/mocks/Unity/Notifications/plugin.cpp 2014-11-05 14:37:57 +0000 |
1989 | @@ -0,0 +1,31 @@ |
1990 | +/* |
1991 | + * Copyright 2014 Canonical Ltd. |
1992 | + * |
1993 | + * This program is free software; you can redistribute it and/or modify |
1994 | + * it under the terms of the GNU Lesser General Public License as published by |
1995 | + * the Free Software Foundation; version 3. |
1996 | + * |
1997 | + * This program is distributed in the hope that it will be useful, |
1998 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1999 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2000 | + * GNU Lesser General Public License for more details. |
2001 | + * |
2002 | + * You should have received a copy of the GNU Lesser General Public License |
2003 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2004 | + * |
2005 | + * Authors: |
2006 | + * Mirco Mueller <mirco.mueller@canonical.com> |
2007 | + */ |
2008 | + |
2009 | +#include "plugin.h" |
2010 | +#include "MockActionModel.h" |
2011 | +#include "MockNotificationTypes.h" |
2012 | + |
2013 | +#include <QtQml/qqml.h> |
2014 | + |
2015 | +void TestNotificationPlugin::registerTypes(const char* uri) |
2016 | +{ |
2017 | + // @uri Unity.Notifications |
2018 | + qmlRegisterUncreatableType<MockNotification>(uri, 1, 0, "Notification", "Notification objects can only be created by the plugin"); |
2019 | + qmlRegisterType<ActionModel>(uri, 1, 0, "ActionModel"); |
2020 | +} |
2021 | |
2022 | === added file 'tests/mocks/Unity/Notifications/plugin.h' |
2023 | --- tests/mocks/Unity/Notifications/plugin.h 1970-01-01 00:00:00 +0000 |
2024 | +++ tests/mocks/Unity/Notifications/plugin.h 2014-11-05 14:37:57 +0000 |
2025 | @@ -0,0 +1,35 @@ |
2026 | +/* |
2027 | + * Copyright 2014 Canonical Ltd. |
2028 | + * |
2029 | + * This program is free software; you can redistribute it and/or modify |
2030 | + * it under the terms of the GNU Lesser General Public License as published by |
2031 | + * the Free Software Foundation; version 3. |
2032 | + * |
2033 | + * This program is distributed in the hope that it will be useful, |
2034 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2035 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
2036 | + * GNU Lesser General Public License for more details. |
2037 | + * |
2038 | + * You should have received a copy of the GNU Lesser General Public License |
2039 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
2040 | + * |
2041 | + * Authors: |
2042 | + * Mirco Mueller <mirco.mueller@canonical.com> |
2043 | + */ |
2044 | + |
2045 | + |
2046 | +#ifndef TESTNOTIFICATION_PLUGIN_H |
2047 | +#define TESTNOTIFICATION_PLUGIN_H |
2048 | + |
2049 | +#include <QtQml/QQmlExtensionPlugin> |
2050 | + |
2051 | +class TestNotificationPlugin : public QQmlExtensionPlugin |
2052 | +{ |
2053 | + Q_OBJECT |
2054 | + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface") |
2055 | + |
2056 | +public: |
2057 | + void registerTypes(const char* uri); |
2058 | +}; |
2059 | + |
2060 | +#endif // TESTNOTIFICATION_PLUGIN_H |
2061 | |
2062 | === modified file 'tests/mocks/Unity/Notifications/qmldir' |
2063 | --- tests/mocks/Unity/Notifications/qmldir 2014-05-02 22:57:21 +0000 |
2064 | +++ tests/mocks/Unity/Notifications/qmldir 2014-11-05 14:37:57 +0000 |
2065 | @@ -1,3 +1,4 @@ |
2066 | module Unity.Notifications |
2067 | -Notification 1.0 notification.js |
2068 | +plugin MockNotificationsPlugin |
2069 | typeinfo Notifications.qmltypes |
2070 | + |
2071 | |
2072 | === modified file 'tests/plugins/Ubuntu/Gestures/GestureTest.cpp' |
2073 | --- tests/plugins/Ubuntu/Gestures/GestureTest.cpp 2014-10-17 11:01:53 +0000 |
2074 | +++ tests/plugins/Ubuntu/Gestures/GestureTest.cpp 2014-11-05 14:37:57 +0000 |
2075 | @@ -90,6 +90,7 @@ |
2076 | mousePressEventHandler = defaultMouseEventHandler; |
2077 | mouseMoveEventHandler = defaultMouseEventHandler; |
2078 | mouseReleaseEventHandler = defaultMouseEventHandler; |
2079 | + mouseDoubleClickEventHandler = defaultMouseEventHandler; |
2080 | } |
2081 | |
2082 | void DummyItem::touchEvent(QTouchEvent *event) |
2083 | @@ -113,6 +114,11 @@ |
2084 | mouseReleaseEventHandler(event); |
2085 | } |
2086 | |
2087 | +void DummyItem::mouseDoubleClickEvent(QMouseEvent *event) |
2088 | +{ |
2089 | + mouseDoubleClickEventHandler(event); |
2090 | +} |
2091 | + |
2092 | void DummyItem::defaultTouchEventHandler(QTouchEvent *event) |
2093 | { |
2094 | event->accept(); |
2095 | |
2096 | === modified file 'tests/plugins/Ubuntu/Gestures/GestureTest.h' |
2097 | --- tests/plugins/Ubuntu/Gestures/GestureTest.h 2014-10-17 11:01:53 +0000 |
2098 | +++ tests/plugins/Ubuntu/Gestures/GestureTest.h 2014-11-05 14:37:57 +0000 |
2099 | @@ -52,12 +52,14 @@ |
2100 | std::function<void(QMouseEvent*)> mousePressEventHandler; |
2101 | std::function<void(QMouseEvent*)> mouseMoveEventHandler; |
2102 | std::function<void(QMouseEvent*)> mouseReleaseEventHandler; |
2103 | + std::function<void(QMouseEvent*)> mouseDoubleClickEventHandler; |
2104 | protected: |
2105 | void touchEvent(QTouchEvent *event) override; |
2106 | |
2107 | void mousePressEvent(QMouseEvent *event) override; |
2108 | void mouseMoveEvent(QMouseEvent *event) override; |
2109 | void mouseReleaseEvent(QMouseEvent *event) override; |
2110 | + void mouseDoubleClickEvent(QMouseEvent *event) override; |
2111 | private: |
2112 | static void defaultTouchEventHandler(QTouchEvent *event); |
2113 | static void defaultMouseEventHandler(QMouseEvent *event); |
2114 | |
2115 | === modified file 'tests/plugins/Ubuntu/Gestures/tst_TouchDispatcher.cpp' |
2116 | --- tests/plugins/Ubuntu/Gestures/tst_TouchDispatcher.cpp 2014-10-17 11:01:53 +0000 |
2117 | +++ tests/plugins/Ubuntu/Gestures/tst_TouchDispatcher.cpp 2014-11-05 14:37:57 +0000 |
2118 | @@ -16,6 +16,7 @@ |
2119 | |
2120 | #include <QtTest> |
2121 | #include <QQuickView> |
2122 | +#include <QStyleHints> |
2123 | |
2124 | #include "GestureTest.h" |
2125 | |
2126 | @@ -29,6 +30,8 @@ |
2127 | private Q_SLOTS: |
2128 | void sendMouseEventIfTouchIgnored_data(); |
2129 | void sendMouseEventIfTouchIgnored(); |
2130 | + void mouseDoubleClick_data(); |
2131 | + void mouseDoubleClick(); |
2132 | }; |
2133 | |
2134 | tst_TouchDispatcher::tst_TouchDispatcher() |
2135 | @@ -85,6 +88,62 @@ |
2136 | QCOMPARE(gotMousePressEvent, shouldGetMousePress); |
2137 | } |
2138 | |
2139 | +void tst_TouchDispatcher::mouseDoubleClick_data() |
2140 | +{ |
2141 | + QTest::addColumn<ulong>("timeBetweenClicks"); |
2142 | + QTest::addColumn<bool>("shouldSendDoubleClick"); |
2143 | + |
2144 | + QTest::newRow("double click") << static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval() / 10) << true; |
2145 | + QTest::newRow("two separate clicks") << static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval() * 2) << false; |
2146 | +} |
2147 | + |
2148 | +void tst_TouchDispatcher::mouseDoubleClick() |
2149 | +{ |
2150 | + QFETCH(ulong, timeBetweenClicks); |
2151 | + QFETCH(bool, shouldSendDoubleClick); |
2152 | + DummyItem *dummyItem = new DummyItem(m_view->rootObject()); |
2153 | + dummyItem->setAcceptedMouseButtons(Qt::LeftButton); |
2154 | + |
2155 | + TouchDispatcher touchDispatcher; |
2156 | + touchDispatcher.setTargetItem(dummyItem); |
2157 | + |
2158 | + bool gotDoubleClickEvent = false; |
2159 | + dummyItem->mouseDoubleClickEventHandler = [&](QMouseEvent *event) { |
2160 | + gotDoubleClickEvent = true; |
2161 | + event->accept(); |
2162 | + }; |
2163 | + |
2164 | + dummyItem->touchEventHandler = [&](QTouchEvent *event) { |
2165 | + event->ignore(); |
2166 | + }; |
2167 | + |
2168 | + ulong doubleClickInterval = static_cast<ulong>(qApp->styleHints()->mouseDoubleClickInterval()); |
2169 | + |
2170 | + QList<QTouchEvent::TouchPoint> touchPoints; |
2171 | + { |
2172 | + QTouchEvent::TouchPoint touchPoint; |
2173 | + touchPoint.setId(0); |
2174 | + touchPoint.setState(Qt::TouchPointPressed); |
2175 | + touchPoints.append(touchPoint); |
2176 | + } |
2177 | + ulong timestamp = 12345; |
2178 | + |
2179 | + touchDispatcher.dispatch(QEvent::TouchBegin, m_device, Qt::NoModifier, touchPoints, m_view, timestamp); |
2180 | + |
2181 | + touchPoints[0].setState(Qt::TouchPointReleased); |
2182 | + timestamp += doubleClickInterval / 10; |
2183 | + |
2184 | + touchDispatcher.dispatch(QEvent::TouchEnd, m_device, Qt::NoModifier, touchPoints, m_view, timestamp); |
2185 | + |
2186 | + touchPoints[0].setId(1); |
2187 | + touchPoints[0].setState(Qt::TouchPointPressed); |
2188 | + timestamp += timeBetweenClicks; |
2189 | + |
2190 | + touchDispatcher.dispatch(QEvent::TouchBegin, m_device, Qt::NoModifier, touchPoints, m_view, timestamp); |
2191 | + |
2192 | + QCOMPARE(gotDoubleClickEvent, shouldSendDoubleClick); |
2193 | +} |
2194 | + |
2195 | QTEST_MAIN(tst_TouchDispatcher) |
2196 | |
2197 | #include "tst_TouchDispatcher.moc" |
2198 | |
2199 | === modified file 'tests/plugins/Unity/Launcher/launchermodeltest.cpp' |
2200 | --- tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-10-30 21:40:34 +0000 |
2201 | +++ tests/plugins/Unity/Launcher/launchermodeltest.cpp 2014-11-05 14:37:57 +0000 |
2202 | @@ -365,8 +365,8 @@ |
2203 | QCOMPARE(map.value("countVisible").toBool(), false); |
2204 | |
2205 | // Now make it visible and set it to 55 through D-Bus |
2206 | - interface.call("Set", "com.canonical.Unity.Launcher.Item", "count", 55); |
2207 | - interface.call("Set", "com.canonical.Unity.Launcher.Item", "countVisible", true); |
2208 | + interface.call("Set", "com.canonical.Unity.Launcher.Item", "count", QVariant::fromValue(QDBusVariant(55))); |
2209 | + interface.call("Set", "com.canonical.Unity.Launcher.Item", "countVisible", QVariant::fromValue(QDBusVariant(true))); |
2210 | |
2211 | // Fetch it again using GetAll |
2212 | reply = interface.call("GetAll"); |
2213 | |
2214 | === modified file 'tests/qmltests/CMakeLists.txt' |
2215 | --- tests/qmltests/CMakeLists.txt 2014-10-13 09:23:34 +0000 |
2216 | +++ tests/qmltests/CMakeLists.txt 2014-11-05 14:37:57 +0000 |
2217 | @@ -70,6 +70,7 @@ |
2218 | add_qml_test(Launcher Launcher) |
2219 | add_qml_test(Notifications Notifications) |
2220 | add_qml_test(Notifications VisualSnapDecisionsQueue) |
2221 | +add_qml_test(Notifications SwipeToAct) |
2222 | add_qml_test(Panel ActiveCallHint) |
2223 | add_qml_test(Panel IndicatorItem) |
2224 | add_qml_test(Panel IndicatorItemRow ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/QMenuModel") |
2225 | |
2226 | === modified file 'tests/qmltests/Greeter/tst_SingleGreeter.qml' |
2227 | --- tests/qmltests/Greeter/tst_SingleGreeter.qml 2014-10-01 13:20:32 +0000 |
2228 | +++ tests/qmltests/Greeter/tst_SingleGreeter.qml 2014-11-05 14:37:57 +0000 |
2229 | @@ -27,50 +27,72 @@ |
2230 | width: units.gu(60) |
2231 | height: units.gu(80) |
2232 | |
2233 | - Greeter { |
2234 | - id: greeter |
2235 | - width: parent.width |
2236 | - height: parent.height |
2237 | - x: 0; y: 0 |
2238 | - |
2239 | - property int minX: 0 |
2240 | - |
2241 | - onXChanged: { |
2242 | - if (x < minX) { |
2243 | - minX = x; |
2244 | - } |
2245 | - } |
2246 | - } |
2247 | - |
2248 | - Component { |
2249 | - id: greeterComponent |
2250 | - Greeter { |
2251 | - SignalSpy { |
2252 | - objectName: "selectedSpy" |
2253 | - target: parent |
2254 | - signalName: "selected" |
2255 | + Loader { |
2256 | + id: greeterLoader |
2257 | + anchors.fill: parent |
2258 | + |
2259 | + property bool itemDestroyed: false |
2260 | + |
2261 | + sourceComponent: Component { |
2262 | + Greeter { |
2263 | + anchors.fill: greeterLoader |
2264 | + |
2265 | + property int minX: 0 |
2266 | + |
2267 | + onXChanged: { |
2268 | + if (x < minX) { |
2269 | + minX = x; |
2270 | + } |
2271 | + } |
2272 | + |
2273 | + Component.onDestruction: { |
2274 | + greeterLoader.itemDestroyed = true; |
2275 | + } |
2276 | + SignalSpy { |
2277 | + objectName: "selectedSpy" |
2278 | + target: parent |
2279 | + signalName: "selected" |
2280 | + } |
2281 | } |
2282 | } |
2283 | } |
2284 | |
2285 | SignalSpy { |
2286 | id: unlockSpy |
2287 | - target: greeter |
2288 | + target: greeterLoader.item |
2289 | signalName: "unlocked" |
2290 | } |
2291 | |
2292 | SignalSpy { |
2293 | id: teaseSpy |
2294 | - target: greeter |
2295 | + target: greeterLoader.item |
2296 | signalName: "tease" |
2297 | } |
2298 | |
2299 | + SignalSpy { |
2300 | + id: infographicDataChangedSpy |
2301 | + target: LightDM.Infographic |
2302 | + signalName: "dataChanged" |
2303 | + } |
2304 | + |
2305 | UT.UnityTestCase { |
2306 | name: "SingleGreeter" |
2307 | when: windowShown |
2308 | |
2309 | + property Greeter greeter: greeterLoader.item |
2310 | + |
2311 | function cleanup() { |
2312 | AccountsService.statsWelcomeScreen = true |
2313 | + |
2314 | + // force a reload so that we get a fresh Greeter for the next test |
2315 | + greeterLoader.itemDestroyed = false; |
2316 | + greeterLoader.active = false; |
2317 | + tryCompare(greeterLoader, "itemDestroyed", true); |
2318 | + |
2319 | + unlockSpy.clear(); |
2320 | + teaseSpy.clear(); |
2321 | + |
2322 | + greeterLoader.active = true; |
2323 | } |
2324 | |
2325 | function test_properties() { |
2326 | @@ -103,11 +125,32 @@ |
2327 | } |
2328 | |
2329 | function test_initial_selected_signal() { |
2330 | - var greeterObj = greeterComponent.createObject(this) |
2331 | - var spy = findChild(greeterObj, "selectedSpy") |
2332 | - spy.wait() |
2333 | - tryCompare(spy, "count", 1) |
2334 | - greeterObj.destroy() |
2335 | + var selectedSpy = findChild(greeter, "selectedSpy"); |
2336 | + selectedSpy.wait(); |
2337 | + tryCompare(selectedSpy, "count", 1); |
2338 | + } |
2339 | + |
2340 | + /* |
2341 | + Regression test for https://bugs.launchpad.net/ubuntu/+source/unity8/+bug/1388359 |
2342 | + "User metrics can no longer be changed by double tap" |
2343 | + */ |
2344 | + function test_doubleTapSwitchesToNextInfographic() { |
2345 | + infographicDataChangedSpy.clear(); |
2346 | + |
2347 | + var infographicPrivate = findInvisibleChild(greeter, "infographicPrivate"); |
2348 | + verify(infographicPrivate); |
2349 | + |
2350 | + // wait for the UI to settle down before double tapping it |
2351 | + tryCompare(infographicPrivate, "animating", false); |
2352 | + |
2353 | + var dataCircle = findChild(greeter, "dataCircle"); |
2354 | + verify(dataCircle); |
2355 | + |
2356 | + tap(dataCircle); |
2357 | + wait(1); |
2358 | + tap(dataCircle); |
2359 | + |
2360 | + tryCompare(infographicDataChangedSpy, "count", 1); |
2361 | } |
2362 | } |
2363 | } |
2364 | |
2365 | === modified file 'tests/qmltests/Notifications/tst_Notifications.qml' |
2366 | --- tests/qmltests/Notifications/tst_Notifications.qml 2014-10-14 10:07:44 +0000 |
2367 | +++ tests/qmltests/Notifications/tst_Notifications.qml 2014-11-05 14:37:57 +0000 |
2368 | @@ -23,280 +23,51 @@ |
2369 | import Unity.Notifications 1.0 |
2370 | import QtMultimedia 5.0 |
2371 | |
2372 | -Row { |
2373 | - id: rootRow |
2374 | - |
2375 | - Component { |
2376 | - id: mockNotification |
2377 | - |
2378 | - QtObject { |
2379 | - function invokeAction(actionId) { |
2380 | - mockModel.actionInvoked(actionId) |
2381 | - } |
2382 | - } |
2383 | - } |
2384 | - |
2385 | - ListModel { |
2386 | - id: mockModel |
2387 | - |
2388 | - signal actionInvoked(string actionId) |
2389 | - |
2390 | - function getRaw(id) { |
2391 | - return mockNotification.createObject(mockModel) |
2392 | - } |
2393 | - |
2394 | - // add the default/PlaceHolder notification to the model |
2395 | - Component.onCompleted: { |
2396 | +Item { |
2397 | + width: notificationsRect.width + interactiveControls.width |
2398 | + height: notificationsRect.height |
2399 | + |
2400 | + Row { |
2401 | + id: rootRow |
2402 | + |
2403 | + Component { |
2404 | + id: mockNotification |
2405 | + |
2406 | + QtObject { |
2407 | + function invokeAction(actionId) { |
2408 | + mockModel.actionInvoked(actionId) |
2409 | + } |
2410 | + } |
2411 | + } |
2412 | + |
2413 | + ListModel { |
2414 | + id: mockModel |
2415 | + dynamicRoles: true |
2416 | + |
2417 | + signal actionInvoked(string actionId) |
2418 | + |
2419 | + function getRaw(id) { |
2420 | + return mockNotification.createObject(mockModel) |
2421 | + } |
2422 | + |
2423 | + // add the default/PlaceHolder notification to the model |
2424 | + Component.onCompleted: { |
2425 | + var n = { |
2426 | + type: Notification.PlaceHolder, |
2427 | + hints: {}, |
2428 | + summary: "", |
2429 | + body: "", |
2430 | + icon: "", |
2431 | + secondaryIcon: "", |
2432 | + actions: [] |
2433 | + } |
2434 | + |
2435 | + append(n) |
2436 | + } |
2437 | + } |
2438 | + |
2439 | + function addSnapDecisionNotification() { |
2440 | var n = { |
2441 | - type: Notification.PlaceHolder, |
2442 | - hints: {}, |
2443 | - summary: "", |
2444 | - body: "", |
2445 | - icon: "", |
2446 | - value: 0, |
2447 | - secondaryIcon: "", |
2448 | - actions: [] |
2449 | - } |
2450 | - |
2451 | - append(n) |
2452 | - } |
2453 | - } |
2454 | - |
2455 | - function addSnapDecisionNotification() { |
2456 | - var n = { |
2457 | - type: Notification.SnapDecision, |
2458 | - hints: {"x-canonical-private-affirmative-tint": "true"}, |
2459 | - summary: "Tom Ato", |
2460 | - body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.", |
2461 | - icon: "../graphics/avatars/funky.png", |
2462 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
2463 | - actions: [{ id: "ok_id", label: "Ok"}, |
2464 | - { id: "cancel_id", label: "Cancel"}, |
2465 | - { id: "notreally_id", label: "Not really"}, |
2466 | - { id: "noway_id", label: "messages:No way"}, |
2467 | - { id: "nada_id", label: "messages:Nada"}] |
2468 | - } |
2469 | - |
2470 | - mockModel.append(n) |
2471 | - } |
2472 | - |
2473 | - function add2over1SnapDecisionNotification() { |
2474 | - var n = { |
2475 | - type: Notification.SnapDecision, |
2476 | - hints: {"x-canonical-private-affirmative-tint": "true",}, |
2477 | - summary: "Theatre at Ferria Stadium", |
2478 | - body: "at Ferria Stadium in Bilbao, Spain\n07578545317", |
2479 | - icon: "", |
2480 | - secondaryIcon: "", |
2481 | - actions: [{ id: "ok_id", label: "Ok"}, |
2482 | - { id: "snooze_id", label: "Snooze"}, |
2483 | - { id: "view_id", label: "View"}] |
2484 | - } |
2485 | - |
2486 | - mockModel.append(n) |
2487 | - } |
2488 | - |
2489 | - function addEphemeralNotification() { |
2490 | - var n = { |
2491 | - type: Notification.Ephemeral, |
2492 | - summary: "Cole Raby", |
2493 | - body: "I did not expect it to be that late.", |
2494 | - icon: "../graphics/avatars/amanda.png", |
2495 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
2496 | - actions: [] |
2497 | - } |
2498 | - |
2499 | - mockModel.append(n) |
2500 | - } |
2501 | - |
2502 | - function addEphemeralNonShapedIconNotification() { |
2503 | - var n = { |
2504 | - type: Notification.Ephemeral, |
2505 | - hints: {"x-canonical-non-shaped-icon": "true"}, |
2506 | - summary: "Contacts", |
2507 | - body: "Synchronised contacts-database with cloud-storage.", |
2508 | - icon: "../graphics/applicationIcons/contacts-app.png", |
2509 | - secondaryIcon: "", |
2510 | - actions: [] |
2511 | - } |
2512 | - |
2513 | - mockModel.append(n) |
2514 | - } |
2515 | - |
2516 | - function addEphemeralIconSummaryNotification() { |
2517 | - var n = { |
2518 | - type: Notification.Ephemeral, |
2519 | - hints: {"x-canonical-non-shaped-icon": "false"}, |
2520 | - summary: "Photo upload completed", |
2521 | - body: "", |
2522 | - icon: "../graphics/applicationIcons/facebook.png", |
2523 | - secondaryIcon: "", |
2524 | - actions: [] |
2525 | - } |
2526 | - |
2527 | - mockModel.append(n) |
2528 | - } |
2529 | - |
2530 | - function addInteractiveNotification() { |
2531 | - var n = { |
2532 | - type: Notification.Interactive, |
2533 | - summary: "Interactive notification", |
2534 | - body: "This is a notification that can be clicked", |
2535 | - icon: "../graphics/avatars/anna_olsson.png", |
2536 | - secondaryIcon: "", |
2537 | - actions: [{ id: "reply_id", label: "Dummy"}], |
2538 | - } |
2539 | - |
2540 | - mockModel.append(n) |
2541 | - } |
2542 | - |
2543 | - function addConfirmationNotification() { |
2544 | - var n = { |
2545 | - type: Notification.Confirmation, |
2546 | - hints: {"x-canonical-non-shaped-icon": "true"}, |
2547 | - summary: "Confirmation notification", |
2548 | - body: "", |
2549 | - icon: "image://theme/audio-volume-medium", |
2550 | - secondaryIcon: "", |
2551 | - value: 50, |
2552 | - actions: [], |
2553 | - } |
2554 | - |
2555 | - mockModel.append(n) |
2556 | - } |
2557 | - |
2558 | - function add2ndConfirmationNotification() { |
2559 | - var n = { |
2560 | - type: Notification.Confirmation, |
2561 | - hints: {"x-canonical-non-shaped-icon": "true", |
2562 | - "x-canonical-value-bar-tint": "true"}, |
2563 | - summary: "Confirmation notification", |
2564 | - body: "High Volume", |
2565 | - icon: "image://theme/audio-volume-high", |
2566 | - secondaryIcon: "", |
2567 | - value: 85, |
2568 | - actions: [], |
2569 | - } |
2570 | - |
2571 | - mockModel.append(n) |
2572 | - } |
2573 | - |
2574 | - function clearNotifications() { |
2575 | - while(mockModel.count > 1) { |
2576 | - remove1stNotification() |
2577 | - } |
2578 | - } |
2579 | - |
2580 | - function remove1stNotification() { |
2581 | - if (mockModel.count > 1) |
2582 | - mockModel.remove(1) |
2583 | - } |
2584 | - |
2585 | - Rectangle { |
2586 | - id: notificationsRect |
2587 | - |
2588 | - width: units.gu(40) |
2589 | - height: units.gu(115) |
2590 | - |
2591 | - MouseArea{ |
2592 | - id: clickThroughCatcher |
2593 | - |
2594 | - anchors.fill: parent |
2595 | - } |
2596 | - |
2597 | - Notifications { |
2598 | - id: notifications |
2599 | - |
2600 | - margin: units.gu(1) |
2601 | - |
2602 | - anchors.fill: parent |
2603 | - model: mockModel |
2604 | - } |
2605 | - } |
2606 | - |
2607 | - Rectangle { |
2608 | - id: interactiveControls |
2609 | - |
2610 | - width: units.gu(30) |
2611 | - height: units.gu(115) |
2612 | - color: "grey" |
2613 | - |
2614 | - Column { |
2615 | - spacing: units.gu(1) |
2616 | - anchors.fill: parent |
2617 | - anchors.margins: units.gu(1) |
2618 | - |
2619 | - Button { |
2620 | - width: parent.width |
2621 | - text: "add a snap-decision" |
2622 | - onClicked: addSnapDecisionNotification() |
2623 | - } |
2624 | - |
2625 | - Button { |
2626 | - width: parent.width |
2627 | - text: "add a 2over1 snap-decision" |
2628 | - onClicked: add2over1SnapDecisionNotification() |
2629 | - } |
2630 | - |
2631 | - Button { |
2632 | - width: parent.width |
2633 | - text: "add an ephemeral" |
2634 | - onClicked: addEphemeralNotification() |
2635 | - } |
2636 | - |
2637 | - Button { |
2638 | - width: parent.width |
2639 | - text: "add an non-shaped-icon-summary-body" |
2640 | - onClicked: addEphemeralNonShapedIconNotification() |
2641 | - } |
2642 | - |
2643 | - Button { |
2644 | - width: parent.width |
2645 | - text: "add an icon-summary" |
2646 | - onClicked: addEphemeralIconSummaryNotification() |
2647 | - } |
2648 | - |
2649 | - Button { |
2650 | - width: parent.width |
2651 | - text: "add an interactive" |
2652 | - onClicked: addInteractiveNotification() |
2653 | - } |
2654 | - |
2655 | - Button { |
2656 | - width: parent.width |
2657 | - text: "add a confirmation" |
2658 | - onClicked: addConfirmationNotification() |
2659 | - } |
2660 | - |
2661 | - Button { |
2662 | - width: parent.width |
2663 | - text: "add a 2nd confirmation" |
2664 | - onClicked: add2ndConfirmationNotification() |
2665 | - } |
2666 | - |
2667 | - Button { |
2668 | - width: parent.width |
2669 | - text: "remove 1st notification" |
2670 | - onClicked: remove1stNotification() |
2671 | - } |
2672 | - |
2673 | - Button { |
2674 | - width: parent.width |
2675 | - text: "clear model" |
2676 | - onClicked: clearNotifications() |
2677 | - } |
2678 | - } |
2679 | - } |
2680 | - |
2681 | - UnityTestCase { |
2682 | - id: root |
2683 | - name: "NotificationRendererTest" |
2684 | - when: windowShown |
2685 | - |
2686 | - function test_NotificationRenderer_data() { |
2687 | - return [ |
2688 | - { |
2689 | - tag: "Snap Decision with secondary icon and button-tint", |
2690 | type: Notification.SnapDecision, |
2691 | hints: {"x-canonical-private-affirmative-tint": "true"}, |
2692 | summary: "Tom Ato", |
2693 | @@ -307,23 +78,14 @@ |
2694 | { id: "cancel_id", label: "Cancel"}, |
2695 | { id: "notreally_id", label: "Not really"}, |
2696 | { id: "noway_id", label: "messages:No way"}, |
2697 | - { id: "nada_id", label: "messages:Nada"}], |
2698 | - summaryVisible: true, |
2699 | - bodyVisible: true, |
2700 | - iconVisible: true, |
2701 | - centeredIconVisible: false, |
2702 | - shaped: true, |
2703 | - nonShaped: false, |
2704 | - secondaryIconVisible: true, |
2705 | - buttonRowVisible: true, |
2706 | - buttonTinted: true, |
2707 | - hasSound: false, |
2708 | - valueVisible: false, |
2709 | - valueLabelVisible: false, |
2710 | - valueTinted: false |
2711 | - }, |
2712 | - { |
2713 | - tag: "2-over-1 Snap Decision with button-tint", |
2714 | + { id: "nada_id", label: "messages:Nada"}] |
2715 | + } |
2716 | + |
2717 | + mockModel.append(n) |
2718 | + } |
2719 | + |
2720 | + function add2over1SnapDecisionNotification() { |
2721 | + var n = { |
2722 | type: Notification.SnapDecision, |
2723 | hints: {"x-canonical-private-affirmative-tint": "true"}, |
2724 | summary: "Theatre at Ferria Stadium", |
2725 | @@ -332,327 +94,573 @@ |
2726 | secondaryIcon: "", |
2727 | actions: [{ id: "ok_id", label: "Ok"}, |
2728 | { id: "snooze_id", label: "Snooze"}, |
2729 | - { id: "view_id", label: "View"}], |
2730 | - summaryVisible: true, |
2731 | - bodyVisible: true, |
2732 | - iconVisible: false, |
2733 | - centeredIconVisible: false, |
2734 | - shaped: false, |
2735 | - secondaryIconVisible: false, |
2736 | - buttonRowVisible: false, |
2737 | - buttonTinted: true, |
2738 | - hasSound: false, |
2739 | - valueVisible: false, |
2740 | - valueLabelVisible: false, |
2741 | - valueTinted: false |
2742 | - }, |
2743 | - { |
2744 | - tag: "Ephemeral notification - icon-summary layout", |
2745 | - type: Notification.Ephemeral, |
2746 | - hints: {}, |
2747 | + { id: "view_id", label: "View"}] |
2748 | + } |
2749 | + |
2750 | + mockModel.append(n) |
2751 | + } |
2752 | + |
2753 | + function addEphemeralNotification() { |
2754 | + var n = { |
2755 | + type: Notification.Ephemeral, |
2756 | + summary: "Cole Raby", |
2757 | + body: "I did not expect it to be that late.", |
2758 | + icon: "../graphics/avatars/amanda.png", |
2759 | + secondaryIcon: "../graphics/applicationIcons/facebook.png", |
2760 | + actions: [] |
2761 | + } |
2762 | + |
2763 | + mockModel.append(n) |
2764 | + } |
2765 | + |
2766 | + function addEphemeralNonShapedIconNotification() { |
2767 | + var n = { |
2768 | + type: Notification.Ephemeral, |
2769 | + hints: {"x-canonical-non-shaped-icon": "true"}, |
2770 | + summary: "Contacts", |
2771 | + body: "Synchronised contacts-database with cloud-storage.", |
2772 | + icon: "../graphics/applicationIcons/contacts-app.png", |
2773 | + secondaryIcon: "", |
2774 | + actions: [] |
2775 | + } |
2776 | + |
2777 | + mockModel.append(n) |
2778 | + } |
2779 | + |
2780 | + function addEphemeralIconSummaryNotification() { |
2781 | + var n = { |
2782 | + type: Notification.Ephemeral, |
2783 | + hints: {"x-canonical-non-shaped-icon": "false"}, |
2784 | summary: "Photo upload completed", |
2785 | body: "", |
2786 | icon: "../graphics/applicationIcons/facebook.png", |
2787 | secondaryIcon: "", |
2788 | - actions: [], |
2789 | - summaryVisible: true, |
2790 | - bodyVisible: false, |
2791 | - iconVisible: true, |
2792 | - centeredIconVisible: false, |
2793 | - shaped: true, |
2794 | - secondaryIconVisible: false, |
2795 | - buttonRowVisible: false, |
2796 | - buttonTinted: false, |
2797 | - hasSound: false, |
2798 | - valueVisible: false, |
2799 | - valueLabelVisible: false, |
2800 | - valueTinted: false |
2801 | - }, |
2802 | - { |
2803 | - tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout", |
2804 | - type: Notification.Ephemeral, |
2805 | - hints: {"x-canonical-private-affirmative-tint": "false", |
2806 | - "sound-file": "dummy.ogg", |
2807 | - "suppress-sound": "true"}, |
2808 | - summary: "New comment successfully published", |
2809 | - body: "", |
2810 | - icon: "", |
2811 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
2812 | - actions: [], |
2813 | - summaryVisible: true, |
2814 | - bodyVisible: false, |
2815 | - interactiveAreaEnabled: false, |
2816 | - iconVisible: false, |
2817 | - centeredIconVisible: false, |
2818 | - shaped: false, |
2819 | - secondaryIconVisible: true, |
2820 | - buttonRowVisible: false, |
2821 | - buttonTinted: false, |
2822 | - hasSound: false, |
2823 | - valueVisible: false, |
2824 | - valueLabelVisible: false, |
2825 | - valueTinted: false |
2826 | - }, |
2827 | - { |
2828 | - tag: "Interactive notification", |
2829 | + actions: [] |
2830 | + } |
2831 | + |
2832 | + mockModel.append(n) |
2833 | + } |
2834 | + |
2835 | + function addInteractiveNotification() { |
2836 | + var n = { |
2837 | type: Notification.Interactive, |
2838 | - hints: {"x-canonical-private-affirmative-tint": "false", |
2839 | - "sound-file": "dummy.ogg"}, |
2840 | summary: "Interactive notification", |
2841 | body: "This is a notification that can be clicked", |
2842 | - icon: "../graphics/avatars/amanda.png", |
2843 | + icon: "../graphics/avatars/anna_olsson.png", |
2844 | secondaryIcon: "", |
2845 | actions: [{ id: "reply_id", label: "Dummy"}], |
2846 | - summaryVisible: true, |
2847 | - bodyVisible: true, |
2848 | - iconVisible: true, |
2849 | - centeredIconVisible: false, |
2850 | - shaped: true, |
2851 | - secondaryIconVisible: false, |
2852 | - buttonRowVisible: false, |
2853 | - buttonTinted: false, |
2854 | - hasSound: true, |
2855 | - valueVisible: false, |
2856 | - valueLabelVisible: false, |
2857 | - valueTinted: false |
2858 | - }, |
2859 | - { |
2860 | - tag: "Snap Decision without secondary icon and no button-tint", |
2861 | - type: Notification.SnapDecision, |
2862 | - hints: {"x-canonical-private-affirmative-tint": "false", |
2863 | - "sound-file": "dummy.ogg"}, |
2864 | - summary: "Bro Coly", |
2865 | - 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.", |
2866 | - icon: "../graphics/avatars/anna_olsson.png", |
2867 | - secondaryIcon: "", |
2868 | - actions: [{ id: "accept_id", label: "Accept"}, |
2869 | - { id: "reject_id", label: "Reject"}], |
2870 | - summaryVisible: true, |
2871 | - bodyVisible: true, |
2872 | - iconVisible: true, |
2873 | - centeredIconVisible: false, |
2874 | - shaped: true, |
2875 | - secondaryIconVisible: false, |
2876 | - buttonRowVisible: true, |
2877 | - buttonTinted: false, |
2878 | - hasSound: true, |
2879 | - valueVisible: false, |
2880 | - valueLabelVisible: false, |
2881 | - valueTinted: false |
2882 | - }, |
2883 | - { |
2884 | - tag: "Ephemeral notification", |
2885 | - type: Notification.Ephemeral, |
2886 | - hints: {"x-canonical-private-affirmative-tint": "false", |
2887 | - "sound-file": "dummy.ogg"}, |
2888 | - summary: "Cole Raby", |
2889 | - body: "I did not expect it to be that late.", |
2890 | - icon: "../graphics/avatars/funky.png", |
2891 | - secondaryIcon: "../graphics/applicationIcons/facebook.png", |
2892 | - actions: [], |
2893 | - summaryVisible: true, |
2894 | - bodyVisible: true, |
2895 | - iconVisible: true, |
2896 | - centeredIconVisible: false, |
2897 | - shaped: true, |
2898 | - secondaryIconVisible: true, |
2899 | - buttonRowVisible: false, |
2900 | - buttonTinted: false, |
2901 | - hasSound: true, |
2902 | - valueVisible: false, |
2903 | - valueLabelVisible: false, |
2904 | - valueTinted: false |
2905 | - }, |
2906 | - { |
2907 | - tag: "Ephemeral notification with non-shaped icon", |
2908 | - type: Notification.Ephemeral, |
2909 | - hints: {"x-canonical-private-affirmative-tint": "false", |
2910 | - "x-canonical-non-shaped-icon": "true"}, |
2911 | - summary: "Contacts", |
2912 | - body: "Synchronised contacts-database with cloud-storage.", |
2913 | - icon: "image://theme/contacts-app", |
2914 | - secondaryIcon: "", |
2915 | - actions: [], |
2916 | - summaryVisible: true, |
2917 | - bodyVisible: true, |
2918 | - iconVisible: true, |
2919 | - centeredIconVisible: false, |
2920 | - shaped: false, |
2921 | - secondaryIconVisible: false, |
2922 | - buttonRowVisible: false, |
2923 | - buttonTinted: false, |
2924 | - hasSound: false, |
2925 | - valueVisible: false, |
2926 | - valueLabelVisible: false, |
2927 | - valueTinted: false |
2928 | - }, |
2929 | - { |
2930 | - tag: "Confirmation notification with value", |
2931 | + } |
2932 | + |
2933 | + mockModel.append(n) |
2934 | + } |
2935 | + |
2936 | + function addConfirmationNotification() { |
2937 | + var n = { |
2938 | type: Notification.Confirmation, |
2939 | hints: {"x-canonical-non-shaped-icon": "true"}, |
2940 | - summary: "", |
2941 | + summary: "Confirmation notification", |
2942 | body: "", |
2943 | icon: "image://theme/audio-volume-medium", |
2944 | secondaryIcon: "", |
2945 | value: 50, |
2946 | actions: [], |
2947 | - summaryVisible: false, |
2948 | - bodyVisible: false, |
2949 | - iconVisible: false, |
2950 | - centeredIconVisible: true, |
2951 | - shaped: false, |
2952 | - secondaryIconVisible: false, |
2953 | - buttonRowVisible: false, |
2954 | - buttonTinted: false, |
2955 | - hasSound: false, |
2956 | - valueVisible: true, |
2957 | - valueLabelVisible: false, |
2958 | - valueTinted: false |
2959 | - }, |
2960 | - { |
2961 | - tag: "Confirmation notification with value, label and tint", |
2962 | + } |
2963 | + |
2964 | + mockModel.append(n) |
2965 | + } |
2966 | + |
2967 | + function add2ndConfirmationNotification() { |
2968 | + var n = { |
2969 | type: Notification.Confirmation, |
2970 | hints: {"x-canonical-non-shaped-icon": "true", |
2971 | - "x-canonical-value-bar-tint" : "true"}, |
2972 | - summary: "", |
2973 | + "x-canonical-value-bar-tint": "true"}, |
2974 | + summary: "Confirmation notification", |
2975 | body: "High Volume", |
2976 | icon: "image://theme/audio-volume-high", |
2977 | secondaryIcon: "", |
2978 | value: 85, |
2979 | actions: [], |
2980 | - summaryVisible: false, |
2981 | - bodyVisible: false, |
2982 | - iconVisible: false, |
2983 | - centeredIconVisible: true, |
2984 | - shaped: false, |
2985 | - secondaryIconVisible: false, |
2986 | - buttonRowVisible: false, |
2987 | - buttonTinted: false, |
2988 | - hasSound: false, |
2989 | - valueVisible: true, |
2990 | - valueLabelVisible: true, |
2991 | - valueTinted: true |
2992 | - } |
2993 | - ] |
2994 | - } |
2995 | - |
2996 | - SignalSpy { |
2997 | - id: clickThroughSpy |
2998 | - |
2999 | - target: clickThroughCatcher |
3000 | - signalName: "clicked" |
3001 | - } |
3002 | - |
3003 | - SignalSpy { |
3004 | - id: actionSpy |
3005 | - |
3006 | - target: mockModel |
3007 | - signalName: "actionInvoked" |
3008 | - } |
3009 | - |
3010 | - function cleanup() { |
3011 | - clickThroughSpy.clear() |
3012 | - actionSpy.clear() |
3013 | - } |
3014 | - |
3015 | - function test_NotificationRenderer(data) { |
3016 | - // populate model with some mock notifications |
3017 | - mockModel.append(data) |
3018 | - |
3019 | - // make sure the view is properly updated before going on |
3020 | - notifications.forceLayout(); |
3021 | - waitForRendering(notifications); |
3022 | - |
3023 | - var notification = findChild(notifications, "notification" + (mockModel.count - 1)) |
3024 | - verify(notification !== undefined, "notification wasn't found"); |
3025 | - |
3026 | - waitForRendering(notification); |
3027 | - |
3028 | - var icon = findChild(notification, "icon") |
3029 | - var centeredIcon = findChild(notification, "centeredIcon") |
3030 | - var interactiveArea = findChild(notification, "interactiveArea") |
3031 | - var secondaryIcon = findChild(notification, "secondaryIcon") |
3032 | - var summaryLabel = findChild(notification, "summaryLabel") |
3033 | - var bodyLabel = findChild(notification, "bodyLabel") |
3034 | - var buttonRow = findChild(notification, "buttonRow") |
3035 | - var valueIndicator = findChild(notification, "valueIndicator") |
3036 | - var valueLabel = findChild(notification, "valueLabel") |
3037 | - var innerBar = findChild(notification, "innerBar") |
3038 | - |
3039 | - compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect") |
3040 | - if (icon.visible) { |
3041 | - compare(icon.shaped, data.shaped, "shaped-status is incorrect") |
3042 | - } |
3043 | - compare(centeredIcon.visible, data.centeredIconVisible, "centered-icon visibility is incorrect") |
3044 | - if (centeredIcon.visible) { |
3045 | - compare(centeredIcon.shaped, data.shaped, "shaped-status is incorrect") |
3046 | - } |
3047 | - compare(valueIndicator.visible, data.valueVisible, "value-indicator visibility is incorrect") |
3048 | - if (valueIndicator.visible) { |
3049 | - verify(innerBar.color === data.valueTinted ? UbuntuColors.orange : "white", "value-bar has the wrong color-tint") |
3050 | - } |
3051 | - compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect") |
3052 | - |
3053 | - // test input does not fall through |
3054 | - mouseClick(notification, notification.width / 2, notification.height / 2) |
3055 | - if(data.type == Notification.Interactive) { |
3056 | - actionSpy.wait() |
3057 | - compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action") |
3058 | - } |
3059 | - compare(clickThroughSpy.count, 0, "click on notification fell through") |
3060 | - |
3061 | - compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect") |
3062 | - compare(summaryLabel.visible, data.summaryVisible, "summary-text visibility is incorrect") |
3063 | - compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect") |
3064 | - compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect") |
3065 | - |
3066 | - var audioItem = findInvisibleChild(notification, "sound") |
3067 | - compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state") |
3068 | - |
3069 | - if(data.buttonRowVisible) { |
3070 | - var buttonCancel = findChild(buttonRow, "notify_button1") |
3071 | - var buttonAccept = findChild(buttonRow, "notify_button0") |
3072 | - |
3073 | - // only test the left/cancel-button if two actions have been passed in |
3074 | - if (data.actions.length == 2) { |
3075 | - tryCompareFunction(function() { mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3076 | - compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action") |
3077 | - actionSpy.clear() |
3078 | - } |
3079 | - |
3080 | - // check the tinting of the positive/right button |
3081 | - verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint") |
3082 | - |
3083 | - // click the positive/right button |
3084 | - tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3085 | - compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action") |
3086 | + } |
3087 | + |
3088 | + mockModel.append(n) |
3089 | + } |
3090 | + |
3091 | + function clearNotifications() { |
3092 | + while(mockModel.count > 1) { |
3093 | + remove1stNotification() |
3094 | + } |
3095 | + } |
3096 | + |
3097 | + function remove1stNotification() { |
3098 | + if (mockModel.count > 1) |
3099 | + mockModel.remove(1) |
3100 | + } |
3101 | + |
3102 | + Rectangle { |
3103 | + id: notificationsRect |
3104 | + |
3105 | + width: units.gu(40) |
3106 | + height: units.gu(115) |
3107 | + |
3108 | + MouseArea{ |
3109 | + id: clickThroughCatcher |
3110 | + |
3111 | + anchors.fill: parent |
3112 | + } |
3113 | + |
3114 | + Notifications { |
3115 | + id: notifications |
3116 | + |
3117 | + margin: units.gu(1) |
3118 | + |
3119 | + anchors.fill: parent |
3120 | + model: mockModel |
3121 | + } |
3122 | + } |
3123 | + |
3124 | + Rectangle { |
3125 | + id: interactiveControls |
3126 | + |
3127 | + width: units.gu(30) |
3128 | + height: units.gu(115) |
3129 | + color: "grey" |
3130 | + |
3131 | + Column { |
3132 | + spacing: units.gu(1) |
3133 | + anchors.fill: parent |
3134 | + anchors.margins: units.gu(1) |
3135 | + |
3136 | + Button { |
3137 | + width: parent.width |
3138 | + text: "add a snap-decision" |
3139 | + onClicked: rootRow.addSnapDecisionNotification() |
3140 | + } |
3141 | + |
3142 | + Button { |
3143 | + width: parent.width |
3144 | + text: "add a 2over1 snap-decision" |
3145 | + onClicked: rootRow.add2over1SnapDecisionNotification() |
3146 | + } |
3147 | + |
3148 | + Button { |
3149 | + width: parent.width |
3150 | + text: "add an ephemeral" |
3151 | + onClicked: rootRow.addEphemeralNotification() |
3152 | + } |
3153 | + |
3154 | + Button { |
3155 | + width: parent.width |
3156 | + text: "add an non-shaped-icon-summary-body" |
3157 | + onClicked: rootRow.addEphemeralNonShapedIconNotification() |
3158 | + } |
3159 | + |
3160 | + Button { |
3161 | + width: parent.width |
3162 | + text: "add an icon-summary" |
3163 | + onClicked: rootRow.addEphemeralIconSummaryNotification() |
3164 | + } |
3165 | + |
3166 | + Button { |
3167 | + width: parent.width |
3168 | + text: "add an interactive" |
3169 | + onClicked: rootRow.addInteractiveNotification() |
3170 | + } |
3171 | + |
3172 | + Button { |
3173 | + width: parent.width |
3174 | + text: "add a confirmation" |
3175 | + onClicked: rootRow.addConfirmationNotification() |
3176 | + } |
3177 | + |
3178 | + Button { |
3179 | + width: parent.width |
3180 | + text: "add a 2nd confirmation" |
3181 | + onClicked: rootRow.add2ndConfirmationNotification() |
3182 | + } |
3183 | + |
3184 | + Button { |
3185 | + width: parent.width |
3186 | + text: "remove 1st notification" |
3187 | + onClicked: rootRow.remove1stNotification() |
3188 | + } |
3189 | + |
3190 | + Button { |
3191 | + width: parent.width |
3192 | + text: "clear model" |
3193 | + onClicked: rootRow.clearNotifications() |
3194 | + } |
3195 | + } |
3196 | + } |
3197 | + |
3198 | + ActionModel { |
3199 | + id: myActionModel |
3200 | + } |
3201 | + |
3202 | + UnityTestCase { |
3203 | + id: root |
3204 | + name: "NotificationRendererTest" |
3205 | + when: windowShown |
3206 | + |
3207 | + function test_NotificationRenderer_data() { |
3208 | + return [ |
3209 | + { |
3210 | + tag: "Snap Decision with secondary icon and button-tint", |
3211 | + type: Notification.SnapDecision, |
3212 | + hints: {"x-canonical-private-affirmative-tint": "true"}, |
3213 | + summary: "Tom Ato", |
3214 | + body: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.", |
3215 | + icon: "../graphics/avatars/funky.png", |
3216 | + secondaryIcon: "../graphics/applicationIcons/facebook.png", |
3217 | + actions: [{ id: "ok_id", label: "Ok"}, |
3218 | + { id: "cancel_id", label: "Cancel"}, |
3219 | + { id: "notreally_id", label: "Not really"}, |
3220 | + { id: "noway_id", label: "messages:No way"}, |
3221 | + { id: "nada_id", label: "messages:Nada"}], |
3222 | + summaryVisible: true, |
3223 | + bodyVisible: true, |
3224 | + iconVisible: true, |
3225 | + centeredIconVisible: false, |
3226 | + shaped: true, |
3227 | + secondaryIconVisible: true, |
3228 | + buttonRowVisible: true, |
3229 | + buttonTinted: true, |
3230 | + hasSound: false, |
3231 | + valueVisible: false, |
3232 | + valueLabelVisible: false, |
3233 | + valueTinted: false |
3234 | + }, |
3235 | + { |
3236 | + tag: "2-over-1 Snap Decision with button-tint", |
3237 | + type: Notification.SnapDecision, |
3238 | + hints: {"x-canonical-private-affirmative-tint": "true"}, |
3239 | + summary: "Theatre at Ferria Stadium", |
3240 | + body: "at Ferria Stadium in Bilbao, Spain\n07578545317", |
3241 | + icon: "", |
3242 | + secondaryIcon: "", |
3243 | + actions: [{ id: "ok_id", label: "Ok"}, |
3244 | + { id: "snooze_id", label: "Snooze"}, |
3245 | + { id: "view_id", label: "View"}], |
3246 | + summaryVisible: true, |
3247 | + bodyVisible: true, |
3248 | + iconVisible: false, |
3249 | + centeredIconVisible: false, |
3250 | + shaped: false, |
3251 | + secondaryIconVisible: false, |
3252 | + buttonRowVisible: false, |
3253 | + buttonTinted: true, |
3254 | + hasSound: false, |
3255 | + valueVisible: false, |
3256 | + valueLabelVisible: false, |
3257 | + valueTinted: false |
3258 | + }, |
3259 | + { |
3260 | + tag: "Ephemeral notification - icon-summary layout", |
3261 | + type: Notification.Ephemeral, |
3262 | + hints: {}, |
3263 | + summary: "Photo upload completed", |
3264 | + body: "", |
3265 | + icon: "../graphics/applicationIcons/facebook.png", |
3266 | + secondaryIcon: "", |
3267 | + actions: [], |
3268 | + summaryVisible: true, |
3269 | + bodyVisible: false, |
3270 | + iconVisible: true, |
3271 | + centeredIconVisible: false, |
3272 | + shaped: true, |
3273 | + secondaryIconVisible: false, |
3274 | + buttonRowVisible: false, |
3275 | + buttonTinted: false, |
3276 | + hasSound: false, |
3277 | + valueVisible: false, |
3278 | + valueLabelVisible: false, |
3279 | + valueTinted: false |
3280 | + }, |
3281 | + { |
3282 | + tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout", |
3283 | + type: Notification.Ephemeral, |
3284 | + hints: {"x-canonical-private-affirmative-tint": "false", |
3285 | + "sound-file": "dummy.ogg", |
3286 | + "suppress-sound": "true"}, |
3287 | + summary: "New comment successfully published", |
3288 | + body: "", |
3289 | + icon: "", |
3290 | + secondaryIcon: "../graphics/applicationIcons/facebook.png", |
3291 | + actions: [], |
3292 | + summaryVisible: true, |
3293 | + bodyVisible: false, |
3294 | + interactiveAreaEnabled: false, |
3295 | + iconVisible: false, |
3296 | + centeredIconVisible: false, |
3297 | + shaped: false, |
3298 | + secondaryIconVisible: true, |
3299 | + buttonRowVisible: false, |
3300 | + buttonTinted: false, |
3301 | + hasSound: false, |
3302 | + valueVisible: false, |
3303 | + valueLabelVisible: false, |
3304 | + valueTinted: false |
3305 | + }, |
3306 | + { |
3307 | + tag: "Interactive notification", |
3308 | + type: Notification.Interactive, |
3309 | + hints: {"x-canonical-private-affirmative-tint": "false", |
3310 | + "sound-file": "dummy.ogg"}, |
3311 | + summary: "Interactive notification", |
3312 | + body: "This is a notification that can be clicked", |
3313 | + icon: "../graphics/avatars/amanda.png", |
3314 | + secondaryIcon: "", |
3315 | + actions: [{ id: "reply_id", label: "Dummy"}], |
3316 | + summaryVisible: true, |
3317 | + bodyVisible: true, |
3318 | + iconVisible: true, |
3319 | + centeredIconVisible: false, |
3320 | + shaped: true, |
3321 | + secondaryIconVisible: false, |
3322 | + buttonRowVisible: false, |
3323 | + buttonTinted: false, |
3324 | + hasSound: true, |
3325 | + valueVisible: false, |
3326 | + valueLabelVisible: false, |
3327 | + valueTinted: false |
3328 | + }, |
3329 | + { |
3330 | + tag: "Snap Decision without secondary icon and no button-tint", |
3331 | + type: Notification.SnapDecision, |
3332 | + hints: {"x-canonical-private-affirmative-tint": "false", |
3333 | + "sound-file": "dummy.ogg"}, |
3334 | + summary: "Bro Coly", |
3335 | + 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.", |
3336 | + icon: "../graphics/avatars/anna_olsson.png", |
3337 | + secondaryIcon: "", |
3338 | + actions: [{ id: "accept_id", label: "Accept"}, |
3339 | + { id: "reject_id", label: "Reject"}], |
3340 | + summaryVisible: true, |
3341 | + bodyVisible: true, |
3342 | + iconVisible: true, |
3343 | + centeredIconVisible: false, |
3344 | + shaped: true, |
3345 | + secondaryIconVisible: false, |
3346 | + buttonRowVisible: true, |
3347 | + buttonTinted: false, |
3348 | + hasSound: true, |
3349 | + valueVisible: false, |
3350 | + valueLabelVisible: false, |
3351 | + valueTinted: false |
3352 | + }, |
3353 | + { |
3354 | + tag: "Ephemeral notification", |
3355 | + type: Notification.Ephemeral, |
3356 | + hints: {"x-canonical-private-affirmative-tint": "false", |
3357 | + "sound-file": "dummy.ogg"}, |
3358 | + summary: "Cole Raby", |
3359 | + body: "I did not expect it to be that late.", |
3360 | + icon: "../graphics/avatars/funky.png", |
3361 | + secondaryIcon: "../graphics/applicationIcons/facebook.png", |
3362 | + actions: [], |
3363 | + summaryVisible: true, |
3364 | + bodyVisible: true, |
3365 | + iconVisible: true, |
3366 | + centeredIconVisible: false, |
3367 | + shaped: true, |
3368 | + secondaryIconVisible: true, |
3369 | + buttonRowVisible: false, |
3370 | + buttonTinted: false, |
3371 | + hasSound: true, |
3372 | + valueVisible: false, |
3373 | + valueLabelVisible: false, |
3374 | + valueTinted: false |
3375 | + }, |
3376 | + { |
3377 | + tag: "Ephemeral notification with non-shaped icon", |
3378 | + type: Notification.Ephemeral, |
3379 | + hints: {"x-canonical-private-affirmative-tint": "false", |
3380 | + "x-canonical-non-shaped-icon": "true"}, |
3381 | + summary: "Contacts", |
3382 | + body: "Synchronised contacts-database with cloud-storage.", |
3383 | + icon: "image://theme/contacts-app", |
3384 | + secondaryIcon: "", |
3385 | + actions: [], |
3386 | + summaryVisible: true, |
3387 | + bodyVisible: true, |
3388 | + iconVisible: true, |
3389 | + centeredIconVisible: false, |
3390 | + shaped: false, |
3391 | + secondaryIconVisible: false, |
3392 | + buttonRowVisible: false, |
3393 | + buttonTinted: false, |
3394 | + hasSound: false, |
3395 | + valueVisible: false, |
3396 | + valueLabelVisible: false, |
3397 | + valueTinted: false |
3398 | + }, |
3399 | + { |
3400 | + tag: "Confirmation notification with value", |
3401 | + type: Notification.Confirmation, |
3402 | + hints: {"x-canonical-non-shaped-icon": "true"}, |
3403 | + summary: "", |
3404 | + body: "", |
3405 | + icon: "image://theme/audio-volume-medium", |
3406 | + secondaryIcon: "", |
3407 | + value: 50, |
3408 | + actions: [], |
3409 | + summaryVisible: false, |
3410 | + bodyVisible: false, |
3411 | + iconVisible: false, |
3412 | + centeredIconVisible: true, |
3413 | + shaped: false, |
3414 | + secondaryIconVisible: false, |
3415 | + buttonRowVisible: false, |
3416 | + buttonTinted: false, |
3417 | + hasSound: false, |
3418 | + valueVisible: true, |
3419 | + valueLabelVisible: false, |
3420 | + valueTinted: false |
3421 | + }, |
3422 | + { |
3423 | + tag: "Confirmation notification with value, label and tint", |
3424 | + type: Notification.Confirmation, |
3425 | + hints: {"x-canonical-non-shaped-icon": "true", |
3426 | + "x-canonical-value-bar-tint" : "true"}, |
3427 | + summary: "", |
3428 | + body: "High Volume", |
3429 | + icon: "image://theme/audio-volume-high", |
3430 | + secondaryIcon: "", |
3431 | + value: 85, |
3432 | + actions: [], |
3433 | + summaryVisible: false, |
3434 | + bodyVisible: false, |
3435 | + iconVisible: false, |
3436 | + centeredIconVisible: true, |
3437 | + shaped: false, |
3438 | + secondaryIconVisible: false, |
3439 | + buttonRowVisible: false, |
3440 | + buttonTinted: false, |
3441 | + hasSound: false, |
3442 | + valueVisible: true, |
3443 | + valueLabelVisible: true, |
3444 | + valueTinted: true |
3445 | + } |
3446 | + ] |
3447 | + } |
3448 | + |
3449 | + SignalSpy { |
3450 | + id: clickThroughSpy |
3451 | + |
3452 | + target: clickThroughCatcher |
3453 | + signalName: "clicked" |
3454 | + } |
3455 | + |
3456 | + SignalSpy { |
3457 | + id: actionSpy |
3458 | + |
3459 | + target: mockModel |
3460 | + signalName: "actionInvoked" |
3461 | + } |
3462 | + |
3463 | + function cleanup() { |
3464 | + clickThroughSpy.clear() |
3465 | actionSpy.clear() |
3466 | - waitForRendering(notification) |
3467 | - |
3468 | - // check if there's a ComboButton created due to more actions being passed |
3469 | - if (data.actions.length > 2) { |
3470 | - var comboButton = findChild(notification, "notify_button2") |
3471 | - tryCompareFunction(function() { return comboButton.expanded == false; }, true); |
3472 | - |
3473 | - // click to expand |
3474 | - tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true); |
3475 | - |
3476 | - // try clicking on choices in expanded comboList |
3477 | - var choiceButton1 = findChild(notification, "notify_button3") |
3478 | - tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3479 | - compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1") |
3480 | - actionSpy.clear() |
3481 | - |
3482 | - var choiceButton2 = findChild(notification, "notify_button4") |
3483 | - tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3484 | - compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2") |
3485 | - actionSpy.clear() |
3486 | - |
3487 | - // click to collapse |
3488 | - //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true); |
3489 | - } else { |
3490 | - mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2) |
3491 | - compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action") |
3492 | + } |
3493 | + |
3494 | + function test_NotificationRenderer(data) { |
3495 | + // populate model with some mock notifications |
3496 | + mockModel.append(data) |
3497 | + |
3498 | + // make sure the view is properly updated before going on |
3499 | + notifications.forceLayout(); |
3500 | + waitForRendering(notifications); |
3501 | + |
3502 | + var notification = findChild(notifications, "notification" + (mockModel.count - 1)) |
3503 | + verify(notification !== undefined, "notification wasn't found"); |
3504 | + |
3505 | + waitForRendering(notification); |
3506 | + |
3507 | + var icon = findChild(notification, "icon") |
3508 | + var centeredIcon = findChild(notification, "centeredIcon") |
3509 | + var interactiveArea = findChild(notification, "interactiveArea") |
3510 | + var secondaryIcon = findChild(notification, "secondaryIcon") |
3511 | + var summaryLabel = findChild(notification, "summaryLabel") |
3512 | + var bodyLabel = findChild(notification, "bodyLabel") |
3513 | + var buttonRow = findChild(notification, "buttonRow") |
3514 | + var valueIndicator = findChild(notification, "valueIndicator") |
3515 | + var valueLabel = findChild(notification, "valueLabel") |
3516 | + var innerBar = findChild(notification, "innerBar") |
3517 | + |
3518 | + compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect") |
3519 | + if (icon.visible) { |
3520 | + compare(icon.shaped, data.shaped, "shaped-status is incorrect") |
3521 | + } |
3522 | + compare(centeredIcon.visible, data.centeredIconVisible, "centered-icon visibility is incorrect") |
3523 | + if (centeredIcon.visible) { |
3524 | + compare(centeredIcon.shaped, data.shaped, "shaped-status is incorrect") |
3525 | + } |
3526 | + compare(valueIndicator.visible, data.valueVisible, "value-indicator visibility is incorrect") |
3527 | + if (valueIndicator.visible) { |
3528 | + verify(innerBar.color === data.valueTinted ? UbuntuColors.orange : "white", "value-bar has the wrong color-tint") |
3529 | + } |
3530 | + compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect") |
3531 | + |
3532 | + // test input does not fall through |
3533 | + mouseClick(notification, notification.width / 2, notification.height / 2) |
3534 | + if(data.type == Notification.Interactive) { |
3535 | + actionSpy.wait() |
3536 | + compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action") |
3537 | + } |
3538 | + compare(clickThroughSpy.count, 0, "click on notification fell through") |
3539 | + |
3540 | + compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect") |
3541 | + compare(summaryLabel.visible, data.summaryVisible, "summary-text visibility is incorrect") |
3542 | + compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect") |
3543 | + compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect") |
3544 | + |
3545 | + var audioItem = findInvisibleChild(notification, "sound") |
3546 | + compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state") |
3547 | + |
3548 | + if(data.buttonRowVisible) { |
3549 | + var buttonCancel = findChild(buttonRow, "notify_button1") |
3550 | + var buttonAccept = findChild(buttonRow, "notify_button0") |
3551 | + |
3552 | + // only test the left/cancel-button if two actions have been passed in |
3553 | + if (data.actions.length == 2) { |
3554 | + tryCompareFunction(function() { mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3555 | + compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action") |
3556 | + actionSpy.clear() |
3557 | + } |
3558 | + |
3559 | + // check the tinting of the positive/right button |
3560 | + verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint") |
3561 | + |
3562 | + // click the positive/right button |
3563 | + tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3564 | + compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action") |
3565 | + actionSpy.clear() |
3566 | + waitForRendering (notification) |
3567 | + |
3568 | + // check if there's a ComboButton created due to more actions being passed |
3569 | + if (data.actions.length > 2) { |
3570 | + var comboButton = findChild(notification, "notify_button2") |
3571 | + tryCompareFunction(function() { return comboButton.expanded == false; }, true); |
3572 | + |
3573 | + // click to expand |
3574 | + tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true); |
3575 | + |
3576 | + // try clicking on choices in expanded comboList |
3577 | + var choiceButton1 = findChild(notification, "notify_button3") |
3578 | + tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3579 | + compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1") |
3580 | + actionSpy.clear() |
3581 | + |
3582 | + var choiceButton2 = findChild(notification, "notify_button4") |
3583 | + tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true); |
3584 | + compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2") |
3585 | + actionSpy.clear() |
3586 | + |
3587 | + // click to collapse |
3588 | + //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true); |
3589 | + } else { |
3590 | + mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2) |
3591 | + compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action") |
3592 | + } |
3593 | } |
3594 | } |
3595 | } |
3596 | |
3597 | === added file 'tests/qmltests/Notifications/tst_SwipeToAct.qml' |
3598 | --- tests/qmltests/Notifications/tst_SwipeToAct.qml 1970-01-01 00:00:00 +0000 |
3599 | +++ tests/qmltests/Notifications/tst_SwipeToAct.qml 2014-11-05 14:37:57 +0000 |
3600 | @@ -0,0 +1,276 @@ |
3601 | +/* |
3602 | + * Copyright (C) 2014 Canonical, Ltd. |
3603 | + * |
3604 | + * This program is free software; you can redistribute it and/or modify |
3605 | + * it under the terms of the GNU General Public License as published by |
3606 | + * the Free Software Foundation; version 3. |
3607 | + * |
3608 | + * This program is distributed in the hope that it will be useful, |
3609 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
3610 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
3611 | + * GNU General Public License for more details. |
3612 | + * |
3613 | + * You should have received a copy of the GNU General Public License |
3614 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
3615 | + */ |
3616 | + |
3617 | +import QtQuick 2.0 |
3618 | +import QtTest 1.0 |
3619 | +import ".." |
3620 | +import "../../../qml/Notifications" |
3621 | +import Ubuntu.Components 0.1 |
3622 | +import Unity.Test 0.1 |
3623 | +import Unity.Notifications 1.0 |
3624 | + |
3625 | +Item { |
3626 | + width: notificationsRect.width + interactiveControls.width |
3627 | + height: notificationsRect.height |
3628 | + |
3629 | + Row { |
3630 | + id: rootRow |
3631 | + |
3632 | + Component { |
3633 | + id: mockNotification |
3634 | + |
3635 | + QtObject { |
3636 | + function invokeAction(actionId) { |
3637 | + mockModel.actionInvoked(actionId) |
3638 | + } |
3639 | + } |
3640 | + } |
3641 | + |
3642 | + ListModel { |
3643 | + id: mockModel |
3644 | + dynamicRoles: true |
3645 | + |
3646 | + signal actionInvoked(string actionId) |
3647 | + |
3648 | + function getRaw(id) { |
3649 | + return mockNotification.createObject(mockModel) |
3650 | + } |
3651 | + |
3652 | + // add the default/PlaceHolder notification to the model |
3653 | + Component.onCompleted: { |
3654 | + var n = { |
3655 | + type: Notification.PlaceHolder, |
3656 | + hints: {}, |
3657 | + summary: "", |
3658 | + body: "", |
3659 | + icon: "", |
3660 | + secondaryIcon: "", |
3661 | + actions: [] |
3662 | + } |
3663 | + |
3664 | + append(n) |
3665 | + } |
3666 | + } |
3667 | + |
3668 | + function addSwipeToActNotification() { |
3669 | + var n = { |
3670 | + type: Notification.SnapDecision, |
3671 | + hints: {"x-canonical-snap-decisions-swipe": "true"}, |
3672 | + summary: "Incoming call", |
3673 | + body: "Frank Zappa\n+44 (0)7736 027340", |
3674 | + icon: "../graphics/avatars/amanda.png", |
3675 | + secondaryIcon: "incoming-call", |
3676 | + actions: [{ id: "ok_id", label: "Ok"}, |
3677 | + { id: "cancel_id", label: "Cancel"}] |
3678 | + } |
3679 | + |
3680 | + mockModel.append(n) |
3681 | + } |
3682 | + |
3683 | + function clearNotifications() { |
3684 | + mockModel.clear() |
3685 | + } |
3686 | + |
3687 | + function remove1stNotification() { |
3688 | + if (mockModel.count > 0) |
3689 | + mockModel.remove(0) |
3690 | + } |
3691 | + |
3692 | + Rectangle { |
3693 | + id: notificationsRect |
3694 | + |
3695 | + width: units.gu(40) |
3696 | + height: units.gu(71) |
3697 | + |
3698 | + MouseArea{ |
3699 | + id: clickThroughCatcher |
3700 | + |
3701 | + anchors.fill: parent |
3702 | + } |
3703 | + |
3704 | + Notifications { |
3705 | + id: notifications |
3706 | + |
3707 | + margin: units.gu(1) |
3708 | + |
3709 | + anchors.fill: parent |
3710 | + model: mockModel |
3711 | + } |
3712 | + } |
3713 | + |
3714 | + Rectangle { |
3715 | + id: interactiveControls |
3716 | + |
3717 | + width: units.gu(30) |
3718 | + height: units.gu(81) |
3719 | + color: "grey" |
3720 | + |
3721 | + Column { |
3722 | + spacing: units.gu(1) |
3723 | + anchors.fill: parent |
3724 | + anchors.margins: units.gu(1) |
3725 | + |
3726 | + Button { |
3727 | + width: parent.width |
3728 | + text: "add a SwipeToAct snap-decision" |
3729 | + onClicked: rootRow.addSwipeToActNotification() |
3730 | + } |
3731 | + |
3732 | + Button { |
3733 | + width: parent.width |
3734 | + text: "remove 1st notification" |
3735 | + onClicked: rootRow.remove1stNotification() |
3736 | + } |
3737 | + |
3738 | + Button { |
3739 | + width: parent.width |
3740 | + text: "clear model" |
3741 | + onClicked: rootRow.clearNotifications() |
3742 | + } |
3743 | + } |
3744 | + } |
3745 | + |
3746 | + ActionModel { |
3747 | + id: myActionModel |
3748 | + } |
3749 | + |
3750 | + UnityTestCase { |
3751 | + id: root |
3752 | + name: "NotificationRendererTest" |
3753 | + when: windowShown |
3754 | + |
3755 | + function test_NotificationRenderer_data() { |
3756 | + return [ |
3757 | + { |
3758 | + tag: "Snap Decision with SwipeToAct-widget (accept)", |
3759 | + type: Notification.SnapDecision, |
3760 | + hints: {"x-canonical-snap-decisions-swipe": "true"}, |
3761 | + summary: "Incoming call", |
3762 | + body: "Frank Zappa\n+44 (0)7736 027340", |
3763 | + icon: "../graphics/avatars/amanda.png", |
3764 | + secondaryIcon: "../graphics/applicationIcons/facebook.png", |
3765 | + actions: myActionModel, |
3766 | + summaryVisible: true, |
3767 | + bodyVisible: true, |
3768 | + iconVisible: true, |
3769 | + shaped: true, |
3770 | + secondaryIconVisible: true, |
3771 | + buttonRowVisible: true, |
3772 | + buttonTinted: false, |
3773 | + checkSwipeToActAccept: true, |
3774 | + checkSwipeToActReject: false |
3775 | + }, |
3776 | + { |
3777 | + tag: "Snap Decision with SwipeToAct-widget (reject)", |
3778 | + type: Notification.SnapDecision, |
3779 | + hints: {"x-canonical-snap-decisions-swipe": "true"}, |
3780 | + summary: "Incoming call", |
3781 | + body: "Bro Coly\n+49 (0)221 426973", |
3782 | + icon: "../graphics/avatars/funky.png", |
3783 | + secondaryIcon: "../graphics/applicationIcons/facebook.png", |
3784 | + actions: myActionModel, |
3785 | + summaryVisible: true, |
3786 | + bodyVisible: true, |
3787 | + iconVisible: true, |
3788 | + shaped: true, |
3789 | + secondaryIconVisible: true, |
3790 | + buttonRowVisible: true, |
3791 | + buttonTinted: false, |
3792 | + checkSwipeToActAccept: false, |
3793 | + checkSwipeToActReject: true |
3794 | + } |
3795 | + ] |
3796 | + } |
3797 | + |
3798 | + SignalSpy { |
3799 | + id: clickThroughSpy |
3800 | + |
3801 | + target: clickThroughCatcher |
3802 | + signalName: "clicked" |
3803 | + } |
3804 | + |
3805 | + SignalSpy { |
3806 | + id: actionSpy |
3807 | + |
3808 | + target: mockModel |
3809 | + signalName: "actionInvoked" |
3810 | + } |
3811 | + |
3812 | + function cleanup() { |
3813 | + clickThroughSpy.clear() |
3814 | + actionSpy.clear() |
3815 | + } |
3816 | + |
3817 | + function test_NotificationRenderer(data) { |
3818 | + // populate model with some mock notifications |
3819 | + mockModel.append(data) |
3820 | + |
3821 | + // make sure the view is properly updated before going on |
3822 | + notifications.forceLayout(); |
3823 | + waitForRendering(notifications); |
3824 | + |
3825 | + var notification = findChild(notifications, "notification" + (mockModel.count - 1)) |
3826 | + verify(notification !== undefined, "notification wasn't found"); |
3827 | + |
3828 | + waitForRendering(notification); |
3829 | + |
3830 | + var icon = findChild(notification, "icon") |
3831 | + var interactiveArea = findChild(notification, "interactiveArea") |
3832 | + var secondaryIcon = findChild(notification, "secondaryIcon") |
3833 | + var summaryLabel = findChild(notification, "summaryLabel") |
3834 | + var bodyLabel = findChild(notification, "bodyLabel") |
3835 | + var buttonRow = findChild(notification, "buttonRow") |
3836 | + |
3837 | + compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect") |
3838 | + if (icon.visible) { |
3839 | + compare(icon.shaped, data.shaped, "shaped-status is incorrect") |
3840 | + } |
3841 | + |
3842 | + // test input does not fall through |
3843 | + mouseClick(notification, notification.width / 2, notification.height / 2) |
3844 | + if(data.type == Notification.Interactive) { |
3845 | + actionSpy.wait() |
3846 | + compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action") |
3847 | + } |
3848 | + compare(clickThroughSpy.count, 0, "click on notification fell through") |
3849 | + |
3850 | + compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect") |
3851 | + compare(summaryLabel.visible, data.summaryVisible, "summary-text visibility is incorrect") |
3852 | + compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect") |
3853 | + compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect") |
3854 | + |
3855 | + if(data.buttonRowVisible) { |
3856 | + var swipeButton = findChild(buttonRow, "notify_swipe_button") |
3857 | + var slider = findChild(swipeButton, "slider") |
3858 | + var swipeMouseArea = findChild(swipeButton, "swipeMouseArea") |
3859 | + var x = swipeMouseArea.width / 2 |
3860 | + var y = swipeMouseArea.height / 2 |
3861 | + |
3862 | + if(data.checkSwipeToActAccept) { |
3863 | + tryCompareFunction(function() { mouseDrag(slider, x, y, (swipeMouseArea.width / 2) - slider.width, 0); return actionSpy.signalArguments.length > 0; }, true); |
3864 | + compare(actionSpy.signalArguments[0][0], data.actions.data(0, ActionModel.RoleActionId), "got wrong id for positive action") |
3865 | + actionSpy.clear() |
3866 | + } |
3867 | + if(data.checkSwipeToActReject) { |
3868 | + tryCompareFunction(function() { mouseDrag(slider, x, y, -(swipeMouseArea.width / 2), 0); return actionSpy.signalArguments.length > 0; }, true); |
3869 | + compare(actionSpy.signalArguments[0][0], data.actions.data(1, ActionModel.RoleActionId), "got wrong id for negative action") |
3870 | + actionSpy.clear() |
3871 | + } |
3872 | + } |
3873 | + } |
3874 | + } |
3875 | + } |
3876 | +} |
3877 | |
3878 | === modified file 'tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml' |
3879 | --- tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml 2014-09-29 15:04:42 +0000 |
3880 | +++ tests/qmltests/Panel/Indicators/tst_MenuItemFactory.qml 2014-11-05 14:37:57 +0000 |
3881 | @@ -740,7 +740,7 @@ |
3882 | compare(loader.item.enabled, data.enabled, "Enabled does not match data"); |
3883 | } |
3884 | |
3885 | - function test_lp1336715_broken_checkbox_bindings() { |
3886 | + function test_lp1336715_broken_switch_bindings() { |
3887 | menuData.type = "com.canonical.indicator.switch"; |
3888 | menuData.sensitive = true; |
3889 | menuData.isToggled = false; |
3890 | @@ -758,5 +758,21 @@ |
3891 | |
3892 | compare(loader.item.checked, false, "Server updates no longer working"); |
3893 | } |
3894 | + |
3895 | + // test that the server value is re-aserted if it is not confirmed. |
3896 | + function test_lp1336715_switch_server_value_reassertion() { |
3897 | + menuData.type = "com.canonical.indicator.switch"; |
3898 | + menuData.sensitive = true; |
3899 | + menuData.isToggled = false; |
3900 | + |
3901 | + loader.data = menuData; |
3902 | + loader.sourceComponent = factory.load(menuData); |
3903 | + |
3904 | + compare(loader.item.checked, false, "Loader did not load check state"); |
3905 | + mouseClick(loader.item, |
3906 | + loader.item.width / 2, loader.item.height / 2); |
3907 | + compare(loader.item.checked, true, "Clicking switch menu should toggle check"); |
3908 | + tryCompare(loader.item, "checked", false); |
3909 | + } |
3910 | } |
3911 | } |
3912 | |
3913 | === modified file 'tests/qmltests/Panel/tst_IndicatorPage.qml' |
3914 | --- tests/qmltests/Panel/tst_IndicatorPage.qml 2014-10-17 14:55:35 +0000 |
3915 | +++ tests/qmltests/Panel/tst_IndicatorPage.qml 2014-11-05 14:37:57 +0000 |
3916 | @@ -18,6 +18,7 @@ |
3917 | import QtTest 1.0 |
3918 | import Unity.Test 0.1 as UT |
3919 | import Unity.Indicators 0.1 as Indicators |
3920 | +import Ubuntu.Settings.Menus 0.1 as Menus |
3921 | import "../../../qml/Panel" |
3922 | |
3923 | Item { |
3924 | @@ -33,8 +34,24 @@ |
3925 | busName: "com.caninical.indicator.test" |
3926 | actionsObjectPath: "/com/canonical/indicator/test" |
3927 | menuObjectPath: "/com/canonical/indicator/test" |
3928 | + |
3929 | + factory { |
3930 | + _map: { |
3931 | + "default": { |
3932 | + "com.canonical.indicator.test" : testMenu |
3933 | + } |
3934 | + } |
3935 | + } |
3936 | } |
3937 | |
3938 | + Component { |
3939 | + id: testMenu |
3940 | + Menus.StandardMenu { |
3941 | + signal menuSelected |
3942 | + signal menuDeselected |
3943 | + } |
3944 | + } |
3945 | + |
3946 | property var fullMenuData: [{ |
3947 | "rowData": { // 1 |
3948 | "label": "root", |
3949 | @@ -51,39 +68,39 @@ |
3950 | }, |
3951 | "submenu": [{ |
3952 | "rowData": { // 1.1 |
3953 | - "label": "menu1", |
3954 | + "label": "menu0", |
3955 | "sensitive": true, |
3956 | "isSeparator": false, |
3957 | "icon": "", |
3958 | - "type": "", |
3959 | + "type": "com.canonical.indicator.test", |
3960 | "ext": {}, |
3961 | - "action": "", |
3962 | + "action": "menu0", |
3963 | "actionState": {}, |
3964 | "isCheck": false, |
3965 | "isRadio": false, |
3966 | "isToggled": false, |
3967 | }}, { |
3968 | "rowData": { // 1.2 |
3969 | - "label": "menu2", |
3970 | + "label": "menu1", |
3971 | "sensitive": true, |
3972 | "isSeparator": false, |
3973 | "icon": "", |
3974 | - "type": "", |
3975 | + "type": "com.canonical.indicator.test", |
3976 | "ext": {}, |
3977 | - "action": "", |
3978 | + "action": "menu1", |
3979 | "actionState": {}, |
3980 | "isCheck": false, |
3981 | "isRadio": false, |
3982 | "isToggled": false, |
3983 | }}, { |
3984 | "rowData": { // row 1.2 |
3985 | - "label": "menu3", |
3986 | + "label": "menu2", |
3987 | "sensitive": true, |
3988 | "isSeparator": false, |
3989 | "icon": "", |
3990 | - "type": "", |
3991 | + "type": "com.canonical.indicator.test", |
3992 | "ext": {}, |
3993 | - "action": "", |
3994 | + "action": "menu2", |
3995 | "actionState": {}, |
3996 | "isCheck": false, |
3997 | "isRadio": false, |
3998 | @@ -147,5 +164,33 @@ |
3999 | var mainMenu = findChild(page, "mainMenu"); |
4000 | tryCompare(mainMenu, "count", data.expectedCount); |
4001 | } |
4002 | + |
4003 | + function test_remove_selected_item_data() { |
4004 | + return [ |
4005 | + { remove: 0 }, |
4006 | + { remove: 2 }, |
4007 | + ] |
4008 | + } |
4009 | + |
4010 | + function test_remove_selected_item(data) { |
4011 | + var mainMenu = findChild(page, "mainMenu"); |
4012 | + initializeMenuData(fullMenuData); |
4013 | + |
4014 | + var menuId = "menu"+data.remove |
4015 | + |
4016 | + tryCompareFunction(function() { return findChild(page, menuId) !== null;}, true); |
4017 | + var menu = findChild(page, menuId); |
4018 | + |
4019 | + menu.menuSelected(); |
4020 | + compare(mainMenu.currentIndex, data.remove, "Incorrect index selected"); |
4021 | + mainMenu.model.removeRow(data.remove); |
4022 | + |
4023 | + compare(mainMenu.currentIndex, -1, "Current index should be reset after current item removal"); |
4024 | + |
4025 | + // now make sure selecting a new menu works. |
4026 | + var menu1 = findChild(page, "menu1"); |
4027 | + menu1.menuSelected(); |
4028 | + compare(menu1.selected, true, "Item not selected"); |
4029 | + } |
4030 | } |
4031 | } |
4032 | |
4033 | === modified file 'tests/qmltests/tst_ShellWithPin.qml' |
4034 | --- tests/qmltests/tst_ShellWithPin.qml 2014-10-30 21:40:34 +0000 |
4035 | +++ tests/qmltests/tst_ShellWithPin.qml 2014-11-05 14:37:57 +0000 |
4036 | @@ -160,6 +160,7 @@ |
4037 | AccountsService.enableLauncherWhileLocked = true |
4038 | AccountsService.enableIndicatorsWhileLocked = true |
4039 | AccountsService.demoEdges = false |
4040 | + callManager.foregroundCall = null |
4041 | |
4042 | // reload our test subject to get it in a fresh state once again |
4043 | shellLoader.active = true |
4044 | @@ -212,6 +213,7 @@ |
4045 | tryCompare(lockscreen, "shown", false) |
4046 | tryCompare(greeter, "hasLockedApp", true) |
4047 | tryCompare(greeter, "lockedApp", app) |
4048 | + tryCompare(LightDM.Greeter, "active", true) |
4049 | tryCompare(ApplicationManager, "focusedApplicationId", app) |
4050 | } |
4051 | |
4052 | @@ -386,5 +388,61 @@ |
4053 | callManager.foregroundCall = phoneCall |
4054 | confirmLockedApp("dialer-app") |
4055 | } |
4056 | + |
4057 | + function test_emergencyDialerActiveCallPanel() { |
4058 | + // Make sure that the following sequence works: |
4059 | + // - Enter emergency mode call |
4060 | + // - Return to greeter |
4061 | + // - Click on active call panel |
4062 | + // - Should be back in emergency mode dialer |
4063 | + |
4064 | + var greeter = findChild(shell, "greeter"); |
4065 | + var lockscreen = findChild(shell, "lockscreen"); |
4066 | + |
4067 | + lockscreen.emergencyCall(); |
4068 | + confirmLockedApp("dialer-app"); |
4069 | + callManager.foregroundCall = phoneCall; |
4070 | + |
4071 | + LightDM.Greeter.showGreeter(); |
4072 | + tryCompare(lockscreen, "shown", true); |
4073 | + tryCompare(greeter, "hasLockedApp", false); |
4074 | + |
4075 | + // simulate a callHint press, the real thing requires dialer: url support |
4076 | + ApplicationManager.requestFocusApplication("dialer-app"); |
4077 | + |
4078 | + confirmLockedApp("dialer-app"); |
4079 | + } |
4080 | + |
4081 | + function test_normalDialerActiveCallPanel() { |
4082 | + // Make sure that the following sequence works: |
4083 | + // - Log in |
4084 | + // - Start a call |
4085 | + // - Switch apps |
4086 | + // - Click on active call panel |
4087 | + // - Should be back in normal dialer |
4088 | + // (we've had a bug where we locked screen in this case) |
4089 | + |
4090 | + var lockscreen = findChild(shell, "lockscreen"); |
4091 | + var panel = findChild(shell, "panel"); |
4092 | + |
4093 | + enterPin("1234"); |
4094 | + tryCompare(lockscreen, "shown", false); |
4095 | + tryCompare(LightDM.Greeter, "active", false); |
4096 | + |
4097 | + ApplicationManager.startApplication("dialer-app", ApplicationManager.NoFlag); |
4098 | + tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app"); |
4099 | + callManager.foregroundCall = phoneCall; |
4100 | + |
4101 | + ApplicationManager.requestFocusApplication("unity8-dash"); |
4102 | + tryCompare(ApplicationManager, "focusedApplicationId", "unity8-dash"); |
4103 | + tryCompare(panel.callHint, "visible", true); |
4104 | + |
4105 | + // simulate a callHint press, the real thing requires dialer: url support |
4106 | + ApplicationManager.requestFocusApplication("dialer-app"); |
4107 | + |
4108 | + tryCompare(ApplicationManager, "focusedApplicationId", "dialer-app"); |
4109 | + tryCompare(lockscreen, "shown", false); |
4110 | + tryCompare(LightDM.Greeter, "active", false); |
4111 | + } |
4112 | } |
4113 | } |
deemed good to go through a lot of testing