Merge lp:~justinmcp/webbrowser-app/mediaplayer into lp:webbrowser-app
- mediaplayer
- Merge into trunk
Proposed by
Justin McPherson
Status: | Work in progress |
---|---|
Proposed branch: | lp:~justinmcp/webbrowser-app/mediaplayer |
Merge into: | lp:webbrowser-app |
Diff against target: |
1082 lines (+991/-1) 11 files modified
src/Ubuntu/Web/Controls.qml (+285/-0) src/Ubuntu/Web/HLine.qml (+28/-0) src/Ubuntu/Web/IconButton.qml (+43/-0) src/Ubuntu/Web/MediaPlayer.qml (+226/-0) src/Ubuntu/Web/SceneFrame.qml (+79/-0) src/Ubuntu/Web/TimeLabel.qml (+58/-0) src/Ubuntu/Web/TimeLine.qml (+89/-0) src/Ubuntu/Web/UbuntuWebView02.qml (+36/-0) src/Ubuntu/Web/VLine.qml (+54/-0) src/Ubuntu/Web/VideoSlider.qml (+89/-0) src/app/webcontainer/webapp-container.cpp (+4/-1) |
To merge this branch: | bzr merge lp:~justinmcp/webbrowser-app/mediaplayer |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phablet Team | Pending | ||
Review via email: mp+260911@code.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Unmerged revisions
- 1001. By Justin McPherson
-
Merge from trunk.
- 1000. By Justin McPherson <justin@phablet-dev>
-
WIP
- 999. By Justin McPherson <justin@phablet-dev>
-
WIP
- 998. By Justin McPherson <justin@phablet-dev>
-
WIP
- 997. By Justin McPherson <justin@phablet-dev>
-
WIP
- 996. By Justin McPherson <justin@phablet-dev>
-
WIP
- 995. By Justin McPherson <justin@phablet-dev>
-
WIP
- 994. By Justin McPherson <justin@phablet-dev>
-
WIP
- 993. By Justin McPherson <justin@phablet-dev>
-
WIP
- 992. By Justin McPherson <justin@phablet-dev>
-
wip
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === added file 'src/Ubuntu/Web/Controls.qml' |
2 | --- src/Ubuntu/Web/Controls.qml 1970-01-01 00:00:00 +0000 |
3 | +++ src/Ubuntu/Web/Controls.qml 2015-08-03 07:20:39 +0000 |
4 | @@ -0,0 +1,285 @@ |
5 | +/* |
6 | + * Copyright (C) 2013 Canonical, Ltd. |
7 | + * |
8 | + * Authors: |
9 | + * Ugo Riboni <ugo.riboni@canonical.com> |
10 | + * MichaĆ Sawicz <michal.sawicz@canonical.com> |
11 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
12 | + * |
13 | + * This program is free software; you can redistribute it and/or modify |
14 | + * it under the terms of the GNU General Public License as published by |
15 | + * the Free Software Foundation; version 3. |
16 | + * |
17 | + * This program is distributed in the hope that it will be useful, |
18 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
19 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
20 | + * GNU General Public License for more details. |
21 | + * |
22 | + * You should have received a copy of the GNU General Public License |
23 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
24 | + */ |
25 | +import QtQuick 2.0 |
26 | +import QtMultimedia 5.0 |
27 | +import Ubuntu.Components 1.1 |
28 | + |
29 | +Item { |
30 | + id: controls |
31 | + |
32 | + readonly property string orientation: controls.width >= units.gu(60) ? "LANDSCAPE" : "PORTRAIT" |
33 | + property variant video: null |
34 | + property int maximumHeight: 0 |
35 | + property int heightOffset: 0 |
36 | + property variant playerStatus: MediaPlayer.NoMedia |
37 | + |
38 | + property alias settingsEnabled: _settingsButton.enabled |
39 | + |
40 | + signal closeClicked |
41 | + signal playbackClicked |
42 | + signal settingsClicked |
43 | + signal shareClicked |
44 | + signal seekRequested(int time) |
45 | + signal startSeek |
46 | + signal endSeek |
47 | + |
48 | + focus: true |
49 | + height: _toolbar.height |
50 | + |
51 | + Rectangle { |
52 | + id: _bgColor |
53 | + |
54 | + color: "black" |
55 | + opacity: 0.8 |
56 | + anchors.fill: parent |
57 | + } |
58 | + |
59 | + HLine { |
60 | + id: _divLine |
61 | + anchors { |
62 | + left: _toolbar.left |
63 | + right: _toolbar.right |
64 | + top: parent.top |
65 | + } |
66 | + } |
67 | + |
68 | + Column { |
69 | + id: _toolbar |
70 | + |
71 | + anchors { |
72 | + bottom: parent.bottom |
73 | + left: parent.left |
74 | + right: parent.right |
75 | + } |
76 | + height: childrenRect.height |
77 | + |
78 | + Item { |
79 | + id: timelinePlaceHolderPortrait |
80 | + |
81 | + anchors { |
82 | + left: parent.left |
83 | + right: parent.right |
84 | + } |
85 | + height: controls.orientation === "PORTRAIT" ? units.gu(5) : 0 |
86 | + } |
87 | + |
88 | + Row { |
89 | + id: controlsRow |
90 | + anchors { |
91 | + left: parent.left |
92 | + right: parent.right |
93 | + margins: units.gu(2) |
94 | + } |
95 | + height: units.gu(5) |
96 | + |
97 | + IconButton { |
98 | + id: _closeButton |
99 | + |
100 | + iconSource: "image://theme/close" |
101 | + iconSize: units.gu(3) |
102 | + anchors.verticalCenter: parent.verticalCenter |
103 | + width: units.gu(8) |
104 | + height: units.gu(4) |
105 | + onClicked: controls.closeClicked() |
106 | + leftAlignment: true |
107 | + } |
108 | + |
109 | + VLine { |
110 | + } |
111 | + |
112 | + IconButton { |
113 | + id: playbackButton |
114 | + objectName: "Controls.PlayBackButton" |
115 | + |
116 | + property string icon |
117 | + |
118 | + iconSource: icon ? "image://theme/media-playback-%1".arg(icon) : "" |
119 | + iconSize: units.gu(3) |
120 | + anchors.verticalCenter: parent.verticalCenter |
121 | + width: controls.orientation === "LANDSCAPE" ? units.gu(10) : |
122 | + controlsRow.width - |
123 | + _closeButton.width - |
124 | + _timeLabel.width - |
125 | + _shareButton.width - |
126 | + _settingsButton.width |
127 | + |
128 | + height: units.gu(4) |
129 | + onClicked: { |
130 | + controls.playbackClicked() |
131 | + } |
132 | + } |
133 | + |
134 | + VLine { |
135 | + } |
136 | + |
137 | + Item { |
138 | + id: timelinePlaceHolderLandscape |
139 | + |
140 | + anchors { |
141 | + top: parent.top |
142 | + bottom: parent.bottom |
143 | + } |
144 | + |
145 | + width: controls.orientation === "LANDSCAPE" ? controlsRow.width - |
146 | + _closeButton.width - |
147 | + playbackButton.width - |
148 | + _timeLabel.width - |
149 | + _shareButton.width - |
150 | + _settingsButton.width - |
151 | + units.gu(2) : 0 |
152 | + |
153 | + |
154 | + TimeLine { |
155 | + id: _timeline |
156 | + |
157 | + property bool seeking: false |
158 | + |
159 | + anchors { |
160 | + left: parent.left |
161 | + right: parent.right |
162 | + margins: units.gu(2) |
163 | + verticalCenter: parent.verticalCenter |
164 | + } |
165 | + height: units.gu(4) |
166 | + parent: controls.orientation === "PORTRAIT" ? timelinePlaceHolderPortrait : timelinePlaceHolderLandscape |
167 | + minimumValue: 0 |
168 | + maximumValue: video ? video.duration / 1000 : 0 |
169 | + |
170 | + // pause the video during the seek |
171 | + onPressedChanged: { |
172 | + if (!pressed && seeking) { |
173 | + endSeek() |
174 | + seeking = false |
175 | + } |
176 | + } |
177 | + |
178 | + // Live value is the real slider value. Ex: User dragging the slider |
179 | + onLiveValueChanged: { |
180 | + if (video) { |
181 | + var changed = Math.abs(liveValue - videoPosition) |
182 | + if (changed > 1) { |
183 | + if (!seeking) { |
184 | + startSeek() |
185 | + seeking = true |
186 | + } |
187 | + seekRequested(liveValue * 1000) |
188 | + } |
189 | + } |
190 | + } |
191 | + } |
192 | + } |
193 | + |
194 | + VLine { |
195 | + visible: controls.orientation === "LANDSCAPE" |
196 | + } |
197 | + |
198 | + TimeLabel { |
199 | + id: _timeLabel |
200 | + |
201 | + remainingTime: _timeline.remainingTime |
202 | + currentTime: _timeline.currentTime |
203 | + |
204 | + anchors { |
205 | + top: parent.top |
206 | + bottom: parent.bottom |
207 | + } |
208 | + width: controls.orientation === "LANDSCAPE" ? units.gu(10) : units.gu(8) |
209 | + } |
210 | + |
211 | + VLine { |
212 | + visible: _shareButton.visible |
213 | + } |
214 | + |
215 | + IconButton { |
216 | + id: _shareButton |
217 | + |
218 | + /* Disable share button for now until we get some feedback from designers */ |
219 | + visible: false |
220 | + iconSource: "artwork/icon_share.png" |
221 | + iconSize: units.gu(3) |
222 | + anchors { |
223 | + top: parent.top |
224 | + bottom: parent.bottom |
225 | + } |
226 | + width: visible ? units.gu(7) : 0 |
227 | + onClicked: controls.shareClicked() |
228 | + } |
229 | + |
230 | + VLine { |
231 | + visible: _settingsButton.visible |
232 | + } |
233 | + |
234 | + IconButton { |
235 | + id: _settingsButton |
236 | + |
237 | + visible: false |
238 | + iconSource: "artwork/icon_settings.png" |
239 | + iconSize: units.gu(3) |
240 | + anchors { |
241 | + top: parent.top |
242 | + bottom: parent.bottom |
243 | + } |
244 | + width: visible ? units.gu(7) : 0 |
245 | + enabled: false |
246 | + opacity: enabled ? 1.0 : 0.2 |
247 | + onClicked: settingsClicked() |
248 | + } |
249 | + } |
250 | + } |
251 | + |
252 | + Connections { |
253 | + target: video |
254 | + |
255 | + onPositionChanged: { |
256 | + // To get position to be smooth and accurate during seeking, do |
257 | + // not use the reported value for position from media-hub but instead |
258 | + // use the value that the user move the scrubber to. This makes seeking |
259 | + // silky smooth. Report correctly on normal advance, or EOS. |
260 | + if (!_timeline.seeking || controls.playerStatus == MediaPlayer.EndOfMedia) |
261 | + _timeline.videoPosition = video ? video.position / 1000 : 0 |
262 | + } |
263 | + } |
264 | + |
265 | + Connections { |
266 | + target: controls |
267 | + onPlayerStatusChanged: { |
268 | + console.debug("onPlayerStatusChanged") |
269 | + _timeline.playerStatus = controls.playerStatus |
270 | + } |
271 | + } |
272 | + |
273 | + states: [ |
274 | + State { |
275 | + name: "stopped" |
276 | + PropertyChanges { target: playbackButton; icon: "start" } |
277 | + }, |
278 | + |
279 | + State { |
280 | + name: "playing" |
281 | + PropertyChanges { target: playbackButton; icon: "pause" } |
282 | + }, |
283 | + |
284 | + State { |
285 | + name: "paused" |
286 | + PropertyChanges { target: playbackButton; icon: "start" } |
287 | + } |
288 | + ] |
289 | +} |
290 | |
291 | === added file 'src/Ubuntu/Web/HLine.qml' |
292 | --- src/Ubuntu/Web/HLine.qml 1970-01-01 00:00:00 +0000 |
293 | +++ src/Ubuntu/Web/HLine.qml 2015-08-03 07:20:39 +0000 |
294 | @@ -0,0 +1,28 @@ |
295 | +/* |
296 | + * Copyright (C) 2013 Canonical, Ltd. |
297 | + * |
298 | + * Authors: |
299 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
300 | + * |
301 | + * This program is free software; you can redistribute it and/or modify |
302 | + * it under the terms of the GNU General Public License as published by |
303 | + * the Free Software Foundation; version 3. |
304 | + * |
305 | + * This program is distributed in the hope that it will be useful, |
306 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
307 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
308 | + * GNU General Public License for more details. |
309 | + * |
310 | + * You should have received a copy of the GNU General Public License |
311 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
312 | + */ |
313 | + |
314 | +import QtQuick 2.0 |
315 | +import Ubuntu.Components 1.1 |
316 | + |
317 | +Rectangle { |
318 | + height: units.dp(1) |
319 | + anchors.left: parent.left |
320 | + anchors.right: parent.right |
321 | + color: UbuntuColors.coolGrey |
322 | +} |
323 | |
324 | === added file 'src/Ubuntu/Web/IconButton.qml' |
325 | --- src/Ubuntu/Web/IconButton.qml 1970-01-01 00:00:00 +0000 |
326 | +++ src/Ubuntu/Web/IconButton.qml 2015-08-03 07:20:39 +0000 |
327 | @@ -0,0 +1,43 @@ |
328 | +/* |
329 | + * Copyright (C) 2013 Canonical, Ltd. |
330 | + * |
331 | + * Authors: |
332 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
333 | + * |
334 | + * This program is free software; you can redistribute it and/or modify |
335 | + * it under the terms of the GNU General Public License as published by |
336 | + * the Free Software Foundation; version 3. |
337 | + * |
338 | + * This program is distributed in the hope that it will be useful, |
339 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
340 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
341 | + * GNU General Public License for more details. |
342 | + * |
343 | + * You should have received a copy of the GNU General Public License |
344 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
345 | + */ |
346 | + |
347 | +import QtQuick 2.0 |
348 | +import Ubuntu.Components 1.1 |
349 | + |
350 | +AbstractButton { |
351 | + id: root |
352 | + |
353 | + property alias iconSource: _image.source |
354 | + property alias iconSize: _image.height |
355 | + property bool leftAlignment: false |
356 | + |
357 | + focus: false |
358 | + |
359 | + Image { |
360 | + id: _image |
361 | + |
362 | + width: height |
363 | + smooth: true |
364 | + anchors { |
365 | + verticalCenter: parent.verticalCenter |
366 | + horizontalCenter: root.leftAlignment ? undefined : parent.horizontalCenter |
367 | + left: root.leftAlignment ? parent.left : undefined |
368 | + } |
369 | + } |
370 | +} |
371 | |
372 | === added file 'src/Ubuntu/Web/MediaPlayer.qml' |
373 | --- src/Ubuntu/Web/MediaPlayer.qml 1970-01-01 00:00:00 +0000 |
374 | +++ src/Ubuntu/Web/MediaPlayer.qml 2015-08-03 07:20:39 +0000 |
375 | @@ -0,0 +1,226 @@ |
376 | +import QtQuick 2.0 |
377 | +import QtMultimedia 5.0 |
378 | +import "." |
379 | + |
380 | +Rectangle { |
381 | + id: mediaPlayer |
382 | + color: "black" |
383 | + state: "stopped" |
384 | + |
385 | + property var content |
386 | + |
387 | + property alias source: player.source |
388 | + property alias duration: player.duration |
389 | + property alias position: player.position |
390 | + property alias playbackState: player.playbackState |
391 | + property alias metaData: player.metaData |
392 | + |
393 | + signal closeClicked |
394 | + |
395 | + onContentChanged: { |
396 | + source = content.url |
397 | + } |
398 | + |
399 | + function play() { |
400 | + state = "playing" |
401 | + } |
402 | + |
403 | + function pause() { |
404 | + state = "paused" |
405 | + } |
406 | + |
407 | + function stop() { |
408 | + state = "stopped" |
409 | + } |
410 | + |
411 | + function playPause() { |
412 | + if (state == "playing") { |
413 | + state = "paused" |
414 | + } else { |
415 | + state = "playing" |
416 | + } |
417 | + } |
418 | + |
419 | + function seek(position) { |
420 | + player.seek(position) |
421 | + } |
422 | + |
423 | + MediaPlayer { |
424 | + id: player |
425 | + source: mediaPlayer.source |
426 | + |
427 | + onPlaybackStateChanged: { |
428 | + if (playbackState == MediaPlayer.PausedState) { |
429 | + mediaPlayer.pause() |
430 | + } else if (playbackState == MediaPlayer.PlayingState) { |
431 | + mediaPlayer.play() |
432 | + } |
433 | + } |
434 | + |
435 | + metaData.onMetaDataChanged: { |
436 | + mediaPlayer.metaDataChanged() |
437 | + } |
438 | + } |
439 | + |
440 | + VideoOutput { |
441 | + id: _videoOutput |
442 | + source: player |
443 | + anchors.fill: parent |
444 | + opacity: 0.0 |
445 | + |
446 | + Behavior on opacity { |
447 | + NumberAnimation { duration: 300 } |
448 | + } |
449 | + |
450 | + MouseArea { |
451 | + anchors { |
452 | + left: parent.left |
453 | + right: parent.right |
454 | + top: parent.top |
455 | + bottom: _controls.top |
456 | + } |
457 | + |
458 | + onClicked: { |
459 | + if (_controls.state == "open") { |
460 | + _controls.state = "closed" |
461 | + } else { |
462 | + _controls.state = "open" |
463 | + } |
464 | + } |
465 | + } |
466 | + |
467 | + Item { |
468 | + id: _controls |
469 | + height: _controlsContents.height |
470 | + anchors { |
471 | + left: parent.left |
472 | + right: parent.right |
473 | + } |
474 | + |
475 | + state: "closed" |
476 | + states: [ |
477 | + State { |
478 | + name: "open" |
479 | + PropertyChanges { |
480 | + target: _controls |
481 | + y: parent.height - height |
482 | + } |
483 | + }, |
484 | + State { |
485 | + name: "closed" |
486 | + PropertyChanges { |
487 | + target: _controls |
488 | + y: parent.height |
489 | + } |
490 | + } |
491 | + ] |
492 | + |
493 | + transitions: [ |
494 | + Transition { |
495 | + to: "closed" |
496 | + PropertyAnimation { |
497 | + target: _controls |
498 | + properties: "y" |
499 | + duration: 175 |
500 | + easing.type: Easing.OutQuad |
501 | + } |
502 | + }, |
503 | + Transition { |
504 | + to: "open" |
505 | + PropertyAnimation { |
506 | + target: _controls |
507 | + properties: "y" |
508 | + duration: 175 |
509 | + easing.type: Easing.OutQuad |
510 | + } |
511 | + } |
512 | + ] |
513 | + |
514 | + Controls { |
515 | + id: _controlsContents |
516 | + property bool isPaused: false |
517 | + |
518 | + settingsEnabled: false |
519 | + |
520 | + objectName: "controls" |
521 | + state: mediaPlayer.state |
522 | + video: player |
523 | + anchors { |
524 | + left: parent.left |
525 | + right: parent.right |
526 | + bottom: parent.bottom |
527 | + } |
528 | + |
529 | + maximumHeight: units.gu(27) |
530 | + playerStatus: player.mediaStatus |
531 | + |
532 | + onPlaybackClicked: { |
533 | + mediaPlayer.playPause() |
534 | + } |
535 | + |
536 | + onSeekRequested: { |
537 | + player.seek(time) |
538 | + } |
539 | + |
540 | + onStartSeek: { |
541 | + isPaused = (state == "paused") |
542 | + player.pause() |
543 | + } |
544 | + |
545 | + onEndSeek: { |
546 | + // Only automatically resume playing after a seek that is not to the |
547 | + // end of stream (i.e. position == duration) |
548 | + if (player.status != MediaPlayer.EndOfMedia && !isPaused) { |
549 | + player.play() |
550 | + } |
551 | + } |
552 | + |
553 | + onCloseClicked: { |
554 | + _controls.state = "closed" |
555 | + mediaPlayer.closeClicked(); |
556 | + } |
557 | + } |
558 | + } |
559 | + } |
560 | + |
561 | + Timer { |
562 | + id: scrubbingTimer |
563 | + interval: 500 |
564 | + repeat: true |
565 | + |
566 | + property int step |
567 | + |
568 | + onTriggered: { |
569 | + if (player.position + step < 0) { |
570 | + player.seek(0) |
571 | + mediaPlayer.state = "playing" |
572 | + } else { |
573 | + player.seek(mediaPlayer.position + step) |
574 | + } |
575 | + } |
576 | + } |
577 | + |
578 | + states: [ |
579 | + State { |
580 | + name: "stopped" |
581 | + StateChangeScript { script: player.stop() } |
582 | + PropertyChanges { target: scrubbingTimer; running: false } |
583 | + PropertyChanges { target: _videoOutput; opacity: 0.0 } |
584 | + }, |
585 | + |
586 | + State { |
587 | + name: "playing" |
588 | + PropertyChanges { target: player; playbackRate: 1.0; muted: false } |
589 | + StateChangeScript { script: player.play() } |
590 | + PropertyChanges { target: scrubbingTimer; running: false } |
591 | + PropertyChanges { target: _videoOutput; opacity: 1.0 } |
592 | + }, |
593 | + |
594 | + State { |
595 | + name: "paused" |
596 | + StateChangeScript { script: player.pause() } |
597 | + PropertyChanges { target: scrubbingTimer; running: false } |
598 | + PropertyChanges { target: _videoOutput; opacity: 1.0 } |
599 | + } |
600 | + ] |
601 | +} |
602 | |
603 | === added file 'src/Ubuntu/Web/SceneFrame.qml' |
604 | --- src/Ubuntu/Web/SceneFrame.qml 1970-01-01 00:00:00 +0000 |
605 | +++ src/Ubuntu/Web/SceneFrame.qml 2015-08-03 07:20:39 +0000 |
606 | @@ -0,0 +1,79 @@ |
607 | +/* |
608 | + * Copyright (C) 2013 Canonical, Ltd. |
609 | + * |
610 | + * Authors: |
611 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
612 | + * |
613 | + * This program is free software; you can redistribute it and/or modify |
614 | + * it under the terms of the GNU General Public License as published by |
615 | + * the Free Software Foundation; version 3. |
616 | + * |
617 | + * This program is distributed in the hope that it will be useful, |
618 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
619 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
620 | + * GNU General Public License for more details. |
621 | + * |
622 | + * You should have received a copy of the GNU General Public License |
623 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
624 | + */ |
625 | + |
626 | +import QtQuick 2.0 |
627 | +import Ubuntu.Components 1.1 |
628 | + |
629 | +MouseArea { |
630 | + id: _imageFrame |
631 | + |
632 | + property int start |
633 | + property int duration |
634 | + property alias source: _image.source |
635 | + property bool active: false |
636 | + readonly property bool ready: (_image.status === Image.Ready) |
637 | + |
638 | + Behavior on width { |
639 | + NumberAnimation { duration: 150; easing.type: Easing.InOutQuart } |
640 | + } |
641 | + |
642 | + UbuntuShape { |
643 | + id: _shape |
644 | + radius: "medium" |
645 | + |
646 | + anchors { |
647 | + fill: parent |
648 | + topMargin: active ? 0 : units.gu(2) |
649 | + bottomMargin: active ? 0 : units.gu(2) |
650 | + leftMargin: units.gu(1) |
651 | + rightMargin: units.gu(1) |
652 | + |
653 | + Behavior on topMargin { |
654 | + NumberAnimation { duration: 150; easing.type: Easing.InOutQuart } |
655 | + } |
656 | + |
657 | + Behavior on bottomMargin { |
658 | + NumberAnimation { duration: 150; easing.type: Easing.InOutQuart } |
659 | + } |
660 | + } |
661 | + |
662 | + image: Image { |
663 | + id: _image |
664 | + |
665 | + fillMode: Image.PreserveAspectCrop |
666 | + smooth: true |
667 | + asynchronous: true |
668 | + sourceSize.width: _shape.width |
669 | + sourceSize.height: _shape.height |
670 | + } |
671 | + } |
672 | + |
673 | + ActivityIndicator { |
674 | + id: imgLoading |
675 | + |
676 | + anchors { |
677 | + verticalCenter: _shape.verticalCenter |
678 | + horizontalCenter: _shape.horizontalCenter |
679 | + margins: units.gu(0.5) |
680 | + } |
681 | + |
682 | + running: _image.status != Image.Ready |
683 | + visible: running |
684 | + } |
685 | +} |
686 | |
687 | === added file 'src/Ubuntu/Web/TimeLabel.qml' |
688 | --- src/Ubuntu/Web/TimeLabel.qml 1970-01-01 00:00:00 +0000 |
689 | +++ src/Ubuntu/Web/TimeLabel.qml 2015-08-03 07:20:39 +0000 |
690 | @@ -0,0 +1,58 @@ |
691 | +/* |
692 | + * Copyright (C) 2013 Canonical, Ltd. |
693 | + * |
694 | + * Authors: |
695 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
696 | + * |
697 | + * This program is free software; you can redistribute it and/or modify |
698 | + * it under the terms of the GNU General Public License as published by |
699 | + * the Free Software Foundation; version 3. |
700 | + * |
701 | + * This program is distributed in the hope that it will be useful, |
702 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
703 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
704 | + * GNU General Public License for more details. |
705 | + * |
706 | + * You should have received a copy of the GNU General Public License |
707 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
708 | + */ |
709 | + |
710 | +import QtQuick 2.0 |
711 | +import Ubuntu.Components 1.1 |
712 | +//import "../sdk" |
713 | + |
714 | +Label { |
715 | + id: _TimeLabel |
716 | + objectName: "TimeLine.TimeLabel" |
717 | + |
718 | + property string currentTime |
719 | + property string remainingTime |
720 | + |
721 | + color: "#e8e1d0" |
722 | + fontSize: "small" |
723 | + state: "PROGRESSIVE" |
724 | + verticalAlignment: Text.AlignVCenter |
725 | + horizontalAlignment: Text.AlignRight |
726 | + |
727 | + states: [ |
728 | + State { |
729 | + name: "PROGRESSIVE" |
730 | + PropertyChanges { target: _TimeLabel; text: _TimeLabel.currentTime } |
731 | + }, |
732 | + State { |
733 | + name: "DEGRESSIVE" |
734 | + PropertyChanges { target: _TimeLabel; text: "- %1".arg(_TimeLabel.remainingTime) } |
735 | + } |
736 | + ] |
737 | + |
738 | + MouseArea { |
739 | + anchors.fill: parent |
740 | + onClicked: { |
741 | + if (_TimeLabel.state === "PROGRESSIVE") { |
742 | + _TimeLabel.state = "DEGRESSIVE" |
743 | + } else { |
744 | + _TimeLabel.state = "PROGRESSIVE" |
745 | + } |
746 | + } |
747 | + } |
748 | +} |
749 | |
750 | === added file 'src/Ubuntu/Web/TimeLine.qml' |
751 | --- src/Ubuntu/Web/TimeLine.qml 1970-01-01 00:00:00 +0000 |
752 | +++ src/Ubuntu/Web/TimeLine.qml 2015-08-03 07:20:39 +0000 |
753 | @@ -0,0 +1,89 @@ |
754 | +/* |
755 | + * Copyright (C) 2013 Canonical, Ltd. |
756 | + * |
757 | + * Authors: |
758 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
759 | + * |
760 | + * This program is free software; you can redistribute it and/or modify |
761 | + * it under the terms of the GNU General Public License as published by |
762 | + * the Free Software Foundation; version 3. |
763 | + * |
764 | + * This program is distributed in the hope that it will be useful, |
765 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
766 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
767 | + * GNU General Public License for more details. |
768 | + * |
769 | + * You should have received a copy of the GNU General Public License |
770 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
771 | + */ |
772 | + |
773 | +import QtQuick 2.0 |
774 | +import QtMultimedia 5.0 |
775 | +import Ubuntu.Components 1.1 |
776 | +//import "../sdk" |
777 | + |
778 | +Slider { |
779 | + id: _slider |
780 | + objectName: "TimeLine.Slider" |
781 | + |
782 | + readonly property alias liveValue: _slider.value |
783 | + property real videoPosition: -1 |
784 | + property variant playerStatus: MediaPlayer.NoMedia |
785 | + property string currentTime |
786 | + property string remainingTime |
787 | + |
788 | + signal clicked(bool insideThumb) |
789 | + |
790 | + function formatProgress(time) { |
791 | + var hour = 0 |
792 | + var min = 0 |
793 | + var secs = 0 |
794 | + time = Math.floor(time) |
795 | + |
796 | + secs = time % 60 |
797 | + time = Math.floor(time / 60) |
798 | + min = time % 60 |
799 | + hour = Math.floor(time / 60) |
800 | + |
801 | + if (secs < 10) secs = "0%1".arg(secs) |
802 | + if (min < 10) min = "0%1".arg(min) |
803 | + if (hour < 10) hour = "0%1".arg(hour) |
804 | + |
805 | + // TRANSLATORS: this refers to a duration/remaining time of the video, of which you can change the order. |
806 | + // %1 refers to hours, %2 refers to minutes and %3 refers to seconds. |
807 | + return i18n.tr("%1:%2:%3").arg(hour).arg(min).arg(secs) |
808 | + } |
809 | + |
810 | + style: VideoSlider {property Item item: _slider} |
811 | + minimumValue: 0 |
812 | + maximumValue: 1000 |
813 | + live: true |
814 | + onVideoPositionChanged: { |
815 | + if (_slider.playerStatus == MediaPlayer.EndOfMedia) |
816 | + { |
817 | + // On EndOfMedia status, make sure the slider returns to the beginning |
818 | + _slider.value = 0 |
819 | + } else { |
820 | + // Else, pass all new positions through to the slider UI |
821 | + _slider.value = _slider.videoPosition |
822 | + } |
823 | + } |
824 | + |
825 | + onValueChanged: { |
826 | + if (value > 0) { |
827 | + _slider.currentTime = formatProgress(value) |
828 | + if (_slider.maximumValue > 0) { |
829 | + _slider.remainingTime = formatProgress(_slider.maximumValue - value) |
830 | + } else { |
831 | + // TRANSLATORS: this refers to an unknown duration. |
832 | + _slider.remainingTime = i18n.tr("unknown") |
833 | + } |
834 | + } else { |
835 | + _slider.currentTime = i18n.tr("0:00:00") |
836 | + } |
837 | + } |
838 | + |
839 | + onTouched: { |
840 | + _slider.clicked(onThumb) |
841 | + } |
842 | +} |
843 | |
844 | === modified file 'src/Ubuntu/Web/UbuntuWebView02.qml' |
845 | --- src/Ubuntu/Web/UbuntuWebView02.qml 2015-06-11 14:35:28 +0000 |
846 | +++ src/Ubuntu/Web/UbuntuWebView02.qml 2015-08-03 07:20:39 +0000 |
847 | @@ -285,4 +285,40 @@ |
848 | console.error(msg) |
849 | } |
850 | } |
851 | + |
852 | + Component { |
853 | + id: playerComponent |
854 | + |
855 | + MediaPlayer { |
856 | + id: player |
857 | + anchors.fill: parent |
858 | + visible: false |
859 | + |
860 | + function showInterface() { |
861 | + visible = true |
862 | + _webview.fullscreen = true |
863 | + } |
864 | + |
865 | + function hideInterface() { |
866 | + visible = false |
867 | + _webview.fullscreen = false |
868 | + } |
869 | + |
870 | + // These MUST stay, apparent signal propagation bug |
871 | + onPlaybackStateChanged: { } |
872 | + onPositionChanged: { } |
873 | + onDurationChanged: { } |
874 | + |
875 | + onCloseClicked: { |
876 | + stop(); |
877 | + source = "" |
878 | + } |
879 | + } |
880 | + } |
881 | + |
882 | + Component.onCompleted: { |
883 | + if (this.hasOwnProperty("mediaPlayer")) { |
884 | + mediaPlayer = playerComponent.createObject(parent) |
885 | + } |
886 | + } |
887 | } |
888 | |
889 | === added file 'src/Ubuntu/Web/VLine.qml' |
890 | --- src/Ubuntu/Web/VLine.qml 1970-01-01 00:00:00 +0000 |
891 | +++ src/Ubuntu/Web/VLine.qml 2015-08-03 07:20:39 +0000 |
892 | @@ -0,0 +1,54 @@ |
893 | +/* |
894 | + * Copyright (C) 2013 Canonical, Ltd. |
895 | + * |
896 | + * Authors: |
897 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
898 | + * |
899 | + * This program is free software; you can redistribute it and/or modify |
900 | + * it under the terms of the GNU General Public License as published by |
901 | + * the Free Software Foundation; version 3. |
902 | + * |
903 | + * This program is distributed in the hope that it will be useful, |
904 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
905 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
906 | + * GNU General Public License for more details. |
907 | + * |
908 | + * You should have received a copy of the GNU General Public License |
909 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
910 | + */ |
911 | + |
912 | +import QtQuick 2.0 |
913 | +import Ubuntu.Components 1.1 |
914 | + |
915 | +Row { |
916 | + id: root |
917 | + |
918 | + anchors { |
919 | + top: parent.top |
920 | + topMargin: units.gu(0.5) |
921 | + bottom: parent.bottom |
922 | + bottomMargin: units.gu(0.5) |
923 | + } |
924 | + width: visible ? units.dp(2) : 0 |
925 | + |
926 | + Rectangle { |
927 | + anchors { |
928 | + top: parent.top |
929 | + bottom: parent.bottom |
930 | + } |
931 | + |
932 | + color: "white" |
933 | + opacity: 0.08 |
934 | + width: root.visible ? units.dp(1) : 0 |
935 | + } |
936 | + Rectangle { |
937 | + anchors { |
938 | + top: parent.top |
939 | + bottom: parent.bottom |
940 | + } |
941 | + |
942 | + color: "black" |
943 | + opacity: 0.03 |
944 | + width: root.visible ? units.dp(1) : 0 |
945 | + } |
946 | +} |
947 | |
948 | === added file 'src/Ubuntu/Web/VideoSlider.qml' |
949 | --- src/Ubuntu/Web/VideoSlider.qml 1970-01-01 00:00:00 +0000 |
950 | +++ src/Ubuntu/Web/VideoSlider.qml 2015-08-03 07:20:39 +0000 |
951 | @@ -0,0 +1,89 @@ |
952 | +/* |
953 | + * Copyright (C) 2013 Canonical, Ltd. |
954 | + * |
955 | + * Authors: |
956 | + * Renato Araujo Oliveira Filho <renato@canonical.com> |
957 | + * |
958 | + * This program is free software; you can redistribute it and/or modify |
959 | + * it under the terms of the GNU General Public License as published by |
960 | + * the Free Software Foundation; version 3. |
961 | + * |
962 | + * This program is distributed in the hope that it will be useful, |
963 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
964 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
965 | + * GNU General Public License for more details. |
966 | + * |
967 | + * You should have received a copy of the GNU General Public License |
968 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
969 | + */ |
970 | + |
971 | +import QtQuick 2.0 |
972 | +import Ubuntu.Components 1.1 |
973 | + |
974 | +Item { |
975 | + id: main |
976 | + anchors.fill: parent |
977 | + |
978 | + // properties to be published: |
979 | + property Item bar: backgroundShape |
980 | + property Item thumb: thumbShape |
981 | + |
982 | + // private properties |
983 | + property real thumbSpacing: units.gu(1) |
984 | + property real liveValue: SliderUtils.liveValue(item) |
985 | + property real normalizedValue: SliderUtils.normalizedValue(item) |
986 | + |
987 | + property real thumbSpace: backgroundShape.width - (2.0 * thumbSpacing + thumbWidth) |
988 | + property real thumbWidth: item.height - thumbSpacing |
989 | + |
990 | + BorderImage { |
991 | + id: backgroundFilledShape |
992 | + |
993 | + border { |
994 | + left: 7 |
995 | + top: 7 |
996 | + right: 7 |
997 | + bottom: 7 |
998 | + } |
999 | + horizontalTileMode: BorderImage.Repeat |
1000 | + verticalTileMode: BorderImage.Repeat |
1001 | + source: "artwork/slider_shape.png" |
1002 | + anchors { |
1003 | + verticalCenter: parent.verticalCenter |
1004 | + left: parent.left |
1005 | + leftMargin: units.gu(0.2) |
1006 | + } |
1007 | + height: units.gu(1) |
1008 | + width: normalizedValue * thumbSpace + thumbSpacing + (thumbShape.width / 2) |
1009 | + } |
1010 | + |
1011 | + BorderImage { |
1012 | + id: backgroundShape |
1013 | + |
1014 | + border { |
1015 | + left: 7 |
1016 | + top: 7 |
1017 | + right: 7 |
1018 | + bottom: 7 |
1019 | + } |
1020 | + horizontalTileMode: BorderImage.Repeat |
1021 | + verticalTileMode: BorderImage.Repeat |
1022 | + source: "artwork/slider_bg.png" |
1023 | + anchors { |
1024 | + verticalCenter: parent.verticalCenter |
1025 | + left: parent.left |
1026 | + right: parent.right |
1027 | + } |
1028 | + height: units.gu(1.5) |
1029 | + } |
1030 | + |
1031 | + Image { |
1032 | + id: thumbShape |
1033 | + |
1034 | + x: backgroundShape.x + thumbSpacing + normalizedValue * thumbSpace |
1035 | + anchors.verticalCenter: backgroundShape.verticalCenter |
1036 | + width: thumbWidth |
1037 | + height: thumbWidth |
1038 | + source: "artwork/slider_handle.png" |
1039 | + } |
1040 | +} |
1041 | |
1042 | === added directory 'src/Ubuntu/Web/artwork' |
1043 | === added file 'src/Ubuntu/Web/artwork/close@20.png' |
1044 | Binary files src/Ubuntu/Web/artwork/close@20.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/close@20.png 2015-08-03 07:20:39 +0000 differ |
1045 | === added file 'src/Ubuntu/Web/artwork/icon_exitfscreen@20.png' |
1046 | Binary files src/Ubuntu/Web/artwork/icon_exitfscreen@20.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/icon_exitfscreen@20.png 2015-08-03 07:20:39 +0000 differ |
1047 | === added file 'src/Ubuntu/Web/artwork/icon_pause@20.png' |
1048 | Binary files src/Ubuntu/Web/artwork/icon_pause@20.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/icon_pause@20.png 2015-08-03 07:20:39 +0000 differ |
1049 | === added file 'src/Ubuntu/Web/artwork/icon_play@20.png' |
1050 | Binary files src/Ubuntu/Web/artwork/icon_play@20.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/icon_play@20.png 2015-08-03 07:20:39 +0000 differ |
1051 | === added file 'src/Ubuntu/Web/artwork/icon_settings@20.png' |
1052 | Binary files src/Ubuntu/Web/artwork/icon_settings@20.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/icon_settings@20.png 2015-08-03 07:20:39 +0000 differ |
1053 | === added file 'src/Ubuntu/Web/artwork/icon_share@20.png' |
1054 | Binary files src/Ubuntu/Web/artwork/icon_share@20.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/icon_share@20.png 2015-08-03 07:20:39 +0000 differ |
1055 | === added file 'src/Ubuntu/Web/artwork/slider_bg.png' |
1056 | Binary files src/Ubuntu/Web/artwork/slider_bg.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/slider_bg.png 2015-08-03 07:20:39 +0000 differ |
1057 | === added file 'src/Ubuntu/Web/artwork/slider_handle.png' |
1058 | Binary files src/Ubuntu/Web/artwork/slider_handle.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/slider_handle.png 2015-08-03 07:20:39 +0000 differ |
1059 | === added file 'src/Ubuntu/Web/artwork/slider_shape.png' |
1060 | Binary files src/Ubuntu/Web/artwork/slider_shape.png 1970-01-01 00:00:00 +0000 and src/Ubuntu/Web/artwork/slider_shape.png 2015-08-03 07:20:39 +0000 differ |
1061 | === modified file 'src/app/webcontainer/webapp-container.cpp' |
1062 | --- src/app/webcontainer/webapp-container.cpp 2015-06-24 13:37:05 +0000 |
1063 | +++ src/app/webcontainer/webapp-container.cpp 2015-08-03 07:20:39 +0000 |
1064 | @@ -286,6 +286,7 @@ |
1065 | out << " --accountProvider=PROVIDER_NAME Online account provider for the application if the application is to reuse a local account." << endl; |
1066 | out << " --accountSwitcher enable switching between different Online Accounts identities" << endl; |
1067 | out << " --store-session-cookies store session cookies on disk" << endl; |
1068 | + out << " --enable-external-media enable use of an external media player" << endl; |
1069 | out << " --enable-media-hub-audio enable media-hub for audio playback" << endl; |
1070 | out << " --user-agent-string=USER_AGENT overrides the default User Agent with the provided one." << endl; |
1071 | out << "Chrome options (if none specified, no chrome is shown by default):" << endl; |
1072 | @@ -296,7 +297,9 @@ |
1073 | void WebappContainer::earlyEnvironment() |
1074 | { |
1075 | Q_FOREACH(const QString& argument, m_arguments) { |
1076 | - if (argument.startsWith("--enable-media-hub-audio")) { |
1077 | + if (argument.startsWith("--enable-external-media")) { |
1078 | + qputenv("OXIDE_ENABLE_EXTERNAL_MEDIA", QString("1").toLocal8Bit().constData()); |
1079 | + } else if (argument.startsWith("--enable-media-hub-audio")) { |
1080 | qputenv("OXIDE_ENABLE_MEDIA_HUB_AUDIO", QString("1").toLocal8Bit().constData()); |
1081 | } |
1082 | } |