Merge lp:~aacid/unity8/list_on_bottom_swipe into lp:unity8

Proposed by Albert Astals Cid
Status: Merged
Approved by: Albert Astals Cid
Approved revision: 1347
Merged at revision: 1479
Proposed branch: lp:~aacid/unity8/list_on_bottom_swipe
Merge into: lp:unity8
Diff against target: 2435 lines (+792/-1116)
20 files modified
debian/control (+1/-1)
po/unity8.pot (+41/-45)
qml/Dash/Dash.qml (+89/-127)
qml/Dash/DashContent.qml (+11/-1)
qml/Dash/GenericScopeView.qml (+1/-1)
qml/Dash/PageHeader.qml (+11/-1)
qml/Dash/ScopesList.qml (+127/-0)
qml/Dash/ScopesListCategory.qml (+176/-0)
qml/Dash/ScopesListCategoryItem.qml (+104/-0)
qml/Dash/ScopesOverview.qml (+0/-575)
qml/Dash/ScopesOverviewAll.qml (+0/-54)
qml/Dash/ScopesOverviewFavorites.qml (+0/-73)
qml/Dash/ScopesOverviewTab.qml (+0/-74)
tests/mocks/Unity/CMakeLists.txt (+1/-1)
tests/mocks/Unity/fake_scopes.cpp (+57/-3)
tests/mocks/Unity/fake_scopes.h (+8/-3)
tests/mocks/Unity/fake_scopesoverview.cpp (+77/-11)
tests/mocks/Unity/fake_scopesoverview.h (+18/-3)
tests/qmltests/Dash/tst_Dash.qml (+70/-142)
tests/qmltests/Dash/tst_GenericScopeView.qml (+0/-1)
To merge this branch: bzr merge lp:~aacid/unity8/list_on_bottom_swipe
Reviewer Review Type Date Requested Status
Nick Dedekind (community) Approve
PS Jenkins bot (community) continuous-integration Needs Fixing
Benjamin Keyser (community) design Approve
Review via email: mp+235266@code.launchpad.net

Commit message

Replace Scopes Overview by the new Manage Dash

Description of the change

The unity-scopes-shell change is not needed if you only want to run tests or use make tryDash

 * Are there any related MPs required for this MP to build/function as expected?
https://code.launchpad.net/~stolowski/unity-scopes-shell/feeds
https://code.launchpad.net/~aacid/unity-api/setMoveFavorite/+merge/238936

 * 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?
This is a design driven change

To post a comment you must log in.
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: Approve (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)
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
Michał Sawicz (saviq) wrote :

Would be nice if the tab with ^ (the hint alone) at the bottom absorbed touches so you couldn't activate items through it.

Revision history for this message
Omer Akram (om26er) wrote :

When do we plan to land this branch ? The bottom edge interaction seems quite complex and ineffective in its current form. Would really love to see this change land soon.

Revision history for this message
Albert Astals Cid (aacid) wrote :

@Omer: As you can see on the bug this is targetted for ota-1

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)
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)
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)
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
Nick Dedekind (nick-dedekind) wrote :

TestCase:
1) Open dash management
2) Enter edit mode
3) Tap an item

Expected: Scope lifts and releases in same position.
Actual: Scope is switched with the next scope in the list.

It should only switch position when it's been removed from the list?

review: Needs Information
Revision history for this message
Albert Astals Cid (aacid) wrote :

Wops, yes that needs fixing.

Revision history for this message
Albert Astals Cid (aacid) wrote :

> TestCase:
> 1) Open dash management
> 2) Enter edit mode
> 3) Tap an item
>
> Expected: Scope lifts and releases in same position.
> Actual: Scope is switched with the next scope in the list.
>
> It should only switch position when it's been removed from the list?

Fixed

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Should we bump the libunity-api requirement to 7.93? If so, can you add https://code.launchpad.net/~aacid/unity-api/setMoveFavorite/+merge/238936 to the related MPs.

review: Needs Information
Revision history for this message
Albert Astals Cid (aacid) wrote :

> Should we bump the libunity-api requirement to 7.93? If so, can you add
> https://code.launchpad.net/~aacid/unity-api/setMoveFavorite/+merge/238936 to
> the related MPs.

Yep, Done :)

Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

 * Did you perform an exploratory manual test run of the code change and any related functionality?
Yes

 * Did CI run pass? If not, please explain why.
No, will not pass due to requirements

 * Did you make sure that the branch does not contain spurious tags?
Yes

review: Approve
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
Nick Dedekind (nick-dedekind) wrote :

Added a few comments when looking over the ScopesList code again. Sorry!

review: Needs Information
Revision history for this message
Albert Astals Cid (aacid) wrote :

> Should we not be able to favourite things that aren't in the "other" category? I would think we can [un]favourite anything.

Thigns in search tha are not favorites or others can't be favorited (e.g. a result to wikipedia when you search for metallica)

Revision history for this message
Albert Astals Cid (aacid) wrote :

> not really sure about this "other" feed. In this context isn't "other" everything except category == "home".

"other" is the new name for "the non favorite", there's "the other other" (e.g. search results that link to wikipedia)

Revision history for this message
Albert Astals Cid (aacid) wrote :

> where does "name" come from? I feel this is putting a bit too much context inside a fairly generic component. Should we not have a root level property for "title" and give the alternative "Home"/"Other" from the usage:

Done

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Nick Dedekind (nick-dedekind) wrote :

Ok, all good again :)

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Benjamin Keyser (bjkeyser) wrote :

Hi, this is my first merge review :) James should do the review, but he's out of the office until Thursday so I'm filling in what I know were the last agreed design asks.

1. The category headings should be Medium weight not light: so "home" and "other" headings should be medium.

2. Please change the "Other" heading to "Also installed" ... this change is just a change of mind because now that I see it, it doesn't make as much sense.

Please include the launcher "nudge out of the way" animation when the list item is being moved up and down, so a small space opens between the items before you drop it in. Check the launcher for the comparison.

review: Needs Fixing (design)
Revision history for this message
Albert Astals Cid (aacid) wrote :

> 1. The category headings should be Medium weight not light: so "home" and "other" headings should be medium.
They are medium font size, effectively they use the same code we use for the category in the rest of the dash.

> 2. Please change the "Other" heading to "Also installed" ... this change is just a change of mind because now that I see it, it doesn't make as much sense.
Changed

> Please include the launcher "nudge out of the way" animation when the list item is being moved up and down, so a small space opens between the items before you drop it in. Check the launcher for the comparison.
Working on it

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Albert Astals Cid (aacid) wrote :

> > Please include the launcher "nudge out of the way" animation when the list
> item is being moved up and down, so a small space opens between the items
> before you drop it in. Check the launcher for the comparison.
> Working on it

This is now done.

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)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Benjamin Keyser (bjkeyser) :
review: Approve (design)
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
Nick Dedekind (nick-dedekind) wrote :

Looks good to me.

review: Approve
Revision history for this message
Albert Astals Cid (aacid) wrote :

I moved to Needs Review thinking i wanted CI to run but then realized it didn't make sense since CI can't run here because of the dependencies so now it looks like i top approved myself but it was in fact Nick Dedekind

1348. By Albert Astals Cid

Merge

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/control'
--- debian/control 2014-12-03 17:22:51 +0000
+++ debian/control 2014-12-05 10:47:59 +0000
@@ -25,7 +25,7 @@
25 libqmenumodel-dev (>= 0.2.8),25 libqmenumodel-dev (>= 0.2.8),
26 libqt5xmlpatterns5-dev,26 libqt5xmlpatterns5-dev,
27 libsystemsettings-dev,27 libsystemsettings-dev,
28 libunity-api-dev (>= 7.93),28 libunity-api-dev (>= 7.94),
29 libusermetricsoutput1-dev,29 libusermetricsoutput1-dev,
30 libxcb1-dev,30 libxcb1-dev,
31 pkg-config,31 pkg-config,
3232
=== modified file 'po/unity8.pot'
--- po/unity8.pot 2014-11-07 09:59:15 +0000
+++ po/unity8.pot 2014-12-05 10:47:59 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: unity8\n"9"Project-Id-Version: unity8\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2014-11-07 10:59+0100\n"11"POT-Creation-Date: 2014-11-20 12:00+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -172,20 +172,24 @@
172msgid "See all"172msgid "See all"
173msgstr ""173msgstr ""
174174
175#: qml/Dash/GenericScopeView.qml:496 qml/Dash/PageHeader.qml:258175#: qml/Dash/GenericScopeView.qml:496 qml/Dash/PageHeader.qml:267
176#: qml/Panel/SearchIndicator.qml:27176#: qml/Panel/SearchIndicator.qml:27
177msgid "Search"177msgid "Search"
178msgstr ""178msgstr ""
179179
180#: qml/Dash/PageHeader.qml:268180#: qml/Dash/PageHeader.qml:260
181msgid "Store"
182msgstr ""
183
184#: qml/Dash/PageHeader.qml:277
181msgid "Settings"185msgid "Settings"
182msgstr ""186msgstr ""
183187
184#: qml/Dash/PageHeader.qml:275188#: qml/Dash/PageHeader.qml:284
185msgid "Remove from Favorites"189msgid "Remove from Favorites"
186msgstr ""190msgstr ""
187191
188#: qml/Dash/PageHeader.qml:275192#: qml/Dash/PageHeader.qml:284
189msgid "Add to Favorites"193msgid "Add to Favorites"
190msgstr ""194msgstr ""
191195
@@ -217,31 +221,23 @@
217msgid "Release to refresh…"221msgid "Release to refresh…"
218msgstr ""222msgstr ""
219223
220#: qml/Dash/ScopesOverview.qml:215224#: qml/Dash/ScopesList.qml:63
221msgid "Manage Scopes"225msgid "Manage"
222msgstr ""226msgstr ""
223227
224#: qml/Dash/ScopesOverview.qml:437228#: qml/Dash/ScopesList.qml:105
225msgid "Done"229msgid "Home"
226msgstr ""230msgstr ""
227231
228#: qml/Dash/ScopesOverview.qml:463232#: qml/Dash/ScopesList.qml:106
229msgid "Store"233msgid "Also installed"
230msgstr ""
231
232#: qml/Dash/ScopesOverviewTab.qml:36
233msgid "Favorites"
234msgstr ""
235
236#: qml/Dash/ScopesOverviewTab.qml:54
237msgid "All"
238msgstr ""234msgstr ""
239235
240#: qml/Greeter/Greeter.qml:174236#: qml/Greeter/Greeter.qml:174
241msgid "Unlock"237msgid "Unlock"
242msgstr ""238msgstr ""
243239
244#: qml/Notifications/NotificationMenuItemFactory.qml:116240#: qml/Notifications/NotificationMenuItemFactory.qml:128
245msgid "Show password"241msgid "Show password"
246msgstr ""242msgstr ""
247243
@@ -289,55 +285,55 @@
289msgid "Roaming"285msgid "Roaming"
290msgstr ""286msgstr ""
291287
288#: qml/Shell.qml:390
289msgid "Enter passphrase"
290msgstr ""
291
292#: qml/Shell.qml:391292#: qml/Shell.qml:391
293msgid "Enter passphrase"293msgid "Sorry, incorrect passphrase"
294msgstr ""294msgstr ""
295295
296#: qml/Shell.qml:392296#: qml/Shell.qml:392
297msgid "Sorry, incorrect passphrase"
298msgstr ""
299
300#: qml/Shell.qml:393
301msgid "Please re-enter"297msgid "Please re-enter"
302msgstr ""298msgstr ""
303299
300#: qml/Shell.qml:394
301msgid "Enter passcode"
302msgstr ""
303
304#: qml/Shell.qml:395304#: qml/Shell.qml:395
305msgid "Enter passcode"
306msgstr ""
307
308#: qml/Shell.qml:396
309msgid "Sorry, incorrect passcode"305msgid "Sorry, incorrect passcode"
310msgstr ""306msgstr ""
311307
308#: qml/Shell.qml:398
309#, qt-format
310msgid "Enter %1"
311msgstr ""
312
312#: qml/Shell.qml:399313#: qml/Shell.qml:399
313#, qt-format314#, qt-format
314msgid "Enter %1"
315msgstr ""
316
317#: qml/Shell.qml:400
318#, qt-format
319msgid "Sorry, incorrect %1"315msgid "Sorry, incorrect %1"
320msgstr ""316msgstr ""
321317
318#: qml/Shell.qml:440
319msgid "Sorry, incorrect passphrase."
320msgstr ""
321
322#: qml/Shell.qml:441322#: qml/Shell.qml:441
323msgid "Sorry, incorrect passphrase."323msgid "Sorry, incorrect passcode."
324msgstr ""324msgstr ""
325325
326#: qml/Shell.qml:442326#: qml/Shell.qml:442
327msgid "Sorry, incorrect passcode."
328msgstr ""
329
330#: qml/Shell.qml:443
331msgid "This will be your last attempt."327msgid "This will be your last attempt."
332msgstr ""328msgstr ""
333329
334#: qml/Shell.qml:445330#: qml/Shell.qml:444
335msgid ""331msgid ""
336"If passphrase is entered incorrectly, your phone will conduct a factory "332"If passphrase is entered incorrectly, your phone will conduct a factory "
337"reset and all personal data will be deleted."333"reset and all personal data will be deleted."
338msgstr ""334msgstr ""
339335
340#: qml/Shell.qml:446336#: qml/Shell.qml:445
341msgid ""337msgid ""
342"If passcode is entered incorrectly, your phone will conduct a factory reset "338"If passcode is entered incorrectly, your phone will conduct a factory reset "
343"and all personal data will be deleted."339"and all personal data will be deleted."
344340
=== modified file 'qml/Dash/Dash.qml'
--- qml/Dash/Dash.qml 2014-12-02 09:25:12 +0000
+++ qml/Dash/Dash.qml 2014-12-05 10:47:59 +0000
@@ -31,16 +31,13 @@
31 DashCommunicatorService {31 DashCommunicatorService {
32 objectName: "dashCommunicatorService"32 objectName: "dashCommunicatorService"
33 onSetCurrentScopeRequested: {33 onSetCurrentScopeRequested: {
34 if (!isSwipe || !window.active || overviewController.progress != 0 || scopeItem.scope || dashContent.subPageShown) {34 if (!isSwipe || !window.active || bottomEdgeController.progress != 0 || scopeItem.scope || dashContent.subPageShown) {
35 if (overviewController.progress != 0 && window.active) animate = false;35 if (bottomEdgeController.progress != 0 && window.active) animate = false;
36 dashContent.setCurrentScopeAtIndex(index, animate, isSwipe)36 dashContent.setCurrentScopeAtIndex(index, animate, isSwipe)
37 // Close dash overview and nested temp scopes in it37 // Close dash overview and nested temp scopes in it
38 if (overviewController.progress != 0) {38 if (bottomEdgeController.progress != 0) {
39 if (window.active) {39 bottomEdgeController.enableAnimation = window.active && !scopesOverview.showingNonFavoriteScope;
40 dashContentCache.scheduleUpdate();40 bottomEdgeController.progress = 0;
41 }
42 overviewController.enableAnimation = window.active && !scopesOverview.showingNonFavoriteScope;
43 overviewController.progress = 0;
44 scopesOverview.closeTempScope();41 scopesOverview.closeTempScope();
45 }42 }
46 // Close normal temp scopes (e.g. App Store)43 // Close normal temp scopes (e.g. App Store)
@@ -92,8 +89,8 @@
92 }89 }
9390
94 QtObject {91 QtObject {
95 id: overviewController92 id: bottomEdgeController
96 objectName: "overviewController"93 objectName: "bottomEdgeController"
9794
98 property alias enableAnimation: progressAnimation.enabled95 property alias enableAnimation: progressAnimation.enabled
99 property real progress: 096 property real progress: 0
@@ -101,108 +98,40 @@
101 id: progressAnimation98 id: progressAnimation
102 UbuntuNumberAnimation { }99 UbuntuNumberAnimation { }
103 }100 }
104 }
105101
106 ScopesOverview {
107 id: scopesOverview
108 objectName: "scopesOverview"
109 anchors.fill: parent
110 scope: scopes.overviewScope
111 progress: overviewController.progress
112 scopeScale: scopeItem.scope ? 0.4 : (1 - overviewController.progress * 0.6)
113 visible: scopeScale != 1
114 currentIndex: dashContent.currentIndex
115 onDone: {
116 if (currentTab == 1) {
117 animateDashFromAll(dashContent.currentScopeId);
118 }
119 hide();
120 }
121 onFavoriteSelected: {
122 setCurrentScope(scopeId, false, false);
123 dashContentCache.scheduleUpdate();
124 hide();
125 }
126 onAllFavoriteSelected: {
127 setCurrentScope(scopeId, false, false);
128 dashContentCache.scheduleUpdate();
129 animateDashFromAll(dashContent.currentScopeId);
130 hide();
131 }
132 onSearchSelected: {
133 var scopeIndex = -1;
134 for (var i = 0; i < scopes.count; ++i) {
135 if (scopes.getScope(i).id == scopeId) {
136 scopeIndex = i;
137 break;
138 }
139 }
140 if (scopeIndex >= 0) {
141 // Is a favorite one
142 setCurrentScope(scopeId, false, false);
143 dashContentCache.scheduleUpdate();
144 showDashFromPos(pos, size);
145 hide();
146 } else {
147 // Is not a favorite one, activate and get openScope
148 scope.activate(result);
149 }
150 }
151 function hide() {
152 overviewController.enableAnimation = true;
153 overviewController.progress = 0;
154 }
155 onProgressChanged: {102 onProgressChanged: {
156 if (progress == 0) {103 // FIXME This is to workaround a Qt bug with the model moving the current item
157 currentTab = scopeItem.scope ? 1 : 0;104 // when the list is ListView.SnapOneItem and ListView.StrictlyEnforceRange
105 // together with the code in DashContent.qml
106 if (dashContent.workaroundRestoreIndex != -1) {
107 dashContent.currentIndex = dashContent.workaroundRestoreIndex;
108 dashContent.workaroundRestoreIndex = -1;
158 }109 }
159 }110 }
160 }111 }
161112
162 ShaderEffectSource {
163 id: dashContentCache
164 parent: scopesOverview.dashItemEater
165 z: 1
166 sourceItem: dashContent
167 height: sourceItem.height
168 width: sourceItem.width
169 opacity: 1 - overviewController.progress
170 visible: overviewController.progress != 0 && scopeItem.scope === null
171 live: false
172 }
173
174 DashContent {113 DashContent {
175 id: dashContent114 id: dashContent
176115
177 property var scopeThatOpenedScope: null
178
179 objectName: "dashContent"116 objectName: "dashContent"
180 width: dash.width117 width: dash.width
181 height: dash.height118 height: dash.height
182 scopes: scopes119 scopes: scopes
183 visible: !scopesOverview.showingNonFavoriteScope && x != -width120 visible: x != -width
184 onGotoScope: {121 onGotoScope: {
185 dash.setCurrentScope(scopeId, true, false);122 dash.setCurrentScope(scopeId, true, false);
186 }123 }
187 onOpenScope: {124 onOpenScope: {
188 scopeThatOpenedScope = currentScope;125 scopeItem.scopeThatOpenedScope = currentScope;
189 scopeItem.scope = scope;126 scopeItem.scope = scope;
190 scopesOverview.currentTab = 1;
191 scopesOverview.ensureAllScopeVisible(scope.id);
192 x = -width;127 x = -width;
193 }128 }
194 clip: scale != 1.0 || scopeItem.visible || overviewController.progress != 0
195 Behavior on x {129 Behavior on x {
196 UbuntuNumberAnimation {130 UbuntuNumberAnimation {
197 duration: overviewController.progress != 0 ? 0 : UbuntuAnimation.FastDuration
198 onRunningChanged: {131 onRunningChanged: {
199 if (!running && dashContent.x == 0) {132 if (!running && dashContent.x == 0) {
200 dashContent.scopeThatOpenedScope.closeScope(scopeItem.scope);133 scopeItem.scopeThatOpenedScope.closeScope(scopeItem.scope);
201 scopeItem.scope = null;134 scopeItem.scope = null;
202 if (overviewController.progress == 0) {
203 // Set tab to Favorites only if we are not showing the overview
204 scopesOverview.currentTab = 0;
205 }
206 }135 }
207 }136 }
208 }137 }
@@ -214,47 +143,78 @@
214 // about whether that touch was indeed performing a directional drag gesture.143 // about whether that touch was indeed performing a directional drag gesture.
215 forceNonInteractive: overviewDragHandle.status != DirectionalDragArea.WaitingForTouch144 forceNonInteractive: overviewDragHandle.status != DirectionalDragArea.WaitingForTouch
216145
217 enabled: overviewController.progress == 0146 enabled: bottomEdgeController.progress == 0
218 opacity: enabled ? 1 : 0147 }
148
149 Rectangle {
150 color: "black"
151 opacity: bottomEdgeController.progress
152 anchors.fill: dashContent
153 }
154
155 ScopesList {
156 id: scopesList
157 objectName: "scopesList"
158 width: dash.width
159 height: dash.height
160 scope: scopes.overviewScope
161 y: dash.height * (1 - bottomEdgeController.progress)
162 visible: bottomEdgeController.progress != 0
163 onBackClicked: {
164 bottomEdgeController.enableAnimation = true;
165 bottomEdgeController.progress = 0;
166 }
167 onStoreClicked: {
168 bottomEdgeController.enableAnimation = true;
169 bottomEdgeController.progress = 0;
170 dashContent.currentScope.performQuery("scope://com.canonical.scopes.clickstore");
171 }
172 onRequestFavorite: {
173 scopes.setFavorite(scopeId, favorite);
174 }
175 onRequestFavoriteMoveTo: {
176 scopes.moveFavoriteTo(scopeId, index);
177 }
178
179 Binding {
180 target: scopesList.scope
181 property: "isActive"
182 value: bottomEdgeController.progress === 1
183 }
184
185 Connections {
186 target: scopesList.scope
187 onOpenScope: {
188 bottomEdgeController.enableAnimation = true;
189 bottomEdgeController.progress = 0;
190 scopeItem.scopeThatOpenedScope = scopesList.scope;
191 scopeItem.scope = scope;
192 dashContent.x = -dashContent.width;
193 }
194 onGotoScope: {
195 bottomEdgeController.enableAnimation = true;
196 bottomEdgeController.progress = 0;
197 dashContent.gotoScope(scopeId);
198 }
199 }
219 }200 }
220201
221 DashBackground202 DashBackground
222 {203 {
223 anchors.fill: scopeItem204 anchors.fill: scopeItem
224 visible: scopeItem.visible205 visible: scopeItem.visible
225 parent: scopeItem.parent
226 scale: scopeItem.scale
227 opacity: scopeItem.opacity
228 }206 }
229207
230 GenericScopeView {208 GenericScopeView {
231 id: scopeItem209 id: scopeItem
232 objectName: "dashTempScopeItem"210 objectName: "dashTempScopeItem"
233211
234 readonly property real targetOverviewScale: {212 property var scopeThatOpenedScope: null
235 if (scopesOverview.currentTab == 0) {
236 return 0.4;
237 } else {
238 return scopesOverview.allCardSize.width / scopeItem.width;
239 }
240 }
241 readonly property real overviewProgressScale: (1 - overviewController.progress * (1 - targetOverviewScale))
242 readonly property var targetOverviewPosition: scope ? scopesOverview.allScopeCardPosition(scope.id) : null
243 readonly property real overviewProgressX: scope && scopesOverview.currentTab == 1 && targetOverviewPosition ?
244 overviewController.progress * (targetOverviewPosition.x - (width - scopesOverview.allCardSize.width) / 2)
245 : 0
246 readonly property real overviewProgressY: scope && scopesOverview.currentTab == 1 && targetOverviewPosition ?
247 overviewController.progress * (targetOverviewPosition.y - (height - scopesOverview.allCardSize.height) / 2)
248 : 0
249213
250 x: overviewController.progress == 0 ? dashContent.x + width : overviewProgressX214 x: dashContent.x + width
251 y: overviewController.progress == 0 ? dashContent.y : overviewProgressY215 y: dashContent.y
252 width: parent.width216 width: parent.width
253 height: parent.height217 height: parent.height
254 scale: overviewProgressScale
255 enabled: opacity == 1
256 opacity: 1 - overviewController.progress
257 clip: scale != 1.0
258 visible: scope != null218 visible: scope != null
259 hasBackAction: true219 hasBackAction: true
260 isCurrent: visible220 isCurrent: visible
@@ -288,7 +248,7 @@
288 opacity: 0248 opacity: 0
289 visible: opacity > 0249 visible: opacity > 0
290250
291 readonly property bool processing: dashContent.processing || scopeItem.processing || scopesOverview.processing251 readonly property bool processing: dashContent.processing || scopeItem.processing || scopesList.processing
292252
293 Behavior on opacity {253 Behavior on opacity {
294 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }254 UbuntuNumberAnimation { duration: UbuntuAnimation.FastDuration }
@@ -345,12 +305,17 @@
345 source: "graphics/overview_hint.png"305 source: "graphics/overview_hint.png"
346 anchors.horizontalCenter: parent.horizontalCenter306 anchors.horizontalCenter: parent.horizontalCenter
347 opacity: (scopeItem.scope ? scopeItem.pageHeaderTotallyVisible : dashContent.pageHeaderTotallyVisible) &&307 opacity: (scopeItem.scope ? scopeItem.pageHeaderTotallyVisible : dashContent.pageHeaderTotallyVisible) &&
348 (overviewDragHandle.enabled || overviewController.progress != 0) ? 1 : 0308 (overviewDragHandle.enabled || bottomEdgeController.progress != 0) ? 1 : 0
349 Behavior on opacity {309 Behavior on opacity {
350 enabled: overviewController.progress == 0310 enabled: bottomEdgeController.progress == 0
351 UbuntuNumberAnimation {}311 UbuntuNumberAnimation {}
352 }312 }
353 y: parent.height - height * (1 - overviewController.progress * 4)313 y: parent.height - height * (1 - bottomEdgeController.progress * 4)
314 MouseArea {
315 // Eat direct presses on the overview hint so that they do not end up in the card below
316 anchors.fill: parent
317 enabled: parent.opacity != 0
318 }
354 }319 }
355320
356 EdgeDragArea {321 EdgeDragArea {
@@ -361,22 +326,19 @@
361 enabled: !dashContent.subPageShown &&326 enabled: !dashContent.subPageShown &&
362 dashContent.currentScope &&327 dashContent.currentScope &&
363 dashContent.currentScope.searchQuery == "" &&328 dashContent.currentScope.searchQuery == "" &&
364 !scopeItem.subPageShown &&329 !scopeItem.scope &&
365 (overviewController.progress == 0 || dragging)330 (bottomEdgeController.progress == 0 || dragging)
366331
367 readonly property real fullMovement: units.gu(20)332 readonly property real fullMovement: dash.height
368333
369 anchors { left: parent.left; right: parent.right; bottom: parent.bottom }334 anchors { left: parent.left; right: parent.right; bottom: parent.bottom }
370 height: units.gu(2)335 height: units.gu(2)
371336
372 onSceneDistanceChanged: {337 onSceneDistanceChanged: {
373 if (status == DirectionalDragArea.Recognized && initialSceneDistance != -1) {338 if (status == DirectionalDragArea.Recognized && initialSceneDistance != -1) {
374 if (overviewController.enableAnimation) {339 bottomEdgeController.enableAnimation = false;
375 dashContentCache.scheduleUpdate();
376 }
377 overviewController.enableAnimation = false;
378 var deltaDistance = sceneDistance - initialSceneDistance;340 var deltaDistance = sceneDistance - initialSceneDistance;
379 overviewController.progress = Math.max(0, Math.min(1, deltaDistance / fullMovement));341 bottomEdgeController.progress = Math.max(0, Math.min(1, deltaDistance / fullMovement));
380 }342 }
381 }343 }
382344
@@ -392,8 +354,8 @@
392 initialSceneDistance = sceneDistance;354 initialSceneDistance = sceneDistance;
393 } else if (status == DirectionalDragArea.WaitingForTouch &&355 } else if (status == DirectionalDragArea.WaitingForTouch &&
394 previousStatus == DirectionalDragArea.Recognized) {356 previousStatus == DirectionalDragArea.Recognized) {
395 overviewController.enableAnimation = true;357 bottomEdgeController.enableAnimation = true;
396 overviewController.progress = (overviewController.progress > 0.7) ? 1 : 0;358 bottomEdgeController.progress = (bottomEdgeController.progress > 0.2) ? 1 : 0;
397 initialSceneDistance = -1;359 initialSceneDistance = -1;
398 }360 }
399 }361 }
400362
=== modified file 'qml/Dash/DashContent.qml'
--- qml/Dash/DashContent.qml 2014-10-30 21:43:18 +0000
+++ qml/Dash/DashContent.qml 2014-12-05 10:47:59 +0000
@@ -25,7 +25,8 @@
2525
26 property bool forceNonInteractive: false26 property bool forceNonInteractive: false
27 property alias scopes: dashContentList.model27 property alias scopes: dashContentList.model
28 readonly property alias currentIndex: dashContentList.currentIndex28 property alias currentIndex: dashContentList.currentIndex
29 property int workaroundRestoreIndex: -1
29 readonly property string currentScopeId: dashContentList.currentItem ? dashContentList.currentItem.scopeId : ""30 readonly property string currentScopeId: dashContentList.currentItem ? dashContentList.currentItem.scopeId : ""
30 readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null31 readonly property var currentScope: dashContentList.currentItem ? dashContentList.currentItem.theScope : null
31 readonly property bool subPageShown: dashContentList.currentItem && dashContentList.currentItem.item ?32 readonly property bool subPageShown: dashContentList.currentItem && dashContentList.currentItem.item ?
@@ -51,6 +52,15 @@
51 set_current_index = undefined;52 set_current_index = undefined;
52 }53 }
53 }54 }
55 onRowsMoved: {
56 // FIXME This is to workaround a Qt bug with the model moving the current item
57 // when the list is ListView.SnapOneItem and ListView.StrictlyEnforceRange
58 // together with the code in Dash.qml
59 if (row == dashContentList.currentIndex || start == dashContentList.currentIndex) {
60 dashContent.workaroundRestoreIndex = dashContentList.currentIndex;
61 dashContentList.currentIndex = -1;
62 }
63 }
54 }64 }
5565
56 Connections {66 Connections {
5767
=== modified file 'qml/Dash/GenericScopeView.qml'
--- qml/Dash/GenericScopeView.qml 2014-11-06 15:25:51 +0000
+++ qml/Dash/GenericScopeView.qml 2014-12-05 10:47:59 +0000
@@ -494,7 +494,7 @@
494 showBackButton: scopeView.hasBackAction494 showBackButton: scopeView.hasBackAction
495 searchEntryEnabled: true495 searchEntryEnabled: true
496 settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false496 settingsEnabled: scopeView.scope && scopeView.scope.settings && scopeView.scope.settings.count > 0 || false
497 favoriteEnabled: scopeView.scope && scopeView.scope.id !== "clickscope"497 favoriteEnabled: scopeView.scope
498 favorite: scopeView.scope && scopeView.scope.favorite498 favorite: scopeView.scope && scopeView.scope.favorite
499 scopeStyle: scopeView.scopeStyle499 scopeStyle: scopeView.scopeStyle
500 paginationCount: scopeView.paginationCount500 paginationCount: scopeView.paginationCount
501501
=== modified file 'qml/Dash/PageHeader.qml'
--- qml/Dash/PageHeader.qml 2014-11-07 14:31:39 +0000
+++ qml/Dash/PageHeader.qml 2014-12-05 10:47:59 +0000
@@ -28,8 +28,10 @@
28 implicitHeight: headerContainer.height + bottomContainer.height + (showSignatureLine ? units.gu(2) : 0)28 implicitHeight: headerContainer.height + bottomContainer.height + (showSignatureLine ? units.gu(2) : 0)
2929
30 property bool showBackButton: false30 property bool showBackButton: false
31 property bool backIsClose: false
31 property string title32 property string title
3233
34 property bool storeEntryEnabled: false
33 property bool searchEntryEnabled: false35 property bool searchEntryEnabled: false
34 property bool settingsEnabled: false36 property bool settingsEnabled: false
35 property bool favoriteEnabled: false37 property bool favoriteEnabled: false
@@ -46,6 +48,7 @@
46 property var scopeStyle: null48 property var scopeStyle: null
4749
48 signal backClicked()50 signal backClicked()
51 signal storeClicked()
49 signal settingsClicked()52 signal settingsClicked()
50 signal favoriteClicked()53 signal favoriteClicked()
5154
@@ -246,13 +249,20 @@
246 property var config: PageHeadConfiguration {249 property var config: PageHeadConfiguration {
247 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : Theme.palette.normal.baseText250 foregroundColor: root.scopeStyle ? root.scopeStyle.headerForeground : Theme.palette.normal.baseText
248 backAction: Action {251 backAction: Action {
249 iconName: "back"252 iconName: backIsClose ? "close" : "back"
250 visible: root.showBackButton253 visible: root.showBackButton
251 onTriggered: root.backClicked()254 onTriggered: root.backClicked()
252 }255 }
253256
254 actions: [257 actions: [
255 Action {258 Action {
259 objectName: "store"
260 text: i18n.tr("Store")
261 iconName: "ubuntu-store-symbolic"
262 visible: root.storeEntryEnabled
263 onTriggered: root.storeClicked();
264 },
265 Action {
256 objectName: "search"266 objectName: "search"
257 text: i18n.tr("Search")267 text: i18n.tr("Search")
258 iconName: "search"268 iconName: "search"
259269
=== added file 'qml/Dash/ScopesList.qml'
--- qml/Dash/ScopesList.qml 1970-01-01 00:00:00 +0000
+++ qml/Dash/ScopesList.qml 2014-12-05 10:47:59 +0000
@@ -0,0 +1,127 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18import Dash 0.1
19
20Item {
21 id: root
22
23 // Properties set by parent
24 property var scope: null
25
26 // Properties used by parent
27 readonly property bool processing: scope ? scope.searchInProgress : false
28
29 // Signals
30 signal backClicked()
31 signal storeClicked()
32 signal requestFavorite(string scopeId, bool favorite)
33 signal requestFavoriteMoveTo(string scopeId, int index)
34
35 state: "browse"
36
37 onStateChanged: {
38 if (state == "edit") {
39 // As per design entering edit mode clears the possible existing search
40 header.resetSearch(false /* false == unfocus */);
41 }
42 }
43
44 DashBackground {
45 anchors.fill: parent
46 }
47
48 Binding {
49 target: root.scope
50 property: "searchQuery"
51 value: header.searchQuery
52 }
53
54 Binding {
55 target: header
56 property: "searchQuery"
57 value: root.scope ? root.scope.searchQuery : ""
58 }
59
60 PageHeader {
61 id: header
62 objectName: "pageHeader"
63 title: i18n.tr("Manage")
64 width: parent.width
65 showBackButton: true
66 backIsClose: root.state == "edit"
67 storeEntryEnabled: root.state == "browse"
68 searchEntryEnabled: false // Disable search for now
69 onBackClicked: {
70 if (backIsClose) {
71 root.state = "browse"
72 } else {
73 root.backClicked()
74 }
75 }
76 onStoreClicked: root.storeClicked();
77 z: 1
78 }
79
80 Flickable {
81 anchors {
82 top: header.bottom
83 bottom: parent.bottom
84 left: parent.left
85 right: parent.right
86 }
87 clip: true
88 contentWidth: root.width
89 contentHeight: column.height
90 onContentHeightChanged: returnToBounds();
91 Column {
92 id: column
93 Repeater {
94 model: scope ? scope.categories : null
95
96 delegate: Loader {
97 asynchronous: true
98 width: root.width
99 active: results.count > 0
100 visible: active
101 sourceComponent: ScopesListCategory {
102 objectName: "scopesListCategory" + categoryId
103
104 model: results
105
106 title: {
107 if (isFavoritesFeed) return i18n.tr("Home");
108 else if (isAlsoInstalled) return i18n.tr("Also installed");
109 else return name;
110 }
111
112 editMode: root.state == "edit"
113
114 scopeStyle: root.scope.scopeStyle
115 isFavoritesFeed: categoryId == "favorites"
116 isAlsoInstalled: categoryId == "other"
117
118 onRequestFavorite: root.requestFavorite(scopeId, favorite);
119 onRequestEditMode: root.state = "edit";
120 onRequestScopeMoveTo: root.requestFavoriteMoveTo(scopeId, index);
121 onRequestActivate: root.scope.activate(result);
122 }
123 }
124 }
125 }
126 }
127}
0128
=== added file 'qml/Dash/ScopesListCategory.qml'
--- qml/Dash/ScopesListCategory.qml 1970-01-01 00:00:00 +0000
+++ qml/Dash/ScopesListCategory.qml 2014-12-05 10:47:59 +0000
@@ -0,0 +1,176 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18import Ubuntu.Components 1.1
19import Dash 0.1
20import "../Components/ListItems" as ListItems
21
22Item {
23 id: root
24
25 property alias model: list.model
26 property alias title: header.text
27 property var scopeStyle
28 property bool editMode: false
29 property bool isFavoritesFeed: false
30 property bool isAlsoInstalled: false
31
32 visible: !editMode || isFavoritesFeed
33
34 signal requestFavorite(string scopeId, bool favorite)
35 signal requestEditMode()
36 signal requestScopeMoveTo(string scopeId, int index)
37 signal requestActivate(var result)
38
39 implicitHeight: visible ? childrenRect.height : 0
40
41 ListItems.Header {
42 id: header
43 width: root.width
44 height: units.gu(5)
45 color: scopeStyle ? scopeStyle.foreground : Theme.palette.normal.baseText
46 }
47
48 readonly property double listItemHeight: units.gu(6)
49
50 ListView {
51 id: list
52 objectName: "scopesListCategoryInnerList"
53
54 readonly property double targetHeight: model.count * listItemHeight
55 clip: height != targetHeight
56 height: targetHeight
57 Behavior on height { enabled: visible; UbuntuNumberAnimation { } }
58 width: parent.width
59 interactive: false
60
61 anchors.top: header.bottom
62 delegate: Loader {
63 id: loader
64 readonly property bool addDropHint: {
65 if (dragMarker.visible) {
66 if (dragItem.originalIndex > index) {
67 return dragMarker.index == index;
68 } else {
69 return dragMarker.index == index - 1;
70 }
71 } else {
72 return false;
73 }
74 }
75 asynchronous: true
76 width: root.width
77 height: listItemHeight + (addDropHint ? units.gu(2) : 0)
78 clip: height < listItemHeight
79 Behavior on height { enabled: visible; UbuntuNumberAnimation { } }
80 sourceComponent: ScopesListCategoryItem {
81 objectName: "delegate" + index
82
83 width: root.width
84 topMargin: height > listItemHeight ? height - listItemHeight : 0
85
86 icon: model.art || model.mascot || ""
87 text: model.title || ""
88 subtext: model.subtitle || ""
89 showStar: root.isFavoritesFeed || root.isAlsoInstalled
90 isFavorite: root.isFavoritesFeed
91
92 hideChildren: dragItem.loaderToShrink == loader
93
94 onClicked: {
95 if (!editMode) {
96 root.requestActivate(result);
97 }
98 }
99 onPressAndHold: {
100 if (!editMode) {
101 root.requestEditMode();
102 }
103 }
104 onRequestFavorite: root.requestFavorite(model.scopeId, favorite);
105 onHandlePressed: {
106 if (editMode) {
107 handle.drag.target = dragItem;
108 handle.drag.maximumX = units.gu(1);
109 handle.drag.minimumX = units.gu(1);
110 handle.drag.minimumY = list.y - dragItem.height / 2;
111 handle.drag.maximumY = list.y + list.height - dragItem.height / 2
112 dragItem.icon = icon;
113 dragItem.text = text;
114 dragItem.subtext = subtext;
115 dragItem.originalY = mapToItem(root, 0, 0).y;
116 dragItem.originalIndex = index;
117 dragItem.y = dragItem.originalY;
118 dragItem.x = units.gu(1);
119 dragItem.visible = true;
120 dragItem.loaderToShrink = loader;
121 }
122 }
123 onHandleReleased: {
124 if (dragItem.visible) {
125 handle.drag.target = undefined;
126 dragItem.visible = false;
127 if (dragMarker.visible && dragMarker.index != index) {
128 root.requestScopeMoveTo(model.scopeId, dragMarker.index);
129 }
130 dragMarker.visible = false;
131 dragItem.loaderToShrink.height = listItemHeight;
132 dragItem.loaderToShrink = null;
133 }
134 }
135 }
136 }
137 }
138
139 ListItems.ThinDivider {
140 id: dragMarker
141 visible: false
142 anchors {
143 leftMargin: units.gu(1)
144 rightMargin: units.gu(1)
145 }
146 property int index: {
147 var i = Math.round((dragItem.y - list.y + dragItem.height/2) / listItemHeight);
148 if (i < 0) i = 0;
149 if (i >= model.count - 1) i = model.count - 1;
150 return i;
151 }
152 y: list.y + index * listItemHeight + units.gu(1)
153 }
154
155 ScopesListCategoryItem {
156 id: dragItem
157
158 property real originalY
159 property int originalIndex
160 property var loaderToShrink: null
161
162 objectName: "dragItem"
163 visible: false
164 showStar: false
165 width: root.width
166 height: listItemHeight
167 opacity: 0.9
168
169 onYChanged: {
170 if (!dragMarker.visible && Math.abs(y - originalY) > height / 2) {
171 dragMarker.visible = true;
172 loaderToShrink.height = 0;
173 }
174 }
175 }
176}
0177
=== added file 'qml/Dash/ScopesListCategoryItem.qml'
--- qml/Dash/ScopesListCategoryItem.qml 1970-01-01 00:00:00 +0000
+++ qml/Dash/ScopesListCategoryItem.qml 2014-12-05 10:47:59 +0000
@@ -0,0 +1,104 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18import QtQuick.Layouts 1.1
19import Ubuntu.Components 1.1
20
21MouseArea {
22 id: root
23
24 signal requestFavorite(string scopeId, bool favorite)
25 signal handlePressed(var handle)
26 signal handleReleased(var handle)
27
28 property real topMargin: 0
29 property alias icon: shapeImage.source
30 property alias text: titleLabel.text
31 property alias subtext: subtitleLabel.text
32 property alias showStar: star.visible
33
34 property bool isFavorite: false
35 property bool hideChildren: false
36
37 Item {
38 id: holder
39 anchors.fill: parent
40 anchors.topMargin: root.topMargin
41
42 UbuntuShape {
43 id: shape
44 anchors {
45 left: parent.left
46 leftMargin: units.gu(1)
47 verticalCenter: parent.verticalCenter
48 }
49 width: units.gu(5)
50 height: units.gu(5)
51 visible: !hideChildren
52 image: Image {
53 id: shapeImage
54 cache: true
55 fillMode: Image.PreserveAspectCrop
56 }
57 }
58
59 ColumnLayout {
60 visible: !hideChildren
61 anchors {
62 left: shape.right
63 leftMargin: units.gu(1)
64 right: starArea.right
65 rightMargin: units.gu(1)
66 verticalCenter: parent.verticalCenter
67 }
68 Label {
69 id: titleLabel
70 elide: Text.ElideRight
71 wrapMode: Text.Wrap
72 maximumLineCount: 1
73 verticalAlignment: Text.AlignHCenter
74 }
75 Label {
76 id: subtitleLabel
77 elide: Text.ElideRight
78 fontSize: "xx-small"
79 wrapMode: Text.Wrap
80 maximumLineCount: 1
81 verticalAlignment: Text.AlignHCenter
82 visible: text != ""
83 }
84 }
85 MouseArea {
86 id: starArea
87 height: parent.height
88 width: height
89 anchors.right: parent.right
90 onClicked: if (!editMode) root.requestFavorite(model.scopeId, !isFavorite);
91 onPressed: if (editMode) root.handlePressed(starArea);
92 onReleased: if (editMode) root.handleReleased(starArea);
93 Icon {
94 id: star
95 anchors.centerIn: parent
96 height: units.gu(2)
97 width: units.gu(2)
98 visible: !hideChildren
99 // TODO is view-grid-symbolic what we really want here? Looks good but seems semantically wrong
100 source: editMode ? "image://theme/view-grid-symbolic" : isFavorite ? "image://theme/starred" : "image://theme/non-starred"
101 }
102 }
103 }
104}
0105
=== removed file 'qml/Dash/ScopesOverview.qml'
--- qml/Dash/ScopesOverview.qml 2014-10-09 14:04:53 +0000
+++ qml/Dash/ScopesOverview.qml 1970-01-01 00:00:00 +0000
@@ -1,575 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import Dash 0.1
19import Ubuntu.Components 0.1
20import "../Components"
21
22Item {
23 id: root
24
25 // Properties set by parent
26 property real progress: 0
27 property var scope: null
28 property int currentIndex: 0
29 property real scopeScale: 1
30
31 // Properties set and used by parent
32 property alias currentTab: tabBar.currentTab
33
34 // Properties used by parent
35 readonly property bool processing: searchResultsViewer.processing || tempScopeItem.processing || previewListView.processing
36 property bool growingDashFromPos: false
37 readonly property bool searching: scope && scope.searchQuery == ""
38 readonly property bool showingNonFavoriteScope: tempScopeItem.scope != null
39 readonly property var dashItemEater: {
40 if (!forceXYScalerEater && tabBar.currentTab == 0 && middleItems.count > 0) {
41 var loaderItem = middleItems.itemAt(0).item;
42 return loaderItem && loaderItem.currentItem ? loaderItem.currentItem : null;
43 }
44 return scopesOverviewXYScaler;
45 }
46 readonly property size allCardSize: {
47 if (middleItems.count > 1) {
48 var loaderItem = middleItems.itemAt(1).item;
49 if (loaderItem) {
50 var cardTool = loaderItem.cardTool;
51 return Qt.size(cardTool.cardWidth, cardTool.cardHeight);
52 }
53 }
54 return Qt.size(0, 0);
55 }
56
57 // Internal properties
58 property bool forceXYScalerEater: false
59
60 signal done()
61 signal favoriteSelected(var scopeId)
62 signal allFavoriteSelected(var scopeId)
63 signal searchSelected(var scopeId, var result, var pos, var size)
64
65 Connections {
66 target: scope
67 onOpenScope: {
68 var itemPos = scopesOverviewXYScaler.restorePosition;
69 var itemSize = scopesOverviewXYScaler.restoreSize;
70 scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
71 if (itemPos) {
72 scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
73 scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
74 } else {
75 scopesOverviewXYScaler.x = 0;
76 scopesOverviewXYScaler.y = 0;
77 }
78 scopesOverviewXYScaler.opacity = 0;
79 tempScopeItem.scope = scope;
80 middleItems.overrideOpacity = 0;
81 scopesOverviewXYScaler.scale = 1;
82 scopesOverviewXYScaler.x = 0;
83 scopesOverviewXYScaler.y = 0;
84 scopesOverviewXYScaler.opacity = 1;
85 }
86 onGotoScope: {
87 if (tabBar.currentTab == 0) {
88 root.favoriteSelected(scopeId);
89 } else {
90 root.allFavoriteSelected(scopeId);
91 }
92 previewListView.open = false;
93 }
94 }
95
96 Binding {
97 target: scope
98 property: "isActive"
99 value: progress === 1
100 }
101
102 function closeTempScope() {
103 if (tempScopeItem.scope) {
104 root.scope.closeScope(tempScopeItem.scope);
105 tempScopeItem.scope = null;
106 tempScopeItem.backClicked()
107 }
108 }
109
110 function animateDashFromAll(scopeId) {
111 var currentScopePos = allScopeCardPosition(scopeId);
112 if (currentScopePos) {
113 showDashFromPos(currentScopePos, allCardSize);
114 } else {
115 console.log("Warning: Could not find Dash OverView All card position for scope", dashContent.currentScopeId);
116 }
117 }
118
119 function showDashFromPos(itemPos, itemSize) {
120 scopesOverviewXYScaler.scale = itemSize.width / scopesOverviewXYScaler.width;
121 scopesOverviewXYScaler.x = itemPos.x -(scopesOverviewXYScaler.width - scopesOverviewXYScaler.width * scopesOverviewXYScaler.scale) / 2;
122 scopesOverviewXYScaler.y = itemPos.y -(scopesOverviewXYScaler.height - scopesOverviewXYScaler.height * scopesOverviewXYScaler.scale) / 2;
123 scopesOverviewXYScaler.opacity = 0;
124 root.growingDashFromPos = true;
125 scopesOverviewXYScaler.scale = 1;
126 scopesOverviewXYScaler.x = 0;
127 scopesOverviewXYScaler.y = 0;
128 scopesOverviewXYScaler.opacity = 1;
129 }
130
131 function allScopeCardPosition(scopeId) {
132 if (middleItems.count > 1) {
133 var loaderItem = middleItems.itemAt(1).item;
134 if (loaderItem) {
135 var pos = loaderItem.scopeCardPosition(scopeId);
136 return loaderItem.mapToItem(null, pos.x, pos.y);
137 }
138 }
139 }
140
141 function ensureAllScopeVisible(scopeId) {
142 if (middleItems.count > 1) {
143 var loaderItem = middleItems.itemAt(1).item;
144 if (loaderItem) {
145 var pos = loaderItem.scopeCardPosition(scopeId);
146 loaderItem.contentY = Math.min(pos.y, loaderItem.contentHeight - loaderItem.height);
147 }
148 }
149 }
150
151 onProgressChanged: {
152 if (progress == 0) {
153 pageHeader.resetSearch();
154 pageHeader.unfocus(); // Shouldn't the previous call do this too?
155 }
156 }
157
158 ScopeStyle {
159 id: overviewScopeStyle
160 style: { "foreground-color" : "white",
161 "background-color" : "transparent",
162 "page-header": {
163 "background": "color:///transparent"
164 }
165 }
166 }
167
168 DashBackground {
169 anchors.fill: parent
170 source: "graphics/dark_background.jpg"
171 }
172
173 Connections {
174 target: pageHeader
175 onSearchQueryChanged: {
176 // Need this in order, otherwise something gets unhappy in rendering
177 // of the overlay in carousels because the parent of the dash dies for
178 // a moment, this way we make sure it's reparented first
179 // by forceXYScalerEater making dashItemEater return scopesOverviewXYScaler
180 // before we kill the previous parent by scope.searchQuery
181 root.forceXYScalerEater = true;
182 root.scope.searchQuery = pageHeader.searchQuery;
183 root.forceXYScalerEater = false;
184 }
185 }
186
187 Binding {
188 target: pageHeader
189 property: "searchQuery"
190 value: scope ? scope.searchQuery : ""
191 }
192
193 Item {
194 id: scopesOverviewContent
195 x: previewListView.open ? -width : 0
196 Behavior on x { UbuntuNumberAnimation { } }
197 width: parent.width
198 height: parent.height
199
200 PageHeader {
201 id: pageHeader
202 objectName: "scopesOverviewPageHeader"
203
204 readonly property real yDisplacement: pageHeader.height + tabBar.height + tabBar.anchors.margins
205
206 y: {
207 if (root.progress < 0.5) {
208 return -yDisplacement;
209 } else {
210 return -yDisplacement + (root.progress - 0.5) * yDisplacement * 2;
211 }
212 }
213 width: parent.width
214 clip: true
215 title: i18n.tr("Manage Scopes")
216 scopeStyle: overviewScopeStyle
217 showSignatureLine: false
218 searchEntryEnabled: true
219 }
220
221 ScopesOverviewTab {
222 id: tabBar
223 anchors {
224 left: parent.left
225 right: parent.right
226 top: pageHeader.bottom
227 margins: units.gu(2)
228 }
229 height: units.gu(4)
230
231 enabled: opacity == 1
232 opacity: !scope || scope.searchQuery == "" ? 1 : 0
233 Behavior on opacity { UbuntuNumberAnimation { } }
234 }
235
236 Repeater {
237 id: middleItems
238 objectName: "scopesOverviewRepeater"
239 property real overrideOpacity: -1
240 model: scope && scope.searchQuery == "" ? scope.categories : null
241 delegate: Loader {
242 id: loader
243 objectName: "scopesOverviewRepeaterChild" + index
244
245 height: {
246 if (index == 0) {
247 return root.height;
248 } else {
249 return root.height - pageHeader.height - tabBar.height - tabBar.anchors.margins - units.gu(2);
250 }
251 }
252 width: {
253 if (index == 0) {
254 return root.width / scopeScale;
255 } else {
256 return root.width;
257 }
258 }
259 x: {
260 if (index == 0) {
261 return (root.width - width) / 2;
262 } else {
263 return 0;
264 }
265 }
266 anchors {
267 bottom: scopesOverviewContent.bottom
268 }
269
270 scale: index == 0 ? scopeScale : 1
271
272 opacity: {
273 if (middleItems.overrideOpacity >= 0)
274 return middleItems.overrideOpacity;
275
276 if (tabBar.currentTab != index)
277 return 0;
278
279 return index == 0 ? 1 : root.progress;
280 }
281 Behavior on opacity {
282 enabled: root.progress == 1
283 UbuntuNumberAnimation { }
284 }
285 enabled: opacity == 1
286
287 clip: index == 1
288
289 CardTool {
290 id: cardTool
291 objectName: "cardTool"
292 count: results.count
293 template: model.renderer
294 components: model.components
295 viewWidth: parent.width
296 }
297
298 source: {
299 if (index == 0 && categoryId == "favorites") return "ScopesOverviewFavorites.qml";
300 else if (index == 1 && categoryId == "all") return "ScopesOverviewAll.qml";
301 else return "";
302 }
303
304 onLoaded: {
305 item.model = Qt.binding(function() { return results; });
306 item.cardTool = cardTool;
307 if (index == 0) {
308 item.scopeWidth = Qt.binding(function() { return root.width; });
309 item.scopeHeight = Qt.binding(function() { return root.height; });
310 item.appliedScale = Qt.binding(function() { return loader.scale });
311 item.currentIndex = Qt.binding(function() { return root.currentIndex });
312 } else if (index == 1) {
313 item.extraHeight = bottomBar.height;
314 }
315 }
316
317 Connections {
318 target: loader.item
319 onClicked: {
320 pageHeader.unfocus();
321 if (tabBar.currentTab == 0) {
322 root.favoriteSelected(itemModel.scopeId);
323 } else {
324 var favoriteScopesItem = middleItems.itemAt(0).item;
325 var scopeIndex = favoriteScopesItem.model.scopeIndex(itemModel.scopeId);
326 if (scopeIndex >= 0) {
327 root.allFavoriteSelected(itemModel.scopeId);
328 } else {
329 // Will result in an openScope from root.scope
330 scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
331 scopesOverviewXYScaler.restoreSize = allCardSize;
332 root.scope.activate(result);
333 }
334 }
335 }
336 onPressAndHold: {
337 // Preview can call openScope so make sure restorePosition and restoreSize are set
338 scopesOverviewXYScaler.restorePosition = undefined;
339 scopesOverviewXYScaler.restoreSize = allCardSize;
340
341 previewListView.model = target.model;
342 previewListView.currentIndex = -1;
343 previewListView.currentIndex = index;
344 previewListView.open = true;
345 }
346 }
347 }
348 }
349
350 GenericScopeView {
351 id: searchResultsViewer
352 objectName: "searchResultsViewer"
353 anchors {
354 top: pageHeader.bottom
355 right: parent.right
356 left: parent.left
357 bottom: parent.bottom
358 }
359 scope: root.scope && root.scope.searchQuery != "" ? root.scope : null
360 scopeStyle: overviewScopeStyle
361 enabled: opacity == 1
362 showPageHeader: false
363 clip: true
364 opacity: searchResultsViewer.scope ? 1 : 0
365 isCurrent: true
366 Behavior on opacity { UbuntuNumberAnimation { } }
367
368 function itemClicked(index, result, item, itemModel, resultsModel, limitedCategoryItemCount) {
369 pageHeader.unfocus();
370 pageHeader.closePopup();
371 if (itemModel.scopeId) {
372 // This can end up in openScope so save restorePosition and restoreSize
373 scopesOverviewXYScaler.restorePosition = item.mapToItem(null, 0, 0);
374 scopesOverviewXYScaler.restoreSize = Qt.size(item.width, item.height);
375 root.searchSelected(itemModel.scopeId, result, item.mapToItem(null, 0, 0), Qt.size(item.width, item.height));
376 } else {
377 // Not a scope, just activate it
378 searchResultsViewer.scope.activate(result);
379 }
380 }
381
382 function itemPressedAndHeld(index, itemModel, resultsModel, limitedCategoryItemCount) {
383 if (itemModel.uri.indexOf("scope://") === 0) {
384 // Preview can call openScope so make sure restorePosition and restoreSize are set
385 scopesOverviewXYScaler.restorePosition = undefined;
386 scopesOverviewXYScaler.restoreSize = allCardSize;
387
388 previewListView.model = resultsModel;
389 previewListView.currentIndex = -1;
390 previewListView.currentIndex = index;
391 previewListView.open = true;
392 }
393 }
394 }
395
396 Rectangle {
397 id: bottomBar
398 objectName: "bottomBar"
399 color: "black"
400 height: units.gu(8)
401 width: parent.width
402 enabled: opacity == 1
403 opacity: scope && scope.searchQuery == "" ? 1 : 0
404 Behavior on opacity { UbuntuNumberAnimation { } }
405 y: {
406 if (root.progress < 0.5) {
407 return parent.height;
408 } else {
409 return parent.height - (root.progress - 0.5) * height * 2;
410 }
411 }
412
413 MouseArea {
414 // Just eat any other press since this parent is black opaque
415 anchors.fill: parent
416 }
417
418 AbstractButton {
419 objectName: "scopesOverviewDoneButton"
420 width: Math.max(label.width + units.gu(2), units.gu(10))
421 height: units.gu(4)
422 anchors {
423 left: parent.left
424 leftMargin: units.gu(2)
425 verticalCenter: parent.verticalCenter
426 }
427 Rectangle {
428 anchors.fill: parent
429 border.color: "white"
430 border.width: units.dp(1)
431 radius: units.dp(10)
432 color: parent.pressed ? Theme.palette.normal.baseText : "transparent"
433 }
434 Label {
435 id: label
436 anchors.centerIn: parent
437 text: i18n.tr("Done")
438 color: parent.pressed ? "black" : "white"
439 }
440 onClicked: root.done();
441 }
442
443 AbstractButton {
444 objectName: "scopesOverviewStoreButton"
445 width: Math.max(storeLabel.width, units.gu(10))
446 height: units.gu(4)
447 anchors {
448 right: parent.right
449 verticalCenter: parent.verticalCenter
450 }
451 Icon {
452 id: storeImage
453 name: "ubuntu-store-symbolic"
454 color: "white"
455 anchors.horizontalCenter: parent.horizontalCenter
456 width: units.gu(2)
457 height: units.gu(2)
458 }
459 Label {
460 id: storeLabel
461 anchors.horizontalCenter: parent.horizontalCenter
462 anchors.top: storeImage.bottom
463 text: i18n.tr("Store")
464 color: "white"
465 }
466 onClicked: {
467 // Just zoom from the middle
468 scopesOverviewXYScaler.restorePosition = undefined;
469 scopesOverviewXYScaler.restoreSize = allCardSize;
470 scope.performQuery("scope://com.canonical.scopes.clickstore");
471 }
472 }
473 }
474 }
475
476 PreviewListView {
477 id: previewListView
478 objectName: "scopesOverviewPreviewListView"
479 scope: root.scope
480 scopeStyle: overviewScopeStyle
481 showSignatureLine: false
482 visible: x != width
483 width: parent.width
484 height: parent.height
485 anchors.left: scopesOverviewContent.right
486
487 onBackClicked: open = false
488 }
489
490 Item {
491 id: scopesOverviewXYScaler
492 width: parent.width
493 height: parent.height
494
495 clip: scale != 1.0
496 enabled: scale == 1
497
498 property bool animationsEnabled: root.showingNonFavoriteScope || root.growingDashFromPos
499
500 property var restorePosition
501 property var restoreSize
502
503 Behavior on x {
504 enabled: scopesOverviewXYScaler.animationsEnabled
505 UbuntuNumberAnimation { }
506 }
507 Behavior on y {
508 enabled: scopesOverviewXYScaler.animationsEnabled
509 UbuntuNumberAnimation { }
510 }
511 Behavior on opacity {
512 enabled: scopesOverviewXYScaler.animationsEnabled
513 UbuntuNumberAnimation { }
514 }
515 Behavior on scale {
516 enabled: scopesOverviewXYScaler.animationsEnabled
517 UbuntuNumberAnimation {
518 onRunningChanged: {
519 if (!running) {
520 if (root.showingNonFavoriteScope && scopesOverviewXYScaler.scale != 1) {
521 root.scope.closeScope(tempScopeItem.scope);
522 tempScopeItem.scope = null;
523 } else if (root.growingDashFromPos) {
524 root.growingDashFromPos = false;
525 }
526 }
527 }
528 }
529 }
530
531 DashBackground {
532 anchors.fill: tempScopeItem
533 visible: tempScopeItem.visible
534 parent: tempScopeItem.parent
535 }
536
537 GenericScopeView {
538 id: tempScopeItem
539 objectName: "scopesOverviewTempScopeItem"
540
541 width: parent.width
542 height: parent.height
543 clip: scale != 1.0
544 visible: scope != null
545 hasBackAction: true
546 isCurrent: visible
547 onBackClicked: {
548 var v = scopesOverviewXYScaler.restoreSize.width / tempScopeItem.width;
549 scopesOverviewXYScaler.scale = v;
550 if (scopesOverviewXYScaler.restorePosition) {
551 scopesOverviewXYScaler.x = scopesOverviewXYScaler.restorePosition.x -(tempScopeItem.width - tempScopeItem.width * v) / 2;
552 scopesOverviewXYScaler.y = scopesOverviewXYScaler.restorePosition.y -(tempScopeItem.height - tempScopeItem.height * v) / 2;
553 } else {
554 scopesOverviewXYScaler.x = 0;
555 scopesOverviewXYScaler.y = 0;
556 }
557 scopesOverviewXYScaler.opacity = 0;
558 middleItems.overrideOpacity = -1;
559 }
560 // TODO Add tests for these connections
561 Connections {
562 target: tempScopeItem.scope
563 onOpenScope: {
564 // TODO Animate the newly opened scope into the foreground (stacked on top of the current scope)
565 tempScopeItem.scope = scope;
566 }
567 onGotoScope: {
568 tempScopeItem.backClicked();
569 root.currentTab = 0;
570 root.scope.gotoScope(scopeId);
571 }
572 }
573 }
574 }
575}
5760
=== removed file 'qml/Dash/ScopesOverviewAll.qml'
--- qml/Dash/ScopesOverviewAll.qml 2014-11-05 08:37:55 +0000
+++ qml/Dash/ScopesOverviewAll.qml 1970-01-01 00:00:00 +0000
@@ -1,54 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import Ubuntu.Components 0.1
19
20Flickable {
21 id: root
22
23 property alias model: cardGrid.model
24 property alias cardTool: cardGrid.cardTool
25
26 property real extraHeight: 0
27
28 signal clicked(int index, var result, var item, var itemModel)
29 signal pressAndHold(int index)
30
31 contentHeight: cardGrid.expandedHeight + extraHeight
32 contentWidth: cardGrid.width
33 flickableDirection: Flickable.VerticalFlick
34
35 function scopeCardPosition(scopeId) {
36 var index = model.scopeIndex(scopeId);
37 var pos = cardGrid.cardPosition(index);
38 pos.y = pos.y - root.contentY;
39 return pos;
40 }
41
42 CardGrid {
43 id: cardGrid
44 width: root.width
45 height: parent.height
46
47 onClicked: {
48 root.clicked(index, result, item, itemModel);
49 }
50 onPressAndHold: {
51 root.pressAndHold(index);
52 }
53 }
54}
550
=== removed file 'qml/Dash/ScopesOverviewFavorites.qml'
--- qml/Dash/ScopesOverviewFavorites.qml 2014-10-23 11:59:22 +0000
+++ qml/Dash/ScopesOverviewFavorites.qml 1970-01-01 00:00:00 +0000
@@ -1,73 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18
19Flickable {
20 id: root
21
22 signal clicked(int index, var result, var itemModel)
23 signal pressAndHold(int index)
24
25 property var cardTool: null
26 property real scopeHeight: 0
27 property real scopeWidth: 0
28 property real appliedScale: 1
29 property int currentIndex: -1
30 property var currentItem: currentIndex < repeater.count ? repeater.itemAt(currentIndex) : null
31
32 property alias model: repeater.model
33
34 contentHeight: height
35 contentWidth: repeater.count * root.scopeWidth + units.gu(2) / appliedScale * (repeater.count - 1)
36
37 contentX: {
38 var indexX = currentIndex * scopeWidth + units.gu(2) / appliedScale * currentIndex;
39 var newContentX = indexX - (width - scopeWidth) / 2;
40 newContentX = Math.min(Math.max(newContentX, 0), contentWidth - width);
41 return newContentX;
42 }
43
44 Repeater {
45 id: repeater
46 objectName: "scopesOverviewFavoritesRepeater"
47
48 delegate: Loader {
49 id: loader
50
51 x: index * root.scopeWidth + units.gu(2) / appliedScale * index
52 asynchronous: true
53
54 sourceComponent: cardTool.cardComponent
55 onLoaded: {
56 item.fixedArtShapeSize = Qt.binding(function() { return Qt.size(root.scopeWidth, root.scopeHeight); });
57 item.fixedHeaderHeight = Qt.binding(function() { return cardTool.headerHeight / appliedScale; });
58 item.fontScale = Qt.binding(function() { return 1 / appliedScale; });
59 item.height = Qt.binding(function() { return root.scopeHeight; });
60 item.width = Qt.binding(function() { return root.scopeWidth; });
61 item.cardData = Qt.binding(function() { return model; });
62 item.template = Qt.binding(function() { return cardTool.template; });
63 item.components = Qt.binding(function() { return cardTool.components; });
64 item.titleAlignment = Qt.binding(function() { return cardTool.titleAlignment; });
65 }
66
67 Connections {
68 target: loader.item
69 onClicked: root.clicked(index, result, model)
70 }
71 }
72 }
73}
740
=== removed file 'qml/Dash/ScopesOverviewTab.qml'
--- qml/Dash/ScopesOverviewTab.qml 2014-07-21 11:10:06 +0000
+++ qml/Dash/ScopesOverviewTab.qml 1970-01-01 00:00:00 +0000
@@ -1,74 +0,0 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.3
18import Ubuntu.Components 0.1
19
20Item {
21 id: root
22
23 property int currentTab: 0
24
25 AbstractButton {
26 id: tab1
27 height: parent.height
28 width: parent.width / 2
29 Rectangle {
30 anchors.fill: parent
31 color: root.currentTab == 0 && root.enabled ? "white" : "transparent"
32 radius: units.dp(10)
33 }
34 Label {
35 anchors.centerIn: parent
36 text: i18n.tr("Favorites")
37 color: root.currentTab == 0 && root.enabled ? "black" : "white"
38 }
39 onClicked: root.currentTab = 0
40 }
41 AbstractButton {
42 id: tab2
43 objectName: "scopesOverviewAllTabButton"
44 x: width
45 height: parent.height
46 width: parent.width / 2
47 Rectangle {
48 anchors.fill: parent
49 color: root.currentTab == 1 && root.enabled ? "white" : "transparent"
50 radius: units.dp(10)
51 }
52 Label {
53 anchors.centerIn: parent
54 text: i18n.tr("All")
55 color: root.currentTab == 1 && root.enabled ? "black" : "white"
56 }
57 onClicked: root.currentTab = 1
58 }
59 Rectangle {
60 id: centerPiece
61 width: root.enabled ? units.dp(10) : units.dp(1)
62 height: parent.height
63 color: "white"
64 x: root.currentTab == 1 ? tab2.x : tab2.x - width
65 }
66 Rectangle {
67 id: border
68 anchors.fill: parent
69 radius: units.dp(10)
70 color: "transparent"
71 border.color: centerPiece.color
72 border.width: units.dp(1)
73 }
74}
750
=== modified file 'tests/mocks/Unity/CMakeLists.txt'
--- tests/mocks/Unity/CMakeLists.txt 2014-10-28 12:29:43 +0000
+++ tests/mocks/Unity/CMakeLists.txt 2014-12-05 10:47:59 +0000
@@ -6,7 +6,7 @@
6add_subdirectory(DashCommunicator)6add_subdirectory(DashCommunicator)
77
8pkg_search_module(GOBJECT gobject-2.0 REQUIRED)8pkg_search_module(GOBJECT gobject-2.0 REQUIRED)
9pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=4)9pkg_check_modules(SCOPES_API REQUIRED unity-shell-scopes=5)
1010
11include_directories(11include_directories(
12 ${CMAKE_CURRENT_BINARY_DIR}12 ${CMAKE_CURRENT_BINARY_DIR}
1313
=== modified file 'tests/mocks/Unity/fake_scopes.cpp'
--- tests/mocks/Unity/fake_scopes.cpp 2014-09-16 04:44:37 +0000
+++ tests/mocks/Unity/fake_scopes.cpp 2014-12-05 10:47:59 +0000
@@ -165,14 +165,68 @@
165 return m_scopesOverview;165 return m_scopesOverview;
166}166}
167167
168QList<Scope*> Scopes::scopes() const168void Scopes::setFavorite(const QString& scopeId, bool favorite)
169{
170 if (favorite) {
171 for (Scope *scope : m_scopes) {
172 // Check it's not already there
173 Q_ASSERT(scope->id() != scopeId);
174 }
175 for (Scope *scope : m_allScopes) {
176 if (scope->id() == scopeId) {
177 const int index = rowCount();
178 beginInsertRows(QModelIndex(), index, index);
179 m_scopes << scope;
180 endInsertRows();
181 m_scopesOverview->setFavorite(scope, true);
182 return;
183 }
184 }
185 Q_ASSERT(false && "Unknown scopeId");
186 } else {
187 for (Scope *scope : m_scopes) {
188 if (scope->id() == scopeId) {
189 const int index = m_scopes.indexOf(scope);
190 beginRemoveRows(QModelIndex(), index, index);
191 m_scopes.removeAt(index);
192 endRemoveRows();
193 m_scopesOverview->setFavorite(scope, false);
194 return;
195 }
196 }
197 Q_ASSERT(false && "Unknown scopeId");
198 }
199}
200
201void Scopes::moveFavoriteTo(const QString& scopeId, int to)
202{
203 int from = -1;
204 for (int i = 0; i < m_scopes.count(); ++i) {
205 if (m_scopes[i]->id() == scopeId) {
206 from = i;
207 break;
208 }
209 }
210 Q_ASSERT(from != -1);
211 beginMoveRows(QModelIndex(), from, from, QModelIndex(), to + (to > from ? 1 : 0));
212 m_scopes.move(from, to);
213 endMoveRows();
214 m_scopesOverview->moveFavoriteTo(m_scopes[to], to);
215}
216
217QList<Scope*> Scopes::favScopes() const
169{218{
170 return m_scopes;219 return m_scopes;
171}220}
172221
173QList<Scope*> Scopes::allScopes() const222QList<Scope*> Scopes::nonFavScopes() const
174{223{
175 return m_allScopes;224 QList<Scope*> res;
225 for (Scope *scope : m_allScopes) {
226 if (!m_scopes.contains(scope))
227 res << scope;
228 }
229 return res;
176}230}
177231
178void Scopes::addScope(Scope* scope)232void Scopes::addScope(Scope* scope)
179233
=== modified file 'tests/mocks/Unity/fake_scopes.h'
--- tests/mocks/Unity/fake_scopes.h 2014-08-25 14:13:24 +0000
+++ tests/mocks/Unity/fake_scopes.h 2014-12-05 10:47:59 +0000
@@ -28,6 +28,8 @@
28#include <QList>28#include <QList>
29#include <QTimer>29#include <QTimer>
3030
31class ScopesOverview;
32
31class Scopes : public unity::shell::scopes::ScopesInterface33class Scopes : public unity::shell::scopes::ScopesInterface
32{34{
33 Q_OBJECT35 Q_OBJECT
@@ -53,9 +55,12 @@
53 int count() const override;55 int count() const override;
54 unity::shell::scopes::ScopeInterface* overviewScope() const override;56 unity::shell::scopes::ScopeInterface* overviewScope() const override;
5557
58 Q_INVOKABLE void setFavorite(const QString& scopeId, bool favorite) override;
59 Q_INVOKABLE void moveFavoriteTo(const QString& scopeId, int index) override;
60
56 // This is used as part of implementation of the other C++ code, not API61 // This is used as part of implementation of the other C++ code, not API
57 QList<Scope*> scopes() const;62 QList<Scope*> favScopes() const;
58 QList<Scope*> allScopes() const;63 QList<Scope*> nonFavScopes() const;
59 Q_INVOKABLE Scope* getScopeFromAll(const QString& scope_id) const;64 Q_INVOKABLE Scope* getScopeFromAll(const QString& scope_id) const;
6065
61private Q_SLOTS:66private Q_SLOTS:
@@ -64,7 +69,7 @@
64private:69private:
65 QList<Scope*> m_scopes; // the favorite ones70 QList<Scope*> m_scopes; // the favorite ones
66 QList<Scope*> m_allScopes;71 QList<Scope*> m_allScopes;
67 Scope *m_scopesOverview;72 ScopesOverview *m_scopesOverview;
68 bool m_loaded;73 bool m_loaded;
69 QTimer timer;74 QTimer timer;
70};75};
7176
=== modified file 'tests/mocks/Unity/fake_scopesoverview.cpp'
--- tests/mocks/Unity/fake_scopesoverview.cpp 2014-08-13 23:26:36 +0000
+++ tests/mocks/Unity/fake_scopesoverview.cpp 2014-12-05 10:47:59 +0000
@@ -44,8 +44,22 @@
44Q_INVOKABLE void ScopesOverview::activate(QVariant const& result)44Q_INVOKABLE void ScopesOverview::activate(QVariant const& result)
45{45{
46 Scopes *scopes = dynamic_cast<Scopes*>(parent());46 Scopes *scopes = dynamic_cast<Scopes*>(parent());
47 m_openScope = scopes->getScopeFromAll(result.toString());47 if (scopes->getScope(result.toString())) {
48 Q_EMIT openScope(m_openScope);48 Q_EMIT gotoScope(result.toString());
49 } else {
50 m_openScope = scopes->getScopeFromAll(result.toString());
51 Q_EMIT openScope(m_openScope);
52 }
53}
54
55void ScopesOverview::setFavorite(Scope *scope, bool favorite)
56{
57 m_scopesOverviewCategories->setFavorite(scope, favorite);
58}
59
60void ScopesOverview::moveFavoriteTo(Scope *scope, int index)
61{
62 m_scopesOverviewCategories->moveFavoriteTo(scope, index);
49}63}
5064
51ScopesOverviewCategories::ScopesOverviewCategories(Scopes *scopes, QObject* parent)65ScopesOverviewCategories::ScopesOverviewCategories(Scopes *scopes, QObject* parent)
@@ -69,19 +83,41 @@
69 qFatal("Using un-implemented ScopesOverviewCategories::overrideCategoryJson");83 qFatal("Using un-implemented ScopesOverviewCategories::overrideCategoryJson");
70}84}
7185
72QVariant86void ScopesOverviewCategories::setFavorite(Scope *scope, bool favorite)
73ScopesOverviewCategories::data(const QModelIndex& index, int role) const87{
88 if (m_resultsModels.value(0)) {
89 if (favorite) {
90 m_resultsModels[0]->appendScope(scope);
91 } else {
92 m_resultsModels[0]->removeScope(scope);
93 }
94 }
95 if (m_resultsModels.value(1)) {
96 if (favorite) {
97 m_resultsModels[1]->removeScope(scope);
98 } else {
99 m_resultsModels[1]->appendScope(scope);
100 }
101 }
102}
103
104void ScopesOverviewCategories::moveFavoriteTo(Scope *scope, int index)
105{
106 m_resultsModels[0]->moveScopeTo(scope, index);
107}
108
109QVariant ScopesOverviewCategories::data(const QModelIndex& index, int role) const
74{110{
75 if (!index.isValid()) {111 if (!index.isValid()) {
76 return QVariant();112 return QVariant();
77 }113 }
78114
79 const QString categoryId = index.row() == 0 ? "favorites" : "all";115 const QString categoryId = index.row() == 0 ? "favorites" : "other";
80116
81 unity::shell::scopes::ResultsModelInterface *resultsModel = m_resultsModels[index.row()];117 ScopesOverviewResultsModel *resultsModel = m_resultsModels[index.row()];
82 if (!resultsModel) {118 if (!resultsModel) {
83 QObject *that = const_cast<ScopesOverviewCategories*>(this);119 QObject *that = const_cast<ScopesOverviewCategories*>(this);
84 QList<Scope*> scopes = index.row() == 0 ? m_scopes->scopes() : m_scopes->allScopes();120 QList<Scope*> scopes = index.row() == 0 ? m_scopes->favScopes() : m_scopes->nonFavScopes();
85 resultsModel = new ScopesOverviewResultsModel(scopes, categoryId, that);121 resultsModel = new ScopesOverviewResultsModel(scopes, categoryId, that);
86 m_resultsModels[index.row()] = resultsModel;122 m_resultsModels[index.row()] = resultsModel;
87 }123 }
@@ -89,7 +125,7 @@
89 case RoleCategoryId:125 case RoleCategoryId:
90 return categoryId;126 return categoryId;
91 case RoleName:127 case RoleName:
92 return index.row() == 0 ? "Favorites" : "All";128 return index.row() == 0 ? "Favorites" : "Non Favorites";
93 case RoleIcon:129 case RoleIcon:
94 return QVariant();130 return QVariant();
95 case RoleRawRendererTemplate:131 case RoleRawRendererTemplate:
@@ -157,7 +193,7 @@
157193
158 const QString categoryId = index.row() == 0 ? "searchA" : "searchB";194 const QString categoryId = index.row() == 0 ? "searchA" : "searchB";
159195
160 unity::shell::scopes::ResultsModelInterface *resultsModel = m_resultsModels[index.row()];196 ScopesOverviewResultsModel *resultsModel = m_resultsModels[index.row()];
161 if (!resultsModel) {197 if (!resultsModel) {
162 QObject *that = const_cast<ScopesOverviewSearchCategories*>(this);198 QObject *that = const_cast<ScopesOverviewSearchCategories*>(this);
163 QList<Scope *> scopes;199 QList<Scope *> scopes;
@@ -256,8 +292,7 @@
256 return rowCount();292 return rowCount();
257}293}
258294
259QVariant295QVariant ScopesOverviewResultsModel::data(const QModelIndex& index, int role) const
260ScopesOverviewResultsModel::data(const QModelIndex& index, int role) const
261{296{
262 unity::shell::scopes::ScopeInterface *scope = m_scopes[index.row()];297 unity::shell::scopes::ScopeInterface *scope = m_scopes[index.row()];
263 switch (role) {298 switch (role) {
@@ -269,6 +304,8 @@
269 return scope ? scope->id() : QString("Result.%1.%2").arg(categoryId()).arg(index.row());304 return scope ? scope->id() : QString("Result.%1.%2").arg(categoryId()).arg(index.row());
270 case RoleTitle:305 case RoleTitle:
271 return scope ? scope->name() : QString("Title.%1.%2").arg(categoryId()).arg(index.row());306 return scope ? scope->name() : QString("Title.%1.%2").arg(categoryId()).arg(index.row());
307 case RoleSubtitle:
308 return scope && scope->name() == "Videos" ? "tube, movies, cinema" : QString();
272 case RoleArt:309 case RoleArt:
273 return qmlDirectory() + "graphics/applicationIcons/dash.png";310 return qmlDirectory() + "graphics/applicationIcons/dash.png";
274 case RoleMascot:311 case RoleMascot:
@@ -281,3 +318,32 @@
281 return QVariant();318 return QVariant();
282 }319 }
283}320}
321
322void ScopesOverviewResultsModel::appendScope(Scope *scope)
323{
324 Q_ASSERT(!m_scopes.contains(scope));
325 const int index = rowCount();
326 beginInsertRows(QModelIndex(), index, index);
327 m_scopes << scope;
328 endInsertRows();
329 Q_EMIT countChanged();
330}
331
332void ScopesOverviewResultsModel::removeScope(Scope *scope)
333{
334 const int index = m_scopes.indexOf(scope);
335 Q_ASSERT(index != -1);
336 beginRemoveRows(QModelIndex(), index, index);
337 m_scopes.removeAt(index);
338 endRemoveRows();
339 Q_EMIT countChanged();
340}
341
342void ScopesOverviewResultsModel::moveScopeTo(Scope *scope, int to)
343{
344 const int from = m_scopes.indexOf(scope);
345 Q_ASSERT(from!= -1);
346 beginMoveRows(QModelIndex(), from, from, QModelIndex(), to + (to > from ? 1 : 0));
347 m_scopes.move(from, to);
348 endMoveRows();
349}
284350
=== modified file 'tests/mocks/Unity/fake_scopesoverview.h'
--- tests/mocks/Unity/fake_scopesoverview.h 2014-08-07 08:52:59 +0000
+++ tests/mocks/Unity/fake_scopesoverview.h 2014-12-05 10:47:59 +0000
@@ -21,6 +21,8 @@
21#include <unity/shell/scopes/ResultsModelInterface.h>21#include <unity/shell/scopes/ResultsModelInterface.h>
2222
23class Scopes;23class Scopes;
24class ScopesOverviewCategories;
25class ScopesOverviewResultsModel;
2426
25class ScopesOverview : public Scope27class ScopesOverview : public Scope
26{28{
@@ -32,8 +34,12 @@
32 void setSearchQuery(const QString& search_query) override;34 void setSearchQuery(const QString& search_query) override;
33 Q_INVOKABLE void activate(QVariant const& result) override;35 Q_INVOKABLE void activate(QVariant const& result) override;
3436
37 // This is implementation detail
38 void setFavorite(Scope *scope, bool favorite);
39 void moveFavoriteTo(Scope *scope, int index);
40
35private:41private:
36 unity::shell::scopes::CategoriesInterface *m_scopesOverviewCategories;42 ScopesOverviewCategories *m_scopesOverviewCategories;
37 unity::shell::scopes::CategoriesInterface *m_searchCategories;43 unity::shell::scopes::CategoriesInterface *m_searchCategories;
38};44};
3945
@@ -50,8 +56,12 @@
50 Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;56 Q_INVOKABLE void addSpecialCategory(QString const& categoryId, QString const& name, QString const& icon, QString const& rawTemplate, QObject* countObject) override;
51 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;57 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
5258
59 // This is implementation detail
60 void setFavorite(Scope *scope, bool favorite);
61 void moveFavoriteTo(Scope *scope, int index);
62
53private:63private:
54 mutable QHash<int, unity::shell::scopes::ResultsModelInterface*> m_resultsModels;64 mutable QHash<int, ScopesOverviewResultsModel*> m_resultsModels;
5565
56 Scopes *m_scopes;66 Scopes *m_scopes;
57};67};
@@ -70,7 +80,7 @@
70 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;80 Q_INVOKABLE bool overrideCategoryJson(QString const& categoryId, QString const& json) override;
7181
72private:82private:
73 mutable QHash<int, unity::shell::scopes::ResultsModelInterface*> m_resultsModels;83 mutable QHash<int, ScopesOverviewResultsModel*> m_resultsModels;
7484
75 Scopes *m_scopes;85 Scopes *m_scopes;
76};86};
@@ -96,6 +106,11 @@
96 Q_INVOKABLE int scopeIndex(QString const& id) const;106 Q_INVOKABLE int scopeIndex(QString const& id) const;
97 QHash<int, QByteArray> roleNames() const override;107 QHash<int, QByteArray> roleNames() const override;
98108
109 // This is implementation detail
110 void appendScope(Scope *scope);
111 void removeScope(Scope *scope);
112 void moveScopeTo(Scope *scope, int index);
113
99private:114private:
100 QList<Scope *> m_scopes;115 QList<Scope *> m_scopes;
101 QString m_categoryId;116 QString m_categoryId;
102117
=== modified file 'tests/qmltests/Dash/tst_Dash.qml'
--- tests/qmltests/Dash/tst_Dash.qml 2014-12-02 09:25:01 +0000
+++ tests/qmltests/Dash/tst_Dash.qml 2014-12-05 10:47:59 +0000
@@ -79,175 +79,108 @@
79 return get_scope_data()79 return get_scope_data()
80 }80 }
8181
82 function test_dash_overview_show_select_same_favorite() {82 function test_manage_dash_select_same_favorite() {
83 // Show the overview83 // Show the manage dash
84 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));84 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
85 var overviewController = findInvisibleChild(dash, "overviewController");85 var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
86 tryCompare(overviewController, "progress", 1);86 tryCompare(bottomEdgeController, "progress", 1);
87
88 // Make sure tab is where it should
89 var scopesOverview = findChild(dash, "scopesOverview");
90 compare(scopesOverview.currentTab, 0);
9187
92 // Make sure stuff is loaded88 // Make sure stuff is loaded
93 var scopesOverviewFavoritesRepeater = findChild(dash, "scopesOverviewFavoritesRepeater");89 var favScopesListCategory = findChild(dash, "scopesListCategoryfavorites");
94 tryCompare(scopesOverviewFavoritesRepeater, "count", 6);90 var favScopesListCategoryList = findChild(favScopesListCategory, "scopesListCategoryInnerList");
95 tryCompareFunction(function() { return scopesOverviewFavoritesRepeater.itemAt(0).item != null; }, true);91 tryCompare(favScopesListCategoryList, "currentIndex", 0);
96 waitForRendering(scopesOverviewFavoritesRepeater.itemAt(0).item);
9792
98 // Click in first item93 // Click in first item
99 mouseClick(scopesOverviewFavoritesRepeater.itemAt(0).item, 0, 0);94 mouseClick(favScopesListCategoryList.currentItem, 0, 0);
10095
101 // Make sure animation went back96 // Make sure animation went back
102 tryCompare(overviewController, "progress", 0);97 tryCompare(bottomEdgeController, "progress", 0);
10398
104 var dashContentList = findChild(dash, "dashContentList");99 var dashContentList = findChild(dash, "dashContentList");
105 compare(dashContentList.currentIndex, 0);100 compare(dashContentList.currentIndex, 0);
106 }101 }
107102
108 function test_dash_overview_show_select_different_favorite() {103 function test_manage_dash_select_different_favorite() {
109 // Show the overview104 // Show the manage dash
110 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));105 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
111 var overviewController = findInvisibleChild(dash, "overviewController");106 var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
112 tryCompare(overviewController, "progress", 1);107 tryCompare(bottomEdgeController, "progress", 1);
113
114 // Make sure tab is where it should
115 var scopesOverview = findChild(dash, "scopesOverview");
116 compare(scopesOverview.currentTab, 0);
117108
118 // Make sure stuff is loaded109 // Make sure stuff is loaded
119 var scopesOverviewFavoritesRepeater = findChild(dash, "scopesOverviewFavoritesRepeater");110 var favScopesListCategory = findChild(dash, "scopesListCategoryfavorites");
120 tryCompare(scopesOverviewFavoritesRepeater, "count", 6);111 var favScopesListCategoryList = findChild(favScopesListCategory, "scopesListCategoryInnerList");
121 tryCompareFunction(function() { return scopesOverviewFavoritesRepeater.itemAt(0).item != null; }, true);112 tryCompare(favScopesListCategoryList, "currentIndex", 0);
122 waitForRendering(scopesOverviewFavoritesRepeater.itemAt(1).item);
123113
124 // Click in first item114 // Click in second item
125 mouseClick(scopesOverviewFavoritesRepeater.itemAt(1).item, 0, 0);115 favScopesListCategoryList.currentIndex = 1;
116 mouseClick(favScopesListCategoryList.currentItem, 0, 0);
126117
127 // Make sure animation went back118 // Make sure animation went back
128 tryCompare(overviewController, "progress", 0);119 tryCompare(bottomEdgeController, "progress", 0);
129 var dashContentList = findChild(dash, "dashContentList");120 var dashContentList = findChild(dash, "dashContentList");
130 compare(dashContentList.currentIndex, 1);121 compare(dashContentList.currentIndex, 1);
131 }122 }
132123
133 function test_dash_overview_all_temp_scope_done_from_all() {124 function test_manage_dash_select_non_favorite() {
134 // Show the overview125 // Show the manage dash
135 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));126 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
136 var overviewController = findInvisibleChild(dash, "overviewController");127 var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
137 tryCompare(overviewController, "progress", 1);128 tryCompare(bottomEdgeController, "progress", 1);
138
139 // Make sure tab is where it should
140 var scopesOverview = findChild(dash, "scopesOverview");
141 compare(scopesOverview.currentTab, 0);
142129
143 // Make sure stuff is loaded130 // Make sure stuff is loaded
144 var scopesOverviewFavoritesRepeater = findChild(dash, "scopesOverviewFavoritesRepeater");131 var nonfavScopesListCategory = findChild(dash, "scopesListCategoryother");
145 tryCompare(scopesOverviewFavoritesRepeater, "count", 6);132 var nonfavScopesListCategoryList = findChild(nonfavScopesListCategory, "scopesListCategoryInnerList");
146 tryCompareFunction(function() { return scopesOverviewFavoritesRepeater.itemAt(0).item != null; }, true);133 tryCompare(nonfavScopesListCategoryList, "currentIndex", 0);
147 waitForRendering(scopesOverviewFavoritesRepeater.itemAt(1).item);134
148135 // Click on a non favorite scope
149 // Click on the all tab136 mouseClick(nonfavScopesListCategoryList.currentItem, 0, 0);
150 var scopesOverviewAllTabButton = findChild(dash, "scopesOverviewAllTabButton");137
151 mouseClick(scopesOverviewAllTabButton, 0, 0);138 // Check the bottom edge (manage dash) is disabled from temp scope
152
153 // Wait for all tab to be enabled (animation finish)
154 var scopesOverviewAllView = findChild(dash, "scopesOverviewRepeaterChild1");
155 tryCompare(scopesOverviewAllView, "enabled", true);
156
157 // Click in the middle of the black bar (nothing happens)
158 var bottomBar = findChild(scopesOverview, "bottomBar");
159 mouseClick(bottomBar, bottomBar.width / 2, bottomBar.height / 2);
160 // Check temp scope is not there
161 var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");
162 expectFailContinue("", "Clicking in the middle of bottom bar should not open a temp scope");
163 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);
164
165 // Click on a temp scope
166 var tempScopeCard = findChild(scopesOverviewAllView, "delegate1");
167 mouseClick(tempScopeCard, 0, 0);
168
169 // Check the bottom edge (overview) is disabled from temp scope
170 var overviewDragHandle = findChild(dash, "overviewDragHandle");139 var overviewDragHandle = findChild(dash, "overviewDragHandle");
171 compare(overviewDragHandle.enabled, false);140 compare(overviewDragHandle.enabled, false);
172141
173 // Check temp scope is there142 // Check temp scope is there
174 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);143 var dashTempScopeItem = findChild(dash, "dashTempScopeItem");
175 tryCompare(scopesOverviewTempScopeItem, "enabled", true);144 tryCompare(dashTempScopeItem, "x", 0);
145 tryCompare(dashTempScopeItem, "visible", true);
146
147 // Check the manage dash is gone
148 tryCompare(bottomEdgeController, "progress", 0);
176149
177 // Go back150 // Go back
178 var scopesOverviewTempScopeItemHeader = findChild(scopesOverviewTempScopeItem, "scopePageHeader");151 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
179 var backButton = findChild(findChild(scopesOverviewTempScopeItemHeader, "innerPageHeader"), "backButton");152 var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "backButton");
180 mouseClick(backButton, 0, 0);153 mouseClick(backButton, 0, 0);
181154
182 // Check temp scope is gone155 // Check temp scope is gone
183 var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");156 tryCompare(dashTempScopeItem, "x", dash.width);
184 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope == null; }, true);157 tryCompare(dashTempScopeItem, "visible", false);
185 tryCompare(scopesOverviewTempScopeItem, "enabled", false);
186
187 // Press on done
188 var scopesOverviewDoneButton = findChild(scopesOverview, "scopesOverviewDoneButton");
189 mouseClick(scopesOverviewDoneButton, 0, 0);
190
191 // Check the dash overview is gone
192 tryCompare(overviewController, "progress", 0);
193158
194 // Original list is still on 0159 // Original list is still on 0
195 var dashContentList = findChild(dash, "dashContentList");160 var dashContentList = findChild(dash, "dashContentList");
196 compare(dashContentList.currentIndex, 0);161 compare(dashContentList.currentIndex, 0);
197 }162 }
198163
199 function test_temp_scope_dash_overview_all_search_temp_scope_favorite_from_all() {164 function test_manage_dash_search_temp_scope() {
200 // Swipe right to Apps scope165 // Show the manage dash
201 var dashContentList = findChild(dash, "dashContentList");166 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, units.gu(2));
202 touchFlick(dash, dash.width - 1, units.gu(1), dash.width - units.gu(10), units.gu(1));167 var bottomEdgeController = findInvisibleChild(dash, "bottomEdgeController");
203 tryCompare(dashContentList, "contentX", dashContentList.width);168 tryCompare(bottomEdgeController, "progress", 1);
204 tryCompare(dashContentList, "currentIndex", 1);
205
206 // Click on card that opens temp scope
207 var categoryListView = findChild(dashContentList.currentItem, "categoryListView");
208 var dashCategory2 = findChild(categoryListView, "dashCategory2");
209 tryCompareFunction(function() {
210 if (dashCategory2.y < 200) return true;
211 categoryListView.contentY += 100;
212 return false;
213 }, true);
214 var card2 = findChild(dashCategory2, "delegate2");
215 waitForRendering(card2);
216 mouseClick(card2, card2.width / 2, card2.height / 2);
217
218 // Wait for temp scope to be there
219 var dashTempScopeItem = findChild(dash, "dashTempScopeItem");
220 tryCompare(dashTempScopeItem, "x", 0);
221
222 // Show the overview
223 touchFlick(dash, dash.width / 2, dash.height - 1, dash.width / 2, dash.height - units.gu(18));
224 var overviewController = findInvisibleChild(dash, "overviewController");
225 tryCompare(overviewController, "progress", 1);
226
227 // Make sure tab is where it should
228 var scopesOverview = findChild(dash, "scopesOverview");
229 compare(scopesOverview.currentTab, 1);
230169
231 // Do a search170 // Do a search
232 var scopesOverviewPageHeader = findChild(scopesOverview, "scopesOverviewPageHeader");171 var scopesList = findChild(dash, "scopesList");
233 var searchButton = findChild(scopesOverviewPageHeader, "search_header_button");172 var scopesListPageHeader = findChild(scopesList, "pageHeader");
173 var searchButton = findChild(scopesListPageHeader, "search_header_button");
234 mouseClick(searchButton, 0, 0);174 mouseClick(searchButton, 0, 0);
235175
236 // Type something176 // Type something
237 keyClick(Qt.Key_H);177 keyClick(Qt.Key_H);
238178
239 // Check results grid is there and the other lists are not
240 var searchResultsViewer = findChild(scopesOverview, "searchResultsViewer");
241 var scopesOverviewRepeater = findChild(dash, "scopesOverviewRepeater");
242 tryCompare(searchResultsViewer, "opacity", 1);
243 tryCompare(scopesOverviewRepeater, "count", 0);
244
245 // Click on a temp scope in the search179 // Click on a temp scope in the search
246 tryCompareFunction( function() {180 tryCompareFunction( function() { return findChild(scopesList, "scopesListCategorysearchA") != null; }, true);
247 return findChild(findChild(searchResultsViewer, "dashCategorysearchA"), "delegate2") != null;181 var dashCategorysearchA = findChild(scopesList, "scopesListCategorysearchA");
248 }, true);182 tryCompareFunction( function() { return findChild(dashCategorysearchA, "delegate2") != null; }, true);
249 var cardTempScope = findChild(findChild(searchResultsViewer, "dashCategorysearchA"), "delegate2");183 var cardTempScope = findChild(dashCategorysearchA, "delegate2");
250 verify(cardTempScope, "Could not find delegate2");
251184
252 waitForRendering(cardTempScope);185 waitForRendering(cardTempScope);
253 mouseClick(cardTempScope, cardTempScope.width / 2, cardTempScope.height / 2);186 mouseClick(cardTempScope, cardTempScope.width / 2, cardTempScope.height / 2);
@@ -257,29 +190,24 @@
257 compare(overviewDragHandle.enabled, false);190 compare(overviewDragHandle.enabled, false);
258191
259 // Check temp scope is there192 // Check temp scope is there
260 var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");193 var dashTempScopeItem = findChild(dash, "dashTempScopeItem");
261 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope != null; }, true);194 tryCompare(dashTempScopeItem, "x", 0);
262 tryCompare(scopesOverviewTempScopeItem, "enabled", true);195 tryCompare(dashTempScopeItem, "visible", true);
196
197 // Check the manage dash is gone
198 tryCompare(bottomEdgeController, "progress", 0);
263199
264 // Go back200 // Go back
265 var scopesOverviewTempScopeItemHeader = findChild(scopesOverviewTempScopeItem, "scopePageHeader");201 var dashTempScopeItemHeader = findChild(dashTempScopeItem, "scopePageHeader");
266 var backButton = findChild(findChild(scopesOverviewTempScopeItemHeader, "innerPageHeader"), "backButton");202 var backButton = findChild(findChild(dashTempScopeItemHeader, "innerPageHeader"), "backButton");
267 mouseClick(backButton, 0, 0);203 mouseClick(backButton, 0, 0);
268204
269 // Check temp scope is gone205 // Check temp scope is gone
270 var scopesOverviewTempScopeItem = findChild(dash, "scopesOverviewTempScopeItem");206 tryCompare(dashTempScopeItem, "x", dash.width);
271 tryCompareFunction( function() { return scopesOverviewTempScopeItem.scope == null; }, true);207 tryCompare(dashTempScopeItem, "visible", false);
272 tryCompare(scopesOverviewTempScopeItem, "enabled", false);208
273209 // Original list is still on 0
274 // Press on a favorite210 var dashContentList = findChild(dash, "dashContentList");
275 var dashCategorysearchB = findChild(searchResultsViewer, "dashCategorysearchB");
276 var cardFavSearch = findChild(dashCategorysearchB, "delegate3");
277 mouseClick(cardFavSearch, 0, 0);
278
279 // Check the dash overview is gone
280 tryCompare(overviewController, "progress", 0);
281
282 // Original list went to the favorite
283 compare(dashContentList.currentIndex, 0);211 compare(dashContentList.currentIndex, 0);
284 }212 }
285213
286214
=== modified file 'tests/qmltests/Dash/tst_GenericScopeView.qml'
--- tests/qmltests/Dash/tst_GenericScopeView.qml 2014-11-26 08:27:45 +0000
+++ tests/qmltests/Dash/tst_GenericScopeView.qml 2014-12-05 10:47:59 +0000
@@ -574,7 +574,6 @@
574 var innerHeader = findChild(header, "innerPageHeader");574 var innerHeader = findChild(header, "innerPageHeader");
575 verify(innerHeader, "Could not find the inner header");575 verify(innerHeader, "Could not find the inner header");
576576
577 expectFail("Apps", "Click scope should not have a favorite button");
578 var favoriteAction = findChild(innerHeader, "favorite_header_button");577 var favoriteAction = findChild(innerHeader, "favorite_header_button");
579 verify(favoriteAction, "Could not find the favorite action.");578 verify(favoriteAction, "Could not find the favorite action.");
580 mouseClick(favoriteAction, favoriteAction.width / 2, favoriteAction.height / 2);579 mouseClick(favoriteAction, favoriteAction.width / 2, favoriteAction.height / 2);

Subscribers

People subscribed via source and target branches