Warning, /multimedia/elisa/src/qml/PlayListEntry.qml is written in an unsupported language. File is not indexed.
0001 /* 0002 SPDX-FileCopyrightText: 2016 (c) Matthieu Gallien <matthieu_gallien@yahoo.fr> 0003 0004 SPDX-License-Identifier: LGPL-3.0-or-later 0005 */ 0006 0007 import QtQuick 2.7 0008 import QtQuick.Layouts 1.2 0009 import QtQuick.Controls 2.3 0010 import QtQuick.Window 2.2 0011 import org.kde.kirigami 2.17 as Kirigami 0012 import org.kde.elisa 1.0 0013 0014 import "shared" 0015 0016 BasePlayListDelegate { 0017 id: playListEntry 0018 0019 property bool editingRating: false 0020 // wideMode means there is enough room for the button row 0021 // otherwise display a menu button 0022 readonly property bool wideMode: width >= elisaTheme.playListEntryMinWidth 0023 0024 property var listDelegate 0025 0026 readonly property string previousAlbum: listDelegate.ListView.previousSection ? JSON.parse(listDelegate.ListView.previousSection)[0] : null 0027 readonly property string currentAlbum: model.album || null 0028 readonly property string nextAlbum: listDelegate.ListView.nextSection ? JSON.parse(listDelegate.ListView.nextSection)[0] : null 0029 0030 readonly property bool grouped: currentAlbum && (previousAlbum === currentAlbum || nextAlbum === currentAlbum) 0031 readonly property bool sectionVisible: currentAlbum && (previousAlbum !== currentAlbum && nextAlbum === currentAlbum) 0032 0033 readonly property bool hasActiveFocus: playListEntry.activeFocus || entryFocusScope.activeFocus 0034 0035 Accessible.role: Accessible.ListItem 0036 Accessible.name: title + ' ' + album + ' ' + artist 0037 0038 Keys.onReturnPressed: { 0039 playListEntry.switchToTrack(playListEntry.index) 0040 playListEntry.startPlayback() 0041 } 0042 0043 KeyNavigation.right: (buttonRowLoader.item && buttonRowLoader.item.children[0]) || menuButtonLoader.item || null 0044 KeyNavigation.left: (buttonRowLoader.item && buttonRowLoader.item.children[buttonRowLoader.item.children.length -1]) || menuButtonLoader.item || null 0045 0046 topPadding: grouped ? 0 : Kirigami.Units.smallSpacing 0047 bottomPadding: grouped ? 0 : Kirigami.Units.smallSpacing 0048 leftPadding: mirrored ? Kirigami.Units.smallSpacing : 0 0049 rightPadding: mirrored ? 0 : Kirigami.Units.smallSpacing 0050 0051 // Set this explicitly since we rely on it; we don't want the theme setting 0052 // it to false under us! 0053 hoverEnabled: true 0054 0055 onHasActiveFocusChanged: { 0056 if (!hasActiveFocus) { 0057 editingRating = false 0058 } 0059 } 0060 0061 contentItem: FocusScope { 0062 id: entryFocusScope 0063 implicitHeight: childrenRect.height 0064 0065 Loader { 0066 id: metadataLoader 0067 active: false 0068 onLoaded: item.show() 0069 0070 sourceComponent: MediaTrackMetadataView { 0071 fileName: playListEntry.fileName 0072 showImage: entryType !== ElisaUtils.Radio 0073 modelType: entryType 0074 showTrackFileName: entryType !== ElisaUtils.Radio 0075 showDeleteButton: entryType === ElisaUtils.Radio 0076 editableMetadata: playListEntry.metadataModifiableRole 0077 canAddMoreMetadata: entryType !== ElisaUtils.Radio 0078 0079 onRejected: metadataLoader.active = false 0080 } 0081 } 0082 0083 QtObject { 0084 id: actionList 0085 property var locateFileAction: Kirigami.Action { 0086 text: i18nc("@action:button Show the file for this song in the file manager", "Show in folder") 0087 icon.name: "document-open-folder" 0088 visible: playListEntry.fileName.toString().substring(0, 7) === 'file://' 0089 enabled: isValid 0090 onTriggered: ElisaApplication.showInFolder(playListEntry.fileName) 0091 } 0092 property var infoAction: Kirigami.Action { 0093 text: i18nc("@action:button Show track metadata", "View details") 0094 icon.name: "help-about" 0095 enabled: isValid 0096 onTriggered: { 0097 if (metadataLoader.active === false) { 0098 metadataLoader.active = true 0099 } 0100 else { 0101 metadataLoader.item.close(); 0102 metadataLoader.active = false 0103 } 0104 } 0105 } 0106 property var ratingAction: Kirigami.Action { 0107 text: i18nc("@action:button", "Set track rating") 0108 icon.name: "view-media-favorite" 0109 visible: !ElisaApplication.useFavoriteStyleRatings 0110 enabled: isValid 0111 0112 onTriggered: { 0113 playListEntry.editingRating = true; 0114 } 0115 } 0116 property var favoriteAction: Kirigami.Action { 0117 text: playListEntry.isFavorite ? i18nc("@action:button", "Un-mark this song as a favorite") : i18nc("@action:button", "Mark this song as a favorite") 0118 icon.name: playListEntry.isFavorite ? "rating" : "rating-unrated" 0119 visible: ElisaApplication.useFavoriteStyleRatings 0120 enabled: isValid 0121 0122 onTriggered: { 0123 const newRating = playListEntry.isFavorite ? 0 : 10; 0124 // Change icon immediately in case backend is slow 0125 icon.name = playListEntry.isFavorite ? "rating-unrated" : "rating"; 0126 ElisaApplication.musicManager.updateSingleFileMetaData(playListEntry.fileName, DataTypes.RatingRole, newRating); 0127 } 0128 } 0129 property var playPauseAction: Kirigami.Action { 0130 text: (isPlaying === MediaPlayList.IsPlaying) ? i18nc("@action:button Pause current track from playlist", "Pause") : i18nc("@action:button Play this track from playlist", "Play") 0131 icon.name: (isPlaying === MediaPlayList.IsPlaying) ? "media-playback-pause" : "media-playback-start" 0132 enabled: isValid 0133 onTriggered: { 0134 if (isPlaying === MediaPlayList.IsPlaying) { 0135 playListEntry.pausePlayback() 0136 } else if (isPlaying === MediaPlayList.IsPaused) { 0137 playListEntry.startPlayback() 0138 } else { 0139 playListEntry.switchToTrack(playListEntry.index) 0140 playListEntry.startPlayback() 0141 } 0142 } 0143 } 0144 property var removeAction: Kirigami.Action { 0145 text: i18nc("@action:button Remove current track from play list", "Remove") 0146 icon.name: "edit-delete-remove" 0147 onTriggered: { 0148 playListEntry.removeFromPlaylist(playListEntry.index) 0149 } 0150 } 0151 } 0152 0153 RowLayout { 0154 id: trackRow 0155 0156 width: parent.width 0157 // We want the list items to be a bit taller in touch mode 0158 height: Math.max( 0159 (playListEntry.grouped && !Kirigami.Settings.hasTransientTouchInput ? Kirigami.Units.gridUnit : Kirigami.Units.gridUnit * 2), 0160 (elisaTheme.toolButtonHeight + Kirigami.Units.smallSpacing)) 0161 0162 spacing: Kirigami.Units.smallSpacing 0163 0164 Loader { 0165 Layout.leftMargin: trackRow.spacing 0166 active: !simpleMode && playListEntry.showDragHandle 0167 sourceComponent: Kirigami.ListItemDragHandle { 0168 listItem: playListEntry 0169 listView: playListEntry.listView 0170 0171 onMoveRequested: (oldIndex, newIndex) => { 0172 playListEntry.listView.draggingEntry = true 0173 ElisaApplication.mediaPlayListProxyModel.moveRow(oldIndex, newIndex) 0174 } 0175 onDropped: { 0176 playListEntry.listView.draggingEntry = false 0177 } 0178 } 0179 } 0180 0181 // Container for the play/pause icon and the track/disc label 0182 Item { 0183 Layout.preferredWidth: Math.max(elisaTheme.trackNumberWidth, elisaTheme.coverArtSize) 0184 Layout.fillHeight: true 0185 0186 Loader { 0187 active: !playListEntry.grouped 0188 opacity: playIcon.visible ? 0.2 : 1 0189 anchors.fill: parent 0190 0191 sourceComponent: ImageWithFallback { 0192 source: imageUrl 0193 fallback: elisaTheme.defaultAlbumImage 0194 0195 sourceSize.width: height 0196 sourceSize.height: height 0197 0198 fillMode: Image.PreserveAspectFit 0199 asynchronous: true 0200 } 0201 } 0202 0203 Kirigami.Icon { 0204 id: playIcon 0205 0206 anchors.centerIn: parent 0207 0208 source: (isPlaying === MediaPlayList.IsPlaying ? 0209 Qt.resolvedUrl(elisaTheme.playingIndicatorIcon) : Qt.resolvedUrl(elisaTheme.pausedIndicatorIcon)) 0210 0211 width: Kirigami.Units.iconSizes.smallMedium 0212 height: Kirigami.Units.iconSizes.smallMedium 0213 0214 visible: isPlaying === MediaPlayList.IsPlaying || isPlaying === MediaPlayList.IsPaused 0215 0216 isMask: simpleMode 0217 color: Kirigami.Theme.textColor 0218 } 0219 0220 Loader { 0221 active: playListEntry.grouped && isValid && !playIcon.visible 0222 anchors.fill: parent 0223 0224 sourceComponent: Label { 0225 //trackAndDiscNumberLabel 0226 0227 horizontalAlignment: Text.AlignRight 0228 verticalAlignment: Text.AlignVCenter 0229 0230 text: { 0231 var trackNumberString; 0232 if (trackNumber !== -1) { 0233 trackNumberString = Number(trackNumber).toLocaleString(Qt.locale(), 'f', 0); 0234 } else { 0235 trackNumberString = '' 0236 } 0237 if (!isSingleDiscAlbum && discNumber !== 0 ) { 0238 return trackNumberString + "/" + Number(discNumber).toLocaleString(Qt.locale(), 'f', 0) 0239 } else { 0240 return trackNumberString 0241 } 0242 } 0243 textFormat: Text.PlainText 0244 font.weight: (isPlaying ? Font.Bold : Font.Normal) 0245 } 0246 } 0247 } 0248 0249 ColumnLayout { 0250 spacing: 0 0251 Layout.fillWidth: true 0252 0253 LabelWithToolTip { 0254 text: title 0255 font.weight: isPlaying ? Font.Bold : Font.Normal 0256 visible: isValid 0257 Layout.fillWidth: true 0258 } 0259 0260 Loader { 0261 active: !playListEntry.grouped && (artist || album) 0262 visible: active 0263 Layout.fillWidth: true 0264 sourceComponent: LabelWithToolTip { 0265 text: [artist, album].filter(Boolean).join(" - ") 0266 type: Kirigami.Heading.Type.Secondary 0267 } 0268 } 0269 } 0270 0271 // button row 0272 Loader { 0273 id: buttonRowLoader 0274 0275 active: false 0276 visible: active && !playListEntry.editingRating 0277 0278 sourceComponent: Row { 0279 Repeater { 0280 model: [ 0281 actionList.locateFileAction, 0282 actionList.infoAction, 0283 actionList.playPauseAction, 0284 actionList.removeAction, 0285 actionList.ratingAction, 0286 actionList.favoriteAction 0287 ] 0288 delegate: FlatButtonWithToolTip { 0289 action: modelData 0290 visible: action.visible 0291 activeFocusOnTab: playListEntry.isSelected 0292 } 0293 } 0294 } 0295 } 0296 0297 FlatButtonWithToolTip { 0298 visible: playListEntry.editingRating && playListEntry.wideMode 0299 text: i18nc("@action:button", "Cancel rating this track") 0300 icon.name: "dialog-cancel" 0301 onClicked: { playListEntry.editingRating = false; } 0302 } 0303 0304 RatingStar { 0305 id: ratingWidget 0306 0307 readOnly: !playListEntry.editingRating 0308 starRating: rating 0309 0310 visible: (playListEntry.editingRating || (rating > 0 && !playListEntry.hovered && !playListEntry.hasActiveFocus && !simpleMode && !ElisaApplication.useFavoriteStyleRatings)) && playListEntry.wideMode 0311 0312 onRatingEdited: { 0313 ElisaApplication.musicManager.updateSingleFileMetaData(playListEntry.fileName, DataTypes.RatingRole, starRating); 0314 playListEntry.editingRating = false; 0315 } 0316 } 0317 0318 Loader { 0319 id: favoriteMark 0320 0321 visible: playListEntry.isFavorite && !playListEntry.hovered && !playListEntry.hasActiveFocus && !simpleMode && ElisaApplication.useFavoriteStyleRatings 0322 0323 sourceComponent: FlatButtonWithToolTip { 0324 visible: action.visible 0325 action: actionList.favoriteAction 0326 } 0327 } 0328 0329 0330 LabelWithToolTip { 0331 id: durationLabel 0332 text: duration 0333 font.weight: isPlaying ? Font.Bold : Font.Normal 0334 } 0335 0336 Loader { 0337 id: menuButtonLoader 0338 active: !playListEntry.wideMode || Kirigami.Settings.hasTransientTouchInput 0339 visible: active 0340 sourceComponent: FlatButtonWithToolTip { 0341 icon.name: "overflow-menu" 0342 text: entryType === ElisaUtils.Track ? i18nc("@action:button", "Track Options") : i18nc("@action:button", "Radio Options") 0343 down: pressed || menuLoader.menuVisible 0344 onPressed: menuLoader.item.open() 0345 Keys.onReturnPressed: menuLoader.item.open() 0346 Keys.onEnterPressed: menuLoader.item.open() 0347 activeFocusOnTab: playListEntry.isSelected 0348 } 0349 } 0350 Loader { 0351 id: menuLoader 0352 property bool menuVisible: false 0353 active: menuButtonLoader.active 0354 onActiveChanged: { 0355 if (!active) { 0356 menuVisible = false 0357 } 0358 } 0359 sourceComponent: Menu { 0360 dim: false 0361 modal: true 0362 x: -width 0363 parent: menuButtonLoader.item 0364 0365 onVisibleChanged: menuLoader.menuVisible = visible 0366 0367 MenuItem { 0368 action: actionList.playPauseAction 0369 } 0370 MenuItem { 0371 action: actionList.infoAction 0372 } 0373 MenuItem { 0374 action: actionList.locateFileAction 0375 } 0376 MenuItem { 0377 action: actionList.ratingAction 0378 visible: action.visible 0379 } 0380 MenuItem { 0381 action: actionList.favoriteAction 0382 visible: action.visible 0383 } 0384 MenuSeparator { } 0385 MenuItem { 0386 action: actionList.removeAction 0387 } 0388 } 0389 } 0390 } 0391 0392 states: [ 0393 State { 0394 name: "dragging" 0395 when: playListEntry.listView.draggingEntry 0396 }, 0397 State { 0398 name: 'hovered' 0399 when: playListEntry.hovered && !playListEntry.hasActiveFocus && !simpleMode 0400 PropertyChanges { 0401 target: buttonRowLoader 0402 active: playListEntry.wideMode 0403 } 0404 }, 0405 State { 0406 name: 'focused' 0407 when: playListEntry.hasActiveFocus && !simpleMode 0408 PropertyChanges { 0409 target: buttonRowLoader 0410 active: playListEntry.wideMode 0411 } 0412 } 0413 ] 0414 } 0415 }