diff --git a/Telegram/SourceFiles/api/api_chat_filters.cpp b/Telegram/SourceFiles/api/api_chat_filters.cpp index dfba82162..1159b3c34 100644 --- a/Telegram/SourceFiles/api/api_chat_filters.cpp +++ b/Telegram/SourceFiles/api/api_chat_filters.cpp @@ -55,14 +55,18 @@ public: [[nodiscard]] auto selectedValue() const -> rpl::producer>>; - void setAddedTopHeight(int addedTopHeight); + void adjust(int minHeight, int maxHeight, int addedTopHeight); + void setRealContentHeight(rpl::producer value); + rpl::producer boxHeightValue() const override; private: void setupAboveWidget(); void setupBelowWidget(); + void initDesiredHeightValue(); const not_null _window; Ui::RpWidget *_addedTopWidget = nullptr; + Ui::RpWidget *_addedBottomWidget = nullptr; ToggleAction _action = ToggleAction::Adding; QString _filterTitle; @@ -70,6 +74,12 @@ private: std::vector> _additional; rpl::variable>> _selected; + int _minTopHeight = 0; + rpl::variable _maxTopHeight; + rpl::variable _aboveHeight; + rpl::variable _belowHeight; + rpl::variable _desiredHeight; + base::unique_qptr _menu; rpl::lifetime _lifetime; @@ -126,7 +136,7 @@ private: void InitFilterLinkHeader( not_null box, - Fn setAddedTopHeight, + Fn adjust, Ui::FilterLinkHeaderType type, const QString &title, const QString &iconEmoji, @@ -159,6 +169,12 @@ void InitFilterLinkHeader( box->sendScrollViewportEvent(e); }, widget->lifetime()); + std::move( + header.closeRequests + ) | rpl::start_with_next([=] { + box->closeBox(); + }, widget->lifetime()); + struct State { bool processing = false; int addedTopHeight = 0; @@ -178,17 +194,18 @@ void InitFilterLinkHeader( const auto addedTopHeight = max - headerHeight; widget->resize(widget->width(), headerHeight); if (state->addedTopHeight < addedTopHeight) { - setAddedTopHeight(addedTopHeight); + adjust(min, max, addedTopHeight); box->setAddedTopScrollSkip(headerHeight); } else { box->setAddedTopScrollSkip(headerHeight); - setAddedTopHeight(addedTopHeight); + adjust(min, max, addedTopHeight); } state->addedTopHeight = addedTopHeight; box->peerListRefreshRows(); }, widget->lifetime()); box->setNoContentMargin(true); + adjust(min, max, 0); } void ImportInvite( @@ -260,6 +277,7 @@ void ToggleChatsController::prepare() { } if (!additional) { delegate()->peerListSetRowChecked(raw, true); + raw->finishCheckedAnimation(); selected.emplace(peer); } else if (_action == ToggleAction::Adding) { raw->setDisabledState(PeerListRow::State::DisabledChecked); @@ -274,6 +292,7 @@ void ToggleChatsController::prepare() { for (const auto &peer : _additional) { add(peer, true); } + initDesiredHeightValue(); delegate()->peerListRefreshRows(); _selected = std::move(selected); } @@ -298,7 +317,9 @@ void ToggleChatsController::setupAboveWidget() { const auto container = wrap.data(); _addedTopWidget = container->add(object_ptr(container)); - AddDivider(container); + const auto realAbove = container->add( + object_ptr(container)); + AddDivider(realAbove); const auto totalCount = [&] { if (_chats.empty()) { return _additional.size(); @@ -319,7 +340,7 @@ void ToggleChatsController::setupAboveWidget() { ? _additional.size() : _chats.size(); AddSubsectionTitle( - container, + realAbove, (_action == ToggleAction::Removing ? tr::lng_filters_by_link_quit : _chats.empty() @@ -329,23 +350,34 @@ void ToggleChatsController::setupAboveWidget() { rpl::single(float64(count))), st::filterLinkSubsectionTitlePadding); + _aboveHeight = realAbove->heightValue(); delegate()->peerListSetAboveWidget(std::move(wrap)); } void ToggleChatsController::setupBelowWidget() { if (_chats.empty()) { + auto widget = object_ptr((QWidget*)nullptr); + _addedBottomWidget = widget.data(); + delegate()->peerListSetBelowWidget(std::move(widget)); return; } - delegate()->peerListSetBelowWidget( - object_ptr( - (QWidget*)nullptr, - object_ptr( - (QWidget*)nullptr, - (_action == ToggleAction::Removing - ? tr::lng_filters_by_link_about_quit - : tr::lng_filters_by_link_about)(tr::now), - st::boxDividerLabel), - st::settingsDividerLabelPadding)); + auto layout = object_ptr((QWidget*)nullptr); + const auto raw = layout.data(); + auto widget = object_ptr( + (QWidget*)nullptr, + std::move(layout), + st::settingsDividerLabelPadding); + raw->add(object_ptr( + raw, + (_action == ToggleAction::Removing + ? tr::lng_filters_by_link_about_quit + : tr::lng_filters_by_link_about)(tr::now), + st::boxDividerLabel)); + _addedBottomWidget = raw->add(object_ptr(raw)); + _belowHeight = widget->heightValue() | rpl::map([=](int value) { + return value - _addedBottomWidget->height(); + }); + delegate()->peerListSetBelowWidget(std::move(widget)); } Main::Session &ToggleChatsController::session() const { @@ -357,10 +389,56 @@ auto ToggleChatsController::selectedValue() const return _selected.value(); } -void ToggleChatsController::setAddedTopHeight(int addedTopHeight) { +void ToggleChatsController::adjust( + int minHeight, + int maxHeight, + int addedTopHeight) { Expects(addedTopHeight >= 0); _addedTopWidget->resize(_addedTopWidget->width(), addedTopHeight); + _minTopHeight = minHeight; + _maxTopHeight = maxHeight; +} + +void ToggleChatsController::setRealContentHeight(rpl::producer value) { + std::move( + value + ) | rpl::start_with_next([=](int height) { + const auto desired = _desiredHeight.current(); + if (height <= computeListSt().item.height) { + return; + } else if (height >= desired) { + _addedBottomWidget->resize(_addedBottomWidget->width(), 0); + } else { + const auto available = desired - height; + const auto required = _maxTopHeight.current() - _minTopHeight; + const auto added = required - available; + _addedBottomWidget->resize( + _addedBottomWidget->width(), + std::max(added, 0)); + } + }, _lifetime); +} + +void ToggleChatsController::initDesiredHeightValue() { + using namespace rpl::mappers; + + const auto &st = computeListSt(); + const auto count = int(delegate()->peerListFullRowsCount()); + const auto middle = st.padding.top() + + (count * st.item.height) + + st.padding.bottom(); + _desiredHeight = rpl::combine( + _maxTopHeight.value(), + _aboveHeight.value(), + _belowHeight.value(), + _1 + _2 + middle + _3); +} + +rpl::producer ToggleChatsController::boxHeightValue() const { + return _desiredHeight.value() | rpl::map([=](int value) { + return std::min(value, st::boxMaxListHeight); + }); } void ShowImportError( @@ -454,10 +532,12 @@ void ProcessFilterInvite( ) | rpl::map([=](const base::flat_set> &peers) { return int(peers.size()); }); - InitFilterLinkHeader(box, [=](int addedTopHeight) { - raw->setAddedTopHeight(addedTopHeight); + InitFilterLinkHeader(box, [=](int min, int max, int addedTop) { + raw->adjust(min, max, addedTop); }, type, title, iconEmoji, rpl::duplicate(badge)); + raw->setRealContentHeight(box->heightValue()); + auto owned = Ui::FilterLinkProcessButton( box, type, @@ -677,8 +757,8 @@ void ProcessFilterRemove( ) | rpl::map([=](const base::flat_set> &peers) { return int(peers.size()); }); - InitFilterLinkHeader(box, [=](int addedTopHeight) { - raw->setAddedTopHeight(addedTopHeight); + InitFilterLinkHeader(box, [=](int min, int max, int addedTop) { + raw->adjust(min, max, addedTop); }, type, title, iconEmoji, rpl::single(0)); auto owned = Ui::FilterLinkProcessButton( diff --git a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp index 69aa79d16..86e531c61 100644 --- a/Telegram/SourceFiles/boxes/edit_privacy_box.cpp +++ b/Telegram/SourceFiles/boxes/edit_privacy_box.cpp @@ -217,16 +217,18 @@ Ui::FlatLabel *EditPrivacyBox::addLabel( if (!text) { return nullptr; } - return container->add( + auto label = object_ptr( + container, + rpl::duplicate(text), + st::boxDividerLabel); + const auto result = label.data(); + container->add( object_ptr( container, - object_ptr( - container, - rpl::duplicate(text), - st::boxDividerLabel), + std::move(label), st::settingsDividerLabelPadding), - { 0, topSkip, 0, 0 } - )->entity(); + { 0, topSkip, 0, 0 }); + return result; } Ui::FlatLabel *EditPrivacyBox::addLabelOrDivider( diff --git a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp index b7ff7a31d..c1bea9990 100644 --- a/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp +++ b/Telegram/SourceFiles/boxes/filters/edit_filter_links.cpp @@ -695,6 +695,7 @@ void LinkController::prepare() { const auto raw = row.get(); delegate()->peerListAppendRow(std::move(row)); delegate()->peerListSetRowChecked(raw, true); + raw->finishCheckedAnimation(); _initial.emplace(peer); } for (const auto &history : _filterChats) { diff --git a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp index f35ad1a61..8c60e671c 100644 --- a/Telegram/SourceFiles/ui/controls/filter_link_header.cpp +++ b/Telegram/SourceFiles/ui/controls/filter_link_header.cpp @@ -31,9 +31,9 @@ public: FilterLinkHeaderDescriptor &&descriptor); void setTitlePosition(int x, int y); - void updateDimensions(int newWidth); [[nodiscard]] rpl::producer> wheelEvents() const; + [[nodiscard]] rpl::producer<> closeRequests() const; private: void resizeEvent(QResizeEvent *e) override; @@ -46,6 +46,7 @@ private: void refreshTitleText(); const not_null _about; + const not_null _close; QMargins _aboutPadding; struct { @@ -176,10 +177,11 @@ Widget::Widget( not_null parent, FilterLinkHeaderDescriptor &&descriptor) : RpWidget(parent) -, _about(CreateChild( +, _about(CreateChild( this, rpl::single(descriptor.about.value()), st::filterLinkAbout)) +, _close(CreateChild(this, st::boxTitleClose)) , _aboutPadding(st::boxRowPadding) , _badge(std::move(descriptor.badge)) , _titleText(descriptor.title) @@ -216,6 +218,10 @@ rpl::producer> Widget::wheelEvents() const { return _wheelEvents.events(); } +rpl::producer<> Widget::closeRequests() const { + return _close->clicks() | rpl::to_empty; +} + void Widget::resizeEvent(QResizeEvent *e) { const auto &padding = _aboutPadding; const auto availableWidth = width() - padding.left() - padding.right(); @@ -258,13 +264,15 @@ void Widget::resizeEvent(QResizeEvent *e) { _about->moveToLeft(_aboutPadding.left(), aboutTop); _about->setOpacity(_progress.body); + _close->moveToRight(0, 0); + update(); } QRectF Widget::previewRect( float64 topProgress, float64 sizeProgress) const { - const auto size = st::filterLinkPreview; + const auto size = st::filterLinkPreview * sizeProgress; return QRectF( (width() - size) / 2., st::filterLinkPreviewTop * topProgress, @@ -276,9 +284,6 @@ void Widget::paintEvent(QPaintEvent *e) { auto p = QPainter(this); p.setOpacity(_progress.body); - p.translate(_previewRect.center()); - p.scale(_progress.body, _progress.body); - p.translate(-_previewRect.center()); if (_progress.top) { auto hq = PainterHighQualityEnabler(p); if (_preview.isNull()) { @@ -327,7 +332,11 @@ void Widget::wheelEvent(QWheelEvent *e) { const auto result = CreateChild( parent.get(), std::move(descriptor)); - return { .widget = result, .wheelEvents = result->wheelEvents() }; + return { + .widget = result, + .wheelEvents = result->wheelEvents(), + .closeRequests = result->closeRequests(), + }; } object_ptr FilterLinkProcessButton( diff --git a/Telegram/SourceFiles/ui/controls/filter_link_header.h b/Telegram/SourceFiles/ui/controls/filter_link_header.h index 7e40ce7ca..8769bf069 100644 --- a/Telegram/SourceFiles/ui/controls/filter_link_header.h +++ b/Telegram/SourceFiles/ui/controls/filter_link_header.h @@ -34,6 +34,7 @@ struct FilterLinkHeaderDescriptor { struct FilterLinkHeader { not_null widget; rpl::producer> wheelEvents; + rpl::producer<> closeRequests; }; [[nodiscard]] FilterLinkHeader MakeFilterLinkHeader(