Adopt statemachine class to manage sound right
[apps/mediaplayer.git] / app / MediaPlayer.qml
1 /*
2  * Copyright (C) 2016 The Qt Company Ltd.
3  * Copyright (C) 2017 Toyota Motor Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 import QtQuick 2.6
19 import QtQuick.Layouts 1.1
20 import QtQuick.Controls 2.0
21 import QtMultimedia 5.6
22 import AGL.Demo.Controls 1.0
23 import QtQml.StateMachine 1.0 as MPSM
24 import 'api' as API
25
26 ApplicationWindow {
27     id: root
28     
29     property int sourceID: 0
30     property int connectionID
31     signal playMediaplayer
32     signal stopMediaplayer
33     signal disconnected
34     signal paused
35     signal connected
36     API.MediaPlayer {
37         id: player
38         url: bindingAddress
39     }
40
41     API.BluetoothManager {
42         id: bluetooth
43         url: bindingAddress
44     }
45
46     MPSM.StateMachine{
47         id: mediaplayerState
48         initialState: stop
49         running: true
50         MPSM.State{
51             id: haveSoundRight
52             MPSM.SignalTransition{
53                 targetState: stop
54                 signal: disconnected
55             }
56             MPSM.SignalTransition{
57                 targetState: pause
58                 signal: paused
59             }
60             MPSM.SignalTransition{
61                 targetState: playing
62                 signal: playMediaplayer
63             }
64             onEntered: {
65                 console.log("enter haveSoundRight")
66             }
67             onExited : {
68                 // Nothing to do
69             }
70         }
71         MPSM.State{
72             id: stop
73             MPSM.SignalTransition{
74                 targetState: haveSoundRight
75                 signal: connected
76             }
77             onEntered: {
78                 console.log("enter stop state")
79             }
80             onExited : {
81                 // Nothing to do
82             }
83         }
84         MPSM.State{
85             id: pause
86             MPSM.SignalTransition{
87                 targetState: haveSoundRight
88                 signal: connected
89             }
90             MPSM.SignalTransition{
91                 targetState: stop
92                 signal: disconnected
93             }
94             onEntered: {
95                 console.log("enter pause state")
96             }
97             onExited : {
98                 // Nothing to do
99             }
100         }
101         MPSM.State{
102             id: playing
103             MPSM.SignalTransition{
104                 targetState: haveSoundRight
105                 signal: stopMediaplayer
106             }
107             MPSM.SignalTransition{
108                 targetState: lostSoundRight
109                 signal: disconnected
110             }
111             onEntered: {
112                 console.log("enter playing state")
113                 player.play()
114             }
115             onExited : {
116                 player.pause()
117             }
118         }
119         MPSM.State{
120             id: lostSoundRight
121             MPSM.SignalTransition{
122                 targetState: playing
123                 signal: connected
124             }
125             onEntered: {
126                 console.log("enter lostSoundRight")
127             }
128             onExited : {
129             }
130         }
131         MPSM.State{
132             id: temporaryLostSoundRight
133             MPSM.SignalTransition{
134                 targetState: playing
135                 signal: connected
136             }
137             MPSM.SignalTransition{
138                 targetState: lostSoundRight
139                 signal: disconnected
140             }
141             onEntered: {
142                 console.log("enter lostSoundRight")
143             }
144             onExited : {
145             }
146         }
147     }
148
149     function slotReply(msg){
150         var jstr = JSON.stringify(msg)
151         var content = JSON.parse(jstr);
152         var verb = content.response.verb
153         var err = content.response.error
154         switch(verb)
155         {
156             case "connect":
157                 if(err == 0){
158                     connectionID = content.response.mainConnectionID
159                 }
160                 break;
161             case "registerSource":
162                 if(err == 0){
163                     sourceID = content.response.sourceID
164                 }
165         }
166     }
167
168     function slotEvent(event,msg){
169         var jstr = JSON.stringify(msg)
170         var content = JSON.parse(jstr);
171         var eventName = content.event
172         switch(eventName)
173         {
174             case "soundmanager\/asyncSetSourceState":
175                 // This event doesn't come for now
176                 if(sourceID == content.data.sourceID){
177                     console.log("mediaplayer: call ackSetSourceState")
178                     smw.ackSetSourceState(content.data.handle, 0)
179                     switch(content.data.sourceState){
180                         case "on":
181                             connected()
182                             break;
183                         case "off":
184                             disconnected()
185                             break;
186                         case "paused":
187                             paused()
188                             break;
189                         default:
190                             break;
191                     }
192                 }
193                 break;
194             default:
195                 break;
196         }
197     }
198
199     Timer {
200         id: timer
201         interval: 250
202         running: (bluetooth.av_connected && bluetooth.state == "playing")
203         repeat: true
204         onTriggered: {
205             bluetooth.position = bluetooth.position + 250
206             slider.value = bluetooth.position
207         }
208     }
209
210     ListModel {
211         id: playlist
212     }
213
214     ColumnLayout {
215         anchors.fill: parent
216         Item {
217             Layout.fillWidth: true
218             Layout.fillHeight: true
219             Layout.preferredHeight: 1080
220             clip: true
221             Image {
222                 id: albumart
223                 anchors.left: parent.left
224                 anchors.right: parent.right
225                 anchors.bottom: parent.bottom
226                 height: sourceSize.height * width / sourceSize.width
227                 fillMode: Image.PreserveAspectCrop
228                 source: player.cover_art ? player.cover_art : ''
229                 visible: bluetooth.av_connected == false
230             }
231
232             Item {
233                 anchors.left: parent.left
234                 anchors.right: parent.right
235                 anchors.bottom: parent.bottom
236                 height :307
237                 Rectangle {
238                     anchors.fill: parent
239                     color: 'black'
240                     opacity: 0.75
241                 }
242
243                 ColumnLayout {
244                     anchors.fill: parent
245                     anchors.margins: root.width * 0.02
246                     Item {
247                         Layout.fillWidth: true
248                         Layout.fillHeight: true
249                         Row {
250                             spacing: 20
251                             //ToggleButton {
252                             //    id: random
253                             //    visible: bluetooth.connected == false
254                             //    offImage: './images/AGL_MediaPlayer_Shuffle_Inactive.svg'
255                             //    onImage: './images/AGL_MediaPlayer_Shuffle_Active.svg'
256                             //}
257                             ToggleButton {
258                                 id: loop
259                                 visible: bluetooth.connected == false
260                                 checked: player.loop_state
261                                 offImage: './images/AGL_MediaPlayer_Loop_Inactive.svg'
262                                 onImage: './images/AGL_MediaPlayer_Loop_Active.svg'
263                                 onClicked: { player.loop(checked) }
264                             }
265                         }
266                         ColumnLayout {
267                             anchors.fill: parent
268                             Label {
269                                 id: title
270                                 Layout.alignment: Layout.Center
271                                 text: bluetooth.av_connected ? bluetooth.title : (player.title ? player.title : '')
272                                 horizontalAlignment: Label.AlignHCenter
273                                 verticalAlignment: Label.AlignVCenter
274                             }
275                             Label {
276                                 Layout.alignment: Layout.Center
277                                 text: bluetooth.av_connected ? bluetooth.artist : (player.artist ? player.artist : '')
278                                 horizontalAlignment: Label.AlignHCenter
279                                 verticalAlignment: Label.AlignVCenter
280                                 font.pixelSize: title.font.pixelSize * 0.6
281                             }
282                         }
283                     }
284                     Slider {
285                         id: slider
286                         Layout.fillWidth: true
287                         to: bluetooth.av_connected ? bluetooth.duration : player.duration
288                         enabled: bluetooth.av_connected == false
289                         value: bluetooth.av_connected ? bluetooth.position : player.position
290                         function getPosition() {
291                             if (bluetooth.av_connected) {
292                                 return player.time2str(bluetooth.position)
293                             }
294                             return player.time2str(player.position)
295                         }
296                         Label {
297                             id: position
298                             anchors.left: parent.left
299                             anchors.bottom: parent.top
300                             font.pixelSize: 32
301                             text: slider.getPosition()
302                         }
303                         Label {
304                             id: duration
305                             anchors.right: parent.right
306                             anchors.bottom: parent.top
307                             font.pixelSize: 32
308                             text: bluetooth.av_connected ? player.time2str(bluetooth.duration) : player.time2str(player.duration)
309                         }
310                         onPressedChanged: player.seek(value)
311                     }
312                     RowLayout {
313                         Layout.fillHeight: true
314 //                        Image {
315 //                            source: './images/AGL_MediaPlayer_Playlist_Inactive.svg'
316 //                        }
317 //                        Image {
318 //                            source: './images/AGL_MediaPlayer_CD_Inactive.svg'
319 //                        }
320                         Item { Layout.fillWidth: true }
321                         ImageButton {
322                             id: previous
323                             offImage: './images/AGL_MediaPlayer_BackArrow.svg'
324                             onClicked: {
325                                 if (bluetooth.av_connected) {
326                                     bluetooth.sendMediaCommand("Previous")
327                                     bluetooth.position = 0
328                                 } else {
329                                     player.previous()
330                                 }
331                             }
332                         }
333                         ImageButton {
334                             id: play
335                             offImage: './images/AGL_MediaPlayer_Player_Play.svg'
336                             onClicked: {
337                                 if (bluetooth.av_connected) {
338                                     bluetooth.sendMediaCommand("Play")
339                                 } else {
340                                     playMediaplayer()
341                                 }
342                             }
343                             states: [
344                                 State {
345                                     when: player.running === true
346                                     PropertyChanges {
347                                         target: play
348                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
349                                         onClicked: {
350                                             stopMediaplayer()
351                                         }
352                                     }
353                                 },
354                                 State {
355                                     when: bluetooth.av_connected && bluetooth.state == "playing"
356                                     PropertyChanges {
357                                         target: play
358                                         offImage: './images/AGL_MediaPlayer_Player_Pause.svg'
359                                         onClicked: bluetooth.sendMediaCommand("Pause")
360                                     }
361                                 }
362
363                             ]
364                         }
365                         ImageButton {
366                             id: forward
367                             offImage: './images/AGL_MediaPlayer_ForwardArrow.svg'
368                             onClicked: {
369                                 if (bluetooth.av_connected) {
370                                     bluetooth.sendMediaCommand("Next")
371                                 } else {
372                                     player.next()
373                                 }
374                             }
375                         }
376
377                         Item { Layout.fillWidth: true }
378  
379                         ToggleButton {
380                               visible: bluetooth.connected
381                               checked: bluetooth.av_connected
382                               offImage: './images/AGL_MediaPlayer_Bluetooth_Inactive.svg'
383                               onImage: './images/AGL_MediaPlayer_Bluetooth_Active.svg'
384
385                               onClicked: {
386                                   if (bluetooth.av_connected) {
387                                       bluetooth.disconnect_profiles()
388                                   } else {
389                                       bluetooth.connect_profiles()
390                                   }
391                               }
392                         }
393                     }
394                 }
395             }
396         }
397         Item {
398             Layout.fillWidth: true
399             Layout.fillHeight: true
400             Layout.preferredHeight: 407
401
402             ListView {
403                 anchors.fill: parent
404                 id: playlistview
405                 visible: bluetooth.av_connected == false
406                 clip: true
407                 header: Label {
408                     x: 50
409                     text: 'PLAYLIST'
410                     opacity: 0.5
411                 }
412                 model: playlist
413                 currentIndex: -1
414
415                 delegate: MouseArea {
416                     id: delegate
417                     width: ListView.view.width
418                     height: ListView.view.height / 4
419                     RowLayout {
420                         anchors.fill: parent
421                         anchors.leftMargin: 50
422                         anchors.rightMargin: 50
423                         ColumnLayout {
424                             Layout.fillWidth: true
425                             Label {
426                                 Layout.fillWidth: true
427                                 text: model.title
428                             }
429                             Label {
430                                 Layout.fillWidth: true
431                                 text: model.artist
432                                 color: '#66FF99'
433                                 font.pixelSize: 32
434                             }
435                         }
436                         //Label {
437                         //    text: player.time2str(model.duration)
438                         //    color: '#66FF99'
439                         //    font.pixelSize: 32
440                         //}
441                     }
442                     onClicked: {
443                         player.pick_track(playlistview.model.get(index).index)
444                         playMediaplayer()
445                     }
446                 }
447
448                 highlight: Rectangle {
449                     color: 'white'
450                     opacity: 0.25
451                 }
452             }
453         }
454         Component.onCompleted: {
455             smw.registerSource("mediaplayer")
456         }
457     }
458 }