Merge lp:~ahayzen/music-app/refactor-move-delegates into lp:music-app
- refactor-move-delegates
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Victor Thompson |
Approved revision: | 845 |
Merged at revision: | 841 |
Proposed branch: | lp:~ahayzen/music-app/refactor-move-delegates |
Merge into: | lp:music-app |
Diff against target: |
1287 lines (+455/-480) 19 files modified
app/components/CMakeLists.txt (+1/-0) app/components/Delegates/CMakeLists.txt (+4/-0) app/components/Delegates/Card.qml (+1/-0) app/components/Delegates/ListItemWithActions.qml (+9/-239) app/components/Delegates/MusicListItem.qml (+151/-0) app/components/ListItemActions/AddToPlaylist.qml (+0/-2) app/components/ListItemActions/Remove.qml (+0/-2) app/components/ListItemReorderComponent.qml (+106/-0) app/ui/AddToPlaylist.qml (+1/-0) app/ui/Albums.qml (+1/-0) app/ui/ArtistView.qml (+1/-0) app/ui/Artists.qml (+1/-0) app/ui/Genres.qml (+1/-0) app/ui/NowPlaying.qml (+57/-90) app/ui/Playlists.qml (+1/-0) app/ui/Recent.qml (+1/-0) app/ui/Songs.qml (+38/-55) app/ui/SongsView.qml (+77/-88) tests/autopilot/music_app/__init__.py (+4/-4) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/refactor-move-delegates |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Victor Thompson | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+249883@code.launchpad.net |
Commit message
* Move delegates into their own folder in components
* Split out multiselect/reorder code from ListItemWithAct
* Fix for ListItemWithAct
Description of the change
* Move delegates into their own folder in components
* Split out multiselect/reorder code from ListItemWithAct
* Fix for ListItemWithAct
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
- 842. By Andrew Hayzen
-
* Fix for autopilot
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:842
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
Is there any way more we could get more code reuse out of MusicListItem.qml? It's a pretty skinny component and we still have a lot of code for each usage of MusicListItem. I'm not seeing an easy way of doing so, however.
- 843. By Andrew Hayzen
-
* Split reorder code into a separate component and out of ListItemWithAct
ions.qml
* Split out some of the custom multiselect code - 844. By Andrew Hayzen
-
* Pull further multiselect code into MusicListItem.qml
* Remove use of primed as it is not used anymore - 845. By Andrew Hayzen
-
* Sort out autogenerated Component
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:845
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
This looks good. One issue I'm having is that deleting a playlist freezes the app. I'm not sure what your change would have done to cause this.
Victor Thompson (vthompson) wrote : | # |
The above issue also exists in the refactor series's trunk. I get the following in the console:
QQmlExpression: Attempted to evaluate an expression in an invalid context
qml: called LibraryListMode
Since this wasn't introduced by the code change here, this looks good to me. :)
Preview Diff
1 | === modified file 'app/components/CMakeLists.txt' | |||
2 | --- app/components/CMakeLists.txt 2015-02-08 04:06:28 +0000 | |||
3 | +++ app/components/CMakeLists.txt 2015-02-22 02:24:31 +0000 | |||
4 | @@ -1,3 +1,4 @@ | |||
5 | 1 | add_subdirectory(Delegates) | ||
6 | 1 | add_subdirectory(Dialog) | 2 | add_subdirectory(Dialog) |
7 | 2 | add_subdirectory(HeadState) | 3 | add_subdirectory(HeadState) |
8 | 3 | add_subdirectory(Flickables) | 4 | add_subdirectory(Flickables) |
9 | 4 | 5 | ||
10 | === added directory 'app/components/Delegates' | |||
11 | === added file 'app/components/Delegates/CMakeLists.txt' | |||
12 | --- app/components/Delegates/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
13 | +++ app/components/Delegates/CMakeLists.txt 2015-02-22 02:24:31 +0000 | |||
14 | @@ -0,0 +1,4 @@ | |||
15 | 1 | # make the qml files visible on qtcreator | ||
16 | 2 | file(GLOB DELEGATES_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | ||
17 | 3 | |||
18 | 4 | add_custom_target(com_ubuntu_music_DELEGATES_QMLFiles ALL SOURCES ${DELEGATES_QML_FILES}) | ||
19 | 0 | 5 | ||
20 | === renamed file 'app/components/Card.qml' => 'app/components/Delegates/Card.qml' | |||
21 | --- app/components/Card.qml 2014-11-11 18:08:40 +0000 | |||
22 | +++ app/components/Delegates/Card.qml 2015-02-22 02:24:31 +0000 | |||
23 | @@ -17,6 +17,7 @@ | |||
24 | 17 | 17 | ||
25 | 18 | import QtQuick 2.3 | 18 | import QtQuick 2.3 |
26 | 19 | import Ubuntu.Components 1.1 | 19 | import Ubuntu.Components 1.1 |
27 | 20 | import "../" | ||
28 | 20 | 21 | ||
29 | 21 | 22 | ||
30 | 22 | Item { | 23 | Item { |
31 | 23 | 24 | ||
32 | === renamed file 'app/components/ListItemWithActions.qml' => 'app/components/Delegates/ListItemWithActions.qml' | |||
33 | --- app/components/ListItemWithActions.qml 2015-01-18 00:06:06 +0000 | |||
34 | +++ app/components/Delegates/ListItemWithActions.qml 2015-02-22 02:24:31 +0000 | |||
35 | @@ -45,11 +45,8 @@ | |||
36 | 45 | readonly property alias swipping: mainItemMoving.running | 45 | readonly property alias swipping: mainItemMoving.running |
37 | 46 | readonly property bool _showActions: mouseArea.pressed || swipeState != "Normal" || swipping | 46 | readonly property bool _showActions: mouseArea.pressed || swipeState != "Normal" || swipping |
38 | 47 | 47 | ||
44 | 48 | property bool reorderable: false // CUSTOM | 48 | property alias _main: main // CUSTOM |
45 | 49 | property bool multiselectable: false // CUSTOM | 49 | property alias pressed: mouseArea.pressed // CUSTOM |
41 | 50 | |||
42 | 51 | property int previousListItemIndex: -1 // CUSTOM | ||
43 | 52 | property int listItemIndex: index // CUSTOM | ||
46 | 53 | 50 | ||
47 | 54 | /* internal */ | 51 | /* internal */ |
48 | 55 | property var _visibleRightSideActions: filterVisibleActions(rightSideActions) | 52 | property var _visibleRightSideActions: filterVisibleActions(rightSideActions) |
49 | @@ -57,55 +54,6 @@ | |||
50 | 57 | signal itemClicked(var mouse) | 54 | signal itemClicked(var mouse) |
51 | 58 | signal itemPressAndHold(var mouse) | 55 | signal itemPressAndHold(var mouse) |
52 | 59 | 56 | ||
53 | 60 | signal reorder(int from, int to) // CUSTOM | ||
54 | 61 | |||
55 | 62 | onItemPressAndHold: { | ||
56 | 63 | if (multiselectable) { | ||
57 | 64 | selectionMode = true | ||
58 | 65 | } | ||
59 | 66 | } | ||
60 | 67 | onListItemIndexChanged: { | ||
61 | 68 | var i = parent.parent.selectedItems.lastIndexOf(previousListItemIndex) | ||
62 | 69 | |||
63 | 70 | if (i !== -1) { | ||
64 | 71 | parent.parent.selectedItems[i] = listItemIndex | ||
65 | 72 | } | ||
66 | 73 | |||
67 | 74 | previousListItemIndex = listItemIndex | ||
68 | 75 | } | ||
69 | 76 | |||
70 | 77 | onSelectedChanged: { | ||
71 | 78 | if (selectionMode) { | ||
72 | 79 | var tmp = parent.parent.selectedItems | ||
73 | 80 | |||
74 | 81 | if (selected) { | ||
75 | 82 | if (parent.parent.selectedItems.indexOf(listItemIndex) === -1) { | ||
76 | 83 | tmp.push(listItemIndex) | ||
77 | 84 | parent.parent.selectedItems = tmp | ||
78 | 85 | } | ||
79 | 86 | } else { | ||
80 | 87 | tmp.splice(parent.parent.selectedItems.indexOf(listItemIndex), 1) | ||
81 | 88 | parent.parent.selectedItems = tmp | ||
82 | 89 | } | ||
83 | 90 | } | ||
84 | 91 | } | ||
85 | 92 | |||
86 | 93 | onSelectionModeChanged: { // CUSTOM | ||
87 | 94 | if (reorderable && selectionMode) { | ||
88 | 95 | resetSwipe() | ||
89 | 96 | } | ||
90 | 97 | |||
91 | 98 | for (var j=0; j < main.children.length; j++) { | ||
92 | 99 | main.children[j].anchors.rightMargin = reorderable && selectionMode ? actionReorderLoader.width + units.gu(2) : 0 | ||
93 | 100 | } | ||
94 | 101 | |||
95 | 102 | parent.parent.state = selectionMode ? "multiselectable" : "normal" | ||
96 | 103 | |||
97 | 104 | if (!selectionMode) { | ||
98 | 105 | selected = false | ||
99 | 106 | } | ||
100 | 107 | } | ||
101 | 108 | |||
102 | 109 | function returnToBoundsRTL(direction) | 57 | function returnToBoundsRTL(direction) |
103 | 110 | { | 58 | { |
104 | 111 | var actionFullWidth = actionWidth + units.gu(2) | 59 | var actionFullWidth = actionWidth + units.gu(2) |
105 | @@ -122,20 +70,11 @@ | |||
106 | 122 | var xOffset = Math.abs(main.x) | 70 | var xOffset = Math.abs(main.x) |
107 | 123 | var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length) | 71 | var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length) |
108 | 124 | var newX = 0 | 72 | var newX = 0 |
109 | 125 | var j // CUSTOM | ||
110 | 126 | 73 | ||
111 | 127 | if (index === _visibleRightSideActions.length) { | 74 | if (index === _visibleRightSideActions.length) { |
112 | 128 | newX = -(rightActionsView.width - units.gu(2)) | 75 | newX = -(rightActionsView.width - units.gu(2)) |
113 | 129 | |||
114 | 130 | for (j=0; j < rightSideActions.length; j++) { // CUSTOM | ||
115 | 131 | rightActionsRepeater.itemAt(j).primed = true | ||
116 | 132 | } | ||
117 | 133 | } else if (index >= 1) { | 76 | } else if (index >= 1) { |
118 | 134 | newX = -(actionFullWidth * index) | 77 | newX = -(actionFullWidth * index) |
119 | 135 | |||
120 | 136 | for (j=0; j < rightSideActions.length; j++) { // CUSTOM | ||
121 | 137 | rightActionsRepeater.itemAt(j).primed = j === index | ||
122 | 138 | } | ||
123 | 139 | } | 78 | } |
124 | 140 | 79 | ||
125 | 141 | updatePosition(newX) | 80 | updatePosition(newX) |
126 | @@ -147,10 +86,6 @@ | |||
127 | 147 | if ((direction === "RTL") || (main.x <= (finalX * root.threshold))) | 86 | if ((direction === "RTL") || (main.x <= (finalX * root.threshold))) |
128 | 148 | finalX = 0 | 87 | finalX = 0 |
129 | 149 | updatePosition(finalX) | 88 | updatePosition(finalX) |
130 | 150 | |||
131 | 151 | if (leftSideAction !== null) { // CUSTOM | ||
132 | 152 | leftActionViewLoader.item.primed = main.x > (finalX * root.threshold) | ||
133 | 153 | } | ||
134 | 154 | } | 89 | } |
135 | 155 | 90 | ||
136 | 156 | function returnToBounds(direction) | 91 | function returnToBounds(direction) |
137 | @@ -206,18 +141,6 @@ | |||
138 | 206 | } | 141 | } |
139 | 207 | } | 142 | } |
140 | 208 | 143 | ||
141 | 209 | function resetPrimed() // CUSTOM | ||
142 | 210 | { | ||
143 | 211 | if (leftSideAction !== null) { | ||
144 | 212 | leftActionViewLoader.item.primed = false | ||
145 | 213 | } | ||
146 | 214 | |||
147 | 215 | for (var j=0; j < rightSideActions.length; j++) { | ||
148 | 216 | console.debug(rightActionsRepeater.itemAt(j)); | ||
149 | 217 | rightActionsRepeater.itemAt(j).primed = false | ||
150 | 218 | } | ||
151 | 219 | } | ||
152 | 220 | |||
153 | 221 | function resetSwipe() | 144 | function resetSwipe() |
154 | 222 | { | 145 | { |
155 | 223 | updatePosition(0) | 146 | updatePosition(0) |
156 | @@ -243,39 +166,6 @@ | |||
157 | 243 | mouseArea.state = "" | 166 | mouseArea.state = "" |
158 | 244 | } | 167 | } |
159 | 245 | main.x = pos | 168 | main.x = pos |
160 | 246 | |||
161 | 247 | if (pos === 0) { // CUSTOM | ||
162 | 248 | //resetPrimed() | ||
163 | 249 | } | ||
164 | 250 | } | ||
165 | 251 | |||
166 | 252 | Connections { // CUSTOM | ||
167 | 253 | target: mainView | ||
168 | 254 | onListItemSwiping: { | ||
169 | 255 | if (i !== index) { | ||
170 | 256 | root.resetSwipe(); | ||
171 | 257 | } | ||
172 | 258 | } | ||
173 | 259 | } | ||
174 | 260 | |||
175 | 261 | Connections { // CUSTOM | ||
176 | 262 | target: root.parent.parent | ||
177 | 263 | onClearSelection: selected = false | ||
178 | 264 | onFlickingChanged: { | ||
179 | 265 | if (root.parent.parent.flicking) { | ||
180 | 266 | root.resetSwipe() | ||
181 | 267 | } | ||
182 | 268 | } | ||
183 | 269 | onSelectAll: selected = true | ||
184 | 270 | onStateChanged: selectionMode = root.parent.parent.state === "multiselectable" | ||
185 | 271 | } | ||
186 | 272 | |||
187 | 273 | Component.onCompleted: { // CUSTOM | ||
188 | 274 | if (parent.parent.selectedItems.indexOf(index) !== -1) { // FIXME: | ||
189 | 275 | selected = true | ||
190 | 276 | } | ||
191 | 277 | |||
192 | 278 | selectionMode = root.parent.parent.state === "multiselectable" | ||
193 | 279 | } | 169 | } |
194 | 280 | 170 | ||
195 | 281 | // CUSTOM remove animation | 171 | // CUSTOM remove animation |
196 | @@ -301,7 +191,7 @@ | |||
197 | 301 | when: selectionMode || selected | 191 | when: selectionMode || selected |
198 | 302 | PropertyChanges { | 192 | PropertyChanges { |
199 | 303 | target: selectionIcon | 193 | target: selectionIcon |
201 | 304 | source: Qt.resolvedUrl("ListItemActions/CheckBox.qml") | 194 | source: Qt.resolvedUrl("../ListItemActions/CheckBox.qml") |
202 | 305 | anchors.leftMargin: units.gu(2) | 195 | anchors.leftMargin: units.gu(2) |
203 | 306 | } | 196 | } |
204 | 307 | PropertyChanges { | 197 | PropertyChanges { |
205 | @@ -337,8 +227,6 @@ | |||
206 | 337 | width: root.leftActionWidth + actionThreshold | 227 | width: root.leftActionWidth + actionThreshold |
207 | 338 | color: UbuntuColors.red | 228 | color: UbuntuColors.red |
208 | 339 | 229 | ||
209 | 340 | property alias primed: leftActionIcon.primed // CUSTOM | ||
210 | 341 | |||
211 | 342 | Icon { | 230 | Icon { |
212 | 343 | id: leftActionIcon | 231 | id: leftActionIcon |
213 | 344 | anchors { | 232 | anchors { |
214 | @@ -350,8 +238,6 @@ | |||
215 | 350 | color: Theme.palette.selected.field | 238 | color: Theme.palette.selected.field |
216 | 351 | height: units.gu(3) | 239 | height: units.gu(3) |
217 | 352 | width: units.gu(3) | 240 | width: units.gu(3) |
218 | 353 | |||
219 | 354 | property bool primed: false // CUSTOM | ||
220 | 355 | } | 241 | } |
221 | 356 | } | 242 | } |
222 | 357 | } | 243 | } |
223 | @@ -400,8 +286,6 @@ | |||
224 | 400 | height: rightActionsView.height | 286 | height: rightActionsView.height |
225 | 401 | width: root.actionWidth | 287 | width: root.actionWidth |
226 | 402 | 288 | ||
227 | 403 | property alias primed: img.primed // CUSTOM | ||
228 | 404 | |||
229 | 405 | Icon { | 289 | Icon { |
230 | 406 | id: img | 290 | id: img |
231 | 407 | 291 | ||
232 | @@ -411,8 +295,6 @@ | |||
233 | 411 | height: units.gu(3) | 295 | height: units.gu(3) |
234 | 412 | name: modelData.iconName | 296 | name: modelData.iconName |
235 | 413 | color: root.activeAction === modelData ? UbuntuColors.blue : styleMusic.common.white // CUSTOM | 297 | color: root.activeAction === modelData ? UbuntuColors.blue : styleMusic.common.white // CUSTOM |
236 | 414 | |||
237 | 415 | property bool primed: false // CUSTOM | ||
238 | 416 | } | 298 | } |
239 | 417 | } | 299 | } |
240 | 418 | } | 300 | } |
241 | @@ -474,118 +356,6 @@ | |||
242 | 474 | } | 356 | } |
243 | 475 | } | 357 | } |
244 | 476 | 358 | ||
245 | 477 | /* CUSTOM Brighten Component */ | ||
246 | 478 | Rectangle { | ||
247 | 479 | id: listItemBrighten | ||
248 | 480 | anchors { | ||
249 | 481 | fill: main | ||
250 | 482 | } | ||
251 | 483 | |||
252 | 484 | color: mouseArea.pressed ? styleMusic.common.white : "transparent" | ||
253 | 485 | opacity: 0.1 | ||
254 | 486 | } | ||
255 | 487 | |||
256 | 488 | /* CUSTOM Reorder Component */ | ||
257 | 489 | Loader { | ||
258 | 490 | id: actionReorderLoader | ||
259 | 491 | anchors { | ||
260 | 492 | bottom: parent.bottom | ||
261 | 493 | right: main.right | ||
262 | 494 | rightMargin: units.gu(1) | ||
263 | 495 | top: parent.top | ||
264 | 496 | } | ||
265 | 497 | asynchronous: true | ||
266 | 498 | sourceComponent: reorderable && selectionMode && root.parent.parent.selectedItems.length === 0 ? actionReorderComponent : undefined | ||
267 | 499 | } | ||
268 | 500 | |||
269 | 501 | Component { | ||
270 | 502 | id: actionReorderComponent | ||
271 | 503 | Item { | ||
272 | 504 | id: actionReorder | ||
273 | 505 | width: units.gu(4) | ||
274 | 506 | visible: reorderable && selectionMode && root.parent.parent.selectedItems.length === 0 | ||
275 | 507 | |||
276 | 508 | Icon { | ||
277 | 509 | anchors { | ||
278 | 510 | horizontalCenter: parent.horizontalCenter | ||
279 | 511 | verticalCenter: parent.verticalCenter | ||
280 | 512 | } | ||
281 | 513 | name: "navigation-menu" // TODO: use proper image | ||
282 | 514 | height: width | ||
283 | 515 | width: units.gu(3) | ||
284 | 516 | } | ||
285 | 517 | |||
286 | 518 | MouseArea { | ||
287 | 519 | id: actionReorderMouseArea | ||
288 | 520 | anchors { | ||
289 | 521 | fill: parent | ||
290 | 522 | } | ||
291 | 523 | property int startY: 0 | ||
292 | 524 | property int startContentY: 0 | ||
293 | 525 | |||
294 | 526 | onPressed: { | ||
295 | 527 | root.parent.parent.interactive = false; // stop scrolling of listview | ||
296 | 528 | startY = root.y; | ||
297 | 529 | startContentY = root.parent.parent.contentY; | ||
298 | 530 | root.z += 10; // force ontop of other elements | ||
299 | 531 | |||
300 | 532 | console.debug("Reorder listitem pressed", root.y) | ||
301 | 533 | } | ||
302 | 534 | onMouseYChanged: root.y += mouse.y - (root.height / 2); | ||
303 | 535 | onReleased: { | ||
304 | 536 | console.debug("Reorder diff by position", getDiff()); | ||
305 | 537 | |||
306 | 538 | var diff = getDiff(); | ||
307 | 539 | |||
308 | 540 | // Remove the height of the actual item if moved down | ||
309 | 541 | if (diff > 0) { | ||
310 | 542 | diff -= 1; | ||
311 | 543 | } | ||
312 | 544 | |||
313 | 545 | root.parent.parent.interactive = true; // reenable scrolling | ||
314 | 546 | |||
315 | 547 | if (diff === 0) { | ||
316 | 548 | // Nothing has changed so reset the item | ||
317 | 549 | // z index is restored after animation | ||
318 | 550 | resetListItemYAnimation.start(); | ||
319 | 551 | } | ||
320 | 552 | else { | ||
321 | 553 | var newIndex = index + diff; | ||
322 | 554 | |||
323 | 555 | if (newIndex < 0) { | ||
324 | 556 | newIndex = 0; | ||
325 | 557 | } | ||
326 | 558 | else if (newIndex > root.parent.parent.count - 1) { | ||
327 | 559 | newIndex = root.parent.parent.count - 1; | ||
328 | 560 | } | ||
329 | 561 | |||
330 | 562 | root.z -= 10; // restore z index | ||
331 | 563 | reorder(index, newIndex) | ||
332 | 564 | } | ||
333 | 565 | } | ||
334 | 566 | |||
335 | 567 | function getDiff() { | ||
336 | 568 | // Get the amount of items that have been passed over (by centre) | ||
337 | 569 | return Math.round((((root.y - startY) + (root.parent.parent.contentY - startContentY)) / root.height) + 0.5); | ||
338 | 570 | } | ||
339 | 571 | } | ||
340 | 572 | |||
341 | 573 | SequentialAnimation { | ||
342 | 574 | id: resetListItemYAnimation | ||
343 | 575 | UbuntuNumberAnimation { | ||
344 | 576 | target: root; | ||
345 | 577 | property: "y"; | ||
346 | 578 | to: actionReorderMouseArea.startY | ||
347 | 579 | } | ||
348 | 580 | ScriptAction { | ||
349 | 581 | script: { | ||
350 | 582 | root.z -= 10; // restore z index | ||
351 | 583 | } | ||
352 | 584 | } | ||
353 | 585 | } | ||
354 | 586 | } | ||
355 | 587 | } | ||
356 | 588 | |||
357 | 589 | SequentialAnimation { | 359 | SequentialAnimation { |
358 | 590 | id: triggerAction | 360 | id: triggerAction |
359 | 591 | 361 | ||
360 | @@ -694,22 +464,22 @@ | |||
361 | 694 | direction = "None" | 464 | direction = "None" |
362 | 695 | } | 465 | } |
363 | 696 | onClicked: { | 466 | onClicked: { |
365 | 697 | if (selectionMode) { // CUSTOM | 467 | if (selectionMode) { // CUSTOM - selecting a listitem should toggle selection if in selectionMode |
366 | 698 | selected = !selected | 468 | selected = !selected |
367 | 699 | return | 469 | return |
370 | 700 | } | 470 | } else if (main.x === 0) { |
369 | 701 | else if (main.x === 0) { | ||
371 | 702 | root.itemClicked(mouse) | 471 | root.itemClicked(mouse) |
372 | 703 | } else if (main.x > 0) { | 472 | } else if (main.x > 0) { |
373 | 704 | var action = getActionAt(Qt.point(mouse.x, mouse.y)) | 473 | var action = getActionAt(Qt.point(mouse.x, mouse.y)) |
374 | 705 | if (action && action !== -1) { | 474 | if (action && action !== -1) { |
375 | 706 | //action.triggered(root) | 475 | //action.triggered(root) |
377 | 707 | removeAnimation.action = action // CUSTOM | 476 | removeAnimation.action = action // CUSTOM - use our animation instead |
378 | 708 | removeAnimation.start() // CUSTOM | 477 | removeAnimation.start() // CUSTOM |
379 | 709 | } | 478 | } |
380 | 710 | } else { | 479 | } else { |
381 | 711 | var actionIndex = getActionAt(Qt.point(mouse.x, mouse.y)) | 480 | var actionIndex = getActionAt(Qt.point(mouse.x, mouse.y)) |
383 | 712 | if (actionIndex !== -1) { | 481 | |
384 | 482 | if (actionIndex !== -1 && actionIndex !== leftSideAction) { // CUSTOM - can be leftAction | ||
385 | 713 | root.activeItem = rightActionsRepeater.itemAt(actionIndex) | 483 | root.activeItem = rightActionsRepeater.itemAt(actionIndex) |
386 | 714 | root.activeAction = root.rightSideActions[actionIndex] | 484 | root.activeAction = root.rightSideActions[actionIndex] |
387 | 715 | triggerAction.start() | 485 | triggerAction.start() |
388 | @@ -723,7 +493,7 @@ | |||
389 | 723 | if (mouseArea.pressed) { | 493 | if (mouseArea.pressed) { |
390 | 724 | updateActiveAction() | 494 | updateActiveAction() |
391 | 725 | 495 | ||
393 | 726 | listItemSwiping(index) // CUSTOM | 496 | listItemSwiping(index) // CUSTOM - tells other listitems to dismiss any swipe |
394 | 727 | } | 497 | } |
395 | 728 | } | 498 | } |
396 | 729 | onPressAndHold: { | 499 | onPressAndHold: { |
397 | 730 | 500 | ||
398 | === added file 'app/components/Delegates/MusicListItem.qml' | |||
399 | --- app/components/Delegates/MusicListItem.qml 1970-01-01 00:00:00 +0000 | |||
400 | +++ app/components/Delegates/MusicListItem.qml 2015-02-22 02:24:31 +0000 | |||
401 | @@ -0,0 +1,151 @@ | |||
402 | 1 | /* | ||
403 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
404 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
405 | 4 | * Nekhelesh Ramananthan <krnekhelesh@gmail.com> | ||
406 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
407 | 6 | * | ||
408 | 7 | * This program is free software; you can redistribute it and/or modify | ||
409 | 8 | * it under the terms of the GNU General Public License as published by | ||
410 | 9 | * the Free Software Foundation; version 3. | ||
411 | 10 | * | ||
412 | 11 | * This program is distributed in the hope that it will be useful, | ||
413 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
414 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
415 | 14 | * GNU General Public License for more details. | ||
416 | 15 | * | ||
417 | 16 | * You should have received a copy of the GNU General Public License | ||
418 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
419 | 18 | */ | ||
420 | 19 | |||
421 | 20 | import QtQuick 2.3 | ||
422 | 21 | import Ubuntu.Components 1.1 | ||
423 | 22 | import "../" | ||
424 | 23 | |||
425 | 24 | |||
426 | 25 | ListItemWithActions { | ||
427 | 26 | id: root | ||
428 | 27 | |||
429 | 28 | property alias column: musicRow.column | ||
430 | 29 | property alias imageSource: musicRow.imageSource | ||
431 | 30 | |||
432 | 31 | property int listItemIndex: index | ||
433 | 32 | property bool multiselectable: false | ||
434 | 33 | property int previousListItemIndex: -1 | ||
435 | 34 | property bool reorderable: false | ||
436 | 35 | |||
437 | 36 | signal reorder(int from, int to) | ||
438 | 37 | |||
439 | 38 | onItemPressAndHold: { | ||
440 | 39 | if (multiselectable) { | ||
441 | 40 | selectionMode = true | ||
442 | 41 | } | ||
443 | 42 | } | ||
444 | 43 | |||
445 | 44 | onListItemIndexChanged: { | ||
446 | 45 | var i = parent.parent.selectedItems.lastIndexOf(previousListItemIndex) | ||
447 | 46 | |||
448 | 47 | if (i !== -1) { | ||
449 | 48 | parent.parent.selectedItems[i] = listItemIndex | ||
450 | 49 | } | ||
451 | 50 | |||
452 | 51 | previousListItemIndex = listItemIndex | ||
453 | 52 | } | ||
454 | 53 | |||
455 | 54 | onSelectedChanged: { | ||
456 | 55 | if (selectionMode) { | ||
457 | 56 | var tmp = parent.parent.selectedItems | ||
458 | 57 | |||
459 | 58 | if (selected) { | ||
460 | 59 | if (parent.parent.selectedItems.indexOf(listItemIndex) === -1) { | ||
461 | 60 | tmp.push(listItemIndex) | ||
462 | 61 | parent.parent.selectedItems = tmp | ||
463 | 62 | } | ||
464 | 63 | } else { | ||
465 | 64 | tmp.splice(parent.parent.selectedItems.indexOf(listItemIndex), 1) | ||
466 | 65 | parent.parent.selectedItems = tmp | ||
467 | 66 | } | ||
468 | 67 | } | ||
469 | 68 | } | ||
470 | 69 | |||
471 | 70 | onSelectionModeChanged: { | ||
472 | 71 | if (reorderable && selectionMode) { | ||
473 | 72 | resetSwipe() | ||
474 | 73 | } | ||
475 | 74 | |||
476 | 75 | for (var j=0; j < _main.children.length; j++) { | ||
477 | 76 | if (_main.children[j] !== actionReorderLoader) { | ||
478 | 77 | _main.children[j].anchors.rightMargin = reorderable && selectionMode ? actionReorderLoader.width + units.gu(2) : 0 | ||
479 | 78 | } | ||
480 | 79 | } | ||
481 | 80 | |||
482 | 81 | parent.parent.state = selectionMode ? "multiselectable" : "normal" | ||
483 | 82 | |||
484 | 83 | if (!selectionMode) { | ||
485 | 84 | selected = false | ||
486 | 85 | } | ||
487 | 86 | } | ||
488 | 87 | |||
489 | 88 | /* Highlight the listitem on press */ | ||
490 | 89 | Rectangle { | ||
491 | 90 | id: listItemBrighten | ||
492 | 91 | color: root.pressed ? styleMusic.common.white : "transparent" | ||
493 | 92 | opacity: 0.1 | ||
494 | 93 | height: root.height | ||
495 | 94 | x: root.x - parent.x // -parent.x due to selectionIcon in ListItemWithActions | ||
496 | 95 | width: root.width | ||
497 | 96 | } | ||
498 | 97 | |||
499 | 98 | /* Reorder Component */ | ||
500 | 99 | Loader { | ||
501 | 100 | id: actionReorderLoader | ||
502 | 101 | active: reorderable && selectionMode && root.parent.parent.selectedItems.length === 0 | ||
503 | 102 | anchors { | ||
504 | 103 | bottom: parent.bottom | ||
505 | 104 | right: parent.right | ||
506 | 105 | rightMargin: units.gu(1) | ||
507 | 106 | top: parent.top | ||
508 | 107 | } | ||
509 | 108 | asynchronous: true | ||
510 | 109 | source: "../ListItemReorderComponent.qml" | ||
511 | 110 | } | ||
512 | 111 | |||
513 | 112 | Item { | ||
514 | 113 | Connections { // Only allow one ListItem to be swiping at any time | ||
515 | 114 | target: mainView | ||
516 | 115 | onListItemSwiping: { | ||
517 | 116 | if (i !== index) { | ||
518 | 117 | root.resetSwipe(); | ||
519 | 118 | } | ||
520 | 119 | } | ||
521 | 120 | } | ||
522 | 121 | |||
523 | 122 | Connections { // Connections from signals in the ListView | ||
524 | 123 | target: root.parent.parent | ||
525 | 124 | onClearSelection: selected = false | ||
526 | 125 | onFlickingChanged: { | ||
527 | 126 | if (root.parent.parent.flicking) { | ||
528 | 127 | root.resetSwipe() | ||
529 | 128 | } | ||
530 | 129 | } | ||
531 | 130 | onSelectAll: selected = true | ||
532 | 131 | onStateChanged: selectionMode = root.parent.parent.state === "multiselectable" | ||
533 | 132 | } | ||
534 | 133 | } | ||
535 | 134 | |||
536 | 135 | |||
537 | 136 | MusicRow { | ||
538 | 137 | id: musicRow | ||
539 | 138 | anchors { | ||
540 | 139 | verticalCenter: parent.verticalCenter | ||
541 | 140 | } | ||
542 | 141 | height: parent.height | ||
543 | 142 | } | ||
544 | 143 | |||
545 | 144 | Component.onCompleted: { // reload settings as delegates are destroyed | ||
546 | 145 | if (parent.parent.selectedItems.indexOf(index) !== -1) { | ||
547 | 146 | selected = true | ||
548 | 147 | } | ||
549 | 148 | |||
550 | 149 | selectionMode = root.parent.parent.state === "multiselectable" | ||
551 | 150 | } | ||
552 | 151 | } | ||
553 | 0 | 152 | ||
554 | === modified file 'app/components/ListItemActions/AddToPlaylist.qml' | |||
555 | --- app/components/ListItemActions/AddToPlaylist.qml 2015-02-04 19:01:14 +0000 | |||
556 | +++ app/components/ListItemActions/AddToPlaylist.qml 2015-02-22 02:24:31 +0000 | |||
557 | @@ -25,8 +25,6 @@ | |||
558 | 25 | objectName: "addToPlaylistAction" | 25 | objectName: "addToPlaylistAction" |
559 | 26 | text: i18n.tr("Add to playlist") | 26 | text: i18n.tr("Add to playlist") |
560 | 27 | 27 | ||
561 | 28 | property bool primed: false | ||
562 | 29 | |||
563 | 30 | onTriggered: { | 28 | onTriggered: { |
564 | 31 | console.debug("Debug: Add track to playlist"); | 29 | console.debug("Debug: Add track to playlist"); |
565 | 32 | 30 | ||
566 | 33 | 31 | ||
567 | === modified file 'app/components/ListItemActions/Remove.qml' | |||
568 | --- app/components/ListItemActions/Remove.qml 2014-09-20 10:50:45 +0000 | |||
569 | +++ app/components/ListItemActions/Remove.qml 2015-02-22 02:24:31 +0000 | |||
570 | @@ -25,6 +25,4 @@ | |||
571 | 25 | iconName: "delete" | 25 | iconName: "delete" |
572 | 26 | objectName: "swipeDeleteAction" | 26 | objectName: "swipeDeleteAction" |
573 | 27 | text: i18n.tr("Remove") | 27 | text: i18n.tr("Remove") |
574 | 28 | |||
575 | 29 | property bool primed: false | ||
576 | 30 | } | 28 | } |
577 | 31 | 29 | ||
578 | === added file 'app/components/ListItemReorderComponent.qml' | |||
579 | --- app/components/ListItemReorderComponent.qml 1970-01-01 00:00:00 +0000 | |||
580 | +++ app/components/ListItemReorderComponent.qml 2015-02-22 02:24:31 +0000 | |||
581 | @@ -0,0 +1,106 @@ | |||
582 | 1 | /* | ||
583 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
584 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
585 | 4 | * Nekhelesh Ramananthan <krnekhelesh@gmail.com> | ||
586 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
587 | 6 | * | ||
588 | 7 | * This program is free software; you can redistribute it and/or modify | ||
589 | 8 | * it under the terms of the GNU General Public License as published by | ||
590 | 9 | * the Free Software Foundation; version 3. | ||
591 | 10 | * | ||
592 | 11 | * This program is distributed in the hope that it will be useful, | ||
593 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
594 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
595 | 14 | * GNU General Public License for more details. | ||
596 | 15 | * | ||
597 | 16 | * You should have received a copy of the GNU General Public License | ||
598 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
599 | 18 | */ | ||
600 | 19 | |||
601 | 20 | import QtQuick 2.3 | ||
602 | 21 | import Ubuntu.Components 1.1 | ||
603 | 22 | |||
604 | 23 | |||
605 | 24 | Item { | ||
606 | 25 | id: actionReorder | ||
607 | 26 | width: units.gu(4) | ||
608 | 27 | |||
609 | 28 | Icon { | ||
610 | 29 | anchors { | ||
611 | 30 | horizontalCenter: parent.horizontalCenter | ||
612 | 31 | verticalCenter: parent.verticalCenter | ||
613 | 32 | } | ||
614 | 33 | name: "navigation-menu" // TODO: use proper image | ||
615 | 34 | height: width | ||
616 | 35 | width: units.gu(3) | ||
617 | 36 | } | ||
618 | 37 | |||
619 | 38 | MouseArea { | ||
620 | 39 | id: actionReorderMouseArea | ||
621 | 40 | anchors { | ||
622 | 41 | fill: parent | ||
623 | 42 | } | ||
624 | 43 | property int startY: 0 | ||
625 | 44 | property int startContentY: 0 | ||
626 | 45 | |||
627 | 46 | onPressed: { | ||
628 | 47 | root.parent.parent.interactive = false; // stop scrolling of listview | ||
629 | 48 | startY = root.y; | ||
630 | 49 | startContentY = root.parent.parent.contentY; | ||
631 | 50 | root.z += 10; // force ontop of other elements | ||
632 | 51 | |||
633 | 52 | console.debug("Reorder listitem pressed", root.y) | ||
634 | 53 | } | ||
635 | 54 | onMouseYChanged: root.y += mouse.y - (root.height / 2); | ||
636 | 55 | onReleased: { | ||
637 | 56 | console.debug("Reorder diff by position", getDiff()); | ||
638 | 57 | |||
639 | 58 | var diff = getDiff(); | ||
640 | 59 | |||
641 | 60 | // Remove the height of the actual item if moved down | ||
642 | 61 | if (diff > 0) { | ||
643 | 62 | diff -= 1; | ||
644 | 63 | } | ||
645 | 64 | |||
646 | 65 | root.parent.parent.interactive = true; // reenable scrolling | ||
647 | 66 | |||
648 | 67 | if (diff === 0) { | ||
649 | 68 | // Nothing has changed so reset the item | ||
650 | 69 | // z index is restored after animation | ||
651 | 70 | resetListItemYAnimation.start(); | ||
652 | 71 | } | ||
653 | 72 | else { | ||
654 | 73 | var newIndex = index + diff; | ||
655 | 74 | |||
656 | 75 | if (newIndex < 0) { | ||
657 | 76 | newIndex = 0; | ||
658 | 77 | } | ||
659 | 78 | else if (newIndex > root.parent.parent.count - 1) { | ||
660 | 79 | newIndex = root.parent.parent.count - 1; | ||
661 | 80 | } | ||
662 | 81 | |||
663 | 82 | root.z -= 10; // restore z index | ||
664 | 83 | reorder(index, newIndex) | ||
665 | 84 | } | ||
666 | 85 | } | ||
667 | 86 | |||
668 | 87 | function getDiff() { | ||
669 | 88 | // Get the amount of items that have been passed over (by centre) | ||
670 | 89 | return Math.round((((root.y - startY) + (root.parent.parent.contentY - startContentY)) / root.height) + 0.5); | ||
671 | 90 | } | ||
672 | 91 | } | ||
673 | 92 | |||
674 | 93 | SequentialAnimation { | ||
675 | 94 | id: resetListItemYAnimation | ||
676 | 95 | UbuntuNumberAnimation { | ||
677 | 96 | target: root; | ||
678 | 97 | property: "y"; | ||
679 | 98 | to: actionReorderMouseArea.startY | ||
680 | 99 | } | ||
681 | 100 | ScriptAction { | ||
682 | 101 | script: { | ||
683 | 102 | root.z -= 10; // restore z index | ||
684 | 103 | } | ||
685 | 104 | } | ||
686 | 105 | } | ||
687 | 106 | } | ||
688 | 0 | 107 | ||
689 | === modified file 'app/ui/AddToPlaylist.qml' | |||
690 | --- app/ui/AddToPlaylist.qml 2015-02-08 04:06:28 +0000 | |||
691 | +++ app/ui/AddToPlaylist.qml 2015-02-22 02:24:31 +0000 | |||
692 | @@ -26,6 +26,7 @@ | |||
693 | 26 | import "../logic/meta-database.js" as Library | 26 | import "../logic/meta-database.js" as Library |
694 | 27 | import "../logic/playlists.js" as Playlists | 27 | import "../logic/playlists.js" as Playlists |
695 | 28 | import "../components" | 28 | import "../components" |
696 | 29 | import "../components/Delegates" | ||
697 | 29 | import "../components/Flickables" | 30 | import "../components/Flickables" |
698 | 30 | import "../components/HeadState" | 31 | import "../components/HeadState" |
699 | 31 | 32 | ||
700 | 32 | 33 | ||
701 | === modified file 'app/ui/Albums.qml' | |||
702 | --- app/ui/Albums.qml 2015-02-08 04:06:28 +0000 | |||
703 | +++ app/ui/Albums.qml 2015-02-22 02:24:31 +0000 | |||
704 | @@ -21,6 +21,7 @@ | |||
705 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
706 | 22 | import Ubuntu.MediaScanner 0.1 | 22 | import Ubuntu.MediaScanner 0.1 |
707 | 23 | import "../components" | 23 | import "../components" |
708 | 24 | import "../components/Delegates" | ||
709 | 24 | import "../components/Flickables" | 25 | import "../components/Flickables" |
710 | 25 | import "../components/HeadState" | 26 | import "../components/HeadState" |
711 | 26 | 27 | ||
712 | 27 | 28 | ||
713 | === modified file 'app/ui/ArtistView.qml' | |||
714 | --- app/ui/ArtistView.qml 2015-02-08 04:06:28 +0000 | |||
715 | +++ app/ui/ArtistView.qml 2015-02-22 02:24:31 +0000 | |||
716 | @@ -26,6 +26,7 @@ | |||
717 | 26 | import QtQuick.LocalStorage 2.0 | 26 | import QtQuick.LocalStorage 2.0 |
718 | 27 | import "../logic/meta-database.js" as Library | 27 | import "../logic/meta-database.js" as Library |
719 | 28 | import "../components" | 28 | import "../components" |
720 | 29 | import "../components/Delegates" | ||
721 | 29 | import "../components/Flickables" | 30 | import "../components/Flickables" |
722 | 30 | import "../components/ViewButton" | 31 | import "../components/ViewButton" |
723 | 31 | 32 | ||
724 | 32 | 33 | ||
725 | === modified file 'app/ui/Artists.qml' | |||
726 | --- app/ui/Artists.qml 2015-02-08 04:06:28 +0000 | |||
727 | +++ app/ui/Artists.qml 2015-02-22 02:24:31 +0000 | |||
728 | @@ -27,6 +27,7 @@ | |||
729 | 27 | import "../logic/meta-database.js" as Library | 27 | import "../logic/meta-database.js" as Library |
730 | 28 | import "../logic/playlists.js" as Playlists | 28 | import "../logic/playlists.js" as Playlists |
731 | 29 | import "../components" | 29 | import "../components" |
732 | 30 | import "../components/Delegates" | ||
733 | 30 | import "../components/Flickables" | 31 | import "../components/Flickables" |
734 | 31 | import "../components/HeadState" | 32 | import "../components/HeadState" |
735 | 32 | 33 | ||
736 | 33 | 34 | ||
737 | === modified file 'app/ui/Genres.qml' | |||
738 | --- app/ui/Genres.qml 2015-02-08 04:06:28 +0000 | |||
739 | +++ app/ui/Genres.qml 2015-02-22 02:24:31 +0000 | |||
740 | @@ -21,6 +21,7 @@ | |||
741 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
742 | 22 | import Ubuntu.MediaScanner 0.1 | 22 | import Ubuntu.MediaScanner 0.1 |
743 | 23 | import "../components" | 23 | import "../components" |
744 | 24 | import "../components/Delegates" | ||
745 | 24 | import "../components/Flickables" | 25 | import "../components/Flickables" |
746 | 25 | import "../components/HeadState" | 26 | import "../components/HeadState" |
747 | 26 | 27 | ||
748 | 27 | 28 | ||
749 | === modified file 'app/ui/NowPlaying.qml' | |||
750 | --- app/ui/NowPlaying.qml 2015-02-08 04:06:28 +0000 | |||
751 | +++ app/ui/NowPlaying.qml 2015-02-22 02:24:31 +0000 | |||
752 | @@ -23,6 +23,7 @@ | |||
753 | 23 | import Ubuntu.Components 1.1 | 23 | import Ubuntu.Components 1.1 |
754 | 24 | import Ubuntu.Thumbnailer 0.1 | 24 | import Ubuntu.Thumbnailer 0.1 |
755 | 25 | import "../components" | 25 | import "../components" |
756 | 26 | import "../components/Delegates" | ||
757 | 26 | import "../components/Flickables" | 27 | import "../components/Flickables" |
758 | 27 | import "../components/HeadState" | 28 | import "../components/HeadState" |
759 | 28 | import "../components/ListItemActions" | 29 | import "../components/ListItemActions" |
760 | @@ -378,7 +379,6 @@ | |||
761 | 378 | fill: parent | 379 | fill: parent |
762 | 379 | topMargin: units.gu(2) | 380 | topMargin: units.gu(2) |
763 | 380 | } | 381 | } |
764 | 381 | delegate: queueDelegate | ||
765 | 382 | footer: Item { | 382 | footer: Item { |
766 | 383 | height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) | 383 | height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) |
767 | 384 | } | 384 | } |
768 | @@ -390,95 +390,62 @@ | |||
769 | 390 | 390 | ||
770 | 391 | onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks") | 391 | onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks") |
771 | 392 | 392 | ||
861 | 393 | Component { | 393 | delegate: MusicListItem { |
862 | 394 | id: queueDelegate | 394 | id: queueListItem |
863 | 395 | ListItemWithActions { | 395 | color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor |
864 | 396 | id: queueListItem | 396 | column: Column { |
865 | 397 | color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor | 397 | Label { |
866 | 398 | height: queueList.normalHeight | 398 | id: trackTitle |
867 | 399 | objectName: "nowPlayingListItem" + index | 399 | color: player.currentIndex === index ? UbuntuColors.blue : styleMusic.common.music |
868 | 400 | state: "" | 400 | fontSize: "small" |
869 | 401 | 401 | objectName: "titleLabel" | |
870 | 402 | leftSideAction: Remove { | 402 | text: model.title |
871 | 403 | onTriggered: trackQueue.removeQueueList([index]) | 403 | } |
872 | 404 | } | 404 | |
873 | 405 | multiselectable: true | 405 | Label { |
874 | 406 | reorderable: true | 406 | id: trackArtist |
875 | 407 | rightSideActions: [ | 407 | color: styleMusic.common.subtitle |
876 | 408 | AddToPlaylist{ | 408 | fontSize: "x-small" |
877 | 409 | 409 | objectName: "artistLabel" | |
878 | 410 | } | 410 | text: model.author |
879 | 411 | ] | 411 | } |
880 | 412 | 412 | } | |
881 | 413 | onItemClicked: { | 413 | height: queueList.normalHeight |
882 | 414 | customdebug("File: " + model.filename) // debugger | 414 | objectName: "nowPlayingListItem" + index |
883 | 415 | trackQueueClick(index); // toggle track state | 415 | state: "" |
884 | 416 | } | 416 | leftSideAction: Remove { |
885 | 417 | onReorder: { | 417 | onTriggered: trackQueue.removeQueueList([index]) |
886 | 418 | console.debug("Move: ", from, to); | 418 | } |
887 | 419 | 419 | multiselectable: true | |
888 | 420 | trackQueue.model.move(from, to, 1); | 420 | reorderable: true |
889 | 421 | Library.moveQueueItem(from, to); | 421 | rightSideActions: [ |
890 | 422 | 422 | AddToPlaylist{ | |
891 | 423 | // Maintain currentIndex with current song | 423 | |
892 | 424 | if (from === player.currentIndex) { | 424 | } |
893 | 425 | player.currentIndex = to; | 425 | ] |
894 | 426 | } | 426 | |
895 | 427 | else if (from < player.currentIndex && to >= player.currentIndex) { | 427 | onItemClicked: { |
896 | 428 | player.currentIndex -= 1; | 428 | customdebug("File: " + model.filename) // debugger |
897 | 429 | } | 429 | trackQueueClick(index); // toggle track state |
898 | 430 | else if (from > player.currentIndex && to <= player.currentIndex) { | 430 | } |
899 | 431 | player.currentIndex += 1; | 431 | onReorder: { |
900 | 432 | } | 432 | console.debug("Move: ", from, to); |
901 | 433 | 433 | ||
902 | 434 | queueIndex = player.currentIndex | 434 | trackQueue.model.move(from, to, 1); |
903 | 435 | } | 435 | Library.moveQueueItem(from, to); |
904 | 436 | 436 | ||
905 | 437 | Item { | 437 | // Maintain currentIndex with current song |
906 | 438 | id: trackContainer; | 438 | if (from === player.currentIndex) { |
907 | 439 | anchors { | 439 | player.currentIndex = to; |
908 | 440 | fill: parent | 440 | } |
909 | 441 | } | 441 | else if (from < player.currentIndex && to >= player.currentIndex) { |
910 | 442 | 442 | player.currentIndex -= 1; | |
911 | 443 | NumberAnimation { | 443 | } |
912 | 444 | id: trackContainerReorderAnimation | 444 | else if (from > player.currentIndex && to <= player.currentIndex) { |
913 | 445 | target: trackContainer; | 445 | player.currentIndex += 1; |
914 | 446 | property: "anchors.leftMargin"; | 446 | } |
915 | 447 | duration: queueList.transitionDuration; | 447 | |
916 | 448 | to: units.gu(2) | 448 | queueIndex = player.currentIndex |
828 | 449 | } | ||
829 | 450 | |||
830 | 451 | NumberAnimation { | ||
831 | 452 | id: trackContainerResetAnimation | ||
832 | 453 | target: trackContainer; | ||
833 | 454 | property: "anchors.leftMargin"; | ||
834 | 455 | duration: queueList.transitionDuration; | ||
835 | 456 | to: units.gu(0.5) | ||
836 | 457 | } | ||
837 | 458 | |||
838 | 459 | MusicRow { | ||
839 | 460 | id: musicRow | ||
840 | 461 | height: parent.height | ||
841 | 462 | column: Column { | ||
842 | 463 | Label { | ||
843 | 464 | id: trackTitle | ||
844 | 465 | color: player.currentIndex === index ? UbuntuColors.blue | ||
845 | 466 | : styleMusic.common.music | ||
846 | 467 | fontSize: "small" | ||
847 | 468 | objectName: "titleLabel" | ||
848 | 469 | text: model.title | ||
849 | 470 | } | ||
850 | 471 | |||
851 | 472 | Label { | ||
852 | 473 | id: trackArtist | ||
853 | 474 | color: styleMusic.common.subtitle | ||
854 | 475 | fontSize: "x-small" | ||
855 | 476 | objectName: "artistLabel" | ||
856 | 477 | text: model.author | ||
857 | 478 | } | ||
858 | 479 | } | ||
859 | 480 | } | ||
860 | 481 | } | ||
917 | 482 | } | 449 | } |
918 | 483 | } | 450 | } |
919 | 484 | } | 451 | } |
920 | 485 | 452 | ||
921 | === modified file 'app/ui/Playlists.qml' | |||
922 | --- app/ui/Playlists.qml 2015-02-08 04:06:28 +0000 | |||
923 | +++ app/ui/Playlists.qml 2015-02-22 02:24:31 +0000 | |||
924 | @@ -25,6 +25,7 @@ | |||
925 | 25 | import QtQuick.LocalStorage 2.0 | 25 | import QtQuick.LocalStorage 2.0 |
926 | 26 | import "../logic/playlists.js" as Playlists | 26 | import "../logic/playlists.js" as Playlists |
927 | 27 | import "../components" | 27 | import "../components" |
928 | 28 | import "../components/Delegates" | ||
929 | 28 | import "../components/Flickables" | 29 | import "../components/Flickables" |
930 | 29 | import "../components/HeadState" | 30 | import "../components/HeadState" |
931 | 30 | 31 | ||
932 | 31 | 32 | ||
933 | === modified file 'app/ui/Recent.qml' | |||
934 | --- app/ui/Recent.qml 2015-02-08 04:06:28 +0000 | |||
935 | +++ app/ui/Recent.qml 2015-02-22 02:24:31 +0000 | |||
936 | @@ -28,6 +28,7 @@ | |||
937 | 28 | import "../logic/meta-database.js" as Library | 28 | import "../logic/meta-database.js" as Library |
938 | 29 | import "../logic/playlists.js" as Playlists | 29 | import "../logic/playlists.js" as Playlists |
939 | 30 | import "../components" | 30 | import "../components" |
940 | 31 | import "../components/Delegates" | ||
941 | 31 | import "../components/Flickables" | 32 | import "../components/Flickables" |
942 | 32 | 33 | ||
943 | 33 | MusicPage { | 34 | MusicPage { |
944 | 34 | 35 | ||
945 | === modified file 'app/ui/Songs.qml' | |||
946 | --- app/ui/Songs.qml 2015-02-08 04:06:28 +0000 | |||
947 | +++ app/ui/Songs.qml 2015-02-22 02:24:31 +0000 | |||
948 | @@ -25,6 +25,7 @@ | |||
949 | 25 | import QtQuick.LocalStorage 2.0 | 25 | import QtQuick.LocalStorage 2.0 |
950 | 26 | import "../logic/playlists.js" as Playlists | 26 | import "../logic/playlists.js" as Playlists |
951 | 27 | import "../components" | 27 | import "../components" |
952 | 28 | import "../components/Delegates" | ||
953 | 28 | import "../components/Flickables" | 29 | import "../components/Flickables" |
954 | 29 | import "../components/HeadState" | 30 | import "../components/HeadState" |
955 | 30 | import "../components/ListItemActions" | 31 | import "../components/ListItemActions" |
956 | @@ -90,61 +91,43 @@ | |||
957 | 90 | } | 91 | } |
958 | 91 | } | 92 | } |
959 | 92 | 93 | ||
1015 | 93 | delegate: trackDelegate | 94 | delegate: MusicListItem { |
1016 | 94 | Component { | 95 | id: track |
1017 | 95 | id: trackDelegate | 96 | objectName: "tracksPageListItem" + index |
1018 | 96 | 97 | column: Column { | |
1019 | 97 | ListItemWithActions { | 98 | Label { |
1020 | 98 | id: track | 99 | id: trackTitle |
1021 | 99 | objectName: "tracksPageListItem" + index | 100 | color: styleMusic.common.music |
1022 | 100 | height: units.gu(7) | 101 | fontSize: "small" |
1023 | 101 | 102 | objectName: "tracktitle" | |
1024 | 102 | multiselectable: true | 103 | text: model.title |
1025 | 103 | rightSideActions: [ | 104 | } |
1026 | 104 | AddToQueue { | 105 | |
1027 | 105 | }, | 106 | Label { |
1028 | 106 | AddToPlaylist { | 107 | id: trackArtist |
1029 | 107 | 108 | color: styleMusic.common.subtitle | |
1030 | 108 | } | 109 | fontSize: "x-small" |
1031 | 109 | ] | 110 | text: model.author |
1032 | 110 | 111 | } | |
1033 | 111 | onItemClicked: { | 112 | } |
1034 | 112 | if (songsPage.state === "search") { // only play single track when searching | 113 | height: units.gu(7) |
1035 | 113 | trackQueue.clear() | 114 | imageSource: {"art": model.art} |
1036 | 114 | trackQueue.append(songsModelFilter.get(index)) | 115 | multiselectable: true |
1037 | 115 | trackQueueClick(0) | 116 | rightSideActions: [ |
1038 | 116 | } else { | 117 | AddToQueue { |
1039 | 117 | trackClicked(songsModelFilter, index) // play track | 118 | }, |
1040 | 118 | } | 119 | AddToPlaylist { |
1041 | 119 | } | 120 | |
1042 | 120 | 121 | } | |
1043 | 121 | MusicRow { | 122 | ] |
1044 | 122 | id: musicRow | 123 | |
1045 | 123 | anchors { | 124 | onItemClicked: { |
1046 | 124 | verticalCenter: parent.verticalCenter | 125 | if (songsPage.state === "search") { // only play single track when searching |
1047 | 125 | } | 126 | trackQueue.clear() |
1048 | 126 | imageSource: {"art": model.art} | 127 | trackQueue.append(songsModelFilter.get(index)) |
1049 | 127 | column: Column { | 128 | trackQueueClick(0) |
1050 | 128 | Label { | 129 | } else { |
1051 | 129 | id: trackTitle | 130 | trackClicked(songsModelFilter, index) // play track |
997 | 130 | color: styleMusic.common.music | ||
998 | 131 | fontSize: "small" | ||
999 | 132 | objectName: "tracktitle" | ||
1000 | 133 | text: model.title | ||
1001 | 134 | } | ||
1002 | 135 | |||
1003 | 136 | Label { | ||
1004 | 137 | id: trackArtist | ||
1005 | 138 | color: styleMusic.common.subtitle | ||
1006 | 139 | fontSize: "x-small" | ||
1007 | 140 | text: model.author | ||
1008 | 141 | } | ||
1009 | 142 | } | ||
1010 | 143 | } | ||
1011 | 144 | |||
1012 | 145 | states: State { | ||
1013 | 146 | name: "Current" | ||
1014 | 147 | when: track.ListView.isCurrentItem | ||
1052 | 148 | } | 131 | } |
1053 | 149 | } | 132 | } |
1054 | 150 | } | 133 | } |
1055 | 151 | 134 | ||
1056 | === modified file 'app/ui/SongsView.qml' | |||
1057 | --- app/ui/SongsView.qml 2015-02-08 04:06:28 +0000 | |||
1058 | +++ app/ui/SongsView.qml 2015-02-22 02:24:31 +0000 | |||
1059 | @@ -27,6 +27,7 @@ | |||
1060 | 27 | import "../logic/meta-database.js" as Library | 27 | import "../logic/meta-database.js" as Library |
1061 | 28 | import "../logic/playlists.js" as Playlists | 28 | import "../logic/playlists.js" as Playlists |
1062 | 29 | import "../components" | 29 | import "../components" |
1063 | 30 | import "../components/Delegates" | ||
1064 | 30 | import "../components/Flickables" | 31 | import "../components/Flickables" |
1065 | 31 | import "../components/HeadState" | 32 | import "../components/HeadState" |
1066 | 32 | import "../components/ListItemActions" | 33 | import "../components/ListItemActions" |
1067 | @@ -186,11 +187,9 @@ | |||
1068 | 186 | anchors { | 187 | anchors { |
1069 | 187 | fill: parent | 188 | fill: parent |
1070 | 188 | } | 189 | } |
1071 | 189 | delegate: albumTracksDelegate | ||
1072 | 190 | model: isAlbum ? songsModel : albumTracksModel.model | 190 | model: isAlbum ? songsModel : albumTracksModel.model |
1073 | 191 | objectName: "songspage-listview" | 191 | objectName: "songspage-listview" |
1074 | 192 | width: parent.width | 192 | width: parent.width |
1075 | 193 | |||
1076 | 194 | header: BlurredHeader { | 193 | header: BlurredHeader { |
1077 | 195 | rightColumn: Column { | 194 | rightColumn: Column { |
1078 | 196 | spacing: units.gu(2) | 195 | spacing: units.gu(2) |
1079 | @@ -290,92 +289,82 @@ | |||
1080 | 290 | } | 289 | } |
1081 | 291 | } | 290 | } |
1082 | 292 | } | 291 | } |
1169 | 293 | 292 | delegate: MusicListItem { | |
1170 | 294 | Component { | 293 | id: track |
1171 | 295 | id: albumTracksDelegate | 294 | objectName: "songsPageListItem" + index |
1172 | 296 | 295 | column: Column { | |
1173 | 297 | ListItemWithActions { | 296 | Label { |
1174 | 298 | id: track | 297 | id: trackTitle |
1175 | 299 | objectName: "songsPageListItem" + index | 298 | color: styleMusic.common.music |
1176 | 300 | height: units.gu(6) | 299 | fontSize: "small" |
1177 | 301 | 300 | objectName: "songspage-tracktitle" | |
1178 | 302 | leftSideAction: songStackPage.line1 === i18n.tr("Playlist") | 301 | text: model.title |
1179 | 303 | ? playlistRemoveAction.item : null | 302 | } |
1180 | 304 | multiselectable: true | 303 | |
1181 | 305 | reorderable: songStackPage.line1 === i18n.tr("Playlist") | 304 | Label { |
1182 | 306 | rightSideActions: [ | 305 | id: trackArtist |
1183 | 307 | AddToQueue { | 306 | color: styleMusic.common.subtitle |
1184 | 308 | 307 | fontSize: "x-small" | |
1185 | 309 | }, | 308 | text: model.author |
1186 | 310 | AddToPlaylist { | 309 | } |
1187 | 311 | 310 | } | |
1188 | 312 | } | 311 | height: units.gu(6) |
1189 | 313 | ] | 312 | |
1190 | 314 | 313 | leftSideAction: songStackPage.line1 === i18n.tr("Playlist") | |
1191 | 315 | onItemClicked: { | 314 | ? playlistRemoveAction.item : null |
1192 | 316 | trackClicked(albumtrackslist.model, index) // play track | 315 | multiselectable: true |
1193 | 317 | 316 | reorderable: songStackPage.line1 === i18n.tr("Playlist") | |
1194 | 318 | if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) { | 317 | rightSideActions: [ |
1195 | 319 | Library.addRecent(albumtrackslist.model.get(0, albumtrackslist.model.RoleModelData).album, "album") | 318 | AddToQueue { |
1196 | 320 | } else if (songStackPage.line1 === i18n.tr("Playlist")) { | 319 | |
1197 | 321 | Library.addRecent(songStackPage.line2, "playlist") | 320 | }, |
1198 | 322 | } else { | 321 | AddToPlaylist { |
1199 | 323 | console.debug("Unknown type to add to recent") | 322 | |
1200 | 324 | } | 323 | } |
1201 | 325 | 324 | ] | |
1202 | 326 | recentModel.filterRecent() | 325 | |
1203 | 327 | } | 326 | onItemClicked: { |
1204 | 328 | onReorder: { | 327 | trackClicked(albumtrackslist.model, index) // play track |
1205 | 329 | console.debug("Move: ", from, to); | 328 | |
1206 | 330 | 329 | if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) { | |
1207 | 331 | Playlists.move(songStackPage.line2, from, to) | 330 | Library.addRecent(albumtrackslist.model.get(0, albumtrackslist.model.RoleModelData).album, "album") |
1208 | 332 | 331 | } else if (songStackPage.line1 === i18n.tr("Playlist")) { | |
1209 | 333 | albumTracksModel.filterPlaylistTracks(songStackPage.line2) | 332 | Library.addRecent(songStackPage.line2, "playlist") |
1210 | 334 | } | 333 | } else { |
1211 | 335 | 334 | console.debug("Unknown type to add to recent") | |
1212 | 336 | Loader { | 335 | } |
1213 | 337 | id: playlistRemoveAction | 336 | |
1214 | 338 | sourceComponent: Remove { | 337 | recentModel.filterRecent() |
1215 | 339 | onTriggered: { | 338 | } |
1216 | 340 | Playlists.removeFromPlaylist(songStackPage.line2, model.i) | 339 | onReorder: { |
1217 | 341 | 340 | console.debug("Move: ", from, to); | |
1218 | 342 | playlistChangedHelper() // update recent/playlist models | 341 | |
1219 | 343 | 342 | Playlists.move(songStackPage.line2, from, to) | |
1220 | 344 | albumTracksModel.filterPlaylistTracks(songStackPage.line2) | 343 | |
1221 | 345 | 344 | albumTracksModel.filterPlaylistTracks(songStackPage.line2) | |
1222 | 346 | // refresh cover art | 345 | } |
1223 | 347 | songStackPage.covers = Playlists.getPlaylistCovers(songStackPage.line2) | 346 | |
1224 | 348 | } | 347 | Loader { |
1225 | 349 | } | 348 | id: playlistRemoveAction |
1226 | 350 | } | 349 | sourceComponent: Remove { |
1227 | 351 | 350 | onTriggered: { | |
1228 | 352 | MusicRow { | 351 | Playlists.removeFromPlaylist(songStackPage.line2, model.i) |
1229 | 353 | id: musicRow | 352 | |
1230 | 354 | height: parent.height | 353 | playlistChangedHelper() // update recent/playlist models |
1231 | 355 | column: Column { | 354 | |
1232 | 356 | Label { | 355 | albumTracksModel.filterPlaylistTracks(songStackPage.line2) |
1233 | 357 | id: trackTitle | 356 | |
1234 | 358 | color: styleMusic.common.music | 357 | // refresh cover art |
1235 | 359 | fontSize: "small" | 358 | songStackPage.covers = Playlists.getPlaylistCovers(songStackPage.line2) |
1236 | 360 | objectName: "songspage-tracktitle" | 359 | } |
1237 | 361 | text: model.title | 360 | } |
1238 | 362 | } | 361 | } |
1239 | 363 | 362 | ||
1240 | 364 | Label { | 363 | Component.onCompleted: { |
1241 | 365 | id: trackArtist | 364 | if (model.date !== undefined) |
1242 | 366 | color: styleMusic.common.subtitle | 365 | { |
1243 | 367 | fontSize: "x-small" | 366 | songStackPage.file = model.filename; |
1244 | 368 | text: model.author | 367 | songStackPage.year = new Date(model.date).toLocaleString(Qt.locale(),'yyyy'); |
1159 | 369 | } | ||
1160 | 370 | } | ||
1161 | 371 | } | ||
1162 | 372 | |||
1163 | 373 | Component.onCompleted: { | ||
1164 | 374 | if (model.date !== undefined) | ||
1165 | 375 | { | ||
1166 | 376 | songStackPage.file = model.filename; | ||
1167 | 377 | songStackPage.year = new Date(model.date).toLocaleString(Qt.locale(),'yyyy'); | ||
1168 | 378 | } | ||
1245 | 379 | } | 368 | } |
1246 | 380 | } | 369 | } |
1247 | 381 | } | 370 | } |
1248 | 382 | 371 | ||
1249 | === modified file 'tests/autopilot/music_app/__init__.py' | |||
1250 | --- tests/autopilot/music_app/__init__.py 2015-02-04 04:20:07 +0000 | |||
1251 | +++ tests/autopilot/music_app/__init__.py 2015-02-22 02:24:31 +0000 | |||
1252 | @@ -187,7 +187,7 @@ | |||
1253 | 187 | self.visible.wait_for(True) | 187 | self.visible.wait_for(True) |
1254 | 188 | 188 | ||
1255 | 189 | def get_track(self, i): | 189 | def get_track(self, i): |
1257 | 190 | return (self.wait_select_single(ListItemWithActions, | 190 | return (self.wait_select_single(MusicListItem, |
1258 | 191 | objectName="tracksPageListItem" + str(i))) | 191 | objectName="tracksPageListItem" + str(i))) |
1259 | 192 | 192 | ||
1260 | 193 | 193 | ||
1261 | @@ -270,7 +270,7 @@ | |||
1262 | 270 | 270 | ||
1263 | 271 | @ensure_now_playing_list | 271 | @ensure_now_playing_list |
1264 | 272 | def get_track(self, i): | 272 | def get_track(self, i): |
1266 | 273 | return (self.wait_select_single(ListItemWithActions, | 273 | return (self.wait_select_single(MusicListItem, |
1267 | 274 | objectName="nowPlayingListItem" + str(i))) | 274 | objectName="nowPlayingListItem" + str(i))) |
1268 | 275 | 275 | ||
1269 | 276 | @ensure_now_playing_full | 276 | @ensure_now_playing_full |
1270 | @@ -331,7 +331,7 @@ | |||
1271 | 331 | objectName="songsPageHeaderAlbumArtist") | 331 | objectName="songsPageHeaderAlbumArtist") |
1272 | 332 | 332 | ||
1273 | 333 | def get_track(self, i): | 333 | def get_track(self, i): |
1275 | 334 | return (self.wait_select_single(ListItemWithActions, | 334 | return (self.wait_select_single(MusicListItem, |
1276 | 335 | objectName="songsPageListItem" + str(i))) | 335 | objectName="songsPageListItem" + str(i))) |
1277 | 336 | 336 | ||
1278 | 337 | 337 | ||
1279 | @@ -358,7 +358,7 @@ | |||
1280 | 358 | now_playing_page.visible.wait_for(True) | 358 | now_playing_page.visible.wait_for(True) |
1281 | 359 | 359 | ||
1282 | 360 | 360 | ||
1284 | 361 | class ListItemWithActions(UbuntuUIToolkitCustomProxyObjectBase): | 361 | class MusicListItem(UbuntuUIToolkitCustomProxyObjectBase): |
1285 | 362 | @click_object | 362 | @click_object |
1286 | 363 | def click_add_to_playlist_action(self): | 363 | def click_add_to_playlist_action(self): |
1287 | 364 | return self.wait_select_single(objectName="addToPlaylistAction") | 364 | return self.wait_select_single(objectName="addToPlaylistAction") |
FAILED: Continuous integration, rev:841 91.189. 93.70:8080/ job/music- app-refactor- ci/38/ 91.189. 93.70:8080/ job/generic- mediumtests- vivid/1080 91.189. 93.70:8080/ job/generic- mediumtests- vivid/1080/ artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/music- app-refactor- vivid-amd64- ci/38
http://
Executed test runs:
UNSTABLE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-refactor- ci/38/rebuild
http://