Merge lp:~cimi/unity8/card_emblems_2 into lp:unity8

Proposed by Andrea Cimitan
Status: Superseded
Proposed branch: lp:~cimi/unity8/card_emblems_2
Merge into: lp:unity8
Prerequisite: lp:~cimi/unity8/card_touchdown_2
Diff against target: 4134 lines (+2313/-477)
52 files modified
data/unity8-dash.conf (+1/-1)
plugins/Dash/CardCreator.js (+187/-154)
plugins/Dash/ScopeStyle.qml (+3/-2)
plugins/Dash/listviewwithpageheader.cpp (+10/-2)
plugins/Dash/listviewwithpageheader.h (+3/-0)
po/hu.po (+6/-5)
po/sl.po (+4/-3)
po/unity8.pot (+80/-44)
qml/Components/PageHeader.qml (+3/-1)
qml/Components/ResponsiveGridView.qml (+3/-3)
qml/Dash/CardCarousel.qml (+2/-2)
qml/Dash/CardGrid.qml (+13/-2)
qml/Dash/CardVerticalJournal.qml (+1/-1)
qml/Dash/Dash.qml (+171/-13)
qml/Dash/DashBackground.qml (+24/-0)
qml/Dash/DashContent.qml (+10/-4)
qml/Dash/DashRenderer.qml (+3/-1)
qml/Dash/GenericScopeView.qml (+86/-48)
qml/Dash/PreviewListView.qml (+1/-1)
qml/Dash/ScopesOverview.qml (+531/-0)
qml/Dash/ScopesOverviewAll.qml (+54/-0)
qml/Dash/ScopesOverviewFavorites.qml (+73/-0)
qml/Dash/ScopesOverviewTab.qml (+74/-0)
tests/autopilot/unity8/shell/tests/test_emulators.py (+1/-1)
tests/mocks/Unity/CMakeLists.txt (+1/-0)
tests/mocks/Unity/fake_categories.cpp (+6/-2)
tests/mocks/Unity/fake_resultsmodel.cpp (+2/-1)
tests/mocks/Unity/fake_scope.cpp (+17/-5)
tests/mocks/Unity/fake_scope.h (+6/-3)
tests/mocks/Unity/fake_scopes.cpp (+46/-7)
tests/mocks/Unity/fake_scopes.h (+8/-1)
tests/mocks/Unity/fake_scopesoverview.cpp (+281/-0)
tests/mocks/Unity/fake_scopesoverview.h (+104/-0)
tests/plugins/Dash/cardcreator/1.res (+6/-6)
tests/plugins/Dash/cardcreator/1.tst (+1/-1)
tests/plugins/Dash/cardcreator/2.res (+27/-19)
tests/plugins/Dash/cardcreator/2.tst (+1/-1)
tests/plugins/Dash/cardcreator/3.res (+12/-12)
tests/plugins/Dash/cardcreator/3.tst (+1/-1)
tests/plugins/Dash/cardcreator/4.res (+23/-15)
tests/plugins/Dash/cardcreator/4.tst (+1/-1)
tests/plugins/Dash/cardcreator/5.res (+21/-19)
tests/plugins/Dash/cardcreator/5.tst (+1/-1)
tests/plugins/Dash/cardcreator/6.res (+98/-45)
tests/plugins/Dash/cardcreator/6.tst (+2/-2)
tests/plugins/Dash/cardcreator/7.res (+35/-23)
tests/plugins/Dash/tst_ScopeStyle.qml (+1/-1)
tests/qmltests/Dash/CardHelpers.js (+1/-0)
tests/qmltests/Dash/tst_Card.qml (+19/-1)
tests/qmltests/Dash/tst_Dash.qml (+229/-7)
tests/qmltests/Dash/tst_DashContent.qml (+7/-6)
tests/qmltests/Dash/tst_GenericScopeView.qml (+12/-9)
To merge this branch: bzr merge lp:~cimi/unity8/card_emblems_2
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Needs Fixing
Michał Sawicz Needs Fixing
Review via email: mp+229046@code.launchpad.net

This proposal has been superseded by a proposal from 2014-08-08.

Commit message

Add emblems

Description of the change

 * Are there any related MPs required for this MP to build/function as expected? Please list.
No
 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
 * Did you make sure that your branch does not contain spurious tags?
Yes
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
 * If you changed the UI, has there been a design review?
N/A

To post a comment you must log in.
lp:~cimi/unity8/card_emblems_2 updated
1094. By Andrea Cimitan

Fixed tests

1095. By Andrea Cimitan

Fixed test

1096. By Andrea Cimitan

Added test

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Andrea Cimitan (cimi) wrote :

 * Are there any related MPs required for this MP to build/function as expected? Please list.
No
 * Did you perform an exploratory manual test run of your code change and any related functionality?
Yes
 * Did you make sure that your branch does not contain spurious tags?
Yes
 * If you changed the packaging (debian), did you subscribe the ubuntu-unity team to this MP?
N/A
 * If you changed the UI, has there been a design review?
N/A

Revision history for this message
Ying-Chun Liu (paulliu) wrote :
Revision history for this message
Ying-Chun Liu (paulliu) wrote :

cardTool?

lp:~cimi/unity8/card_emblems_2 updated
1097. By Andrea Cimitan

More fixes

Revision history for this message
Ying-Chun Liu (paulliu) wrote :

In the diff there's conflict. Seems we need a re-merge trunk here?

lp:~cimi/unity8/card_emblems_2 updated
1098. By Andrea Cimitan

[ Gerry Boland ]
* Fix the run.sh script - pretend to be running with qtmir and emit
  SIGSTOP at the right time
[ Ying-Chun Liu ]
* Implement Attribute UI. (LP: #1282460)
[ Albert Astals ]
* Hide search history popup as soon as you start typing As discussed
  with Mike and Saviq
* Compile with for scopes-v3 unity-api
* PageHeader: Unfocus search field when search entry is selected
* Show search field if the search query changes
* Test: Add a condition for art.height being > 0 means stuff has
  already been layouted a bit without it it can happen that we get 0
  for everything at startup and tests still pass
* Remove leftover in test of an old headerless implementation
[ Michael Zanetti ]
* Drop Recent apps category from Dash (LP: #1281092)
* update launcher count emblems to match new spec (LP: #1338984)
[ Bill Filler ]
* disable predictive text for dash search field (LP: #1340409)
[ CI bot ]
* Resync trunk
[ Antti Kaijanmäki ]
* DefaultIndicatorPage: use Loader status to determine the visible
  property. (LP: #1350555)

1099. By Andrea Cimitan

Merge

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~cimi/unity8/card_emblems_2 updated
1100. By Andrea Cimitan

merged trunk

1101. By Andrea Cimitan

Fix categories with attributes

1102. By Andrea Cimitan

Moar fixes

1103. By Andrea Cimitan

Fixed whitespaces

1104. By Andrea Cimitan

merged overview

Revision history for this message
Michał Sawicz (saviq) wrote :

When emblem is declared, but invalid, there's no right text margin.

You should use StatusIcon (like attributes do) for the emblem, and colourize it with the foreground color.

review: Needs Fixing
lp:~cimi/unity8/card_emblems_2 updated
1105. By Andrea Cimitan

Fixed right padding

1106. By Andrea Cimitan

Fixed issue of spacing when the touchdown is on the art only

1107. By Andrea Cimitan

Fixed another review erequest

1108. By Andrea Cimitan

Add colorisation

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~cimi/unity8/card_emblems_2 updated
1109. By Andrea Cimitan

Fix issue in reviewy

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/unity8-dash.conf'
2--- data/unity8-dash.conf 2014-07-29 11:35:10 +0000
3+++ data/unity8-dash.conf 2014-08-08 14:57:17 +0000
4@@ -13,7 +13,7 @@
5 pre-start script
6 if [ -z "$UNITY_SCOPES_LIST" ]; then
7 # FIXME: remove once we have this in dconf
8- initctl set-env UNITY_SCOPES_LIST="scopes;clickscope;musicaggregator;videoaggregator"
9+ initctl set-env UNITY_SCOPES_LIST="clickscope;musicaggregator;videoaggregator"
10 fi
11
12 initctl emit scope-ui-starting
13
14=== modified file 'plugins/Dash/CardCreator.js'
15--- plugins/Dash/CardCreator.js 2014-08-06 19:39:39 +0000
16+++ plugins/Dash/CardCreator.js 2014-08-08 14:57:17 +0000
17@@ -108,6 +108,7 @@
18 sourceComponent: ShaderEffect { \n\
19 id: overlay; \n\
20 height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
21+ property real luminance: 0.2126 * overlayColor.r + 0.7152 * overlayColor.g + 0.0722 * overlayColor.b; \n\
22 property color overlayColor: cardData && cardData["overlayColor"] || "#99000000"; \n\
23 property var source: ShaderEffectSource { \n\
24 id: shaderSource; \n\
25@@ -137,69 +138,43 @@
26 } \n\
27 }\n';
28
29-// %1 is used as anchors of row
30-// %2 is used as first child of the row
31-// %3 is used as second child of the row
32-var kHeaderRow2Code = 'Row { \n\
33- id: row; \n\
34- objectName: "outerRow"; \n\
35- property real margins: units.gu(1); \n\
36- spacing: margins; \n\
37- height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
38- anchors { %1 } \n\
39- anchors.right: parent.right; \n\
40- anchors.margins: margins;\n\
41- data: [ %2\n\
42- ,\n\
43- %3 \n\
44- ] \n\
45- }\n';
46-
47-// %1 is used as anchors of row
48-// %2 is used as first child of the row
49-// %3 is used as second child of the row
50-// %4 is used as third child of the row
51-var kHeaderRow3Code = 'Row { \n\
52- id: row; \n\
53- objectName: "outerRow"; \n\
54- property real margins: units.gu(1); \n\
55- spacing: margins; \n\
56- height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
57- anchors { %1 } \n\
58- anchors.right: parent.right; \n\
59- anchors.margins: margins;\n\
60- data: [ %2\n\
61- ,\n\
62- %3 \n\
63- ,\n\
64- %4 \n\
65- ] \n\
66- }\n';
67-
68-// %1 is used as first child of the column
69-// %2 is used as second child of the column
70-var kHeaderColumnCode = 'Column { \n\
71- anchors.verticalCenter: parent.verticalCenter; \n\
72- spacing: units.dp(2); \n\
73- width: parent.width - x;\n\
74- data: [ %1\n\
75- ,\n\
76- %2 \n\
77- ] \n\
78+// multiple row version of HeaderRowCode
79+function kHeaderRowCodeGenerator() {
80+var kHeaderRowCodeTemplate = 'Row { \n\
81+ id: row; \n\
82+ objectName: "outerRow"; \n\
83+ property real margins: units.gu(1); \n\
84+ spacing: margins; \n\
85+ height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight; \n\
86+ anchors { %1 } \n\
87+ anchors.right: parent.right; \n\
88+ anchors.margins: margins; \n\
89+ anchors.rightMargin: 0; \n\
90+ data: [ \n\
91+ %2 \n\
92+ ] \n\
93+ }\n';
94+ var args = Array.prototype.slice.call(arguments);
95+ var HeaderRowAnchors = args.shift();
96+ var code = kHeaderRowCodeTemplate.arg(HeaderRowAnchors).arg(args.join(',\n'));
97+ return code;
98+}
99+
100+// multiple item version of kHeaderContainerCode
101+function kHeaderContainerCodeGenerator() {
102+ var headerContainerCodeTemplate = 'Item { \n\
103+ id: headerTitleContainer; \n\
104+ anchors { %1 } \n\
105+ width: parent.width - x; \n\
106+ implicitHeight: %2; \n\
107+ data: [ \n\
108+ %3 \n\
109+ ]\n\
110 }\n';
111-
112-// multiple column version of kHeaderColumnCode.
113-function kHeaderColumnCodeGenerator() {
114- var headerColumnCodeTemplate = 'Column { \n\
115- anchors.verticalCenter: parent.verticalCenter; \n\
116- spacing: units.dp(2); \n\
117- width: parent.width - x;\n\
118- data: [ \n\
119- %1 \n\
120- ]\n\
121- }\n';
122 var args = Array.prototype.slice.call(arguments);
123- var code = headerColumnCodeTemplate.arg(args.join(',\n'));
124+ var headerContainerAnchors = args.shift();
125+ var headerContainerHeight = args.shift();
126+ var code = headerContainerCodeTemplate.arg(headerContainerAnchors).arg(headerContainerHeight).arg(args.join(',\n'));
127 return code;
128 }
129
130@@ -223,7 +198,7 @@
131 objectName: "mascotImage"; \n\
132 anchors { %1 } \n\
133 readonly property int maxSize: Math.max(width, height) * 4; \n\
134- source: cardData && cardData["mascot"]; \n\
135+ source: cardData && cardData["mascot"] || ""; \n\
136 width: units.gu(6); \n\
137 height: units.gu(5.625); \n\
138 sourceSize { width: maxSize; height: maxSize } \n\
139@@ -252,6 +227,20 @@
140 horizontalAlignment: root.headerAlignment; \n\
141 }\n';
142
143+var kEmblemImageCode = 'Image { \n\
144+ id: emblemImage; \n\
145+ objectName: "emblemImage"; \n\
146+ anchors { \n\
147+ bottom: titleLabel.baseline; \n\
148+ right: parent.right; \n\
149+ rightMargin: status === Image.Ready ? units.gu(1) : 0; \n\
150+ } \n\
151+ source: cardData && cardData["emblem"] || ""; \n\
152+ width: height; \n\
153+ height: status === Image.Ready ? titleLabel.font.pixelSize : 0; \n\
154+ fillMode: Image.PreserveAspectFit; \n\
155+ }\n';
156+
157 // %1 is used as anchors of touchdown effect
158 var kTouchdownCode = 'UbuntuShape { \n\
159 id: touchdown; \n\
160@@ -268,6 +257,7 @@
161 id: subtitleLabel; \n\
162 objectName: "subtitleLabel"; \n\
163 anchors { %1 } \n\
164+ anchors.topMargin: units.dp(2); \n\
165 elide: Text.ElideRight; \n\
166 fontSize: "small"; \n\
167 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale); \n\
168@@ -284,7 +274,7 @@
169 objectName: "attributesRow"; \n\
170 anchors { %1 } \n\
171 color: %2; \n\
172- model: cardData["attributes"]; \n\
173+ model: cardData && cardData["attributes"]; \n\
174 }\n';
175
176 // %1 is used as top anchor of summary
177@@ -334,10 +324,11 @@
178 var hasBackground = !isHorizontal && (template["card-background"] || components["background"] || artAndSummary);
179 var hasTitle = components["title"] || false;
180 var hasMascot = components["mascot"] || false;
181+ var hasEmblem = components["emblem"] && !(hasMascot && template["card-size"] === "small") || false;
182 var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
183 var hasSubtitle = hasTitle && components["subtitle"] || false;
184 var hasHeaderRow = hasMascot && hasTitle;
185- var hasAttributes = hasTitle && components["attributes"] || false;
186+ var hasAttributes = hasTitle && components["attributes"]["field"] || false;
187
188 if (hasBackground) {
189 code += kBackgroundLoaderCode;
190@@ -348,9 +339,9 @@
191 code += 'readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);\n';
192
193 var widthCode, heightCode;
194- var anchors;
195+ var artAnchors;
196 if (isHorizontal) {
197- anchors = 'left: parent.left';
198+ artAnchors = 'left: parent.left';
199 if (hasMascot || hasTitle) {
200 widthCode = 'height * artShape.aspect'
201 heightCode = 'headerHeight + 2 * units.gu(1)';
202@@ -361,12 +352,12 @@
203 heightCode = 'units.gu(7.625)';
204 }
205 } else {
206- anchors = 'horizontalCenter: parent.horizontalCenter;';
207+ artAnchors = 'horizontalCenter: parent.horizontalCenter;';
208 widthCode = 'root.width'
209 heightCode = 'width / artShape.aspect';
210 }
211
212- code += kArtShapeHolderCode.arg(anchors).arg(widthCode).arg(heightCode);
213+ code += kArtShapeHolderCode.arg(artAnchors).arg(widthCode).arg(heightCode);
214 } else {
215 code += 'readonly property size artShapeSize: Qt.size(-1, -1);\n'
216 }
217@@ -423,155 +414,194 @@
218 code += 'readonly property int headerHeight: 0;\n'
219 }
220
221- var mascotShapeCode = "";
222- var mascotCode = "";
223+ var mascotShapeCode = '';
224+ var mascotCode = '';
225 if (hasMascot) {
226 var useMascotShape = !hasBackground && !headerAsOverlay;
227- var anchors = "";
228+ var mascotAnchors = '';
229 if (!hasHeaderRow) {
230- anchors += headerLeftAnchor;
231- anchors += headerVerticalAnchors;
232+ mascotAnchors += headerLeftAnchor;
233+ mascotAnchors += headerVerticalAnchors;
234 if (!headerLeftAnchorHasMargin) {
235- anchors += 'leftMargin: units.gu(1);\n'
236+ mascotAnchors += 'leftMargin: units.gu(1);\n'
237 }
238 } else {
239- anchors = "verticalCenter: parent.verticalCenter;"
240+ mascotAnchors = 'verticalCenter: parent.verticalCenter;'
241 }
242
243 if (useMascotShape) {
244- mascotShapeCode = kMascotShapeLoaderCode.arg(anchors);
245+ mascotShapeCode = kMascotShapeLoaderCode.arg(mascotAnchors);
246 }
247
248 var mascotImageVisible = useMascotShape ? 'false' : 'showHeader';
249- mascotCode = kMascotImageCode.arg(anchors).arg(mascotImageVisible);
250+ mascotCode = kMascotImageCode.arg(mascotAnchors).arg(mascotImageVisible);
251 }
252
253- var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey")';
254+ var summaryColorWithBackground = 'backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey")';
255
256- var titleSubtitleCode = "";
257+ var hasTitleContainer = hasTitle && (hasEmblem || (hasMascot && (hasSubtitle || hasAttributes)));
258+ var titleSubtitleCode = '';
259 if (hasTitle) {
260- var color;
261+ var titleColor;
262 if (headerAsOverlay) {
263- color = '"white"';
264+ titleColor = 'overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey")';
265 } else if (hasSummary) {
266- color = 'summary.color';
267+ titleColor = 'summary.color';
268 } else if (hasBackground) {
269- color = summaryColorWithBackground;
270+ titleColor = summaryColorWithBackground;
271 } else {
272- color = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
273+ titleColor = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
274 }
275
276 var titleAnchors;
277 var subtitleAnchors;
278 var attributesAnchors;
279- if (hasMascot && (hasSubtitle || hasAttributes)) {
280- // Using row + column
281- titleAnchors = 'left: parent.left; right: parent.right';
282- subtitleAnchors = titleAnchors;
283- attributesAnchors = subtitleAnchors;
284+ var titleContainerAnchors;
285+ var titleRightAnchor;
286+
287+ if (hasMascot) {
288+ titleContainerAnchors = 'verticalCenter: parent.verticalCenter; ';
289+ } else {
290+ titleContainerAnchors = 'right: parent.right; ';
291+ titleContainerAnchors += headerLeftAnchor;
292+ titleContainerAnchors += headerVerticalAnchors;
293+ if (!headerLeftAnchorHasMargin) {
294+ titleContainerAnchors += 'leftMargin: units.gu(1);\n';
295+ }
296+ }
297+ if (hasEmblem) {
298+ titleRightAnchor = 'right: emblemImage.left; \n\
299+ rightMargin: emblemImage.width > 0 ? units.gu(0.5) : 0; \n';
300+ } else {
301+ titleRightAnchor = 'right: parent.right; \n\
302+ rightMargin: units.gu(1); \n';
303+ }
304+
305+ if (hasTitleContainer) {
306+ // Using headerTitleContainer
307+ titleAnchors = titleRightAnchor;
308+ titleAnchors += 'left: parent.left; \n\
309+ top: parent.top;';
310+ subtitleAnchors = 'right: parent.right; \n\
311+ left: parent.left; \n\
312+ rightMargin: units.gu(1); \n';
313+ if (hasSubtitle) {
314+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
315+ subtitleAnchors += 'top: titleLabel.bottom;\n';
316+ } else {
317+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
318+ }
319 } else if (hasMascot) {
320- // Using row + label
321- titleAnchors = 'verticalCenter: parent.verticalCenter;\n'
322+ // Using row + titleContainer
323+ titleAnchors = 'verticalCenter: parent.verticalCenter;\n';
324 } else {
325 if (headerAsOverlay) {
326 // Using anchors to the overlay
327- titleAnchors = 'left: parent.left; \n\
328- leftMargin: units.gu(1); \n\
329- right: parent.right; \n\
330- rightMargin: units.gu(1); \n\
331- top: overlayLoader.top; \n\
332- topMargin: units.gu(1);\n';
333+ titleAnchors = titleRightAnchor;
334+ titleAnchors += 'left: parent.left; \n\
335+ leftMargin: units.gu(1); \n\
336+ top: overlayLoader.top; \n\
337+ topMargin: units.gu(1);\n';
338 } else {
339 // Using anchors to the mascot/parent
340- titleAnchors = "right: parent.right;\n";
341- titleAnchors += "rightMargin: units.gu(1);\n";
342+ titleAnchors = titleRightAnchor;
343 titleAnchors += headerLeftAnchor;
344 titleAnchors += headerVerticalAnchors;
345 if (!headerLeftAnchorHasMargin) {
346- titleAnchors += 'leftMargin: units.gu(1);\n'
347+ titleAnchors += 'leftMargin: units.gu(1);\n';
348 }
349 }
350 subtitleAnchors = 'left: titleLabel.left; \n\
351 leftMargin: titleLabel.leftMargin; \n\
352- right: titleLabel.right; \n\
353- rightMargin: titleLabel.rightMargin; \n\
354- top: titleLabel.bottom; \n\
355- topMargin: units.dp(2);\n';
356+ rightMargin: units.gu(1); \n';
357+ if (hasEmblem) {
358+ // using container
359+ subtitleAnchors += 'right: parent.right; \n';
360+ } else {
361+ subtitleAnchors += 'right: titleLabel.right; \n';
362+ }
363+
364 if (hasSubtitle) {
365- attributesAnchors = 'left: subtitleLabel.left; \n\
366- leftMargin: subtitleLabel.leftMargin; \n\
367- right: subtitleLabel.right; \n\
368- rightMargin: subtitleLabel.rightMargin; \n\
369- top: subtitleLabel.bottom; \n\
370- topMargin: units.dp(2);\n';
371+ attributesAnchors = subtitleAnchors + 'top: subtitleLabel.bottom;\n';
372+ subtitleAnchors += 'top: titleLabel.bottom;\n';
373 } else {
374- attributesAnchors = subtitleAnchors;
375+ attributesAnchors = subtitleAnchors + 'top: titleLabel.bottom;\n';
376 }
377 }
378
379+ // code for different elements
380 var titleLabelVisibleExtra = (headerAsOverlay ? '&& overlayLoader.active': '');
381- var titleCode = kTitleLabelCode.arg(titleAnchors).arg(color).arg(titleLabelVisibleExtra);
382- var subtitleCode = "";
383+ var titleCode = kTitleLabelCode.arg(titleAnchors).arg(titleColor).arg(titleLabelVisibleExtra);
384+ var subtitleCode;
385+ var attributesCode;
386+ var emblemCode;
387+
388+ // code for the title container
389+ var containerCode = [];
390+ var containerHeight = 'titleLabel.height';
391+ containerCode.push(titleCode);
392 if (hasSubtitle) {
393- subtitleCode += kSubtitleLabelCode.arg(subtitleAnchors).arg(color);
394+ subtitleCode = kSubtitleLabelCode.arg(subtitleAnchors).arg(titleColor);
395+ containerCode.push(subtitleCode);
396+ containerHeight += ' + subtitleLabel.height';
397+ }
398+ if (hasEmblem) {
399+ containerCode.push(kEmblemImageCode);
400+ }
401+ if (hasAttributes) {
402+ attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(titleColor);
403+ containerCode.push(kAttributesRowCode.arg(attributesAnchors).arg(titleColor));
404+ containerHeight += ' + attributesRow.height';
405 }
406
407- if (hasMascot && (hasSubtitle || hasAttributes)) {
408- // If using row + column wrap the code in the column
409- titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(subtitleCode);
410- if (hasSubtitle && hasAttributes) {
411- var attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(color);
412- titleSubtitleCode = kHeaderColumnCodeGenerator(titleCode, subtitleCode, attributesCode);
413- } else if (hasSubtitle) {
414- titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(subtitleCode);
415- } else if (hasAttributes) {
416- var attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(color);
417- titleSubtitleCode = kHeaderColumnCode.arg(titleCode).arg(attributesCode);
418- }
419+ if (hasTitleContainer) {
420+ // use container
421+ titleSubtitleCode = kHeaderContainerCodeGenerator(titleContainerAnchors, containerHeight, containerCode);
422 } else {
423+ // no container
424 titleSubtitleCode = titleCode;
425 if (hasSubtitle) {
426- titleSubtitleCode = titleSubtitleCode + subtitleCode;
427+ titleSubtitleCode += subtitleCode;
428 }
429 if (hasAttributes) {
430- var attributesCode = kAttributesRowCode.arg(attributesAnchors).arg(color);
431- titleSubtitleCode = titleSubtitleCode + attributesCode;
432+ titleSubtitleCode += attributesCode;
433 }
434 }
435 }
436
437 if (hasHeaderRow) {
438- if (mascotShapeCode != "") {
439- code += kHeaderRow3Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotShapeCode).arg(mascotCode).arg(titleSubtitleCode);
440- } else {
441- code += kHeaderRow2Code.arg(headerVerticalAnchors + headerLeftAnchor).arg(mascotCode).arg(titleSubtitleCode);
442+ var rowCode = [mascotCode, titleSubtitleCode];
443+ if (mascotShapeCode != '') {
444+ rowCode.unshift(mascotShapeCode);
445 }
446+ code += kHeaderRowCodeGenerator(headerVerticalAnchors + headerLeftAnchor, rowCode)
447 } else {
448 code += mascotShapeCode + mascotCode + titleSubtitleCode;
449 }
450
451 if (hasSummary) {
452 var summaryTopAnchor;
453- if (isHorizontal && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
454- else if (headerAsOverlay && hasArt) summaryTopAnchor = "artShapeHolder.bottom";
455- else if (hasHeaderRow) summaryTopAnchor = "row.bottom";
456- else if (hasMascot) summaryTopAnchor = "mascotImage.bottom";
457- else if (hasAttributes) summaryTopAnchor = "attributesRow.bottom";
458- else if (hasSubtitle) summaryTopAnchor = "subtitleLabel.bottom";
459- else if (hasTitle) summaryTopAnchor = "titleLabel.bottom";
460- else if (hasArt) summaryTopAnchor = "artShapeHolder.bottom";
461- else summaryTopAnchor = "parent.top";
462+ if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
463+ else if (headerAsOverlay && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
464+ else if (hasHeaderRow) summaryTopAnchor = 'row.bottom';
465+ else if (hasTitleContainer) summaryTopAnchor = 'headerTitleContainer.bottom';
466+ else if (hasMascot) summaryTopAnchor = 'mascotImage.bottom';
467+ else if (hasAttributes) summaryTopAnchor = 'attributesRow.bottom';
468+ else if (hasSubtitle) summaryTopAnchor = 'subtitleLabel.bottom';
469+ else if (hasTitle) summaryTopAnchor = 'titleLabel.bottom';
470+ else if (hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
471+ else summaryTopAnchor = 'parent.top';
472
473- var color;
474+ var summaryColor;
475 if (hasBackground) {
476- color = summaryColorWithBackground;
477+ summaryColor = summaryColorWithBackground;
478 } else {
479- color = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
480+ summaryColor = 'root.scopeStyle ? root.scopeStyle.foreground : "grey"';
481 }
482
483 var summaryTopMargin = (hasMascot || hasSubtitle || hasAttributes ? 'anchors.margins' : '0');
484
485- code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(color);
486+ code += kSummaryLabelCode.arg(summaryTopAnchor).arg(summaryTopMargin).arg(summaryColor);
487 }
488
489 var touchdownAnchors;
490@@ -584,23 +614,26 @@
491 }
492 code += kTouchdownCode.arg(touchdownAnchors);
493
494+ var implicitHeight = 'implicitHeight: ';
495 if (hasSummary) {
496- code += 'implicitHeight: summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
497+ implicitHeight += 'summary.y + summary.height + (summary.text ? units.gu(1) : 0);\n';
498 } else if (hasHeaderRow) {
499- code += 'implicitHeight: row.y + row.height + units.gu(1);\n';
500+ implicitHeight += 'row.y + row.height + units.gu(1);\n';
501 } else if (hasMascot) {
502- code += 'implicitHeight: mascotImage.y + mascotImage.height;\n';
503+ implicitHeight += 'mascotImage.y + mascotImage.height;\n';
504+ } else if (hasTitleContainer) {
505+ implicitHeight += 'headerTitleContainer.y + headerTitleContainer.height + units.gu(1);\n';
506 } else if (hasAttributes) {
507- code += 'implicitHeight: attributesRow.y + attributesRow.height + units.gu(1);\n';
508+ implicitHeight += 'attributesRow.y + attributesRow.height + units.gu(1);\n';
509 } else if (hasSubtitle) {
510- code += 'implicitHeight: subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
511+ implicitHeight += 'subtitleLabel.y + subtitleLabel.height + units.gu(1);\n';
512 } else if (hasTitle) {
513- code += 'implicitHeight: titleLabel.y + titleLabel.height + units.gu(1);\n';
514+ implicitHeight += 'titleLabel.y + titleLabel.height + units.gu(1);\n';
515 } else if (hasArt) {
516- code += 'implicitHeight: artShapeHolder.height;\n';
517+ implicitHeight += 'artShapeHolder.height;\n';
518 }
519 // Close the AbstractButton
520- code += '}\n';
521+ code += implicitHeight + '}\n';
522
523 return code;
524 }
525
526=== modified file 'plugins/Dash/ScopeStyle.qml'
527--- plugins/Dash/ScopeStyle.qml 2014-07-25 11:42:06 +0000
528+++ plugins/Dash/ScopeStyle.qml 2014-08-08 14:57:17 +0000
529@@ -49,9 +49,10 @@
530
531 /*! \brief Luminance threshold for switching between fore and background color
532
533- \note If background colour is not fully opaque, it's not taken into account.
534+ \note If background colour is not fully opaque, the defaultLightLuminance it's taken into account instead of it.
535 */
536- readonly property real threshold: background.a !== 1.0 ? foregroundLuminance : (foregroundLuminance + backgroundLuminance) / 2
537+ readonly property real threshold: background.a !== 1.0 ? (foregroundLuminance + d.defaultLightLuminance) / 2
538+ : (foregroundLuminance + backgroundLuminance) / 2
539
540 /*! \brief The lighter of foreground and background colors
541
542
543=== modified file 'plugins/Dash/listviewwithpageheader.cpp'
544--- plugins/Dash/listviewwithpageheader.cpp 2014-07-25 10:47:08 +0000
545+++ plugins/Dash/listviewwithpageheader.cpp 2014-08-08 14:57:17 +0000
546@@ -330,6 +330,11 @@
547 return m_topSectionItem ? m_topSectionItem->height() : 0;
548 }
549
550+qreal ListViewWithPageHeader::headerItemShownHeight() const
551+{
552+ return m_headerItemShownHeight;
553+}
554+
555 void ListViewWithPageHeader::positionAtBeginning()
556 {
557 if (m_delegateModel->count() <= 0)
558@@ -396,6 +401,7 @@
559 firstItem->setY(firstItem->y() - m_headerItemShownHeight);
560 layout();
561 }
562+ Q_EMIT headerItemShownHeightChanged();
563 }
564 m_contentYAnimation->setTo(to);
565 contentYAnimationType = ContentYAnimationShowHeader;
566@@ -544,6 +550,7 @@
567 m_headerItem->setY(-m_minYExtent);
568 }
569 }
570+ Q_EMIT headerItemShownHeightChanged();
571 } else {
572 // Stick the header item to the top when dragging down
573 m_headerItem->setY(contentY());
574@@ -822,8 +829,8 @@
575 ListItem *nextItem = itemAtIndex(modelIndex + 1);
576 if (nextItem) {
577 listItem->setY(nextItem->y() - listItem->height());
578- } else if (modelIndex == 0 && m_headerItem) {
579- listItem->setY(m_headerItem->height());
580+ } else if (modelIndex == 0) {
581+ listItem->setY(m_headerItem ? m_headerItem->height() : 0);
582 } else if (!m_visibleItems.isEmpty()) {
583 lostItem = true;
584 }
585@@ -1096,6 +1103,7 @@
586 m_headerItemShownHeight = qBound(static_cast<qreal>(0.), m_headerItemShownHeight, newHeaderHeight);
587 updateClipItem();
588 adjustMinYExtent();
589+ Q_EMIT headerItemShownHeightChanged();
590 } else {
591 if (oldHeaderY + oldHeaderHeight > contentY()) {
592 // If the header is shown because its position
593
594=== modified file 'plugins/Dash/listviewwithpageheader.h'
595--- plugins/Dash/listviewwithpageheader.h 2014-06-12 14:08:54 +0000
596+++ plugins/Dash/listviewwithpageheader.h 2014-08-08 14:57:17 +0000
597@@ -53,6 +53,7 @@
598 Q_PROPERTY(QString sectionProperty READ sectionProperty WRITE setSectionProperty NOTIFY sectionPropertyChanged)
599 Q_PROPERTY(bool forceNoClip READ forceNoClip WRITE setForceNoClip NOTIFY forceNoClipChanged)
600 Q_PROPERTY(int stickyHeaderHeight READ stickyHeaderHeight NOTIFY stickyHeaderHeightChanged)
601+ Q_PROPERTY(qreal headerItemShownHeight READ headerItemShownHeight NOTIFY headerItemShownHeightChanged)
602
603 friend class ListViewWithPageHeaderTest;
604 friend class ListViewWithPageHeaderTestSection;
605@@ -81,6 +82,7 @@
606 void setForceNoClip(bool noClip);
607
608 int stickyHeaderHeight() const;
609+ qreal headerItemShownHeight() const;
610
611 Q_INVOKABLE void positionAtBeginning();
612 Q_INVOKABLE void showHeader();
613@@ -100,6 +102,7 @@
614 void sectionPropertyChanged();
615 void forceNoClipChanged();
616 void stickyHeaderHeightChanged();
617+ void headerItemShownHeightChanged();
618
619 protected:
620 void componentComplete() override;
621
622=== modified file 'po/hu.po'
623--- po/hu.po 2014-08-08 07:07:33 +0000
624+++ po/hu.po 2014-08-08 14:57:17 +0000
625@@ -6,16 +6,17 @@
626 msgid ""
627 msgstr ""
628 "Project-Id-Version: unity\n"
629-"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
630+"Report-Msgid-Bugs-To: \n"
631 "POT-Creation-Date: 2014-07-11 14:59+0200\n"
632 "PO-Revision-Date: 2014-08-06 07:41+0000\n"
633 "Last-Translator: Richard Somlói <ricsipontaz@gmail.com>\n"
634 "Language-Team: Hungarian <hu@li.org>\n"
635+"Language: hu\n"
636 "MIME-Version: 1.0\n"
637 "Content-Type: text/plain; charset=UTF-8\n"
638 "Content-Transfer-Encoding: 8bit\n"
639-"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
640-"X-Generator: Launchpad (build 17156)\n"
641+"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
642+"X-Generator: Launchpad (build 17147)\n"
643
644 #: plugins/Unity/Launcher/launcheritem.cpp:43
645 #: plugins/Unity/Launcher/launcheritem.cpp:73
646@@ -73,8 +74,8 @@
647 "You have now mastered the edge gestures and can start using the "
648 "phone<br><br>Tap on the screen to start"
649 msgstr ""
650-"Elsajátította a gesztusokat, és megkezdheti a telefon "
651-"használatát.<br><br>Koppintson a képernyőre a kezdéshez."
652+"Elsajátította a gesztusokat, és megkezdheti a telefon használatát."
653+"<br><br>Koppintson a képernyőre a kezdéshez."
654
655 #: qml/Components/Lockscreen.qml:214
656 msgid "Emergency Call"
657
658=== modified file 'po/sl.po'
659--- po/sl.po 2014-08-08 07:07:33 +0000
660+++ po/sl.po 2014-08-08 14:57:17 +0000
661@@ -6,16 +6,17 @@
662 msgid ""
663 msgstr ""
664 "Project-Id-Version: unity\n"
665-"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
666+"Report-Msgid-Bugs-To: \n"
667 "POT-Creation-Date: 2014-07-11 14:59+0200\n"
668 "PO-Revision-Date: 2014-08-06 06:11+0000\n"
669 "Last-Translator: Damir Jerovšek <Unknown>\n"
670 "Language-Team: Slovenian <sl@li.org>\n"
671+"Language: sl\n"
672 "MIME-Version: 1.0\n"
673 "Content-Type: text/plain; charset=UTF-8\n"
674 "Content-Transfer-Encoding: 8bit\n"
675-"X-Launchpad-Export-Date: 2014-08-08 07:07+0000\n"
676-"X-Generator: Launchpad (build 17156)\n"
677+"X-Launchpad-Export-Date: 2014-08-07 06:27+0000\n"
678+"X-Generator: Launchpad (build 17147)\n"
679
680 #: plugins/Unity/Launcher/launcheritem.cpp:43
681 #: plugins/Unity/Launcher/launcheritem.cpp:73
682
683=== modified file 'po/unity8.pot'
684--- po/unity8.pot 2014-07-11 14:20:12 +0000
685+++ po/unity8.pot 2014-08-08 14:57:17 +0000
686@@ -8,7 +8,7 @@
687 msgstr ""
688 "Project-Id-Version: unity8\n"
689 "Report-Msgid-Bugs-To: \n"
690-"POT-Creation-Date: 2014-07-11 14:59+0200\n"
691+"POT-Creation-Date: 2014-08-08 11:17+0200\n"
692 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
693 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
694 "Language-Team: LANGUAGE <LL@li.org>\n"
695@@ -26,66 +26,82 @@
696 msgid "Unpin shortcut"
697 msgstr ""
698
699+#: qml/Components/Dialogs.qml:142
700+msgid "Are you sure you would like to turn power off?"
701+msgstr ""
702+
703+#: qml/Components/Dialogs.qml:144
704+msgid "Power off"
705+msgstr ""
706+
707+#: qml/Components/Dialogs.qml:153
708+msgid "Restart"
709+msgstr ""
710+
711+#: qml/Components/Dialogs.qml:162
712+msgid "Cancel"
713+msgstr ""
714+
715 #: qml/Components/EdgeDemoOverlay.qml:151
716 msgid "Skip intro"
717 msgstr ""
718
719+#: qml/Components/EdgeDemo.qml:112
720+msgid "Right edge"
721+msgstr ""
722+
723 #: qml/Components/EdgeDemo.qml:113
724-msgid "Right edge"
725-msgstr ""
726-
727-#: qml/Components/EdgeDemo.qml:114
728 msgid "Try swiping from the right edge to unlock the phone"
729 msgstr ""
730
731+#: qml/Components/EdgeDemo.qml:144
732+msgid "Top edge"
733+msgstr ""
734+
735 #: qml/Components/EdgeDemo.qml:145
736-msgid "Top edge"
737-msgstr ""
738-
739-#: qml/Components/EdgeDemo.qml:146
740 msgid "Try swiping from the top edge to access the indicators"
741 msgstr ""
742
743+#: qml/Components/EdgeDemo.qml:170
744+msgid "Close"
745+msgstr ""
746+
747 #: qml/Components/EdgeDemo.qml:171
748-msgid "Close"
749-msgstr ""
750-
751-#: qml/Components/EdgeDemo.qml:172
752 msgid "Swipe up again to close the settings screen"
753 msgstr ""
754
755+#: qml/Components/EdgeDemo.qml:198
756+msgid "Left edge"
757+msgstr ""
758+
759 #: qml/Components/EdgeDemo.qml:199
760-msgid "Left edge"
761-msgstr ""
762-
763-#: qml/Components/EdgeDemo.qml:200
764 msgid "Swipe from the left to reveal the launcher for quick access to apps"
765 msgstr ""
766
767+#: qml/Components/EdgeDemo.qml:226
768+msgid "Well done"
769+msgstr ""
770+
771 #: qml/Components/EdgeDemo.qml:227
772-msgid "Well done"
773-msgstr ""
774-
775-#: qml/Components/EdgeDemo.qml:228
776 msgid ""
777 "You have now mastered the edge gestures and can start using the "
778 "phone<br><br>Tap on the screen to start"
779 msgstr ""
780
781-#: qml/Components/Lockscreen.qml:214
782+#: qml/Components/Lockscreen.qml:220
783 msgid "Emergency Call"
784 msgstr ""
785
786-#: qml/Components/Lockscreen.qml:231
787+#: qml/Components/Lockscreen.qml:243
788 msgid "OK"
789 msgstr ""
790
791-#: qml/Components/PassphraseLockscreen.qml:60
792+#: qml/Components/PassphraseLockscreen.qml:62
793 #, qt-format
794 msgid "Hello %1"
795 msgstr ""
796
797-#: qml/Components/PassphraseLockscreen.qml:60
798+#: qml/Components/PassphraseLockscreen.qml:62
799 msgid "Hello"
800 msgstr ""
801
802@@ -97,19 +113,11 @@
803 msgid "DONE"
804 msgstr ""
805
806-#: qml/Components/SeeMore.qml:35
807-msgid "See more"
808-msgstr ""
809-
810-#: qml/Components/SeeMore.qml:58 qml/Dash/GenericScopeView.qml:330
811+#: qml/Dash/GenericScopeView.qml:358
812 msgid "See less"
813 msgstr ""
814
815-#: qml/Dash/DashApps.qml:37
816-msgid "Recent"
817-msgstr ""
818-
819-#: qml/Dash/GenericScopeView.qml:330
820+#: qml/Dash/GenericScopeView.qml:358
821 msgid "See all"
822 msgstr ""
823
824@@ -133,6 +141,26 @@
825 msgid "Send"
826 msgstr ""
827
828+#: qml/Dash/ScopesOverview.qml:200
829+msgid "Manage Dash"
830+msgstr ""
831+
832+#: qml/Dash/ScopesOverview.qml:405
833+msgid "Done"
834+msgstr ""
835+
836+#: qml/Dash/ScopesOverview.qml:431
837+msgid "Store"
838+msgstr ""
839+
840+#: qml/Dash/ScopesOverviewTab.qml:36
841+msgid "Favorites"
842+msgstr ""
843+
844+#: qml/Dash/ScopesOverviewTab.qml:54
845+msgid "All"
846+msgstr ""
847+
848 #: qml/Greeter/Greeter.qml:157
849 msgid "Swipe to unlock"
850 msgstr ""
851@@ -157,11 +185,11 @@
852 msgid "Speaking..."
853 msgstr ""
854
855-#: qml/Notifications/NotificationMenuItemFactory.qml:91
856+#: qml/Notifications/NotificationMenuItemFactory.qml:100
857 msgid "Show password"
858 msgstr ""
859
860-#: qml/Notifications/NotificationMenuItemFactory.qml:103
861+#: qml/Notifications/NotificationMenuItemFactory.qml:115
862 msgid "Please enter SIM PIN"
863 msgstr ""
864
865@@ -173,35 +201,43 @@
866 msgid "Conference"
867 msgstr ""
868
869-#: qml/Panel/Indicators/MenuItemFactory.qml:583
870+#: qml/Panel/Indicators/MenuItemFactory.qml:651
871 msgid "In queue…"
872 msgstr ""
873
874-#: qml/Panel/Indicators/MenuItemFactory.qml:587
875+#: qml/Panel/Indicators/MenuItemFactory.qml:655
876 msgid "Downloading"
877 msgstr ""
878
879-#: qml/Panel/Indicators/MenuItemFactory.qml:589
880+#: qml/Panel/Indicators/MenuItemFactory.qml:657
881 msgid "Paused, tap to resume"
882 msgstr ""
883
884-#: qml/Panel/Indicators/MenuItemFactory.qml:591
885+#: qml/Panel/Indicators/MenuItemFactory.qml:659
886 msgid "Canceled"
887 msgstr ""
888
889-#: qml/Panel/Indicators/MenuItemFactory.qml:593
890+#: qml/Panel/Indicators/MenuItemFactory.qml:661
891 msgid "Finished"
892 msgstr ""
893
894-#: qml/Panel/Indicators/MenuItemFactory.qml:595
895+#: qml/Panel/Indicators/MenuItemFactory.qml:663
896 msgid "Failed, tap to retry"
897 msgstr ""
898
899+#: qml/Panel/Indicators/ModemInfoItem.qml:105
900+msgid "Unlock SIM"
901+msgstr ""
902+
903+#: qml/Panel/Indicators/RoamingIndication.qml:27
904+msgid "Roaming"
905+msgstr ""
906+
907 #: qml/Panel/SearchIndicator.qml:27
908 msgid "Search"
909 msgstr ""
910
911-#: qml/Shell.qml:359
912+#: qml/Shell.qml:256
913 #, qt-format
914 msgid "Please enter %1"
915 msgstr ""
916
917=== modified file 'qml/Components/PageHeader.qml'
918--- qml/Components/PageHeader.qml 2014-08-06 19:39:30 +0000
919+++ qml/Components/PageHeader.qml 2014-08-08 14:57:17 +0000
920@@ -24,7 +24,7 @@
921 Item {
922 id: root
923 objectName: "pageHeader"
924- implicitHeight: headerContainer.height + units.gu(2) + bottomContainer.height
925+ implicitHeight: headerContainer.height + bottomContainer.height + (showSignatureLine ? units.gu(2) : 0)
926
927 property bool showBackButton: false
928 property string title
929@@ -32,6 +32,7 @@
930 property bool searchEntryEnabled: false
931 property ListModel searchHistory: SearchHistoryModel
932 property alias searchQuery: searchTextField.text
933+ property alias showSignatureLine: bottomBorder.visible
934
935 property alias bottomItem: bottomContainer.children
936 property int paginationCount: 0
937@@ -251,6 +252,7 @@
938
939 actions: [
940 Action {
941+ objectName: "search"
942 iconName: "search"
943 visible: root.searchEntryEnabled
944 onTriggered: {
945
946=== modified file 'qml/Components/ResponsiveGridView.qml'
947--- qml/Components/ResponsiveGridView.qml 2014-07-11 12:12:50 +0000
948+++ qml/Components/ResponsiveGridView.qml 2014-08-08 14:57:17 +0000
949@@ -34,7 +34,7 @@
950 readonly property int cellWidth: gridView.cellWidth
951 readonly property int cellHeight: gridView.cellHeight
952 readonly property int totalContentHeight: {
953- return contentHeightForRows(Math.ceil(gridView.model.count / columns))
954+ return contentHeightForRows(Math.ceil(gridView.model.count / columns), cellHeight)
955 }
956 property alias interactive: gridView.interactive
957 readonly property alias flicking: gridView.flicking
958@@ -47,8 +47,8 @@
959 property alias cacheBuffer: gridView.cacheBuffer
960 readonly property alias currentItem: gridView.currentItem
961
962- function contentHeightForRows(rows) {
963- return rows * cellHeight;
964+ function contentHeightForRows(rows, height) {
965+ return rows * height
966 }
967
968 GridView {
969
970=== removed directory 'qml/Dash/Apps'
971=== modified file 'qml/Dash/CardCarousel.qml'
972--- qml/Dash/CardCarousel.qml 2014-07-11 12:13:08 +0000
973+++ qml/Dash/CardCarousel.qml 2014-08-08 14:57:17 +0000
974@@ -48,8 +48,8 @@
975
976 objectName: "carouselDelegate" + index
977
978- function clicked() { cardCarousel.clicked(index, model.result) }
979- function pressAndHold() { cardCarousel.pressAndHold(index, model.result) }
980+ function clicked() { cardCarousel.clicked(index, model.result, loader.item, model) }
981+ function pressAndHold() { cardCarousel.pressAndHold(index) }
982
983 sourceComponent: cardTool.cardComponent
984 onLoaded: {
985
986=== modified file 'qml/Dash/CardGrid.qml'
987--- qml/Dash/CardGrid.qml 2014-07-18 11:35:47 +0000
988+++ qml/Dash/CardGrid.qml 2014-08-08 14:57:17 +0000
989@@ -26,10 +26,20 @@
990 }
991
992 expandedHeight: grid.totalContentHeight
993- collapsedHeight: Math.min(grid.contentHeightForRows(collapsedRows), expandedHeight)
994+ collapsedHeight: Math.min(grid.contentHeightForRows(collapsedRows, grid.cellHeight), expandedHeight)
995 collapsedItemCount: collapsedRows * grid.columns
996 originY: grid.originY
997
998+ function cardPosition(index) {
999+ var pos = {};
1000+ var row = Math.floor(index / grid.columns);
1001+ var column = index % grid.columns;
1002+ // Bit sad this is not symmetrical
1003+ pos.x = column * grid.cellWidth + grid.margins;
1004+ pos.y = row * grid.cellHeight;
1005+ return pos;
1006+ }
1007+
1008 ResponsiveGridView {
1009 id: grid
1010 anchors.fill: parent
1011@@ -53,6 +63,7 @@
1012 item.objectName = "delegate" + index;
1013 item.width = Qt.binding(function() { return cardTool.cardWidth; });
1014 item.height = Qt.binding(function() { return cardTool.cardHeight; });
1015+ item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight; });
1016 item.fixedArtShapeSize = Qt.binding(function() { return cardTool.artShapeSize; });
1017 item.cardData = Qt.binding(function() { return model; });
1018 item.template = Qt.binding(function() { return cardTool.template; });
1019@@ -62,7 +73,7 @@
1020 }
1021 Connections {
1022 target: loader.item
1023- onClicked: root.clicked(index, result)
1024+ onClicked: root.clicked(index, result, loader.item, model)
1025 onPressAndHold: root.pressAndHold(index)
1026 }
1027 }
1028
1029=== modified file 'qml/Dash/CardVerticalJournal.qml'
1030--- qml/Dash/CardVerticalJournal.qml 2014-07-22 12:17:34 +0000
1031+++ qml/Dash/CardVerticalJournal.qml 2014-08-08 14:57:17 +0000
1032@@ -61,7 +61,7 @@
1033 }
1034 Connections {
1035 target: loader.item
1036- onClicked: root.clicked(index, result)
1037+ onClicked: root.clicked(index, result, loader.item, model)
1038 onPressAndHold: root.pressAndHold(index)
1039 }
1040 }
1041
1042=== modified file 'qml/Dash/Dash.qml'
1043--- qml/Dash/Dash.qml 2014-08-06 19:39:30 +0000
1044+++ qml/Dash/Dash.qml 2014-08-08 14:57:17 +0000
1045@@ -16,6 +16,7 @@
1046
1047 import QtQuick 2.2
1048 import Ubuntu.Components 0.1
1049+import Ubuntu.Gestures 0.1
1050 import Unity 0.2
1051 import Utils 0.1
1052 import Unity.DashCommunicator 0.1
1053@@ -73,26 +74,104 @@
1054 id: scopes
1055 }
1056
1057- Image {
1058+ QtObject {
1059+ id: overviewController
1060+ objectName: "overviewController"
1061+
1062+ property alias enableAnimation: progressAnimation.enabled
1063+ property real progress: 0
1064+ Behavior on progress {
1065+ id: progressAnimation
1066+ UbuntuNumberAnimation { }
1067+ }
1068+ }
1069+
1070+ ScopesOverview {
1071+ id: scopesOverview
1072+ objectName: "scopesOverview"
1073 anchors.fill: parent
1074- source: parent.width > parent.height ? "graphics/paper_landscape.png" : "graphics/paper_portrait.png"
1075- fillMode: Image.PreserveAspectCrop
1076- horizontalAlignment: Image.AlignRight
1077- verticalAlignment: Image.AlignTop
1078+ scope: scopes.overviewScope
1079+ progress: overviewController.progress
1080+ scopeScale: scopeItem.scope ? 0.4 : (1 - overviewController.progress * 0.6)
1081+ visible: scopeScale != 1
1082+ currentIndex: dashContent.currentIndex
1083+ onDone: {
1084+ if (currentTab == 1) {
1085+ animateDashFromAll(dashContent.currentScopeId);
1086+ }
1087+ hide();
1088+ }
1089+ onFavoriteSelected: {
1090+ setCurrentScope(scopeId, false, false);
1091+ dashContentCache.scheduleUpdate();
1092+ hide();
1093+ }
1094+ onAllFavoriteSelected: {
1095+ setCurrentScope(scopeId, false, false);
1096+ dashContentCache.scheduleUpdate();
1097+ animateDashFromAll(dashContent.currentScopeId);
1098+ hide();
1099+ }
1100+ onSearchSelected: {
1101+ var scopeIndex = -1;
1102+ for (var i = 0; i < scopes.count; ++i) {
1103+ if (scopes.getScope(i).id == scopeId) {
1104+ scopeIndex = i;
1105+ break;
1106+ }
1107+ }
1108+ if (scopeIndex >= 0) {
1109+ // Is a favorite one
1110+ setCurrentScope(scopeId, false, false);
1111+ dashContentCache.scheduleUpdate();
1112+ showDashFromPos(pos, size);
1113+ hide();
1114+ } else {
1115+ // Is not a favorite one, activate and get openScope
1116+ scope.activate(result);
1117+ }
1118+ }
1119+ function hide() {
1120+ overviewController.enableAnimation = true;
1121+ overviewController.progress = 0;
1122+ }
1123+ onProgressChanged: {
1124+ if (progress == 0) {
1125+ currentTab = scopeItem.scope ? 1 : 0;
1126+ }
1127+ }
1128+ }
1129+
1130+ ShaderEffectSource {
1131+ id: dashContentCache
1132+ parent: scopesOverview.dashItemEater
1133+ z: 1
1134+ sourceItem: dashContent
1135+ height: sourceItem.height
1136+ width: sourceItem.width
1137+ opacity: 1 - overviewController.progress
1138+ visible: overviewController.progress != 0 && scopeItem.scope === null
1139+ live: false
1140 }
1141
1142 DashContent {
1143 id: dashContent
1144+
1145+ property var scopeThatOpenedScope: null
1146+
1147 objectName: "dashContent"
1148- width: parent.width
1149- height: parent.height
1150+ width: dash.width
1151+ height: dash.height
1152 scopes: scopes
1153- visible: x != -width
1154+ visible: !scopesOverview.showingNonFavoriteScope && x != -width
1155 onGotoScope: {
1156 dash.setCurrentScope(scopeId, true, false);
1157 }
1158 onOpenScope: {
1159+ scopeThatOpenedScope = currentScope;
1160 scopeItem.scope = scope;
1161+ scopesOverview.currentTab = 1;
1162+ scopesOverview.ensureAllScopeVisible(scope.id);
1163 x = -width;
1164 }
1165 onScopeLoaded: {
1166@@ -102,25 +181,63 @@
1167 }
1168 }
1169 scale: dash.contentScale
1170- clip: scale != 1.0 || scopeItem.visible
1171+ clip: scale != 1.0 || scopeItem.visible || overviewController.progress != 0
1172 Behavior on x {
1173 UbuntuNumberAnimation {
1174+ duration: overviewController.progress != 0 ? 0 : UbuntuAnimation.FastDuration
1175 onRunningChanged: {
1176 if (!running && dashContent.x == 0) {
1177- dashContent.closeScope(scopeItem.scope);
1178+ dashContent.scopeThatOpenedScope.closeScope(scopeItem.scope);
1179 scopeItem.scope = null;
1180+ if (overviewController.progress == 0) {
1181+ // Set tab to Favorites only if we are not showing the overview
1182+ scopesOverview.currentTab = 0;
1183+ }
1184 }
1185 }
1186 }
1187 }
1188+
1189+ enabled: overviewController.progress == 0
1190+ opacity: enabled ? 1 : 0
1191+ }
1192+
1193+ DashBackground
1194+ {
1195+ anchors.fill: scopeItem
1196+ visible: scopeItem.visible
1197+ parent: scopeItem.parent
1198+ scale: scopeItem.scale
1199+ opacity: scopeItem.opacity
1200 }
1201
1202 GenericScopeView {
1203 id: scopeItem
1204- anchors.left: dashContent.right
1205+ objectName: "dashTempScopeItem"
1206+
1207+ readonly property real targetOverviewScale: {
1208+ if (scopesOverview.currentTab == 0) {
1209+ return 0.4;
1210+ } else {
1211+ return scopesOverview.allCardSize.width / scopeItem.width;
1212+ }
1213+ }
1214+ readonly property real overviewProgressScale: (1 - overviewController.progress * (1 - targetOverviewScale))
1215+ readonly property var targetOverviewPosition: scope ? scopesOverview.allScopeCardPosition(scope.id) : null
1216+ readonly property real overviewProgressX: scope && scopesOverview.currentTab == 1 && targetOverviewPosition ?
1217+ overviewController.progress * (targetOverviewPosition.x - (width - scopesOverview.allCardSize.width) / 2)
1218+ : 0
1219+ readonly property real overviewProgressY: scope && scopesOverview.currentTab == 1 && targetOverviewPosition ?
1220+ overviewController.progress * (targetOverviewPosition.y - (height - scopesOverview.allCardSize.height) / 2)
1221+ : 0
1222+
1223+ x: overviewController.progress == 0 ? dashContent.x + width : overviewProgressX
1224+ y: overviewController.progress == 0 ? dashContent.y : overviewProgressY
1225 width: parent.width
1226 height: parent.height
1227- scale: dash.contentScale
1228+ scale: dash.contentScale * overviewProgressScale
1229+ enabled: opacity == 1
1230+ opacity: 1 - overviewController.progress
1231 clip: scale != 1.0
1232 visible: scope != null
1233 hasBackAction: true
1234@@ -154,7 +271,7 @@
1235 opacity: 0
1236 visible: opacity > 0
1237
1238- readonly property bool processing: dashContent.processing || scopeItem.processing
1239+ readonly property bool processing: dashContent.processing || scopeItem.processing || scopesOverview.processing
1240
1241 Behavior on opacity {
1242 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
1243@@ -207,4 +324,45 @@
1244 }
1245 }
1246
1247+ Image {
1248+ source: "graphics/overview_hint.png"
1249+ anchors.horizontalCenter: parent.horizontalCenter
1250+ opacity: (scopeItem.scope ? scopeItem.pageHeaderTotallyVisible : dashContent.pageHeaderTotallyVisible) &&
1251+ (overviewDragHandle.enabled || overviewController.progress != 0) ? 1 : 0
1252+ Behavior on opacity {
1253+ enabled: overviewController.progress == 0
1254+ UbuntuNumberAnimation {}
1255+ }
1256+ y: parent.height - height * (1 - overviewController.progress * 4)
1257+ }
1258+
1259+ EdgeDragArea {
1260+ id: overviewDragHandle
1261+ objectName: "overviewDragHandle"
1262+ z: 1
1263+ direction: Direction.Upwards
1264+ enabled: !dashContent.previewShown &&
1265+ dashContent.currentScope &&
1266+ dashContent.currentScope.searchQuery == "" &&
1267+ (overviewController.progress == 0 || dragging)
1268+
1269+ readonly property real fullMovement: units.gu(20)
1270+
1271+ anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
1272+ height: units.gu(2)
1273+
1274+ onSceneDistanceChanged: {
1275+ if (overviewController.enableAnimation) {
1276+ dashContentCache.scheduleUpdate();
1277+ }
1278+ overviewController.enableAnimation = false;
1279+ overviewController.progress = Math.max(0, Math.min(1, sceneDistance / fullMovement));
1280+ }
1281+
1282+ onDraggingChanged: {
1283+ overviewController.enableAnimation = true;
1284+ overviewController.progress = (overviewController.progress > 0.7) ? 1 : 0;
1285+ }
1286+ }
1287+
1288 }
1289
1290=== added file 'qml/Dash/DashBackground.qml'
1291--- qml/Dash/DashBackground.qml 1970-01-01 00:00:00 +0000
1292+++ qml/Dash/DashBackground.qml 2014-08-08 14:57:17 +0000
1293@@ -0,0 +1,24 @@
1294+/*
1295+ * Copyright (C) 2013, 2014 Canonical, Ltd.
1296+ *
1297+ * This program is free software; you can redistribute it and/or modify
1298+ * it under the terms of the GNU General Public License as published by
1299+ * the Free Software Foundation; version 3.
1300+ *
1301+ * This program is distributed in the hope that it will be useful,
1302+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1303+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1304+ * GNU General Public License for more details.
1305+ *
1306+ * You should have received a copy of the GNU General Public License
1307+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1308+ */
1309+
1310+import QtQuick 2.0
1311+
1312+Image {
1313+ source: anchors.fill.width > anchors.fill.height ? "graphics/paper_landscape.png" : "graphics/paper_portrait.png"
1314+ fillMode: Image.PreserveAspectCrop
1315+ horizontalAlignment: Image.AlignRight
1316+ verticalAlignment: Image.AlignTop
1317+}
1318
1319=== modified file 'qml/Dash/DashContent.qml'
1320--- qml/Dash/DashContent.qml 2014-08-06 19:39:30 +0000
1321+++ qml/Dash/DashContent.qml 2014-08-08 14:57:17 +0000
1322@@ -25,8 +25,14 @@
1323
1324 property alias scopes: dashContentList.model
1325 readonly property alias currentIndex: dashContentList.currentIndex
1326+ readonly property string currentScopeId: dashContentList.currentItem ? dashContentList.currentItem.scopeId : ""
1327+ readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
1328+ readonly property bool previewShown: dashContentList.currentItem && dashContentList.currentItem.item ?
1329+ dashContentList.currentItem.item.previewShown : false
1330 readonly property bool processing: dashContentList.currentItem && dashContentList.currentItem.item
1331 && dashContentList.currentItem.item.processing || false
1332+ readonly property bool pageHeaderTotallyVisible: dashContentList.currentItem && dashContentList.currentItem.item
1333+ && dashContentList.currentItem.item.pageHeaderTotallyVisible || false
1334
1335 signal scopeLoaded(string scopeId)
1336 signal gotoScope(string scopeId)
1337@@ -77,15 +83,15 @@
1338 }
1339 }
1340
1341- function closeScope(scope) {
1342- dashContentList.currentItem.theScope.closeScope(scope)
1343- }
1344-
1345 Item {
1346 id: dashContentListHolder
1347
1348 anchors.fill: parent
1349
1350+ DashBackground {
1351+ anchors.fill: parent
1352+ }
1353+
1354 ListView {
1355 id: dashContentList
1356 objectName: "dashContentList"
1357
1358=== modified file 'qml/Dash/DashRenderer.qml'
1359--- qml/Dash/DashRenderer.qml 2014-07-22 12:17:34 +0000
1360+++ qml/Dash/DashRenderer.qml 2014-08-08 14:57:17 +0000
1361@@ -41,7 +41,9 @@
1362 /// Emitted when the user clicked on an item
1363 /// @param index is the index of the clicked item
1364 /// @param result result model of the cliked item, used for activation
1365- signal clicked(int index, var result)
1366+ /// @param item item that has been clicked
1367+ /// @param itemModel model of the item
1368+ signal clicked(int index, var result, var item, var itemModel)
1369
1370 /// Emitted when the user pressed and held on an item
1371 /// @param index is the index of the held item
1372
1373=== modified file 'qml/Dash/GenericScopeView.qml'
1374--- qml/Dash/GenericScopeView.qml 2014-08-06 19:39:30 +0000
1375+++ qml/Dash/GenericScopeView.qml 2014-08-08 14:57:17 +0000
1376@@ -25,7 +25,7 @@
1377 FocusScope {
1378 id: scopeView
1379
1380- readonly property alias navigationShown: dashNavigation.showList
1381+ readonly property bool navigationShown: pageHeaderLoader.item ? pageHeaderLoader.item.bottomItem[0].showList : false
1382 property var scope: null
1383 property SortFilterProxyModel categories: categoryFilter
1384 property bool isCurrent: false
1385@@ -33,8 +33,11 @@
1386 property bool hasBackAction: false
1387 property bool enableHeightBehaviorOnNextCreation: false
1388 property var categoryView: categoryView
1389- property alias paginationCount: pageHeader.paginationCount
1390- property alias paginationIndex: pageHeader.paginationIndex
1391+ property bool showPageHeader: true
1392+ readonly property alias previewShown: previewListView.open
1393+ property int paginationCount: 0
1394+ property int paginationIndex: 0
1395+ property alias pageHeaderTotallyVisible: categoryView.pageHeaderTotallyVisible
1396
1397 property var scopeStyle: ScopeStyle {
1398 style: scope ? scope.customizations : {}
1399@@ -56,6 +59,34 @@
1400 previewListView.open = false;
1401 }
1402
1403+ function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount) {
1404+ if (scope.id === "scopes" || scope.id == "clickscope") {
1405+ // TODO Technically it is possible that calling activate() will make the scope emit
1406+ // previewRequested so that we show a preview but there's no scope that does that yet
1407+ // so it's not implemented
1408+ scope.activate(result)
1409+ } else {
1410+ openPreview(index, resultsModel, limitedCategoryItemCount);
1411+ }
1412+ }
1413+
1414+ function itemPressedAndHeld(index, resultsModel, limitedCategoryItemCount) {
1415+ openPreview(index, resultsModel, limitedCategoryItemCount);
1416+ }
1417+
1418+ function openPreview(index, resultsModel, limitedCategoryItemCount) {
1419+ if (limitedCategoryItemCount > 0) {
1420+ previewLimitModel.model = resultsModel;
1421+ previewLimitModel.limit = limitedCategoryItemCount;
1422+ previewListView.model = previewLimitModel;
1423+ } else {
1424+ previewListView.model = resultsModel;
1425+ }
1426+ previewListView.currentIndex = -1;
1427+ previewListView.currentIndex = index;
1428+ previewListView.open = true;
1429+ }
1430+
1431 Binding {
1432 target: scope
1433 property: "isActive"
1434@@ -72,22 +103,24 @@
1435 }
1436
1437 onIsCurrentChanged: {
1438- pageHeader.resetSearch();
1439+ if (showPageHeader) {
1440+ pageHeaderLoader.item.resetSearch();
1441+ }
1442 previewListView.open = false;
1443 }
1444
1445 Binding {
1446 target: scopeView.scope
1447 property: "searchQuery"
1448- value: pageHeader.searchQuery
1449- when: isCurrent
1450+ value: pageHeaderLoader.item ? pageHeaderLoader.item.searchQuery : ""
1451+ when: isCurrent && showPageHeader
1452 }
1453
1454 Binding {
1455- target: pageHeader
1456+ target: pageHeaderLoader.item
1457 property: "searchQuery"
1458 value: scopeView.scope ? scopeView.scope.searchQuery : ""
1459- when: isCurrent
1460+ when: isCurrent && showPageHeader
1461 }
1462
1463 Connections {
1464@@ -114,10 +147,13 @@
1465 model: scopeView.categories
1466 forceNoClip: previewListView.open
1467 pixelAligned: true
1468- interactive: !dashNavigation.showList
1469+ interactive: !navigationShown
1470
1471 property string expandedCategoryId: ""
1472
1473+ readonly property bool pageHeaderTotallyVisible: scopeView.showPageHeader &&
1474+ ((headerItemShownHeight == 0 && categoryView.contentY <= categoryView.originY) || (headerItemShownHeight == pageHeaderLoader.item.height))
1475+
1476 delegate: ListItems.Base {
1477 id: baseItem
1478 objectName: "dashCategory" + category
1479@@ -223,28 +259,19 @@
1480 Connections {
1481 target: rendererLoader.item
1482 onClicked: {
1483- if (scopeView.scope.id === "scopes" || scopeView.scope.id == "clickscope") {
1484- // TODO Technically it is possible that calling activate() will make the scope emit
1485- // previewRequested so that we show a preview but there's no scope that does that yet
1486- // so it's not implemented
1487- scopeView.scope.activate(result)
1488- } else {
1489- openPreview(index);
1490- }
1491- }
1492- onPressAndHold: openPreview(index)
1493-
1494- function openPreview(index) {
1495+ scopeView.itemClicked(index, result, item, itemModel, target.model, categoryItemCount());
1496+ }
1497+
1498+ onPressAndHold: {
1499+ scopeView.itemPressedAndHeld(index, target.model, categoryItemCount());
1500+ }
1501+
1502+ function categoryItemCount() {
1503+ var categoryItemCount = -1;
1504 if (!rendererLoader.expanded && !seeAllLabel.visible && target.collapsedItemCount > 0) {
1505- previewLimitModel.model = target.model;
1506- previewLimitModel.limit = target.collapsedItemCount;
1507- previewListView.model = previewLimitModel;
1508- } else {
1509- previewListView.model = target.model;
1510+ categoryItemCount = target.collapsedItemCount;
1511 }
1512- previewListView.currentIndex = -1;
1513- previewListView.currentIndex = index;
1514- previewListView.open = true;
1515+ return categoryItemCount;
1516 }
1517 }
1518 Connections {
1519@@ -380,26 +407,35 @@
1520 }
1521 }
1522
1523- pageHeader: PageHeader {
1524- id: pageHeader
1525- objectName: "scopePageHeader"
1526+ pageHeader: scopeView.showPageHeader ? pageHeaderLoader : null
1527+ Loader {
1528+ id: pageHeaderLoader
1529 width: parent.width
1530- title: scopeView.scope ? scopeView.scope.name : ""
1531- showBackButton: scopeView.hasBackAction
1532- searchEntryEnabled: true
1533- scopeStyle: scopeView.scopeStyle
1534-
1535- bottomItem: DashNavigation {
1536- id: dashNavigation
1537- scope: scopeView.scope
1538- width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
1539- anchors.right: parent.right
1540- windowHeight: scopeView.height
1541- windowWidth: scopeView.width
1542- scopeStyle: scopeView.scopeStyle
1543+ sourceComponent: scopeView.showPageHeader ? pageHeaderComponent : undefined
1544+ Component {
1545+ id: pageHeaderComponent
1546+ PageHeader {
1547+ objectName: "scopePageHeader"
1548+ width: parent.width
1549+ title: scopeView.scope ? scopeView.scope.name : ""
1550+ showBackButton: scopeView.hasBackAction
1551+ searchEntryEnabled: true
1552+ scopeStyle: scopeView.scopeStyle
1553+ paginationCount: scopeView.paginationCount
1554+ paginationIndex: scopeView.paginationIndex
1555+
1556+ bottomItem: DashNavigation {
1557+ scope: scopeView.scope
1558+ width: parent.width <= units.gu(60) ? parent.width : units.gu(40)
1559+ anchors.right: parent.right
1560+ windowHeight: scopeView.height
1561+ windowWidth: scopeView.width
1562+ scopeStyle: scopeView.scopeStyle
1563+ }
1564+
1565+ onBackClicked: scopeView.backClicked()
1566+ }
1567 }
1568-
1569- onBackClicked: scopeView.backClicked()
1570 }
1571 }
1572
1573@@ -418,7 +454,9 @@
1574 anchors.left: categoryView.right
1575
1576 onOpenChanged: {
1577- pageHeader.unfocus();
1578+ if (showPageHeader) {
1579+ pageHeaderLoader.item.unfocus();
1580+ }
1581 }
1582 }
1583
1584
1585=== modified file 'qml/Dash/PreviewListView.qml'
1586--- qml/Dash/PreviewListView.qml 2014-07-30 15:46:44 +0000
1587+++ qml/Dash/PreviewListView.qml 2014-08-08 14:57:17 +0000
1588@@ -108,7 +108,7 @@
1589 anchors {
1590 left: parent.left
1591 right: parent.right
1592- top: pageHeader.bottom
1593+ top: header.bottom
1594 bottom: parent.bottom
1595 }
1596
1597
1598=== added file 'qml/Dash/ScopesOverview.qml'
1599--- qml/Dash/ScopesOverview.qml 1970-01-01 00:00:00 +0000
1600+++ qml/Dash/ScopesOverview.qml 2014-08-08 14:57:17 +0000
1601@@ -0,0 +1,531 @@
1602+/*
1603+ * Copyright (C) 2014 Canonical, Ltd.
1604+ *
1605+ * This program is free software; you can redistribute it and/or modify
1606+ * it under the terms of the GNU General Public License as published by
1607+ * the Free Software Foundation; version 3.
1608+ *
1609+ * This program is distributed in the hope that it will be useful,
1610+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1611+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1612+ * GNU General Public License for more details.
1613+ *
1614+ * You should have received a copy of the GNU General Public License
1615+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1616+ */
1617+
1618+import QtQuick 2.0
1619+import Dash 0.1
1620+import Ubuntu.Components 0.1
1621+import "../Components"
1622+
1623+Item {
1624+ id: root
1625+
1626+ // Properties set by parent
1627+ property real progress: 0
1628+ property var scope: null
1629+ property int currentIndex: 0
1630+ property real scopeScale: 1
1631+
1632+ // Properties set and used by parent
1633+ property alias currentTab: tabBar.currentTab
1634+
1635+ // Properties used by parent
1636+ readonly property bool processing: searchResultsViewer.processing || tempScopeItem.processing
1637+ property bool growingDashFromPos: false
1638+ readonly property bool searching: scope && scope.searchQuery == ""
1639+ readonly property bool showingNonFavoriteScope: tempScopeItem.scope != null
1640+ readonly property var dashItemEater: {
1641+ if (!forceXYScalerEater && tabBar.currentTab == 0 && middleItems.count > 0) {
1642+ var loaderItem = middleItems.itemAt(0).item;
1643+ return loaderItem && loaderItem.currentItem ? loaderItem.currentItem : null;
1644+ }
1645+ return scopesOverviewXYScaler;
1646+ }
1647+ readonly property size allCardSize: {
1648+ if (middleItems.count > 1) {
1649+ var loaderItem = middleItems.itemAt(1).item;
1650+ if (loaderItem) {
1651+ var cardTool = loaderItem.cardTool;
1652+ return Qt.size(cardTool.cardWidth, cardTool.cardHeight);
1653+ }
1654+ }
1655+ return Qt.size(0, 0);
1656+ }
1657+
1658+ // Internal properties
1659+ property bool forceXYScalerEater: false
1660+
1661+ signal done()
1662+ signal favoriteSelected(var scopeId)
1663+ signal allFavoriteSelected(var scopeId)
1664+ signal searchSelected(var scopeId, var result, var pos, var size)
1665+
1666+ Connections {
1667+ target: scope
1668+ onOpenScope: {
1669+ var itemPos = scopesOverviewXYScaler.restorePosition;
1670+ var itemSize = scopesOverviewXYScaler.restoreSize;
1671+ scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
1672+ if (itemPos) {
1673+ scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
1674+ scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
1675+ } else {
1676+ scopesOverviewXYScaler.x = 0;
1677+ scopesOverviewXYScaler.y = 0;
1678+ }
1679+ scopesOverviewXYScaler.opacity = 0;
1680+ tempScopeItem.scope = scope;
1681+ middleItems.overrideOpacity = 0;
1682+ scopesOverviewXYScaler.scale = 1;
1683+ scopesOverviewXYScaler.x = 0;
1684+ scopesOverviewXYScaler.y = 0;
1685+ scopesOverviewXYScaler.opacity = 1;
1686+ }
1687+ onGotoScope: {
1688+ if (tabBar.currentTab == 0) {
1689+ root.favoriteSelected(scopeId);
1690+ } else {
1691+ root.allFavoriteSelected(scopeId);
1692+ }
1693+ }
1694+ }
1695+
1696+ Binding {
1697+ target: scope
1698+ property: "isActive"
1699+ value: progress === 1
1700+ }
1701+
1702+ function animateDashFromAll(scopeId) {
1703+ var currentScopePos = allScopeCardPosition(scopeId);
1704+ if (currentScopePos) {
1705+ showDashFromPos(currentScopePos, allCardSize);
1706+ } else {
1707+ console.log("Warning: Could not find Dash OverView All card position for scope", dashContent.currentScopeId);
1708+ }
1709+ }
1710+
1711+ function showDashFromPos(itemPos, itemSize) {
1712+ scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
1713+ scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
1714+ scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
1715+ scopesOverviewXYScaler.opacity = 0;
1716+ root.growingDashFromPos = true;
1717+ scopesOverviewXYScaler.scale = 1;
1718+ scopesOverviewXYScaler.x = 0;
1719+ scopesOverviewXYScaler.y = 0;
1720+ scopesOverviewXYScaler.opacity = 1;
1721+ }
1722+
1723+ function allScopeCardPosition(scopeId) {
1724+ if (middleItems.count > 1) {
1725+ var loaderItem = middleItems.itemAt(1).item;
1726+ if (loaderItem) {
1727+ var pos = loaderItem.scopeCardPosition(scopeId);
1728+ return loaderItem.mapToItem(null, pos.x, pos.y);
1729+ }
1730+ }
1731+ }
1732+
1733+ function ensureAllScopeVisible(scopeId) {
1734+ if (middleItems.count > 1) {
1735+ var loaderItem = middleItems.itemAt(1).item;
1736+ if (loaderItem) {
1737+ var pos = loaderItem.scopeCardPosition(scopeId);
1738+ loaderItem.contentY = Math.min(pos.y, loaderItem.contentHeight - loaderItem.height);
1739+ }
1740+ }
1741+ }
1742+
1743+ onProgressChanged: {
1744+ if (progress == 0) {
1745+ pageHeader.resetSearch();
1746+ pageHeader.unfocus(); // Shouldn't the previous call do this too?
1747+ }
1748+ }
1749+
1750+ ScopeStyle {
1751+ id: overviewScopeStyle
1752+ style: { "foreground-color" : "white", "background-color" : "transparent" }
1753+ }
1754+
1755+ DashBackground {
1756+ anchors.fill: parent
1757+ source: "graphics/dark_background.jpg"
1758+ }
1759+
1760+ Connections {
1761+ target: pageHeader
1762+ onSearchQueryChanged: {
1763+ // Need this in order, otherwise something gets unhappy in rendering
1764+ // of the overlay in carousels because the parent of the dash dies for
1765+ // a moment, this way we make sure it's reparented first
1766+ // by forceXYScalerEater making dashItemEater return scopesOverviewXYScaler
1767+ // before we kill the previous parent by scope.searchQuery
1768+ root.forceXYScalerEater = true;
1769+ root.scope.searchQuery = pageHeader.searchQuery;
1770+ root.forceXYScalerEater = false;
1771+ }
1772+ }
1773+
1774+ Binding {
1775+ target: pageHeader
1776+ property: "searchQuery"
1777+ value: scope ? scope.searchQuery : ""
1778+ }
1779+
1780+ Item {
1781+ id: scopesOverviewContent
1782+ x: previewListView.open ? -width : 0
1783+ Behavior on x { UbuntuNumberAnimation { } }
1784+ width: parent.width
1785+ height: parent.height
1786+
1787+ PageHeader {
1788+ id: pageHeader
1789+ objectName: "scopesOverviewPageHeader"
1790+
1791+ readonly property real yDisplacement: pageHeader.height + tabBar.height + tabBar.anchors.margins
1792+
1793+ y: {
1794+ if (root.progress < 0.5) {
1795+ return -yDisplacement;
1796+ } else {
1797+ return -yDisplacement + (root.progress - 0.5) * yDisplacement * 2;
1798+ }
1799+ }
1800+ width: parent.width
1801+ clip: true
1802+ title: i18n.tr("Manage Dash")
1803+ scopeStyle: overviewScopeStyle
1804+ showSignatureLine: false
1805+ searchEntryEnabled: true
1806+ }
1807+
1808+ ScopesOverviewTab {
1809+ id: tabBar
1810+ anchors {
1811+ left: parent.left
1812+ right: parent.right
1813+ top: pageHeader.bottom
1814+ margins: units.gu(2)
1815+ }
1816+ height: units.gu(4)
1817+
1818+ enabled: opacity == 1
1819+ opacity: !scope || scope.searchQuery == "" ? 1 : 0
1820+ Behavior on opacity { UbuntuNumberAnimation { } }
1821+ }
1822+
1823+ Repeater {
1824+ id: middleItems
1825+ objectName: "scopesOverviewRepeater"
1826+ property real overrideOpacity: -1
1827+ model: scope && scope.searchQuery == "" ? scope.categories : null
1828+ delegate: Loader {
1829+ id: loader
1830+ objectName: "scopesOverviewRepeaterChild" + index
1831+
1832+ height: {
1833+ if (index == 0) {
1834+ return root.height;
1835+ } else {
1836+ return root.height - pageHeader.height - tabBar.height - tabBar.anchors.margins - units.gu(2);
1837+ }
1838+ }
1839+ width: {
1840+ if (index == 0) {
1841+ return root.width / scopeScale;
1842+ } else {
1843+ return root.width;
1844+ }
1845+ }
1846+ x: {
1847+ if (index == 0) {
1848+ return (root.width - width) / 2;
1849+ } else {
1850+ return 0;
1851+ }
1852+ }
1853+ anchors {
1854+ bottom: scopesOverviewContent.bottom
1855+ }
1856+
1857+ scale: index == 0 ? scopeScale : 1
1858+
1859+ opacity: {
1860+ if (middleItems.overrideOpacity >= 0)
1861+ return middleItems.overrideOpacity;
1862+
1863+ if (tabBar.currentTab != index)
1864+ return 0;
1865+
1866+ return index == 0 ? 1 : root.progress;
1867+ }
1868+ Behavior on opacity {
1869+ enabled: root.progress == 1
1870+ UbuntuNumberAnimation { }
1871+ }
1872+ enabled: opacity == 1
1873+
1874+ clip: index == 1
1875+
1876+ CardTool {
1877+ id: cardTool
1878+ objectName: "cardTool"
1879+ count: results.count
1880+ template: model.renderer
1881+ components: model.components
1882+ viewWidth: parent.width
1883+ }
1884+
1885+ source: {
1886+ if (index == 0 && categoryId == "favorites") return "ScopesOverviewFavorites.qml";
1887+ else if (index == 1 && categoryId == "all") return "ScopesOverviewAll.qml";
1888+ else return "";
1889+ }
1890+
1891+ onLoaded: {
1892+ item.model = Qt.binding(function() { return results; });
1893+ item.cardTool = cardTool;
1894+ if (index == 0) {
1895+ item.scopeWidth = Qt.binding(function() { return root.width; });
1896+ item.scopeHeight = Qt.binding(function() { return root.height; });
1897+ item.appliedScale = Qt.binding(function() { return loader.scale });
1898+ item.currentIndex = Qt.binding(function() { return root.currentIndex });
1899+ } else if (index == 1) {
1900+ item.extraHeight = bottomBar.height;
1901+ }
1902+ }
1903+
1904+ Connections {
1905+ target: loader.item
1906+ onClicked: {
1907+ if (tabBar.currentTab == 0) {
1908+ root.favoriteSelected(itemModel.scopeId);
1909+ } else {
1910+ var favoriteScopesItem = middleItems.itemAt(0).item;
1911+ var scopeIndex = favoriteScopesItem.model.scopeIndex(itemModel.scopeId);
1912+ if (scopeIndex >= 0) {
1913+ root.allFavoriteSelected(itemModel.scopeId);
1914+ } else {
1915+ // Will result in an openScope from root.scope
1916+ scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
1917+ scopesOverviewXYScaler.restoreSize = allCardSize;
1918+ root.scope.activate(result);
1919+ }
1920+ }
1921+ }
1922+ onPressAndHold: {
1923+ // Preview can call openScope so make sure restorePosition and restoreSize are set
1924+ scopesOverviewXYScaler.restorePosition = undefined;
1925+ scopesOverviewXYScaler.restoreSize = allCardSize;
1926+
1927+ previewListView.model = target.model;
1928+ previewListView.currentIndex = -1;
1929+ previewListView.currentIndex = index;
1930+ previewListView.open = true;
1931+ }
1932+ }
1933+ }
1934+ }
1935+
1936+ GenericScopeView {
1937+ id: searchResultsViewer
1938+ objectName: "searchResultsViewer"
1939+ anchors {
1940+ top: pageHeader.bottom
1941+ right: parent.right
1942+ left: parent.left
1943+ bottom: parent.bottom
1944+ }
1945+ scope: root.scope && root.scope.searchQuery != "" ? root.scope : null
1946+ scopeStyle: overviewScopeStyle
1947+ enabled: opacity == 1
1948+ showPageHeader: false
1949+ clip: true
1950+ opacity: searchResultsViewer.scope ? 1 : 0
1951+ isCurrent: true
1952+ Behavior on opacity { UbuntuNumberAnimation { } }
1953+
1954+ function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount) {
1955+ pageHeader.closePopup();
1956+ if (itemModel.scopeId) {
1957+ // This can end up in openScope so save restorePosition and restoreSize
1958+ scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
1959+ scopesOverviewXYScaler.restoreSize = Qt.size(item.width, item.height);
1960+ root.searchSelected(itemModel.scopeId, result, item.mapToItem(null, 0, 0), Qt.size(item.width, item.height));
1961+ } else {
1962+ // Not a scope, just activate it
1963+ searchResultsViewer.scope.activate(result);
1964+ }
1965+ }
1966+
1967+ function itemPressedAndHeld(index, resultsModel, limitedCategoryItemCount) {
1968+ // Do nothing
1969+ }
1970+ }
1971+
1972+ Rectangle {
1973+ id: bottomBar
1974+ color: "black"
1975+ height: units.gu(8)
1976+ width: parent.width
1977+ enabled: opacity == 1
1978+ opacity: scope && scope.searchQuery == "" ? 1 : 0
1979+ Behavior on opacity { UbuntuNumberAnimation { } }
1980+ y: {
1981+ if (root.progress < 0.5) {
1982+ return parent.height;
1983+ } else {
1984+ return parent.height - (root.progress - 0.5) * height * 2;
1985+ }
1986+ }
1987+
1988+ AbstractButton {
1989+ objectName: "scopesOverviewDoneButton"
1990+ width: Math.max(label.width + units.gu(2), units.gu(10))
1991+ height: units.gu(4)
1992+ anchors {
1993+ left: parent.left
1994+ leftMargin: units.gu(2)
1995+ verticalCenter: parent.verticalCenter
1996+ }
1997+ Rectangle {
1998+ anchors.fill: parent
1999+ border.color: "white"
2000+ border.width: units.dp(1)
2001+ radius: units.dp(10)
2002+ color: parent.pressed ? "gray" : "transparent"
2003+ }
2004+ Label {
2005+ id: label
2006+ anchors.centerIn: parent
2007+ text: i18n.tr("Done")
2008+ color: parent.pressed ? "black" : "white"
2009+ }
2010+ onClicked: root.done();
2011+ }
2012+
2013+ AbstractButton {
2014+ objectName: "scopesOverviewStoreButton"
2015+ width: Math.max(storeLabel.width, units.gu(10))
2016+ height: units.gu(4)
2017+ anchors {
2018+ right: parent.right
2019+ verticalCenter: parent.verticalCenter
2020+ }
2021+ Icon {
2022+ id: storeImage
2023+ name: "ubuntu-store-symbolic"
2024+ color: "white"
2025+ anchors.horizontalCenter: parent.horizontalCenter
2026+ width: units.gu(2)
2027+ height: units.gu(2)
2028+ }
2029+ Label {
2030+ id: storeLabel
2031+ anchors.horizontalCenter: parent.horizontalCenter
2032+ anchors.top: storeImage.bottom
2033+ text: i18n.tr("Store")
2034+ color: "white"
2035+ }
2036+ onClicked: {
2037+ // Just zoom from the middle
2038+ scopesOverviewXYScaler.restorePosition = undefined;
2039+ scopesOverviewXYScaler.restoreSize = allCardSize;
2040+ scope.performQuery("scope://com.canonical.scopes.clickstore");
2041+ }
2042+ }
2043+ }
2044+ }
2045+
2046+ PreviewListView {
2047+ id: previewListView
2048+ objectName: "scopesOverviewPreviewListView"
2049+ scope: root.scope
2050+ scopeStyle: overviewScopeStyle
2051+ visible: x != width
2052+ width: parent.width
2053+ height: parent.height
2054+ anchors.left: scopesOverviewContent.right
2055+ }
2056+
2057+
2058+
2059+ Item {
2060+ id: scopesOverviewXYScaler
2061+ width: parent.width
2062+ height: parent.height
2063+
2064+ clip: scale != 1.0
2065+ enabled: scale == 1
2066+
2067+ property bool animationsEnabled: root.showingNonFavoriteScope || root.growingDashFromPos
2068+
2069+ property var restorePosition
2070+ property var restoreSize
2071+
2072+ Behavior on x {
2073+ enabled: scopesOverviewXYScaler.animationsEnabled
2074+ UbuntuNumberAnimation { }
2075+ }
2076+ Behavior on y {
2077+ enabled: scopesOverviewXYScaler.animationsEnabled
2078+ UbuntuNumberAnimation { }
2079+ }
2080+ Behavior on opacity {
2081+ enabled: scopesOverviewXYScaler.animationsEnabled
2082+ UbuntuNumberAnimation { }
2083+ }
2084+ Behavior on scale {
2085+ enabled: scopesOverviewXYScaler.animationsEnabled
2086+ UbuntuNumberAnimation {
2087+ onRunningChanged: {
2088+ if (!running) {
2089+ if (root.showingNonFavoriteScope && scopesOverviewXYScaler.scale != 1) {
2090+ root.scope.closeScope(tempScopeItem.scope);
2091+ tempScopeItem.scope = null;
2092+ } else if (root.growingDashFromPos) {
2093+ root.growingDashFromPos = false;
2094+ }
2095+ }
2096+ }
2097+ }
2098+ }
2099+
2100+ DashBackground {
2101+ anchors.fill: tempScopeItem
2102+ visible: tempScopeItem.visible
2103+ parent: tempScopeItem.parent
2104+ }
2105+
2106+ GenericScopeView {
2107+ id: tempScopeItem
2108+ objectName: "scopesOverviewTempScopeItem"
2109+
2110+ width: parent.width
2111+ height: parent.height
2112+ scale: dash.contentScale
2113+ clip: scale != 1.0
2114+ visible: scope != null
2115+ hasBackAction: true
2116+ isCurrent: visible
2117+ onBackClicked: {
2118+ var v = scopesOverviewXYScaler.restoreSize.width / tempScopeItem.width;
2119+ scopesOverviewXYScaler.scale = v;
2120+ if (scopesOverviewXYScaler.restorePosition) {
2121+ scopesOverviewXYScaler.x = scopesOverviewXYScaler.restorePosition.x -(tempScopeItem.width - tempScopeItem.width * v) / 2;
2122+ scopesOverviewXYScaler.y = scopesOverviewXYScaler.restorePosition.y -(tempScopeItem.height - tempScopeItem.height * v) / 2;
2123+ } else {
2124+ scopesOverviewXYScaler.x = 0;
2125+ scopesOverviewXYScaler.y = 0;
2126+ }
2127+ scopesOverviewXYScaler.opacity = 0;
2128+ middleItems.overrideOpacity = -1;
2129+ }
2130+ }
2131+ }
2132+}
2133
2134=== added file 'qml/Dash/ScopesOverviewAll.qml'
2135--- qml/Dash/ScopesOverviewAll.qml 1970-01-01 00:00:00 +0000
2136+++ qml/Dash/ScopesOverviewAll.qml 2014-08-08 14:57:17 +0000
2137@@ -0,0 +1,54 @@
2138+/*
2139+ * Copyright (C) 2014 Canonical, Ltd.
2140+ *
2141+ * This program is free software; you can redistribute it and/or modify
2142+ * it under the terms of the GNU General Public License as published by
2143+ * the Free Software Foundation; version 3.
2144+ *
2145+ * This program is distributed in the hope that it will be useful,
2146+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2147+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2148+ * GNU General Public License for more details.
2149+ *
2150+ * You should have received a copy of the GNU General Public License
2151+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2152+ */
2153+
2154+import QtQuick 2.0
2155+import Ubuntu.Components 0.1
2156+
2157+Flickable {
2158+ id: root
2159+
2160+ property alias model: cardGrid.model
2161+ property alias cardTool: cardGrid.cardTool
2162+
2163+ property real extraHeight: 0
2164+
2165+ signal clicked(int index, var result, var item, var itemModel)
2166+ signal pressAndHold(int index)
2167+
2168+ contentHeight: cardGrid.expandedHeight + extraHeight
2169+ contentWidth: cardGrid.width
2170+ flickableDirection: Flickable.VerticalFlick
2171+
2172+ function scopeCardPosition(scopeId) {
2173+ var index = model.scopeIndex(scopeId);
2174+ var pos = cardGrid.cardPosition(index);
2175+ pos.y = pos.y - root.contentY;
2176+ return pos;
2177+ }
2178+
2179+ CardGrid {
2180+ id: cardGrid
2181+ width: root.width
2182+ height: parent.height
2183+
2184+ onClicked: {
2185+ root.clicked(index, result, item, itemModel);
2186+ }
2187+ onPressAndHold: {
2188+ root.pressAndHold(index);
2189+ }
2190+ }
2191+}
2192
2193=== added file 'qml/Dash/ScopesOverviewFavorites.qml'
2194--- qml/Dash/ScopesOverviewFavorites.qml 1970-01-01 00:00:00 +0000
2195+++ qml/Dash/ScopesOverviewFavorites.qml 2014-08-08 14:57:17 +0000
2196@@ -0,0 +1,73 @@
2197+/*
2198+ * Copyright (C) 2014 Canonical, Ltd.
2199+ *
2200+ * This program is free software; you can redistribute it and/or modify
2201+ * it under the terms of the GNU General Public License as published by
2202+ * the Free Software Foundation; version 3.
2203+ *
2204+ * This program is distributed in the hope that it will be useful,
2205+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2206+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2207+ * GNU General Public License for more details.
2208+ *
2209+ * You should have received a copy of the GNU General Public License
2210+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2211+ */
2212+
2213+import QtQuick 2.0
2214+
2215+Flickable {
2216+ id: root
2217+
2218+ signal clicked(int index, var result, var itemModel)
2219+ signal pressAndHold(int index)
2220+
2221+ property var cardTool: null
2222+ property real scopeHeight: 0
2223+ property real scopeWidth: 0
2224+ property real appliedScale: 1
2225+ property int currentIndex: -1
2226+ property var currentItem: currentIndex < repeater.count ? repeater.itemAt(currentIndex) : null
2227+
2228+ property alias model: repeater.model
2229+
2230+ contentHeight: height
2231+ contentWidth: repeater.count * root.scopeWidth + units.gu(2) / appliedScale * (repeater.count - 1)
2232+
2233+ contentX: {
2234+ var indexX = currentIndex * scopeWidth + units.gu(2) / appliedScale * currentIndex;
2235+ var newContentX = indexX - (width - scopeWidth) / 2;
2236+ newContentX = Math.min(Math.max(newContentX, 0), contentWidth - width);
2237+ return newContentX;
2238+ }
2239+
2240+ Repeater {
2241+ id: repeater
2242+ objectName: "scopesOverviewFavoritesRepeater"
2243+
2244+ delegate: Loader {
2245+ id: loader
2246+
2247+ x: index * root.scopeWidth + units.gu(2) / appliedScale * index
2248+ asynchronous: true
2249+
2250+ sourceComponent: cardTool.cardComponent
2251+ onLoaded: {
2252+ item.fixedArtShapeSize = Qt.binding(function() { return Qt.size(root.scopeWidth, root.scopeHeight); });
2253+ item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight / appliedScale; });
2254+ item.fontScale = Qt.binding(function() { return 1 / appliedScale; });
2255+ item.height = Qt.binding(function() { return root.scopeHeight; });
2256+ item.width = Qt.binding(function() { return root.scopeWidth; });
2257+ item.cardData = Qt.binding(function() { return model; });
2258+ item.template = Qt.binding(function() { return cardTool.template; });
2259+ item.components = Qt.binding(function() { return cardTool.components; });
2260+ item.headerAlignment = Qt.binding(function() { return cardTool.headerAlignment; });
2261+ }
2262+
2263+ Connections {
2264+ target: loader.item
2265+ onClicked: root.clicked(index, result, model)
2266+ }
2267+ }
2268+ }
2269+}
2270
2271=== added file 'qml/Dash/ScopesOverviewTab.qml'
2272--- qml/Dash/ScopesOverviewTab.qml 1970-01-01 00:00:00 +0000
2273+++ qml/Dash/ScopesOverviewTab.qml 2014-08-08 14:57:17 +0000
2274@@ -0,0 +1,74 @@
2275+/*
2276+ * Copyright (C) 2014 Canonical, Ltd.
2277+ *
2278+ * This program is free software; you can redistribute it and/or modify
2279+ * it under the terms of the GNU General Public License as published by
2280+ * the Free Software Foundation; version 3.
2281+ *
2282+ * This program is distributed in the hope that it will be useful,
2283+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2284+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2285+ * GNU General Public License for more details.
2286+ *
2287+ * You should have received a copy of the GNU General Public License
2288+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2289+ */
2290+
2291+import QtQuick 2.3
2292+import Ubuntu.Components 0.1
2293+
2294+Item {
2295+ id: root
2296+
2297+ property int currentTab: 0
2298+
2299+ AbstractButton {
2300+ id: tab1
2301+ height: parent.height
2302+ width: parent.width / 2
2303+ Rectangle {
2304+ anchors.fill: parent
2305+ color: root.currentTab == 0 && root.enabled ? "white" : "transparent"
2306+ radius: units.dp(10)
2307+ }
2308+ Label {
2309+ anchors.centerIn: parent
2310+ text: i18n.tr("Favorites")
2311+ color: root.currentTab == 0 && root.enabled ? "black" : "white"
2312+ }
2313+ onClicked: root.currentTab = 0
2314+ }
2315+ AbstractButton {
2316+ id: tab2
2317+ objectName: "scopesOverviewAllTabButton"
2318+ x: width
2319+ height: parent.height
2320+ width: parent.width / 2
2321+ Rectangle {
2322+ anchors.fill: parent
2323+ color: root.currentTab == 1 && root.enabled ? "white" : "transparent"
2324+ radius: units.dp(10)
2325+ }
2326+ Label {
2327+ anchors.centerIn: parent
2328+ text: i18n.tr("All")
2329+ color: root.currentTab == 1 && root.enabled ? "black" : "white"
2330+ }
2331+ onClicked: root.currentTab = 1
2332+ }
2333+ Rectangle {
2334+ id: centerPiece
2335+ width: root.enabled ? units.dp(10) : units.dp(1)
2336+ height: parent.height
2337+ color: "white"
2338+ x: root.currentTab == 1 ? tab2.x : tab2.x - width
2339+ }
2340+ Rectangle {
2341+ id: border
2342+ anchors.fill: parent
2343+ radius: units.dp(10)
2344+ color: "transparent"
2345+ border.color: centerPiece.color
2346+ border.width: units.dp(1)
2347+ }
2348+}
2349
2350=== added file 'qml/Dash/graphics/dark_background.jpg'
2351Binary files qml/Dash/graphics/dark_background.jpg 1970-01-01 00:00:00 +0000 and qml/Dash/graphics/dark_background.jpg 2014-08-08 14:57:17 +0000 differ
2352=== added file 'qml/Dash/graphics/overview_hint@27.png'
2353Binary files qml/Dash/graphics/overview_hint@27.png 1970-01-01 00:00:00 +0000 and qml/Dash/graphics/overview_hint@27.png 2014-08-08 14:57:17 +0000 differ
2354=== modified file 'tests/autopilot/unity8/shell/tests/test_emulators.py'
2355--- tests/autopilot/unity8/shell/tests/test_emulators.py 2014-07-30 20:01:30 +0000
2356+++ tests/autopilot/unity8/shell/tests/test_emulators.py 2014-08-08 14:57:17 +0000
2357@@ -122,7 +122,7 @@
2358 self._assert_scope_is_opened(scope, scope_id)
2359
2360 def test_open_generic_scope(self):
2361- scope_id = 'scopes'
2362+ scope_id = 'musicaggregator'
2363 scope = self.dash.open_scope(scope_id)
2364 self._assert_scope_is_opened(scope, scope_id)
2365 self.assertIsInstance(scope, dash_emulators.GenericScopeView)
2366
2367=== modified file 'tests/mocks/Unity/CMakeLists.txt'
2368--- tests/mocks/Unity/CMakeLists.txt 2014-08-06 19:38:57 +0000
2369+++ tests/mocks/Unity/CMakeLists.txt 2014-08-08 14:57:17 +0000
2370@@ -22,6 +22,7 @@
2371 set(UnityQML_SOURCES
2372 fake_scope.cpp
2373 fake_scopes.cpp
2374+ fake_scopesoverview.cpp
2375 fake_categories.cpp
2376 fake_navigation.cpp
2377 fake_resultsmodel.cpp
2378
2379=== modified file 'tests/mocks/Unity/fake_categories.cpp'
2380--- tests/mocks/Unity/fake_categories.cpp 2014-07-18 11:35:47 +0000
2381+++ tests/mocks/Unity/fake_categories.cpp 2014-08-08 14:57:17 +0000
2382@@ -109,11 +109,13 @@
2383 }
2384 case RoleComponents:
2385 {
2386- QVariantMap map, artMap;
2387+ QVariantMap map, artMap, attributeMap;
2388 artMap["aspect-ratio"] = "1.0";
2389 artMap["field"] = "art";
2390 map["art"] = artMap;
2391 map["title"] = "HOLA";
2392+ attributeMap["field"] = "attribute";
2393+ map["attributes"] = attributeMap;
2394 return map;
2395 }
2396 case RoleHeaderLink:
2397@@ -156,7 +158,7 @@
2398 }
2399 case RoleComponents:
2400 {
2401- QVariantMap map, artMap;
2402+ QVariantMap map, artMap, attributeMap;
2403 if (index.row() % 2 != 0) {
2404 artMap["aspect-ratio"] = QString("1.%1").arg(index.row());
2405 } else {
2406@@ -166,6 +168,8 @@
2407 map["art"] = artMap;
2408 map["title"] = "HOLA";
2409 map["subtitle"] = "HOLA";
2410+ attributeMap["field"] = "attribute";
2411+ map["attributes"] = attributeMap;
2412 return map;
2413 }
2414 case RoleHeaderLink:
2415
2416=== modified file 'tests/mocks/Unity/fake_resultsmodel.cpp'
2417--- tests/mocks/Unity/fake_resultsmodel.cpp 2014-05-20 10:29:20 +0000
2418+++ tests/mocks/Unity/fake_resultsmodel.cpp 2014-08-08 14:57:17 +0000
2419@@ -58,8 +58,9 @@
2420 case RoleUri:
2421 case RoleCategoryId:
2422 case RoleDndUri:
2423+ return QString();
2424 case RoleResult:
2425- return QString();
2426+ return QString("Result.%1.%2").arg(m_categoryId).arg(index.row());
2427 case RoleTitle:
2428 return QString("Title.%1.%2").arg(m_categoryId).arg(index.row());
2429 case RoleArt:
2430
2431=== modified file 'tests/mocks/Unity/fake_scope.cpp'
2432--- tests/mocks/Unity/fake_scope.cpp 2014-08-06 10:03:55 +0000
2433+++ tests/mocks/Unity/fake_scope.cpp 2014-08-08 14:57:17 +0000
2434@@ -18,14 +18,16 @@
2435 #include <QUrl>
2436
2437 #include "fake_scope.h"
2438+
2439 #include "fake_navigation.h"
2440 #include "fake_resultsmodel.h"
2441+#include "fake_scopes.h"
2442
2443-Scope::Scope(QObject* parent) : Scope(QString(), QString(), false, parent)
2444+Scope::Scope(Scopes* parent) : Scope(QString(), QString(), false, parent)
2445 {
2446 }
2447
2448-Scope::Scope(QString const& id, QString const& name, bool favorite, QObject* parent, int categories)
2449+Scope::Scope(QString const& id, QString const& name, bool favorite, Scopes* parent, int categories)
2450 : unity::shell::scopes::ScopeInterface(parent)
2451 , m_id(id)
2452 , m_name(name)
2453@@ -36,6 +38,7 @@
2454 , m_currentAltNavigationId("altroot")
2455 , m_previewRendererName("preview-generic")
2456 , m_categories(new Categories(categories, this))
2457+ , m_openScope(nullptr)
2458 {
2459 }
2460
2461@@ -158,7 +161,12 @@
2462
2463 void Scope::activate(QVariant const& result)
2464 {
2465- Q_UNUSED(result);
2466+ qDebug() << "Called activate on scope" << m_id << "with result" << result;
2467+ if (result.toString() == "Result.2.2") {
2468+ Scopes *scopes = dynamic_cast<Scopes*>(parent());
2469+ m_openScope = scopes->getScopeFromAll("MockScope9");
2470+ Q_EMIT openScope(m_openScope);
2471+ }
2472 }
2473
2474 PreviewStack* Scope::preview(QVariant const& result)
2475@@ -174,9 +182,13 @@
2476 {
2477 }
2478
2479-void Scope::closeScope(unity::shell::scopes::ScopeInterface* /*scope*/)
2480+void Scope::closeScope(unity::shell::scopes::ScopeInterface* scope)
2481 {
2482- qFatal("Scope::closeScope is not implemented");
2483+ if (scope != m_openScope) {
2484+ qDebug() << scope << m_openScope;
2485+ qFatal("Scope::closeScope got wrong scope in closeScope");
2486+ }
2487+ m_openScope = nullptr;
2488 }
2489
2490 QString Scope::currentNavigationId() const
2491
2492=== modified file 'tests/mocks/Unity/fake_scope.h'
2493--- tests/mocks/Unity/fake_scope.h 2014-08-06 10:03:55 +0000
2494+++ tests/mocks/Unity/fake_scope.h 2014-08-08 14:57:17 +0000
2495@@ -24,13 +24,15 @@
2496
2497 #include <QTimer>
2498
2499+class Scopes;
2500+
2501 class Scope : public unity::shell::scopes::ScopeInterface
2502 {
2503 Q_OBJECT
2504
2505 public:
2506- Scope(QObject* parent = 0);
2507- Scope(QString const& id, QString const& name, bool favorite, QObject* parent = 0, int categories = 20);
2508+ Scope(Scopes* parent = 0);
2509+ Scope(QString const& id, QString const& name, bool favorite, Scopes* parent = 0, int categories = 20);
2510
2511 /* getters */
2512 QString id() const override;
2513@@ -92,7 +94,8 @@
2514
2515 QString m_previewRendererName;
2516
2517- Categories* m_categories;
2518+ unity::shell::scopes::CategoriesInterface* m_categories;
2519+ unity::shell::scopes::ScopeInterface* m_openScope;
2520 };
2521
2522 #endif // FAKE_SCOPE_H
2523
2524=== modified file 'tests/mocks/Unity/fake_scopes.cpp'
2525--- tests/mocks/Unity/fake_scopes.cpp 2014-08-06 19:38:57 +0000
2526+++ tests/mocks/Unity/fake_scopes.cpp 2014-08-08 14:57:17 +0000
2527@@ -18,6 +18,7 @@
2528
2529 // Self
2530 #include "fake_scopes.h"
2531+#include "fake_scopesoverview.h"
2532
2533 // TODO: Implement remaining pieces, like Categories (i.e. LensView now gives warnings)
2534
2535@@ -26,6 +27,7 @@
2536
2537 Scopes::Scopes(QObject *parent)
2538 : unity::shell::scopes::ScopesInterface(parent)
2539+ , m_scopesOverview(nullptr)
2540 , m_loaded(false)
2541 , timer(this)
2542 {
2543@@ -52,10 +54,17 @@
2544 addScope(new Scope("clickscope", "Apps", true, this));
2545 addScope(new Scope("MockScope5", "Videos", true, this));
2546 addScope(new Scope("SingleCategoryScope", "Single", true, this, 1));
2547+ addScope(new Scope("MockScope4", "MS4", true, this));
2548+ addScope(new Scope("MockScope6", "MS6", true, this));
2549+ addScope(new Scope("MockScope7", "MS7", false, this));
2550+ addScope(new Scope("MockScope8", "MS8", false, this));
2551+ addScope(new Scope("MockScope9", "MS9", false, this));
2552+ m_scopesOverview = new ScopesOverview(this);
2553
2554 if (!m_loaded) {
2555 m_loaded = true;
2556 Q_EMIT loadedChanged();
2557+ Q_EMIT overviewScopeChanged();
2558 }
2559 }
2560
2561@@ -64,10 +73,13 @@
2562 timer.stop();
2563 if (m_scopes.size() > 0) {
2564 beginRemoveRows(QModelIndex(), 0, m_scopes.count()-1);
2565- qDeleteAll(m_scopes);
2566+ qDeleteAll(m_allScopes);
2567+ m_allScopes.clear();
2568 m_scopes.clear();
2569 endRemoveRows();
2570 }
2571+ delete m_scopesOverview;
2572+ m_scopesOverview = nullptr;
2573
2574 if (m_loaded) {
2575 m_loaded = false;
2576@@ -113,8 +125,22 @@
2577 return m_scopes[row];
2578 }
2579
2580-unity::shell::scopes::ScopeInterface* Scopes::getScope(QString const&) const
2581-{
2582+unity::shell::scopes::ScopeInterface* Scopes::getScope(QString const &scope_id) const
2583+{
2584+ // According to mh3 Scopes::getScope should only return favorite scopes (i.e the ones in the model)
2585+ for (Scope *scope : m_scopes) {
2586+ if (scope->id() == scope_id)
2587+ return scope;
2588+ }
2589+ return nullptr;
2590+}
2591+
2592+Scope* Scopes::getScopeFromAll(const QString& scope_id) const
2593+{
2594+ for (Scope *scope : m_allScopes) {
2595+ if (scope->id() == scope_id)
2596+ return scope;
2597+ }
2598 return nullptr;
2599 }
2600
2601@@ -135,13 +161,26 @@
2602
2603 unity::shell::scopes::ScopeInterface* Scopes::overviewScope() const
2604 {
2605- return nullptr;
2606+ return m_scopesOverview;
2607+}
2608+
2609+QList<Scope*> Scopes::scopes() const
2610+{
2611+ return m_scopes;
2612+}
2613+
2614+QList<Scope*> Scopes::allScopes() const
2615+{
2616+ return m_allScopes;
2617 }
2618
2619 void Scopes::addScope(Scope* scope)
2620 {
2621 int index = rowCount();
2622- beginInsertRows(QModelIndex(), index, index);
2623- m_scopes.append(scope);
2624- endInsertRows();
2625+ if (scope->favorite()) {
2626+ beginInsertRows(QModelIndex(), index, index);
2627+ m_scopes.append(scope);
2628+ endInsertRows();
2629+ }
2630+ m_allScopes.append(scope);
2631 }
2632
2633=== modified file 'tests/mocks/Unity/fake_scopes.h'
2634--- tests/mocks/Unity/fake_scopes.h 2014-08-06 19:38:57 +0000
2635+++ tests/mocks/Unity/fake_scopes.h 2014-08-08 14:57:17 +0000
2636@@ -53,11 +53,18 @@
2637 int count() const override;
2638 unity::shell::scopes::ScopeInterface* overviewScope() const override;
2639
2640+ // This is used as part of implementation of the other C++ code, not API
2641+ QList<Scope*> scopes() const;
2642+ QList<Scope*> allScopes() const;
2643+ Scope* getScopeFromAll(const QString& scope_id) const;
2644+
2645 private Q_SLOTS:
2646 void updateScopes();
2647
2648 private:
2649- QList<Scope*> m_scopes;
2650+ QList<Scope*> m_scopes; // the favorite ones
2651+ QList<Scope*> m_allScopes;
2652+ Scope *m_scopesOverview;
2653 bool m_loaded;
2654 QTimer timer;
2655 };
2656
2657=== added file 'tests/mocks/Unity/fake_scopesoverview.cpp'
2658--- tests/mocks/Unity/fake_scopesoverview.cpp 1970-01-01 00:00:00 +0000
2659+++ tests/mocks/Unity/fake_scopesoverview.cpp 2014-08-08 14:57:17 +0000
2660@@ -0,0 +1,281 @@
2661+/*
2662+ * Copyright (C) 2014 Canonical, Ltd.
2663+ *
2664+ * This program is free software; you can redistribute it and/or modify
2665+ * it under the terms of the GNU General Public License as published by
2666+ * the Free Software Foundation; version 3.
2667+ *
2668+ * This program is distributed in the hope that it will be useful,
2669+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2670+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2671+ * GNU General Public License for more details.
2672+ *
2673+ * You should have received a copy of the GNU General Public License
2674+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2675+ */
2676+
2677+#include "fake_scopesoverview.h"
2678+
2679+#include "fake_scopes.h"
2680+
2681+#include <paths.h>
2682+
2683+ScopesOverview::ScopesOverview(Scopes* parent)
2684+ : Scope("scopesOverview", "Scopes Overview", false, parent)
2685+{
2686+ delete m_categories; // delete the usual categories, we're not going to use it
2687+ m_scopesOverviewCategories = new ScopesOverviewCategories(parent, this);
2688+ m_searchCategories = new ScopesOverviewSearchCategories(parent, this);
2689+ m_categories = m_scopesOverviewCategories;
2690+}
2691+
2692+void ScopesOverview::setSearchQuery(const QString& search_query)
2693+{
2694+ Scope::setSearchQuery(search_query);
2695+
2696+ auto origCategories = m_categories;
2697+ if (search_query.isEmpty()) m_categories = m_scopesOverviewCategories;
2698+ else m_categories = m_searchCategories;
2699+
2700+ if (m_categories != origCategories)
2701+ Q_EMIT categoriesChanged();
2702+}
2703+
2704+Q_INVOKABLE void ScopesOverview::activate(QVariant const& result)
2705+{
2706+ Scopes *scopes = dynamic_cast<Scopes*>(parent());
2707+ m_openScope = scopes->getScopeFromAll(result.toString());
2708+ Q_EMIT openScope(m_openScope);
2709+}
2710+
2711+ScopesOverviewCategories::ScopesOverviewCategories(Scopes *scopes, QObject* parent)
2712+ : unity::shell::scopes::CategoriesInterface(parent)
2713+ , m_scopes(scopes)
2714+{
2715+}
2716+
2717+int ScopesOverviewCategories::rowCount(const QModelIndex& /*parent*/) const
2718+{
2719+ return 2;
2720+}
2721+
2722+void ScopesOverviewCategories::addSpecialCategory(QString const&, QString const&, QString const&, QString const&, QObject*)
2723+{
2724+ qFatal("Using un-implemented ScopesOverviewCategories::addSpecialCategory");
2725+}
2726+
2727+bool ScopesOverviewCategories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */)
2728+{
2729+ qFatal("Using un-implemented ScopesOverviewCategories::overrideCategoryJson");
2730+}
2731+
2732+QVariant
2733+ScopesOverviewCategories::data(const QModelIndex& index, int role) const
2734+{
2735+ if (!index.isValid()) {
2736+ return QVariant();
2737+ }
2738+
2739+ const QString categoryId = index.row() == 0 ? "favorites" : "all";
2740+
2741+ unity::shell::scopes::ResultsModelInterface *resultsModel = m_resultsModels[index.row()];
2742+ if (!resultsModel) {
2743+ QObject *that = const_cast<ScopesOverviewCategories*>(this);
2744+ QList<Scope*> scopes = index.row() == 0 ? m_scopes->scopes() : m_scopes->allScopes();
2745+ resultsModel = new ScopesOverviewResultsModel(scopes, categoryId, that);
2746+ m_resultsModels[index.row()] = resultsModel;
2747+ }
2748+ switch (role) {
2749+ case RoleCategoryId:
2750+ return categoryId;
2751+ case RoleName:
2752+ return index.row() == 0 ? "Favorites" : "All";
2753+ case RoleIcon:
2754+ return QVariant();
2755+ case RoleRawRendererTemplate:
2756+ qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
2757+ return QVariant();
2758+ case RoleRenderer:
2759+ {
2760+ QVariantMap map;
2761+ map["category-layout"] = "grid";
2762+ map["card-size"] = "small";
2763+ map["overlay"] = true;
2764+ return map;
2765+ }
2766+ case RoleComponents:
2767+ {
2768+ QVariantMap map, artMap;
2769+ artMap["aspect-ratio"] = "0.5";
2770+ artMap["field"] = "art";
2771+ map["art"] = artMap;
2772+ map["title"] = "HOLA";
2773+ return map;
2774+ }
2775+ case RoleResults:
2776+ return QVariant::fromValue(resultsModel);
2777+ case RoleCount:
2778+ return resultsModel->rowCount();
2779+ case RoleHeaderLink:
2780+ return QString();
2781+ default:
2782+ qFatal("Using un-implemented Categories role");
2783+ return QVariant();
2784+ }
2785+}
2786+
2787+
2788+
2789+ScopesOverviewSearchCategories::ScopesOverviewSearchCategories(Scopes *scopes, QObject* parent)
2790+ : unity::shell::scopes::CategoriesInterface(parent)
2791+ , m_scopes(scopes)
2792+{
2793+}
2794+
2795+int ScopesOverviewSearchCategories::rowCount(const QModelIndex& /*parent*/) const
2796+{
2797+ return 2;
2798+}
2799+
2800+void ScopesOverviewSearchCategories::addSpecialCategory(QString const&, QString const&, QString const&, QString const&, QObject*)
2801+{
2802+ qFatal("Using un-implemented ScopesOverviewSearchCategories::addSpecialCategory");
2803+}
2804+
2805+bool ScopesOverviewSearchCategories::overrideCategoryJson(QString const& /* categoryId */, QString const& /* json */)
2806+{
2807+ qFatal("Using un-implemented ScopesOverviewSearchCategories::overrideCategoryJson");
2808+}
2809+
2810+QVariant
2811+ScopesOverviewSearchCategories::data(const QModelIndex& index, int role) const
2812+{
2813+ if (!index.isValid()) {
2814+ return QVariant();
2815+ }
2816+
2817+ const QString categoryId = index.row() == 0 ? "searchA" : "searchB";
2818+
2819+ unity::shell::scopes::ResultsModelInterface *resultsModel = m_resultsModels[index.row()];
2820+ if (!resultsModel) {
2821+ QObject *that = const_cast<ScopesOverviewSearchCategories*>(this);
2822+ QList<Scope *> scopes;
2823+ if (index.row() == 0) {
2824+ scopes << m_scopes->getScopeFromAll("clickscope") << nullptr << m_scopes->getScopeFromAll("MockScope2");
2825+ } else {
2826+ scopes << nullptr << m_scopes->getScopeFromAll("MockScope7") << nullptr << m_scopes->getScopeFromAll("MockScope1");
2827+ }
2828+ resultsModel = new ScopesOverviewResultsModel(scopes, categoryId, that);
2829+ m_resultsModels[index.row()] = resultsModel;
2830+ }
2831+ switch (role) {
2832+ case RoleCategoryId:
2833+ return categoryId;
2834+ case RoleName:
2835+ return index.row() == 0 ? "SearchA" : "SearchB";
2836+ case RoleIcon:
2837+ return QVariant();
2838+ case RoleRawRendererTemplate:
2839+ qFatal("Using un-implemented RoleRawRendererTemplate Categories role");
2840+ return QVariant();
2841+ case RoleRenderer:
2842+ {
2843+ QVariantMap map;
2844+ map["category-layout"] = "grid";
2845+ map["card-size"] = "small";
2846+ map["overlay"] = true;
2847+ return map;
2848+ }
2849+ case RoleComponents:
2850+ {
2851+ QVariantMap map, artMap;
2852+ artMap["aspect-ratio"] = "1";
2853+ artMap["field"] = "art";
2854+ map["art"] = artMap;
2855+ map["title"] = "HOLA";
2856+ return map;
2857+ }
2858+ case RoleResults:
2859+ return QVariant::fromValue(resultsModel);
2860+ case RoleCount:
2861+ return resultsModel->rowCount();
2862+ case RoleHeaderLink:
2863+ return QString();
2864+ default:
2865+ qFatal("Using un-implemented Categories role");
2866+ return QVariant();
2867+ }
2868+}
2869+
2870+
2871+ScopesOverviewResultsModel::ScopesOverviewResultsModel(const QList<Scope *> &scopes, const QString &categoryId, QObject* parent)
2872+ : unity::shell::scopes::ResultsModelInterface(parent)
2873+ , m_scopes(scopes)
2874+ , m_categoryId(categoryId)
2875+{
2876+}
2877+
2878+QString ScopesOverviewResultsModel::categoryId() const
2879+{
2880+ return m_categoryId;
2881+}
2882+
2883+void ScopesOverviewResultsModel::setCategoryId(QString const& /*id*/)
2884+{
2885+ qFatal("Calling un-implemented ScopesOverviewResultsModel::setCategoryId");
2886+}
2887+
2888+int ScopesOverviewResultsModel::scopeIndex(QString const& id) const
2889+{
2890+ const int scopeCount = count();
2891+ for (int i = 0; i < scopeCount; ++i) {
2892+ if (m_scopes[i]->id() == id)
2893+ return i;
2894+ }
2895+ return -1;
2896+}
2897+
2898+QHash<int, QByteArray> ScopesOverviewResultsModel::roleNames() const
2899+{
2900+ QHash<int, QByteArray> roles = unity::shell::scopes::ResultsModelInterface::roleNames();
2901+ roles[RoleBackground + 1] = "scopeId";
2902+ return roles;
2903+}
2904+
2905+int ScopesOverviewResultsModel::rowCount(const QModelIndex& parent) const
2906+{
2907+ Q_UNUSED(parent);
2908+
2909+ return m_scopes.count();
2910+}
2911+
2912+int ScopesOverviewResultsModel::count() const
2913+{
2914+ return rowCount();
2915+}
2916+
2917+QVariant
2918+ScopesOverviewResultsModel::data(const QModelIndex& index, int role) const
2919+{
2920+ unity::shell::scopes::ScopeInterface *scope = m_scopes[index.row()];
2921+ switch (role) {
2922+ case RoleUri:
2923+ case RoleCategoryId:
2924+ case RoleDndUri:
2925+ return QString();
2926+ case RoleResult:
2927+ return scope ? scope->id() : QString("Result.%1.%2").arg(categoryId()).arg(index.row());
2928+ case RoleTitle:
2929+ return scope ? scope->name() : QString("Title.%1.%2").arg(categoryId()).arg(index.row());
2930+ case RoleArt:
2931+ return qmlDirectory() + "graphics/applicationIcons/dash.png";
2932+ case RoleMascot:
2933+ case RoleEmblem:
2934+ case RoleSummary:
2935+ case RoleBackground + 1: // scopeId
2936+ return scope ? scope->id() : nullptr;
2937+ break;
2938+ default:
2939+ return QVariant();
2940+ }
2941+}
2942
2943=== added file 'tests/mocks/Unity/fake_scopesoverview.h'
2944--- tests/mocks/Unity/fake_scopesoverview.h 1970-01-01 00:00:00 +0000
2945+++ tests/mocks/Unity/fake_scopesoverview.h 2014-08-08 14:57:17 +0000
2946@@ -0,0 +1,104 @@
2947+/*
2948+ * Copyright (C) 2014 Canonical, Ltd.
2949+ *
2950+ * This program is free software; you can redistribute it and/or modify
2951+ * it under the terms of the GNU General Public License as published by
2952+ * the Free Software Foundation; version 3.
2953+ *
2954+ * This program is distributed in the hope that it will be useful,
2955+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2956+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2957+ * GNU General Public License for more details.
2958+ *
2959+ * You should have received a copy of the GNU General Public License
2960+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2961+ */
2962+
2963+#ifndef FAKE_SCOPESOVERVIEW_H
2964+#define FAKE_SCOPESOVERVIEW_H
2965+
2966+#include "fake_scope.h"
2967+#include <unity/shell/scopes/ResultsModelInterface.h>
2968+
2969+class Scopes;
2970+
2971+class ScopesOverview : public Scope
2972+{
2973+ Q_OBJECT
2974+
2975+public:
2976+ ScopesOverview(Scopes* parent = 0);
2977+
2978+ void setSearchQuery(const QString& search_query) override;
2979+ Q_INVOKABLE void activate(QVariant const& result) override;
2980+
2981+private:
2982+ unity::shell::scopes::CategoriesInterface *m_scopesOverviewCategories;
2983+ unity::shell::scopes::CategoriesInterface *m_searchCategories;
2984+};
2985+
2986+class ScopesOverviewCategories : public unity::shell::scopes::CategoriesInterface
2987+{
2988+ Q_OBJECT
2989+
2990+public:
2991+ ScopesOverviewCategories(Scopes *scopes, QObject* parent = 0);
2992+
2993+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
2994+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
2995+
2996+ Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;
2997+ Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
2998+
2999+private:
3000+ mutable QHash<int, unity::shell::scopes::ResultsModelInterface*> m_resultsModels;
3001+
3002+ Scopes *m_scopes;
3003+};
3004+
3005+class ScopesOverviewSearchCategories : public unity::shell::scopes::CategoriesInterface
3006+{
3007+ Q_OBJECT
3008+
3009+public:
3010+ ScopesOverviewSearchCategories(Scopes *scopes, QObject* parent = 0);
3011+
3012+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
3013+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
3014+
3015+ Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;
3016+ Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
3017+
3018+private:
3019+ mutable QHash<int, unity::shell::scopes::ResultsModelInterface*> m_resultsModels;
3020+
3021+ Scopes *m_scopes;
3022+};
3023+
3024+class ScopesOverviewResultsModel : public unity::shell::scopes::ResultsModelInterface
3025+{
3026+ Q_OBJECT
3027+
3028+public:
3029+ explicit ScopesOverviewResultsModel(const QList<Scope *> &scopes, const QString &categoryId, QObject* parent = 0);
3030+
3031+ int rowCount(const QModelIndex& parent = QModelIndex()) const override;
3032+ QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
3033+
3034+ /* getters */
3035+ QString categoryId() const override;
3036+ int count() const override;
3037+
3038+ /* setters */
3039+ void setCategoryId(QString const& id) override;
3040+
3041+ /* Special API */
3042+ Q_INVOKABLE int scopeIndex(QString const& id) const;
3043+ QHash<int, QByteArray> roleNames() const override;
3044+
3045+private:
3046+ QList<Scope *> m_scopes;
3047+ QString m_categoryId;
3048+};
3049+
3050+#endif // FAKE_SCOPESOVERVIEW_H
3051
3052=== modified file 'tests/plugins/Dash/cardcreator/1.res'
3053--- tests/plugins/Dash/cardcreator/1.res 2014-08-05 22:51:17 +0000
3054+++ tests/plugins/Dash/cardcreator/1.res 2014-08-08 14:57:17 +0000
3055@@ -61,12 +61,12 @@
3056 id: titleLabel;
3057 objectName: "titleLabel";
3058 anchors { right: parent.right;
3059-rightMargin: units.gu(1);
3060-left: parent.left;
3061-top: artShapeHolder.bottom;
3062- topMargin: units.gu(1);
3063-leftMargin: units.gu(1);
3064- }
3065+ rightMargin: units.gu(1);
3066+ left: parent.left;
3067+ top: artShapeHolder.bottom;
3068+ topMargin: units.gu(1);
3069+ leftMargin: units.gu(1);
3070+ }
3071 elide: Text.ElideRight;
3072 fontSize: "small";
3073 wrapMode: Text.Wrap;
3074
3075=== modified file 'tests/plugins/Dash/cardcreator/1.tst'
3076--- tests/plugins/Dash/cardcreator/1.tst 2014-07-28 15:09:45 +0000
3077+++ tests/plugins/Dash/cardcreator/1.tst 2014-08-08 14:57:17 +0000
3078@@ -1,3 +1,3 @@
3079 template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
3080-components: {"art":{"aspect-ratio":1.6,"field":"art"},"title":{"field":"title"}}
3081+components: {"art":{"aspect-ratio":1.6,"field":"art"},"title":{"field":"title"},"attributes":{}}
3082 result: 1.res
3083
3084=== modified file 'tests/plugins/Dash/cardcreator/2.res'
3085--- tests/plugins/Dash/cardcreator/2.res 2014-07-31 13:33:56 +0000
3086+++ tests/plugins/Dash/cardcreator/2.res 2014-08-08 14:57:17 +0000
3087@@ -55,17 +55,19 @@
3088 spacing: margins;
3089 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
3090 anchors { top: parent.top;
3091- topMargin: units.gu(1);
3092-left: parent.left;
3093- }
3094+ topMargin: units.gu(1);
3095+ left: parent.left;
3096+ }
3097 anchors.right: parent.right;
3098 anchors.margins: margins;
3099- data: [ Image {
3100+ anchors.rightMargin: 0;
3101+ data: [
3102+Image {
3103 id: mascotImage;
3104 objectName: "mascotImage";
3105 anchors { verticalCenter: parent.verticalCenter; }
3106 readonly property int maxSize: Math.max(width, height) * 4;
3107- source: cardData && cardData["mascot"];
3108+ source: cardData && cardData["mascot"] || "";
3109 width: units.gu(6);
3110 height: units.gu(5.625);
3111 sourceSize { width: maxSize; height: maxSize }
3112@@ -74,37 +76,43 @@
3113 verticalAlignment: Image.AlignVCenter;
3114 visible: showHeader;
3115 }
3116-
3117- ,
3118- Column {
3119- anchors.verticalCenter: parent.verticalCenter;
3120- spacing: units.dp(2);
3121- width: parent.width - x;
3122- data: [ Label {
3123+,Item {
3124+ id: headerTitleContainer;
3125+ anchors { verticalCenter: parent.verticalCenter; }
3126+ width: parent.width - x;
3127+ implicitHeight: titleLabel.height + subtitleLabel.height;
3128+ data: [
3129+ Label {
3130 id: titleLabel;
3131 objectName: "titleLabel";
3132- anchors { left: parent.left; right: parent.right }
3133+ anchors { right: parent.right;
3134+ rightMargin: units.gu(1);
3135+ left: parent.left;
3136+ top: parent.top; }
3137 elide: Text.ElideRight;
3138 fontSize: "small";
3139 wrapMode: Text.Wrap;
3140 maximumLineCount: 2;
3141 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3142- color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
3143+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3144 visible: showHeader ;
3145 text: root.title;
3146 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
3147 horizontalAlignment: root.headerAlignment;
3148 }
3149-
3150- ,
3151- Label {
3152+ ,Label {
3153 id: subtitleLabel;
3154 objectName: "subtitleLabel";
3155- anchors { left: parent.left; right: parent.right }
3156+ anchors { right: parent.right;
3157+ left: parent.left;
3158+ rightMargin: units.gu(1);
3159+ top: titleLabel.bottom;
3160+ }
3161+ anchors.topMargin: units.dp(2);
3162 elide: Text.ElideRight;
3163 fontSize: "small";
3164 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3165- color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
3166+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3167 visible: titleLabel.visible && titleLabel.text;
3168 text: cardData && cardData["subtitle"] || "";
3169 font.weight: Font.Light;
3170
3171=== modified file 'tests/plugins/Dash/cardcreator/2.tst'
3172--- tests/plugins/Dash/cardcreator/2.tst 2014-07-28 15:09:45 +0000
3173+++ tests/plugins/Dash/cardcreator/2.tst 2014-08-08 14:57:17 +0000
3174@@ -1,3 +1,3 @@
3175 template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
3176-components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"}}
3177+components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"mascot":{"field":"icon"},"subtitle":{"field":"author"},"title":{"field":"title"},"attributes":{}}
3178 result: 2.res
3179
3180=== modified file 'tests/plugins/Dash/cardcreator/3.res'
3181--- tests/plugins/Dash/cardcreator/3.res 2014-08-05 22:51:17 +0000
3182+++ tests/plugins/Dash/cardcreator/3.res 2014-08-08 14:57:17 +0000
3183@@ -61,12 +61,12 @@
3184 id: titleLabel;
3185 objectName: "titleLabel";
3186 anchors { right: parent.right;
3187-rightMargin: units.gu(1);
3188-left: parent.left;
3189-top: artShapeHolder.bottom;
3190- topMargin: units.gu(1);
3191-leftMargin: units.gu(1);
3192- }
3193+ rightMargin: units.gu(1);
3194+ left: parent.left;
3195+ top: artShapeHolder.bottom;
3196+ topMargin: units.gu(1);
3197+ leftMargin: units.gu(1);
3198+ }
3199 elide: Text.ElideRight;
3200 fontSize: "small";
3201 wrapMode: Text.Wrap;
3202@@ -82,12 +82,12 @@
3203 id: subtitleLabel;
3204 objectName: "subtitleLabel";
3205 anchors { left: titleLabel.left;
3206- leftMargin: titleLabel.leftMargin;
3207- right: titleLabel.right;
3208- rightMargin: titleLabel.rightMargin;
3209- top: titleLabel.bottom;
3210- topMargin: units.dp(2);
3211- }
3212+ leftMargin: titleLabel.leftMargin;
3213+ rightMargin: units.gu(1);
3214+ right: titleLabel.right;
3215+ top: titleLabel.bottom;
3216+ }
3217+ anchors.topMargin: units.dp(2);
3218 elide: Text.ElideRight;
3219 fontSize: "small";
3220 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3221
3222=== modified file 'tests/plugins/Dash/cardcreator/3.tst'
3223--- tests/plugins/Dash/cardcreator/3.tst 2014-07-28 15:09:45 +0000
3224+++ tests/plugins/Dash/cardcreator/3.tst 2014-08-08 14:57:17 +0000
3225@@ -1,3 +1,3 @@
3226 template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
3227-components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"}}
3228+components: {"art":{"aspect-ratio":0.75,"field":"art"},"subtitle":{"field":"price"},"title":{"field":"title"},"attributes":{}}
3229 result: 3.res
3230
3231=== modified file 'tests/plugins/Dash/cardcreator/4.res'
3232--- tests/plugins/Dash/cardcreator/4.res 2014-07-25 13:41:19 +0000
3233+++ tests/plugins/Dash/cardcreator/4.res 2014-08-08 14:57:17 +0000
3234@@ -27,7 +27,9 @@
3235 }
3236 anchors.right: parent.right;
3237 anchors.margins: margins;
3238-data: [ Loader {
3239+ anchors.rightMargin: 0;
3240+data: [
3241+Loader {
3242 id: mascotShapeLoader;
3243 objectName: "mascotShapeLoader";
3244 asynchronous: root.asynchronous;
3245@@ -39,13 +41,12 @@
3246 anchors { verticalCenter: parent.verticalCenter; }
3247 }
3248
3249-,
3250-Image {
3251+,Image {
3252 id: mascotImage;
3253 objectName: "mascotImage";
3254 anchors { verticalCenter: parent.verticalCenter; }
3255 readonly property int maxSize: Math.max(width, height) * 4;
3256- source: cardData && cardData["mascot"];
3257+ source: cardData && cardData["mascot"] || "";
3258 width: units.gu(6);
3259 height: units.gu(5.625);
3260 sourceSize { width: maxSize; height: maxSize }
3261@@ -55,15 +56,19 @@
3262 visible: false;
3263 }
3264
3265-,
3266-Column {
3267- anchors.verticalCenter: parent.verticalCenter;
3268- spacing: units.dp(2);
3269- width: parent.width - x;
3270-data: [ Label {
3271+,Item {
3272+ id: headerTitleContainer;
3273+ anchors { verticalCenter: parent.verticalCenter; }
3274+ width: parent.width - x;
3275+ implicitHeight: titleLabel.height + subtitleLabel.height;
3276+ data: [
3277+Label {
3278 id: titleLabel;
3279 objectName: "titleLabel";
3280- anchors { left: parent.left; right: parent.right }
3281+ anchors { right: parent.right;
3282+ rightMargin: units.gu(1);
3283+ left: parent.left;
3284+ top: parent.top; }
3285 elide: Text.ElideRight;
3286 fontSize: "small";
3287 wrapMode: Text.Wrap;
3288@@ -75,12 +80,15 @@
3289 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
3290 horizontalAlignment: root.headerAlignment;
3291 }
3292-,
3293-Label {
3294+,Label {
3295 id: subtitleLabel;
3296 objectName: "subtitleLabel";
3297- anchors { left: parent.left; right: parent.right }
3298-
3299+ anchors { right: parent.right;
3300+ left: parent.left;
3301+ rightMargin: units.gu(1);
3302+ top: titleLabel.bottom;
3303+ }
3304+ anchors.topMargin: units.dp(2);
3305 elide: Text.ElideRight;
3306 fontSize: "small";
3307 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3308
3309=== modified file 'tests/plugins/Dash/cardcreator/4.tst'
3310--- tests/plugins/Dash/cardcreator/4.tst 2014-07-28 15:09:45 +0000
3311+++ tests/plugins/Dash/cardcreator/4.tst 2014-08-08 14:57:17 +0000
3312@@ -1,3 +1,3 @@
3313 template: {"card-layout":"horizontal","card-size":"large","category-layout":"grid","collapsed-rows":2}
3314-components: {"art":{"aspect-ratio":1},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"}}
3315+components: {"art":{"aspect-ratio":1},"mascot":{"field":"mascot"},"subtitle":{"field":"domain"},"title":{"field":"title"},"attributes":{}}
3316 result: 4.res
3317
3318=== modified file 'tests/plugins/Dash/cardcreator/5.res'
3319--- tests/plugins/Dash/cardcreator/5.res 2014-08-05 22:51:17 +0000
3320+++ tests/plugins/Dash/cardcreator/5.res 2014-08-08 14:57:17 +0000
3321@@ -68,8 +68,9 @@
3322 visible: showHeader && status == Loader.Ready;
3323 sourceComponent: ShaderEffect {
3324 id: overlay;
3325- height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2);
3326- opacity: 0.6;
3327+ height: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2);
3328+ property real luminance: 0.2126 * overlayColor.r + 0.7152 * overlayColor.g + 0.0722 * overlayColor.b;
3329+ property color overlayColor: cardData && cardData["overlayColor"] || "#99000000";
3330 property var source: ShaderEffectSource {
3331 id: shaderSource;
3332 sourceItem: artShapeLoader.item;
3333@@ -90,29 +91,30 @@
3334 varying highp vec2 coord;
3335 uniform sampler2D source;
3336 uniform lowp float qt_Opacity;
3337+ uniform highp vec4 overlayColor;
3338 void main() {
3339 lowp vec4 tex = texture2D(source, coord);
3340- gl_FragColor = vec4(0, 0, 0, tex.a) * qt_Opacity;
3341+ gl_FragColor = vec4(overlayColor.r, overlayColor.g, overlayColor.b, 1) * qt_Opacity * overlayColor.a * tex.a;
3342 }";
3343 }
3344 }
3345 readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
3346 Label {
3347- id: titleLabel;
3348+ id: titleLabel;
3349 objectName: "titleLabel";
3350- anchors { left: parent.left;
3351- leftMargin: units.gu(1);
3352- right: parent.right;
3353- rightMargin: units.gu(1);
3354- top: overlayLoader.top;
3355- topMargin: units.gu(1);
3356- }
3357+ anchors { right: parent.right;
3358+ rightMargin: units.gu(1);
3359+ left: parent.left;
3360+ leftMargin: units.gu(1);
3361+ top: overlayLoader.top;
3362+ topMargin: units.gu(1);
3363+ }
3364 elide: Text.ElideRight;
3365 fontSize: "small";
3366 wrapMode: Text.Wrap;
3367 maximumLineCount: 2;
3368 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3369- color: "white";
3370+ color: overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3371 visible: showHeader && overlayLoader.active;
3372 text: root.title;
3373 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
3374@@ -122,16 +124,16 @@
3375 id: subtitleLabel;
3376 objectName: "subtitleLabel";
3377 anchors { left: titleLabel.left;
3378- leftMargin: titleLabel.leftMargin;
3379- right: titleLabel.right;
3380- rightMargin: titleLabel.rightMargin;
3381- top: titleLabel.bottom;
3382- topMargin: units.dp(2);
3383- }
3384+ leftMargin: titleLabel.leftMargin;
3385+ rightMargin: units.gu(1);
3386+ right: titleLabel.right;
3387+ top: titleLabel.bottom;
3388+ }
3389+ anchors.topMargin: units.dp(2);
3390 elide: Text.ElideRight;
3391 fontSize: "small";
3392 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3393- color: "white";
3394+ color: overlayLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3395 visible: titleLabel.visible && titleLabel.text;
3396 text: cardData && cardData["subtitle"] || "";
3397 font.weight: Font.Light;
3398
3399=== modified file 'tests/plugins/Dash/cardcreator/5.tst'
3400--- tests/plugins/Dash/cardcreator/5.tst 2014-07-28 15:09:45 +0000
3401+++ tests/plugins/Dash/cardcreator/5.tst 2014-08-08 14:57:17 +0000
3402@@ -1,3 +1,3 @@
3403 template: {"card-layout":"vertical","card-size":"medium","category-layout":"carousel","collapsed-rows":2,"overlay":true}
3404-components: {"art":{"aspect-ratio":1,"field":"art"},"subtitle":{"field":"artist"},"title":{"field":"title"}}
3405+components: {"art":{"aspect-ratio":1,"field":"art"},"subtitle":{"field":"artist"},"title":{"field":"title"},"attributes":{}}
3406 result: 5.res
3407
3408=== modified file 'tests/plugins/Dash/cardcreator/6.res'
3409--- tests/plugins/Dash/cardcreator/6.res 2014-08-05 22:51:17 +0000
3410+++ tests/plugins/Dash/cardcreator/6.res 2014-08-08 14:57:17 +0000
3411@@ -13,57 +13,110 @@
3412 property bool asynchronous: true;
3413 property bool showHeader: true;
3414 implicitWidth: childrenRect.width;
3415-onArtShapeBorderSourceChanged: { if (artShapeBorderSource !== undefined && artShapeLoader.item) artShapeLoader.item.borderSource = artShapeBorderSource; }
3416-readonly property size artShapeSize: artShapeLoader.item ? Qt.size(artShapeLoader.item.width, artShapeLoader.item.height) : Qt.size(-1, -1);
3417-Item {
3418- id: artShapeHolder;
3419- height: root.fixedArtShapeSize.height > 0 ? root.fixedArtShapeSize.height : artShapeLoader.height;
3420- width: root.fixedArtShapeSize.width > 0 ? root.fixedArtShapeSize.width : artShapeLoader.width;
3421- anchors { horizontalCenter: parent.horizontalCenter; }
3422- Loader {
3423- id: artShapeLoader;
3424- objectName: "artShapeLoader";
3425- active: cardData && cardData["art"] || false;
3426- asynchronous: root.asynchronous;
3427- visible: status == Loader.Ready;
3428- sourceComponent: UbuntuShape {
3429- id: artShape;
3430- objectName: "artShape";
3431- radius: "medium";
3432- visible: image.status == Image.Ready;
3433- readonly property real fixedArtShapeSizeAspect: (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) ? root.fixedArtShapeSize.width / root.fixedArtShapeSize.height : -1;
3434- readonly property real aspect: fixedArtShapeSizeAspect > 0 ? fixedArtShapeSizeAspect : components !== undefined ? components["art"]["aspect-ratio"] : 1;
3435- Component.onCompleted: { updateWidthHeightBindings(); if (artShapeBorderSource !== undefined) borderSource = artShapeBorderSource; }
3436- Connections { target: root; onFixedArtShapeSizeChanged: updateWidthHeightBindings(); }
3437- function updateWidthHeightBindings() {
3438- if (root.fixedArtShapeSize.height > 0 && root.fixedArtShapeSize.width > 0) {
3439- width = root.fixedArtShapeSize.width;
3440- height = root.fixedArtShapeSize.height;
3441- } else {
3442- width = Qt.binding(function() { return !visible ? 0 : image.width });
3443- height = Qt.binding(function() { return !visible ? 0 : image.height });
3444- }
3445- }
3446- image: Image {
3447- objectName: "artImage";
3448- source: cardData && cardData["art"] || "";
3449- cache: true;
3450- asynchronous: root.asynchronous;
3451- fillMode: Image.PreserveAspectCrop;
3452- width: root.width;
3453- height: width / artShape.aspect;
3454- }
3455- }
3456+Loader {
3457+ id: backgroundLoader;
3458+ objectName: "backgroundLoader";
3459+ anchors.fill: parent;
3460+ asynchronous: root.asynchronous;
3461+ visible: status == Loader.Ready;
3462+ sourceComponent: UbuntuShape {
3463+ objectName: "background";
3464+ radius: "medium";
3465+ color: getColor(0) || "white";
3466+ gradientColor: getColor(1) || color;
3467+ anchors.fill: parent;
3468+ image: backgroundImage.source ? backgroundImage : null;
3469+ property real luminance: 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
3470+ property Image backgroundImage: Image {
3471+ objectName: "backgroundImage";
3472+ source: {
3473+ if (cardData && typeof cardData["background"] === "string") return cardData["background"];
3474+ else if (template && typeof template["card-background"] === "string") return template["card-background"];
3475+ else return "";
3476+ }
3477+ }
3478+ function getColor(index) {
3479+ if (cardData && typeof cardData["background"] === "object"
3480+ && (cardData["background"]["type"] === "color" || cardData["background"]["type"] === "gradient")) {
3481+ return cardData["background"]["elements"][index];
3482+ } else if (template && typeof template["card-background"] === "object"
3483+ && (template["card-background"]["type"] === "color" || template["card-background"]["type"] === "gradient")) {
3484+ return template["card-background"]["elements"][index];
3485+ } else return undefined;
3486+ }
3487+ }
3488+ }
3489+readonly property size artShapeSize: Qt.size(-1, -1);
3490+readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;
3491+Item {
3492+ id: headerTitleContainer;
3493+ anchors { right: parent.right; left: parent.left;
3494+ top: parent.top;
3495+ topMargin: units.gu(1);
3496+ leftMargin: units.gu(1);
3497+ }
3498+ width: parent.width - x;
3499+ implicitHeight: titleLabel.height + subtitleLabel.height;
3500+ data: [
3501+ Label {
3502+ id: titleLabel;
3503+ objectName: "titleLabel";
3504+ anchors { right: emblemImage.left;
3505+ rightMargin: emblemImage.width > 0 ? units.gu(0.5) : 0;
3506+ left: parent.left;
3507+ top: parent.top; }
3508+ elide: Text.ElideRight;
3509+ fontSize: "small";
3510+ wrapMode: Text.Wrap;
3511+ maximumLineCount: 2;
3512+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3513+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3514+ visible: showHeader ;
3515+ text: root.title;
3516+ font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
3517+ horizontalAlignment: root.headerAlignment;
3518 }
3519- }
3520-readonly property int headerHeight: 0;
3521+,Label {
3522+ id: subtitleLabel;
3523+ objectName: "subtitleLabel";
3524+ anchors { right: parent.right;
3525+ left: parent.left;
3526+ rightMargin: units.gu(1);
3527+ top: titleLabel.bottom;
3528+ }
3529+ anchors.topMargin: units.dp(2);
3530+ elide: Text.ElideRight;
3531+ fontSize: "small";
3532+ font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3533+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3534+ visible: titleLabel.visible && titleLabel.text;
3535+ text: cardData && cardData["subtitle"] || "";
3536+ font.weight: Font.Light;
3537+ horizontalAlignment: root.headerAlignment;
3538+ }
3539+,Image {
3540+ id: emblemImage;
3541+ objectName: "emblemImage";
3542+ anchors {
3543+ bottom: titleLabel.baseline;
3544+ right: parent.right;
3545+ rightMargin: status === Image.Ready ? units.gu(1) : 0;
3546+ }
3547+ source: cardData && cardData["emblem"] || "";
3548+ width: height;
3549+ height: status === Image.Ready ? titleLabel.font.pixelSize : 0;
3550+ fillMode: Image.PreserveAspectFit;
3551+ }
3552+
3553+ ]
3554+ }
3555 UbuntuShape {
3556 id: touchdown;
3557 objectName: "touchdown";
3558- anchors { fill: artShapeHolder }
3559+ anchors { fill: backgroundLoader }
3560 visible: root.pressed;
3561 radius: "medium";
3562 borderSource: "radius_pressed.sci"
3563 }
3564-implicitHeight: artShapeHolder.height;
3565+implicitHeight: headerTitleContainer.y + headerTitleContainer.height + units.gu(1);
3566 }
3567
3568=== modified file 'tests/plugins/Dash/cardcreator/6.tst'
3569--- tests/plugins/Dash/cardcreator/6.tst 2014-07-28 15:09:45 +0000
3570+++ tests/plugins/Dash/cardcreator/6.tst 2014-08-08 14:57:17 +0000
3571@@ -1,3 +1,3 @@
3572-template: {"card-layout":"vertical","card-size":"small","category-layout":"grid","collapsed-rows":2}
3573-components: {"art":{"aspect-ratio":1.6,"field":"art"}}
3574+template: {"card-background":{"elements":["#E9E9E9"],"type":"color"},"card-layout":"vertical","card-size":"medium","category-layout":"grid","collapsed-rows":2}
3575+components: {"art":{"aspect-ratio":1},"background":{"field":"background"},"subtitle":{"field":"author"},"title":{"field":"title"},"emblem":{"field":"source"},"attributes":{}}
3576 result: 6.res
3577
3578=== modified file 'tests/plugins/Dash/cardcreator/7.res'
3579--- tests/plugins/Dash/cardcreator/7.res 2014-08-05 22:51:17 +0000
3580+++ tests/plugins/Dash/cardcreator/7.res 2014-08-08 14:57:17 +0000
3581@@ -55,17 +55,19 @@
3582 spacing: margins;
3583 height: root.fixedHeaderHeight != -1 ? root.fixedHeaderHeight : implicitHeight;
3584 anchors { top: parent.top;
3585- topMargin: units.gu(1);
3586-left: parent.left;
3587- }
3588+ topMargin: units.gu(1);
3589+ left: parent.left;
3590+ }
3591 anchors.right: parent.right;
3592 anchors.margins: margins;
3593- data: [ Image {
3594+ anchors.rightMargin: 0;
3595+ data: [
3596+Image {
3597 id: mascotImage;
3598 objectName: "mascotImage";
3599 anchors { verticalCenter: parent.verticalCenter; }
3600 readonly property int maxSize: Math.max(width, height) * 4;
3601- source: cardData && cardData["mascot"];
3602+ source: cardData && cardData["mascot"] || "";
3603 width: units.gu(6);
3604 height: units.gu(5.625);
3605 sourceSize { width: maxSize; height: maxSize }
3606@@ -75,48 +77,58 @@
3607 visible: showHeader;
3608 }
3609
3610- ,
3611- Column {
3612- anchors.verticalCenter: parent.verticalCenter;
3613- spacing: units.dp(2);
3614- width: parent.width - x;
3615- data: [
3616- Label {
3617+,Item {
3618+ id: headerTitleContainer;
3619+ anchors { verticalCenter: parent.verticalCenter; }
3620+ width: parent.width - x;
3621+ implicitHeight: titleLabel.height + subtitleLabel.height + attributesRow.height;
3622+ data: [
3623+ Label {
3624 id: titleLabel;
3625 objectName: "titleLabel";
3626- anchors { left: parent.left; right: parent.right }
3627+ anchors { right: parent.right;
3628+ rightMargin: units.gu(1);
3629+ left: parent.left;
3630+ top: parent.top; }
3631 elide: Text.ElideRight;
3632 fontSize: "small";
3633 wrapMode: Text.Wrap;
3634 maximumLineCount: 2;
3635 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3636- color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
3637+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3638 visible: showHeader ;
3639 text: root.title;
3640 font.weight: components && components["subtitle"] ? Font.DemiBold : Font.Normal;
3641 horizontalAlignment: root.headerAlignment;
3642 }
3643-,
3644-Label {
3645+,Label {
3646 id: subtitleLabel;
3647 objectName: "subtitleLabel";
3648- anchors { left: parent.left; right: parent.right }
3649+ anchors { right: parent.right;
3650+ left: parent.left;
3651+ rightMargin: units.gu(1);
3652+ top: titleLabel.bottom;
3653+ }
3654+ anchors.topMargin: units.dp(2);
3655 elide: Text.ElideRight;
3656 fontSize: "small";
3657 font.pixelSize: Math.round(FontUtils.sizeToPixels(fontSize) * fontScale);
3658- color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
3659+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3660 visible: titleLabel.visible && titleLabel.text;
3661 text: cardData && cardData["subtitle"] || "";
3662 font.weight: Font.Light;
3663 horizontalAlignment: root.headerAlignment;
3664 }
3665-,
3666-CardAttributes {
3667+,CardAttributes {
3668 id: attributesRow;
3669 objectName: "attributesRow";
3670- anchors { left: parent.left; right: parent.right }
3671- color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < 0.7 ? "white" : (root.scopeStyle ? root.scopeStyle.foreground : "grey");
3672- model: cardData["attributes"];
3673+ anchors { right: parent.right;
3674+ left: parent.left;
3675+ rightMargin: units.gu(1);
3676+ top: subtitleLabel.bottom;
3677+ }
3678+ color: backgroundLoader.active && backgroundLoader.item && backgroundLoader.item.luminance < (root.scopeStyle ? root.scopeStyle.threshold : 0.7) ? (root.scopeStyle ? root.scopeStyle.light : "white") : (root.scopeStyle ? root.scopeStyle.dark : "grey");
3679+ model: cardData && cardData["attributes"];
3680 }
3681
3682 ]
3683
3684=== modified file 'tests/plugins/Dash/tst_ScopeStyle.qml'
3685--- tests/plugins/Dash/tst_ScopeStyle.qml 2014-07-25 11:42:06 +0000
3686+++ tests/plugins/Dash/tst_ScopeStyle.qml 2014-08-08 14:57:17 +0000
3687@@ -101,7 +101,7 @@
3688
3689 function test_threshold_data() {
3690 return [
3691- { tag: "default", index: 0, threshold: 0.5020 },
3692+ { tag: "default", index: 0, threshold: 0.7510 },
3693 { tag: "red on black", index: 1, threshold: 0.1063 },
3694 { tag: "green on white", index: 2, threshold: 0.6795 },
3695 { tag: "blue on darkgrey", index: 3, threshold: 0.3675 },
3696
3697=== modified file 'tests/qmltests/Dash/CardHelpers.js'
3698--- tests/qmltests/Dash/CardHelpers.js 2014-08-06 19:38:16 +0000
3699+++ tests/qmltests/Dash/CardHelpers.js 2014-08-08 14:57:17 +0000
3700@@ -60,6 +60,7 @@
3701 "art": "art", \
3702 "subtitle": "subtitle", \
3703 "mascot": "mascot", \
3704+ "emblem": "emblem", \
3705 "overlayColor": "overlayColor", \
3706 "summary": "summary", \
3707 "attributes": "attributes" \
3708
3709=== added file 'tests/qmltests/Dash/artwork/emblem.png'
3710Binary files tests/qmltests/Dash/artwork/emblem.png 1970-01-01 00:00:00 +0000 and tests/qmltests/Dash/artwork/emblem.png 2014-08-08 14:57:17 +0000 differ
3711=== modified file 'tests/qmltests/Dash/tst_Card.qml'
3712--- tests/qmltests/Dash/tst_Card.qml 2014-08-05 22:51:17 +0000
3713+++ tests/qmltests/Dash/tst_Card.qml 2014-08-08 14:57:17 +0000
3714@@ -31,6 +31,7 @@
3715 {
3716 "art": "../../../tests/qmltests/Dash/artwork/music-player-design.png",
3717 "mascot": "../../../tests/qmltests/Dash/artwork/avatar.png",
3718+ "emblem": "../../../tests/qmltests/Dash/artwork/emblem.png",
3719 "title": "foo",
3720 "subtitle": "bar",
3721 "summary": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
3722@@ -270,7 +271,7 @@
3723 { tag: "Large", width: units.gu(38), index: 2 },
3724 { tag: "Wide", height: units.gu(19), size: "large", index: 3 },
3725 { tag: "Tall", height: units.gu(38) / 0.7, size: "large", width: units.gu(38), index: 4 },
3726- { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) * 2 }, index: 0 },
3727+ { tag: "VerticalWidth", width: function() { return headerRow.width + units.gu(1) }, index: 0 },
3728 { tag: "HorizontalHeight", height: function() { return headerRow.height + units.gu(1) * 2 }, index: 5 },
3729 { tag: "HorizontalWidth", width: function() { return headerRow.x - units.gu(1) }, index: 5 },
3730 ]
3731@@ -458,6 +459,23 @@
3732 tryCompareFunction(function() { return Qt.colorEqual(subtitle.color, fontColor); }, true);
3733 }
3734
3735+ function test_emblemImage_data() {
3736+ return [
3737+ { tag: "Art and summary", emblem: true, index: 0 },
3738+ { tag: "Art and summary, small", emblem: false, index: 1 },
3739+ { tag: "No header", emblem: false, index: 7 },
3740+ { tag: "With background", emblem: true, index: 10 },
3741+ ];
3742+ }
3743+
3744+ function test_emblemImage(data) {
3745+ selector.selectedIndex = data.index;
3746+ waitForRendering(card);
3747+
3748+ var emblemImage = findChild(card, "emblemImage");
3749+ compare(emblemImage !== null, data.emblem);
3750+ }
3751+
3752 function test_mascotShape_data() {
3753 return [
3754 { tag: "Art and summary", shape: false, index: 0 },
3755
3756=== modified file 'tests/qmltests/Dash/tst_Dash.qml'
3757--- tests/qmltests/Dash/tst_Dash.qml 2014-08-06 14:50:25 +0000
3758+++ tests/qmltests/Dash/tst_Dash.qml 2014-08-08 14:57:17 +0000
3759@@ -20,8 +20,6 @@
3760 import Ubuntu.Components 0.1
3761 import Unity.Test 0.1 as UT
3762
3763-// TODO We don't have any tests for the overlay scope functionality.
3764-
3765 Item {
3766 id: shell
3767 width: units.gu(40)
3768@@ -61,9 +59,9 @@
3769 function get_scope_data() {
3770 return [
3771 { tag: "MockScope1", visualIndex: 0 },
3772- { tag: "MockScope2", visualIndex: 1 },
3773- { tag: "clickscope", visualIndex: 2 },
3774- { tag: "MockScope5", visualIndex: 3 },
3775+ { tag: "MockScope2", visualIndex: -1 },
3776+ { tag: "clickscope", visualIndex: 1 },
3777+ { tag: "MockScope5", visualIndex: 2 },
3778 ]
3779 }
3780
3781@@ -79,10 +77,234 @@
3782 tryCompare(dashContentList, "count", 0);
3783 scopes.load();
3784 tryCompare(scopes, "loaded", true);
3785- tryCompare(dashContentList, "count", 5);
3786+ tryCompare(dashContentList, "count", 6);
3787
3788 verify(dashContentList != undefined);
3789- tryCompare(dashContentList, "currentIndex", data.visualIndex);
3790+ if (data.visualIndex == -1) {
3791+ tryCompare(dashContentList, "currentIndex", 0);
3792+ expectFail(data.tag, "non favorite scopes should not be visble in the scopes model");
3793+ compare(dashContentList.currentItem.scopeId, data.tag); // this should fail
3794+ } else {
3795+ tryCompare(dashContentList, "currentIndex", data.visualIndex);
3796+ compare(dashContentList.currentItem.scopeId, data.tag);
3797+ }
3798+ }
3799+
3800+ function test_dash_overview_show_select_same_favorite() {
3801+ // Wait for stuff to be loaded
3802+ tryCompare(scopes, "loaded", true);
3803+ var dashContentList = findChild(dash, "dashContentList");
3804+ tryCompare(dashContentList, "count", 6);
3805+ var mockScope1Loader = findChild(dash, "MockScope1 loader");
3806+ tryCompareFunction(function() { return mockScope1Loader.item != null; }, true);
3807+
3808+ // Show the overview
3809+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
3810+ var overviewController = findInvisibleChild(dash, "overviewController");
3811+ tryCompare(overviewController, "progress", 1);
3812+
3813+ // Make sure tab is where it should
3814+ var scopesOverview = findChild(dash, "scopesOverview");
3815+ compare(scopesOverview.currentTab, 0);
3816+
3817+ // Make sure stuff is loaded
3818+ var scopesOverviewFavoritesRepeater = findChild(dash, "scopesOverviewFavoritesRepeater");
3819+ tryCompare(scopesOverviewFavoritesRepeater, "count", 6);
3820+ tryCompareFunction(function() { return scopesOverviewFavoritesRepeater.itemAt(0).item != null; }, true);
3821+ waitForRendering(scopesOverviewFavoritesRepeater.itemAt(0).item);
3822+
3823+ // Click in first item
3824+ mouseClick(scopesOverviewFavoritesRepeater.itemAt(0).item, 0, 0);
3825+
3826+ // Make sure animation went back
3827+ tryCompare(overviewController, "progress", 0);
3828+ compare(dashContentList.currentIndex, 0);
3829+ }
3830+
3831+ function test_dash_overview_show_select_different_favorite() {
3832+ // Wait for stuff to be loaded
3833+ tryCompare(scopes, "loaded", true);
3834+ var dashContentList = findChild(dash, "dashContentList");
3835+ tryCompare(dashContentList, "count", 6);
3836+ var mockScope1Loader = findChild(dash, "MockScope1 loader");
3837+ tryCompareFunction(function() { return mockScope1Loader.item != null; }, true);
3838+
3839+ // Show the overview
3840+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
3841+ var overviewController = findInvisibleChild(dash, "overviewController");
3842+ tryCompare(overviewController, "progress", 1);
3843+
3844+ // Make sure tab is where it should
3845+ var scopesOverview = findChild(dash, "scopesOverview");
3846+ compare(scopesOverview.currentTab, 0);
3847+
3848+ // Make sure stuff is loaded
3849+ var scopesOverviewFavoritesRepeater = findChild(dash, "scopesOverviewFavoritesRepeater");
3850+ tryCompare(scopesOverviewFavoritesRepeater, "count", 6);
3851+ tryCompareFunction(function() { return scopesOverviewFavoritesRepeater.itemAt(0).item != null; }, true);
3852+ waitForRendering(scopesOverviewFavoritesRepeater.itemAt(1).item);
3853+
3854+ // Click in first item
3855+ mouseClick(scopesOverviewFavoritesRepeater.itemAt(1).item, 0, 0);
3856+
3857+ // Make sure animation went back
3858+ tryCompare(overviewController, "progress", 0);
3859+ compare(dashContentList.currentIndex, 1);
3860+ }
3861+
3862+ function test_dash_overview_all_temp_scope_done_from_all() {
3863+ // Wait for stuff to be loaded
3864+ tryCompare(scopes, "loaded", true);
3865+ var dashContentList = findChild(dash, "dashContentList");
3866+ tryCompare(dashContentList, "count", 6);
3867+ var mockScope1Loader = findChild(dash, "MockScope1 loader");
3868+ tryCompareFunction(function() { return mockScope1Loader.item != null; }, true);
3869+
3870+ // Show the overview
3871+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
3872+ var overviewController = findInvisibleChild(dash, "overviewController");
3873+ tryCompare(overviewController, "progress", 1);
3874+
3875+ // Make sure tab is where it should
3876+ var scopesOverview = findChild(dash, "scopesOverview");
3877+ compare(scopesOverview.currentTab, 0);
3878+
3879+ // Make sure stuff is loaded
3880+ var scopesOverviewFavoritesRepeater = findChild(dash, "scopesOverviewFavoritesRepeater");
3881+ tryCompare(scopesOverviewFavoritesRepeater, "count", 6);
3882+ tryCompareFunction(function() { return scopesOverviewFavoritesRepeater.itemAt(0).item != null; }, true);
3883+ waitForRendering(scopesOverviewFavoritesRepeater.itemAt(1).item);
3884+
3885+ // Click on the all tab
3886+ var scopesOverviewAllTabButton = findChild(dash, "scopesOverviewAllTabButton");
3887+ mouseClick(scopesOverviewAllTabButton, 0, 0);
3888+
3889+ // Wait for all tab to be enabled (animation finish)
3890+ var scopesOverviewAllView = findChild(dash, "scopesOverviewRepeaterChild1");
3891+ tryCompare(scopesOverviewAllView, "enabled", true);
3892+
3893+ // Click on a temp scope
3894+ var tempScopeCard = findChild(scopesOverviewAllView, "delegate1");
3895+ mouseClick(tempScopeCard, 0, 0);
3896+
3897+ // Check the bottom edge (overview) is disabled from temp scope
3898+ var overviewDragHandle = findChild(dash, "overviewDragHandle");
3899+ compare(overviewDragHandle.enabled, false);
3900+
3901+ // Check temp scope is there
3902+ var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
3903+ tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);
3904+ tryCompare(scopesOverviewTempScopeItem, "enabled", true);
3905+
3906+ // Go back
3907+ var scopesOverviewTempScopeItemHeader = findChild(scopesOverviewTempScopeItem, "scopePageHeader");
3908+ var backButton = findChild(findChild(scopesOverviewTempScopeItemHeader, "innerPageHeader"), "backButton");
3909+ mouseClick(backButton, 0, 0);
3910+
3911+ // Check temp scope is gone
3912+ var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
3913+ tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope == null; }, true);
3914+ tryCompare(scopesOverviewTempScopeItem, "enabled", false);
3915+
3916+ // Press on done
3917+ var scopesOverviewDoneButton = findChild(scopesOverview, "scopesOverviewDoneButton");
3918+ mouseClick(scopesOverviewDoneButton, 0, 0);
3919+
3920+ // Check the dash overview is gone
3921+ tryCompare(overviewController, "progress", 0);
3922+
3923+ // Original list is still on 0
3924+ compare(dashContentList.currentIndex, 0);
3925+ }
3926+
3927+ function test_temp_scope_dash_overview_all_search_temp_scope_favorite_from_all() {
3928+ // Wait for stuff to be loaded
3929+ tryCompare(scopes, "loaded", true);
3930+ var dashContentList = findChild(dash, "dashContentList");
3931+ tryCompare(dashContentList, "count", 6);
3932+ var mockScope1Loader = findChild(dash, "MockScope1 loader");
3933+ tryCompareFunction(function() { return mockScope1Loader.item != null; }, true);
3934+
3935+ // Swipe right to Apps scope
3936+ touchFlick(dash, dash.width - 1, units.gu(1), dash.width - units.gu(10), units.gu(1));
3937+ tryCompare(dashContentList, "contentX", dashContentList.width);
3938+ tryCompare(dashContentList, "currentIndex", 1);
3939+
3940+ // Click on card that opens temp scope
3941+ var categoryListView = findChild(dashContentList.currentItem, "categoryListView");
3942+ var dashCategory2 = findChild(categoryListView, "dashCategory2");
3943+ tryCompareFunction(function() {
3944+ var d = findChild(dashCategory2, "delegate2");
3945+ if (d) return true;
3946+ categoryListView.contentY += 100;
3947+ return false;
3948+ }, true);
3949+ var card2 = findChild(dashCategory2, "delegate2");
3950+ waitForRendering(card2);
3951+ mouseClick(card2, card2.width / 2, card2.height / 2);
3952+
3953+ // Wait for temp scope to be there
3954+ var dashTempScopeItem = findChild(dash, "dashTempScopeItem");
3955+ tryCompare(dashTempScopeItem, "x", 0);
3956+
3957+ // Show the overview
3958+ touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
3959+ var overviewController = findInvisibleChild(dash, "overviewController");
3960+ tryCompare(overviewController, "progress", 1);
3961+
3962+ // Make sure tab is where it should
3963+ var scopesOverview = findChild(dash, "scopesOverview");
3964+ compare(scopesOverview.currentTab, 1);
3965+
3966+ // Do a search
3967+ var scopesOverviewPageHeader = findChild(scopesOverview, "scopesOverviewPageHeader");
3968+ var searchButton = findChild(scopesOverviewPageHeader, "search_header_button");
3969+ mouseClick(searchButton, 0, 0);
3970+
3971+ // Type something
3972+ keyClick(Qt.Key_H);
3973+
3974+ // Check results grid is there and the other lists are not
3975+ var searchResultsViewer = findChild(scopesOverview, "searchResultsViewer");
3976+ var scopesOverviewRepeater = findChild(dash, "scopesOverviewRepeater");
3977+ tryCompare(searchResultsViewer, "opacity", 1);
3978+ tryCompare(scopesOverviewRepeater, "count", 0);
3979+
3980+ // Click on a temp scope in the search
3981+ var dashCategorysearchA = findChild(searchResultsViewer, "dashCategorysearchA");
3982+ var cardTempScope = findChild(dashCategorysearchA, "delegate2");
3983+ waitForRendering(cardTempScope);
3984+ mouseClick(cardTempScope, cardTempScope.width / 2, cardTempScope.height / 2);
3985+
3986+ // Check the bottom edge (overview) is disabled from temp scope
3987+ var overviewDragHandle = findChild(dash, "overviewDragHandle");
3988+ compare(overviewDragHandle.enabled, false);
3989+
3990+ // Check temp scope is there
3991+ var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
3992+ tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);
3993+ tryCompare(scopesOverviewTempScopeItem, "enabled", true);
3994+
3995+ // Go back
3996+ var scopesOverviewTempScopeItemHeader = findChild(scopesOverviewTempScopeItem, "scopePageHeader");
3997+ var backButton = findChild(findChild(scopesOverviewTempScopeItemHeader, "innerPageHeader"), "backButton");
3998+ mouseClick(backButton, 0, 0);
3999+
4000+ // Check temp scope is gone
4001+ var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
4002+ tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope == null; }, true);
4003+ tryCompare(scopesOverviewTempScopeItem, "enabled", false);
4004+
4005+ // Press on a favorite
4006+ var dashCategorysearchB = findChild(searchResultsViewer, "dashCategorysearchB");
4007+ var cardFavSearch = findChild(dashCategorysearchB, "delegate3");
4008+ mouseClick(cardFavSearch, 0, 0);
4009+
4010+ // Check the dash overview is gone
4011+ tryCompare(overviewController, "progress", 0);
4012+
4013+ // Original list went to the favorite
4014+ compare(dashContentList.currentIndex, 0);
4015 }
4016
4017 function test_setCurrentScope() {
4018
4019=== modified file 'tests/qmltests/Dash/tst_DashContent.qml'
4020--- tests/qmltests/Dash/tst_DashContent.qml 2014-08-06 10:16:59 +0000
4021+++ tests/qmltests/Dash/tst_DashContent.qml 2014-08-08 14:57:17 +0000
4022@@ -70,7 +70,7 @@
4023 function loadScopes() {
4024 scopeLoadedSpy.clear();
4025 scopesModel.load();
4026- tryCompare(scopeLoadedSpy, "count", 4);
4027+ tryCompare(scopeLoadedSpy, "count", 6);
4028 }
4029
4030 function init() {
4031@@ -114,7 +114,8 @@
4032
4033 loadScopes();
4034
4035- verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < 5);
4036+ compare(dashContentList.count, 6);
4037+ verify(dashContentList.currentIndex >= 0 && dashContentList.currentIndex < dashContentList.count);
4038 }
4039
4040 function test_show_header_on_list_movement() {
4041@@ -170,7 +171,7 @@
4042
4043 // test greater than scope count.
4044 var currentScopeIndex = dashContent.currentIndex;
4045- dashContent.setCurrentScopeAtIndex(8, true, false);
4046+ dashContent.setCurrentScopeAtIndex(18, true, false);
4047 compare(dashContent.currentIndex, currentScopeIndex, "Scope should not change if changing to greater index than count");
4048 }
4049
4050@@ -189,9 +190,9 @@
4051 function test_scope_mapping_data() {
4052 return [
4053 {tag: "index0", index: 0, objectName: "MockScope1"},
4054- {tag: "index1", index: 1, objectName: "MockScope2"},
4055- {tag: "index2", index: 2, objectName: "clickscope"},
4056- {tag: "index3", index: 3, objectName: "MockScope5"}
4057+ {tag: "index1", index: 1, objectName: "clickscope"},
4058+ {tag: "index2", index: 2, objectName: "MockScope5"},
4059+ {tag: "index3", index: 3, objectName: "SingleCategoryScope"}
4060 ]
4061 }
4062
4063
4064=== modified file 'tests/qmltests/Dash/tst_GenericScopeView.qml'
4065--- tests/qmltests/Dash/tst_GenericScopeView.qml 2014-08-06 19:39:30 +0000
4066+++ tests/qmltests/Dash/tst_GenericScopeView.qml 2014-08-08 14:57:17 +0000
4067@@ -61,8 +61,8 @@
4068 property Item header: findChild(genericScopeView, "scopePageHeader")
4069
4070 function init() {
4071- genericScopeView.scope = scopes.getScope(1)
4072- shell.width = units.gu(120)
4073+ genericScopeView.scope = scopes.getScope(2);
4074+ shell.width = units.gu(120);
4075 genericScopeView.categoryView.positionAtBeginning();
4076 waitForRendering(genericScopeView.categoryView);
4077 }
4078@@ -88,13 +88,13 @@
4079
4080 function test_showDash() {
4081 testCase.previewListView.open = true;
4082- scopes.getScope(1).showDash();
4083+ genericScopeView.scope.showDash();
4084 tryCompare(testCase.previewListView, "open", false);
4085 }
4086
4087 function test_hideDash() {
4088 testCase.previewListView.open = true;
4089- scopes.getScope(1).hideDash();
4090+ genericScopeView.scope.hideDash();
4091 tryCompare(testCase.previewListView, "open", false);
4092 }
4093
4094@@ -111,8 +111,9 @@
4095
4096 function test_changeScope() {
4097 genericScopeView.scope.searchQuery = "test"
4098- genericScopeView.scope = scopes.getScope(2)
4099- genericScopeView.scope = scopes.getScope(1)
4100+ var originalScopeId = genericScopeView.scope.id;
4101+ genericScopeView.scope = scopes.getScope(originalScopeId + 1)
4102+ genericScopeView.scope = scopes.getScope(originalScopeId)
4103 tryCompare(genericScopeView.scope, "searchQuery", "test")
4104 }
4105
4106@@ -198,6 +199,8 @@
4107 openPreview(4, 0);
4108
4109 compare(testCase.previewListView.count, 12, "There should only be 12 items in preview.");
4110+
4111+ closePreview();
4112 }
4113
4114 function test_narrow_delegate_ranges_expand() {
4115@@ -232,7 +235,7 @@
4116 }
4117
4118 function test_single_category_expansion() {
4119- genericScopeView.scope = scopes.getScope(4);
4120+ genericScopeView.scope = scopes.getScope(3);
4121
4122 tryCompareFunction(function() { return findChild(genericScopeView, "dashCategory0") != undefined; }, true);
4123 var category = findChild(genericScopeView, "dashCategory0")
4124@@ -329,8 +332,8 @@
4125 function test_header_style_data() {
4126 return [
4127 { tag: "Default", index: 0, foreground: "grey", background: "", logo: "" },
4128- { tag: "Foreground", index: 2, foreground: "yellow", background: "", logo: "" },
4129- { tag: "Logo+Background", index: 3, foreground: "grey", background: "gradient:///lightgrey/grey",
4130+ { tag: "Foreground", index: 1, foreground: "yellow", background: "", logo: "" },
4131+ { tag: "Logo+Background", index: 2, foreground: "grey", background: "gradient:///lightgrey/grey",
4132 logo: Qt.resolvedUrl("../Components/tst_PageHeader/logo-ubuntu-orange.svg") },
4133 ];
4134 }

Subscribers

People subscribed via source and target branches