From 8aac07b3c0f21d317af684f6852924bdf7fe8811 Mon Sep 17 00:00:00 2001 From: John Preston Date: Fri, 12 Jul 2024 16:34:14 +0200 Subject: [PATCH] Show empty venue search states. --- Telegram/Resources/langs/lang.strings | 1 + .../chat_helpers/chat_helpers.style | 5 + .../ui/controls/location_picker.cpp | 104 ++++++++++++++++-- Telegram/lib_ui | 2 +- 4 files changed, 100 insertions(+), 12 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index b15436b2b..08368d748 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -3198,6 +3198,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL "lng_maps_or_choose" = "Or choose a venue"; "lng_maps_places_in_area" = "Places in this area"; "lng_maps_no_places" = "No places found"; +"lng_maps_choose_to_search" = "Choose location to see places nearby."; "lng_live_location" = "Live Location"; "lng_live_location_now" = "updated just now"; "lng_live_location_minutes#one" = "updated {count} minute ago"; diff --git a/Telegram/SourceFiles/chat_helpers/chat_helpers.style b/Telegram/SourceFiles/chat_helpers/chat_helpers.style index 452a9f89b..d31d2919a 100644 --- a/Telegram/SourceFiles/chat_helpers/chat_helpers.style +++ b/Telegram/SourceFiles/chat_helpers/chat_helpers.style @@ -1476,3 +1476,8 @@ pickLocationVenueList: PeerList(defaultPeerList) { padding: margins(0px, 0px, 0px, 0px); } pickLocationIconSkip: 6px; +pickLocationLoading: InfiniteRadialAnimation(defaultInfiniteRadialAnimation) { + size: size(56px, 56px); + color: windowSubTextFg; + thickness: 4px; +} diff --git a/Telegram/SourceFiles/ui/controls/location_picker.cpp b/Telegram/SourceFiles/ui/controls/location_picker.cpp index d363bbe6d..ed9d84f7a 100644 --- a/Telegram/SourceFiles/ui/controls/location_picker.cpp +++ b/Telegram/SourceFiles/ui/controls/location_picker.cpp @@ -17,11 +17,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_location.h" #include "data/data_session.h" #include "data/data_user.h" +#include "dialogs/ui/chat_search_empty.h" // Dialogs::SearchEmpty. #include "lang/lang_instance.h" #include "lang/lang_keys.h" #include "main/session/session_show.h" #include "main/main_session.h" #include "mtproto/mtproto_config.h" +#include "ui/effects/radial_animation.h" +#include "ui/text/text_utilities.h" #include "ui/widgets/scroll_area.h" #include "ui/widgets/separate_panel.h" #include "ui/widgets/buttons.h" @@ -468,17 +471,95 @@ void VenuesController::rowPaintIcon( return result; } +void SetupLoadingView(not_null container) { + class Loading final : public RpWidget { + public: + explicit Loading(QWidget *parent) + : RpWidget(parent) + , animation( + [=] { if (!anim::Disabled()) update(); }, + st::pickLocationLoading) { + animation.start(st::pickLocationLoading.sineDuration); + } + + private: + void paintEvent(QPaintEvent *e) override { + auto p = QPainter(this); + const auto size = st::pickLocationLoading.size; + const auto inner = QRect(QPoint(), size); + const auto positioned = style::centerrect(rect(), inner); + animation.draw(p, positioned.topLeft(), size, width()); + } + + InfiniteRadialAnimation animation; + + }; + + const auto view = CreateChild(container); + view->resize(container->width(), st::recentPeersEmptyHeightMin); + view->show(); + + ResizeFitChild(container, view); +} + +void SetupEmptyView( + not_null container, + std::optional query) { + using Icon = Dialogs::SearchEmptyIcon; + const auto view = CreateChild( + container, + (query ? Icon::NoResults : Icon::Search), + (query + ? tr::lng_maps_no_places + : tr::lng_maps_choose_to_search)(Ui::Text::WithEntities)); + view->setMinimalHeight(st::recentPeersEmptyHeightMin); + view->show(); + + ResizeFitChild(container, view); + + InvokeQueued(view, [=] { view->animate(); }); +} + void SetupVenues( not_null container, std::shared_ptr show, - rpl::producer> value, + rpl::producer value, Fn callback) { + const auto otherWrap = container->add(object_ptr>( + container, + object_ptr(container))); + const auto other = otherWrap->entity(); + rpl::duplicate( + value + ) | rpl::start_with_next([=](const PickerVenueState &state) { + while (!other->children().isEmpty()) { + delete other->children()[0]; + } + if (v::is(state)) { + otherWrap->hide(anim::type::instant); + return; + } else if (v::is(state)) { + SetupLoadingView(other); + } else { + const auto n = std::get_if(&state); + SetupEmptyView(other, n ? n->query : std::optional()); + } + otherWrap->show(anim::type::instant); + }, otherWrap->lifetime()); + auto &lifetime = container->lifetime(); + auto venuesList = rpl::duplicate( + value + ) | rpl::map([=](PickerVenueState &&state) { + return v::is(state) + ? std::move(v::get(state).list) + : std::vector(); + }); const auto delegate = lifetime.make_state( show); const auto controller = lifetime.make_state( &show->session(), - std::move(value), + std::move(venuesList), std::move(callback)); controller->setStyleOverrides(&st::pickLocationVenueList); const auto content = container->add(object_ptr( @@ -601,8 +682,7 @@ void LocationPicker::setupWindow(const Descriptor &descriptor) { _mapControlsWrap = controls->add( object_ptr>( controls, - object_ptr(controls)) - )->setDuration(0); + object_ptr(controls))); _mapControlsWrap->show(anim::type::instant); const auto mapControls = _mapControlsWrap->entity(); @@ -619,12 +699,8 @@ void LocationPicker::setupWindow(const Descriptor &descriptor) { AddSkip(mapControls); AddSubsectionTitle(mapControls, tr::lng_maps_or_choose()); - SetupVenues(controls, uiShow(), _venueState.value( - ) | rpl::filter([=](const PickerVenueState &state) { - return v::is(state); - }) | rpl::map([=](PickerVenueState &&state) { - return std::move(v::get(state).list); - }), [=](VenueData info) { + auto state = _venueState.value(); + SetupVenues(controls, uiShow(), std::move(state), [=](VenueData info) { _callback(std::move(info)); close(); }); @@ -706,6 +782,9 @@ void LocationPicker::setupWebview(const Descriptor &descriptor) { if (event == u"ready"_q) { mapReady(); resolveCurrentLocation(); + if (_webview) { + _webview->focus(); + } } else if (event == u"keydown"_q) { const auto key = object.value("key").toString(); const auto modifier = object.value("modifier").toString(); @@ -974,7 +1053,6 @@ void LocationPicker::venuesSearchChanged( _mapControlsWrap->toggle(!shown, anim::type::instant); if (shown) { _venuesNoSearchLocation = _venuesRequestLocation; - _venueState = PickerVenueLoading(); } else if (_venuesNoSearchLocation) { if (!venuesFromCache(_venuesNoSearchLocation)) { venuesRequest(_venuesNoSearchLocation); @@ -986,6 +1064,7 @@ void LocationPicker::venuesSearchChanged( && !venuesFromCache( *_venuesSearchLocation, *_venuesSearchQuery)) { + _venueState = PickerVenueLoading(); _venuesSearchDebounceTimer.callOnce(kSearchDebounceDelay); } else { _venuesSearchDebounceTimer.cancel(); @@ -998,6 +1077,9 @@ void LocationPicker::resolveCurrentLocation() { ResolveCurrentGeoLocation(crl::guard(window, [=](GeoLocation location) { const auto changed = !AreTheSame(LastExactLocation, location); if (location.accuracy != GeoLocationAccuracy::Exact || !changed) { + if (!_venuesSearchLocation) { + _venueState = PickerVenueWaitingForLocation(); + } return; } LastExactLocation = location; diff --git a/Telegram/lib_ui b/Telegram/lib_ui index a95caea1a..f046725ec 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit a95caea1adac69ca6d95b55fe920eac33cdf9580 +Subproject commit f046725ecde41bf5779d69393cc592786ee0440c