Commit 5d8c2630 authored by Tranter Madi's avatar Tranter Madi 🌧 Committed by Nate Graham
Browse files

Make more use of Kirigami stuff

- Use Kirigami stuff instead of handmade ones.
- `alternativeBackground` should only be used when section is not used.

BUG: 448461
BUG: 447984
CCBUG: 434437
FIXED-IN: 22.04
parent ab0c2b2b
Pipeline #140669 passed with stage
in 5 minutes and 18 seconds
......@@ -400,7 +400,6 @@ if (Qt5Quick_FOUND AND Qt5Widgets_FOUND)
qml/LabelWithToolTip.qml
qml/RatingStar.qml
qml/DraggableItem.qml
qml/TrackImportNotification.qml
qml/ImageWithFallback.qml
......
......@@ -7,24 +7,20 @@
import QtQuick 2.7
import QtQuick.Layouts 1.2
import QtQuick.Controls 2.3
import org.kde.kirigami 2.5 as Kirigami
import org.kde.kirigami 2.10 as Kirigami
import org.kde.elisa 1.0
import QtQuick 2.0
Rectangle {
id: background
Kirigami.ListSectionHeader {
property var headerData
property string album: headerData[0]
property string albumArtist: headerData[1]
property url imageUrl: headerData[2]
property alias backgroundColor: background.color
implicitHeight: contentLayout.implicitHeight
color: myPalette.midlight
height: contentLayout.implicitHeight
padding: 0
RowLayout {
id: contentLayout
......
......@@ -311,8 +311,6 @@ RowLayout {
MediaPlayListView {
id: playList
Layout.fillHeight: true
onStartPlayback: ElisaApplication.audioControl.ensurePlay()
onPausePlayback: ElisaApplication.audioControl.playPause()
}
states: [
......
/*
SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr>
SPDX-FileCopyrightText: 2016 (c) Aurélien Gâteau <mail@agateau.com>
SPDX-License-Identifier: LGPL-3.0-or-later
*/
/*
* listviewdragitem
*
* An example of reordering items in a ListView via drag'n'drop.
*
* Author: Aurélien Gâteau
* License: BSD
*/
import QtQuick 2.7
FocusScope {
id: root
default property alias contentItem: dragArea.contentItem
// This item will become the parent of the dragged item during the drag operation
property Item draggedItemParent
signal moveItemRequested(int from, int to)
// Size of the area at the top and bottom of the list where drag-scrolling happens
property int scrollEdgeSize: 6
// Internal: set to -1 when drag-scrolling up and 1 when drag-scrolling down
property int _scrollingDirection: 0
// Internal: shortcut to access the attached ListView from everywhere. Shorter than root.ListView.view
property ListView _listView: ListView.view
property alias containsMouse: dragArea.containsMouse
signal clicked()
signal doubleClicked()
width: contentItem.width
height: topPlaceholder.height + wrapperParent.height + bottomPlaceholder.height
property int placeholderHeight
// Make contentItem a child of contentItemWrapper
onContentItemChanged: {
contentItem.parent = dragArea;
}
Rectangle {
id: topPlaceholder
anchors {
left: parent.left
right: parent.right
top: parent.top
}
height: 0
color: myPalette.mid
}
Item {
id: wrapperParent
anchors {
left: parent.left
right: parent.right
top: topPlaceholder.bottom
}
height: contentItem.height
Item {
id: contentItemWrapper
anchors.fill: parent
Drag.active: dragArea.drag.active
Drag.hotSpot {
x: contentItem.width / 2
y: contentItem.height / 2
}
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: parent
// Disable smoothed so that the Item pixel from where we started the drag remains under the mouse cursor
drag.smoothed: false
property Item contentItem
hoverEnabled: true
preventStealing: true
acceptedButtons: Qt.LeftButton
onReleased: {
if (drag.active) {
emitMoveItemRequested();
}
}
onClicked: root.clicked()
onDoubleClicked: root.doubleClicked()
}
}
}
Rectangle {
id: bottomPlaceholder
anchors {
left: parent.left
right: parent.right
top: wrapperParent.bottom
}
height: 0
color: myPalette.mid
}
SmoothedAnimation {
id: upAnimation
target: _listView
property: "contentY"
to: 0
running: _scrollingDirection == -1
}
SmoothedAnimation {
id: downAnimation
target: _listView
property: "contentY"
to: _listView.contentHeight - _listView.height
running: _scrollingDirection == 1
}
Loader {
id: topDropAreaLoader
active: model.index === 0
anchors {
left: parent.left
right: parent.right
bottom: wrapperParent.verticalCenter
}
height: placeholderHeight
sourceComponent: Component {
DropArea {
property int dropIndex: 0
}
}
}
DropArea {
id: bottomDropArea
anchors {
left: parent.left
right: parent.right
top: wrapperParent.verticalCenter
}
property bool isLast: model.index === _listView.count - 1
height: isLast ? _listView.contentHeight - y : placeholderHeight
property int dropIndex: model.index + 1
}
states: [
State {
when: dragArea.drag.active
name: "dragging"
ParentChange {
target: contentItemWrapper
parent: draggedItemParent
}
PropertyChanges {
target: contentItemWrapper
opacity: 0.9
anchors.fill: undefined
width: contentItem.width
height: contentItem.height
}
PropertyChanges {
target: wrapperParent
height: 0
}
PropertyChanges {
target: root
_scrollingDirection: {
var yCoord = _listView.mapFromItem(dragArea, 0, dragArea.mouseY).y;
if (yCoord < scrollEdgeSize) {
-1;
} else if (yCoord > _listView.height - scrollEdgeSize) {
1;
} else {
0;
}
}
}
},
State {
when: bottomDropArea.containsDrag
name: "droppingBelow"
PropertyChanges {
target: bottomPlaceholder
height: placeholderHeight
}
PropertyChanges {
target: bottomDropArea
height: contentItem.height
}
},
State {
when: topDropAreaLoader.item && topDropAreaLoader.item.containsDrag
name: "droppingAbove"
PropertyChanges {
target: topPlaceholder
height: placeholderHeight
}
PropertyChanges {
target: topDropAreaLoader
height: contentItem.height
}
}
]
function emitMoveItemRequested() {
var dropArea = contentItemWrapper.Drag.target;
if (!dropArea) {
return;
}
var dropIndex = dropArea.dropIndex;
// If the target item is below us, then decrement dropIndex because the target item is going to move up when
// our item leaves its place
if (model.index < dropIndex) {
dropIndex--;
}
if (model.index === dropIndex) {
return;
}
root.moveItemRequested(model.index, dropIndex);
// Scroll the ListView to ensure the dropped item is visible. This is required when dropping an item after the
// last item of the view. Delay the scroll using a Timer because we have to wait until the view has moved the
// item before we can scroll to it.
makeDroppedItemVisibleTimer.start();
}
Timer {
id: makeDroppedItemVisibleTimer
interval: 0
onTriggered: {
_listView.positionViewAtIndex(model.index, ListView.Contain);
}
}
}
......@@ -43,8 +43,6 @@ Kirigami.ApplicationWindow {
enabled: true
MediaPlayListView {
anchors.fill: parent
onStartPlayback: ElisaApplication.audioControl.ensurePlay()
onPausePlayback: ElisaApplication.audioControl.playPause()
}
}
......
......@@ -319,7 +319,6 @@ FocusScope {
Loader {
id: playLoader
active: headerBar.isMaximized
visible: headerBar.isMaximized
Layout.fillWidth: true
Layout.fillHeight: true
......@@ -327,8 +326,7 @@ FocusScope {
Layout.topMargin: Kirigami.Units.largeSpacing
sourceComponent: SimplePlayListView {
anchors.fill: parent
playListModel: ElisaApplication.mediaPlayListProxyModel
model: ElisaApplication.mediaPlayListProxyModel
}
}
......
......@@ -21,9 +21,6 @@ import "mobile"
Kirigami.Page {
id: topItem
signal startPlayback()
signal pausePlayback()
// set by the respective mobile/desktop view
property var playListNotification
property var playListView
......@@ -95,6 +92,7 @@ Kirigami.Page {
// ========== desktop listview ==========
Component {
id: desktopListView
ScrollView {
property alias list: playListView
......@@ -104,6 +102,8 @@ Kirigami.Page {
contentItem: ListView {
id: playListView
signal moveItemRequested(int oldIndex, int newIndex)
focus: true
clip: true
keyNavigationEnabled: true
......@@ -122,6 +122,62 @@ Kirigami.Page {
width: playListView.width
}
model: ElisaApplication.mediaPlayListProxyModel
onCurrentIndexChanged: {
if (currentItem) {
currentItem.entry.forceActiveFocus()
}
}
delegate: Item {
property alias entry: entry
width: entry.width
height: entry.height
// ListItemDragHandle requires listItem
// to be a child of delegate
PlayListEntry {
id: entry
width: playListView.width
index: model.index
isSelected: playListView.currentIndex === index
databaseId: model.databaseId ? model.databaseId : 0
entryType: model.entryType ? model.entryType : ElisaUtils.Unknown
title: model.title ? model.title : ''
artist: model.artist ? model.artist : ''
album: model.album ? model.album : ''
albumArtist: model.albumArtist ? model.albumArtist : ''
duration: model.duration ? model.duration : ''
fileName: model.trackResource ? model.trackResource : ''
imageUrl: model.imageUrl ? model.imageUrl : ''
trackNumber: model.trackNumber ? model.trackNumber : -1
discNumber: model.discNumber ? model.discNumber : -1
rating: model.rating ? model.rating : 0
isSingleDiscAlbum: model.isSingleDiscAlbum !== undefined ? model.isSingleDiscAlbum : true
isValid: model.isValid
isPlaying: model.isPlaying
metadataModifiableRole: model ? model.metadataModifiableRole : false
listView: playListView
}
}
onCountChanged: if (count === 0) {
currentIndex = -1;
}
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
width: parent.width - (Kirigami.Units.largeSpacing * 4)
text: i18n("Playlist is empty")
explanation: i18n("Add some songs to get started. You can browse your music using the views on the left.")
visible: playListView.count === 0
}
/* currently disabled animations due to display corruption
because of https://bugreports.qt.io/browse/QTBUG-49868
causing https://bugs.kde.org/show_bug.cgi?id=406524
......@@ -157,155 +213,6 @@ Kirigami.Page {
easing.type: Easing.InOutQuad }
}
*/
model: DelegateModel {
model: ElisaApplication.mediaPlayListProxyModel
groups: [
DelegateModelGroup { name: "selected" }
]
delegate: DraggableItem {
id: item
width: playListView.width
placeholderHeight: elisaTheme.dragDropPlaceholderHeight
focus: true
PlayListEntry {
id: entry
focus: true
width: parent.width
index: model.index
isAlternateColor: item.DelegateModel.itemsIndex % 2
isSelected: playListView.currentIndex === index
containsMouse: item.containsMouse
databaseId: model.databaseId ? model.databaseId : 0
entryType: model.entryType ? model.entryType : ElisaUtils.Unknown
title: model.title ? model.title : ''
artist: model.artist ? model.artist : ''
album: model.album ? model.album : ''
albumArtist: model.albumArtist ? model.albumArtist : ''
duration: model.duration ? model.duration : ''
fileName: model.trackResource ? model.trackResource : ''
imageUrl: model.imageUrl ? model.imageUrl : ''
trackNumber: model.trackNumber ? model.trackNumber : -1
discNumber: model.discNumber ? model.discNumber : -1
rating: model.rating ? model.rating : 0
isSingleDiscAlbum: model.isSingleDiscAlbum !== undefined ? model.isSingleDiscAlbum : true
isValid: model.isValid
isPlaying: model.isPlaying
metadataModifiableRole: model ? model.metadataModifiableRole : false
onStartPlayback: topItem.startPlayback()
onPausePlayback: topItem.pausePlayback()
onRemoveFromPlaylist: ElisaApplication.mediaPlayListProxyModel.removeRow(trackIndex)
onSwitchToTrack: ElisaApplication.mediaPlayListProxyModel.switchTo(trackIndex)
onActiveFocusChanged: {
if (activeFocus && playListView.currentIndex !== index) {
playListView.currentIndex = index
}
}
}
draggedItemParent: playListView
onClicked: {
playListView.currentIndex = index
entry.forceActiveFocus()
}
onDoubleClicked: {
if (model.isValid) {
ElisaApplication.mediaPlayListProxyModel.switchTo(model.index)
topItem.startPlayback()
}
}
onMoveItemRequested: {
ElisaApplication.mediaPlayListProxyModel.moveRow(from, to);
}
}
}
onCountChanged: if (count === 0) {
currentIndex = -1;
}
Kirigami.PlaceholderMessage {
anchors.centerIn: parent
width: parent.width - (Kirigami.Units.largeSpacing * 4)
text: i18n("Playlist is empty")
explanation: i18n("Add some songs to get started. You can browse your music using the views on the left.")
visible: playListView.count === 0
}
}
}
}
// ========== mobile delegate ==========
Component {
id: mobileDelegateComponent
MobilePlayListDelegate {
property var model
width: parent ? parent.width : topItem.width
index: model ? model.index : 0
isAlternateColor: playListView.currentIndex % 2
isSelected: playListView.currentIndex === index
databaseId: model && model.databaseId ? model.databaseId : 0
entryType: model && model.entryType ? model.entryType : ElisaUtils.Unknown
title: model ? model.title || '' : ''
artist: model ? model.artist || '' : ''
album: model ? model.album || '' : ''
albumArtist: model ? model.albumArtist || '' : ''
duration: model ? model.duration || '' : ''
fileName: model ? model.trackResource || '' : ''
imageUrl: model ? model.imageUrl || '' : ''
trackNumber: model ? model.trackNumber || -1 : -1
discNumber: model ? model.discNumber || -1 : -1
rating: model ? model.rating || 0 : 0
isSingleDiscAlbum: model && model.isSingleDiscAlbum !== undefined ? model.isSingleDiscAlbum : true
isValid: model && model.isValid
isPlaying: model ? model.isPlaying : false
metadataModifiableRole: model ? model.metadataModifiableRole : false
hideDiscNumber: model && model.isSingleDiscAlbum
listView: playListView
onStartPlayback: topItem.startPlayback()
onPausePlayback: topItem.pausePlayback()
onRemoveFromPlaylist: ElisaApplication.mediaPlayListProxyModel.removeRow(trackIndex)
onSwitchToTrack: ElisaApplication.mediaPlayListProxyModel.switchTo(trackIndex)
onActiveFocusChanged: {
if (activeFocus && playListView.currentIndex !== index) {
playListView.currentIndex = index
}
}
onClicked: {
playListView.currentIndex = index
forceActiveFocus()
if (model.isValid) {
if (model.isPlaying === MediaPlayList.IsPlaying) {
topItem.pausePlayback()
} else {
ElisaApplication.mediaPlayListProxyModel.switchTo(model.index)
topItem.startPlayback()
}
}
}
onMoveItemRequested: {
ElisaApplication.mediaPlayListProxyModel.moveRow(from, to);
}
}
}
......@@ -313,13 +220,14 @@ Kirigami.Page {
// ========== mobile listview ==========
Component {
id: mobileListView
ScrollView {
property alias list: playListView
contentItem: ListView {
id: playListView
anchors.fill: parent
reuseItems: true
reuseItems: true
model: ElisaApplication.mediaPlayListProxyModel
moveDisplaced: Transition {
......@@ -341,13 +249,44 @@ Kirigami.Page {
text: xi18nc("@info", "Your playlist is empty.")
}
delegate: Loader {
// apparently it's possible for parent to be null, set to undefined to ignore warning
anchors.left: parent ? parent.left : undefined
anchors.right: parent ? parent.right : undefined
sourceComponent: mobileDelegateComponent
onLoaded: {
item.model = model;
delegate: Item {
width: entry.width
height: entry.height
// ListItemDragHandle requires listItem
// to be a child of delegate
MobilePlayListDelegate {
id: entry
width: playListView.width
index: model ? model.index : 0
isSelected: playListView.currentIndex === index
databaseId