Merge lp:~martin-borho/ubuntu-weather-app/RunningRealData into lp:ubuntu-weather-app/obsolete.trunk

Proposed by Martin Borho on 2013-04-20
Status: Merged
Approved by: David Planella on 2013-04-22
Approved revision: 13
Merged at revision: 9
Proposed branch: lp:~martin-borho/ubuntu-weather-app/RunningRealData
Merge into: lp:ubuntu-weather-app/obsolete.trunk
Diff against target: 680 lines (+321/-230)
7 files modified
components/AddLocationDialog.qml (+53/-61)
components/DateComponent.qml (+5/-1)
components/LocationTab.qml (+148/-0)
components/LocationTabEmpty.qml (+35/-0)
components/WeatherApi.js (+2/-2)
ubuntu-weather-app.qml (+77/-165)
weather.qmlproject (+1/-1)
To merge this branch: bzr merge lp:~martin-borho/ubuntu-weather-app/RunningRealData
Reviewer Review Type Date Requested Status
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve on 2013-04-22
Raúl Yeguas 2013-04-20 Approve on 2013-04-20
Review via email: mp+159951@code.launchpad.net

Commit message

First version with real data.

Description of the change

First version with real data. Locations can be added and removed. Data gets updated at start.

To post a comment you must log in.
Raúl Yeguas (neokore) :
review: Approve
David Planella (dpm) wrote :

Thanks Raúl for your review. To ensure Jenkins automatically merges the branch in a merge proposal into trunk, please set the overall status to "Approved" (i.e. not "Merged").

I'll change it to approved myself this time around. If you've got any questions on bzr, landing branches or Jenkins, feel free to ask.

Nice to see the Weather app branches coming in! :-)

Cheers,
David.

review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'components/AddLocationDialog.qml'
2--- components/AddLocationDialog.qml 2013-03-12 19:28:16 +0000
3+++ components/AddLocationDialog.qml 2013-04-20 18:49:27 +0000
4@@ -1,23 +1,39 @@
5 import QtQuick 2.0
6 import Ubuntu.Components 0.1
7 import Ubuntu.Components.Popups 0.1
8+import Ubuntu.Components.ListItems 0.1 as ListItem;
9+import "WeatherApi.js" as Api
10
11 // Dialog for adding a new location
12 Component {
13 id: addLocationDialog
14 Dialog {
15 id: addLocationDialogue
16- property string cityCode: ''
17 height: units.gu(10)
18 title: i18n.tr("Add location")
19 text: i18n.tr("Write a city name o pick it by GPS location")
20
21- onCityCodeChanged: {
22- PopupUtils.close(addLocationDialogue);
23- addLocationAction.cityCode = cityCode;
24- }
25-
26- Row{
27+ function locationSelected(index) {
28+ var location = citiesModel.get(index);
29+ // make clone
30+ location = JSON.parse(JSON.stringify(location));
31+ mainView.locationAdded(location);
32+ PopupUtils.close(addLocationDialogue)
33+ }
34+
35+ function onApiError(err) {
36+ // TODO display
37+ console.log("onApiError")
38+ console.log(err.msg+" / "+err.request.url)
39+ }
40+
41+ function onSearchSuccess(locations) {
42+ locations.results.forEach(function(v) {
43+ citiesModel.append(v);
44+ })
45+ }
46+
47+ Row {
48 TextField {
49 id: locationString
50 width: units.gu(25)
51@@ -30,9 +46,8 @@
52 iconSource: "../resources/images/search_icon.png"
53
54 onClicked: {
55- // Load cities from API search
56- var cities = [{"id":"100000","name":"Madrid"}, {"id":"200000","name":"Seville"}, {"id":"300000","name":"Barcelona"}, {"id":"400000","name":"Valencia"},{"id":"500000","name":"Jaen"}];
57- createCityList(cities);
58+ citiesModel.clear();
59+ Api.WeatherApi.searchLocationByName({name:locationString.text, units:"metric"},onSearchSuccess,onApiError);
60 }
61 }
62 }
63@@ -41,26 +56,18 @@
64 id: locationGPSButton
65 text: i18n.tr("Get by GPS location")
66 onClicked: {
67- // Load cities from API search
68- var cities = [{"id":"100000","name":"Madrid"}, {"id":"200000","name":"Seville"}, {"id":"300000","name":"Barcelona"}, {"id":"400000","name":"Valencia"},{"id":"500000","name":"Jaen"}];
69- createCityList(cities);
70+ citiesModel.clear();
71+ Api.WeatherApi.searchLocationByPoint({coords: {"lon":10,"lat":53.549999}, units:"metric"}, onSearchSuccess,onApiError);
72 }
73 }
74
75 Button {
76- id: locationCancelButton
77+ id:locationCancelButton
78 text: i18n.tr("Cancel")
79 color: "#C00000"
80 onClicked: PopupUtils.close(addLocationDialogue)
81 }
82
83- // This rectangle is a workaround to keep enough height in the dialog
84- Rectangle {
85- width: units.gu(30)
86- height: units.gu(20)
87- color: "transparent"
88- }
89-
90 Item {
91 id: locationResultBox
92 anchors {
93@@ -69,47 +76,32 @@
94 }
95 }
96
97- // Function to show a list of cities in addCityAction
98- function createCityList(cities) {
99- if(resultList){
100- resultList.destroy();
101- }
102+ ListModel {
103+ id: citiesModel
104+ }
105
106- var list = 'import QtQuick 2.0; \
107- import Ubuntu.Components 0.1; \
108- import Ubuntu.Components.ListItems 0.1 as ListItem; \
109- Rectangle { \
110- id: cityList; \
111- width: units.gu(30); \
112- height: units.gu(20); \
113- color: "transparent"; \
114- ListView { \
115- id: listView; \
116- clip: true; \
117- anchors.fill: parent; \
118- model: ListModel { \
119- ';
120- for (var i in cities) {
121- list += 'ListElement { \
122- label:\''+cities[i]["name"]+'\'; \
123- code:\''+cities[i]["id"]+'\'; \
124- }';
125- };
126- list += ' \
127- } \
128- delegate: ListItem.Standard { \
129- text: i18n.tr(label); \
130- progression: true; \
131- onClicked: { addLocationDialogue.cityCode = code;} \
132- } \
133- } \
134- Scrollbar { \
135- flickableItem: listView; \
136- align: Qt.AlignTrailing; \
137- } \
138- } \
139- ';
140- resultList = Qt.createQmlObject(list,locationResultBox,'results');
141+ Rectangle {
142+ id: cityList;
143+ width: units.gu(30);
144+ height: units.gu(30);
145+ color: "transparent";
146+ ListView {
147+ id: listView;
148+ clip: true;
149+ anchors.fill: parent;
150+ model: citiesModel;
151+ delegate: ListItem.Standard {
152+ text: i18n.tr(name)+((country) ? ', '+i18n.tr(country): '');
153+ progression: true;
154+ onClicked: {
155+ locationSelected(index);
156+ }
157+ }
158+ }
159+ Scrollbar {
160+ flickableItem: listView;
161+ align: Qt.AlignTrailing;
162+ }
163 }
164 }
165 }
166
167=== modified file 'components/DateComponent.qml'
168--- components/DateComponent.qml 2013-03-09 15:30:09 +0000
169+++ components/DateComponent.qml 2013-04-20 18:49:27 +0000
170@@ -11,7 +11,11 @@
171 property string borderColor: "#D6D6D6"
172 property int borderHeight: units.gu(0.1)
173
174- Component.onCompleted: {
175+ Component.onCompleted: {
176+ renderText()
177+ }
178+
179+ function renderText() {
180 var dateText = ""
181 if(dateRelative !== "") {
182 dateText += dateRelative+", ";
183
184=== added file 'components/LocationTab.qml'
185--- components/LocationTab.qml 1970-01-01 00:00:00 +0000
186+++ components/LocationTab.qml 2013-04-20 18:49:27 +0000
187@@ -0,0 +1,148 @@
188+import QtQuick 2.0
189+import Ubuntu.Components.Popups 0.1
190+import Ubuntu.Components 0.1
191+
192+Tab {
193+ id: locationTab
194+ property int locationIndex: 0
195+ property var locationData: {}
196+
197+ function formatTimestamp(timestamp, format) {
198+ var date = new Date(timestamp*1000);
199+ return Qt.formatDate(date, format)
200+ }
201+
202+ function formatTimestampToTime(timestamp, format) {
203+ var date = new Date(timestamp*1000);
204+ return Qt.formatTime(date, format)
205+ }
206+
207+ Component.onCompleted: {
208+ var locData = mainView.locationsList[locationIndex],
209+ currentData = locData.current.results;
210+
211+ // set location data as property
212+ locationData = locData;
213+
214+ // set today date
215+ var todayStr = formatTimestamp(currentData.timestamp, 'dddd, dd MMMM yyyy');
216+ todayDateComponent.dateString = todayStr+" - "+ formatTimestampToTime(currentData.timestamp, 'HH:mm');
217+ todayDateComponent.renderText()
218+
219+ // set current Condition
220+ currentCondition.condition = 801; //currentData.condition.id;
221+ currentCondition.currentTemp = currentData.temp;
222+ currentCondition.minTemp = currentData.temp_min;
223+ currentCondition.maxTemp = currentData.temp_max;
224+
225+ // set daily forecasts
226+ var dailyForecasts = locationData.daily.results,
227+ dailyLength = dailyForecasts.length;
228+ for(var x=0;x<dailyLength;x++) {
229+ dayForecastModel.append({
230+ dateRel: "",//Tomorrow",
231+ date: formatTimestamp(dailyForecasts[x].timestamp, 'dddd, dd MMMM yyyy'),
232+ temp: dailyForecasts[x].temp,
233+ tempMin: dailyForecasts[x].night,
234+ cond: 801 // dailyForecasts[x].condition.id;
235+ });
236+ }
237+ }
238+
239+ function locationAdded(location) {
240+ mainView.locationAdded({"service":"openweathermap","service_id":2643743,"name":"London","country":"GB"});
241+ }
242+
243+ // Menu for options
244+ page: Page {
245+
246+ tools: ToolbarActions {
247+ Action {
248+ id: addLocationAction
249+ property string cityCode: ''
250+ objectName: "action"
251+
252+ iconSource: Qt.resolvedUrl("../resources/images/add_icon.png")
253+ text: i18n.tr("Add")
254+
255+ onTriggered: {
256+ PopupUtils.open(addLocationDialog, locationTab);
257+ }
258+ }
259+
260+ Action {
261+ id: removeLocationAction
262+ property string cityCode: ''
263+ objectName: "action"
264+
265+ iconSource: Qt.resolvedUrl("../resources/images/remove_icon.png")
266+ text: i18n.tr("Remove")
267+
268+ onTriggered: {
269+ mainView.removeLocation(locationData.db.id)
270+ }
271+ }
272+ }
273+ }
274+
275+ ListModel {
276+ id: dayForecastModel
277+ }
278+
279+ Rectangle {
280+ id:startPage
281+ width: parent.width
282+ height: parent.height
283+
284+ Flickable {
285+ id: flickable
286+ width: parent.width
287+ height: parent.height
288+ contentHeight: flickContent.height;
289+ Rectangle {
290+ id: flickContent
291+ width:parent.width
292+ height: childrenRect.height
293+ DateComponent {
294+ id: todayDateComponent
295+ //dateRelative: i18n.tr("Today")
296+ borderTopVisible: false
297+ }
298+ CurrentWeather {
299+ id: currentCondition
300+ anchors.top: todayDateComponent.bottom
301+ condition: 801
302+ }
303+ /*ChartComponent{
304+ id: chartComponent
305+ anchors.top: currentCondition.bottom
306+ }*/
307+ ListView {
308+ id: dailyForecastList
309+ width: parent.width;
310+ height:childrenRect.height
311+ anchors.top: currentCondition.bottom
312+ model:dayForecastModel
313+ interactive: false
314+ delegate: Item {
315+ id: dailyForecastItem
316+ width:parent.width
317+ height: childrenRect.height
318+ DateComponent {
319+ id: dateComponent
320+ dateRelative: dateRel
321+ dateString: date
322+ }
323+ DayWeatherComponent {
324+ anchors.top: dateComponent.bottom
325+ temperature: temp
326+ temperatureMin: tempMin
327+ condition: cond
328+ }
329+ }
330+ }
331+ }
332+ }
333+ }
334+
335+}
336
337=== added file 'components/LocationTabEmpty.qml'
338--- components/LocationTabEmpty.qml 1970-01-01 00:00:00 +0000
339+++ components/LocationTabEmpty.qml 2013-04-20 18:49:27 +0000
340@@ -0,0 +1,35 @@
341+import QtQuick 2.0
342+import Ubuntu.Components.Popups 0.1
343+import Ubuntu.Components 0.1
344+
345+Tab {
346+ id: locationTabEmpty
347+
348+ title: i18n.tr("No Locations")
349+
350+ // Menu for options
351+ page: Page {
352+ anchors.fill: parent
353+ tools: ToolbarActions {
354+ Action {
355+ id: addLocationAction
356+ property string cityCode: ''
357+ objectName: "action"
358+
359+ iconSource: Qt.resolvedUrl("../resources/images/add_icon.png")
360+ text: i18n.tr("Add")
361+
362+ onTriggered: {
363+ PopupUtils.open(addLocationDialog, locationTabEmpty);
364+ }
365+ }
366+ }
367+
368+ Label {
369+ anchors.centerIn: parent;
370+ text: "Add one";
371+ }
372+
373+ }
374+
375+}
376
377=== modified file 'components/WeatherApi.js'
378--- components/WeatherApi.js 2013-03-28 12:33:37 +0000
379+++ components/WeatherApi.js 2013-04-20 18:49:27 +0000
380@@ -17,7 +17,7 @@
381 service_id: r.id,
382 name: r.name,
383 coord: r.coords,
384- country: (r.sys && r.sys.country) ? r.sys.country : null
385+ country: (r.sys && r.sys.country) ? r.sys.country : ""
386 });
387 })
388 return searchResult;
389@@ -206,7 +206,7 @@
390 if(response["current"] !== undefined && response["forecast"] !== undefined && response["daily"] !== undefined) {
391 onSuccess(response);
392 }
393- })
394+ });
395
396 this.getCurrentCondition(params, addDataToResponse, addDataToResponse)
397 this.getForecast(params, addDataToResponse, addDataToResponse);
398
399=== renamed file 'weather.qml' => 'ubuntu-weather-app.qml'
400--- weather.qml 2013-04-19 19:15:40 +0000
401+++ ubuntu-weather-app.qml 2013-04-20 18:49:27 +0000
402@@ -1,18 +1,85 @@
403 import QtQuick 2.0
404 import Ubuntu.Components 0.1
405+import "components" as Components
406 import Ubuntu.Components.Popups 0.1
407-import "components" as Components
408 import "components/WeatherApi.js" as Api
409
410 MainView {
411 // objectName for functional testing purposes (autopilot-qt5)
412 objectName: "weather"
413+ applicationName: "ubuntu-weather-app"
414+
415 id: mainView
416
417 width: units.gu(50)
418 height: units.gu(75)
419
420- property var resultList: null
421+ property var locationsList: []
422+ property var tabsObject: null
423+
424+ // see https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1124071, temporary workaround
425+ function buildTabs(locations) {
426+ locationsList = locations;
427+ if(tabsObject !== null) {
428+ tabsObject.destroy()
429+ }
430+ var locLength = locations.length,
431+ tabsString = "import QtQuick 2.0; import Ubuntu.Components 0.1; import Ubuntu.Components.Popups 0.1; import \"components\" as Components; "
432+ + "Tabs {id: tabs; anchors.fill: parent;"
433+ if(locLength > 0) {
434+ for(var x=0;x<locLength;x++) {
435+ tabsString += "Components.LocationTab {title: '"+locations[x].location.name+"'; locationIndex: "+x+"} "
436+ };
437+ } else {
438+ tabsString += "Components.LocationTabEmpty { }"
439+ }
440+ tabsString += "}"; // END Tabs componen
441+ tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs")
442+ }
443+
444+ function removeLocation(dbId) {
445+ storage.clearLocation(dbId);
446+ storage.getLocations(buildTabs);
447+ }
448+
449+ function locationAdded(locationObj) {
450+ Api.WeatherApi.getLocationData({location:locationObj, units: "metric"}, onNewLocationDataSuccess, onApiError);
451+ }
452+
453+ function onApiError(err) {
454+ // TODO show error popup
455+ console.log("onApiError")
456+ console.log(err.msg+" / "+err.request.url)
457+ }
458+
459+ function onNewLocationDataSuccess(resp) {
460+ var res = storage.insertLocation(resp);
461+ storage.getLocations(buildTabs);
462+ }
463+
464+ function refreshData() {
465+ storage.getLocations(function(locations) {
466+ var locLength = locations.length,
467+ locUpdated = 0;
468+ if(locLength > 0) {
469+ locations.forEach(function(loc) {
470+ var updatedHnd = function (newData) {
471+ locUpdated += 1;
472+ storage.updateLocation(loc.db.id, newData);
473+ if(locUpdated === locLength) {
474+ buildTabs(locations);
475+ }
476+ }
477+ Api.WeatherApi.getLocationData({location:loc.location, units: "metric"}, updatedHnd, onApiError);
478+ })
479+ } else buildTabs(locations);
480+ });
481+ }
482+
483+ Component.onCompleted: {
484+ //storage.clearDB();
485+ refreshData();
486+ }
487
488 Components.AddLocationDialog {
489 id: addLocationDialog
490@@ -22,169 +89,14 @@
491 id: storage
492 }
493
494- Tabs {
495- id: tabs
496- anchors.fill: parent
497-
498- // Location 1
499- Tab {
500- id: location1
501- objectName: "City1"
502-
503- title: i18n.tr("London")
504-
505- // Menu for options
506- page: Page {
507-
508- tools: ToolbarActions {
509- Action {
510- id: addLocationAction
511- property string cityCode: ''
512- objectName: "action"
513-
514- iconSource: Qt.resolvedUrl("resources/images/add_icon.png")
515- text: i18n.tr("Add")
516-
517- onTriggered: {
518- PopupUtils.open(addLocationDialog, location1);
519- }
520-
521- onCityCodeChanged: {
522- // Action for adding a new cityCode
523- console.log('DEBUG: cityCode has changed to '+cityCode);
524- }
525- }
526-
527- Action {
528- id: removeLocationAction
529- property string cityCode: ''
530- objectName: "action"
531-
532- iconSource: Qt.resolvedUrl("resources/images/remove_icon.png")
533- text: i18n.tr("Remove")
534-
535- onTriggered: {
536- // Action for removing a weather location
537- }
538- }
539- }
540-
541- Rectangle {
542- id: startPage
543- width: parent.width
544- height: parent.height
545- Flickable {
546- width: parent.width
547- height: parent.height
548- contentHeight: column1.height
549- Column {
550- id: column1
551- width: parent.width
552- Components.DateComponent {
553- dateRelative: "Today"
554- dateString:"Saturday, 9th February"
555- borderTopVisible: false
556- }
557- Components.CurrentWeather {
558- condition: 801
559- currentTemp: 20
560- minTemp: 12
561- maxTemp: 25
562- metric: true
563- }
564- Components.ChartComponent{
565-
566- }
567- Components.DateComponent {
568- dateRelative: "Tomorrow"
569- dateString:"Sunday, 10th February"
570- }
571- Components.DayWeatherComponent {
572- temperature: 22
573- temperatureMin: 11
574- condition: 801
575- }
576- Components.DateComponent {
577- dateString:"Monday, 11th February"
578- }
579- Components.DayWeatherComponent {
580- temperature: 22
581- temperatureMin: 11
582- condition: 801
583- }
584- Components.DateComponent {
585- dateString:"Tuesday, 12th February"
586- }
587- Components.DayWeatherComponent {
588- temperature: 22
589- temperatureMin: 11
590- condition: 801
591- }
592- }
593- }
594- }
595- }
596- }
597-
598- // Location 2
599- Tab {
600- objectName: "City2"
601-
602- title: i18n.tr("San Francisco")
603-
604- page: Page {
605-
606- Rectangle {
607- id: cityForecast2
608- width: parent.width
609- height: parent.height
610- Flickable {
611- width: parent.width
612- height: parent.height
613- contentHeight: column1.height
614- Column {
615- width: parent.width
616- Components.DateComponent {
617- dateRelative: "Today"
618- dateString:"Saturday, 9th February"
619- borderTopVisible: false
620- }
621- Components.CurrentWeather {
622- condition: 801
623- currentTemp: 11
624- minTemp: 8
625- maxTemp: 17
626- metric: true
627- }
628- Components.DateComponent {
629- dateRelative: "Tomorrow"
630- dateString:"Sunday, 10th February"
631- }
632- Components.DayWeatherComponent {
633- temperature: 18
634- temperatureMin: 10
635- condition: 801
636- }
637- Components.DateComponent {
638- dateString:"Monday, 11th February"
639- }
640- Components.DayWeatherComponent {
641- temperature: 20
642- temperatureMin: 10
643- condition: 801
644- }
645- Components.DateComponent {
646- dateString:"Tuesday, 12th February"
647- }
648- Components.DayWeatherComponent {
649- temperature: 20
650- temperatureMin: 11
651- condition: 801
652- }
653- }
654- }
655- }
656- }
657+ Page {
658+ id: tabPage
659+ title: "Simple page"
660+
661+ Tabs {
662+ id: tabs
663+ anchors.fill: parent
664+ Tab {}
665 }
666 }
667 }
668
669=== modified file 'weather.qmlproject'
670--- weather.qmlproject 2013-02-12 16:27:32 +0000
671+++ weather.qmlproject 2013-04-20 18:49:27 +0000
672@@ -3,7 +3,7 @@
673 import QmlProject 1.1
674
675 Project {
676- mainFile: "weather.qml"
677+ mainFile: "ubuntu-weather-app.qml"
678
679 /* Include .qml, .js, and image files from current directory and subdirectories */
680 QmlFiles {

Subscribers

People subscribed via source and target branches