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