Lomiri
Loading...
Searching...
No Matches
50-timezone.qml
1/*
2 * Copyright (C) 2015-2016 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.12
18import QtQuick.Layouts 1.1
19import Lomiri.Components 1.3
20import Wizard 0.1
21import Lomiri.SystemSettings.TimeDate 1.1
22import Utils 0.1 as Utils
23import ".." as LocalComponents
24import "../../Components"
25
26LocalComponents.Page {
27 id: tzPage
28 objectName: "tzPage"
29
30 title: i18n.tr("Time Zone")
31 focusItem: searchField
32 forwardButtonSourceComponent: forwardButton
33
34 property string selectedTimeZone: ""
35 property string selectedTimeZoneName: ""
36 readonly property bool showingMap: wideMode && width >= units.gu(110)
37
38 // for testing
39 readonly property alias tdModule: timeDatePanel
40 onlyOnInstall: true
41
42 function highlightTimezone(offset) {
43 highlightImage.source = "data/timezonemap/timezone_" + offset + ".png";
44 }
45
46 // geo coords conversion functions (adapted from libtimezonemap)
47 function radians(degrees) {
48 return degrees * Math.PI / 180;
49 }
50
51 function longitudeToX(longitude, map_width) {
52 const xdeg_offset = -6;
53 const x = (map_width * (180.0 + longitude) / 360.0) + (map_width * xdeg_offset / 180.0);
54 return x;
55 }
56
57 function latitudeToY(latitude, map_height) {
58 const bottom_lat = -59;
59 const top_lat = 81;
60 const top_per = top_lat / 180.0;
61
62 var y = 1.25 * Math.log(Math.tan(0.25*Math.PI + 0.4 * radians(latitude)));
63 const full_range = 4.6068250867599998;
64 const top_offset = full_range * top_per;
65 const map_range = Math.abs(1.25 * Math.log(Math.tan(0.25*Math.PI + 0.4 * radians(bottom_lat))) - top_offset);
66 y = Math.abs(y - top_offset);
67 y = y / map_range;
68 y = y * map_height;
69 return y;
70 }
71
72 function resetViews() {
73 selectedTimeZone = ""
74 selectedTimeZoneName = ""
75 tzList.currentIndex = -1
76 highlightImage.source = ""
77 pinImage.x = 0;
78 pinImage.y = 0;
79 }
80
81 LomiriTimeDatePanel {
82 id: timeDatePanel
83 }
84
85 onContentAnimationRunningChanged: {
86 if (!contentAnimationRunning) {
87 if (tzList.count == 1) { // preselect the first (and only) TZ
88 var tz = tzList.itemAt(0,0);
89 if (!!tz) {
90 tz.clicked();
91 }
92 }
93
94 resetViews();
95 }
96 }
97
98 Component {
99 id: tzComponent
100 ListItem {
101 id: tz
102 objectName: "tz" + index
103 highlightColor: backgroundColor
104 divider.colorFrom: dividerColor
105 divider.colorTo: backgroundColor
106 readonly property bool currentTz: ListView.view.currentIndex === index
107
108 Column {
109 anchors.verticalCenter: parent.verticalCenter
110 anchors.left: parent.left
111 anchors.leftMargin: !wideMode ? staticMargin : 0
112 anchors.right: image.left
113 anchors.rightMargin: units.gu(2)
114
115 Label {
116 id: cityLabel
117 text: displayName
118 font.weight: tz.currentTz ? Font.Normal : Font.Light
119 fontSize: "medium"
120 color: textColor
121 elide: Text.ElideMiddle
122 maximumLineCount: 1
123 width: parent.width
124 }
125 Label {
126 id: timeLabel
127 text: Utils.TimezoneFormatter.currentTimeInTimezoneWithAbbrev(timeZone)
128 font.weight: tz.currentTz ? Font.Normal : Font.Light
129 fontSize: "small"
130 color: textColor
131 }
132 }
133 Image {
134 id: image
135 anchors {
136 right: parent.right
137 verticalCenter: parent.verticalCenter
138 rightMargin: !wideMode ? staticMargin : 0
139 }
140 fillMode: Image.PreserveAspectFit
141 height: units.gu(1.5)
142
143 source: "data/Tick@30.png"
144 visible: tz.currentTz
145 }
146
147 onClicked: {
148 highlightTimezone(offset);
149 ListView.view.currentIndex = index;
150 selectedTimeZone = timeZone;
151 selectedTimeZoneName = city;
152 //print("Clicked at city with coords:", longitude, latitude);
153 //print("Clicked on TZ:", timeZone);
154 //print("Highlight at (x,y):", longitudeToX(longitude, map.width), latitudeToY(latitude, map.height));
155 pinImage.x = Qt.binding(function() { return longitudeToX(longitude, map.width) - pinImage.width; });
156 pinImage.y = Qt.binding(function() { return latitudeToY(latitude, map.height) - pinImage.height; });
157 }
158 }
159 }
160
161
162 ColumnLayout {
163 id: leftColumn
164 anchors {
165 left: content.left
166 top: content.top
167 bottom: content.bottom
168 right: !showingMap ? content.right : undefined
169 leftMargin: showingMap ? staticMargin : (wideMode ? tzPage.leftMargin : 0)
170 rightMargin: showingMap ? staticMargin : (wideMode ? tzPage.rightMargin : 0)
171 topMargin: customMargin
172 }
173
174 width: Math.min(parent.width, units.gu(34))
175
176 LocalComponents.WizardTextField {
177 Layout.fillWidth: true
178 id: searchField
179 objectName: "tzFilter"
180 anchors.leftMargin: !showingMap && !wideMode ? staticMargin : undefined
181 anchors.rightMargin: !showingMap && !wideMode ? staticMargin : undefined
182 placeholderText: i18n.tr("Enter your city")
183 inputMethodHints: Qt.ImhNoPredictiveText
184 onTextChanged: resetViews();
185 }
186
187 ListView {
188 Layout.fillWidth: true
189 Layout.fillHeight: true
190 id: tzList
191 objectName: "tzList"
192 clip: true
193 currentIndex: -1
194 model: TimeZoneModel {
195 id: timeZoneModel
196 filter: searchField.text
197 country: i18n.language.split('_')[1].split('.')[0]
198 }
199 delegate: tzComponent
200
201 ActivityIndicator {
202 anchors.centerIn: parent
203 running: tzList.count == 0 &&
204 searchField.length > 0 &&
205 timeZoneModel.listUpdating
206 visible: running
207 }
208 }
209 }
210
211 Item {
212 id: mapContainer
213 visible: showingMap && !contentAnimationRunning
214 enabled: visible
215
216 anchors {
217 left: leftColumn.right
218 leftMargin: units.gu(4)
219 right: content.right
220 rightMargin: staticMargin
221 top: content.top
222 topMargin: customMargin
223 bottom: parent.bottom
224 bottomMargin: buttonBarHeight
225 }
226
227 Item {
228 id: map
229 width: Math.min(parent.width, height * 1.95) // keep our aspect ratio
230 height: parent.height
231 anchors {
232 centerIn: parent
233 }
234
235 Image {
236 id: backgroundImage
237 source: "data/timezonemap/map.png"
238 sourceSize: Qt.size(map.width, map.height)
239 fillMode: Image.PreserveAspectFit
240 smooth: false
241 visible: mapContainer.visible
242 asynchronous: true
243 anchors.fill: parent
244 }
245
246 Image {
247 id: highlightImage
248 sourceSize: Qt.size(map.width, map.height)
249 fillMode: Image.PreserveAspectFit
250 smooth: false
251 visible: selectedTimeZone != ""
252 asynchronous: true
253 anchors.fill: backgroundImage
254 }
255
256 Image {
257 id: pinImage
258 source: "data/timezonemap/pin.png"
259 visible: x != 0 && y != 0
260 width: units.dp(12)
261 height: units.dp(20)
262 z: map.z + 1
263 }
264 }
265 }
266
267 Component {
268 id: forwardButton
269 LocalComponents.StackButton {
270 text: i18n.tr("Next")
271 enabled: selectedTimeZone != ""
272 onClicked: {
273 timeDatePanel.setTimeZone(selectedTimeZone, selectedTimeZoneName);
274 pageStack.next();
275 }
276 }
277 }
278}