dbus: monitor for udisks media removal events
[apps/mediaplayer.git] / app / MediaPlayer.qml
1 /*
2  * Copyright (C) 2016 The Qt Company Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 import QtQuick 2.6
18 import QtQuick.Layouts 1.1
19 import QtQuick.Controls 2.0
20 import QtMultimedia 5.6
21 import AGL.Demo.Controls 1.0
22 import MediaPlayer 1.0
23
24 ApplicationWindow {
25     id: root
26
27     Item {
28         id: bluetooth
29         property bool connected: false
30         property string state
31
32         property string artist
33         property string title
34         property int duration: 0
35         property int position: 0
36
37         function disableBluetooth() {
38             bluetooth.artist = ''
39             bluetooth.title = ''
40             bluetooth.duration = 0
41             bluetooth.position = 0
42             bluetooth.connected = false
43         }
44     }
45
46     Connections {
47         target: dbus
48
49         onStopPlayback: {
50             player.stop()
51             playlist.clear()
52             playlistmodel.setSource(playlist)
53             playlistview.visible = false
54         }
55
56         onProcessPlaylistUpdate: {
57             playlist.clear()
58             playlist.addItems(mediaFiles)
59
60             playlistmodel.setSource(playlist)
61             playlistview.visible = bluetooth.connected == false
62         }
63
64         onProcessPlaylistHide: {
65             playlistview.visible = false
66             player.stop()
67         }
68
69         onProcessPlaylistShow: {
70             playlistview.visible = true
71             bluetooth.disableBluetooth()
72         }
73
74         onDisplayBluetoothMetadata: {
75             if (avrcp_artist)
76                 bluetooth.artist = avrcp_artist
77             if (avrcp_title)
78                 bluetooth.title = avrcp_title
79             bluetooth.duration = avrcp_duration
80         }
81
82         onUpdatePlayerStatus: {
83             bluetooth.connected = true
84             bluetooth.state = status
85         }
86
87         onUpdatePosition: {
88             slider.value = current_position
89             bluetooth.position = current_position
90         }
91     }
92
93     MediaPlayer {
94         id: player
95         audioRole: MediaPlayer.MusicRole
96         autoLoad: true
97         playlist: playlist
98
99         property bool is_bluetooth: false
100         function time2str(value) {
101             return Qt.formatTime(new Date(value), 'mm:ss')
102         }
103         onPositionChanged: slider.value = player.position
104     }
105
106     Timer {
107         id: timer
108         interval: 250
109         running: (bluetooth.connected && bluetooth.state == "playing")
110         repeat: true
111         onTriggered: {
112             bluetooth.position = dbus.getCurrentPosition()
113             slider.value = bluetooth.position
114         }
115     }
116
117     Playlist {
118         id: playlist
119         playbackMode: random.checked ? Playlist.Random : loop.checked ? Playlist.Loop : Playlist.Sequential
120
121         Component.onCompleted: {
122             playlist.addItems(mediaFiles)
123         }
124     }
125
126
127     ColumnLayout {
128         anchors.fill: parent
129         Item {
130             Layout.fillWidth: true
131             Layout.fillHeight: true
132             Layout.preferredHeight: 1080
133             clip: true
134             Image {
135                 id: albumart
136                 anchors.left: parent.left
137                 anchors.right: parent.right
138                 anchors.bottom: parent.bottom
139                 height: sourceSize.height * width / sourceSize.width
140                 fillMode: Image.PreserveAspectCrop
141                 source: player.metaData.coverArtImage ? player.metaData.coverArtImage : ''
142                 visible: bluetooth.connected == false
143             }
144
145             Item {
146                 anchors.left: parent.left
147                 anchors.right: parent.right
148                 anchors.bottom: parent.bottom
149                 height :307
150                 Rectangle {
151                     anchors.fill: parent
152                     color: 'black'
153                     opacity: 0.75
154                 }
155
156                 ColumnLayout {
157                     anchors.fill: parent
158                     anchors.margins: root.width * 0.02
159                     Item {
160                         Layout.fillWidth: true
161                         Layout.fillHeight: true
162                         Row {
163                             spacing: 20
164                             ToggleButton {
165                                 id: random
166                                 visible: bluetooth.connected == false
167                                 offImage: './images/AGL_MediaPlayer_Shuffle_Inactive.svg'
168                                 onImage: './images/AGL_MediaPlayer_Shuffle_Active.svg'
169                             }
170                             ToggleButton {
171                                 id: loop
172                                 visible: bluetooth.connected == false
173                                 offImage: './images/AGL_MediaPlayer_Loop_Inactive.svg'
174                                 onImage: './images/AGL_MediaPlayer_Loop_Active.svg'
175                             }
176                         }
177                         ColumnLayout {
178                             anchors.fill: parent
179                             Label {
180                                 id: title
181                                 Layout.alignment: Layout.Center
182                                 text: bluetooth.title ? bluetooth.title : (player.metaData.title ? player.metaData.title : '')
183                                 horizontalAlignment: Label.AlignHCenter
184                                 verticalAlignment: Label.AlignVCenter
185                             }
186                             Label {
187                                 Layout.alignment: Layout.Center
188                                 text: bluetooth.artist ? bluetooth.artist : (player.metaData.contributingArtist ? player.metaData.contributingArtist : '')
189                                 horizontalAlignment: Label.AlignHCenter
190                                 verticalAlignment: Label.AlignVCenter
191                                 font.pixelSize: title.font.pixelSize * 0.6
192                             }
193                         }
194                     }
195                     Slider {
196                         id: slider
197                         Layout.fillWidth: true
198                         to: bluetooth.connected ? bluetooth.duration : player.duration
199                         enabled: bluetooth.connected == false
200                         function getPosition() {
201                             if (bluetooth.connected && bluetooth.position) {
202                                 return player.time2str(bluetooth.position)
203                             }
204                             return player.time2str(player.position)
205                         }
206                         Label {
207                             id: position
208                             anchors.left: parent.left
209                             anchors.bottom: parent.top
210                             font.pixelSize: 32
211                             text: slider.getPosition()
212                         }
213                         Label {
214                             id: duration
215                             anchors.right: parent.right
216                             anchors.bottom: parent.top
217                             font.pixelSize: 32
218                             text: bluetooth.connected ? player.time2str(bluetooth.duration) : player.time2str(player.duration)
219                         }
220                         onPressedChanged: player.seek(value)
221                     }
222                     RowLayout {
223                         Layout.fillHeight: true
224 //                        Image {
225 //                            source: './images/AGL_MediaPlayer_Playlist_Inactive.svg'
226 //                        }
227 //                        Image {
228 //                            source: './images/AGL_MediaPlayer_CD_Inactive.svg'
229 //                        }
230                         Item { Layout.fillWidth: true }
231                         ImageButton {
232                             id: previous
233                             offImage: './images/AGL_MediaPlayer_BackArrow.svg'
234                             onClicked: {
235                                 if (bluetooth.connected) {
236                                     dbus.processQMLEvent("Previous")
237                                 } else {
238                                     playlist.previous()
239                                 }
240                             }
241                         }
242                         ImageButton {
243                             id: play
244                             offImage: './images/AGL_MediaPlayer_Player_Play.svg'
245                             onClicked: {
246                                 if (bluetooth.connected) {
247                                     dbus.processQMLEvent("Play")
248                                 } else {
249                                     player.play()
250                                 }
251                             }
252                             states: [
253                                 State {
254                                     when: player.playbackState === MediaPlayer.PlayingState
255                                     PropertyChanges {
256                                         target: play
257                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
258                                         onClicked: player.pause()
259                                     }
260                                 },
261                                 State {
262                                     when: bluetooth.connected && bluetooth.state == "playing"
263                                     PropertyChanges {
264                                         target: play
265                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
266                                         onClicked: dbus.processQMLEvent("Pause")
267                                     }
268                                 }
269
270                             ]
271                         }
272                         ImageButton {
273                             id: forward
274                             offImage: './images/AGL_MediaPlayer_ForwardArrow.svg'
275                             onClicked: {
276                                 if (bluetooth.connected) {
277                                     dbus.processQMLEvent("Next")
278                                 } else {
279                                     playlist.next()
280                                 }
281                             }
282                         }
283
284                         Item { Layout.fillWidth: true }
285 //                        Image {
286 //                            source: './images/AGL_MediaPlayer_Bluetooth_Inactive.svg'
287 //                        }
288 //                        Image {
289 //                            source: './images/AGL_MediaPlayer_Radio_Inactive.svg'
290 //                        }
291                     }
292                 }
293             }
294         }
295         Item {
296             Layout.fillWidth: true
297             Layout.fillHeight: true
298             Layout.preferredHeight: 407
299
300             PlaylistWithMetadata {
301                 id: playlistmodel
302                 source: playlist
303             }
304
305             ListView {
306                 anchors.fill: parent
307                 id: playlistview
308                 clip: true
309                 header: Label {
310                     x: 50
311                     text: 'PLAYLIST'
312                     opacity: 0.5
313                 }
314                 model: playlistmodel
315                 currentIndex: playlist.currentIndex
316
317                 delegate: MouseArea {
318                     id: delegate
319                     width: ListView.view.width
320                     height: ListView.view.height / 4
321                     RowLayout {
322                         anchors.fill: parent
323                         anchors.leftMargin: 50
324                         anchors.rightMargin: 50
325                         Image {
326                             source: model.coverArt
327                             fillMode: Image.PreserveAspectFit
328                             Layout.preferredWidth: delegate.height
329                             Layout.preferredHeight: delegate.height
330                         }
331                         ColumnLayout {
332                             Layout.fillWidth: true
333                             Label {
334                                 Layout.fillWidth: true
335                                 text: model.title
336                             }
337                             Label {
338                                 Layout.fillWidth: true
339                                 text: model.artist
340                                 color: '#66FF99'
341                                 font.pixelSize: 32
342                             }
343                         }
344                         Label {
345                             text: player.time2str(model.duration)
346                             color: '#66FF99'
347                             font.pixelSize: 32
348                         }
349                     }
350                     onClicked: {
351                         playlist.currentIndex = model.index
352                         player.play()
353                     }
354                 }
355
356                 highlight: Rectangle {
357                     color: 'white'
358                     opacity: 0.25
359                 }
360             }
361         }
362     }
363 }