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 : childrenRect.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: "#b2b2b2"
40  readonly property color sliderBGColor: "#f4f4f4"
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  Button {
70  id: leftButton
71  objectName: "leftButton"
72  anchors.verticalCenter: parent.verticalCenter
73  anchors.left: parent.left
74  iconName: leftIconName
75  visible: clickToAct
76  width: (parent.width / 2) - priv.gap
77  color: UbuntuColors.red
78  onClicked: {
79  leftTriggered()
80  }
81  }
82 
83  Button {
84  id: rightButton
85  objectName: "rightButton"
86  anchors.verticalCenter: parent.verticalCenter
87  anchors.right: parent.right
88  iconName: rightIconName
89  visible: clickToAct
90  width: (parent.width / 2) - priv.gap
91  color: UbuntuColors.green
92  onClicked: {
93  rightTriggered()
94  }
95  }
96 
97  UbuntuShape {
98  id: row
99  width: parent.width
100  height: priv.sliderHeight
101  backgroundColor: priv.sliderBGColor
102  aspect: UbuntuShape.Flat
103  visible: !clickToAct
104 
105  UbuntuShape {
106  id: leftShape
107  objectName: "leftArea"
108  anchors.top: parent.top
109  anchors.left: parent.left
110  anchors.margins: priv.gap
111  backgroundColor: UbuntuColors.red
112  aspect: UbuntuShape.Flat
113 
114  state: "normal"
115  height: units.gu(6)
116  width: units.gu(6)
117  radius: "medium"
118  opacity: slider.x <= priv.halfWay ? 1.0 : 1.0 - ((slider.x - priv.halfWay) / priv.halfWay)
119 
120  Icon {
121  anchors.centerIn: parent
122  width: units.gu(3.5)
123  height: units.gu(3.5)
124  name: leftIconName
125  color: "white"
126  }
127  }
128 
129  Row {
130  anchors.verticalCenter: parent.verticalCenter
131  anchors.right: slider.left
132  anchors.rightMargin: units.gu(1.5)
133  spacing: -units.gu(1)
134  visible: slider.x === priv.halfWay
135  Icon {
136  name: "back"
137  height: units.gu(2.5)
138  color: priv.sliderMainColor
139  opacity: .5 + priv.opacityDelta
140  }
141  Icon {
142  name: "back"
143  height: units.gu(2.5)
144  color: priv.sliderMainColor
145  opacity: 1 - priv.opacityDelta
146  }
147  }
148 
149  UbuntuShape {
150  id: slider
151  objectName: "slider"
152  anchors.top: parent.top
153  anchors.margins: priv.gap
154  x: priv.halfWay
155 
156  Component.onCompleted: {
157  xBehavior.enabled = true
158  }
159 
160  Behavior on x {
161  id: xBehavior
162  enabled: false
163  UbuntuNumberAnimation {
164  duration: UbuntuAnimation.FastDuration
165  easing.type: Easing.OutBounce
166  }
167  }
168 
169  Behavior on opacity {
170  UbuntuNumberAnimation {
171  duration: UbuntuAnimation.FastDuration
172  }
173  }
174 
175  onXChanged: {
176  var factor
177  if (slider.x <= priv.gap + leftShape.width)
178  {
179  factor = (slider.x - priv.gap) / leftShape.width
180  slider.color = priv.interpolate(leftShape.color, priv.sliderMainColor, factor)
181  } else if (slider.x >= rightShape.x - slider.width) {
182  factor = (slider.x - rightShape.x + rightShape.width) / rightShape.width
183  slider.color = priv.interpolate(priv.sliderMainColor, rightShape.color, factor)
184  } else {
185  slider.color = priv.sliderMainColor
186  }
187  }
188 
189  z: 1
190  backgroundColor: priv.sliderMainColor
191  height: units.gu(6)
192  width: units.gu(6)
193  aspect: UbuntuShape.Flat
194  radius: "medium"
195  Icon {
196  anchors.fill: parent
197  anchors.margins: units.gu(1.5)
198  source: "grip-large.svg"
199  color: "white"
200  }
201  }
202 
203  Row {
204  anchors.verticalCenter: parent.verticalCenter
205  anchors.left: slider.right
206  anchors.leftMargin: units.gu(1.5)
207  spacing: -units.gu(1)
208  visible: slider.x === priv.halfWay
209  Icon {
210  name: "next"
211  height: units.gu(2.5)
212  color: priv.sliderMainColor
213  opacity: 1 - priv.opacityDelta
214  }
215  Icon {
216  name: "next"
217  height: units.gu(2.5)
218  color: priv.sliderMainColor
219  opacity: 0.5 + priv.opacityDelta
220  }
221  }
222 
223  UbuntuShape {
224  id: rightShape
225  objectName: "rightArea"
226  anchors.top: parent.top
227  anchors.right: parent.right
228  anchors.margins: priv.gap
229  backgroundColor: UbuntuColors.green
230  aspect: UbuntuShape.Flat
231 
232  state: "normal"
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 }