Unity 8
 All Classes Functions
DashContent.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.0
18 import Ubuntu.Components 0.1
19 import Unity 0.2
20 import Utils 0.1
21 import "../Components"
22 
23 Item {
24  id: dashContent
25 
26  property alias scopes: dashContentList.model
27  readonly property alias currentIndex: dashContentList.currentIndex
28  readonly property string currentScopeId: dashContentList.currentItem ? dashContentList.currentItem.scopeId : ""
29  readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
30  readonly property bool subPageShown: dashContentList.currentItem && dashContentList.currentItem.item ?
31  dashContentList.currentItem.item.subPageShown : false
32  readonly property bool processing: dashContentList.currentItem && dashContentList.currentItem.item
33  && dashContentList.currentItem.item.processing || false
34  readonly property bool pageHeaderTotallyVisible: dashContentList.currentItem && dashContentList.currentItem.item
35  && dashContentList.currentItem.item.pageHeaderTotallyVisible || false
36 
37  signal scopeLoaded(string scopeId)
38  signal gotoScope(string scopeId)
39  signal openScope(var scope)
40  signal closePreview()
41 
42  // If we set the current scope index before the scopes have been added,
43  // then we need to wait until the loaded signals gets emitted from the scopes
44  property var set_current_index: undefined
45  Connections {
46  target: scopes
47  onLoadedChanged: {
48  if (scopes.loaded && set_current_index != undefined) {
49  setCurrentScopeAtIndex(set_current_index[0], set_current_index[1], set_current_index[2]);
50  set_current_index = undefined;
51  }
52  }
53  }
54 
55  Connections {
56  target: UriHandler
57  onOpened: dashContentList.currentItem.theScope.performQuery(uris[0])
58  }
59 
60  function setCurrentScopeAtIndex(index, animate, reset) {
61  // if the scopes haven't loaded yet, then wait until they are.
62  if (!scopes.loaded) {
63  set_current_index = [ index, animate, reset ]
64  return;
65  }
66 
67  var storedMoveDuration = dashContentList.highlightMoveDuration
68  var storedMoveSpeed = dashContentList.highlightMoveVelocity
69  if (!animate) {
70  dashContentList.highlightMoveVelocity = units.gu(4167)
71  dashContentList.highlightMoveDuration = 0
72  }
73 
74  set_current_index = undefined;
75 
76  if (dashContentList.count > index)
77  {
78  dashContentList.currentIndex = index
79 
80  if (reset) {
81  dashContentList.currentItem.item.positionAtBeginning()
82  }
83  }
84 
85  if (!animate) {
86  dashContentList.highlightMoveDuration = storedMoveDuration
87  dashContentList.highlightMoveVelocity = storedMoveSpeed
88  }
89  }
90 
91  Item {
92  id: dashContentListHolder
93 
94  anchors.fill: parent
95 
96  DashBackground {
97  anchors.fill: parent
98  }
99 
100  ListView {
101  id: dashContentList
102  objectName: "dashContentList"
103 
104  interactive: dashContent.scopes.loaded && currentItem && !currentItem.moving && !currentItem.navigationShown && !currentItem.subPageShown
105  anchors.fill: parent
106  orientation: ListView.Horizontal
107  boundsBehavior: Flickable.DragAndOvershootBounds
108  flickDeceleration: units.gu(625)
109  maximumFlickVelocity: width * 5
110  snapMode: ListView.SnapOneItem
111  highlightMoveDuration: 250
112  highlightRangeMode: ListView.StrictlyEnforceRange
113  // TODO Investigate if we can switch to a smaller cache buffer when/if UbuntuShape gets more performant
114  // 1073741823 is s^30 -1. A quite big number so that you have "infinite" cache, but not so
115  // big so that if you add if with itself you're outside the 2^31 int range
116  cacheBuffer: 1073741823
117  onMovementStarted: currentItem.item.showHeader();
118  clip: parent.x != 0
119 
120  // TODO QTBUG-40846 and QTBUG-40848
121  // The remove transition doesn't happen when removing the last item
122  // And can't work around it because index is reset to -1 regardless of
123  // ListView.delayRemove
124 
125  remove: Transition {
126  SequentialAnimation {
127  PropertyAction { property: "layer.enabled"; value: true }
128  PropertyAction { property: "ListView.delayRemove"; value: true }
129  ParallelAnimation {
130  PropertyAnimation { properties: "scale"; to: 0.25; duration: UbuntuAnimation.SnapDuration }
131  PropertyAnimation { properties: "y"; to: dashContent.height; duration: UbuntuAnimation.SnapDuration }
132  }
133  PropertyAction { property: "ListView.delayRemove"; value: false }
134  }
135  }
136  removeDisplaced: Transition {
137  PropertyAnimation { property: "x"; duration: UbuntuAnimation.SnapDecision }
138  }
139 
140  // If the number of items is less than the current index, then need to reset to another item.
141  onCountChanged: {
142  if (count > 0) {
143  if (currentIndex >= count) {
144  dashContent.setCurrentScopeAtIndex(count-1, true, true)
145  } else if (currentIndex < 0) {
146  // setting currentIndex directly, cause we don't want to loose set_current_index
147  dashContentList.currentIndex = 0
148  }
149  }
150  }
151 
152  delegate:
153  Loader {
154  width: ListView.view.width
155  height: ListView.view.height
156  opacity: { // hide delegate if offscreen
157  var xPositionRelativetoView = ListView.view.contentX - x
158  return (xPositionRelativetoView > -width && xPositionRelativetoView < width) ? 1 : 0
159  }
160  asynchronous: true
161  source: "GenericScopeView.qml"
162  objectName: scope.id + " loader"
163 
164  readonly property bool moving: item ? item.moving : false
165  readonly property bool navigationShown: item ? item.navigationShown : false
166  readonly property bool subPageShown: item ? item.subPageShown : false
167  readonly property var categoryView: item ? item.categoryView : null
168  readonly property var theScope: scope
169 
170  // these are needed for autopilot tests
171  readonly property string scopeId: scope.id
172  readonly property bool isCurrent: ListView.isCurrentItem
173  readonly property bool isLoaded: status == Loader.Ready
174 
175  onLoaded: {
176  item.objectName = scope.id
177  item.scope = Qt.binding(function() { return scope })
178  item.isCurrent = Qt.binding(function() { return visible && ListView.isCurrentItem })
179  dashContent.scopeLoaded(item.scope.id)
180  item.paginationCount = Qt.binding(function() { return dashContentList.count } )
181  item.paginationIndex = Qt.binding(function() { return dashContentList.currentIndex } )
182  item.holdingList = dashContentList;
183  }
184  Connections {
185  target: isCurrent ? scope : null
186  onGotoScope: {
187  // Note here scopeId is the signal parameter and not the loader property
188  dashContent.gotoScope(scopeId);
189  }
190  onOpenScope: {
191  dashContent.openScope(scope);
192  }
193  }
194  Connections {
195  target: dashContent
196  onClosePreview: if (item) item.closePreview()
197  }
198 
199  Component.onDestruction: active = false
200  }
201  }
202  }
203 }