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);
92
previewListView.open = false;
102
function closeTempScope() {
103
if (tempScopeItem.scope) {
104
root.scope.closeScope(tempScopeItem.scope);
105
tempScopeItem.scope = null;
106
tempScopeItem.backClicked()
110
function animateDashFromAll(scopeId) {
111
var currentScopePos = allScopeCardPosition(scopeId);
112
if (currentScopePos) {
113
showDashFromPos(currentScopePos, allCardSize);
115
console.log("Warning: Could not find Dash OverView All card position for scope", dashContent.currentScopeId);
119
function showDashFromPos(itemPos, itemSize) {
120
scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
121
scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
122
scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
123
scopesOverviewXYScaler.opacity = 0;
124
root.growingDashFromPos = true;
125
scopesOverviewXYScaler.scale = 1;
126
scopesOverviewXYScaler.x = 0;
127
scopesOverviewXYScaler.y = 0;
128
scopesOverviewXYScaler.opacity = 1;
131
function allScopeCardPosition(scopeId) {
132
if (middleItems.count > 1) {
133
var loaderItem = middleItems.itemAt(1).item;
135
var pos = loaderItem.scopeCardPosition(scopeId);
136
return loaderItem.mapToItem(null, pos.x, pos.y);
141
function ensureAllScopeVisible(scopeId) {
142
if (middleItems.count > 1) {
143
var loaderItem = middleItems.itemAt(1).item;
145
var pos = loaderItem.scopeCardPosition(scopeId);
146
loaderItem.contentY = Math.min(pos.y, loaderItem.contentHeight - loaderItem.height);
153
pageHeader.resetSearch();
154
pageHeader.unfocus(); // Shouldn't the previous call do this too?
159
id: overviewScopeStyle
160
style: { "foreground-color" : "white",
161
"background-color" : "transparent",
163
"background": "color:///transparent"
170
source: "graphics/dark_background.jpg"
175
onSearchQueryChanged: {
176
// Need this in order, otherwise something gets unhappy in rendering
177
// of the overlay in carousels because the parent of the dash dies for
178
// a moment, this way we make sure it's reparented first
179
// by forceXYScalerEater making dashItemEater return scopesOverviewXYScaler
180
// before we kill the previous parent by scope.searchQuery
181
root.forceXYScalerEater = true;
182
root.scope.searchQuery = pageHeader.searchQuery;
183
root.forceXYScalerEater = false;
189
property: "searchQuery"
190
value: scope ? scope.searchQuery : ""
194
id: scopesOverviewContent
195
x: previewListView.open ? -width : 0
196
Behavior on x { UbuntuNumberAnimation { } }
198
height: parent.height
202
objectName: "scopesOverviewPageHeader"
204
readonly property real yDisplacement: pageHeader.height + tabBar.height + tabBar.anchors.margins
207
if (root.progress < 0.5) {
208
return -yDisplacement;
210
return -yDisplacement + (root.progress - 0.5) * yDisplacement * 2;
215
title: i18n.tr("Manage Scopes")
216
scopeStyle: overviewScopeStyle
217
showSignatureLine: false
218
searchEntryEnabled: true
226
top: pageHeader.bottom
231
enabled: opacity == 1
232
opacity: !scope || scope.searchQuery == "" ? 1 : 0
233
Behavior on opacity { UbuntuNumberAnimation { } }
238
objectName: "scopesOverviewRepeater"
239
property real overrideOpacity: -1
240
model: scope && scope.searchQuery == "" ? scope.categories : null
243
objectName: "scopesOverviewRepeaterChild" + index
249
return root.height - pageHeader.height - tabBar.height - tabBar.anchors.margins - units.gu(2);
254
return root.width / scopeScale;
261
return (root.width - width) / 2;
267
bottom: scopesOverviewContent.bottom
270
scale: index == 0 ? scopeScale : 1
273
if (middleItems.overrideOpacity >= 0)
274
return middleItems.overrideOpacity;
276
if (tabBar.currentTab != index)
279
return index == 0 ? 1 : root.progress;
281
Behavior on opacity {
282
enabled: root.progress == 1
283
UbuntuNumberAnimation { }
285
enabled: opacity == 1
291
objectName: "cardTool"
293
template: model.renderer
294
components: model.components
295
viewWidth: parent.width
299
if (index == 0 && categoryId == "favorites") return "ScopesOverviewFavorites.qml";
300
else if (index == 1 && categoryId == "all") return "ScopesOverviewAll.qml";
305
item.model = Qt.binding(function() { return results; });
306
item.cardTool = cardTool;
308
item.scopeWidth = Qt.binding(function() { return root.width; });
309
item.scopeHeight = Qt.binding(function() { return root.height; });
310
item.appliedScale = Qt.binding(function() { return loader.scale });
311
item.currentIndex = Qt.binding(function() { return root.currentIndex });
312
} else if (index == 1) {
313
item.extraHeight = bottomBar.height;
320
pageHeader.unfocus();
321
if (tabBar.currentTab == 0) {
322
root.favoriteSelected(itemModel.scopeId);
324
var favoriteScopesItem = middleItems.itemAt(0).item;
325
var scopeIndex = favoriteScopesItem.model.scopeIndex(itemModel.scopeId);
326
if (scopeIndex >= 0) {
327
root.allFavoriteSelected(itemModel.scopeId);
329
// Will result in an openScope from root.scope
330
scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
331
scopesOverviewXYScaler.restoreSize = allCardSize;
332
root.scope.activate(result);
337
// Preview can call openScope so make sure restorePosition and restoreSize are set
338
scopesOverviewXYScaler.restorePosition = undefined;
339
scopesOverviewXYScaler.restoreSize = allCardSize;
341
previewListView.model = target.model;
342
previewListView.currentIndex = -1;
343
previewListView.currentIndex = index;
344
previewListView.open = true;
351
id: searchResultsViewer
352
objectName: "searchResultsViewer"
354
top: pageHeader.bottom
357
bottom: parent.bottom
359
scope: root.scope && root.scope.searchQuery != "" ? root.scope : null
360
scopeStyle: overviewScopeStyle
361
enabled: opacity == 1
362
showPageHeader: false
364
opacity: searchResultsViewer.scope ? 1 : 0
366
Behavior on opacity { UbuntuNumberAnimation { } }
368
function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount) {
369
pageHeader.unfocus();
370
pageHeader.closePopup();
371
if (itemModel.scopeId) {
372
// This can end up in openScope so save restorePosition and restoreSize
373
scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
374
scopesOverviewXYScaler.restoreSize = Qt.size(item.width, item.height);
375
root.searchSelected(itemModel.scopeId, result, item.mapToItem(null, 0, 0), Qt.size(item.width, item.height));
377
// Not a scope, just activate it
378
searchResultsViewer.scope.activate(result);
382
function itemPressedAndHeld(index, itemModel, resultsModel, limitedCategoryItemCount) {
383
if (itemModel.uri.indexOf("scope://") === 0) {
384
// Preview can call openScope so make sure restorePosition and restoreSize are set
385
scopesOverviewXYScaler.restorePosition = undefined;
386
scopesOverviewXYScaler.restoreSize = allCardSize;
388
previewListView.model = resultsModel;
389
previewListView.currentIndex = -1;
390
previewListView.currentIndex = index;
391
previewListView.open = true;
398
objectName: "bottomBar"
402
enabled: opacity == 1
403
opacity: scope && scope.searchQuery == "" ? 1 : 0
404
Behavior on opacity { UbuntuNumberAnimation { } }
406
if (root.progress < 0.5) {
407
return parent.height;
409
return parent.height - (root.progress - 0.5) * height * 2;
414
// Just eat any other press since this parent is black opaque
419
objectName: "scopesOverviewDoneButton"
420
width: Math.max(label.width + units.gu(2), units.gu(10))
424
leftMargin: units.gu(2)
425
verticalCenter: parent.verticalCenter
429
border.color: "white"
430
border.width: units.dp(1)
432
color: parent.pressed ? Theme.palette.normal.baseText : "transparent"
436
anchors.centerIn: parent
437
text: i18n.tr("Done")
438
color: parent.pressed ? "black" : "white"
440
onClicked: root.done();
444
objectName: "scopesOverviewStoreButton"
445
width: Math.max(storeLabel.width, units.gu(10))
449
verticalCenter: parent.verticalCenter
453
name: "ubuntu-store-symbolic"
455
anchors.horizontalCenter: parent.horizontalCenter
461
anchors.horizontalCenter: parent.horizontalCenter
462
anchors.top: storeImage.bottom
463
text: i18n.tr("Store")
467
// Just zoom from the middle
468
scopesOverviewXYScaler.restorePosition = undefined;
469
scopesOverviewXYScaler.restoreSize = allCardSize;
470
scope.performQuery("scope://com.canonical.scopes.clickstore");
478
objectName: "scopesOverviewPreviewListView"
480
scopeStyle: overviewScopeStyle
481
showSignatureLine: false
484
height: parent.height
485
anchors.left: scopesOverviewContent.right
487
onBackClicked: open = false
491
id: scopesOverviewXYScaler
493
height: parent.height
498
property bool animationsEnabled: root.showingNonFavoriteScope || root.growingDashFromPos
500
property var restorePosition
501
property var restoreSize
504
enabled: scopesOverviewXYScaler.animationsEnabled
505
UbuntuNumberAnimation { }
508
enabled: scopesOverviewXYScaler.animationsEnabled
509
UbuntuNumberAnimation { }
511
Behavior on opacity {
512
enabled: scopesOverviewXYScaler.animationsEnabled
513
UbuntuNumberAnimation { }
516
enabled: scopesOverviewXYScaler.animationsEnabled
517
UbuntuNumberAnimation {
520
if (root.showingNonFavoriteScope && scopesOverviewXYScaler.scale != 1) {
521
root.scope.closeScope(tempScopeItem.scope);
522
tempScopeItem.scope = null;
523
} else if (root.growingDashFromPos) {
524
root.growingDashFromPos = false;
532
anchors.fill: tempScopeItem
533
visible: tempScopeItem.visible
534
parent: tempScopeItem.parent
539
objectName: "scopesOverviewTempScopeItem"
542
height: parent.height
544
visible: scope != null
548
var v = scopesOverviewXYScaler.restoreSize.width / tempScopeItem.width;
549
scopesOverviewXYScaler.scale = v;
550
if (scopesOverviewXYScaler.restorePosition) {
551
scopesOverviewXYScaler.x = scopesOverviewXYScaler.restorePosition.x -(tempScopeItem.width - tempScopeItem.width * v) / 2;
552
scopesOverviewXYScaler.y = scopesOverviewXYScaler.restorePosition.y -(tempScopeItem.height - tempScopeItem.height * v) / 2;
554
scopesOverviewXYScaler.x = 0;
555
scopesOverviewXYScaler.y = 0;
557
scopesOverviewXYScaler.opacity = 0;
558
middleItems.overrideOpacity = -1;
560
// TODO Add tests for these connections
562
target: tempScopeItem.scope
564
// TODO Animate the newly opened scope into the foreground (stacked on top of the current scope)
565
tempScopeItem.scope = scope;
568
tempScopeItem.backClicked();
570
root.scope.gotoScope(scopeId);