Merge lp:~martin-borho/ubuntu-weather-app/location-manager into lp:ubuntu-weather-app/obsolete.trunk
- location-manager
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Raúl Yeguas |
Approved revision: | 40 |
Merged at revision: | 35 |
Proposed branch: | lp:~martin-borho/ubuntu-weather-app/location-manager |
Merge into: | lp:ubuntu-weather-app/obsolete.trunk |
Diff against target: |
625 lines (+293/-204) 6 files modified
components/AddLocationPage.qml (+70/-103) components/LocationManagerPage.qml (+174/-0) components/LocationTab.qml (+8/-29) components/LocationTabEmpty.qml (+0/-35) components/WeatherApi.js (+2/-4) ubuntu-weather-app.qml (+39/-33) |
To merge this branch: | bzr merge lp:~martin-borho/ubuntu-weather-app/location-manager |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Raúl Yeguas | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+169022@code.launchpad.net |
Commit message
Location manager added
Description of the change
* Added location manager for adding and removing location. Bug #1187314
* "Remove" action removed from toolbar, Bug #1187315
* at first start or when no locations are defined the location manager is shown.
* LocationTabEmpt
* PageStack component added to the app.
* LocationManagerPage added
* AddLocationDialog became AddLocationPage
* dummy item added in LocationManager for "Current location" like in http://
* disabled api requests for hourly forcasts until data will be used in the UI
* locations can be removed by sliding them from the locations list in location manager
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Raúl Yeguas (neokore) wrote : | # |
Great work again, Martin!
Preview Diff
1 | === renamed file 'components/AddLocationDialog.qml' => 'components/AddLocationPage.qml' |
2 | --- components/AddLocationDialog.qml 2013-06-09 15:42:41 +0000 |
3 | +++ components/AddLocationPage.qml 2013-06-12 17:57:26 +0000 |
4 | @@ -1,113 +1,79 @@ |
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 | - |
10 | -// Dialog for adding a new location |
11 | -Component { |
12 | - id: addLocationDialog |
13 | - |
14 | - Dialog { |
15 | - id: addLocationDialogue |
16 | - height: units.gu(10) |
17 | - title: i18n.tr("Add location") |
18 | - text: i18n.tr("Write a city name or pick it by your location") |
19 | - |
20 | - WorkerScript { |
21 | - id: searchWorker |
22 | - source: "./WeatherApi.js" |
23 | - onMessage: { |
24 | - if(!messageObject.error) { |
25 | - |
26 | - messageObject.result.locations.forEach(function(loc) { |
27 | - citiesModel.append(loc); |
28 | - }); |
29 | - } else { |
30 | - console.log(messageObject.error.msg+" / "+messageObject.error.request.url) |
31 | - } |
32 | - } |
33 | - } |
34 | - |
35 | - function locationSelected(index) { |
36 | - var location = citiesModel.get(index); |
37 | - // make clone |
38 | - location = JSON.parse(JSON.stringify(location)); |
39 | - mainView.locationAdded(location); |
40 | - PopupUtils.close(addLocationDialogue) |
41 | - } |
42 | - |
43 | - Row { |
44 | - TextField { |
45 | - id: locationString |
46 | - width: units.gu(25) |
47 | - placeholderText: i18n.tr("Enter a city name") |
48 | - } |
49 | - Button { |
50 | - id: locationSearchButton |
51 | - |
52 | - width: units.gu(5) |
53 | - iconSource: "../resources/images/search_icon.png" |
54 | - |
55 | - onClicked: { |
56 | - citiesModel.clear(); |
57 | - searchWorker.sendMessage({ |
58 | - action: "searchByName", |
59 | - params: {name:locationString.text, units:mainView.settings["units"]} |
60 | - }) |
61 | - } |
62 | - } |
63 | - } |
64 | - |
65 | - Button { |
66 | - id: locationGPSButton |
67 | - text: i18n.tr("Use my own location") |
68 | - onClicked: { |
69 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
70 | + |
71 | +Page { |
72 | + id: addLocationPage |
73 | + objectName: "AddLocationrPage" |
74 | + title: i18n.tr("Add city") |
75 | + visible: false |
76 | + tools.locked: true |
77 | + tools.opened: true |
78 | + |
79 | + WorkerScript { |
80 | + id: searchWorker |
81 | + source: "./WeatherApi.js" |
82 | + onMessage: { |
83 | + if(!messageObject.error) { |
84 | + messageObject.result.locations.forEach(function(loc) { |
85 | + citiesModel.append(loc); |
86 | + }); |
87 | + } else { |
88 | + console.log(messageObject.error.msg+" / "+messageObject.error.request.url) |
89 | + } |
90 | + } |
91 | + } |
92 | + |
93 | + function clear() { |
94 | + locationString.text = '' |
95 | + citiesModel.clear() |
96 | + } |
97 | + |
98 | + Rectangle { |
99 | + id: searchInput |
100 | + width:parent.width |
101 | + height:units.gu(7) |
102 | + color: "transparent" |
103 | + TextField { |
104 | + id: locationString |
105 | + width: parent.width-units.gu(2) |
106 | + height:units.gu(5) |
107 | + anchors.centerIn: parent |
108 | + placeholderText: i18n.tr("Enter a city name") |
109 | + hasClearButton: true |
110 | + onAccepted: { |
111 | citiesModel.clear(); |
112 | searchWorker.sendMessage({ |
113 | - action: "searchByPoint", |
114 | - params: {coords: {"lon":10,"lat":53.549999}, units:mainView.settings["units"]} |
115 | + action: "searchByName", |
116 | + params: {name:locationString.text, units:"metric"} |
117 | }) |
118 | } |
119 | } |
120 | - |
121 | - Button { |
122 | - id:locationCancelButton |
123 | - text: i18n.tr("Cancel") |
124 | - color: "#C00000" |
125 | - onClicked: PopupUtils.close(addLocationDialogue) |
126 | - } |
127 | - |
128 | - Item { |
129 | - id: locationResultBox |
130 | - anchors { |
131 | - top: locationCancelButton.bottom |
132 | - topMargin: units.gu(2) |
133 | - } |
134 | - } |
135 | - |
136 | - ListModel { |
137 | - id: citiesModel |
138 | - } |
139 | - |
140 | - Rectangle { |
141 | - id: cityList; |
142 | - width: units.gu(30); |
143 | - height: units.gu(30); |
144 | - color: "transparent"; |
145 | - ListView { |
146 | - id: listView; |
147 | - clip: true; |
148 | - anchors.fill: parent; |
149 | - model: citiesModel; |
150 | - delegate: ListItem.Standard { |
151 | - text: i18n.tr(name)+((country) ? ', '+i18n.tr(country): ''); |
152 | - progression: true; |
153 | - onClicked: { |
154 | - var tabsString = "import QtQuick 2.0; import Ubuntu.Components 0.1; import Ubuntu.Components.Popups 0.1;" |
155 | - + "Tabs {id: tabs; anchors.fill: parent; Tab { title: 'Loading...'; LoadingComponent{id:bigLoading; anchors.fill: parent; z: 2;}}}" |
156 | - tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs") |
157 | - locationSelected(index); |
158 | - } |
159 | + } |
160 | + |
161 | + ListModel { |
162 | + id: citiesModel |
163 | + } |
164 | + |
165 | + Rectangle { |
166 | + id: cityList; |
167 | + anchors.top: searchInput.bottom |
168 | + width: parent.width |
169 | + height: units.gu(52) |
170 | + color: "transparent" |
171 | + ListView { |
172 | + id: listView; |
173 | + clip: true; |
174 | + anchors.fill: parent; |
175 | + model: citiesModel; |
176 | + delegate: ListItem.Standard { |
177 | + text: i18n.tr(name)+((country) ? ', '+i18n.tr(country): ''); |
178 | + progression: true; |
179 | + onClicked: { |
180 | + var location = citiesModel.get(index) |
181 | + locationManager.addLocation(location) |
182 | + pageStack.pop() |
183 | + clear() |
184 | } |
185 | } |
186 | Scrollbar { |
187 | @@ -116,4 +82,5 @@ |
188 | } |
189 | } |
190 | } |
191 | + |
192 | } |
193 | |
194 | === added file 'components/LocationManagerPage.qml' |
195 | --- components/LocationManagerPage.qml 1970-01-01 00:00:00 +0000 |
196 | +++ components/LocationManagerPage.qml 2013-06-12 17:57:26 +0000 |
197 | @@ -0,0 +1,174 @@ |
198 | +import QtQuick 2.0 |
199 | +import Ubuntu.Components 0.1 |
200 | +import Ubuntu.Components.ListItems 0.1 as ListItem |
201 | +import Ubuntu.Components.Popups 0.1 |
202 | + |
203 | +Page { |
204 | + id: locationManagerPage |
205 | + objectName: "LocationManagerPage" |
206 | + title: i18n.tr("Edit locations") |
207 | + visible: false |
208 | + |
209 | + property bool locationsChanged: false |
210 | + |
211 | + tools: ToolbarActions { |
212 | + locked: true |
213 | + opened: (locationModel.count > 0) ? true : false |
214 | + back.onTriggered: { |
215 | + if(locationsChanged) { |
216 | + mainView.refreshData() |
217 | + locationsChanged = false; |
218 | + } |
219 | + // handle dummy "current location" item |
220 | + currentLocationItem.visible = false |
221 | + locationLookupItem.visible = true |
222 | + lookupItemAddButton.visible = true |
223 | + } |
224 | + } |
225 | + |
226 | + function loadData() { |
227 | + storage.getLocations(fillLocationsList); |
228 | + } |
229 | + |
230 | + function checkLocationExists(location) { |
231 | + for(var x=0;x<locationModel.count;x++) { |
232 | + var loc = locationModel.get(x); |
233 | + if(loc.service === location.service |
234 | + && loc.service_id === location.service_id) { |
235 | + existsNotification.show() |
236 | + return true; |
237 | + } |
238 | + } |
239 | + return false; |
240 | + } |
241 | + |
242 | + function fillLocationsList(locations) { |
243 | + locationModel.clear() |
244 | + for(var x=0;x<locations.length;x++) { |
245 | + var dbId = locations[x].db.id, |
246 | + location = locations[x].location; |
247 | + // add db-id to the location object |
248 | + location.dbId = dbId; |
249 | + locationModel.append(locations[x].location); |
250 | + } |
251 | + } |
252 | + |
253 | + function addLocation(location) { |
254 | + if(!checkLocationExists(location)) { |
255 | + storage.insertLocation({location:location}); |
256 | + loadData() |
257 | + locationsChanged = true; |
258 | + } |
259 | + } |
260 | + |
261 | + |
262 | + Dialog { |
263 | + id:existsNotification |
264 | + title: i18n.tr("Location already added.") |
265 | + Button { |
266 | + text: i18n.tr("OK") |
267 | + onClicked: PopupUtils.close(existsNotification) |
268 | + } |
269 | + } |
270 | + |
271 | + ListModel { |
272 | + id: locationModel |
273 | + } |
274 | + |
275 | + Column { |
276 | + anchors.fill: parent |
277 | + Rectangle { |
278 | + color: "#D6D6D6" |
279 | + width:parent.width |
280 | + height: units.gu(0.3) |
281 | + } |
282 | + Rectangle { |
283 | + width: parent.width |
284 | + height: units.gu(5) |
285 | + Label { |
286 | + anchors.verticalCenter: parent.verticalCenter |
287 | + text: " "+i18n.tr("Current location") |
288 | + fontSize: "large" |
289 | + } |
290 | + } |
291 | + Rectangle { |
292 | + color: "#D6D6D6" |
293 | + width:parent.width |
294 | + height: units.gu(0.3) |
295 | + } |
296 | + ListItem.Standard { |
297 | + id: locationLookupItem |
298 | + text: i18n.tr("Lookup location")+" (Dummy)" |
299 | + progression: true |
300 | + onClicked: { |
301 | + print("TODO: lookup current location") |
302 | + visible = false |
303 | + currentLocationItem.visible = true; |
304 | + } |
305 | + } |
306 | + ListItem.Standard { |
307 | + id: currentLocationItem |
308 | + visible: false |
309 | + text: i18n.tr("London") |
310 | + //icon: Qt.resolvedUrl("../resources/images/refresh_icon.png") |
311 | + control: Button { |
312 | + id: lookupItemAddButton |
313 | + anchors.verticalCenter: parent.verticalCenter |
314 | + text: i18n.tr("add") |
315 | + MouseArea { |
316 | + anchors.fill: parent |
317 | + onClicked: { |
318 | + // add dummy location |
319 | + addLocation({"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"}) |
320 | + lookupItemAddButton.visible = false; |
321 | + } |
322 | + } |
323 | + } |
324 | + } |
325 | + Rectangle { |
326 | + id:test2 |
327 | + width: parent.width |
328 | + height: units.gu(5) |
329 | + Label { |
330 | + anchors.verticalCenter: parent.verticalCenter |
331 | + text: " "+i18n.tr("World") |
332 | + fontSize: "large" |
333 | + } |
334 | + } |
335 | + Rectangle { |
336 | + color: "#D6D6D6" |
337 | + width:parent.width |
338 | + height: units.gu(0.3) |
339 | + } |
340 | + Rectangle { |
341 | + width: parent.width |
342 | + clip:true |
343 | + color:"transparent" |
344 | + height: units.gu(40) |
345 | + ListView { |
346 | + objectName: "locationList" |
347 | + anchors.fill: parent |
348 | + model: locationModel |
349 | + delegate: ListItem.Standard { |
350 | + text: model.name |
351 | + removable: true |
352 | + onItemRemoved: { |
353 | + var location = locationModel.get(index) |
354 | + locationsChanged = true; |
355 | + storage.clearLocation(location.dbId); |
356 | + locationModel.remove(index) |
357 | + } |
358 | + backgroundIndicator: Rectangle { |
359 | + anchors.fill: parent |
360 | + color: "gray" |
361 | + } |
362 | + } |
363 | + footer: ListItem.Standard { |
364 | + text: i18n.tr("Add city") |
365 | + progression: true |
366 | + onClicked: pageStack.push(addLocationPage) |
367 | + } |
368 | + } |
369 | + } |
370 | + } |
371 | +} |
372 | |
373 | === modified file 'components/LocationTab.qml' |
374 | --- components/LocationTab.qml 2013-06-12 17:08:05 +0000 |
375 | +++ components/LocationTab.qml 2013-06-12 17:57:26 +0000 |
376 | @@ -56,44 +56,23 @@ |
377 | |
378 | tools: ToolbarActions { |
379 | Action { |
380 | - id: addLocationAction |
381 | - property string cityCode: '' |
382 | - objectName: "action" |
383 | - |
384 | - iconSource: Qt.resolvedUrl("../resources/images/add_icon.png") |
385 | - text: i18n.tr("Add") |
386 | - |
387 | - onTriggered: { |
388 | - PopupUtils.open(addLocationDialog, locationTab); |
389 | - } |
390 | - } |
391 | - |
392 | - Action { |
393 | - id: removeLocationAction |
394 | - property string cityCode: '' |
395 | - objectName: "action" |
396 | - |
397 | - iconSource: Qt.resolvedUrl("../resources/images/remove_icon.png") |
398 | - text: i18n.tr("Remove") |
399 | - |
400 | - onTriggered: { |
401 | - mainView.removeLocation(locationData.db.id) |
402 | - } |
403 | - } |
404 | - |
405 | - Action { |
406 | id: refreshAction |
407 | iconSource: Qt.resolvedUrl("../resources/images/refresh_icon.png") |
408 | text: i18n.tr("Refresh") |
409 | |
410 | onTriggered: { |
411 | - var tabsString = "import QtQuick 2.0; import Ubuntu.Components 0.1; import Ubuntu.Components.Popups 0.1;" |
412 | - + "Tabs {id: tabs; anchors.fill: parent; Tab { title: 'Loading...'; LoadingComponent{id:bigLoading; anchors.fill: parent; z: 2;}}}" |
413 | - tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs") |
414 | mainView.refreshData(); |
415 | } |
416 | } |
417 | + Action { |
418 | + id: editLocationAction |
419 | + iconSource: Qt.resolvedUrl("../resources/images/add_icon.png") |
420 | + text: i18n.tr("Edit") |
421 | |
422 | + onTriggered: { |
423 | + mainView.showLocationManager() |
424 | + } |
425 | + } |
426 | Action { |
427 | id: configAction |
428 | iconSource: Qt.resolvedUrl("../resources/images/refresh_icon.png") |
429 | |
430 | === removed file 'components/LocationTabEmpty.qml' |
431 | --- components/LocationTabEmpty.qml 2013-04-20 16:17:57 +0000 |
432 | +++ components/LocationTabEmpty.qml 1970-01-01 00:00:00 +0000 |
433 | @@ -1,35 +0,0 @@ |
434 | -import QtQuick 2.0 |
435 | -import Ubuntu.Components.Popups 0.1 |
436 | -import Ubuntu.Components 0.1 |
437 | - |
438 | -Tab { |
439 | - id: locationTabEmpty |
440 | - |
441 | - title: i18n.tr("No Locations") |
442 | - |
443 | - // Menu for options |
444 | - page: Page { |
445 | - anchors.fill: parent |
446 | - tools: ToolbarActions { |
447 | - Action { |
448 | - id: addLocationAction |
449 | - property string cityCode: '' |
450 | - objectName: "action" |
451 | - |
452 | - iconSource: Qt.resolvedUrl("../resources/images/add_icon.png") |
453 | - text: i18n.tr("Add") |
454 | - |
455 | - onTriggered: { |
456 | - PopupUtils.open(addLocationDialog, locationTabEmpty); |
457 | - } |
458 | - } |
459 | - } |
460 | - |
461 | - Label { |
462 | - anchors.centerIn: parent; |
463 | - text: "Add one"; |
464 | - } |
465 | - |
466 | - } |
467 | - |
468 | -} |
469 | |
470 | === modified file 'components/WeatherApi.js' |
471 | --- components/WeatherApi.js 2013-06-09 15:42:41 +0000 |
472 | +++ components/WeatherApi.js 2013-06-12 17:57:26 +0000 |
473 | @@ -233,7 +233,7 @@ |
474 | addDataToResponse = (function(data) { |
475 | response[data.request.type] = data; |
476 | if(response["current"] !== undefined |
477 | - && response["forecast"] !== undefined |
478 | + //&& response["forecast"] !== undefined |
479 | && response["daily"] !== undefined) { |
480 | onSuccess(response); |
481 | } |
482 | @@ -248,7 +248,7 @@ |
483 | }) |
484 | |
485 | this.getCurrentCondition(params, addDataToResponse, retryHandler); |
486 | - this.getForecast(params, addDataToResponse, retryHandler); |
487 | + //this.getForecast(params, addDataToResponse, retryHandler); |
488 | this.getDailyForecast(params, addDataToResponse, retryHandler); |
489 | } |
490 | } |
491 | @@ -285,8 +285,6 @@ |
492 | WeatherApi.search("name", message.params, finished, onError); |
493 | } else if(message.action === "searchByPoint") { |
494 | WeatherApi.search("point", message.params, finished, onError); |
495 | - } else if(message.action === "newLocationData") { |
496 | - WeatherApi.getLocationData(message.params, finished, onError); |
497 | } else if(message.action === "updateData") { |
498 | var locLength = message.params.locations.length, |
499 | locUpdated = 0, |
500 | |
501 | === modified file 'ubuntu-weather-app.qml' |
502 | --- ubuntu-weather-app.qml 2013-06-12 17:08:05 +0000 |
503 | +++ ubuntu-weather-app.qml 2013-06-12 17:57:26 +0000 |
504 | @@ -28,8 +28,6 @@ |
505 | storage.updateLocation(loc.db.id, loc); |
506 | }); |
507 | buildTabs(messageObject.result); |
508 | - } else if(messageObject.action === "newLocationData") { |
509 | - onNewLocationDataSuccess(messageObject.result); |
510 | } |
511 | } else { |
512 | console.log(messageObject.error.msg+" / "+messageObject.error.request.url) |
513 | @@ -43,6 +41,12 @@ |
514 | var locLength = locations.length, |
515 | locBeforeLen = locationsList.length, |
516 | focusToLast = (locBeforeLen > 0 && locLength > locBeforeLen) ? true : false; |
517 | + // show locationmanager when no location is added |
518 | + if(locLength === 0) { |
519 | + showLocationManager() |
520 | + return; |
521 | + } |
522 | + |
523 | locationsList = locations; |
524 | if(tabsObject !== null) { |
525 | tabsObject.destroy() |
526 | @@ -53,8 +57,6 @@ |
527 | for(var x=0;x<locLength;x++) { |
528 | tabsString += "Components.LocationTab {title: '"+locations[x].location.name+"'; locationIndex: "+x+"} " |
529 | }; |
530 | - } else { |
531 | - tabsString += "Components.LocationTabEmpty { }" |
532 | } |
533 | tabsString += "}"; // END Tabs componen |
534 | if(bigLoading !== null) |
535 | @@ -65,24 +67,9 @@ |
536 | tabsObject.selectedTabIndex = locLength -1; |
537 | } |
538 | |
539 | - function removeLocation(dbId) { |
540 | - storage.clearLocation(dbId); |
541 | - storage.getLocations(buildTabs); |
542 | - } |
543 | - |
544 | - function locationAdded(locationObj) { |
545 | - locationDataWorker.sendMessage({ |
546 | - action: "newLocationData", |
547 | - params: {location:locationObj, units:settings["units"]} |
548 | - }); |
549 | - } |
550 | - |
551 | - function onNewLocationDataSuccess(resp) { |
552 | - var res = storage.insertLocation(resp); |
553 | - storage.getLocations(buildTabs); |
554 | - } |
555 | - |
556 | function refreshData() { |
557 | + if(bigLoading === null) |
558 | + loading.running = true; |
559 | storage.getLocations(function(locations) { |
560 | locationDataWorker.sendMessage({ |
561 | action: "updateData", |
562 | @@ -91,6 +78,11 @@ |
563 | }); |
564 | } |
565 | |
566 | + function showLocationManager() { |
567 | + pageStack.push(locationManager) |
568 | + locationManager.loadData() |
569 | + } |
570 | + |
571 | Component.onCompleted: { |
572 | //storage.clearDB(); |
573 | //storage.clearSetting('units'); |
574 | @@ -103,7 +95,7 @@ |
575 | }) |
576 | } |
577 | |
578 | - Components.AddLocationDialog { |
579 | + Components.AddLocationPage { |
580 | id: addLocationDialog |
581 | } |
582 | |
583 | @@ -115,17 +107,31 @@ |
584 | id: storage |
585 | } |
586 | |
587 | - Page { |
588 | - id: tabPage |
589 | - title: "Simple page" |
590 | - ActivityIndicator{id:loading; running: false; z: 1; anchors{top: parent.top; topMargin: units.gu(0.5); right: parent.right; rightMargin: units.gu(1)}} |
591 | - Tabs { |
592 | - id: tabs |
593 | - objectName: "Tabs" |
594 | - anchors.fill: parent |
595 | - Tab { |
596 | - title: "Loading..." |
597 | - Components.LoadingComponent{id:bigLoading; anchors.fill: parent; z: 2;} |
598 | + Components.LocationManagerPage { |
599 | + id:locationManager |
600 | + } |
601 | + |
602 | + Components.AddLocationPage { |
603 | + id:addLocationPage |
604 | + } |
605 | + |
606 | + PageStack { |
607 | + id: pageStack |
608 | + Component.onCompleted: push(tabPage) |
609 | + |
610 | + Page { |
611 | + id: tabPage |
612 | + title: "Simple page" |
613 | + visible: false |
614 | + ActivityIndicator{id:loading; running: false; z: 1; anchors{top: parent.top; topMargin: units.gu(0.5); right: parent.right; rightMargin: units.gu(1)}} |
615 | + Tabs { |
616 | + id: tabs |
617 | + objectName: "Tabs" |
618 | + anchors.fill: parent |
619 | + Tab { |
620 | + title: "Loading..." |
621 | + Components.LoadingComponent{id:bigLoading; anchors.fill: parent; z: 2;} |
622 | + } |
623 | } |
624 | } |
625 | } |
PASSED: Continuous integration, rev:40 91.189. 93.125: 8080/job/ ubuntu- weather- app-ci/ 19/ 91.189. 93.125: 8080/job/ ubuntu- weather- app-quantal- amd64-ci/ 16 91.189. 93.125: 8080/job/ ubuntu- weather- app-raring- amd64-ci/ 19
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.125: 8080/job/ ubuntu- weather- app-ci/ 19/rebuild
http://