From 1c69103fc8c02701eaeef6941f57109e92c4d26f Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 16 May 2026 10:17:08 +0300 Subject: [PATCH] Froze top bar suggestion content during child-list collapse animation. --- .../dialogs/dialogs_top_bar_suggestion.cpp | 20 ++- .../dialogs/dialogs_top_bar_suggestion.h | 3 +- .../SourceFiles/dialogs/dialogs_widget.cpp | 4 +- Telegram/SourceFiles/dialogs/dialogs_widget.h | 1 + .../ui/dialogs_top_bar_suggestion_content.cpp | 114 ++++++++++++++++-- .../ui/dialogs_top_bar_suggestion_content.h | 35 +++++- 6 files changed, 153 insertions(+), 24 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp index 72b49c05d3..cb2ac5f2c2 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.cpp @@ -151,10 +151,13 @@ rpl::producer*> TopBarSuggestionValue( not_null parent, not_null session, rpl::producer outerWrapToggleValue, - rpl::producer childListShown) { + rpl::producer childListShown, + rpl::producer<> prepareCollapseSnapshot) { return [=, outerWrapToggleValue = rpl::duplicate(outerWrapToggleValue), - childListShown = rpl::duplicate(childListShown)]( + childListShown = rpl::duplicate(childListShown), + prepareCollapseSnapshot = rpl::duplicate( + prepareCollapseSnapshot)]( auto consumer) { auto lifetime = rpl::lifetime(); @@ -165,7 +168,7 @@ rpl::producer*> TopBarSuggestionValue( struct State { TopBarSuggestionContent *content = nullptr; - Ui::SlideWrap *unconfirmedWarning = nullptr; + UnconfirmedAuthWrap *unconfirmedWarning = nullptr; base::unique_qptr> wrap; rpl::variable desiredWrapToggle; rpl::variable outerWrapToggle; @@ -227,7 +230,8 @@ rpl::producer*> TopBarSuggestionValue( session->api().authorizations().review( hashes, confirmed); - }); + }, + rpl::duplicate(childListShown)); ensureWrap(content); const auto wasUnconfirmedWarning = state->unconfirmedWarning; state->unconfirmedWarning = content; @@ -718,6 +722,14 @@ rpl::producer*> TopBarSuggestionValue( } }, lifetime); + rpl::duplicate(prepareCollapseSnapshot) | rpl::on_next([=] { + if (state->unconfirmedWarning) { + state->unconfirmedWarning->prepareCollapseSnapshot(); + } else if (state->content) { + state->content->prepareCollapseSnapshot(); + } + }, lifetime); + return lifetime; }; } diff --git a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.h b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.h index cb83206a32..9ad295c3c5 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.h +++ b/Telegram/SourceFiles/dialogs/dialogs_top_bar_suggestion.h @@ -26,7 +26,8 @@ namespace Dialogs { not_null parent, not_null, rpl::producer outerWrapToggleValue, - rpl::producer childListShown) + rpl::producer childListShown, + rpl::producer<> prepareCollapseSnapshot) -> rpl::producer*>; } // namespace Dialogs diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index 401900b166..04e8afcbe8 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -1123,7 +1123,8 @@ void Widget::setupTopBarSuggestions() { _innerList, &session(), std::move(on), - _childListShown.value()); + _childListShown.value(), + _prepareTopBarSnapshot.events()); }) | rpl::flatten_latest() | rpl::on_next([=]( Ui::SlideWrap *raw) { if (raw) { @@ -3467,6 +3468,7 @@ void Widget::openChildList( } }, shadow->lifetime()); + _prepareTopBarSnapshot.fire({}); updateControlsGeometry(); updateControlsVisibility(true); diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.h b/Telegram/SourceFiles/dialogs/dialogs_widget.h index d379e7e304..fde36c875e 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.h @@ -335,6 +335,7 @@ private: QPointer> _topBarSuggestion; rpl::event_stream _topBarSuggestionHeightChanged; rpl::event_stream _searchStateForTopBarSuggestion; + rpl::event_stream<> _prepareTopBarSnapshot; rpl::event_stream _openedFolderOrForumChanges; object_ptr _scroll; diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp index 40e0615da3..32a61125df 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.cpp @@ -20,6 +20,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "ui/text/format_values.h" #include "ui/text/text_custom_emoji.h" #include "ui/ui_rpl_filter.h" +#include "ui/ui_utility.h" #include "ui/vertical_list.h" #include "ui/vertical_list.h" #include "ui/widgets/buttons.h" @@ -44,26 +45,77 @@ constexpr auto kLinesForPhoto = 3; } // namespace -class UnconfirmedAuthWrap : public Ui::SlideWrap { -public: - UnconfirmedAuthWrap( - not_null parent, - object_ptr &&child) - : Ui::SlideWrap(parent, std::move(child)) { - } +UnconfirmedAuthWrap::UnconfirmedAuthWrap( + not_null parent, + object_ptr &&child) +: Ui::SlideWrap(parent, std::move(child)) { + paintRequest() | rpl::on_next([=] { + if (!_collapseSnapshot.isNull()) { + auto p = QPainter(this); + p.drawPixmap(0, 0, _collapseSnapshot); + } + }, lifetime()); +} - rpl::producer desiredHeightValue() const override { - return entity()->heightValue(); - } -}; +rpl::producer UnconfirmedAuthWrap::desiredHeightValue() const { + return entity()->heightValue(); +} -not_null*> CreateUnconfirmedAuthContent( +void UnconfirmedAuthWrap::setCollapseProgress( + rpl::producer progress) { + std::move(progress) | rpl::on_next([=](float64 value) { + if (_collapseProgress == value) { + return; + } + _collapseProgress = value; + if (value == 0.) { + releaseCollapseSnapshot(); + } + resizeToWidth(width()); + update(); + }, lifetime()); +} + +void UnconfirmedAuthWrap::prepareCollapseSnapshot() { + _collapseSnapshot = Ui::GrabWidget(this); + if (const auto w = wrapped()) { + w->hide(); + } + update(); +} + +void UnconfirmedAuthWrap::releaseCollapseSnapshot() { + if (_collapseSnapshot.isNull()) { + return; + } + _collapseSnapshot = QPixmap(); + if (const auto w = wrapped()) { + w->show(); + } +} + +int UnconfirmedAuthWrap::resizeGetHeight(int newWidth) { + if (!_collapseSnapshot.isNull()) { + const auto fullHeight = int(_collapseSnapshot.height() + / _collapseSnapshot.devicePixelRatio()); + return int(base::SafeRound( + fullHeight * (1. - _collapseProgress))); + } + if (const auto w = wrapped()) { + w->resizeToWidth(newWidth); + } + return wrapped() ? wrapped()->height() : 0; +} + +not_null CreateUnconfirmedAuthContent( not_null parent, const std::vector &list, - Fn callback) { + Fn callback, + rpl::producer collapseProgress) { const auto wrap = Ui::CreateChild( parent, object_ptr(parent)); + wrap->setCollapseProgress(std::move(collapseProgress)); const auto content = wrap->entity(); content->paintRequest() | rpl::on_next([=] { auto p = QPainter(content); @@ -489,10 +541,42 @@ void TopBarSuggestionContent::setContent( void TopBarSuggestionContent::paintEvent(QPaintEvent *) { auto p = QPainter(this); + if (!_collapseSnapshot.isNull()) { + p.drawPixmap(0, 0, _collapseSnapshot); + return; + } draw(p); } +void TopBarSuggestionContent::prepareCollapseSnapshot() { + _collapseSnapshot = Ui::GrabWidget(this); + for (const auto child : children()) { + if (const auto widget = qobject_cast(child)) { + widget->hide(); + } + } + update(); +} + +void TopBarSuggestionContent::releaseCollapseSnapshot() { + if (_collapseSnapshot.isNull()) { + return; + } + _collapseSnapshot = QPixmap(); + for (const auto child : children()) { + if (const auto widget = qobject_cast(child)) { + widget->show(); + } + } +} + int TopBarSuggestionContent::resizeGetHeight(int newWidth) { + if (!_collapseSnapshot.isNull()) { + const auto fullHeight = int(_collapseSnapshot.height() + / _collapseSnapshot.devicePixelRatio()); + return int(base::SafeRound( + fullHeight * (1. - _collapseProgress))); + } const auto topPadding = st::msgReplyPadding.top(); const auto bottomPadding = st::msgReplyPadding.top(); const auto availableWidthNoPhoto = newWidth @@ -549,7 +633,11 @@ void TopBarSuggestionContent::setCollapseProgress( return; } _collapseProgress = value; + if (value == 0.) { + releaseCollapseSnapshot(); + } resizeToWidth(width()); + update(); }, lifetime()); } diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.h b/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.h index 5a80485760..f10d04b4bc 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_top_bar_suggestion_content.h @@ -8,14 +8,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #pragma once #include "ui/widgets/buttons.h" +#include "ui/wrap/slide_wrap.h" +#include "ui/wrap/vertical_layout.h" namespace Ui { class DynamicImage; class GenericBox; class IconButton; -class VerticalLayout; -template -class SlideWrap; } // namespace Ui namespace Ui::Text { @@ -28,10 +27,33 @@ struct UnreviewedAuth; namespace Dialogs { -not_null*> CreateUnconfirmedAuthContent( +class UnconfirmedAuthWrap : public Ui::SlideWrap { +public: + UnconfirmedAuthWrap( + not_null parent, + object_ptr &&child); + + [[nodiscard]] rpl::producer desiredHeightValue() const override; + + void setCollapseProgress(rpl::producer progress); + void prepareCollapseSnapshot(); + +protected: + int resizeGetHeight(int newWidth) override; + +private: + void releaseCollapseSnapshot(); + + float64 _collapseProgress = 0.; + QPixmap _collapseSnapshot; + +}; + +not_null CreateUnconfirmedAuthContent( not_null parent, const std::vector &list, - Fn callback); + Fn callback, + rpl::producer collapseProgress); void ShowAuthDeniedBox( not_null box, @@ -63,6 +85,7 @@ public: Fn callback); void setLeadingWidget(Ui::RpWidget *widget); void setCollapseProgress(rpl::producer progress); + void prepareCollapseSnapshot(); [[nodiscard]] const style::TextStyle &contentTitleSt() const; @@ -72,6 +95,7 @@ protected: private: void draw(QPainter &p); + void releaseCollapseSnapshot(); const style::TextStyle &_titleSt; const style::TextStyle &_contentTitleSt; @@ -80,6 +104,7 @@ private: Ui::Text::String _contentTitle; Ui::Text::String _contentText; float64 _collapseProgress = 0.; + QPixmap _collapseSnapshot; std::optional _descriptionColorOverride; base::unique_qptr _rightHide;