Merge lp:~macslow/unity8/synchronous-notification into lp:unity8/rtm-14.09

Proposed by Michał Sawicz
Status: Merged
Approved by: Albert Astals Cid
Approved revision: 1105
Merged at revision: 1354
Proposed branch: lp:~macslow/unity8/synchronous-notification
Merge into: lp:unity8/rtm-14.09
Diff against target: 544 lines (+248/-52)
3 files modified
qml/Notifications/Notification.qml (+72/-8)
qml/Notifications/Notifications.qml (+1/-0)
tests/qmltests/Notifications/tst_Notifications.qml (+175/-44)
To merge this branch: bzr merge lp:~macslow/unity8/synchronous-notification
Reviewer Review Type Date Requested Status
Albert Astals Cid (community) Approve
Review via email: mp+238119@code.launchpad.net

Commit message

Added synchronous/confirmation notification support to unity8.

Description of the change

Added synchronous/confirmation notification support to unity8.

You can test it with the icon-value.py Python-script from the corresponding lp:~macslow/unity-notifications/synchronous-notification branch.

For the reviewers convenience, here's a video of all three branches in action: http://www.youtube.com/watch?v=mi-Z2Rn7Fxo

* Are there any related MPs required for this MP to build/function as expected? Please list.
Yes. For correct operation lp:~macslow/unity-notifications/synchronous-notification needs to be merged to lp:unity-notifications first.

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

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

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

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

To post a comment you must log in.
1103. By Mirco Müller

Solved top-margin issues in fullscreen snap-decision due to added sync. notification support.

1104. By Mirco Müller

Fix trailing whitespaces.

1105. By Mirco Müller

Simplify implicitHeight binding a bit.

Revision history for this message
Albert Astals Cid (aacid) wrote :

Approve this one for rtm too since at this stage is basically the same a trunk. See https://code.launchpad.net/~macslow/unity8/synchronous-notification/+merge/229059

review: Approve
1106. By Mirco Müller

Make sure any attached sound-file is played back for sync. notifications any time its hints are changed.

1107. By Mirco Müller

Add audioRole to fix LP: #1378920.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'qml/Notifications/Notification.qml'
2--- qml/Notifications/Notification.qml 2014-09-18 21:25:00 +0000
3+++ qml/Notifications/Notification.qml 2014-10-15 13:56:02 +0000
4@@ -30,6 +30,7 @@
5 property alias secondaryIconSource: secondaryIcon.source
6 property alias summary: summaryLabel.text
7 property alias body: bodyLabel.text
8+ property alias value: valueIndicator.value
9 property var actions
10 property var notificationId
11 property var type
12@@ -39,6 +40,7 @@
13 property bool fullscreen: false
14 property int maxHeight
15 property int margins
16+ readonly property bool darkOnBright: panel.indicators.shown || type === Notification.SnapDecision
17 readonly property color red: "#fc4949"
18 readonly property color green: "#3fb24f"
19 readonly property color sdLightGrey: "#eaeaea"
20@@ -47,9 +49,9 @@
21 readonly property real contentSpacing: units.gu(2)
22
23 objectName: "background"
24- implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height + contentSpacing * 2) : 0
25+ implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : outterColumn.height - shapedBack.anchors.topMargin + contentSpacing * 2) : 0
26
27- color: type == Notification.SnapDecision ? sdLightGrey : Qt.rgba(0.132, 0.117, 0.109, 0.97)
28+ color: (type === Notification.Confirmation && notificationList.useModal && !greeter.shown) || darkOnBright ? sdLightGrey : Qt.rgba(0.132, 0.117, 0.109, 0.97)
29 opacity: 1 // FIXME: 1 because of LP: #1354406 workaround, has to be 0 really
30
31 state: {
32@@ -77,6 +79,7 @@
33 Audio {
34 id: sound
35 objectName: "sound"
36+ audioRole: MediaPlayer.alert
37 source: hints["suppress-sound"] != "true" && hints["sound-file"] != undefined ? hints["sound-file"] : ""
38 }
39
40@@ -87,6 +90,12 @@
41 }
42 }
43
44+ onHintsChanged: {
45+ if (type === Notification.Confirmation && opacity == 1.0 && hints["suppress-sound"] != "true" && sound.source != "") {
46+ sound.play();
47+ }
48+ }
49+
50 Behavior on height {
51 id: normalHeightBehavior
52
53@@ -125,6 +134,7 @@
54 fill: parent
55 leftMargin: notification.margins
56 rightMargin: notification.margins
57+ topMargin: type === Notification.Confirmation ? units.gu(.5) : 0
58 }
59 color: parent.color
60 opacity: parent.opacity
61@@ -205,10 +215,10 @@
62 right: parent.right
63 top: parent.top
64 margins: 0
65- topMargin: fullscreen ? 0 : units.gu(2)
66+ topMargin: fullscreen ? 0 : type === Notification.Confirmation ? units.gu(1) : units.gu(2)
67 }
68
69- spacing: units.gu(2)
70+ spacing: type === Notification.Confirmation ? units.gu(1) : units.gu(2)
71
72 Row {
73 id: topRow
74@@ -227,7 +237,7 @@
75 width: type == Notification.Ephemeral && !bodyLabel.visible ? units.gu(3) : units.gu(6)
76 height: width
77 shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
78- visible: iconSource !== undefined && iconSource != ""
79+ visible: iconSource !== undefined && iconSource !== "" && type !== Notification.Confirmation
80 }
81
82 Column {
83@@ -244,8 +254,9 @@
84 left: parent.left
85 right: parent.right
86 }
87+ visible: type !== Notification.Confirmation
88 fontSize: "medium"
89- color: type == Notification.SnapDecision ? sdFontColor : Theme.palette.selected.backgroundText
90+ color: darkOnBright ? sdFontColor : Theme.palette.selected.backgroundText
91 elide: Text.ElideRight
92 textFormat: Text.PlainText
93 }
94@@ -258,9 +269,9 @@
95 left: parent.left
96 right: parent.right
97 }
98- visible: body != ""
99+ visible: body != "" && type !== Notification.Confirmation
100 fontSize: "small"
101- color: type == Notification.SnapDecision ? sdFontColor : Theme.palette.selected.backgroundText
102+ color: darkOnBright ? sdFontColor : Theme.palette.selected.backgroundText
103 wrapMode: Text.WordWrap
104 maximumLineCount: type == Notification.SnapDecision ? 12 : 2
105 elide: Text.ElideRight
106@@ -283,6 +294,59 @@
107 visible: type == Notification.SnapDecision
108 }
109
110+ ShapedIcon {
111+ id: centeredIcon
112+ objectName: "centeredIcon"
113+ width: units.gu(5)
114+ height: width
115+ shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
116+ fileSource: icon.fileSource
117+ visible: fileSource !== undefined && fileSource !== "" && type === Notification.Confirmation
118+ anchors.horizontalCenter: parent.horizontalCenter
119+ }
120+
121+ Label {
122+ id: valueLabel
123+ objectName: "valueLabel"
124+ text: body
125+ anchors.horizontalCenter: parent.horizontalCenter
126+ visible: type === Notification.Confirmation && body !== ""
127+ fontSize: "medium"
128+ color: darkOnBright ? sdFontColor : Theme.palette.selected.backgroundText
129+ wrapMode: Text.WordWrap
130+ maximumLineCount: 1
131+ elide: Text.ElideRight
132+ textFormat: Text.PlainText
133+ }
134+
135+ UbuntuShape {
136+ id: valueIndicator
137+ objectName: "valueIndicator"
138+ visible: type === Notification.Confirmation
139+ property double value
140+
141+ anchors {
142+ left: parent.left
143+ right: parent.right
144+ margins: contentSpacing
145+ }
146+
147+ height: units.gu(1)
148+ color: darkOnBright ? UbuntuColors.darkGrey : UbuntuColors.lightGrey
149+ borderSource: "none"
150+ radius: "small"
151+
152+ UbuntuShape {
153+ id: innerBar
154+ objectName: "innerBar"
155+ width: valueIndicator.width * valueIndicator.value / 100
156+ height: units.gu(1)
157+ color: notification.hints["x-canonical-value-bar-tint"] === "true" ? UbuntuColors.orange : darkOnBright ? UbuntuColors.lightGrey : "white"
158+ borderSource: "none"
159+ radius: "small"
160+ }
161+ }
162+
163 Column {
164 id: dialogColumn
165 objectName: "dialogListView"
166
167=== modified file 'qml/Notifications/Notifications.qml'
168--- qml/Notifications/Notifications.qml 2014-08-25 11:31:05 +0000
169+++ qml/Notifications/Notifications.qml 2014-10-15 13:56:02 +0000
170@@ -55,6 +55,7 @@
171 secondaryIconSource: model.secondaryIcon
172 summary: model.summary
173 body: model.body
174+ value: model.value
175 actions: model.actions
176 notificationId: model.id
177 notification: notificationList.model.getRaw(notificationId)
178
179=== modified file 'tests/qmltests/Notifications/tst_Notifications.qml'
180--- tests/qmltests/Notifications/tst_Notifications.qml 2014-09-12 14:51:55 +0000
181+++ tests/qmltests/Notifications/tst_Notifications.qml 2014-10-15 13:56:02 +0000
182@@ -53,6 +53,7 @@
183 summary: "",
184 body: "",
185 icon: "",
186+ value: 0,
187 secondaryIcon: "",
188 actions: []
189 }
190@@ -125,10 +126,11 @@
191 function addEphemeralIconSummaryNotification() {
192 var n = {
193 type: Notification.Ephemeral,
194+ hints: {"x-canonical-non-shaped-icon": "false"},
195 summary: "Photo upload completed",
196 body: "",
197- icon: "",
198- secondaryIcon: "../graphics/applicationIcons/facebook.png",
199+ icon: "../graphics/applicationIcons/facebook.png",
200+ secondaryIcon: "",
201 actions: []
202 }
203
204@@ -148,20 +150,53 @@
205 mockModel.append(n)
206 }
207
208+ function addConfirmationNotification() {
209+ var n = {
210+ type: Notification.Confirmation,
211+ hints: {"x-canonical-non-shaped-icon": "true"},
212+ summary: "Confirmation notification",
213+ body: "",
214+ icon: "image://theme/audio-volume-medium",
215+ secondaryIcon: "",
216+ value: 50,
217+ actions: [],
218+ }
219+
220+ mockModel.append(n)
221+ }
222+
223+ function add2ndConfirmationNotification() {
224+ var n = {
225+ type: Notification.Confirmation,
226+ hints: {"x-canonical-non-shaped-icon": "true",
227+ "x-canonical-value-bar-tint": "true"},
228+ summary: "Confirmation notification",
229+ body: "High Volume",
230+ icon: "image://theme/audio-volume-high",
231+ secondaryIcon: "",
232+ value: 85,
233+ actions: [],
234+ }
235+
236+ mockModel.append(n)
237+ }
238+
239 function clearNotifications() {
240- mockModel.clear()
241+ while(mockModel.count > 1) {
242+ remove1stNotification()
243+ }
244 }
245
246 function remove1stNotification() {
247- if (mockModel.count > 0)
248- mockModel.remove(0)
249+ if (mockModel.count > 1)
250+ mockModel.remove(1)
251 }
252
253 Rectangle {
254 id: notificationsRect
255
256 width: units.gu(40)
257- height: units.gu(71)
258+ height: units.gu(115)
259
260 MouseArea{
261 id: clickThroughCatcher
262@@ -183,7 +218,7 @@
263 id: interactiveControls
264
265 width: units.gu(30)
266- height: units.gu(81)
267+ height: units.gu(115)
268 color: "grey"
269
270 Column {
271@@ -229,6 +264,18 @@
272
273 Button {
274 width: parent.width
275+ text: "add a confirmation"
276+ onClicked: addConfirmationNotification()
277+ }
278+
279+ Button {
280+ width: parent.width
281+ text: "add a 2nd confirmation"
282+ onClicked: add2ndConfirmationNotification()
283+ }
284+
285+ Button {
286+ width: parent.width
287 text: "remove 1st notification"
288 onClicked: remove1stNotification()
289 }
290@@ -264,12 +311,16 @@
291 summaryVisible: true,
292 bodyVisible: true,
293 iconVisible: true,
294- shapedIcon: true,
295- nonShapedIcon: false,
296+ centeredIconVisible: false,
297+ shaped: true,
298+ nonShaped: false,
299 secondaryIconVisible: true,
300 buttonRowVisible: true,
301 buttonTinted: true,
302- hasSound: false
303+ hasSound: false,
304+ valueVisible: false,
305+ valueLabelVisible: false,
306+ valueTinted: false
307 },
308 {
309 tag: "2-over-1 Snap Decision with button-tint",
310@@ -285,31 +336,37 @@
311 summaryVisible: true,
312 bodyVisible: true,
313 iconVisible: false,
314- shapedIcon: false,
315- nonShapedIcon: false,
316+ centeredIconVisible: false,
317+ shaped: false,
318 secondaryIconVisible: false,
319 buttonRowVisible: false,
320 buttonTinted: true,
321- hasSound: false
322+ hasSound: false,
323+ valueVisible: false,
324+ valueLabelVisible: false,
325+ valueTinted: false
326 },
327 {
328 tag: "Ephemeral notification - icon-summary layout",
329 type: Notification.Ephemeral,
330- hints: {"x-canonical-private-affirmative-tint": "false"},
331+ hints: {},
332 summary: "Photo upload completed",
333 body: "",
334- icon: "",
335- secondaryIcon: "../graphics/applicationIcons/facebook.png",
336+ icon: "../graphics/applicationIcons/facebook.png",
337+ secondaryIcon: "",
338 actions: [],
339 summaryVisible: true,
340 bodyVisible: false,
341- iconVisible: false,
342- shapedIcon: false,
343- nonShapedIcon: false,
344- secondaryIconVisible: true,
345+ iconVisible: true,
346+ centeredIconVisible: false,
347+ shaped: true,
348+ secondaryIconVisible: false,
349 buttonRowVisible: false,
350 buttonTinted: false,
351- hasSound: false
352+ hasSound: false,
353+ valueVisible: false,
354+ valueLabelVisible: false,
355+ valueTinted: false
356 },
357 {
358 tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
359@@ -326,12 +383,15 @@
360 bodyVisible: false,
361 interactiveAreaEnabled: false,
362 iconVisible: false,
363- shapedIcon: false,
364- nonShapedIcon: false,
365+ centeredIconVisible: false,
366+ shaped: false,
367 secondaryIconVisible: true,
368 buttonRowVisible: false,
369 buttonTinted: false,
370- hasSound: false
371+ hasSound: false,
372+ valueVisible: false,
373+ valueLabelVisible: false,
374+ valueTinted: false
375 },
376 {
377 tag: "Interactive notification",
378@@ -346,12 +406,15 @@
379 summaryVisible: true,
380 bodyVisible: true,
381 iconVisible: true,
382- shapedIcon: true,
383- nonShapedIcon: false,
384+ centeredIconVisible: false,
385+ shaped: true,
386 secondaryIconVisible: false,
387 buttonRowVisible: false,
388 buttonTinted: false,
389- hasSound: true
390+ hasSound: true,
391+ valueVisible: false,
392+ valueLabelVisible: false,
393+ valueTinted: false
394 },
395 {
396 tag: "Snap Decision without secondary icon and no button-tint",
397@@ -367,12 +430,15 @@
398 summaryVisible: true,
399 bodyVisible: true,
400 iconVisible: true,
401- shapedIcon: true,
402- nonShapedIcon: false,
403+ centeredIconVisible: false,
404+ shaped: true,
405 secondaryIconVisible: false,
406 buttonRowVisible: true,
407 buttonTinted: false,
408- hasSound: true
409+ hasSound: true,
410+ valueVisible: false,
411+ valueLabelVisible: false,
412+ valueTinted: false
413 },
414 {
415 tag: "Ephemeral notification",
416@@ -387,12 +453,15 @@
417 summaryVisible: true,
418 bodyVisible: true,
419 iconVisible: true,
420- shapedIcon: true,
421- nonShapedIcon: false,
422+ centeredIconVisible: false,
423+ shaped: true,
424 secondaryIconVisible: true,
425 buttonRowVisible: false,
426 buttonTinted: false,
427- hasSound: true
428+ hasSound: true,
429+ valueVisible: false,
430+ valueLabelVisible: false,
431+ valueTinted: false
432 },
433 {
434 tag: "Ephemeral notification with non-shaped icon",
435@@ -401,18 +470,68 @@
436 "x-canonical-non-shaped-icon": "true"},
437 summary: "Contacts",
438 body: "Synchronised contacts-database with cloud-storage.",
439- icon: "../graphics/applicationIcons/contacts-app.png",
440+ icon: "image://theme/contacts-app",
441 secondaryIcon: "",
442 actions: [],
443 summaryVisible: true,
444 bodyVisible: true,
445 iconVisible: true,
446- shapedIcon: false,
447- nonShapedIcon: true,
448- secondaryIconVisible: false,
449- buttonRowVisible: false,
450- buttonTinted: false,
451- hasSound: false
452+ centeredIconVisible: false,
453+ shaped: false,
454+ secondaryIconVisible: false,
455+ buttonRowVisible: false,
456+ buttonTinted: false,
457+ hasSound: false,
458+ valueVisible: false,
459+ valueLabelVisible: false,
460+ valueTinted: false
461+ },
462+ {
463+ tag: "Confirmation notification with value",
464+ type: Notification.Confirmation,
465+ hints: {"x-canonical-non-shaped-icon": "true"},
466+ summary: "",
467+ body: "",
468+ icon: "image://theme/audio-volume-medium",
469+ secondaryIcon: "",
470+ value: 50,
471+ actions: [],
472+ summaryVisible: false,
473+ bodyVisible: false,
474+ iconVisible: false,
475+ centeredIconVisible: true,
476+ shaped: false,
477+ secondaryIconVisible: false,
478+ buttonRowVisible: false,
479+ buttonTinted: false,
480+ hasSound: false,
481+ valueVisible: true,
482+ valueLabelVisible: false,
483+ valueTinted: false
484+ },
485+ {
486+ tag: "Confirmation notification with value, label and tint",
487+ type: Notification.Confirmation,
488+ hints: {"x-canonical-non-shaped-icon": "true",
489+ "x-canonical-value-bar-tint" : "true"},
490+ summary: "",
491+ body: "High Volume",
492+ icon: "image://theme/audio-volume-high",
493+ secondaryIcon: "",
494+ value: 85,
495+ actions: [],
496+ summaryVisible: false,
497+ bodyVisible: false,
498+ iconVisible: false,
499+ centeredIconVisible: true,
500+ shaped: false,
501+ secondaryIconVisible: false,
502+ buttonRowVisible: false,
503+ buttonTinted: false,
504+ hasSound: false,
505+ valueVisible: true,
506+ valueLabelVisible: true,
507+ valueTinted: true
508 }
509 ]
510 }
511@@ -450,17 +569,29 @@
512 waitForRendering(notification);
513
514 var icon = findChild(notification, "icon")
515- var shapedIcon = findChild(notification, "shapedIcon")
516- var nonShapedIcon = findChild(notification, "nonShapedIcon")
517+ var centeredIcon = findChild(notification, "centeredIcon")
518 var interactiveArea = findChild(notification, "interactiveArea")
519 var secondaryIcon = findChild(notification, "secondaryIcon")
520 var summaryLabel = findChild(notification, "summaryLabel")
521 var bodyLabel = findChild(notification, "bodyLabel")
522 var buttonRow = findChild(notification, "buttonRow")
523+ var valueIndicator = findChild(notification, "valueIndicator")
524+ var valueLabel = findChild(notification, "valueLabel")
525+ var innerBar = findChild(notification, "innerBar")
526
527 compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect")
528- compare(shapedIcon.visible, data.shapedIcon, "shaped-icon visibility is incorrect")
529- compare(nonShapedIcon.visible, data.nonShapedIcon, "non-shaped-icon visibility is incorrect")
530+ if (icon.visible) {
531+ compare(icon.shaped, data.shaped, "shaped-status is incorrect")
532+ }
533+ compare(centeredIcon.visible, data.centeredIconVisible, "centered-icon visibility is incorrect")
534+ if (centeredIcon.visible) {
535+ compare(centeredIcon.shaped, data.shaped, "shaped-status is incorrect")
536+ }
537+ compare(valueIndicator.visible, data.valueVisible, "value-indicator visibility is incorrect")
538+ if (valueIndicator.visible) {
539+ verify(innerBar.color === data.valueTinted ? UbuntuColors.orange : "white", "value-bar has the wrong color-tint")
540+ }
541+ compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect")
542
543 // test input does not fall through
544 mouseClick(notification, notification.width / 2, notification.height / 2)

Subscribers

People subscribed via source and target branches

to all changes: