on 67dc769 help sign in
unity8/qml/Notifications/Notification.qml
430 lines 14 kB history raw
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 */
17import QtQuick 2.0
18import QtMultimedia 5.0
19import Ubuntu.Components 1.1
20import Unity.Notifications 1.0
21import QMenuModel 0.1
22import Utils 0.1
24import Ubuntu.Components.ListItems 0.1 as ListItem
26Item {
27 id: notification
29 property alias iconSource: icon.fileSource
30 property alias secondaryIconSource: secondaryIcon.source
31 property alias summary: summaryLabel.text
32 property alias body: bodyLabel.text
33 property var actions
34 property var notificationId
35 property var type
36 property var hints
37 property var notification
38 property color color
39 property bool fullscreen
40 property int maxHeight
41 property int margins
42 property Gradient greenGradient : Gradient {
43 GradientStop { position: 0.0; color: "#3fb24f" }
44 GradientStop { position: 1.0; color: "#3fb24f" }
45 }
46 property Gradient darkgreyGradient: Gradient {
47 GradientStop { position: 0.0; color: "#4d4745" }
48 GradientStop { position: 1.0; color: "#4d4745" }
49 }
51 fullscreen: false
52 objectName: "background"
53 implicitHeight: type !== Notification.PlaceHolder ? (fullscreen ? maxHeight : contentColumn.height + contentColumn.spacing * 2) : 0
55 color: Qt.rgba(0.132, 0.117, 0.109, 0.97)
56 opacity: 0
58 state: {
59 var result = "";
61 if (type == Notification.SnapDecision) {
62 if (ListView.view.currentIndex == index) {
63 result = "expanded";
64 } else {
65 if (ListView.view.count > 2) {
66 if (ListView.view.currentIndex == -1 && index == 1) {
67 result = "expanded";
68 } else {
69 result = "contracted";
70 }
71 } else {
72 result = "expanded";
73 }
74 }
75 }
77 return result;
78 }
80 Audio {
81 id: sound
82 objectName: "sound"
83 source: hints["suppress-sound"] != "" ? hints["sound-file"] : undefined
84 }
86 onOpacityChanged: {
87 if (opacity == 1.0 && hints["suppress-sound"] != "true" && sound.source) {
88 sound.play();
89 }
90 }
92 Behavior on height {
93 id: normalHeightBehavior
95 //enabled: menuItemFactory.progress == 1
96 enabled: true
97 SequentialAnimation {
98 PauseAnimation {
99 duration: UbuntuAnimation.SnapDuration
100 }
101 UbuntuNumberAnimation {
102 duration: UbuntuAnimation.SnapDuration
103 }
104 }
105 }
107 states:[
108 State {
109 name: "contracted"
110 PropertyChanges {target: notification; height: units.gu(8)}
111 },
112 State {
113 name: "expanded"
114 PropertyChanges {target: notification; height: implicitHeight}
115 }
116 ]
118 clip: fullscreen ? false : true
120 visible: type != Notification.PlaceHolder
122 UbuntuShape {
123 id: shapedBack
125 visible: !fullscreen
126 anchors {
127 fill: parent
128 leftMargin: notification.margins
129 rightMargin: notification.margins
130 }
131 color: parent.color
132 opacity: parent.opacity
133 radius: "medium"
134 }
136 Rectangle {
137 id: nonShapedBack
139 visible: fullscreen
140 anchors.fill: parent
141 color: parent.color
142 opacity: parent.opacity
143 }
145 Item {
146 id: contents
147 anchors.fill: fullscreen ? nonShapedBack : shapedBack
149 UnityMenuModelPaths {
150 id: paths
152 source: hints["x-canonical-private-menu-model"]
154 busNameHint: "busName"
155 actionsHint: "actions"
156 menuObjectPathHint: "menuPath"
157 }
159 UnityMenuModel {
160 id: unityMenuModel
162 busName: paths.busName
163 actions: paths.actions
164 menuObjectPath: paths.menuObjectPath
165 }
167 Behavior on implicitHeight {
168 id: heightBehavior
170 enabled: false
171 UbuntuNumberAnimation {
172 duration: UbuntuAnimation.SnapDuration
173 }
174 }
176 // delay enabling height behavior until the add transition is complete
177 onOpacityChanged: if (opacity == 1) heightBehavior.enabled = true
179 MouseArea {
180 id: interactiveArea
182 anchors.fill: parent
183 objectName: "interactiveArea"
184 onClicked: {
185 if (notification.type == Notification.Interactive) {
186 notification.notification.invokeAction(actionRepeater.itemAt(0).actionId)
187 } else {
188 notificationList.currentIndex = index;
189 }
190 }
191 }
193 Column {
194 id: contentColumn
195 objectName: "contentColumn"
197 anchors {
198 left: parent.left
199 right: parent.right
200 top: parent.top
201 margins: fullscreen ? 0 : spacing
202 }
204 spacing: units.gu(1)
206 Row {
207 id: topRow
209 spacing: contentColumn.spacing
210 anchors {
211 left: parent.left
212 right: parent.right
213 }
215 ShapedIcon {
216 id: icon
218 objectName: "icon"
219 width: units.gu(6)
220 height: units.gu(6)
221 shaped: notification.hints["x-canonical-non-shaped-icon"] == "true" ? false : true
222 visible: iconSource !== undefined && iconSource != ""
223 }
225 Image {
226 id: secondaryIcon
228 objectName: "secondaryIcon"
229 width: units.gu(2)
230 height: units.gu(2)
231 visible: source !== undefined && source != ""
232 fillMode: Image.PreserveAspectCrop
233 }
235 Column {
236 id: labelColumn
237 width: parent.width - x
239 anchors.verticalCenter: (icon.visible && !bodyLabel.visible) ? icon.verticalCenter : undefined
241 Label {
242 id: summaryLabel
244 objectName: "summaryLabel"
245 anchors {
246 left: parent.left
247 right: parent.right
248 }
249 fontSize: "medium"
250 font.bold: true
251 color: Theme.palette.selected.backgroundText
252 elide: Text.ElideRight
253 }
255 Label {
256 id: bodyLabel
258 objectName: "bodyLabel"
259 anchors {
260 left: parent.left
261 right: parent.right
262 }
263 visible: body != ""
264 fontSize: "small"
265 color: Theme.palette.selected.backgroundText
266 opacity: 0.6
267 wrapMode: Text.WordWrap
268 maximumLineCount: 10
269 elide: Text.ElideRight
270 }
271 }
272 }
274 Column {
275 objectName: "dialogListView"
276 spacing: units.gu(2)
278 visible: count > 0
280 anchors.left: parent.left; anchors.right: parent.right
281 anchors.top: fullscreen ? parent.top : undefined
282 anchors.bottom: fullscreen ? parent.bottom : undefined
284 Repeater {
285 model: unityMenuModel
287 NotificationMenuItemFactory {
288 id: menuItemFactory
290 anchors.left: parent.left; anchors.right: parent.right
292 menuModel: unityMenuModel
293 menuData: model
294 menuIndex: index
295 maxHeight: notification.maxHeight
297 onLoaded: {
298 notification.fullscreen = Qt.binding(function() { return fullscreen; });
299 }
300 }
301 }
302 }
304 Row {
305 id: buttonRow
307 objectName: "buttonRow"
308 anchors {
309 left: parent.left
310 right: parent.right
311 }
312 visible: notification.type == Notification.SnapDecision && actionRepeater.count > 0
313 spacing: units.gu(1)
314 layoutDirection: Qt.RightToLeft
316 Repeater {
317 id: actionRepeater
319 model: notification.actions
320 delegate: Loader {
321 id: loader
323 property string actionId: id
324 property string actionLabel: label
326 Component {
327 id: actionButton
329 Button {
330 objectName: "button" + index
331 width: buttonRow.width / 2 - spacing
332 text: loader.actionLabel
333 gradient: notification.hints["x-canonical-private-button-tint"] == "true" && index == 0 ? greenGradient : darkgreyGradient
334 onClicked: notification.notification.invokeAction(loader.actionId)
335 }
336 }
337 sourceComponent: (index == 0 || index == 1) ? actionButton : undefined
338 }
339 }
340 }
342 ComboButton {
343 id: comboButton
345 objectName: "button2"
346 width: parent.width
347 visible: notification.type == Notification.SnapDecision && actionRepeater.count > 3
348 gradient: darkgreyGradient
349 onClicked: notification.notification.invokeAction(comboRepeater.itemAt(2).actionId)
350 expanded: false
351 expandedHeight: (comboRepeater.count - 2) * units.gu(4) + units.gu(.5)
352 comboList: Flickable {
353 // this has to be wrapped inside a flickable
354 // to work around a feature/bug? of the
355 // ComboButton SDK-element, making a regular
356 // unwrapped Column item flickable
357 // see LP: #1332590
358 interactive: false
359 Column {
360 Repeater {
361 id: comboRepeater
363 onVisibleChanged: {
364 comboButton.text = comboRepeater.itemAt(2).actionLabel
365 }
367 model: notification.actions
368 delegate: Loader {
369 id: comboLoader
371 asynchronous: true
372 visible: status == Loader.Ready
373 property string actionId: id
374 property string actionLabel: label
375 readonly property var splitLabel: actionLabel.match(/(^([-a-z0-9]+):)?(.*)$/)
376 Component {
377 id: comboEntry
379 MouseArea {
380 id: comboInputArea
382 objectName: "button" + index
383 width: comboButton.width
384 height: comboIcon.height + units.gu(2)
386 onClicked: {
387 notification.notification.invokeAction(actionId)
388 }
390 ListItem.ThinDivider {
391 visible: index > 3
392 }
394 Icon {
395 id: comboIcon
397 anchors {
398 left: parent.left
399 leftMargin: units.gu(.5)
400 verticalCenter: parent.verticalCenter
401 }
402 width: units.gu(2)
403 height: units.gu(2)
404 color: "white"
405 name: splitLabel[2]
406 }
408 Label {
409 id: comboLabel
411 anchors {
412 left: comboIcon.right
413 leftMargin: units.gu(1)
414 verticalCenter: comboIcon.verticalCenter
415 }
416 fontSize: "small"
417 color: "white"
418 text: splitLabel[3]
419 }
420 }
421 }
422 sourceComponent: (index > 2) ? comboEntry : undefined
423 }
424 }
425 }
426 }
427 }
428 }
429 }