diff --git a/Telegram/SourceFiles/info/info_layer_widget.cpp b/Telegram/SourceFiles/info/info_layer_widget.cpp index deb98a178f..52905efa39 100644 --- a/Telegram/SourceFiles/info/info_layer_widget.cpp +++ b/Telegram/SourceFiles/info/info_layer_widget.cpp @@ -86,15 +86,50 @@ void LayerWidget::setupHeightConsumers() { }) | rpl::start_with_next([this] { resizeToWidth(width()); }, lifetime()); + + _content->grabbingForExpanding( + ) | rpl::start_with_next([=](bool grabbing) { + if (grabbing) { + _savedHeight = _contentHeight; + _savedHeightAnimation = base::take(_heightAnimation); + setContentHeight(_desiredHeight); + } else { + _heightAnimation = base::take(_savedHeightAnimation); + setContentHeight(_savedHeight); + } + }, lifetime()); + _content->desiredHeightValue( ) | rpl::start_with_next([this](int height) { - accumulate_max(_desiredHeight, height); - if (_content && !_inResize) { + if (!height) { + // New content arrived. + _heightAnimated = _heightAnimation.animating(); + return; + } + std::swap(_desiredHeight, height); + if (!height + || (_heightAnimated && !_heightAnimation.animating())) { + setContentHeight(_desiredHeight); + } else { + _heightAnimated = true; + _heightAnimation.start([=] { + setContentHeight(_heightAnimation.value(_desiredHeight)); + }, _contentHeight, _desiredHeight, st::slideDuration); resizeToWidth(width()); } }, lifetime()); } +void LayerWidget::setContentHeight(int height) { + if (_contentHeight == height) { + return; + } + _contentHeight = height; + if (_content && !_inResize) { + resizeToWidth(width()); + } +} + void LayerWidget::showFinished() { floatPlayerShowVisible(); } @@ -217,8 +252,8 @@ int LayerWidget::resizeGetHeight(int newWidth) { st::infoLayerTopMaximal); auto newBottom = newTop; - // Top rounding is included in _desiredHeight. - auto desiredHeight = _desiredHeight + st::boxRadius; + // Top rounding is included in _contentHeight. + auto desiredHeight = _contentHeight + st::boxRadius; accumulate_min(desiredHeight, windowHeight - newTop - newBottom); // First resize content to new width and get the new desired height. @@ -230,6 +265,8 @@ int LayerWidget::resizeGetHeight(int newWidth) { auto scrollTillBottom = _content->scrollTillBottom(contentHeight); auto additionalScroll = std::min(scrollTillBottom, newBottom); + const auto expanding = (_desiredHeight > _contentHeight); + desiredHeight += additionalScroll; contentHeight += additionalScroll; _tillBottom = (newTop + desiredHeight >= windowHeight); @@ -241,7 +278,8 @@ int LayerWidget::resizeGetHeight(int newWidth) { contentLeft, contentTop, contentWidth, - contentHeight }, additionalScroll); + contentHeight, + }, expanding, additionalScroll); auto newGeometry = QRect(newLeft, newTop, newWidth, desiredHeight); if (newGeometry != geometry()) { diff --git a/Telegram/SourceFiles/info/info_layer_widget.h b/Telegram/SourceFiles/info/info_layer_widget.h index 4499a8d22e..60d947e218 100644 --- a/Telegram/SourceFiles/info/info_layer_widget.h +++ b/Telegram/SourceFiles/info/info_layer_widget.h @@ -68,11 +68,17 @@ private: not_null item) override; void setupHeightConsumers(); + void setContentHeight(int height); not_null _controller; object_ptr _content; int _desiredHeight = 0; + int _contentHeight = 0; + int _savedHeight = 0; + Ui::Animations::Simple _heightAnimation; + Ui::Animations::Simple _savedHeightAnimation; + bool _heightAnimated = false; bool _inResize = false; bool _tillBottom = false; diff --git a/Telegram/SourceFiles/info/info_section_widget.cpp b/Telegram/SourceFiles/info/info_section_widget.cpp index 1884323083..1b6f522f47 100644 --- a/Telegram/SourceFiles/info/info_section_widget.cpp +++ b/Telegram/SourceFiles/info/info_section_widget.cpp @@ -44,9 +44,10 @@ void SectionWidget::init() { sizeValue( ) | rpl::start_with_next([wrap = _content.data()](QSize size) { + const auto expanding = false; auto wrapGeometry = QRect{ { 0, 0 }, size }; auto additionalScroll = 0; - wrap->updateGeometry(wrapGeometry, additionalScroll); + wrap->updateGeometry(wrapGeometry, expanding, additionalScroll); }, _content->lifetime()); _connecting = std::make_unique( diff --git a/Telegram/SourceFiles/info/info_wrap_widget.cpp b/Telegram/SourceFiles/info/info_wrap_widget.cpp index 7b94f26a7d..c63fb8a39b 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.cpp +++ b/Telegram/SourceFiles/info/info_wrap_widget.cpp @@ -645,10 +645,10 @@ rpl::producer WrapWidget::topShadowToggledValue() const { rpl::producer WrapWidget::desiredHeightForContent() const { using namespace rpl::mappers; - return rpl::combine( + return rpl::single(0) | rpl::then(rpl::combine( _content->desiredHeightValue(), topWidget()->heightValue(), - _1 + _2); + _1 + _2)); } rpl::producer WrapWidget::selectedListValue() const { @@ -738,7 +738,14 @@ QPixmap WrapWidget::grabForShowAnimation( //if (params.withTabs && _topTabs) { // _topTabs->hide(); //} + const auto expanding = _expanding; + if (expanding) { + _grabbingForExpanding = true; + } auto result = Ui::GrabWidget(this); + if (expanding) { + _grabbingForExpanding = false; + } if (params.withTopBarShadow) { _topShadow->setVisible(true); } @@ -1007,11 +1014,15 @@ object_ptr WrapWidget::createTopBarSurrogate( return nullptr; } -void WrapWidget::updateGeometry(QRect newGeometry, int additionalScroll) { +void WrapWidget::updateGeometry( + QRect newGeometry, + bool expanding, + int additionalScroll) { auto scrollChanged = (_additionalScroll != additionalScroll); auto geometryChanged = (geometry() != newGeometry); auto shrinkingContent = (additionalScroll < _additionalScroll); _additionalScroll = additionalScroll; + _expanding = expanding; if (geometryChanged) { if (shrinkingContent) { @@ -1038,6 +1049,10 @@ rpl::producer WrapWidget::scrollTillBottomChanges() const { ) | rpl::flatten_latest(); } +rpl::producer WrapWidget::grabbingForExpanding() const { + return _grabbingForExpanding.value(); +} + WrapWidget::~WrapWidget() = default; } // namespace Info diff --git a/Telegram/SourceFiles/info/info_wrap_widget.h b/Telegram/SourceFiles/info/info_wrap_widget.h index 4ed2f6057d..6141321ce8 100644 --- a/Telegram/SourceFiles/info/info_wrap_widget.h +++ b/Telegram/SourceFiles/info/info_wrap_widget.h @@ -118,11 +118,15 @@ public: object_ptr createTopBarSurrogate(QWidget *parent); - bool closeByOutsideClick() const; + [[nodiscard]] bool closeByOutsideClick() const; - void updateGeometry(QRect newGeometry, int additionalScroll); - int scrollTillBottom(int forHeight) const; - rpl::producer scrollTillBottomChanges() const; + void updateGeometry( + QRect newGeometry, + bool expanding, + int additionalScroll); + [[nodiscard]] int scrollTillBottom(int forHeight) const; + [[nodiscard]] rpl::producer scrollTillBottomChanges() const; + [[nodiscard]] rpl::producer grabbingForExpanding() const; ~WrapWidget(); @@ -203,6 +207,8 @@ private: std::unique_ptr _controller; object_ptr _content = { nullptr }; int _additionalScroll = 0; + bool _expanding = false; + rpl::variable _grabbingForExpanding = false; //object_ptr _topTabsBackground = { nullptr }; //object_ptr _topTabs = { nullptr }; object_ptr _topBar = { nullptr };