← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~ahayzen/music-app/refactor-use-sdk-listitems into lp:music-app

 

Andrew Hayzen has proposed merging lp:~ahayzen/music-app/refactor-use-sdk-listitems into lp:music-app with lp:~vthompson/music-app/music-uc1.3 as a prerequisite.

Commit message:
* Switch to using the new listitems within the SDK

Requested reviews:
  Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot): continuous-integration
  Andrew Hayzen (ahayzen)
Related bugs:
  Bug #1400551 in Ubuntu Music App: "[Music] When reordering, an item can be made to temporarily disappear"
  https://bugs.launchpad.net/music-app/+bug/1400551
  Bug #1472080 in Ubuntu Music App: "Select boxes display a little lag when quick swipe up/down in playlist"
  https://bugs.launchpad.net/music-app/+bug/1472080

For more details, see:
https://code.launchpad.net/~ahayzen/music-app/refactor-use-sdk-listitems/+merge/274829

* Switch to using the new listitems within the SDK

Note: this includes lp:~ahayzen/music-app/fix-child-page-freezes to ease testing otherwise you'll likely be able to freeze some views
-- 
Your team Music App Developers is subscribed to branch lp:music-app.
=== modified file 'app/components/BlurredHeader.qml'
--- app/components/BlurredHeader.qml	2015-10-18 18:16:18 +0000
+++ app/components/BlurredHeader.qml	2015-10-18 18:16:18 +0000
@@ -18,9 +18,8 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import Ubuntu.Components.ListItems 1.0 as ListItem
 
-ListItem.Standard {
+ListItem {
     width: parent.width
 
     property alias bottomColumn: bottomColumnLoader.sourceComponent

=== added file 'app/components/Delegates/ActionDelegate.qml'
--- app/components/Delegates/ActionDelegate.qml	1970-01-01 00:00:00 +0000
+++ app/components/Delegates/ActionDelegate.qml	2015-10-18 18:16:18 +0000
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2015
+ *      Andrew Hayzen <ahayzen@xxxxxxxxx>
+ *      Victor Thompson <victor.thompson@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.4
+import Ubuntu.Components 1.2
+
+Rectangle {
+    color: currentColor
+    width: height
+
+    Icon {
+        anchors {
+            centerIn: parent
+        }
+        objectName: action.objectName
+        color: pressed ? UbuntuColors.blue : styleMusic.common.white
+        name: action.iconName
+        height: units.gu(3)
+        width: units.gu(3)
+    }
+
+    Rectangle {  // FIXME: pad.lv/1507339 Workaround for gap between end of listitem and first action
+        anchors {
+            bottom: parent.bottom
+            right: parent.left
+            top: parent.top
+        }
+        color: currentColor
+        width: units.gu(0.5)
+    }
+}

=== removed file 'app/components/Delegates/ListItemWithActions.qml'
--- app/components/Delegates/ListItemWithActions.qml	2015-10-18 18:16:18 +0000
+++ app/components/Delegates/ListItemWithActions.qml	1970-01-01 00:00:00 +0000
@@ -1,507 +0,0 @@
-/*
- * Copyright (C) 2012-2015 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-import QtQuick 2.4
-import Ubuntu.Components 1.3
-import Ubuntu.Components.ListItems 1.0 as ListItem
-
-
-Item {
-    id: root
-    width: parent.width
-
-    property Action leftSideAction: null
-    property list<Action> rightSideActions
-    property double defaultHeight: units.gu(8)
-    property bool locked: false
-    property Action activeAction: null
-    property var activeItem: null
-    property bool triggerActionOnMouseRelease: false
-    property color color: styleMusic.mainView.backgroundColor
-    property color selectedColor: "#3d3d45"  // "#E6E6E6"  // CUSTOM
-    property bool selected: false
-    property bool selectionMode: false
-    property alias internalAnchors: mainContents.anchors
-    default property alias contents: mainContents.children
-
-    readonly property double actionWidth: units.gu(4)  // CUSTOM 5?
-    readonly property double leftActionWidth: units.gu(10)
-    readonly property double actionThreshold: actionWidth * 0.4
-    readonly property double threshold: 0.4
-    readonly property string swipeState: main.x == 0 ? "Normal" : main.x > 0 ? "LeftToRight" : "RightToLeft"
-    readonly property alias swipping: mainItemMoving.running
-    readonly property bool _showActions: mouseArea.pressed || swipeState != "Normal" || swipping
-
-    property alias _main: main  // CUSTOM
-    property alias pressed: mouseArea.pressed  // CUSTOM
-
-    /* internal */
-    property var _visibleRightSideActions: filterVisibleActions(rightSideActions)
-
-    signal itemClicked(var mouse)
-    signal itemPressAndHold(var mouse)
-
-    function returnToBoundsRTL(direction)
-    {
-        var actionFullWidth = actionWidth + units.gu(2)
-
-        // go back to normal state if swipping reverse
-        if (direction === "LTR") {
-            updatePosition(0)
-            return
-        } else if (!triggerActionOnMouseRelease) {
-            updatePosition(-rightActionsView.width + units.gu(2))
-            return
-        }
-
-        var xOffset = Math.abs(main.x)
-        var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length)
-        var newX = 0
-
-        if (index === _visibleRightSideActions.length) {
-            newX = -(rightActionsView.width - units.gu(2))
-        } else if (index >= 1) {
-            newX = -(actionFullWidth * index)
-        }
-
-        updatePosition(newX)
-    }
-
-    function returnToBoundsLTR(direction)
-    {
-        var finalX = leftActionWidth
-        if ((direction === "RTL") || (main.x <= (finalX * root.threshold)))
-            finalX = 0
-        updatePosition(finalX)
-    }
-
-    function returnToBounds(direction)
-    {
-        if (main.x < 0) {
-            returnToBoundsRTL(direction)
-        } else if (main.x > 0) {
-            returnToBoundsLTR(direction)
-        } else {
-            updatePosition(0)
-        }
-    }
-
-    function contains(item, point, marginX)
-    {
-        var itemStartX = item.x - marginX
-        var itemEndX = item.x + item.width + marginX
-        return (point.x >= itemStartX) && (point.x <= itemEndX) &&
-               (point.y >= item.y) && (point.y <= (item.y + item.height));
-    }
-
-    function getActionAt(point)
-    {
-        if (leftSideAction && contains(leftActionViewLoader.item, point, 0)) {
-            return leftSideAction
-        } else if (contains(rightActionsView, point, 0)) {
-            var newPoint = root.mapToItem(rightActionsView, point.x, point.y)
-            for (var i = 0; i < rightActionsRepeater.count; i++) {
-                var child = rightActionsRepeater.itemAt(i)
-                if (contains(child, newPoint, units.gu(1))) {
-                    return i
-                }
-            }
-        }
-        return -1
-    }
-
-    function updateActiveAction()
-    {
-        if (triggerActionOnMouseRelease &&
-            (main.x <= -(root.actionWidth + units.gu(2))) &&
-            (main.x > -(rightActionsView.width - units.gu(2)))) {
-            var actionFullWidth = actionWidth + units.gu(2)
-            var xOffset = Math.abs(main.x)
-            var index = Math.min(Math.floor(xOffset / actionFullWidth), _visibleRightSideActions.length)
-            index = index - 1
-            if (index > -1) {
-                root.activeItem = rightActionsRepeater.itemAt(index)
-                root.activeAction = root._visibleRightSideActions[index]
-            }
-        } else {
-            root.activeAction = null
-        }
-    }
-
-    function resetSwipe()
-    {
-        updatePosition(0)
-    }
-
-    function filterVisibleActions(actions)
-    {
-        var visibleActions = []
-        for(var i = 0; i < actions.length; i++) {
-            var action = actions[i]
-            if (action.visible) {
-                visibleActions.push(action)
-            }
-        }
-        return visibleActions
-    }
-
-    function updatePosition(pos)
-    {
-        if (!root.triggerActionOnMouseRelease && (pos !== 0)) {
-            mouseArea.state = pos > 0 ? "RightToLeft" : "LeftToRight"
-        } else {
-            mouseArea.state = ""
-        }
-        main.x = pos
-    }
-
-    // CUSTOM remove animation
-    SequentialAnimation {
-        id: removeAnimation
-
-        property var action
-
-        UbuntuNumberAnimation {
-            target: root
-            duration: UbuntuAnimation.BriskDuration
-            property: "height";
-            to: 0
-        }
-        ScriptAction {
-            script: removeAnimation.action.trigger()
-        }
-    }
-
-    states: [
-        State {
-            name: "select"
-            when: selectionMode || selected
-            PropertyChanges {
-                target: selectionIcon
-                source: Qt.resolvedUrl("../ListItemActions/CheckBox.qml")
-                anchors.leftMargin: units.gu(2)
-            }
-            PropertyChanges {
-                target: root
-                locked: true
-            }
-            PropertyChanges {
-                target: main
-                x: 0
-            }
-        }
-    ]
-
-    height: defaultHeight
-    //clip: height !== defaultHeight  // CUSTOM
-
-    Loader {  // CUSTOM
-        id: leftActionViewLoader
-        anchors {
-            top: parent.top
-            bottom: parent.bottom
-            right: main.left
-        }
-        asynchronous: true
-        sourceComponent: leftSideAction ? leftActionViewComponent : undefined
-    }
-
-    Component {  // CUSTOM
-        id: leftActionViewComponent
-
-        Rectangle {
-            id: leftActionView
-            width: root.leftActionWidth + actionThreshold
-            color: UbuntuColors.red
-
-            Icon {
-                id: leftActionIcon
-                anchors {
-                    centerIn: parent
-                    horizontalCenterOffset: actionThreshold / 2
-                }
-                objectName: "swipeDeleteAction"  // CUSTOM
-                name: leftSideAction && _showActions ? leftSideAction.iconName : ""
-                color: Theme.palette.selected.field
-                height: units.gu(3)
-                width: units.gu(3)
-            }
-        }
-    }
-
-    //Rectangle {
-    Item {  // CUSTOM
-       id: rightActionsView
-
-       anchors {
-           top: main.top
-           left: main.right
-           bottom: main.bottom
-       }
-       visible: _visibleRightSideActions.length > 0
-       width: rightActionsRepeater.count > 0 ? rightActionsRepeater.count * (root.actionWidth + units.gu(2)) + root.actionThreshold + units.gu(2) : 0
-       // color: "white"  // CUSTOM
-
-       Rectangle {  // CUSTOM
-           anchors {
-               bottom: parent.bottom
-               left: parent.left
-               top: parent.top
-           }
-           color: styleMusic.common.black
-           opacity: 0.7
-           width: parent.width + actionThreshold
-       }
-
-       Row {
-           anchors{
-               top: parent.top
-               left: parent.left
-               leftMargin: units.gu(2)
-               right: parent.right
-               rightMargin: units.gu(2)
-               bottom: parent.bottom
-           }
-           spacing: units.gu(2)
-           Repeater {
-               id: rightActionsRepeater
-
-               model: _showActions ? _visibleRightSideActions : []
-               Item {
-                   property alias image: img
-
-                   height: rightActionsView.height
-                   width: root.actionWidth
-
-                   Icon {
-                       id: img
-
-                       anchors.centerIn: parent
-                       objectName: rightSideActions[index].objectName  // CUSTOM
-                       width: units.gu(3)
-                       height: units.gu(3)
-                       name: modelData.iconName
-                       color: root.activeAction === modelData ? UbuntuColors.blue : styleMusic.common.white  // CUSTOM
-                   }
-               }
-           }
-       }
-    }
-
-    Rectangle {
-        id: main
-        objectName: "mainItem"
-
-        anchors {
-            top: parent.top
-            bottom: parent.bottom
-        }
-
-        width: parent.width
-        color: root.selected ? root.selectedColor : root.color
-
-        Loader {
-            id: selectionIcon
-
-            anchors {
-                left: main.left
-                verticalCenter: main.verticalCenter
-            }
-            asynchronous: true  // CUSTOM
-            width: (status === Loader.Ready) ? item.implicitWidth : 0
-            visible: (status === Loader.Ready) && (item.width === item.implicitWidth)
-
-            Behavior on width {
-                NumberAnimation {
-                    duration: UbuntuAnimation.SnapDuration
-                }
-            }
-        }
-
-        Item {
-            id: mainContents
-
-            anchors {
-                left: selectionIcon.right
-                //leftMargin: units.gu(2)  // CUSTOM
-                top: parent.top
-                //topMargin: units.gu(1)  // CUSTOM
-                right: parent.right
-                //rightMargin: units.gu(2)  // CUSTOM
-                bottom: parent.bottom
-                //bottomMargin: units.gu(1)  // CUSTOM
-            }
-        }
-
-        Behavior on x {
-            UbuntuNumberAnimation {
-                id: mainItemMoving
-
-                easing.type: Easing.OutElastic
-                duration: UbuntuAnimation.SlowDuration
-            }
-        }
-    }
-
-    SequentialAnimation {
-        id: triggerAction
-
-        property var currentItem: root.activeItem ? root.activeItem.image : null
-
-        running: false
-        ParallelAnimation {
-            UbuntuNumberAnimation {
-                target: triggerAction.currentItem
-                property: "opacity"
-                from: 1.0
-                to: 0.0
-                duration: UbuntuAnimation.SlowDuration
-                easing {type: Easing.InOutBack; }
-            }
-            UbuntuNumberAnimation {
-                target: triggerAction.currentItem
-                properties: "width, height"
-                from: units.gu(3)
-                to: root.actionWidth
-                duration: UbuntuAnimation.SlowDuration
-                easing {type: Easing.InOutBack; }
-            }
-        }
-        PropertyAction {
-            target: triggerAction.currentItem
-            properties: "width, height"
-            value: units.gu(3)
-        }
-        PropertyAction {
-            target: triggerAction.currentItem
-            properties: "opacity"
-            value: 1.0
-        }
-        ScriptAction {
-            script: {
-                root.activeAction.triggered(root)
-                mouseArea.state = ""
-            }
-        }
-        PauseAnimation {
-            duration: 500
-        }
-        UbuntuNumberAnimation {
-            target: main
-            property: "x"
-            to: 0
-        }
-    }
-
-    MouseArea {
-        id: mouseArea
-
-        property bool locked: root.locked || ((root.leftSideAction === null) && (root._visibleRightSideActions.count === 0))  // CUSTOM
-        property bool manual: false
-        property string direction: "None"
-        property real lastX: -1
-
-        anchors.fill: parent
-        drag {
-            target: locked ? null : main
-            axis: Drag.XAxis
-            minimumX: rightActionsView.visible ? -(rightActionsView.width) : 0
-            maximumX: leftSideAction ? leftActionViewLoader.item.width : 0
-            threshold: root.actionThreshold
-        }
-
-        states: [
-            State {
-                name: "LeftToRight"
-                PropertyChanges {
-                    target: mouseArea
-                    drag.maximumX: 0
-                }
-            },
-            State {
-                name: "RightToLeft"
-                PropertyChanges {
-                    target: mouseArea
-                    drag.minimumX: 0
-                }
-            }
-        ]
-
-        onMouseXChanged: {
-            var offset = (lastX - mouseX)
-            if (Math.abs(offset) <= root.actionThreshold) {
-                return
-            }
-            lastX = mouseX
-            direction = offset > 0 ? "RTL" : "LTR";
-        }
-
-        onPressed: {
-            lastX = mouse.x
-        }
-
-        onReleased: {
-            if (root.triggerActionOnMouseRelease && root.activeAction) {
-                triggerAction.start()
-            } else {
-                root.returnToBounds()
-                root.activeAction = null
-            }
-            lastX = -1
-            direction = "None"
-        }
-        onClicked: {
-            if (selectionMode) {  // CUSTOM - selecting a listitem should toggle selection if in selectionMode
-                selected = !selected
-                return
-            } else if (main.x === 0) {
-                root.itemClicked(mouse)
-            } else if (main.x > 0) {
-                var action = getActionAt(Qt.point(mouse.x, mouse.y))
-                if (action && action !== -1) {
-                    //action.triggered(root)
-                    removeAnimation.action = action  // CUSTOM - use our animation instead
-                    removeAnimation.start()  // CUSTOM
-                }
-            } else {
-                var actionIndex = getActionAt(Qt.point(mouse.x, mouse.y))
-
-                if (actionIndex !== -1 && actionIndex !== leftSideAction) {  // CUSTOM - can be leftAction
-                    root.activeItem = rightActionsRepeater.itemAt(actionIndex)
-                    root.activeAction = root.rightSideActions[actionIndex]
-                    triggerAction.start()
-                    return
-                }
-            }
-            root.resetSwipe()
-        }
-
-        onPositionChanged: {
-            if (mouseArea.pressed) {
-                updateActiveAction()
-
-                listItemSwiping(index)  // CUSTOM - tells other listitems to dismiss any swipe
-            }
-        }
-        onPressAndHold: {
-            if (main.x === 0) {
-                root.itemPressAndHold(mouse)
-            }
-        }
-
-        z: -1
-    }
-}

=== modified file 'app/components/Delegates/MusicListItem.qml'
--- app/components/Delegates/MusicListItem.qml	2015-10-18 18:16:18 +0000
+++ app/components/Delegates/MusicListItem.qml	2015-10-18 18:16:18 +0000
@@ -21,131 +21,66 @@
 import Ubuntu.Components 1.3
 import "../"
 
+ListItem {
+    color: styleMusic.mainView.backgroundColor
+    highlightColor: Qt.lighter(color, 1.2)
 
-ListItemWithActions {
-    id: root
+    // Store the currentColor so that actions can bind to it
+    property var currentColor: highlighted ? highlightColor : color
 
     property alias column: musicRow.column
     property alias imageSource: musicRow.imageSource
 
-    property int listItemIndex: index
     property bool multiselectable: false
-    property int previousListItemIndex: -1
     property bool reorderable: false
 
-    signal reorder(int from, int to)
-
-    onItemPressAndHold: {
+    signal itemClicked()
+
+    onClicked: {
+        if (selectMode) {
+            selected = !selected;
+        } else {
+            itemClicked()
+        }
+    }
+
+    onPressAndHold: {
+        // FIXME: pad.lv/1468100 drag a listitem with no leadingActions to right, then press and hold causes no signal
+
+        if (reorderable) {
+            ListView.view.ViewItems.dragMode = !ListView.view.ViewItems.dragMode
+        }
+
         if (multiselectable) {
-            selectionMode = true
-        }
-    }
-
-    onListItemIndexChanged: {
-        var i = parent.parent.selectedItems.lastIndexOf(previousListItemIndex)
-
-        if (i !== -1) {
-            parent.parent.selectedItems[i] = listItemIndex
-        }
-
-        previousListItemIndex = listItemIndex
-    }
-
-    onSelectedChanged: {
-        if (selectionMode) {
-            var tmp = parent.parent.selectedItems
-
-            if (selected) {
-                if (parent.parent.selectedItems.indexOf(listItemIndex) === -1) {
-                    tmp.push(listItemIndex)
-                    parent.parent.selectedItems = tmp
-                }
-            } else {
-                tmp.splice(parent.parent.selectedItems.indexOf(listItemIndex), 1)
-                parent.parent.selectedItems = tmp
-            }
-        }
-    }
-
-    onSelectionModeChanged: {
-        if (reorderable && selectionMode) {
-            resetSwipe()
-        }
-
-        for (var j=0; j < _main.children.length; j++) {
-            if (_main.children[j] !== actionReorderLoader) {
-                _main.children[j].anchors.rightMargin = reorderable && selectionMode ? actionReorderLoader.width + units.gu(2) : 0
-            }
-        }
-
-        parent.parent.state = selectionMode ? "multiselectable" : "normal"
-
-        if (!selectionMode) {
-            selected = false
-        }
-    }
-
-    /* Highlight the listitem on press */
-    Rectangle {
-        id: listItemBrighten
-        color: root.pressed ? styleMusic.common.white : "transparent"
-        opacity: 0.1
-        height: root.height
-        x: root.x - parent.x  // -parent.x due to selectionIcon in ListItemWithActions
-        width: root.width
-    }
-
-    /* Reorder Component */
-    Loader {
-        id: actionReorderLoader
-        active: reorderable && selectionMode && root.parent.parent.selectedItems.length === 0
-        anchors {
-            bottom: parent.bottom
-            right: parent.right
-            rightMargin: units.gu(1)
-            top: parent.top
-        }
-        asynchronous: true
-        source: "../ListItemReorderComponent.qml"
-    }
-
-    Item {
-        Connections {  // Only allow one ListItem to be swiping at any time
-            target: mainView
-            onListItemSwiping: {
-                if (i !== index) {
-                    root.resetSwipe();
-                }
-            }
-        }
-
-        Connections {  // Connections from signals in the ListView
-            target: root.parent.parent
-            onClearSelection: selected = false
-            onFlickingChanged: {
-                if (root.parent.parent.flicking) {
-                    root.resetSwipe()
-                }
-            }
-            onSelectAll: selected = true
-            onStateChanged: selectionMode = root.parent.parent.state === "multiselectable"
-        }
-    }
-
+            ListView.view.ViewItems.selectMode = !ListView.view.ViewItems.selectMode
+        }
+    }
+
+    divider {
+        visible: false
+    }
 
     MusicRow {
         id: musicRow
         anchors {
-            verticalCenter: parent.verticalCenter
-        }
-        height: parent.height
-    }
-
-    Component.onCompleted: {  // reload settings as delegates are destroyed
-        if (parent.parent.selectedItems.indexOf(index) !== -1) {
-            selected = true
-        }
-
-        selectionMode = root.parent.parent.state === "multiselectable"
+            fill: parent
+            // When not in selectMode we want a margin between the Image and the left edge
+            // when in selectMode the checkbox has its own margin so we don't want a double margin
+            leftMargin: selectMode ? 0 : units.gu(2)
+            rightMargin: selectMode ? 0 : units.gu(2)
+        }
+
+        // Animate margin changes so it isn't noticible
+        Behavior on anchors.leftMargin {
+            NumberAnimation {
+
+            }
+        }
+
+        Behavior on anchors.rightMargin {
+            NumberAnimation {
+
+            }
+        }
     }
 }

=== modified file 'app/components/Flickables/MultiSelectListView.qml'
--- app/components/Flickables/MultiSelectListView.qml	2015-10-18 18:16:18 +0000
+++ app/components/Flickables/MultiSelectListView.qml	2015-10-18 18:16:18 +0000
@@ -21,31 +21,50 @@
 import Ubuntu.Components 1.3
 
 MusicListView {
-    property var selectedItems: []
+    // Can't access ViewItems externally
+    // so we need to expose if in multiselect mode for the header states
+    state: ViewItems.selectMode ? "multiselectable" : "normal"
 
     signal clearSelection()
     signal closeSelection()
+    signal reorder(int from, int to)
     signal selectAll()
 
-    onClearSelection: selectedItems = []
+    onClearSelection: ViewItems.selectedIndices = []
     onCloseSelection: {
         clearSelection()
-        state = "normal"
+        ViewItems.selectMode = false
+        ViewItems.dragMode = false
     }
     onSelectAll: {
-        var tmp = selectedItems
+        var tmp = []
 
         for (var i=0; i < model.count; i++) {
-            if (tmp.indexOf(i) === -1) {
-                tmp.push(i)
-            }
+            tmp.push(i)
         }
 
-        selectedItems = tmp
-    }
-    onVisibleChanged: {
-        if (!visible) {
-            closeSelection()
+        ViewItems.selectedIndices = tmp
+    }
+
+    // Can't access ViewItems externally
+    // so for the header actions we need to expose the selectedIndices
+    function getSelectedIndices() {
+        var indicies = ViewItems.selectedIndices.slice();
+
+        indicies.sort();  // ensure indicies are in-order
+
+        return indicies;
+    }
+
+    ViewItems.selectMode: false
+    ViewItems.dragMode: false
+    ViewItems.onDragUpdated: {
+        // Only update the model when the listitem is dropped, not 'live'
+        if (event.status == ListItemDrag.Moving) {
+            event.accept = false
+        } else if (event.status == ListItemDrag.Dropped) {
+            model.move(event.from, event.to, 1);
+            reorder(event.from, event.to)
         }
     }
 }

=== modified file 'app/components/HeadState/MultiSelectHeadState.qml'
--- app/components/HeadState/MultiSelectHeadState.qml	2015-10-18 18:16:18 +0000
+++ app/components/HeadState/MultiSelectHeadState.qml	2015-10-18 18:16:18 +0000
@@ -18,6 +18,7 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
+import "../Flickables"
 
 PageHeadState {
     id: selectionState
@@ -26,7 +27,7 @@
             iconName: "select"
             text: i18n.tr("Select All")
             onTriggered: {
-                if (listview.selectedItems.length === listview.model.count) {
+                if (listview.getSelectedIndices().length === listview.model.count) {
                     listview.clearSelection()
                 } else {
                     listview.selectAll()
@@ -34,14 +35,15 @@
             }
         },
         Action {
-            enabled: listview !== null ? listview.selectedItems.length > 0 : false
+            enabled: listview !== null ? listview.getSelectedIndices().length > 0 : false
             iconName: "add-to-playlist"
             text: i18n.tr("Add to playlist")
             onTriggered: {
                 var items = []
+                var indicies = listview.getSelectedIndices();
 
-                for (var i=0; i < listview.selectedItems.length; i++) {
-                    items.push(makeDict(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData)));
+                for (var i=0; i < indicies.length; i++) {
+                    items.push(makeDict(listview.model.get(indicies[i], listview.model.RoleModelData)));
                 }
 
                 mainPageStack.push(Qt.resolvedUrl("../../ui/AddToPlaylist.qml"),
@@ -51,16 +53,17 @@
             }
         },
         Action {
-            enabled: listview !== null ? listview.selectedItems.length > 0 : false
+            enabled: listview !== null ? listview.getSelectedIndices().length > 0 : false
             iconName: "add"
             text: i18n.tr("Add to queue")
             visible: addToQueue
 
             onTriggered: {
                 var items = []
+                var indicies = listview.getSelectedIndices();
 
-                for (var i=0; i < listview.selectedItems.length; i++) {
-                    items.push(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData));
+                for (var i=0; i < indicies.length; i++) {
+                    items.push(listview.model.get(indicies[i], listview.model.RoleModelData));
                 }
 
                 trackQueue.appendList(items)
@@ -69,13 +72,13 @@
             }
         },
         Action {
-            enabled: listview !== null ? listview.selectedItems.length > 0 : false
+            enabled: listview !== null ? listview.getSelectedIndices().length > 0 : false
             iconName: "delete"
             text: i18n.tr("Delete")
             visible: removable
 
             onTriggered: {
-                removed(listview.selectedItems)
+                removed(listview.getSelectedIndices())
 
                 listview.closeSelection()
             }
@@ -85,10 +88,7 @@
     backAction: Action {
         text: i18n.tr("Cancel selection")
         iconName: "back"
-        onTriggered: {
-            listview.clearSelection()
-            listview.state = "normal"
-        }
+        onTriggered: listview.closeSelection()
     }
     head: thisPage.head
     name: "selection"
@@ -100,9 +100,9 @@
     }
 
     property bool addToQueue: true
-    property ListView listview
+    property MultiSelectListView listview
     property bool removable: false
     property Page thisPage
 
-    signal removed(var selectedItems)
+    signal removed(var selectedIndices)
 }

=== added file 'app/components/ListItemActions/AddToQueueAndPlaylist.qml'
--- app/components/ListItemActions/AddToQueueAndPlaylist.qml	1970-01-01 00:00:00 +0000
+++ app/components/ListItemActions/AddToQueueAndPlaylist.qml	2015-10-18 18:16:18 +0000
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015
+ *      Andrew Hayzen <ahayzen@xxxxxxxxx>
+ *      Victor Thompson <victor.thompson@xxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+import QtQuick 2.4
+import Ubuntu.Components 1.2
+import "../Delegates"
+
+ListItemActions {
+    actions: [
+        AddToQueue {
+
+        },
+        AddToPlaylist {
+        }
+    ]
+    delegate: ActionDelegate {
+
+    }
+}

=== removed file 'app/components/ListItemActions/CheckBox.qml'
--- app/components/ListItemActions/CheckBox.qml	2015-10-18 18:16:18 +0000
+++ app/components/ListItemActions/CheckBox.qml	1970-01-01 00:00:00 +0000
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2012-2015 Canonical, Ltd.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-import QtQuick 2.4
-import Ubuntu.Components 1.3
-
-CheckBox {
-    checked: root.selected
-    width: implicitWidth
-    // disable item mouse area to avoid conflicts with parent mouse area
-    __mouseArea.enabled: false
-}

=== modified file 'app/components/MusicRow.qml'
--- app/components/MusicRow.qml	2015-10-18 18:16:18 +0000
+++ app/components/MusicRow.qml	2015-10-18 18:16:18 +0000
@@ -22,12 +22,6 @@
 
 
 Row {
-    anchors {
-        left: parent.left
-        leftMargin: units.gu(2)
-        right: parent.right
-        rightMargin: units.gu(2)
-    }
     height: units.gu(7)
 
     property alias column: columnComponent.sourceComponent

=== modified file 'app/components/Queue.qml'
--- app/components/Queue.qml	2015-10-18 18:16:18 +0000
+++ app/components/Queue.qml	2015-10-18 18:16:18 +0000
@@ -37,9 +37,6 @@
     model: trackQueue.model
     objectName: "nowPlayingqueueList"
 
-    property int normalHeight: units.gu(6)
-    property int transitionDuration: 250  // transition length of animations
-
     onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks")
 
     delegate: MusicListItem {
@@ -62,41 +59,44 @@
                 text: model.author
             }
         }
-        height: queueList.normalHeight
+        leadingActions: ListItemActions {
+            actions: [
+                Remove {
+                    onTriggered: trackQueue.removeQueueList([index])
+                }
+            ]
+        }
+        multiselectable: true
         objectName: "nowPlayingListItem" + index
-        state: ""
-        leftSideAction: Remove {
-            onTriggered: trackQueue.removeQueueList([index])
-        }
-        multiselectable: true
         reorderable: true
-        rightSideActions: [
-            AddToPlaylist{
+        trailingActions: ListItemActions {
+            actions: [
+                AddToPlaylist {
+                }
+            ]
+            delegate: ActionDelegate {
+
             }
-        ]
+        }
 
         onItemClicked: {
             customdebug("File: " + model.filename) // debugger
             trackQueueClick(index);  // toggle track state
         }
-        onReorder: {
-            console.debug("Move: ", from, to);
-
-            trackQueue.model.move(from, to, 1);
-            Library.moveQueueItem(from, to);
-
-            // Maintain currentIndex with current song
-            if (from === player.currentIndex) {
-                player.currentIndex = to;
-            }
-            else if (from < player.currentIndex && to >= player.currentIndex) {
-                player.currentIndex -= 1;
-            }
-            else if (from > player.currentIndex && to <= player.currentIndex) {
-                player.currentIndex += 1;
-            }
-
-            queueIndex = player.currentIndex
+    }
+
+    onReorder: {
+        Library.moveQueueItem(from, to);
+
+        // Maintain currentIndex with current song
+        if (from === player.currentIndex) {
+            player.currentIndex = to;
+        } else if (from < player.currentIndex && to >= player.currentIndex) {
+            player.currentIndex -= 1;
+        } else if (from > player.currentIndex && to <= player.currentIndex) {
+            player.currentIndex += 1;
         }
+
+        queueIndex = player.currentIndex
     }
 }

=== modified file 'app/components/Walkthrough/Walkthrough.qml'
--- app/components/Walkthrough/Walkthrough.qml	2015-10-18 18:16:18 +0000
+++ app/components/Walkthrough/Walkthrough.qml	2015-10-18 18:16:18 +0000
@@ -22,7 +22,6 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import Ubuntu.Components.ListItems 1.0 as ListItem
 
 Page {
     id: walkthrough

=== modified file 'app/ui/AddToPlaylist.qml'
--- app/ui/AddToPlaylist.qml	2015-10-18 18:16:18 +0000
+++ app/ui/AddToPlaylist.qml	2015-10-18 18:16:18 +0000
@@ -20,7 +20,6 @@
 import QtMultimedia 5.0
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import Ubuntu.Components.ListItems 1.0 as ListItem
 import Ubuntu.Components.Popups 1.0
 import QtQuick.LocalStorage 2.0
 import "../logic/meta-database.js" as Library

=== modified file 'app/ui/ArtistView.qml'
--- app/ui/ArtistView.qml	2015-10-18 18:16:18 +0000
+++ app/ui/ArtistView.qml	2015-10-18 18:16:18 +0000
@@ -20,7 +20,6 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
 import Ubuntu.Components.Popups 1.0
-import Ubuntu.Components.ListItems 1.0 as ListItem
 import Ubuntu.MediaScanner 0.1
 import Ubuntu.Thumbnailer 0.1
 import QtQuick.LocalStorage 2.0

=== modified file 'app/ui/Artists.qml'
--- app/ui/Artists.qml	2015-10-18 18:16:18 +0000
+++ app/ui/Artists.qml	2015-10-18 18:16:18 +0000
@@ -20,7 +20,6 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
 import Ubuntu.Components.Popups 1.0
-import Ubuntu.Components.ListItems 1.0 as ListItem
 import Ubuntu.MediaScanner 0.1
 import Ubuntu.Thumbnailer 0.1
 import QtQuick.LocalStorage 2.0

=== modified file 'app/ui/NowPlaying.qml'
--- app/ui/NowPlaying.qml	2015-10-18 18:16:18 +0000
+++ app/ui/NowPlaying.qml	2015-10-18 18:16:18 +0000
@@ -128,7 +128,7 @@
                 // Remove the tracks from the queue
                 // Use slice() to copy the list
                 // so that the indexes don't change as they are removed
-                trackQueue.removeQueueList(selectedItems.slice())
+                trackQueue.removeQueueList(selectedIndices.slice())
             }
         }
     ]

=== modified file 'app/ui/Recent.qml'
--- app/ui/Recent.qml	2015-10-18 18:16:18 +0000
+++ app/ui/Recent.qml	2015-10-18 18:16:18 +0000
@@ -20,7 +20,6 @@
 import QtQuick 2.4
 import Ubuntu.Components 1.3
 import Ubuntu.Components.Popups 1.0
-import Ubuntu.Components.ListItems 1.0 as ListItem
 import Ubuntu.MediaScanner 0.1
 import Ubuntu.Thumbnailer 0.1
 import QtMultimedia 5.0

=== modified file 'app/ui/Songs.qml'
--- app/ui/Songs.qml	2015-10-18 18:16:18 +0000
+++ app/ui/Songs.qml	2015-10-18 18:16:18 +0000
@@ -65,7 +65,6 @@
             fill: parent
             topMargin: units.gu(2)
         }
-        highlightFollowsCurrentItem: false
         objectName: "trackstab-listview"
         model: SortFilterModel {
             id: songsModelFilter
@@ -113,12 +112,8 @@
             height: units.gu(7)
             imageSource: {"art": model.art}
             multiselectable: true
-            rightSideActions: [
-                AddToQueue {
-                },
-                AddToPlaylist {
-                }
-            ]
+            trailingActions: AddToQueueAndPlaylist {
+            }
 
             onItemClicked: {
                 if (songsPage.state === "search") {  // only play single track when searching

=== modified file 'app/ui/SongsView.qml'
--- app/ui/SongsView.qml	2015-10-18 18:16:18 +0000
+++ app/ui/SongsView.qml	2015-10-18 18:16:18 +0000
@@ -19,7 +19,6 @@
 
 import QtQuick 2.4
 import Ubuntu.Components 1.3
-import Ubuntu.Components.ListItems 1.0 as ListItem
 import Ubuntu.Components.Popups 1.0
 import Ubuntu.MediaScanner 0.1
 import Ubuntu.Thumbnailer 0.1
@@ -155,7 +154,7 @@
             thisPage: songStackPage
 
             onRemoved: {
-                Playlists.removeFromPlaylist(songStackPage.line2, selectedItems)
+                Playlists.removeFromPlaylist(songStackPage.line2, selectedIndices)
 
                 playlistChangedHelper()  // update recent/playlist models
 
@@ -315,18 +314,12 @@
                 }
             }
             height: units.gu(6)
-
-            leftSideAction: songStackPage.line1 === i18n.tr("Playlist")
+            leadingActions: songStackPage.line1 === i18n.tr("Playlist")
                             ? playlistRemoveAction.item : null
             multiselectable: true
             reorderable: songStackPage.line1 === i18n.tr("Playlist")
-            rightSideActions: [
-                AddToQueue {
-
-                },
-                AddToPlaylist {
-                }
-            ]
+            trailingActions: AddToQueueAndPlaylist {
+            }
 
             onItemClicked: {
                 trackClicked(albumtrackslist.model, index)  // play track
@@ -341,24 +334,21 @@
 
                 recentChangedHelper();
             }
-            onReorder: {
-                console.debug("Move: ", from, to);
-
-                Playlists.move(songStackPage.line2, from, to)
-
-                albumTracksModel.filterPlaylistTracks(songStackPage.line2)
-            }
 
             Loader {
                 id: playlistRemoveAction
-                sourceComponent: Remove {
-                    onTriggered: {
-                        Playlists.removeFromPlaylist(songStackPage.line2, [model.i])
-
-                        playlistChangedHelper()  // update recent/playlist models
-
-                        albumTracksModel.filterPlaylistTracks(songStackPage.line2)
-                    }
+                sourceComponent: ListItemActions {
+                    actions: [
+                        Remove {
+                            onTriggered: {
+                                Playlists.removeFromPlaylist(songStackPage.line2, [model.i])
+
+                                playlistChangedHelper()  // update recent/playlist models
+
+                                albumTracksModel.filterPlaylistTracks(songStackPage.line2)
+                            }
+                        }
+                    ]
                 }
             }
 
@@ -370,6 +360,14 @@
                 }
             }
         }
+
+        onReorder: {
+            console.debug("Move: ", from, to);
+
+            Playlists.move(songStackPage.line2, from, to)
+
+            albumTracksModel.filterPlaylistTracks(songStackPage.line2)
+        }
     }
 
     Component.onCompleted: loaded = true

=== modified file 'debian/changelog'
--- debian/changelog	2015-10-18 18:16:18 +0000
+++ debian/changelog	2015-10-18 18:16:18 +0000
@@ -6,6 +6,9 @@
   [ Victor Thompson ]
   * Remove some deprecated code for the UbuntuShape image property.
 
+  [ Andrew Hayzen ]
+  * Switch to using the new listitems within the SDK 
+
  -- Bartosz Kosiorek <gang65@xxxxxxxxxxxxxx>  Tue, 08 Sep 2015 10:08:49 +0200
 
 music-app (2.2ubuntu1) vivid; urgency=medium

=== modified file 'tests/autopilot/music_app/__init__.py'
--- tests/autopilot/music_app/__init__.py	2015-05-04 14:07:05 +0000
+++ tests/autopilot/music_app/__init__.py	2015-10-18 18:16:18 +0000
@@ -6,7 +6,9 @@
 # by the Free Software Foundation.
 
 """music-app tests and emulators - top level package."""
-from ubuntuuitoolkit import MainView, UbuntuUIToolkitCustomProxyObjectBase
+from ubuntuuitoolkit import (
+    MainView, UbuntuUIToolkitCustomProxyObjectBase, UCListItem
+)
 
 
 class MusicAppException(Exception):
@@ -383,42 +385,20 @@
         now_playing_page.visible.wait_for(True)
 
 
-class MusicListItem(UbuntuUIToolkitCustomProxyObjectBase):
-    @click_object
+class MusicListItem(UCListItem):
     def click_add_to_playlist_action(self):
-        return self.wait_select_single(objectName="addToPlaylistAction")
+        return self.trigger_trailing_action("addToPlaylistAction")
 
-    @click_object
     def click_add_to_queue_action(self):
-        return self.wait_select_single(objectName="addToQueueAction")
+        return self.trigger_trailing_action("addToQueueAction")
 
-    @click_object
-    def confirm_removal(self):
-        return self.wait_select_single(objectName="swipeDeleteAction")
+    def click_remove_action(self):
+        return self.trigger_leading_action("swipeDeleteAction",
+                                           self.wait_until_destroyed)
 
     def get_label_text(self, name):
         return self.wait_select_single(objectName=name).text
 
-    def swipe_reveal_actions(self):
-        x, y, width, height = self.globalRect
-        start_x = x + (width * 0.8)
-        stop_x = x + (width * 0.2)
-        start_y = stop_y = y + (height // 2)
-
-        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
-
-        self.swipping.wait_for(False)
-
-    def swipe_to_delete(self):
-        x, y, width, height = self.globalRect
-        start_x = x + (width * 0.2)
-        stop_x = x + (width * 0.8)
-        start_y = stop_y = y + (height // 2)
-
-        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
-
-        self.swipping.wait_for(False)
-
 
 class Dialog(UbuntuUIToolkitCustomProxyObjectBase):
     @click_object

=== modified file 'tests/autopilot/music_app/tests/test_music.py'
--- tests/autopilot/music_app/tests/test_music.py	2015-04-29 00:55:02 +0000
+++ tests/autopilot/music_app/tests/test_music.py	2015-10-18 18:16:18 +0000
@@ -79,7 +79,6 @@
 
         # get track item to swipe and queue
         track = self.app.get_songs_view().get_track(0)
-        track.swipe_reveal_actions()
 
         # add track to the queue
         track.click_add_to_queue_action()
@@ -206,8 +205,6 @@
 
         # get track row and swipe to reveal actions
         track = tracks_page.get_track(i)
-        track.swipe_reveal_actions()
-
         track.click_add_to_queue_action()  # add track to queue
 
         # wait for the player index to change
@@ -344,8 +341,6 @@
         songs_page = self.app.get_songs_view()
 
         track = songs_page.get_track(0)
-        track.swipe_reveal_actions()
-
         track.click_add_to_queue_action()  # add track to the queue
 
         # verify track queue has added one to initial value
@@ -417,8 +412,6 @@
 
         # get track row and swipe to reveal actions
         track = tracks_page.get_track(0)
-        track.swipe_reveal_actions()
-
         track.click_add_to_queue_action()  # add track to queue
 
         # verify track queue has added all songs to initial value
@@ -452,8 +445,6 @@
 
         # get track row and swipe to reveal actions
         track = tracks_page.get_track(0)
-        track.swipe_reveal_actions()
-
         track.click_add_to_playlist_action()  # add track to queue
 
         add_to_playlist_page = self.app.get_add_to_playlist_page()
@@ -601,9 +592,7 @@
 
         # get track row and swipe to reveal swipe to delete
         track = now_playing_page.get_track(0)
-        track.swipe_to_delete()
-
-        track.confirm_removal()  # confirm delete
+        track.click_remove_action()
 
         # verify song has been deleted
         self.assertThat(self.app.get_queue_count(),


Follow ups