Unity 8
SwipeToAct.qml
1 /*
2  * Copyright (C) 2014-2015 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.4
18 import Ubuntu.Components 1.3
19 
20 Item {
21  id: swipeToAct
22 
23  height: clickToAct ? leftButton.height : row.height
24 
25  signal leftTriggered()
26  signal rightTriggered()
27 
28  property string leftIconName
29  property string rightIconName
30 
31  property bool clickToAct
32 
33  QtObject {
34  id: priv
35 
36  property double opacityDelta
37  readonly property double sliderHeight: units.gu(8)
38  readonly property double gap: units.gu(1)
39  readonly property color sliderMainColor: theme.palette.normal.base
40  readonly property color sliderBGColor: theme.palette.normal.background
41  readonly property double halfWay: mouseArea.drag.maximumX / 2
42 
43  UbuntuNumberAnimation on opacityDelta {
44  from: 0
45  to: .5
46  loops: Animation.Infinite
47  duration: UbuntuAnimation.SleepyDuration
48  easing.type: Easing.Linear
49  }
50 
51  // linearly interpolate between start- and end-color
52  // with a normalized weight-factor
53  // 0.0 meaning just the start-color being taken into
54  // account and 1.0 only taking the end-color into
55  // account
56  function interpolate(start, end, factor) {
57  var rdiff = start.r > end.r ? end.r - start.r : end.r - start.r
58  var gdiff = start.g > end.g ? end.g - start.g : end.g - start.g
59  var bdiff = start.b > end.b ? end.b - start.b : end.b - start.b
60  var adiff = start.a > end.a ? end.a - start.a : end.a - start.a
61  var r = start.r + factor * rdiff
62  var g = start.g + factor * gdiff
63  var b = start.b + factor * bdiff
64  var a = start.a + factor * adiff
65  return Qt.rgba(r,g,b,a)
66  }
67  }
68 
69  NotificationButton {
70  id: leftButton
71  objectName: "leftButton"
72  anchors.verticalCenter: parent.verticalCenter
73  anchors.left: parent.left
74  iconName: leftIconName
75  visible: clickToAct
76  outline: false
77  width: (parent.width / 2) - priv.gap / 2
78  color: theme.palette.normal.negative
79  onClicked: leftTriggered()
80  }
81 
82  NotificationButton {
83  id: rightButton
84  objectName: "rightButton"
85  anchors.verticalCenter: parent.verticalCenter
86  anchors.right: parent.right
87  iconName: rightIconName
88  visible: clickToAct
89  outline: false
90  width: (parent.width / 2) - priv.gap / 2
91  color: theme.palette.normal.positive
92  onClicked: rightTriggered()
93  }
94 
95  UbuntuShape {
96  id: row
97  width: parent.width
98  height: priv.sliderHeight
99  backgroundColor: priv.sliderBGColor
100  aspect: UbuntuShape.Flat
101  visible: !clickToAct
102 
103  UbuntuShape {
104  id: leftShape
105  objectName: "leftArea"
106  anchors.top: parent.top
107  anchors.left: parent.left
108  anchors.margins: priv.gap
109  backgroundColor: theme.palette.normal.negative
110  aspect: UbuntuShape.Flat
111 
112  height: units.gu(6)
113  width: units.gu(6)
114  radius: "medium"
115  opacity: slider.x <= priv.halfWay ? 1.0 : 1.0 - ((slider.x - priv.halfWay) / priv.halfWay)
116 
117  Icon {
118  anchors.centerIn: parent
119  width: units.gu(3.5)
120  height: units.gu(3.5)
121  name: leftIconName
122  color: "white"
123  }
124  }
125 
126  Row {
127  anchors.verticalCenter: parent.verticalCenter
128  anchors.right: slider.left
129  anchors.rightMargin: units.gu(1.5)
130  spacing: -units.gu(1)
131  visible: slider.x === priv.halfWay
132  Icon {
133  name: "back"
134  height: units.gu(2.5)
135  color: priv.sliderMainColor
136  opacity: .5 + priv.opacityDelta
137  }
138  Icon {
139  name: "back"
140  height: units.gu(2.5)
141  color: priv.sliderMainColor
142  opacity: 1 - priv.opacityDelta
143  }
144  }
145 
146  UbuntuShape {
147  id: slider
148  objectName: "slider"
149  anchors.top: parent.top
150  anchors.margins: priv.gap
151  x: priv.halfWay
152 
153  Component.onCompleted: {
154  xBehavior.enabled = true
155  }
156 
157  Behavior on x {
158  id: xBehavior
159  enabled: false
160  UbuntuNumberAnimation {
161  duration: UbuntuAnimation.FastDuration
162  easing.type: Easing.OutBounce
163  }
164  }
165 
166  Behavior on opacity {
167  UbuntuNumberAnimation {
168  duration: UbuntuAnimation.FastDuration
169  }
170  }
171 
172  onXChanged: {
173  var factor
174  if (slider.x <= priv.gap + leftShape.width)
175  {
176  factor = (slider.x - priv.gap) / leftShape.width
177  slider.color = priv.interpolate(leftShape.color, priv.sliderMainColor, factor)
178  } else if (slider.x >= rightShape.x - slider.width) {
179  factor = (slider.x - rightShape.x + rightShape.width) / rightShape.width
180  slider.color = priv.interpolate(priv.sliderMainColor, rightShape.color, factor)
181  } else {
182  slider.color = priv.sliderMainColor
183  }
184  }
185 
186  z: 1
187  backgroundColor: priv.sliderMainColor
188  height: units.gu(6)
189  width: units.gu(6)
190  aspect: UbuntuShape.Flat
191  radius: "medium"
192  Icon {
193  anchors.fill: parent
194  anchors.margins: units.gu(1.5)
195  name: "grip-large"
196  color: "white"
197  }
198  }
199 
200  Row {
201  anchors.verticalCenter: parent.verticalCenter
202  anchors.left: slider.right
203  anchors.leftMargin: units.gu(1.5)
204  spacing: -units.gu(1)
205  visible: slider.x === priv.halfWay
206  Icon {
207  name: "next"
208  height: units.gu(2.5)
209  color: priv.sliderMainColor
210  opacity: 1 - priv.opacityDelta
211  }
212  Icon {
213  name: "next"
214  height: units.gu(2.5)
215  color: priv.sliderMainColor
216  opacity: 0.5 + priv.opacityDelta
217  }
218  }
219 
220  UbuntuShape {
221  id: rightShape
222  objectName: "rightArea"
223  anchors.top: parent.top
224  anchors.right: parent.right
225  anchors.margins: priv.gap
226  backgroundColor: theme.palette.normal.positive
227  aspect: UbuntuShape.Flat
228 
229  height: units.gu(6)
230  width: units.gu(6)
231  radius: "medium"
232  opacity: slider.x >= priv.halfWay ? 1.0 : slider.x / priv.halfWay
233 
234  Icon {
235  anchors.centerIn: parent
236  width: units.gu(3.5)
237  height: units.gu(3.5)
238  name: rightIconName
239  color: "white"
240  }
241  }
242  }
243 
244  MouseArea {
245  id: mouseArea
246  objectName: "swipeMouseArea"
247  enabled: !clickToAct
248 
249  anchors.fill: row
250  drag.target: slider
251  drag.axis: Drag.XAxis
252  drag.minimumX: priv.gap
253  drag.maximumX: row.width - slider.width - priv.gap
254 
255  onReleased: {
256  if (slider.x !== drag.minimumX || slider.x !== drag.maximumX) {
257  slider.x = priv.halfWay
258  }
259  if (slider.x === drag.minimumX) {
260  slider.x = drag.minimumX
261  enabled = false
262  leftTriggered()
263  }
264  if (slider.x === drag.maximumX) {
265  slider.x = drag.maximumX
266  enabled = false
267  rightTriggered()
268  }
269  }
270  }
271 }