Merge lp:~fboucault/camera-app/async_lib_loading into lp:camera-app
- async_lib_loading
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Bill Filler |
Approved revision: | 485 |
Merged at revision: | 473 |
Proposed branch: | lp:~fboucault/camera-app/async_lib_loading |
Merge into: | lp:camera-app |
Diff against target: |
658 lines (+233/-109) 10 files modified
CameraApp/foldersmodel.cpp (+113/-61) CameraApp/foldersmodel.h (+19/-3) GalleryView.qml (+39/-1) GalleryViewLoader.qml (+5/-0) PhotogridView.qml (+1/-6) SlideshowView.qml (+6/-0) ViewFinderView.qml (+11/-10) camera-app.qml (+8/-2) po/camera-app.pot (+26/-22) tests/autopilot/camera_app/tests/test_gallery_view.py (+5/-4) |
To merge this branch: | bzr merge lp:~fboucault/camera-app/async_lib_loading |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+247485@code.launchpad.net |
Commit message
Asynchronously scan the filesystem for media. Fixes freeze at startup with a huge amount of media.
Significantly faster deletion when deleting a huge amount of media.
Taking a photo is now always fast even with a huge amount of media.
Description of the change
- 474. By Florian Boucault
-
Faster scanning.
- 475. By Florian Boucault
-
Sorting is still important.
- 476. By Florian Boucault
-
Reverted pointless change
- 477. By Florian Boucault
-
Do not scan until FoldersModel is fully instantiated.
- 478. By Florian Boucault
-
Clear model immediately when updating.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 479. By Florian Boucault
-
Vastly more efficient selectAll with large collections.
- 480. By Florian Boucault
-
Fixed deletion bug.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:480
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 481. By Florian Boucault
-
Do not monitor for added file anylonger, instead manually prepend new media files shot. Depends on fix in qtubuntu-camera https:/
/code.launchpad .net/~fboucault /qtubuntu- camera/ fix_video_ location/ +merge/ 247507 - 482. By Florian Boucault
-
Significantly faster deletion of selected files.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:482
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 483. By Florian Boucault
-
Added feedback while media scanning is in progress.
- 484. By Florian Boucault
-
Updated pot file.
- 485. By Florian Boucault
-
Fixed autopilot tests.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:484
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:485
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'CameraApp/foldersmodel.cpp' |
2 | --- CameraApp/foldersmodel.cpp 2014-11-26 14:45:34 +0000 |
3 | +++ CameraApp/foldersmodel.cpp 2015-01-24 18:49:40 +0000 |
4 | @@ -18,14 +18,26 @@ |
5 | #include <QtCore/QDir> |
6 | #include <QtCore/QUrl> |
7 | #include <QtCore/QDateTime> |
8 | +#include <QtCore/QFuture> |
9 | +#include <QtCore/QFutureWatcher> |
10 | +#include <QtCore/QtAlgorithms> |
11 | +#include <QtConcurrent/QtConcurrentRun> |
12 | + |
13 | +bool newerThan(const QFileInfo& fileInfo1, const QFileInfo& fileInfo2) |
14 | +{ |
15 | + return fileInfo1.lastModified() > fileInfo2.lastModified(); |
16 | +} |
17 | + |
18 | |
19 | FoldersModel::FoldersModel(QObject *parent) : |
20 | QAbstractListModel(parent), |
21 | - m_singleSelectionOnly(true) |
22 | + m_singleSelectionOnly(true), |
23 | + m_completed(false), |
24 | + m_loading(false) |
25 | { |
26 | m_watcher = new QFileSystemWatcher(this); |
27 | - connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString))); |
28 | connect(m_watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString))); |
29 | + connect(&m_updateFutureWatcher, SIGNAL(finished()), this, SLOT(updateFileInfoListFinished())); |
30 | } |
31 | |
32 | QStringList FoldersModel::folders() const |
33 | @@ -80,31 +92,70 @@ |
34 | return m_fileInfoList.count(); |
35 | } |
36 | |
37 | +bool FoldersModel::loading() const |
38 | +{ |
39 | + return m_loading; |
40 | +} |
41 | + |
42 | void FoldersModel::updateFileInfoList() |
43 | { |
44 | + if (!m_completed) { |
45 | + return; |
46 | + } |
47 | + |
48 | + m_loading = true; |
49 | + Q_EMIT loadingChanged(); |
50 | + |
51 | beginResetModel(); |
52 | m_fileInfoList.clear(); |
53 | - Q_FOREACH (QString folder, m_folders) { |
54 | + endResetModel(); |
55 | + m_selectedFiles.clear(); |
56 | + Q_EMIT selectedFilesChanged(); |
57 | + Q_EMIT countChanged(); |
58 | + |
59 | + m_updateFutureWatcher.cancel(); |
60 | + QFuture<QPair<QFileInfoList, QStringList> > future = QtConcurrent::run(this, &FoldersModel::computeFileInfoList, m_folders); |
61 | + m_updateFutureWatcher.setFuture(future); |
62 | +} |
63 | + |
64 | +QPair<QFileInfoList, QStringList> FoldersModel::computeFileInfoList(QStringList folders) |
65 | +{ |
66 | + QFileInfoList filteredFileInfoList; |
67 | + QStringList filesToWatch; |
68 | + |
69 | + Q_FOREACH (QString folder, folders) { |
70 | QDir currentDir(folder); |
71 | QFileInfoList fileInfoList = currentDir.entryInfoList(QDir::Files | QDir::Readable, |
72 | QDir::Time | QDir::Reversed); |
73 | Q_FOREACH (QFileInfo fileInfo, fileInfoList) { |
74 | - if (fileInfo.isDir()) continue; |
75 | - m_watcher->addPath(fileInfo.absoluteFilePath()); |
76 | + filesToWatch.append(fileInfo.absoluteFilePath()); |
77 | if (fileMatchesTypeFilters(fileInfo)) { |
78 | - insertFileInfo(fileInfo, false); |
79 | + filteredFileInfoList.append(fileInfo); |
80 | } |
81 | } |
82 | } |
83 | + qSort(filteredFileInfoList.begin(), filteredFileInfoList.end(), newerThan); |
84 | + return QPair<QFileInfoList, QStringList>(filteredFileInfoList, filesToWatch); |
85 | +} |
86 | + |
87 | +void FoldersModel::updateFileInfoListFinished() |
88 | +{ |
89 | + QPair<QFileInfoList, QStringList> result = m_updateFutureWatcher.result(); |
90 | + setFileInfoList(result.first, result.second); |
91 | +} |
92 | + |
93 | +void FoldersModel::setFileInfoList(const QFileInfoList& fileInfoList, const QStringList& filesToWatch) |
94 | +{ |
95 | + beginResetModel(); |
96 | + m_fileInfoList = fileInfoList; |
97 | endResetModel(); |
98 | - m_selectedFiles.clear(); |
99 | + |
100 | + // Start monitoring files for modifications in a separate thread as it is very time consuming |
101 | + QtConcurrent::run(m_watcher, &QFileSystemWatcher::addPaths, filesToWatch); |
102 | + |
103 | + m_loading = false; |
104 | + Q_EMIT loadingChanged(); |
105 | Q_EMIT countChanged(); |
106 | - Q_EMIT selectedFilesChanged(); |
107 | -} |
108 | - |
109 | -bool moreRecentThan(const QFileInfo& fileInfo1, const QFileInfo& fileInfo2) |
110 | -{ |
111 | - return fileInfo1.lastModified() < fileInfo2.lastModified(); |
112 | } |
113 | |
114 | bool FoldersModel::fileMatchesTypeFilters(const QFileInfo& newFileInfo) |
115 | @@ -120,33 +171,25 @@ |
116 | |
117 | // inserts newFileInfo into m_fileInfoList while keeping m_fileInfoList sorted by |
118 | // file modification time with the files most recently modified first |
119 | -void FoldersModel::insertFileInfo(const QFileInfo& newFileInfo, bool emitChange) |
120 | +void FoldersModel::insertFileInfo(const QFileInfo& newFileInfo) |
121 | { |
122 | QFileInfoList::iterator i; |
123 | for (i = m_fileInfoList.begin(); i != m_fileInfoList.end(); ++i) { |
124 | QFileInfo fileInfo = *i; |
125 | - if (!moreRecentThan(newFileInfo, fileInfo)) { |
126 | - if (emitChange) { |
127 | - int index = m_fileInfoList.indexOf(*i); |
128 | - beginInsertRows(QModelIndex(), index, index); |
129 | - m_fileInfoList.insert(i, newFileInfo); |
130 | - endInsertRows(); |
131 | - } else { |
132 | - m_fileInfoList.insert(i, newFileInfo); |
133 | - } |
134 | + if (newerThan(newFileInfo, fileInfo)) { |
135 | + int index = m_fileInfoList.indexOf(*i); |
136 | + beginInsertRows(QModelIndex(), index, index); |
137 | + m_fileInfoList.insert(i, newFileInfo); |
138 | + endInsertRows(); |
139 | return; |
140 | } |
141 | } |
142 | |
143 | - if (emitChange) { |
144 | - int index = m_fileInfoList.size(); |
145 | - beginInsertRows(QModelIndex(), index, index); |
146 | - m_fileInfoList.append(newFileInfo); |
147 | - endInsertRows(); |
148 | - Q_EMIT countChanged(); |
149 | - } else { |
150 | - m_fileInfoList.append(newFileInfo); |
151 | - } |
152 | + int index = m_fileInfoList.size(); |
153 | + beginInsertRows(QModelIndex(), index, index); |
154 | + m_fileInfoList.append(newFileInfo); |
155 | + endInsertRows(); |
156 | + Q_EMIT countChanged(); |
157 | } |
158 | |
159 | QHash<int, QByteArray> FoldersModel::roleNames() const |
160 | @@ -205,31 +248,6 @@ |
161 | return data(index(row), roleNames().key(role.toUtf8())); |
162 | } |
163 | |
164 | -void FoldersModel::directoryChanged(const QString &directoryPath) |
165 | -{ |
166 | - /* Only react when a file is added. Ignore when a file was modified or |
167 | - * deleted as this is taken care of by FoldersModel::fileChanged() |
168 | - * To do so we go through all the files in directoryPath and add |
169 | - * all the ones we were not watching before. |
170 | - */ |
171 | - QStringList watchedFiles = m_watcher->files(); |
172 | - QDir directory(directoryPath); |
173 | - QStringList files = directory.entryList(QDir::Files | QDir::Readable, |
174 | - QDir::Time | QDir::Reversed); |
175 | - |
176 | - Q_FOREACH (QString fileName, files) { |
177 | - QString filePath = directory.absoluteFilePath(fileName); |
178 | - if (!watchedFiles.contains(filePath)) { |
179 | - QFileInfo fileInfo(filePath); |
180 | - if (fileInfo.isDir()) continue; |
181 | - m_watcher->addPath(filePath); |
182 | - if (fileMatchesTypeFilters(fileInfo)) { |
183 | - insertFileInfo(fileInfo, true); |
184 | - } |
185 | - } |
186 | - } |
187 | -} |
188 | - |
189 | void FoldersModel::fileChanged(const QString &filePath) |
190 | { |
191 | /* Act appropriately upon file change or removal */ |
192 | @@ -242,7 +260,7 @@ |
193 | if (fileIndex == -1) { |
194 | // file's type might have changed and file might have to be included |
195 | if (fileMatchesTypeFilters(fileInfo)) { |
196 | - insertFileInfo(fileInfo, true); |
197 | + insertFileInfo(fileInfo); |
198 | } |
199 | } else { |
200 | // update file information |
201 | @@ -290,10 +308,44 @@ |
202 | Q_EMIT selectedFilesChanged(); |
203 | } |
204 | |
205 | +void FoldersModel::prependFile(QString filePath) |
206 | +{ |
207 | + if (!m_watcher->files().contains(filePath)) { |
208 | + QFileInfo fileInfo(filePath); |
209 | + m_watcher->addPath(filePath); |
210 | + if (fileMatchesTypeFilters(fileInfo)) { |
211 | + insertFileInfo(fileInfo); |
212 | + } |
213 | + } |
214 | +} |
215 | + |
216 | void FoldersModel::selectAll() |
217 | { |
218 | for (int row = 0; row < m_fileInfoList.size(); ++row) { |
219 | - if (!m_selectedFiles.contains(row)) |
220 | - toggleSelected(row); |
221 | - } |
222 | + if (!m_selectedFiles.contains(row)) { |
223 | + m_selectedFiles.insert(row); |
224 | + } |
225 | + Q_EMIT dataChanged(index(row), index(row)); |
226 | + } |
227 | + Q_EMIT selectedFilesChanged(); |
228 | +} |
229 | + |
230 | +void FoldersModel::deleteSelectedFiles() |
231 | +{ |
232 | + Q_FOREACH (int selectedFile, m_selectedFiles) { |
233 | + QString filePath = m_fileInfoList.at(selectedFile).filePath(); |
234 | + QFile::remove(filePath); |
235 | + } |
236 | + m_selectedFiles.clear(); |
237 | + Q_EMIT selectedFilesChanged(); |
238 | +} |
239 | + |
240 | +void FoldersModel::classBegin() |
241 | +{ |
242 | +} |
243 | + |
244 | +void FoldersModel::componentComplete() |
245 | +{ |
246 | + m_completed = true; |
247 | + updateFileInfoList(); |
248 | } |
249 | |
250 | === modified file 'CameraApp/foldersmodel.h' |
251 | --- CameraApp/foldersmodel.h 2014-11-26 14:45:34 +0000 |
252 | +++ CameraApp/foldersmodel.h 2015-01-24 18:49:40 +0000 |
253 | @@ -23,8 +23,10 @@ |
254 | #include <QtCore/QFileSystemWatcher> |
255 | #include <QtCore/QMimeDatabase> |
256 | #include <QtCore/QSet> |
257 | +#include <QtCore/QFutureWatcher> |
258 | +#include <QtQml/QQmlParserStatus> |
259 | |
260 | -class FoldersModel : public QAbstractListModel |
261 | +class FoldersModel : public QAbstractListModel, public QQmlParserStatus |
262 | { |
263 | Q_OBJECT |
264 | Q_PROPERTY (QStringList folders READ folders WRITE setFolders NOTIFY foldersChanged) |
265 | @@ -32,6 +34,7 @@ |
266 | Q_PROPERTY (QList<int> selectedFiles READ selectedFiles NOTIFY selectedFilesChanged) |
267 | Q_PROPERTY (bool singleSelectionOnly READ singleSelectionOnly WRITE setSingleSelectionOnly NOTIFY singleSelectionOnlyChanged) |
268 | Q_PROPERTY(int count READ count NOTIFY countChanged) |
269 | + Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged) |
270 | |
271 | public: |
272 | enum Roles { |
273 | @@ -52,10 +55,13 @@ |
274 | bool singleSelectionOnly() const; |
275 | void setSingleSelectionOnly(bool singleSelectionOnly); |
276 | int count() const; |
277 | + bool loading() const; |
278 | |
279 | void updateFileInfoList(); |
280 | + QPair<QFileInfoList, QStringList> computeFileInfoList(QStringList folders); |
281 | bool fileMatchesTypeFilters(const QFileInfo& newFileInfo); |
282 | - void insertFileInfo(const QFileInfo& newFileInfo, bool emitChange); |
283 | + void insertFileInfo(const QFileInfo& newFileInfo); |
284 | + void setFileInfoList(const QFileInfoList& fileInfoList, const QStringList& filesToWatch); |
285 | |
286 | QHash<int, QByteArray> roleNames() const; |
287 | QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; |
288 | @@ -64,10 +70,16 @@ |
289 | Q_INVOKABLE void toggleSelected(int row); |
290 | Q_INVOKABLE void clearSelection(); |
291 | Q_INVOKABLE void selectAll(); |
292 | + Q_INVOKABLE void prependFile(QString filePath); |
293 | + Q_INVOKABLE void deleteSelectedFiles(); |
294 | + |
295 | + // inherited from QQmlParserStatus |
296 | + void classBegin(); |
297 | + void componentComplete(); |
298 | |
299 | public Q_SLOTS: |
300 | - void directoryChanged(const QString &directoryPath); |
301 | void fileChanged(const QString &directoryPath); |
302 | + void updateFileInfoListFinished(); |
303 | |
304 | Q_SIGNALS: |
305 | void foldersChanged(); |
306 | @@ -75,6 +87,7 @@ |
307 | void selectedFilesChanged(); |
308 | void singleSelectionOnlyChanged(); |
309 | void countChanged(); |
310 | + void loadingChanged(); |
311 | |
312 | private: |
313 | QStringList m_folders; |
314 | @@ -84,6 +97,9 @@ |
315 | QMimeDatabase m_mimeDatabase; |
316 | QSet<int> m_selectedFiles; |
317 | bool m_singleSelectionOnly; |
318 | + QFutureWatcher<QPair<QFileInfoList, QStringList> > m_updateFutureWatcher; |
319 | + bool m_completed; |
320 | + bool m_loading; |
321 | }; |
322 | |
323 | #endif // FOLDERSMODEL_H |
324 | |
325 | === modified file 'GalleryView.qml' |
326 | --- GalleryView.qml 2014-12-05 18:50:53 +0000 |
327 | +++ GalleryView.qml 2015-01-24 18:49:40 +0000 |
328 | @@ -47,6 +47,10 @@ |
329 | showLastPhotoTakenPending = true; |
330 | } |
331 | |
332 | + function prependMediaToModel(filePath) { |
333 | + galleryView.model.prependFile(filePath); |
334 | + } |
335 | + |
336 | function exitUserSelectionMode() { |
337 | if (gridMode) { |
338 | model.clearSelection(); |
339 | @@ -155,7 +159,7 @@ |
340 | Rectangle { |
341 | objectName: "noMediaHint" |
342 | anchors.fill: parent |
343 | - visible: model.count === 0 |
344 | + visible: model.count === 0 && !model.loading |
345 | color: "#0F0F0F" |
346 | |
347 | Icon { |
348 | @@ -186,6 +190,40 @@ |
349 | } |
350 | } |
351 | |
352 | + Rectangle { |
353 | + objectName: "scanningMediaHint" |
354 | + anchors.fill: parent |
355 | + visible: model.loading |
356 | + color: "#0F0F0F" |
357 | + |
358 | + Icon { |
359 | + id: scanningMediaIcon |
360 | + anchors { |
361 | + horizontalCenter: parent.horizontalCenter |
362 | + verticalCenter: parent.verticalCenter |
363 | + verticalCenterOffset: -units.gu(1) |
364 | + } |
365 | + height: units.gu(9) |
366 | + width: units.gu(9) |
367 | + color: "white" |
368 | + opacity: 0.2 |
369 | + name: "camera-app-symbolic" |
370 | + } |
371 | + |
372 | + Label { |
373 | + id: scanningMediaLabel |
374 | + anchors { |
375 | + horizontalCenter: parent.horizontalCenter |
376 | + top: scanningMediaIcon.bottom |
377 | + topMargin: units.gu(4) |
378 | + } |
379 | + text: i18n.tr("Scanning for content...") |
380 | + color: "white" |
381 | + opacity: 0.2 |
382 | + fontSize: "large" |
383 | + } |
384 | + } |
385 | + |
386 | state: galleryView.gridMode || main.contentExportMode ? "GRID" : "SLIDESHOW" |
387 | states: [ |
388 | State { |
389 | |
390 | === modified file 'GalleryViewLoader.qml' |
391 | --- GalleryViewLoader.qml 2014-08-27 00:31:30 +0000 |
392 | +++ GalleryViewLoader.qml 2015-01-24 18:49:40 +0000 |
393 | @@ -27,6 +27,11 @@ |
394 | loader.item.showLastPhotoTaken(); |
395 | } |
396 | |
397 | + function prependMediaToModel(filePath) { |
398 | + loader.item.prependMediaToModel(filePath); |
399 | + } |
400 | + |
401 | + |
402 | asynchronous: true |
403 | |
404 | Component.onCompleted: { |
405 | |
406 | === modified file 'PhotogridView.qml' |
407 | --- PhotogridView.qml 2014-12-03 12:37:15 +0000 |
408 | +++ PhotogridView.qml 2015-01-24 18:49:40 +0000 |
409 | @@ -210,12 +210,7 @@ |
410 | } |
411 | |
412 | onDeleteFiles: { |
413 | - for (var i=model.selectedFiles.length-1; i>=0; i--) { |
414 | - var currentFilePath = model.get(model.selectedFiles[i], "filePath"); |
415 | - model.toggleSelected(model.selectedFiles[i]) |
416 | - fileOperations.remove(currentFilePath); |
417 | - } |
418 | - |
419 | + model.deleteSelectedFiles(); |
420 | photogridView.exitUserSelectionMode(); |
421 | } |
422 | } |
423 | |
424 | === modified file 'SlideshowView.qml' |
425 | --- SlideshowView.qml 2014-12-05 18:50:53 +0000 |
426 | +++ SlideshowView.qml 2015-01-24 18:49:40 +0000 |
427 | @@ -79,6 +79,12 @@ |
428 | // were hitting https://bugreports.qt-project.org/browse/QTBUG-41035 |
429 | highlightMoveDuration: 0 |
430 | snapMode: ListView.SnapOneItem |
431 | + onCountChanged: { |
432 | + // currentIndex is -1 by default and stays so until manually set to something else |
433 | + if (currentIndex == -1 && count != 0) { |
434 | + currentIndex = 0; |
435 | + } |
436 | + } |
437 | spacing: units.gu(1) |
438 | interactive: currentItem ? !currentItem.pinchInProgress : true |
439 | property real maxDimension: Math.max(width, height) |
440 | |
441 | === modified file 'ViewFinderView.qml' |
442 | --- ViewFinderView.qml 2014-12-11 12:24:25 +0000 |
443 | +++ ViewFinderView.qml 2015-01-24 18:49:40 +0000 |
444 | @@ -29,8 +29,8 @@ |
445 | property bool touchAcquired: viewFinderOverlay.touchAcquired || camera.videoRecorder.recorderState == CameraRecorder.RecordingState |
446 | property bool inView |
447 | property alias captureMode: camera.captureMode |
448 | - signal photoTaken |
449 | - signal videoShot |
450 | + signal photoTaken(string filePath) |
451 | + signal videoShot(string filePath) |
452 | |
453 | Camera { |
454 | id: camera |
455 | @@ -84,18 +84,19 @@ |
456 | } |
457 | onImageCaptured: { |
458 | snapshot.source = preview; |
459 | + if (!main.contentExportMode) { |
460 | + viewFinderOverlay.visible = true; |
461 | + snapshot.startOutAnimation(); |
462 | + if (photoRollHint.necessary) { |
463 | + photoRollHint.enable(); |
464 | + } |
465 | + } |
466 | } |
467 | onImageSaved: { |
468 | if (main.contentExportMode) { |
469 | viewFinderExportConfirmation.confirmExport(path); |
470 | - } else { |
471 | - viewFinderOverlay.visible = true; |
472 | - snapshot.startOutAnimation(); |
473 | - if (photoRollHint.necessary) { |
474 | - photoRollHint.enable(); |
475 | - } |
476 | } |
477 | - viewFinderView.photoTaken(); |
478 | + viewFinderView.photoTaken(path); |
479 | metricPhotos.increment(); |
480 | console.log("Picture saved as " + path); |
481 | } |
482 | @@ -109,7 +110,7 @@ |
483 | } |
484 | metricVideos.increment() |
485 | viewFinderOverlay.visible = true; |
486 | - viewFinderView.videoShot(); |
487 | + viewFinderView.videoShot(videoRecorder.actualLocation); |
488 | } |
489 | } |
490 | } |
491 | |
492 | === modified file 'camera-app.qml' |
493 | --- camera-app.qml 2014-09-05 11:43:11 +0000 |
494 | +++ camera-app.qml 2015-01-24 18:49:40 +0000 |
495 | @@ -152,8 +152,14 @@ |
496 | height: viewSwitcher.height |
497 | overlayVisible: !viewSwitcher.moving && !viewSwitcher.flicking |
498 | inView: !viewSwitcher.atXEnd |
499 | - onPhotoTaken: galleryView.showLastPhotoTaken(); |
500 | - onVideoShot: galleryView.showLastPhotoTaken(); |
501 | + onPhotoTaken: { |
502 | + galleryView.prependMediaToModel(filePath); |
503 | + galleryView.showLastPhotoTaken(); |
504 | + } |
505 | + onVideoShot: { |
506 | + galleryView.prependMediaToModel(filePath); |
507 | + galleryView.showLastPhotoTaken(); |
508 | + } |
509 | } |
510 | |
511 | GalleryViewLoader { |
512 | |
513 | === modified file 'po/camera-app.pot' |
514 | --- po/camera-app.pot 2014-12-15 10:51:14 +0000 |
515 | +++ po/camera-app.pot 2015-01-24 18:49:40 +0000 |
516 | @@ -8,7 +8,7 @@ |
517 | msgstr "" |
518 | "Project-Id-Version: camera-app\n" |
519 | "Report-Msgid-Bugs-To: \n" |
520 | -"POT-Creation-Date: 2014-12-15 08:50-0200\n" |
521 | +"POT-Creation-Date: 2015-01-24 15:51-0200\n" |
522 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
523 | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
524 | "Language-Team: LANGUAGE <LL@li.org>\n" |
525 | @@ -29,10 +29,14 @@ |
526 | msgid "Cancel" |
527 | msgstr "" |
528 | |
529 | -#: ../GalleryView.qml:182 |
530 | +#: ../GalleryView.qml:186 |
531 | msgid "No media available." |
532 | msgstr "" |
533 | |
534 | +#: ../GalleryView.qml:220 |
535 | +msgid "Scanning for content..." |
536 | +msgstr "" |
537 | + |
538 | #: ../GalleryViewHeader.qml:75 |
539 | msgid "Select" |
540 | msgstr "" |
541 | @@ -49,55 +53,55 @@ |
542 | msgid "Share" |
543 | msgstr "" |
544 | |
545 | -#: ../ViewFinderOverlay.qml:185 ../ViewFinderOverlay.qml:208 |
546 | -#: ../ViewFinderOverlay.qml:236 ../ViewFinderOverlay.qml:259 |
547 | -#: ../ViewFinderOverlay.qml:336 |
548 | +#: ../ViewFinderOverlay.qml:195 ../ViewFinderOverlay.qml:218 |
549 | +#: ../ViewFinderOverlay.qml:246 ../ViewFinderOverlay.qml:269 |
550 | +#: ../ViewFinderOverlay.qml:346 |
551 | msgid "On" |
552 | msgstr "" |
553 | |
554 | -#: ../ViewFinderOverlay.qml:190 ../ViewFinderOverlay.qml:218 |
555 | -#: ../ViewFinderOverlay.qml:241 ../ViewFinderOverlay.qml:264 |
556 | -#: ../ViewFinderOverlay.qml:283 ../ViewFinderOverlay.qml:341 |
557 | +#: ../ViewFinderOverlay.qml:200 ../ViewFinderOverlay.qml:228 |
558 | +#: ../ViewFinderOverlay.qml:251 ../ViewFinderOverlay.qml:274 |
559 | +#: ../ViewFinderOverlay.qml:293 ../ViewFinderOverlay.qml:351 |
560 | msgid "Off" |
561 | msgstr "" |
562 | |
563 | -#: ../ViewFinderOverlay.qml:213 |
564 | +#: ../ViewFinderOverlay.qml:223 |
565 | msgid "Auto" |
566 | msgstr "" |
567 | |
568 | -#: ../ViewFinderOverlay.qml:250 |
569 | +#: ../ViewFinderOverlay.qml:260 |
570 | msgid "HDR" |
571 | msgstr "" |
572 | |
573 | -#: ../ViewFinderOverlay.qml:288 |
574 | +#: ../ViewFinderOverlay.qml:298 |
575 | msgid "5 seconds" |
576 | msgstr "" |
577 | |
578 | -#: ../ViewFinderOverlay.qml:293 |
579 | +#: ../ViewFinderOverlay.qml:303 |
580 | msgid "15 seconds" |
581 | msgstr "" |
582 | |
583 | -#: ../ViewFinderOverlay.qml:310 |
584 | +#: ../ViewFinderOverlay.qml:320 |
585 | msgid "Fine Quality" |
586 | msgstr "" |
587 | |
588 | -#: ../ViewFinderOverlay.qml:314 |
589 | +#: ../ViewFinderOverlay.qml:324 |
590 | msgid "Normal Quality" |
591 | msgstr "" |
592 | |
593 | -#: ../ViewFinderOverlay.qml:318 |
594 | +#: ../ViewFinderOverlay.qml:328 |
595 | msgid "Basic Quality" |
596 | msgstr "" |
597 | |
598 | -#: ../ViewFinderOverlay.qml:350 |
599 | +#: ../ViewFinderOverlay.qml:360 |
600 | msgid "SD" |
601 | msgstr "" |
602 | |
603 | -#: ../ViewFinderOverlay.qml:358 |
604 | +#: ../ViewFinderOverlay.qml:368 |
605 | msgid "Save to SD Card" |
606 | msgstr "" |
607 | |
608 | -#: ../ViewFinderOverlay.qml:363 |
609 | +#: ../ViewFinderOverlay.qml:373 |
610 | msgid "Save internally" |
611 | msgstr "" |
612 | |
613 | @@ -141,21 +145,21 @@ |
614 | msgid "Lighting Condition;Day;Cloudy;Inside" |
615 | msgstr "" |
616 | |
617 | -#: ../camera-app.qml:214 |
618 | +#: ../camera-app.qml:220 |
619 | #, qt-format |
620 | msgid "<b>%1</b> photos taken today" |
621 | msgstr "" |
622 | |
623 | -#: ../camera-app.qml:215 |
624 | +#: ../camera-app.qml:221 |
625 | msgid "No photos taken today" |
626 | msgstr "" |
627 | |
628 | -#: ../camera-app.qml:223 |
629 | +#: ../camera-app.qml:229 |
630 | #, qt-format |
631 | msgid "<b>%1</b> videos recorded today" |
632 | msgstr "" |
633 | |
634 | -#: ../camera-app.qml:224 |
635 | +#: ../camera-app.qml:230 |
636 | msgid "No videos recorded today" |
637 | msgstr "" |
638 | |
639 | |
640 | === modified file 'tests/autopilot/camera_app/tests/test_gallery_view.py' |
641 | --- tests/autopilot/camera_app/tests/test_gallery_view.py 2014-11-20 22:02:12 +0000 |
642 | +++ tests/autopilot/camera_app/tests/test_gallery_view.py 2015-01-24 18:49:40 +0000 |
643 | @@ -62,10 +62,11 @@ |
644 | os.remove(os.path.join(self.videos_dir, f)) |
645 | |
646 | def add_sample_photo(self): |
647 | - # add a fake photo to pictures_dir |
648 | - photo_path = os.path.join(self.pictures_dir, "fake_photo.jpg") |
649 | - with open(photo_path, 'a'): |
650 | - os.utime(photo_path, None) |
651 | + self.main_window.swipe_to_viewfinder(self) |
652 | + exposure_button = self.main_window.get_exposure_button() |
653 | + self.assertThat(exposure_button.enabled, Eventually(Equals(True))) |
654 | + self.pointing_device.move_to_object(exposure_button) |
655 | + self.pointing_device.click() |
656 | |
657 | def select_first_photo(self): |
658 | # select the first photo |
FAILED: Continuous integration, rev:474 jenkins. qa.ubuntu. com/job/ camera- app-ci/ 358/ jenkins. qa.ubuntu. com/job/ camera- app-vivid- amd64-ci/ 54 jenkins. qa.ubuntu. com/job/ camera- app-vivid- armhf-ci/ 54 jenkins. qa.ubuntu. com/job/ camera- app-vivid- armhf-ci/ 54/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ camera- app-vivid- i386-ci/ 54 jenkins. qa.ubuntu. com/job/ generic- click-autopilot -vivid- touch/88/ console jenkins. qa.ubuntu. com/job/ generic- mediumtests- vivid/439 jenkins. qa.ubuntu. com/job/ generic- click-autopilot -runner- mako/728/ console jenkins. qa.ubuntu. com/job/ generic- click-builder- vivid-armhf/ 183 s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 17406 jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-vivid/ 360 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-amd64/ 531 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-amd64/ 531/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/camera- app-ci/ 358/rebuild
http://