1/*
2   SPDX-FileCopyrightText: 2020 (c) Devin Lin <espidev@gmail.com>
3
4   SPDX-License-Identifier: LGPL-3.0-or-later
5 */
6
7import QtQuick 2.7
8import QtQuick.Layouts 1.2
9import QtQuick.Controls 2.3
10import QtQuick.Window 2.2
11import QtGraphicalEffects 1.0
12import org.kde.kirigami 2.5 as Kirigami
13import org.kde.elisa 1.0
14import ".."
15import "../shared"
16
17BasePlayerControl {
18    id: trackPlayer
19
20    property alias volume: volumeButton.sliderValue
21
22    property string image
23    property string title
24    property string artist
25    property string albumArtist
26    property string album
27
28    property bool portrait
29
30    property int imageSourceSize: 512
31
32    // hardcode slider colours because theming doesn't really make sense on top of the blurred background
33    property color sliderElapsedColor: "white"
34    property color sliderRemainingColor: "grey"
35    property color sliderHandleColor: "white"
36
37    ColumnLayout {
38        anchors.fill: parent
39        spacing: Kirigami.Units.largeSpacing
40
41        // hide arrow button
42        FlatButtonWithToolTip {
43            id: minimizePlayer
44            Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
45            Layout.maximumHeight: parent.height
46            Layout.preferredHeight: Kirigami.Units.gridUnit * 2
47            Layout.maximumWidth: parent.height
48            Layout.preferredWidth: Kirigami.Units.gridUnit * 2
49            text: i18nc("minimize player", "Minimize Player")
50            icon.name: "arrow-down"
51            icon.color: "white"
52            Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
53            Kirigami.Theme.inherit: false
54            onClicked: toClose.restart()
55        }
56
57        // album art
58        ImageWithFallback {
59            property double specWidth: {
60                let allowedWidth = mainWindow.width - Kirigami.Units.largeSpacing * 4;
61                let allowedHeight = mainWindow.height - Kirigami.Units.largeSpacing * 8 - (minimizePlayer.height + bottomPlayerControls.height);
62                if (allowedWidth > allowedHeight) {
63                    return allowedHeight;
64                } else {
65                    return allowedWidth;
66                }
67            }
68            Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
69            Layout.preferredWidth: specWidth
70            Layout.minimumWidth: specWidth
71            Layout.maximumWidth: specWidth
72            Layout.preferredHeight: specWidth
73
74            asynchronous: true
75            mipmap: true
76
77            source: trackPlayer.image
78            fallback: Qt.resolvedUrl(elisaTheme.defaultAlbumImage)
79
80            sourceSize {
81                width: imageSourceSize
82                height: imageSourceSize
83            }
84
85            fillMode: Image.PreserveAspectFit
86        }
87
88        Item { Layout.fillHeight: true }
89
90        // bottom player controls
91        ColumnLayout {
92            id: bottomPlayerControls
93            spacing: Kirigami.Units.smallSpacing
94
95            Layout.alignment: Qt.AlignBottom
96            Layout.fillWidth: true
97
98            property int maxWidth: mainWindow.width - Kirigami.Units.largeSpacing * 4
99            Layout.maximumWidth: maxWidth
100
101            LabelWithToolTip {
102                id: mainLabel
103                text: title
104                wrapMode: Text.Wrap
105                Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
106                Layout.fillWidth: true
107                elide: Text.ElideRight
108                maximumLineCount: 1
109                // Hardcoded because the footerbar blur always makes a dark-ish
110                // background, so we don't want to use a color scheme color that
111                // might also be dark
112                color: "white"
113                level: 4
114                font.weight: Font.Bold
115                font.bold: true
116
117                MouseArea {
118                    id: titleMouseArea
119                    hoverEnabled: true
120                    anchors.left: parent.left
121                    anchors.top: parent.top
122                    anchors.bottom: parent.bottom
123                    width: parent.implicitWidth
124                    cursorShape: Qt.PointingHandCursor
125                    onClicked: {
126                        openNowPlaying()
127                    }
128                }
129            }
130
131            LabelWithToolTip {
132                id: authorLabel
133                text: artist
134                visible: text.length > 0
135                wrapMode: Text.Wrap
136                Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
137                Layout.fillWidth: true
138                elide: Text.ElideRight
139                maximumLineCount: 1
140                // Hardcoded because the footerbar blur always makes a dark-ish
141                // background, so we don't want to use a color scheme color that
142                // might also be dark
143                color: "white"
144                level: 4
145
146                MouseArea {
147                    id: authorMouseArea
148                    hoverEnabled: true
149                    anchors.left: parent.left
150                    anchors.top: parent.top
151                    anchors.bottom: parent.bottom
152                    width: parent.implicitWidth
153                    cursorShape: Qt.PointingHandCursor
154                    onClicked: {
155                        openArtist()
156                    }
157                }
158            }
159
160            LabelWithToolTip {
161                id: albumLabel
162                text: album
163                visible: text.length > 0
164                wrapMode: Text.Wrap
165                Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
166                Layout.fillWidth: true
167                elide: Text.ElideRight
168                maximumLineCount: 1
169                // Hardcoded because the footerbar blur always makes a dark-ish
170                // background, so we don't want to use a color scheme color that
171                // might also be dark
172                color: "white"
173                level: 4
174
175                MouseArea {
176                    id: albumMouseArea
177                    hoverEnabled: true
178                    anchors.left: parent.left
179                    anchors.top: parent.top
180                    anchors.bottom: parent.bottom
181                    width: parent.implicitWidth
182                    cursorShape: Qt.PointingHandCursor
183                    onClicked: {
184                        openAlbum()
185                    }
186                }
187            }
188
189            // misc. player controls
190            RowLayout {
191                Layout.preferredHeight: Kirigami.Units.gridUnit * 3
192
193                // ensure white icons
194                Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
195                Kirigami.Theme.inherit: false
196
197                FlatButtonWithToolTip {
198                    id: infoButton
199                    Layout.maximumHeight: parent.height
200                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
201                    Layout.maximumWidth: height
202                    Layout.preferredWidth: height
203                    text: i18nc("show track information", "Show Info")
204                    icon.name: "documentinfo"
205                    icon.color: "white"
206                    onClicked: openNowPlaying()
207                }
208
209                FlatButtonWithToolTip {
210                    id: shuffleButton
211                    Layout.maximumHeight: parent.height
212                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
213                    Layout.maximumWidth: height
214                    Layout.preferredWidth: height
215                    text: i18nc("toggle shuffle mode for playlist", "Toggle Shuffle")
216                    icon.name: "media-playlist-shuffle"
217                    icon.color: "white"
218                    onClicked: trackPlayer.shuffle = !trackPlayer.shuffle
219                    checked: trackPlayer.shuffle
220                }
221
222                FlatButtonWithToolTip {
223                    id: repeatButton
224                    Layout.maximumHeight: parent.height
225                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
226                    Layout.maximumWidth: height
227                    Layout.preferredWidth: height
228                    text: {
229                        const map = {
230                            0: i18n("Current: Don't repeat tracks"),
231                            1: i18n("Current: Repeat current track"),
232                            2: i18n("Current: Repeat all tracks in playlist")
233                        }
234                        return map[trackPlayer.repeat]
235                    }
236                    icon.name: {
237                        const map = {
238                            0: "media-repeat-none",
239                            1: "media-repeat-single",
240                            2: "media-repeat-all"
241                        }
242                        return map[trackPlayer.repeat]
243                    }
244                    icon.color: "white"
245                    checked: repeat !== 0
246                    onClicked: {
247                        let nextRepeat = trackPlayer.repeat + 1
248                        if (nextRepeat >= 3) {
249                            nextRepeat = 0
250                        }
251                        trackPlayer.repeat = nextRepeat
252                    }
253                    onPressAndHold: {
254                        playlistModeMenu.popup()
255                    }
256
257                    Menu {
258                        id: playlistModeMenu
259
260                        PlaylistModeItem {
261                            text: i18n("Playlist")
262                            mode: MediaPlayListProxyModel.Playlist
263                        }
264                        PlaylistModeItem {
265                            text: i18n("One")
266                            mode: MediaPlayListProxyModel.One
267                        }
268                        PlaylistModeItem {
269                            text: i18n("None")
270                            mode: MediaPlayListProxyModel.None
271                        }
272                    }
273                }
274            }
275
276            // duration slider
277            DurationSlider {
278                Layout.fillWidth: true
279                Layout.maximumHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
280                position: trackPlayer.position
281                duration: trackPlayer.duration
282                seekable: trackPlayer.seekable
283                playEnabled: trackPlayer.playEnabled
284                onSeek: trackPlayer.seek(position)
285
286                // this color works well over the blurred/darkened background
287                labelColor: "white"
288            }
289
290            // bottom play controls
291            RowLayout {
292                Layout.alignment: Qt.AlignHCenter
293                Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
294
295                // ensure white icons
296                Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
297                Kirigami.Theme.inherit: false
298
299                // volume button
300                MobileVolumeButton {
301                    id: volumeButton
302                    muted: trackPlayer.muted
303                    Layout.maximumHeight: parent.height
304                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
305                    Layout.maximumWidth: height
306                    Layout.preferredWidth: height
307                }
308
309                Item { Layout.fillWidth: true }
310
311                FlatButtonWithToolTip {
312                    id: skipBackwardButton
313                    Layout.maximumHeight: parent.height
314                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
315                    Layout.maximumWidth: height
316                    Layout.preferredWidth: height
317                    enabled: skipBackwardEnabled
318                    text: i18nc("skip backward in playlists", "Skip Backward")
319                    onClicked: trackPlayer.playPrevious()
320                    icon.name: trackPlayer.LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward"
321                    icon.width: Kirigami.Units.gridUnit
322                    icon.height: Kirigami.Units.gridUnit
323                    icon.color: "white"
324                }
325
326                FlatButtonWithToolTip {
327                    id: playPauseButton
328                    Layout.maximumHeight: parent.height
329                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
330                    Layout.maximumWidth: height
331                    Layout.preferredWidth: height
332                    enabled: playEnabled
333                    text: i18nc("toggle play and pause for the audio player", "Toggle Play and Pause")
334                    onClicked: trackPlayer.isPlaying ? trackPlayer.pause() : trackPlayer.play()
335                    icon.name: trackPlayer.isPlaying? "media-playback-pause" : "media-playback-start"
336                    icon.width: Kirigami.Units.gridUnit
337                    icon.height: Kirigami.Units.gridUnit
338                    icon.color: "white"
339                }
340
341                FlatButtonWithToolTip {
342                    id: skipForwardButton
343                    Layout.maximumHeight: parent.height
344                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
345                    Layout.maximumWidth: height
346                    Layout.preferredWidth: height
347                    enabled: skipForwardEnabled
348                    text: i18nc("skip forward in playlists", "Skip Forward")
349                    onClicked: trackPlayer.playNext()
350                    icon.name: trackPlayer.LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward"
351                    icon.width: Kirigami.Units.gridUnit
352                    icon.height: Kirigami.Units.gridUnit
353                    icon.color: "white"
354                }
355
356                Item { Layout.fillWidth: true }
357
358                FlatButtonWithToolTip {
359                    id: showPlaylistButton
360                    Layout.maximumHeight: parent.height
361                    Layout.preferredHeight: Math.floor(Kirigami.Units.gridUnit * 2.5)
362                    Layout.maximumWidth: height
363                    Layout.preferredWidth: height
364                    text: i18nc("show the playlist", "Show Playlist")
365                    onClicked: playlistDrawer.open()
366                    icon.name: "view-media-playlist"
367                    icon.width: Kirigami.Units.gridUnit
368                    icon.height: Kirigami.Units.gridUnit
369                    icon.color: "white"
370                }
371            }
372        }
373    }
374}
375