Merge lp:~rpadovani/reminders-app/bottomEdge into lp:reminders-app
- bottomEdge
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Nicholas Skaggs |
Approved revision: | 198 |
Merged at revision: | 241 |
Proposed branch: | lp:~rpadovani/reminders-app/bottomEdge |
Merge into: | lp:reminders-app |
Diff against target: |
525 lines (+404/-6) 6 files modified
src/app/qml/components/PageWithBottomEdge.qml (+376/-0) src/app/qml/reminders.qml (+5/-1) src/app/qml/ui/EditNotePage.qml (+1/-0) src/app/qml/ui/EditNoteView.qml (+3/-0) src/app/qml/ui/NotebooksPage.qml (+4/-2) src/app/qml/ui/NotesPage.qml (+15/-3) |
To merge this branch: | bzr merge lp:~rpadovani/reminders-app/bottomEdge |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Michael Zanetti (community) | Approve | ||
Review via email: mp+231118@code.launchpad.net |
Commit message
Implemented bottomEdge
Description of the change
Added bottomEdge in phone mode: to avoid an annoying flickering when users open a notebook, the bottomEdge is loaded only after notes are loaded (only for notebooks page).
The bottomEdge component has been modified for our purpose
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:197
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Michael Zanetti (mzanetti) wrote : | # |
small nitpick inline (2 comments). Works reasonably well.
Riccardo Padovani (rpadovani) wrote : | # |
Thanks, improved
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:198
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Pope πΊπ§π± π¦ (popey) wrote : | # |
E: Release 'utopic' for 'qtdeclarative5
E: Release 'utopic' for 'qtdeclarative5
E: Release 'utopic' for 'qtdeclarative5
E: Release 'utopic' for 'ubuntu-
E: Release 'utopic' for 'ubuntu-
Looks oddly broken?
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:198
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Francis Ginther (fginther) wrote : | # |
> E: Release 'utopic' for 'qtdeclarative5
> not found
> E: Release 'utopic' for 'qtdeclarative5
> E: Release 'utopic' for 'qtdeclarative5
> E: Release 'utopic' for 'ubuntu-
> E: Release 'utopic' for 'ubuntu-
>
> Looks oddly broken?
This appears to be fallout from the recent testing issues.
Preview Diff
1 | === added file 'src/app/qml/components/PageWithBottomEdge.qml' |
2 | --- src/app/qml/components/PageWithBottomEdge.qml 1970-01-01 00:00:00 +0000 |
3 | +++ src/app/qml/components/PageWithBottomEdge.qml 2014-09-03 16:57:24 +0000 |
4 | @@ -0,0 +1,376 @@ |
5 | +/* |
6 | + * Copyright (C) 2014 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 | +/* |
22 | + Example: |
23 | + |
24 | + MainView { |
25 | + objectName: "mainView" |
26 | + |
27 | + applicationName: "com.ubuntu.developer.boiko.bottomedge" |
28 | + |
29 | + width: units.gu(100) |
30 | + height: units.gu(75) |
31 | + |
32 | + Component { |
33 | + id: pageComponent |
34 | + |
35 | + PageWithBottomEdge { |
36 | + id: mainPage |
37 | + title: i18n.tr("Main Page") |
38 | + |
39 | + Rectangle { |
40 | + anchors.fill: parent |
41 | + color: "white" |
42 | + } |
43 | + |
44 | + bottomEdgePageComponent: Page { |
45 | + title: "Contents" |
46 | + anchors.fill: parent |
47 | + //anchors.topMargin: contentsPage.flickable.contentY |
48 | + |
49 | + ListView { |
50 | + anchors.fill: parent |
51 | + model: 50 |
52 | + delegate: ListItems.Standard { |
53 | + text: "One Content Item: " + index |
54 | + } |
55 | + } |
56 | + } |
57 | + bottomEdgeTitle: i18n.tr("Bottom edge action") |
58 | + } |
59 | + } |
60 | + |
61 | + PageStack { |
62 | + id: stack |
63 | + Component.onCompleted: stack.push(pageComponent) |
64 | + } |
65 | + } |
66 | + |
67 | +*/ |
68 | + |
69 | +import QtQuick 2.0 |
70 | +import Ubuntu.Components 0.1 |
71 | +import Evernote 0.1 |
72 | + |
73 | +Page { |
74 | + id: page |
75 | + |
76 | + property alias bottomEdgePageComponent: edgeLoader.sourceComponent |
77 | + property alias bottomEdgePageSource: edgeLoader.source |
78 | + property alias bottomEdgeTitle: tipLabel.text |
79 | + property alias bottomEdgeEnabled: bottomEdge.visible |
80 | + property int bottomEdgeExpandThreshold: page.height * 0.2 |
81 | + property int bottomEdgeExposedArea: bottomEdge.state !== "expanded" ? (page.height - bottomEdge.y - bottomEdge.tipHeight) : _areaWhenExpanded |
82 | + property bool reloadBottomEdgePage: true |
83 | + |
84 | + readonly property alias bottomEdgePage: edgeLoader.item |
85 | + readonly property bool isReady: (tip.opacity === 0.0) |
86 | + readonly property bool isCollapsed: (tip.opacity === 1.0) |
87 | + readonly property bool bottomEdgePageLoaded: (edgeLoader.status == Loader.Ready) |
88 | + property var temporaryProperties: null |
89 | + |
90 | + property bool bottomEdgeLabelVisible: true |
91 | + |
92 | + property bool _showEdgePageWhenReady: false |
93 | + property int _areaWhenExpanded: 0 |
94 | + |
95 | + signal bottomEdgeReleased() |
96 | + signal bottomEdgeDismissed() |
97 | + |
98 | + |
99 | + function showBottomEdgePage(source, properties) |
100 | + { |
101 | + edgeLoader.setSource(source, properties) |
102 | + temporaryProperties = properties |
103 | + _showEdgePageWhenReady = true |
104 | + } |
105 | + |
106 | + function setBottomEdgePage(source, properties) |
107 | + { |
108 | + edgeLoader.setSource(source, properties) |
109 | + } |
110 | + |
111 | + function _pushPage() |
112 | + { |
113 | + if (edgeLoader.status === Loader.Ready) { |
114 | + edgeLoader.item.active = true |
115 | + |
116 | + NotesStore.createNote("Untitled", filter); |
117 | + |
118 | + if (edgeLoader.item.flickable) { |
119 | + edgeLoader.item.flickable.contentY = -page.header.height |
120 | + edgeLoader.item.flickable.returnToBounds() |
121 | + } |
122 | + if (edgeLoader.item.ready) |
123 | + edgeLoader.item.ready() |
124 | + } |
125 | + } |
126 | + |
127 | + |
128 | + Component.onCompleted: { |
129 | + // avoid a binding on the expanded height value |
130 | + var expandedHeight = height; |
131 | + _areaWhenExpanded = expandedHeight; |
132 | + } |
133 | + |
134 | + onActiveChanged: { |
135 | + if (active) { |
136 | + bottomEdge.state = "collapsed" |
137 | + } |
138 | + } |
139 | + |
140 | + onBottomEdgePageLoadedChanged: { |
141 | + if (_showEdgePageWhenReady && bottomEdgePageLoaded) { |
142 | + bottomEdge.state = "expanded" |
143 | + _showEdgePageWhenReady = false |
144 | + } |
145 | + } |
146 | + |
147 | + Rectangle { |
148 | + id: bgVisual |
149 | + |
150 | + visible: bottomEdgeLabelVisible |
151 | + |
152 | + color: "black" |
153 | + anchors.fill: page |
154 | + opacity: 0.7 * ((page.height - bottomEdge.y) / page.height) |
155 | + z: 1 |
156 | + } |
157 | + |
158 | + Rectangle { |
159 | + id: bottomEdge |
160 | + objectName: "bottomEdge" |
161 | + |
162 | + readonly property int tipHeight: units.gu(3) |
163 | + readonly property int pageStartY: 0 |
164 | + |
165 | + visible: bottomEdgeLabelVisible |
166 | + |
167 | + z: 1 |
168 | + color: Theme.palette.normal.background |
169 | + parent: page |
170 | + anchors { |
171 | + left: parent.left |
172 | + right: parent.right |
173 | + } |
174 | + height: page.height |
175 | + y: height |
176 | + |
177 | + Rectangle { |
178 | + id: shadow |
179 | + |
180 | + anchors { |
181 | + left: parent.left |
182 | + right: parent.right |
183 | + } |
184 | + height: units.gu(1) |
185 | + y: -height |
186 | + opacity: 0.0 |
187 | + gradient: Gradient { |
188 | + GradientStop { position: 0.0; color: "transparent" } |
189 | + GradientStop { position: 1.0; color: Qt.rgba(0, 0, 0, 0.2) } |
190 | + } |
191 | + } |
192 | + |
193 | + Item { |
194 | + id: tipContainer |
195 | + objectName: "bottomEdgeTip" |
196 | + |
197 | + width: childrenRect.width |
198 | + height: bottomEdge.tipHeight |
199 | + clip: true |
200 | + y: -bottomEdge.tipHeight |
201 | + anchors.horizontalCenter: parent.horizontalCenter |
202 | + |
203 | + UbuntuShape { |
204 | + id: tip |
205 | + |
206 | + width: tipLabel.paintedWidth + units.gu(6) |
207 | + height: bottomEdge.tipHeight + units.gu(1) |
208 | + color: Theme.palette.normal.overlay |
209 | + Label { |
210 | + id: tipLabel |
211 | + |
212 | + anchors { |
213 | + top: parent.top |
214 | + left: parent.left |
215 | + right: parent.right |
216 | + } |
217 | + height: bottomEdge.tipHeight |
218 | + verticalAlignment: Text.AlignVCenter |
219 | + horizontalAlignment: Text.AlignHCenter |
220 | + } |
221 | + } |
222 | + } |
223 | + |
224 | + MouseArea { |
225 | + preventStealing: true |
226 | + drag.axis: Drag.YAxis |
227 | + drag.target: bottomEdge |
228 | + drag.minimumY: bottomEdge.pageStartY |
229 | + drag.maximumY: page.height |
230 | + |
231 | + anchors { |
232 | + left: parent.left |
233 | + right: parent.right |
234 | + } |
235 | + height: bottomEdge.tipHeight |
236 | + y: -height |
237 | + |
238 | + onReleased: { |
239 | + page.bottomEdgeReleased() |
240 | + if (bottomEdge.y < (page.height - bottomEdgeExpandThreshold - bottomEdge.tipHeight)) { |
241 | + bottomEdge.state = "expanded" |
242 | + } else { |
243 | + bottomEdge.state = "collapsed" |
244 | + bottomEdge.y = bottomEdge.height |
245 | + } |
246 | + } |
247 | + |
248 | + onPressed: { |
249 | + bottomEdge.state = "floating" |
250 | + bottomEdge.y -= bottomEdge.tipHeight |
251 | + } |
252 | + } |
253 | + |
254 | + Behavior on y { |
255 | + UbuntuNumberAnimation {} |
256 | + } |
257 | + |
258 | + state: "collapsed" |
259 | + states: [ |
260 | + State { |
261 | + name: "collapsed" |
262 | + PropertyChanges { |
263 | + target: bottomEdge |
264 | + y: bottomEdge.height |
265 | + } |
266 | + PropertyChanges { |
267 | + target: tip |
268 | + opacity: 1.0 |
269 | + } |
270 | + }, |
271 | + State { |
272 | + name: "expanded" |
273 | + PropertyChanges { |
274 | + target: bottomEdge |
275 | + y: bottomEdge.pageStartY |
276 | + } |
277 | + PropertyChanges { |
278 | + target: tip |
279 | + opacity: 0.0 |
280 | + } |
281 | + }, |
282 | + State { |
283 | + name: "floating" |
284 | + PropertyChanges { |
285 | + target: shadow |
286 | + opacity: 1.0 |
287 | + } |
288 | + } |
289 | + ] |
290 | + |
291 | + transitions: [ |
292 | + Transition { |
293 | + to: "expanded" |
294 | + SequentialAnimation { |
295 | + UbuntuNumberAnimation { |
296 | + targets: [bottomEdge,tip] |
297 | + properties: "y,opacity" |
298 | + duration: UbuntuAnimation.SlowDuration |
299 | + } |
300 | + ScriptAction { |
301 | + script: page._pushPage() |
302 | + } |
303 | + } |
304 | + }, |
305 | + Transition { |
306 | + from: "expanded" |
307 | + to: "collapsed" |
308 | + SequentialAnimation { |
309 | + ScriptAction { |
310 | + script: { |
311 | + edgeLoader.item.parent = edgeLoader |
312 | + edgeLoader.item.anchors.fill = edgeLoader |
313 | + edgeLoader.item.active = false |
314 | + } |
315 | + } |
316 | + UbuntuNumberAnimation { |
317 | + targets: [bottomEdge,tip] |
318 | + properties: "y,opacity" |
319 | + duration: UbuntuAnimation.SlowDuration |
320 | + } |
321 | + ScriptAction { |
322 | + script: { |
323 | + // destroy current bottom page |
324 | + if (page.reloadBottomEdgePage) { |
325 | + edgeLoader.active = false |
326 | + // remove properties from old instance |
327 | + if (edgeLoader.source !== "") { |
328 | + var properties = {} |
329 | + if (temporaryProperties !== null) { |
330 | + properties = temporaryProperties |
331 | + temporaryProperties = null |
332 | + } |
333 | + |
334 | + edgeLoader.setSource(edgeLoader.source, properties) |
335 | + } |
336 | + } |
337 | + |
338 | + // notify |
339 | + page.bottomEdgeDismissed() |
340 | + |
341 | + // load a new bottom page in memory |
342 | + edgeLoader.active = true |
343 | + } |
344 | + } |
345 | + } |
346 | + }, |
347 | + Transition { |
348 | + from: "floating" |
349 | + to: "collapsed" |
350 | + UbuntuNumberAnimation { |
351 | + targets: [bottomEdge,tip] |
352 | + properties: "y,opacity" |
353 | + } |
354 | + } |
355 | + ] |
356 | + |
357 | + Loader { |
358 | + id: edgeLoader |
359 | + |
360 | + z: 1 |
361 | + active: true |
362 | + asynchronous: true |
363 | + anchors.fill: parent |
364 | + |
365 | + //WORKAROUND: The SDK move the page contents down to allocate space for the header we need to avoid that during the page dragging |
366 | + Binding { |
367 | + target: edgeLoader |
368 | + property: "anchors.topMargin" |
369 | + value: edgeLoader.item && edgeLoader.item.flickable ? edgeLoader.item.flickable.contentY : 0 |
370 | + when: (edgeLoader.status === Loader.Ready && !page.isReady) |
371 | + } |
372 | + |
373 | + onLoaded: { |
374 | + if (page.isReady && edgeLoader.item.active != true) { |
375 | + page._pushPage() |
376 | + } |
377 | + } |
378 | + } |
379 | + } |
380 | +} |
381 | |
382 | === modified file 'src/app/qml/reminders.qml' |
383 | --- src/app/qml/reminders.qml 2014-08-06 09:44:18 +0000 |
384 | +++ src/app/qml/reminders.qml 2014-09-03 16:57:24 +0000 |
385 | @@ -207,6 +207,8 @@ |
386 | page: NotesPage { |
387 | id: notesPage |
388 | |
389 | + narrowMode: root.narrowMode |
390 | + |
391 | onEditNote: { |
392 | root.switchToEditMode(note) |
393 | } |
394 | @@ -236,11 +238,13 @@ |
395 | page: NotebooksPage { |
396 | id: notebooksPage |
397 | |
398 | + narrowMode: root.narrowMode |
399 | + |
400 | onOpenNotebook: { |
401 | var component = Qt.createComponent(Qt.resolvedUrl("ui/NotesPage.qml")) |
402 | var page = component.createObject(); |
403 | print("opening note page for notebook", notebookGuid) |
404 | - pagestack.push(page, {title: title, filter: notebookGuid}); |
405 | + pagestack.push(page, {title: title, filter: notebookGuid, narrowMode: narrowMode}); |
406 | page.selectedNoteChanged.connect(function() { |
407 | print("foo", page.selectedNote); |
408 | if (page.selectedNote) { |
409 | |
410 | === modified file 'src/app/qml/ui/EditNotePage.qml' |
411 | --- src/app/qml/ui/EditNotePage.qml 2014-05-07 16:34:06 +0000 |
412 | +++ src/app/qml/ui/EditNotePage.qml 2014-09-03 16:57:24 +0000 |
413 | @@ -25,6 +25,7 @@ |
414 | Page { |
415 | id: root |
416 | property alias note: editNoteView.note |
417 | + property alias isBottomEdge: editNoteView.isBottomEdge |
418 | |
419 | signal exitEditMode(var note) |
420 | |
421 | |
422 | === modified file 'src/app/qml/ui/EditNoteView.qml' |
423 | --- src/app/qml/ui/EditNoteView.qml 2014-07-14 13:40:24 +0000 |
424 | +++ src/app/qml/ui/EditNoteView.qml 2014-09-03 16:57:24 +0000 |
425 | @@ -26,6 +26,7 @@ |
426 | Item { |
427 | id: root |
428 | property var note |
429 | + property bool isBottomEdge: false |
430 | |
431 | onNoteChanged: { |
432 | for (var i = 0; i < notebookSelector.model.count; i++) { |
433 | @@ -74,6 +75,7 @@ |
434 | spacing: units.gu(1) |
435 | |
436 | Row { |
437 | + visible: !root.isBottomEdge |
438 | anchors { left: parent.left; right: parent.right } |
439 | height: units.gu(5) |
440 | spacing: units.gu(2) |
441 | @@ -126,6 +128,7 @@ |
442 | } |
443 | |
444 | Divider { |
445 | + visible: !root.isBottomEdge |
446 | anchors { leftMargin: -units.gu(2); rightMargin: -units.gu(2) } |
447 | height: units.gu(2) |
448 | } |
449 | |
450 | === modified file 'src/app/qml/ui/NotebooksPage.qml' |
451 | --- src/app/qml/ui/NotebooksPage.qml 2014-06-24 00:01:51 +0000 |
452 | +++ src/app/qml/ui/NotebooksPage.qml 2014-09-03 16:57:24 +0000 |
453 | @@ -26,7 +26,9 @@ |
454 | id: root |
455 | objectName: 'notebooksPage' |
456 | |
457 | - signal openNotebook(string title, string notebookGuid) |
458 | + property bool narrowMode |
459 | + |
460 | + signal openNotebook(string title, string notebookGuid, bool narrowMode) |
461 | |
462 | onActiveChanged: { |
463 | if (active) { |
464 | @@ -135,7 +137,7 @@ |
465 | delegate: NotebooksDelegate { |
466 | onClicked: { |
467 | print("selected notebook:", model.guid) |
468 | - root.openNotebook(name, model.guid) |
469 | + root.openNotebook(name, model.guid, narrowMode) |
470 | } |
471 | } |
472 | |
473 | |
474 | === modified file 'src/app/qml/ui/NotesPage.qml' |
475 | --- src/app/qml/ui/NotesPage.qml 2014-08-14 17:17:05 +0000 |
476 | +++ src/app/qml/ui/NotesPage.qml 2014-09-03 16:57:24 +0000 |
477 | @@ -23,13 +23,24 @@ |
478 | import Evernote 0.1 |
479 | import "../components" |
480 | |
481 | -Page { |
482 | +PageWithBottomEdge { |
483 | id: root |
484 | |
485 | property var selectedNote: null |
486 | + property bool narrowMode |
487 | |
488 | property alias filter: notes.filterNotebookGuid |
489 | |
490 | + // We enable bottomEdge only in narrowMode. |
491 | + // To avoid flashing when a notebook is loaded, we wait to have all notes |
492 | + // loaded, but only in notebook view (when a filter is set), not in notes |
493 | + // page, because there isn't he flashing. |
494 | + bottomEdgeLabelVisible: narrowMode && (!notes.filterNotebookGuid || !notes.loading) |
495 | + bottomEdgeTitle: i18n.tr("Add note") |
496 | + bottomEdgePageComponent: EditNotePage { |
497 | + isBottomEdge: true; |
498 | + } |
499 | + |
500 | signal openSearch() |
501 | signal editNote(var note) |
502 | |
503 | @@ -42,11 +53,12 @@ |
504 | tools: ToolbarItems { |
505 | ToolbarButton { |
506 | action: Action { |
507 | + visible: !narrowMode |
508 | text: i18n.tr("Add note") |
509 | iconName: "add" |
510 | onTriggered: { |
511 | NotesStore.createNote(i18n.tr("Untitled"), filter); |
512 | - } |
513 | + } |
514 | } |
515 | } |
516 | |
517 | @@ -118,7 +130,7 @@ |
518 | } |
519 | } |
520 | } |
521 | - } |
522 | + } |
523 | |
524 | Notes { |
525 | id: notes |
FAILED: Continuous integration, rev:196 91.189. 93.70:8080/ job/reminders- app-ci/ 481/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic/ 1578/console 91.189. 93.70:8080/ job/reminders- app-utopic- amd64-ci/ 177/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/reminders- app-ci/ 481/rebuild
http://