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