@@ -23,280 +23,51 @@ import Unity.Test 0.1
2323import Unity.Notifications 1.0
2424import QtMultimedia 5.0
2525
26−Row {
27− id: rootRow
26+Item {
27+ width: notificationsRect.width + interactiveControls.width
28+ height: notificationsRect.height
2829
29− Component {
30− id: mockNotification
30+ Row {
31+ id: rootRow
3132
32− QtObject {
33− function invokeAction(actionId) {
34− mockModel.actionInvoked(actionId)
35− }
36− }
37− }
38−
39− ListModel {
40− id: mockModel
41−
42− signal actionInvoked(string actionId)
43−
44− function getRaw(id) {
45− return mockNotification.createObject(mockModel)
46− }
33+ Component {
34+ id: mockNotification
4735
48− // add the default/PlaceHolder notification to the model
49− Component.onCompleted: {
50− var n = {
51− type: Notification.PlaceHolder,
52− hints: {},
53− summary: "",
54− body: "",
55− icon: "",
56− value: 0,
57− secondaryIcon: "",
58− actions: []
36+ QtObject {
37+ function invokeAction(actionId) {
38+ mockModel.actionInvoked(actionId)
39+ }
5940 }
60−
61− append(n)
62− }
63− }
64−
65− function addSnapDecisionNotification() {
66− var n = {
67− type: Notification.SnapDecision,
68− hints: {"x-canonical-private-affirmative-tint": "true"},
69− summary: "Tom Ato",
70− 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.",
71− icon: "../graphics/avatars/funky.png",
72− secondaryIcon: "../graphics/applicationIcons/facebook.png",
73− actions: [{ id: "ok_id", label: "Ok"},
74− { id: "cancel_id", label: "Cancel"},
75− { id: "notreally_id", label: "Not really"},
76− { id: "noway_id", label: "messages:No way"},
77− { id: "nada_id", label: "messages:Nada"}]
7841 }
7942
80− mockModel.append(n)
81− }
82−
83− function add2over1SnapDecisionNotification() {
84− var n = {
85− type: Notification.SnapDecision,
86− hints: {"x-canonical-private-affirmative-tint": "true",},
87− summary: "Theatre at Ferria Stadium",
88− body: "at Ferria Stadium in Bilbao, Spain\n07578545317",
89− icon: "",
90− secondaryIcon: "",
91− actions: [{ id: "ok_id", label: "Ok"},
92− { id: "snooze_id", label: "Snooze"},
93− { id: "view_id", label: "View"}]
94− }
95−
96− mockModel.append(n)
97− }
98−
99− function addEphemeralNotification() {
100− var n = {
101− type: Notification.Ephemeral,
102− summary: "Cole Raby",
103− body: "I did not expect it to be that late.",
104− icon: "../graphics/avatars/amanda.png",
105− secondaryIcon: "../graphics/applicationIcons/facebook.png",
106− actions: []
107− }
108−
109− mockModel.append(n)
110− }
111−
112− function addEphemeralNonShapedIconNotification() {
113− var n = {
114− type: Notification.Ephemeral,
115− hints: {"x-canonical-non-shaped-icon": "true"},
116− summary: "Contacts",
117− body: "Synchronised contacts-database with cloud-storage.",
118− icon: "../graphics/applicationIcons/contacts-app.png",
119− secondaryIcon: "",
120− actions: []
121− }
122−
123− mockModel.append(n)
124− }
125−
126− function addEphemeralIconSummaryNotification() {
127− var n = {
128− type: Notification.Ephemeral,
129− hints: {"x-canonical-non-shaped-icon": "false"},
130− summary: "Photo upload completed",
131− body: "",
132− icon: "../graphics/applicationIcons/facebook.png",
133− secondaryIcon: "",
134− actions: []
135− }
136−
137− mockModel.append(n)
138− }
139−
140− function addInteractiveNotification() {
141− var n = {
142− type: Notification.Interactive,
143− summary: "Interactive notification",
144− body: "This is a notification that can be clicked",
145− icon: "../graphics/avatars/anna_olsson.png",
146− secondaryIcon: "",
147− actions: [{ id: "reply_id", label: "Dummy"}],
148− }
149−
150− mockModel.append(n)
151− }
152−
153− function addConfirmationNotification() {
154− var n = {
155− type: Notification.Confirmation,
156− hints: {"x-canonical-non-shaped-icon": "true"},
157− summary: "Confirmation notification",
158− body: "",
159− icon: "image://theme/audio-volume-medium",
160− secondaryIcon: "",
161− value: 50,
162− actions: [],
163− }
164−
165− mockModel.append(n)
166− }
167−
168− function add2ndConfirmationNotification() {
169− var n = {
170− type: Notification.Confirmation,
171− hints: {"x-canonical-non-shaped-icon": "true",
172− "x-canonical-value-bar-tint": "true"},
173− summary: "Confirmation notification",
174− body: "High Volume",
175− icon: "image://theme/audio-volume-high",
176− secondaryIcon: "",
177− value: 85,
178− actions: [],
179− }
180−
181− mockModel.append(n)
182− }
183−
184− function clearNotifications() {
185− while(mockModel.count > 1) {
186− remove1stNotification()
187− }
188− }
189−
190− function remove1stNotification() {
191− if (mockModel.count > 1)
192− mockModel.remove(1)
193− }
43+ ListModel {
44+ id: mockModel
45+ dynamicRoles: true
19446
195− Rectangle {
196− id: notificationsRect
47+ signal actionInvoked(string actionId)
19748
198− width: units.gu(40)
199− height: units.gu(115)
200−
201− MouseArea{
202− id: clickThroughCatcher
203−
204− anchors.fill: parent
205− }
206−
207− Notifications {
208− id: notifications
209−
210− margin: units.gu(1)
211−
212− anchors.fill: parent
213− model: mockModel
214− }
215− }
216−
217− Rectangle {
218− id: interactiveControls
219−
220− width: units.gu(30)
221− height: units.gu(115)
222− color: "grey"
223−
224− Column {
225− spacing: units.gu(1)
226− anchors.fill: parent
227− anchors.margins: units.gu(1)
228−
229− Button {
230− width: parent.width
231− text: "add a snap-decision"
232− onClicked: addSnapDecisionNotification()
233− }
234−
235− Button {
236− width: parent.width
237− text: "add a 2over1 snap-decision"
238− onClicked: add2over1SnapDecisionNotification()
239− }
240−
241− Button {
242− width: parent.width
243− text: "add an ephemeral"
244− onClicked: addEphemeralNotification()
245− }
246−
247− Button {
248− width: parent.width
249− text: "add an non-shaped-icon-summary-body"
250− onClicked: addEphemeralNonShapedIconNotification()
251− }
252−
253− Button {
254− width: parent.width
255− text: "add an icon-summary"
256− onClicked: addEphemeralIconSummaryNotification()
257− }
258−
259− Button {
260− width: parent.width
261− text: "add an interactive"
262− onClicked: addInteractiveNotification()
263− }
264−
265− Button {
266− width: parent.width
267− text: "add a confirmation"
268− onClicked: addConfirmationNotification()
269− }
270−
271− Button {
272− width: parent.width
273− text: "add a 2nd confirmation"
274− onClicked: add2ndConfirmationNotification()
49+ function getRaw(id) {
50+ return mockNotification.createObject(mockModel)
27551 }
27652
277− Button {
278− width: parent.width
279− text: "remove 1st notification"
280− onClicked: remove1stNotification()
281− }
53+ // add the default/PlaceHolder notification to the model
54+ Component.onCompleted: {
55+ var n = {
56+ type: Notification.PlaceHolder,
57+ hints: {},
58+ summary: "",
59+ body: "",
60+ icon: "",
61+ secondaryIcon: "",
62+ actions: []
63+ }
28264
283− Button {
284− width: parent.width
285− text: "clear model"
286− onClicked: clearNotifications()
65+ append(n)
28766 }
28867 }
289− }
29068
291− UnityTestCase {
292− id: root
293− name: "NotificationRendererTest"
294− when: windowShown
295−
296− function test_NotificationRenderer_data() {
297− return [
298− {
299− tag: "Snap Decision with secondary icon and button-tint",
69+ function addSnapDecisionNotification() {
70+ var n = {
30071 type: Notification.SnapDecision,
30172 hints: {"x-canonical-private-affirmative-tint": "true"},
30273 summary: "Tom Ato",
@@ -307,23 +78,14 @@ Row {
30778 { id: "cancel_id", label: "Cancel"},
30879 { id: "notreally_id", label: "Not really"},
30980 { id: "noway_id", label: "messages:No way"},
310− { id: "nada_id", label: "messages:Nada"}],
311− summaryVisible: true,
312− bodyVisible: true,
313− iconVisible: true,
314− centeredIconVisible: false,
315− shaped: true,
316− nonShaped: false,
317− secondaryIconVisible: true,
318− buttonRowVisible: true,
319− buttonTinted: true,
320− hasSound: false,
321− valueVisible: false,
322− valueLabelVisible: false,
323− valueTinted: false
324− },
325− {
326− tag: "2-over-1 Snap Decision with button-tint",
81+ { id: "nada_id", label: "messages:Nada"}]
82+ }
83+
84+ mockModel.append(n)
85+ }
86+
87+ function add2over1SnapDecisionNotification() {
88+ var n = {
32789 type: Notification.SnapDecision,
32890 hints: {"x-canonical-private-affirmative-tint": "true"},
32991 summary: "Theatre at Ferria Stadium",
@@ -332,327 +94,573 @@ Row {
33294 secondaryIcon: "",
33395 actions: [{ id: "ok_id", label: "Ok"},
33496 { id: "snooze_id", label: "Snooze"},
335− { id: "view_id", label: "View"}],
336− summaryVisible: true,
337− bodyVisible: true,
338− iconVisible: false,
339− centeredIconVisible: false,
340− shaped: false,
341− secondaryIconVisible: false,
342− buttonRowVisible: false,
343− buttonTinted: true,
344− hasSound: false,
345− valueVisible: false,
346− valueLabelVisible: false,
347− valueTinted: false
348− },
349− {
350− tag: "Ephemeral notification - icon-summary layout",
97+ { id: "view_id", label: "View"}]
98+ }
99+
100+ mockModel.append(n)
101+ }
102+
103+ function addEphemeralNotification() {
104+ var n = {
105+ type: Notification.Ephemeral,
106+ summary: "Cole Raby",
107+ body: "I did not expect it to be that late.",
108+ icon: "../graphics/avatars/amanda.png",
109+ secondaryIcon: "../graphics/applicationIcons/facebook.png",
110+ actions: []
111+ }
112+
113+ mockModel.append(n)
114+ }
115+
116+ function addEphemeralNonShapedIconNotification() {
117+ var n = {
118+ type: Notification.Ephemeral,
119+ hints: {"x-canonical-non-shaped-icon": "true"},
120+ summary: "Contacts",
121+ body: "Synchronised contacts-database with cloud-storage.",
122+ icon: "../graphics/applicationIcons/contacts-app.png",
123+ secondaryIcon: "",
124+ actions: []
125+ }
126+
127+ mockModel.append(n)
128+ }
129+
130+ function addEphemeralIconSummaryNotification() {
131+ var n = {
351132 type: Notification.Ephemeral,
352− hints: {},
133+ hints: {"x-canonical-non-shaped-icon": "false"},
353134 summary: "Photo upload completed",
354135 body: "",
355136 icon: "../graphics/applicationIcons/facebook.png",
356137 secondaryIcon: "",
357− actions: [],
358− summaryVisible: true,
359− bodyVisible: false,
360− iconVisible: true,
361− centeredIconVisible: false,
362− shaped: true,
363− secondaryIconVisible: false,
364− buttonRowVisible: false,
365− buttonTinted: false,
366− hasSound: false,
367− valueVisible: false,
368− valueLabelVisible: false,
369− valueTinted: false
370− },
371− {
372− tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
373− type: Notification.Ephemeral,
374− hints: {"x-canonical-private-affirmative-tint": "false",
375− "sound-file": "dummy.ogg",
376− "suppress-sound": "true"},
377− summary: "New comment successfully published",
378− body: "",
379− icon: "",
380− secondaryIcon: "../graphics/applicationIcons/facebook.png",
381− actions: [],
382− summaryVisible: true,
383− bodyVisible: false,
384− interactiveAreaEnabled: false,
385− iconVisible: false,
386− centeredIconVisible: false,
387− shaped: false,
388− secondaryIconVisible: true,
389− buttonRowVisible: false,
390− buttonTinted: false,
391− hasSound: false,
392− valueVisible: false,
393− valueLabelVisible: false,
394− valueTinted: false
395− },
396− {
397− tag: "Interactive notification",
138+ actions: []
139+ }
140+
141+ mockModel.append(n)
142+ }
143+
144+ function addInteractiveNotification() {
145+ var n = {
398146 type: Notification.Interactive,
399− hints: {"x-canonical-private-affirmative-tint": "false",
400− "sound-file": "dummy.ogg"},
401147 summary: "Interactive notification",
402148 body: "This is a notification that can be clicked",
403− icon: "../graphics/avatars/amanda.png",
404− secondaryIcon: "",
405− actions: [{ id: "reply_id", label: "Dummy"}],
406− summaryVisible: true,
407− bodyVisible: true,
408− iconVisible: true,
409− centeredIconVisible: false,
410− shaped: true,
411− secondaryIconVisible: false,
412− buttonRowVisible: false,
413− buttonTinted: false,
414− hasSound: true,
415− valueVisible: false,
416− valueLabelVisible: false,
417− valueTinted: false
418− },
419− {
420− tag: "Snap Decision without secondary icon and no button-tint",
421− type: Notification.SnapDecision,
422− hints: {"x-canonical-private-affirmative-tint": "false",
423− "sound-file": "dummy.ogg"},
424− summary: "Bro Coly",
425− 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.",
426149 icon: "../graphics/avatars/anna_olsson.png",
427150 secondaryIcon: "",
428− actions: [{ id: "accept_id", label: "Accept"},
429− { id: "reject_id", label: "Reject"}],
430− summaryVisible: true,
431− bodyVisible: true,
432− iconVisible: true,
433− centeredIconVisible: false,
434− shaped: true,
435− secondaryIconVisible: false,
436− buttonRowVisible: true,
437− buttonTinted: false,
438− hasSound: true,
439− valueVisible: false,
440− valueLabelVisible: false,
441− valueTinted: false
442− },
443− {
444− tag: "Ephemeral notification",
445− type: Notification.Ephemeral,
446− hints: {"x-canonical-private-affirmative-tint": "false",
447− "sound-file": "dummy.ogg"},
448− summary: "Cole Raby",
449− body: "I did not expect it to be that late.",
450− icon: "../graphics/avatars/funky.png",
451− secondaryIcon: "../graphics/applicationIcons/facebook.png",
452− actions: [],
453− summaryVisible: true,
454− bodyVisible: true,
455− iconVisible: true,
456− centeredIconVisible: false,
457− shaped: true,
458− secondaryIconVisible: true,
459− buttonRowVisible: false,
460− buttonTinted: false,
461− hasSound: true,
462− valueVisible: false,
463− valueLabelVisible: false,
464− valueTinted: false
465− },
466− {
467− tag: "Ephemeral notification with non-shaped icon",
468− type: Notification.Ephemeral,
469− hints: {"x-canonical-private-affirmative-tint": "false",
470− "x-canonical-non-shaped-icon": "true"},
471− summary: "Contacts",
472− body: "Synchronised contacts-database with cloud-storage.",
473− icon: "image://theme/contacts-app",
474− secondaryIcon: "",
475− actions: [],
476− summaryVisible: true,
477− bodyVisible: true,
478− iconVisible: true,
479− centeredIconVisible: false,
480− shaped: false,
481− secondaryIconVisible: false,
482− buttonRowVisible: false,
483− buttonTinted: false,
484− hasSound: false,
485− valueVisible: false,
486− valueLabelVisible: false,
487− valueTinted: false
488− },
489− {
490− tag: "Confirmation notification with value",
151+ actions: [{ id: "reply_id", label: "Dummy"}],
152+ }
153+
154+ mockModel.append(n)
155+ }
156+
157+ function addConfirmationNotification() {
158+ var n = {
491159 type: Notification.Confirmation,
492160 hints: {"x-canonical-non-shaped-icon": "true"},
493− summary: "",
161+ summary: "Confirmation notification",
494162 body: "",
495163 icon: "image://theme/audio-volume-medium",
496164 secondaryIcon: "",
497165 value: 50,
498166 actions: [],
499− summaryVisible: false,
500− bodyVisible: false,
501− iconVisible: false,
502− centeredIconVisible: true,
503− shaped: false,
504− secondaryIconVisible: false,
505− buttonRowVisible: false,
506− buttonTinted: false,
507− hasSound: false,
508− valueVisible: true,
509− valueLabelVisible: false,
510− valueTinted: false
511− },
512− {
513− tag: "Confirmation notification with value, label and tint",
167+ }
168+
169+ mockModel.append(n)
170+ }
171+
172+ function add2ndConfirmationNotification() {
173+ var n = {
514174 type: Notification.Confirmation,
515175 hints: {"x-canonical-non-shaped-icon": "true",
516− "x-canonical-value-bar-tint" : "true"},
517− summary: "",
176+ "x-canonical-value-bar-tint": "true"},
177+ summary: "Confirmation notification",
518178 body: "High Volume",
519179 icon: "image://theme/audio-volume-high",
520180 secondaryIcon: "",
521181 value: 85,
522182 actions: [],
523− summaryVisible: false,
524− bodyVisible: false,
525− iconVisible: false,
526− centeredIconVisible: true,
527− shaped: false,
528− secondaryIconVisible: false,
529− buttonRowVisible: false,
530− buttonTinted: false,
531− hasSound: false,
532− valueVisible: true,
533− valueLabelVisible: true,
534− valueTinted: true
535183 }
536− ]
184+
185+ mockModel.append(n)
537186 }
538187
539− SignalSpy {
540− id: clickThroughSpy
188+ function clearNotifications() {
189+ while(mockModel.count > 1) {
190+ remove1stNotification()
191+ }
192+ }
541193
542− target: clickThroughCatcher
543− signalName: "clicked"
194+ function remove1stNotification() {
195+ if (mockModel.count > 1)
196+ mockModel.remove(1)
544197 }
545198
546− SignalSpy {
547− id: actionSpy
199+ Rectangle {
200+ id: notificationsRect
548201
549− target: mockModel
550− signalName: "actionInvoked"
551− }
202+ width: units.gu(40)
203+ height: units.gu(115)
552204
553− function cleanup() {
554− clickThroughSpy.clear()
555− actionSpy.clear()
556− }
205+ MouseArea{
206+ id: clickThroughCatcher
557207
558− function test_NotificationRenderer(data) {
559− // populate model with some mock notifications
560− mockModel.append(data)
561−
562− // make sure the view is properly updated before going on
563− notifications.forceLayout();
564− waitForRendering(notifications);
565−
566− var notification = findChild(notifications, "notification" + (mockModel.count - 1))
567− verify(notification !== undefined, "notification wasn't found");
568−
569− waitForRendering(notification);
570−
571− var icon = findChild(notification, "icon")
572− var centeredIcon = findChild(notification, "centeredIcon")
573− var interactiveArea = findChild(notification, "interactiveArea")
574− var secondaryIcon = findChild(notification, "secondaryIcon")
575− var summaryLabel = findChild(notification, "summaryLabel")
576− var bodyLabel = findChild(notification, "bodyLabel")
577− var buttonRow = findChild(notification, "buttonRow")
578− var valueIndicator = findChild(notification, "valueIndicator")
579− var valueLabel = findChild(notification, "valueLabel")
580− var innerBar = findChild(notification, "innerBar")
581−
582− compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect")
583− if (icon.visible) {
584− compare(icon.shaped, data.shaped, "shaped-status is incorrect")
208+ anchors.fill: parent
585209 }
586− compare(centeredIcon.visible, data.centeredIconVisible, "centered-icon visibility is incorrect")
587− if (centeredIcon.visible) {
588− compare(centeredIcon.shaped, data.shaped, "shaped-status is incorrect")
210+
211+ Notifications {
212+ id: notifications
213+
214+ margin: units.gu(1)
215+
216+ anchors.fill: parent
217+ model: mockModel
218+ }
219+ }
220+
221+ Rectangle {
222+ id: interactiveControls
223+
224+ width: units.gu(30)
225+ height: units.gu(115)
226+ color: "grey"
227+
228+ Column {
229+ spacing: units.gu(1)
230+ anchors.fill: parent
231+ anchors.margins: units.gu(1)
232+
233+ Button {
234+ width: parent.width
235+ text: "add a snap-decision"
236+ onClicked: rootRow.addSnapDecisionNotification()
237+ }
238+
239+ Button {
240+ width: parent.width
241+ text: "add a 2over1 snap-decision"
242+ onClicked: rootRow.add2over1SnapDecisionNotification()
243+ }
244+
245+ Button {
246+ width: parent.width
247+ text: "add an ephemeral"
248+ onClicked: rootRow.addEphemeralNotification()
249+ }
250+
251+ Button {
252+ width: parent.width
253+ text: "add an non-shaped-icon-summary-body"
254+ onClicked: rootRow.addEphemeralNonShapedIconNotification()
255+ }
256+
257+ Button {
258+ width: parent.width
259+ text: "add an icon-summary"
260+ onClicked: rootRow.addEphemeralIconSummaryNotification()
261+ }
262+
263+ Button {
264+ width: parent.width
265+ text: "add an interactive"
266+ onClicked: rootRow.addInteractiveNotification()
267+ }
268+
269+ Button {
270+ width: parent.width
271+ text: "add a confirmation"
272+ onClicked: rootRow.addConfirmationNotification()
273+ }
274+
275+ Button {
276+ width: parent.width
277+ text: "add a 2nd confirmation"
278+ onClicked: rootRow.add2ndConfirmationNotification()
279+ }
280+
281+ Button {
282+ width: parent.width
283+ text: "remove 1st notification"
284+ onClicked: rootRow.remove1stNotification()
285+ }
286+
287+ Button {
288+ width: parent.width
289+ text: "clear model"
290+ onClicked: rootRow.clearNotifications()
291+ }
589292 }
590− compare(valueIndicator.visible, data.valueVisible, "value-indicator visibility is incorrect")
591− if (valueIndicator.visible) {
592− verify(innerBar.color === data.valueTinted ? UbuntuColors.orange : "white", "value-bar has the wrong color-tint")
293+ }
294+
295+ ActionModel {
296+ id: myActionModel
297+ }
298+
299+ UnityTestCase {
300+ id: root
301+ name: "NotificationRendererTest"
302+ when: windowShown
303+
304+ function test_NotificationRenderer_data() {
305+ return [
306+ {
307+ tag: "Snap Decision with secondary icon and button-tint",
308+ type: Notification.SnapDecision,
309+ hints: {"x-canonical-private-affirmative-tint": "true"},
310+ summary: "Tom Ato",
311+ 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.",
312+ icon: "../graphics/avatars/funky.png",
313+ secondaryIcon: "../graphics/applicationIcons/facebook.png",
314+ actions: [{ id: "ok_id", label: "Ok"},
315+ { id: "cancel_id", label: "Cancel"},
316+ { id: "notreally_id", label: "Not really"},
317+ { id: "noway_id", label: "messages:No way"},
318+ { id: "nada_id", label: "messages:Nada"}],
319+ summaryVisible: true,
320+ bodyVisible: true,
321+ iconVisible: true,
322+ centeredIconVisible: false,
323+ shaped: true,
324+ secondaryIconVisible: true,
325+ buttonRowVisible: true,
326+ buttonTinted: true,
327+ hasSound: false,
328+ valueVisible: false,
329+ valueLabelVisible: false,
330+ valueTinted: false
331+ },
332+ {
333+ tag: "2-over-1 Snap Decision with button-tint",
334+ type: Notification.SnapDecision,
335+ hints: {"x-canonical-private-affirmative-tint": "true"},
336+ summary: "Theatre at Ferria Stadium",
337+ body: "at Ferria Stadium in Bilbao, Spain\n07578545317",
338+ icon: "",
339+ secondaryIcon: "",
340+ actions: [{ id: "ok_id", label: "Ok"},
341+ { id: "snooze_id", label: "Snooze"},
342+ { id: "view_id", label: "View"}],
343+ summaryVisible: true,
344+ bodyVisible: true,
345+ iconVisible: false,
346+ centeredIconVisible: false,
347+ shaped: false,
348+ secondaryIconVisible: false,
349+ buttonRowVisible: false,
350+ buttonTinted: true,
351+ hasSound: false,
352+ valueVisible: false,
353+ valueLabelVisible: false,
354+ valueTinted: false
355+ },
356+ {
357+ tag: "Ephemeral notification - icon-summary layout",
358+ type: Notification.Ephemeral,
359+ hints: {},
360+ summary: "Photo upload completed",
361+ body: "",
362+ icon: "../graphics/applicationIcons/facebook.png",
363+ secondaryIcon: "",
364+ actions: [],
365+ summaryVisible: true,
366+ bodyVisible: false,
367+ iconVisible: true,
368+ centeredIconVisible: false,
369+ shaped: true,
370+ secondaryIconVisible: false,
371+ buttonRowVisible: false,
372+ buttonTinted: false,
373+ hasSound: false,
374+ valueVisible: false,
375+ valueLabelVisible: false,
376+ valueTinted: false
377+ },
378+ {
379+ tag: "Ephemeral notification - check suppression of secondary icon for icon-summary layout",
380+ type: Notification.Ephemeral,
381+ hints: {"x-canonical-private-affirmative-tint": "false",
382+ "sound-file": "dummy.ogg",
383+ "suppress-sound": "true"},
384+ summary: "New comment successfully published",
385+ body: "",
386+ icon: "",
387+ secondaryIcon: "../graphics/applicationIcons/facebook.png",
388+ actions: [],
389+ summaryVisible: true,
390+ bodyVisible: false,
391+ interactiveAreaEnabled: false,
392+ iconVisible: false,
393+ centeredIconVisible: false,
394+ shaped: false,
395+ secondaryIconVisible: true,
396+ buttonRowVisible: false,
397+ buttonTinted: false,
398+ hasSound: false,
399+ valueVisible: false,
400+ valueLabelVisible: false,
401+ valueTinted: false
402+ },
403+ {
404+ tag: "Interactive notification",
405+ type: Notification.Interactive,
406+ hints: {"x-canonical-private-affirmative-tint": "false",
407+ "sound-file": "dummy.ogg"},
408+ summary: "Interactive notification",
409+ body: "This is a notification that can be clicked",
410+ icon: "../graphics/avatars/amanda.png",
411+ secondaryIcon: "",
412+ actions: [{ id: "reply_id", label: "Dummy"}],
413+ summaryVisible: true,
414+ bodyVisible: true,
415+ iconVisible: true,
416+ centeredIconVisible: false,
417+ shaped: true,
418+ secondaryIconVisible: false,
419+ buttonRowVisible: false,
420+ buttonTinted: false,
421+ hasSound: true,
422+ valueVisible: false,
423+ valueLabelVisible: false,
424+ valueTinted: false
425+ },
426+ {
427+ tag: "Snap Decision without secondary icon and no button-tint",
428+ type: Notification.SnapDecision,
429+ hints: {"x-canonical-private-affirmative-tint": "false",
430+ "sound-file": "dummy.ogg"},
431+ summary: "Bro Coly",
432+ 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.",
433+ icon: "../graphics/avatars/anna_olsson.png",
434+ secondaryIcon: "",
435+ actions: [{ id: "accept_id", label: "Accept"},
436+ { id: "reject_id", label: "Reject"}],
437+ summaryVisible: true,
438+ bodyVisible: true,
439+ iconVisible: true,
440+ centeredIconVisible: false,
441+ shaped: true,
442+ secondaryIconVisible: false,
443+ buttonRowVisible: true,
444+ buttonTinted: false,
445+ hasSound: true,
446+ valueVisible: false,
447+ valueLabelVisible: false,
448+ valueTinted: false
449+ },
450+ {
451+ tag: "Ephemeral notification",
452+ type: Notification.Ephemeral,
453+ hints: {"x-canonical-private-affirmative-tint": "false",
454+ "sound-file": "dummy.ogg"},
455+ summary: "Cole Raby",
456+ body: "I did not expect it to be that late.",
457+ icon: "../graphics/avatars/funky.png",
458+ secondaryIcon: "../graphics/applicationIcons/facebook.png",
459+ actions: [],
460+ summaryVisible: true,
461+ bodyVisible: true,
462+ iconVisible: true,
463+ centeredIconVisible: false,
464+ shaped: true,
465+ secondaryIconVisible: true,
466+ buttonRowVisible: false,
467+ buttonTinted: false,
468+ hasSound: true,
469+ valueVisible: false,
470+ valueLabelVisible: false,
471+ valueTinted: false
472+ },
473+ {
474+ tag: "Ephemeral notification with non-shaped icon",
475+ type: Notification.Ephemeral,
476+ hints: {"x-canonical-private-affirmative-tint": "false",
477+ "x-canonical-non-shaped-icon": "true"},
478+ summary: "Contacts",
479+ body: "Synchronised contacts-database with cloud-storage.",
480+ icon: "image://theme/contacts-app",
481+ secondaryIcon: "",
482+ actions: [],
483+ summaryVisible: true,
484+ bodyVisible: true,
485+ iconVisible: true,
486+ centeredIconVisible: false,
487+ shaped: false,
488+ secondaryIconVisible: false,
489+ buttonRowVisible: false,
490+ buttonTinted: false,
491+ hasSound: false,
492+ valueVisible: false,
493+ valueLabelVisible: false,
494+ valueTinted: false
495+ },
496+ {
497+ tag: "Confirmation notification with value",
498+ type: Notification.Confirmation,
499+ hints: {"x-canonical-non-shaped-icon": "true"},
500+ summary: "",
501+ body: "",
502+ icon: "image://theme/audio-volume-medium",
503+ secondaryIcon: "",
504+ value: 50,
505+ actions: [],
506+ summaryVisible: false,
507+ bodyVisible: false,
508+ iconVisible: false,
509+ centeredIconVisible: true,
510+ shaped: false,
511+ secondaryIconVisible: false,
512+ buttonRowVisible: false,
513+ buttonTinted: false,
514+ hasSound: false,
515+ valueVisible: true,
516+ valueLabelVisible: false,
517+ valueTinted: false
518+ },
519+ {
520+ tag: "Confirmation notification with value, label and tint",
521+ type: Notification.Confirmation,
522+ hints: {"x-canonical-non-shaped-icon": "true",
523+ "x-canonical-value-bar-tint" : "true"},
524+ summary: "",
525+ body: "High Volume",
526+ icon: "image://theme/audio-volume-high",
527+ secondaryIcon: "",
528+ value: 85,
529+ actions: [],
530+ summaryVisible: false,
531+ bodyVisible: false,
532+ iconVisible: false,
533+ centeredIconVisible: true,
534+ shaped: false,
535+ secondaryIconVisible: false,
536+ buttonRowVisible: false,
537+ buttonTinted: false,
538+ hasSound: false,
539+ valueVisible: true,
540+ valueLabelVisible: true,
541+ valueTinted: true
542+ }
543+ ]
593544 }
594− compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect")
595545
596− // test input does not fall through
597− mouseClick(notification, notification.width / 2, notification.height / 2)
598− if(data.type == Notification.Interactive) {
599− actionSpy.wait()
600− compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
546+ SignalSpy {
547+ id: clickThroughSpy
548+
549+ target: clickThroughCatcher
550+ signalName: "clicked"
601551 }
602− compare(clickThroughSpy.count, 0, "click on notification fell through")
603552
604− compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect")
605− compare(summaryLabel.visible, data.summaryVisible, "summary-text visibility is incorrect")
606− compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect")
607− compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect")
553+ SignalSpy {
554+ id: actionSpy
608555
609− var audioItem = findInvisibleChild(notification, "sound")
610− compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state")
556+ target: mockModel
557+ signalName: "actionInvoked"
558+ }
611559
612− if(data.buttonRowVisible) {
613− var buttonCancel = findChild(buttonRow, "notify_button1")
614− var buttonAccept = findChild(buttonRow, "notify_button0")
560+ function cleanup() {
561+ clickThroughSpy.clear()
562+ actionSpy.clear()
563+ }
615564
616− // only test the left/cancel-button if two actions have been passed in
617− if (data.actions.length == 2) {
618− tryCompareFunction(function() { mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2); return actionSpy.signalArguments.length > 0; }, true);
619− compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
620− actionSpy.clear()
565+ function test_NotificationRenderer(data) {
566+ // populate model with some mock notifications
567+ mockModel.append(data)
568+
569+ // make sure the view is properly updated before going on
570+ notifications.forceLayout();
571+ waitForRendering(notifications);
572+
573+ var notification = findChild(notifications, "notification" + (mockModel.count - 1))
574+ verify(notification !== undefined, "notification wasn't found");
575+
576+ waitForRendering(notification);
577+
578+ var icon = findChild(notification, "icon")
579+ var centeredIcon = findChild(notification, "centeredIcon")
580+ var interactiveArea = findChild(notification, "interactiveArea")
581+ var secondaryIcon = findChild(notification, "secondaryIcon")
582+ var summaryLabel = findChild(notification, "summaryLabel")
583+ var bodyLabel = findChild(notification, "bodyLabel")
584+ var buttonRow = findChild(notification, "buttonRow")
585+ var valueIndicator = findChild(notification, "valueIndicator")
586+ var valueLabel = findChild(notification, "valueLabel")
587+ var innerBar = findChild(notification, "innerBar")
588+
589+ compare(icon.visible, data.iconVisible, "avatar-icon visibility is incorrect")
590+ if (icon.visible) {
591+ compare(icon.shaped, data.shaped, "shaped-status is incorrect")
592+ }
593+ compare(centeredIcon.visible, data.centeredIconVisible, "centered-icon visibility is incorrect")
594+ if (centeredIcon.visible) {
595+ compare(centeredIcon.shaped, data.shaped, "shaped-status is incorrect")
621596 }
597+ compare(valueIndicator.visible, data.valueVisible, "value-indicator visibility is incorrect")
598+ if (valueIndicator.visible) {
599+ verify(innerBar.color === data.valueTinted ? UbuntuColors.orange : "white", "value-bar has the wrong color-tint")
600+ }
601+ compare(valueLabel.visible, data.valueLabelVisible, "value-label visibility is incorrect")
622602
623− // check the tinting of the positive/right button
624− verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint")
603+ // test input does not fall through
604+ mouseClick(notification, notification.width / 2, notification.height / 2)
605+ if(data.type == Notification.Interactive) {
606+ actionSpy.wait()
607+ compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
608+ }
609+ compare(clickThroughSpy.count, 0, "click on notification fell through")
625610
626− // click the positive/right button
627− tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true);
628− compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action")
629− actionSpy.clear()
630− waitForRendering(notification)
611+ compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect")
612+ compare(summaryLabel.visible, data.summaryVisible, "summary-text visibility is incorrect")
613+ compare(bodyLabel.visible, data.bodyVisible, "body-text visibility is incorrect")
614+ compare(buttonRow.visible, data.buttonRowVisible, "button visibility is incorrect")
631615
632− // check if there's a ComboButton created due to more actions being passed
633− if (data.actions.length > 2) {
634− var comboButton = findChild(notification, "notify_button2")
635− tryCompareFunction(function() { return comboButton.expanded == false; }, true);
616+ var audioItem = findInvisibleChild(notification, "sound")
617+ compare(audioItem.playbackState, data.hasSound ? Audio.PlayingState : Audio.StoppedState, "Audio has wrong state")
636618
637− // click to expand
638− tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true);
619+ if(data.buttonRowVisible) {
620+ var buttonCancel = findChild(buttonRow, "notify_button1")
621+ var buttonAccept = findChild(buttonRow, "notify_button0")
639622
640− // try clicking on choices in expanded comboList
641− var choiceButton1 = findChild(notification, "notify_button3")
642− tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
643− compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
644− actionSpy.clear()
623+ // only test the left/cancel-button if two actions have been passed in
624+ if (data.actions.length == 2) {
625+ tryCompareFunction(function() { mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2); return actionSpy.signalArguments.length > 0; }, true);
626+ compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
627+ actionSpy.clear()
628+ }
645629
646− var choiceButton2 = findChild(notification, "notify_button4")
647− tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
648− compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
649− actionSpy.clear()
630+ // check the tinting of the positive/right button
631+ verify(buttonAccept.color === data.buttonTinted ? "#3fb24f" : "#dddddd", "button has the wrong color-tint")
650632
651− // click to collapse
652− //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true);
653− } else {
654− mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
655− compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
633+ // click the positive/right button
634+ tryCompareFunction(function() { mouseClick(buttonAccept, buttonAccept.width / 2, buttonAccept.height / 2); return actionSpy.signalArguments.length > 0; }, true);
635+ compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id positive action")
636+ actionSpy.clear()
637+ waitForRendering (notification)
638+
639+ // check if there's a ComboButton created due to more actions being passed
640+ if (data.actions.length > 2) {
641+ var comboButton = findChild(notification, "notify_button2")
642+ tryCompareFunction(function() { return comboButton.expanded == false; }, true);
643+
644+ // click to expand
645+ tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true);
646+
647+ // try clicking on choices in expanded comboList
648+ var choiceButton1 = findChild(notification, "notify_button3")
649+ tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
650+ compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
651+ actionSpy.clear()
652+
653+ var choiceButton2 = findChild(notification, "notify_button4")
654+ tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
655+ compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
656+ actionSpy.clear()
657+
658+ // click to collapse
659+ //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true);
660+ } else {
661+ mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
662+ compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")
663+ }
656664 }
657665 }
658666 }