mediaplayer: qml: pause agl-service-mediaplayer on A2DP stream
[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
23 ApplicationWindow {
24     id: root
25
26     Item {
27         id: player
28
29         property string title: ""
30         property string album: ""
31         property string artist: ""
32
33         property int duration: 0
34         property int position: 0
35
36         property string cover_art: ""
37         property string status: ""
38
39         function time2str(value) {
40             return Qt.formatTime(new Date(value), 'mm:ss')
41         }
42     }
43
44     Item {
45         id: bluetooth
46
47         property string deviceAddress: ""
48         property bool connected: false
49         property bool av_connected: false
50
51         property int position: 0
52         property int duration: 0
53
54         property string artist: ""
55         property string title: ""
56         property string state: "stopped"
57
58         // AVRCP Target UUID
59         property string avrcp_uuid: "0000110e-0000-1000-8000-00805f9b34fb"
60
61         function connect_profiles() {
62             var address = bluetooth.deviceAddress;
63             bluetooth_connection.connect(address, "a2dp")
64             bluetooth_connection.connect(address, "avrcp")
65         }
66
67         function disconnect_profiles() {
68             var address = bluetooth.deviceAddress;
69             bluetooth_connection.disconnect(address, "a2dp")
70             bluetooth_connection.disconnect(address, "avrcp")
71         }
72
73         function set_avrcp_controls(cmd) {
74             bluetooth_connection.set_avrcp_controls(bluetooth.deviceAddress, cmd)
75         }
76     }
77
78     Connections {
79         target: bluetooth_connection
80
81         onDeviceListEvent: {
82             var address = ""
83             for (var i = 0; i < data.list.length; i++) {
84                 var item = data.list[i]
85                 if (item.Connected == "True" && item.UUIDs.indexOf(bluetooth.avrcp_uuid) >= 0) {
86                     address = item.Address
87
88                     bluetooth.connected = true
89                     mediaplayer.pause()
90
91                     //NOTE: This hack is here for when MediaPlayer is started
92                     //      with an existing connection.
93                     bluetooth.av_connected = item.AVPConnected == "True" 
94                 }
95             }
96             if (!address)
97                 bluetooth.connected = false
98             else
99                 bluetooth.deviceAddress = address
100         }
101
102         onDeviceUpdatedEvent: {
103             var metadata = data.Metadata
104
105             if (data.Connected == "False")
106                 return
107
108             if (!bluetooth.av_connected && data.AVPConnected == "True")
109                 mediaplayer.pause()
110
111             bluetooth.connected = data.Connected == "True"
112             bluetooth.av_connected = data.AVPConnected == "True"
113             bluetooth.deviceAddress = data.Address
114
115             if ('Position' in metadata)
116                 bluetooth.position = metadata.Position
117
118             if ('Duration' in metadata)
119                 bluetooth.duration = metadata.Duration
120
121             if ('Status' in metadata)
122                 bluetooth.state = metadata.Status
123
124             if ('Artist' in metadata)
125                 bluetooth.artist = metadata.Artist
126
127             if ('Title' in metadata)
128                 bluetooth.title = metadata.Title
129         }
130     }
131
132     Connections {
133         target: mediaplayer
134
135         onPlaylistChanged: {
136             playlist_model.clear();
137
138             for (var i = 0; i < playlist.list.length; i++) {
139                 var item = playlist.list[i]
140
141                 playlist_model.append({ "index": item.index, "artist": item.artist ? item.artist : '', "title": item.title ? item.title : '' })
142
143                 if (item.selected) {
144                     playlistview.currentIndex = i
145                 }
146             }
147         }
148
149         onMetadataChanged: {
150             player.title = metadata.title
151             player.album = metadata.album
152             player.artist = metadata.artist
153
154             if (metadata.duration) {
155                 player.duration = metadata.duration
156             }
157
158             if (metadata.position) {
159                 player.position = metadata.position
160             }
161
162             if (metadata.status) {
163                 player.status = metadata.status
164             }
165
166             if (metadata.image) {
167                 player.cover_art = metadata.image
168             }
169
170             playlistview.currentIndex = metadata.index
171         }
172     }
173
174     Timer {
175         id: timer
176         interval: 250
177         running: (bluetooth.av_connected && bluetooth.state == "playing")
178         repeat: true
179         onTriggered: {
180             bluetooth.position = bluetooth.position + 250
181         }
182     }
183
184     ListModel {
185         id: playlist_model
186     }
187
188     ColumnLayout {
189         anchors.fill: parent
190         Item {
191             Layout.fillWidth: true
192             Layout.fillHeight: true
193             Layout.preferredHeight: 1080
194             clip: true
195             Image {
196                 id: albumart
197                 anchors.left: parent.left
198                 anchors.right: parent.right
199                 anchors.bottom: parent.bottom
200                 height: sourceSize.height * width / sourceSize.width
201                 fillMode: Image.PreserveAspectCrop
202                 source: player.cover_art ? player.cover_art : ''
203                 visible: bluetooth.av_connected == false
204             }
205
206             Item {
207                 anchors.left: parent.left
208                 anchors.right: parent.right
209                 anchors.bottom: parent.bottom
210                 height :307
211                 Rectangle {
212                     anchors.fill: parent
213                     color: 'black'
214                     opacity: 0.75
215                 }
216
217                 ColumnLayout {
218                     anchors.fill: parent
219                     anchors.margins: root.width * 0.02
220                     Item {
221                         Layout.fillWidth: true
222                         Layout.fillHeight: true
223                         Row {
224                             spacing: 20
225                             //ToggleButton {
226                             //    id: random
227                             //    visible: bluetooth.connected == false
228                             //    offImage: './images/AGL_MediaPlayer_Shuffle_Inactive.svg'
229                             //    onImage: './images/AGL_MediaPlayer_Shuffle_Active.svg'
230                             //}
231                             ToggleButton {
232                                 id: loop
233                                 visible: bluetooth.connected == false
234                                 //checked: player.loop_state
235                                 offImage: './images/AGL_MediaPlayer_Loop_Inactive.svg'
236                                 onImage: './images/AGL_MediaPlayer_Loop_Active.svg'
237                                 onClicked: { mediaplayer.loop(checked) }
238                             }
239                         }
240                         ColumnLayout {
241                             anchors.fill: parent
242                             Label {
243                                 id: title
244                                 Layout.alignment: Layout.Center
245                                 text: bluetooth.av_connected ? bluetooth.title : (player.title ? player.title : '')
246                                 horizontalAlignment: Label.AlignHCenter
247                                 verticalAlignment: Label.AlignVCenter
248                             }
249                             Label {
250                                 Layout.alignment: Layout.Center
251                                 text: bluetooth.av_connected ? bluetooth.artist : (player.artist ? player.artist : '')
252                                 horizontalAlignment: Label.AlignHCenter
253                                 verticalAlignment: Label.AlignVCenter
254                                 font.pixelSize: title.font.pixelSize * 0.6
255                             }
256                         }
257                     }
258                     Slider {
259                         id: slider
260                         Layout.fillWidth: true
261                         to: bluetooth.av_connected ? bluetooth.duration : player.duration
262                         enabled: bluetooth.av_connected == false
263                         value: bluetooth.av_connected ? bluetooth.position : player.position
264                         function getPosition() {
265                             if (bluetooth.av_connected) {
266                                 return player.time2str(bluetooth.position)
267                             }
268                             return player.time2str(player.position)
269                         }
270                         Label {
271                             id: position
272                             anchors.left: parent.left
273                             anchors.bottom: parent.top
274                             font.pixelSize: 32
275                             text: slider.getPosition()
276                         }
277                         Label {
278                             id: duration
279                             anchors.right: parent.right
280                             anchors.bottom: parent.top
281                             font.pixelSize: 32
282                             text: bluetooth.av_connected ? player.time2str(bluetooth.duration) : player.time2str(player.duration)
283                         }
284                         onPressedChanged: mediaplayer.seek(value)
285                     }
286                     RowLayout {
287                         Layout.fillHeight: true
288 //                        Image {
289 //                            source: './images/AGL_MediaPlayer_Playlist_Inactive.svg'
290 //                        }
291 //                        Image {
292 //                            source: './images/AGL_MediaPlayer_CD_Inactive.svg'
293 //                        }
294                         Item { Layout.fillWidth: true }
295                         ImageButton {
296                             id: previous
297                             offImage: './images/AGL_MediaPlayer_BackArrow.svg'
298                             onClicked: {
299                                 if (bluetooth.av_connected) {
300                                     bluetooth.set_avrcp_controls("Previous")
301                                     bluetooth.position = 0
302                                 } else {
303                                     mediaplayer.previous()
304                                 }
305                             }
306                         }
307                         ImageButton {
308                             id: play
309                             offImage: './images/AGL_MediaPlayer_Player_Play.svg'
310                             onClicked: {
311                                 if (bluetooth.av_connected) {
312                                     bluetooth.set_avrcp_controls("Play")
313                                 } else {
314                                     mediaplayer.play()
315                                 }
316                             }
317                             states: [
318                                 State {
319                                     when: player.status == "playing"
320                                     PropertyChanges {
321                                         target: play
322                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
323                                         onClicked: {
324                                             player.status = ""
325                                             mediaplayer.pause()
326                                         }
327                                     }
328                                 },
329                                 State {
330                                     when: bluetooth.av_connected && bluetooth.state == "playing"
331                                     PropertyChanges {
332                                         target: play
333                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
334                                         onClicked: bluetooth.set_avrcp_controls("Pause")
335                                     }
336                                 }
337
338                             ]
339                         }
340                         ImageButton {
341                             id: forward
342                             offImage: './images/AGL_MediaPlayer_ForwardArrow.svg'
343                             onClicked: {
344                                 if (bluetooth.av_connected) {
345                                     bluetooth.set_avrcp_controls("Next")
346                                 } else {
347                                     mediaplayer.next()
348                                 }
349                             }
350                         }
351
352                         Item { Layout.fillWidth: true }
353  
354                         ToggleButton {
355                               visible: bluetooth.connected
356                               checked: bluetooth.av_connected
357                               offImage: './images/AGL_MediaPlayer_Bluetooth_Inactive.svg'
358                               onImage: './images/AGL_MediaPlayer_Bluetooth_Active.svg'
359
360                               onClicked: {
361                                   if (bluetooth.av_connected) {
362                                       bluetooth.disconnect_profiles()
363                                   } else {
364                                       bluetooth.connect_profiles()
365                                   }
366                               }
367                         }
368                     }
369                 }
370             }
371         }
372         Item {
373             Layout.fillWidth: true
374             Layout.fillHeight: true
375             Layout.preferredHeight: 407
376
377             ListView {
378                 anchors.fill: parent
379                 id: playlistview
380                 visible: bluetooth.av_connected == false
381                 clip: true
382                 header: Label {
383                     x: 50
384                     text: 'PLAYLIST'
385                     opacity: 0.5
386                 }
387                 model: playlist_model
388                 currentIndex: -1
389
390                 delegate: MouseArea {
391                     id: delegate
392                     width: ListView.view.width
393                     height: ListView.view.height / 4
394                     RowLayout {
395                         anchors.fill: parent
396                         anchors.leftMargin: 50
397                         anchors.rightMargin: 50
398                         ColumnLayout {
399                             Layout.fillWidth: true
400                             Label {
401                                 Layout.fillWidth: true
402                                 text: model.title
403                             }
404                             Label {
405                                 Layout.fillWidth: true
406                                 text: model.artist
407                                 color: '#00ADDC'
408                                 font.pixelSize: 32
409                             }
410                         }
411                         //Label {
412                         //    text: player.time2str(model.duration)
413                         //    color: '#00ADDC'
414                         //    font.pixelSize: 32
415                         //}
416                     }
417                     onClicked: {
418                         mediaplayer.picktrack(playlistview.model.get(index).index)
419                     }
420                 }
421
422                 highlight: Rectangle {
423                     color: 'white'
424                     opacity: 0.25
425                 }
426             }
427         }
428     }
429 }