~cibersheep/unav/systemcolors

« back to all changes in this revision

Viewing changes to qml/PoiListPage.qml

  • Committer: costales
  • Date: 2016-03-26 18:53:17 UTC
  • Revision ID: costales.marcos@gmail.com-20160326185317-4iau3yhe8986h5pg
Init team

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * GPS Navigation http://launchpad.net/unav
 
3
 * Copyright (C) 2015-2016 Marcos Alvarez Costales https://launchpad.net/~costales
 
4
 * Copyright (C) 2015-2016 JkB https://launchpad.net/~joergberroth
 
5
 *
 
6
 * GPS Navigation is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 3 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * GPS Navigation is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 */
 
16
 
 
17
import QtQuick 2.4
 
18
import QtQuick.Layouts 1.1
 
19
import Ubuntu.Components 1.3
 
20
import Ubuntu.Components.Popups 1.3
 
21
import Ubuntu.Components.ListItems 1.3 as ListItems
 
22
import QtQuick.XmlListModel 2.0
 
23
import "js/utils.js" as QmlJs
 
24
import QtQml 2.0
 
25
 
 
26
Page {
 
27
    id: poiListPage
 
28
 
 
29
    property var fromPage
 
30
    property var lat
 
31
    property var lng
 
32
    property string poiType: ""
 
33
    property string clause: ""
 
34
 
 
35
    property double geoDistFactor: 1.0
 
36
 
 
37
    title: poiType
 
38
    anchors.fill: parent
 
39
 
 
40
    Component.onCompleted: {
 
41
        resultsListView.visible = false
 
42
        if (poiListPage.lat !== "null" && poiListPage.lng !== "null") {
 
43
            poiXmlModel.search();
 
44
        } else {
 
45
            statusLabel.text = i18n.tr("Unknown current position")
 
46
            statusLabel.visible = true;
 
47
        }
 
48
    }
 
49
 
 
50
    head.contents: Item {
 
51
        id: headerContentsItem
 
52
        anchors.fill: parent
 
53
        
 
54
        Label { // Show number of poi in header
 
55
            id: numberLabel
 
56
            anchors {
 
57
                right: parent.right
 
58
                rightMargin: units.gu(-1)
 
59
                verticalCenter: parent.verticalCenter
 
60
            }
 
61
            z: 500
 
62
            width: units.gu(2)
 
63
            visible: sortedPoiModel.count !== 0
 
64
            horizontalAlignment: Text.AlignRight
 
65
            text: (sortedPoiModel.count !== 50 ? i18n.tr("%1 POIs").arg(sortedPoiModel.count) : i18n.tr("First %1 POIs").arg(sortedPoiModel.count)) + " "
 
66
            fontSize: "small"
 
67
            color: UbuntuColors.purple
 
68
        }
 
69
 
 
70
        Label {
 
71
            id: pageTitleLabel
 
72
            anchors {
 
73
                verticalCenter: parent.verticalCenter
 
74
            }
 
75
            fontSize: "large"
 
76
            text: poiType
 
77
        }
 
78
    }
 
79
 
 
80
    head.actions: Action {
 
81
        id: routeAction
 
82
        iconSource: "../nav/img/header/poimap.svg"
 
83
        text: i18n.tr("Show POIs on map")
 
84
        visible: sortedPoiModel.count !== 0
 
85
        onTriggered: {
 
86
            if (mainPageStack.center_onpos === 2)
 
87
                mainPageStack.center_onpos = 1;
 
88
            mainPageStack.executeJavaScript("ui.markers_POI_set(" + JSON.stringify(sortedPoiModel.allPOI()) + ");")
 
89
            mainPageStack.pop(poiListPage.fromPage)
 
90
            mainPageStack.pop(poiListPage)
 
91
        }
 
92
    }
 
93
 
 
94
    Label {
 
95
        id: statusLabel
 
96
        anchors {
 
97
            centerIn: parent
 
98
            horizontalCenter: parent.horizontalCenter
 
99
            verticalCenter: parent.verticalCenter
 
100
        }
 
101
        width: parent.width - units.gu(4)
 
102
        visible: poiXmlModel.status === XmlListModel.Loading
 
103
        wrapMode: Text.WordWrap
 
104
        horizontalAlignment: Text.AlignHCenter
 
105
        text: i18n.tr("Something was wrong. Please, try again…")
 
106
    }
 
107
 
 
108
    // Indicator to show load activity
 
109
    ActivityIndicator {
 
110
        id: searchActivity
 
111
        anchors {
 
112
            bottom: statusLabel.top
 
113
            bottomMargin: units.gu (1)
 
114
            horizontalCenter: parent.horizontalCenter
 
115
        }
 
116
        running: poiXmlModel.status === XmlListModel.Loading
 
117
    }
 
118
 
 
119
    Slider {
 
120
        id: distSlider
 
121
        width: parent.width - units.gu(4)
 
122
        anchors {
 
123
            top: statusLabel.bottom
 
124
            topMargin: units.gu (4)
 
125
            horizontalCenter: parent.horizontalCenter
 
126
        }
 
127
        visible: false
 
128
        z: 500
 
129
 
 
130
        function formatValue(v) {
 
131
            return v.toFixed(0).toString() + (navApp.settings.unit === 0 ? " km" : " mi" )
 
132
        }
 
133
        minimumValue: 5.0
 
134
        maximumValue: 100.0
 
135
        value: geoDistFactor <= 25 ? 25.0 : geoDistFactor
 
136
        live: true
 
137
    }
 
138
 
 
139
    Button {
 
140
        id: distButton
 
141
        visible: false
 
142
        z: 500
 
143
        anchors {
 
144
            top: distSlider.bottom
 
145
            topMargin: units.gu (1)
 
146
            horizontalCenter: parent.horizontalCenter
 
147
        }
 
148
        iconName: "reload"
 
149
        onClicked: {
 
150
            poiListPage.geoDistFactor = distSlider.value
 
151
            poiXmlModel.search()
 
152
            distButton.visible = false;
 
153
            distSlider.visible = false;
 
154
        }
 
155
    }
 
156
 
 
157
 
 
158
    //OSMTouch (lp:osmtouch) POIModel:
 
159
    XmlListModel {
 
160
        id: poiXmlModel
 
161
 
 
162
        onStatusChanged: {
 
163
 
 
164
            if (status === XmlListModel.Error) {
 
165
                console.log(errorString())
 
166
                statusLabel.text = i18n.tr("Time out! Please try again");
 
167
                statusLabel.visible = true;
 
168
                resultsListView.visible = false;
 
169
                source = "";
 
170
            }
 
171
            if (status === XmlListModel.Ready && count === 0) {
 
172
                //TRANSLATORS: The Argument is the POI type. E.G. a pub, station....
 
173
                statusLabel.text = i18n.tr("Sorry, no %1 found nearby. Try again with another radius").arg(poiType);
 
174
                statusLabel.visible = true;
 
175
                distButton.visible = true;
 
176
                distSlider.visible = true;
 
177
                resultsListView.visible = false;
 
178
            }
 
179
            if (status === XmlListModel.Ready && count >> 0) {
 
180
                statusLabel.visible = false;
 
181
                sortedPoiModel.sortXmlList();
 
182
            }
 
183
            if (status === XmlListModel.Loading) { statusLabel.text =  i18n.tr("Searching…") }
 
184
        }
 
185
 
 
186
        readonly property string baseUrl: "http://nominatim.openstreetmap.org/search?format=xml&bounded=1&limit=50&email=costales.marcos@gmail.com&extratags=1"
 
187
        readonly property double geoDist: navApp.settings.unit === 0 ? 0.01 : 0.01 / 0.621371192
 
188
        // geographic distance ~1.1km / ~1.1mi
 
189
        // rough estimation only. Could be redefined.
 
190
        function search() {
 
191
            // Boxed area in which to search for PoI
 
192
            var bbox = ( Number(poiListPage.lng) - geoDist*geoDistFactor).toString() + ","
 
193
                     + ( Number(poiListPage.lat) - geoDist*geoDistFactor).toString() + ","
 
194
                     + ( Number(poiListPage.lng) + geoDist*geoDistFactor).toString() + ","
 
195
                     + ( Number(poiListPage.lat) + geoDist*geoDistFactor).toString();
 
196
            source = (baseUrl + "&q=" + clause + "&viewbox=" + bbox);
 
197
        }
 
198
        function clear() {
 
199
            source: "";
 
200
        }
 
201
 
 
202
        source: ""
 
203
        query: "/searchresults/place"
 
204
 
 
205
        XmlRole { name: "osm_id"; query: "@place_id/string()"; }
 
206
        XmlRole { name: "name"; query: "@display_name/string()"; }
 
207
        XmlRole { name: "phone"; query: "extratags/tag[@key='phone']/@value/string()"; }
 
208
        XmlRole { name: "website"; query: "extratags/tag[@key='website']/@value/string()"; }
 
209
        // XmlRole { name: "cuisine"; query: "extratags/tag[@key='cuisine']/@value/string()"; }
 
210
        XmlRole { name: "wheelchair"; query: "extratags/tag[@key='wheelchair']/@value/string()"; }
 
211
        XmlRole { name: "openinghours"; query: "extratags/tag[@key='opening_hours']/@value/string()"; }
 
212
        XmlRole { name: "lat"; query: "@lat/string()"; }
 
213
        XmlRole { name: "lng"; query: "@lon/string()"; }
 
214
    }
 
215
 
 
216
    ListModel {
 
217
        id: sortedPoiModel
 
218
 
 
219
        function allPOI() {
 
220
            var allPOI = [];
 
221
            for (var i = 0; i < sortedPoiModel.count; i++) {
 
222
                allPOI.push({
 
223
                    title: sortedPoiModel.get(i).name,
 
224
                    lat: parseFloat(sortedPoiModel.get(i).lat),
 
225
                    lng: parseFloat(sortedPoiModel.get(i).lng),
 
226
                    website: sortedPoiModel.get(i).website,
 
227
                    phone: sortedPoiModel.get(i).phone
 
228
                });
 
229
            }
 
230
            return allPOI;
 
231
        }
 
232
 
 
233
        function sortXmlList (){
 
234
            var item
 
235
            for (var i = 0; i < poiXmlModel.count; i++) {
 
236
               item  = {"osmid":        poiXmlModel.get(i).osm_id,
 
237
                        "name":             poiXmlModel.get(i).name.split(',')[0],
 
238
                        "phone":        poiXmlModel.get(i).phone,
 
239
                        "website":        poiXmlModel.get(i).website,
 
240
                        // "cuisine":    poiXmlModel.get(i).cuisine,
 
241
                        "wheelchair":    poiXmlModel.get(i).wheelchair,
 
242
                        "openinghours":    poiXmlModel.get(i).openinghours,
 
243
                        "lat":            poiXmlModel.get(i).lat,
 
244
                        "lng":            poiXmlModel.get(i).lng,
 
245
                        "distance":        QmlJs.calcPoiDistance(
 
246
                            poiListPage.lat,
 
247
                            poiListPage.lng,
 
248
                            poiXmlModel.get(i).lat,
 
249
                            poiXmlModel.get(i).lng,
 
250
                            10
 
251
                        ),
 
252
                    }
 
253
                if (i === 0) {
 
254
                    sortedPoiModel.append(item)
 
255
                        } else { // sort model by distance
 
256
                    var j = 0;
 
257
                    while (j <= sortedPoiModel.count) {
 
258
                        if (j === sortedPoiModel.count) {
 
259
                            sortedPoiModel.append(item)
 
260
                            break;
 
261
                        } else if (item.distance < sortedPoiModel.get(j).distance){
 
262
                           sortedPoiModel.insert(j,item)
 
263
                           break;
 
264
                        } else {
 
265
                            j++;
 
266
                        }
 
267
                    }
 
268
                }
 
269
                poiXmlModel.clear();
 
270
                resultsListView.visible = true;
 
271
            }
 
272
        }
 
273
    }
 
274
 
 
275
    UbuntuListView {
 
276
        id: resultsListView
 
277
        model: sortedPoiModel
 
278
        anchors.fill: parent
 
279
        visible: false
 
280
 
 
281
        delegate: ListItem {
 
282
            trailingActions:  ListItemActions {
 
283
                actions: [
 
284
                    Action {
 
285
                        iconName: "send"
 
286
                        onTriggered: {
 
287
                            mainPageStack.pop(poiListPage.fromPage)
 
288
                            mainPageStack.pop(poiListPage)
 
289
                            mainPageStack.center_onpos = 2;
 
290
                            mainPageStack.routeState = 'yes'
 
291
                            mainPageStack.executeJavaScript("calc2coord("+ model.lat + "," + model.lng + ");");
 
292
                        }
 
293
                    },
 
294
                    Action {
 
295
                        iconName: "non-starred"
 
296
                        onTriggered: {
 
297
                            mainPageStack.pop(poiListPage.fromPage)
 
298
                            mainPageStack.pop(poiListPage)
 
299
                            mainPageStack.push(Qt.resolvedUrl("FavoritesPage.qml"), {state:"adding", lat: model.lat, lng: model.lng, favName: model.name})
 
300
                        }
 
301
                    },
 
302
                    Action {
 
303
                        iconName: "share"
 
304
                        onTriggered: {
 
305
                            PopupUtils.open(Qt.resolvedUrl("./Share.qml"), navApp, {"lat": model.lat, "lon": model.lng})
 
306
                        }
 
307
                    },
 
308
                    Action {
 
309
                        iconName: "external-link"
 
310
                        visible: (model.website !== "" && model.website.substring(0, 4) === "http")
 
311
                        onTriggered: {
 
312
                            Qt.openUrlExternally(website)
 
313
                        }
 
314
                    },
 
315
                    Action {
 
316
                        iconName: "call-start"
 
317
                        visible: model.phone !== ""
 
318
                        onTriggered: {
 
319
                            Qt.openUrlExternally("tel:///"+ phone)
 
320
                        }
 
321
                    }
 
322
                ]
 
323
            }
 
324
 
 
325
            onClicked: {
 
326
                mainPageStack.pop(poiListPage.fromPage)
 
327
                mainPageStack.pop(poiListPage);
 
328
                mainPageStack.executeJavaScript("ui.markers_POI_set([{title: \"" + model.name + "\", lat: " + model.lat + ", lng: " + model.lng + ", website: \"" + model.website + "\", phone: \"" + model.phone + "\"}]);");
 
329
            }
 
330
 
 
331
            contentItem.anchors {
 
332
                leftMargin: units.gu(1)
 
333
                rightMargin: units.gu(1)
 
334
                topMargin: units.gu(0.5)
 
335
                bottomMargin: units.gu(0.5)
 
336
            }
 
337
 
 
338
            Label {
 
339
                id: nameLabel
 
340
                anchors {
 
341
                    top:parent.top
 
342
                    left: parent.left
 
343
                    right: acessibilityIcon.left
 
344
                }
 
345
                text: model.name !== "" ? model.name : poiListPage.poiType
 
346
                font.weight: Font.DemiBold
 
347
                fontSize: "medium"
 
348
                elide: Text.ElideRight
 
349
            }
 
350
 
 
351
            Label {
 
352
                anchors.bottom: parent.bottom
 
353
                width: parent.width *4/5
 
354
 
 
355
                text: model.openinghours !== "" ?
 
356
                    //TRANSLATORS: abbreviation for Monday
 
357
                    model.openinghours.replace("Mo", Qt.locale().dayName(1, Locale.ShortFormat)).
 
358
                    //TRANSLATORS: abbreviation for Tuesday
 
359
                    replace("Tu", Qt.locale().dayName(2, Locale.ShortFormat)).
 
360
                    //TRANSLATORS: abbreviation for Wednesday
 
361
                    replace("We", Qt.locale().dayName(3, Locale.ShortFormat)).
 
362
                    //TRANSLATORS: abbreviation for Thursday
 
363
                    replace("Th", Qt.locale().dayName(4, Locale.ShortFormat)).
 
364
                    //TRANSLATORS: abbreviation for Friday
 
365
                    replace("Fr", Qt.locale().dayName(5, Locale.ShortFormat)).
 
366
                    //TRANSLATORS: abbreviation for Saturday
 
367
                    replace("Sa", Qt.locale().dayName(6, Locale.ShortFormat)).
 
368
                    //TRANSLATORS: abbreviation for Sunday
 
369
                    replace("Su", Qt.locale().dayName(0, Locale.ShortFormat)).
 
370
                    //TRANSLATORS: abbreviation for Public Holiday
 
371
                    replace("PH", i18n.tr("PH") ).
 
372
                    //TRANSLATORS: "closed"
 
373
                    replace("off", i18n.tr("off") ) : ""
 
374
                fontSize: "small"
 
375
                elide: Text.ElideRight
 
376
                wrapMode: Text.WordWrap
 
377
                maximumLineCount: 2
 
378
            }
 
379
 
 
380
            Label{
 
381
                anchors.bottom: parent.bottom
 
382
                width: parent.width /5
 
383
                anchors.right: parent.right
 
384
                horizontalAlignment: Text.AlignRight
 
385
 
 
386
                text: QmlJs.formatDistance(model.distance, navApp.settings.unit)
 
387
                fontSize: "small"
 
388
            }
 
389
 
 
390
            Icon {
 
391
                id: acessibilityIcon
 
392
                name: "preferences-desktop-accessibility-symbolic"
 
393
 
 
394
                visible: model.wheelchair === "yes" || model.wheelchair === "limited" // is limited enought as criteria?
 
395
                anchors.top: parent.top
 
396
                anchors.right: parent.right
 
397
                width: parent.height /2
 
398
            }
 
399
        }
 
400
    }
 
401
}