Merge lp:~nik90/ubuntu-weather-app/1-improve-add-location-page into lp:ubuntu-weather-app

Proposed by Nekhelesh Ramananthan
Status: Merged
Approved by: Martin Borho
Approved revision: 20
Merged at revision: 17
Proposed branch: lp:~nik90/ubuntu-weather-app/1-improve-add-location-page
Merge into: lp:ubuntu-weather-app
Prerequisite: lp:~nik90/ubuntu-weather-app/0-fix-broken-settings-links
Diff against target: 777 lines (+600/-55)
5 files modified
app/components/FastScroll.js (+130/-0)
app/components/FastScroll.qml (+321/-0)
app/ui/AddLocationPage.qml (+126/-40)
app/ui/LocationsPage.qml (+1/-1)
po/com.ubuntu.weather.pot (+22/-14)
To merge this branch: bzr merge lp:~nik90/ubuntu-weather-app/1-improve-add-location-page
Reviewer Review Type Date Requested Status
Martin Borho Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+252115@code.launchpad.net

This proposal supersedes a proposal from 2015-03-06.

Commit message

This MP brings the Add Location Page more in line with Clock app's own add city page to maintain consistency. Also there was no design specified for the add location page in weather app's design spec.

- Added fast scroll to add location page
- Renamed AddPage.qml to AddLocationPage.qml to be more specific
- Added section headers to listview
- Removed focus on search textfield immediately after opening the add location page. The reasoning here being that we show a list of cities that the user can choose from. Only if doesnt find his city there should he resort to searching online.
- Moved the search textfield to a component to allow for dynamic loading

Description of the change

This MP brings the Add Location Page more in line with Clock app's own add city page to maintain consistency. Also there was no design specified for the add location page in weather app's design spec.

- Added fast scroll to add location page
- Renamed AddPage.qml to AddLocationPage.qml to be more specific
- Added section headers to listview
- Removed focus on search textfield immediately after opening the add location page. The reasoning here being that we show a list of cities that the user can choose from. Only if doesnt find his city there should he resort to searching online.
- Moved the search textfield to a component to allow for dynamic loading

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Martin Borho (martin-borho) wrote :

Very good, thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added file 'app/components/FastScroll.js'
--- app/components/FastScroll.js 1970-01-01 00:00:00 +0000
+++ app/components/FastScroll.js 2015-03-06 14:21:02 +0000
@@ -0,0 +1,130 @@
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** Copyright (C) 2014 Canonical Ltda
5** All rights reserved.
6** Contact: Nokia Corporation (qt-info@nokia.com)
7**
8** This file is part of the Qt Components project.
9**
10** $QT_BEGIN_LICENSE:BSD$
11** You may use this file under the terms of the BSD license as follows:
12**
13** "Redistribution and use in source and binary forms, with or without
14** modification, are permitted provided that the following conditions are
15** met:
16** * Redistributions of source code must retain the above copyright
17** notice, this list of conditions and the following disclaimer.
18** * Redistributions in binary form must reproduce the above copyright
19** notice, this list of conditions and the following disclaimer in
20** the documentation and/or other materials provided with the
21** distribution.
22** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
23** the names of its contributors may be used to endorse or promote
24** products derived from this software without specific prior written
25** permission.
26**
27** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42// FastScroll.js - this is just SectionScroller.js with a fix for
43// section.criteria == ViewSection.FirstCharacter
44var sectionData = [];
45var _sections = [];
46
47function initialize(list) {
48 initSectionData(list);
49}
50
51function contains(name) {
52 return (_sections.indexOf(name) > -1)
53}
54
55function initSectionData(list) {
56 if (!list || !list.model) return;
57 sectionData = [];
58 _sections = [];
59 var current = "",
60 prop = list.section.property,
61 sectionText;
62
63 if (list.section.criteria === ViewSection.FullString) {
64 for (var i = 0, count = list.model.count; i < count; i++) {
65 sectionText = list.getSectionText(i)
66 if (sectionText !== current) {
67 current = sectionText;
68 _sections.push(current);
69 sectionData.push({ index: i, header: current });
70 }
71 }
72 } else if (list.section.criteria === ViewSection.FirstCharacter) {
73 for (var i = 0, count = list.model.count; i < count; i++) {
74 sectionText = list.getSectionText(i).substring(0, 1)
75 if (sectionText !== current) {
76 current = sectionText
77 _sections.push(sectionText);
78 sectionData.push({ index: i, header: current });
79 }
80 }
81 }
82}
83
84function getSectionPositionString(name) {
85 var val = _sections.indexOf(name);
86 return val === 0 ? "first" :
87 val === _sections.length - 1 ? "last" : false;
88}
89
90function getAt(pos) {
91 return _sections[pos] ? _sections[pos] : "";
92}
93
94function getRelativeSections(current) {
95 var val = _sections.indexOf(current),
96 sect = [],
97 sl = _sections.length;
98
99 val = val < 1 ? 1 : val >= sl-1 ? sl-2 : val;
100 sect = [getAt(val - 1), getAt(val), getAt(val + 1)];
101
102 return sect;
103}
104
105function getClosestSection(pos, down) {
106 var tmp = (_sections.length) * pos;
107 var val = Math.ceil(tmp) // TODO: better algorithm
108 val = val < 2 ? 1 : val;
109 return _sections[val-1];
110}
111
112function getNextSection(current) {
113 var val = _sections.indexOf(current);
114 return (val > -1 ? _sections[(val < _sections.length - 1 ? val + 1 : val)] : _sections[0]) || "";
115}
116
117function getPreviousSection(current) {
118 var val = _sections.indexOf(current);
119 return (val > -1 ? _sections[(val > 0 ? val - 1 : val)] : _sections[0]) || "";
120}
121
122function getIndexFor(sectionName) {
123 var data = sectionData[_sections.indexOf(sectionName)]
124 if (data) {
125 var val = data.index;
126 return val === 0 || val > 0 ? val : -1;
127 } else {
128 return -1
129 }
130}
0131
=== added file 'app/components/FastScroll.qml'
--- app/components/FastScroll.qml 1970-01-01 00:00:00 +0000
+++ app/components/FastScroll.qml 2015-03-06 14:21:02 +0000
@@ -0,0 +1,321 @@
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** Copyright (C) 2014 Canonical Ltda
5** All rights reserved.
6** Contact: Nokia Corporation (qt-info@nokia.com)
7**
8** This file is part of the Qt Components project.
9**
10** $QT_BEGIN_LICENSE:BSD$
11** You may use this file under the terms of the BSD license as follows:
12**
13** "Redistribution and use in source and binary forms, with or without
14** modification, are permitted provided that the following conditions are
15** met:
16** * Redistributions of source code must retain the above copyright
17** notice, this list of conditions and the following disclaimer.
18** * Redistributions in binary form must reproduce the above copyright
19** notice, this list of conditions and the following disclaimer in
20** the documentation and/or other materials provided with the
21** distribution.
22** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
23** the names of its contributors may be used to endorse or promote
24** products derived from this software without specific prior written
25** permission.
26**
27** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42// FastScroll.qml
43import QtQuick 2.3
44import Ubuntu.Components 1.1
45import "FastScroll.js" as Sections
46
47Item {
48 id: root
49
50 property ListView listView
51 property int pinSize: units.gu(2)
52
53 readonly property var letters: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
54 readonly property alias fastScrolling: internal.fastScrolling
55 readonly property bool showing: (rail.opacity !== 0.0)
56 readonly property double minimumHeight: rail.height
57
58 width: units.gu(7)
59 height: rail.height
60
61 onListViewChanged: {
62 if (listView && listView.model) {
63 internal.initDirtyObserver();
64 } else if (listView) {
65 listView.modelChanged.connect(function() {
66 if (listView.model) {
67 internal.initDirtyObserver();
68 }
69 });
70 }
71 }
72
73 Connections {
74 target: listView
75 onCurrentIndexChanged: {
76 if (currentIndex != -1) {
77 rail.opacity = 0.0
78 }
79 }
80 }
81
82 Rectangle {
83 id: magnified
84
85 color: Theme.palette.normal.overlay
86 radius: height * 0.3
87 height: pinSize * 2
88 width: height
89 opacity: internal.fastScrolling && root.enabled ? 1.0 : 0.0
90 x: -cursor.width - units.gu(3)
91 y: {
92 if (internal.currentItem) {
93 var itemCenterY = rail.y + internal.currentItem.y + (internal.currentItem.height / 2)
94 return (itemCenterY - (magnified.height / 2))
95 } else {
96 return 0
97 }
98 }
99
100 Label {
101 anchors.fill: parent
102 horizontalAlignment: Text.AlignHCenter
103 verticalAlignment: Text.AlignVCenter
104 text: internal.desireSection
105 fontSize: "small"
106 }
107
108 Behavior on opacity {
109 UbuntuNumberAnimation {}
110 }
111 }
112
113 Rectangle {
114 id: cursor
115
116 property bool showLabel: false
117 property string currentSectionName: ""
118
119 radius: pinSize * 0.3
120 height: pinSize
121 width: height
122 color: Theme.palette.normal.foreground
123 opacity: rail.opacity
124 x: rail.x
125 y: {
126 if (internal.currentItem) {
127 var itemCenterY = rail.y + internal.currentItem.y + (internal.currentItem.height / 2)
128 return (itemCenterY - (cursor.height / 2))
129 } else {
130 return 0
131 }
132 }
133 Behavior on y {
134 enabled: !internal.fastScrolling
135 UbuntuNumberAnimation { }
136 }
137 }
138
139 Column {
140 id: rail
141
142 property bool isVisible: root.enabled &&
143 (listView.flicking || dragArea.pressed) &&
144 (listView.currentIndex == -1)
145 anchors {
146 right: parent.right
147 rightMargin: units.gu(2)
148 left: parent.left
149 leftMargin: units.gu(2)
150 top: parent.top
151 }
152 height: childrenRect.height
153 opacity: 0.0
154 onIsVisibleChanged: {
155 if (isVisible) {
156 rail.opacity = 1.0
157 hideTimer.stop()
158 } else if (!root.enabled) {
159 rail.opacity = 0.0
160 } else {
161 hideTimer.restart()
162 }
163 }
164
165 Behavior on opacity {
166 UbuntuNumberAnimation { }
167 }
168
169 Repeater {
170 id: sectionsRepeater
171
172 model: root.letters
173 Label {
174 id: lbl
175
176 anchors.left: parent.left
177 height: pinSize
178 width: pinSize
179 verticalAlignment: Text.AlignVCenter
180 horizontalAlignment: Text.AlignHCenter
181 text: modelData
182 fontSize: "x-small"
183 color: cursor.y === y ? "white" : Theme.palette.selected.backgroundText
184 opacity: !internal.modelDirty && Sections.contains(text) ? 1.0 : 0.5
185 }
186 }
187
188 Timer {
189 id: hideTimer
190
191 running: false
192 interval: 2000
193 onTriggered: rail.opacity = 0.0
194 }
195 }
196
197 MouseArea {
198 id: dragArea
199
200 anchors {
201 left: parent.left
202 right: parent.right
203 }
204 y: rail.y
205 height: rail.height
206 visible: rail.opacity == 1.0
207
208 preventStealing: true
209 onPressed: {
210 internal.adjustContentPosition(mouseY)
211 dragginTimer.start()
212 }
213
214 onReleased: {
215 dragginTimer.stop()
216 internal.desireSection = ""
217 internal.fastScrolling = false
218 }
219
220 onPositionChanged: internal.adjustContentPosition(mouseY)
221
222 Timer {
223 id: dragginTimer
224
225 running: false
226 interval: 150
227 onTriggered: {
228 internal.fastScrolling = true
229 }
230 }
231 }
232
233 Timer {
234 id: dirtyTimer
235 interval: 500
236 running: false
237 onTriggered: {
238 Sections.initSectionData(listView);
239 internal.modelDirty = false;
240 }
241 }
242
243 Timer {
244 id: timerScroll
245
246 running: false
247 interval: 10
248 onTriggered: {
249 if (internal.desireSection != internal.currentSection) {
250 var idx = Sections.getIndexFor(internal.desireSection)
251 if (idx !== -1) {
252 listView.cancelFlick()
253 listView.positionViewAtIndex(idx, ListView.Beginning)
254 }
255 }
256 }
257 }
258
259 QtObject {
260 id: internal
261
262 property string currentSection: listView.currentSection
263 property string desireSection: ""
264 property string targetSection: fastScrolling ? desireSection : currentSection
265 property int oldY: 0
266 property bool modelDirty: false
267 property bool down: true
268 property bool fastScrolling: false
269 property var currentItem: null
270
271 onTargetSectionChanged: moveIndicator(targetSection)
272
273 function initDirtyObserver() {
274 Sections.initialize(listView);
275 function dirtyObserver() {
276 if (!internal.modelDirty) {
277 internal.modelDirty = true;
278 dirtyTimer.running = true;
279 }
280 }
281
282 if (listView.model.countChanged)
283 listView.model.countChanged.connect(dirtyObserver);
284
285 if (listView.model.itemsChanged)
286 listView.model.itemsChanged.connect(dirtyObserver);
287
288 if (listView.model.itemsInserted)
289 listView.model.itemsInserted.connect(dirtyObserver);
290
291 if (listView.model.itemsMoved)
292 listView.model.itemsMoved.connect(dirtyObserver);
293
294 if (listView.model.itemsRemoved)
295 listView.model.itemsRemoved.connect(dirtyObserver);
296 }
297
298 function adjustContentPosition(mouseY) {
299 var child = rail.childAt(rail.width / 2, mouseY)
300 if (!child || child.text === "") {
301 return
302 }
303 var section = child.text
304 if (internal.desireSection !== section) {
305 internal.desireSection = section
306 moveIndicator(section)
307 if (dragArea.pressed) {
308 timerScroll.restart()
309 }
310 }
311 }
312
313 function moveIndicator(section)
314 {
315 var index = root.letters.indexOf(section)
316 if (index != -1) {
317 currentItem = sectionsRepeater.itemAt(index)
318 }
319 }
320 }
321}
0322
=== renamed file 'app/ui/AddPage.qml' => 'app/ui/AddLocationPage.qml'
--- app/ui/AddPage.qml 2015-03-03 13:52:31 +0000
+++ app/ui/AddLocationPage.qml 2015-03-06 14:21:02 +0000
@@ -25,32 +25,77 @@
25import "../data/WeatherApi.js" as WeatherApi25import "../data/WeatherApi.js" as WeatherApi
2626
27Page {27Page {
28 id: addPage28 id: addLocationPage
29 title: i18n.tr("Add city")29
3030 title: i18n.tr("Select a city")
31 head.contents: TextField {31 visible: false
32 id: searchField32
33 anchors {33 /*
34 left: parent ? parent.left : undefined34 Flickable is set to null to stop page header from hiding since the fast
35 right: parent ? parent.right : undefined35 scroll component hides top anchor margin is incorrect.
36 rightMargin: units.gu(2)36 */
37 }37 flickable: null
38 hasClearButton: true38
39 inputMethodHints: Qt.ImhNoPredictiveText39 state: "default"
40 placeholderText: i18n.tr("Search city")40 states: [
4141 PageHeadState {
42 onTextChanged: {42 name: "default"
43 if (text.trim() === "") {43 head: addLocationPage.head
44 loadEmpty()44 actions: [
45 } else {45 Action {
46 loadFromProvider(text)46 iconName: "search"
47 }47 text: i18n.tr("City")
48 }48 onTriggered: {
4949 addLocationPage.state = "search"
50 onVisibleChanged: {50 searchComponentLoader.sourceComponent = searchComponent
51 if (visible) {51 searchComponentLoader.item.forceActiveFocus()
52 forceActiveFocus()52 }
53 }53 }
54 ]
55 },
56
57 PageHeadState {
58 name: "search"
59 head: addLocationPage.head
60 backAction: Action {
61 iconName: "back"
62 text: i18n.tr("Back")
63 onTriggered: {
64 locationList.forceActiveFocus()
65 searchComponentLoader.item.text = ""
66 addLocationPage.state = "default"
67 searchComponentLoader.sourceComponent = undefined
68 }
69 }
70
71 contents: Loader {
72 id: searchComponentLoader
73 anchors {
74 left: parent ? parent.left : undefined
75 right: parent ? parent.right : undefined
76 rightMargin: units.gu(2)
77 }
78 }
79 }
80 ]
81
82 Component {
83 id: searchComponent
84 TextField {
85 id: searchField
86 objectName: "searchField"
87
88 inputMethodHints: Qt.ImhNoPredictiveText
89 placeholderText: i18n.tr("Search city")
90 hasClearButton: true
91
92 onTextChanged: {
93 if (text.trim() === "") {
94 loadEmpty()
95 } else {
96 loadFromProvider(text)
97 }
98 }
54 }99 }
55 }100 }
56101
@@ -78,12 +123,12 @@
78 clearModelForLoading()123 clearModelForLoading()
79124
80 WeatherApi.sendRequest({125 WeatherApi.sendRequest({
81 action: "searchByName",126 action: "searchByName",
82 params: {127 params: {
83 name: search,128 name: search,
84 units: "metric"129 units: "metric"
85 }130 }
86 }, searchResponseHandler)131 }, searchResponseHandler)
87 }132 }
88133
89 function searchResponseHandler(msgObject) {134 function searchResponseHandler(msgObject) {
@@ -97,10 +142,30 @@
97 }142 }
98143
99 ListView {144 ListView {
100 id: addLocationView145 id: locationList
101 anchors {146
102 fill: parent147 clip: true
103 }148 currentIndex: -1
149 anchors.fill: parent
150 anchors.rightMargin: fastScroll.showing ? fastScroll.width - units.gu(1)
151 : 0
152
153 function getSectionText(index) {
154 return citiesModel.get(index).name.substring(0,1)
155 }
156
157 onFlickStarted: {
158 forceActiveFocus()
159 }
160
161 section.property: "name"
162 section.criteria: ViewSection.FirstCharacter
163 section.labelPositioning: ViewSection.InlineLabels
164
165 section.delegate: ListItem.Header {
166 text: section
167 }
168
104 model: ListModel {169 model: ListModel {
105 id: citiesModel170 id: citiesModel
106171
@@ -109,7 +174,9 @@
109174
110 onRowsAboutToBeInserted: loading = false175 onRowsAboutToBeInserted: loading = false
111 }176 }
177
112 delegate: ListItem.Empty {178 delegate: ListItem.Empty {
179 showDivider: false
113 Column {180 Column {
114 anchors {181 anchors {
115 left: parent.left182 left: parent.left
@@ -118,20 +185,19 @@
118 rightMargin: units.gu(2)185 rightMargin: units.gu(2)
119 verticalCenter: parent.verticalCenter186 verticalCenter: parent.verticalCenter
120 }187 }
121 spacing: units.gu(0.5)
122188
123 Label {189 Label {
124 color: UbuntuColors.darkGrey190 color: UbuntuColors.darkGrey
125 elide: Text.ElideRight191 elide: Text.ElideRight
126 fontSize: "medium"192 fontSize: "medium"
127 text: model.name193 text: name
128 }194 }
129195
130 Label {196 Label {
131 color: UbuntuColors.lightGrey197 color: UbuntuColors.lightGrey
132 elide: Text.ElideRight198 elide: Text.ElideRight
133 fontSize: "small"199 fontSize: "xx-small"
134 text: model.countryName200 text: countryName
135 }201 }
136 }202 }
137203
@@ -145,6 +211,26 @@
145 }211 }
146212
147 Component.onCompleted: loadEmpty()213 Component.onCompleted: loadEmpty()
214
215 Behavior on anchors.rightMargin {
216 UbuntuNumberAnimation {}
217 }
218 }
219
220 FastScroll {
221 id: fastScroll
222
223 listView: locationList
224
225 enabled: (locationList.contentHeight > (locationList.height * 2)) &&
226 (locationList.height >= minimumHeight)
227
228 anchors {
229 top: locationList.top
230 topMargin: units.gu(1.5)
231 bottom: locationList.bottom
232 right: parent.right
233 }
148 }234 }
149235
150 ActivityIndicator {236 ActivityIndicator {
151237
=== modified file 'app/ui/LocationsPage.qml'
--- app/ui/LocationsPage.qml 2015-03-03 18:37:59 +0000
+++ app/ui/LocationsPage.qml 2015-03-06 14:21:02 +0000
@@ -37,7 +37,7 @@
37 actions: [37 actions: [
38 Action {38 Action {
39 iconName: "add"39 iconName: "add"
40 onTriggered: mainPageStack.push(Qt.resolvedUrl("AddPage.qml"))40 onTriggered: mainPageStack.push(Qt.resolvedUrl("AddLocationPage.qml"))
41 }41 }
42 ]42 ]
43 PropertyChanges {43 PropertyChanges {
4444
=== modified file 'po/com.ubuntu.weather.pot'
--- po/com.ubuntu.weather.pot 2015-03-06 14:21:02 +0000
+++ po/com.ubuntu.weather.pot 2015-03-06 14:21:02 +0000
@@ -8,7 +8,7 @@
8msgstr ""8msgstr ""
9"Project-Id-Version: ubuntu-weather-app\n"9"Project-Id-Version: ubuntu-weather-app\n"
10"Report-Msgid-Bugs-To: \n"10"Report-Msgid-Bugs-To: \n"
11"POT-Creation-Date: 2015-03-06 14:23+0100\n"11"POT-Creation-Date: 2015-03-06 15:08+0100\n"
12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"12"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"13"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14"Language-Team: LANGUAGE <LL@li.org>\n"14"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -37,27 +37,35 @@
37msgid "Cancel selection"37msgid "Cancel selection"
38msgstr ""38msgstr ""
3939
40#: ../app/ui/AddPage.qml:2940#: ../app/ui/AddLocationPage.qml:30
41msgid "Add city"41msgid "Select a city"
42msgstr ""42msgstr ""
4343
44#: ../app/ui/AddPage.qml:4044#: ../app/ui/AddLocationPage.qml:47
45msgid "City"
46msgstr ""
47
48#: ../app/ui/AddLocationPage.qml:62
49msgid "Back"
50msgstr ""
51
52#: ../app/ui/AddLocationPage.qml:89
45msgid "Search city"53msgid "Search city"
46msgstr ""54msgstr ""
4755
48#: ../app/ui/AddPage.qml:16356#: ../app/ui/AddLocationPage.qml:249
49msgid "No city found"57msgid "No city found"
50msgstr ""58msgstr ""
5159
52#: ../app/ui/AddPage.qml:17660#: ../app/ui/AddLocationPage.qml:262
53msgid "Couldn't load weather data, please try later again!"61msgid "Couldn't load weather data, please try later again!"
54msgstr ""62msgstr ""
5563
56#: ../app/ui/AddPage.qml:18664#: ../app/ui/AddLocationPage.qml:272
57msgid "Location already added."65msgid "Location already added."
58msgstr ""66msgstr ""
5967
60#: ../app/ui/AddPage.qml:18968#: ../app/ui/AddLocationPage.qml:275
61msgid "OK"69msgid "OK"
62msgstr ""70msgstr ""
6371
@@ -65,19 +73,19 @@
65msgid "Locations"73msgid "Locations"
66msgstr ""74msgstr ""
6775
68#: ../app/ui/SettingsPage.qml:2576#: ../app/ui/SettingsPage.qml:24
69msgid "Settings"77msgid "Settings"
70msgstr ""78msgstr ""
7179
72#: ../app/ui/SettingsPage.qml:42 ../app/ui/settings/UnitsPage.qml:2580#: ../app/ui/SettingsPage.qml:41 ../app/ui/settings/UnitsPage.qml:25
73msgid "Units"81msgid "Units"
74msgstr ""82msgstr ""
7583
76#: ../app/ui/SettingsPage.qml:49 ../app/ui/settings/DataProviderPage.qml:2584#: ../app/ui/SettingsPage.qml:48 ../app/ui/settings/DataProviderPage.qml:25
77msgid "Data Provider"85msgid "Data Provider"
78msgstr ""86msgstr ""
7987
80#: ../app/ui/SettingsPage.qml:56 ../app/ui/settings/RefreshIntervalPage.qml:2588#: ../app/ui/SettingsPage.qml:55 ../app/ui/settings/RefreshIntervalPage.qml:25
81msgid "Refresh Interval"89msgid "Refresh Interval"
82msgstr ""90msgstr ""
8391

Subscribers

People subscribed via source and target branches