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

Improve playlist button handling

- Avoid the label overlapping the hovering buttons when the width of
the playlist is small enough and the user clicks the play button
- Collapse button row into a menu when playlist is very narrow
- Use better icon for "remove"
- Remove some unneeded code

CCBUG: 434437
FIXED-IN: 22.04
parent f4355463
Pipeline #146682 passed with stage
in 4 minutes and 23 seconds
......@@ -51,6 +51,11 @@ Item {
readonly property alias sectionHeight: sectionSizer.implicitHeight
readonly property alias toolButtonHeight: button.height
readonly property alias trackNumberWidth: trackNumber.width
readonly property alias durationWidth: duration.width
readonly property int playListEntryMinWidth: button.width * 6 + duration.width + trackNumber.width * 2
// calculate a fixed height for playlist's section delegates
// workaround for QTBUG-52595
Column {
......@@ -60,4 +65,21 @@ Item {
LabelWithToolTip { text: "M\nM"; level: 2 }
LabelWithToolTip { text: "M" }
}
// get height of buttons inside loaders
FlatButtonWithToolTip {
id: button
visible: false
icon.name: "document-open-folder"
}
TextMetrics {
id: trackNumber
text: '99/9'
font.bold: true
}
TextMetrics {
id: duration
text: '0:00:00'
font.bold: true
}
}
......@@ -304,12 +304,15 @@ RowLayout {
Kirigami.Separator {
id: playListSeparatorItem
visible: false
Layout.fillHeight: true
}
// playlist right sidebar
MediaPlayListView {
id: playList
Layout.preferredWidth: 0
Layout.fillWidth: false
Layout.fillHeight: true
}
......@@ -317,17 +320,6 @@ RowLayout {
State {
name: "smallScreen"
when: mainWindow.width < elisaTheme.viewSelectorSmallSizeThreshold
PropertyChanges {
target: playList
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
visible: false
}
PropertyChanges {
target: playListSeparatorItem
visible: false
}
PropertyChanges {
target: playlistDrawer
modal: true
......@@ -338,16 +330,6 @@ RowLayout {
State {
name: "wideScreenNoPlaylist"
when: mainWindow.width >= elisaTheme.viewSelectorSmallSizeThreshold && contentViewContainer.showPlaylist === false
PropertyChanges {
target: playList
Layout.minimumWidth: 0
Layout.maximumWidth: 0
Layout.preferredWidth: 0
}
PropertyChanges {
target: playListSeparatorItem
visible: false
}
PropertyChanges {
target: playlistDrawer
collapsed: true
......@@ -361,8 +343,6 @@ RowLayout {
when: mainWindow.width >= elisaTheme.viewSelectorSmallSizeThreshold && contentViewContainer.showPlaylist === true
PropertyChanges {
target: playList
Layout.minimumWidth: contentViewContainer.width * 0.28
Layout.maximumWidth: contentViewContainer.width * 0.28
Layout.preferredWidth: contentViewContainer.width * 0.28
}
PropertyChanges {
......@@ -381,7 +361,7 @@ RowLayout {
]
transitions: Transition {
NumberAnimation {
properties: "Layout.minimumWidth, Layout.maximumWidth, Layout.preferredWidth, opacity"
property: "Layout.preferredWidth"
easing.type: Easing.InOutQuad
duration: Kirigami.Units.longDuration
}
......
......@@ -18,6 +18,9 @@ BasePlayListDelegate {
id: playListEntry
property bool editingRating: false
// wideMode means there is enough room for the button row
// otherwise display a menu button
readonly property bool wideMode: width >= elisaTheme.playListEntryMinWidth
Accessible.role: Accessible.ListItem
Accessible.name: title + ' ' + album + ' ' + artist
......@@ -33,7 +36,7 @@ BasePlayListDelegate {
contentItem: Item {
implicitWidth: playListEntry.width
implicitHeight: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
implicitHeight: Math.max(Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2, elisaTheme.toolButtonHeight)
Loader {
id: metadataLoader
......@@ -53,6 +56,76 @@ BasePlayListDelegate {
}
}
Loader {
id: actionsLoader
active: false
sourceComponent: QtObject {
property var locateFileAction: Action {
text: i18nc("Show the file for this song in the file manager", "Show in folder")
icon.name: "document-open-folder"
onTriggered: {
ElisaApplication.showInFolder(playListEntry.fileName)
}
}
property var infoAction: Action {
text: i18nc("Show track metadata", "View Details")
icon.name: "help-about"
onTriggered: {
if (metadataLoader.active === false) {
metadataLoader.active = true
}
else {
metadataLoader.item.close();
metadataLoader.active = false
}
}
}
property var ratingAction: Action {
text: i18nc("Show track rating", "Set track rating")
icon.name: "view-media-favorite"
onTriggered: {
playListEntry.editingRating = true;
}
}
property var favoriteAction: Action {
text: rating == 10 ? i18n("Un-mark this song as a favorite") : i18n("Mark this song as a favorite")
icon.name: rating == 10 ? "rating" : "rating-unrated"
onTriggered: {
var newRating = 0;
if (rating == 10) {
newRating = 0;
// Change icon immediately in case backend is slow
icon.name = "rating-unrated";
} else {
newRating = 10;
// Change icon immediately in case backend is slow
icon.name = "rating";
}
ElisaApplication.musicManager.updateSingleFileMetaData(playListEntry.fileName, DataTypes.RatingRole, newRating);
}
}
property var playPauseAction: Action {
text: (isPlaying === MediaPlayList.IsPlaying) ? i18nc("Pause current track from play list", "Pause") : i18nc("Play this track from play list", "Play")
icon.name: (isPlaying === MediaPlayList.IsPlaying) ? "media-playback-pause" : "media-playback-start"
onTriggered: if (isPlaying === MediaPlayList.IsPlaying) {
playListEntry.pausePlayback()
} else if (isPlaying === MediaPlayList.IsPaused) {
playListEntry.startPlayback()
} else {
playListEntry.switchToTrack(playListEntry.index)
playListEntry.startPlayback()
}
}
property var removeAction: Action {
text: i18nc("Remove current track from play list", "Remove")
icon.name: "edit-delete-remove"
onTriggered: playListEntry.removeFromPlaylist(playListEntry.index)
}
}
}
RowLayout {
id: trackRow
......@@ -71,12 +144,7 @@ BasePlayListDelegate {
// Container for the play/pause icon and the track/disc label
Item {
TextMetrics {
id: fakeLabel
text: '99/9'
}
Layout.preferredWidth: fakeLabel.width
Layout.preferredWidth: elisaTheme.trackNumberWidth
Layout.preferredHeight: parent.height
Layout.leftMargin: !LayoutMirroring.enabled ? Kirigami.Units.smallSpacing : 0
Layout.rightMargin: LayoutMirroring.enabled ? Kirigami.Units.smallSpacing : 0
......@@ -128,146 +196,67 @@ BasePlayListDelegate {
}
LabelWithToolTip {
id: mainCompactLabel
text: title
font.weight: (isPlaying ? Font.Bold : Font.Normal)
Layout.fillWidth: true
font.weight: isPlaying ? Font.Bold : Font.Normal
visible: isValid
elide: Text.ElideRight
horizontalAlignment: Text.AlignLeft
}
LabelWithToolTip {
id: mainInvalidCompactLabel
text: title
Layout.fillWidth: true
visible: !isValid
elide: Text.ElideRight
Layout.preferredHeight: playListEntry.height
}
// button row
Loader {
id: hoverLoader
active: false
active: actionsLoader.item && playListEntry.wideMode
visible: active && !playListEntry.editingRating
sourceComponent: Row {
anchors.centerIn: parent
FlatButtonWithToolTip {
visible: playListEntry.fileName.toString().substring(0, 7) === 'file://'
id: locateFileButton
enabled: isValid
text: i18nc("Show the file for this song in the file manager", "Show in folder")
icon.name: "document-open-folder"
onClicked: {
ElisaApplication.showInFolder(playListEntry.fileName)
}
visible: playListEntry.wideMode && playListEntry.fileName.toString().substring(0, 7) === 'file://'
action: actionsLoader.item.locateFileAction
}
FlatButtonWithToolTip {
id: infoButton
objectName: 'infoButton'
enabled: isValid
text: i18nc("Show track metadata", "View Details")
icon.name: "help-about"
onClicked: {
if (metadataLoader.active === false) {
metadataLoader.active = true
}
else {
metadataLoader.item.close();
metadataLoader.active = false
}
}
visible: playListEntry.wideMode
action: actionsLoader.item.infoAction
}
FlatButtonWithToolTip {
id: ratingButton
objectName: 'ratingButton'
visible: !ElisaApplication.useFavoriteStyleRatings
visible: playListEntry.wideMode && !ElisaApplication.useFavoriteStyleRatings
enabled: isValid
text: i18nc("Show track rating", "Set track rating")
icon.name: "view-media-favorite"
onClicked: {
playListEntry.editingRating = true;
}
action: actionsLoader.item.ratingAction
}
FlatButtonWithToolTip {
id: favoriteButton
objectName: 'favoriteButton'
visible: ElisaApplication.useFavoriteStyleRatings
visible: playListEntry.wideMode && ElisaApplication.useFavoriteStyleRatings
enabled: isValid
text: rating == 10 ? i18n("Un-mark this song as a favorite") : i18n("Mark this song as a favorite")
icon.name: rating == 10 ? "rating" : "rating-unrated"
onClicked: {
var newRating = 0;
if (rating == 10) {
newRating = 0;
// Change icon immediately in case backend is slow
icon.name = "rating-unrated";
} else {
newRating = 10;
// Change icon immediately in case backend is slow
icon.name = "rating";
}
ElisaApplication.musicManager.updateSingleFileMetaData(playListEntry.fileName, DataTypes.RatingRole, newRating);
}
action: actionsLoader.item.favoriteAction
}
FlatButtonWithToolTip {
id: playPauseButton
objectName: 'playPauseButton'
enabled: isValid
scale: LayoutMirroring.enabled ? -1 : 1 // We can mirror the symmetrical pause icon
text: (isPlaying === MediaPlayList.IsPlaying) ? i18nc("Pause current track from play list", "Pause") : i18nc("Play this track from play list", "Play")
icon.name: (isPlaying === MediaPlayList.IsPlaying) ? "media-playback-pause" : "media-playback-start"
onClicked: if (isPlaying === MediaPlayList.IsPlaying) {
playListEntry.pausePlayback()
} else if (isPlaying === MediaPlayList.IsPaused) {
playListEntry.startPlayback()
} else {
playListEntry.switchToTrack(playListEntry.index)
playListEntry.startPlayback()
}
visible: playListEntry.wideMode
action: actionsLoader.item.playPauseAction
}
FlatButtonWithToolTip {
id: removeButton
objectName: 'removeButton'
text: i18nc("Remove current track from play list", "Remove")
icon.name: "error"
onClicked: playListEntry.removeFromPlaylist(playListEntry.index)
visible: playListEntry.wideMode
action: actionsLoader.item.removeAction
}
}
}
FlatButtonWithToolTip {
visible: playListEntry.editingRating
visible: playListEntry.editingRating && playListEntry.wideMode
text: i18nc("Cancel rating this track", "Cancel rating this track")
icon.name: "dialog-cancel"
onClicked: { playListEntry.editingRating = false; }
......@@ -279,7 +268,7 @@ BasePlayListDelegate {
readOnly: false
starRating: rating
visible: playListEntry.editingRating || (rating > 0 && !containsMouse && !isSelected && !playListEntry.activeFocus && !simpleMode && !ElisaApplication.useFavoriteStyleRatings)
visible: (playListEntry.editingRating || (rating > 0 && !containsMouse && !isSelected && !playListEntry.activeFocus && !simpleMode && !ElisaApplication.useFavoriteStyleRatings)) && playListEntry.wideMode
onRatingEdited: {
ElisaApplication.musicManager.updateSingleFileMetaData(playListEntry.fileName, DataTypes.RatingRole, starRating);
......@@ -298,24 +287,67 @@ BasePlayListDelegate {
LabelWithToolTip {
id: durationLabel
text: duration
font.weight: (isPlaying ? Font.Bold : Font.Normal)
Layout.leftMargin: Kirigami.Units.smallSpacing
Layout.rightMargin: Kirigami.Units.smallSpacing
}
Layout.leftMargin: Kirigami.Units.largeSpacing
Layout.rightMargin: Kirigami.Units.largeSpacing
Loader {
id: menuButtonLoader
active: !playListEntry.wideMode
visible: active
sourceComponent: FlatButtonWithToolTip {
icon.name: "overflow-menu"
down: menuLoader.menuVisible
onClicked: menuLoader.item.open()
}
}
Loader {
id: menuLoader
property bool menuVisible: false
active: !playListEntry.wideMode && actionsLoader.item
onActiveChanged: {
if (!active) {
menuVisible = false
}
}
sourceComponent: Menu {
dim: false
modal: true
x: -width
parent: menuButtonLoader.item
onVisibleChanged: menuLoader.menuVisible = visible
MenuItem {
action: actionsLoader.item.locateFileAction
}
MenuItem {
action: actionsLoader.item.infoAction
}
MenuItem {
action: actionsLoader.item.playPauseAction
}
MenuItem {
action: actionsLoader.item.removeAction
}
}
}
}
states: [
State {
name: 'notSelected'
when: !containsMouse && !isSelected && !playListEntry.activeFocus && !simpleMode
name: "menuVisible"
when: menuLoader.menuVisible && !playListEntry.wideMode
PropertyChanges {
target: hoverLoader
active: false
target: actionsLoader
active: true
}
},
State {
name: 'notSelected'
when: !containsMouse && !isSelected && !playListEntry.activeFocus && !simpleMode
PropertyChanges {
target: ratingWidget
hoverWidgetOpacity: 0.0
......@@ -325,7 +357,7 @@ BasePlayListDelegate {
name: 'hovered'
when: containsMouse && !playListEntry.activeFocus && !simpleMode
PropertyChanges {
target: hoverLoader
target: actionsLoader
active: true
}
PropertyChanges {
......@@ -336,10 +368,6 @@ BasePlayListDelegate {
State {
name: 'selected'
when: !playListEntry.activeFocus && isSelected && !simpleMode
PropertyChanges {
target: hoverLoader
active: false
}
PropertyChanges {
target: ratingWidget
hoverWidgetOpacity: 1.0
......@@ -349,7 +377,7 @@ BasePlayListDelegate {
name: 'focused'
when: playListEntry.activeFocus && !simpleMode
PropertyChanges {
target: hoverLoader
target: actionsLoader
active: true
}
PropertyChanges {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment