Merge lp:~renatofilho/mediaplayer-app/use-cotent-hub into lp:mediaplayer-app
- use-cotent-hub
- Merge into trunk
Proposed by
Renato Araujo Oliveira Filho
Status: | Merged |
---|---|
Approved by: | Bill Filler |
Approved revision: | 454 |
Merged at revision: | 441 |
Proposed branch: | lp:~renatofilho/mediaplayer-app/use-cotent-hub |
Merge into: | lp:mediaplayer-app |
Diff against target: |
655 lines (+280/-119) 9 files modified
data/mediaplayer-app.desktop.in.in (+0/-1) src/mediaplayer.cpp (+1/-46) src/mediaplayer.h (+0/-4) src/qml/VideoImport.qml (+40/-0) src/qml/VideoImportDialog.qml (+98/-0) src/qml/player.qml (+30/-18) src/qml/player/Controls.qml (+27/-16) src/qml/player/VideoPlayer.qml (+66/-33) tests/unittest/tst_video_player.qml (+18/-1) |
To merge this branch: | bzr merge lp:~renatofilho/mediaplayer-app/use-cotent-hub |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
system-apps-ci-bot | continuous-integration | Approve | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+320366@code.launchpad.net |
Commit message
Open content peer selection in case of the app start without a video url.
Description of the change
To post a comment you must log in.
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
review:
Approve
(continuous-integration)
- 444. By Renato Araujo Oliveira Filho
-
Added missing files.
- 445. By Renato Araujo Oliveira Filho
-
Fixed vide import using content-hub.
- 446. By Renato Araujo Oliveira Filho
-
add a option to switch to full screen.
- 447. By Renato Araujo Oliveira Filho
-
Fixed check for desktop mode on unity7.
- 448. By Renato Araujo Oliveira Filho
-
Ask to pick a video file if player is empty while clicking on "play" button.
- 449. By Renato Araujo Oliveira Filho
-
Added a open-file button.
- 450. By Renato Araujo Oliveira Filho
-
Always show quit an fullscreen button.
Does not pause video if the app loses focus. - 451. By Renato Araujo Oliveira Filho
-
Show a empty state if the app was started without a URL.
- 452. By Renato Araujo Oliveira Filho
-
Fixed empty state on player startup.
- 453. By Renato Araujo Oliveira Filho
-
Use a different icon for open a new file.
- 454. By Renato Araujo Oliveira Filho
-
Pause video player if it is playing while picking a new file.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'data/mediaplayer-app.desktop.in.in' | |||
2 | --- data/mediaplayer-app.desktop.in.in 2016-11-23 22:58:39 +0000 | |||
3 | +++ data/mediaplayer-app.desktop.in.in 2017-03-21 19:39:57 +0000 | |||
4 | @@ -12,4 +12,3 @@ | |||
5 | 12 | X-Ubuntu-Gettext-Domain=mediaplayer-app | 12 | X-Ubuntu-Gettext-Domain=mediaplayer-app |
6 | 13 | X-Ubuntu-Single-Instance=true | 13 | X-Ubuntu-Single-Instance=true |
7 | 14 | X-Ubuntu-Default-Department-ID=sound-video | 14 | X-Ubuntu-Default-Department-ID=sound-video |
8 | 15 | OnlyShowIn=Old | ||
9 | 16 | 15 | ||
10 | === modified file 'src/mediaplayer.cpp' | |||
11 | --- src/mediaplayer.cpp 2017-01-12 13:17:45 +0000 | |||
12 | +++ src/mediaplayer.cpp 2017-03-21 19:39:57 +0000 | |||
13 | @@ -47,7 +47,7 @@ | |||
14 | 47 | } | 47 | } |
15 | 48 | 48 | ||
16 | 49 | MediaPlayer::MediaPlayer(int &argc, char **argv) | 49 | MediaPlayer::MediaPlayer(int &argc, char **argv) |
18 | 50 | : QApplication(argc, argv), m_view(0), m_fileChooser(0) | 50 | : QApplication(argc, argv), m_view(0) |
19 | 51 | { | 51 | { |
20 | 52 | } | 52 | } |
21 | 53 | 53 | ||
22 | @@ -57,9 +57,6 @@ | |||
23 | 57 | bool windowed = args.removeAll("-w") + args.removeAll("--windowed") > 0; | 57 | bool windowed = args.removeAll("-w") + args.removeAll("--windowed") > 0; |
24 | 58 | bool testability = args.removeAll("-testability") > 0; | 58 | bool testability = args.removeAll("-testability") > 0; |
25 | 59 | 59 | ||
26 | 60 | // use windowed in desktop as default | ||
27 | 61 | windowed = windowed || isDesktopMode(); | ||
28 | 62 | |||
29 | 63 | // The testability driver is only loaded by QApplication but not by | 60 | // The testability driver is only loaded by QApplication but not by |
30 | 64 | // QGuiApplication. | 61 | // QGuiApplication. |
31 | 65 | // However, QApplication depends on QWidget which would add some | 62 | // However, QApplication depends on QWidget which would add some |
32 | @@ -155,10 +152,6 @@ | |||
33 | 155 | if (m_view) { | 152 | if (m_view) { |
34 | 156 | delete m_view; | 153 | delete m_view; |
35 | 157 | } | 154 | } |
36 | 158 | if (m_fileChooser) { | ||
37 | 159 | delete m_fileChooser; | ||
38 | 160 | m_fileChooser = 0; | ||
39 | 161 | } | ||
40 | 162 | } | 155 | } |
41 | 163 | 156 | ||
42 | 164 | void | 157 | void |
43 | @@ -189,44 +182,6 @@ | |||
44 | 189 | m_view->rootContext()->setContextProperty("screenHeight", height); | 182 | m_view->rootContext()->setContextProperty("screenHeight", height); |
45 | 190 | } | 183 | } |
46 | 191 | 184 | ||
47 | 192 | bool MediaPlayer::isDesktopMode() const | ||
48 | 193 | { | ||
49 | 194 | // WORKAROUND: check unity profile | ||
50 | 195 | if (qgetenv("UNITY_INDICATOR_PROFILE") == "desktop") | ||
51 | 196 | return true; | ||
52 | 197 | |||
53 | 198 | // Assume that platformName (QtUbuntu) with ubuntu | ||
54 | 199 | // in name means it's running on device | ||
55 | 200 | // TODO: replace this check with SDK call for formfactor | ||
56 | 201 | QString platform = QGuiApplication::platformName(); | ||
57 | 202 | return !((platform == "ubuntu") || (platform == "ubuntumirclient")); | ||
58 | 203 | } | ||
59 | 204 | |||
60 | 205 | QUrl MediaPlayer::chooseFile() | ||
61 | 206 | { | ||
62 | 207 | QUrl fileName; | ||
63 | 208 | if (!m_fileChooser) { | ||
64 | 209 | m_fileChooser = new QFileDialog(0, | ||
65 | 210 | tr("Open Video"), | ||
66 | 211 | QStandardPaths::writableLocation(QStandardPaths::MoviesLocation), | ||
67 | 212 | tr("Video files (*.avi *.mov *.mp4 *.divx *.ogg *.ogv *.mpeg);;All files (*)")); | ||
68 | 213 | m_fileChooser->setModal(true); | ||
69 | 214 | int result = m_fileChooser->exec(); | ||
70 | 215 | if (result == QDialog::Accepted) { | ||
71 | 216 | QStringList selectedFiles = m_fileChooser->selectedFiles(); | ||
72 | 217 | if (selectedFiles.count() > 0) { | ||
73 | 218 | fileName = selectedFiles[0]; | ||
74 | 219 | } | ||
75 | 220 | } | ||
76 | 221 | delete m_fileChooser; | ||
77 | 222 | m_fileChooser = 0; | ||
78 | 223 | } else { | ||
79 | 224 | m_fileChooser->raise(); | ||
80 | 225 | } | ||
81 | 226 | |||
82 | 227 | return fileName; | ||
83 | 228 | } | ||
84 | 229 | |||
85 | 230 | QList<QUrl> MediaPlayer::copyFiles(const QList<QUrl> &urls) | 185 | QList<QUrl> MediaPlayer::copyFiles(const QList<QUrl> &urls) |
86 | 231 | { | 186 | { |
87 | 232 | static QString moviesDir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); | 187 | static QString moviesDir = QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); |
88 | 233 | 188 | ||
89 | === modified file 'src/mediaplayer.h' | |||
90 | --- src/mediaplayer.h 2016-01-20 15:44:22 +0000 | |||
91 | +++ src/mediaplayer.h 2017-03-21 19:39:57 +0000 | |||
92 | @@ -25,7 +25,6 @@ | |||
93 | 25 | class MediaPlayer : public QApplication | 25 | class MediaPlayer : public QApplication |
94 | 26 | { | 26 | { |
95 | 27 | Q_OBJECT | 27 | Q_OBJECT |
96 | 28 | Q_PROPERTY(bool desktopMode READ isDesktopMode CONSTANT) | ||
97 | 29 | 28 | ||
98 | 30 | public: | 29 | public: |
99 | 31 | MediaPlayer(int &argc, char **argv); | 30 | MediaPlayer(int &argc, char **argv); |
100 | @@ -38,13 +37,10 @@ | |||
101 | 38 | void leaveFullScreen(); | 37 | void leaveFullScreen(); |
102 | 39 | void onWidthChanged(int); | 38 | void onWidthChanged(int); |
103 | 40 | void onHeightChanged(int); | 39 | void onHeightChanged(int); |
104 | 41 | bool isDesktopMode() const; | ||
105 | 42 | QUrl chooseFile(); | ||
106 | 43 | QList<QUrl> copyFiles(const QList<QUrl> &urls); | 40 | QList<QUrl> copyFiles(const QList<QUrl> &urls); |
107 | 44 | 41 | ||
108 | 45 | private: | 42 | private: |
109 | 46 | QQuickView *m_view; | 43 | QQuickView *m_view; |
110 | 47 | QFileDialog *m_fileChooser; | ||
111 | 48 | }; | 44 | }; |
112 | 49 | 45 | ||
113 | 50 | #endif // MEDIAPLAYER_H | 46 | #endif // MEDIAPLAYER_H |
114 | 51 | 47 | ||
115 | === added file 'src/qml/VideoImport.qml' | |||
116 | --- src/qml/VideoImport.qml 1970-01-01 00:00:00 +0000 | |||
117 | +++ src/qml/VideoImport.qml 2017-03-21 19:39:57 +0000 | |||
118 | @@ -0,0 +1,40 @@ | |||
119 | 1 | /* | ||
120 | 2 | * Copyright (C) 2012-2016 Canonical, Ltd. | ||
121 | 3 | * | ||
122 | 4 | * This program is free software; you can redistribute it and/or modify | ||
123 | 5 | * it under the terms of the GNU General Public License as published by | ||
124 | 6 | * the Free Software Foundation; version 3. | ||
125 | 7 | * | ||
126 | 8 | * This program is distributed in the hope that it will be useful, | ||
127 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
128 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
129 | 11 | * GNU General Public License for more details. | ||
130 | 12 | * | ||
131 | 13 | * You should have received a copy of the GNU General Public License | ||
132 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
133 | 15 | */ | ||
134 | 16 | |||
135 | 17 | import QtQuick 2.4 | ||
136 | 18 | |||
137 | 19 | import Ubuntu.Components 1.3 | ||
138 | 20 | import Ubuntu.Components.Popups 1.3 | ||
139 | 21 | |||
140 | 22 | Item { | ||
141 | 23 | id: root | ||
142 | 24 | |||
143 | 25 | property var importDialog: null | ||
144 | 26 | |||
145 | 27 | signal videoReceived(string videoUrl) | ||
146 | 28 | |||
147 | 29 | function requestVideo() | ||
148 | 30 | { | ||
149 | 31 | if (!root.importDialog) { | ||
150 | 32 | root.importDialog = PopupUtils.open(Qt.resolvedUrl("VideoImportDialog.qml"), null) | ||
151 | 33 | root.importDialog.videoReceived.connect(root.videoReceived) | ||
152 | 34 | root.importDialog.destruction.connect(function () {root.importDialog = null}) | ||
153 | 35 | |||
154 | 36 | } else { | ||
155 | 37 | console.warn("Import dialog already running") | ||
156 | 38 | } | ||
157 | 39 | } | ||
158 | 40 | } | ||
159 | 0 | 41 | ||
160 | === added file 'src/qml/VideoImportDialog.qml' | |||
161 | --- src/qml/VideoImportDialog.qml 1970-01-01 00:00:00 +0000 | |||
162 | +++ src/qml/VideoImportDialog.qml 2017-03-21 19:39:57 +0000 | |||
163 | @@ -0,0 +1,98 @@ | |||
164 | 1 | /* | ||
165 | 2 | * Copyright (C) 2016 Canonical, Ltd. | ||
166 | 3 | * | ||
167 | 4 | * This program is free software; you can redistribute it and/or modify | ||
168 | 5 | * it under the terms of the GNU General Public License as published by | ||
169 | 6 | * the Free Software Foundation; version 3. | ||
170 | 7 | * | ||
171 | 8 | * This program is distributed in the hope that it will be useful, | ||
172 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
173 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
174 | 11 | * GNU General Public License for more details. | ||
175 | 12 | * | ||
176 | 13 | * You should have received a copy of the GNU General Public License | ||
177 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
178 | 15 | */ | ||
179 | 16 | |||
180 | 17 | import QtQuick 2.4 | ||
181 | 18 | |||
182 | 19 | import Ubuntu.Components 1.3 | ||
183 | 20 | import Ubuntu.Components.Popups 1.3 | ||
184 | 21 | import Ubuntu.Content 1.3 | ||
185 | 22 | |||
186 | 23 | PopupBase { | ||
187 | 24 | id: dialogue | ||
188 | 25 | |||
189 | 26 | property alias activeTransfer: signalConnections.target | ||
190 | 27 | signal videoReceived(string videoUrl) | ||
191 | 28 | signal destruction() | ||
192 | 29 | |||
193 | 30 | parent: QuickUtils.rootItem(this) | ||
194 | 31 | focus: true | ||
195 | 32 | |||
196 | 33 | Rectangle { | ||
197 | 34 | anchors.fill: parent | ||
198 | 35 | |||
199 | 36 | ContentTransferHint { | ||
200 | 37 | anchors.fill: parent | ||
201 | 38 | activeTransfer: dialogue.activeTransfer | ||
202 | 39 | } | ||
203 | 40 | |||
204 | 41 | ContentPeerPicker { | ||
205 | 42 | id: peerPicker | ||
206 | 43 | |||
207 | 44 | anchors.fill: parent | ||
208 | 45 | contentType: ContentType.Videos | ||
209 | 46 | handler: ContentHandler.Source | ||
210 | 47 | |||
211 | 48 | onPeerSelected: { | ||
212 | 49 | peer.selectionType = ContentTransfer.Single | ||
213 | 50 | dialogue.activeTransfer = peer.request() | ||
214 | 51 | } | ||
215 | 52 | |||
216 | 53 | onCancelPressed: { | ||
217 | 54 | PopupUtils.close(dialogue) | ||
218 | 55 | } | ||
219 | 56 | } | ||
220 | 57 | } | ||
221 | 58 | |||
222 | 59 | Connections { | ||
223 | 60 | id: signalConnections | ||
224 | 61 | |||
225 | 62 | onStateChanged: { | ||
226 | 63 | var done = ((dialogue.activeTransfer.state === ContentTransfer.Charged) || | ||
227 | 64 | (dialogue.activeTransfer.state === ContentTransfer.Aborted)) | ||
228 | 65 | |||
229 | 66 | if (dialogue.activeTransfer.state === ContentTransfer.Charged) { | ||
230 | 67 | if (dialogue.activeTransfer.items.length > 0) { | ||
231 | 68 | dialogue.videoReceived(dialogue.activeTransfer.items[0].url) | ||
232 | 69 | } | ||
233 | 70 | } | ||
234 | 71 | |||
235 | 72 | if (done) { | ||
236 | 73 | acceptTimer.restart() | ||
237 | 74 | } | ||
238 | 75 | } | ||
239 | 76 | } | ||
240 | 77 | |||
241 | 78 | // WORKAROUND: Work around for application becoming insensitive to touch events | ||
242 | 79 | // if the dialog is dismissed while the application is inactive. | ||
243 | 80 | // Just listening for changes to Qt.application.active doesn't appear | ||
244 | 81 | // to be enough to resolve this, so it seems that something else needs | ||
245 | 82 | // to be happening first. As such there's a potential for a race | ||
246 | 83 | // condition here, although as yet no problem has been encountered. | ||
247 | 84 | Timer { | ||
248 | 85 | id: acceptTimer | ||
249 | 86 | |||
250 | 87 | interval: 100 | ||
251 | 88 | repeat: true | ||
252 | 89 | running: false | ||
253 | 90 | onTriggered: { | ||
254 | 91 | if(Qt.application.state === Qt.ApplicationActive) { | ||
255 | 92 | PopupUtils.close(dialogue) | ||
256 | 93 | } | ||
257 | 94 | } | ||
258 | 95 | } | ||
259 | 96 | |||
260 | 97 | Component.onDestruction: dialogue.destruction() | ||
261 | 98 | } | ||
262 | 0 | 99 | ||
263 | === modified file 'src/qml/player.qml' | |||
264 | --- src/qml/player.qml 2016-01-26 14:48:04 +0000 | |||
265 | +++ src/qml/player.qml 2017-03-21 19:39:57 +0000 | |||
266 | @@ -25,7 +25,7 @@ | |||
267 | 25 | import Ubuntu.Unity.Action 1.1 as UnityActions | 25 | import Ubuntu.Unity.Action 1.1 as UnityActions |
268 | 26 | import Ubuntu.Components 1.3 | 26 | import Ubuntu.Components 1.3 |
269 | 27 | import Ubuntu.Components.Popups 1.0 as Popups | 27 | import Ubuntu.Components.Popups 1.0 as Popups |
271 | 28 | import Ubuntu.Content 0.1 as ContentHub | 28 | import Ubuntu.Content 1.3 |
272 | 29 | 29 | ||
273 | 30 | Item { | 30 | Item { |
274 | 31 | id: mediaPlayer | 31 | id: mediaPlayer |
275 | @@ -38,15 +38,25 @@ | |||
276 | 38 | property bool appActive: Qt.application.active | 38 | property bool appActive: Qt.application.active |
277 | 39 | property variant nativeOrientation: Screen.primaryOrientation | 39 | property variant nativeOrientation: Screen.primaryOrientation |
278 | 40 | 40 | ||
284 | 41 | onAppActiveChanged: { | 41 | function pickAFile() |
285 | 42 | if (!appActive && | 42 | { |
286 | 43 | !mpApplication.desktopMode && | 43 | if (playerLoader.item.playing) |
282 | 44 | playerLoader.item && | ||
283 | 45 | playerLoader.item.playing) { | ||
287 | 46 | playerLoader.item.pause() | 44 | playerLoader.item.pause() |
289 | 47 | } | 45 | videoImport.requestVideo() |
290 | 48 | } | 46 | } |
291 | 49 | 47 | ||
292 | 48 | // FIXME: For now keep the video playing even if the app is not active | ||
293 | 49 | // Wait for a better app life cycle to inform if the app will be suspended or not | ||
294 | 50 | // | ||
295 | 51 | // onAppActiveChanged: { | ||
296 | 52 | // if (!appActive && | ||
297 | 53 | // !mpApplication.desktopMode && | ||
298 | 54 | // playerLoader.item && | ||
299 | 55 | // playerLoader.item.playing) { | ||
300 | 56 | // playerLoader.item.pause() | ||
301 | 57 | // } | ||
302 | 58 | // } | ||
303 | 59 | |||
304 | 50 | Screen.onOrientationChanged: { | 60 | Screen.onOrientationChanged: { |
305 | 51 | // Rotate the UI when the device orientation changes | 61 | // Rotate the UI when the device orientation changes |
306 | 52 | mediaPlayer.orientation = Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) | 62 | mediaPlayer.orientation = Screen.angleBetween(Screen.primaryOrientation, Screen.orientation) |
307 | @@ -170,6 +180,7 @@ | |||
308 | 170 | playerLoader.item.controlsActive = true | 180 | playerLoader.item.controlsActive = true |
309 | 171 | } | 181 | } |
310 | 172 | } | 182 | } |
311 | 183 | onPlayEmptyFile: mediaPlayer.pickAFile() | ||
312 | 173 | } | 184 | } |
313 | 174 | 185 | ||
314 | 175 | UnityActions.ActionManager { | 186 | UnityActions.ActionManager { |
315 | @@ -225,10 +236,10 @@ | |||
316 | 225 | } | 236 | } |
317 | 226 | 237 | ||
318 | 227 | Connections { | 238 | Connections { |
320 | 228 | target: ContentHub.ContentHub | 239 | target: ContentHub |
321 | 229 | onImportRequested: { | 240 | onImportRequested: { |
322 | 230 | lateUrlCheck.stop() | 241 | lateUrlCheck.stop() |
324 | 231 | if (transfer.state === ContentHub.ContentTransfer.Charged) { | 242 | if (transfer.state === ContentTransfer.Charged) { |
325 | 232 | var urls = [] | 243 | var urls = [] |
326 | 233 | for(var i=0; i < transfer.items.length; i++) { | 244 | for(var i=0; i < transfer.items.length; i++) { |
327 | 234 | urls.push(transfer.items[i].url) | 245 | urls.push(transfer.items[i].url) |
328 | @@ -241,6 +252,14 @@ | |||
329 | 241 | } | 252 | } |
330 | 242 | } | 253 | } |
331 | 243 | 254 | ||
332 | 255 | VideoImport { | ||
333 | 256 | id: videoImport | ||
334 | 257 | |||
335 | 258 | onVideoReceived: { | ||
336 | 259 | playerLoader.item.playUri(videoUrl) | ||
337 | 260 | } | ||
338 | 261 | } | ||
339 | 262 | |||
340 | 244 | Timer { | 263 | Timer { |
341 | 245 | id: lateUrlCheck | 264 | id: lateUrlCheck |
342 | 246 | 265 | ||
343 | @@ -248,15 +267,8 @@ | |||
344 | 248 | repeat: false | 267 | repeat: false |
345 | 249 | running: true | 268 | running: true |
346 | 250 | onTriggered: { | 269 | onTriggered: { |
356 | 251 | if ((playUri == "") && !ContentHub.ContentHub.hasPending) { | 270 | if (playerLoader.item && (playerLoader.item.source == "") && !ContentHub.hasPending) { |
357 | 252 | if (mpApplication.desktopMode) { | 271 | mediaPlayer.pickAFile() |
349 | 253 | var videoFile = mpApplication.chooseFile() | ||
350 | 254 | if (videoFile != "") { | ||
351 | 255 | playerLoader.item.playUri(videoFile) | ||
352 | 256 | } | ||
353 | 257 | } else { | ||
354 | 258 | PopupUtils.open(dialogNoUrl, null) | ||
355 | 259 | } | ||
358 | 260 | } | 272 | } |
359 | 261 | } | 273 | } |
360 | 262 | } | 274 | } |
361 | 263 | 275 | ||
362 | === modified file 'src/qml/player/Controls.qml' | |||
363 | --- src/qml/player/Controls.qml 2016-11-22 20:22:15 +0000 | |||
364 | +++ src/qml/player/Controls.qml 2017-03-21 19:39:57 +0000 | |||
365 | @@ -35,11 +35,12 @@ | |||
366 | 35 | property variant playerStatus: MediaPlayer.NoMedia | 35 | property variant playerStatus: MediaPlayer.NoMedia |
367 | 36 | 36 | ||
368 | 37 | property alias finalSeekPosition: _timeline.finalSeekPosition | 37 | property alias finalSeekPosition: _timeline.finalSeekPosition |
370 | 38 | property alias settingsEnabled: _settingsButton.enabled | 38 | property alias openFileEnabled: _openFileButton.enabled |
371 | 39 | 39 | ||
372 | 40 | signal fullscreenClicked | 40 | signal fullscreenClicked |
373 | 41 | signal playbackClicked | 41 | signal playbackClicked |
374 | 42 | signal settingsClicked | 42 | signal settingsClicked |
375 | 43 | signal openFileClicked | ||
376 | 43 | signal shareClicked | 44 | signal shareClicked |
377 | 44 | signal seekRequested(int time) | 45 | signal seekRequested(int time) |
378 | 45 | signal startSeek | 46 | signal startSeek |
379 | @@ -153,12 +154,7 @@ | |||
380 | 153 | IconButton { | 154 | IconButton { |
381 | 154 | id: _fullScreenButton | 155 | id: _fullScreenButton |
382 | 155 | 156 | ||
389 | 156 | //TODO: use the correct icon based on window state | 157 | iconSource: Window.visibility === Window.FullScreen ? "image://theme/view-restore" : "image://theme/view-fullscreen" |
384 | 157 | // visible: (mpApplication.desktopMode || (Window.visibility === Window.FullScreen)) | ||
385 | 158 | // iconSource: mpApplication.desktopMode ? | ||
386 | 159 | // Window.visibility === Window.FullScreen ? "image://theme/view-restore" : "image://theme/view-fullscreen" : | ||
387 | 160 | // "image://theme/close" | ||
388 | 161 | iconSource: mpApplication.desktopMode ? "image://theme/view-fullscreen" : "image://theme/close" | ||
390 | 162 | iconSize: units.gu(3) | 158 | iconSize: units.gu(3) |
391 | 163 | anchors.verticalCenter: parent.verticalCenter | 159 | anchors.verticalCenter: parent.verticalCenter |
392 | 164 | width: visible ? units.gu(8) : 0 | 160 | width: visible ? units.gu(8) : 0 |
393 | @@ -184,7 +180,8 @@ | |||
394 | 184 | _fullScreenButton.width - | 180 | _fullScreenButton.width - |
395 | 185 | _timeLabel.width - | 181 | _timeLabel.width - |
396 | 186 | _shareButton.width - | 182 | _shareButton.width - |
398 | 187 | _settingsButton.width | 183 | _openFileButton.width - |
399 | 184 | _quitButton.width | ||
400 | 188 | 185 | ||
401 | 189 | height: units.gu(4) | 186 | height: units.gu(4) |
402 | 190 | onClicked: controls.playbackClicked() | 187 | onClicked: controls.playbackClicked() |
403 | @@ -206,9 +203,8 @@ | |||
404 | 206 | playbackButton.width - | 203 | playbackButton.width - |
405 | 207 | _timeLabel.width - | 204 | _timeLabel.width - |
406 | 208 | _shareButton.width - | 205 | _shareButton.width - |
410 | 209 | _settingsButton.width - | 206 | _openFileButton.width - |
411 | 210 | units.gu(2) : 0 | 207 | _quitButton.width : 0 |
409 | 211 | |||
412 | 212 | 208 | ||
413 | 213 | TimeLine { | 209 | TimeLine { |
414 | 214 | id: _timeline | 210 | id: _timeline |
415 | @@ -297,14 +293,14 @@ | |||
416 | 297 | } | 293 | } |
417 | 298 | 294 | ||
418 | 299 | VLine { | 295 | VLine { |
420 | 300 | visible: _settingsButton.visible | 296 | visible: _openFileButton.visible |
421 | 301 | } | 297 | } |
422 | 302 | 298 | ||
423 | 303 | IconButton { | 299 | IconButton { |
425 | 304 | id: _settingsButton | 300 | id: _openFileButton |
426 | 305 | 301 | ||
429 | 306 | visible: false | 302 | visible: enabled |
430 | 307 | iconSource: "artwork/icon_settings.png" | 303 | iconSource: "image://theme/document-open" |
431 | 308 | iconSize: units.gu(3) | 304 | iconSize: units.gu(3) |
432 | 309 | anchors { | 305 | anchors { |
433 | 310 | top: parent.top | 306 | top: parent.top |
434 | @@ -313,7 +309,22 @@ | |||
435 | 313 | width: visible ? units.gu(7) : 0 | 309 | width: visible ? units.gu(7) : 0 |
436 | 314 | enabled: false | 310 | enabled: false |
437 | 315 | opacity: enabled ? 1.0 : 0.2 | 311 | opacity: enabled ? 1.0 : 0.2 |
439 | 316 | onClicked: settingsClicked() | 312 | onClicked: openFileClicked() |
440 | 313 | } | ||
441 | 314 | |||
442 | 315 | VLine {} | ||
443 | 316 | |||
444 | 317 | IconButton { | ||
445 | 318 | id: _quitButton | ||
446 | 319 | |||
447 | 320 | iconSource: "image://theme/close" | ||
448 | 321 | iconSize: units.gu(3) | ||
449 | 322 | anchors { | ||
450 | 323 | top: parent.top | ||
451 | 324 | bottom: parent.bottom | ||
452 | 325 | } | ||
453 | 326 | width: units.gu(7) | ||
454 | 327 | onClicked: Qt.quit() | ||
455 | 317 | } | 328 | } |
456 | 318 | } | 329 | } |
457 | 319 | } | 330 | } |
458 | 320 | 331 | ||
459 | === modified file 'src/qml/player/VideoPlayer.qml' | |||
460 | --- src/qml/player/VideoPlayer.qml 2016-02-19 11:14:53 +0000 | |||
461 | +++ src/qml/player/VideoPlayer.qml 2017-03-21 19:39:57 +0000 | |||
462 | @@ -28,20 +28,21 @@ | |||
463 | 28 | AbstractPlayer { | 28 | AbstractPlayer { |
464 | 29 | id: player | 29 | id: player |
465 | 30 | 30 | ||
467 | 31 | property variant nfo | 31 | property variant info |
468 | 32 | property int pressCount: 0 | 32 | property int pressCount: 0 |
469 | 33 | property bool wasPlaying: false | 33 | property bool wasPlaying: false |
470 | 34 | property string uri | ||
471 | 35 | property bool rotating: false | 34 | property bool rotating: false |
472 | 36 | property alias controlsActive: _controls.active | 35 | property alias controlsActive: _controls.active |
473 | 37 | property bool componentLoaded: false | 36 | property bool componentLoaded: false |
474 | 38 | readonly property int seekStep: 1000 | 37 | readonly property int seekStep: 1000 |
475 | 38 | readonly property bool isEmpty: source == "" | ||
476 | 39 | property var errorDialog: null | 39 | property var errorDialog: null |
477 | 40 | 40 | ||
478 | 41 | signal timeClicked | 41 | signal timeClicked |
479 | 42 | signal playEmptyFile | ||
480 | 42 | 43 | ||
481 | 43 | objectName: "player" | 44 | objectName: "player" |
483 | 44 | nfo: VideoInfo { | 45 | info: VideoInfo { |
484 | 45 | uri: source | 46 | uri: source |
485 | 46 | } | 47 | } |
486 | 47 | 48 | ||
487 | @@ -134,8 +135,7 @@ | |||
488 | 134 | player.video.seek(time) | 135 | player.video.seek(time) |
489 | 135 | } | 136 | } |
490 | 136 | 137 | ||
493 | 137 | settingsEnabled: mpApplication.desktopMode | 138 | openFileEnabled: true |
492 | 138 | |||
494 | 139 | objectName: "controls" | 139 | objectName: "controls" |
495 | 140 | state: player.state | 140 | state: player.state |
496 | 141 | video: player.video | 141 | video: player.video |
497 | @@ -149,46 +149,79 @@ | |||
498 | 149 | sceneSelectorHeight: units.gu(18) | 149 | sceneSelectorHeight: units.gu(18) |
499 | 150 | playerStatus: player.status | 150 | playerStatus: player.status |
500 | 151 | 151 | ||
506 | 152 | onPlaybackClicked: player.playPause() | 152 | onPlaybackClicked: { |
507 | 153 | 153 | if (player.source == "") { | |
508 | 154 | onFullscreenClicked: { | 154 | player.playEmptyFile() |
504 | 155 | if (mpApplication.desktopMode) { | ||
505 | 156 | mpApplication.toggleFullscreen() | ||
509 | 157 | } else { | 155 | } else { |
511 | 158 | Qt.quit() | 156 | player.playPause() |
512 | 159 | } | 157 | } |
513 | 160 | } | 158 | } |
514 | 161 | 159 | ||
515 | 160 | onFullscreenClicked: mpApplication.toggleFullscreen() | ||
516 | 161 | onOpenFileClicked: player.playEmptyFile() | ||
517 | 162 | onStartSeek: aboutToSeek() | 162 | onStartSeek: aboutToSeek() |
518 | 163 | onEndSeek: seekDone() | 163 | onEndSeek: seekDone() |
519 | 164 | onSeekRequested: seek(time) | 164 | onSeekRequested: seek(time) |
520 | 165 | |||
521 | 166 | onSettingsClicked: { | ||
522 | 167 | if (mpApplication.desktopMode) { | ||
523 | 168 | var videoFile = mpApplication.chooseFile() | ||
524 | 169 | if (videoFile != "") { | ||
525 | 170 | player.stop() | ||
526 | 171 | item.playUri(videoFile) | ||
527 | 172 | } | ||
528 | 173 | } | ||
529 | 174 | } | ||
530 | 175 | } | 165 | } |
531 | 176 | } | 166 | } |
532 | 177 | 167 | ||
533 | 178 | MouseArea { | 168 | MouseArea { |
537 | 179 | id: _mouseArea | 169 | id: _mouseArea |
538 | 180 | 170 | ||
539 | 181 | objectName: "videoMouseArea" | 171 | objectName: "videoMouseArea" |
540 | 172 | anchors { | ||
541 | 173 | left: parent.left | ||
542 | 174 | right: parent.right | ||
543 | 175 | top: parent.top | ||
544 | 176 | bottom: _controls.top | ||
545 | 177 | } | ||
546 | 178 | onClicked: _controls.active = !_controls.active | ||
547 | 179 | } | ||
548 | 180 | |||
549 | 181 | Item { | ||
550 | 182 | id: emptyState | ||
551 | 183 | |||
552 | 184 | anchors.fill: parent | ||
553 | 185 | visible: false | ||
554 | 186 | Icon { | ||
555 | 187 | id: emptyStateIcon | ||
556 | 188 | |||
557 | 189 | source: "image://theme/document-open" | ||
558 | 190 | color: "white" | ||
559 | 191 | anchors.centerIn: parent | ||
560 | 192 | width: units.gu(4) | ||
561 | 193 | } | ||
562 | 194 | Label { | ||
563 | 195 | text: i18n.tr("Please choose a file to open") | ||
564 | 196 | color: "white" | ||
565 | 197 | textSize: Label.Large | ||
566 | 182 | anchors { | 198 | anchors { |
576 | 183 | left: parent.left | 199 | horizontalCenter: parent.horizontalCenter |
577 | 184 | right: parent.right | 200 | top: emptyStateIcon.bottom |
578 | 185 | top: parent.top | 201 | topMargin: units.gu(2) |
579 | 186 | bottom: _controls.top | 202 | } |
580 | 187 | } | 203 | } |
581 | 188 | 204 | } | |
582 | 189 | onClicked: _controls.active = !_controls.active | 205 | |
583 | 190 | } | 206 | state: player.isEmpty ? "empty" : "" |
584 | 191 | 207 | states: [ | |
585 | 208 | State { | ||
586 | 209 | name: "empty" | ||
587 | 210 | PropertyChanges { | ||
588 | 211 | target: _controls | ||
589 | 212 | active: true | ||
590 | 213 | } | ||
591 | 214 | PropertyChanges { | ||
592 | 215 | target: emptyState | ||
593 | 216 | visible: true | ||
594 | 217 | } | ||
595 | 218 | PropertyChanges { | ||
596 | 219 | target: _mouseArea | ||
597 | 220 | enabled: false | ||
598 | 221 | } | ||
599 | 222 | } | ||
600 | 223 | |||
601 | 224 | ] | ||
602 | 192 | 225 | ||
603 | 193 | Keys.onReleased: | 226 | Keys.onReleased: |
604 | 194 | { | 227 | { |
605 | 195 | 228 | ||
606 | === modified file 'tests/unittest/tst_video_player.qml' | |||
607 | --- tests/unittest/tst_video_player.qml 2016-09-26 23:12:42 +0000 | |||
608 | +++ tests/unittest/tst_video_player.qml 2017-03-21 19:39:57 +0000 | |||
609 | @@ -75,6 +75,21 @@ | |||
610 | 75 | tryCompare(player, 'paused', false) | 75 | tryCompare(player, 'paused', false) |
611 | 76 | tryCompare(player, 'playing', false) | 76 | tryCompare(player, 'playing', false) |
612 | 77 | tryCompare(player, 'wasPlaying', false) | 77 | tryCompare(player, 'wasPlaying', false) |
613 | 78 | tryCompare(player, 'isEmpty', true) | ||
614 | 79 | } | ||
615 | 80 | |||
616 | 81 | function test_empty_state() | ||
617 | 82 | { | ||
618 | 83 | tryCompare(player, 'isEmpty', true) | ||
619 | 84 | tryCompare(player, 'controlsActive', true) | ||
620 | 85 | |||
621 | 86 | // test if controls stay active after click on empty state | ||
622 | 87 | mouseClick(player) | ||
623 | 88 | tryCompare(player, 'controlsActive', true) | ||
624 | 89 | |||
625 | 90 | // play any uri should leave empty state | ||
626 | 91 | player.playUri(videUri) | ||
627 | 92 | tryCompare(player, 'isEmpty', false) | ||
628 | 78 | } | 93 | } |
629 | 79 | 94 | ||
630 | 80 | function test_open_video() | 95 | function test_open_video() |
631 | @@ -87,6 +102,8 @@ | |||
632 | 87 | function test_play_pause_video() | 102 | function test_play_pause_video() |
633 | 88 | { | 103 | { |
634 | 89 | player.playUri(videUri) | 104 | player.playUri(videUri) |
635 | 105 | |||
636 | 106 | tryCompare(player, 'isEmpty', false) | ||
637 | 90 | tryCompare(player, 'playing', true) | 107 | tryCompare(player, 'playing', true) |
638 | 91 | player.playPause() | 108 | player.playPause() |
639 | 92 | tryCompare(player, 'paused', true) | 109 | tryCompare(player, 'paused', true) |
640 | @@ -98,6 +115,7 @@ | |||
641 | 98 | { | 115 | { |
642 | 99 | player.playUri(videUri) | 116 | player.playUri(videUri) |
643 | 100 | tryCompare(player, 'playing', true) | 117 | tryCompare(player, 'playing', true) |
644 | 118 | tryCompare(player, 'controlsActive', false) | ||
645 | 101 | 119 | ||
646 | 102 | mouseClick(player) | 120 | mouseClick(player) |
647 | 103 | tryCompare(player, 'controlsActive', true) | 121 | tryCompare(player, 'controlsActive', true) |
648 | @@ -126,7 +144,6 @@ | |||
649 | 126 | tryCompare(player, 'paused', true) | 144 | tryCompare(player, 'paused', true) |
650 | 127 | } | 145 | } |
651 | 128 | 146 | ||
652 | 129 | |||
653 | 130 | function test_play_after_pause() | 147 | function test_play_after_pause() |
654 | 131 | { | 148 | { |
655 | 132 | // play video | 149 | // play video |
PASSED: Continuous integration, rev:443 /jenkins. canonical. com/system- apps/job/ lp-mediaplayer- app-ci/ 3/ /jenkins. canonical. com/system- apps/job/ build/2328 /jenkins. canonical. com/system- apps/job/ build-0- fetch/2327 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 2149 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 2149/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= zesty/2149 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= zesty/2149/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 2149 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 2149/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= zesty/2149 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= zesty/2149/ artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 2149 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 2149/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= zesty/2149 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= zesty/2149/ artifact/ output/ *zip*/output. zip
https:/
Executed test runs:
SUCCESS: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-mediaplayer- app-ci/ 3/rebuild
https:/