Unity 8
 All Classes Functions
Dash.qml
1 /*
2  * Copyright (C) 2013, 2014 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.2
18 import Ubuntu.Components 0.1
19 import Ubuntu.Gestures 0.1
20 import Unity 0.2
21 import Utils 0.1
22 import Unity.DashCommunicator 0.1
23 import "../Components"
24 
25 Showable {
26  id: dash
27  objectName: "dash"
28 
29  visible: shown
30 
31  property string showScopeOnLoaded: "clickscope"
32 
33  DashCommunicatorService {
34  objectName: "dashCommunicatorService"
35  onSetCurrentScopeRequested: {
36  if (!isSwipe || !window.active || overviewController.progress != 0) {
37  if (overviewController.progress != 0 && window.active) animate = false;
38  dash.setCurrentScope(scopeId, animate, isSwipe)
39  if (overviewController.progress != 0) {
40  if (window.active) {
41  dashContentCache.scheduleUpdate();
42  }
43  overviewController.enableAnimation = window.active && !scopesOverview.showingNonFavoriteScope;
44  overviewController.progress = 0;
45  scopesOverview.closeTempScope();
46  }
47  }
48  }
49  }
50 
51  function setCurrentScope(scopeId, animate, reset) {
52  var scopeIndex = -1;
53  for (var i = 0; i < scopes.count; ++i) {
54  if (scopes.getScope(i).id == scopeId) {
55  scopeIndex = i;
56  break;
57  }
58  }
59 
60  if (scopeIndex == -1) {
61  console.warn("No match for scope with id: %1".arg(scopeId))
62  return
63  }
64 
65  closeOverlayScope();
66 
67  dashContent.closePreview();
68 
69  if (scopeIndex == dashContent.currentIndex && !reset) {
70  // the scope is already the current one
71  return
72  }
73 
74  dashContent.setCurrentScopeAtIndex(scopeIndex, animate, reset)
75  }
76 
77  function closeOverlayScope() {
78  if (dashContent.x != 0) {
79  dashContent.x = 0;
80  }
81  }
82 
83  Scopes {
84  id: scopes
85  }
86 
87  QtObject {
88  id: overviewController
89  objectName: "overviewController"
90 
91  property alias enableAnimation: progressAnimation.enabled
92  property real progress: 0
93  Behavior on progress {
94  id: progressAnimation
95  UbuntuNumberAnimation { }
96  }
97  }
98 
99  ScopesOverview {
100  id: scopesOverview
101  objectName: "scopesOverview"
102  anchors.fill: parent
103  scope: scopes.overviewScope
104  progress: overviewController.progress
105  scopeScale: scopeItem.scope ? 0.4 : (1 - overviewController.progress * 0.6)
106  visible: scopeScale != 1
107  currentIndex: dashContent.currentIndex
108  onDone: {
109  if (currentTab == 1) {
110  animateDashFromAll(dashContent.currentScopeId);
111  }
112  hide();
113  }
114  onFavoriteSelected: {
115  setCurrentScope(scopeId, false, false);
116  dashContentCache.scheduleUpdate();
117  hide();
118  }
119  onAllFavoriteSelected: {
120  setCurrentScope(scopeId, false, false);
121  dashContentCache.scheduleUpdate();
122  animateDashFromAll(dashContent.currentScopeId);
123  hide();
124  }
125  onSearchSelected: {
126  var scopeIndex = -1;
127  for (var i = 0; i < scopes.count; ++i) {
128  if (scopes.getScope(i).id == scopeId) {
129  scopeIndex = i;
130  break;
131  }
132  }
133  if (scopeIndex >= 0) {
134  // Is a favorite one
135  setCurrentScope(scopeId, false, false);
136  dashContentCache.scheduleUpdate();
137  showDashFromPos(pos, size);
138  hide();
139  } else {
140  // Is not a favorite one, activate and get openScope
141  scope.activate(result);
142  }
143  }
144  function hide() {
145  overviewController.enableAnimation = true;
146  overviewController.progress = 0;
147  }
148  onProgressChanged: {
149  if (progress == 0) {
150  currentTab = scopeItem.scope ? 1 : 0;
151  }
152  }
153  }
154 
155  ShaderEffectSource {
156  id: dashContentCache
157  parent: scopesOverview.dashItemEater
158  z: 1
159  sourceItem: dashContent
160  height: sourceItem.height
161  width: sourceItem.width
162  opacity: 1 - overviewController.progress
163  visible: overviewController.progress != 0 && scopeItem.scope === null
164  live: false
165  }
166 
167  DashContent {
168  id: dashContent
169 
170  property var scopeThatOpenedScope: null
171 
172  objectName: "dashContent"
173  width: dash.width
174  height: dash.height
175  scopes: scopes
176  visible: !scopesOverview.showingNonFavoriteScope && x != -width
177  onGotoScope: {
178  dash.setCurrentScope(scopeId, true, false);
179  }
180  onOpenScope: {
181  scopeThatOpenedScope = currentScope;
182  scopeItem.scope = scope;
183  scopesOverview.currentTab = 1;
184  scopesOverview.ensureAllScopeVisible(scope.id);
185  x = -width;
186  }
187  onScopeLoaded: {
188  if (scopeId == dash.showScopeOnLoaded) {
189  dash.setCurrentScope(scopeId, false, false)
190  dash.showScopeOnLoaded = ""
191  }
192  }
193  clip: scale != 1.0 || scopeItem.visible || overviewController.progress != 0
194  Behavior on x {
195  UbuntuNumberAnimation {
196  duration: overviewController.progress != 0 ? 0 : UbuntuAnimation.FastDuration
197  onRunningChanged: {
198  if (!running && dashContent.x == 0) {
199  dashContent.scopeThatOpenedScope.closeScope(scopeItem.scope);
200  scopeItem.scope = null;
201  if (overviewController.progress == 0) {
202  // Set tab to Favorites only if we are not showing the overview
203  scopesOverview.currentTab = 0;
204  }
205  }
206  }
207  }
208  }
209 
210  // This is to avoid the situation where a bottom-edge swipe would bring up the dash overview
211  // (as expected) but would also cause the dash content flickable to move a bit, because
212  // that flickable was getting the touch events while overviewDragHandle was still undecided
213  // about whether that touch was indeed performing a directional drag gesture.
214  forceNonInteractive: overviewDragHandle.status != DirectionalDragArea.WaitingForTouch
215 
216  enabled: overviewController.progress == 0
217  opacity: enabled ? 1 : 0
218  }
219 
220  DashBackground
221  {
222  anchors.fill: scopeItem
223  visible: scopeItem.visible
224  parent: scopeItem.parent
225  scale: scopeItem.scale
226  opacity: scopeItem.opacity
227  }
228 
229  GenericScopeView {
230  id: scopeItem
231  objectName: "dashTempScopeItem"
232 
233  readonly property real targetOverviewScale: {
234  if (scopesOverview.currentTab == 0) {
235  return 0.4;
236  } else {
237  return scopesOverview.allCardSize.width / scopeItem.width;
238  }
239  }
240  readonly property real overviewProgressScale: (1 - overviewController.progress * (1 - targetOverviewScale))
241  readonly property var targetOverviewPosition: scope ? scopesOverview.allScopeCardPosition(scope.id) : null
242  readonly property real overviewProgressX: scope && scopesOverview.currentTab == 1 && targetOverviewPosition ?
243  overviewController.progress * (targetOverviewPosition.x - (width - scopesOverview.allCardSize.width) / 2)
244  : 0
245  readonly property real overviewProgressY: scope && scopesOverview.currentTab == 1 && targetOverviewPosition ?
246  overviewController.progress * (targetOverviewPosition.y - (height - scopesOverview.allCardSize.height) / 2)
247  : 0
248 
249  x: overviewController.progress == 0 ? dashContent.x + width : overviewProgressX
250  y: overviewController.progress == 0 ? dashContent.y : overviewProgressY
251  width: parent.width
252  height: parent.height
253  scale: overviewProgressScale
254  enabled: opacity == 1
255  opacity: 1 - overviewController.progress
256  clip: scale != 1.0
257  visible: scope != null
258  hasBackAction: true
259  isCurrent: visible
260  onBackClicked: {
261  closeOverlayScope();
262  closePreview();
263  }
264 
265  Connections {
266  target: scopeItem.scope
267  onGotoScope: {
268  dashContent.gotoScope(scopeId);
269  }
270  onOpenScope: {
271  dashContent.openScope(scope);
272  }
273  }
274  }
275 
276  Rectangle {
277  id: indicator
278  objectName: "processingIndicator"
279  anchors {
280  left: parent.left
281  right: parent.right
282  bottom: parent.bottom
283  bottomMargin: Qt.inputMethod.keyboardRectangle.height
284  }
285  height: units.dp(3)
286  color: scopeStyle.backgroundLuminance > 0.7 ? "#50000000" : "#50ffffff"
287  opacity: 0
288  visible: opacity > 0
289 
290  readonly property bool processing: dashContent.processing || scopeItem.processing || scopesOverview.processing
291 
292  Behavior on opacity {
293  UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
294  }
295 
296  onProcessingChanged: {
297  if (processing) delay.start();
298  else if (!persist.running) indicator.opacity = 0;
299  }
300 
301  Timer {
302  id: delay
303  interval: 200
304  onTriggered: if (indicator.processing) {
305  persist.restart();
306  indicator.opacity = 1;
307  }
308  }
309 
310  Timer {
311  id: persist
312  interval: 2 * UbuntuAnimation.SleepyDuration - UbuntuAnimation.FastDuration
313  onTriggered: if (!indicator.processing) indicator.opacity = 0
314  }
315 
316  Rectangle {
317  id: orange
318  anchors { top: parent.top; bottom: parent.bottom }
319  width: parent.width / 4
320  color: Theme.palette.selected.foreground
321 
322  SequentialAnimation {
323  running: indicator.visible
324  loops: Animation.Infinite
325  XAnimator {
326  from: -orange.width / 2
327  to: indicator.width - orange.width / 2
328  duration: UbuntuAnimation.SleepyDuration
329  easing.type: Easing.InOutSine
330  target: orange
331  }
332  XAnimator {
333  from: indicator.width - orange.width / 2
334  to: -orange.width / 2
335  duration: UbuntuAnimation.SleepyDuration
336  easing.type: Easing.InOutSine
337  target: orange
338  }
339  }
340  }
341  }
342 
343  Image {
344  source: "graphics/overview_hint.png"
345  anchors.horizontalCenter: parent.horizontalCenter
346  opacity: (scopeItem.scope ? scopeItem.pageHeaderTotallyVisible : dashContent.pageHeaderTotallyVisible) &&
347  (overviewDragHandle.enabled || overviewController.progress != 0) ? 1 : 0
348  Behavior on opacity {
349  enabled: overviewController.progress == 0
350  UbuntuNumberAnimation {}
351  }
352  y: parent.height - height * (1 - overviewController.progress * 4)
353  }
354 
355  EdgeDragArea {
356  id: overviewDragHandle
357  objectName: "overviewDragHandle"
358  z: 1
359  direction: Direction.Upwards
360  enabled: !dashContent.subPageShown &&
361  dashContent.currentScope &&
362  dashContent.currentScope.searchQuery == "" &&
363  !scopeItem.subPageShown &&
364  (overviewController.progress == 0 || dragging)
365 
366  readonly property real fullMovement: units.gu(20)
367 
368  anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
369  height: units.gu(2)
370 
371  onSceneDistanceChanged: {
372  if (status == DirectionalDragArea.Recognized && initialSceneDistance != -1) {
373  if (overviewController.enableAnimation) {
374  dashContentCache.scheduleUpdate();
375  }
376  overviewController.enableAnimation = false;
377  var deltaDistance = sceneDistance - initialSceneDistance;
378  overviewController.progress = Math.max(0, Math.min(1, deltaDistance / fullMovement));
379  }
380  }
381 
382  property int previousStatus: -1
383  property int currentStatus: DirectionalDragArea.WaitingForTouch
384  property real initialSceneDistance: -1
385 
386  onStatusChanged: {
387  previousStatus = currentStatus;
388  currentStatus = status;
389 
390  if (status == DirectionalDragArea.Recognized) {
391  initialSceneDistance = sceneDistance;
392  } else if (status == DirectionalDragArea.WaitingForTouch &&
393  previousStatus == DirectionalDragArea.Recognized) {
394  overviewController.enableAnimation = true;
395  overviewController.progress = (overviewController.progress > 0.7) ? 1 : 0;
396  initialSceneDistance = -1;
397  }
398  }
399  }
400 
401 }