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  // Used by the tests to determine when the slider is ready to move
154  readonly property bool atRest: ((x === priv.halfWay) && (!mouseArea.dragging) && (!sliderXAnimation.running))
155 
156  Component.onCompleted: {
157  xBehavior.enabled = true
158  }
159 
160  Behavior on x {
161  id: xBehavior
162  enabled: false
163  UbuntuNumberAnimation {
164  id: sliderXAnimation
165  duration: UbuntuAnimation.FastDuration
166  easing.type: Easing.OutBounce
167  }
168  }
169 
170  Behavior on opacity {
171  UbuntuNumberAnimation {
172  duration: UbuntuAnimation.FastDuration
173  }
174  }
175 
176  onXChanged: {
177  var factor
178  if (slider.x <= priv.gap + leftShape.width)
179  {
180  factor = (slider.x - priv.gap) / leftShape.width
181  slider.color = priv.interpolate(leftShape.color, priv.sliderMainColor, factor)
182  } else if (slider.x >= rightShape.x - slider.width) {
183  factor = (slider.x - rightShape.x + rightShape.width) / rightShape.width
184  slider.color = priv.interpolate(priv.sliderMainColor, rightShape.color, factor)
185  } else {
186  slider.color = priv.sliderMainColor
187  }
188  }
189 
190  z: 1
191  backgroundColor: priv.sliderMainColor
192  height: units.gu(6)
193  width: units.gu(6)
194  aspect: UbuntuShape.Flat
195  radius: "medium"
196  Icon {
197  anchors.fill: parent
198  anchors.margins: units.gu(1.5)
199  name: "grip-large"
200  color: "white"
201  }
202  }
203 
204  Row {
205  anchors.verticalCenter: parent.verticalCenter
206  anchors.left: slider.right
207  anchors.leftMargin: units.gu(1.5)
208  spacing: -units.gu(1)
209  visible: slider.x === priv.halfWay
210  Icon {
211  name: "next"
212  height: units.gu(2.5)
213  color: priv.sliderMainColor
214  opacity: 1 - priv.opacityDelta
215  }
216  Icon {
217  name: "next"
218  height: units.gu(2.5)
219  color: priv.sliderMainColor
220  opacity: 0.5 + priv.opacityDelta
221  }
222  }
223 
224  UbuntuShape {
225  id: rightShape
226  objectName: "rightArea"
227  anchors.top: parent.top
228  anchors.right: parent.right
229  anchors.margins: priv.gap
230  backgroundColor: theme.palette.normal.positive
231  aspect: UbuntuShape.Flat
232 
233  height: units.gu(6)
234  width: units.gu(6)
235  radius: "medium"
236  opacity: slider.x >= priv.halfWay ? 1.0 : slider.x / priv.halfWay
237 
238  Icon {
239  anchors.centerIn: parent
240  width: units.gu(3.5)
241  height: units.gu(3.5)
242  name: rightIconName
243  color: "white"
244  }
245  }
246  }
247 
248  MouseArea {
249  id: mouseArea
250  objectName: "swipeMouseArea"
251  enabled: !clickToAct
252 
253  anchors.fill: row
254  drag.target: slider
255  drag.axis: Drag.XAxis
256  drag.minimumX: priv.gap
257  drag.maximumX: row.width - slider.width - priv.gap
258 
259  onReleased: {
260  if (slider.x !== drag.minimumX || slider.x !== drag.maximumX) {
261  slider.x = priv.halfWay
262  }
263  if (slider.x === drag.minimumX) {
264  slider.x = drag.minimumX
265  enabled = false
266  leftTriggered()
267  }
268  if (slider.x === drag.maximumX) {
269  slider.x = drag.maximumX
270  enabled = false
271  rightTriggered()
272  }
273  }
274  }
275 }