Merge lp:~fboucault/camera-app/async_lib_loading into lp:camera-app

Proposed by Florian Boucault
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
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.

To post a comment you must log in.
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
479. By Florian Boucault

Vastly more efficient selectAll with large collections.

480. By Florian Boucault

Fixed deletion bug.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
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.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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

Subscribers

People subscribed via source and target branches