Merge lp:~martin-borho/ubuntu-weather-app/edit-locations-in-sheets into lp:ubuntu-weather-app/obsolete.trunk

Proposed by Martin Borho on 2013-07-19
Status: Merged
Approved by: David Planella on 2013-07-21
Approved revision: 72
Merged at revision: 71
Proposed branch: lp:~martin-borho/ubuntu-weather-app/edit-locations-in-sheets
Merge into: lp:ubuntu-weather-app/obsolete.trunk
Diff against target: 1291 lines (+528/-442)
13 files modified
components/AddLocationPage.qml (+0/-114)
components/AddLocationSheet.qml (+134/-0)
components/CurrentWeather.qml (+6/-1)
components/DateComponent.qml (+3/-2)
components/DayWeatherComponent.qml (+4/-1)
components/LocationManagerPage.qml (+0/-182)
components/LocationManagerSheet.qml (+228/-0)
components/LocationTab.qml (+48/-56)
components/SettingsSheet.qml (+2/-2)
tests/autopilot/ubuntu_weather_app/tests/__init__.py (+9/-0)
tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py (+61/-22)
tests/autopilot/ubuntu_weather_app/tests/test_settings.py (+5/-13)
ubuntu-weather-app.qml (+28/-49)
To merge this branch: bzr merge lp:~martin-borho/ubuntu-weather-app/edit-locations-in-sheets
Reviewer Review Type Date Requested Status
David Planella 2013-07-19 Approve on 2013-07-21
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve on 2013-07-20
Review via email: mp+175815@code.launchpad.net

Commit message

LocationManager now implemented with Sheet components, PageStack removed, Suru gradient background added.

Description of the change

* LocationManager is now implemented with Sheet components, like discussed in Bug #1187314
* Flat navigation is used everywhere now, which means the tab header will slide away when a tab gets scrolled down (default behaviour). Solves Bug #1201094
* PageStack removed, since not needed anymore.
* Autopilot tests updated accordingly
* one ActivityIndicator removed
* Suru gradient background added

To post a comment you must log in.
71. By Martin Borho on 2013-07-20

autopilot settings tests now also uses SheetMixin

72. By Martin Borho on 2013-07-20

suru gradient background added

David Planella (dpm) wrote :

Nice work, thanks for updating the tests as well!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== removed file 'components/AddLocationPage.qml'
2--- components/AddLocationPage.qml 2013-07-16 08:25:05 +0000
3+++ components/AddLocationPage.qml 1970-01-01 00:00:00 +0000
4@@ -1,114 +0,0 @@
5-import QtQuick 2.0
6-import Ubuntu.Components 0.1
7-import Ubuntu.Components.ListItems 0.1 as ListItem
8-
9-Page {
10- id: addLocationPage
11- objectName: "AddLocationPage"
12- title: i18n.tr("Add city")
13- visible: false
14- tools: ToolbarItems{
15- locked: true
16- opened: true
17- back: ToolbarButton {
18- objectName: "BackButton"
19- iconSource: Qt.resolvedUrl("../resources/images/back@18.png")
20- text: i18n.tr("Back")
21- onTriggered: {
22- if(pageStack.depth === 3) pageStack.pop()
23- }
24- }
25- }
26-
27- WorkerScript {
28- id: searchWorker
29- source: "./WeatherApi.js"
30- onMessage: {
31- if(!messageObject.error) {
32- listView.visible = true
33- messageObject.result.locations.forEach(function(loc) {
34- citiesModel.append(loc);
35- noCityError.visible = false
36- });
37- } else {
38- console.log(messageObject.error.msg+" / "+messageObject.error.request.url)
39- }
40- if (!citiesModel.count) {
41- noCityError.visible = true
42- noCityError.text = i18n.tr("No location was found for ") + locationString.text
43- }
44- }
45- }
46-
47- function clear() {
48- locationString.text = '';
49- citiesModel.clear();
50- listView.visible = true;
51- }
52-
53- Rectangle {
54- id: searchInput
55- width:parent.width
56- height:units.gu(7)
57- color: "transparent"
58- TextField {
59- id: locationString
60- objectName: "SearchField"
61- width: parent.width-units.gu(2)
62- height:units.gu(5)
63- anchors.centerIn: parent
64- placeholderText: i18n.tr("Enter a city name")
65- hasClearButton: true
66- onAccepted: {
67- citiesModel.clear();
68- searchWorker.sendMessage({
69- action: "searchByName",
70- params: {name:locationString.text, units:"metric"}
71- })
72- }
73- }
74- }
75-
76- ListModel {
77- id: citiesModel
78- }
79-
80- Rectangle {
81- id: cityList;
82- anchors.top: searchInput.bottom
83- width: parent.width
84- height: units.gu(52)
85- color: "transparent"
86- Label {
87- id: noCityError
88- objectName: "noCityError"
89- visible: false
90- anchors.centerIn: parent;
91- font.pixelSize: 18
92- }
93-
94- ListView {
95- id: listView;
96- objectName: "SearchResultList"
97- visible: false
98- clip: true;
99- anchors.fill: parent;
100- model: citiesModel;
101- delegate: ListItem.Standard {
102- text: i18n.tr(name)+((country) ? ', '+i18n.tr(country): '');
103- progression: true;
104- onClicked: {
105- var location = citiesModel.get(index)
106- locationManager.addLocation(location)
107- pageStack.pop()
108- clear()
109- }
110- }
111- Scrollbar {
112- flickableItem: listView;
113- align: Qt.AlignTrailing;
114- }
115- }
116- }
117-
118-}
119
120=== added file 'components/AddLocationSheet.qml'
121--- components/AddLocationSheet.qml 1970-01-01 00:00:00 +0000
122+++ components/AddLocationSheet.qml 2013-07-20 16:54:27 +0000
123@@ -0,0 +1,134 @@
124+/*
125+ * Copyright (C) 2013 Canonical Ltd
126+ *
127+ * This program is free software: you can redistribute it and/or modify
128+ * it under the terms of the GNU General Public License version 3 as
129+ * published by the Free Software Foundation.
130+ *
131+ * This program is distributed in the hope that it will be useful,
132+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
133+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
134+ * GNU General Public License for more details.
135+ *
136+ * You should have received a copy of the GNU General Public License
137+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
138+ *
139+ * Authored by: Raúl Yeguas <neokore@gmail.com>
140+ * Martin Borho <martin@borho.net>
141+ */
142+import QtQuick 2.0
143+import Ubuntu.Components 0.1
144+import Ubuntu.Components.Popups 0.1
145+import Ubuntu.Components.ListItems 0.1 as ListItem
146+
147+Component {
148+
149+ DefaultSheet {
150+ id: addLocationSheet
151+ objectName: "AddLocationSheet"
152+ title: i18n.tr("Add city")
153+ contentsHeight: parent.height
154+ doneButton: false
155+
156+ WorkerScript {
157+ id: searchWorker
158+ source: "./WeatherApi.js"
159+ onMessage: {
160+ if(!messageObject.error) {
161+ listView.visible = true
162+ messageObject.result.locations.forEach(function(loc) {
163+ citiesModel.append(loc);
164+ noCityError.visible = false
165+ });
166+ } else {
167+ console.log(messageObject.error.msg+" / "+messageObject.error.request.url)
168+ }
169+ if (!citiesModel.count) {
170+ noCityError.visible = true
171+ noCityError.text = i18n.tr("No location was found for ") + locationString.text
172+ }
173+ }
174+ }
175+
176+ Component.onCompleted: {
177+
178+ }
179+
180+ function clear() {
181+ locationString.text = '';
182+ citiesModel.clear();
183+ listView.visible = true;
184+ }
185+
186+ ListModel {
187+ id: citiesModel
188+ }
189+
190+ container: Item {
191+ width: parent.width
192+ Rectangle {
193+ id: searchInput
194+ width:parent.width
195+ height:units.gu(7)
196+ color: "transparent"
197+ TextField {
198+ id: locationString
199+ objectName: "SearchField"
200+ width: parent.width-units.gu(2)
201+ height:units.gu(5)
202+ anchors.centerIn: parent
203+ placeholderText: i18n.tr("Enter a city name")
204+ hasClearButton: true
205+ onAccepted: {
206+ citiesModel.clear();
207+ searchWorker.sendMessage({
208+ action: "searchByName",
209+ params: {name:locationString.text, units:"metric"}
210+ })
211+ }
212+ }
213+ }
214+
215+ Rectangle {
216+ id: cityList;
217+ anchors.top: searchInput.bottom
218+ width: parent.width
219+ height: units.gu(52)
220+ color: "transparent"
221+ Label {
222+ id: noCityError
223+ objectName: "noCityError"
224+ visible: false
225+ anchors.centerIn: parent;
226+ font.pixelSize: 18
227+ }
228+
229+ ListView {
230+ id: listView;
231+ objectName: "SearchResultList"
232+ visible: false
233+ clip: true;
234+ anchors.fill: parent;
235+ model: citiesModel;
236+ delegate: ListItem.Standard {
237+ text: i18n.tr(name)+((country) ? ', '+i18n.tr(country): '');
238+ progression: true;
239+ onClicked: {
240+ var location = citiesModel.get(index)
241+ //locationManager.addLocation(location)
242+ //mainView.newLocationAdded(location)
243+ locationManagerSheet.addLocation(location)
244+ PopupUtils.close(addLocationSheet)
245+ //pageStack.pop()
246+ clear()
247+ }
248+ }
249+ Scrollbar {
250+ flickableItem: listView;
251+ align: Qt.AlignTrailing;
252+ }
253+ }
254+ }
255+ }
256+ }
257+}
258
259=== modified file 'components/CurrentWeather.qml'
260--- components/CurrentWeather.qml 2013-06-26 10:43:49 +0000
261+++ components/CurrentWeather.qml 2013-07-20 16:54:27 +0000
262@@ -4,6 +4,7 @@
263
264 Rectangle {
265 id: currentWeather
266+ color: "transparent"
267
268 // For Status I take the same condition codes from OpenWeatherMap (http://openweathermap.org/wiki/API/Weather_Condition_Codes)
269 property int condition
270@@ -44,7 +45,7 @@
271 anchors.horizontalCenter: parent.horizontalCenter
272 anchors.top: currentCondition.bottom
273 anchors.topMargin: 0
274- color: "#00000000"
275+ color: "transparent"
276
277 Column {
278 id: column1
279@@ -67,6 +68,7 @@
280 anchors.horizontalCenter: parent.horizontalCenter
281 font.pixelSize: FontUtils.sizeToPixels("medium")
282 horizontalAlignment: Text.AlignHCenter
283+ color: Theme.palette.normal.baseText
284 }
285 }
286
287@@ -84,6 +86,7 @@
288 anchors.verticalCenter: parent.verticalCenter
289 font.pointSize: 52
290 horizontalAlignment: Text.AlignHCenter
291+ color: Theme.palette.normal.baseText
292 }
293
294 Column {
295@@ -99,6 +102,7 @@
296 horizontalAlignment: Text.AlignHCenter
297 anchors.horizontalCenter: parent.horizontalCenter
298 font.pixelSize: FontUtils.sizeToPixels("x-small")
299+ color: Theme.palette.normal.baseText
300 }
301
302 Label {
303@@ -107,6 +111,7 @@
304 horizontalAlignment: Text.AlignHCenter
305 anchors.horizontalCenter: parent.horizontalCenter
306 font.pixelSize: FontUtils.sizeToPixels("medium")
307+ color: Theme.palette.normal.baseText
308 }
309 }
310 }
311
312=== modified file 'components/DateComponent.qml'
313--- components/DateComponent.qml 2013-06-26 11:12:34 +0000
314+++ components/DateComponent.qml 2013-07-20 16:54:27 +0000
315@@ -4,11 +4,11 @@
316 Rectangle {
317 width: parent.width
318 height: childrenRect.height
319-
320+ color: "transparent"
321 property bool borderTopVisible: true
322 property string dateRelative: ""
323 property string dateString: ""
324- property string borderColor: "#D6D6D6"
325+ property string borderColor: "transparent"
326 property int borderHeight: units.gu(0.1)
327
328 Component.onCompleted: {
329@@ -44,6 +44,7 @@
330 objectName: "DayDateLabel"
331 height: parent.height
332 verticalAlignment: Text.AlignVCenter
333+ color: Theme.palette.normal.baseText
334 }
335 }
336
337
338=== modified file 'components/DayWeatherComponent.qml'
339--- components/DayWeatherComponent.qml 2013-06-26 23:50:16 +0000
340+++ components/DayWeatherComponent.qml 2013-07-20 16:54:27 +0000
341@@ -8,13 +8,14 @@
342 width: parent.width-units.gu(2)
343 anchors.horizontalCenter: parent.horizontalCenter
344 height:contentShape.height+units.gu(2)
345+ color: "transparent"
346
347 property int condition
348 property string icon
349 property int temperature
350 property int temperatureMin
351 property string scale: (mainView.settings["units"] === "imperial") ? "F" : "C"
352- property string shapeColor: "#D6D6D6"
353+ property string shapeColor: "transparent"
354
355 UbuntuShape{
356 id: contentShape
357@@ -38,6 +39,7 @@
358 width:parent.width/9*3
359 height:parent.height
360 text: dayWeatherComponent.temperature+"°"+dayWeatherComponent.scale
361+ color: Theme.palette.normal.baseText
362 }
363 Label {
364 id: minTemp
365@@ -46,6 +48,7 @@
366 width:parent.width/9*3
367 height: parent.height
368 text: i18n.tr("Min.")+"\n"+dayWeatherComponent.temperatureMin+"°"+dayWeatherComponent.scale
369+ color: Theme.palette.normal.baseText
370 }
371 }
372 }
373
374=== removed file 'components/LocationManagerPage.qml'
375--- components/LocationManagerPage.qml 2013-07-16 09:39:11 +0000
376+++ components/LocationManagerPage.qml 1970-01-01 00:00:00 +0000
377@@ -1,182 +0,0 @@
378-import QtQuick 2.0
379-import Ubuntu.Components 0.1
380-import Ubuntu.Components.ListItems 0.1 as ListItem
381-import Ubuntu.Components.Popups 0.1
382-
383-Page {
384- id: locationManagerPage
385- objectName: "LocationManagerPage"
386- title: i18n.tr("Edit locations")
387- visible: false
388-
389- property bool locationsChanged: false
390-
391- tools: ToolbarItems {
392- locked: true
393- opened: (locationModel.count > 0) ? true : false
394- back: ToolbarButton {
395- objectName: "BackButton"
396- text: i18n.tr("Back")
397- iconSource: Qt.resolvedUrl("../resources/images/back@18.png")
398- onTriggered: {
399- if(locationsChanged) {
400- mainView.refreshData()
401- locationsChanged = false;
402- }
403- // handle dummy "current location" item
404- currentLocationItem.visible = false
405- locationLookupItem.visible = true
406- lookupItemAddButton.visible = true
407-
408- if(pageStack.depth === 2) pageStack.pop()
409- }
410- }
411- }
412-
413- function loadData() {
414- storage.getLocations(fillLocationsList);
415- }
416-
417- function checkLocationExists(location) {
418- for(var x=0;x<locationModel.count;x++) {
419- var loc = locationModel.get(x);
420- if(loc.service === location.service
421- && loc.service_id === location.service_id) {
422- existsNotification.show()
423- return true;
424- }
425- }
426- return false;
427- }
428-
429- function fillLocationsList(locations) {
430- locationModel.clear()
431- for(var x=0;x<locations.length;x++) {
432- var dbId = locations[x].db.id,
433- location = locations[x].location;
434- // add db-id to the location object
435- location.dbId = dbId;
436- locationModel.append(locations[x].location);
437- }
438- }
439-
440- function addLocation(location) {
441- if(!checkLocationExists(location)) {
442- storage.insertLocation({location:location});
443- loadData()
444- locationsChanged = true;
445- }
446- }
447-
448-
449- Dialog {
450- id:existsNotification
451- title: i18n.tr("Location already added.")
452- Button {
453- text: i18n.tr("OK")
454- onClicked: PopupUtils.close(existsNotification)
455- }
456- }
457-
458- ListModel {
459- id: locationModel
460- }
461-
462- Column {
463- anchors.fill: parent
464- Rectangle {
465- color: "#D6D6D6"
466- width:parent.width
467- height: units.gu(0.3)
468- }
469- Rectangle {
470- width: parent.width
471- height: units.gu(5)
472- Label {
473- anchors.verticalCenter: parent.verticalCenter
474- text: " "+i18n.tr("Current location")
475- fontSize: "large"
476- }
477- }
478- Rectangle {
479- color: "#D6D6D6"
480- width:parent.width
481- height: units.gu(0.3)
482- }
483- ListItem.Standard {
484- id: locationLookupItem
485- text: i18n.tr("Lookup location")+" (Dummy)"
486- progression: true
487- onClicked: {
488- print("TODO: lookup current location")
489- visible = false
490- currentLocationItem.visible = true;
491- }
492- }
493- ListItem.Standard {
494- id: currentLocationItem
495- visible: false
496- text: i18n.tr("London")
497- //icon: Qt.resolvedUrl("../resources/images/refresh_icon.png")
498- control: Button {
499- id: lookupItemAddButton
500- anchors.verticalCenter: parent.verticalCenter
501- text: i18n.tr("add")
502- MouseArea {
503- anchors.fill: parent
504- onClicked: {
505- // add dummy location
506- addLocation({"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"})
507- lookupItemAddButton.visible = false;
508- }
509- }
510- }
511- }
512- Rectangle {
513- id:test2
514- width: parent.width
515- height: units.gu(5)
516- Label {
517- anchors.verticalCenter: parent.verticalCenter
518- text: " "+i18n.tr("World")
519- fontSize: "large"
520- }
521- }
522- Rectangle {
523- color: "#D6D6D6"
524- width:parent.width
525- height: units.gu(0.3)
526- }
527- Rectangle {
528- width: parent.width
529- clip:true
530- color:"transparent"
531- height: units.gu(40)
532- ListView {
533- objectName: "LocationList"
534- anchors.fill: parent
535- model: locationModel
536- delegate: ListItem.Standard {
537- text: model.name
538- removable: true
539- onItemRemoved: {
540- var location = locationModel.get(index)
541- locationsChanged = true;
542- storage.clearLocation(location.dbId);
543- locationModel.remove(index)
544- }
545- backgroundIndicator: SwipeDelete {
546- id: swipeDelete
547- state: swipingState
548- }
549- }
550- footer: ListItem.Standard {
551- objectName: "AddCityListItem"
552- text: i18n.tr("Add city")
553- progression: true
554- onClicked: pageStack.push(addLocationPage)
555- }
556- }
557- }
558- }
559-}
560
561=== added file 'components/LocationManagerSheet.qml'
562--- components/LocationManagerSheet.qml 1970-01-01 00:00:00 +0000
563+++ components/LocationManagerSheet.qml 2013-07-20 16:54:27 +0000
564@@ -0,0 +1,228 @@
565+/*
566+ * Copyright (C) 2013 Canonical Ltd
567+ *
568+ * This program is free software: you can redistribute it and/or modify
569+ * it under the terms of the GNU General Public License version 3 as
570+ * published by the Free Software Foundation.
571+ *
572+ * This program is distributed in the hope that it will be useful,
573+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
574+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
575+ * GNU General Public License for more details.
576+ *
577+ * You should have received a copy of the GNU General Public License
578+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
579+ *
580+ * Authored by: Martin Borho <martin@borho.net>
581+ Raúl Yeguas <neokore@gmail.com>
582+ Riccardo Padovani <ricki.padovani@gmail.com>
583+ */
584+import QtQuick 2.0
585+import Ubuntu.Components 0.1
586+import Ubuntu.Components.Popups 0.1
587+import Ubuntu.Components.ListItems 0.1 as ListItem
588+
589+Component {
590+ id: locationManagerComponent
591+
592+ ComposerSheet {
593+ id: locationManagerSheet
594+ objectName: "LocationManagerSheet"
595+ title: i18n.tr("Edit locations")
596+ contentsHeight: parent.height
597+
598+ property int initial_sum: 0
599+
600+ Component.onCompleted: {
601+ locationsRemoved.clear()
602+ loadData()
603+ }
604+
605+ function loadData() {
606+ storage.getLocations(fillLocationsList);
607+ }
608+
609+ function checkLocationExists(location) {
610+ for(var x=0;x<locationModel.count;x++) {
611+ var loc = locationModel.get(x);
612+ if(loc.service === location.service
613+ && loc.service_id === location.service_id) {
614+ existsNotification.show()
615+ return true;
616+ }
617+ }
618+ return false;
619+ }
620+
621+ function fillLocationsList(locations) {
622+ initial_sum = locations.length;
623+ locationModel.clear()
624+ for(var x=0;x<locations.length;x++) {
625+ var dbId = locations[x].db.id,
626+ location = locations[x].location;
627+ // add db-id to the location object
628+ location.dbId = dbId;
629+ locationModel.append(locations[x].location);
630+ }
631+ }
632+
633+ function addLocation(location) {
634+ if(!checkLocationExists(location)) {
635+ locationModel.append(location)
636+ }
637+ }
638+
639+ container: Column {
640+ anchors.fill: parent
641+ Rectangle {
642+ width: parent.width
643+ height: units.gu(5)
644+ color: "transparent"
645+ Label {
646+ anchors.verticalCenter: parent.verticalCenter
647+ text: " "+i18n.tr("Current location")
648+ fontSize: "large"
649+ }
650+ }
651+ Rectangle {
652+ color: "#A9A9A9"
653+ width:parent.width
654+ height: units.gu(0.1)
655+ }
656+ ListItem.Standard {
657+ id: locationLookupItem
658+ text: i18n.tr("Lookup location")+" (Dummy)"
659+ progression: true
660+ onClicked: {
661+ print("TODO: lookup current location")
662+ visible = false
663+ currentLocationItem.visible = true;
664+ }
665+ }
666+ ListItem.Standard {
667+ id: currentLocationItem
668+ visible: false
669+ text: i18n.tr("London")
670+ control: Button {
671+ id: lookupItemAddButton
672+ anchors.verticalCenter: parent.verticalCenter
673+ text: i18n.tr("add")
674+ MouseArea {
675+ anchors.fill: parent
676+ onClicked: {
677+ // add dummy location
678+ addLocation({"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"})
679+ lookupItemAddButton.visible = false;
680+ }
681+ }
682+ }
683+ }
684+ Rectangle {
685+ width: parent.width
686+ height: units.gu(5)
687+ color: "transparent"
688+ Label {
689+ anchors.verticalCenter: parent.verticalCenter
690+ text: " "+i18n.tr("World")
691+ fontSize: "large"
692+ }
693+ }
694+ Rectangle {
695+ color: "#A9A9A9"
696+ width:parent.width
697+ height: units.gu(0.1)
698+ }
699+ Rectangle {
700+ width: parent.width
701+ clip:true
702+ color:"transparent"
703+ height: units.gu(40)
704+ ListView {
705+ objectName: "LocationList"
706+ anchors.fill: parent
707+ model: locationModel
708+ delegate: ListItem.Standard {
709+ text: model.name
710+ removable: true
711+ onItemRemoved: {
712+ var location = locationModel.get(index)
713+ // clone location obj
714+ location = JSON.parse(JSON.stringify(location));
715+ locationsRemoved.append(location)
716+ locationModel.remove(index)
717+
718+ }
719+ backgroundIndicator: SwipeDelete {
720+ id: swipeDelete
721+ state: swipingState
722+ }
723+ }
724+ footer: ListItem.Standard {
725+ objectName: "AddCityListItem"
726+ text: i18n.tr("Add city")
727+ progression: true
728+ onClicked: {
729+ PopupUtils.open(addLocationSheet)
730+ }
731+ }
732+ }
733+ }
734+ }
735+
736+ Dialog {
737+ id:existsNotification
738+ title: i18n.tr("Location already added.")
739+ Button {
740+ text: i18n.tr("OK")
741+ onClicked: PopupUtils.close(existsNotification)
742+ }
743+ }
744+
745+ ListModel {
746+ id: locationModel
747+ }
748+
749+ ListModel {
750+ id: locationsRemoved
751+ }
752+
753+ onConfirmClicked: {
754+ var locationsChanged = false;
755+ // remove
756+ for(var x=0;x<locationsRemoved.count;x++) {
757+ var delLoc = locationsRemoved.get(x);
758+ storage.clearLocation(delLoc.dbId);
759+ locationsChanged = true;
760+ }
761+ // add
762+ for(var y=0;y<locationModel.count;y++) {
763+ var loc = locationModel.get(y);
764+ if(loc.dbId === undefined || loc.dbId=== 0) {
765+ storage.insertLocation({location:loc});
766+ locationsChanged = true;
767+ }
768+ }
769+ // refresh tabs if neccessary
770+ if(locationsChanged || locationModel.count === 0) {
771+ mainView.refreshData()
772+ }
773+ // handle dummy "current location" item
774+ currentLocationItem.visible = false
775+ locationLookupItem.visible = true
776+ lookupItemAddButton.visible = true
777+ }
778+
779+ onCancelClicked: {
780+ if(initial_sum === 0) {
781+ // refresh mainview to land again here,
782+ // when no locations were defined when
783+ // opening the sheet
784+ mainView.refreshData()
785+ }
786+ }
787+
788+ AddLocationSheet {
789+ id:addLocationSheet
790+ }
791+ }
792+}
793
794=== modified file 'components/LocationTab.qml'
795--- components/LocationTab.qml 2013-07-15 18:04:37 +0000
796+++ components/LocationTab.qml 2013-07-20 16:54:27 +0000
797@@ -75,66 +75,21 @@
798 // Menu for options
799 page: Page {
800 id: locationPage
801- tools: ToolbarItems {
802- id: pageTools
803- ToolbarButton {
804- objectName: "RefreshButton"
805- action:Action {
806- id: refreshAction
807- objectName: "RefreshAction"
808- iconSource: Qt.resolvedUrl("../resources/images/refresh_icon.png")
809- text: i18n.tr("Refresh")
810-
811- onTriggered: {
812- mainView.refreshData(false, true);
813- }
814- }
815- }
816- ToolbarButton {
817- objectName: "EditButton"
818- action:Action {
819- id: editLocationAction
820- iconSource: Qt.resolvedUrl("../resources/images/add_icon.png")
821- text: i18n.tr("Edit")
822-
823- onTriggered: {
824- mainView.showLocationManager()
825- }
826- }
827- }
828- ToolbarButton {
829- objectName: "SettingsButton"
830- action:Action {
831- id: configAction
832- iconSource: Qt.resolvedUrl("../resources/images/settings.png")
833- text: i18n.tr("Settings")
834-
835- onTriggered: {
836- mainView.showSettings();
837- }
838- }
839- }
840+ anchors.fill: parent
841+
842+ ListModel {
843+ id: dayForecastModel
844 }
845- }
846-
847- ListModel {
848- id: dayForecastModel
849- }
850-
851- Rectangle {
852- id:startPage
853- width: parent.width
854- height: parent.height
855
856 Flickable {
857 id: flickable
858- width: parent.width
859- height: parent.height
860+ anchors.fill: parent
861 contentHeight: flickContent.height;
862 Rectangle {
863 id: flickContent
864 width:parent.width
865 height: childrenRect.height
866+ color: "transparent"
867 DateComponent {
868 id: todayDateComponent
869 //dateRelative: i18n.tr("Today")
870@@ -144,10 +99,6 @@
871 id: currentCondition
872 anchors.top: todayDateComponent.bottom
873 }
874- /*ChartComponent{
875- id: chartComponent
876- anchors.top: currentCondition.bottom
877- }*/
878 ListView {
879 id: dailyForecastList
880 width: parent.width;
881@@ -175,6 +126,47 @@
882 }
883 }
884 }
885+
886+
887+ tools: ToolbarItems {
888+ id: pageTools
889+ ToolbarButton {
890+ objectName: "RefreshButton"
891+ action:Action {
892+ id: refreshAction
893+ objectName: "RefreshAction"
894+ iconSource: Qt.resolvedUrl("../resources/images/refresh_icon.png")
895+ text: i18n.tr("Refresh")
896+
897+ onTriggered: {
898+ mainView.refreshData(false, true);
899+ }
900+ }
901+ }
902+ ToolbarButton {
903+ objectName: "EditButton"
904+ action:Action {
905+ id: editLocationAction
906+ iconSource: Qt.resolvedUrl("../resources/images/add_icon.png")
907+ text: i18n.tr("Edit")
908+
909+ onTriggered: {
910+ mainView.showLocationManager()
911+ }
912+ }
913+ }
914+ ToolbarButton {
915+ objectName: "SettingsButton"
916+ action:Action {
917+ id: configAction
918+ iconSource: Qt.resolvedUrl("../resources/images/settings.png")
919+ text: i18n.tr("Settings")
920+
921+ onTriggered: {
922+ mainView.showSettings();
923+ }
924+ }
925+ }
926+ }
927 }
928-
929 }
930
931=== modified file 'components/SettingsSheet.qml'
932--- components/SettingsSheet.qml 2013-07-11 18:50:23 +0000
933+++ components/SettingsSheet.qml 2013-07-20 16:54:27 +0000
934@@ -27,9 +27,9 @@
935 id: sheet
936 objectName: "SettingsSheet"
937 title: i18n.tr("Settings")
938- contentsHeight: parent.height
939+ contentsHeight: parent.height
940
941- container: ListItem.ValueSelector {
942+ container: ListItem.ValueSelector {
943 id: unitsSelector
944 objectName: "UnitsSelector"
945 text: i18n.tr("Temperature unit")
946
947=== modified file 'tests/autopilot/ubuntu_weather_app/tests/__init__.py'
948--- tests/autopilot/ubuntu_weather_app/tests/__init__.py 2013-07-11 20:03:29 +0000
949+++ tests/autopilot/ubuntu_weather_app/tests/__init__.py 2013-07-20 16:54:27 +0000
950@@ -76,6 +76,15 @@
951 def main_window(self):
952 return ubuntusdk(self, self.app)#MainWindow(self, self.app)
953
954+class SheetMixin(object):
955+ """A mixin to to give access to common sheet elements"""
956+ def _click_sheet_confirm(self):
957+ """Clicks the confirm button"""
958+ self.pointing_device.click_object(self.main_window.app.select_many('Button')[1])
959+
960+ def _click_sheet_cancel(self):
961+ """Clicks the cancel button"""
962+ self.pointing_device.click_object(self.main_window.app.select_many('Button')[0])
963
964 class DatabaseMixin(object):
965
966
967=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py'
968--- tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2013-07-16 19:34:12 +0000
969+++ tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2013-07-20 16:54:27 +0000
970@@ -12,10 +12,10 @@
971 from testtools.matchers import Equals
972 from autopilot.matchers import Eventually
973
974-from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin
975+from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin, SheetMixin
976 from ubuntu_weather_app.tests.weatherdata import locations_data
977
978-class TestLocationManager(WeatherTestCase, DatabaseMixin):
979+class TestLocationManager(WeatherTestCase, DatabaseMixin, SheetMixin):
980 def setUp(self):
981 self.clean_db()
982 super(TestLocationManager, self).setUp()
983@@ -30,7 +30,7 @@
984 self.pointing_device.move_to_object(addCityItem)
985 self.pointing_device.click()
986
987- addLocPage = self.main_window.get_object("AddLocationPage", "AddLocationPage")
988+ addLocPage = self.main_window.get_object("DefaultSheet", "AddLocationSheet")
989 self.assertThat(addLocPage.visible, Eventually(Equals(True)))
990
991 def test_add_location(self):
992@@ -56,10 +56,17 @@
993 locationList = self.main_window.get_object('QQuickListView', 'LocationList')
994 addedItem = locationList.get_children()[0]
995 self.assertThat(addedItem.get_children()[1].text, Eventually(Equals("London")))
996-
997- # a location is defined, so toolbar should be visible
998- toolbar = self.main_window.get_toolbar()
999- self.assertThat(toolbar.opened, Eventually(Equals(True)))
1000+ self._click_sheet_confirm()
1001+
1002+ # back to locations, wait till data is loaded
1003+ load_indicator = self.main_window.get_object('ActivityIndicator', 'LoadingSpinner')
1004+ self.assertThat(load_indicator.running, Eventually(Equals(False)))
1005+
1006+ # only location is there
1007+ loadingPage = self.main_window.get_object("Tabs", "rootTabs")
1008+ self.assertThat(loadingPage.visible, Eventually(Equals(True)))
1009+ tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
1010+ self.assertEqual(1, len(tabObjects))
1011
1012 def test_toolbar_hidden_when_no_location_is_defined(self):
1013 """Toolbar is not visible when there's no location is defined"""
1014@@ -99,7 +106,7 @@
1015 def test_cancel_adding_location(self):
1016 """Cancel the cities search"""
1017 self._open_add_location_page()
1018- self.main_window.click_toolbar_button("BackButton")
1019+ self._click_sheet_cancel()
1020 locationList = self.main_window.get_object('QQuickListView', 'LocationList')
1021 self.assertThat(locationList.visible, Eventually(Equals(True)))
1022
1023@@ -120,12 +127,13 @@
1024 self.assertThat(errorLabel.visible, Eventually(Equals(True), timeout=30))
1025
1026
1027-class TestLocationManagerWithLocation(WeatherTestCase, DatabaseMixin):
1028+class TestLocationManagerWithLocation(WeatherTestCase, DatabaseMixin, SheetMixin):
1029 def setUp(self):
1030 self.clean_db()
1031 self.launch_and_quit_app()
1032 # add one location to storage
1033- self.save_locations_to_storage([locations_data[0]])
1034+ #self.save_locations_to_storage([locations_data[0]])
1035+ self.save_locations_to_storage(locations_data)
1036 super(TestLocationManagerWithLocation, self).setUp()
1037 self.assertThat(
1038 self.main_window.get_qml_view().visible, Eventually(Equals(True)))
1039@@ -136,16 +144,8 @@
1040 self.assertThat(self.main_window.get_toolbar().opened, Eventually(Equals(True)))
1041 self.main_window.click_toolbar_button("EditButton")
1042
1043- def test_remove_location(self):
1044- """Removes location"""
1045- # check loading screen diappears
1046- loadingPage = self.main_window.get_object("Page", "MainPage")
1047- self.assertThat(loadingPage.visible, Eventually(Equals(True)))
1048-
1049- # go to the location manegr
1050- self._open_location_manager()
1051-
1052- # swipe right to delete the first location
1053+ def _swipe_location_to_remove(self):
1054+ """Swipe right to delete the first location"""
1055 locationList = self.main_window.get_object('QQuickListView', 'LocationList')
1056 locItem = locationList.get_children()[0]
1057 loc_x, loc_y, loc_w, loc_h = locItem.globalRect
1058@@ -154,8 +154,47 @@
1059 self.pointing_device.move(loc_x + loc_w - 10, loc_y + loc_h / 2)
1060 self.pointing_device.release()
1061
1062- # toolbar disappears since no locations defined
1063- self.assertThat(self.main_window.get_toolbar().opened, Eventually(Equals(False)))
1064+ def test_remove_location(self):
1065+ """Removes location"""
1066+ # wait till data is loaded
1067+ loadingPage = self.main_window.get_object("Tabs", "rootTabs")
1068+ self.assertThat(loadingPage.visible, Eventually(Equals(True)))
1069+
1070+ # count locations at start
1071+ tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
1072+ tabsSumStart = len(tabObjects)
1073+
1074+ # go to the location manager and remove location
1075+ self._open_location_manager()
1076+ self._swipe_location_to_remove()
1077+ self._click_sheet_confirm()
1078+
1079+ # back to locations, only one is left
1080+ load_indicator = self.main_window.get_object('ActivityIndicator', 'LoadingSpinner')
1081+ self.assertThat(load_indicator.running, Eventually(Equals(False)))
1082+ tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
1083+ self.assertEqual(tabsSumStart-1, len(tabObjects))
1084+
1085+ def test_cancel_remove_location(self):
1086+ """Cancels removing of location"""
1087+ # wait data is loaded
1088+ loadingPage = self.main_window.get_object("Tabs", "rootTabs")
1089+ self.assertThat(loadingPage.visible, Eventually(Equals(True)))
1090+
1091+ # count locations at start
1092+ tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
1093+ tabsSumStart = len(tabObjects)
1094+
1095+ # go to the location manager, remove location, but click cancel
1096+ self._open_location_manager()
1097+ self._swipe_location_to_remove()
1098+ self._click_sheet_cancel()
1099+
1100+ # back to locations, no loction is removed
1101+ loadingPage = self.main_window.get_object("Tabs", "rootTabs")
1102+ self.assertThat(loadingPage.visible, Eventually(Equals(True)))
1103+ tabObjects = self.main_window.get_objects('LocationTab','LocationTab')
1104+ self.assertEqual(tabsSumStart, len(tabObjects))
1105
1106 def test_toolbar_opened_when_location_is_defined(self):
1107 """Toolbar is visible since there's a location defined"""
1108
1109=== modified file 'tests/autopilot/ubuntu_weather_app/tests/test_settings.py'
1110--- tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2013-07-16 19:43:28 +0000
1111+++ tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2013-07-20 16:54:27 +0000
1112@@ -12,10 +12,10 @@
1113 from testtools.matchers import Equals
1114 from autopilot.matchers import Eventually
1115
1116-from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin
1117+from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin, SheetMixin
1118 from ubuntu_weather_app.tests.weatherdata import locations_data
1119
1120-class TestSettings(WeatherTestCase, DatabaseMixin):
1121+class TestSettings(WeatherTestCase, DatabaseMixin, SheetMixin):
1122 def setUp(self):
1123 self.clean_db()
1124 self.launch_and_quit_app()
1125@@ -35,14 +35,6 @@
1126 sheet = self.main_window.get_object('ComposerSheet', 'SettingsSheet')
1127 self.pointing_device.move_to_object(sheet)
1128
1129- def _click_confirm(self):
1130- """Clicks the confirm button"""
1131- self.pointing_device.click_object(self.main_window.app.select_many('Button')[1])
1132-
1133- def _click_cancel(self):
1134- """Clicks the cancel button"""
1135- self.pointing_device.click_object(self.main_window.app.select_many('Button')[0])
1136-
1137 def _check_units(self, units):
1138 """Checks selected units by values from the first location tab"""
1139 current_temps = self.main_window.get_objects('QQuickText', 'CurrentTempText')
1140@@ -69,7 +61,7 @@
1141 imperial_option = units_selector.get_children()[3]
1142 self.pointing_device.click_object(imperial_option)
1143 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))
1144- self._click_confirm()
1145+ self._click_sheet_confirm()
1146
1147 # wait for reload and check the imperial values
1148 load_indicator = self.main_window.get_object('ActivityIndicator', 'LoadingSpinner')
1149@@ -90,7 +82,7 @@
1150
1151 # confirm
1152 self.assertThat(units_selector.selectedIndex, Eventually(Equals(0)))
1153- self._click_confirm()
1154+ self._click_sheet_confirm()
1155
1156 # wait for reload and check the metric values again
1157 load_indicator = self.main_window.get_object('ActivityIndicator', 'LoadingSpinner')
1158@@ -114,6 +106,6 @@
1159 self.assertThat(units_selector.selectedIndex, Eventually(Equals(1)))
1160
1161 # cancel and check
1162- self._click_cancel()
1163+ self._click_sheet_cancel()
1164 self._check_units('metric')
1165
1166
1167=== modified file 'ubuntu-weather-app.qml'
1168--- ubuntu-weather-app.qml 2013-07-16 19:34:12 +0000
1169+++ ubuntu-weather-app.qml 2013-07-20 16:54:27 +0000
1170@@ -31,6 +31,10 @@
1171 width: units.gu(50)
1172 height: units.gu(75)
1173
1174+ headerColor: "#57365E"
1175+ backgroundColor: "#A55263"
1176+ footerColor: "#D75669"
1177+
1178 property var locationsList: []
1179 property var tabsObject: null
1180 // set default values for settings here
1181@@ -61,13 +65,14 @@
1182 var locLength = locations.length,
1183 locBeforeLen = locationsList.length,
1184 focusToLast = (locBeforeLen > 0 && locLength > locBeforeLen) ? true : false;
1185+ loading.running = false;
1186 // show locationmanager when no location is added
1187 if(locLength === 0) {
1188 showLocationManager()
1189 return;
1190 }
1191
1192- locationsList = locations;
1193+ locationsList = locations;
1194 if(tabsObject !== null) {
1195 tabsObject.destroy()
1196 }
1197@@ -79,19 +84,13 @@
1198 };
1199 }
1200 tabsString += "}"; // END Tabs componen
1201- if(bigLoading !== null) {
1202- bigLoading.destroy();
1203- }
1204- loading.running = false;
1205 tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs")
1206 if(focusToLast)
1207 tabsObject.selectedTabIndex = locLength -1;
1208 }
1209
1210 function refreshData(from_storage, force_refresh) {
1211- if(bigLoading === null) {
1212- loading.running = true;
1213- }
1214+ loading.running = true;
1215 //
1216 if(from_storage === true && force_refresh !== true) {
1217 storage.getLocations(buildTabs);
1218@@ -106,8 +105,7 @@
1219 }
1220
1221 function showLocationManager() {
1222- pageStack.push(locationManager)
1223- locationManager.loadData()
1224+ PopupUtils.open(locationManager)
1225 }
1226
1227 function showSettings() {
1228@@ -131,43 +129,24 @@
1229
1230 Components.Storage{
1231 id: storage
1232- }
1233-
1234- Components.LocationManagerPage {
1235- id:locationManager
1236- }
1237-
1238- Components.AddLocationPage {
1239- id:addLocationPage
1240- }
1241-
1242- PageStack {
1243- id: pageStack
1244- Component.onCompleted: push(tabPage)
1245-
1246- Page {
1247- id: tabPage
1248- objectName: "MainPage"
1249- visible: false
1250- ActivityIndicator{
1251- id:loading
1252- objectName: "LoadingSpinner"
1253- running: false
1254- z: 1
1255- anchors{
1256- top: parent.top
1257- topMargin: units.gu(0.5)
1258- right: parent.right
1259- rightMargin: units.gu(1)
1260- }
1261- }
1262- ActivityIndicator{
1263- id:bigLoading
1264- objectName: "LoadingSpinner"
1265- running: true
1266- z: 1
1267- anchors.centerIn: parent
1268- }
1269- }
1270- }
1271+ }
1272+
1273+ Components.LocationManagerSheet {
1274+ id:locationManager
1275+ }
1276+
1277+ ActivityIndicator{
1278+ id:loading
1279+ objectName: "LoadingSpinner"
1280+ running: false
1281+ z: 1
1282+ anchors.centerIn: parent
1283+ }
1284+
1285+ Item {
1286+ id:tabPage
1287+ width: parent.width
1288+ height:parent.height
1289+ }
1290+
1291 }

Subscribers

People subscribed via source and target branches