Change layer widget height with animation.

This commit is contained in:
John Preston 2022-04-12 16:07:25 +04:00
parent 9933d1ff3a
commit f6f39d1560
5 changed files with 79 additions and 13 deletions

View File

@ -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()) {

View File

@ -68,11 +68,17 @@ private:
not_null<const HistoryItem*> item) override;
void setupHeightConsumers();
void setContentHeight(int height);
not_null<Window::SessionController*> _controller;
object_ptr<WrapWidget> _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;

View File

@ -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<Window::ConnectionState>(

View File

@ -645,10 +645,10 @@ rpl::producer<bool> WrapWidget::topShadowToggledValue() const {
rpl::producer<int> 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<SelectedItems> 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<Ui::RpWidget> 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<int> WrapWidget::scrollTillBottomChanges() const {
) | rpl::flatten_latest();
}
rpl::producer<bool> WrapWidget::grabbingForExpanding() const {
return _grabbingForExpanding.value();
}
WrapWidget::~WrapWidget() = default;
} // namespace Info

View File

@ -118,11 +118,15 @@ public:
object_ptr<Ui::RpWidget> createTopBarSurrogate(QWidget *parent);
bool closeByOutsideClick() const;
[[nodiscard]] bool closeByOutsideClick() const;
void updateGeometry(QRect newGeometry, int additionalScroll);
int scrollTillBottom(int forHeight) const;
rpl::producer<int> scrollTillBottomChanges() const;
void updateGeometry(
QRect newGeometry,
bool expanding,
int additionalScroll);
[[nodiscard]] int scrollTillBottom(int forHeight) const;
[[nodiscard]] rpl::producer<int> scrollTillBottomChanges() const;
[[nodiscard]] rpl::producer<bool> grabbingForExpanding() const;
~WrapWidget();
@ -203,6 +207,8 @@ private:
std::unique_ptr<Controller> _controller;
object_ptr<ContentWidget> _content = { nullptr };
int _additionalScroll = 0;
bool _expanding = false;
rpl::variable<bool> _grabbingForExpanding = false;
//object_ptr<Ui::PlainShadow> _topTabsBackground = { nullptr };
//object_ptr<Ui::SettingsSlider> _topTabs = { nullptr };
object_ptr<TopBar> _topBar = { nullptr };