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