PlayListEntry.qml 12.5 KB
Newer Older
1
/*
2
 * Copyright 2016-2017 Matthieu Gallien <matthieu_gallien@yahoo.fr>
3
 *
4
5
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
6
7
8
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
9
 * This program is distributed in the hope that it will be useful,
10
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
 * Lesser General Public License for more details.
13
 *
14
15
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16
17
 */

Alexander Stippich's avatar
Alexander Stippich committed
18
import QtQuick 2.7
19
import QtQuick.Layouts 1.2
20
import QtQuick.Controls 2.3
21
22
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
23
import org.kde.elisa 1.0
24

25
FocusScope {
26
    id: playListEntry
27

28
    property var index
29
    property bool isSingleDiscAlbum
30
    property int isPlaying
31
    property bool isSelected
32
    property bool isValid
33
    property bool isAlternateColor
34
    property bool containsMouse
35
    property int databaseId: 0
36
    property var entryType
37
38
39
40
41
    property string title
    property string artist
    property string album
    property string albumArtist
    property string duration
42
    property url fileName
43
44
45
46
47
    property url imageUrl
    property int trackNumber
    property int discNumber
    property int rating
    property bool hasValidDiscNumber: true
48
    property int scrollBarWidth
49
    property bool simpleMode: false
50

51
    signal startPlayback()
52
    signal pausePlayback()
53
54
55
    signal removeFromPlaylist(var trackIndex)
    signal switchToTrack(var trackIndex)

56
57
58
    Accessible.role: Accessible.ListItem
    Accessible.name: title + ' ' + album + ' ' + artist

59
60
61
62
63
64
    TextMetrics {
        id: mainCompactLabelSize
        font: mainCompactLabel.font
        text: mainCompactLabel.text
    }

65
66
67
68
    Keys.onReturnPressed: {
        playListEntry.switchToTrack(playListEntry.index)
        playListEntry.startPlayback()
    }
69

70
    height: mainCompactLabelSize.height + 2 * elisaTheme.layoutVerticalMargin
71

72
73
74
    Loader {
        id: metadataLoader
        active: false
75
        onLoaded: item.show()
76
77

        sourceComponent:  MediaTrackMetadataView {
78
            fileName: playListEntry.fileName
79
            showImage: entryType !== ElisaUtils.Radio
80
            modelType: entryType
81
82
83
84
            showTrackFileName: entryType !== ElisaUtils.Radio
            showDeleteButton: entryType === ElisaUtils.Radio
            showApplyButton: entryType === ElisaUtils.Radio
            editableMetadata: entryType === ElisaUtils.Radio
85
86

            onRejected: metadataLoader.active = false
87
88
89
        }
    }

90
91
    Rectangle {
        id: entryBackground
92

93
        anchors.fill: parent
94
        anchors.rightMargin: LayoutMirroring.enabled ? scrollBarWidth : 0
95
        z: 1
96

97
        color: simpleMode ? "transparent" : myPalette.base
98

99
        height: elisaTheme.playListDelegateHeight
100
    }
101

102
103
104
    RowLayout {
        id: trackRow
        z: 2
105

106
        anchors.fill: parent
107
        anchors.leftMargin: elisaTheme.layoutHorizontalMargin
108
        anchors.rightMargin: LayoutMirroring.enabled ? scrollBarWidth : 0
109

110
        spacing: elisaTheme.layoutHorizontalMargin / 4
111

112
        // Container for the play/pause icon and the track/disc label
113
        Item {
114
115
116
117
            TextMetrics {
                id: fakeLabel
                text: '99/9'
            }
118

119
120
121
122
            Layout.minimumWidth: fakeLabel.width
            Layout.preferredWidth: fakeLabel.width
            Layout.maximumWidth: fakeLabel.width
            Layout.preferredHeight: elisaTheme.playListDelegateHeight
123
124
125
            Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
            Layout.leftMargin: !LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin / 2 : 0
            Layout.rightMargin: LayoutMirroring.enabled ? elisaTheme.layoutHorizontalMargin / 2 : 0
126

127
128
            Image {
                id: playIcon
129

130
                anchors.centerIn: parent
131

132
133
                source: (isPlaying === MediaPlayList.IsPlaying ?
                             Qt.resolvedUrl(elisaTheme.playingIndicatorIcon) : Qt.resolvedUrl(elisaTheme.pausedIndicatorIcon))
134

135
136
137
138
139
140
                width: elisaTheme.smallControlButtonSize
                height: elisaTheme.smallControlButtonSize
                sourceSize.width: elisaTheme.smallControlButtonSize
                sourceSize.height: elisaTheme.smallControlButtonSize
                fillMode: Image.PreserveAspectFit
                mirror: LayoutMirroring.enabled
141
142
143
144
145
146
147

                layer.enabled: simpleMode
                layer.effect: ColorOverlay {
                    cached: true

                    color: myPalette.highlightedText
                }
148

149
                visible: isPlaying === MediaPlayList.IsPlaying || isPlaying === MediaPlayList.IsPaused
150
            }
151

152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
            Label {
                id: trackAndDiscNumberLabel

                anchors.fill: parent
                anchors.rightMargin: LayoutMirroring.enabled ? 0 : elisaTheme.layoutHorizontalMargin
                anchors.leftMargin: !LayoutMirroring.enabled ? 0 : elisaTheme.layoutHorizontalMargin

                horizontalAlignment: Text.AlignRight

                text: {
                    var trackNumberString;
                    if (trackNumber !== -1) {
                        trackNumberString = Number(trackNumber).toLocaleString(Qt.locale(), 'f', 0);
                    } else {
                        trackNumberString = ''
                    }
                    if (!isSingleDiscAlbum && discNumber !== 0 ) {
                        return trackNumberString + "/" + Number(discNumber).toLocaleString(Qt.locale(), 'f', 0)
                    } else {
                        return trackNumberString
                    }
                }
174

175
176
                font.weight: (isPlaying ? Font.Bold : Font.Light)
                color: simpleMode ? myPalette.highlightedText : myPalette.text
177

178
                visible: isValid && !playIcon.visible
179
180
            }
        }
181

182
183
        LabelWithToolTip {
            id: mainCompactLabel
184

185
            text: title
186

187
            font.weight: (isPlaying ? Font.Bold : Font.Normal)
188
            color: simpleMode ? myPalette.highlightedText : myPalette.text
189

190
191
192
            Layout.maximumWidth: mainCompactLabel.implicitWidth + 1
            Layout.fillWidth: true
            Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
193

194
            visible: isValid
195

196
197
198
            elide: Text.ElideRight
            horizontalAlignment: Text.AlignLeft
        }
199

200
201
        LabelWithToolTip {
            id: mainInvalidCompactLabel
202

203
            text: title
204

205
            color: simpleMode ? myPalette.highlightedText : myPalette.text
206

207
208
            Layout.fillWidth: true
            Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
209

210
            visible: !isValid
211

212
213
            elide: Text.ElideRight
        }
214

215
216
217
218
        Item {
            Layout.fillWidth: true
            Layout.preferredWidth: 0
        }
219

220
221
222
223
        Loader {
            id: hoverLoader
            active: false
            visible: active
224

225
            Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
226

227
228
            sourceComponent: Row {
                anchors.centerIn: parent
229
230
                enabled: isValid

231
232
233
                FlatButtonWithToolTip {
                    id: infoButton
                    objectName: 'infoButton'
234

235
236
                    implicitHeight: elisaTheme.playListDelegateHeight
                    implicitWidth: elisaTheme.playListDelegateHeight
237

238
239
240
241
242
243
244
245
246
247
248
                    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
                        }
                    }
249
                }
250

251
252
253
                FlatButtonWithToolTip {
                    id: playPauseButton
                    objectName: 'playPauseButton'
254

255
256
                    implicitHeight: elisaTheme.playListDelegateHeight
                    implicitWidth: elisaTheme.playListDelegateHeight
257

258
                    scale: LayoutMirroring.enabled ? -1 : 1 // We can mirror the symmetrical pause icon
259

260
261
262
263
264
265
266
267
                    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 {
                        playListEntry.switchToTrack(playListEntry.index)
                        playListEntry.startPlayback()
                    }
268
                }
269

270
271
272
                FlatButtonWithToolTip {
                    id: removeButton
                    objectName: 'removeButton'
273

274
275
                    implicitHeight: elisaTheme.playListDelegateHeight
                    implicitWidth: elisaTheme.playListDelegateHeight
276
277
278
279

                    text: i18nc("Remove current track from play list", "Remove")
                    icon.name: "error"
                    onClicked: playListEntry.removeFromPlaylist(playListEntry.index)
280
281
282
                }

            }
283
        }
284

285
286
        RatingStar {
            id: ratingWidget
287

288
            starRating: rating
289

290
            starSize: elisaTheme.ratingStarSize
291

292
293
            visible: rating > 0
        }
294

295
296
        LabelWithToolTip {
            id: durationLabel
Safa AlFulaij's avatar
Safa AlFulaij committed
297

298
            text: duration
299

300
            font.weight: (isPlaying ? Font.Bold : Font.Normal)
301
            color: simpleMode ? myPalette.highlightedText : myPalette.text
302

303
304
305
            Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
            Layout.leftMargin: elisaTheme.layoutHorizontalMargin
            Layout.rightMargin: elisaTheme.layoutHorizontalMargin
Safa AlFulaij's avatar
Safa AlFulaij committed
306

307
            horizontalAlignment: Text.AlignRight
308
        }
309
    }
310

311
312
313
    states: [
        State {
            name: 'notSelected'
314
            when: !containsMouse && !isSelected && !playListEntry.activeFocus && !simpleMode
315
            PropertyChanges {
316
317
                target: hoverLoader
                active: false
318
            }
319
            PropertyChanges {
320
                target: entryBackground
321
                color: (isAlternateColor ? myPalette.alternateBase : myPalette.base)
322
            }
323
324
325
326
            PropertyChanges {
                target: entryBackground
                opacity: 1.
            }
327
328
329
330
            PropertyChanges {
                target: ratingWidget
                hoverWidgetOpacity: 0.0
            }
331
        },
332
        State {
333
            name: 'hovered'
334
            when: containsMouse && !playListEntry.activeFocus && !simpleMode
335
            PropertyChanges {
336
337
                target: hoverLoader
                active: true
338
            }
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
            PropertyChanges {
                target: entryBackground
                color: myPalette.highlight
            }
            PropertyChanges {
                target: entryBackground
                opacity: 0.2
            }
            PropertyChanges {
                target: ratingWidget
                hoverWidgetOpacity: 1.0
            }
        },
        State {
            name: 'selected'
354
            when: !playListEntry.activeFocus && isSelected && !simpleMode
355
            PropertyChanges {
356
357
                target: hoverLoader
                active: false
358
            }
359
            PropertyChanges {
360
                target: entryBackground
361
                color: myPalette.mid
362
            }
363
364
365
366
367
368
369
370
371
372
373
            PropertyChanges {
                target: entryBackground
                opacity: 1.
            }
            PropertyChanges {
                target: ratingWidget
                hoverWidgetOpacity: 1.0
            }
        },
        State {
            name: 'focused'
374
            when: playListEntry.activeFocus && !simpleMode
375
            PropertyChanges {
376
377
                target: hoverLoader
                active: true
378
379
380
381
382
383
384
385
386
            }
            PropertyChanges {
                target: entryBackground
                color: myPalette.highlight
            }
            PropertyChanges {
                target: entryBackground
                opacity: 0.6
            }
387
388
389
390
            PropertyChanges {
                target: ratingWidget
                hoverWidgetOpacity: 1.0
            }
391
392
        }
    ]
393
394
}