Resolve different addresses.

This commit is contained in:
John Preston 2024-07-11 16:31:33 +02:00
parent 310837c9e1
commit de52ac6b28
10 changed files with 159 additions and 23 deletions

View file

@ -50,7 +50,7 @@ html.custom_scroll ::-webkit-scrollbar-thumb:hover {
}
#marker {
pointer-events: none;
display: flex;
display: none;
z-index: 2;
position: absolute;
width: 100%;
@ -58,3 +58,13 @@ html.custom_scroll ::-webkit-scrollbar-thumb:hover {
justify-content: center;
align-items: center;
}
#marker_drop {
margin-bottom: 0px;
transition: margin 160ms ease-in-out;
}
#marker_drop.moving {
margin-bottom: 24px;
}
#marker_shadow {
position: absolute;
}

View file

@ -70,16 +70,41 @@ var LocationPicker = {
center = [0, 0];
}
LocationPicker.map = new mapboxgl.Map(options);
const marker = new mapboxgl.Marker()
.setLngLat(center)
.addTo(LocationPicker.map);
const drop = document.getElementById('marker_drop');
const element = marker.getElement();
drop.innerHTML = element.innerHTML;
const offset = marker.getOffset();
drop.style.transform = 'translate(' + offset.x + 'px, ' + offset.y + 'px)';
marker.remove();
LocationPicker.createMarker(center);
LocationPicker.trackMovement();
},
marker: function() {
return document.getElementById('marker_drop');
},
createMarker: function(center) {
document.getElementById('marker').style.display = 'flex';
},
clearMovingTimer: function() {
if (LocationPicker.clearMovingTimeoutId) {
clearTimeout(LocationPicker.clearMovingTimeoutId);
LocationPicker.clearMovingTimeoutId = 0;
}
},
startMovingTimer: function(done) {
LocationPicker.clearMovingTimer();
LocationPicker.clearMovingTimeoutId = setTimeout(done, 500);
},
trackMovement: function() {
LocationPicker.map.on('movestart', function() {
LocationPicker.marker().classList.add('moving');
LocationPicker.clearMovingTimer();
LocationPicker.notify({ event: 'movestart' });
});
LocationPicker.map.on('moveend', function() {
LocationPicker.startMovingTimer(function() {
LocationPicker.marker().classList.remove('moving');
LocationPicker.notify({
event: 'moveend',
latitude: LocationPicker.map.getCenter().lat,
longitude: LocationPicker.map.getCenter().lng
});
});
});
},
narrowTo: function (point) {
LocationPicker.map.flyTo({

View file

@ -27,14 +27,51 @@ namespace {
constexpr auto kDestroyManagerTimeout = 20 * crl::time(1000);
[[nodiscard]] QString ChooseLanguage(const QString &language) {
// https://docs.mapbox.com/api/search/geocoding#language-coverage
auto result = language.toLower().replace('-', '_');
static const auto kGood = std::array{
// Global coverage.
u"de"_q, u"en"_q, u"es"_q, u"fr"_q, u"it"_q, u"nl"_q, u"pl"_q,
// Local coverage.
u"az"_q, u"bn"_q, u"ca"_q, u"cs"_q, u"da"_q, u"el"_q, u"fa"_q,
u"fi"_q, u"ga"_q, u"hu"_q, u"id"_q, u"is"_q, u"ja"_q, u"ka"_q,
u"km"_q, u"ko"_q, u"lt"_q, u"lv"_q, u"mn"_q, u"pt"_q, u"ro"_q,
u"sk"_q, u"sq"_q, u"sv"_q, u"th"_q, u"tl"_q, u"uk"_q, u"vi"_q,
u"zh"_q, u"zh_Hans"_q, u"zh_TW"_q,
// Limited coverage.
u"ar"_q, u"bs"_q, u"gu"_q, u"he"_q, u"hi"_q, u"kk"_q, u"lo"_q,
u"my"_q, u"nb"_q, u"ru"_q, u"sr"_q, u"te"_q, u"tk"_q, u"tr"_q,
u"zh_Hant"_q,
};
for (const auto &known : kGood) {
if (known.toLower() == result) {
return known;
}
}
if (const auto delimeter = result.indexOf('_'); delimeter > 0) {
result = result.mid(0, delimeter);
for (const auto &known : kGood) {
if (known == result) {
return known;
}
}
}
return u"en"_q;
}
void ResolveLocationAddressGeneric(
const GeoLocation &location,
const QString &language,
const QString &token,
Fn<void(GeoAddress)> callback) {
const auto partialUrl = u"https://api.mapbox.com/search/geocode/v6"
"/reverse?longitude=%1&latitude=%2&access_token=%3"_q
"/reverse?longitude=%1&latitude=%2&language=%3&access_token=%4"_q
.arg(location.point.y())
.arg(location.point.x());
.arg(location.point.x())
.arg(ChooseLanguage(language));
static auto Cache = base::flat_map<QString, GeoAddress>();
const auto i = Cache.find(partialUrl);
if (i != end(Cache)) {
@ -161,16 +198,21 @@ void ResolveCurrentGeoLocation(Fn<void(GeoLocation)> callback) {
void ResolveLocationAddress(
const GeoLocation &location,
const QString &language,
const QString &token,
Fn<void(GeoAddress)> callback) {
auto done = [=, done = std::move(callback)](GeoAddress result) mutable {
if (!result && !token.isEmpty()) {
ResolveLocationAddressGeneric(location, token, std::move(done));
ResolveLocationAddressGeneric(
location,
language,
token,
std::move(done));
} else {
done(result);
}
};
Platform::ResolveLocationAddress(location, std::move(done));
Platform::ResolveLocationAddress(location, language, std::move(done));
}
} // namespace Core

View file

@ -55,6 +55,7 @@ void ResolveCurrentGeoLocation(Fn<void(GeoLocation)> callback);
void ResolveLocationAddress(
const GeoLocation &location,
const QString &language,
const QString &token,
Fn<void(GeoAddress)> callback);

View file

@ -16,6 +16,7 @@ void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
}
void ResolveLocationAddress(
const Core::GeoLocation &location,
const QString &language,
Fn<void(Core::GeoAddress)> callback) {
callback({});
}

View file

@ -118,6 +118,7 @@ void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
void ResolveLocationAddress(
const Core::GeoLocation &location,
const QString &language,
Fn<void(Core::GeoAddress)> callback) {
callback({});
}

View file

@ -17,6 +17,7 @@ namespace Platform {
void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback);
void ResolveLocationAddress(
const Core::GeoLocation &location,
const QString &language,
Fn<void(Core::GeoAddress)> callback);
} // namespace Platform

View file

@ -61,6 +61,7 @@ void ResolveCurrentExactLocation(Fn<void(Core::GeoLocation)> callback) {
void ResolveLocationAddress(
const Core::GeoLocation &location,
const QString &language,
Fn<void(Core::GeoAddress)> callback) {
callback({});
}

View file

@ -17,6 +17,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "data/data_location.h"
#include "data/data_session.h"
#include "data/data_user.h"
#include "lang/lang_instance.h"
#include "lang/lang_keys.h"
#include "main/session/session_show.h"
#include "main/main_session.h"
@ -46,6 +47,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Ui {
namespace {
constexpr auto kResolveAddressDelay = 3 * crl::time(1000);
#ifdef Q_OS_MAC
const auto kProtocolOverride = "mapboxapihelper";
#else // Q_OS_MAC
@ -355,7 +358,30 @@ void LinksController::rowPaintIcon(
<link href='https://api.mapbox.com/mapbox-gl-js/v3.4.0/mapbox-gl.css' rel='stylesheet' />
</head>
<body>
<div id="marker"><div id="marker_drop"></div></div>
<div id="marker">
<div id="marker_shadow" style="transform: translate(0px, -14px);">
<svg display="block" height="41px" width="27px" viewBox="0 0 27 41">
<defs>
<radialGradient id="shadowGradient">
<stop offset="10%" stop-opacity="0.4"></stop>
<stop offset="100%" stop-opacity="0.05"></stop>
</radialGradient>
</defs>
<ellipse
cx="13.5"
cy="34.8"
rx="10.5"
ry="5.25"
fill=")" + "url(#shadowGradient)" + R"("></ellipse>
</svg>
</div>
<div id="marker_drop" style="transform: translate(0px, -14px);">
<svg display="block" height="41px" width="27px" viewBox="0 0 27 41">
<path fill="#3FB1CE" d="M27,13.5C27,19.07 20.25,27 14.75,34.5C14.02,35.5 12.98,35.5 12.25,34.5C6.75,27 0,19.22 0,13.5C0,6.04 6.04,0 13.5,0C20.96,0 27,6.04 27,13.5Z"></path><path opacity="0.25" d="M13.5,0C6.04,0 0,6.04 0,13.5C0,19.22 6.75,27 12.25,34.5C13,35.52 14.02,35.5 14.75,34.5C20.25,27 27,19.07 27,13.5C27,6.04 20.96,0 13.5,0ZM13.5,1C20.42,1 26,6.58 26,13.5C26,15.9 24.5,19.18 22.22,22.74C19.95,26.3 16.71,30.14 13.94,33.91C13.74,34.18 13.61,34.32 13.5,34.44C13.39,34.32 13.26,34.18 13.06,33.91C10.28,30.13 7.41,26.31 5.02,22.77C2.62,19.23 1,15.95 1,13.5C1,6.58 6.58,1 13.5,1Z"></path>
<circle fill="white" cx="13.5" cy="13.5" r="5.5"></circle>
</svg>
</div>
</div>
<div id="map"></div>
<script>LocationPicker.notify({ event: 'ready' });</script>
</body>
@ -408,26 +434,26 @@ void LinksController::rowPaintIcon(
raw,
rpl::duplicate(statusText),
st::pickLocationButtonStatus);
status->showOn(std::move(
status->showOn(rpl::duplicate(
statusText
) | rpl::map([](const QString &text) {
return !text.isEmpty();
}) | rpl::distinct_until_changed());
rpl::combine(
result->widthValue(),
status->shownValue()
) | rpl::start_with_next([=](int width, bool statusShown) {
std::move(statusText)
) | rpl::start_with_next([=](int width, const QString &statusText) {
const auto available = width
- st->namePosition.x()
- st->button.padding.right();
const auto namePosition = st->namePosition;
const auto statusPosition = st->statusPosition;
name->resizeToWidth(available);
const auto nameTop = statusShown
? namePosition.y()
: (st->height - name->height()) / 2;
const auto nameTop = statusText.isEmpty()
? ((st->height - name->height()) / 2)
: namePosition.y();
name->moveToLeft(namePosition.x(), nameTop, width);
status->resizeToWidth(available);
status->resizeToNaturalWidth(available);
status->moveToLeft(statusPosition.x(), statusPosition.y(), width);
}, name->lifetime());
@ -501,6 +527,7 @@ LocationPicker::LocationPicker(Descriptor &&descriptor)
_webview->eval("LocationPicker.updateStyles('" + str + "');");
}
})
, _geocoderResolveTimer([=] { resolveAddressByTimer(); })
, _venueState(PickerVenueLoading())
, _session(descriptor.session)
, _api(&_session->mtp()) {
@ -660,6 +687,17 @@ void LocationPicker::setupWebview(const Descriptor &descriptor) {
const auto lon = object.value("longitude").toDouble();
_callback({ lat, lon });
close();
} else if (event == u"movestart"_q) {
_geocoderAddress = QString();
_geocoderResolveTimer.cancel();
} else if (event == u"moveend"_q) {
const auto lat = object.value("latitude").toDouble();
const auto lon = object.value("longitude").toDouble();
_geocoderResolvePostponed = Core::GeoLocation{
.point = { lat, lon },
.accuracy = Core::GeoLocationAccuracy::Exact,
};
_geocoderResolveTimer.callOnce(kResolveAddressDelay);
}
});
});
@ -714,6 +752,12 @@ void LocationPicker::setupWebview(const Descriptor &descriptor) {
raw->navigateToData("location/picker.html");
}
void LocationPicker::resolveAddressByTimer() {
if (const auto location = base::take(_geocoderResolvePostponed)) {
resolveAddress(location);
}
}
void LocationPicker::resolveAddress(Core::GeoLocation location) {
if (_geocoderResolvingFor == location) {
return;
@ -730,8 +774,14 @@ void LocationPicker::resolveAddress(Core::GeoLocation location) {
.arg(location.point.y(), 0, 'f');
}
};
const auto baseLangId = Lang::GetInstance().baseId();
const auto langId = baseLangId.isEmpty()
? Lang::GetInstance().id()
: baseLangId;
const auto nonEmptyId = langId.isEmpty() ? u"en"_q : langId;
Core::ResolveLocationAddress(
location,
langId,
GeocodingProviderToken,
crl::guard(this, done));
}

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#pragma once
#include "base/invoke_queued.h"
#include "base/timer.h"
#include "base/weak_ptr.h"
#include "core/current_geo_location.h"
#include "mtproto/sender.h"
@ -106,6 +107,7 @@ private:
void setupWebview(const Descriptor &descriptor);
void processKey(const QString &key, const QString &modifier);
void resolveCurrentLocation();
void resolveAddressByTimer();
void resolveAddress(Core::GeoLocation location);
void mapReady();
@ -124,6 +126,8 @@ private:
SingleQueuedInvokation _updateStyles;
bool _subscribedToColors = false;
base::Timer _geocoderResolveTimer;
Core::GeoLocation _geocoderResolvePostponed;
Core::GeoLocation _geocoderResolvingFor;
rpl::variable<QString> _geocoderAddress;