Unity 8
 All Classes Functions Properties
Notification.qml
1 /*
2  * Copyright (C) 2013 Canonical, Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 3.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 import QtQuick 2.0
18 import Ubuntu.Components 0.1
19 import Unity.Notifications 1.0
20 import QMenuModel 0.1
21 import Utils 0.1
22 
23 Item {
24  id: notification
25 
26  property alias iconSource: icon.fileSource
27  property alias secondaryIconSource: secondaryIcon.source
28  property alias summary: summaryLabel.text
29  property alias body: bodyLabel.text
30  property var actions
31  property var notificationId
32  property var type
33  property var hints
34  property var notification
35  property color color
36  property bool fullscreen
37  property int maxHeight
38  property int margins
39 
40  fullscreen: false
41  objectName: "background"
42  implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : contentColumn.height + contentColumn.spacing * 2) : 0
43 
44  color: Qt.rgba(0.132, 0.117, 0.109, 0.97)
45  opacity: 0
46 
47  state: {
48  var result = "";
49 
50  if (type == Notification.SnapDecision) {
51  if (ListView.view.currentIndex == index) {
52  result = "expanded";
53  } else {
54  if (ListView.view.count > 2) {
55  if (ListView.view.currentIndex == -1 && index == 1) {
56  result = "expanded";
57  } else {
58  result = "contracted";
59  }
60  } else {
61  result = "expanded";
62  }
63  }
64  }
65 
66  return result;
67  }
68 
69  Behavior on height {
70  id: normalHeightBehavior
71 
72  //enabled: menuItemFactory.progress == 1
73  enabled: true
74  SequentialAnimation {
75  PauseAnimation {
76  duration: UbuntuAnimation.SnapDuration
77  }
78  UbuntuNumberAnimation {
79  duration: UbuntuAnimation.SnapDuration
80  }
81  }
82  }
83 
84  states:[
85  State {
86  name: "contracted"
87  PropertyChanges {target: notification; height: units.gu(8)}
88  },
89  State {
90  name: "expanded"
91  PropertyChanges {target: notification; height: implicitHeight}
92  }
93  ]
94 
95  clip: fullscreen ? false : true
96 
97  visible: type != Notification.PlaceHolder
98 
99  UbuntuShape {
100  id: shapedBack
101 
102  visible: !fullscreen
103  anchors {
104  fill: parent
105  leftMargin: notification.margins
106  rightMargin: notification.margins
107  }
108  color: parent.color
109  opacity: parent.opacity
110  radius: "medium"
111  }
112 
113  Rectangle {
114  id: nonShapedBack
115 
116  visible: fullscreen
117  anchors.fill: parent
118  color: parent.color
119  opacity: parent.opacity
120  }
121 
122  Item {
123  id: contents
124  anchors.fill: fullscreen ? nonShapedBack : shapedBack
125 
126  UnityMenuModelPaths {
127  id: paths
128 
129  source: hints["x-canonical-private-menu-model"]
130 
131  busNameHint: "busName"
132  actionsHint: "actions"
133  menuObjectPathHint: "menuPath"
134  }
135 
136  UnityMenuModel {
137  id: unityMenuModel
138 
139  busName: paths.busName
140  actions: paths.actions
141  menuObjectPath: paths.menuObjectPath
142  }
143 
144  Behavior on implicitHeight {
145  id: heightBehavior
146 
147  enabled: false
148  UbuntuNumberAnimation {
149  duration: UbuntuAnimation.SnapDuration
150  }
151  }
152 
153  // delay enabling height behavior until the add transition is complete
154  onOpacityChanged: if (opacity == 1) heightBehavior.enabled = true
155 
156  MouseArea {
157  id: interactiveArea
158 
159  anchors.fill: parent
160  objectName: "interactiveArea"
161  onClicked: {
162  if (notification.type == Notification.Interactive) {
163  notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
164  } else {
165  notificationList.currentIndex = index;
166  }
167  }
168  }
169 
170  Column {
171  id: contentColumn
172  objectName: "contentColumn"
173 
174  anchors {
175  left: parent.left
176  right: parent.right
177  top: parent.top
178  margins: fullscreen ? 0 : spacing
179  }
180 
181  spacing: units.gu(1)
182 
183  Row {
184  id: topRow
185 
186  spacing: contentColumn.spacing
187  anchors {
188  left: parent.left
189  right: parent.right
190  }
191 
192  ShapedIcon {
193  id: icon
194 
195  objectName: "icon"
196  width: units.gu(6)
197  height: units.gu(6)
198  shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
199  visible: iconSource !== undefined && iconSource != ""
200  }
201 
202  Image {
203  id: secondaryIcon
204 
205  objectName: "secondaryIcon"
206  width: units.gu(2)
207  height: units.gu(2)
208  visible: source !== undefined && source != ""
209  fillMode: Image.PreserveAspectCrop
210  }
211 
212  Column {
213  id: labelColumn
214  width: parent.width - x
215 
216  anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
217 
218  Label {
219  id: summaryLabel
220 
221  objectName: "summaryLabel"
222  anchors {
223  left: parent.left
224  right: parent.right
225  }
226  fontSize: "medium"
227  font.bold: true
228  color: Theme.palette.selected.backgroundText
229  elide: Text.ElideRight
230  }
231 
232  Label {
233  id: bodyLabel
234 
235  objectName: "bodyLabel"
236  anchors {
237  left: parent.left
238  right: parent.right
239  }
240  visible: body != ""
241  fontSize: "small"
242  color: Theme.palette.selected.backgroundText
243  opacity: 0.6
244  wrapMode: Text.WordWrap
245  maximumLineCount: 10
246  elide: Text.ElideRight
247  }
248  }
249  }
250 
251  Column {
252  objectName: "dialogListView"
253  spacing: units.gu(2)
254 
255  visible: count > 0
256 
257  anchors.left: parent.left; anchors.right: parent.right
258  anchors.top: fullscreen ? parent.top : undefined
259  anchors.bottom: fullscreen ? parent.bottom : undefined
260 
261  Repeater {
262  model: unityMenuModel
263 
264  NotificationMenuItemFactory {
265  id: menuItemFactory
266 
267  anchors.left: parent.left; anchors.right: parent.right
268 
269  menuModel: unityMenuModel
270  menuData: model
271  menuIndex: index
272  maxHeight: notification.maxHeight
273 
274  onLoaded: {
275  notification.fullscreen = Qt.binding(function() { return fullscreen; });
276  }
277  }
278  }
279  }
280 
281  Item {
282  id: buttonRow
283 
284  objectName: "buttonRow"
285  anchors {
286  left: parent.left
287  right: parent.right
288  }
289  visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0
290  height: units.gu(5)
291 
292  property real buttonWidth: (width - contentColumn.spacing) / 2
293  property bool expanded
294 
295  Button {
296  id: leftButton
297 
298  objectName: "button1"
299  width: parent.expanded ? parent.width : parent.buttonWidth
300  anchors {
301  top: parent.top
302  bottom: parent.bottom
303  }
304  text: notification.type == Notification.SnapDecision && actionRepeater.count >= 2 ? actionRepeater.itemAt(1).actionLabel : ""
305  gradient: UbuntuColors.greyGradient
306  onClicked: {
307  if (actionRepeater.count > 2) {
308  buttonRow.expanded = !buttonRow.expanded
309  } else {
310  notification.notification.invokeAction(actionRepeater.itemAt(1).actionId)
311  }
312  }
313 
314  Behavior on width {
315  UbuntuNumberAnimation {
316  duration: UbuntuAnimation.SnapDuration
317  }
318  }
319  }
320 
321  Button {
322  id: rightButton
323 
324  objectName: "button0"
325  anchors {
326  left: leftButton.right
327  leftMargin: contentColumn.spacing
328  right: parent.right
329  }
330  text: notification.type == Notification.SnapDecision && actionRepeater.count >= 1 ? actionRepeater.itemAt(0).actionLabel : ""
331  anchors {
332  top: parent.top
333  bottom: parent.bottom
334  }
335  gradient: notification.hints["x-canonical-private-button-tint"] == "true" ? UbuntuColors.orangeGradient : UbuntuColors.greyGradient
336  visible: width > 0
337  onClicked: notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
338  }
339  }
340 
341  Column {
342  objectName: "buttonColumn"
343  spacing: contentColumn.spacing
344  anchors {
345  left: parent.left
346  right: parent.right
347  }
348 
349  // calculate initial position before Column takes over
350  y: buttonRow.y + buttonRow.height + contentColumn.spacing
351 
352  visible: notification.type == Notification.SnapDecision && buttonRow.expanded
353  height: buttonRow.expanded ? implicitHeight : 0
354 
355  Repeater {
356  id: actionRepeater
357 
358  model: notification.actions
359  delegate: Loader {
360  id: loader
361 
362  property string actionId: id
363  property string actionLabel: label
364 
365  anchors {
366  left: parent.left
367  right: parent.right
368  }
369 
370  Component {
371  id: actionButton
372 
373  Button {
374  objectName: "button" + index
375  anchors {
376  left: parent.left
377  right: parent.right
378  }
379 
380  text: loader.actionLabel
381  height: units.gu(5)
382  gradient: UbuntuColors.greyGradient
383  onClicked: notification.notification.invokeAction(loader.actionId)
384  }
385  }
386  sourceComponent: (index == 0 || index == 1) ? undefined : actionButton
387  }
388  }
389  }
390  }
391  }
392 }