on xenial help sign in
Support fullscreen for special-case extended snap-decision of the pin-unlock dialog.
91ccb6cMirco Müller
Notifications/Notification.qml+211−181
@@ -20,7 +20,7 @@ import Unity.Notifications 1.0
20import QMenuModel 0.1
20import QMenuModel 0.1
21import Utils 0.1
21import Utils 0.1
22
22
23−UbuntuShape {
23+Item {
24 id: notification
24 id: notification
25
25
26 property alias iconSource: icon.fileSource
26 property alias iconSource: icon.fileSource
@@ -32,262 +32,292 @@ UbuntuShape {
32 property var type
32 property var type
33 property var hints
33 property var hints
34 property var notification
34 property var notification
35+ property color color
36+ property bool fullscreen
35
37
38+ fullscreen: false
36 objectName: "background"
39 objectName: "background"
37− implicitHeight: type != Notification.PlaceHolder ? contentColumn.height + contentColumn.spacing * 2 : 0
40+ implicitHeight: type != Notification.PlaceHolder ? (fullscreen ? notificationList.fullHeight : contentColumn.height + contentColumn.spacing * 4) : 0
41+
38 color: Qt.rgba(0.132, 0.117, 0.109, 0.97)
42 color: Qt.rgba(0.132, 0.117, 0.109, 0.97)
39 opacity: 0
43 opacity: 0
40− radius: "medium"
41
44
42− clip: true
45+ clip: fullscreen ? false : true
43 visible: type != Notification.PlaceHolder
46 visible: type != Notification.PlaceHolder
44
47
45− UnityMenuModelPaths {
48+ UbuntuShape {
46− id: paths
49+ id: shapedBack
47−
48− source: hints["x-canonical-private-menu-model"]
49
50
50− busNameHint: "busName"
51+ visible: !fullscreen
51− actionsHint: "actions"
52+ anchors.fill: parent
52− menuObjectPathHint: "menuPath"
53+ anchors.margins: notificationList.margin
54+ color: parent.color
55+ opacity: parent.opacity
56+ radius: "medium"
53 }
57 }
54
58
55− UnityMenuModel {
59+ Rectangle {
56− id: unityMenuModel
60+ id: nonShapedBack
57
61
58− busName: paths.busName
62+ visible: fullscreen
59− actions: paths.actions
63+ anchors.fill: parent
60− menuObjectPath: paths.menuObjectPath
64+ color: parent.color
65+ opacity: parent.opacity
61 }
66 }
62
67
63− Behavior on implicitHeight {
68+ Item {
64− id: heightBehavior
69+ id: contents
70+ anchors.fill: fullscreen ? nonShapedBack : shapedBack
65
71
66− enabled: false
72+ UnityMenuModelPaths {
67− UbuntuNumberAnimation {
73+ id: paths
68− duration: UbuntuAnimation.SnapDuration
69− }
70− }
71
74
72− // delay enabling height behavior until the add transition is complete
75+ source: hints["x-canonical-private-menu-model"]
73− onOpacityChanged: if (opacity == 1) heightBehavior.enabled = true
74
76
75− MouseArea {
77+ busNameHint: "busName"
76− id: interactiveArea
78+ actionsHint: "actions"
79+ menuObjectPathHint: "menuPath"
80+ }
77
81
78− anchors.fill: contentColumn
82+ UnityMenuModel {
79− objectName: "interactiveArea"
83+ id: unityMenuModel
80− enabled: notification.type == Notification.Interactive
84+
81− onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
85+ busName: paths.busName
86+ actions: paths.actions
87+ menuObjectPath: paths.menuObjectPath
82− }
88+ }
83
89
84− Column {
90+ Behavior on implicitHeight {
85− id: contentColumn
91+ id: heightBehavior
86
92
87− anchors {
93+ enabled: false
88− left: parent.left
94+ UbuntuNumberAnimation {
89− right: parent.right
95+ duration: UbuntuAnimation.SnapDuration
90− top: parent.top
96+ }
91− margins: spacing
92 }
97 }
93
98
94− spacing: units.gu(1)
99+ // delay enabling height behavior until the add transition is complete
100+ onOpacityChanged: if (opacity == 1) heightBehavior.enabled = true
95
101
96− Row {
102+ MouseArea {
97− id: topRow
103+ id: interactiveArea
104+
105+ anchors.fill: contentColumn
106+ objectName: "interactiveArea"
107+ enabled: notification.type == Notification.Interactive
108+ onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
109+ }
110+
111+ Column {
112+ id: contentColumn
98
113
99− spacing: contentColumn.spacing
100 anchors {
114 anchors {
101 left: parent.left
115 left: parent.left
102 right: parent.right
116 right: parent.right
117+ top: parent.top
118+ margins: fullscreen ? 0 : spacing
103 }
119 }
104
120
105− ShapedIcon {
121+ spacing: units.gu(1)
106− id: icon
107
122
108− objectName: "icon"
123+ Row {
109− width: units.gu(6)
124+ id: topRow
110− height: units.gu(6)
111− shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
112− visible: iconSource !== undefined && iconSource != ""
113− }
114
125
115− Image {
126+ spacing: contentColumn.spacing
116− id: secondaryIcon
127+ anchors {
128+ left: parent.left
129+ right: parent.right
130+ }
117
131
118− objectName: "secondaryIcon"
132+ ShapedIcon {
119− width: units.gu(2)
133+ id: icon
120− height: units.gu(2)
121− visible: source !== undefined && source != ""
122− fillMode: Image.PreserveAspectCrop
123− }
124
134
125− Column {
135+ objectName: "icon"
126− id: labelColumn
136+ width: units.gu(6)
127− width: parent.width - x
137+ height: units.gu(6)
138+ shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
139+ visible: iconSource !== undefined && iconSource != ""
140+ }
128
141
129− anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
142+ Image {
143+ id: secondaryIcon
130
144
131− Label {
145+ objectName: "secondaryIcon"
132− id: summaryLabel
146+ width: units.gu(2)
147+ height: units.gu(2)
148+ visible: source !== undefined && source != ""
149+ fillMode: Image.PreserveAspectCrop
150+ }
133
151
152+ Column {
153+ id: labelColumn
154+ width: parent.width - x
155+
156+ anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
157+
158+ Label {
159+ id: summaryLabel
160+
134− objectName: "summaryLabel"
161+ objectName: "summaryLabel"
135− anchors {
162+ anchors {
136− left: parent.left
163+ left: parent.left
137− right: parent.right
164+ right: parent.right
165+ }
166+ fontSize: "medium"
167+ font.bold: true
168+ color: Theme.palette.selected.backgroundText
169+ elide: Text.ElideRight
138 }
170 }
139− fontSize: "medium"
140− font.bold: true
141− color: Theme.palette.selected.backgroundText
142− elide: Text.ElideRight
143− }
144
171
145− Label {
172+ Label {
146− id: bodyLabel
173+ id: bodyLabel
147
174
148− objectName: "bodyLabel"
175+ objectName: "bodyLabel"
149− anchors {
176+ anchors {
150− left: parent.left
177+ left: parent.left
151− right: parent.right
178+ right: parent.right
179+ }
180+ visible: body != ""
181+ fontSize: "small"
182+ color: Theme.palette.selected.backgroundText
183+ opacity: 0.6
184+ wrapMode: Text.WordWrap
185+ maximumLineCount: 10
186+ elide: Text.ElideRight
152 }
187 }
153− visible: body != ""
154− fontSize: "small"
155− color: Theme.palette.selected.backgroundText
156− opacity: 0.6
157− wrapMode: Text.WordWrap
158− maximumLineCount: 10
159− elide: Text.ElideRight
160 }
188 }
161 }
189 }
162− }
163
190
164− Column {
191+ Column {
165− objectName: "dialogListView"
192+ objectName: "dialogListView"
166− spacing: units.gu(2)
193+ spacing: units.gu(2)
167
194
168− visible: count > 0
195+ visible: count > 0
169
196
170− anchors.left: parent.left; anchors.right: parent.right
197+ anchors.left: parent.left; anchors.right: parent.right
198+ anchors.top: fullscreen ? parent.top : undefined
199+ anchors.bottom: fullscreen ? parent.bottom : undefined
171
200
172− Repeater {
201+ Repeater {
173− model: unityMenuModel
202+ model: unityMenuModel
174
203
175− NotificationMenuItemFactory {
204+ NotificationMenuItemFactory {
176− anchors.left: parent.left; anchors.right: parent.right
205+ anchors.left: parent.left; anchors.right: parent.right
177
206
178− menuModel: unityMenuModel
207+ menuModel: unityMenuModel
179− menuData: model
208+ menuData: model
180− menuIndex: index
209+ menuIndex: index
210+ }
181 }
211 }
182 }
212 }
183− }
184
213
185− Item {
214+ Item {
186− id: buttonRow
215+ id: buttonRow
187
216
188− objectName: "buttonRow"
217+ objectName: "buttonRow"
189− anchors {
218+ anchors {
190− left: parent.left
219+ left: parent.left
191− right: parent.right
220+ right: parent.right
192− }
221+ }
193− visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0
222+ visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0
194− height: units.gu(5)
223+ height: units.gu(5)
195
224
196− property real buttonWidth: (width - contentColumn.spacing) / 2
225+ property real buttonWidth: (width - contentColumn.spacing) / 2
197− property bool expanded
226+ property bool expanded
198
227
199− Button {
228+ Button {
200− id: leftButton
229+ id: leftButton
201
230
202− objectName: "button1"
231+ objectName: "button1"
203− width: parent.expanded ? parent.width : parent.buttonWidth
232+ width: parent.expanded ? parent.width : parent.buttonWidth
204− anchors {
233+ anchors {
205− top: parent.top
234+ top: parent.top
206− bottom: parent.bottom
235+ bottom: parent.bottom
207− }
236+ }
208− text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
237+ text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
209− gradient: UbuntuColors.greyGradient
238+ gradient: UbuntuColors.greyGradient
210− onClicked: {
239+ onClicked: {
211− if (actionRepeater.count > 2) {
240+ if (actionRepeater.count > 2) {
212− buttonRow.expanded = !buttonRow.expanded
241+ buttonRow.expanded = !buttonRow.expanded
213− } else {
242+ } else {
214− notification.notification.invokeAction(actionRepeater.itemAt(1).actionId)
243+ notification.notification.invokeAction(actionRepeater.itemAt(1).actionId)
244+ }
245+ }
246+
247+ Behavior on width {
248+ UbuntuNumberAnimation {
249+ duration: UbuntuAnimation.SnapDuration
250+ }
215 }
251 }
216 }
252 }
217
253
218− Behavior on width {
254+ Button {
219− UbuntuNumberAnimation {
255+ id: rightButton
220− duration: UbuntuAnimation.SnapDuration
256+
257+ objectName: "button0"
258+ anchors {
259+ left: leftButton.right
260+ leftMargin: contentColumn.spacing
261+ right: parent.right
221 }
262 }
263+ text: notification.type == Notification.SnapDecision && actionRepeater.count >= 1 ? actionRepeater.itemAt(0).actionLabel : ""
264+ anchors {
265+ top: parent.top
266+ bottom: parent.bottom
267+ }
268+ gradient: notification.hints["x-canonical-private-button-tint"] == "true" ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
269+ visible: width > 0
270+ onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
222 }
271 }
223 }
272 }
224
273
225− Button {
274+ Column {
226− id: rightButton
227−
228− objectName: "button0"
275+ objectName: "buttonColumn"
276+ spacing: contentColumn.spacing
229 anchors {
277 anchors {
230− left: leftButton.right
278+ left: parent.left
231− leftMargin: contentColumn.spacing
232 right: parent.right
279 right: parent.right
233 }
280 }
234− text: notification.type == Notification.SnapDecision && actionRepeater.count >= 1 ? actionRepeater.itemAt(0).actionLabel : ""
235− anchors {
236− top: parent.top
237− bottom: parent.bottom
238− }
239− gradient: notification.hints["x-canonical-private-button-tint"] == "true" ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
240− visible: width > 0
241− onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
242− }
243− }
244
281
245− Column {
282+ // calculate initial position before Column takes over
246− objectName: "buttonColumn"
247− spacing: contentColumn.spacing
283+ y: buttonRow.y + buttonRow.height + contentColumn.spacing
248− anchors {
249− left: parent.left
250− right: parent.right
251− }
252
284
253− // calculate initial position before Column takes over
285+ visible: notification.type == Notification.SnapDecision && buttonRow.expanded
254− y: buttonRow.y + buttonRow.height + contentColumn.spacing
286+ height: buttonRow.expanded ? implicitHeight : 0
255
287
256− visible: notification.type == Notification.SnapDecision
288+ Repeater {
257− height: buttonRow.expanded ? implicitHeight : 0
289+ id: actionRepeater
258
290
259− Repeater {
291+ model: notification.actions
260− id: actionRepeater
292+ delegate: Loader {
293+ id: loader
261
294
262− model: notification.actions
295+ property string actionId: id
263− delegate: Loader {
296+ property string actionLabel: label
264− id: loader
265
297
266− property string actionId: id
298+ anchors {
267− property string actionLabel: label
299+ left: parent.left
300+ right: parent.right
301+ }
268
302
269− anchors {
303+ Component {
270− left: parent.left
304+ id: actionButton
271− right: parent.right
272− }
273
305
274− Component {
306+ Button {
275− id: actionButton
307+ objectName: "button" + index
308+ anchors {
309+ left: parent.left
310+ right: parent.right
311+ }
276
312
277− Button {
313+ text: loader.actionLabel
278− objectName: "button" + index
314+ height: units.gu(5)
279− anchors {
315+ gradient: UbuntuColors.greyGradient
280− left: parent.left
316+ onClicked: notification.notification.invokeAction(loader.actionId)
281− right: parent.right
282 }
317 }
283−
284− text: loader.actionLabel
285− height: units.gu(5)
286− gradient: UbuntuColors.greyGradient
287− onClicked: notification.notification.invokeAction(loader.actionId)
288 }
318 }
319+ sourceComponent: (index == 0 || index == 1) ? undefined : actionButton
289 }
320 }
290− sourceComponent: (index == 0 || index == 1) ? undefined : actionButton
291 }
321 }
292 }
322 }
293 }
323 }
Notifications/NotificationMenuItemFactory.qml+9−2
@@ -28,7 +28,6 @@ Loader {
28 property QtObject menuModel: null
28 property QtObject menuModel: null
29 property QtObject menuData: null
29 property QtObject menuData: null
30 property int menuIndex
30 property int menuIndex
31− property var notification
32
31
33 property var _map: {
32 property var _map: {
34 "com.canonical.snapdecision.textfield": textfield,
33 "com.canonical.snapdecision.textfield": textfield,
@@ -44,6 +43,10 @@ Loader {
44 }
43 }
45 }
44 }
46
45
46+ Component.onCompleted: {
47+ notification.fullscreen = menuData.type == "com.canonical.snapdecision.pinlock"
48+ }
49+
47 Component {
50 Component {
48 id: textfield
51 id: textfield
49
52
@@ -94,8 +97,12 @@ Loader {
94
97
95 Component {
98 Component {
96 id: pinLock
99 id: pinLock
97− PinLockscreen {
100+
101+ Lockscreen {
98 anchors.left: parent.left; anchors.right: parent.right
102 anchors.left: parent.left; anchors.right: parent.right
103+ height: notificationList.fullHeight
104+ placeholderText: i18n.tr("Please enter SIM PIN")
105+ background: shell.background
99
106
100 onEntered: {
107 onEntered: {
101 menuModel.changeState(menuIndex, passphrase);
108 menuModel.changeState(menuIndex, passphrase);
Notifications/Notifications.qml+3−1
@@ -24,7 +24,9 @@ ListView {
24 objectName: "notificationList"
24 objectName: "notificationList"
25 interactive: false
25 interactive: false
26
26
27− spacing: units.gu(.5)
27+ property real margin
28+ property real fullHeight
29+
28 delegate: Notification {
30 delegate: Notification {
29 objectName: "notification" + index
31 objectName: "notification" + index
30 anchors {
32 anchors {
Shell.qml+4−3
@@ -704,13 +704,14 @@ FocusScope {
704 id: notifications
704 id: notifications
705
705
706 model: NotificationBackend.Model
706 model: NotificationBackend.Model
707+ margin: units.gu(1)
708+ fullHeight: parent.height - panel.panelHeight
709+
707 anchors {
710 anchors {
708 top: parent.top
711 top: parent.top
709 right: parent.right
712 right: parent.right
710 bottom: parent.bottom
713 bottom: parent.bottom
711− leftMargin: units.gu(1)
712− rightMargin: units.gu(1)
713− topMargin: panel.panelHeight + units.gu(1)
714+ topMargin: panel.panelHeight
714 }
715 }
715 states: [
716 states: [
716 State {
717 State {
tests/autopilot/unity8/shell/tests/test_notifications.py+1−1
@@ -65,7 +65,7 @@ class NotificationsBase(UnityTestCase):
65 def _get_notifications_list(self):
65 def _get_notifications_list(self):
66 main_view = self.main_window.get_qml_view()
66 main_view = self.main_window.get_qml_view()
67 return main_view.select_single(
67 return main_view.select_single(
68− "QQuickListView",
68+ "Notifications",
69 objectName='notificationList'
69 objectName='notificationList'
70 )
70 )
71
71
tests/qmltests/Notifications/tst_Notifications.qml+3−4
@@ -140,8 +140,10 @@ Row {
140 Notifications {
140 Notifications {
141 id: notifications
141 id: notifications
142
142
143+ margin: units.gu(1)
144+ fullHeight: parent.height
145+
143 anchors.fill: parent
146 anchors.fill: parent
144− anchors.margins: units.gu(1)
145 model: mockModel
147 model: mockModel
146 }
148 }
147 }
149 }
@@ -401,9 +403,6 @@ Row {
401 actionSpy.wait()
403 actionSpy.wait()
402 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
404 compare(actionSpy.signalArguments[0][0], data.actions[0]["id"], "got wrong id for interactive action")
403 compare(clickThroughSpy.count, 0, "click on interactive notification fell through")
405 compare(clickThroughSpy.count, 0, "click on interactive notification fell through")
404− } else {
405− mouseClick(notification, notification.width / 2, notification.height / 2)
406− clickThroughSpy.wait()
407 }
406 }
408
407
409 compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect")
408 compare(secondaryIcon.visible, data.secondaryIconVisible, "secondary-icon visibility is incorrect")