diff --git a/Telegram/Resources/picker_html/picker.css b/Telegram/Resources/picker_html/picker.css index 0c791008d..4d8f378ae 100644 --- a/Telegram/Resources/picker_html/picker.css +++ b/Telegram/Resources/picker_html/picker.css @@ -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; +} diff --git a/Telegram/Resources/picker_html/picker.js b/Telegram/Resources/picker_html/picker.js index cb936cf0b..27ffd3b6c 100644 --- a/Telegram/Resources/picker_html/picker.js +++ b/Telegram/Resources/picker_html/picker.js @@ -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({ diff --git a/Telegram/SourceFiles/core/current_geo_location.cpp b/Telegram/SourceFiles/core/current_geo_location.cpp index b649ea2ea..818ea361a 100644 --- a/Telegram/SourceFiles/core/current_geo_location.cpp +++ b/Telegram/SourceFiles/core/current_geo_location.cpp @@ -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 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(); const auto i = Cache.find(partialUrl); if (i != end(Cache)) { @@ -161,16 +198,21 @@ void ResolveCurrentGeoLocation(Fn callback) { void ResolveLocationAddress( const GeoLocation &location, + const QString &language, const QString &token, Fn 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 diff --git a/Telegram/SourceFiles/core/current_geo_location.h b/Telegram/SourceFiles/core/current_geo_location.h index e3b92222e..dab4ffd00 100644 --- a/Telegram/SourceFiles/core/current_geo_location.h +++ b/Telegram/SourceFiles/core/current_geo_location.h @@ -55,6 +55,7 @@ void ResolveCurrentGeoLocation(Fn callback); void ResolveLocationAddress( const GeoLocation &location, + const QString &language, const QString &token, Fn callback); diff --git a/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp b/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp index 6f42c0afd..f87c343d3 100644 --- a/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/current_geo_location_linux.cpp @@ -16,6 +16,7 @@ void ResolveCurrentExactLocation(Fn callback) { } void ResolveLocationAddress( const Core::GeoLocation &location, + const QString &language, Fn callback) { callback({}); } diff --git a/Telegram/SourceFiles/platform/mac/current_geo_location_mac.mm b/Telegram/SourceFiles/platform/mac/current_geo_location_mac.mm index 452bc6e3a..1a5382f19 100644 --- a/Telegram/SourceFiles/platform/mac/current_geo_location_mac.mm +++ b/Telegram/SourceFiles/platform/mac/current_geo_location_mac.mm @@ -118,6 +118,7 @@ void ResolveCurrentExactLocation(Fn callback) { void ResolveLocationAddress( const Core::GeoLocation &location, + const QString &language, Fn callback) { callback({}); } diff --git a/Telegram/SourceFiles/platform/platform_current_geo_location.h b/Telegram/SourceFiles/platform/platform_current_geo_location.h index 9feb4b376..269ee81f3 100644 --- a/Telegram/SourceFiles/platform/platform_current_geo_location.h +++ b/Telegram/SourceFiles/platform/platform_current_geo_location.h @@ -17,6 +17,7 @@ namespace Platform { void ResolveCurrentExactLocation(Fn callback); void ResolveLocationAddress( const Core::GeoLocation &location, + const QString &language, Fn callback); } // namespace Platform diff --git a/Telegram/SourceFiles/platform/win/current_geo_location_win.cpp b/Telegram/SourceFiles/platform/win/current_geo_location_win.cpp index a83dedb88..9c7967588 100644 --- a/Telegram/SourceFiles/platform/win/current_geo_location_win.cpp +++ b/Telegram/SourceFiles/platform/win/current_geo_location_win.cpp @@ -61,6 +61,7 @@ void ResolveCurrentExactLocation(Fn callback) { void ResolveLocationAddress( const Core::GeoLocation &location, + const QString &language, Fn callback) { callback({}); } diff --git a/Telegram/SourceFiles/ui/controls/location_picker.cpp b/Telegram/SourceFiles/ui/controls/location_picker.cpp index a4658e7be..2eef9d698 100644 --- a/Telegram/SourceFiles/ui/controls/location_picker.cpp +++ b/Telegram/SourceFiles/ui/controls/location_picker.cpp @@ -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( -
+
+
+ + + + + + + + + +
+
+ + + + +
+
@@ -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)); } diff --git a/Telegram/SourceFiles/ui/controls/location_picker.h b/Telegram/SourceFiles/ui/controls/location_picker.h index 9a4ca56d5..e9c0d9801 100644 --- a/Telegram/SourceFiles/ui/controls/location_picker.h +++ b/Telegram/SourceFiles/ui/controls/location_picker.h @@ -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 _geocoderAddress;