Merge lp:~martin-borho/ubuntu-weather-app/pagestack into lp:ubuntu-weather-app/obsolete.trunk
- pagestack
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Alan Pope πΊπ§π± π¦ |
Approved revision: | 348 |
Merged at revision: | 355 |
Proposed branch: | lp:~martin-borho/ubuntu-weather-app/pagestack |
Merge into: | lp:ubuntu-weather-app/obsolete.trunk |
Diff against target: |
1503 lines (+580/-550) 9 files modified
components/AddLocationPage.qml (+117/-96) components/LocationManagerPage.qml (+157/-152) components/SettingsPage.qml (+194/-0) components/SettingsSheet.qml (+0/-195) tests/autopilot/ubuntu_weather_app/emulators.py (+0/-45) tests/autopilot/ubuntu_weather_app/tests/__init__.py (+74/-19) tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py (+15/-14) tests/autopilot/ubuntu_weather_app/tests/test_settings.py (+18/-16) ubuntu-weather-app.qml (+5/-13) |
To merge this branch: | bzr merge lp:~martin-borho/ubuntu-weather-app/pagestack |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Alan Pope πΊπ§π± π¦ (community) | Needs Fixing | ||
Review via email: mp+231093@code.launchpad.net |
Commit message
Replaced used Sheet components for settings and managing locations with Page components.
Description of the change
Replaced the Sheet components used for settings and managing locations with Page components. No extra confirm button anymore.
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:341
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Pope πΊπ§π± π¦ (popey) wrote : | # |
Looks good, thanks Martin!
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
None: http://
FAILURE: http://
SUCCESS: http://
Martin Borho (martin-borho) wrote : | # |
balloons ran in this yesterday too, seems like a jenkins related issue...
https:/
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:341
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:341
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:341
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:342
http://
Executed test runs:
FAILURE: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:343
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:344
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:345
http://
Executed test runs:
FAILURE: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:346
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Alan Pope πΊπ§π± π¦ (popey) wrote : | # |
Tried running the tests locally on my nexus 4 and they fail here. http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:346
http://
Executed test runs:
FAILURE: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Martin Borho (martin-borho) wrote : | # |
popey: test on devices shuldbe fixed when https:/
But the jenkins errors I can't reproduce neither on device nor on desktop... and I have no clue why.
Some files were removed/added, should the deb-version get increased perhaps?
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:347
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Martin Borho (martin-borho) wrote : | # |
\o/
Alan Pope πΊπ§π± π¦ (popey) wrote : | # |
Sweet!
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
None: http://
FAILURE: http://
deb: http://
FAILURE: http://
- 348. By Martin Borho
-
merged from trunk, fixed conflict
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:348
http://
Executed test runs:
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === renamed file 'components/AddLocationSheet.qml' => 'components/AddLocationPage.qml' |
2 | --- components/AddLocationSheet.qml 2014-09-02 07:21:28 +0000 |
3 | +++ components/AddLocationPage.qml 2014-09-04 17:21:39 +0000 |
4 | @@ -25,102 +25,122 @@ |
5 | import "WeatherApi.js" as WeatherApi |
6 | import "CitiesList.js" as Cities |
7 | |
8 | -Component { |
9 | - |
10 | - DefaultSheet { |
11 | - id: addLocationSheet |
12 | - objectName: "AddLocationSheet" |
13 | - title: i18n.tr("Add city") |
14 | - contentsHeight: parent.height |
15 | - contentsWidth: parent.width |
16 | - doneButton: false |
17 | - |
18 | - Component.onCompleted: { |
19 | - Cities.preList.forEach(function(loc) { |
20 | - citiesModel.append(loc) |
21 | - }) |
22 | - } |
23 | - |
24 | - Connections { |
25 | - target: mainView |
26 | - onEscapeKey: { |
27 | - PopupUtils.close(addLocationSheet) |
28 | - clear() |
29 | - } |
30 | - } |
31 | - |
32 | - function searchResponseHandler(messageObject) { |
33 | - searching.running = false; |
34 | - if(!messageObject.error) { |
35 | - listView.visible = true |
36 | - var results = [], |
37 | +Page { |
38 | + id: addLocationPage |
39 | + objectName: "AddLocationPage" |
40 | + title: i18n.tr("Add city") |
41 | + anchors.fill: parent |
42 | + visible: false |
43 | + |
44 | + readonly property real headerHeight: units.gu(9.5) |
45 | + readonly property real bottomHeight: units.gu(9.5) |
46 | + |
47 | + property variant addCallback: null |
48 | + |
49 | + Connections { |
50 | + target: mainView |
51 | + onEscapeKey: { |
52 | + pageStack.pop() |
53 | + clear() |
54 | + } |
55 | + } |
56 | + |
57 | + head.backAction: Action { |
58 | + iconName: "back" |
59 | + visible: true |
60 | + onTriggered: { |
61 | + pageStack.pop() |
62 | + } |
63 | + } |
64 | + |
65 | + Component.onCompleted: { |
66 | + Cities.preList.forEach(function(loc) { |
67 | + citiesModel.append(loc) |
68 | + }) |
69 | + console.log(addCallback) |
70 | + } |
71 | + |
72 | + function searchResponseHandler(messageObject) { |
73 | + searching.running = false; |
74 | + if(!messageObject.error) { |
75 | + listView.visible = true |
76 | + var results = [], |
77 | a1Counts = {}, |
78 | - a3Counts = {}, |
79 | - location; |
80 | - // build a temp list and count the adminAreas |
81 | - messageObject.result.locations.forEach(function(loc) { |
82 | - a1Counts[loc.name+loc.adminName1] = (!a1Counts[loc.name+loc.adminName1]) ? 1 : a1Counts[loc.name+loc.adminName1]+1; |
83 | - a3Counts[loc.name+loc.adminName3] = (!a3Counts[loc.name+loc.adminName3]) ? 1 : a3Counts[loc.name+loc.adminName3]+1; |
84 | - results.push(loc); |
85 | - }); |
86 | - // append results to the model and build a distinct subtitle |
87 | - for(var x=0;x<results.length;x++) { |
88 | - location = results[x]; |
89 | - location["areaLabel"] = buildAreaLabel(location, a1Counts ,a3Counts) |
90 | - citiesModel.append(location); |
91 | - noCityError.visible = false |
92 | - } |
93 | - // |
94 | - if (!citiesModel.count) { |
95 | - noCityError.visible = true |
96 | - noCityError.text = i18n.tr("No location was found for %1").arg(locationString.text) |
97 | - } |
98 | - } else { |
99 | - console.log("search: "+messageObject.error.msg+" / "+messageObject.error.request.url) |
100 | - httpFailedSearch.show(); |
101 | - } |
102 | - } |
103 | - |
104 | - function buildAreaLabel(loc, a1Counts, a3Counts) { |
105 | - var label = ""; |
106 | - label += ((loc.adminName1) ? loc.adminName1.replace(/ Region$/,'')+", ":""); |
107 | - label += ((loc.adminName2 && a1Counts[loc.name+loc.adminName1] > 1 && a3Counts[loc.name+loc.adminName3] > 1) ? loc.adminName2.replace(/ Region$/,'')+", ":""); |
108 | - label += ((loc.adminName3 && a1Counts[loc.name+loc.adminName1] > 1) ? loc.adminName3.replace(/ Region$/,'')+", ":""); |
109 | - label += ((Countries.codes[loc.country]) ? i18n.tr(Countries.codes[loc.country]): loc.country); |
110 | - return label; |
111 | - } |
112 | - |
113 | - function clear() { |
114 | - locationString.text = ''; |
115 | + a3Counts = {}, |
116 | + location; |
117 | + // build a temp list and count the adminAreas |
118 | + messageObject.result.locations.forEach(function(loc) { |
119 | + a1Counts[loc.name+loc.adminName1] = (!a1Counts[loc.name+loc.adminName1]) ? 1 : a1Counts[loc.name+loc.adminName1]+1; |
120 | + a3Counts[loc.name+loc.adminName3] = (!a3Counts[loc.name+loc.adminName3]) ? 1 : a3Counts[loc.name+loc.adminName3]+1; |
121 | + results.push(loc); |
122 | + }); |
123 | + // append results to the model and build a distinct subtitle |
124 | + for(var x=0;x<results.length;x++) { |
125 | + location = results[x]; |
126 | + location["areaLabel"] = buildAreaLabel(location, a1Counts ,a3Counts) |
127 | + citiesModel.append(location); |
128 | + noCityError.visible = false |
129 | + } |
130 | + // |
131 | + if (!citiesModel.count) { |
132 | + noCityError.visible = true |
133 | + noCityError.text = i18n.tr("No location was found for %1").arg(locationString.text) |
134 | + } |
135 | + } else { |
136 | + console.log("search: "+messageObject.error.msg+" / "+messageObject.error.request.url) |
137 | + httpFailedSearch.show(); |
138 | + } |
139 | + } |
140 | + |
141 | + function buildAreaLabel(loc, a1Counts, a3Counts) { |
142 | + var label = ""; |
143 | + label += ((loc.adminName1) ? loc.adminName1.replace(/ Region$/,'')+", ":""); |
144 | + label += ((loc.adminName2 && a1Counts[loc.name+loc.adminName1] > 1 && a3Counts[loc.name+loc.adminName3] > 1) ? loc.adminName2.replace(/ Region$/,'')+", ":""); |
145 | + label += ((loc.adminName3 && a1Counts[loc.name+loc.adminName1] > 1) ? loc.adminName3.replace(/ Region$/,'')+", ":""); |
146 | + label += ((Countries.codes[loc.country]) ? i18n.tr(Countries.codes[loc.country]): loc.country); |
147 | + return label; |
148 | + } |
149 | + |
150 | + function clear() { |
151 | + locationString.text = ''; |
152 | + citiesModel.clear(); |
153 | + listView.visible = true; |
154 | + } |
155 | + |
156 | + function doSearch() { |
157 | + if(locationString.text !== "") { |
158 | + cityList.visible = true |
159 | citiesModel.clear(); |
160 | - listView.visible = true; |
161 | - } |
162 | - |
163 | - function doSearch() { |
164 | - if(locationString.text !== "") { |
165 | - cityList.visible = true |
166 | - citiesModel.clear(); |
167 | - searching.running = true; |
168 | - WeatherApi.sendRequest({ |
169 | - action: "searchByName", |
170 | - params: {name:locationString.text, units:"metric"} |
171 | - }, searchResponseHandler) |
172 | - } |
173 | - } |
174 | - |
175 | - SplashComponent { |
176 | - id: httpFailedSearch |
177 | - objectName: "HTTPFailedSearch" |
178 | - } |
179 | - |
180 | - ListModel { |
181 | - id: citiesModel |
182 | - } |
183 | - |
184 | - container: Item { |
185 | + searching.running = true; |
186 | + WeatherApi.sendRequest({ |
187 | + action: "searchByName", |
188 | + params: {name:locationString.text, units:"metric"} |
189 | + }, searchResponseHandler) |
190 | + } |
191 | + } |
192 | + |
193 | + SplashComponent { |
194 | + id: httpFailedSearch |
195 | + objectName: "HTTPFailedSearch" |
196 | + } |
197 | + |
198 | + ListModel { |
199 | + id: citiesModel |
200 | + } |
201 | + |
202 | + Rectangle { |
203 | + anchors.fill:parent |
204 | + color: "lightgrey" |
205 | + |
206 | + Item { |
207 | anchors { |
208 | + top:parent.top |
209 | + topMargin:headerHeight+units.gu(1) |
210 | + margins: units.gu(2) |
211 | right: parent.right |
212 | left: parent.left |
213 | + bottom: parent.bottom |
214 | + bottomMargin:bottomHeight |
215 | } |
216 | Rectangle { |
217 | id: searchInput |
218 | @@ -134,7 +154,7 @@ |
219 | color: "transparent" |
220 | TextField { |
221 | id: locationString |
222 | - objectName: "SearchField" |
223 | + objectName: "SearchField" |
224 | anchors.fill: parent |
225 | placeholderText: i18n.tr("Enter a city name") |
226 | hasClearButton: true |
227 | @@ -184,7 +204,7 @@ |
228 | left: parent.left |
229 | right: parent.right |
230 | } |
231 | - height: addLocationSheet.height-searchInput.height-units.gu(9.5) |
232 | + height: addLocationPage.height-searchInput.height-units.gu(9.5) |
233 | color: "transparent" |
234 | visible: true |
235 | Label { |
236 | @@ -214,7 +234,7 @@ |
237 | fontSize: "medium" |
238 | } |
239 | } |
240 | - } |
241 | + } |
242 | ListView { |
243 | id: listView; |
244 | objectName: "SearchResultList" |
245 | @@ -256,8 +276,8 @@ |
246 | } |
247 | onClicked: { |
248 | var location = citiesModel.get(index) |
249 | - locationManagerSheet.addLocation(location) |
250 | - PopupUtils.close(addLocationSheet) |
251 | + locationManagerPage.addLocation(location) |
252 | + pageStack.pop() |
253 | clear() |
254 | } |
255 | } |
256 | @@ -269,4 +289,5 @@ |
257 | } |
258 | } |
259 | } |
260 | + |
261 | } |
262 | |
263 | === renamed file 'components/LocationManagerSheet.qml' => 'components/LocationManagerPage.qml' |
264 | --- components/LocationManagerSheet.qml 2014-09-02 07:21:28 +0000 |
265 | +++ components/LocationManagerPage.qml 2014-09-04 17:21:39 +0000 |
266 | @@ -24,93 +24,152 @@ |
267 | import "CountryCodes.js" as Countries |
268 | import "WeatherApi.js" as WeatherApi |
269 | |
270 | -Component { |
271 | - id: locationManagerComponent |
272 | - |
273 | - ComposerSheet { |
274 | - id: locationManagerSheet |
275 | - objectName: "LocationManagerSheet" |
276 | - title: i18n.tr("Edit locations") |
277 | - contentsHeight: parent.height |
278 | - contentsWidth: parent.width |
279 | - |
280 | - property int initial_sum: 0 |
281 | - property bool limited: (locationModel.count > 7) |
282 | - |
283 | - signal cancelSheet() |
284 | - onCancelSheet: { |
285 | - if(initial_sum === 0) { |
286 | - // refresh mainview to land again here, |
287 | - // when no locations were defined when |
288 | - // opening the sheet |
289 | - mainView.refreshData() |
290 | - } else { |
291 | +Page { |
292 | + id: locationManagerPage |
293 | + objectName: "LocationManagerPage" |
294 | + title: i18n.tr("Edit locations") |
295 | + anchors.fill: parent |
296 | + visible: false |
297 | + |
298 | + readonly property real headerHeight: units.gu(9.5) |
299 | + readonly property real bottomHeight: units.gu(9.5) |
300 | + |
301 | + property int initial_sum: 0 |
302 | + property bool limited: (locationModel.count > 7) |
303 | + |
304 | + head.backAction: Action { |
305 | + iconName: "back" |
306 | + onTriggered: { |
307 | + var locationsChanged = false, |
308 | + refresh = false; |
309 | + // remove |
310 | + for(var x=0;x<locationsRemoved.count;x++) { |
311 | + var delLoc = locationsRemoved.get(x); |
312 | + storage.clearLocation(delLoc.dbId); |
313 | + locationsChanged = true; |
314 | + } |
315 | + // add |
316 | + for(var y=0;y<locationModel.count;y++) { |
317 | + var loc = locationModel.get(y); |
318 | + if(loc.dbId === undefined || loc.dbId=== 0) { |
319 | + storage.insertLocation({location:loc}); |
320 | + locationsChanged = true; |
321 | + } |
322 | + } |
323 | + // refresh tabs if neccessary |
324 | + if(locationsChanged || locationModel.count === 0) { |
325 | + refresh = true; |
326 | + } |
327 | + // handle dummy "current location" item |
328 | + currentLocationItem.visible = false |
329 | + locationLookupItem.visible = true |
330 | + lookupItemAddButton.visible = true |
331 | + mainView.shortCutsLimited = false; |
332 | + if(locationModel.count > 0) { |
333 | + // reset text color |
334 | Theme.palette.selected.backgroundText = "#f4f4e8" |
335 | - } |
336 | - mainView.shortCutsLimited = false; |
337 | - PopupUtils.close(locationManagerSheet) |
338 | - } |
339 | - Connections { target: mainView; onEscapeKey: cancelSheet()} |
340 | - |
341 | - Component.onCompleted: { |
342 | - mainView.shortCutsLimited = true; |
343 | - locationsRemoved.clear(); |
344 | - loadData(); |
345 | - Theme.palette.selected.backgroundText = "#656565" |
346 | - } |
347 | - |
348 | - function lookupResponseHandler(messageObject) { |
349 | - lookupIndicator.running = false; |
350 | - if(!messageObject.error) { |
351 | - if(messageObject.result.locations && messageObject.result.locations.length > 0) { |
352 | - var location = messageObject.result.locations[0]; |
353 | - currentLocationItem.detectedLocation = location; |
354 | - currentLocationLabel.text = location.name |
355 | - currentLocationAreaLabel.text = location.adminName1 |
356 | - locationLookupItem.visible = false |
357 | - currentLocationItem.visible = true; |
358 | - } |
359 | - } else { |
360 | - console.log("search: "+messageObject.error.msg+" / "+messageObject.error.request.url) |
361 | - httpFailedLookup.show(); |
362 | - } |
363 | - } |
364 | - |
365 | - function loadData() { |
366 | - storage.getLocations(fillLocationsList); |
367 | - } |
368 | - |
369 | - function checkLocationExists(location) { |
370 | - for(var x=0;x<locationModel.count;x++) { |
371 | - var loc = locationModel.get(x); |
372 | - if(loc.services.geonames && (loc.services.geonames === location.services.geonames)) { |
373 | - existsNotification.show() |
374 | - return true; |
375 | - } |
376 | - } |
377 | - return false; |
378 | - } |
379 | - |
380 | - function fillLocationsList(locations) { |
381 | - initial_sum = locations.length; |
382 | - locationModel.clear() |
383 | - for(var x=0;x<locations.length;x++) { |
384 | - var dbId = locations[x].db.id, |
385 | + popFromStack(refresh) |
386 | + } |
387 | + } |
388 | + } |
389 | + |
390 | + Component.onCompleted: { |
391 | + mainView.shortCutsLimited = true; |
392 | + locationsRemoved.clear(); |
393 | + loadData(); |
394 | + Theme.palette.selected.backgroundText = "#656565" |
395 | + } |
396 | + |
397 | + Connections { target: mainView; onEscapeKey: popFromStack()} |
398 | + |
399 | + function popFromStack(refresh) { |
400 | + Theme.palette.selected.backgroundText = "#f3f3e7" |
401 | + pageStack.pop() |
402 | + // refresh at least from storage, to prevent header content from disapearing |
403 | + refreshData(!refresh, refresh); |
404 | + } |
405 | + |
406 | + function lookupResponseHandler(messageObject) { |
407 | + lookupIndicator.running = false; |
408 | + if(!messageObject.error) { |
409 | + if(messageObject.result.locations && messageObject.result.locations.length > 0) { |
410 | + var location = messageObject.result.locations[0]; |
411 | + currentLocationItem.detectedLocation = location; |
412 | + currentLocationLabel.text = location.name |
413 | + currentLocationAreaLabel.text = location.adminName1 |
414 | + locationLookupItem.visible = false |
415 | + currentLocationItem.visible = true; |
416 | + } |
417 | + } else { |
418 | + console.log("search: "+messageObject.error.msg+" / "+messageObject.error.request.url) |
419 | + httpFailedLookup.show(); |
420 | + } |
421 | + } |
422 | + |
423 | + function loadData() { |
424 | + storage.getLocations(fillLocationsList); |
425 | + } |
426 | + |
427 | + function checkLocationExists(location) { |
428 | + for(var x=0;x<locationModel.count;x++) { |
429 | + var loc = locationModel.get(x); |
430 | + if(loc.services.geonames && (loc.services.geonames === location.services.geonames)) { |
431 | + existsNotification.show() |
432 | + return true; |
433 | + } |
434 | + } |
435 | + return false; |
436 | + } |
437 | + |
438 | + function fillLocationsList(locations) { |
439 | + initial_sum = locations.length; |
440 | + locationModel.clear() |
441 | + for(var x=0;x<locations.length;x++) { |
442 | + var dbId = locations[x].db.id, |
443 | location = locations[x].location; |
444 | - // add db-id to the location object |
445 | - location.dbId = dbId; |
446 | - locationModel.append(locations[x].location); |
447 | - } |
448 | - } |
449 | - |
450 | - function addLocation(location) { |
451 | - if(!checkLocationExists(location)) { |
452 | - locationModel.append(location) |
453 | - } |
454 | - } |
455 | - |
456 | - container: Column { |
457 | - anchors.fill: parent |
458 | + // add db-id to the location object |
459 | + location.dbId = dbId; |
460 | + locationModel.append(locations[x].location); |
461 | + } |
462 | + } |
463 | + |
464 | + function addLocation(location) { |
465 | + if(!checkLocationExists(location)) { |
466 | + locationModel.append(location) |
467 | + } |
468 | + } |
469 | + |
470 | + Dialog { |
471 | + id:existsNotification |
472 | + title: i18n.tr("Location already added.") |
473 | + Button { |
474 | + text: i18n.tr("OK") |
475 | + onClicked: PopupUtils.close(existsNotification) |
476 | + } |
477 | + } |
478 | + |
479 | + ListModel { |
480 | + id: locationModel |
481 | + } |
482 | + |
483 | + ListModel { |
484 | + id: locationsRemoved |
485 | + } |
486 | + |
487 | + Rectangle { |
488 | + anchors.fill:parent |
489 | + color: "lightgrey" |
490 | + |
491 | + Column { |
492 | + anchors { |
493 | + top:parent.top |
494 | + topMargin:headerHeight |
495 | + margins: units.gu(2) |
496 | + right: parent.right |
497 | + left: parent.left |
498 | + bottom: parent.bottom |
499 | + bottomMargin:bottomHeight |
500 | + } |
501 | Rectangle { |
502 | anchors { |
503 | left:parent.left |
504 | @@ -161,12 +220,12 @@ |
505 | anchors.left: parent.left |
506 | anchors.leftMargin: units.gu(3) |
507 | } |
508 | - onClicked: { |
509 | + onClicked: { |
510 | lookupIndicator.running = true; |
511 | WeatherApi.sendRequest({ |
512 | - action: "getGeoIp", |
513 | - params: {} |
514 | - }, lookupResponseHandler); |
515 | + action: "getGeoIp", |
516 | + params: {} |
517 | + }, lookupResponseHandler); |
518 | } |
519 | } |
520 | ListItem.Standard { |
521 | @@ -181,7 +240,7 @@ |
522 | objectName: "CurrentLocationLabel" |
523 | text: "" |
524 | elide: Text.ElideRight |
525 | - anchors { |
526 | + anchors { |
527 | top: parent.top |
528 | topMargin: units.gu(0.5) |
529 | left: parent.left |
530 | @@ -255,7 +314,7 @@ |
531 | } |
532 | clip:true |
533 | color:"transparent" |
534 | - height: locationManagerSheet.height-locationLookupItem.height-units.gu(19.2) |
535 | + height: locationManagerPage.height-locationLookupItem.height-units.gu(19.2) |
536 | ListView { |
537 | objectName: "LocationList" |
538 | anchors.fill: parent |
539 | @@ -338,71 +397,17 @@ |
540 | fontSize: "small" |
541 | } |
542 | onClicked: { |
543 | - PopupUtils.open(addLocationSheet) |
544 | + pageStack.push(Qt.createComponent("AddLocationPage.qml")) |
545 | } |
546 | } |
547 | } |
548 | } |
549 | } |
550 | - |
551 | - Dialog { |
552 | - id:existsNotification |
553 | - title: i18n.tr("Location already added.") |
554 | - Button { |
555 | - text: i18n.tr("OK") |
556 | - onClicked: PopupUtils.close(existsNotification) |
557 | - } |
558 | - } |
559 | - |
560 | - ListModel { |
561 | - id: locationModel |
562 | - } |
563 | - |
564 | - ListModel { |
565 | - id: locationsRemoved |
566 | - } |
567 | - |
568 | - onConfirmClicked: { |
569 | - var locationsChanged = false; |
570 | - // remove |
571 | - for(var x=0;x<locationsRemoved.count;x++) { |
572 | - var delLoc = locationsRemoved.get(x); |
573 | - storage.clearLocation(delLoc.dbId); |
574 | - locationsChanged = true; |
575 | - } |
576 | - // add |
577 | - for(var y=0;y<locationModel.count;y++) { |
578 | - var loc = locationModel.get(y); |
579 | - if(loc.dbId === undefined || loc.dbId=== 0) { |
580 | - storage.insertLocation({location:loc}); |
581 | - locationsChanged = true; |
582 | - } |
583 | - } |
584 | - // refresh tabs if neccessary |
585 | - if(locationsChanged || locationModel.count === 0) { |
586 | - mainView.refreshData() |
587 | - } |
588 | - // handle dummy "current location" item |
589 | - currentLocationItem.visible = false |
590 | - locationLookupItem.visible = true |
591 | - lookupItemAddButton.visible = true |
592 | - if(locationModel.count > 0) { |
593 | - // reset text color |
594 | - Theme.palette.selected.backgroundText = "#f4f4e8" |
595 | - } |
596 | - mainView.shortCutsLimited = false; |
597 | - } |
598 | - |
599 | - onCancelClicked: cancelSheet() |
600 | - |
601 | - AddLocationSheet { |
602 | - id:addLocationSheet |
603 | - } |
604 | - |
605 | - SplashComponent { |
606 | - id: httpFailedLookup |
607 | - objectName: "HTTPFailedLookup" |
608 | - message: i18n.tr("Couldn't specify your current location, please try later again!") |
609 | - } |
610 | + } |
611 | + |
612 | + SplashComponent { |
613 | + id: httpFailedLookup |
614 | + objectName: "HTTPFailedLookup" |
615 | + message: i18n.tr("Couldn't specify your current location, please try later again!") |
616 | } |
617 | } |
618 | |
619 | === added file 'components/SettingsPage.qml' |
620 | --- components/SettingsPage.qml 1970-01-01 00:00:00 +0000 |
621 | +++ components/SettingsPage.qml 2014-09-04 17:21:39 +0000 |
622 | @@ -0,0 +1,194 @@ |
623 | +/* |
624 | + * Copyright (C) 2013, 2014 Canonical Ltd |
625 | + * |
626 | + * This program is free software: you can redistribute it and/or modify |
627 | + * it under the terms of the GNU General Public License version 3 as |
628 | + * published by the Free Software Foundation. |
629 | + * |
630 | + * This program is distributed in the hope that it will be useful, |
631 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
632 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
633 | + * GNU General Public License for more details. |
634 | + * |
635 | + * You should have received a copy of the GNU General Public License |
636 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
637 | + * |
638 | + * Authored by: RaΓΊl Yeguas <neokore@gmail.com> |
639 | + * Martin Borho <martin@borho.net> |
640 | + */ |
641 | +import QtQuick 2.0 |
642 | +import Ubuntu.Components 1.1 |
643 | + |
644 | +Page { |
645 | + title: i18n.tr("Settings") |
646 | + anchors.fill: parent |
647 | + visible: false |
648 | + readonly property real headerHeight: units.gu(9.5) |
649 | + readonly property real bottomHeight: units.gu(9.5) |
650 | + property bool refresh_from_storage: false |
651 | + property bool refresh_from_service: false |
652 | + |
653 | + head.backAction: Action { |
654 | + iconName: "back" |
655 | + onTriggered: { |
656 | + if(refresh_from_storage === true || refresh_from_service === true) { |
657 | + storage.getSettings(function(storedSettings) { |
658 | + for(var settingName in storedSettings) { |
659 | + settings[settingName] = storedSettings[settingName]; |
660 | + } |
661 | + refreshData(refresh_from_storage, refresh_from_service); |
662 | + }); |
663 | + } else { |
664 | + // reload tabs from storage, to prevent header content from diappearing |
665 | + refreshData(true); |
666 | + } |
667 | + popFromStack() |
668 | + } |
669 | + } |
670 | + |
671 | + Connections { target: mainView; onEscapeKey: popFromStack()} |
672 | + |
673 | + function popFromStack() { |
674 | + Theme.palette.selected.backgroundText = "#f3f3e7" |
675 | + pageStack.pop() |
676 | + } |
677 | + |
678 | + function fillTempSelector() { |
679 | + temperatureUnitsSelectorModel.append({ name: "celsiusOption", label: i18n.tr("Celsius")}); |
680 | + temperatureUnitsSelectorModel.append({ name: "fahrenheitOption", label: i18n.tr("Fahrenheit")}); |
681 | + temperatureUnitsSelector.selectedIndex = (settings["units"] === "imperial") ? 1 : 0; |
682 | + } |
683 | + |
684 | + function fillWindSelector() { |
685 | + windUnitsSelectorModel.append({ name: "kmhOption", label: i18n.tr("Kilometers per hour")}); |
686 | + windUnitsSelectorModel.append({ name: "mphOption", label: i18n.tr("Miles per hour")}); |
687 | + windUnitsSelector.selectedIndex = (settings["wind_units"] === "mph") ? 1 : 0; |
688 | + } |
689 | + |
690 | + function fillPrecipSelector() { |
691 | + precipitationUnitsSelectorModel.append({ name: "millimetersOption", label: i18n.tr("Millimeters")}); |
692 | + precipitationUnitsSelectorModel.append({ name: "inchesOption", label: i18n.tr("Inches")}); |
693 | + precipitationUnitsSelector.selectedIndex = (settings["precip_units"] === "in") ? 1 : 0; |
694 | + } |
695 | + |
696 | + Component.onCompleted: { |
697 | + refresh_from_service = false; |
698 | + refresh_from_storage = false; |
699 | + fillTempSelector(); |
700 | + fillWindSelector(); |
701 | + fillPrecipSelector(); |
702 | + mainView.shortCutsLimited = true; |
703 | + Theme.palette.selected.backgroundText = "#656565" |
704 | + //Theme.palette.selected.background = "#656565" |
705 | + } |
706 | + |
707 | + Rectangle { |
708 | + anchors.fill:parent |
709 | + color: "lightgrey" |
710 | + |
711 | + Column { |
712 | + anchors { |
713 | + top:parent.top |
714 | + topMargin:headerHeight+units.gu(3) |
715 | + margins: units.gu(2) |
716 | + right: parent.right |
717 | + left: parent.left |
718 | + bottom: parent.bottom |
719 | + bottomMargin:bottomHeight |
720 | + } |
721 | + |
722 | + |
723 | + Component { |
724 | + id: unitsSelectorDelegate |
725 | + OptionSelectorDelegate { |
726 | + text: i18n.tr(label) |
727 | + objectName: name |
728 | + } |
729 | + } |
730 | + |
731 | + ListModel { |
732 | + id: temperatureUnitsSelectorModel |
733 | + } |
734 | + |
735 | + OptionSelector { |
736 | + id: temperatureUnitsSelector |
737 | + objectName: "TemperatureUnitsSelector" |
738 | + text: i18n.tr("Temperature units") |
739 | + delegate: unitsSelectorDelegate |
740 | + model: temperatureUnitsSelectorModel |
741 | + onSelectedIndexChanged: { |
742 | + var selectedUnit = (selectedIndex === 0) ? "metric" : "imperial"; |
743 | + storage.saveSetting("units", selectedUnit); |
744 | + refresh_from_storage = true; |
745 | + } |
746 | + } |
747 | + |
748 | + ListModel { |
749 | + id: windUnitsSelectorModel |
750 | + } |
751 | + |
752 | + OptionSelector { |
753 | + id: windUnitsSelector |
754 | + objectName: "WindUnitsSelector" |
755 | + text: i18n.tr("Wind speed units") |
756 | + delegate: unitsSelectorDelegate |
757 | + model: windUnitsSelectorModel |
758 | + onSelectedIndexChanged: { |
759 | + var selectedWindUnit = (selectedIndex === 0) ? "kmh" : "mph"; |
760 | + storage.saveSetting("wind_units", selectedWindUnit); |
761 | + refresh_from_storage = true; |
762 | + } |
763 | + } |
764 | + |
765 | + ListModel { |
766 | + id: precipitationUnitsSelectorModel |
767 | + } |
768 | + |
769 | + OptionSelector { |
770 | + id: precipitationUnitsSelector |
771 | + objectName: "PrecipitationUnitsSelector" |
772 | + text: i18n.tr("Precipitation units") |
773 | + delegate: unitsSelectorDelegate |
774 | + model: precipitationUnitsSelectorModel |
775 | + // Precipitation units not available at TWC |
776 | + visible: (serviceSelector.selectedIndex !== 0) ? 1 : 0 |
777 | + opacity: (serviceSelector.selectedIndex !== 0) ? 1 : 0 |
778 | + Behavior on visible { |
779 | + enabled: (serviceSelector.selectedIndex === 0) |
780 | + NumberAnimation { duration: 1500} |
781 | + } |
782 | + Behavior on opacity { |
783 | + NumberAnimation { |
784 | + easing: UbuntuAnimation.StandardEasingReverse; |
785 | + duration: UbuntuAnimation.SlowDuration |
786 | + } |
787 | + } |
788 | + onSelectedIndexChanged: { |
789 | + var selectedPrecipUnit = (selectedIndex === 0) ? "mm" : "in"; |
790 | + storage.saveSetting("precip_units", selectedPrecipUnit); |
791 | + refresh_from_storage = true; |
792 | + } |
793 | + } |
794 | + |
795 | + ListModel { |
796 | + id: serviceSelectorModel |
797 | + ListElement { name: "twcOption"; label: "The Weather Channel" } |
798 | + ListElement { name: "owmOption"; label: "Openweathermap" } |
799 | + } |
800 | + |
801 | + OptionSelector { |
802 | + id: serviceSelector |
803 | + objectName: "ServiceSelector" |
804 | + text: i18n.tr("Weather Service") |
805 | + delegate: unitsSelectorDelegate |
806 | + model: serviceSelectorModel |
807 | + selectedIndex: (settings["service"] === "openweathermap") ? 1 : 0; |
808 | + onSelectedIndexChanged: { |
809 | + var selectedService = (selectedIndex === 0) ? "weatherchannel" : "openweathermap"; |
810 | + storage.saveSetting("service", selectedService); |
811 | + refresh_from_service = true; |
812 | + } |
813 | + } |
814 | + } |
815 | + } |
816 | +} |
817 | |
818 | === removed file 'components/SettingsSheet.qml' |
819 | --- components/SettingsSheet.qml 2014-09-02 07:21:28 +0000 |
820 | +++ components/SettingsSheet.qml 1970-01-01 00:00:00 +0000 |
821 | @@ -1,195 +0,0 @@ |
822 | -/* |
823 | - * Copyright (C) 2013 Canonical Ltd |
824 | - * |
825 | - * This program is free software: you can redistribute it and/or modify |
826 | - * it under the terms of the GNU General Public License version 3 as |
827 | - * published by the Free Software Foundation. |
828 | - * |
829 | - * This program is distributed in the hope that it will be useful, |
830 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
831 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
832 | - * GNU General Public License for more details. |
833 | - * |
834 | - * You should have received a copy of the GNU General Public License |
835 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
836 | - * |
837 | - * Authored by: RaΓΊl Yeguas <neokore@gmail.com> |
838 | - * Martin Borho <martin@borho.net> |
839 | - */ |
840 | -import QtQuick 2.0 |
841 | -import Ubuntu.Components 1.1 |
842 | -import Ubuntu.Components.Popups 1.0 |
843 | - |
844 | -Component { |
845 | - ComposerSheet { |
846 | - id: sheet |
847 | - objectName: "SettingsSheet" |
848 | - title: i18n.tr("Settings") |
849 | - contentsHeight: parent.height |
850 | - contentsWidth: parent.width |
851 | - |
852 | - function fillTempSelector() { |
853 | - with(temperatureUnitsSelectorModel) { |
854 | - append({ name: "celsiusOption", label: i18n.tr("Celsius")}); |
855 | - append({ name: "fahrenheitOption", label: i18n.tr("Fahrenheit")}); |
856 | - } |
857 | - temperatureUnitsSelector.selectedIndex = (settings["units"] === "imperial") ? 1 : 0; |
858 | - } |
859 | - |
860 | - function fillWindSelector() { |
861 | - with(windUnitsSelectorModel) { |
862 | - append({ name: "kmhOption", label: i18n.tr("Kilometers per hour")}); |
863 | - append({ name: "mphOption", label: i18n.tr("Miles per hour")}); |
864 | - } |
865 | - windUnitsSelector.selectedIndex = (settings["wind_units"] === "mph") ? 1 : 0; |
866 | - } |
867 | - |
868 | - function fillPrecipSelector() { |
869 | - with(precipitationUnitsSelectorModel) { |
870 | - append({ name: "millimetersOption", label: i18n.tr("Millimeters")}); |
871 | - append({ name: "inchesOption", label: i18n.tr("Inches")}); |
872 | - } |
873 | - precipitationUnitsSelector.selectedIndex = (settings["precip_units"] === "in") ? 1 : 0; |
874 | - } |
875 | - |
876 | - Component.onCompleted: { |
877 | - fillTempSelector(); |
878 | - fillWindSelector(); |
879 | - fillPrecipSelector(); |
880 | - mainView.shortCutsLimited = true; |
881 | - Theme.palette.selected.backgroundText = "#656565" |
882 | - } |
883 | - |
884 | - container: Column { |
885 | - anchors.left: parent.left |
886 | - anchors.right: parent.right |
887 | - |
888 | - Component { |
889 | - id: unitsSelectorDelegate |
890 | - OptionSelectorDelegate { |
891 | - text: i18n.tr(label) |
892 | - objectName: name |
893 | - } |
894 | - } |
895 | - |
896 | - ListModel { |
897 | - id: temperatureUnitsSelectorModel |
898 | - } |
899 | - |
900 | - OptionSelector { |
901 | - id: temperatureUnitsSelector |
902 | - objectName: "TemperatureUnitsSelector" |
903 | - text: i18n.tr("Temperature units") |
904 | - delegate: unitsSelectorDelegate |
905 | - model: temperatureUnitsSelectorModel |
906 | - } |
907 | - |
908 | - ListModel { |
909 | - id: windUnitsSelectorModel |
910 | - } |
911 | - |
912 | - OptionSelector { |
913 | - id: windUnitsSelector |
914 | - objectName: "WindUnitsSelector" |
915 | - text: i18n.tr("Wind speed units") |
916 | - delegate: unitsSelectorDelegate |
917 | - model: windUnitsSelectorModel |
918 | - } |
919 | - |
920 | - ListModel { |
921 | - id: precipitationUnitsSelectorModel |
922 | - } |
923 | - |
924 | - OptionSelector { |
925 | - id: precipitationUnitsSelector |
926 | - objectName: "PrecipitationUnitsSelector" |
927 | - text: i18n.tr("Precipitation units") |
928 | - delegate: unitsSelectorDelegate |
929 | - model: precipitationUnitsSelectorModel |
930 | - // Precipitation units not available at TWC |
931 | - visible: (serviceSelector.selectedIndex !== 0) ? 1 : 0 |
932 | - opacity: (serviceSelector.selectedIndex !== 0) ? 1 : 0 |
933 | - Behavior on visible { |
934 | - enabled: (serviceSelector.selectedIndex === 0) |
935 | - NumberAnimation { duration: 1500} |
936 | - } |
937 | - Behavior on opacity { |
938 | - NumberAnimation { |
939 | - easing: UbuntuAnimation.StandardEasingReverse; |
940 | - duration: UbuntuAnimation.SlowDuration |
941 | - } |
942 | - } |
943 | - } |
944 | - |
945 | - ListModel { |
946 | - id: serviceSelectorModel |
947 | - ListElement { name: "twcOption"; label: "The Weather Channel" } |
948 | - ListElement { name: "owmOption"; label: "Openweathermap" } |
949 | - } |
950 | - |
951 | - OptionSelector { |
952 | - id: serviceSelector |
953 | - objectName: "ServiceSelector" |
954 | - text: i18n.tr("Weather Service") |
955 | - delegate: unitsSelectorDelegate |
956 | - model: serviceSelectorModel |
957 | - selectedIndex: (settings["service"] === "openweathermap") ? 1 : 0; |
958 | - } |
959 | - } |
960 | - |
961 | - signal cancelSheet() |
962 | - onCancelSheet: { |
963 | - Theme.palette.selected.backgroundText = "#f4f4e8"; |
964 | - mainView.shortCutsLimited = false; |
965 | - PopupUtils.close(sheet) |
966 | - } |
967 | - Connections { target: mainView; onEscapeKey: cancelSheet() } |
968 | - |
969 | - onConfirmClicked: { |
970 | - var refresh_from_storage = false, |
971 | - refresh_from_service = false, |
972 | - selectedUnit = (temperatureUnitsSelector.selectedIndex === 0) ? "metric" : "imperial", |
973 | - selectedWindUnit = (windUnitsSelector.selectedIndex === 0) ? "kmh" : "mph", |
974 | - selectedPrecipUnit = (precipitationUnitsSelector.selectedIndex === 0) ? "mm" : "in", |
975 | - selectedService = (serviceSelector.selectedIndex === 0) ? "weatherchannel" : "openweathermap"; |
976 | - // check if temperaure scale was changed |
977 | - if(settings["units"] !== selectedUnit) { |
978 | - storage.saveSetting("units", selectedUnit); |
979 | - refresh_from_storage = true; |
980 | - } |
981 | - // |
982 | - if(settings["wind_units"] !== selectedWindUnit) { |
983 | - storage.saveSetting("wind_units", selectedWindUnit); |
984 | - refresh_from_storage = true; |
985 | - } |
986 | - // |
987 | - if(settings["precip_units"] !== selectedPrecipUnit) { |
988 | - storage.saveSetting("precip_units", selectedPrecipUnit); |
989 | - refresh_from_storage = true; |
990 | - } |
991 | - // |
992 | - if(settings["service"] !== selectedService) { |
993 | - storage.saveSetting("service", selectedService); |
994 | - refresh_from_service = true; |
995 | - } |
996 | - // handling of other settings here |
997 | - // .... |
998 | - |
999 | - // a setting was changed, reload settings and refresh the location tabs |
1000 | - if(refresh_from_storage === true || refresh_from_service === true) { |
1001 | - storage.getSettings(function(storedSettings) { |
1002 | - for(var settingName in storedSettings) { |
1003 | - settings[settingName] = storedSettings[settingName]; |
1004 | - } |
1005 | - refreshData(refresh_from_storage, refresh_from_service); |
1006 | - }); |
1007 | - } |
1008 | - Theme.palette.selected.backgroundText = "#f4f4e8" |
1009 | - PopupUtils.close(sheet) |
1010 | - } |
1011 | - |
1012 | - onCancelClicked: { |
1013 | - cancelSheet() |
1014 | - } |
1015 | - } |
1016 | -} |
1017 | |
1018 | === removed file 'tests/autopilot/ubuntu_weather_app/emulators.py' |
1019 | --- tests/autopilot/ubuntu_weather_app/emulators.py 2014-05-19 16:05:56 +0000 |
1020 | +++ tests/autopilot/ubuntu_weather_app/emulators.py 1970-01-01 00:00:00 +0000 |
1021 | @@ -1,45 +0,0 @@ |
1022 | -# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
1023 | -# Copyright 2013 Canonical |
1024 | -# |
1025 | -# This program is free software: you can redistribute it and/or modify it |
1026 | -# under the terms of the GNU General Public License version 3, as published |
1027 | -# by the Free Software Foundation. |
1028 | -# |
1029 | -# Authored by: Martin Borho <martin@borho.net> |
1030 | - |
1031 | -"""weather app autopilot tests and emulators - top level package.""" |
1032 | - |
1033 | -from ubuntuuitoolkit import emulators as toolkit_emulators |
1034 | - |
1035 | - |
1036 | -class MainView(toolkit_emulators.MainView): |
1037 | - |
1038 | - def get_tabs(self): |
1039 | - """Return the LocationTabs emulator of the MainView.""" |
1040 | - tabs = self.wait_select_single(Tabs) |
1041 | - assert tabs is not None, toolkit_emulators._NO_TABS_ERROR |
1042 | - return tabs |
1043 | - |
1044 | - def wait_for_activity_to_finish(self): |
1045 | - """Wait for any running activity indicator to finish""" |
1046 | - try: |
1047 | - self._get_activity_indicator().running.wait_for(False) |
1048 | - except: |
1049 | - # No activity in progress. |
1050 | - pass |
1051 | - |
1052 | - def _get_activity_indicator(self): |
1053 | - """Return an activity indicator""" |
1054 | - return self.select_single("ActivityIndicator", running="True") |
1055 | - |
1056 | - |
1057 | -class Tabs(toolkit_emulators.UbuntuUIToolkitEmulatorBase): |
1058 | - """LocationTabs Autopilot emulator.""" |
1059 | - |
1060 | - def get_current_tab(self): |
1061 | - """Return the currently selected tab.""" |
1062 | - return self.select_many('LocationTab')[self.selectedTabIndex] |
1063 | - |
1064 | - def get_number_of_tabs(self): |
1065 | - """Return the number of tabs.""" |
1066 | - return len(self.select_many('LocationTab')) |
1067 | |
1068 | === modified file 'tests/autopilot/ubuntu_weather_app/tests/__init__.py' |
1069 | --- tests/autopilot/ubuntu_weather_app/tests/__init__.py 2014-09-04 05:56:22 +0000 |
1070 | +++ tests/autopilot/ubuntu_weather_app/tests/__init__.py 2014-09-04 17:21:39 +0000 |
1071 | @@ -1,5 +1,5 @@ |
1072 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
1073 | -# Copyright 2013 Canonical |
1074 | +# Copyright 2013, 2014 Canonical |
1075 | # |
1076 | # This program is free software: you can redistribute it and/or modify it |
1077 | # under the terms of the GNU General Public License version 3, as published |
1078 | @@ -25,11 +25,44 @@ |
1079 | base, |
1080 | emulators as toolkit_emulators |
1081 | ) |
1082 | -from ubuntu_weather_app import emulators |
1083 | +from ubuntuuitoolkit._custom_proxy_objects import AppHeader |
1084 | import ubuntu_weather_app |
1085 | |
1086 | logger = logging.getLogger(__name__) |
1087 | |
1088 | +# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
1089 | +# Copyright 2013 Canonical |
1090 | +# |
1091 | +# This program is free software: you can redistribute it and/or modify it |
1092 | +# under the terms of the GNU General Public License version 3, as published |
1093 | +# by the Free Software Foundation. |
1094 | +# |
1095 | +# Authored by: Martin Borho <martin@borho.net> |
1096 | + |
1097 | +"""weather app autopilot tests and emulators - top level package.""" |
1098 | + |
1099 | +import ubuntuuitoolkit |
1100 | + |
1101 | + |
1102 | +class MainView(ubuntuuitoolkit.MainView): |
1103 | + |
1104 | + def get_tabs(self): |
1105 | + tabs = self.wait_select_single(Tabs) |
1106 | + assert tabs is not None, toolkit_emulators._NO_TABS_ERROR |
1107 | + return tabs |
1108 | + |
1109 | + def wait_for_activity_to_finish(self): |
1110 | + """Wait for any running activity indicator to finish""" |
1111 | + try: |
1112 | + self._get_activity_indicator().running.wait_for(False) |
1113 | + except: |
1114 | + # No activity in progress. |
1115 | + pass |
1116 | + |
1117 | + def _get_activity_indicator(self): |
1118 | + """Return an activity indicator""" |
1119 | + return self.select_single("ActivityIndicator", running="True") |
1120 | + |
1121 | |
1122 | class WeatherTestCase(base.UbuntuUIToolkitAppTestCase): |
1123 | |
1124 | @@ -89,23 +122,45 @@ |
1125 | |
1126 | @property |
1127 | def main_view(self): |
1128 | - return self.app.wait_select_single(emulators.MainView) |
1129 | - |
1130 | - |
1131 | -class SheetMixin(object): |
1132 | + return self.app.wait_select_single(MainView) |
1133 | + |
1134 | + |
1135 | +class AppHeader(AppHeader): |
1136 | + """AppHeader Autopilot custom proxy object.""" |
1137 | + |
1138 | + def click_action_button(self, action_object_name): |
1139 | + """Click an action button of the header. |
1140 | + |
1141 | + :parameter object_name: The QML objectName property of the action |
1142 | + :raise ToolkitException: If there is no action button with that object |
1143 | + name. |
1144 | + |
1145 | + """ |
1146 | + self._show_if_not_visible() |
1147 | + |
1148 | + button = self._get_action_button(action_object_name) |
1149 | + time.sleep(2) |
1150 | + self.pointing_device.click_object(button) |
1151 | + |
1152 | + |
1153 | +class Tabs(toolkit_emulators.UbuntuUIToolkitEmulatorBase): |
1154 | + """LocationTabs Autopilot emulator.""" |
1155 | + |
1156 | + def get_current_tab(self): |
1157 | + """Return the currently selected tab.""" |
1158 | + return self.select_many('LocationTab')[self.selectedTabIndex] |
1159 | + |
1160 | + def get_number_of_tabs(self): |
1161 | + """Return the number of tabs.""" |
1162 | + return len(self.select_many('LocationTab')) |
1163 | + |
1164 | + |
1165 | +class PageMixin(object): |
1166 | """A mixin to to give access to common sheet elements""" |
1167 | |
1168 | - def _click_sheet_confirm(self): |
1169 | - """Clicks the confirm button""" |
1170 | - button = self.main_view.select_single( |
1171 | - 'Button', objectName='confirmButton') |
1172 | - self.pointing_device.click_object(button) |
1173 | - |
1174 | - def _click_sheet_cancel(self): |
1175 | - """Clicks the cancel button""" |
1176 | - button = self.main_view.select_single( |
1177 | - 'Button', objectName='cancelButton') |
1178 | - self.pointing_device.click_object(button) |
1179 | + def _go_back(self): |
1180 | + """Go back in PageStack""" |
1181 | + self.main_view.get_header().click_custom_back_button() |
1182 | |
1183 | |
1184 | class LocationManagerMixin(object): |
1185 | @@ -119,8 +174,8 @@ |
1186 | self.pointing_device.move_to_object(addCityItem) |
1187 | self.pointing_device.click() |
1188 | |
1189 | - addLocPage = self.main_view.select_single( |
1190 | - "DefaultSheet", objectName="AddLocationSheet") |
1191 | + addLocPage = self.main_view.wait_select_single( |
1192 | + "AddLocationPage", objectName="AddLocationPage") |
1193 | self.assertThat(addLocPage.visible, Eventually(Equals(True))) |
1194 | |
1195 | |
1196 | |
1197 | === modified file 'tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py' |
1198 | --- tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2014-09-04 06:37:54 +0000 |
1199 | +++ tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2014-09-04 17:21:39 +0000 |
1200 | @@ -17,7 +17,7 @@ |
1201 | from ubuntu_weather_app.tests import ( |
1202 | WeatherTestCase, |
1203 | DatabaseMixin, |
1204 | - SheetMixin, |
1205 | + PageMixin, |
1206 | LocationManagerMixin |
1207 | ) |
1208 | |
1209 | @@ -30,7 +30,7 @@ |
1210 | # FIXME Use fixtures instead of the complex multiple inheritance. |
1211 | # --elopio - 2014-09-03 |
1212 | class BaseTestLocationManager( |
1213 | - WeatherTestCase, DatabaseMixin, SheetMixin, LocationManagerMixin): |
1214 | + WeatherTestCase, DatabaseMixin, PageMixin, LocationManagerMixin): |
1215 | |
1216 | def _open_location_manager(self, kb=False): |
1217 | """Opens the location manager""" |
1218 | @@ -40,8 +40,8 @@ |
1219 | self.main_view.get_header().click_action_button("EditButton") |
1220 | |
1221 | # test location manager becomes visible |
1222 | - managerSheet = self.main_view.select_single( |
1223 | - 'ComposerSheet', objectName='LocationManagerSheet') |
1224 | + managerSheet = self.main_view.wait_select_single( |
1225 | + 'LocationManagerPage', objectName='LocationManagerPage') |
1226 | self.assertThat(managerSheet.visible, Eventually(Equals(True))) |
1227 | |
1228 | def _swipe_first_location_to_remove(self): |
1229 | @@ -58,8 +58,8 @@ |
1230 | Eventually(Equals(number_of_locations - 1))) |
1231 | |
1232 | def _get_number_of_locations(self): |
1233 | - qqlw = self.app.wait_select_single("ComposerSheet").wait_select_single( |
1234 | - "QQuickListView") |
1235 | + qqlw = self.app.wait_select_single( |
1236 | + "LocationManagerPage").wait_select_single("QQuickListView") |
1237 | return qqlw.count |
1238 | |
1239 | def _add_location(self, location): |
1240 | @@ -81,7 +81,7 @@ |
1241 | # LocationManagerPage should be visible and location added |
1242 | addedItem = self.main_view.wait_select_single('Label', text=location) |
1243 | self.assertThat(addedItem.text, Eventually(Equals(location))) |
1244 | - self._click_sheet_confirm() |
1245 | + self._go_back() |
1246 | |
1247 | # back to locations, wait till data is loaded |
1248 | self.main_view.wait_for_activity_to_finish() |
1249 | @@ -144,7 +144,7 @@ |
1250 | addedItem = self.main_view.wait_select_single( |
1251 | 'Label', objectName="existingLocation0") |
1252 | self.assertThat(addedItem.text, Eventually(Equals(location))) |
1253 | - self._click_sheet_confirm() |
1254 | + self._go_back() |
1255 | |
1256 | # back to locations, wait till data is loaded |
1257 | self.main_view.wait_for_activity_to_finish() |
1258 | @@ -188,7 +188,7 @@ |
1259 | def test_cancel_adding_location(self): |
1260 | """Cancel the cities search""" |
1261 | self._open_add_location_page() |
1262 | - self._click_sheet_cancel() |
1263 | + self._go_back() |
1264 | locationList = self.main_view.wait_select_single( |
1265 | 'QQuickListView', objectName='LocationList') |
1266 | self.assertThat(locationList.visible, Eventually(Equals(True))) |
1267 | @@ -231,7 +231,7 @@ |
1268 | addedItem = self.main_view.wait_select_single( |
1269 | 'Label', objectName="existingLocation0") |
1270 | self.assertThat(addedItem.text, Eventually(Equals(location_name))) |
1271 | - self._click_sheet_confirm() |
1272 | + self._go_back() |
1273 | |
1274 | # back to locations, wait till data is loaded |
1275 | self.main_view.wait_for_activity_to_finish() |
1276 | @@ -260,10 +260,11 @@ |
1277 | self.add_locations_to_database() |
1278 | logger.debug("Re-Launching app to introspect") |
1279 | |
1280 | - def _remove_location(self): |
1281 | + def _remove_location(self, stay=False): |
1282 | self._open_location_manager() |
1283 | self._swipe_first_location_to_remove() |
1284 | - self._click_sheet_confirm() |
1285 | + if not stay: |
1286 | + self._go_back() |
1287 | |
1288 | def _wait_for_tab(self): |
1289 | loadingPage = self.main_view.get_tabs() |
1290 | @@ -286,6 +287,7 @@ |
1291 | tabObjects = lambda: len(self.main_view.select_many('LocationTab')) |
1292 | self.assertThat(tabObjects, Eventually(Equals(tabsSumStart - 1))) |
1293 | |
1294 | + @skip("skipped because of no cancel action exists atm") |
1295 | def test_cancel_remove_location(self): |
1296 | """Cancels removing of location""" |
1297 | # wait data is loaded |
1298 | @@ -309,10 +311,9 @@ |
1299 | """Tests if removing and add a location in one action works |
1300 | https://bugs.launchpad.net/ubuntu-weather-app/+bug/1230297""" |
1301 | # remove a location |
1302 | - self._remove_location() |
1303 | + self._remove_location(stay=True) |
1304 | |
1305 | # add a location |
1306 | - self._open_location_manager() |
1307 | self._add_location("Cairo") |
1308 | |
1309 | # back to locations, wait till data is loaded |
1310 | |
1311 | === modified file 'tests/autopilot/ubuntu_weather_app/tests/test_settings.py' |
1312 | --- tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2014-07-10 19:34:54 +0000 |
1313 | +++ tests/autopilot/ubuntu_weather_app/tests/test_settings.py 2014-09-04 17:21:39 +0000 |
1314 | @@ -10,14 +10,15 @@ |
1315 | from __future__ import absolute_import |
1316 | from testtools.matchers import Equals, Is, Not |
1317 | from autopilot.matchers import Eventually |
1318 | +from unittest import skip |
1319 | import logging |
1320 | |
1321 | -from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin, SheetMixin |
1322 | +from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin, PageMixin |
1323 | |
1324 | logger = logging.getLogger(__name__) |
1325 | |
1326 | |
1327 | -class TestSettings(WeatherTestCase, DatabaseMixin, SheetMixin): |
1328 | +class TestSettings(WeatherTestCase, DatabaseMixin, PageMixin): |
1329 | def setUp(self): |
1330 | # we want to start with fake settings data |
1331 | self.create_blank_db() |
1332 | @@ -28,7 +29,7 @@ |
1333 | self.assertThat( |
1334 | self.main_view.visible, Eventually(Equals(True))) |
1335 | |
1336 | - def _open_settings_sheet(self): |
1337 | + def _open_settings_page(self): |
1338 | """Opens the settings sheet""" |
1339 | self.main_view.get_header().click_action_button("SettingsButton") |
1340 | |
1341 | @@ -146,37 +147,38 @@ |
1342 | """Tests switching the scale in the settings""" |
1343 | # first check metric values and open the settings sheet |
1344 | self._check_units('metric') |
1345 | - self._open_settings_sheet() |
1346 | + self._open_settings_page() |
1347 | |
1348 | # get temp selector |
1349 | units_selector = self._get_selector("TemperatureUnitsSelector") |
1350 | |
1351 | # choose second option, fahrenheit |
1352 | units_selector.select_option(objectName="fahrenheitOption") |
1353 | - self._click_sheet_confirm() |
1354 | + self._go_back() |
1355 | |
1356 | # wait for reload and check the imperial values |
1357 | self.main_view.wait_for_activity_to_finish() |
1358 | self._check_units('imperial') |
1359 | |
1360 | # switch back to metric values again |
1361 | - self._open_settings_sheet() |
1362 | + self._open_settings_page() |
1363 | units_selector = self._get_selector("TemperatureUnitsSelector") |
1364 | |
1365 | # click celsius option |
1366 | units_selector.select_option(objectName="celsiusOption") |
1367 | - self._click_sheet_confirm() |
1368 | + self._go_back() |
1369 | |
1370 | # wait for reload and check the metric values again |
1371 | self.main_view.wait_for_activity_to_finish() |
1372 | self._check_units('metric') |
1373 | |
1374 | + @skip("skipped because of missing cancel action") |
1375 | def test_switch_scale_cancel(self): |
1376 | """Test canceling switching scale""" |
1377 | # first check metric values and open the settings sheet |
1378 | self._check_units('metric') |
1379 | self._check_wind_units('kmh') |
1380 | - self._open_settings_sheet() |
1381 | + self._open_settings_page() |
1382 | |
1383 | # open the temp value selector |
1384 | units_selector = self._get_selector("TemperatureUnitsSelector") |
1385 | @@ -197,22 +199,22 @@ |
1386 | """Tests switching the wind scale in the settings""" |
1387 | # first check metric values and open the settings sheet |
1388 | self._check_wind_units('kmh') |
1389 | - self._open_settings_sheet() |
1390 | + self._open_settings_page() |
1391 | |
1392 | # choose mph and confirm |
1393 | wind_selector = self._get_selector("WindUnitsSelector") |
1394 | wind_selector.select_option(objectName="mphOption") |
1395 | - self._click_sheet_confirm() |
1396 | + self._go_back() |
1397 | |
1398 | # wait for reload and check the mph values |
1399 | self.main_view.wait_for_activity_to_finish() |
1400 | self._check_wind_units('mph') |
1401 | |
1402 | # switch back to kmh values again |
1403 | - self._open_settings_sheet() |
1404 | + self._open_settings_page() |
1405 | wind_selector = self._get_selector("WindUnitsSelector") |
1406 | wind_selector.select_option(objectName="kmhOption") |
1407 | - self._click_sheet_confirm() |
1408 | + self._go_back() |
1409 | |
1410 | # wait for reload and check the metric values again |
1411 | self.main_view.wait_for_activity_to_finish() |
1412 | @@ -222,7 +224,7 @@ |
1413 | """Tests switching the scale in the settings""" |
1414 | # first check metric values and open the settings sheet |
1415 | self._check_service('weatherchannel') |
1416 | - self._open_settings_sheet() |
1417 | + self._open_settings_page() |
1418 | |
1419 | # choose second option, openweathermap |
1420 | selector = self._get_selector("ServiceSelector") |
1421 | @@ -232,14 +234,14 @@ |
1422 | self.assertThat(lambda: self.main_view.select_single('OptionSelector', |
1423 | objectName='PrecipitationUnitsSelector'), |
1424 | Eventually(Not(Is(None)))) |
1425 | - self._click_sheet_confirm() |
1426 | + self._go_back() |
1427 | |
1428 | # wait for reload and check the used service |
1429 | self.main_view.wait_for_activity_to_finish() |
1430 | self._check_service('openweathermap') |
1431 | |
1432 | # switch back to twc values again |
1433 | - self._open_settings_sheet() |
1434 | + self._open_settings_page() |
1435 | selector = self._get_selector("ServiceSelector") |
1436 | selector.select_option(objectName="twcOption") |
1437 | |
1438 | @@ -247,7 +249,7 @@ |
1439 | self.assertThat(lambda: self.main_view.select_single('OptionSelector', |
1440 | objectName='PrecipitationUnitsSelector'), |
1441 | Eventually(Not(Is(None)))) |
1442 | - self._click_sheet_confirm() |
1443 | + self._go_back() |
1444 | |
1445 | # wait for reload and check the metric values again |
1446 | self.main_view.wait_for_activity_to_finish() |
1447 | |
1448 | === modified file 'ubuntu-weather-app.qml' |
1449 | --- ubuntu-weather-app.qml 2014-09-02 07:21:28 +0000 |
1450 | +++ ubuntu-weather-app.qml 2014-09-04 17:21:39 +0000 |
1451 | @@ -185,7 +185,7 @@ |
1452 | }; |
1453 | } |
1454 | tabsString += "}"; // END Tabs componen |
1455 | - tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs") |
1456 | + tabsObject = Qt.createQmlObject(tabsString, pageStack, "tabs") |
1457 | if(focusToLast) { |
1458 | tabsObject.selectedTabIndex = locLength -1; |
1459 | } else if(tabIndexAtRefresh > -1) { |
1460 | @@ -215,11 +215,11 @@ |
1461 | } |
1462 | |
1463 | function showLocationManager() { |
1464 | - PopupUtils.open(locationManager) |
1465 | + pageStack.push(Qt.resolvedUrl("components/LocationManagerPage.qml")) |
1466 | } |
1467 | |
1468 | function showSettings() { |
1469 | - PopupUtils.open(settingsSheet) |
1470 | + pageStack.push(Qt.resolvedUrl("components/SettingsPage.qml")) |
1471 | } |
1472 | |
1473 | Component.onCompleted: { |
1474 | @@ -237,19 +237,11 @@ |
1475 | refreshData(); |
1476 | }) |
1477 | } |
1478 | - |
1479 | - Components.SettingsSheet { |
1480 | - id: settingsSheet |
1481 | - } |
1482 | |
1483 | Components.Storage{ |
1484 | id: storage |
1485 | } |
1486 | |
1487 | - Components.LocationManagerSheet { |
1488 | - id:locationManager |
1489 | - } |
1490 | - |
1491 | Components.SplashComponent { |
1492 | id:httpFailedSplash |
1493 | objectName: "HTTPFailedSplash" |
1494 | @@ -259,8 +251,8 @@ |
1495 | id:refresh |
1496 | } |
1497 | |
1498 | - Item { |
1499 | - id:tabPage |
1500 | + PageStack { |
1501 | + id:pageStack |
1502 | anchors.fill: parent |
1503 | } |
1504 |
FAILED: Continuous integration, rev:340 91.189. 93.70:8080/ job/ubuntu- weather- app-ci/ 234/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic- weather- app/55 91.189. 93.70:8080/ job/generic- mediumtests- utopic- weather- app/55/ artifact/ work/output/ *zip*/output. zip 91.189. 93.70:8080/ job/ubuntu- weather- app-utopic- amd64-ci/ 41/console
http://
Executed test runs:
SUCCESS: http://
deb: http://
FAILURE: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- weather- app-ci/ 234/rebuild
http://