on xenial help sign in
Notifications visual update, close button on mouse hover Fixes: #1564343

Approved by: Michael Zanetti

commit83d09186df6c14e9820726502a4041d5face4f3f authorLukáš Tinkl <lukas.tinkl@canonical.com> dateWed 27 Apr 2016, 14:57 (10 years ago) parenta3512b0e68fbae
14 files changed+334−399
qml/Notifications/Notification.qml+129−119 qml/Notifications/NotificationButton.qml+72 qml/Notifications/NotificationMenuItemFactory.qml+5−11 qml/Notifications/Notifications.qml+4−5 qml/Notifications/OptionToggle.qml+12−10 qml/Notifications/ShapedIcon.qml+1 qml/Notifications/SwipeToAct.qml+16−20 qml/Notifications/grip-large.svg−150 qml/Shell.qml+3−11 tests/mocks/Unity/Notifications/MockNotificationModel.cpp+6−11 tests/qmltests/Notifications/tst_Notifications.qml+50−54 tests/qmltests/Notifications/tst_OptionToggle.qml+10−1 tests/qmltests/Notifications/tst_SwipeToAct.qml+11−1 tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+15−6
qml/Notifications/Notification.qml+129−119
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013, 2015 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -36,44 +36,40 @@ StyledItem {
3636 property var type
3737 property var hints
3838 property var notification
39− property color color
39+ property color color: theme.palette.normal.background
4040 property bool fullscreen: false
4141 property int maxHeight
42− property int margins
43− readonly property bool draggable: (type === Notification.SnapDecision && state === "contracted") || type === Notification.Interactive || type === Notification.Ephemeral
44− readonly property bool darkOnBright: inverseMode || type === Notification.SnapDecision
45− readonly property color sdLightGrey: "#eaeaea"
46− readonly property real contentSpacing: units.gu(2)
47− readonly property bool canBeClosed: type === Notification.Ephemeral
42+ property int margins: units.gu(1)
43+
44+ readonly property real defaultOpacity: 1.0
4845 property bool hasMouse
49− property bool inverseMode
5046 property url background: ""
5147
5248 objectName: "background"
53− implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0
49+ implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height + shapedBack.anchors.topMargin + margins * 2) : 0
5450
55− color: (type === Notification.Confirmation && notificationList.useModal && !greeter.shown) || darkOnBright ? sdLightGrey : Qt.rgba(0.132, 0.117, 0.109, 0.97)
56− opacity: 1 - (x / notification.width) // FIXME: non-zero initially because of LP: #1354406 workaround, we want this to start at 0 upon creation eventually
51+ // FIXME: non-zero initially because of LP: #1354406 workaround, we want this to start at 0 upon creation eventually
52+ opacity: defaultOpacity - Math.abs(x / notification.width)
5753
5854 theme: ThemeSettings {
59− name: darkOnBright ? "Ubuntu.Components.Themes.Ambiance" : "Ubuntu.Components.Themes.SuruDark"
55+ name: "Ubuntu.Components.Themes.Ambiance"
6056 }
6157
62− state: {
63− var result = "";
58+ readonly property bool expanded: {
59+ var result = false;
6460
65− if (type == Notification.SnapDecision) {
66− if (ListView.view.currentIndex == index) {
67− result = "expanded";
61+ if (type === Notification.SnapDecision) {
62+ if (ListView.view.currentIndex === index) {
63+ result = true;
6864 } else {
6965 if (ListView.view.count > 2) {
70− if (ListView.view.currentIndex == -1 && index == 1) {
71− result = "expanded";
66+ if (ListView.view.currentIndex === -1 && index == 1) {
67+ result = true;
7268 } else {
73− result = "contracted";
69+ result = false;
7470 }
7571 } else {
76− result = "expanded";
72+ result = true;
7773 }
7874 }
7975 }
@@ -90,72 +86,66 @@ StyledItem {
9086 Component.onCompleted: {
9187 // Turn on screen as needed (Powerd.Notification means the screen
9288 // stays on for a shorter amount of time)
93− if (type == Notification.SnapDecision) {
89+ if (type === Notification.SnapDecision) {
9490 Powerd.setStatus(Powerd.On, Powerd.SnapDecision);
95− } else if (type != Notification.Confirmation) {
91+ } else if (type !== Notification.Confirmation) {
9692 Powerd.setStatus(Powerd.On, Powerd.Notification);
9793 }
9894
9995 // FIXME: using onCompleted because of LP: #1354406 workaround, has to be onOpacityChanged really
100− if (opacity == 1.0 && hints["suppress-sound"] !== "true" && sound.source !== "") {
96+ if (opacity == defaultOpacity && hints["suppress-sound"] !== "true" && sound.source !== "") {
10197 sound.play();
10298 }
10399 }
104100
105− Behavior on x {
106− id: normalXBehavior
107−
108− enabled: draggable
109− UbuntuNumberAnimation {
110− duration: UbuntuAnimation.FastDuration
111− easing.type: Easing.OutBounce
101+ function closeNotification() {
102+ if (notification.actions.count > 1) { // perform the "reject" action
103+ notification.notification.invokeAction(notification.actions.data(1, ActionModel.RoleActionId));
112104 }
105+ notification.notification.close();
106+ }
107+
108+ Behavior on x {
109+ UbuntuNumberAnimation { easing.type: Easing.OutBounce }
113110 }
114111
115112 onHintsChanged: {
116− if (type === Notification.Confirmation && opacity == 1.0 && hints["suppress-sound"] !== "true" && sound.source !== "") {
113+ if (type === Notification.Confirmation && opacity == defaultOpacity && hints["suppress-sound"] !== "true" && sound.source !== "") {
117114 sound.play();
118115 }
119116 }
120117
121118 Behavior on height {
122− id: normalHeightBehavior
123−
124− //enabled: menuItemFactory.progress == 1
125− enabled: true
126119 UbuntuNumberAnimation {
127120 duration: UbuntuAnimation.SnapDuration
128121 }
129122 }
130123
131− states:[
132− State {
133− name: "contracted"
134− PropertyChanges {target: notification; height: units.gu(10)}
135− },
136− State {
137− name: "expanded"
138− PropertyChanges {target: notification; height: implicitHeight}
139− }
140− ]
141−
142− clip: fullscreen ? false : true
124+ visible: type !== Notification.PlaceHolder
143125
144− visible: type != Notification.PlaceHolder
126+ BorderImage {
127+ anchors {
128+ fill: contents
129+ margins: shapedBack.visible ? -units.gu(1) : -units.gu(1.5)
130+ }
131+ source: "../Stages/graphics/dropshadow2gu.sci"
132+ opacity: notification.opacity * 0.5
133+ enabled: !fullscreen
134+ }
145135
146136 UbuntuShape {
147137 id: shapedBack
138+ objectName: "shapedBack"
148139
149140 visible: !fullscreen
150141 anchors {
151142 fill: parent
152143 leftMargin: notification.margins
153144 rightMargin: notification.margins
154− topMargin: type === Notification.Confirmation ? units.gu(.5) : 0
145+ topMargin: index == 0 ? notification.margins : 0
155146 }
156147 backgroundColor: parent.color
157− opacity: parent.opacity
158− radius: "medium"
148+ radius: "small"
159149 aspect: UbuntuShape.Flat
160150 }
161151
@@ -165,12 +155,11 @@ StyledItem {
165155 visible: fullscreen
166156 anchors.fill: parent
167157 color: parent.color
168− opacity: parent.opacity
169158 }
170159
171160 onXChanged: {
172− if (draggable && notification.x > 0.75 * notification.width) {
173− notification.notification.close()
161+ if (Math.abs(notification.x) > 0.75 * notification.width) {
162+ closeNotification();
174163 }
175164 }
176165
@@ -210,22 +199,21 @@ StyledItem {
210199 anchors.fill: parent
211200 objectName: "interactiveArea"
212201
213− drag.target: draggable ? notification : undefined
202+ drag.target: notification
214203 drag.axis: Drag.XAxis
215− drag.minimumX: 0
204+ drag.minimumX: -notification.width
216205 drag.maximumX: notification.width
206+ hoverEnabled: true
217207
218208 onClicked: {
219− if (notification.type == Notification.Interactive) {
209+ if (notification.type === Notification.Interactive) {
220210 notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
221− } else if (hasMouse && canBeClosed) {
222− notification.notification.close()
223211 } else {
224212 notificationList.currentIndex = index;
225213 }
226214 }
227215 onReleased: {
228− if (notification.x < notification.width / 2) {
216+ if (Math.abs(notification.x) < notification.width / 2) {
229217 notification.x = 0
230218 } else {
231219 notification.x = notification.width
@@ -233,44 +221,61 @@ StyledItem {
233221 }
234222 }
235223
224+ NotificationButton {
225+ objectName: "closeButton"
226+ width: units.gu(2)
227+ height: width
228+ radius: width / 2
229+ visible: hasMouse && (containsMouse || interactiveArea.containsMouse)
230+ iconName: "close"
231+ outline: false
232+ hoverEnabled: true
233+ color: theme.palette.normal.negative
234+ anchors.horizontalCenter: parent.left
235+ anchors.horizontalCenterOffset: notification.parent.state === "narrow" ? notification.margins / 2 : 0
236+ anchors.verticalCenter: parent.top
237+ anchors.verticalCenterOffset: notification.parent.state === "narrow" ? notification.margins / 2 : 0
238+
239+ onClicked: closeNotification();
240+ }
241+
236242 Column {
237243 id: outterColumn
244+ objectName: "outterColumn"
238245
239246 anchors {
240247 left: parent.left
241248 right: parent.right
242249 top: parent.top
243− margins: 0
244− topMargin: fullscreen ? 0 : type === Notification.Confirmation ? units.gu(1) : units.gu(2)
250+ margins: !fullscreen ? notification.margins : 0
245251 }
246252
247− spacing: type === Notification.Confirmation ? units.gu(1) : units.gu(2)
253+ spacing: notification.margins
248254
249255 Row {
250256 id: topRow
251257
252− spacing: contentSpacing
258+ spacing: notification.margins
253259 anchors {
254260 left: parent.left
255261 right: parent.right
256− margins: contentSpacing
257262 }
258263
259264 ShapedIcon {
260265 id: icon
261266
262267 objectName: "icon"
263− width: type == Notification.Ephemeral && !bodyLabel.visible ? units.gu(3) : units.gu(6)
268+ width: units.gu(6)
264269 height: width
265− shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
266− visible: iconSource !== undefined && iconSource !== "" && type !== Notification.Confirmation
270+ shaped: notification.hints["x-canonical-non-shaped-icon"] !== "true"
271+ visible: iconSource !== "" && type !== Notification.Confirmation
267272 }
268273
269274 Column {
270275 id: labelColumn
271− width: secondaryIcon.visible ? parent.width - x - units.gu(4.5) : parent.width - x
272−
276+ width: secondaryIcon.visible ? parent.width - x - units.gu(3) : parent.width - x
273277 anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
278+ spacing: units.gu(.4)
274279
275280 Label {
276281 id: summaryLabel
@@ -282,6 +287,8 @@ StyledItem {
282287 }
283288 visible: type !== Notification.Confirmation
284289 fontSize: "medium"
290+ font.weight: Font.Light
291+ color: theme.palette.normal.backgroundSecondaryText
285292 elide: Text.ElideRight
286293 textFormat: Text.PlainText
287294 }
@@ -296,10 +303,13 @@ StyledItem {
296303 }
297304 visible: body != "" && type !== Notification.Confirmation
298305 fontSize: "small"
306+ font.weight: Font.Light
307+ color: theme.palette.normal.backgroundTertiaryText
299308 wrapMode: Text.Wrap
300− maximumLineCount: type == Notification.SnapDecision ? 12 : 2
309+ maximumLineCount: type === Notification.SnapDecision ? 12 : 2
301310 elide: Text.ElideRight
302311 textFormat: Text.PlainText
312+ lineHeight: 1.1
303313 }
304314 }
305315
@@ -307,25 +317,34 @@ StyledItem {
307317 id: secondaryIcon
308318
309319 objectName: "secondaryIcon"
310− width: units.gu(3)
311− height: units.gu(3)
320+ width: units.gu(2)
321+ height: width
312322 visible: status === Image.Ready
313323 fillMode: Image.PreserveAspectCrop
314324 }
315325 }
316326
317327 ListItem.ThinDivider {
318− visible: type == Notification.SnapDecision
328+ visible: type === Notification.SnapDecision && notification.expanded
329+ }
330+
331+ Icon {
332+ name: "toolkit_chevron-down_3gu"
333+ visible: type === Notification.SnapDecision && !notification.expanded
334+ width: units.gu(2)
335+ height: width
336+ anchors.horizontalCenter: parent.horizontalCenter
337+ color: theme.palette.normal.base
319338 }
320339
321340 ShapedIcon {
322341 id: centeredIcon
323342 objectName: "centeredIcon"
324− width: units.gu(5)
343+ width: units.gu(4)
325344 height: width
326− shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
345+ shaped: notification.hints["x-canonical-non-shaped-icon"] !== "true"
327346 fileSource: icon.fileSource
328− visible: fileSource !== undefined && fileSource !== "" && type === Notification.Confirmation
347+ visible: fileSource !== "" && type === Notification.Confirmation
329348 anchors.horizontalCenter: parent.horizontalCenter
330349 }
331350
@@ -336,44 +355,32 @@ StyledItem {
336355 anchors.horizontalCenter: parent.horizontalCenter
337356 visible: type === Notification.Confirmation && body !== ""
338357 fontSize: "medium"
358+ font.weight: Font.Light
359+ color: theme.palette.normal.backgroundSecondaryText
339360 wrapMode: Text.WordWrap
340361 maximumLineCount: 1
341362 elide: Text.ElideRight
342363 textFormat: Text.PlainText
343364 }
344365
345− UbuntuShape {
366+ ProgressBar {
346367 id: valueIndicator
347368 objectName: "valueIndicator"
348369 visible: type === Notification.Confirmation
349− property double value
350−
370+ minimumValue: 0
371+ maximumValue: 100
372+ showProgressPercentage: false
351373 anchors {
352374 left: parent.left
353375 right: parent.right
354− margins: contentSpacing
355376 }
356−
357377 height: units.gu(1)
358− backgroundColor: theme.palette.normal.background
359− aspect: UbuntuShape.Flat
360− radius: "small"
361−
362− UbuntuShape {
363− id: innerBar
364− objectName: "innerBar"
365− width: valueIndicator.width * valueIndicator.value / 100
366− height: units.gu(1)
367− backgroundColor: notification.hints["x-canonical-value-bar-tint"] === "true" ? theme.palette.normal.activity : theme.palette.highlighted.foreground
368− aspect: UbuntuShape.Flat
369− radius: "small"
370− }
371378 }
372379
373380 Column {
374381 id: dialogColumn
375382 objectName: "dialogListView"
376− spacing: units.gu(2)
383+ spacing: notification.margins
377384
378385 visible: count > 0
379386
@@ -417,12 +424,11 @@ StyledItem {
417424 anchors {
418425 left: parent.left
419426 right: parent.right
420− margins: contentSpacing
421427 }
422428
423− spacing: contentSpacing
429+ spacing: notification.margins
424430
425− visible: notification.type === Notification.SnapDecision && oneOverTwoRepeaterTop.count === 3
431+ visible: notification.type === Notification.SnapDecision && oneOverTwoRepeaterTop.count === 3 && notification.expanded
426432
427433 Repeater {
428434 id: oneOverTwoRepeaterTop
@@ -437,11 +443,13 @@ StyledItem {
437443 Component {
438444 id: oneOverTwoButtonTop
439445
440− Button {
446+ NotificationButton {
441447 objectName: "notify_oot_button" + index
442448 width: oneOverTwoCase.width
443449 text: oneOverTwoLoaderTop.actionLabel
444− color: notification.hints["x-canonical-private-affirmative-tint"] == "true" ? UbuntuColors.green : theme.palette.normal.baseText
450+ outline: notification.hints["x-canonical-private-affirmative-tint"] !== "true"
451+ color: notification.hints["x-canonical-private-affirmative-tint"] === "true" ? theme.palette.normal.positive
452+ : theme.palette.normal.foreground
445453 onClicked: notification.notification.invokeAction(oneOverTwoLoaderTop.actionId)
446454 }
447455 }
@@ -450,7 +458,7 @@ StyledItem {
450458 }
451459
452460 Row {
453− spacing: contentSpacing
461+ spacing: notification.margins
454462
455463 Repeater {
456464 id: oneOverTwoRepeaterBottom
@@ -465,11 +473,13 @@ StyledItem {
465473 Component {
466474 id: oneOverTwoButtonBottom
467475
468− Button {
476+ NotificationButton {
469477 objectName: "notify_oot_button" + index
470− width: oneOverTwoCase.width / 2 - spacing * 2
478+ width: oneOverTwoCase.width / 2 - spacing / 2
471479 text: oneOverTwoLoaderBottom.actionLabel
472− color: index == 1 && notification.hints["x-canonical-private-rejection-tint"] == "true" ? UbuntuColors.red : theme.palette.normal.baseText
480+ outline: notification.hints["x-canonical-private-rejection-tint"] !== "true"
481+ color: index == 1 && notification.hints["x-canonical-private-rejection-tint"] === "true" ? theme.palette.normal.negative
482+ : theme.palette.normal.foreground
473483 onClicked: notification.notification.invokeAction(oneOverTwoLoaderBottom.actionId)
474484 }
475485 }
@@ -486,10 +496,9 @@ StyledItem {
486496 anchors {
487497 left: parent.left
488498 right: parent.right
489− margins: contentSpacing
490499 }
491− visible: notification.type === Notification.SnapDecision && actionRepeater.count > 0 && !oneOverTwoCase.visible
492− spacing: contentSpacing
500+ visible: notification.type === Notification.SnapDecision && actionRepeater.count > 0 && !oneOverTwoCase.visible && notification.expanded
501+ spacing: notification.margins
493502 layoutDirection: Qt.RightToLeft
494503
495504 Loader {
@@ -525,17 +534,19 @@ StyledItem {
525534 Component {
526535 id: actionButton
527536
528− Button {
537+ NotificationButton {
529538 objectName: "notify_button" + index
530− width: buttonRow.width / 2 - spacing * 2
539+ width: buttonRow.width / 2 - spacing / 2
531540 text: loader.actionLabel
541+ outline: (index == 0 && notification.hints["x-canonical-private-affirmative-tint"] !== "true") ||
542+ (index == 1 && notification.hints["x-canonical-private-rejection-tint"] !== "true")
532543 color: {
533− var result = theme.palette.normal.baseText;
534− if (index == 0 && notification.hints["x-canonical-private-affirmative-tint"] == "true") {
535− result = UbuntuColors.green;
544+ var result = theme.palette.normal.foreground;
545+ if (index == 0 && notification.hints["x-canonical-private-affirmative-tint"] === "true") {
546+ result = theme.palette.normal.positive;
536547 }
537− if (index == 1 && notification.hints["x-canonical-private-rejection-tint"] == "true") {
538− result = UbuntuColors.red;
548+ if (index == 1 && notification.hints["x-canonical-private-rejection-tint"] === "true") {
549+ result = theme.palette.normal.negative;
539550 }
540551 return result;
541552 }
@@ -554,10 +565,9 @@ StyledItem {
554565 anchors {
555566 left: parent.left
556567 right: parent.right
557− margins: contentSpacing
558568 }
559569
560− visible: notification.type == Notification.SnapDecision && actionRepeater.count > 3 && !oneOverTwoCase.visible
570+ visible: notification.type === Notification.SnapDecision && actionRepeater.count > 3 && !oneOverTwoCase.visible && notification.expanded
561571 model: notification.actions
562572 expanded: false
563573 startIndex: 2
qml/Notifications/NotificationButton.qmlnew file+72
@@ -0,0 +1,72 @@
1+/*
2+ * Copyright 2016 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU Lesser General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU Lesser General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU Lesser General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+
20+Rectangle {
21+ id: root
22+ height: units.gu(4)
23+ radius: units.gu(0.6)
24+
25+ // to be read from outside
26+ readonly property alias containsMouse: mouseArea.containsMouse
27+
28+ // to be set from outside
29+ property bool outline: true
30+ property alias text: label.text
31+ property alias iconName: icon.name
32+ property bool hoverEnabled: false
33+
34+ signal clicked()
35+
36+ Label {
37+ id: label
38+ fontSize: "medium"
39+ font.weight: Font.Light
40+ anchors.centerIn: root
41+ color: outline ? theme.palette.normal.backgroundSecondaryText : "white"
42+ visible: text !== ""
43+ }
44+
45+ Icon {
46+ id: icon
47+ height: root.height * 2 / 3
48+ width: height
49+ anchors.centerIn: root
50+ color: "white"
51+ visible: !label.visible
52+ }
53+
54+ MouseArea {
55+ id: mouseArea
56+ anchors.fill: root
57+ hoverEnabled: root.hoverEnabled
58+ onClicked: {
59+ Haptics.play();
60+ root.clicked();
61+ }
62+ }
63+
64+ transformOrigin: Item.Top
65+ scale: mouseArea.pressed ? 0.98 : 1.0
66+ Behavior on scale {
67+ ScaleAnimator {
68+ duration: UbuntuAnimation.SnapDuration
69+ easing.type: Easing.Linear
70+ }
71+ }
72+}
qml/Notifications/NotificationMenuItemFactory.qml+5−11
@@ -1,5 +1,5 @@
11/*
2− * Copyright 2013 Canonical Ltd.
2+ * Copyright 2013-2016 Canonical Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU Lesser General Public License as published by
@@ -12,9 +12,6 @@
1212 *
1313 * You should have received a copy of the GNU Lesser General Public License
1414 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15− *
16− * Authors:
17− * Nick Dedekind <nick.dedekind@canonical.com>
1815 */
1916
2017import QtQuick 2.4
@@ -71,7 +68,7 @@ Loader {
7168 id: textfield
7269
7370 Column {
74− spacing: units.gu(2)
71+ spacing: notification.margins
7572
7673 anchors {
7774 left: parent.left
@@ -87,12 +84,10 @@ Loader {
8784
8885 Label {
8986 text: menuData.label
90− color: notification.sdFontColor
87+ color: theme.palette.normal.backgroundSecondaryText
9188 }
9289
9390 TextField {
94− id: textfield
95−
9691 // TODO using Qt.ImhNoPredictiveText here until lp #1291575 is fixed for ubuntu-ui-toolkit
9792 inputMethodHints: Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText
9893 anchors {
@@ -115,7 +110,7 @@ Loader {
115110 Row {
116111 id: checkBoxRow
117112
118− spacing: units.gu(.5)
113+ spacing: notification.margins
119114
120115 CheckBox {
121116 id: checkBox
@@ -127,7 +122,7 @@ Loader {
127122 Label {
128123 anchors.verticalCenter: checkBox.verticalCenter
129124 text: i18n.tr("Show password")
130− color: notification.sdFontColor
125+ color: theme.palette.normal.backgroundSecondaryText
131126
132127 MouseArea {
133128 anchors.fill: parent
@@ -151,7 +146,6 @@ Loader {
151146 errorText: errorAction.valid ? errorAction.state : ""
152147 retryText: notification.body
153148 background: menuFactory.background
154− darkenBackground: 0.4
155149
156150 onEntered: {
157151 menuModel.changeState(menuIndex, passphrase);
qml/Notifications/Notifications.qml+4−5
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2013 Canonical, Ltd.
2+ * Copyright (C) 2013-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -27,11 +27,11 @@ ListView {
2727 interactive: false
2828
2929 property real margin
30− property bool useModal: snapDecisionProxyModel.count > 0
3130 property bool hasMouse
32− property bool inverseMode
3331 property url background: ""
3432
33+ readonly property bool useModal: snapDecisionProxyModel.count > 0
34+
3535 UnitySortFilterProxyModel {
3636 id: snapDecisionProxyModel
3737 objectName: "snapDecisionProxyModel"
@@ -42,7 +42,7 @@ ListView {
4242 }
4343
4444 property bool topmostIsFullscreen: false
45− spacing: topmostIsFullscreen ? 0 : units.gu(.5)
45+ spacing: topmostIsFullscreen ? 0 : units.gu(1)
4646
4747 currentIndex: count > 1 ? 1 : -1
4848
@@ -62,7 +62,6 @@ ListView {
6262 maxHeight: notificationList.height
6363 margins: notificationList.margin
6464 hasMouse: notificationList.hasMouse
65− inverseMode: notificationList.inverseMode
6665 background: notificationList.background
6766
6867 // make sure there's no opacity-difference between the several
qml/Notifications/OptionToggle.qml+12−10
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014,2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -19,22 +19,23 @@ import Ubuntu.Components 1.3
1919import Ubuntu.Components.ListItems 1.3 as ListItem
2020import Ubuntu.Components.Popups 1.3
2121
22−UbuntuShape {
22+Rectangle {
2323 id: optionToggle
2424
2525 property bool expanded
2626 property var model
2727 property int startIndex
28− readonly property double itemHeight: units.gu(5)
28+ readonly property double itemHeight: units.gu(4)
2929
3030 signal triggered(string id)
3131
32− backgroundColor: theme.palette.normal.base
33− aspect: UbuntuShape.Flat
32+ color: theme.palette.normal.background
3433 height: expanded ? (optionToggleRepeater.count - startIndex) * itemHeight : itemHeight
3534 width: parent.width
36− radius: "medium"
35+ radius: units.gu(0.6)
3736 clip: true
37+ border.width: units.dp(1)
38+ border.color: theme.palette.normal.base
3839
3940 Column {
4041 id: optionToggleContent
@@ -75,7 +76,7 @@ UbuntuShape {
7576 id: delegateIcon
7677 anchors {
7778 left: parent.left
78− leftMargin: units.gu(2)
79+ leftMargin: units.gu(1)
7980 verticalCenter: parent.verticalCenter
8081 }
8182 visible: index !== startIndex
@@ -90,14 +91,15 @@ UbuntuShape {
9091 left: delegateIcon.visible ? delegateIcon.right : parent.left
9192 leftMargin: delegateIcon.visible ? units.gu(1) : units.gu(2)
9293 right: parent.right
93− rightMargin: units.gu(2)
94+ rightMargin: units.gu(1)
9495 verticalCenter: delegateIcon.visible ? delegateIcon.verticalCenter : parent.verticalCenter
9596 }
9697
9798 width: parent.width
9899 text: splitLabel[3]
99− color: theme.palette.normal.backgroundText
100+ color: theme.palette.normal.backgroundSecondaryText
100101 fontSize: "small"
102+ font.weight: Font.Light
101103 maximumLineCount: 1
102104 elide: Text.ElideRight
103105 }
@@ -105,7 +107,7 @@ UbuntuShape {
105107 Icon {
106108 anchors {
107109 right: parent.right
108− rightMargin: units.gu(2)
110+ rightMargin: units.gu(1)
109111 verticalCenter: delegateIcon.verticalCenter
110112 }
111113
qml/Notifications/ShapedIcon.qml+1
@@ -27,6 +27,7 @@ Item {
2727 visible: shaped
2828 source: realImage
2929 sourceFillMode: UbuntuShape.PreserveAspectCrop
30+ aspect: UbuntuShape.Flat
3031 }
3132
3233 Image {
qml/Notifications/SwipeToAct.qml+16−20
@@ -20,7 +20,7 @@ import Ubuntu.Components 1.3
2020Item {
2121 id: swipeToAct
2222
23− height: clickToAct ? leftButton.height : childrenRect.height
23+ height: clickToAct ? leftButton.height : row.height
2424
2525 signal leftTriggered()
2626 signal rightTriggered()
@@ -36,8 +36,8 @@ Item {
3636 property double opacityDelta
3737 readonly property double sliderHeight: units.gu(8)
3838 readonly property double gap: units.gu(1)
39− readonly property color sliderMainColor: "#b2b2b2"
40− readonly property color sliderBGColor: "#f4f4f4"
39+ readonly property color sliderMainColor: theme.palette.normal.base
40+ readonly property color sliderBGColor: theme.palette.normal.background
4141 readonly property double halfWay: mouseArea.drag.maximumX / 2
4242
4343 UbuntuNumberAnimation on opacityDelta {
@@ -66,32 +66,30 @@ Item {
6666 }
6767 }
6868
69− Button {
69+ NotificationButton {
7070 id: leftButton
7171 objectName: "leftButton"
7272 anchors.verticalCenter: parent.verticalCenter
7373 anchors.left: parent.left
7474 iconName: leftIconName
7575 visible: clickToAct
76− width: (parent.width / 2) - priv.gap
77− color: UbuntuColors.red
78− onClicked: {
79− leftTriggered()
80− }
76+ outline: false
77+ width: (parent.width / 2) - priv.gap / 2
78+ color: theme.palette.normal.negative
79+ onClicked: leftTriggered()
8180 }
8281
83− Button {
82+ NotificationButton {
8483 id: rightButton
8584 objectName: "rightButton"
8685 anchors.verticalCenter: parent.verticalCenter
8786 anchors.right: parent.right
8887 iconName: rightIconName
8988 visible: clickToAct
90− width: (parent.width / 2) - priv.gap
91− color: UbuntuColors.green
92− onClicked: {
93− rightTriggered()
94− }
89+ outline: false
90+ width: (parent.width / 2) - priv.gap / 2
91+ color: theme.palette.normal.positive
92+ onClicked: rightTriggered()
9593 }
9694
9795 UbuntuShape {
@@ -108,10 +106,9 @@ Item {
108106 anchors.top: parent.top
109107 anchors.left: parent.left
110108 anchors.margins: priv.gap
111− backgroundColor: UbuntuColors.red
109+ backgroundColor: theme.palette.normal.negative
112110 aspect: UbuntuShape.Flat
113111
114− state: "normal"
115112 height: units.gu(6)
116113 width: units.gu(6)
117114 radius: "medium"
@@ -195,7 +192,7 @@ Item {
195192 Icon {
196193 anchors.fill: parent
197194 anchors.margins: units.gu(1.5)
198− source: "grip-large.svg"
195+ name: "grip-large"
199196 color: "white"
200197 }
201198 }
@@ -226,10 +223,9 @@ Item {
226223 anchors.top: parent.top
227224 anchors.right: parent.right
228225 anchors.margins: priv.gap
229− backgroundColor: UbuntuColors.green
226+ backgroundColor: theme.palette.normal.positive
230227 aspect: UbuntuShape.Flat
231228
232− state: "normal"
233229 height: units.gu(6)
234230 width: units.gu(6)
235231 radius: "medium"
qml/Notifications/grip-large.svgdeleted−150
@@ -1,150 +0,0 @@
1−<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2−<!-- Created with Inkscape (http://www.inkscape.org/) -->
3−
4−<svg
5− xmlns:dc="http://purl.org/dc/elements/1.1/"
6− xmlns:cc="http://creativecommons.org/ns#"
7− xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8− xmlns:svg="http://www.w3.org/2000/svg"
9− xmlns="http://www.w3.org/2000/svg"
10− xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11− xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12− width="90"
13− height="90"
14− id="svg4874"
15− version="1.1"
16− inkscape:version="0.91+devel r"
17− viewBox="0 0 90 90.000001"
18− sodipodi:docname="grip-large01.svg">
19− <defs
20− id="defs4876" />
21− <sodipodi:namedview
22− id="base"
23− pagecolor="#ffffff"
24− bordercolor="#666666"
25− borderopacity="1.0"
26− inkscape:pageopacity="0.0"
27− inkscape:pageshadow="2"
28− inkscape:zoom="7.9580786"
29− inkscape:cx="13.632541"
30− inkscape:cy="49.591116"
31− inkscape:document-units="px"
32− inkscape:current-layer="g1708"
33− showgrid="true"
34− showborder="true"
35− fit-margin-top="0"
36− fit-margin-left="0"
37− fit-margin-right="0"
38− fit-margin-bottom="0"
39− inkscape:snap-bbox="true"
40− inkscape:bbox-paths="true"
41− inkscape:bbox-nodes="true"
42− inkscape:snap-bbox-edge-midpoints="true"
43− inkscape:snap-bbox-midpoints="true"
44− inkscape:object-paths="true"
45− inkscape:snap-intersection-paths="true"
46− inkscape:object-nodes="true"
47− inkscape:snap-smooth-nodes="true"
48− inkscape:snap-midpoints="true"
49− inkscape:snap-object-midpoints="true"
50− inkscape:snap-center="true"
51− showguides="true"
52− inkscape:guide-bbox="true">
53− <inkscape:grid
54− type="xygrid"
55− id="grid5451"
56− empspacing="6" />
57− <sodipodi:guide
58− orientation="1,0"
59− position="6,77"
60− id="guide4063" />
61− <sodipodi:guide
62− orientation="1,0"
63− position="3,78"
64− id="guide4065" />
65− <sodipodi:guide
66− orientation="0,1"
67− position="55,84"
68− id="guide4067" />
69− <sodipodi:guide
70− orientation="0,1"
71− position="53,87"
72− id="guide4069" />
73− <sodipodi:guide
74− orientation="0,1"
75− position="20,3"
76− id="guide4071" />
77− <sodipodi:guide
78− orientation="0,1"
79− position="20,6"
80− id="guide4073" />
81− <sodipodi:guide
82− orientation="1,0"
83− position="87,7"
84− id="guide4075" />
85− <sodipodi:guide
86− orientation="1,0"
87− position="84,7"
88− id="guide4077" />
89− <sodipodi:guide
90− orientation="0,1"
91− position="58,81"
92− id="guide4074" />
93− <sodipodi:guide
94− orientation="1,0"
95− position="9,74"
96− id="guide4076" />
97− <sodipodi:guide
98− orientation="0,1"
99− position="21,9"
100− id="guide4078" />
101− <sodipodi:guide
102− orientation="1,0"
103− position="81,4"
104− id="guide4080" />
105− </sodipodi:namedview>
106− <metadata
107− id="metadata4879">
108− <rdf:RDF>
109− <cc:Work
110− rdf:about="">
111− <dc:format>image/svg+xml</dc:format>
112− <dc:type
113− rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
114− <dc:title></dc:title>
115− </cc:Work>
116− </rdf:RDF>
117− </metadata>
118− <g
119− inkscape:label="Layer 1"
120− inkscape:groupmode="layer"
121− id="layer1"
122− transform="translate(67.857146,-84.50504)">
123− <g
124− transform="matrix(0,-1,-1,0,373.50506,516.50504)"
125− id="g4845"
126− style="display:inline">
127− <g
128− inkscape:label="Layer 1"
129− id="g1708"
130− transform="matrix(0,-1,-1,0,1394.3622,441.36221)"
131− inkscape:export-filename="add01.png"
132− inkscape:export-xdpi="90"
133− inkscape:export-ydpi="90">
134− <rect
135− style="color:#000000;fill:none;stroke:none;stroke-width:7.5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
136− id="rect1710"
137− width="90"
138− height="90"
139− x="0"
140− y="962.36218" />
141− <path
142− style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.5;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
143− d="m 9.000004,971.3622 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m -72,16 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.79086 -4,4 0,2.20914 1.790861,4 4,4 2.209139,0 4,-1.79086 4,-4 0,-2.20914 -1.790861,-4 -4,-4 z m -72,16 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m -72,16 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m -72,16 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 18.199219,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z m 17.800781,0 c -2.209139,0 -4,1.7909 -4,4 0,2.2091 1.790861,4 4,4 2.209139,0 4,-1.7909 4,-4 0,-2.2091 -1.790861,-4 -4,-4 z"
144− id="path4169"
145− inkscape:connector-curvature="0"
146− sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss" />
147− </g>
148− </g>
149− </g>
150−</svg>
qml/Shell.qml+3−11
@@ -639,17 +639,10 @@ Item {
639639 onActiveChanged: unlockWhenDoneWithWizard()
640640 }
641641
642− Rectangle {
643− id: modalNotificationBackground
644−
645− visible: notifications.useModal
646− color: "#000000"
642+ MouseArea { // modal notifications prevent interacting with other contents
647643 anchors.fill: parent
648− opacity: 0.9
649−
650− MouseArea {
651− anchors.fill: parent
652− }
644+ visible: notifications.useModal
645+ enabled: visible
653646 }
654647
655648 Notifications {
@@ -658,7 +651,6 @@ Item {
658651 model: NotificationBackend.Model
659652 margin: units.gu(1)
660653 hasMouse: shell.hasMouse
661− inverseMode: panel.indicators.shown
662654 background: wallpaperResolver.background
663655
664656 y: topmostIsFullscreen ? 0 : panel.panelHeight
tests/mocks/Unity/Notifications/MockNotificationModel.cpp+6−11
@@ -90,6 +90,7 @@ QVariant MockNotificationModel::data(const QModelIndex &index, int role) const {
9090}
9191
9292void MockNotificationModel::append(MockNotification* n) {
93+ QQmlEngine::setObjectOwnership(n, QQmlEngine::CppOwnership);
9394 int location = m_queue.size();
9495 QModelIndex insertionPoint = QModelIndex();
9596 beginInsertRows(insertionPoint, location, location);
@@ -98,9 +99,10 @@ void MockNotificationModel::append(MockNotification* n) {
9899}
99100
100101MockNotification* MockNotificationModel::getNotification(int id) const {
101− for(int i=0; i < m_queue.size(); i++) {
102− if(m_queue[i]->getID() == id) {
103− return m_queue[i];
102+ for(int i = 0; i < m_queue.size(); i++) {
103+ MockNotification* n = m_queue.at(i);
104+ if(n && n->getID() == id) {
105+ return n;
104106 }
105107 }
106108
@@ -130,14 +132,7 @@ void MockNotificationModel::removeInternal(int loc) {
130132}
131133
132134MockNotification* MockNotificationModel::getRaw(const int notificationId) const {
133− for(int i = 0; i < m_queue.size(); i++) {
134− if(m_queue[i]->getID() == notificationId) {
135− MockNotification* n = m_queue[i];
136− return n;
137− }
138− }
139−
140− return nullptr;
135+ return getNotification(notificationId);
141136}
142137
143138int MockNotificationModel::queued() const {
tests/qmltests/Notifications/tst_Notifications.qml+50−54
@@ -31,26 +31,26 @@ Item {
3131 height: notificationsRect.height
3232 property int index: 0
3333
34+ // add the default/PlaceHolder notification to the model
35+ Component.onCompleted: {
36+ var component = Qt.createComponent("Notification.qml")
37+ var n = component.createObject("notification", {"nid": index++,
38+ "type": Notification.PlaceHolder,
39+ "hints": {},
40+ "summary": "",
41+ "body": "",
42+ "icon": "",
43+ "secondaryIcon": "",
44+ "rawActions": []})
45+ n.completed.connect(mockModel.onCompleted)
46+ mockModel.append(n)
47+ }
48+
3449 Row {
3550 id: rootRow
3651
3752 NotificationModel {
3853 id: mockModel
39−
40− // add the default/PlaceHolder notification to the model
41− Component.onCompleted: {
42− var component = Qt.createComponent("Notification.qml")
43− var n = component.createObject("notification", {"nid": index++,
44− "type": Notification.PlaceHolder,
45− "hints": {},
46− "summary": "",
47− "body": "",
48− "icon": "",
49− "secondaryIcon": "",
50− "rawActions": []})
51− n.completed.connect(mockModel.onCompleted)
52− append(n)
53− }
5454 }
5555
5656 function add2over1SnapDecisionNotification() {
@@ -188,7 +188,6 @@ Item {
188188 anchors.fill: parent
189189 model: mockModel
190190 hasMouse: fakeMouseCB.checked
191− inverseMode: inverseModeCB.checked
192191 }
193192 }
194193
@@ -269,15 +268,9 @@ Item {
269268 }
270269 }
271270
272− RowLayout {
273− Layout.fillWidth: true
274− CheckBox {
275− id: inverseModeCB
276− }
277− Label {
278− text: "Inverse mode"
279− anchors.verticalCenter: parent.verticalCenter
280− }
271+ MouseTouchEmulationCheckbox {
272+ id: mouseEmulation
273+ checked: false
281274 }
282275 }
283276 }
@@ -562,6 +555,12 @@ Item {
562555 signalName: "actionInvoked"
563556 }
564557
558+ function init() {
559+ while (mockModel.count > 0) {
560+ mockModel.remove(0);
561+ }
562+ }
563+
565564 function cleanup() {
566565 clickThroughSpy.clear()
567566 actionSpy.clear()
@@ -582,10 +581,9 @@ Item {
582581 waitForRendering(notifications);
583582
584583 var notification = findChild(notifications, "notification" + (mockModel.count - 1))
585− verify(notification !== undefined, "notification wasn't found");
586−
587584 waitForRendering(notification);
588− tryCompare(notification, "height", notification.state === "contracted" ? units.gu(10) : notification.implicitHeight);
585+ verify(notification, "notification wasn't found");
586+ tryCompare(notification, "height", notification.implicitHeight);
589587
590588 var icon = findChild(notification, "icon")
591589 var centeredIcon = findChild(notification, "centeredIcon")
@@ -596,7 +594,6 @@ Item {
596594 var buttonRow = findChild(notification, "buttonRow")
597595 var valueIndicator = findChild(notification, "valueIndicator")
598596 var valueLabel = findChild(notification, "valueLabel")
599− var innerBar = findChild(notification, "innerBar")
600597
601598 compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect")
602599 if (icon.visible) {
@@ -607,9 +604,6 @@ Item {
607604 compare(centeredIcon.shaped, data.shaped, "shaped-status is incorrect")
608605 }
609606 compare(valueIndicator.visible, data.valueVisible, "value-indicator visibility is incorrect")
610− if (valueIndicator.visible) {
611− verify(innerBar.color === data.valueTinted ? UbuntuColors.orange : "white", "value-bar has the wrong color-tint")
612− }
613607 compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect")
614608
615609 // test input does not fall through
@@ -629,7 +623,12 @@ Item {
629623 // for their height animations to finish before continuing
630624 for (var i = 0; i < mockModel.count; ++i) {
631625 var n = findChild(notifications, "notification" + i)
632− tryCompare(n, "height", n.state === "contracted" ? units.gu(10) : n.implicitHeight);
626+ if (n.type === Notification.PlaceHolder)
627+ continue;
628+ waitForRendering(n);
629+ var outterColumn = findChild(n, "outterColumn");
630+ var shapedBack = findChild(n, "shapedBack");
631+ tryCompare(n, "height", outterColumn.height + n.margins * 2 + shapedBack.anchors.topMargin);
633632 }
634633
635634 if (data.hasSound) {
@@ -662,7 +661,7 @@ Item {
662661 tryCompareFunction(function() { return comboButton.expanded === false; }, true);
663662
664663 // click to expand
665− tryCompareFunction(function() { mouseClick(comboButton, comboButton.width / 2, comboButton.height / 2); return comboButton.expanded === true; }, true);
664+ tryCompareFunction(function() { mouseClick(comboButton, comboButton.width / 2, comboButton.height / 2); return comboButton.expanded; }, true);
666665
667666 // try clicking on choices in expanded comboList
668667 var choiceButton1 = findChild(notification, "notify_button3")
@@ -676,7 +675,7 @@ Item {
676675 actionSpy.clear()
677676
678677 // click to collapse
679− tryCompareFunction(function() { mouseClick(comboButton, comboButton.width / 2, comboButton.height / 2); return comboButton.expanded == false; }, true);
678+ tryCompareFunction(function() { mouseClick(comboButton, comboButton.width / 2, comboButton.height / 2); return !comboButton.expanded; }, true);
680679 } else {
681680 mouseClick(buttonCancel)
682681 compare(actionSpy.signalArguments[0][0], data.n.actions.data(1, ActionModel.RoleActionId), "got wrong id for negative action")
@@ -691,19 +690,18 @@ Item {
691690 var dragY = notification.height / 2;
692691 touchFlick(notification, dragStart, dragY, dragEnd, dragY)
693692 waitForRendering(notification)
694− if ((data.n.type === Notification.SnapDecision && notification.state === "expanded") || data.n.type === Notification.Confirmation) {
695− tryCompare(mockModel, "count", before)
696− } else {
697− tryCompare(mockModel, "count", before - 1)
698− }
693+ tryCompare(mockModel, "count", before - 1)
699694 }
700695
701− function test_clickToClose_data() { // reuse the data
696+ function test_closeButton_data() { // reuse the data
702697 notifications.hasMouse = true;
703698 return test_NotificationRenderer_data();
704699 }
705700
706− function test_clickToClose(data) {
701+ function test_closeButton(data) {
702+ // hook up notification's completed-signal with model's onCompleted-slot, so that remove() (model) happens on close() (notification)
703+ data.n.completed.connect(mockModel.onCompleted)
704+
707705 // populate model with some mock notifications
708706 mockModel.append(data.n)
709707
@@ -712,21 +710,19 @@ Item {
712710 waitForRendering(notifications);
713711
714712 var notification = findChild(notifications, "notification" + (mockModel.count - 1))
713+ waitForRendering(notification);
715714 verify(!!notification, "notification wasn't found");
716715
717− // click-to-dismiss check
718− waitForRendering(notification);
716+ // close button check
717+ mouseMove(notification, notification.width/2, notification.height/2);
718+ var closeButton = findChild(notification, "closeButton");
719+ tryCompare(closeButton, "visible", true);
719720 var before = mockModel.count;
720− var canBeClosed = notification.canBeClosed;
721− mouseClick(notification);
722−
723− if (canBeClosed) {
724− // closing the notification, the model count should be one less
725− tryCompare(mockModel, "count", before - 1)
726− } else {
727− // not closing, model stays the same
728− tryCompare(mockModel, "count", before)
729− }
721+ mouseClick(closeButton);
722+ waitForRendering(notification);
723+
724+ // closing the notification, the model count should be one less
725+ tryCompare(mockModel, "count", before - 1)
730726 }
731727
732728 function cleanupTestCase() {
tests/qmltests/Notifications/tst_OptionToggle.qml+10−1
@@ -36,6 +36,10 @@ Row {
3636 console.log("Action invoked", actionId);
3737 mockModel.actionInvoked(actionId)
3838 }
39+
40+ function close() {
41+ console.log("Close notification");
42+ }
3943 }
4044 }
4145
@@ -96,7 +100,7 @@ Row {
96100
97101 width: units.gu(40)
98102 height: units.gu(81)
99− color: "#cccccc"
103+ color: theme.palette.normal.background
100104
101105 MouseArea{
102106 id: clickThroughCatcher
@@ -143,6 +147,11 @@ Row {
143147 text: "clear model"
144148 onClicked: clearNotifications()
145149 }
150+
151+ MouseTouchEmulationCheckbox {
152+ id: mouseEmulation
153+ checked: false
154+ }
146155 }
147156 }
148157
tests/qmltests/Notifications/tst_SwipeToAct.qml+11−1
@@ -37,6 +37,10 @@ Item {
3737 function invokeAction(actionId) {
3838 mockModel.actionInvoked(actionId)
3939 }
40+
41+ function close() {
42+ console.log("Close notification");
43+ }
4044 }
4145 }
4246
@@ -73,7 +77,7 @@ Item {
7377 summary: "Incoming call",
7478 body: "Frank Zappa\n+44 (0)7736 027340",
7579 icon: "../../tests/graphics/avatars/amanda.png",
76− secondaryIcon: "incoming-call",
80+ secondaryIcon: "image://theme/incoming-call",
7781 actions: [{ id: "ok_id", label: "Ok"},
7882 { id: "cancel_id", label: "Cancel"},
7983 { id: "foo_id", label: "Foo"},
@@ -162,6 +166,11 @@ Item {
162166 anchors.verticalCenter: parent.verticalCenter
163167 }
164168 }
169+
170+ MouseTouchEmulationCheckbox {
171+ id: mouseEmulation
172+ checked: false
173+ }
165174 }
166175 }
167176
@@ -301,6 +310,7 @@ Item {
301310
302311 // add a mock mouse, test clicking the left/right buttons
303312 notifications.hasMouse = true;
313+ waitForRendering(notification);
304314 var leftButton = findChild(swipeButton, "leftButton");
305315 var rightButton = findChild(swipeButton, "rightButton");
306316
tests/qmltests/Notifications/tst_VisualSnapDecisionsQueue.qml+15−6
@@ -1,5 +1,5 @@
11/*
2− * Copyright (C) 2014 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
33 *
44 * This program is free software; you can redistribute it and/or modify
55 * it under the terms of the GNU General Public License as published by
@@ -32,6 +32,10 @@ Row {
3232 function invokeAction(actionId) {
3333 mockModel.actionInvoked(actionId)
3434 }
35+
36+ function close() {
37+ console.log("Close notification");
38+ }
3539 }
3640 }
3741
@@ -180,6 +184,11 @@ Row {
180184 text: "clear model"
181185 onClicked: clearNotifications()
182186 }
187+
188+ MouseTouchEmulationCheckbox {
189+ id: mouseEmulation
190+ checked: false
191+ }
183192 }
184193 }
185194
@@ -207,9 +216,9 @@ Row {
207216 }
208217
209218 // check initial states once all five snap-decisions were appended to the model
210− compare(snap_decision[0].state, "expanded", "state of first snap-decision is not expanded");
219+ compare(snap_decision[0].expanded, true, "state of first snap-decision is not expanded");
211220 for (var index = 1; index < snap_decision.length; index++) {
212− compare(snap_decision[index].state, "contracted", "state of "+ index + ".snap-decision is not contracted");
221+ compare(snap_decision[index].expanded, false, "state of "+ index + ".snap-decision is not contracted");
213222 }
214223
215224 // click/tap on each snap-decision and verify only one is in expanded-state at any time
@@ -217,9 +226,9 @@ Row {
217226 mouseClick(snap_decision[index])
218227 for (var kindex = 0; kindex < snap_decision.length; kindex++) {
219228 if (kindex == index) {
220− compare(snap_decision[kindex].state, "expanded", "state of "+ kindex + ".snap-decision is not expanded");
229+ compare(snap_decision[kindex].expanded, true, "state of "+ kindex + ".snap-decision is not expanded");
221230 } else {
222− compare(snap_decision[kindex].state, "contracted", "state of "+ kindex + ".snap-decision is not contracted");
231+ compare(snap_decision[kindex].expanded, false, "state of "+ kindex + ".snap-decision is not contracted");
223232 }
224233 }
225234 }
@@ -232,7 +241,7 @@ Row {
232241
233242 for (var index = 1; index < snap_decision.length; index++) {
234243 removeTopMostNotification();
235− compare(snap_decision[index].state, "expanded", "state of " + index + ". snap-decision is not expanded");
244+ compare(snap_decision[index].expanded, true, "state of " + index + ". snap-decision is not expanded");
236245 }
237246 }
238247 }