Merge lp:~ahayzen/music-app/remix-add-multi-select-mode into lp:music-app/remix
- remix-add-multi-select-mode
- Merge into remix
Status: | Merged |
---|---|
Approved by: | Victor Thompson |
Approved revision: | 681 |
Merged at revision: | 689 |
Proposed branch: | lp:~ahayzen/music-app/remix-add-multi-select-mode |
Merge into: | lp:music-app/remix |
Diff against target: |
1307 lines (+669/-182) 9 files modified
MusicNowPlaying.qml (+151/-69) MusicSearch.qml (+25/-0) MusicTracks.qml (+91/-7) MusicaddtoPlaylist.qml (+4/-5) common/ListItemActions/AddToPlaylist.qml (+1/-1) common/ListItemActions/CheckBox.qml (+25/-0) common/ListItemWithActions.qml (+261/-86) common/SongsPage.qml (+104/-10) music-app.qml (+7/-4) |
To merge this branch: | bzr merge lp:~ahayzen/music-app/remix-add-multi-select-mode |
Related bugs: | |
Related blueprints: |
Music Remix for RTM
(Essential)
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Victor Thompson | Approve | ||
Review via email: mp+239098@code.launchpad.net |
Commit message
* Pull upstream ListItemWithAct
* Add support for multiselect mode
* Disable triggerOnRelease
Description of the change
* Pull upstream ListItemWithAct
* Add support for multiselect mode
* Disable triggerOnRelease
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:679
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
A few initial things need fixing:
1. It seems as though the playlists are filtered again while reordering, this causes the view to flicker and the checked items get confused.
2. After reordering selected items and adding them to a playlist from the queue the items aren't quite right. Perhaps we shouldn't allow reordering when items are being selected.
Victor Thompson (vthompson) wrote : | # |
Also, we may want to talk to design about the "select all"/"select none" icon. Perhaps it could/should toggle to an empty square or a "clear" icon when all is selected?
Andrew Hayzen (ahayzen) wrote : | # |
1) Fixed due to the change in 2)
2) Disabled reordering when selectmode is enabled
Victor Thompson (vthompson) wrote : | # |
While I think preventing reorder when items are selected is the proper way of doing this... we probably should talk to Design about it.
Victor Thompson (vthompson) wrote : | # |
Could we please have 2 signals...
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:680
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Victor Thompson (vthompson) wrote : | # |
LGTM! This should help a lot and put us on the path towards improving performance elsewhere! Thanks!
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:681
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) : | # |
Preview Diff
1 | === modified file 'MusicNowPlaying.qml' |
2 | --- MusicNowPlaying.qml 2014-10-21 16:22:20 +0000 |
3 | +++ MusicNowPlaying.qml 2014-10-21 21:53:07 +0000 |
4 | @@ -25,6 +25,7 @@ |
5 | import "common" |
6 | import "common/ListItemActions" |
7 | import "settings.js" as Settings |
8 | +import "playlists.js" as Playlists |
9 | |
10 | MusicPage { |
11 | id: nowPlaying |
12 | @@ -41,43 +42,110 @@ |
13 | } |
14 | } |
15 | |
16 | - head.backAction: Action { |
17 | - iconName: "back"; |
18 | - objectName: "backButton" |
19 | - onTriggered: { |
20 | - mainPageStack.pop(); |
21 | - |
22 | - while (mainPageStack.depth > 1) { // jump back to the tab layer if via SongsPage |
23 | - mainPageStack.pop(); |
24 | - } |
25 | - } |
26 | - } |
27 | - |
28 | - head { |
29 | - actions: [ |
30 | - Action { |
31 | - objectName: "clearQueue" |
32 | - iconName: "delete" |
33 | - visible: isListView |
34 | - onTriggered: { |
35 | - head.backAction.trigger() |
36 | - trackQueue.model.clear() |
37 | - } |
38 | - }, |
39 | - Action { |
40 | - objectName: "toggleView" |
41 | - iconName: "media-playlist" |
42 | - onTriggered: { |
43 | - isListView = !isListView |
44 | - } |
45 | - } |
46 | - ] |
47 | - } |
48 | - |
49 | function positionAt(index) { |
50 | queuelist.positionViewAtIndex(index, ListView.Center); |
51 | } |
52 | |
53 | + state: isListView && queuelist.state === "multiselectable" ? "selection" : "default" |
54 | + states: [ |
55 | + PageHeadState { |
56 | + id: defaultState |
57 | + |
58 | + name: "default" |
59 | + backAction: Action { |
60 | + iconName: "back"; |
61 | + objectName: "backButton" |
62 | + onTriggered: { |
63 | + mainPageStack.pop(); |
64 | + |
65 | + while (mainPageStack.depth > 1) { // jump back to the tab layer if via SongsPage |
66 | + mainPageStack.pop(); |
67 | + } |
68 | + } |
69 | + } |
70 | + actions: [ |
71 | + Action { |
72 | + objectName: "clearQueue" |
73 | + iconName: "delete" |
74 | + visible: isListView |
75 | + onTriggered: { |
76 | + head.backAction.trigger() |
77 | + trackQueue.model.clear() |
78 | + } |
79 | + }, |
80 | + Action { |
81 | + objectName: "toggleView" |
82 | + iconName: "media-playlist" |
83 | + onTriggered: { |
84 | + isListView = !isListView |
85 | + } |
86 | + } |
87 | + ] |
88 | + PropertyChanges { |
89 | + target: nowPlaying.head |
90 | + backAction: defaultState.backAction |
91 | + actions: defaultState.actions |
92 | + } |
93 | + }, |
94 | + PageHeadState { |
95 | + id: selectionState |
96 | + |
97 | + name: "selection" |
98 | + backAction: Action { |
99 | + text: i18n.tr("Cancel selection") |
100 | + iconName: "back" |
101 | + onTriggered: queuelist.state = "normal" |
102 | + } |
103 | + actions: [ |
104 | + Action { |
105 | + text: i18n.tr("Select All") |
106 | + iconName: "select" |
107 | + onTriggered: { |
108 | + if (queuelist.selectedItems.length === queuelist.model.count) { |
109 | + queuelist.clearSelection() |
110 | + } else { |
111 | + queuelist.selectAll() |
112 | + } |
113 | + } |
114 | + }, |
115 | + Action { |
116 | + enabled: queuelist.selectedItems.length > 0 |
117 | + iconName: "add-to-playlist" |
118 | + text: i18n.tr("Add to playlist") |
119 | + onTriggered: { |
120 | + var items = [] |
121 | + |
122 | + for (var i=0; i < queuelist.selectedItems.length; i++) { |
123 | + items.push(makeDict(trackQueue.model.get(queuelist.selectedItems[i]))); |
124 | + } |
125 | + |
126 | + chosenElements = items; |
127 | + mainPageStack.push(addtoPlaylist) |
128 | + |
129 | + queuelist.closeSelection() |
130 | + } |
131 | + }, |
132 | + Action { |
133 | + enabled: queuelist.selectedItems.length > 0 |
134 | + iconName: "delete" |
135 | + text: i18n.tr("Delete") |
136 | + onTriggered: { |
137 | + for (var i=0; i < queuelist.selectedItems.length; i++) { |
138 | + removeQueue(queuelist.selectedItems[i]) |
139 | + } |
140 | + |
141 | + queuelist.closeSelection() |
142 | + } |
143 | + } |
144 | + ] |
145 | + PropertyChanges { |
146 | + target: nowPlaying.head |
147 | + backAction: selectionState.backAction |
148 | + actions: selectionState.actions |
149 | + } |
150 | + } |
151 | + ] |
152 | + |
153 | Rectangle { |
154 | id: fullview |
155 | anchors.fill: parent |
156 | @@ -376,6 +444,25 @@ |
157 | } |
158 | } |
159 | |
160 | + function removeQueue(index) |
161 | + { |
162 | + var removedIndex = index |
163 | + |
164 | + if (queuelist.count === 1) { |
165 | + player.stop() |
166 | + musicToolbar.goBack() |
167 | + } else if (index === player.currentIndex) { |
168 | + player.nextSong(player.isPlaying); |
169 | + } |
170 | + |
171 | + queuelist.model.remove(index); |
172 | + |
173 | + if (removedIndex < player.currentIndex) { |
174 | + // update index as the old has been removed |
175 | + player.currentIndex -= 1; |
176 | + } |
177 | + } |
178 | + |
179 | ListView { |
180 | id: queuelist |
181 | anchors { |
182 | @@ -388,23 +475,6 @@ |
183 | } |
184 | model: trackQueue.model |
185 | objectName: "nowPlayingQueueList" |
186 | - state: "normal" |
187 | - states: [ |
188 | - State { |
189 | - name: "normal" |
190 | - PropertyChanges { |
191 | - target: queuelist |
192 | - interactive: true |
193 | - } |
194 | - }, |
195 | - State { |
196 | - name: "reorder" |
197 | - PropertyChanges { |
198 | - target: queuelist |
199 | - interactive: false |
200 | - } |
201 | - } |
202 | - ] |
203 | visible: isListView |
204 | |
205 | property int normalHeight: units.gu(6) |
206 | @@ -414,6 +484,35 @@ |
207 | customdebug("Queue: Now has: " + queuelist.count + " tracks") |
208 | } |
209 | |
210 | + // Requirements for ListItemWithActions |
211 | + property var selectedItems: [] |
212 | + |
213 | + signal clearSelection() |
214 | + signal closeSelection() |
215 | + signal selectAll() |
216 | + |
217 | + onClearSelection: selectedItems = [] |
218 | + onCloseSelection: { |
219 | + clearSelection() |
220 | + state = "normal" |
221 | + } |
222 | + onSelectAll: { |
223 | + var tmp = selectedItems |
224 | + |
225 | + for (var i=0; i < model.count; i++) { |
226 | + if (tmp.indexOf(i) === -1) { |
227 | + tmp.push(i) |
228 | + } |
229 | + } |
230 | + |
231 | + selectedItems = tmp |
232 | + } |
233 | + onVisibleChanged: { |
234 | + if (!visible) { |
235 | + clearSelection(true) |
236 | + } |
237 | + } |
238 | + |
239 | Component { |
240 | id: queueDelegate |
241 | ListItemWithActions { |
242 | @@ -421,35 +520,18 @@ |
243 | color: player.currentIndex === index ? "#2c2c34" : "transparent" |
244 | height: queuelist.normalHeight |
245 | objectName: "nowPlayingListItem" + index |
246 | - showDivider: false |
247 | state: "" |
248 | |
249 | leftSideAction: Remove { |
250 | - onTriggered: { |
251 | - var removedIndex = index |
252 | - |
253 | - if (queuelist.count === 1) { |
254 | - player.stop() |
255 | - musicToolbar.goBack() |
256 | - } else if (index === player.currentIndex) { |
257 | - player.nextSong(player.isPlaying); |
258 | - } |
259 | - |
260 | - queuelist.model.remove(index); |
261 | - |
262 | - if (removedIndex < player.currentIndex) { |
263 | - // update index as the old has been removed |
264 | - player.currentIndex -= 1; |
265 | - } |
266 | - } |
267 | + onTriggered: removeQueue(index) |
268 | } |
269 | + multiselectable: true |
270 | reorderable: true |
271 | rightSideActions: [ |
272 | AddToPlaylist{ |
273 | |
274 | } |
275 | ] |
276 | - triggerActionOnMouseRelease: true |
277 | |
278 | onItemClicked: { |
279 | customdebug("File: " + model.filename) // debugger |
280 | |
281 | === modified file 'MusicSearch.qml' |
282 | --- MusicSearch.qml 2014-09-20 15:41:33 +0000 |
283 | +++ MusicSearch.qml 2014-10-21 21:53:07 +0000 |
284 | @@ -154,6 +154,31 @@ |
285 | searchTrackView.forceActiveFocus() |
286 | } |
287 | |
288 | + // Requirements for ListItemWithActions |
289 | + property var selectedItems: [] |
290 | + |
291 | + signal clearSelection(bool closeSelection) |
292 | + signal selectAll() |
293 | + |
294 | + onClearSelection: { |
295 | + selectedItems = [] |
296 | + |
297 | + if (closeSelection || closeSelection === undefined) { |
298 | + state = "normal" |
299 | + } |
300 | + } |
301 | + onSelectAll: { |
302 | + for (var i=0; i < model.count; i++) { |
303 | + if (selectedItems.indexOf(i) === -1) { |
304 | + selectedItems.push(i) |
305 | + } |
306 | + } |
307 | + } |
308 | + onVisibleChanged: { |
309 | + if (!visible) { |
310 | + clearSelection(true) |
311 | + } |
312 | + } |
313 | delegate: ListItemWithActions { |
314 | id: search |
315 | color: "transparent" |
316 | |
317 | === modified file 'MusicTracks.qml' |
318 | --- MusicTracks.qml 2014-10-10 05:50:32 +0000 |
319 | +++ MusicTracks.qml 2014-10-21 21:53:07 +0000 |
320 | @@ -34,6 +34,66 @@ |
321 | objectName: "tracksPage" |
322 | title: i18n.tr("Songs") |
323 | |
324 | + state: tracklist.state === "multiselectable" ? "selection" : "default" |
325 | + states: [ |
326 | + PageHeadState { |
327 | + id: selectionState |
328 | + name: "selection" |
329 | + backAction: Action { |
330 | + text: i18n.tr("Cancel selection") |
331 | + iconName: "back" |
332 | + onTriggered: tracklist.state = "normal" |
333 | + } |
334 | + actions: [ |
335 | + Action { |
336 | + iconName: "select" |
337 | + text: i18n.tr("Select All") |
338 | + onTriggered: { |
339 | + if (tracklist.selectedItems.length === tracklist.model.count) { |
340 | + tracklist.clearSelection() |
341 | + } else { |
342 | + tracklist.selectAll() |
343 | + } |
344 | + } |
345 | + }, |
346 | + Action { |
347 | + enabled: tracklist.selectedItems.length !== 0 |
348 | + iconName: "add-to-playlist" |
349 | + text: i18n.tr("Add to playlist") |
350 | + onTriggered: { |
351 | + var items = [] |
352 | + |
353 | + for (var i=0; i < tracklist.selectedItems.length; i++) { |
354 | + items.push(makeDict(tracklist.model.get(tracklist.selectedItems[i], tracklist.model.RoleModelData))); |
355 | + } |
356 | + |
357 | + chosenElements = items; |
358 | + mainPageStack.push(addtoPlaylist) |
359 | + |
360 | + tracklist.closeSelection() |
361 | + } |
362 | + }, |
363 | + Action { |
364 | + enabled: tracklist.selectedItems.length > 0 |
365 | + iconName: "add" |
366 | + text: i18n.tr("Add to queue") |
367 | + onTriggered: { |
368 | + for (var i=0; i < tracklist.selectedItems.length; i++) { |
369 | + trackQueue.model.append(makeDict(tracklist.model.get(tracklist.selectedItems[i], tracklist.model.RoleModelData))); |
370 | + } |
371 | + |
372 | + tracklist.closeSelection() |
373 | + } |
374 | + } |
375 | + ] |
376 | + PropertyChanges { |
377 | + target: mainpage.head |
378 | + backAction: selectionState.backAction |
379 | + actions: selectionState.actions |
380 | + } |
381 | + } |
382 | + ] |
383 | + |
384 | ListView { |
385 | id: tracklist |
386 | anchors { |
387 | @@ -52,18 +112,46 @@ |
388 | sort.property: "title" |
389 | sort.order: Qt.AscendingOrder |
390 | } |
391 | + |
392 | + // Requirements for ListItemWithActions |
393 | + property var selectedItems: [] |
394 | + |
395 | + signal clearSelection() |
396 | + signal closeSelection() |
397 | + signal selectAll() |
398 | + |
399 | + onClearSelection: selectedItems = [] |
400 | + onCloseSelection: { |
401 | + clearSelection() |
402 | + state = "normal" |
403 | + } |
404 | + onSelectAll: { |
405 | + var tmp = selectedItems |
406 | + |
407 | + for (var i=0; i < model.count; i++) { |
408 | + if (tmp.indexOf(i) === -1) { |
409 | + tmp.push(i) |
410 | + } |
411 | + } |
412 | + |
413 | + selectedItems = tmp |
414 | + } |
415 | + onVisibleChanged: { |
416 | + if (!visible) { |
417 | + clearSelection(true) |
418 | + } |
419 | + } |
420 | + |
421 | delegate: trackDelegate |
422 | Component { |
423 | id: trackDelegate |
424 | |
425 | ListItemWithActions { |
426 | id: track |
427 | - color: "transparent" |
428 | objectName: "tracksPageListItem" + index |
429 | - width: parent.width |
430 | height: units.gu(7) |
431 | - showDivider: false |
432 | |
433 | + multiselectable: true |
434 | rightSideActions: [ |
435 | AddToQueue { |
436 | }, |
437 | @@ -71,10 +159,6 @@ |
438 | |
439 | } |
440 | ] |
441 | - triggerActionOnMouseRelease: true |
442 | - |
443 | - // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well. |
444 | - onPressedChanged: musicRow.pressed = pressed |
445 | |
446 | onItemClicked: trackClicked(tracklist.model, index) // play track |
447 | |
448 | |
449 | === modified file 'MusicaddtoPlaylist.qml' |
450 | --- MusicaddtoPlaylist.qml 2014-09-30 15:18:25 +0000 |
451 | +++ MusicaddtoPlaylist.qml 2014-10-21 21:53:07 +0000 |
452 | @@ -81,18 +81,17 @@ |
453 | property string count: model.count |
454 | |
455 | onClicked: { |
456 | - console.debug("Debug: "+chosenElement.filename+" added to "+name) |
457 | + for (var i=0; i < chosenElements.length; i++) { |
458 | + console.debug("Debug: "+chosenElements[i].filename+" added to "+name) |
459 | |
460 | - Playlists.addToPlaylist(name, chosenElement) |
461 | + Playlists.addToPlaylist(name, chosenElements[i]) |
462 | + } |
463 | |
464 | playlistModel.filterPlaylists(); |
465 | |
466 | musicToolbar.goBack(); // go back to the previous page |
467 | } |
468 | |
469 | - // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well. |
470 | - onPressedChanged: musicRow.pressed = pressed |
471 | - |
472 | MusicRow { |
473 | id: musicRow |
474 | covers: Playlists.getPlaylistCovers(playlist.name) |
475 | |
476 | === modified file 'common/ListItemActions/AddToPlaylist.qml' |
477 | --- common/ListItemActions/AddToPlaylist.qml 2014-09-20 10:50:45 +0000 |
478 | +++ common/ListItemActions/AddToPlaylist.qml 2014-10-21 21:53:07 +0000 |
479 | @@ -27,7 +27,7 @@ |
480 | property bool primed: false |
481 | |
482 | onTriggered: { |
483 | - chosenElement = makeDict(model); |
484 | + chosenElements = [makeDict(model)]; |
485 | console.debug("Debug: Add track to playlist"); |
486 | mainPageStack.push(addtoPlaylist) |
487 | } |
488 | |
489 | === added file 'common/ListItemActions/CheckBox.qml' |
490 | --- common/ListItemActions/CheckBox.qml 1970-01-01 00:00:00 +0000 |
491 | +++ common/ListItemActions/CheckBox.qml 2014-10-21 21:53:07 +0000 |
492 | @@ -0,0 +1,25 @@ |
493 | +/* |
494 | + * Copyright (C) 2012-2014 Canonical, Ltd. |
495 | + * |
496 | + * This program is free software; you can redistribute it and/or modify |
497 | + * it under the terms of the GNU General Public License as published by |
498 | + * the Free Software Foundation; version 3. |
499 | + * |
500 | + * This program is distributed in the hope that it will be useful, |
501 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
502 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
503 | + * GNU General Public License for more details. |
504 | + * |
505 | + * You should have received a copy of the GNU General Public License |
506 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
507 | + */ |
508 | + |
509 | +import QtQuick 2.2 |
510 | +import Ubuntu.Components 1.1 |
511 | + |
512 | +CheckBox { |
513 | + checked: root.selected |
514 | + width: implicitWidth |
515 | + // disable item mouse area to avoid conflicts with parent mouse area |
516 | + __mouseArea.enabled: false |
517 | +} |
518 | |
519 | === modified file 'common/ListItemWithActions.qml' |
520 | --- common/ListItemWithActions.qml 2014-09-20 10:50:45 +0000 |
521 | +++ common/ListItemWithActions.qml 2014-10-21 21:53:07 +0000 |
522 | @@ -19,116 +19,170 @@ |
523 | import Ubuntu.Components.ListItems 1.0 as ListItem |
524 | |
525 | |
526 | -ListItem.Standard { // CUSTOM |
527 | -//Item { |
528 | +Item { |
529 | id: root |
530 | + width: parent.width |
531 | |
532 | property Action leftSideAction: null |
533 | property list<Action> rightSideActions |
534 | property double defaultHeight: units.gu(8) |
535 | property bool locked: false |
536 | - property bool pressed: false |
537 | property Action activeAction: null |
538 | property var activeItem: null |
539 | property bool triggerActionOnMouseRelease: false |
540 | - property alias color: main.color |
541 | - default property alias contents: main.children |
542 | - |
543 | - property bool reorderable: false // CUSTOM |
544 | - property bool reordering: false // CUSTOM |
545 | - |
546 | - readonly property double actionWidth: units.gu(5) |
547 | + property color color: Theme.palette.normal.background |
548 | + property color selectedColor: "#3d3d45" // "#E6E6E6" // CUSTOM |
549 | + property bool selected: false |
550 | + property bool selectionMode: false |
551 | + property alias internalAnchors: mainContents.anchors |
552 | + default property alias contents: mainContents.children |
553 | + |
554 | + readonly property double actionWidth: units.gu(4) // CUSTOM 5? |
555 | readonly property double leftActionWidth: units.gu(10) |
556 | readonly property double actionThreshold: actionWidth * 0.4 |
557 | readonly property double threshold: 0.4 |
558 | readonly property string swipeState: main.x == 0 ? "Normal" : main.x > 0 ? "LeftToRight" : "RightToLeft" |
559 | readonly property alias swipping: mainItemMoving.running |
560 | + readonly property bool _showActions: mouseArea.pressed || swipeState != "Normal" || swipping |
561 | + |
562 | + property bool reorderable: false // CUSTOM |
563 | + property bool reordering: false // CUSTOM |
564 | + property bool multiselectable: false // CUSTOM |
565 | + |
566 | + property int previousListItemIndex: -1 // CUSTOM |
567 | + property int listItemIndex: index // CUSTOM |
568 | + |
569 | + /* internal */ |
570 | + property var _visibleRightSideActions: filterVisibleActions(rightSideActions) |
571 | |
572 | signal itemClicked(var mouse) |
573 | signal itemPressAndHold(var mouse) |
574 | |
575 | signal reorder(int from, int to) // CUSTOM |
576 | |
577 | - onItemPressAndHold: reordering = reorderable && !reordering // CUSTOM |
578 | - onReorderingChanged: { // CUSTOM |
579 | - if (reordering) { |
580 | + onItemPressAndHold: { |
581 | + //reordering = reorderable && !reordering // CUSTOM |
582 | + if (multiselectable) { |
583 | + selectionMode = true |
584 | + } |
585 | + } |
586 | + onListItemIndexChanged: { |
587 | + var i = parent.parent.selectedItems.lastIndexOf(previousListItemIndex) |
588 | + |
589 | + if (i !== -1) { |
590 | + parent.parent.selectedItems[i] = listItemIndex |
591 | + } |
592 | + |
593 | + previousListItemIndex = listItemIndex |
594 | + } |
595 | + |
596 | + onSelectedChanged: { |
597 | + if (selectionMode) { |
598 | + var tmp = parent.parent.selectedItems |
599 | + |
600 | + if (selected) { |
601 | + if (parent.parent.selectedItems.indexOf(listItemIndex) === -1) { |
602 | + tmp.push(listItemIndex) |
603 | + parent.parent.selectedItems = tmp |
604 | + } |
605 | + } else { |
606 | + tmp.splice(parent.parent.selectedItems.indexOf(listItemIndex), 1) |
607 | + parent.parent.selectedItems = tmp |
608 | + } |
609 | + } |
610 | + } |
611 | + |
612 | + onSelectionModeChanged: { // CUSTOM |
613 | + if (reorderable && selectionMode) { |
614 | resetSwipe() |
615 | } |
616 | |
617 | for (var j=0; j < main.children.length; j++) { |
618 | - main.children[j].anchors.rightMargin = reordering ? actionReorder.width + units.gu(2) : 0 |
619 | - } |
620 | - |
621 | - parent.state = reordering ? "reorder" : "normal" |
622 | + main.children[j].anchors.rightMargin = reorderable && selectionMode ? actionReorder.width + units.gu(2) : 0 |
623 | + } |
624 | + |
625 | + parent.parent.state = selectionMode ? "multiselectable" : "normal" |
626 | + |
627 | + if (!selectionMode) { |
628 | + selected = false |
629 | + } |
630 | } |
631 | |
632 | - function returnToBoundsRTL() |
633 | + function returnToBoundsRTL(direction) |
634 | { |
635 | var actionFullWidth = actionWidth + units.gu(2) |
636 | + |
637 | + // go back to normal state if swipping reverse |
638 | + if (direction === "LTR") { |
639 | + updatePosition(0) |
640 | + return |
641 | + } else if (!triggerActionOnMouseRelease) { |
642 | + updatePosition(-rightActionsView.width + units.gu(2)) |
643 | + return |
644 | + } |
645 | + |
646 | var xOffset = Math.abs(main.x) |
647 | - var index = Math.min(Math.floor(xOffset / actionFullWidth), rightSideActions.length) |
648 | - var j; // CUSTOM |
649 | - |
650 | - if (index < 1) { |
651 | - main.x = 0 |
652 | - |
653 | - resetPrimed() // CUSTOM |
654 | - } else if (index === rightSideActions.length) { |
655 | - main.x = -rightActionsView.width |
656 | + var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length) |
657 | + var newX = 0 |
658 | + var j // CUSTOM |
659 | + |
660 | + if (index === _visibleRightSideActions.length) { |
661 | + newX = -(rightActionsView.width - units.gu(2)) |
662 | |
663 | for (j=0; j < rightSideActions.length; j++) { // CUSTOM |
664 | rightActionsRepeater.itemAt(j).primed = true |
665 | } |
666 | - } else { |
667 | - main.x = -(actionFullWidth * index) |
668 | + } else if (index >= 1) { |
669 | + newX = -(actionFullWidth * index) |
670 | |
671 | for (j=0; j < rightSideActions.length; j++) { // CUSTOM |
672 | rightActionsRepeater.itemAt(j).primed = j === index |
673 | } |
674 | } |
675 | + |
676 | + updatePosition(newX) |
677 | } |
678 | |
679 | - function returnToBoundsLTR() |
680 | + function returnToBoundsLTR(direction) |
681 | { |
682 | var finalX = leftActionWidth |
683 | - if (main.x > (finalX * root.threshold)) |
684 | - main.x = finalX |
685 | - else { |
686 | - main.x = 0 |
687 | - |
688 | - resetPrimed() // CUSTOM |
689 | - } |
690 | + if ((direction === "RTL") || (main.x <= (finalX * root.threshold))) |
691 | + finalX = 0 |
692 | + updatePosition(finalX) |
693 | |
694 | if (leftSideAction !== null) { // CUSTOM |
695 | leftActionIcon.primed = main.x > (finalX * root.threshold) |
696 | } |
697 | } |
698 | |
699 | - function returnToBounds() |
700 | + function returnToBounds(direction) |
701 | { |
702 | if (main.x < 0) { |
703 | - returnToBoundsRTL() |
704 | + returnToBoundsRTL(direction) |
705 | } else if (main.x > 0) { |
706 | - returnToBoundsLTR() |
707 | - } else { // CUSTOM |
708 | - resetPrimed() // CUSTOM |
709 | + returnToBoundsLTR(direction) |
710 | + } else { |
711 | + updatePosition(0) |
712 | } |
713 | } |
714 | |
715 | - function contains(item, point) |
716 | + function contains(item, point, marginX) |
717 | { |
718 | - return (point.x >= item.x) && (point.x <= (item.x + item.width)) && (point.y >= item.y) && (point.y <= (item.y + item.height)); |
719 | + var itemStartX = item.x - marginX |
720 | + var itemEndX = item.x + item.width + marginX |
721 | + return (point.x >= itemStartX) && (point.x <= itemEndX) && |
722 | + (point.y >= item.y) && (point.y <= (item.y + item.height)); |
723 | } |
724 | |
725 | function getActionAt(point) |
726 | { |
727 | - if (contains(leftActionView, point)) { |
728 | + if (contains(leftActionView, point, 0)) { |
729 | return leftSideAction |
730 | - } else if (contains(rightActionsView, point)) { |
731 | + } else if (contains(rightActionsView, point, 0)) { |
732 | var newPoint = root.mapToItem(rightActionsView, point.x, point.y) |
733 | for (var i = 0; i < rightActionsRepeater.count; i++) { |
734 | var child = rightActionsRepeater.itemAt(i) |
735 | - if (contains(child, newPoint)) { |
736 | + if (contains(child, newPoint, units.gu(1))) { |
737 | return i |
738 | } |
739 | } |
740 | @@ -138,15 +192,16 @@ |
741 | |
742 | function updateActiveAction() |
743 | { |
744 | - if ((main.x <= -root.actionWidth) && |
745 | - (main.x > -rightActionsView.width)) { |
746 | + if (triggerActionOnMouseRelease && |
747 | + (main.x <= -(root.actionWidth + units.gu(2))) && |
748 | + (main.x > -(rightActionsView.width - units.gu(2)))) { |
749 | var actionFullWidth = actionWidth + units.gu(2) |
750 | var xOffset = Math.abs(main.x) |
751 | - var index = Math.min(Math.floor(xOffset / actionFullWidth), rightSideActions.length) |
752 | + var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length) |
753 | index = index - 1 |
754 | if (index > -1) { |
755 | root.activeItem = rightActionsRepeater.itemAt(index) |
756 | - root.activeAction = root.rightSideActions[index] |
757 | + root.activeAction = root._visibleRightSideActions[index] |
758 | } |
759 | } else { |
760 | root.activeAction = null |
761 | @@ -160,15 +215,40 @@ |
762 | } |
763 | |
764 | for (var j=0; j < rightSideActions.length; j++) { |
765 | + console.debug(rightActionsRepeater.itemAt(j)); |
766 | rightActionsRepeater.itemAt(j).primed = false |
767 | } |
768 | } |
769 | |
770 | function resetSwipe() |
771 | { |
772 | - main.x = 0 |
773 | - |
774 | - resetPrimed() // CUSTOM |
775 | + updatePosition(0) |
776 | + } |
777 | + |
778 | + function filterVisibleActions(actions) |
779 | + { |
780 | + var visibleActions = [] |
781 | + for(var i = 0; i < actions.length; i++) { |
782 | + var action = actions[i] |
783 | + if (action.visible) { |
784 | + visibleActions.push(action) |
785 | + } |
786 | + } |
787 | + return visibleActions |
788 | + } |
789 | + |
790 | + function updatePosition(pos) |
791 | + { |
792 | + if (!root.triggerActionOnMouseRelease && (pos !== 0)) { |
793 | + mouseArea.state = pos > 0 ? "RightToLeft" : "LeftToRight" |
794 | + } else { |
795 | + mouseArea.state = "" |
796 | + } |
797 | + main.x = pos |
798 | + |
799 | + if (pos === 0) { // CUSTOM |
800 | + //resetPrimed() |
801 | + } |
802 | } |
803 | |
804 | Connections { // CUSTOM |
805 | @@ -181,8 +261,10 @@ |
806 | } |
807 | |
808 | Connections { // CUSTOM |
809 | - target: root.parent |
810 | - onStateChanged: reordering = root.parent.state === "reorder" |
811 | + target: root.parent.parent |
812 | + onClearSelection: selected = false |
813 | + onSelectAll: selected = true |
814 | + onStateChanged: selectionMode = root.parent.parent.state === "multiselectable" |
815 | onVisibleChanged: { |
816 | if (!visible) { |
817 | reordering = false |
818 | @@ -190,7 +272,13 @@ |
819 | } |
820 | } |
821 | |
822 | - Component.onCompleted: reordering = root.parent.state === "reorder" // CUSTOM |
823 | + Component.onCompleted: { // CUSTOM |
824 | + if (parent.parent.selectedItems.indexOf(index) !== -1) { // FIXME: |
825 | + selected = true |
826 | + } |
827 | + |
828 | + selectionMode = root.parent.parent.state === "multiselectable" |
829 | + } |
830 | |
831 | /* CUSTOM Dim Component */ |
832 | Rectangle { |
833 | @@ -228,6 +316,26 @@ |
834 | } |
835 | } |
836 | |
837 | + states: [ |
838 | + State { |
839 | + name: "select" |
840 | + when: selectionMode || selected |
841 | + PropertyChanges { |
842 | + target: selectionIcon |
843 | + source: Qt.resolvedUrl("ListItemActions/CheckBox.qml") |
844 | + anchors.leftMargin: units.gu(2) |
845 | + } |
846 | + PropertyChanges { |
847 | + target: root |
848 | + locked: true |
849 | + } |
850 | + PropertyChanges { |
851 | + target: main |
852 | + x: 0 |
853 | + } |
854 | + } |
855 | + ] |
856 | + |
857 | height: defaultHeight |
858 | clip: height !== defaultHeight |
859 | |
860 | @@ -241,16 +349,15 @@ |
861 | } |
862 | width: root.leftActionWidth + actionThreshold |
863 | visible: leftSideAction |
864 | - color: "red" |
865 | + color: UbuntuColors.red |
866 | |
867 | Icon { |
868 | - id: leftActionIcon |
869 | anchors { |
870 | centerIn: parent |
871 | horizontalCenterOffset: actionThreshold / 2 |
872 | } |
873 | objectName: "swipeDeleteAction" // CUSTOM |
874 | - name: leftSideAction ? leftSideAction.iconName : "" |
875 | + name: leftSideAction && _showActions ? leftSideAction.iconName : "" |
876 | color: Theme.palette.selected.field |
877 | height: units.gu(3) |
878 | width: units.gu(3) |
879 | @@ -259,7 +366,8 @@ |
880 | } |
881 | } |
882 | |
883 | - Item { |
884 | + //Rectangle { |
885 | + Item { // CUSTOM |
886 | id: rightActionsView |
887 | |
888 | anchors { |
889 | @@ -268,8 +376,9 @@ |
890 | leftMargin: reordering ? actionReorder.width : units.gu(1) // CUSTOM |
891 | bottom: main.bottom |
892 | } |
893 | - visible: rightSideActions.length > 0 |
894 | - width: rightActionsRepeater.count > 0 ? rightActionsRepeater.count * (root.actionWidth + units.gu(2)) + actionThreshold : 0 |
895 | + visible: _visibleRightSideActions.length > 0 |
896 | + width: rightActionsRepeater.count > 0 ? rightActionsRepeater.count * (root.actionWidth + units.gu(2)) + root.actionThreshold + units.gu(2) : 0 |
897 | + // color: "white" // CUSTOM |
898 | |
899 | Rectangle { // CUSTOM |
900 | anchors { |
901 | @@ -283,22 +392,23 @@ |
902 | } |
903 | |
904 | Row { |
905 | - anchors { |
906 | - fill: parent |
907 | - leftMargin: units.gu(2) // CUSTOM |
908 | + anchors{ |
909 | + top: parent.top |
910 | + left: parent.left |
911 | + leftMargin: units.gu(2) |
912 | + right: parent.right |
913 | + rightMargin: units.gu(2) |
914 | + bottom: parent.bottom |
915 | } |
916 | spacing: units.gu(2) |
917 | Repeater { |
918 | id: rightActionsRepeater |
919 | |
920 | - model: rightSideActions |
921 | + model: _showActions ? _visibleRightSideActions : [] |
922 | Item { |
923 | property alias image: img |
924 | |
925 | - anchors { |
926 | - top: parent.top |
927 | - bottom: parent.bottom |
928 | - } |
929 | + height: rightActionsView.height |
930 | width: root.actionWidth |
931 | |
932 | property alias primed: img.primed // CUSTOM |
933 | @@ -310,8 +420,8 @@ |
934 | objectName: rightSideActions[index].objectName // CUSTOM |
935 | width: units.gu(3) |
936 | height: units.gu(3) |
937 | - name: iconName |
938 | - color: root.activeAction === modelData || !root.triggerActionOnMouseRelease ? UbuntuColors.orange : styleMusic.common.white // CUSTOM |
939 | + name: modelData.iconName |
940 | + color: root.activeAction === modelData ? UbuntuColors.orange : styleMusic.common.white // CUSTOM |
941 | |
942 | property bool primed: false // CUSTOM |
943 | } |
944 | @@ -330,6 +440,38 @@ |
945 | } |
946 | |
947 | width: parent.width |
948 | + color: root.selected ? root.selectedColor : root.color |
949 | + |
950 | + Loader { |
951 | + id: selectionIcon |
952 | + |
953 | + anchors { |
954 | + left: main.left |
955 | + verticalCenter: main.verticalCenter |
956 | + } |
957 | + width: (status === Loader.Ready) ? item.implicitWidth : 0 |
958 | + visible: (status === Loader.Ready) && (item.width === item.implicitWidth) |
959 | + Behavior on width { |
960 | + NumberAnimation { |
961 | + duration: UbuntuAnimation.SnapDuration |
962 | + } |
963 | + } |
964 | + } |
965 | + |
966 | + Item { |
967 | + id: mainContents |
968 | + |
969 | + anchors { |
970 | + left: selectionIcon.right |
971 | + //leftMargin: units.gu(2) // CUSTOM |
972 | + top: parent.top |
973 | + //topMargin: units.gu(1) // CUSTOM |
974 | + right: parent.right |
975 | + //rightMargin: units.gu(2) // CUSTOM |
976 | + bottom: parent.bottom |
977 | + //bottomMargin: units.gu(1) // CUSTOM |
978 | + } |
979 | + } |
980 | |
981 | Behavior on x { |
982 | UbuntuNumberAnimation { |
983 | @@ -342,7 +484,7 @@ |
984 | } |
985 | |
986 | /* CUSTOM Reorder Component */ |
987 | - Rectangle { |
988 | + Item { |
989 | id: actionReorder |
990 | anchors { |
991 | bottom: parent.bottom |
992 | @@ -350,9 +492,8 @@ |
993 | rightMargin: units.gu(1) |
994 | top: parent.top |
995 | } |
996 | - color: "transparent" |
997 | width: units.gu(4) |
998 | - visible: reordering |
999 | + visible: reorderable && selectionMode && root.parent.parent.selectedItems.length === 0 |
1000 | |
1001 | Icon { |
1002 | anchors { |
1003 | @@ -469,7 +610,10 @@ |
1004 | value: 1.0 |
1005 | } |
1006 | ScriptAction { |
1007 | - script: root.activeAction.triggered(root) |
1008 | + script: { |
1009 | + root.activeAction.triggered(root) |
1010 | + mouseArea.state = "" |
1011 | + } |
1012 | } |
1013 | PauseAnimation { |
1014 | duration: 500 |
1015 | @@ -479,23 +623,53 @@ |
1016 | property: "x" |
1017 | to: 0 |
1018 | } |
1019 | - ScriptAction { |
1020 | - script: resetPrimed() |
1021 | - } |
1022 | } |
1023 | |
1024 | MouseArea { |
1025 | id: mouseArea |
1026 | |
1027 | - property bool locked: root.locked || ((root.leftSideAction === null) && (root.rightSideActions.count === 0)) || reordering // CUSTOM |
1028 | + property bool locked: root.locked || ((root.leftSideAction === null) && (root._visibleRightSideActions.count === 0)) || reordering // CUSTOM |
1029 | property bool manual: false |
1030 | + property string direction: "None" |
1031 | + property real lastX: -1 |
1032 | |
1033 | anchors.fill: parent |
1034 | drag { |
1035 | target: locked ? null : main |
1036 | axis: Drag.XAxis |
1037 | - minimumX: rightActionsView.visible ? -(rightActionsView.width + root.actionThreshold) : 0 |
1038 | + minimumX: rightActionsView.visible ? -(rightActionsView.width) : 0 |
1039 | maximumX: leftActionView.visible ? leftActionView.width : 0 |
1040 | + threshold: root.actionThreshold |
1041 | + } |
1042 | + |
1043 | + states: [ |
1044 | + State { |
1045 | + name: "LeftToRight" |
1046 | + PropertyChanges { |
1047 | + target: mouseArea |
1048 | + drag.maximumX: 0 |
1049 | + } |
1050 | + }, |
1051 | + State { |
1052 | + name: "RightToLeft" |
1053 | + PropertyChanges { |
1054 | + target: mouseArea |
1055 | + drag.minimumX: 0 |
1056 | + } |
1057 | + } |
1058 | + ] |
1059 | + |
1060 | + onMouseXChanged: { |
1061 | + var offset = (lastX - mouseX) |
1062 | + if (Math.abs(offset) <= root.actionThreshold) { |
1063 | + return |
1064 | + } |
1065 | + lastX = mouseX |
1066 | + direction = offset > 0 ? "RTL" : "LTR"; |
1067 | + } |
1068 | + |
1069 | + onPressed: { |
1070 | + lastX = mouse.x |
1071 | } |
1072 | |
1073 | onReleased: { |
1074 | @@ -505,10 +679,13 @@ |
1075 | root.returnToBounds() |
1076 | root.activeAction = null |
1077 | } |
1078 | + lastX = -1 |
1079 | + direction = "None" |
1080 | } |
1081 | onClicked: { |
1082 | - if (reordering) { // CUSTOM |
1083 | - reordering = false |
1084 | + if (selectionMode) { // CUSTOM |
1085 | + selected = !selected |
1086 | + return |
1087 | } |
1088 | else if (main.x === 0) { |
1089 | root.itemClicked(mouse) |
1090 | @@ -544,8 +721,6 @@ |
1091 | } |
1092 | } |
1093 | |
1094 | - onPressedChanged: root.pressed = pressed |
1095 | - |
1096 | z: -1 |
1097 | } |
1098 | } |
1099 | |
1100 | === modified file 'common/SongsPage.qml' |
1101 | --- common/SongsPage.qml 2014-10-21 17:30:51 +0000 |
1102 | +++ common/SongsPage.qml 2014-10-21 21:53:07 +0000 |
1103 | @@ -44,7 +44,7 @@ |
1104 | property alias album: songsModel.album |
1105 | property alias genre: songsModel.genre |
1106 | |
1107 | - state: songStackPage.line1 === i18n.tr("Playlist") ? "playlist" : "album" |
1108 | + state: albumtrackslist.state === "multiselectable" ? "selection" : (songStackPage.line1 === i18n.tr("Playlist") ? "playlist" : "album") |
1109 | states: [ |
1110 | PageHeadState { |
1111 | id: albumState |
1112 | @@ -57,7 +57,6 @@ |
1113 | }, |
1114 | PageHeadState { |
1115 | id: playlistState |
1116 | - |
1117 | name: "playlist" |
1118 | actions: [ |
1119 | Action { |
1120 | @@ -82,6 +81,78 @@ |
1121 | backAction: playlistState.backAction |
1122 | actions: playlistState.actions |
1123 | } |
1124 | + }, |
1125 | + PageHeadState { |
1126 | + id: selectionState |
1127 | + name: "selection" |
1128 | + backAction: Action { |
1129 | + text: i18n.tr("Cancel selection") |
1130 | + iconName: "back" |
1131 | + onTriggered: albumtrackslist.state = "normal" |
1132 | + } |
1133 | + actions: [ |
1134 | + Action { |
1135 | + iconName: "select" |
1136 | + text: i18n.tr("Select All") |
1137 | + onTriggered: { |
1138 | + if (albumtrackslist.selectedItems.length === albumtrackslist.model.count) { |
1139 | + albumtrackslist.clearSelection() |
1140 | + } else { |
1141 | + albumtrackslist.selectAll() |
1142 | + } |
1143 | + } |
1144 | + }, |
1145 | + Action { |
1146 | + enabled: albumtrackslist.selectedItems.length > 0 |
1147 | + iconName: "add-to-playlist" |
1148 | + text: i18n.tr("Add to playlist") |
1149 | + onTriggered: { |
1150 | + var items = [] |
1151 | + |
1152 | + for (var i=0; i < albumtrackslist.selectedItems.length; i++) { |
1153 | + items.push(makeDict(albumtrackslist.model.get(albumtrackslist.selectedItems[i], albumtrackslist.model.RoleModelData))); |
1154 | + } |
1155 | + |
1156 | + chosenElements = items; |
1157 | + mainPageStack.push(addtoPlaylist) |
1158 | + |
1159 | + albumtrackslist.closeSelection() |
1160 | + } |
1161 | + }, |
1162 | + Action { |
1163 | + enabled: albumtrackslist.selectedItems.length > 0 |
1164 | + iconName: "add" |
1165 | + text: i18n.tr("Add to queue") |
1166 | + onTriggered: { |
1167 | + for (var i=0; i < albumtrackslist.selectedItems.length; i++) { |
1168 | + trackQueue.model.append(makeDict(albumtrackslist.model.get(albumtrackslist.selectedItems[i], albumtrackslist.model.RoleModelData))); |
1169 | + } |
1170 | + |
1171 | + albumtrackslist.closeSelection() |
1172 | + } |
1173 | + }, |
1174 | + Action { |
1175 | + enabled: albumtrackslist.selectedItems.length > 0 |
1176 | + iconName: "delete" |
1177 | + text: i18n.tr("Delete") |
1178 | + visible: songStackPage.line1 === i18n.tr("Playlist") |
1179 | + onTriggered: { |
1180 | + for (var i=0; i < albumtrackslist.selectedItems.length; i++) { |
1181 | + Playlists.removeFromPlaylist(songStackPage.line2, albumtrackslist.selectedItems[i] - i) |
1182 | + } |
1183 | + |
1184 | + albumtrackslist.closeSelection() |
1185 | + |
1186 | + albumTracksModel.filterPlaylistTracks(songStackPage.line2) |
1187 | + playlistModel.filterPlaylists() |
1188 | + } |
1189 | + } |
1190 | + ] |
1191 | + PropertyChanges { |
1192 | + target: songStackPage.head |
1193 | + backAction: selectionState.backAction |
1194 | + actions: selectionState.actions |
1195 | + } |
1196 | } |
1197 | ] |
1198 | |
1199 | @@ -99,6 +170,36 @@ |
1200 | model: isAlbum ? songsModel : albumTracksModel.model |
1201 | objectName: "songspage-listview" |
1202 | width: parent.width |
1203 | + |
1204 | + // Requirements for ListItemWithActions |
1205 | + property var selectedItems: [] |
1206 | + |
1207 | + signal clearSelection() |
1208 | + signal closeSelection() |
1209 | + signal selectAll() |
1210 | + |
1211 | + onClearSelection: selectedItems = [] |
1212 | + onCloseSelection: { |
1213 | + clearSelection() |
1214 | + state = "normal" |
1215 | + } |
1216 | + onSelectAll: { |
1217 | + var tmp = selectedItems |
1218 | + |
1219 | + for (var i=0; i < model.count; i++) { |
1220 | + if (tmp.indexOf(i) === -1) { |
1221 | + tmp.push(i) |
1222 | + } |
1223 | + } |
1224 | + |
1225 | + selectedItems = tmp |
1226 | + } |
1227 | + onVisibleChanged: { |
1228 | + if (!visible) { |
1229 | + clearSelection(true) |
1230 | + } |
1231 | + } |
1232 | + |
1233 | header: BlurredHeader { |
1234 | rightColumn: Column { |
1235 | spacing: units.gu(2) |
1236 | @@ -238,15 +339,12 @@ |
1237 | |
1238 | ListItemWithActions { |
1239 | id: track |
1240 | - color: "transparent" |
1241 | objectName: "songsPageListItem" + index |
1242 | - iconFrame: false |
1243 | - progression: false |
1244 | - showDivider: false |
1245 | height: units.gu(6) |
1246 | |
1247 | leftSideAction: songStackPage.line1 === i18n.tr("Playlist") |
1248 | ? playlistRemoveAction.item : null |
1249 | + multiselectable: true |
1250 | reorderable: songStackPage.line1 === i18n.tr("Playlist") |
1251 | rightSideActions: [ |
1252 | AddToQueue { |
1253 | @@ -256,7 +354,6 @@ |
1254 | |
1255 | } |
1256 | ] |
1257 | - triggerActionOnMouseRelease: true |
1258 | |
1259 | onItemClicked: { |
1260 | trackClicked(albumtrackslist.model, index) // play track |
1261 | @@ -289,9 +386,6 @@ |
1262 | } |
1263 | } |
1264 | |
1265 | - // TODO: If http://pad.lv/1354753 is fixed to expose whether the Shape should appear pressed, update this as well. |
1266 | - onPressedChanged: musicRow.pressed = pressed |
1267 | - |
1268 | MusicRow { |
1269 | id: musicRow |
1270 | covers: [] |
1271 | |
1272 | === modified file 'music-app.qml' |
1273 | --- music-app.qml 2014-10-21 14:59:51 +0000 |
1274 | +++ music-app.qml 2014-10-21 21:53:07 +0000 |
1275 | @@ -594,7 +594,7 @@ |
1276 | property string lastfmusername |
1277 | property string lastfmpassword |
1278 | property string timestamp // used to scrobble |
1279 | - property var chosenElement: null |
1280 | + property var chosenElements: [] |
1281 | property bool toolbarShown: musicToolbar.visible |
1282 | property bool selectedAlbum: false |
1283 | |
1284 | @@ -875,7 +875,7 @@ |
1285 | } |
1286 | |
1287 | // Popover for tracks, queue and add to playlist, for example |
1288 | - Component { |
1289 | + Component { // TODO: needed anymore? remove? |
1290 | id: trackPopoverComponent |
1291 | Popover { |
1292 | id: trackPopover |
1293 | @@ -895,9 +895,12 @@ |
1294 | anchors.verticalCenter: parent.verticalCenter |
1295 | } |
1296 | onClicked: { |
1297 | - console.debug("Debug: Add track to queue: " + JSON.stringify(chosenElement)) |
1298 | + console.debug("Debug: Add track to queue: " + JSON.stringify(chosenElements)) |
1299 | PopupUtils.close(trackPopover) |
1300 | - trackQueue.append(chosenElement) |
1301 | + |
1302 | + for (var i=0; i < chosenElements.length; i++) { |
1303 | + trackQueue.append(chosenElements[i]) |
1304 | + } |
1305 | } |
1306 | } |
1307 | ListItem.Standard { |
PASSED: Continuous integration, rev:677 91.189. 93.70:8080/ job/music- app-remix- ci/128/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic- python3/ 1108 91.189. 93.70:8080/ job/generic- mediumtests- utopic- python3/ 1108/artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/music- app-remix- utopic- amd64-ci/ 128
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-remix- ci/128/ rebuild
http://