[Merge] lp:~fboucault/camera-app/ui_rewrite into lp:camera-app
Florian Boucault
florian.boucault at canonical.com
Thu Jun 26 11:44:52 UTC 2014
New version available at:
http://people.canonical.com/~kaleo/com.ubuntu.camera_3.0.0.latest_armhf.click
Diff comments:
> === modified file 'CMakeLists.txt'
> --- CMakeLists.txt 2014-05-06 18:41:31 +0000
> +++ CMakeLists.txt 2014-06-26 09:06:29 +0000
> @@ -79,6 +79,9 @@
>
> file(GLOB QML_JS_FILES *.qml *.js)
>
> +# make the files visible on qtcreator
> +add_custom_target(QML_JS_TARGET ALL SOURCES ${QML_JS_FILES})
> +
> install(FILES ${QML_JS_FILES}
> DESTINATION ${CAMERA_APP_DIR}
> )
> @@ -105,6 +108,9 @@
> install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE}
> DESTINATION ${CMAKE_INSTALL_DATADIR}/applications
> )
> +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DESKTOP_FILE}
> + DESTINATION /
> + )
>
> add_subdirectory(CameraApp)
> add_subdirectory(click)
>
> === modified file 'CameraApp/CMakeLists.txt'
> --- CameraApp/CMakeLists.txt 2013-09-26 14:16:34 +0000
> +++ CameraApp/CMakeLists.txt 2014-06-26 09:06:29 +0000
> @@ -3,11 +3,13 @@
> set(plugin_SRCS
> components.cpp
> advancedcamerasettings.cpp
> + fileoperations.cpp
> )
>
> set(plugin_HDRS
> components.h
> advancedcamerasettings.h
> + fileoperations.h
> )
>
> add_library(camera-qml SHARED ${plugin_SRCS} ${plugin_HDRS})
>
> === modified file 'CameraApp/advancedcamerasettings.cpp'
> --- CameraApp/advancedcamerasettings.cpp 2013-06-21 10:22:23 +0000
> +++ CameraApp/advancedcamerasettings.cpp 2014-06-26 09:06:29 +0000
> @@ -24,6 +24,7 @@
> #include <QtMultimedia/QCameraControl>
> #include <QtMultimedia/QMediaService>
> #include <QtMultimedia/QVideoDeviceSelectorControl>
> +#include <QtMultimedia/QCameraFlashControl>
>
> AdvancedCameraSettings::AdvancedCameraSettings(QObject *parent) :
> QObject(parent),
> @@ -113,13 +114,25 @@
>
> QCameraControl *camControl = qobject_cast<QCameraControl*>(control);
> if (camControl == 0) {
> - qWarning() << "No viewfinder settings support";
> + qWarning() << "No camera control support";
> return 0;
> }
>
> return camControl;
> }
>
> +QCameraFlashControl *AdvancedCameraSettings::flashControlFromCamera(QCamera *camera) const
> +{
> + QMediaControl *control = mediaControlFromCamera(camera, QCameraFlashControl_iid);
> + QCameraFlashControl *flashControl = qobject_cast<QCameraFlashControl*>(control);
> +
> + if (flashControl == 0) {
> + qWarning() << "No flash control support";
> + }
> +
> + return flashControl;
> +}
> +
> QObject* AdvancedCameraSettings::camera() const
> {
> return m_cameraObject;
> @@ -142,25 +155,15 @@
> m_camera = camera;
> if (m_camera != 0) {
> this->connect(m_camera, SIGNAL(stateChanged(QCamera::State)),
> - SIGNAL(resolutionChanged()));
> - }
> -
> - QVideoDeviceSelectorControl* selector = selectorFromCamera(m_camera);
> - m_deviceSelector = selector;
> - if (selector) {
> - m_deviceSelector->setSelectedDevice(m_activeCameraIndex);
> -
> - QCameraViewfinderSettingsControl* viewfinder = viewfinderFromCamera(m_camera);
> - if (viewfinder) {
> - m_viewFinderControl = viewfinder;
> - resolutionChanged();
> + SLOT(onCameraStateChanged()));
> + if (m_camera->state() == QCamera::LoadedState || m_camera->state() == QCamera::ActiveState) {
> + readCapabilities();
> }
>
> - QCameraControl* cameraControl = camcontrolFromCamera(m_camera);
> - if (cameraControl) {
> - QObject::connect(cameraControl,
> - SIGNAL(captureModeChanged(QCamera::CaptureModes)),
> - this, SIGNAL(resolutionChanged()));
> + QVideoDeviceSelectorControl* selector = selectorFromCamera(m_camera);
> + m_deviceSelector = selector;
> + if (selector) {
> + m_deviceSelector->setSelectedDevice(m_activeCameraIndex);
> }
> }
>
> @@ -168,6 +171,29 @@
> }
> }
>
> +void AdvancedCameraSettings::readCapabilities()
> +{
> + m_viewFinderControl = viewfinderFromCamera(m_camera);
> + m_cameraControl = camcontrolFromCamera(m_camera);
> + if (m_cameraControl) {
> + QObject::connect(m_cameraControl,
> + SIGNAL(captureModeChanged(QCamera::CaptureModes)),
> + this, SIGNAL(resolutionChanged()));
> + }
> +
> + m_cameraFlashControl = flashControlFromCamera(m_camera);
> +
> + Q_EMIT resolutionChanged();
> + Q_EMIT hasFlashChanged();
> +}
> +
> +void AdvancedCameraSettings::onCameraStateChanged()
> +{
> + if (m_camera->state() == QCamera::LoadedState || m_camera->state() == QCamera::ActiveState) {
> + readCapabilities();
> + }
> +}
> +
> void AdvancedCameraSettings::setActiveCameraIndex(int index)
> {
> if (index != m_activeCameraIndex) {
> @@ -177,6 +203,7 @@
> }
> Q_EMIT activeCameraIndexChanged();
> Q_EMIT resolutionChanged();
> + Q_EMIT hasFlashChanged();
> }
> }
>
> @@ -191,3 +218,14 @@
>
> return QSize();
> }
> +
> +bool AdvancedCameraSettings::hasFlash() const
> +{
> + if (m_cameraFlashControl) {
> + return m_cameraFlashControl->isFlashModeSupported(QCameraExposure::FlashAuto)
> + && m_cameraFlashControl->isFlashModeSupported(QCameraExposure::FlashOff)
> + && m_cameraFlashControl->isFlashModeSupported(QCameraExposure::FlashOn);
> + } else {
> + return false;
> + }
> +}
>
> === modified file 'CameraApp/advancedcamerasettings.h'
> --- CameraApp/advancedcamerasettings.h 2013-06-21 10:22:23 +0000
> +++ CameraApp/advancedcamerasettings.h 2014-06-26 09:06:29 +0000
> @@ -27,6 +27,7 @@
> #include <QtMultimedia/QMediaControl>
>
> class QCameraControl;
> +class QCameraFlashControl;
>
> class AdvancedCameraSettings : public QObject
> {
> @@ -35,6 +36,7 @@
> Q_PROPERTY (int activeCameraIndex READ activeCameraIndex WRITE setActiveCameraIndex
> NOTIFY activeCameraIndexChanged)
> Q_PROPERTY (QSize resolution READ resolution NOTIFY resolutionChanged)
> + Q_PROPERTY (bool hasFlash READ hasFlash NOTIFY hasFlashChanged)
>
> public:
> explicit AdvancedCameraSettings(QObject *parent = 0);
> @@ -43,16 +45,23 @@
> void setCamera(QObject* camera);
> void setActiveCameraIndex(int index);
> QSize resolution() const;
> + bool hasFlash() const;
> + void readCapabilities();
>
> Q_SIGNALS:
> void cameraChanged();
> void activeCameraIndexChanged();
> void resolutionChanged();
> + void hasFlashChanged();
> +
> +private Q_SLOTS:
> + void onCameraStateChanged();
>
> private:
> QVideoDeviceSelectorControl* selectorFromCamera(QCamera *camera) const;
> QCameraViewfinderSettingsControl* viewfinderFromCamera(QCamera *camera) const;
> QCameraControl *camcontrolFromCamera(QCamera *camera) const;
> + QCameraFlashControl* flashControlFromCamera(QCamera* camera) const;
> QCamera* cameraFromCameraObject(QObject* cameraObject) const;
> QMediaControl* mediaControlFromCamera(QCamera *camera, const char* iid) const;
>
> @@ -61,6 +70,9 @@
> QVideoDeviceSelectorControl* m_deviceSelector;
> int m_activeCameraIndex;
> QCameraViewfinderSettingsControl* m_viewFinderControl;
> + QCameraControl* m_cameraControl;
> + QCameraFlashControl* m_cameraFlashControl;
> +
> };
>
> #endif // ADVANCEDCAMERASETTINGS_H
>
> === modified file 'CameraApp/components.cpp'
> --- CameraApp/components.cpp 2012-11-12 09:56:58 +0000
> +++ CameraApp/components.cpp 2014-06-26 09:06:29 +0000
> @@ -1,8 +1,9 @@
> /*
> - * Copyright (C) 2012 Canonical, Ltd.
> + * Copyright (C) 2014 Canonical, Ltd.
> *
> * Authors:
> * Ugo Riboni <ugo.riboni at canonical.com>
> + * Florian Boucault <florian.boucault at canonical.com>
> *
> * 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
> @@ -20,10 +21,15 @@
> #include <QtQuick>
> #include "components.h"
> #include "advancedcamerasettings.h"
> +#include "fileoperations.h"
>
> void Components::registerTypes(const char *uri)
> {
> + Q_ASSERT(uri == QLatin1String("CameraApp"));
> +
> + // @uri CameraApp
> qmlRegisterType<AdvancedCameraSettings>(uri, 0, 1, "AdvancedCameraSettings");
> + qmlRegisterType<FileOperations>(uri, 0, 1, "FileOperations");
> }
>
> void Components::initializeEngine(QQmlEngine *engine, const char *uri)
>
> === added file 'CameraApp/fileoperations.cpp'
> --- CameraApp/fileoperations.cpp 1970-01-01 00:00:00 +0000
> +++ CameraApp/fileoperations.cpp 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,28 @@
> +/*
> + * Copyright (C) 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/>.
> + */
> +
> +#include "fileoperations.h"
> +#include <QtCore/QFile>
> +
> +FileOperations::FileOperations(QObject *parent) :
> + QObject(parent)
> +{
> +}
> +
> +bool FileOperations::remove(const QString & fileName) const
> +{
> + return QFile::remove(fileName);
> +}
>
> === added file 'CameraApp/fileoperations.h'
> --- CameraApp/fileoperations.h 1970-01-01 00:00:00 +0000
> +++ CameraApp/fileoperations.h 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,31 @@
> +/*
> + * Copyright (C) 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/>.
> + */
> +
> +#ifndef FILEOPERATIONS_H
> +#define FILEOPERATIONS_H
> +
> +#include <QtCore/QObject>
> +
> +class FileOperations : public QObject
> +{
> + Q_OBJECT
> +
> +public:
> + explicit FileOperations(QObject *parent = 0);
> + Q_INVOKABLE bool remove(const QString & fileName) const;
> +};
> +
> +#endif // FILEOPERATIONS_H
>
> === modified file 'CameraApp/qmldir'
> --- CameraApp/qmldir 2012-09-26 11:22:50 +0000
> +++ CameraApp/qmldir 2014-06-26 09:06:29 +0000
> @@ -1,1 +1,2 @@
> +module CameraApp
> plugin camera-qml
>
> === added file 'CircleButton.qml'
> --- CircleButton.qml 1970-01-01 00:00:00 +0000
> +++ CircleButton.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,77 @@
> +/*
> + * 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 QtQuick.Window 2.0
> +import Ubuntu.Components 1.0
> +
> +AbstractButton {
> + id: button
> +
> + property alias iconName: icon.name
> + property bool on: true
> + property string label: ""
> +
> + width: units.gu(5)
> + height: width
> +
> + Image {
> + anchors.fill: parent
> + source: "assets/ubuntu_shape.svg"
Nope, I want it to be sharp at any resolution. Given that it's a very simple SVG I'm confident the loading is cheap and the rendering is reliable.
> + opacity: button.pressed ? 0.7 : 0.3
> + sourceSize.width: width
> + sourceSize.height: height
> + }
> +
> + Icon {
> + id: icon
> + anchors {
> + fill: parent
> + margins: units.gu(1)
> + }
> + color: "white"
> + opacity: button.on ? 1.0 : 0.5
> + visible: label === ""
> + rotation: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
> + Behavior on rotation {
> + RotationAnimator {
> + duration: UbuntuAnimation.BriskDuration
> + easing: UbuntuAnimation.StandardEasing
> + direction: RotationAnimator.Shortest
> + }
> + }
> + }
> +
> + Label {
> + anchors {
> + centerIn: parent
> + }
> + font.weight: Font.Light
> + fontSize: "small"
> + color: "white"
> + text: label
> + opacity: button.on ? 1.0 : 0.5
> + visible: label !== ""
> + rotation: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
> + Behavior on rotation {
> + RotationAnimator {
> + duration: UbuntuAnimation.BriskDuration
> + easing: UbuntuAnimation.StandardEasing
> + direction: RotationAnimator.Shortest
> + }
> + }
> + }
> +}
>
> === removed file 'CrossFadingButton.qml'
> --- CrossFadingButton.qml 2013-02-07 13:13:23 +0000
> +++ CrossFadingButton.qml 1970-01-01 00:00:00 +0000
> @@ -1,60 +0,0 @@
> -/*
> - * Copyright (C) 2012 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.0
> -import Ubuntu.Components 0.1
> -import "constants.js" as Const
> -
> -AbstractButton {
> - id: button
> - property string iconSource
> -
> - property Image __active: icon1
> - property Image __inactive: icon2
> -
> - onIconSourceChanged: {
> - if (__active && __inactive) {
> - __inactive.source = iconSource
> - __active.opacity = 0.0
> - __inactive.opacity = 1.0
> - var swap = __active
> - __active = __inactive
> - __inactive = swap
> - } else icon1.source = iconSource
> - }
> -
> - Image {
> - id: icon1
> - anchors.fill: parent
> - Behavior on opacity {
> - NumberAnimation {
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - }
> - }
> -
> - Image {
> - id: icon2
> - anchors.fill: parent
> - opacity: 0.0
> - Behavior on opacity {
> - NumberAnimation {
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - }
> - }
> -}
> -
>
> === removed file 'DeviceOrientation.qml'
> --- DeviceOrientation.qml 2013-06-10 12:38:15 +0000
> +++ DeviceOrientation.qml 1970-01-01 00:00:00 +0000
> @@ -1,37 +0,0 @@
> -/*
> - * Copyright 2013 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.0
> -import QtQuick.Window 2.0
> -
> -// We must use Item element because Screen component does not works with QtObject
> -Item {
> - property string naturalOrientation: Screen.primaryOrientation == Qt.LandscapeOrientation ? "landscape" : "portrait"
> -
> - /* Is the device currently rotated to be in lanscape orientation ? */
> - property bool isLandscape: Screen.orientation == Qt.LandscapeOrientation ||
> - Screen.orientation == Qt.InvertedLandscapeOrientation
> -
> - /* Is the device currently rotated upside down ? */
> - property bool isInverted: Screen.orientation == Qt.InvertedLandscapeOrientation ||
> - Screen.orientation == Qt.InvertedPortraitOrientation
> -
> - /* The rotation angle in 90 degrees increments with respect to the device being in its
> - default position */
> - property int rotationAngle: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
> -
> - visible: false
> -}
>
> === removed file 'FadingButton.qml'
> --- FadingButton.qml 2013-02-07 13:13:23 +0000
> +++ FadingButton.qml 1970-01-01 00:00:00 +0000
> @@ -1,72 +0,0 @@
> -/*
> - * Copyright (C) 2012 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.0
> -import Ubuntu.Components 0.1
> -import "constants.js" as Const
> -
> -AbstractButton {
> - id: button
> - property string iconSource
> -
> - property Image __active: icon1
> - property Image __inactive: icon2
> -
> - onIconSourceChanged: {
> - if (__active && __inactive) {
> - __inactive.source = iconSource
> - __active.opacity = 0.0
> - } else icon1.source = iconSource
> - }
> -
> - Image {
> - id: icon1
> - anchors.fill: parent
> - Behavior on opacity {
> - NumberAnimation {
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - }
> - }
> -
> - Image {
> - id: icon2
> - anchors.fill: parent
> - opacity: 0.0
> - Behavior on opacity {
> - NumberAnimation {
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - }
> - }
> -
> - Connections {
> - target: __active
> - onOpacityChanged: if (__active.opacity == 0.0) __inactive.opacity = 1.0
> - }
> -
> - Connections {
> - target: __inactive
> - onOpacityChanged: {
> - if (__inactive.opacity == 1.0) {
> - var swap = __active
> - __active = __inactive
> - __inactive = swap
> - }
> - }
> - }
> -}
> -
>
> === removed file 'FlashButton.qml'
> --- FlashButton.qml 2013-02-07 13:13:23 +0000
> +++ FlashButton.qml 1970-01-01 00:00:00 +0000
> @@ -1,82 +0,0 @@
> -/*
> - * Copyright (C) 2012 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.0
> -import "constants.js" as Const
> -
> -Item {
> - id: button
> -
> - property bool flashAllowed: true
> - property bool torchMode: false
> - property string flashState: "off"
> - signal clicked()
> -
> - CrossFadingButton {
> - id: flash
> - anchors.fill: parent
> - iconSource: (flashState == "off") ? "assets/flash_off.png" :
> - ((flashState == "on") ? "assets/flash_on.png" : "assets/flash_auto.png")
> - onClicked: button.clicked()
> - enabled: !torchMode
> - }
> -
> - CrossFadingButton {
> - id: torch
> - anchors.fill: parent
> - iconSource: (flashState == "on") ? "assets/torch_on.png" : "assets/torch_off.png"
> - enabled: torchMode
> - onClicked: button.clicked()
> - }
> -
> - states: [
> - State { name: "flash"; when: !torchMode
> - PropertyChanges { target: flash; opacity: 1.0 }
> - PropertyChanges { target: torch; opacity: 0.0 }
> - },
> - State { name: "torch"; when: torchMode
> - PropertyChanges { target: flash; opacity: 0.0 }
> - PropertyChanges { target: torch; opacity: 1.0 }
> - }
> - ]
> -
> - transitions: [
> - Transition { from: "flash"; to: "torch";
> - SequentialAnimation {
> - NumberAnimation {
> - target: flash; property: "opacity";
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - NumberAnimation {
> - target: torch; property: "opacity";
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - }
> - },
> - Transition { from: "torch"; to: "flash";
> - SequentialAnimation {
> - NumberAnimation {
> - target: torch; property: "opacity";
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - NumberAnimation {
> - target: flash; property: "opacity";
> - duration: Const.iconFadeDuration; easing.type: Easing.InOutQuad
> - }
> - }
> - }
> - ]
> -}
>
> === modified file 'FocusRing.qml'
> --- FocusRing.qml 2013-04-12 15:19:35 +0000
> +++ FocusRing.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (C) 2012 Canonical, Ltd.
> + * Copyright (C) 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
> @@ -15,28 +15,39 @@
> */
>
> import QtQuick 2.0
> -import Ubuntu.Components 0.1
> +import Ubuntu.Components 1.0
>
> Image {
> - property var center
> + id: focusRing
> +
> + property point center
> + function show() {
> + hideTimer.restart();
> + rotationAnimation.restart();
> + opacity = 1.0;
> + }
> +
> + x: center.x - width / 2.0
> + y: center.y - height / 2.0
> + width: units.gu(11)
> + height: units.gu(11)
> source: "assets/focus_ring.png"
>
> - Behavior on opacity { NumberAnimation { duration: 500 } }
> - onCenterChanged: {
> - x = center.x - focusRing.width * 0.5
> - y = center.y - focusRing.height * 0.5
> - opacity = 1.0
> - restartTimeout()
> - }
> -
> - function restartTimeout()
> - {
> - focusRingTimeout.restart()
> - }
> + opacity: 0.0
> + Behavior on opacity { UbuntuNumberAnimation {} }
>
> Timer {
> - id: focusRingTimeout
> - interval: 2000
> - onTriggered: focusRing.opacity = 0.0
> + id: hideTimer
> + interval: 1000
> + onTriggered: focusRing.opacity = 0.0;
> + }
> +
> + UbuntuNumberAnimation {
> + id: rotationAnimation
> + target: focusRing
> + property: "rotation"
> + from: 0
> + to: 90
> + duration: UbuntuAnimation.SleepyDuration
> }
No it does not, the only benefit of UbuntuNumberAnimation is that it has a default easing. Let me fix it to use a RotationAnimator
> }
>
> === added file 'GalleryView.qml'
> --- GalleryView.qml 1970-01-01 00:00:00 +0000
> +++ GalleryView.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,125 @@
> +/*
> + * 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.0
> +import Qt.labs.folderlistmodel 2.1
> +
> +Item {
> + id: galleryView
> +
> + signal exit
> + property bool inView
> + property Item currentView: state == "GRID" ? photogridView : slideshowView
> + property var model: FolderListModel {
> + folder: application.mediaLocation
> + nameFilters: [ "*.png", "*.jpg", "*.jpeg", "*.PNG", "*.JPG", "*.JPEG" ]
> + showOnlyReadable: true
> + sortField: FolderListModel.LastModified
> + sortReversed: true
> + showDirs: false
> + }
> + property bool gridMode: false
> +
> + function showLastPhotoTaken() {
> + galleryView.gridMode = false;
> + slideshowView.showLastPhotoTaken();
> + }
> +
> + onExit: {
> + slideshowView.exit();
> + photogridView.exit();
> + }
> +
> + OrientationHelper {
> + visible: inView
> +
> + SlideshowView {
> + id: slideshowView
> + anchors.fill: parent
> + model: galleryView.model
> + visible: opacity != 0.0
> + onToggleHeader: header.toggle();
> + }
> +
> + PhotogridView {
> + id: photogridView
> + anchors.fill: parent
> + headerHeight: header.height
> + model: galleryView.model
> + visible: opacity != 0.0
> + onPhotoClicked: {
> + slideshowView.showPhotoAtIndex(index);
> + galleryView.gridMode = false;
> + }
> + }
> +
> + GalleryViewHeader {
> + id: header
> + onExit: galleryView.exit()
> + actions: currentView.actions
> + onToggleViews: {
> + if (!galleryView.gridMode) {
> + // position grid view so that the current photo in slideshow view is visible
> + photogridView.showPhotoAtIndex(slideshowView.currentIndex);
> + }
> +
> + galleryView.gridMode = !galleryView.gridMode
> + }
> + }
> + }
> +
> + onInViewChanged: if (inView) {
> + header.show();
> + }
> +
> + state: galleryView.gridMode ? "GRID" : "SLIDESHOW"
> + states: [
> + State {
> + name: "SLIDESHOW"
> + PropertyChanges {
> + target: slideshowView
> + scale: 1.0
> + opacity: 1.0
> + }
> + PropertyChanges {
> + target: photogridView
> + scale: 1.4
> + opacity: 0.0
> + }
> + },
> + State {
> + name: "GRID"
> + PropertyChanges {
> + target: slideshowView
> + scale: 1.4
> + opacity: 0.0
> + }
> + PropertyChanges {
> + target: photogridView
> + scale: 1.0
> + opacity: 1.0
> + }
> + }
> + ]
> +
> + transitions: [
> + Transition {
> + to: "*"
> + UbuntuNumberAnimation { properties: "scale,opacity"; duration: UbuntuAnimation.SnapDuration }
> + }
> + ]
> +}
>
> === added file 'GalleryViewHeader.qml'
> --- GalleryViewHeader.qml 1970-01-01 00:00:00 +0000
> +++ GalleryViewHeader.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,178 @@
> +/*
> + * 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.0
> +import QtQuick.Layouts 1.1
> +
> +Item {
> + id: header
> + anchors {
> + left: parent.left
> + right: parent.right
> + }
> + y: shown ? 0 : -height
> + Behavior on y { UbuntuNumberAnimation {} }
> + opacity: shown ? 1.0 : 0.0
> + Behavior on opacity { UbuntuNumberAnimation {} }
> +
> + height: units.gu(7)
> +
> + property bool shown: true
> + property alias actions: actionsDrawer.actions
> + signal exit
> + signal toggleViews
> +
> + function show() {
> + shown = true;
> + }
> +
> + function toggle() {
> + shown = !shown;
> + }
> +
> + Rectangle {
> + anchors.fill: parent
> + color: "black"
> + opacity: 0.6
> + }
> +
> + RowLayout {
> + anchors.fill: parent
> + spacing: 0
> +
> + IconButton {
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + }
> + width: units.gu(8)
> + iconHeight: units.gu(3)
> + iconWidth: iconHeight
> + iconName: "back"
> + iconColor: Theme.palette.normal.foregroundText
> + onClicked: header.exit()
> + }
> +
> + Label {
> + text: i18n.tr("Photo Roll")
> + fontSize: "x-large"
> + color: Theme.palette.normal.foregroundText
> + Layout.fillWidth: true
> + }
> +
> + ImageButton {
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + }
> + width: units.gu(6)
> + iconSource: "assets/gridview.png"
> + onClicked: header.toggleViews()
> + // IconButton {
> + // iconName: "view-grid-symbolic"
> + }
> +
> + ImageButton {
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + }
> + width: units.gu(6)
> + iconSource: "assets/options.png"
> + visible: actionsDrawer.actions.length > 0
> + // IconButton {
> + // iconName: "contextual-menu"
> + onClicked: actionsDrawer.opened = !actionsDrawer.opened
> + }
> + }
> +
> + Item {
> + id: actionsDrawer
> +
> + anchors {
> + top: parent.bottom
> + right: parent.right
> + }
> + width: units.gu(20)
> + height: childrenRect.height
> + clip: actionsColumn.y != 0
> +
> + function close() {
> + opened = false;
> + }
> +
> + property bool opened: false
> + property list<Action> actions
> +
> + InverseMouseArea {
> + onPressed: actionsDrawer.close();
> + enabled: actionsDrawer.opened
> + }
> +
> + Column {
> + id: actionsColumn
> + anchors {
> + left: parent.left
> + right: parent.right
> + }
> + y: actionsDrawer.opened ? 0 : -height
> + Behavior on y { UbuntuNumberAnimation {} }
> +
> + Repeater {
> + model: actionsDrawer.actions
> + delegate: AbstractButton {
> + anchors {
> + left: actionsColumn.left
> + right: actionsColumn.right
> + }
> + height: units.gu(6)
> +
> + action: modelData
> + onClicked: actionsDrawer.close()
> +
> + Rectangle {
> + anchors.fill: parent
> + color: Qt.rgba(0.0, 0.0, 0.0, 0.6)
> + }
> +
> + Label {
> + id: label
> + anchors {
> + left: parent.left
> + leftMargin: units.gu(2)
> + verticalCenter: parent.verticalCenter
> + }
> + text: model.text
> + color: Theme.palette.normal.foregroundText
> + }
> +
> + Icon {
> + anchors {
> + right: parent.right
> + rightMargin: units.gu(2)
> + verticalCenter: parent.verticalCenter
> + }
> + width: height
> + height: label.paintedHeight
> + color: Theme.palette.normal.foregroundText
> + name: model.iconName
> + }
> + }
> + }
> + }
> + }
> +}
>
> === added file 'IconButton.qml'
> --- IconButton.qml 1970-01-01 00:00:00 +0000
> +++ IconButton.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,37 @@
> +/*
> + * 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.0
> +import Ubuntu.Components 1.0
> +
> +AbstractButton {
> + property alias iconWidth: icon.width
> + property alias iconHeight: icon.height
> + property alias iconName: icon.name
> + property alias iconColor: icon.color
> +
> + width: units.gu(4)
> + height: units.gu(4)
> +
> + Icon {
> + id: icon
> + anchors.centerIn: parent
> + width: parent.width
> + height: parent.height
> + color: "white"
> + }
> +}
> +
>
> === renamed file 'CameraToolbarButton.qml' => 'ImageButton.qml'
> --- CameraToolbarButton.qml 2013-06-20 05:51:52 +0000
> +++ ImageButton.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2012 Canonical Ltd.
> + * 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
> @@ -15,18 +15,19 @@
> */
>
> import QtQuick 2.0
> -import Ubuntu.Components 0.1
> +import Ubuntu.Components 1.0
>
> AbstractButton {
> property alias iconWidth: icon.width
> property alias iconHeight: icon.height
> property alias iconSource: icon.source
>
> - width: icon.paintedWidth
> - height: icon.paintedHeight
> + width: icon.width
> + height: icon.height
>
> Image {
> id: icon
> + anchors.centerIn: parent
> }
> }
>
>
> === added file 'PhotogridView.qml'
> --- PhotogridView.qml 1970-01-01 00:00:00 +0000
> +++ PhotogridView.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,98 @@
> +/*
> + * 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.0
> +
> +Item {
> + id: photogridView
> +
> + property int itemsPerRow: 3
> + property var model
> + signal photoClicked(int index)
> + property real headerHeight
> + property list<Action> actions
> +
> + function showPhotoAtIndex(index) {
> + gridView.positionViewAtIndex(index, GridView.Center);
> + }
> +
> + function exit() {
> + }
> +
> + GridView {
> + id: gridView
> + anchors.fill: parent
> + // FIXME: prevent the header from overlapping the beginning of the grid
> + // when Qt 5.3 is landed, use property 'displayMarginBeginning' instead
> + // cf. http://qt-project.org/doc/qt-5/qml-qtquick-gridview.html#displayMarginBeginning-prop
> + header: Item {
> + width: gridView.width
> + height: headerHeight
> + }
> +
> + Component.onCompleted: {
> + // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
> + // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
> + var scaleFactor = units.gridUnit / 8;
> + maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
> + flickDeceleration = flickDeceleration * scaleFactor;
> + }
> +
> + cellWidth: width / photogridView.itemsPerRow
> + cellHeight: cellWidth
> +
> + model: photogridView.model
> + delegate: Item {
> + id: cellDelegate
> +
> + width: GridView.view.cellWidth
> + height: GridView.view.cellHeight
> +
> + Image {
> + id: thumbnail
> + property real margin: units.dp(2)
> + anchors {
> + top: parent.top
> + topMargin: index < photogridView.itemsPerRow ? 0 : margin/2
> + bottom: parent.bottom
> + bottomMargin: margin/2
> + left: parent.left
> + leftMargin: index % photogridView.itemsPerRow == 0 ? 0 : margin/2
> + right: parent.right
> + rightMargin: index % photogridView.itemsPerRow == photogridView.itemsPerRow - 1 ? 0 : margin/2
> + }
> +
> + asynchronous: true
> + cache: false
> + // FIXME: should use the thumbnailer instead of loading the full image and downscaling on the fly
> + source: fileURL
> + sourceSize {
> + width: width
> + height: height
> + }
> + fillMode: Image.PreserveAspectCrop
> + opacity: status == Image.Ready ? 1.0 : 0.0
> + Behavior on opacity { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
> + }
> +
> + MouseArea {
> + anchors.fill: parent
> + onClicked: photogridView.photoClicked(index)
> + }
> + }
> + }
> +}
>
> === modified file 'ShootButton.qml'
> --- ShootButton.qml 2013-06-20 05:51:52 +0000
> +++ ShootButton.qml 2014-06-26 09:06:29 +0000
> @@ -15,61 +15,77 @@
> */
>
> import QtQuick 2.0
> -import Ubuntu.Components 0.1
> -
> -CameraToolbarButton {
> - id: button
> -
> - states: [
> - State { name: "camera"
> - PropertyChanges { target: button; iconSource: "assets/shoot.png" }
> - PropertyChanges { target: recordOn; opacity: 0.0 }
> - PropertyChanges { target: pulseAnimation; running: false }
> - },
> - State { name: "record_off"
> - PropertyChanges { target: button; iconSource: "assets/record_off.png" }
> - PropertyChanges { target: recordOn; opacity: 0.0 }
> - PropertyChanges { target: pulseAnimation; running: false }
> - },
> - State { name: "record_on"
> - PropertyChanges { target: button; iconSource: "assets/record_off.png" }
> - PropertyChanges { target: recordOn; opacity: 1.0 }
> - PropertyChanges { target: pulseAnimation; running: true }
> - }
> - ]
> -
> - property int pulsePeriod: 750
> -
> - Image {
> - id: recordOn
> - anchors.fill: parent
> - source: "assets/record_on.png"
> - Behavior on opacity { NumberAnimation { duration: pulsePeriod } }
> - }
> -
> - Image {
> - id: pulse
> - anchors.fill: parent
> - source: "assets/record_on_pulse.png"
> - opacity: 1.0
> - visible: button.state != "camera"
> -
> - SequentialAnimation on opacity {
> - id: pulseAnimation
> - loops: Animation.Infinite
> - alwaysRunToEnd: true
> - running: false
> -
> - PropertyAnimation {
> - from: 1.0
> - to: 0.0
> - duration: pulsePeriod
> - }
> - PropertyAnimation {
> - from: 0.0
> - to: 1.0
> - duration: pulsePeriod
> - }
> - }
> - }
> +import Ubuntu.Components 1.0
> +
> +Item {
> + id: shootButton
> +
> + signal clicked()
> +
> + width: icon.width
> + height: icon.height
> + opacity: enabled ? 1.0 : 0.5
> +
> + MouseArea {
> + anchors.fill: parent
> + onClicked: shootButton.clicked()
> + }
> +
> + Image {
> + id: icon
> + anchors.centerIn: parent
> + source: "assets/shutter_stills.png"
> + }
> +// states: [
> +// State { name: "camera"
> +// PropertyChanges { target: shootButton; iconSource: "assets/shoot.png" }
> +// PropertyChanges { target: recordOn; opacity: 0.0 }
> +// PropertyChanges { target: pulseAnimation; running: false }
> +// },
> +// State { name: "record_off"
> +// PropertyChanges { target: shootButton; iconSource: "assets/record_off.png" }
> +// PropertyChanges { target: recordOn; opacity: 0.0 }
> +// PropertyChanges { target: pulseAnimation; running: false }
> +// },
> +// State { name: "record_on"
> +// PropertyChanges { target: shootButton; iconSource: "assets/record_off.png" }
> +// PropertyChanges { target: recordOn; opacity: 1.0 }
> +// PropertyChanges { target: pulseAnimation; running: true }
> +// }
> +// ]
> +
> +// property int pulsePeriod: 750
> +
> +// Image {
> +// id: recordOn
> +// anchors.fill: parent
> +// source: "assets/record_on.png"
> +// Behavior on opacity { NumberAnimation { duration: pulsePeriod } }
> +// }
> +
> +// Image {
> +// id: pulse
> +// anchors.fill: parent
> +// source: "assets/record_on_pulse.png"
> +// opacity: 1.0
> +// visible: shootButton.state != "camera"
> +
> +// SequentialAnimation on opacity {
> +// id: pulseAnimation
> +// loops: Animation.Infinite
> +// alwaysRunToEnd: true
> +// running: false
> +
> +// PropertyAnimation {
> +// from: 1.0
> +// to: 0.0
> +// duration: pulsePeriod
> +// }
> +// PropertyAnimation {
> +// from: 0.0
> +// to: 1.0
> +// duration: pulsePeriod
> +// }
> +// }
> +// }
> }
>
> === added file 'SlideshowView.qml'
> --- SlideshowView.qml 1970-01-01 00:00:00 +0000
> +++ SlideshowView.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,244 @@
> +/*
> + * 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.0
> +import Ubuntu.Components.ListItems 1.0 as ListItems
> +import Ubuntu.Components.Popups 1.0
> +import Ubuntu.Content 0.1
> +import CameraApp 0.1
> +
> +Item {
> + id: slideshowView
> +
> + property var model
> + property int currentIndex: listView.currentIndex
> + property string currentFilePath: {
> + var filePath = slideshowView.model.get(slideshowView.currentIndex, "filePath")
> + if (filePath) {
> + return filePath;
> + } else {
> + return "";
> + }
> + }
> +
> + signal toggleHeader
> + property list<Action> actions: [
> + Action {
> + text: i18n.tr("Share")
> + iconName: "share"
> + onTriggered: PopupUtils.open(sharePopoverComponent)
> + },
> + Action {
> + text: i18n.tr("Delete")
> + iconName: "delete"
> + onTriggered: PopupUtils.open(deleteDialogComponent)
> + }
> + ]
> +
> + function showPhotoAtIndex(index) {
> + listView.positionViewAtIndex(index, ListView.Contain);
> + }
> +
> + function showLastPhotoTaken() {
> + listView.positionViewAtBeginning();
> + }
> +
> + function exit() {
> + if (listView.currentItem) {
> + listView.currentItem.zoomOut();
> + }
> + }
> +
> + ListView {
> + id: listView
> + Component.onCompleted: {
> + // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
> + // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
> + var scaleFactor = units.gridUnit / 8;
> + maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
> + flickDeceleration = flickDeceleration * scaleFactor;
> + }
> +
> + anchors.fill: parent
> + model: slideshowView.model
> + orientation: ListView.Horizontal
> + boundsBehavior: Flickable.StopAtBounds
> + cacheBuffer: width
> + highlightRangeMode: ListView.StrictlyEnforceRange
> + spacing: units.gu(1)
> + property real maxDimension: Math.max(width, height)
> +
> + delegate: Item {
> + function zoomIn(centerX, centerY) {
> + flickable.scaleCenterX = centerX / flickable.width;
> + flickable.scaleCenterY = centerY / flickable.height;
> + flickable.sizeScale = 3.0;
> + }
> +
> + function zoomOut() {
> + if (flickable.sizeScale != 1.0) {
> + flickable.scaleCenterX = flickable.contentX / flickable.width / (flickable.sizeScale - 1);
> + flickable.scaleCenterY = flickable.contentY / flickable.height / (flickable.sizeScale - 1);
> + flickable.sizeScale = 1.0;
> + }
> + }
> +
> + width: ListView.view.width
> + height: ListView.view.height
> +
> + ActivityIndicator {
> + anchors.centerIn: parent
> + visible: running
> + running: image.status != Image.Ready
> + }
> +
> + Flickable {
> + id: flickable
> + anchors.fill: parent
> + contentWidth: media.width
> + contentHeight: media.height
> + contentX: (sizeScale - 1) * scaleCenterX * width
> + contentY: (sizeScale - 1) * scaleCenterY * height
> +
> + property real sizeScale: 1.0
> + property real scaleCenterX: 0.0
> + property real scaleCenterY: 0.0
> + Behavior on sizeScale { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
> +
> + Item {
> + id: media
> +
> + width: flickable.width * flickable.sizeScale
> + height: flickable.height * flickable.sizeScale
> +
> + Image {
> + id: image
> + anchors.fill: parent
> + asynchronous: true
> + cache: false
> + // FIXME: should use the thumbnailer instead of loading the full image and downscaling on the fly
> + source: fileURL
> + sourceSize {
> + width: listView.maxDimension
> + height: listView.maxDimension
> + }
> + fillMode: Image.PreserveAspectFit
> + opacity: status == Image.Ready ? 1.0 : 0.0
> + Behavior on opacity { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
> +
> + }
> +
> + Image {
> + id: highResolutionImage
> + anchors.fill: parent
> + asynchronous: true
> + cache: false
> + source: flickable.sizeScale > 1.0 ? fileURL : ""
> + sourceSize {
> + width: width
> + height: height
> + }
> + fillMode: Image.PreserveAspectFit
> + }
> + }
> +
> + MouseArea {
> + anchors.fill: parent
> + onClicked: {
> + slideshowView.toggleHeader();
> + mouse.accepted = false;
> + }
> + onDoubleClicked: {
> + if (flickable.sizeScale == 1.0) {
> + zoomIn(mouse.x, mouse.y);
> + } else {
> + zoomOut();
> + }
> + }
> + }
> + }
> + }
> + }
> +
> +
> + Component {
> + id: sharePopoverComponent
> +
> + PopupBase {
> + id: sharePopover
> +
> + fadingAnimation: UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration }
> +
> + // FIXME: ContentPeerPicker should either have a background or not, not half of one
> + Rectangle {
> + anchors.fill: parent
> + color: Theme.palette.normal.overlay
> + }
> +
> + ContentItem {
> + id: contentItem
> + url: slideshowView.currentFilePath
> + }
> +
> + ContentPeerPicker {
> + // FIXME: ContentPeerPicker should define an implicit size and not refer to its parent
> + // FIXME: ContentPeerPicker should not be visible: false by default
> + visible: true
> + contentType: ContentType.Pictures
> + handler: ContentHandler.Share
> +
> + onPeerSelected: {
> + var transfer = peer.request();
> + if (transfer.state === ContentTransfer.InProgress) {
> + transfer.items = [ contentItem ];
> + transfer.state = ContentTransfer.Charged;
> + }
> + PopupUtils.close(sharePopover);
> + }
> + onCancelPressed: PopupUtils.close(sharePopover);
> + }
> + }
> + }
> +
> + Component {
> + id: deleteDialogComponent
> +
> + Dialog {
> + id: deleteDialog
> +
> + title: i18n.tr("Delete media?")
> +
> + FileOperations {
> + id: fileOperations
> + }
> +
> + Button {
> + text: i18n.tr("Cancel")
> + color: UbuntuColors.warmGrey
> + onClicked: PopupUtils.close(deleteDialog)
> + }
> + Button {
> + text: i18n.tr("Delete")
> + color: UbuntuColors.orange
> + onClicked: {
> + fileOperations.remove(slideshowView.currentFilePath);
> + PopupUtils.close(deleteDialog);
> + }
> + }
> + }
> + }
> +}
>
> === modified file 'Snapshot.qml'
> --- Snapshot.qml 2013-02-19 09:06:08 +0000
> +++ Snapshot.qml 2014-06-26 09:06:29 +0000
> @@ -14,8 +14,8 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> -import QtQuick 2.0
> -import Ubuntu.Components 0.1
> +import QtQuick 2.2
> +import Ubuntu.Components 1.0
>
> Item {
> id: snapshotRoot
> @@ -25,12 +25,18 @@
> property ViewFinderGeometry geometry
> property bool deviceDefaultIsPortrait: true
>
> + function startOutAnimation() {
> + shoot.restart()
> + }
> +
> Item {
> id: container
> - anchors.left: parent.left
> - anchors.right: parent.right
> - height:parent.height
> - y: 0
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + }
> + width: parent.width
> + visible: false
>
> Image {
> id: snapshot
> @@ -38,33 +44,34 @@
> rotation: snapshotRoot.orientation * -1
>
> asynchronous: true
> - opacity: 0.0
> fillMode: Image.PreserveAspectFit
> smooth: false
> - width: deviceDefaultIsPortrait ? geometry.height : geometry.width
> + width: deviceDefaultIsPortrait ? geometry.height : geometry.width
> height: deviceDefaultIsPortrait ? geometry.width : geometry.height
> sourceSize.width: width
> sourceSize.height: height
> -
> - onStatusChanged: if (status == Image.Ready) shoot.restart()
> + }
> +
> + Image {
> + id: shadow
> +
> + property bool rotated: (snapshot.rotation % 180) != 0
> + height: rotated ? snapshot.width : snapshot.height
> + width: units.gu(2)
> + x: (container.width - (rotated ? snapshot.height : snapshot.width)) / 2 - width
> + source: "assets/shadow.png"
> + fillMode: Image.Stretch
> }
> }
>
> SequentialAnimation {
> id: shoot
> - PropertyAction { target: snapshot; property: "opacity"; value: 1.0 }
> - ParallelAnimation {
> - NumberAnimation { target: container; property: "y";
> - to: container.parent.height; duration: 500; easing.type: Easing.InCubic }
> - SequentialAnimation {
> - PauseAnimation { duration: 0 }
> - NumberAnimation { target: snapshot; property: "opacity";
> - to: 0.0; duration: 500; easing.type: Easing.InCubic }
> - }
> - }
>
> - PropertyAction { target: snapshot; property: "opacity"; value: 0.0 }
> + PropertyAction { target: container; 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: "y"; value: 0 }
> + PropertyAction { target: container; property: "visible"; value: false }
> + PropertyAction { target: container; property: "x"; value: 0 }
> }
> }
>
> === modified file 'StopWatch.qml'
> --- StopWatch.qml 2013-07-30 09:36:01 +0000
> +++ StopWatch.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2012 Canonical Ltd.
> + * 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
> @@ -15,7 +15,7 @@
> */
>
> import QtQuick 2.0
> -import Ubuntu.Components 0.1
> +import Ubuntu.Components 1.0
>
> Item {
> property int time: 0
>
> === modified file 'ThinSliderStyle.qml'
> --- ThinSliderStyle.qml 2013-06-27 15:22:59 +0000
> +++ ThinSliderStyle.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2012 Canonical Ltd.
> + * 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
> @@ -15,7 +15,7 @@
> */
>
> import QtQuick 2.0
> -import Ubuntu.Components 0.1
> +import Ubuntu.Components 1.0
>
> /*
> This delegate is styled using the following properties:
> @@ -45,6 +45,9 @@
> property string backgroundImage: "assets/zoom_bar at 18.png"
> property string thumbImage: "assets/zoom_point at 18.png"
>
> + implicitHeight: thumbShape.height + 2.0 * thumbSpacing + units.gu(2)
> + implicitWidth: backgroundShape.width
> +
> Image {
> id: backgroundShape
> anchors {
> @@ -67,12 +70,4 @@
> anchors.verticalCenter: backgroundShape.verticalCenter
> source: thumbImage
> }
> -
> - // set styledItem's implicitHeight to the thumbShape's height
> - // this can also control the default sensing area
> - Binding {
> - target: styledItem
> - property: "implicitHeight"
> - value: thumbShape.height + 2.0 * thumbSpacing
> - }
> }
>
> === modified file 'Toolbar.qml'
> --- Toolbar.qml 2014-02-14 18:09:17 +0000
> +++ Toolbar.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2012 Canonical Ltd.
> + * 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
> @@ -16,55 +16,11 @@
>
> import QtQuick 2.0
> import QtMultimedia 5.0
> -import Ubuntu.Components 0.1
> +import Ubuntu.Components 1.0
>
> Item {
> id: toolbar
>
> - property Camera camera
> - property int iconsRotation
> -
> - signal recordClicked()
> - signal zoomClicked()
> -
> - Behavior on opacity { NumberAnimation { duration: 500 } }
> -
> - height: middle.height
> - property int iconWidth: units.gu(6)
> - property int iconHeight: units.gu(5)
> - property bool canCapture
> -
> - function shoot() {
> - var orientation = 90
> - if (device.isLandscape) {
> - if (device.naturalOrientation === "portrait") {
> - orientation = 180
> - } else {
> - orientation = 0
> - }
> - }
> - if (device.isInverted)
> - orientation += 180
> -
> - if (camera.captureMode == Camera.CaptureVideo) {
> - if (camera.videoRecorder.recorderState == CameraRecorder.StoppedState) {
> - camera.videoRecorder.setMetadata("Orientation", orientation)
> - camera.videoRecorder.record()
> - } else {
> - camera.videoRecorder.stop()
> - // TODO: there's no event to tell us that the video has been successfully recorder or failed,
> - // and no preview to slide off anyway. Figure out what to do in this case.
> - }
> - } else {
> - camera.imageCapture.setMetadata("Orientation", orientation)
> - camera.imageCapture.capture()
> - }
> - }
> -
> - function switchCamera() {
> - camera.advanced.activeCameraIndex = (camera.advanced.activeCameraIndex === 0) ? 1 : 0
> - }
> -
> function switchFlashMode() {
> if (flashButton.torchMode) {
> camera.flash.mode = (flashButton.flashState == "on") ?
> @@ -75,83 +31,64 @@
> }
> }
>
> - function changeRecordMode() {
> - if (camera.captureMode == Camera.CaptureVideo) camera.videoRecorder.stop()
> - camera.captureMode = (camera.captureMode == Camera.CaptureVideo) ? Camera.CaptureStillImage : Camera.CaptureVideo
> - }
> -
> -
> - BorderImage {
> - id: leftBackground
> + FlashButton {
> + id: flashButton
> + anchors.verticalCenter: parent.verticalCenter
> anchors.left: parent.left
> - anchors.top: parent.top
> - anchors.bottom: parent.bottom
> - anchors.right: middle.left
> - anchors.topMargin: units.dp(2)
> - anchors.bottomMargin: units.dp(2)
> - source: "assets/toolbar-left.sci"
> -
> - property int iconSpacing: (width - toolbar.iconWidth * children.length) / 3
> -
> - FlashButton {
> - id: flashButton
> - anchors.verticalCenter: parent.verticalCenter
> - anchors.left: parent.left
> - anchors.leftMargin: parent.iconSpacing
> -
> - height: toolbar.iconHeight
> - width: toolbar.iconWidth
> - visible: !application.desktopMode
> - enabled: toolbar.opacity > 0.0
> - rotation: iconsRotation
> -
> - Connections {
> - target: camera.advanced
> - onActiveCameraIndexChanged: {
> - if (camera.advanced.activeCameraIndex == 1) {
> - camera.flash.mode = Camera.FlashOff;
> - flashButton.previousFlashMode = Camera.FlashOff;
> - }
> + anchors.leftMargin: parent.iconSpacing
> +
> + height: toolbar.iconHeight
> + width: toolbar.iconWidth
> + visible: !application.desktopMode
> + enabled: toolbar.opacity > 0.0
> + rotation: iconsRotation
> +
> + Connections {
> + target: camera.advanced
> + onActiveCameraIndexChanged: {
> + if (camera.advanced.activeCameraIndex == 1) {
> + camera.flash.mode = Camera.FlashOff;
> + flashButton.previousFlashMode = Camera.FlashOff;
> }
> }
> -
> - torchMode: camera.captureMode == Camera.CaptureVideo
> - flashState: { switch (camera.flash.mode) {
> - case Camera.FlashAuto: return "auto";
> - case Camera.FlashOn:
> - case Camera.FlashVideoLight: return "on";
> - case Camera.FlashOff:
> - default: return "off"
> - }}
> -
> - onClicked: toolbar.switchFlashMode()
> -
> - property variant previousFlashMode: Camera.FlashOff
> -
> - onTorchModeChanged: {
> - var previous = camera.flash.mode;
> - camera.flash.mode = previousFlashMode;
> - previousFlashMode = previous;
> - }
> - }
> -
> - FadingButton {
> - id: recordModeButton
> - objectName: "recordModeButton"
> - anchors.verticalCenter: parent.verticalCenter
> - anchors.left: flashButton.right
> - anchors.leftMargin: parent.iconSpacing
> - rotation: iconsRotation
> -
> - // Disabled the video recording button for V1.0 since the feature is broken, leave it enabled for desktopMode
> - enabled: application.desktopMode
> - opacity: 0.5
> -
> - width: toolbar.iconWidth
> - height: toolbar.iconHeight
> - iconSource: camera.captureMode == Camera.CaptureVideo ? "assets/record_picture.png" : "assets/record_video.png"
> - onClicked: toolbar.changeRecordMode()
> - }
> + }
> +
> + torchMode: camera.captureMode == Camera.CaptureVideo
> + flashState: { switch (camera.flash.mode) {
> + case Camera.FlashAuto: return "auto";
> + case Camera.FlashOn:
> + case Camera.FlashVideoLight: return "on";
> + case Camera.FlashOff:
> + default: return "off"
> + }}
> +
> + onClicked: toolbar.switchFlashMode()
> +
> + property variant previousFlashMode: Camera.FlashOff
> +
> + onTorchModeChanged: {
> + var previous = camera.flash.mode;
> + camera.flash.mode = previousFlashMode;
> + previousFlashMode = previous;
> + }
> + }
> +
> + FadingButton {
> + id: recordModeButton
> + objectName: "recordModeButton"
> + anchors.verticalCenter: parent.verticalCenter
> + anchors.left: flashButton.right
> + anchors.leftMargin: parent.iconSpacing
> + rotation: iconsRotation
> +
> + // Disabled the video recording button for V1.0 since the feature is broken, leave it enabled for desktopMode
> + enabled: application.desktopMode
> + opacity: 0.5
> +
> + width: toolbar.iconWidth
> + height: toolbar.iconHeight
> + iconSource: camera.captureMode == Camera.CaptureVideo ? "assets/record_picture.png" : "assets/record_video.png"
> + onClicked: toolbar.changeRecordMode()
> }
>
> BorderImage {
> @@ -177,49 +114,4 @@
> }
> }
>
> - BorderImage {
> - id: rightBackground
> - anchors.right: parent.right
> - anchors.top: parent.top
> - anchors.bottom: parent.bottom
> - anchors.left: middle.right
> - anchors.topMargin: units.dp(2)
> - anchors.bottomMargin: units.dp(2)
> - source: "assets/toolbar-right.sci"
> -
> - property int iconSpacing: (width - toolbar.iconWidth * children.length) / 3
> -
> - CameraToolbarButton {
> - id: swapButton
> - objectName: "swapButton"
> - anchors.verticalCenter: parent.verticalCenter
> - anchors.right: galleryButton.left
> - anchors.rightMargin: parent.iconSpacing
> - rotation: iconsRotation
> - visible: !application.desktopMode
> - enabled: toolbar.opacity > 0.0
> - iconWidth: toolbar.iconWidth
> - iconHeight: toolbar.iconHeight
> - iconSource: "assets/swap_camera.png"
> -
> - onClicked: toolbar.switchCamera()
> - }
> -
> - CameraToolbarButton {
> - id: galleryButton
> - objectName: "galleryButton"
> - anchors.verticalCenter: parent.verticalCenter
> - anchors.right: parent.right
> - anchors.rightMargin: parent.iconSpacing
> - rotation: iconsRotation
> - visible: !application.desktopMode
> - enabled: toolbar.opacity > 0.0
> -
> - iconWidth: toolbar.iconWidth
> - iconHeight: toolbar.iconHeight
> - iconSource: "assets/gallery.png"
> -
> - onClicked: Qt.openUrlExternally("appid://com.ubuntu.gallery/gallery/current-user-version")
> - }
> - }
> }
>
> === added file 'ViewFinderOverlay.qml'
> --- ViewFinderOverlay.qml 1970-01-01 00:00:00 +0000
> +++ ViewFinderOverlay.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,554 @@
> +/*
> + * 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 QtQuick.Window 2.0
> +import Ubuntu.Components 1.0
> +import QtMultimedia 5.0
> +import CameraApp 0.1
> +
> +Item {
> + id: viewFinderOverlay
> +
> + property Camera camera
> + property bool touchAcquired: bottomEdge.pressed || zoomPinchArea.active
> + property real revealProgress: bottomEdge.progress
> +
> + function showFocusRing(x, y) {
> + focusRing.center = Qt.point(x, y);
> + focusRing.show();
> + }
> +
> + QtObject {
> + id: settings
> +
> + property int flashMode: Camera.FlashAuto
> + property bool gpsEnabled: false
> + property bool hdrEnabled: false
> + }
> +
> + Binding {
> + target: camera.flash
> + property: "mode"
> + value: settings.flashMode
> + }
> +
> + Connections {
> + target: camera.imageCapture
> + onReadyChanged: {
> + if (camera.imageCapture.ready) {
> + // FIXME: this is a workaround: simply setting
> + // camera.flash.mode to the settings value does not have any effect
> + camera.flash.mode = Camera.FlashOff;
> + camera.flash.mode = settings.flashMode;
> + }
> + }
> + }
> +
> + Panel {
> + id: bottomEdge
> + anchors {
> + right: parent.right
> + left: parent.left
> + bottom: parent.bottom
> + }
> + height: units.gu(9)
> + onOpenedChanged: optionValueSelector.hide()
> +
> + property real progress: (bottomEdge.height - bottomEdge.position) / bottomEdge.height
> + property list<ListModel> options: [
> + ListModel {
> + id: gpsOptionsModel
> +
> + property string settingsProperty: "gpsEnabled"
> + property string icon: "location"
> + property string label: ""
> + property bool isToggle: true
> + property int selectedIndex: bottomEdge.indexForValue(gpsOptionsModel, settings.gpsEnabled)
> + property bool available: true
> +
> + ListElement {
> + icon: ""
> + label: "On"
> + value: true
> + }
> + ListElement {
> + icon: ""
> + label: "Off"
> + value: false
> + }
> + },
> + ListModel {
> + id: flashOptionsModel
> +
> + property string settingsProperty: "flashMode"
> + property string icon: ""
> + property string label: ""
> + property bool isToggle: false
> + property int selectedIndex: bottomEdge.indexForValue(flashOptionsModel, settings.flashMode)
> + property bool available: camera.advanced.hasFlash
> +
> + ListElement {
> + icon: "flash-on"
> + label: "On"
> + value: Camera.FlashOn
> + }
> + ListElement {
> + icon: "flash-auto"
> + label: "Auto"
> + value: Camera.FlashAuto
> + }
> + ListElement {
> + icon: "flash-off"
> + label: "Off"
> + value: Camera.FlashOff
> + }
> + },
> + ListModel {
> + id: hdrOptionsModel
> +
> + property string settingsProperty: "hdrEnabled"
> + property string icon: "import-image"
> + property string label: "HDR"
> + property bool isToggle: true
> + property int selectedIndex: bottomEdge.indexForValue(hdrOptionsModel, settings.hdrEnabled)
> + property bool available: true
> +
> + ListElement {
> + icon: ""
> + label: "On"
> + value: true
> + }
> + ListElement {
> + icon: ""
> + label: "Off"
> + value: false
> + }
> + }
> + ]
> +
> + function indexForValue(model, value) {
> + var i;
> + var element;
> + for (i=0; i<model.count; i++) {
> + element = model.get(i);
> + if (element.value === value) {
> + return i;
> + }
> + }
> +
> + return -1;
> + }
> +
> + Item {
> + anchors {
> + horizontalCenter: parent.horizontalCenter
> + bottom: parent.top
> + }
> + width: indicators.width + units.gu(2)
> + height: units.gu(3)
> + opacity: bottomEdge.pressed || bottomEdge.opened ? 0.0 : 1.0
> + Behavior on opacity { UbuntuNumberAnimation {} }
> +
> + Image {
> + anchors {
> + left: parent.left
> + right: parent.right
> + top: parent.top
> + }
> + height: parent.height * 2
> + opacity: 0.3
> + source: "assets/ubuntu_shape.svg"
> + sourceSize.width: width
> + sourceSize.height: height
> + cache: false
> + visible: indicators.visibleChildren.length > 1
> + }
> +
> + Row {
> + id: indicators
> +
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + horizontalCenter: parent.horizontalCenter
> + }
> + spacing: units.gu(1)
> +
> + Repeater {
> + model: bottomEdge.options
> + delegate: Icon {
> + anchors {
> + top: parent.top
> + topMargin: units.gu(0.5)
> + bottom: parent.bottom
> + bottomMargin: units.gu(0.5)
> + }
> + width: units.gu(2)
> + color: "white"
> + opacity: 0.5
> + name: modelData.isToggle ? modelData.icon : modelData.get(model.selectedIndex).icon
> + visible: modelData.available ? (modelData.isToggle ? modelData.get(model.selectedIndex).value : true) : false
> + }
> + }
> + }
> + }
> + }
> +
> + Item {
> + id: controls
> +
> + anchors {
> + left: parent.left
> + right: parent.right
> + }
> + height: parent.height
> + y: bottomEdge.position - bottomEdge.height
> + opacity: 1 - bottomEdge.progress
> + visible: opacity != 0.0
> + enabled: visible
> +
> + function shoot() {
> + camera.captureInProgress = true;
> + shootFeedback.start();
> +
> + var orientation = Screen.angleBetween(Screen.orientation, Screen.primaryOrientation);
> + if (Screen.primaryOrientation == Qt.PortraitOrientation) {
> + orientation += 90;
> + }
> +
> + if (camera.captureMode == Camera.CaptureVideo) {
> + if (camera.videoRecorder.recorderState == CameraRecorder.StoppedState) {
> + camera.videoRecorder.setMetadata("Orientation", orientation)
> + camera.videoRecorder.record()
> + } else {
> + camera.videoRecorder.stop()
> + // TODO: there's no event to tell us that the video has been successfully recorder or failed,
> + // and no preview to slide off anyway. Figure out what to do in this case.
> + }
> + } else {
> + camera.imageCapture.setMetadata("Orientation", orientation)
> + camera.imageCapture.captureToLocation(application.mediaLocation)
> + }
> + }
> +
> + function completeCapture() {
> + print("COMPLETE CAPTURE")
> + viewFinderOverlay.visible = true;
> + snapshot.startOutAnimation();
> + camera.captureInProgress = false;
> + }
> +
> + function switchCamera() {
> + camera.switchInProgress = true;
> + // viewFinderGrab.sourceItem = viewFinder;
> + viewFinderGrab.x = viewFinder.x;
> + viewFinderGrab.y = viewFinder.y;
> + viewFinderGrab.width = viewFinder.width;
> + viewFinderGrab.height = viewFinder.height;
> + viewFinderGrab.visible = true;
> + viewFinderGrab.scheduleUpdate();
> + }
> +
> + function completeSwitch() {
> + print("COMPLETE SWITCH")
> + viewFinderSwitcherAnimation.restart();
> + camera.switchInProgress = false;
> + }
> +
> + function changeRecordMode() {
> + if (camera.captureMode == Camera.CaptureVideo) camera.videoRecorder.stop()
> + camera.captureMode = (camera.captureMode == Camera.CaptureVideo) ? Camera.CaptureStillImage : Camera.CaptureVideo
> + }
> +
> + Connections {
> + target: camera.imageCapture
> + onReadyChanged: {
> + print("READY", camera.imageCapture.ready)
> + if (camera.imageCapture.ready) {
> + if (camera.captureInProgress) {
> + controls.completeCapture();
> + } else if (camera.switchInProgress) {
> + controls.completeSwitch();
> + }
> + }
> + }
> + }
> +
> + CircleButton {
> + id: recordModeButton
> + objectName: "recordModeButton"
> +
> + anchors {
> + right: shootButton.left
> + rightMargin: units.gu(7.5)
> + bottom: parent.bottom
> + bottomMargin: units.gu(6)
> + }
> +
> + iconName: "camcorder"
> + onClicked: controls.changeRecordMode()
> + }
> +
> + ShootButton {
> + id: shootButton
> +
> + anchors {
> + bottom: parent.bottom
> + // account for the bottom shadow in the asset
> + bottomMargin: units.gu(5) - units.dp(6)
> + horizontalCenter: parent.horizontalCenter
> + }
> +
> + enabled: camera.imageCapture.ready
> + onClicked: controls.shoot()
> + rotation: Screen.angleBetween(Screen.primaryOrientation, Screen.orientation)
> + Behavior on rotation {
> + RotationAnimator {
> + duration: UbuntuAnimation.BriskDuration
> + easing: UbuntuAnimation.StandardEasing
> + direction: RotationAnimator.Shortest
> + }
> + }
> + }
> +
> + CircleButton {
> + id: swapButton
> + objectName: "swapButton"
> +
> + anchors {
> + left: shootButton.right
> + leftMargin: units.gu(7.5)
> + bottom: parent.bottom
> + bottomMargin: units.gu(6)
> + }
> +
> + iconName: "camera-flip"
> + onClicked: controls.switchCamera()
> + }
> +
> +
> + PinchArea {
> + id: zoomPinchArea
> + anchors {
> + top: parent.top
> + bottom: shootButton.top
> + bottomMargin: units.gu(1)
> + left: parent.left
> + right: parent.right
> + }
> +
> + property real initialZoom
> + property real minimumScale: 0.3
> + property real maximumScale: 3.0
> + property bool active: false
> +
> + onPinchStarted: {
> + active = true;
> + initialZoom = zoomControl.value;
> + zoomControl.show();
> + }
> + onPinchUpdated: {
> + zoomControl.show();
> + var scaleFactor = MathUtils.projectValue(pinch.scale, 1.0, maximumScale, 0.0, zoomControl.maximumValue);
> + zoomControl.value = MathUtils.clamp(initialZoom + scaleFactor, zoomControl.minimumValue, zoomControl.maximumValue);
> + }
> + onPinchFinished: {
> + active = false;
> + }
> +
> +
> + MouseArea {
> + id: manualFocusMouseArea
> + anchors.fill: parent
> + onClicked: {
> + camera.manualFocus(mouse.x, mouse.y);
> + mouse.accepted = false;
> + }
> + // FIXME: calling 'isFocusPointModeSupported' fails with
> + // "Error: Unknown method parameter type: QDeclarativeCamera::FocusPointMode"
> + //enabled: camera.focus.isFocusPointModeSupported(Camera.FocusPointCustom)
> + enabled: !application.desktopMode
> + }
> + }
> +
> + ZoomControl {
> + id: zoomControl
> +
> + anchors {
> + bottom: shootButton.top
> + bottomMargin: units.gu(2)
> + left: parent.left
> + right: parent.right
> + leftMargin: recordModeButton.x
> + rightMargin: parent.width - (swapButton.x + swapButton.width)
> + }
> + maximumValue: camera.maximumZoom
> +
> + Binding { target: camera; property: "currentZoom"; value: zoomControl.value }
> + }
> +
> + FocusRing {
> + id: focusRing
> + }
> + }
> +
> + Item {
> + id: options
> +
> + anchors {
> + left: parent.left
> + right: parent.right
> + top: controls.bottom
> + }
> + height: optionsGrid.height
> +
> + Grid {
> + id: optionsGrid
> + anchors {
> + horizontalCenter: parent.horizontalCenter
> + }
> +
> + columns: 3
> + columnSpacing: units.gu(9.5)
> + rowSpacing: units.gu(9.5)
> +
> + Repeater {
> + model: bottomEdge.options
> + delegate: CircleButton {
> + id: optionsButton
> +
> + property var model: modelData
> +
> + iconName: model.isToggle ? model.icon : model.get(model.selectedIndex).icon
> + onClicked: optionValueSelector.toggle(model, optionsButton)
> + on: model.isToggle ? model.get(model.selectedIndex).value : true
> + visible: model.available
> + label: model.label
> + }
> + }
> + }
> +
> + Column {
> + id: optionValueSelector
> + anchors {
> + bottom: optionsGrid.top
> + bottomMargin: units.gu(2)
> + }
> + width: units.gu(12)
> +
> + function toggle(model, callerButton) {
> + if (optionValueSelectorVisible && optionsRepeater.model === model) {
> + hide();
> + } else {
> + show(model, callerButton);
> + }
> + }
> +
> + function show(model, callerButton) {
> + alignWith(callerButton);
> + optionsRepeater.model = model;
> + optionValueSelectorVisible = true;
> + }
> +
> + function hide() {
> + optionValueSelectorVisible = false;
> + }
> +
> + function alignWith(item) {
> + // horizontally center optionValueSelector with the center of item
> + // if there is enough space to do so, that is as long as optionValueSelector
> + // does not get cropped by the edge of the screen
> + var itemX = parent.mapFromItem(item, 0, 0).x;
> + var centeredX = itemX + item.width / 2.0 - width / 2.0;
> + var margin = units.gu(1);
> +
> + if (centeredX < margin) {
> + x = itemX;
> + } else if (centeredX + width > item.parent.width - margin) {
> + x = itemX + item.width - width;
> + } else {
> + x = centeredX;
> + }
> + }
> +
> + visible: opacity !== 0.0
> + onVisibleChanged: if (!visible) optionsRepeater.model = null;
> + opacity: optionValueSelectorVisible ? 1.0 : 0.0
> + Behavior on opacity {UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}}
> +
> + Repeater {
> + id: optionsRepeater
> +
> + delegate: AbstractButton {
> + id: optionDelegate
> +
> + anchors {
> + right: optionValueSelector.right
> + left: optionValueSelector.left
> + }
> + height: units.gu(5)
> +
> + property bool selected: optionsRepeater.model.selectedIndex == index
> + onClicked: settings[optionsRepeater.model.settingsProperty] = optionsRepeater.model.get(index).value
> +
> + Icon {
> + id: icon
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + left: parent.left
> + topMargin: units.gu(1)
> + bottomMargin: units.gu(1)
> + leftMargin: units.gu(1)
> + }
> + width: height
> + color: "white"
> + opacity: optionDelegate.selected ? 1.0 : 0.5
> + name: model.icon
> + }
> +
> + Label {
> + id: label
> + anchors {
> + left: model.icon != "" ? icon.right : parent.left
> + leftMargin: units.gu(2)
> + right: parent.right
> + rightMargin: units.gu(2)
> + verticalCenter: parent.verticalCenter
> + }
> +
> + color: "white"
> + opacity: optionDelegate.selected ? 1.0 : 0.5
> + text: model.label
> + }
> +
> + Rectangle {
> + anchors {
> + left: parent.left
> + right: parent.right
> + bottom: parent.bottom
> + }
> + height: units.dp(1)
> + color: "white"
> + opacity: 0.5
> + visible: index !== optionsRepeater.count - 1
> + }
> + }
> + }
> + }
> + }
> +}
>
> === added file 'ViewFinderView.qml'
> --- ViewFinderView.qml 1970-01-01 00:00:00 +0000
> +++ ViewFinderView.qml 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,282 @@
> +/*
> + * 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 QtQuick.Window 2.0
> +import Ubuntu.Components 1.0
> +import QtMultimedia 5.0
> +import CameraApp 0.1
> +import QtGraphicalEffects 1.0
> +
> +Item {
> + id: viewFinderView
> +
> + property bool overlayVisible: true
> + property bool optionValueSelectorVisible: false
> + property bool touchAcquired: viewFinderOverlay.touchAcquired
> + property bool inView
> + signal photoTaken
> +
> + Camera {
> + id: camera
> + captureMode: Camera.CaptureStillImage
> +
> + function manualFocus(x, y) {
> + viewFinderOverlay.showFocusRing(x, y);
> + autoFocusTimer.restart();
> + focus.focusMode = Camera.FocusAuto;
> + focus.customFocusPoint = viewFinder.mapPointToSourceNormalized(Qt.point(x, y));
> + focus.focusPointMode = Camera.FocusPointCustom;
> + }
> +
> + function autoFocus() {
> + focus.focusMode = Camera.FocusContinuous;
> + focus.focusPointMode = Camera.FocusPointAuto;
> + }
> +
> + property var autoFocusTimer: Timer {
> + interval: 5000
> + onTriggered: camera.autoFocus();
> + }
> +
> + focus {
> + focusMode: Camera.FocusContinuous
> + focusPointMode: Camera.FocusPointAuto
> + }
> +
> + property AdvancedCameraSettings advanced: AdvancedCameraSettings {
> + camera: camera
> + }
> +
> + Component.onCompleted: {
> + camera.start();
> + }
> +
> + /* Use only digital zoom for now as it's what phone cameras mostly use.
> + TODO: if optical zoom is available, maximumZoom should be the combined
> + range of optical and digital zoom and currentZoom should adjust the two
> + transparently based on the value. */
> + property alias currentZoom: camera.digitalZoom
> + property alias maximumZoom: camera.maximumDigitalZoom
> + property bool captureInProgress: false
> + property bool switchInProgress: false
> + onCameraStateChanged: print("STATE", cameraState)
> + onCameraStatusChanged: print("STATUS", cameraStatus)
> + onAvailabilityChanged: print("AVAIL", availability)
> +
> + imageCapture {
> + onCaptureFailed: {
> + console.log("Capture failed for request " + requestId + ": " + message);
> + }
> + onImageCaptured: {
> + print("CAPTURED")
> + snapshot.source = preview;
> + }
> + onImageSaved: {
> + viewFinderView.photoTaken();
> + metricPhotos.increment();
> + console.log("Picture saved as " + path);
> + }
> + }
> +
> + videoRecorder {
> + onRecorderStateChanged: {
> + if (videoRecorder.recorderState === CameraRecorder.StoppedState)
> + metricVideos.increment()
> + }
> +
> + }
> + }
> +
> + Connections {
> + target: Qt.application
> + onActiveChanged: {
> + if (Qt.application.active)
> + camera.start()
> + else if (!application.desktopMode)
> + camera.stop()
> + }
> + }
> +
> + Item {
> + id: viewFinderSwitcher
> + anchors.fill: parent
> +
> + ShaderEffectSource {
> + id: viewFinderGrab
> + live: false
> + sourceItem: viewFinder
> +
> + onScheduledUpdateCompleted: {
> + print("SCHEDULE UPDATE COMPLETED")
> + if (camera.switchInProgress) {
> + // FIXME: hack to make viewFinder invisible
> + // 'viewFinder.visible = false' prevents the camera switching
> + viewFinder.width = 1;
> + viewFinder.height = 1;
> + camera.advanced.activeCameraIndex = (camera.advanced.activeCameraIndex === 0) ? 1 : 0;
> + viewFinderSwitcherRotation.angle = 180;
> + }
> + }
> + transform: Rotation {
> + origin.x: viewFinderGrab.width/2
> + origin.y: viewFinderGrab.height/2
> + axis.x: 0; axis.y: 1; axis.z: 0
> + angle: 180
> + }
> + }
> +
> + transform: [
> + Scale {
> + id: viewFinderSwitcherScale
> + origin.x: viewFinderSwitcher.width/2
> + origin.y: viewFinderSwitcher.height/2
> + xScale: 1
> + yScale: xScale
> + },
> + Rotation {
> + id: viewFinderSwitcherRotation
> + origin.x: viewFinderSwitcher.width/2
> + origin.y: viewFinderSwitcher.height/2
> + axis.x: 0; axis.y: 1; axis.z: 0
> + angle: 0
> + }
> + ]
> +
> +
> + SequentialAnimation {
> + id: viewFinderSwitcherAnimation
> +
> + SequentialAnimation {
> + ParallelAnimation {
> + UbuntuNumberAnimation {target: viewFinderSwitcherScale; property: "xScale"; from: 1.0; to: 0.8; duration: UbuntuAnimation.BriskDuration ; easing: UbuntuAnimation.StandardEasing}
> + UbuntuNumberAnimation {
> + target: viewFinderSwitcherRotation
> + property: "angle"
> + from: 180
> + to: 90
> + duration: UbuntuAnimation.BriskDuration
> + easing: UbuntuAnimation.StandardEasing
> + }
> + }
> + PropertyAction { target: viewFinder; property: "width"; value: viewFinderSwitcher.width}
> + PropertyAction { target: viewFinder; property: "height"; value: viewFinderSwitcher.height}
> + PropertyAction { target: viewFinderGrab; property: "visible"; value: false }
> + ParallelAnimation {
> + UbuntuNumberAnimation {target: viewFinderSwitcherScale; property: "xScale"; from: 0.8; to: 1.0; duration: UbuntuAnimation.BriskDuration; easing: UbuntuAnimation.StandardEasingReverse}
> + UbuntuNumberAnimation {
> + target: viewFinderSwitcherRotation
> + property: "angle"
> + from: 90
> + to: 0
> + duration: UbuntuAnimation.BriskDuration
> + easing: UbuntuAnimation.StandardEasingReverse
> + }
> + }
> + }
> + }
> +
> + VideoOutput {
> + id: viewFinder
> +
> + x: 0
> + y: -viewFinderGeometry.y
> + width: parent.width
> + height: parent.height
> + source: camera
> +
> + /* This rotation need to be applied since the camera hardware in the
> + Galaxy Nexus phone is mounted at an angle inside the device, so the video
> + feed is rotated too.
> + FIXME: This should come from a system configuration option so that we
> + don't have to have a different codebase for each different device we want
> + to run on */
> + orientation: Screen.primaryOrientation === Qt.PortraitOrientation ? -90 : 0
> +
> + /* Convenience item tracking the real position and size of the real video feed.
> + Having this helps since these values depend on a lot of rules:
> + - the feed is automatically scaled to fit the viewfinder
> + - the viewfinder might apply a rotation to the feed, depending on device orientation
> + - the resolution and aspect ratio of the feed changes depending on the active camera
> + The item is also separated in a component so it can be unit tested.
> + */
> +
> + transform: Rotation {
> + origin.x: viewFinder.width / 2
> + origin.y: viewFinder.height / 2
> + axis.x: 0; axis.y: 1; axis.z: 0
> + angle: application.desktopMode ? 180 : 0
> + }
> +
> + ViewFinderGeometry {
> + id: viewFinderGeometry
> + anchors.centerIn: parent
> +
> + cameraResolution: camera.advanced.resolution
> + viewFinderHeight: viewFinder.height
> + viewFinderWidth: viewFinder.width
> + viewFinderOrientation: viewFinder.orientation
> + }
> +
> + Rectangle {
> + id: shootFeedback
> + anchors.fill: parent
> + color: "white"
> + visible: opacity != 0.0
> + opacity: 0.0
> +
> + function start() {
> + shootFeedback.opacity = 1.0;
> + viewFinderOverlay.visible = false;
> + shootFeedbackAnimation.restart();
> + }
> +
> + OpacityAnimator {
> + id: shootFeedbackAnimation
> + target: shootFeedback
> + from: 1.0
> + to: 0.0
> + duration: 50
> + easing: UbuntuAnimation.StandardEasing
> + }
> + }
> + }
> + }
> +
> + FastBlur {
> + anchors.fill: viewFinderSwitcher
> + radius: viewFinderOverlay.revealProgress * 64
> + source: radius !== 0 ? viewFinderSwitcher : null
> + visible: radius !== 0
> + }
> +
> + ViewFinderOverlay {
> + id: viewFinderOverlay
> +
> + anchors.fill: parent
> + camera: camera
> + opacity: overlayVisible ? 1.0 : 0.0
> + Behavior on opacity {UbuntuNumberAnimation {duration: UbuntuAnimation.SnapDuration}}
> + }
> +
> + Snapshot {
> + id: snapshot
> + anchors.fill: parent
> + orientation: viewFinder.orientation
> + geometry: viewFinderGeometry
> + deviceDefaultIsPortrait: Screen.primaryOrientation === Qt.PortraitOrientation
> + }
> +}
>
> === modified file 'ZoomControl.qml'
> --- ZoomControl.qml 2013-06-27 15:22:59 +0000
> +++ ZoomControl.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2012 Canonical Ltd.
> + * 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
> @@ -15,79 +15,64 @@
> */
>
> import QtQuick 2.0
> -import Ubuntu.Components 0.1// as SDK
> +import Ubuntu.Components 1.0
>
> Item {
> - id: zoom
> + id: zoomControl
> + property alias minimumValue: slider.minimumValue
> property alias maximumValue: slider.maximumValue
> property alias value: slider.value
> - property real zoomStep: (slider.maximumValue - slider.minimumValue) / 20
> - property int iconsRotation
> -
> - AbstractButton {
> - id: minus
> - objectName: "zoomMinus"
> - anchors.left: parent.left
> - anchors.verticalCenter: parent.verticalCenter
> - width: minusIcon.width
> - height: minusIcon.height
> - onClicked: slider.value = Math.max(value - zoom.zoomStep, slider.minimumValue)
> - onPressedChanged: if (pressed) minusTimer.restart(); else minusTimer.stop();
> - rotation: iconsRotation
> -
> - Image {
> - id: minusIcon
> - anchors.centerIn: parent
> - source: "assets/zoom_minus.png"
> - sourceSize.height: units.gu(2)
> - smooth: true
> - }
> -
> - Timer {
> - id: minusTimer
> - interval: 40
> - repeat: true
> - onTriggered: slider.value = Math.max(value - zoom.zoomStep, slider.minimumValue)
> - }
> +
> + function show() {
> + zoomAutoHide.restart();
> + shown = true;
> + }
> +
> + property bool shown: false
> + visible: opacity != 0.0
> + opacity: shown ? 1.0 : 0.0
> + layer.enabled: fadeAnimation.running
> + Behavior on opacity { UbuntuNumberAnimation {id: fadeAnimation} }
> +
> + Timer {
> + id: zoomAutoHide
> + interval: 2000
> + onTriggered: {
> + zoomControl.shown = false;
> + }
> + }
> +
> + implicitHeight: slider.height
> +
> + Image {
> + id: minusIcon
> + anchors {
> + left: parent.left
> + verticalCenter: parent.verticalCenter
> + }
> + source: "assets/zoom_minus.png"
> }
>
> Slider {
> id: slider
> style: ThinSliderStyle {}
> - anchors.left: minus.right
> - anchors.right: plus.left
> - anchors.verticalCenter: parent.verticalCenter
> + anchors {
> + left: minusIcon.right
> + right: plusIcon.left
> + }
> +
> live: true
> minimumValue: 1.0 // No zoom => 1.0 zoom factor
> value: minimumValue
> - height: slider.implicitHeight + units.gu(4)
> }
>
> - AbstractButton {
> - id: plus
> - objectName: "zoomPlus"
> - anchors.right: parent.right
> - anchors.verticalCenter: parent.verticalCenter
> - width: plusIcon.width
> - height: plusIcon.height
> - onClicked: slider.value = Math.min(value + zoom.zoomStep, slider.maximumValue)
> - onPressedChanged: if (pressed) plusTimer.restart(); else plusTimer.stop();
> - rotation: iconsRotation
> -
> - Image {
> - id: plusIcon
> - anchors.centerIn: parent
> - source: "assets/zoom_plus.png"
> - sourceSize.height: units.gu(2)
> - smooth: true
> - }
> -
> - Timer {
> - id: plusTimer
> - interval: 40
> - repeat: true
> - onTriggered: slider.value = Math.min(value + zoom.zoomStep, slider.maximumValue)
> - }
> + Image {
> + id: plusIcon
> + anchors {
> + right: parent.right
> + verticalCenter: parent.verticalCenter
> + }
> + source: "assets/zoom_plus.png"
> }
> }
>
>
> === removed file 'assets/camera at 18.png'
> Binary files assets/camera at 18.png 2012-11-21 15:41:50 +0000 and assets/camera at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/flash_auto at 18.png'
> Binary files assets/flash_auto at 18.png 2012-11-21 15:41:50 +0000 and assets/flash_auto at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/flash_off at 18.png'
> Binary files assets/flash_off at 18.png 2012-11-21 15:41:50 +0000 and assets/flash_off at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/flash_on at 18.png'
> Binary files assets/flash_on at 18.png 2012-11-21 15:41:50 +0000 and assets/flash_on at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/focus_ring at 18.png'
> Binary files assets/focus_ring at 18.png 2012-11-21 15:41:50 +0000 and assets/focus_ring at 18.png 1970-01-01 00:00:00 +0000 differ
> === added file 'assets/focus_ring at 27.png'
> Binary files assets/focus_ring at 27.png 1970-01-01 00:00:00 +0000 and assets/focus_ring at 27.png 2014-06-26 09:06:29 +0000 differ
> === removed file 'assets/gallery at 18.png'
> Binary files assets/gallery at 18.png 2012-11-21 15:41:50 +0000 and assets/gallery at 18.png 1970-01-01 00:00:00 +0000 differ
> === added file 'assets/gridview at 12.png'
> Binary files assets/gridview at 12.png 1970-01-01 00:00:00 +0000 and assets/gridview at 12.png 2014-06-26 09:06:29 +0000 differ
> === added file 'assets/options at 12.png'
> Binary files assets/options at 12.png 1970-01-01 00:00:00 +0000 and assets/options at 12.png 2014-06-26 09:06:29 +0000 differ
> === removed file 'assets/record_off at 18.png'
> Binary files assets/record_off at 18.png 2012-11-21 15:41:50 +0000 and assets/record_off at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/record_on at 18.png'
> Binary files assets/record_on at 18.png 2012-11-21 15:41:50 +0000 and assets/record_on at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/record_on_pulse at 18.png'
> Binary files assets/record_on_pulse at 18.png 2012-11-21 15:41:50 +0000 and assets/record_on_pulse at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/record_picture at 18.png'
> Binary files assets/record_picture at 18.png 2012-11-21 15:41:50 +0000 and assets/record_picture at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/record_video at 18.png'
> Binary files assets/record_video at 18.png 2012-11-21 15:41:50 +0000 and assets/record_video at 18.png 1970-01-01 00:00:00 +0000 differ
> === added file 'assets/shadow at 27.png'
> Binary files assets/shadow at 27.png 1970-01-01 00:00:00 +0000 and assets/shadow at 27.png 2014-06-26 09:06:29 +0000 differ
> === removed file 'assets/shoot at 18.png'
> Binary files assets/shoot at 18.png 2012-11-21 15:41:50 +0000 and assets/shoot at 18.png 1970-01-01 00:00:00 +0000 differ
> === added file 'assets/shutter_stills at 27.png'
> Binary files assets/shutter_stills at 27.png 1970-01-01 00:00:00 +0000 and assets/shutter_stills at 27.png 2014-06-26 09:06:29 +0000 differ
> === removed file 'assets/swap_camera at 18.png'
> Binary files assets/swap_camera at 18.png 2012-11-21 15:41:50 +0000 and assets/swap_camera at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/toolbar-left at 18.png'
> Binary files assets/toolbar-left at 18.png 2012-11-21 15:41:50 +0000 and assets/toolbar-left at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/toolbar-left at 18.sci'
> --- assets/toolbar-left at 18.sci 2012-11-21 15:41:50 +0000
> +++ assets/toolbar-left at 18.sci 1970-01-01 00:00:00 +0000
> @@ -1,7 +0,0 @@
> -source: toolbar-left at 18.png
> -border.left: 80
> -border.right: 0
> -border.top: 30
> -border.bottom: 30
> -horizontalTileMode: Stretch
> -verticalTileMode: Stretch
>
> === removed file 'assets/toolbar-middle at 18.png'
> Binary files assets/toolbar-middle at 18.png 2012-11-21 15:41:50 +0000 and assets/toolbar-middle at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/toolbar-middle at 18.sci'
> --- assets/toolbar-middle at 18.sci 2012-11-21 15:41:50 +0000
> +++ assets/toolbar-middle at 18.sci 1970-01-01 00:00:00 +0000
> @@ -1,7 +0,0 @@
> -source: toolbar-middle at 18.png
> -border.left: 0
> -border.right: 0
> -border.top: 41
> -border.bottom: 41
> -horizontalTileMode: Stretch
> -verticalTileMode: Stretch
>
> === removed file 'assets/toolbar-right at 18.png'
> Binary files assets/toolbar-right at 18.png 2012-11-21 15:41:50 +0000 and assets/toolbar-right at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/toolbar-right at 18.sci'
> --- assets/toolbar-right at 18.sci 2012-11-21 15:41:50 +0000
> +++ assets/toolbar-right at 18.sci 1970-01-01 00:00:00 +0000
> @@ -1,7 +0,0 @@
> -source: toolbar-right at 18.png
> -border.right: 80
> -border.left: 0
> -border.top: 30
> -border.bottom: 30
> -horizontalTileMode: Stretch
> -verticalTileMode: Stretch
>
> === removed file 'assets/torch_off at 18.png'
> Binary files assets/torch_off at 18.png 2012-12-04 17:16:35 +0000 and assets/torch_off at 18.png 1970-01-01 00:00:00 +0000 differ
> === removed file 'assets/torch_on at 18.png'
> Binary files assets/torch_on at 18.png 2012-12-04 17:16:35 +0000 and assets/torch_on at 18.png 1970-01-01 00:00:00 +0000 differ
> === added file 'assets/ubuntu_shape.svg'
> --- assets/ubuntu_shape.svg 1970-01-01 00:00:00 +0000
> +++ assets/ubuntu_shape.svg 2014-06-26 09:06:29 +0000
> @@ -0,0 +1,74 @@
> +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
> +<!-- Created with Inkscape (http://www.inkscape.org/) -->
> +
> +<svg
> + xmlns:dc="http://purl.org/dc/elements/1.1/"
> + xmlns:cc="http://creativecommons.org/ns#"
> + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
> + xmlns:svg="http://www.w3.org/2000/svg"
> + xmlns="http://www.w3.org/2000/svg"
> + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
> + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
> + width="512"
> + height="476"
> + id="svg3336"
> + version="1.1"
> + inkscape:version="0.48.3.1 r9886"
> + sodipodi:docname="New document 2">
> + <defs
> + id="defs3338" />
> + <sodipodi:namedview
> + id="base"
> + pagecolor="#ffffff"
> + bordercolor="#666666"
> + borderopacity="1.0"
> + inkscape:pageopacity="0.0"
> + inkscape:pageshadow="2"
> + inkscape:zoom="0.35"
> + inkscape:cx="375"
> + inkscape:cy="520"
> + inkscape:document-units="px"
> + inkscape:current-layer="layer1"
> + showgrid="false"
> + inkscape:window-width="1920"
> + inkscape:window-height="1029"
> + inkscape:window-x="0"
> + inkscape:window-y="24"
> + inkscape:window-maximized="1" />
> + <metadata
> + id="metadata3341">
> + <rdf:RDF>
> + <cc:Work
> + rdf:about="">
> + <dc:format>image/svg+xml</dc:format>
> + <dc:type
> + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
> + <dc:title></dc:title>
> + </cc:Work>
> + </rdf:RDF>
> + </metadata>
> + <g
> + inkscape:label="Layer 1"
> + inkscape:groupmode="layer"
> + id="layer1"
> + transform="translate(0,-576.36218)">
> + <g
> + transform="matrix(3.5555556,0,0,3.5522388,0,-2685.8796)"
> + id="layer1-3"
> + inkscape:label="Layer 1"
> + style="fill:#000000;display:inline">
> + <g
> + style="fill:#000000"
> + inkscape:label="Layer 1"
> + id="layer1-2"
> + transform="translate(0,9.99998)">
> + <path
> + sodipodi:nodetypes="sssssssss"
> + inkscape:connector-curvature="0"
> + id="path3774"
> + d="m 46.702703,908.3622 50.594594,0 C 138.16216,908.3622 144,914.2 144,955.06487 l 0,40.59483 c 0,40.8647 -5.83784,46.7025 -46.702703,46.7025 l -50.594594,0 C 5.8378378,1042.3622 0,1036.5244 0,995.6597 L 0,955.06487 C 0,914.2 5.8378378,908.3622 46.702703,908.3622 z"
> + style="fill:#000000;fill-opacity:1;stroke:none;display:inline" />
> + </g>
> + </g>
> + </g>
> +</svg>
>
> === modified file 'assets/zoom_point at 18.png'
> Binary files assets/zoom_point at 18.png 2013-06-27 00:31:29 +0000 and assets/zoom_point at 18.png 2014-06-26 09:06:29 +0000 differ
> === modified file 'camera-app.qml'
> --- camera-app.qml 2014-05-17 07:42:35 +0000
> +++ camera-app.qml 2014-06-26 09:06:29 +0000
> @@ -1,5 +1,5 @@
> /*
> - * Copyright 2012 Canonical Ltd.
> + * 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
> @@ -14,44 +14,43 @@
> * along with this program. If not, see <http://www.gnu.org/licenses/>.
> */
>
> -import QtQuick 2.0
> -import Ubuntu.Components 0.1
> +import QtQuick 2.2
> +import QtQuick.Window 2.0
> +import Ubuntu.Components 1.0
> import Ubuntu.Unity.Action 1.1 as UnityActions
> -import QtMultimedia 5.0
> -import CameraApp 0.1
> -import QtQuick.Window 2.0
> import UserMetrics 0.1
>
> -Rectangle {
> +Item {
> id: main
> objectName: "main"
> - width: application.desktopMode ? units.gu(120) : (device.naturalOrientation == "portrait" ? units.gu(40) : units.gu(80))
> - height: application.desktopMode ? units.gu(60) : (device.naturalOrientation == "portrait" ? units.gu(80) : units.gu(40))
> - color: "#252423"
> + width: units.gu(40)
> + height: units.gu(71)
> +// width: application.desktopMode ? units.gu(120) : (Screen.primaryOrientation === Qt.PortraitOrientation ? units.gu(40) : units.gu(80))
> +// height: application.desktopMode ? units.gu(60) : (Screen.primaryOrientation === Qt.PortraitOrientation ? units.gu(80) : units.gu(40))
>
> UnityActions.ActionManager {
> actions: [
> - UnityActions.Action {
> - text: i18n.tr("Flash")
> - keywords: i18n.tr("Light;Dark")
> - onTriggered: toolbar.switchFlashMode()
> - },
> - UnityActions.Action {
> - text: i18n.tr("Flip Camera")
> - keywords: i18n.tr("Front Facing;Back Facing")
> - onTriggered: toolbar.switchCamera()
> - },
> - UnityActions.Action {
> - text: i18n.tr("Shutter")
> - keywords: i18n.tr("Take a Photo;Snap;Record")
> - onTriggered: toolbar.shoot()
> - },
> - UnityActions.Action {
> - text: i18n.tr("Mode")
> - keywords: i18n.tr("Stills;Video")
> - onTriggered: toolbar.changeRecordMode()
> - enabled: false
> - },
> +// UnityActions.Action {
> +// text: i18n.tr("Flash")
> +// keywords: i18n.tr("Light;Dark")
> +// onTriggered: toolbar.switchFlashMode()
> +// },
> +// UnityActions.Action {
> +// text: i18n.tr("Flip Camera")
> +// keywords: i18n.tr("Front Facing;Back Facing")
> +// onTriggered: toolbar.switchCamera()
> +// },
> +// UnityActions.Action {
> +// text: i18n.tr("Shutter")
> +// keywords: i18n.tr("Take a Photo;Snap;Record")
> +// onTriggered: toolbar.shoot()
> +// },
> +// UnityActions.Action {
> +// text: i18n.tr("Mode")
> +// keywords: i18n.tr("Stills;Video")
> +// onTriggered: toolbar.changeRecordMode()
> +// enabled: false
> +// },
> UnityActions.Action {
> text: i18n.tr("White Balance")
> keywords: i18n.tr("Lighting Condition;Day;Cloudy;Inside")
> @@ -65,304 +64,108 @@
>
> Component.onCompleted: {
> i18n.domain = "camera-app";
> - camera.start();
> - }
> -
> - DeviceOrientation {
> - id: device
> - }
> -
> - Camera {
> - id: camera
> - flash.mode: Camera.FlashOff
> - captureMode: Camera.CaptureStillImage
> - focus.focusMode: Camera.FocusAuto //TODO: Not sure if Continuous focus is better here
> - focus.focusPointMode: application.desktopMode ? Camera.FocusPointAuto : (focusRing.opacity > 0 ? Camera.FocusPointCustom : Camera.FocusPointAuto)
> -
> - property AdvancedCameraSettings advanced: AdvancedCameraSettings {
> - camera: camera
> - }
> -
> - /* Use only digital zoom for now as it's what phone cameras mostly use.
> - TODO: if optical zoom is available, maximumZoom should be the combined
> - range of optical and digital zoom and currentZoom should adjust the two
> - transparently based on the value. */
> - property alias currentZoom: camera.digitalZoom
> - property alias maximumZoom: camera.maximumDigitalZoom
> -
> - imageCapture {
> - onCaptureFailed: {
> - console.log("Capture failed for request " + requestId + ": " + message);
> - focusRing.opacity = 0.0;
> - }
> - onImageCaptured: {
> - focusRing.opacity = 0.0;
> - snapshot.source = preview;
> - }
> - onImageSaved: {
> - metricPhotos.increment()
> - console.log("Picture saved as " + path)
> - }
> - }
> -
> - videoRecorder {
> - onRecorderStateChanged: {
> - if (videoRecorder.recorderState === CameraRecorder.StoppedState)
> - metricVideos.increment()
> - }
> -
> - }
> - }
> -
> - Connections {
> - target: Qt.application
> - onActiveChanged: {
> - if (Qt.application.active)
> - camera.start()
> - else if (!application.desktopMode)
> - camera.stop()
> - }
> - }
> -
> - VideoOutput {
> - id: viewFinder
> -
> - property bool shouldBeCentered: device.isLandscape ||
> - ((viewFinder.width > viewFinderGeometry.width) &&
> - device.naturalOrientation === "portrait")
> - property real anchoredY: viewFinderGeometry.y * (device.isInverted ? +1 : -1)
> - property real anchoredX: viewFinderGeometry.x * (device.isInverted ? +1 : -1)
> -
> - x: viewFinder.shouldBeCentered ? 0 : viewFinder.anchoredX
> - y: viewFinder.shouldBeCentered || device.naturalOrientation === "landscape" ?
> - 0 : viewFinder.anchoredY
> - width: parent.width
> - height: parent.height
> - source: camera
> -
> - /* This rotation need to be applied since the camera hardware in the
> - Galaxy Nexus phone is mounted at an angle inside the device, so the video
> - feed is rotated too.
> - FIXME: This should come from a system configuration option so that we
> - don't have to have a different codebase for each different device we want
> - to run on */
> - orientation: device.naturalOrientation === "portrait" ? -90 : 0
> -
> - /* Convenience item tracking the real position and size of the real video feed.
> - Having this helps since these values depend on a lot of rules:
> - - the feed is automatically scaled to fit the viewfinder
> - - the viewfinder might apply a rotation to the feed, depending on device orientation
> - - the resolution and aspect ratio of the feed changes depending on the active camera
> - The item is also separated in a component so it can be unit tested.
> - */
> -
> - transform: Rotation {
> - origin.x: viewFinder.width / 2
> - origin.y: viewFinder.height / 2
> - axis.x: 0; axis.y: 1; axis.z: 0
> - angle: application.desktopMode ? 180 : 0
> - }
> -
> - ViewFinderGeometry {
> - id: viewFinderGeometry
> - anchors.centerIn: parent
> -
> - cameraResolution: camera.advanced.resolution
> - viewFinderHeight: viewFinder.height
> - viewFinderWidth: viewFinder.width
> - viewFinderOrientation: viewFinder.orientation
> -
> - Item {
> - id: itemScale
> - visible: false
> - }
> -
> - PinchArea {
> - id: area
> -
> - state: device.isLandscape ? "split" : "joined"
> - anchors.left: viewFinderGeometry.left
> - anchors.right: viewFinderGeometry.right
> -
> - pinch.minimumScale: 0.0
> - pinch.maximumScale: camera.maximumZoom
> - pinch.target: itemScale
> -
> - states: [
> - State {
> - name: "joined"
> - PropertyChanges {
> - target: area
> - height: zoomControl.y
> - }
> - AnchorChanges {
> - target: area;
> - anchors.top: viewFinderGeometry.top
> - }
> - },
> - State {
> - name: "split"
> - PropertyChanges {
> - target: area
> - y: device.isInverted ? zoomControl.height : toolbar.height
> - height: viewFinderGeometry.height - zoomControl.height - toolbar.height
> - }
> - AnchorChanges {
> - target: area;
> - anchors.top: undefined
> - }
> - }
> - ]
> -
> - onPinchStarted: {
> - if (!application.desktopMode)
> - focusRing.center = main.mapFromItem(area, pinch.center.x, pinch.center.y);
> - }
> -
> - onPinchFinished: {
> - if (!application.desktopMode) {
> - focusRing.restartTimeout()
> - var center = pinch.center
> - var focusPoint = viewFinder.mapPointToSourceNormalized(pinch.center);
> - camera.focus.customFocusPoint = focusPoint;
> - }
> - }
> -
> - onPinchUpdated: {
> - if (!application.desktopMode) {
> - focusRing.center = main.mapFromItem(area, pinch.center.x, pinch.center.y);
> - camera.currentZoom = itemScale.scale
> - }
> - }
> -
> - MouseArea {
> - id: mouseArea
> -
> - anchors.fill: parent
> -
> - onPressed: {
> - if (!application.desktopMode && !area.pinch.active)
> - focusRing.center = main.mapFromItem(area, mouse.x, mouse.y);
> - }
> -
> - onReleased: {
> - if (!application.desktopMode && !area.pinch.active) {
> - var focusPoint = viewFinder.mapPointToSourceNormalized(Qt.point(mouse.x, mouse.y))
> -
> - focusRing.restartTimeout()
> - camera.focus.customFocusPoint = focusPoint;
> - }
> - }
> -
> - drag {
> - target: application.desktopMode ? "" : focusRing
> - minimumY: area.y - focusRing.height / 2
> - maximumY: area.y + area.height - focusRing.height / 2
> - minimumX: area.x - focusRing.width / 2
> - maximumX: area.x + area.width - focusRing.width / 2
> - }
> -
> - }
> - }
> -
> - Snapshot {
> - id: snapshot
> - anchors.left: parent.left
> - anchors.right: parent.right
> - height: parent.height
> - y: 0
> - orientation: viewFinder.orientation
> - geometry: viewFinderGeometry
> - deviceDefaultIsPortrait: device.naturalOrientation === "portrait"
> - }
> - }
> - }
> -
> - FocusRing {
> - id: focusRing
> - height: units.gu(13)
> - width: units.gu(13)
> - opacity: 0.0
> - }
> -
> - Item {
> - id: controlsArea
> - anchors.centerIn: parent
> -
> - height: (device.naturalOrientation == "portrait") ? parent.height : parent.width
> - width: (device.naturalOrientation == "portrait") ? parent.width : parent.height
> -
> - rotation: device.naturalOrientation == "landscape" ?
> - ((device.isInverted) ? 90 : -90) :
> - (!device.isLandscape ? (device.isInverted ? 180 : 0) :
> - (device.isInverted ? 0 : 180))
> -
> - state: device.isLandscape ? "split" : "joined"
> - states: [
> - State { name: "joined"
> - AnchorChanges { target: zoomControl; anchors.bottom: toolbar.top }
> - AnchorChanges {
> - target: stopWatch
> - anchors.top: parent.top
> - anchors.horizontalCenter: parent.horizontalCenter
> - }
> - },
> - State { name: "split"
> - AnchorChanges { target: zoomControl; anchors.top: parent.top }
> - AnchorChanges {
> - target: stopWatch
> - anchors.right: parent.right
> - anchors.verticalCenter: parent.verticalCenter
> - }
> - }
> - ]
> -
> - ZoomControl {
> - id: zoomControl
> - maximumValue: camera.maximumZoom
> - height: units.gu(4.5)
> -
> - anchors.left: parent.left
> - anchors.right: parent.right
> - anchors.leftMargin: units.gu(0.75)
> - anchors.rightMargin: units.gu(0.75)
> - anchors.bottomMargin: controlsArea.state == "split" ? units.gu(3.25) : units.gu(0.5)
> - anchors.topMargin: controlsArea.state == "split" ? units.gu(3.25) : units.gu(0.5)
> -
> - visible: camera.maximumZoom > 1
> -
> - // Create a two way binding between the zoom control value and the actual camera zoom,
> - // so that they can stay in sync when the zoom is changed from the UI or from the hardware
> - Binding { target: zoomControl; property: "value"; value: camera.currentZoom }
> - Binding { target: camera; property: "currentZoom"; value: zoomControl.value }
> -
> - iconsRotation: device.rotationAngle - controlsArea.rotation
> - }
> -
> - Toolbar {
> - id: toolbar
> -
> - anchors.bottom: parent.bottom
> - anchors.left: parent.left
> - anchors.right: parent.right
> - anchors.bottomMargin: units.gu(1)
> - anchors.leftMargin: units.gu(1)
> - anchors.rightMargin: units.gu(1)
> -
> - camera: camera
> - canCapture: camera.imageCapture.ready && !snapshot.sliding
> - iconsRotation: device.rotationAngle - controlsArea.rotation
> - }
> -
> - StopWatch {
> - id: stopWatch
> - opacity: camera.videoRecorder.recorderState == CameraRecorder.StoppedState ? 0.0 : 1.0
> - time: camera.videoRecorder.duration / 1000
> - labelRotation: device.rotationAngle - controlsArea.rotation
> - anchors.topMargin: units.gu(2)
> - anchors.rightMargin: units.gu(2)
> - }
> - }
> + }
> +
> +
> + Flickable {
> + id: viewSwitcher
> + anchors.fill: parent
> + flickableDirection: Flickable.HorizontalFlick
> + boundsBehavior: Flickable.StopAtBounds
> + contentWidth: contentItem.childrenRect.width
> + contentHeight: contentItem.childrenRect.height
> + interactive: !viewFinderView.touchAcquired
> +
> + Component.onCompleted: {
> + // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
> + // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
> + var scaleFactor = units.gridUnit / 8;
> + maximumFlickVelocity = maximumFlickVelocity * scaleFactor;
> + flickDeceleration = flickDeceleration * scaleFactor;
> + }
> +
> + property bool settling: false
> + property bool switching: false
> + property real settleVelocity: units.dp(5000)
> +
> + function settle() {
> + settling = true;
> + var velocity;
> + if (horizontalVelocity < 0 || (horizontalVelocity == 0 && visibleArea.xPosition <= 0.25)) {
> + // FIXME: compute velocity better to ensure it reaches rest position (maybe in a constant time)
> + velocity = settleVelocity;
> + } else {
> + velocity = -settleVelocity;
> + }
> +
> + flick(velocity, 0);
> + }
> +
> + function switchToViewFinder() {
> + cancelFlick();
> + switching = true;
> + flick(settleVelocity, 0);
> + }
> +
> + onMovementEnded: {
> + // go to a rest position as soon as user stops interacting with the Flickable
> + settle();
> + }
> +
> + onFlickStarted: {
> + // cancel user triggered flicks
> + if (!settling && !switching) {
> + cancelFlick();
> + }
> + }
> +
> + onFlickingHorizontallyChanged: {
> + // use flickingHorizontallyChanged instead of flickEnded because flickEnded
> + // is not called when a flick is interrupted by the user
> + if (!flickingHorizontally) {
> + if (settling) {
> + settling = false;
> + }
> + if (switching) {
> + switching = true;
> + }
> + }
> + }
> +
> + onHorizontalVelocityChanged: {
> + // FIXME: this is a workaround for the lack of notification when
> + // the user manually interrupts a flick by pressing and releasing
> + if (horizontalVelocity == 0 && !atXBeginning && !atXEnd && !settling && !moving) {
> + settle();
> + }
> + }
> +
> + Row {
> + anchors {
> + top: parent.top
> + bottom: parent.bottom
> + }
> + spacing: units.gu(1)
> +
> + ViewFinderView {
> + id: viewFinderView
> + width: viewSwitcher.width
> + height: viewSwitcher.height
> + overlayVisible: !viewSwitcher.moving && !viewSwitcher.flicking
> + inView: !viewSwitcher.atXEnd
> + onPhotoTaken: galleryView.showLastPhotoTaken();
> + }
> +
> + GalleryView {
> + id: galleryView
> + width: viewSwitcher.width
> + height: viewSwitcher.height
> + inView: !viewSwitcher.atXBeginning
> + onExit: viewSwitcher.switchToViewFinder()
> + }
> + }
> + }
> +
>
> Metric {
> id: metricPhotos
>
> === modified file 'cameraapplication.cpp'
> --- cameraapplication.cpp 2014-03-28 02:27:15 +0000
> +++ cameraapplication.cpp 2014-06-26 09:06:29 +0000
> @@ -24,6 +24,8 @@
> #include <QtCore/QDebug>
> #include <QtCore/QStringList>
> #include <QtCore/QLibrary>
> +#include <QtCore/QStandardPaths>
> +#include <QtCore/QDir>
> #include <QDate>
> #include <QQmlContext>
> #include <QQmlEngine>
> @@ -86,6 +88,7 @@
> m_view.reset(new QQuickView());
> m_view->setResizeMode(QQuickView::SizeRootObjectToView);
> m_view->setTitle("Camera");
> + m_view->setColor("black");
> m_view->rootContext()->setContextProperty("application", this);
> m_view->engine()->setBaseUrl(QUrl::fromLocalFile(cameraAppDirectory()));
> if (isClick()) {
> @@ -104,3 +107,11 @@
>
> return true;
> }
> +
> +QString CameraApplication::mediaLocation() const
> +{
> + QString location = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation).at(0) + "/camera";
> + QDir dir;
> + dir.mkpath(location);
> + return location;
> +}
>
> === modified file 'cameraapplication.h'
> --- cameraapplication.h 2014-01-24 21:05:20 +0000
> +++ cameraapplication.h 2014-06-26 09:06:29 +0000
> @@ -29,12 +29,14 @@
> {
> Q_OBJECT
> Q_PROPERTY(bool desktopMode READ isDesktopMode CONSTANT)
> + Q_PROPERTY(QString mediaLocation READ mediaLocation CONSTANT)
>
> public:
> CameraApplication(int &argc, char **argv);
> virtual ~CameraApplication();
> bool setup();
> bool isDesktopMode() const;
> + QString mediaLocation() const;
>
> private:
> QScopedPointer<QQuickView> m_view;
>
> === removed file 'constants.js'
> --- constants.js 2013-02-07 13:13:23 +0000
> +++ constants.js 1970-01-01 00:00:00 +0000
> @@ -1,19 +0,0 @@
> -/*
> - * Copyright 2012 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/>.
> - */
> -
> -.pragma library
> -
> -var iconFadeDuration = 300;
>
> === modified file 'debian/camera-app.install'
> --- debian/camera-app.install 2014-02-13 17:32:29 +0000
> +++ debian/camera-app.install 2014-06-26 09:06:29 +0000
> @@ -1,7 +1,6 @@
> /usr/lib/*/qt5/qml/*
> usr/bin/camera-app
> usr/share/applications/camera-app.desktop
> -usr/share/camera-app/*.js
> usr/share/camera-app/*.qml
> usr/share/camera-app/assets/*
> usr/share/icons
>
> === modified file 'debian/control'
> --- debian/control 2014-05-09 16:03:59 +0000
> +++ debian/control 2014-06-26 09:06:29 +0000
> @@ -16,6 +16,7 @@
> qtdeclarative5-ubuntu-ui-toolkit-plugin,
> qtdeclarative5-unity-action-plugin (>= 1.1.0),
> qtdeclarative5-usermetrics0.1,
> + qtdeclarative5-ubuntu-content0.1,
> qtmultimedia5-dev,
> libusermetricsinput1-dev,
> gettext,
>
> === modified file 'tests/autopilot/CMakeLists.txt'
> --- tests/autopilot/CMakeLists.txt 2014-05-06 18:41:31 +0000
> +++ tests/autopilot/CMakeLists.txt 2014-06-26 09:06:29 +0000
> @@ -2,7 +2,8 @@
> OUTPUT_VARIABLE PYTHON_PACKAGE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
>
> if(INSTALL_TESTS)
> -install(DIRECTORY ${AUTOPILOT_DIR}
> - DESTINATION ${PYTHON_PACKAGE_DIR}
> - )
> +message(WARNING ${PYTHON_PACKAGE_DIR})
> +#install(DIRECTORY ${AUTOPILOT_DIR}
> +# DESTINATION ${PYTHON_PACKAGE_DIR}
> +# )
> endif(INSTALL_TESTS)
>
--
https://code.launchpad.net/~fboucault/camera-app/ui_rewrite/+merge/224451
Your team Ubuntu Phablet Team is requested to review the proposed merge of lp:~fboucault/camera-app/ui_rewrite into lp:camera-app.
More information about the Ubuntu-reviews
mailing list