2 * Copyright (C) 2014 Canonical, Ltd.
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.
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.
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/>.
19 import Ubuntu.Components 0.1
20 import "../Components"
25 // Properties set by parent
26 property real progress: 0
27 property var scope: null
28 property int currentIndex: 0
29 property real scopeScale: 1
31 // Properties set and used by parent
32 property alias currentTab: tabBar.currentTab
34 // Properties used by parent
35 readonly property bool processing: searchResultsViewer.processing || tempScopeItem.processing || previewListView.processing
36 property bool growingDashFromPos: false
37 readonly property bool searching: scope && scope.searchQuery == ""
38 readonly property bool showingNonFavoriteScope: tempScopeItem.scope != null
39 readonly property var dashItemEater: {
40 if (!forceXYScalerEater && tabBar.currentTab == 0 && middleItems.count > 0) {
41 var loaderItem = middleItems.itemAt(0).item;
42 return loaderItem && loaderItem.currentItem ? loaderItem.currentItem : null;
44 return scopesOverviewXYScaler;
46 readonly property size allCardSize: {
47 if (middleItems.count > 1) {
48 var loaderItem = middleItems.itemAt(1).item;
50 var cardTool = loaderItem.cardTool;
51 return Qt.size(cardTool.cardWidth, cardTool.cardHeight);
57 // Internal properties
58 property bool forceXYScalerEater: false
61 signal favoriteSelected(var scopeId)
62 signal allFavoriteSelected(var scopeId)
63 signal searchSelected(var scopeId, var result, var pos, var size)
68 var itemPos = scopesOverviewXYScaler.restorePosition;
69 var itemSize = scopesOverviewXYScaler.restoreSize;
70 scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
72 scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
73 scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
75 scopesOverviewXYScaler.x = 0;
76 scopesOverviewXYScaler.y = 0;
78 scopesOverviewXYScaler.opacity = 0;
79 tempScopeItem.scope = scope;
80 middleItems.overrideOpacity = 0;
81 scopesOverviewXYScaler.scale = 1;
82 scopesOverviewXYScaler.x = 0;
83 scopesOverviewXYScaler.y = 0;
84 scopesOverviewXYScaler.opacity = 1;
87 if (tabBar.currentTab == 0) {
88 root.favoriteSelected(scopeId);
90 root.allFavoriteSelected(scopeId);
101 function animateDashFromAll(scopeId) {
102 var currentScopePos = allScopeCardPosition(scopeId);
103 if (currentScopePos) {
104 showDashFromPos(currentScopePos, allCardSize);
106 console.log("Warning: Could not find Dash OverView All card position for scope", dashContent.currentScopeId);
110 function showDashFromPos(itemPos, itemSize) {
111 scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
112 scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
113 scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
114 scopesOverviewXYScaler.opacity = 0;
115 root.growingDashFromPos = true;
116 scopesOverviewXYScaler.scale = 1;
117 scopesOverviewXYScaler.x = 0;
118 scopesOverviewXYScaler.y = 0;
119 scopesOverviewXYScaler.opacity = 1;
122 function allScopeCardPosition(scopeId) {
123 if (middleItems.count > 1) {
124 var loaderItem = middleItems.itemAt(1).item;
126 var pos = loaderItem.scopeCardPosition(scopeId);
127 return loaderItem.mapToItem(null, pos.x, pos.y);
132 function ensureAllScopeVisible(scopeId) {
133 if (middleItems.count > 1) {
134 var loaderItem = middleItems.itemAt(1).item;
136 var pos = loaderItem.scopeCardPosition(scopeId);
137 loaderItem.contentY = Math.min(pos.y, loaderItem.contentHeight - loaderItem.height);
144 pageHeader.resetSearch();
145 pageHeader.unfocus(); // Shouldn't the previous call do this too?
150 id: overviewScopeStyle
151 style: { "foreground-color" : "white",
152 "background-color" : "transparent",
154 "background": "color:///transparent"
161 source: "graphics/dark_background.jpg"
166 onSearchQueryChanged: {
167 // Need this in order, otherwise something gets unhappy in rendering
168 // of the overlay in carousels because the parent of the dash dies for
169 // a moment, this way we make sure it's reparented first
170 // by forceXYScalerEater making dashItemEater return scopesOverviewXYScaler
171 // before we kill the previous parent by scope.searchQuery
172 root.forceXYScalerEater = true;
173 root.scope.searchQuery = pageHeader.searchQuery;
174 root.forceXYScalerEater = false;
180 property: "searchQuery"
181 value: scope ? scope.searchQuery : ""
185 id: scopesOverviewContent
186 x: previewListView.open ? -width : 0
187 Behavior on x { UbuntuNumberAnimation { } }
189 height: parent.height
193 objectName: "scopesOverviewPageHeader"
195 readonly property real yDisplacement: pageHeader.height + tabBar.height + tabBar.anchors.margins
198 if (root.progress < 0.5) {
199 return -yDisplacement;
201 return -yDisplacement + (root.progress - 0.5) * yDisplacement * 2;
206 title: i18n.tr("Manage Dash")
207 scopeStyle: overviewScopeStyle
208 showSignatureLine: false
209 searchEntryEnabled: true
217 top: pageHeader.bottom
222 enabled: opacity == 1
223 opacity: !scope || scope.searchQuery == "" ? 1 : 0
224 Behavior on opacity { UbuntuNumberAnimation { } }
229 objectName: "scopesOverviewRepeater"
230 property real overrideOpacity: -1
231 model: scope && scope.searchQuery == "" ? scope.categories : null
234 objectName: "scopesOverviewRepeaterChild" + index
240 return root.height - pageHeader.height - tabBar.height - tabBar.anchors.margins - units.gu(2);
245 return root.width / scopeScale;
252 return (root.width - width) / 2;
258 bottom: scopesOverviewContent.bottom
261 scale: index == 0 ? scopeScale : 1
264 if (middleItems.overrideOpacity >= 0)
265 return middleItems.overrideOpacity;
267 if (tabBar.currentTab != index)
270 return index == 0 ? 1 : root.progress;
272 Behavior on opacity {
273 enabled: root.progress == 1
274 UbuntuNumberAnimation { }
276 enabled: opacity == 1
282 objectName: "cardTool"
284 template: model.renderer
285 components: model.components
286 viewWidth: parent.width
290 if (index == 0 && categoryId == "favorites") return "ScopesOverviewFavorites.qml";
291 else if (index == 1 && categoryId == "all") return "ScopesOverviewAll.qml";
296 item.model = Qt.binding(function() { return results; });
297 item.cardTool = cardTool;
299 item.scopeWidth = Qt.binding(function() { return root.width; });
300 item.scopeHeight = Qt.binding(function() { return root.height; });
301 item.appliedScale = Qt.binding(function() { return loader.scale });
302 item.currentIndex = Qt.binding(function() { return root.currentIndex });
303 } else if (index == 1) {
304 item.extraHeight = bottomBar.height;
311 pageHeader.unfocus();
312 if (tabBar.currentTab == 0) {
313 root.favoriteSelected(itemModel.scopeId);
315 var favoriteScopesItem = middleItems.itemAt(0).item;
316 var scopeIndex = favoriteScopesItem.model.scopeIndex(itemModel.scopeId);
317 if (scopeIndex >= 0) {
318 root.allFavoriteSelected(itemModel.scopeId);
320 // Will result in an openScope from root.scope
321 scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
322 scopesOverviewXYScaler.restoreSize = allCardSize;
323 root.scope.activate(result);
328 // Preview can call openScope so make sure restorePosition and restoreSize are set
329 scopesOverviewXYScaler.restorePosition = undefined;
330 scopesOverviewXYScaler.restoreSize = allCardSize;
332 previewListView.model = target.model;
333 previewListView.currentIndex = -1;
334 previewListView.currentIndex = index;
335 previewListView.open = true;
342 id: searchResultsViewer
343 objectName: "searchResultsViewer"
345 top: pageHeader.bottom
348 bottom: parent.bottom
350 scope: root.scope && root.scope.searchQuery != "" ? root.scope : null
351 scopeStyle: overviewScopeStyle
352 enabled: opacity == 1
353 showPageHeader: false
355 opacity: searchResultsViewer.scope ? 1 : 0
357 Behavior on opacity { UbuntuNumberAnimation { } }
359 function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount) {
360 pageHeader.unfocus();
361 pageHeader.closePopup();
362 if (itemModel.scopeId) {
363 // This can end up in openScope so save restorePosition and restoreSize
364 scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
365 scopesOverviewXYScaler.restoreSize = Qt.size(item.width, item.height);
366 root.searchSelected(itemModel.scopeId, result, item.mapToItem(null, 0, 0), Qt.size(item.width, item.height));
368 // Not a scope, just activate it
369 searchResultsViewer.scope.activate(result);
373 function itemPressedAndHeld(index, itemModel, resultsModel, limitedCategoryItemCount) {
374 if (itemModel.uri.indexOf("scope://") === 0) {
375 // Preview can call openScope so make sure restorePosition and restoreSize are set
376 scopesOverviewXYScaler.restorePosition = undefined;
377 scopesOverviewXYScaler.restoreSize = allCardSize;
379 previewListView.model = resultsModel;
380 previewListView.currentIndex = -1;
381 previewListView.currentIndex = index;
382 previewListView.open = true;
389 objectName: "bottomBar"
393 enabled: opacity == 1
394 opacity: scope && scope.searchQuery == "" ? 1 : 0
395 Behavior on opacity { UbuntuNumberAnimation { } }
397 if (root.progress < 0.5) {
398 return parent.height;
400 return parent.height - (root.progress - 0.5) * height * 2;
405 // Just eat any other press since this parent is black opaque
410 objectName: "scopesOverviewDoneButton"
411 width: Math.max(label.width + units.gu(2), units.gu(10))
415 leftMargin: units.gu(2)
416 verticalCenter: parent.verticalCenter
420 border.color: "white"
421 border.width: units.dp(1)
423 color: parent.pressed ? Theme.palette.normal.baseText : "transparent"
427 anchors.centerIn: parent
428 text: i18n.tr("Done")
429 color: parent.pressed ? "black" : "white"
431 onClicked: root.done();
435 objectName: "scopesOverviewStoreButton"
436 width: Math.max(storeLabel.width, units.gu(10))
440 verticalCenter: parent.verticalCenter
444 name: "ubuntu-store-symbolic"
446 anchors.horizontalCenter: parent.horizontalCenter
452 anchors.horizontalCenter: parent.horizontalCenter
453 anchors.top: storeImage.bottom
454 text: i18n.tr("Store")
458 // Just zoom from the middle
459 scopesOverviewXYScaler.restorePosition = undefined;
460 scopesOverviewXYScaler.restoreSize = allCardSize;
461 scope.performQuery("scope://com.canonical.scopes.clickstore");
469 objectName: "scopesOverviewPreviewListView"
471 scopeStyle: overviewScopeStyle
472 showSignatureLine: false
475 height: parent.height
476 anchors.left: scopesOverviewContent.right
478 onBackClicked: open = false
482 id: scopesOverviewXYScaler
484 height: parent.height
489 property bool animationsEnabled: root.showingNonFavoriteScope || root.growingDashFromPos
491 property var restorePosition
492 property var restoreSize
495 enabled: scopesOverviewXYScaler.animationsEnabled
496 UbuntuNumberAnimation { }
499 enabled: scopesOverviewXYScaler.animationsEnabled
500 UbuntuNumberAnimation { }
502 Behavior on opacity {
503 enabled: scopesOverviewXYScaler.animationsEnabled
504 UbuntuNumberAnimation { }
507 enabled: scopesOverviewXYScaler.animationsEnabled
508 UbuntuNumberAnimation {
511 if (root.showingNonFavoriteScope && scopesOverviewXYScaler.scale != 1) {
512 root.scope.closeScope(tempScopeItem.scope);
513 tempScopeItem.scope = null;
514 } else if (root.growingDashFromPos) {
515 root.growingDashFromPos = false;
523 anchors.fill: tempScopeItem
524 visible: tempScopeItem.visible
525 parent: tempScopeItem.parent
530 objectName: "scopesOverviewTempScopeItem"
533 height: parent.height
534 scale: dash.contentScale
536 visible: scope != null
540 var v = scopesOverviewXYScaler.restoreSize.width / tempScopeItem.width;
541 scopesOverviewXYScaler.scale = v;
542 if (scopesOverviewXYScaler.restorePosition) {
543 scopesOverviewXYScaler.x = scopesOverviewXYScaler.restorePosition.x -(tempScopeItem.width - tempScopeItem.width * v) / 2;
544 scopesOverviewXYScaler.y = scopesOverviewXYScaler.restorePosition.y -(tempScopeItem.height - tempScopeItem.height * v) / 2;
546 scopesOverviewXYScaler.x = 0;
547 scopesOverviewXYScaler.y = 0;
549 scopesOverviewXYScaler.opacity = 0;
550 middleItems.overrideOpacity = -1;
552 // TODO Add tests for these connections
554 target: tempScopeItem.scope
556 // TODO Animate the newly opened scope into the foreground (stacked on top of the current scope)
557 tempScopeItem.scope = scope;
560 tempScopeItem.backClicked();
562 root.scope.gotoScope(scopeId);