Merge lp:~uriboni/camera-app/real-picture-snapshot into lp:camera-app/staging

Proposed by Ugo Riboni
Status: Rejected
Rejected by: Florian Boucault
Proposed branch: lp:~uriboni/camera-app/real-picture-snapshot
Merge into: lp:camera-app/staging
Diff against target: 401 lines (+143/-68)
5 files modified
ProcessingFeedback.qml (+43/-0)
Snapshot.qml (+25/-17)
ViewFinderExportConfirmation.qml (+6/-20)
ViewFinderOverlay.qml (+11/-1)
ViewFinderView.qml (+58/-30)
To merge this branch: bzr merge lp:~uriboni/camera-app/real-picture-snapshot
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+283812@code.launchpad.net

Commit message

Use the final picture as the sliding snapshot instead of the preview

Description of the change

Use the final picture as the sliding snapshot instead of the preview

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
642. By Ugo Riboni

Merge Florian's fixes

643. By Ugo Riboni

Go back to using a preview, which the backend now creates from the actual image before saving it to disk

644. By Ugo Riboni

Keep the controls always visible and below the snapshot while it slides

645. By Ugo Riboni

Ensure everything works properly when exporting pictures

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

On media export prevent the screen from turning black while the snapshot loads

647. By Ugo Riboni

Remove unused properties

648. By Ugo Riboni

Refactor the export confirmation so it does not use identifiers out of scope

649. By Ugo Riboni

Remove debug

650. By Ugo Riboni

Pulse the shoot button while the capture is in progress to indicate progress

651. By Ugo Riboni

Simplify code

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

Ensure the photo roll hint is below the snapshot and that it does not become visible too early

653. By Ugo Riboni

Merge from parent branch

654. By Ugo Riboni

Merge more fixes from another branch

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

Unmerged revisions

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'ProcessingFeedback.qml'
2--- ProcessingFeedback.qml 1970-01-01 00:00:00 +0000
3+++ ProcessingFeedback.qml 2016-01-28 15:06:01 +0000
4@@ -0,0 +1,43 @@
5+/*
6+ * Copyright 2016 Canonical Ltd.
7+ *
8+ * This program is free software; you can redistribute it and/or modify
9+ * it under the terms of the GNU General Public License as published by
10+ * the Free Software Foundation; version 3.
11+ *
12+ * This program is distributed in the hope that it will be useful,
13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+ * GNU General Public License for more details.
16+ *
17+ * You should have received a copy of the GNU General Public License
18+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
19+ */
20+
21+import QtQuick 2.4
22+import Ubuntu.Components 1.3
23+
24+Item {
25+ id: processingFeedback
26+
27+ property bool processing: false
28+
29+ Timer {
30+ interval: 2000
31+ running: processing
32+ onTriggered: spinner.running = true
33+ }
34+
35+ onProcessingChanged: if (!processing) spinner.running = false
36+
37+ ActivityIndicator {
38+ id: spinner
39+ opacity: running ? 1.0 : 0.0
40+ Behavior on opacity {
41+ OpacityAnimator {
42+ duration: UbuntuAnimation.SnapDuration
43+ easing: UbuntuAnimation.StandardEasing
44+ }
45+ }
46+ }
47+}
48
49=== modified file 'Snapshot.qml'
50--- Snapshot.qml 2015-10-22 12:21:14 +0000
51+++ Snapshot.qml 2016-01-28 15:06:01 +0000
52@@ -21,17 +21,19 @@
53 Item {
54 id: snapshotRoot
55 property alias source: snapshot.source
56- property alias sliding: shoot.running
57- property int orientation
58+ property bool shouldSlide: true
59+ property bool sliding: false
60 property ViewFinderGeometry geometry
61- property bool deviceDefaultIsPortrait: true
62 property bool loading: snapshot.status == Image.Loading
63-
64- function startOutAnimation() {
65- shoot.restart()
66- }
67-
68- visible: false
69+ property bool loaded: snapshot.status == Image.Ready
70+
71+ opacity: 0.0
72+
73+ // Rotation and sliding direction is locked at the moment the picture is shoot
74+ // (in case processing is long, such as with HDR)
75+ function lockOrientation() { snapshot.rotation = orientationAngle }
76+
77+ onLoadedChanged: if (loaded && shouldSlide) shoot.restart()
78
79 Item {
80 id: container
81@@ -42,14 +44,13 @@
82 id: snapshot
83 anchors.centerIn: parent
84 anchors.verticalCenterOffset: -geometry.y
85- rotation: snapshotRoot.orientation * -1
86
87 asynchronous: true
88 cache: false
89 fillMode: Image.PreserveAspectFit
90 smooth: false
91- width: deviceDefaultIsPortrait ? geometry.height : geometry.width
92- height: deviceDefaultIsPortrait ? geometry.width : geometry.height
93+ width: rotation == 0 ? geometry.width : geometry.height
94+ height: rotation == 0 ? geometry.height : geometry.width
95 sourceSize.width: width
96 sourceSize.height: height
97 }
98@@ -57,10 +58,12 @@
99 Image {
100 id: shadow
101
102- property bool rotated: (snapshot.rotation % 180) != 0
103- height: rotated ? snapshot.width : snapshot.height
104+ transformOrigin: Item.TopLeft
105+ rotation: snapshot.rotation
106 width: units.gu(2)
107- x: (container.width - (rotated ? snapshot.height : snapshot.width)) / 2 - width
108+ height: rotation == 0 ? snapshot.height : snapshot.width
109+ x: rotation == 90 ? container.width : - width
110+ y: rotation == 270 ? container.height + width : (rotation == 90 ? - width : 0)
111 source: "assets/shadow.png"
112 fillMode: Image.Stretch
113 asynchronous: true
114@@ -75,8 +78,12 @@
115 SequentialAnimation {
116 id: shoot
117
118- PropertyAction { target: snapshotRoot; property: "visible"; value: true }
119+ NumberAnimation {
120+ target: snapshotRoot; property: "opacity"; to: 1.0
121+ duration: UbuntuAnimation.SnapDuration
122+ }
123 PauseAnimation { duration: 150 }
124+ PropertyAction { target: snapshotRoot; property: "sliding"; value: true}
125 XAnimator {
126 target: container
127 to: angleToOrientation[orientationAngle] == "PORTRAIT" ? container.width + shadow.width : 0
128@@ -91,8 +98,9 @@
129 easing: UbuntuAnimation.StandardEasing
130 }
131 PropertyAction { target: snapshot; property: "source"; value: ""}
132- PropertyAction { target: snapshotRoot; property: "visible"; value: false }
133+ PropertyAction { target: snapshotRoot; property: "opacity"; value: 0.0 }
134 PropertyAction { target: container; property: "x"; value: 0 }
135 PropertyAction { target: container; property: "y"; value: 0 }
136+ PropertyAction { target: snapshotRoot; property: "sliding"; value: false}
137 }
138 }
139
140=== modified file 'ViewFinderExportConfirmation.qml'
141--- ViewFinderExportConfirmation.qml 2015-12-10 12:17:49 +0000
142+++ ViewFinderExportConfirmation.qml 2016-01-28 15:06:01 +0000
143@@ -22,23 +22,7 @@
144
145 property bool isVideo
146 property string mediaPath
147- property Snapshot snapshot
148-
149- function confirmExport(path) {
150- viewFinder.visible = false;
151- viewFinderOverlay.visible = false;
152- mediaPath = path;
153- if (!isVideo) snapshot.visible = true;
154- visible = true;
155- }
156-
157- function hide() {
158- viewFinder.visible = true;
159- viewFinderOverlay.visible = true;
160- snapshot.source = "";
161- snapshot.visible = false;
162- visible = false;
163- }
164+ signal hideRequested()
165
166 visible: false
167
168@@ -74,7 +58,7 @@
169 }
170
171 iconName: "reload"
172- onClicked: viewFinderExportConfirmation.hide()
173+ onClicked: hideRequested()
174 }
175
176 CircleButton {
177@@ -90,8 +74,9 @@
178
179 iconName: "ok"
180 onClicked: {
181- viewFinderExportConfirmation.hide();
182+ hideRequested();
183 main.exportContent([mediaPath]);
184+ mediaPath = "";
185 }
186 }
187
188@@ -108,8 +93,9 @@
189
190 iconName: "close"
191 onClicked: {
192- viewFinderExportConfirmation.hide();
193+ hideRequested();
194 main.cancelExport();
195+ mediaPath = "";
196 }
197 }
198 }
199
200=== modified file 'ViewFinderOverlay.qml'
201--- ViewFinderOverlay.qml 2016-01-21 17:12:30 +0000
202+++ ViewFinderOverlay.qml 2016-01-28 15:06:01 +0000
203@@ -684,6 +684,7 @@
204 if (!main.contentExportMode) {
205 shootFeedback.start();
206 }
207+ camera.photoCaptureInProgress = true;
208 camera.imageCapture.setMetadata("Orientation", orientation);
209 var position = positionSource.position;
210 if (settings.gpsEnabled && positionSource.valid
211@@ -698,7 +699,6 @@
212 }
213 }
214
215- camera.photoCaptureInProgress = true;
216 if (main.contentExportMode) {
217 camera.imageCapture.captureToLocation(application.temporaryLocation);
218 } else if (application.removableStoragePresent && settings.preferRemovableStorage) {
219@@ -945,6 +945,16 @@
220 }
221 }
222
223+ ProcessingFeedback {
224+ anchors {
225+ top: parent.top
226+ topMargin: units.gu(2)
227+ left: parent.left
228+ leftMargin: units.gu(2)
229+ }
230+ processing: camera.photoCaptureInProgress
231+ }
232+
233 StorageMonitor {
234 id: storageMonitor
235 location: (application.removableStoragePresent && settings.preferRemovableStorage) ?
236
237=== modified file 'ViewFinderView.qml'
238--- ViewFinderView.qml 2016-01-21 16:40:19 +0000
239+++ ViewFinderView.qml 2016-01-28 15:06:01 +0000
240@@ -96,6 +96,13 @@
241 property bool switchInProgress: false
242 property bool photoCaptureInProgress: false
243
244+ onPhotoCaptureInProgressChanged: {
245+ if (photoCaptureInProgress) {
246+ snapshot.lockOrientation();
247+ viewFinder.opacity = 0.1;
248+ }
249+ }
250+
251 imageCapture {
252 onReadyChanged: {
253 if (camera.imageCapture.ready && main.transfer) {
254@@ -110,20 +117,17 @@
255 camera.photoCaptureInProgress = false;
256 console.log("Capture failed for request " + requestId + ": " + message);
257 }
258- onImageCaptured: {
259- snapshot.source = preview;
260- if (!main.contentExportMode) {
261- viewFinderOverlay.visible = true;
262- snapshot.startOutAnimation();
263- if (photoRollHint.necessary) {
264- photoRollHint.enable();
265- }
266- }
267- }
268+
269+ onImageCaptured: snapshot.source = preview
270+
271 onImageSaved: {
272 if (main.contentExportMode) {
273- viewFinderExportConfirmation.confirmExport(path);
274+ // show export confirmation only when both the image is saved and the snapshot
275+ // is loaded to prevent the screen being black while the image loads
276+ viewFinderExportConfirmation.mediaPath = path;
277+ if (snapshot.loaded) viewFinderExportConfirmation.show()
278 }
279+
280 viewFinderView.photoTaken(path);
281 camera.photoCaptureInProgress = false;
282 metricPhotos.increment();
283@@ -135,10 +139,10 @@
284 onRecorderStateChanged: {
285 if (videoRecorder.recorderState === CameraRecorder.StoppedState) {
286 metricVideos.increment()
287- viewFinderOverlay.visible = true;
288 viewFinderView.videoShot(videoRecorder.actualLocation);
289 if (main.contentExportMode) {
290- viewFinderExportConfirmation.confirmExport(videoRecorder.actualLocation);
291+ viewFinderExportConfirmation.mediaPath = videoRecorder.actualLocation
292+ viewFinderExportConfirmation.show();
293 } else if (photoRollHint.necessary) {
294 photoRollHint.enable();
295 }
296@@ -329,12 +333,10 @@
297 anchors.fill: parent
298
299 function start() {
300- viewFinderOverlay.visible = false;
301 }
302
303 function stop() {
304 remainingSecsLabel.text = "";
305- viewFinderOverlay.visible = true;
306 }
307
308 function showRemainingSecs(secs) {
309@@ -383,7 +385,6 @@
310
311 function start() {
312 shootFeedback.opacity = 1.0;
313- viewFinderOverlay.visible = false;
314 shootFeedbackAnimation.restart();
315 }
316
317@@ -392,7 +393,7 @@
318 target: shootFeedback
319 from: 1.0
320 to: 0.0
321- duration: 50
322+ duration: UbuntuAnimation.SnapDuration
323 easing: UbuntuAnimation.StandardEasing
324 }
325 }
326@@ -409,19 +410,10 @@
327 visible: radius !== 0
328 }
329
330- ViewFinderOverlayLoader {
331- id: viewFinderOverlay
332-
333- anchors.fill: parent
334- camera: camera
335- opacity: status == Loader.Ready && overlayVisible && !photoRollHint.enabled ? 1.0 : 0.0
336- Behavior on opacity {UbuntuNumberAnimation {duration: UbuntuAnimation.SnapDuration}}
337- }
338-
339 PhotoRollHint {
340 id: photoRollHint
341 anchors.fill: parent
342- visible: enabled && !snapshot.loading
343+ visible: enabled
344
345 Connections {
346 target: viewFinderView
347@@ -432,15 +424,51 @@
348 Snapshot {
349 id: snapshot
350 anchors.fill: parent
351- orientation: viewFinder.orientation
352 geometry: viewFinderGeometry
353- deviceDefaultIsPortrait: Screen.primaryOrientation === Qt.PortraitOrientation
354+ shouldSlide: !main.contentExportMode
355+ onSlidingChanged: {
356+ if (sliding) {
357+ viewFinder.opacity = 1.0;
358+ if (!main.contentExportMode && photoRollHint.necessary) photoRollHint.enable();
359+ }
360+ }
361+
362+ // show export confirmation only when both the image is saved and the snapshot
363+ // is loaded to prevent the screen being black while the image loads
364+ onLoadedChanged: {
365+ if (main.contentExportMode && loaded && viewFinderExportConfirmation.mediaPath != "") viewFinderExportConfirmation.show()
366+ }
367+ }
368+
369+ ViewFinderOverlayLoader {
370+ id: viewFinderOverlay
371+
372+ anchors.fill: parent
373+ camera: camera
374+ opacity: status == Loader.Ready && overlayVisible && !photoRollHint.enabled ? 1.0 : 0.0
375+ Behavior on opacity {UbuntuNumberAnimation {duration: UbuntuAnimation.SnapDuration}}
376 }
377
378 ViewFinderExportConfirmation {
379 id: viewFinderExportConfirmation
380 anchors.fill: parent
381- snapshot: snapshot
382+
383 isVideo: main.transfer.contentType == ContentType.Videos
384+ onVisibleChanged: if (visible) viewFinder.opacity = 1.0
385+
386+ function show() {
387+ viewFinder.visible = false;
388+ viewFinderOverlay.visible = false;
389+ if (!isVideo) snapshot.opacity = 1.0;
390+ visible = true;
391+ }
392+
393+ onHideRequested: {
394+ viewFinder.visible = true;
395+ viewFinderOverlay.visible = true;
396+ snapshot.source = "";
397+ snapshot.opacity = 0.0;
398+ visible = false;
399+ }
400 }
401 }

Subscribers

People subscribed via source and target branches