Merge lp:~macslow/unity8/combo-button-support into lp:unity8

Proposed by Mirco Müller
Status: Merged
Approved by: Michał Sawicz
Approved revision: 940
Merged at revision: 1042
Proposed branch: lp:~macslow/unity8/combo-button-support
Merge into: lp:unity8
Diff against target: 363 lines (+135/-118)
4 files modified
debian/control (+1/-1)
qml/Notifications/Notification.qml (+104/-79)
tests/autopilot/unity8/shell/tests/test_notifications.py (+10/-13)
tests/qmltests/Notifications/tst_Notifications.qml (+20/-25)
To merge this branch: bzr merge lp:~macslow/unity8/combo-button-support
Reviewer Review Type Date Requested Status
Michał Sawicz Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+221499@code.launchpad.net

Commit message

Added support for utilization of the ComboButton SDK-element for snap-decision notifications with many actions.

Description of the change

Added support for the ComboButton SDK-element to be utilized for snap-decision notifications with many actions (upto 7) to comply with design presented in the "compact widget patterns"-document from January 2014.

QML- and autopilot-tests were also updated to reflect the change in layout and behaviour.

Furthermore there'll be a newer version of lp:unity-notifications with some tweaks and updated example code of how to use the comboButton-support. This newer version of lp:unity-notifications is mandatory for this unity8 branch to work correctly.

Here's a short screencast: http://www.youtube.com/watch?v=4KMrsj_h0EM

- Are there any related MPs required for this MP to build/function as expected?
Yes. https://code.launchpad.net/~macslow/unity-notifications/combo-button-support

- Did you perform an exploratory manual test run of your code change and any related functionality?
Yes, but only on desktop not yet on the device/phone since cross-compiling currently doesn't work for me (Malta-sprint, unreliable wifi)

- 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?
Not yet. This branch does implement a desired design though.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

It feels to me like the pip should be colourized (grey?) instead of white, is the design to leave it white?

review: Needs Fixing
Revision history for this message
Mirco Müller (macslow) wrote :

Correct. That's a fix to the ComboButton SDK-element, which has not been done yet. I'm currently looking into this. Furthermore the "carret" of the drop-down button has the wrong color. It should be full white. This too needs to be fixed in the ComboButton SDK-element.

Revision history for this message
Michał Sawicz (saviq) wrote :

Please bump the plugin dep after you bump it in the corresponding MP in lp:unity-notifications.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Test Result (1 failure / -7)
    unity8.shell.tests.test_notifications.InteractiveNotificationBase.test_sd_incoming_call(Native Device)

931. By Mirco Müller

Enforce dependency on 0.1.2 version of notification-plugin to reflect newly supported max. number of snap-decision actions.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
932. By Mirco Müller

The even newer Design wants flat colors. But the ubuntu-ui-toolkit does not offer those yet. Thus I'll stick with these hard-coded values for the time being. I'll change the notification-code once the newer themed flat colors become available in our SDK.

933. By Mirco Müller

Further fixes from MP-comments.

934. By Mirco Müller

More cleanup and fixes from MP-comments.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
935. By Mirco Müller

Merged with trunk.

936. By Mirco Müller

Use a regular expression instead of two custom JavaScript-functions for the icon-label split of the action-label.

937. By Mirco Müller

Tighten up anchors code a bit.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
938. By Mirco Müller

Merged again with trunk and solved merge-conflicts.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

See inline.

review: Needs Fixing
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

Text conflict in debian/control
1 conflicts encountered.

review: Needs Fixing
939. By Mirco Müller

Merged with trunk and resolved conflicts.

940. By Mirco Müller

Adjust regular expression to allow a larger variety of icon-names.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Michał Sawicz (saviq) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes. Works nicely!

 * Did CI run pass? If not, please explain why.
Yes!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2014-07-09 19:44:14 +0000
3+++ debian/control 2014-07-11 08:50:45 +0000
4@@ -103,7 +103,7 @@
5 Architecture: all
6 Depends: qtdeclarative5-ubuntu-thumbnailer0.1 | ubuntu-thumbnailer-impl,
7 qtdeclarative5-ubuntu-ui-toolkit-plugin (>= 0.1.49) | qtdeclarative5-ubuntu-ui-toolkit-plugin-gles (>= 0.1.49),
8- qtdeclarative5-unity-notifications-plugin | unity-notifications-impl,
9+ qtdeclarative5-unity-notifications-plugin (>= 0.1.2) | unity-notifications-impl,
10 ubuntu-thumbnailer-impl-0,
11 unity-application-impl-2,
12 unity-notifications-impl-3,
13
14=== modified file 'qml/Notifications/Notification.qml'
15--- qml/Notifications/Notification.qml 2014-06-18 09:45:37 +0000
16+++ qml/Notifications/Notification.qml 2014-07-11 08:50:45 +0000
17@@ -16,11 +16,13 @@
18
19 import QtQuick 2.0
20 import QtMultimedia 5.0
21-import Ubuntu.Components 0.1
22+import Ubuntu.Components 1.1
23 import Unity.Notifications 1.0
24 import QMenuModel 0.1
25 import Utils 0.1
26
27+import Ubuntu.Components.ListItems 0.1 as ListItem
28+
29 Item {
30 id: notification
31
32@@ -37,6 +39,14 @@
33 property bool fullscreen
34 property int maxHeight
35 property int margins
36+ property Gradient greenGradient : Gradient {
37+ GradientStop { position: 0.0; color: "#3fb24f" }
38+ GradientStop { position: 1.0; color: "#3fb24f" }
39+ }
40+ property Gradient darkgreyGradient: Gradient {
41+ GradientStop { position: 0.0; color: "#4d4745" }
42+ GradientStop { position: 1.0; color: "#4d4745" }
43+ }
44
45 fullscreen: false
46 objectName: "background"
47@@ -291,7 +301,7 @@
48 }
49 }
50
51- Item {
52+ Row {
53 id: buttonRow
54
55 objectName: "buttonRow"
56@@ -300,70 +310,8 @@
57 right: parent.right
58 }
59 visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0
60- height: units.gu(5)
61-
62- property real buttonWidth: (width - contentColumn.spacing) / 2
63- property bool expanded
64-
65- Button {
66- id: leftButton
67-
68- objectName: "button1"
69- width: parent.expanded ? parent.width : parent.buttonWidth
70- anchors {
71- top: parent.top
72- bottom: parent.bottom
73- }
74- text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
75- gradient: UbuntuColors.greyGradient
76- onClicked: {
77- if (actionRepeater.count > 2) {
78- buttonRow.expanded = !buttonRow.expanded
79- } else {
80- notification.notification.invokeAction(actionRepeater.itemAt(1).actionId)
81- }
82- }
83-
84- Behavior on width {
85- UbuntuNumberAnimation {
86- duration: UbuntuAnimation.SnapDuration
87- }
88- }
89- }
90-
91- Button {
92- id: rightButton
93-
94- objectName: "button0"
95- anchors {
96- left: leftButton.right
97- leftMargin: contentColumn.spacing
98- right: parent.right
99- }
100- text: notification.type == Notification.SnapDecision && actionRepeater.count >= 1 ? actionRepeater.itemAt(0).actionLabel : ""
101- anchors {
102- top: parent.top
103- bottom: parent.bottom
104- }
105- gradient: notification.hints["x-canonical-private-button-tint"] == "true" ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
106- visible: width > 0
107- onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
108- }
109- }
110-
111- Column {
112- objectName: "buttonColumn"
113- spacing: contentColumn.spacing
114- anchors {
115- left: parent.left
116- right: parent.right
117- }
118-
119- // calculate initial position before Column takes over
120- y: buttonRow.y + buttonRow.height + contentColumn.spacing
121-
122- visible: notification.type == Notification.SnapDecision && buttonRow.expanded
123- height: buttonRow.expanded ? implicitHeight : 0
124+ spacing: units.gu(1)
125+ layoutDirection: Qt.RightToLeft
126
127 Repeater {
128 id: actionRepeater
129@@ -375,28 +323,105 @@
130 property string actionId: id
131 property string actionLabel: label
132
133- anchors {
134- left: parent.left
135- right: parent.right
136- }
137-
138 Component {
139 id: actionButton
140
141 Button {
142 objectName: "button" + index
143- anchors {
144- left: parent.left
145- right: parent.right
146- }
147-
148+ width: buttonRow.width / 2 - spacing
149 text: loader.actionLabel
150- height: units.gu(5)
151- gradient: UbuntuColors.greyGradient
152+ gradient: notification.hints["x-canonical-private-button-tint"] == "true" && index == 0 ? greenGradient : darkgreyGradient
153 onClicked: notification.notification.invokeAction(loader.actionId)
154 }
155 }
156- sourceComponent: (index == 0 || index == 1) ? undefined : actionButton
157+ sourceComponent: (index == 0 || index == 1) ? actionButton : undefined
158+ }
159+ }
160+ }
161+
162+ ComboButton {
163+ id: comboButton
164+
165+ objectName: "button2"
166+ width: parent.width
167+ visible: notification.type == Notification.SnapDecision && actionRepeater.count > 3
168+ gradient: darkgreyGradient
169+ onClicked: notification.notification.invokeAction(comboRepeater.itemAt(2).actionId)
170+ expanded: false
171+ expandedHeight: (comboRepeater.count - 2) * units.gu(4) + units.gu(.5)
172+ comboList: Flickable {
173+ // this has to be wrapped inside a flickable
174+ // to work around a feature/bug? of the
175+ // ComboButton SDK-element, making a regular
176+ // unwrapped Column item flickable
177+ // see LP: #1332590
178+ interactive: false
179+ Column {
180+ Repeater {
181+ id: comboRepeater
182+
183+ onVisibleChanged: {
184+ comboButton.text = comboRepeater.itemAt(2).actionLabel
185+ }
186+
187+ model: notification.actions
188+ delegate: Loader {
189+ id: comboLoader
190+
191+ asynchronous: true
192+ visible: status == Loader.Ready
193+ property string actionId: id
194+ property string actionLabel: label
195+ readonly property var splitLabel: actionLabel.match(/(^([-a-z0-9]+):)?(.*)$/)
196+ Component {
197+ id: comboEntry
198+
199+ MouseArea {
200+ id: comboInputArea
201+
202+ objectName: "button" + index
203+ width: comboButton.width
204+ height: comboIcon.height + units.gu(2)
205+
206+ onClicked: {
207+ notification.notification.invokeAction(actionId)
208+ }
209+
210+ ListItem.ThinDivider {
211+ visible: index > 3
212+ }
213+
214+ Icon {
215+ id: comboIcon
216+
217+ anchors {
218+ left: parent.left
219+ leftMargin: units.gu(.5)
220+ verticalCenter: parent.verticalCenter
221+ }
222+ width: units.gu(2)
223+ height: units.gu(2)
224+ color: "white"
225+ name: splitLabel[2]
226+ }
227+
228+ Label {
229+ id: comboLabel
230+
231+ anchors {
232+ left: comboIcon.right
233+ leftMargin: units.gu(1)
234+ verticalCenter: comboIcon.verticalCenter
235+ }
236+ fontSize: "small"
237+ color: "white"
238+ text: splitLabel[3]
239+ }
240+ }
241+ }
242+ sourceComponent: (index > 2) ? comboEntry : undefined
243+ }
244+ }
245 }
246 }
247 }
248
249=== modified file 'tests/autopilot/unity8/shell/tests/test_notifications.py'
250--- tests/autopilot/unity8/shell/tests/test_notifications.py 2014-07-07 08:51:33 +0000
251+++ tests/autopilot/unity8/shell/tests/test_notifications.py 2014-07-11 08:50:45 +0000
252@@ -178,11 +178,13 @@
253 ]
254
255 actions = [
256- ('action_accept', 'Accept'),
257- ('action_decline_1', 'Decline'),
258- ('action_decline_2', '"Can\'t talk now, what\'s up?"'),
259- ('action_decline_3', '"I call you back."'),
260- ('action_decline_4', 'Send custom message...'),
261+ ('action_accept', 'Hold + Answer'),
262+ ('action_decline_1', 'End + Answer'),
263+ ('action_decline_2', 'Decline'),
264+ ('action_decline_3', 'messages:I missed your call - can you call me now?'),
265+ ('action_decline_4', 'messages:I\'m running late. I\'m on my way.'),
266+ ('action_decline_5', 'messages:I\'m busy at the moment. I\'ll call later.'),
267+ ('action_decline_6', 'edit:Custom'),
268 ]
269
270 self._create_interactive_notification(
271@@ -200,14 +202,9 @@
272 notification = get_notification()
273 self._assert_notification(notification, summary, body, True, True, 1.0)
274 initial_height = notification.height
275- self.touch.tap_object(notification.select_single(objectName="button1"))
276- self.assertThat(
277- notification.height,
278- Eventually(Equals(initial_height +
279- 3 * notification.select_single(
280- objectName="buttonColumn").spacing +
281- 3 * notification.select_single(
282- objectName="button4").height)))
283+ self.touch.tap_object(notification.select_single(objectName="combobutton_dropdown"))
284+ self.assertThat(notification.select_single(objectName="button2").expanded, Eventually(Equals(True)))
285+ time.sleep(2)
286 self.touch.tap_object(notification.select_single(objectName="button4"))
287 self.assert_notification_action_id_was_called("action_decline_4")
288
289
290=== modified file 'tests/qmltests/Notifications/tst_Notifications.qml'
291--- tests/qmltests/Notifications/tst_Notifications.qml 2014-06-16 11:07:18 +0000
292+++ tests/qmltests/Notifications/tst_Notifications.qml 2014-07-11 08:50:45 +0000
293@@ -72,8 +72,8 @@
294 actions: [{ id: "ok_id", label: "Ok"},
295 { id: "cancel_id", label: "Cancel"},
296 { id: "notreally_id", label: "Not really"},
297- { id: "noway_id", label: "No way"},
298- { id: "nada_id", label: "Nada"}]
299+ { id: "noway_id", label: "messages:No way"},
300+ { id: "nada_id", label: "messages:Nada"}]
301 }
302
303 mockModel.append(n)
304@@ -237,8 +237,8 @@
305 actions: [{ id: "ok_id", label: "Ok"},
306 { id: "cancel_id", label: "Cancel"},
307 { id: "notreally_id", label: "Not really"},
308- { id: "noway_id", label: "No way"},
309- { id: "nada_id", label: "Nada"}],
310+ { id: "noway_id", label: "messages:No way"},
311+ { id: "nada_id", label: "messages:Nada"}],
312 summaryVisible: true,
313 bodyVisible: true,
314 iconVisible: true,
315@@ -456,32 +456,27 @@
316 actionSpy.clear()
317 waitForRendering(notification)
318
319- // check if there's more than one negative choice
320+ // check if there's a ComboButton created due to more actions being passed
321 if (data.actions.length > 2) {
322- var initialHeight = notification.implicitHeight
323+ var comboButton = findChild(notification, "button2")
324+ tryCompareFunction(function() { return comboButton.expanded == false; }, true);
325
326 // click to expand
327- mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
328- var contentColumn = findChild(notification, "contentColumn")
329- var collapsedContentColumnHeight = contentColumn.height;
330- // Waiting for the inner column to change height because buttons appear
331- tryCompareFunction(function() { return collapsedContentColumnHeight != contentColumn.height; }, true);
332- // Waiting for notification to reach its target size
333- tryCompare(notification, "height", contentColumn.height + contentColumn.spacing * 2)
334- actionSpy.clear()
335-
336- // test the additional buttons
337- for (var i = 2; i < data.actions.length; i++) {
338- var buttonColumn = findChild(notification, "buttonColumn")
339- var button = findChild(buttonColumn, "button" + i)
340- mouseClick(button, button.width / 2, button.height / 2)
341- compare(actionSpy.signalArguments[0][0], data.actions[i]["id"], "got wrong id for additional negative action")
342- actionSpy.clear()
343- }
344+ tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == true; }, true);
345+
346+ // try clicking on choices in expanded comboList
347+ var choiceButton1 = findChild(notification, "button3")
348+ tryCompareFunction(function() { mouseClick(choiceButton1, choiceButton1.width / 2, choiceButton1.height / 2); return actionSpy.signalArguments.length > 0; }, true);
349+ compare(actionSpy.signalArguments[0][0], data.actions[3]["id"], "got wrong id choice action 1")
350+ actionSpy.clear()
351+
352+ var choiceButton2 = findChild(notification, "button4")
353+ tryCompareFunction(function() { mouseClick(choiceButton2, choiceButton2.width / 2, choiceButton2.height / 2); return actionSpy.signalArguments.length > 0; }, true);
354+ compare(actionSpy.signalArguments[0][0], data.actions[4]["id"], "got wrong id choice action 2")
355+ actionSpy.clear()
356
357 // click to collapse
358- mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
359- tryCompare(notification, "height", initialHeight)
360+ //tryCompareFunction(function() { mouseClick(comboButton, comboButton.width - comboButton.__styleInstance.dropDownWidth / 2, comboButton.height / 2); return comboButton.expanded == false; }, true);
361 } else {
362 mouseClick(buttonCancel, buttonCancel.width / 2, buttonCancel.height / 2)
363 compare(actionSpy.signalArguments[0][0], data.actions[1]["id"], "got wrong id for negative action")

Subscribers

People subscribed via source and target branches