Merge lp:~nik90/ubuntu-clock-app/clock-code-restructure into lp:ubuntu-clock-app/saucy
- clock-code-restructure
- Merge into saucy
Status: | Merged |
---|---|
Approved by: | Nekhelesh Ramananthan |
Approved revision: | 261 |
Merged at revision: | 247 |
Proposed branch: | lp:~nik90/ubuntu-clock-app/clock-code-restructure |
Merge into: | lp:ubuntu-clock-app/saucy |
Diff against target: |
1125 lines (+518/-417) 11 files modified
clock/AnalogClockFace.qml (+33/-6) clock/CityTimezone.qml (+53/-0) clock/ClockPage.qml (+11/-30) clock/EasterEgg.qml (+8/-82) clock/EasterEggModel.qml (+41/-0) clock/EasterEggStorage.js (+76/-0) clock/SearchBox.qml (+65/-0) clock/WorldCity.qml (+57/-0) clock/WorldClock.qml (+173/-222) clock/WorldPage.qml (+0/-76) tests/autopilot/ubuntu_clock_app/emulators.py (+1/-1) |
To merge this branch: | bzr merge lp:~nik90/ubuntu-clock-app/clock-code-restructure |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Ubuntu Clock Developers | Pending | ||
Review via email: mp+191912@code.launchpad.net |
Commit message
This commit performs some code restructuring and organises elements into separate components.
- Moved world clock search box, worldcity xml model and citytimezone xml model to its own component
- Split EasterEgg.qml into EasterEggModel.qml, EasterEggStorage.js and EasterEgg.qml
- Merged WorldClock.qml and WorldPage.qml
- Removed inverse_mouse area (not required)
- Removed search button
- Added TODO, FIXME comments. Increased code clarity and made it easier for new developers to get involved (clock).
This commit should make it easier to fix any world clock related bugs and is a nice pre-runner to https:/
Description of the change
In the rush to 1.0 release, the code dealing with clock alone has become messy and complexy interlinked. This MP performs some code restructuring and organises elements into separate components.
- Moved world clock search box, worldcity xml model and citytimezone xml model to its own component
- Split EasterEgg.qml into EasterEggModel.qml, EasterEggStorage.js and EasterEgg.qml
- Merged WorldClock.qml and WorldPage.qml
- Removed inverse_mouse area (not required)
- Removed search button
- Added TODO, FIXME comments. Increased code clarity and made it easier for new developers to get involved (clock).
This MP should make it easier to fix any world clock related bugs and is a nice pre-runner to https:/
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
- 259. By Nekhelesh Ramananthan
-
Fixed autopilot test
- 260. By Nekhelesh Ramananthan
-
removed username variable
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:259
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:260
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 261. By Nekhelesh Ramananthan
-
Merge from master
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:261
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'clock/AnalogClockFace.qml' |
2 | --- clock/AnalogClockFace.qml 2013-07-14 12:33:25 +0000 |
3 | +++ clock/AnalogClockFace.qml 2013-10-22 17:11:13 +0000 |
4 | @@ -22,13 +22,16 @@ |
5 | import Ubuntu.Components 0.1 |
6 | import "../common" |
7 | |
8 | +// Element which draws the clock face along with the hour, minute, second hand and the clock label |
9 | AnalogFaceBase { |
10 | id: clockRoot |
11 | |
12 | property var currDate: new Date; |
13 | property int hours: currDate.getHours() |
14 | property int minutes: currDate.getMinutes() |
15 | - property int seconds: currDate.getUTCSeconds(); |
16 | + property int seconds: currDate.getUTCSeconds(); |
17 | + |
18 | + property alias clockLabel: currentTimeLabel |
19 | |
20 | signal clicked(var mouse) |
21 | |
22 | @@ -43,7 +46,7 @@ |
23 | |
24 | z: parent.z |
25 | handHeight: units.gu(12.5); handWidth: units.gu(1); |
26 | - rotation: (clockRoot.hours * 30) + (clockRoot.minutes / 2); |
27 | + rotation: (hours * 30) + (minutes / 2); |
28 | } |
29 | |
30 | AnalogClockHand { |
31 | @@ -51,7 +54,7 @@ |
32 | |
33 | z: parent.z + 1 |
34 | handHeight: units.gu(14.5); handWidth: units.gu(0.5); |
35 | - rotation: clockRoot.minutes * 6; |
36 | + rotation: minutes * 6; |
37 | } |
38 | |
39 | AnalogClockHand { |
40 | @@ -59,9 +62,33 @@ |
41 | |
42 | z: parent.z - 1; |
43 | handHeight: units.gu(17); handWidth: units.gu(0.5) |
44 | - rotation: clockRoot.seconds * 6; |
45 | - } |
46 | - |
47 | + rotation: seconds * 6; |
48 | + } |
49 | + |
50 | + // Label to show the current time |
51 | + // TODO: Investigate moving this component into common/AnalogFaceBase.qml since it is required by |
52 | + // clock, timer, stopwatch and alarm. |
53 | + Rectangle { |
54 | + id: labelContainer; |
55 | + |
56 | + z: innerCircle.z + 1; |
57 | + width: innerCircle.width; height: width; |
58 | + anchors.centerIn: parent; |
59 | + color: "transparent" |
60 | + |
61 | + Label { |
62 | + id: currentTimeLabel |
63 | + objectName: "currentTimeLabel" |
64 | + |
65 | + anchors.centerIn: parent |
66 | + horizontalAlignment: Text.AlignHCenter |
67 | + verticalAlignment: Text.AlignVCenter |
68 | + color: Theme.palette.normal.baseText |
69 | + font.pixelSize: units.dp(41) |
70 | + } |
71 | + } |
72 | + |
73 | + // Mouse area to reveal the clock sunrise/sunset on clicking the clock face |
74 | MouseArea { |
75 | anchors.fill: parent |
76 | z: parent.z + 1; |
77 | |
78 | === added file 'clock/CityTimezone.qml' |
79 | --- clock/CityTimezone.qml 1970-01-01 00:00:00 +0000 |
80 | +++ clock/CityTimezone.qml 2013-10-22 17:11:13 +0000 |
81 | @@ -0,0 +1,53 @@ |
82 | +/* |
83 | + * Copyright (C) 2013 Canonical Ltd |
84 | + * |
85 | + * This program is free software: you can redistribute it and/or modify |
86 | + * it under the terms of the GNU General Public License version 3 as |
87 | + * published by the Free Software Foundation. |
88 | + * |
89 | + * This program is distributed in the hope that it will be useful, |
90 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
91 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
92 | + * GNU General Public License for more details. |
93 | + * |
94 | + * You should have received a copy of the GNU General Public License |
95 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
96 | + * |
97 | + * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
98 | + */ |
99 | + |
100 | +import QtQuick 2.0 |
101 | +import Ubuntu.Components 0.1 |
102 | +import QtQuick.XmlListModel 2.0 |
103 | + |
104 | +// XML Model to retrieve the timezone info of a city searched by the user online. |
105 | +XmlListModel { |
106 | + id: cityTimezoneModel; |
107 | + |
108 | + readonly property string timezone_base_url: "http://api.geonames.org/timezone?lat="; |
109 | + |
110 | + // TODO: Change username to something along the lines of "com.ubuntu.clock" |
111 | + readonly property string username: "krnekhelesh"; |
112 | + |
113 | + // Function to return the online url for timezone info of a city |
114 | + function getCityTimezoneUrl (lat, lng) { |
115 | + return (timezone_base_url + lat + "&lng=" + lng + "&username=" + username); |
116 | + } |
117 | + |
118 | + // Function to calculate the time difference w.r.t UTC |
119 | + function getTimeDifference(data) { |
120 | + var worldTime = data.split(' ')[1].split(':'); |
121 | + var hoursWT = parseInt(worldTime[0]); |
122 | + var minutesWT = parseInt(worldTime[1]); |
123 | + var now = new Date(); |
124 | + var UTCdiff = new Date().getTimezoneOffset() |
125 | + now.setMinutes(now.getMinutes() + UTCdiff) |
126 | + |
127 | + // Calculating world city time diff w.r.t UTC |
128 | + return ((hoursWT - now.getHours()) * 60 + (minutesWT - now.getMinutes())); |
129 | + } |
130 | + |
131 | + query: "/geonames/timezone" |
132 | + XmlRole { name: "time"; query: "time/string()" } |
133 | + onSourceChanged: reload(); |
134 | +} |
135 | |
136 | === modified file 'clock/ClockPage.qml' |
137 | --- clock/ClockPage.qml 2013-10-06 12:13:35 +0000 |
138 | +++ clock/ClockPage.qml 2013-10-22 17:11:13 +0000 |
139 | @@ -38,7 +38,7 @@ |
140 | |
141 | Component.onCompleted: { |
142 | // TODO: Query GPS for location data |
143 | - Utils.log("ClockPage loaded"); |
144 | + Utils.log("ClockPage loaded"); |
145 | if (worldModel.city !== "undefined") { |
146 | currentCity = worldModel.city; |
147 | currentLng = worldModel.longitude; |
148 | @@ -58,18 +58,20 @@ |
149 | keywords: i18n.tr("Add;Timezone;Timezones;World;City;Cities;Town;Towns;Place;Places;Location;Locations;Time;Locale;Local;Current") |
150 | description: "Add a world city" |
151 | iconSource: Qt.resolvedUrl("../images/add_icon.png") |
152 | - onTriggered: pagestack.push(Qt.resolvedUrl("WorldPage.qml"), {"isWorldCity": true}) |
153 | + onTriggered: pagestack.push(Qt.resolvedUrl("WorldClock.qml"), {"isWorldCity": true}) |
154 | } |
155 | ] |
156 | |
157 | + // Function which runs every second to update the clock label |
158 | function onTimerUpdate(now) { |
159 | - currentTimeFormatted = Qt.formatTime(new Date(), "hh:mm") |
160 | + currentTimeFormatted = Qt.formatTime(new Date(), "hh:mm") |
161 | clockFace.timeChanged(now) |
162 | if (now.getUTCSeconds() == 0) { |
163 | updateTime(); |
164 | } |
165 | } |
166 | |
167 | + // Function which runs every minute to update the world time |
168 | function updateTime() { |
169 | var now = new Date(); |
170 | now.setMinutes(now.getMinutes() + diff) |
171 | @@ -111,40 +113,19 @@ |
172 | contentWidth: parent.width |
173 | contentHeight: clockFace.height + clockFace.anchors.topMargin + savedWorldClock.height + savedWorldClock.anchors.topMargin + units.gu(3) |
174 | |
175 | - // Label to show the current time |
176 | - Rectangle { |
177 | - id: labelContainer; |
178 | - |
179 | - z: clockFace.z + 1; |
180 | - width: clockFace.innerCircle.width; height: width; |
181 | - anchors.centerIn: clockFace; |
182 | - color: "transparent" |
183 | - |
184 | - Label { |
185 | - id: currentTimeLabel |
186 | - objectName: "currentTimeLabel" |
187 | - |
188 | - anchors.centerIn: parent |
189 | - horizontalAlignment: Text.AlignHCenter |
190 | - verticalAlignment: Text.AlignVCenter |
191 | - color: Theme.palette.normal.baseText |
192 | - font.pixelSize: units.dp(41) |
193 | - text: currentTimeFormatted |
194 | - } |
195 | - } |
196 | - |
197 | // Qml Element to draw the analogue clock face along with its hour, minute and second hands. |
198 | AnalogClockFace { |
199 | id: clockFace |
200 | |
201 | anchors { top: parent.top; topMargin: units.gu(10); horizontalCenter: parent.horizontalCenter } |
202 | + clockLabel.text: currentTimeFormatted |
203 | |
204 | onClicked: { |
205 | - if (easterEggCircle.isReady == XmlListModel.Ready && worldModel.city !== "undefined") { |
206 | + if (easterEggCircle.isReady == XmlListModel.Ready && worldModel.city !== "undefined") |
207 | clockFace.state == "" ? clockFace.state = "easteregg" : clockFace.state = ""; |
208 | - } else { |
209 | + else |
210 | Utils.error("Sunrise/Sunset times cannot be loaded without setting the current location or without a internet connection.") |
211 | - } |
212 | + |
213 | } |
214 | |
215 | EasterEgg { |
216 | @@ -158,13 +139,13 @@ |
217 | State { |
218 | name: "easteregg" |
219 | PropertyChanges { target: easterEggCircle; opacity: 1; } |
220 | - PropertyChanges { target: currentTimeLabel; opacity: 0; } |
221 | + PropertyChanges { target: clockFace.clockLabel; opacity: 0; } |
222 | PropertyChanges { target: easterEggCircle; sunriseLabel: easterEggCircle.getSunTime(easterEggCircle.model.get(0).sunriseTime); } |
223 | PropertyChanges { target: easterEggCircle; sunsetLabel: easterEggCircle.getSunTime(easterEggCircle.model.get(0).sunsetTime); } |
224 | }, |
225 | State { |
226 | name: "" |
227 | - PropertyChanges { target: currentTimeLabel; opacity: 1; } |
228 | + PropertyChanges { target: clockFace.clockLabel; opacity: 1; } |
229 | PropertyChanges { target: easterEggCircle; opacity: 0; } |
230 | } |
231 | ] |
232 | |
233 | === modified file 'clock/EasterEgg.qml' |
234 | --- clock/EasterEgg.qml 2013-10-08 13:01:27 +0000 |
235 | +++ clock/EasterEgg.qml 2013-10-22 17:11:13 +0000 |
236 | @@ -21,70 +21,13 @@ |
237 | import Ubuntu.Components 0.1 |
238 | import QtQuick.XmlListModel 2.0 |
239 | import QtQuick.LocalStorage 2.0 |
240 | - |
241 | +import "EasterEggStorage.js" as Storage |
242 | import "../common/ClockUtils.js" as Utils |
243 | |
244 | // Qml Element to draw the easter egg (sunrise and sunset) on the analogue clock face. |
245 | Rectangle { |
246 | id: easterEggCircle; |
247 | |
248 | - property var db: null |
249 | - |
250 | - // Opens the local db if not already open. On the first call creates the table |
251 | - function openDB () { |
252 | - if(db !== null) return; |
253 | - |
254 | - db = LocalStorage.openDatabaseSync("ubuntu-clock-app", "", "Sunrise and Sunset Database", 1000); |
255 | - |
256 | - try { |
257 | - db.transaction(function(tx){ |
258 | - tx.executeSql('CREATE TABLE IF NOT EXISTS Easteregg(key INTEGER PRIMARY KEY, date TEXT, riseTime TEXT, setTime TEXT)'); |
259 | - var table = tx.executeSql("SELECT * FROM Easteregg"); |
260 | - if (table.rows.length == 0) { |
261 | - tx.executeSql('INSERT INTO Easteregg VALUES(?, ?, ?, ?)', [1, '', '', '']); |
262 | - }; |
263 | - }); |
264 | - } catch (err) { |
265 | - Utils.error("Error creating table in Sunrise/Sunset database: " + err); |
266 | - }; |
267 | - } |
268 | - |
269 | - //Read date last checked from DB |
270 | - function getSavedData () { |
271 | - |
272 | - openDB(); |
273 | - |
274 | - var result = new Array(); |
275 | - try { |
276 | - db.readTransaction( |
277 | - function(tx){ |
278 | - var res = tx.executeSql('SELECT * FROM Easteregg WHERE key = 1'); |
279 | - if (res.rows.length > 0) { |
280 | - result[0] = new Array(); |
281 | - result[0][0] = res.rows.item(0).key; |
282 | - result[0][1] = res.rows.item(0).date; |
283 | - result[0][2] = res.rows.item(0).riseTime; |
284 | - result[0][3] = res.rows.item(0).setTime; |
285 | - }; |
286 | - }); |
287 | - } catch (err) { |
288 | - Utils.error("Error getting sunrise/sunset last checked date: " + err); |
289 | - } |
290 | - return result; |
291 | - } |
292 | - |
293 | - function saveSunTimes (date, sunRise, sunSet) { |
294 | - openDB(); |
295 | - try { |
296 | - db.transaction(function(tx){ |
297 | - var res = tx.executeSql('UPDATE Easteregg SET date = ?, riseTime = ?, setTime = ? WHERE key = 1', [date, sunRise, sunSet]); |
298 | - Utils.log("Saving Sunrise/Sunset times to disk"); |
299 | - }); |
300 | - } catch (err) { |
301 | - Utils.error("Error saving sunrise/sunset times: " + err); |
302 | - }; |
303 | - } |
304 | - |
305 | // FIXME: Replace these constant values with user's location coordinates when automatic location detection is implemented. |
306 | property real latitude: 200; |
307 | property real longitude: 200; |
308 | @@ -95,49 +38,32 @@ |
309 | |
310 | // properties to get the sunRiseModel XML model. |
311 | property alias isReady: sunRiseModel.status; |
312 | - property alias model: sunRiseModel; |
313 | - |
314 | - // Online API properties |
315 | - readonly property string base_url: "http://api.geonames.org/timezone?"; |
316 | - readonly property string username: "krnekhelesh"; |
317 | + property alias model: sunRiseModel; |
318 | |
319 | opacity: 0 |
320 | color: "transparent" |
321 | z: parent.z + 100 |
322 | visible: opacity == 0 ? false : true |
323 | |
324 | - function reloadSunRiseModel () { |
325 | - sunRiseModel.reload() |
326 | - } |
327 | - |
328 | - // Function to form the url string to make the API call |
329 | - function getUrlString (latitude, longitude) { |
330 | - return (base_url + "lat=" + latitude + "&lng=" + longitude + "&username=" + username); |
331 | - } |
332 | - |
333 | // Function to convert online data format "2013-04-20 19:40" to just "19:40" |
334 | function getSunTime (data) { |
335 | return data.split(' ')[1]; |
336 | } |
337 | |
338 | + onLatitudeChanged: sunRiseModel.source = sunRiseModel.getUrlString(latitude, longitude) |
339 | + onLongitudeChanged: sunRiseModel.source = sunRiseModel.getUrlString(latitude, longitude) |
340 | + |
341 | // TODO 1: Get the latitude and longitude using the platform API automatically instead of using static values. |
342 | - XmlListModel { |
343 | + EasterEggModel { |
344 | id: sunRiseModel |
345 | - |
346 | - source: getUrlString(latitude, longitude) |
347 | - query: "/geonames/timezone" |
348 | - |
349 | - XmlRole { name: "sunriseTime"; query: "sunrise/string()"; isKey: true } |
350 | - XmlRole { name: "sunsetTime"; query: "sunset/string()"; isKey: true } |
351 | - |
352 | onStatusChanged: { |
353 | - var savedData = getSavedData(); |
354 | + var savedData = Storage.getSavedData(); |
355 | var checkedDate = savedData[0][1].split('T')[0] |
356 | var date = new Date().toISOString(); |
357 | if (status == XmlListModel.Ready && checkedDate != date.split('T')[0] && longitude != 200 && latitude != 200){ |
358 | sunriseTimeLabel.text = getSunTime(sunRiseModel.get(0).sunriseTime); |
359 | sunsetTimeLabel.text = getSunTime(sunRiseModel.get(0).sunsetTime); |
360 | - saveSunTimes(date, sunriseTimeLabel.text, sunsetTimeLabel.text); |
361 | + Storage.saveSunTimes(date, sunriseTimeLabel.text, sunsetTimeLabel.text); |
362 | } |
363 | else if (status == XmlListModel.Ready) { |
364 | Utils.log("Retrieving Sunrise/Sunset times from disk"); |
365 | |
366 | === added file 'clock/EasterEggModel.qml' |
367 | --- clock/EasterEggModel.qml 1970-01-01 00:00:00 +0000 |
368 | +++ clock/EasterEggModel.qml 2013-10-22 17:11:13 +0000 |
369 | @@ -0,0 +1,41 @@ |
370 | +/* |
371 | + * Copyright (C) 2013 Canonical Ltd |
372 | + * |
373 | + * This program is free software: you can redistribute it and/or modify |
374 | + * it under the terms of the GNU General Public License version 3 as |
375 | + * published by the Free Software Foundation. |
376 | + * |
377 | + * This program is distributed in the hope that it will be useful, |
378 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
379 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
380 | + * GNU General Public License for more details. |
381 | + * |
382 | + * You should have received a copy of the GNU General Public License |
383 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
384 | + * |
385 | + * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
386 | + */ |
387 | + |
388 | +import QtQuick 2.0 |
389 | +import Ubuntu.Components 0.1 |
390 | +import QtQuick.XmlListModel 2.0 |
391 | + |
392 | +// Qml Element to draw the easter egg (sunrise and sunset) on the analogue clock face. |
393 | +XmlListModel { |
394 | + id: sunRiseModel |
395 | + |
396 | + // Online API properties |
397 | + readonly property string base_url: "http://api.geonames.org/timezone?"; |
398 | + readonly property string username: "krnekhelesh"; |
399 | + |
400 | + // Function to form the url string to make the API call |
401 | + function getUrlString (latitude, longitude) { |
402 | + return (base_url + "lat=" + latitude + "&lng=" + longitude + "&username=" + username); |
403 | + } |
404 | + |
405 | + query: "/geonames/timezone" |
406 | + onSourceChanged: reload() |
407 | + |
408 | + XmlRole { name: "sunriseTime"; query: "sunrise/string()"; isKey: true } |
409 | + XmlRole { name: "sunsetTime"; query: "sunset/string()"; isKey: true } |
410 | +} |
411 | |
412 | === added file 'clock/EasterEggStorage.js' |
413 | --- clock/EasterEggStorage.js 1970-01-01 00:00:00 +0000 |
414 | +++ clock/EasterEggStorage.js 2013-10-22 17:11:13 +0000 |
415 | @@ -0,0 +1,76 @@ |
416 | +/* |
417 | + * Copyright (C) 2013 Canonical Ltd |
418 | + * |
419 | + * This program is free software: you can redistribute it and/or modify |
420 | + * it under the terms of the GNU General Public License version 3 as |
421 | + * published by the Free Software Foundation. |
422 | + * |
423 | + * This program is distributed in the hope that it will be useful, |
424 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
425 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
426 | + * GNU General Public License for more details. |
427 | + * |
428 | + * You should have received a copy of the GNU General Public License |
429 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
430 | + * |
431 | + * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
432 | + */ |
433 | + |
434 | +Qt.include("../common/ClockUtils.js") |
435 | + |
436 | +var db = null; |
437 | + |
438 | +// Opens the local db if not already open. On the first call creates the table |
439 | +function openDB () { |
440 | + if(db !== null) return; |
441 | + |
442 | + db = LocalStorage.openDatabaseSync("ubuntu-clock-app", "", "Sunrise and Sunset Database", 1000); |
443 | + |
444 | + try { |
445 | + db.transaction(function(tx){ |
446 | + tx.executeSql('CREATE TABLE IF NOT EXISTS Easteregg(key INTEGER PRIMARY KEY, date TEXT, riseTime TEXT, setTime TEXT)'); |
447 | + var table = tx.executeSql("SELECT * FROM Easteregg"); |
448 | + if (table.rows.length == 0) { |
449 | + tx.executeSql('INSERT INTO Easteregg VALUES(?, ?, ?, ?)', [1, '', '', '']); |
450 | + }; |
451 | + }); |
452 | + } catch (err) { |
453 | + console.error("Error creating table in Sunrise/Sunset database: " + err); |
454 | + }; |
455 | +} |
456 | + |
457 | +//Read date last checked from DB |
458 | +function getSavedData () { |
459 | + |
460 | + openDB(); |
461 | + |
462 | + var result = new Array(); |
463 | + try { |
464 | + db.readTransaction( |
465 | + function(tx){ |
466 | + var res = tx.executeSql('SELECT * FROM Easteregg WHERE key = 1'); |
467 | + if (res.rows.length > 0) { |
468 | + result[0] = new Array(); |
469 | + result[0][0] = res.rows.item(0).key; |
470 | + result[0][1] = res.rows.item(0).date; |
471 | + result[0][2] = res.rows.item(0).riseTime; |
472 | + result[0][3] = res.rows.item(0).setTime; |
473 | + }; |
474 | + }); |
475 | + } catch (err) { |
476 | + console.error("Error getting sunrise/sunset last checked date: " + err); |
477 | + } |
478 | + return result; |
479 | +} |
480 | + |
481 | +function saveSunTimes (date, sunRise, sunSet) { |
482 | + openDB(); |
483 | + try { |
484 | + db.transaction(function(tx){ |
485 | + var res = tx.executeSql('UPDATE Easteregg SET date = ?, riseTime = ?, setTime = ? WHERE key = 1', [date, sunRise, sunSet]); |
486 | + console.log("Saving Sunrise/Sunset times to disk"); |
487 | + }); |
488 | + } catch (err) { |
489 | + console.error("Error saving sunrise/sunset times: " + err); |
490 | + }; |
491 | +} |
492 | |
493 | === added file 'clock/SearchBox.qml' |
494 | --- clock/SearchBox.qml 1970-01-01 00:00:00 +0000 |
495 | +++ clock/SearchBox.qml 2013-10-22 17:11:13 +0000 |
496 | @@ -0,0 +1,65 @@ |
497 | +/* |
498 | + * Copyright (C) 2013 Canonical Ltd |
499 | + * |
500 | + * This program is free software: you can redistribute it and/or modify |
501 | + * it under the terms of the GNU General Public License version 3 as |
502 | + * published by the Free Software Foundation. |
503 | + * |
504 | + * This program is distributed in the hope that it will be useful, |
505 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
506 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
507 | + * GNU General Public License for more details. |
508 | + * |
509 | + * You should have received a copy of the GNU General Public License |
510 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
511 | + * |
512 | + * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
513 | + */ |
514 | + |
515 | +import QtQuick 2.0 |
516 | +import Ubuntu.Components 0.1 |
517 | +import QtQuick.XmlListModel 2.0 |
518 | + |
519 | +// Search Box element for world clock. Instant search as you type after a small pause. |
520 | +Item { |
521 | + id: searchBox; |
522 | + |
523 | + // Property to hold the string inputted by the user. This is required in other places such as the XML Model for initiating an online query. |
524 | + property alias search_string: searchLabel.text |
525 | + |
526 | + // Signal connected to the search_timer triggered signal to expose it to outside objects |
527 | + signal searchTriggered() |
528 | + |
529 | + Component.onCompleted: search_timer.triggered.connect(searchTriggered) |
530 | + |
531 | + // Search Label |
532 | + TextField { |
533 | + id: searchLabel |
534 | + |
535 | + anchors { left: parent.left; leftMargin: units.gu(2); top: parent.top; bottom: parent.bottom; right: parent.right; rightMargin: units.gu(2) } |
536 | + width: parent.width/1.5 |
537 | + hasClearButton: true |
538 | + placeholderText: i18n.tr("Search") |
539 | + primaryItem: Image { |
540 | + height: parent.height/1.5; |
541 | + fillMode: Image.PreserveAspectFit |
542 | + source: Qt.resolvedUrl("../images/search_icon.svg") |
543 | + } |
544 | + |
545 | + // Provide a small pause before going online to search |
546 | + Timer { |
547 | + id: search_timer |
548 | + interval: 1100 |
549 | + repeat: false |
550 | + } |
551 | + |
552 | + onTextChanged: search_timer.restart() |
553 | + } |
554 | + |
555 | + // Indicator to show search activity |
556 | + ActivityIndicator { |
557 | + id: searchActivity |
558 | + anchors { verticalCenter: searchLabel.verticalCenter; right: searchLabel.right; rightMargin: units.gu(1) } |
559 | + running: searchCityModel.status === XmlListModel.Loading |
560 | + } |
561 | +} |
562 | |
563 | === added file 'clock/WorldCity.qml' |
564 | --- clock/WorldCity.qml 1970-01-01 00:00:00 +0000 |
565 | +++ clock/WorldCity.qml 2013-10-22 17:11:13 +0000 |
566 | @@ -0,0 +1,57 @@ |
567 | +/* |
568 | + * Copyright (C) 2013 Canonical Ltd |
569 | + * |
570 | + * This program is free software: you can redistribute it and/or modify |
571 | + * it under the terms of the GNU General Public License version 3 as |
572 | + * published by the Free Software Foundation. |
573 | + * |
574 | + * This program is distributed in the hope that it will be useful, |
575 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
576 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
577 | + * GNU General Public License for more details. |
578 | + * |
579 | + * You should have received a copy of the GNU General Public License |
580 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
581 | + * |
582 | + * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
583 | + */ |
584 | + |
585 | +import QtQuick 2.0 |
586 | +import Ubuntu.Components 0.1 |
587 | +import QtQuick.XmlListModel 2.0 |
588 | + |
589 | +// XML Model to list cities provided locally by clock-app or search online (geoname.org) for more cities and return latitude and longitude information of the city |
590 | +XmlListModel { |
591 | + id: worldCityModel; |
592 | + |
593 | + readonly property string search_base_url: "http://api.geonames.org/search?q=" |
594 | + readonly property string local_base_url: "common-cities.xml" |
595 | + readonly property int no_of_results: 5 |
596 | + property string search_string: "" |
597 | + |
598 | + // TODO: Change username to something along the lines of "com.ubuntu.clock" |
599 | + readonly property string username: "krnekhelesh"; |
600 | + |
601 | + // Function to return the online search url for city search |
602 | + function searchCityUrl(city) { |
603 | + return (search_base_url + search_string + "&maxRows=" + no_of_results + "&username=" + username + "&style=full&featureClass=P&name_startsWith=" + city); |
604 | + } |
605 | + |
606 | + // Function to return the url of the locally provided city list (xml file) |
607 | + function localCityUrl() { |
608 | + return Qt.resolvedUrl(local_base_url); |
609 | + } |
610 | + |
611 | + // By default list the cities provided locally by clock app |
612 | + source: localCityUrl() |
613 | + query: "/geonames/geoname" |
614 | + |
615 | + XmlRole { name: "city"; query: "toponymName/string()"; isKey: true } |
616 | + XmlRole { name: "country"; query: "countryName/string()"; isKey: true } |
617 | + XmlRole { name: "lat"; query: "lat/string()"; isKey: true } |
618 | + XmlRole { name: "lng"; query: "lng/string()"; isKey: true } |
619 | + XmlRole { name: "adminName"; query: "adminName1/string()"; isKey: true} |
620 | + XmlRole { name: "adminName2"; query: "adminName2/string()"; isKey: true} |
621 | + |
622 | + onSourceChanged: reload(); |
623 | +} |
624 | |
625 | === modified file 'clock/WorldClock.qml' |
626 | --- clock/WorldClock.qml 2013-10-08 22:52:13 +0000 |
627 | +++ clock/WorldClock.qml 2013-10-22 17:11:13 +0000 |
628 | @@ -1,230 +1,181 @@ |
629 | +/* |
630 | + * Copyright (C) 2013 Canonical Ltd |
631 | + * |
632 | + * This program is free software: you can redistribute it and/or modify |
633 | + * it under the terms of the GNU General Public License version 3 as |
634 | + * published by the Free Software Foundation. |
635 | + * |
636 | + * This program is distributed in the hope that it will be useful, |
637 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
638 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
639 | + * GNU General Public License for more details. |
640 | + * |
641 | + * You should have received a copy of the GNU General Public License |
642 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
643 | + * |
644 | + * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
645 | + */ |
646 | + |
647 | import QtQuick 2.0 |
648 | import Ubuntu.Components 0.1 |
649 | import Ubuntu.Components.ListItems 0.1 as ListItem |
650 | import QtQuick.XmlListModel 2.0 |
651 | |
652 | -Column { |
653 | - id: worldClocks |
654 | - |
655 | - // Properties to store the user searched city details |
656 | - property string city: "null"; |
657 | - property real lng: 0; |
658 | - property real lat: 0; |
659 | - property real rawOffSet: 0; |
660 | - |
661 | - // Property to store the city searched by the user |
662 | - property string search_string: "null"; |
663 | - |
664 | - // Properties to store the information related to api.geonames.org |
665 | - readonly property string username: "krnekhelesh"; |
666 | - readonly property string search_base_url: "http://api.geonames.org/search?q="; |
667 | - readonly property string timezone_base_url: "http://api.geonames.org/timezone?lat="; |
668 | - readonly property string local_base_url: "common-cities.xml"; |
669 | - readonly property int no_of_results: 5; |
670 | - |
671 | - property alias searchModel: searchCityModel; |
672 | - property alias index: worldList.currentIndex; |
673 | - |
674 | - signal clicked() |
675 | - |
676 | - function searchCityUrl (city) { |
677 | - return (search_base_url + search_string + "&maxRows=" + no_of_results + "&username=" + username + "&style=full&featureClass=P&name_startsWith=" + city); |
678 | - } |
679 | - |
680 | - function localCityUrl () { |
681 | - return Qt.resolvedUrl(local_base_url); |
682 | - } |
683 | - |
684 | - function getCityTimezoneUrl (lat, lng) { |
685 | - return (timezone_base_url + lat + "&lng=" + lng + "&username=" + username); |
686 | - } |
687 | - |
688 | - function clearUserSearch () { |
689 | - searchCityModel.source = localCityUrl(); |
690 | - searchLabel.text = ""; |
691 | - worldList.currentIndex = -1; |
692 | - } |
693 | - |
694 | - height: childrenRect.height; |
695 | - spacing: units.gu(2); |
696 | - |
697 | - // Xml model to search city online and retrieve latitude and longitude of searched city |
698 | - XmlListModel { |
699 | - id: searchCityModel; |
700 | - |
701 | - source: localCityUrl() |
702 | - query: "/geonames/geoname" |
703 | - |
704 | - XmlRole { name: "city"; query: "toponymName/string()"; isKey: true } |
705 | - XmlRole { name: "country"; query: "countryName/string()"; isKey: true } |
706 | - XmlRole { name: "lat"; query: "lat/string()"; isKey: true } |
707 | - XmlRole { name: "lng"; query: "lng/string()"; isKey: true } |
708 | - XmlRole { name: "adminName"; query: "adminName1/string()"; isKey: true} |
709 | - XmlRole { name: "adminName2"; query: "adminName2/string()"; isKey: true} |
710 | - |
711 | - onSourceChanged: reload(); |
712 | - } |
713 | - |
714 | - Item { |
715 | - id: searchBox; |
716 | - |
717 | - anchors { left: parent.left; right: parent.right } |
718 | - height: units.gu(4) |
719 | - |
720 | - TextField { |
721 | - id: searchLabel |
722 | - |
723 | - anchors { left: parent.left; leftMargin: units.gu(2); top: parent.top; bottom: parent.bottom; right: searchButton.left; rightMargin: -units.gu(1) } |
724 | - width: worldClocks.width/1.5 |
725 | - hasClearButton: true |
726 | - placeholderText: i18n.tr("Search") |
727 | - primaryItem: Image { |
728 | - height: parent.height/2 |
729 | - width: parent.height/2 |
730 | - source: Qt.resolvedUrl("../images/search_icon.svg") |
731 | - } |
732 | - |
733 | - // Provide a small pause before going online to search |
734 | - Timer { |
735 | - id: search_timer |
736 | - |
737 | - interval: 1100 |
738 | - repeat: false |
739 | - onTriggered: { |
740 | - if (searchLabel.text != "") { |
741 | - search_string = searchLabel.text; |
742 | - searchCityModel.source = searchCityUrl(search_string); |
743 | - } else { |
744 | - searchCityModel.source = localCityUrl() |
745 | - } |
746 | - } |
747 | - } |
748 | - |
749 | - onTextChanged: search_timer.restart() |
750 | - |
751 | - InverseMouseArea { |
752 | - visible: searchLabel.activeFocus |
753 | - anchors.fill: parent |
754 | - onClicked: { |
755 | - worldClocks.forceActiveFocus() |
756 | - mouse.accepted = false |
757 | - } |
758 | - } |
759 | - } |
760 | - |
761 | - Item { |
762 | - id: searchButton; |
763 | - anchors { right: parent.right; rightMargin: units.gu(6.5); top: parent.top; bottom: parent.bottom } |
764 | - height: searchLabel.height |
765 | - visible: !searchActivity.running |
766 | - Image { |
767 | - id: name |
768 | - source: Qt.resolvedUrl("../images/search_item.svg") |
769 | - } |
770 | - |
771 | - // Make searchButton clickable |
772 | - MouseArea { |
773 | - id: searchArea; |
774 | - enabled: true; |
775 | - anchors.fill: searchButton |
776 | - onClicked: { |
777 | - if (searchLabel.text != "") { |
778 | - search_string = searchLabel.text; |
779 | - searchCityModel.source = searchCityUrl(search_string); |
780 | - } |
781 | - } |
782 | - } |
783 | - } |
784 | - |
785 | - |
786 | - ActivityIndicator { |
787 | - id: searchActivity |
788 | - anchors { verticalCenter: searchButton.verticalCenter; left: searchButton.left; leftMargin: units.gu(1.5) } |
789 | - running: searchCityModel.status === XmlListModel.Loading |
790 | - |
791 | - } |
792 | - } |
793 | - |
794 | - ListView { |
795 | - id: worldList |
796 | - objectName: "worldList" |
797 | - |
798 | - anchors { left: parent.left; right: parent.right } |
799 | - height: units.gu(50) |
800 | - model: searchCityModel |
801 | - currentIndex: -1 |
802 | - clip: true; |
803 | - |
804 | - Component { |
805 | - id: sectionHeading |
806 | - ListItem.Header { |
807 | - Label { |
808 | - text: section |
809 | - anchors { verticalCenter: parent.verticalCenter; left: parent.left; leftMargin: units.gu(2) } |
810 | - color: Theme.palette.normal.baseText |
811 | - fontSize: "medium" |
812 | - } |
813 | - } |
814 | - } |
815 | - |
816 | - Label { |
817 | - id: errorMessage |
818 | - width: parent.width |
819 | - fontSize: "large" |
820 | - wrapMode: Text.WordWrap |
821 | - horizontalAlignment: TextInput.AlignHCenter |
822 | - anchors.horizontalCenter: parent.horizontalCenter |
823 | - visible: worldList.count == 0 || searchCityModel.status == XmlListModel.Error || cityDetailsModel.status == XmlListModel.Error |
824 | - text: searchCityModel.status == XmlListModel.Error || cityDetailsModel.status == XmlListModel.Error ? i18n.tr("Unable to search online \nPlease check your internet connection") : i18n.tr("No results found") |
825 | - } |
826 | - |
827 | - section.property: !errorMessage.visible ? "city" : "" |
828 | - section.criteria: ViewSection.FirstCharacter |
829 | - section.delegate: sectionHeading; |
830 | - section.labelPositioning: ViewSection.InlineLabels |
831 | - |
832 | - delegate: ListItem.Base { |
833 | - visible: !errorMessage.visible |
834 | - height: adminName || adminName2 ? units.gu(8) : units.gu(6) |
835 | - Column { |
836 | - anchors { top: parent.top; topMargin: units.gu(0.5); left: parent.left; leftMargin: units.gu(3) } |
837 | - Label { |
838 | - id: cityDelegate |
839 | - text: city |
840 | - color: Theme.palette.normal.baseText |
841 | - fontSize: "large" |
842 | - } |
843 | - Label { |
844 | - id: stateDelegate |
845 | - width: worldClocks.width |
846 | - elide: Text.ElideRight |
847 | - text: { |
848 | - if (adminName && adminName2) |
849 | - return adminName2 + ", " + adminName |
850 | - else if(adminName) |
851 | - return adminName |
852 | - else if(adminName2) |
853 | - return adminName2 |
854 | - else |
855 | - return "" |
856 | - } |
857 | - visible: text == "" ? false : true |
858 | - color: Theme.palette.normal.baseText |
859 | - fontSize: "small" |
860 | - } |
861 | - Label { |
862 | - id: countryDelegate |
863 | - text: country |
864 | - color: Theme.palette.normal.baseText |
865 | - fontSize: "small" |
866 | - } |
867 | - } |
868 | - |
869 | - selected: worldList.currentIndex == index; |
870 | - |
871 | - onClicked: { |
872 | - worldList.currentIndex = index; |
873 | - worldClocks.clicked() |
874 | +// Page to to search a world city and add it to the world clocks |
875 | +Page { |
876 | + id: worldPage |
877 | + |
878 | + property bool isWorldCity; |
879 | + |
880 | + visible: false; |
881 | + title: isWorldCity ? i18n.tr("Add City") : i18n.tr("Edit Current Location") |
882 | + |
883 | + Column { |
884 | + id: worldClocks |
885 | + |
886 | + // Properties to store the user searched city details |
887 | + property string city: "null"; |
888 | + property real lng: 0; |
889 | + property real lat: 0; |
890 | + |
891 | + // Function to clear user search and return to original state |
892 | + function clearUserSearch () { |
893 | + searchCityModel.source = searchCityModel.localCityUrl(); |
894 | + searchBox.search_string = ""; |
895 | + worldList.currentIndex = -1; |
896 | + } |
897 | + |
898 | + anchors { fill: parent; topMargin: units.gu(2) } |
899 | + height: childrenRect.height; |
900 | + spacing: units.gu(2); |
901 | + |
902 | + // XML Model to list cities provided locally with clock-app or search cities online and retrieve latitude and longitude of searched city |
903 | + WorldCity { |
904 | + id: searchCityModel |
905 | + search_string: searchBox.search_string |
906 | + } |
907 | + |
908 | + // XML Model to retrieve timezone of searched city |
909 | + CityTimezone { |
910 | + id: cityDetailsModel |
911 | + onStatusChanged: { |
912 | + if(status == XmlListModel.Ready && worldClocks.city != "null") { |
913 | + if (isWorldCity) |
914 | + worldModel.appendPreset(worldClocks.city, getTimeDifference(cityDetailsModel.get(0).time), worldClocks.lng, worldClocks.lat); |
915 | + else |
916 | + worldModel.appendCurrentLocation(worldClocks.city, worldClocks.lng, worldClocks.lat); |
917 | + worldClocks.clearUserSearch(); |
918 | + pageStack.pop() |
919 | + } |
920 | + } |
921 | + } |
922 | + |
923 | + // Search Bar to search for cities (online) |
924 | + // TODO: Add capability to also search cities provided locally with clock-app |
925 | + SearchBox { |
926 | + id: searchBox |
927 | + |
928 | + height: units.gu(4) |
929 | + anchors { left: parent.left; right: parent.right } |
930 | + |
931 | + onSearchTriggered: { |
932 | + if (search_string != "") |
933 | + searchCityModel.source = searchCityModel.searchCityUrl(search_string); |
934 | + else |
935 | + searchCityModel.source = searchCityModel.localCityUrl() |
936 | + } |
937 | + } |
938 | + |
939 | + // List to display the search results |
940 | + ListView { |
941 | + id: worldList |
942 | + objectName: "worldList" |
943 | + |
944 | + anchors { left: parent.left; right: parent.right } |
945 | + height: units.gu(50) // TODO: Make list view dynamic rather than the fixed 50 units gu. |
946 | + model: searchCityModel |
947 | + currentIndex: -1 |
948 | + clip: true; |
949 | + |
950 | + Component { |
951 | + id: sectionHeading |
952 | + ListItem.Header { |
953 | + Label { |
954 | + text: section |
955 | + anchors { verticalCenter: parent.verticalCenter; left: parent.left; leftMargin: units.gu(2) } |
956 | + color: Theme.palette.normal.baseText |
957 | + fontSize: "medium" |
958 | + } |
959 | + } |
960 | + } |
961 | + |
962 | + Label { |
963 | + id: errorMessage |
964 | + width: parent.width |
965 | + fontSize: "large" |
966 | + wrapMode: Text.WordWrap |
967 | + horizontalAlignment: TextInput.AlignHCenter |
968 | + anchors.horizontalCenter: parent.horizontalCenter |
969 | + visible: worldList.count == 0 || searchCityModel.status == XmlListModel.Error || cityDetailsModel.status == XmlListModel.Error |
970 | + text: searchCityModel.status == XmlListModel.Error || cityDetailsModel.status == XmlListModel.Error ? i18n.tr("Unable to search online \nPlease check your internet connection") : i18n.tr("No results found") |
971 | + } |
972 | + |
973 | + section.property: !errorMessage.visible ? "city" : "" |
974 | + section.criteria: ViewSection.FirstCharacter |
975 | + section.delegate: sectionHeading; |
976 | + section.labelPositioning: ViewSection.InlineLabels |
977 | + |
978 | + delegate: ListItem.Base { |
979 | + visible: !errorMessage.visible |
980 | + height: adminName || adminName2 ? units.gu(8) : units.gu(6) |
981 | + Column { |
982 | + anchors { top: parent.top; topMargin: units.gu(0.5); left: parent.left; leftMargin: units.gu(3) } |
983 | + Label { |
984 | + id: cityDelegate |
985 | + text: city |
986 | + color: Theme.palette.normal.baseText |
987 | + fontSize: "large" |
988 | + } |
989 | + Label { |
990 | + id: stateDelegate |
991 | + width: worldClocks.width |
992 | + elide: Text.ElideRight |
993 | + text: { |
994 | + if (adminName && adminName2) |
995 | + return adminName2 + ", " + adminName |
996 | + else if(adminName) |
997 | + return adminName |
998 | + else if(adminName2) |
999 | + return adminName2 |
1000 | + else |
1001 | + return "" |
1002 | + } |
1003 | + visible: text == "" ? false : true |
1004 | + color: Theme.palette.normal.baseText |
1005 | + fontSize: "small" |
1006 | + } |
1007 | + Label { |
1008 | + id: countryDelegate |
1009 | + text: country |
1010 | + color: Theme.palette.normal.baseText |
1011 | + fontSize: "small" |
1012 | + } |
1013 | + } |
1014 | + |
1015 | + selected: worldList.currentIndex == index; |
1016 | + |
1017 | + onClicked: { |
1018 | + worldList.currentIndex = index; |
1019 | + worldClocks.lat = searchCityModel.get(index).lat; |
1020 | + worldClocks.lng = searchCityModel.get(index).lng; |
1021 | + worldClocks.city = searchCityModel.get(index).city; |
1022 | + cityDetailsModel.source = cityDetailsModel.getCityTimezoneUrl(worldClocks.lat, worldClocks.lng) |
1023 | + } |
1024 | + } |
1025 | + |
1026 | + Scrollbar { |
1027 | + flickableItem: worldList; |
1028 | + align: Qt.AlignTrailing; |
1029 | } |
1030 | } |
1031 | } |
1032 | |
1033 | === removed file 'clock/WorldPage.qml' |
1034 | --- clock/WorldPage.qml 2013-09-27 08:38:15 +0000 |
1035 | +++ clock/WorldPage.qml 1970-01-01 00:00:00 +0000 |
1036 | @@ -1,76 +0,0 @@ |
1037 | -/* |
1038 | - * Copyright (C) 2013 Canonical Ltd |
1039 | - * |
1040 | - * This program is free software: you can redistribute it and/or modify |
1041 | - * it under the terms of the GNU General Public License version 3 as |
1042 | - * published by the Free Software Foundation. |
1043 | - * |
1044 | - * This program is distributed in the hope that it will be useful, |
1045 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1046 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1047 | - * GNU General Public License for more details. |
1048 | - * |
1049 | - * You should have received a copy of the GNU General Public License |
1050 | - * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1051 | - * |
1052 | - * Authored by: Nekhelesh Ramananthan <krnekhelesh@gmail.com> |
1053 | - */ |
1054 | - |
1055 | -import QtQuick 2.0 |
1056 | -import Ubuntu.Components 0.1 |
1057 | -import QtQuick.XmlListModel 2.0 |
1058 | - |
1059 | -Page { |
1060 | - id: worldPage |
1061 | - |
1062 | - property bool isWorldCity; |
1063 | - |
1064 | - visible: false; |
1065 | - title: isWorldCity ? i18n.tr("Add City") : i18n.tr("Edit Current Location") |
1066 | - |
1067 | - function getTimeDifference(data) { |
1068 | - var worldTime = data.split(' ')[1].split(':'); |
1069 | - var hoursWT = parseInt(worldTime[0]); |
1070 | - var minutesWT = parseInt(worldTime[1]); |
1071 | - var now = new Date(); |
1072 | - var UTCdiff = new Date().getTimezoneOffset() |
1073 | - now.setMinutes(now.getMinutes() + UTCdiff) |
1074 | - |
1075 | - // Calculating world city time diff w.r.t UTC |
1076 | - return ((hoursWT - now.getHours()) * 60 + (minutesWT - now.getMinutes())); |
1077 | - } |
1078 | - |
1079 | - WorldClock { |
1080 | - id: worldClockList; |
1081 | - |
1082 | - anchors { fill: parent; topMargin: units.gu(2) } |
1083 | - |
1084 | - // Xml model to retrieve timezone of searched city |
1085 | - XmlListModel { |
1086 | - id: cityDetailsModel; |
1087 | - |
1088 | - source: worldClockList.getCityTimezoneUrl(worldClockList.lat, worldClockList.lng) |
1089 | - query: "/geonames/timezone" |
1090 | - |
1091 | - onStatusChanged: { |
1092 | - if(status == XmlListModel.Ready && worldClockList.city != "null") { |
1093 | - if (isWorldCity) |
1094 | - worldModel.appendPreset(worldClockList.city, getTimeDifference(cityDetailsModel.get(0).time), worldClockList.lng, worldClockList.lat); |
1095 | - else |
1096 | - worldModel.appendCurrentLocation(worldClockList.city, worldClockList.lng, worldClockList.lat); |
1097 | - worldClockList.clearUserSearch(); |
1098 | - pageStack.pop() |
1099 | - } |
1100 | - } |
1101 | - |
1102 | - XmlRole { name: "time"; query: "time/string()" } |
1103 | - } |
1104 | - |
1105 | - onClicked: { |
1106 | - lat = searchModel.get(index).lat; |
1107 | - lng = searchModel.get(index).lng; |
1108 | - city = searchModel.get(index).city; |
1109 | - cityDetailsModel.reload() |
1110 | - } |
1111 | - } |
1112 | -} |
1113 | |
1114 | === modified file 'tests/autopilot/ubuntu_clock_app/emulators.py' |
1115 | --- tests/autopilot/ubuntu_clock_app/emulators.py 2013-10-21 21:16:41 +0000 |
1116 | +++ tests/autopilot/ubuntu_clock_app/emulators.py 2013-10-22 17:11:13 +0000 |
1117 | @@ -294,7 +294,7 @@ |
1118 | |
1119 | def get_world_cities_page(self): |
1120 | """Return the page containing the world cities.""" |
1121 | - return self.select_single("WorldPage") |
1122 | + return self.select_single("WorldClock") |
1123 | |
1124 | def get_clock_page(self): |
1125 | """Return the page containing the main clock.""" |
FAILED: Continuous integration, rev:258 91.189. 93.70:8080/ job/ubuntu- clock-app- ci/77/ 91.189. 93.70:8080/ job/generic- mediumtests/ 1167 91.189. 93.70:8080/ job/ubuntu- clock-app- precise- amd64-ci/ 77 91.189. 93.70:8080/ job/ubuntu- clock-app- quantal- amd64-ci/ 77 91.189. 93.70:8080/ job/ubuntu- clock-app- raring- amd64-ci/ 77 91.189. 93.70:8080/ job/ubuntu- clock-app- saucy-amd64- ci/77
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- clock-app- ci/77/rebuild
http://