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