@@ -0,0 +1,518 @@
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+ property bool growingDashFromPos: false
36+ readonly property bool searching: scope && scope.searchQuery == ""
37+ readonly property bool showingNonFavoriteScope: tempScopeItem.scope != null
38+ readonly property var dashItemEater: {
39+ if (!forceXYScalerEater && tabBar.currentTab == 0 && middleItems.count > 0) {
40+ var loaderItem = middleItems.itemAt(0).item;
41+ return loaderItem && loaderItem.currentItem ? loaderItem.currentItem : null;
43+ return scopesOverviewXYScaler;
45+ readonly property size allCardSize: {
46+ if (middleItems.count > 1) {
47+ var loaderItem = middleItems.itemAt(1).item;
49+ var cardTool = loaderItem.cardTool;
50+ return Qt.size(cardTool.cardWidth, cardTool.cardHeight);
53+ return Qt.size(0, 0);
56+ // Internal properties
57+ property bool forceXYScalerEater: false
60+ signal favoriteSelected(var scopeId)
61+ signal allFavoriteSelected(var scopeId)
62+ signal searchSelected(var scopeId, var result, var pos, var size)
67+ var itemPos = scopesOverviewXYScaler.restorePosition;
68+ var itemSize = scopesOverviewXYScaler.restoreSize;
69+ scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
71+ scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
72+ scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
74+ scopesOverviewXYScaler.x = 0;
75+ scopesOverviewXYScaler.y = 0;
77+ scopesOverviewXYScaler.opacity = 0;
78+ tempScopeItem.scope = scope;
79+ middleItems.overrideOpacity = 0;
80+ scopesOverviewXYScaler.scale = 1;
81+ scopesOverviewXYScaler.x = 0;
82+ scopesOverviewXYScaler.y = 0;
83+ scopesOverviewXYScaler.opacity = 1;
87+ function animateDashFromAll(scopeId) {
88+ var currentScopePos = allScopeCardPosition(scopeId);
89+ if (currentScopePos) {
90+ showDashFromPos(currentScopePos, allCardSize);
92+ console.log("Warning: Could not find Dash OverView All card position for scope", dashContent.currentScopeId);
96+ function showDashFromPos(itemPos, itemSize) {
97+ scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
98+ scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
99+ scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
100+ scopesOverviewXYScaler.opacity = 0;
101+ root.growingDashFromPos = true;
102+ scopesOverviewXYScaler.scale = 1;
103+ scopesOverviewXYScaler.x = 0;
104+ scopesOverviewXYScaler.y = 0;
105+ scopesOverviewXYScaler.opacity = 1;
108+ function allScopeCardPosition(scopeId) {
109+ if (middleItems.count > 1) {
110+ var loaderItem = middleItems.itemAt(1).item;
112+ var pos = loaderItem.scopeCardPosition(scopeId);
113+ return loaderItem.mapToItem(null, pos.x, pos.y);
118+ function ensureAllScopeVisible(scopeId) {
119+ if (middleItems.count > 1) {
120+ var loaderItem = middleItems.itemAt(1).item;
122+ var pos = loaderItem.scopeCardPosition(scopeId);
123+ loaderItem.contentY = Math.min(pos.y, loaderItem.contentHeight - loaderItem.height);
128+ onProgressChanged: {
129+ if (progress == 0) {
130+ pageHeader.resetSearch();
131+ pageHeader.unfocus(); // Shouldn't the previous call do this too?
136+ id: overviewScopeStyle
137+ style: { "foreground-color" : "white", "background-color" : "transparent" }
141+ anchors.fill: parent
142+ source: "graphics/dark_background.jpg"
147+ onSearchQueryChanged: {
148+ // Need this in order, otherwise something gets unhappy in rendering
149+ // of the overlay in carousels because the parent of the dash dies for
150+ // a moment, this way we make sure it's reparented first
151+ // by forceXYScalerEater making dashItemEater return scopesOverviewXYScaler
152+ // before we kill the previous parent by scope.searchQuery
153+ root.forceXYScalerEater = true;
154+ root.scope.searchQuery = pageHeader.searchQuery;
155+ root.forceXYScalerEater = false;
161+ property: "searchQuery"
162+ value: scope ? scope.searchQuery : ""
166+ id: scopesOverviewContent
167+ x: previewListView.open ? -width : 0
168+ Behavior on x { UbuntuNumberAnimation { } }
170+ height: parent.height
174+ objectName: "scopesOverviewPageHeader"
176+ readonly property real yDisplacement: pageHeader.height + tabBar.height + tabBar.anchors.margins
179+ if (root.progress < 0.5) {
180+ return -yDisplacement;
182+ return -yDisplacement + (root.progress - 0.5) * yDisplacement * 2;
187+ title: i18n.tr("Manage Dash")
188+ scopeStyle: overviewScopeStyle
189+ showSignatureLine: false
190+ searchEntryEnabled: true
191+ searchInProgress: root.scope ? root.scope.searchInProgress : false
199+ top: pageHeader.bottom
200+ margins: units.gu(2)
204+ enabled: opacity == 1
205+ opacity: !scope || scope.searchQuery == "" ? 1 : 0
206+ Behavior on opacity { UbuntuNumberAnimation { } }
211+ objectName: "scopesOverviewRepeater"
212+ property real overrideOpacity: -1
213+ model: scope && scope.searchQuery == "" ? scope.categories : null
216+ objectName: "scopesOverviewRepeaterChild" + index
222+ return root.height - pageHeader.height - tabBar.height - tabBar.anchors.margins - units.gu(2)
227+ return root.width / scopeScale
234+ return (root.width - width) / 2;
240+ bottom: scopesOverviewContent.bottom
243+ scale: index == 0 ? scopeScale : 1
246+ if (middleItems.overrideOpacity >= 0)
247+ return middleItems.overrideOpacity;
249+ if (tabBar.currentTab != index)
252+ return index == 0 ? 1 : root.progress;
254+ Behavior on opacity {
255+ enabled: root.progress == 1
256+ UbuntuNumberAnimation { }
258+ enabled: opacity == 1
264+ objectName: "cardTool"
265+ count: results.count
266+ template: model.renderer
267+ components: model.components
268+ viewWidth: parent.width
272+ if (index == 0 && categoryId == "favorites") return "ScopesOverviewFavorites.qml";
273+ else if (index == 1 && categoryId == "all") return "ScopesOverviewAll.qml";
278+ item.model = Qt.binding(function() { return results })
279+ item.cardTool = cardTool;
281+ item.scopeWidth = Qt.binding(function() { return root.width; });
282+ item.scopeHeight = Qt.binding(function() { return root.height; });
283+ item.appliedScale = Qt.binding(function() { return loader.scale });
284+ item.currentIndex = Qt.binding(function() { return root.currentIndex });
285+ } else if (index == 1) {
286+ item.extraHeight = bottomBar.height;
293+ if (tabBar.currentTab == 0) {
294+ root.favoriteSelected(itemModel.scopeId)
296+ var favoriteScopesItem = middleItems.itemAt(0).item;
297+ var scopeIndex = favoriteScopesItem.model.scopeIndex(itemModel.scopeId);
298+ if (scopeIndex >= 0) {
299+ root.allFavoriteSelected(itemModel.scopeId);
301+ // Will result in an openScope from root.scope
302+ scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
303+ scopesOverviewXYScaler.restoreSize = allCardSize;
304+ root.scope.activate(result);
309+ // Preview can call openScope so make sure restorePosition and restoreSize are set
310+ scopesOverviewXYScaler.restorePosition = undefined;
311+ scopesOverviewXYScaler.restoreSize = allCardSize;
313+ previewListView.model = target.model;
314+ previewListView.currentIndex = -1
315+ previewListView.currentIndex = index;
316+ previewListView.open = true
323+ id: searchResultsViewer
324+ objectName: "searchResultsViewer"
326+ top: pageHeader.bottom
329+ bottom: parent.bottom
331+ scope: root.scope && root.scope.searchQuery != "" ? root.scope : null
332+ scopeStyle: overviewScopeStyle
333+ enabled: opacity == 1
334+ showPageHeader: false
336+ opacity: searchResultsViewer.scope ? 1 : 0
337+ Behavior on opacity { UbuntuNumberAnimation { } }
339+ clickOverride: function (index, result, item, itemModel) {
340+ pageHeader.closePopup();
341+ if (itemModel.scopeId) {
342+ // This can end up in openScope so save restorePosition and restoreSize
343+ scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
344+ scopesOverviewXYScaler.restoreSize = Qt.size(item.width, item.height);
345+ root.searchSelected(itemModel.scopeId, result, item.mapToItem(null, 0, 0), Qt.size(item.width, item.height));
347+ // Not a scope, just activate it
348+ searchResultsViewer.scope.activate(result);
352+ pressAndHoldOverride: function (index) {
362+ enabled: opacity == 0.4
363+ opacity: scope && scope.searchQuery == "" ? 0.4 : 0
364+ Behavior on opacity { UbuntuNumberAnimation { } }
366+ if (root.progress < 0.5) {
367+ return parent.height;
369+ return parent.height - (root.progress - 0.5) * height * 2;
374+ objectName: "scopesOverviewDoneButton"
375+ width: Math.max(label.width + units.gu(2), units.gu(10))
379+ leftMargin: units.gu(2)
380+ verticalCenter: parent.verticalCenter
383+ anchors.fill: parent
384+ border.color: "white"
385+ border.width: units.dp(1)
386+ radius: units.dp(10)
387+ color: parent.pressed ? "gray" : "transparent"
391+ anchors.centerIn: parent
392+ text: i18n.tr("Done")
393+ color: parent.pressed ? "black" : "white"
395+ onClicked: root.done();
399+ objectName: "scopesOverviewStoreButton"
400+ width: Math.max(storeLabel.width, units.gu(10))
404+ verticalCenter: parent.verticalCenter
408+ source: "graphics/apps-scope.png"
409+ anchors.horizontalCenter: parent.horizontalCenter
412+ fillMode: Image.Stretch
416+ anchors.horizontalCenter: parent.horizontalCenter
417+ anchors.top: storeImage.bottom
418+ text: i18n.tr("Store")
422+ // Just zoom from the middle
423+ scopesOverviewXYScaler.restorePosition = undefined;
424+ scopesOverviewXYScaler.restoreSize = allCardSize;
425+ scope.performQuery("scope://com.canonical.scopes.clickstore");
433+ objectName: "scopesOverviewPreviewListView"
435+ scopeStyle: overviewScopeStyle
438+ height: parent.height
439+ anchors.left: scopesOverviewContent.right
445+ id: scopesOverviewXYScaler
447+ height: parent.height
452+ property bool animationsEnabled: root.showingNonFavoriteScope || root.growingDashFromPos
454+ property var restorePosition
455+ property var restoreSize
458+ enabled: scopesOverviewXYScaler.animationsEnabled
459+ UbuntuNumberAnimation { }
462+ enabled: scopesOverviewXYScaler.animationsEnabled
463+ UbuntuNumberAnimation { }
465+ Behavior on opacity {
466+ enabled: scopesOverviewXYScaler.animationsEnabled
467+ UbuntuNumberAnimation { }
470+ enabled: scopesOverviewXYScaler.animationsEnabled
471+ UbuntuNumberAnimation {
474+ if (root.showingNonFavoriteScope && scopesOverviewXYScaler.scale != 1) {
475+ root.scope.closeScope(tempScopeItem.scope);
476+ tempScopeItem.scope = null;
477+ } else if (root.growingDashFromPos) {
478+ root.growingDashFromPos = false;
487+ anchors.fill: tempScopeItem
488+ visible: tempScopeItem.visible
489+ parent: tempScopeItem.parent
494+ objectName: "scopesOverviewTempScopeItem"
497+ height: parent.height
498+ scale: dash.contentScale
500+ visible: scope != null
504+ var v = scopesOverviewXYScaler.restoreSize.width / tempScopeItem.width;
505+ scopesOverviewXYScaler.scale = v;
506+ if (scopesOverviewXYScaler.restorePosition) {
507+ scopesOverviewXYScaler.x = scopesOverviewXYScaler.restorePosition.x -(tempScopeItem.width - tempScopeItem.width * v) / 2;
508+ scopesOverviewXYScaler.y = scopesOverviewXYScaler.restorePosition.y -(tempScopeItem.height - tempScopeItem.height * v) / 2;
510+ scopesOverviewXYScaler.x = 0;
511+ scopesOverviewXYScaler.y = 0;
513+ scopesOverviewXYScaler.opacity = 0;
514+ middleItems.overrideOpacity = -1;