libqtappfw: bluetooth: switch from qml websockets to libqtappfw
[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             bluetooth.connected = data.Connected == "True"
109             bluetooth.av_connected = data.AVPConnected == "True"
110             bluetooth.deviceAddress = data.Address
111
112             if ('Position' in metadata)
113                 bluetooth.position = metadata.Position
114
115             if ('Duration' in metadata)
116                 bluetooth.duration = metadata.Duration
117
118             if ('Status' in metadata)
119                 bluetooth.state = metadata.Status
120
121             if ('Artist' in metadata)
122                 bluetooth.artist = metadata.Artist
123
124             if ('Title' in metadata)
125                 bluetooth.title = metadata.Title
126         }
127     }
128
129     Connections {
130         target: mediaplayer
131
132         onPlaylistChanged: {
133             playlist.clear()
134
135             for (var i = 0; i < playlist.list.length; i++) {
136                 var item = playlist.list[i]
137
138                 playlist_model.append({ "index": item.index, "artist": item.artist ? item.artist : '', "title": item.title ? item.title : '' })
139
140                 if (item.selected) {
141                     playlistview.currentIndex = i
142                 }
143             }
144         }
145
146         onMetadataChanged: {
147             player.title = metadata.title
148             player.album = metadata.album
149             player.artist = metadata.artist
150
151             if (metadata.duration) {
152                 player.duration = metadata.duration
153             }
154
155             if (metadata.position) {
156                 player.position = metadata.position
157             }
158
159             if (metadata.status) {
160                 player.status = metadata.status
161             }
162
163             if (metadata.image) {
164                 player.cover_art = metadata.image
165             }
166
167             playlistview.currentIndex = metadata.index
168         }
169     }
170
171     Timer {
172         id: timer
173         interval: 250
174         running: (bluetooth.av_connected && bluetooth.state == "playing")
175         repeat: true
176         onTriggered: {
177             bluetooth.position = bluetooth.position + 250
178         }
179     }
180
181     ListModel {
182         id: playlist_model
183     }
184
185     ColumnLayout {
186         anchors.fill: parent
187         Item {
188             Layout.fillWidth: true
189             Layout.fillHeight: true
190             Layout.preferredHeight: 1080
191             clip: true
192             Image {
193                 id: albumart
194                 anchors.left: parent.left
195                 anchors.right: parent.right
196                 anchors.bottom: parent.bottom
197                 height: sourceSize.height * width / sourceSize.width
198                 fillMode: Image.PreserveAspectCrop
199                 source: player.cover_art ? player.cover_art : ''
200                 visible: bluetooth.av_connected == false
201             }
202
203             Item {
204                 anchors.left: parent.left
205                 anchors.right: parent.right
206                 anchors.bottom: parent.bottom
207                 height :307
208                 Rectangle {
209                     anchors.fill: parent
210                     color: 'black'
211                     opacity: 0.75
212                 }
213
214                 ColumnLayout {
215                     anchors.fill: parent
216                     anchors.margins: root.width * 0.02
217                     Item {
218                         Layout.fillWidth: true
219                         Layout.fillHeight: true
220                         Row {
221                             spacing: 20
222                             //ToggleButton {
223                             //    id: random
224                             //    visible: bluetooth.connected == false
225                             //    offImage: './images/AGL_MediaPlayer_Shuffle_Inactive.svg'
226                             //    onImage: './images/AGL_MediaPlayer_Shuffle_Active.svg'
227                             //}
228                             ToggleButton {
229                                 id: loop
230                                 visible: bluetooth.connected == false
231                                 //checked: player.loop_state
232                                 offImage: './images/AGL_MediaPlayer_Loop_Inactive.svg'
233                                 onImage: './images/AGL_MediaPlayer_Loop_Active.svg'
234                                 onClicked: { mediaplayer.loop(checked) }
235                             }
236                         }
237                         ColumnLayout {
238                             anchors.fill: parent
239                             Label {
240                                 id: title
241                                 Layout.alignment: Layout.Center
242                                 text: bluetooth.av_connected ? bluetooth.title : (player.title ? player.title : '')
243                                 horizontalAlignment: Label.AlignHCenter
244                                 verticalAlignment: Label.AlignVCenter
245                             }
246                             Label {
247                                 Layout.alignment: Layout.Center
248                                 text: bluetooth.av_connected ? bluetooth.artist : (player.artist ? player.artist : '')
249                                 horizontalAlignment: Label.AlignHCenter
250                                 verticalAlignment: Label.AlignVCenter
251                                 font.pixelSize: title.font.pixelSize * 0.6
252                             }
253                         }
254                     }
255                     Slider {
256                         id: slider
257                         Layout.fillWidth: true
258                         to: bluetooth.av_connected ? bluetooth.duration : player.duration
259                         enabled: bluetooth.av_connected == false
260                         value: bluetooth.av_connected ? bluetooth.position : player.position
261                         function getPosition() {
262                             if (bluetooth.av_connected) {
263                                 return player.time2str(bluetooth.position)
264                             }
265                             return player.time2str(player.position)
266                         }
267                         Label {
268                             id: position
269                             anchors.left: parent.left
270                             anchors.bottom: parent.top
271                             font.pixelSize: 32
272                             text: slider.getPosition()
273                         }
274                         Label {
275                             id: duration
276                             anchors.right: parent.right
277                             anchors.bottom: parent.top
278                             font.pixelSize: 32
279                             text: bluetooth.av_connected ? player.time2str(bluetooth.duration) : player.time2str(player.duration)
280                         }
281                         onPressedChanged: mediaplayer.seek(value)
282                     }
283                     RowLayout {
284                         Layout.fillHeight: true
285 //                        Image {
286 //                            source: './images/AGL_MediaPlayer_Playlist_Inactive.svg'
287 //                        }
288 //                        Image {
289 //                            source: './images/AGL_MediaPlayer_CD_Inactive.svg'
290 //                        }
291                         Item { Layout.fillWidth: true }
292                         ImageButton {
293                             id: previous
294                             offImage: './images/AGL_MediaPlayer_BackArrow.svg'
295                             onClicked: {
296                                 if (bluetooth.av_connected) {
297                                     bluetooth.set_avrcp_controls("Previous")
298                                     bluetooth.position = 0
299                                 } else {
300                                     mediaplayer.previous()
301                                 }
302                             }
303                         }
304                         ImageButton {
305                             id: play
306                             offImage: './images/AGL_MediaPlayer_Player_Play.svg'
307                             onClicked: {
308                                 if (bluetooth.av_connected) {
309                                     bluetooth.set_avrcp_controls("Play")
310                                 } else {
311                                     mediaplayer.play()
312                                 }
313                             }
314                             states: [
315                                 State {
316                                     when: player.status == "playing"
317                                     PropertyChanges {
318                                         target: play
319                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
320                                         onClicked: {
321                                             player.status = ""
322                                             mediaplayer.pause()
323                                         }
324                                     }
325                                 },
326                                 State {
327                                     when: bluetooth.av_connected && bluetooth.state == "playing"
328                                     PropertyChanges {
329                                         target: play
330                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
331                                         onClicked: bluetooth.set_avrcp_controls("Pause")
332                                     }
333                                 }
334
335                             ]
336                         }
337                         ImageButton {
338                             id: forward
339                             offImage: './images/AGL_MediaPlayer_ForwardArrow.svg'
340                             onClicked: {
341                                 if (bluetooth.av_connected) {
342                                     bluetooth.set_avrcp_controls("Next")
343                                 } else {
344                                     mediaplayer.next()
345                                 }
346                             }
347                         }
348
349                         Item { Layout.fillWidth: true }
350  
351                         ToggleButton {
352                               visible: bluetooth.connected
353                               checked: bluetooth.av_connected
354                               offImage: './images/AGL_MediaPlayer_Bluetooth_Inactive.svg'
355                               onImage: './images/AGL_MediaPlayer_Bluetooth_Active.svg'
356
357                               onClicked: {
358                                   if (bluetooth.av_connected) {
359                                       bluetooth.disconnect_profiles()
360                                   } else {
361                                       bluetooth.connect_profiles()
362                                   }
363                               }
364                         }
365                     }
366                 }
367             }
368         }
369         Item {
370             Layout.fillWidth: true
371             Layout.fillHeight: true
372             Layout.preferredHeight: 407
373
374             ListView {
375                 anchors.fill: parent
376                 id: playlistview
377                 visible: bluetooth.av_connected == false
378                 clip: true
379                 header: Label {
380                     x: 50
381                     text: 'PLAYLIST'
382                     opacity: 0.5
383                 }
384                 model: playlist_model
385                 currentIndex: -1
386
387                 delegate: MouseArea {
388                     id: delegate
389                     width: ListView.view.width
390                     height: ListView.view.height / 4
391                     RowLayout {
392                         anchors.fill: parent
393                         anchors.leftMargin: 50
394                         anchors.rightMargin: 50
395                         ColumnLayout {
396                             Layout.fillWidth: true
397                             Label {
398                                 Layout.fillWidth: true
399                                 text: model.title
400                             }
401                             Label {
402                                 Layout.fillWidth: true
403                                 text: model.artist
404                                 color: '#00ADDC'
405                                 font.pixelSize: 32
406                             }
407                         }
408                         //Label {
409                         //    text: player.time2str(model.duration)
410                         //    color: '#00ADDC'
411                         //    font.pixelSize: 32
412                         //}
413                     }
414                     onClicked: {
415                         mediaplayer.picktrack(playlistview.model.get(index).index)
416                     }
417                 }
418
419                 highlight: Rectangle {
420                     color: 'white'
421                     opacity: 0.25
422                 }
423             }
424         }
425     }
426 }