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

Proposed by Florian Boucault
Status: Merged
Approved by: Florian Boucault
Approved revision: 591
Merged at revision: 590
Proposed branch: lp:~fboucault/camera-app/desktop_better_responsiveness
Merge into: lp:camera-app
Diff against target: 368 lines (+160/-38)
8 files modified
PhotogridView.qml (+11/-10)
ResponsiveGridView.qml (+108/-0)
ViewFinderGeometry.qml (+6/-2)
ViewFinderView.qml (+1/-0)
camera-app.qml (+26/-8)
cameraapplication.cpp (+5/-15)
cameraapplication.h (+2/-2)
tests/autopilot/camera_app/emulators/main_window.py (+1/-1)
To merge this branch: bzr merge lp:~fboucault/camera-app/desktop_better_responsiveness
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Ubuntu Phablet Team Pending
Review via email: mp+275721@code.launchpad.net

Commit message

Desktop convergence fixes:
- Fix viewfinder positioning.
- Resize window to follow viewfinder's aspect ratio.
- Made photo grid responsive.

To post a comment you must log in.
588. By Florian Boucault

Added missing properties

589. By Florian Boucault

Reposition content appropriately when resizing window.

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)
590. By Florian Boucault

Fix viewfinder positioning properly.

591. By Florian Boucault

Fix positionContentAtRatio in INVERTED_LANDSCAPE

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'PhotogridView.qml'
2--- PhotogridView.qml 2015-10-22 12:24:01 +0000
3+++ PhotogridView.qml 2015-10-27 10:36:20 +0000
4@@ -25,7 +25,6 @@
5 Item {
6 id: photogridView
7
8- property int itemsPerRow: 3
9 property var model
10 signal photoClicked(int index)
11 signal photoPressAndHold(int index)
12@@ -63,7 +62,7 @@
13 function exit() {
14 }
15
16- GridView {
17+ ResponsiveGridView {
18 id: gridView
19 anchors.fill: parent
20 // FIXME: prevent the header from overlapping the beginning of the grid
21@@ -73,7 +72,7 @@
22 width: gridView.width
23 height: headerHeight
24 }
25-
26+
27 Component.onCompleted: {
28 // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition
29 // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration
30@@ -82,16 +81,18 @@
31 flickDeceleration = flickDeceleration * scaleFactor;
32 }
33
34- cellWidth: width / photogridView.itemsPerRow
35- cellHeight: cellWidth
36+ minimumHorizontalSpacing: units.dp(2)
37+ maximumNumberOfColumns: 100
38+ delegateWidth: units.gu(13)
39+ delegateHeight: units.gu(13)
40
41 model: photogridView.model
42 delegate: Item {
43 id: cellDelegate
44 objectName: "mediaItem" + index
45
46- width: GridView.view.cellWidth
47- height: GridView.view.cellHeight
48+ width: gridView.cellWidth
49+ height: gridView.cellHeight
50
51 property bool isVideo: MimeTypeMapper.mimeTypeToContentType(fileType) === ContentType.Videos
52
53@@ -100,13 +101,13 @@
54 property real margin: units.dp(2)
55 anchors {
56 top: parent.top
57- topMargin: index < photogridView.itemsPerRow ? 0 : margin/2
58+ topMargin: index < photogridView.columns ? 0 : margin/2
59 bottom: parent.bottom
60 bottomMargin: margin/2
61 left: parent.left
62- leftMargin: index % photogridView.itemsPerRow == 0 ? 0 : margin/2
63+ leftMargin: index % photogridView.columns == 0 ? 0 : margin/2
64 right: parent.right
65- rightMargin: index % photogridView.itemsPerRow == photogridView.itemsPerRow - 1 ? 0 : margin/2
66+ rightMargin: index % photogridView.columns == photogridView.columns - 1 ? 0 : margin/2
67 }
68
69 asynchronous: true
70
71=== added file 'ResponsiveGridView.qml'
72--- ResponsiveGridView.qml 1970-01-01 00:00:00 +0000
73+++ ResponsiveGridView.qml 2015-10-27 10:36:20 +0000
74@@ -0,0 +1,108 @@
75+/*
76+ * Copyright (C) 2013 Canonical, Ltd.
77+ *
78+ * This program is free software; you can redistribute it and/or modify
79+ * it under the terms of the GNU General Public License as published by
80+ * the Free Software Foundation; version 3.
81+ *
82+ * This program is distributed in the hope that it will be useful,
83+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
84+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85+ * GNU General Public License for more details.
86+ *
87+ * You should have received a copy of the GNU General Public License
88+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
89+ */
90+
91+import QtQuick 2.3
92+import Ubuntu.Components 0.1
93+
94+// FIXME: this is a copy of Unity8's ResponsiveGridView
95+
96+/*
97+ Essentially a GridView where you can specify the maximum number of columns it can have.
98+ */
99+Item {
100+ property int minimumHorizontalSpacing: units.gu(0.5)
101+ // property int minimumNumberOfColumns: 2 // FIXME: not implemented
102+ property int maximumNumberOfColumns: 6
103+ readonly property int columns: gridView.columns
104+ property alias verticalSpacing: gridView.verticalSpacing
105+ readonly property alias margins: gridView.margin
106+ property int delegateWidth
107+ property int delegateHeight
108+ property alias model: gridView.model
109+ property alias delegate: gridView.delegate
110+ readonly property int cellWidth: gridView.cellWidth
111+ readonly property int cellHeight: gridView.cellHeight
112+ readonly property int totalContentHeight: {
113+ if (gridView.model) {
114+ return contentHeightForRows(Math.ceil(gridView.model.count / columns), cellHeight)
115+ } else {
116+ return 0;
117+ }
118+ }
119+ property alias interactive: gridView.interactive
120+ readonly property alias flicking: gridView.flicking
121+ readonly property alias moving: gridView.moving
122+ readonly property alias pressDelay: gridView.pressDelay
123+ readonly property alias originY: gridView.originY
124+ property alias displayMarginBeginning: gridView.displayMarginBeginning
125+ property alias displayMarginEnd: gridView.displayMarginEnd
126+ property alias highlightIndex: gridView.highlightIndex
127+ property alias cacheBuffer: gridView.cacheBuffer
128+ readonly property alias currentItem: gridView.currentItem
129+ property alias header: gridView.header
130+ property alias maximumFlickVelocity: gridView.maximumFlickVelocity
131+ property alias flickDeceleration: gridView.flickDeceleration
132+
133+ function contentHeightForRows(rows, height) {
134+ return rows * height
135+ }
136+
137+ function positionViewAtIndex(index, mode) {
138+ gridView.positionViewAtIndex(index, mode);
139+ }
140+
141+ GridView {
142+ id: gridView
143+ objectName: "responsiveGridViewGrid"
144+ anchors {
145+ fill: parent
146+ leftMargin: margin/2
147+ rightMargin: margin/2
148+ }
149+ clip: parent.height != totalContentHeight
150+
151+ function pixelToGU(value) {
152+ return Math.floor(value / units.gu(1));
153+ }
154+
155+ function spacingForColumns(columns) {
156+ // spacing between columns as an integer number of GU, the remainder goes in the margins
157+ var spacingGU = pixelToGU(allocatableHorizontalSpace / columns);
158+ return units.gu(spacingGU);
159+ }
160+
161+ function columnsForSpacing(spacing) {
162+ // minimum margin is half of the spacing
163+ return Math.max(1, Math.floor(parent.width / (delegateWidth + spacing)));
164+ }
165+
166+ property real allocatableHorizontalSpace: parent.width - columns * delegateWidth
167+ property int columns: Math.min(columnsForSpacing(minimumHorizontalSpacing), maximumNumberOfColumns)
168+ property real horizontalSpacing: spacingForColumns(columns)
169+ property real verticalSpacing: horizontalSpacing
170+ property int margin: allocatableHorizontalSpace - columns * horizontalSpacing
171+ property int highlightIndex: -1
172+
173+ cellWidth: delegateWidth + horizontalSpacing
174+ cellHeight: delegateHeight + verticalSpacing
175+
176+ onHighlightIndexChanged: {
177+ if (highlightIndex != -1) {
178+ currentIndex = highlightIndex
179+ }
180+ }
181+ }
182+}
183
184=== modified file 'ViewFinderGeometry.qml'
185--- ViewFinderGeometry.qml 2015-10-22 12:21:14 +0000
186+++ ViewFinderGeometry.qml 2015-10-27 10:36:20 +0000
187@@ -18,6 +18,8 @@
188
189 Item {
190 property size cameraResolution;
191+ property bool cameraResolutionValid: cameraResolution.width != -1
192+ && cameraResolution.height != -1
193 property int viewFinderHeight;
194 property int viewFinderWidth;
195 property int viewFinderOrientation;
196@@ -30,6 +32,8 @@
197 property real widthScale: viewFinderWidth / __cameraWidth
198 property real heightScale: viewFinderHeight / __cameraHeight
199
200- width: (widthScale <= heightScale) ? viewFinderWidth : __cameraWidth * heightScale
201- height: (widthScale <= heightScale) ? __cameraHeight * widthScale : viewFinderHeight
202+ width: cameraResolutionValid ? ((widthScale <= heightScale) ? viewFinderWidth : __cameraWidth * heightScale)
203+ : viewFinderWidth
204+ height: cameraResolutionValid ? ((widthScale <= heightScale) ? __cameraHeight * widthScale : viewFinderHeight)
205+ : viewFinderHeight
206 }
207
208=== modified file 'ViewFinderView.qml'
209--- ViewFinderView.qml 2015-10-22 12:21:14 +0000
210+++ ViewFinderView.qml 2015-10-27 10:36:20 +0000
211@@ -29,6 +29,7 @@
212 property bool touchAcquired: viewFinderOverlay.touchAcquired || camera.videoRecorder.recorderState == CameraRecorder.RecordingState
213 property bool inView
214 property alias captureMode: camera.captureMode
215+ property real aspectRatio: viewFinder.sourceRect.width / viewFinder.sourceRect.height
216 signal photoTaken(string filePath)
217 signal videoShot(string filePath)
218
219
220=== modified file 'camera-app.qml'
221--- camera-app.qml 2015-10-26 13:19:14 +0000
222+++ camera-app.qml 2015-10-27 10:36:20 +0000
223@@ -23,13 +23,13 @@
224 import Ubuntu.Content 0.1
225 import CameraApp 0.1
226
227-Item {
228+Window {
229 id: main
230 objectName: "main"
231- width: units.gu(40)
232- height: units.gu(71)
233-// width: application.desktopMode ? units.gu(120) : (Screen.primaryOrientation === Qt.PortraitOrientation ? units.gu(40) : units.gu(80))
234-// height: application.desktopMode ? units.gu(60) : (Screen.primaryOrientation === Qt.PortraitOrientation ? units.gu(80) : units.gu(40))
235+ width: height * viewFinderView.aspectRatio
236+ height: units.gu(80)
237+ color: "black"
238+ title: "Camera"
239
240 UnityActions.ActionManager {
241 actions: [
242@@ -63,6 +63,11 @@
243
244 Component.onCompleted: {
245 i18n.domain = "camera-app";
246+ if (!application.desktopMode) {
247+ main.showFullScreen();
248+ } else {
249+ main.show();
250+ }
251 }
252
253
254@@ -91,7 +96,7 @@
255 galleryView.y = 0;
256 viewFinderView.x = 0;
257 viewFinderView.y = 0;
258- viewSwitcher.contentX = viewSwitcher.ratio * viewSwitcher.contentWidth;
259+ viewSwitcher.positionContentAtRatio(viewSwitcher.ratio)
260 viewSwitcher.ratio = Qt.binding(function() { return viewSwitcher.contentX / viewSwitcher.contentWidth });
261 }
262 }
263@@ -107,7 +112,7 @@
264 galleryView.y = Qt.binding(function() { return viewFinderView.height + viewSwitcher.panesMargin });
265 viewFinderView.x = 0;
266 viewFinderView.y = 0;
267- viewSwitcher.contentY = viewSwitcher.ratio * viewSwitcher.contentHeight;
268+ viewSwitcher.positionContentAtRatio(viewSwitcher.ratio)
269 viewSwitcher.ratio = Qt.binding(function() { return viewSwitcher.contentY / viewSwitcher.contentHeight });
270 }
271 }
272@@ -123,7 +128,7 @@
273 galleryView.y = 0;
274 viewFinderView.x = 0;
275 viewFinderView.y = Qt.binding(function() { return galleryView.height + viewSwitcher.panesMargin });
276- viewSwitcher.contentY = (0.5 - viewSwitcher.ratio) * viewSwitcher.contentHeight;
277+ viewSwitcher.positionContentAtRatio(viewSwitcher.ratio)
278 viewSwitcher.ratio = Qt.binding(function() { return 0.5 - viewSwitcher.contentY / viewSwitcher.contentHeight });
279 }
280 }
281@@ -177,6 +182,19 @@
282 }
283 }
284
285+ function positionContentAtRatio(ratio) {
286+ if (state == "PORTRAIT") {
287+ viewSwitcher.contentX = ratio * viewSwitcher.contentWidth;
288+ } else if (state == "LANDSCAPE") {
289+ viewSwitcher.contentY = ratio * viewSwitcher.contentHeight;
290+ } else if (state == "INVERTED_LANDSCAPE") {
291+ viewSwitcher.contentY = (0.5 - ratio) * viewSwitcher.contentHeight;
292+ }
293+ }
294+
295+ onContentWidthChanged: positionContentAtRatio(viewSwitcher.ratio)
296+ onContentHeightChanged: positionContentAtRatio(viewSwitcher.ratio)
297+
298 onMovementEnded: {
299 // go to a rest position as soon as user stops interacting with the Flickable
300 settle();
301
302=== modified file 'cameraapplication.cpp'
303--- cameraapplication.cpp 2015-01-23 19:38:32 +0000
304+++ cameraapplication.cpp 2015-10-27 10:36:20 +0000
305@@ -85,23 +85,13 @@
306 Qt::InvertedPortraitOrientation |
307 Qt::InvertedLandscapeOrientation);
308
309- m_view.reset(new QQuickView());
310- m_view->setResizeMode(QQuickView::SizeRootObjectToView);
311- m_view->setTitle("Camera");
312- m_view->setColor("black");
313- m_view->rootContext()->setContextProperty("application", this);
314- m_view->engine()->setBaseUrl(QUrl::fromLocalFile(cameraAppDirectory()));
315- m_view->engine()->addImportPath(cameraAppImportDirectory());
316+ m_engine.reset(new QQmlApplicationEngine());
317+ m_engine->rootContext()->setContextProperty("application", this);
318+ m_engine->setBaseUrl(QUrl::fromLocalFile(cameraAppDirectory()));
319+ m_engine->addImportPath(cameraAppImportDirectory());
320 qDebug() << "Import path added" << cameraAppImportDirectory();
321 qDebug() << "Camera app directory" << cameraAppDirectory();
322- QObject::connect(m_view->engine(), SIGNAL(quit()), this, SLOT(quit()));
323- m_view->setSource(QUrl::fromLocalFile(sourceQml()));
324-
325- //run fullscreen if specified at command line or not in DESKTOP_MODE (i.e. on a device)
326- if (arguments().contains(QLatin1String("--fullscreen")) || !isDesktopMode())
327- m_view->showFullScreen();
328- else
329- m_view->show();
330+ m_engine->load(QUrl::fromLocalFile(sourceQml()));
331
332 return true;
333 }
334
335=== modified file 'cameraapplication.h'
336--- cameraapplication.h 2014-11-13 09:39:37 +0000
337+++ cameraapplication.h 2015-10-27 10:36:20 +0000
338@@ -20,7 +20,7 @@
339 #ifndef CAMERAAPPLICATION_H
340 #define CAMERAAPPLICATION_H
341
342-#include <QtQuick/QQuickView>
343+#include <QtQml/QQmlApplicationEngine>
344 #include <QGuiApplication>
345
346 class QDate;
347@@ -54,7 +54,7 @@
348 void removableStoragePresentChanged();
349
350 private:
351- QScopedPointer<QQuickView> m_view;
352+ QScopedPointer<QQmlApplicationEngine> m_engine;
353 };
354
355 #endif // CAMERAAPPLICATION_H
356
357=== modified file 'tests/autopilot/camera_app/emulators/main_window.py'
358--- tests/autopilot/camera_app/emulators/main_window.py 2015-05-15 07:40:37 +0000
359+++ tests/autopilot/camera_app/emulators/main_window.py 2015-10-27 10:36:20 +0000
360@@ -18,7 +18,7 @@
361
362 def get_qml_view(self):
363 """Get the main QML view"""
364- return self.app.wait_select_single("QQuickView")
365+ return self.get_root()
366
367 def get_root(self):
368 """Returns the root QML Item"""

Subscribers

People subscribed via source and target branches