[Merge] lp:~fboucault/camera-app/content_source into lp:camera-app

Ugo Riboni ugo.riboni at canonical.com
Mon Aug 4 11:32:18 UTC 2014


Review: Needs Fixing

Minor style and edge cases pointed out inline. 
Runs fine, but not sure how to test the actual functionality.

Diff comments:

> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt	2014-07-29 10:06:21 +0000
> +++ CMakeLists.txt	2014-08-01 15:50:37 +0000
> @@ -120,6 +120,8 @@
>              DESTINATION ${CMAKE_INSTALL_PREFIX})
>      install(FILES camera-apparmor.json
>              DESTINATION ${CMAKE_INSTALL_PREFIX})
> +    install(FILES camera-contenthub.json
> +            DESTINATION ${CMAKE_INSTALL_PREFIX})
>  
>  else(CLICK_MODE)
>      install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE}
> 
> === modified file 'CameraApp/foldersmodel.cpp'
> --- CameraApp/foldersmodel.cpp	2014-07-29 11:57:12 +0000
> +++ CameraApp/foldersmodel.cpp	2014-08-01 15:50:37 +0000
> @@ -20,7 +20,8 @@
>  #include <QtCore/QDateTime>
>  
>  FoldersModel::FoldersModel(QObject *parent) :
> -    QAbstractListModel(parent)
> +    QAbstractListModel(parent),
> +    m_singleSelectionOnly(true)
>  {
>      m_watcher = new QFileSystemWatcher(this);
>      connect(m_watcher, SIGNAL(directoryChanged(QString)), this, SLOT(directoryChanged(QString)));
> @@ -40,31 +41,60 @@
>      Q_EMIT foldersChanged();
>  }
>  
> -QStringList FoldersModel::nameFilters() const
> +QStringList FoldersModel::typeFilters() const
>  {
> -    return m_nameFilters;
> +    return m_typeFilters;
>  }
>  
> -void FoldersModel::setNameFilters(const QStringList& nameFilters)
> +void FoldersModel::setTypeFilters(const QStringList& typeFilters)
>  {
> -    m_nameFilters = nameFilters;
> +    m_typeFilters = typeFilters;
>      updateFileInfoList();
> -    Q_EMIT nameFiltersChanged();
> -}
> +    Q_EMIT typeFiltersChanged();
> +}
> +
> +QList<int> FoldersModel::selectedFiles() const
> +{
> +    return m_selectedFiles.values();
> +}
> +
> +bool FoldersModel::singleSelectionOnly() const
> +{
> +    return m_singleSelectionOnly;
> +}
> +
> +void FoldersModel::setSingleSelectionOnly(bool singleSelectionOnly)
> +{
> +    if (singleSelectionOnly != m_singleSelectionOnly) {
> +        if (singleSelectionOnly && m_selectedFiles.count() > 1) {
> +            clearSelection();
> +        }
> +        m_singleSelectionOnly = singleSelectionOnly;
> +        Q_EMIT singleSelectionOnlyChanged();
> +    }
> +}
> +
>  
>  void FoldersModel::updateFileInfoList()
>  {
>      m_fileInfoList.clear();
>      Q_FOREACH (QString folder, m_folders) {
>          QDir currentDir(folder);
> -        QFileInfoList fileInfoList = currentDir.entryInfoList(m_nameFilters,
> -                                                              QDir::Files | QDir::Readable,
> +        QFileInfoList fileInfoList = currentDir.entryInfoList(QDir::Files | QDir::Readable,
>                                                                QDir::Time | QDir::Reversed);
>          Q_FOREACH (QFileInfo fileInfo, fileInfoList) {
> -            insertFileInfo(fileInfo);
> +            QString type = m_mimeDatabase.mimeTypeForFile(fileInfo).name();
> +            Q_FOREACH (QString filterType, m_typeFilters) {
> +                if (type.startsWith(filterType)) {
> +                    insertFileInfo(fileInfo);
> +                    break;
> +                }
> +            }
>          }
>      }
>      endResetModel();
> +    m_selectedFiles.clear();
> +    Q_EMIT selectedFilesChanged();
>  }
>  
>  bool moreRecentThan(const QFileInfo& fileInfo1, const QFileInfo& fileInfo2)
> @@ -94,6 +124,7 @@
>      roles[FilePathRole] = "filePath";
>      roles[FileUrlRole] = "fileURL";
>      roles[FileTypeRole] = "fileType";
> +    roles[SelectedRole] = "selected";
>      return roles;
>  }
>  
> @@ -120,7 +151,10 @@
>              return QUrl::fromLocalFile(item.filePath());
>              break;
>          case FileTypeRole:
> -            return m_mimeDatabase.mimeTypeForFile(item.fileName()).name();
> +            return m_mimeDatabase.mimeTypeForFile(item).name();
> +            break;
> +        case SelectedRole:
> +            return m_selectedFiles.contains(index.row());
>              break;
>          default:
>              break;
> @@ -143,3 +177,31 @@
>  {
>      updateFileInfoList();
>  }
> +
> +void FoldersModel::toggleSelected(int row)
> +{
> +    if (m_selectedFiles.contains(row)) {
> +        m_selectedFiles.remove(row);
> +    } else {
> +        if (m_singleSelectionOnly) {
> +            int previouslySelected = m_selectedFiles.isEmpty() ? -1 : m_selectedFiles.values().first();
> +            if (previouslySelected != -1) {
> +                m_selectedFiles.remove(previouslySelected);
> +                Q_EMIT dataChanged(index(previouslySelected), index(previouslySelected));
> +            }
> +        }
> +        m_selectedFiles.insert(row);
> +    }
> +
> +    Q_EMIT dataChanged(index(row), index(row));
> +    Q_EMIT selectedFilesChanged();
> +}
> +
> +void FoldersModel::clearSelection()
> +{
> +    Q_FOREACH (int selectedFile, m_selectedFiles) {
> +        m_selectedFiles.remove(selectedFile);
> +        Q_EMIT dataChanged(index(selectedFile), index(selectedFile));
> +    }
> +    Q_EMIT selectedFilesChanged();
> +}
> 
> === modified file 'CameraApp/foldersmodel.h'
> --- CameraApp/foldersmodel.h	2014-07-29 11:57:12 +0000
> +++ CameraApp/foldersmodel.h	2014-08-01 15:50:37 +0000
> @@ -22,27 +22,34 @@
>  #include <QtCore/QFileInfo>
>  #include <QtCore/QFileSystemWatcher>
>  #include <QtCore/QMimeDatabase>
> +#include <QtCore/QSet>
>  
>  class FoldersModel : public QAbstractListModel
>  {
>      Q_OBJECT
>      Q_PROPERTY (QStringList folders READ folders WRITE setFolders NOTIFY foldersChanged)
> -    Q_PROPERTY (QStringList nameFilters READ nameFilters WRITE setNameFilters NOTIFY nameFiltersChanged)
> +    Q_PROPERTY (QStringList typeFilters READ typeFilters WRITE setTypeFilters NOTIFY typeFiltersChanged)
> +    Q_PROPERTY (QList<int> selectedFiles READ selectedFiles NOTIFY selectedFilesChanged)
> +    Q_PROPERTY (bool singleSelectionOnly READ singleSelectionOnly WRITE setSingleSelectionOnly NOTIFY singleSelectionOnlyChanged)
>  
>  public:
>      enum Roles {
>          FileNameRole = Qt::UserRole + 1,
>          FilePathRole = Qt::UserRole + 2,
>          FileUrlRole = Qt::UserRole + 3,
> -        FileTypeRole = Qt::UserRole + 4
> +        FileTypeRole = Qt::UserRole + 4,
> +        SelectedRole = Qt::UserRole + 5
>      };
>  
>      explicit FoldersModel(QObject *parent = 0);
>  
>      QStringList folders() const;
>      void setFolders(const QStringList& folders);
> -    QStringList nameFilters() const;
> -    void setNameFilters(const QStringList& nameFilters);
> +    QStringList typeFilters() const;
> +    void setTypeFilters(const QStringList& typeFilters);
> +    QList<int> selectedFiles() const;
> +    bool singleSelectionOnly() const;
> +    void setSingleSelectionOnly(bool singleSelectionOnly);
>  
>      void updateFileInfoList();
>      void insertFileInfo(const QFileInfo& newFileInfo);
> @@ -51,20 +58,26 @@
>      QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
>      int rowCount(const QModelIndex& parent = QModelIndex()) const;
>      Q_INVOKABLE QVariant get(int row, QString role) const;
> +    Q_INVOKABLE void toggleSelected(int row);
> +    Q_INVOKABLE void clearSelection();
>  
>  public Q_SLOTS:
>      void directoryChanged(const QString &directoryPath);
>  
>  Q_SIGNALS:
>      void foldersChanged();
> -    void nameFiltersChanged();
> +    void typeFiltersChanged();
> +    void selectedFilesChanged();
> +    void singleSelectionOnlyChanged();
>  
>  private:
>      QStringList m_folders;
> -    QStringList m_nameFilters;
> +    QStringList m_typeFilters;
>      QFileInfoList m_fileInfoList;
>      QFileSystemWatcher* m_watcher;
>      QMimeDatabase m_mimeDatabase;
> +    QSet<int> m_selectedFiles;
> +    bool m_singleSelectionOnly;
>  };
>  
>  #endif // FOLDERSMODEL_H
> 
> === modified file 'GalleryView.qml'
> --- GalleryView.qml	2014-07-25 12:44:19 +0000
> +++ GalleryView.qml	2014-08-01 15:50:37 +0000
> @@ -16,7 +16,9 @@
>  
>  import QtQuick 2.2
>  import Ubuntu.Components 1.0
> +import Ubuntu.Content 0.1
>  import CameraApp 0.1
> +import "MimeTypeMapper.js" as MimeTypeMapper
>  
>  Item {
>      id: galleryView
> @@ -26,7 +28,9 @@
>      property Item currentView: state == "GRID" ? photogridView : slideshowView
>      property var model: FoldersModel {
>          folders: [application.picturesLocation, application.videosLocation]
> -        nameFilters: [ "*.png", "*.jpg", "*.jpeg", "*.PNG", "*.JPG", "*.JPEG", "*.mp4" ]
> +        typeFilters: !main.contentExportMode ? [ "image", "video" ]
> +                                              : [MimeTypeMapper.contentTypeToMimeType(main.transferContentType)]
> +        singleSelectionOnly: main.transfer.selectionType === ContentTransfer.Single
>      }
>  
>      property bool gridMode: false
> @@ -59,8 +63,12 @@
>              model: galleryView.model
>              visible: opacity != 0.0
>              onPhotoClicked: {
> -                slideshowView.showPhotoAtIndex(index);
> -                galleryView.gridMode = false;
> +                if (main.contentExportMode) {
> +                    model.toggleSelected(index);
> +                } else {
> +                    slideshowView.showPhotoAtIndex(index);
> +                    galleryView.gridMode = false;
> +                }
>              }
>          }
>  
> @@ -69,7 +77,8 @@
>              id: header
>              onExit: galleryView.exit()
>              actions: currentView.actions
> -            gridMode: galleryView.gridMode
> +            gridMode: galleryView.gridMode || main.contentExportMode
> +            validationVisible: main.contentExportMode && model.selectedFiles.length > 0
>              onToggleViews: {
>                  if (!galleryView.gridMode) {
>                      // position grid view so that the current photo in slideshow view is visible
> @@ -78,6 +87,15 @@
>  
>                  galleryView.gridMode = !galleryView.gridMode
>              }
> +            onValidationClicked: {
> +                var selection = model.selectedFiles;
> +                var urls = [];
> +                for (var i=0; i<selection.length; i++) {
> +                    urls.push(model.get(selection[i], "fileURL"));
> +                }
> +                model.clearSelection();
> +                main.exportContent(urls);
> +            }
>          }
>      }
>  
> @@ -93,7 +111,7 @@
>          text: i18n.tr("No media available.")
>      }
>  
> -    state: galleryView.gridMode ? "GRID" : "SLIDESHOW"
> +    state: galleryView.gridMode || main.contentExportMode ? "GRID" : "SLIDESHOW"
>      states: [
>          State {
>              name: "SLIDESHOW"
> 
> === modified file 'GalleryViewHeader.qml'
> --- GalleryViewHeader.qml	2014-07-30 19:29:56 +0000
> +++ GalleryViewHeader.qml	2014-08-01 15:50:37 +0000
> @@ -34,8 +34,10 @@
>      property bool shown: true
>      property alias actions: actionsDrawer.actions
>      property bool gridMode: false
> +    property bool validationVisible
>      signal exit
>      signal toggleViews
> +    signal validationClicked
>  
>      function show() {
>          shown = true;
> @@ -83,6 +85,7 @@
>              }
>              iconName: header.gridMode ? "stock_image" : "view-grid-symbolic"
>              onClicked: header.toggleViews()
> +            visible: !main.contentExportMode
>          }
>  
>          IconButton {
> @@ -95,6 +98,17 @@
>              visible: actionsDrawer.actions.length > 0
>              onClicked: actionsDrawer.opened = !actionsDrawer.opened
>          }
> +
> +        IconButton {
> +            objectName: "validationButton"
> +            anchors {
> +                top: parent.top
> +                bottom: parent.bottom
> +            }
> +            iconName: "ok"
> +            onClicked: header.validationClicked()
> +            visible: header.validationVisible
> +        }
>      }
>  
>      Item {
> 
> === modified file 'MimeTypeMapper.js'
> --- MimeTypeMapper.js	2014-07-29 11:57:12 +0000
> +++ MimeTypeMapper.js	2014-08-01 15:50:37 +0000
> @@ -16,22 +16,33 @@
>   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
>  */
>  
> +.pragma library
> +.import Ubuntu.Content 0.1 as UbuntuContent
> +
>  function startsWith(string, prefix) {
>      return string.indexOf(prefix) === 0;
>  }
>  
>  function mimeTypeToContentType(mimeType) {
>      if(startsWith(mimeType, "image")) {
> -        return ContentType.Pictures;
> +        return UbuntuContent.ContentType.Pictures;
>      } else if(startsWith(mimeType, "audio")) {
> -        return ContentType.Music;
> +        return UbuntuContent.ContentType.Music;
>      } else if(startsWith(mimeType, "video")) {
> -        return ContentType.Videos;
> +        return UbuntuContent.ContentType.Videos;
>      } else if(startsWith(mimeType, "text/x-vcard")) {
> -        return ContentType.Contacts;
> +        return UbuntuContent.ContentType.Contacts;
>      } else if(startsWith(mimeType, "text")) {
> -        return ContentType.Documents;
> +        return UbuntuContent.ContentType.Documents;
>      } else {
> -        return ContentType.Unknown;
> +        return UbuntuContent.ContentType.Unknown;
> +    }
> +}
> +
> +function contentTypeToMimeType(contentType) {
> +    if (contentType === UbuntuContent.ContentType.Pictures) {
> +        return "image";
> +    } else if (contentType === UbuntuContent.ContentType.Videos) {
> +        return "video";
>      }
>  }
> 
> === modified file 'PhotogridView.qml'
> --- PhotogridView.qml	2014-07-29 11:57:12 +0000
> +++ PhotogridView.qml	2014-08-01 15:50:37 +0000
> @@ -15,7 +15,7 @@
>   */
>  
>  import QtQuick 2.2
> -import Ubuntu.Components 1.0
> +import Ubuntu.Components 1.1
>  import Ubuntu.Thumbnailer 0.1
>  import Ubuntu.Content 0.1
>  import "MimeTypeMapper.js" as MimeTypeMapper
> @@ -103,6 +103,13 @@
>                  visible: isVideo
>              }
>  
> +            Rectangle {
> +                anchors.fill: parent
> +                color: UbuntuColors.blue
> +                opacity: 0.4
> +                visible: selected
> +            }
> +
>              MouseArea {
>                  anchors.fill: parent
>                  onClicked: photogridView.photoClicked(index)
> 
> === modified file 'Snapshot.qml'
> --- Snapshot.qml	2014-06-04 14:48:22 +0000
> +++ Snapshot.qml	2014-08-01 15:50:37 +0000
> @@ -29,6 +29,8 @@
>          shoot.restart()
>      }
>  
> +    visible: false
> +
>      Item {
>          id: container
>          anchors {
> @@ -36,7 +38,6 @@
>              bottom: parent.bottom
>          }
>          width: parent.width
> -        visible: false
>  
>          Image {
>              id: snapshot
> @@ -67,11 +68,11 @@
>      SequentialAnimation {
>          id: shoot
>  
> -        PropertyAction { target: container; property: "visible"; value: true }
> +        PropertyAction { target: snapshotRoot; property: "visible"; value: true }
>          PauseAnimation { duration: 150 }
>          XAnimator { target: container; to: container.width + shadow.width; duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasing}
>          PropertyAction { target: snapshot; property: "source"; value: ""}
> -        PropertyAction { target: container; property: "visible"; value: false }
> +        PropertyAction { target: snapshotRoot; property: "visible"; value: false }
>          PropertyAction { target: container; property: "x"; value: 0 }
>      }
>  }
> 
> === added file 'ViewFinderExportConfirmation.qml'
> --- ViewFinderExportConfirmation.qml	1970-01-01 00:00:00 +0000
> +++ ViewFinderExportConfirmation.qml	2014-08-01 15:50:37 +0000
> @@ -0,0 +1,92 @@
> +/*
> + * Copyright 2014 Canonical Ltd.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; version 3.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +import QtQuick 2.2
> +import Ubuntu.Components 1.1
> +
> +Item {
> +    id: viewFinderExportConfirmation
> +
> +    property string mediaPath
> +    property Snapshot snapshot
> +
> +    function confirmExport(path) {
> +        mediaPath = path;
> +        snapshot.visible = true;
> +        visible = true;
> +    }
> +
> +    function hide() {
> +        mediaPath = "";
> +        viewFinderOverlay.visible = true;
> +        snapshot.source = "";
> +        snapshot.visible = false;
> +        visible = false;
> +    }
> +
> +    visible: false
> +
> +    CircleButton {
> +        id: retryButton
> +        objectName: "retryButton"
> +
> +        anchors {
> +            right: validateButton.left
> +            rightMargin: units.gu(7.5)
> +            bottom: parent.bottom
> +            bottomMargin: units.gu(6)
> +        }
> +
> +        iconName: "reload"
> +        onClicked: hide()
> +    }
> +
> +    CircleButton {
> +        id: validateButton
> +        objectName: "validateButton"
> +
> +        width: units.gu(8)
> +        anchors {
> +            bottom: parent.bottom
> +            bottomMargin: units.gu(5)
> +            horizontalCenter: parent.horizontalCenter
> +        }
> +
> +        iconName: "ok"
> +        onClicked: {
> +            hide();
> +            main.exportContent([mediaPath]);
> +        }
> +    }
> +
> +    CircleButton {
> +        id: cancelButton
> +        objectName: "cancelButton"
> +
> +        anchors {
> +            left: validateButton.right
> +            leftMargin: units.gu(7.5)
> +            bottom: parent.bottom
> +            bottomMargin: units.gu(6)
> +        }
> +
> +        iconName: "close"
> +        onClicked: {
> +            hide();
> +            main.cancelExport();
> +        }
> +    }
> +}
> 
> === modified file 'ViewFinderOverlay.qml'
> --- ViewFinderOverlay.qml	2014-07-30 19:29:39 +0000
> +++ ViewFinderOverlay.qml	2014-08-01 15:50:37 +0000
> @@ -288,8 +288,6 @@
>          enabled: visible
>  
>          function shoot() {
> -            camera.captureInProgress = true;
> -
>              var orientation = Screen.angleBetween(Screen.orientation, Screen.primaryOrientation);
>              if (Screen.primaryOrientation == Qt.PortraitOrientation) {
>                  orientation += 90;
> @@ -304,7 +302,9 @@
>                      // TODO: there's no event to tell us that the video has been successfully recorder or failed
>                  }
>              } else {
> -                shootFeedback.start();
> +                if (!main.contentExportMode) {
> +                    shootFeedback.start();
> +                }
>                  camera.imageCapture.setMetadata("Orientation", orientation);
>                  var position = positionSource.position;
>                  if (settings.gpsEnabled && positionSource.valid
> @@ -317,17 +317,12 @@
>                      camera.imageCapture.setMetadata("GPSTimeStamp", position.timestamp);
>                      camera.imageCapture.setMetadata("GPSProcessingMethod", "GPS");
>                  }
> -                camera.imageCapture.captureToLocation(application.picturesLocation);
> -            }
> -        }
> -
> -        function completeCapture() {
> -            viewFinderOverlay.visible = true;
> -            // FIXME: no snapshot is available for videos
> -            if (camera.captureMode != Camera.CaptureVideo) {
> -                snapshot.startOutAnimation();
> -            }
> -            camera.captureInProgress = false;
> +                if (main.contentExportMode) {
> +                    camera.imageCapture.captureToLocation(application.temporaryLocation);
> +                } else {
> +                    camera.imageCapture.captureToLocation(application.picturesLocation);
> +                }
> +            }
>          }
>  
>          function switchCamera() {
> @@ -361,9 +356,7 @@
>              target: camera.imageCapture
>              onReadyChanged: {
>                  if (camera.imageCapture.ready) {
> -                    if (camera.captureInProgress) {
> -                        controls.completeCapture();
> -                    } else if (camera.switchInProgress) {
> +                    if (camera.switchInProgress) {
>                          controls.completeSwitch();
>                      }
>                  }
> @@ -383,6 +376,7 @@
>  
>              iconName: (camera.captureMode == Camera.CaptureStillImage) ? "camcorder" : "camera-symbolic"
>              onClicked: controls.changeRecordMode()
> +            enabled: !main.contentExportMode
>          }
>  
>          ShootButton {
> 
> === modified file 'ViewFinderView.qml'
> --- ViewFinderView.qml	2014-07-28 12:55:56 +0000
> +++ ViewFinderView.qml	2014-08-01 15:50:37 +0000
> @@ -28,6 +28,7 @@
>      property bool optionValueSelectorVisible: false
>      property bool touchAcquired: viewFinderOverlay.touchAcquired
>      property bool inView
> +    property alias captureMode: camera.captureMode
>      signal photoTaken
>      signal videoShot
>  
> @@ -75,7 +76,6 @@
>                 transparently based on the value. */
>          property alias currentZoom: camera.digitalZoom
>          property alias maximumZoom: camera.maximumDigitalZoom
> -        property bool captureInProgress: false
>          property bool switchInProgress: false
>          
>          imageCapture {
> @@ -86,6 +86,12 @@
>                  snapshot.source = preview;
>              }
>              onImageSaved: {
> +                if (main.contentExportMode) {
> +                    viewFinderExportConfirmation.confirmExport(path);
> +                } else {
> +                    viewFinderOverlay.visible = true;
> +                    snapshot.startOutAnimation();
> +                }
>                  viewFinderView.photoTaken();
>                  metricPhotos.increment();
>                  console.log("Picture saved as " + path);
> @@ -96,7 +102,7 @@
>              onRecorderStateChanged: {
>                  if (videoRecorder.recorderState === CameraRecorder.StoppedState) {
>                      metricVideos.increment()
> -                    viewFinderOverlay.controls.completeCapture();
> +                    viewFinderOverlay.visible = true;
>                      viewFinderView.videoShot();
>                  }
>              }
> @@ -284,4 +290,10 @@
>          geometry: viewFinderGeometry
>          deviceDefaultIsPortrait: Screen.primaryOrientation === Qt.PortraitOrientation
>      }
> +
> +    ViewFinderExportConfirmation {
> +        id: viewFinderExportConfirmation
> +        anchors.fill: parent
> +        snapshot: snapshot
> +    }
>  }
> 
> === modified file 'camera-app.qml'
> --- camera-app.qml	2014-07-28 12:55:56 +0000
> +++ camera-app.qml	2014-08-01 15:50:37 +0000
> @@ -16,9 +16,11 @@
>  
>  import QtQuick 2.2
>  import QtQuick.Window 2.0
> +import QtMultimedia 5.0
>  import Ubuntu.Components 1.0
>  import Ubuntu.Unity.Action 1.1 as UnityActions
>  import UserMetrics 0.1
> +import Ubuntu.Content 0.1
>  
>  Item {
>      id: main
> @@ -164,6 +166,46 @@
>          }
>      }
>  
> +    property bool contentExportMode: transfer !== null
> +    property var transfer: null
> +    property var transferContentType: ContentType.Pictures
> +
> +    function exportContent(urls) {
> +        if (!main.transfer) return;
> +
> +        var item;
> +        var items = [];
> +        for (var i=0; i<urls.length; i++) {
> +            item = contentItemComponent.createObject(main.transfer, {"url": urls[i]});
> +            items.push(item);
> +        }
> +        main.transfer.items = items;
> +        main.transfer.state = ContentTransfer.Charged;
> +        main.transfer = null;
> +    }
> +
> +    function cancelExport() {
> +        main.transfer.state = ContentTransfer.Aborted;
> +        main.transfer = null;
> +    }
> +
> +    Component {
> +        id: contentItemComponent
> +        ContentItem {
> +        }
> +    }
> +
> +    Connections {
> +        target: ContentHub
> +        onExportRequested: {
> +            if (transferContentType === ContentType.Videos) {
> +                viewFinderView.captureMode = Camera.CaptureVideo;
> +            } else {
> +                viewFinderView.captureMode = Camera.CaptureStillImage;
> +            }
> +            main.transfer = transfer;
> +        }
> +    }
>  
>      Metric {
>          id: metricPhotos
> 
> === modified file 'camera-apparmor.json'
> --- camera-apparmor.json	2014-07-17 11:03:53 +0000
> +++ camera-apparmor.json	2014-08-01 15:50:37 +0000
> @@ -11,4 +11,4 @@
>          "location"
>      ],
>      "policy_version": 1.2
> -}

Nitpick: this change does nothing, just alter whitespace

> +}
> \ No newline at end of file
> 
> === added file 'camera-contenthub.json'
> --- camera-contenthub.json	1970-01-01 00:00:00 +0000
> +++ camera-contenthub.json	2014-08-01 15:50:37 +0000
> @@ -0,0 +1,5 @@
> +{
> +    "source": [
> +        "pictures"
> +    ]
> +}
> 
> === modified file 'cameraapplication.cpp'
> --- cameraapplication.cpp	2014-07-29 18:08:21 +0000
> +++ cameraapplication.cpp	2014-08-01 15:50:37 +0000
> @@ -123,3 +123,11 @@
>      dir.mkpath(location);
>      return location;
>  }
> +
> +QString CameraApplication::temporaryLocation() const
> +{
> +    QString location = QStandardPaths::standardLocations(QStandardPaths::TempLocation).at(0);

Unlikely, but the list returned by this function can be empty, so at(0) will crash the app. Please check or use value()

> +    QDir dir;
> +    dir.mkpath(location);
> +    return location;
> +}
> 
> === modified file 'cameraapplication.h'
> --- cameraapplication.h	2014-07-02 15:43:31 +0000
> +++ cameraapplication.h	2014-08-01 15:50:37 +0000
> @@ -31,6 +31,7 @@
>      Q_PROPERTY(bool desktopMode READ isDesktopMode CONSTANT)
>      Q_PROPERTY(QString picturesLocation READ picturesLocation CONSTANT)
>      Q_PROPERTY(QString videosLocation READ videosLocation CONSTANT)
> +    Q_PROPERTY(QString temporaryLocation READ temporaryLocation CONSTANT)
>  
>  public:
>      CameraApplication(int &argc, char **argv);
> @@ -39,6 +40,7 @@
>      bool isDesktopMode() const;
>      QString picturesLocation() const;
>      QString videosLocation() const;
> +    QString temporaryLocation() const;
>  
>  private:
>      QScopedPointer<QQuickView> m_view;
> 
> === modified file 'manifest.json'
> --- manifest.json	2014-07-10 14:27:45 +0000
> +++ manifest.json	2014-08-01 15:50:37 +0000
> @@ -5,7 +5,8 @@
>      "hooks": {
>          "camera": {
>              "apparmor": "camera-apparmor.json",
> -            "desktop": "@DESKTOP_FILE@"
> +            "desktop": "@DESKTOP_FILE@",
> +            "content-hub": "camera-contenthub.json"
>          }
>      },
>      "icon": "@CAMERA_ICON@",
> @@ -20,4 +21,4 @@
>      "x-test": {
>          "autopilot": "@AUTOPILOT_DIR@"
>      }
> -}
> +}

More unnecessary whitespace changes

> \ No newline at end of file
> 


-- 
https://code.launchpad.net/~fboucault/camera-app/content_source/+merge/229250
Your team Ubuntu Phablet Team is subscribed to branch lp:camera-app.



More information about the Ubuntu-reviews mailing list