mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 06:07:06 +02:00
Improve scrolling limits in chat select boxes.
This commit is contained in:
parent
9b1c5b1050
commit
7ff0659e91
5 changed files with 128 additions and 35 deletions
|
@ -55,14 +55,18 @@ public:
|
|||
[[nodiscard]] auto selectedValue() const
|
||||
-> rpl::producer<base::flat_set<not_null<PeerData*>>>;
|
||||
|
||||
void setAddedTopHeight(int addedTopHeight);
|
||||
void adjust(int minHeight, int maxHeight, int addedTopHeight);
|
||||
void setRealContentHeight(rpl::producer<int> value);
|
||||
rpl::producer<int> boxHeightValue() const override;
|
||||
|
||||
private:
|
||||
void setupAboveWidget();
|
||||
void setupBelowWidget();
|
||||
void initDesiredHeightValue();
|
||||
|
||||
const not_null<Window::SessionController*> _window;
|
||||
Ui::RpWidget *_addedTopWidget = nullptr;
|
||||
Ui::RpWidget *_addedBottomWidget = nullptr;
|
||||
|
||||
ToggleAction _action = ToggleAction::Adding;
|
||||
QString _filterTitle;
|
||||
|
@ -70,6 +74,12 @@ private:
|
|||
std::vector<not_null<PeerData*>> _additional;
|
||||
rpl::variable<base::flat_set<not_null<PeerData*>>> _selected;
|
||||
|
||||
int _minTopHeight = 0;
|
||||
rpl::variable<int> _maxTopHeight;
|
||||
rpl::variable<int> _aboveHeight;
|
||||
rpl::variable<int> _belowHeight;
|
||||
rpl::variable<int> _desiredHeight;
|
||||
|
||||
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||
|
||||
rpl::lifetime _lifetime;
|
||||
|
@ -126,7 +136,7 @@ private:
|
|||
|
||||
void InitFilterLinkHeader(
|
||||
not_null<PeerListBox*> box,
|
||||
Fn<void(int)> setAddedTopHeight,
|
||||
Fn<void(int minHeight, int maxHeight, int addedTopHeight)> 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<Ui::RpWidget>(container));
|
||||
AddDivider(container);
|
||||
const auto realAbove = container->add(
|
||||
object_ptr<Ui::VerticalLayout>(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<Ui::RpWidget>((QWidget*)nullptr);
|
||||
_addedBottomWidget = widget.data();
|
||||
delegate()->peerListSetBelowWidget(std::move(widget));
|
||||
return;
|
||||
}
|
||||
delegate()->peerListSetBelowWidget(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
(QWidget*)nullptr,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
(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<Ui::VerticalLayout>((QWidget*)nullptr);
|
||||
const auto raw = layout.data();
|
||||
auto widget = object_ptr<Ui::DividerLabel>(
|
||||
(QWidget*)nullptr,
|
||||
std::move(layout),
|
||||
st::settingsDividerLabelPadding);
|
||||
raw->add(object_ptr<Ui::FlatLabel>(
|
||||
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<Ui::RpWidget>(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<int> 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<int> 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<not_null<PeerData*>> &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<not_null<PeerData*>> &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(
|
||||
|
|
|
@ -217,16 +217,18 @@ Ui::FlatLabel *EditPrivacyBox::addLabel(
|
|||
if (!text) {
|
||||
return nullptr;
|
||||
}
|
||||
return container->add(
|
||||
auto label = object_ptr<Ui::FlatLabel>(
|
||||
container,
|
||||
rpl::duplicate(text),
|
||||
st::boxDividerLabel);
|
||||
const auto result = label.data();
|
||||
container->add(
|
||||
object_ptr<Ui::DividerLabel>(
|
||||
container,
|
||||
object_ptr<Ui::FlatLabel>(
|
||||
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(
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -31,9 +31,9 @@ public:
|
|||
FilterLinkHeaderDescriptor &&descriptor);
|
||||
|
||||
void setTitlePosition(int x, int y);
|
||||
void updateDimensions(int newWidth);
|
||||
|
||||
[[nodiscard]] rpl::producer<not_null<QWheelEvent*>> wheelEvents() const;
|
||||
[[nodiscard]] rpl::producer<> closeRequests() const;
|
||||
|
||||
private:
|
||||
void resizeEvent(QResizeEvent *e) override;
|
||||
|
@ -46,6 +46,7 @@ private:
|
|||
void refreshTitleText();
|
||||
|
||||
const not_null<FlatLabel*> _about;
|
||||
const not_null<IconButton*> _close;
|
||||
QMargins _aboutPadding;
|
||||
|
||||
struct {
|
||||
|
@ -176,10 +177,11 @@ Widget::Widget(
|
|||
not_null<QWidget*> parent,
|
||||
FilterLinkHeaderDescriptor &&descriptor)
|
||||
: RpWidget(parent)
|
||||
, _about(CreateChild<Ui::FlatLabel>(
|
||||
, _about(CreateChild<FlatLabel>(
|
||||
this,
|
||||
rpl::single(descriptor.about.value()),
|
||||
st::filterLinkAbout))
|
||||
, _close(CreateChild<IconButton>(this, st::boxTitleClose))
|
||||
, _aboutPadding(st::boxRowPadding)
|
||||
, _badge(std::move(descriptor.badge))
|
||||
, _titleText(descriptor.title)
|
||||
|
@ -216,6 +218,10 @@ rpl::producer<not_null<QWheelEvent*>> 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<Widget>(
|
||||
parent.get(),
|
||||
std::move(descriptor));
|
||||
return { .widget = result, .wheelEvents = result->wheelEvents() };
|
||||
return {
|
||||
.widget = result,
|
||||
.wheelEvents = result->wheelEvents(),
|
||||
.closeRequests = result->closeRequests(),
|
||||
};
|
||||
}
|
||||
|
||||
object_ptr<RoundButton> FilterLinkProcessButton(
|
||||
|
|
|
@ -34,6 +34,7 @@ struct FilterLinkHeaderDescriptor {
|
|||
struct FilterLinkHeader {
|
||||
not_null<RpWidget*> widget;
|
||||
rpl::producer<not_null<QWheelEvent*>> wheelEvents;
|
||||
rpl::producer<> closeRequests;
|
||||
};
|
||||
|
||||
[[nodiscard]] FilterLinkHeader MakeFilterLinkHeader(
|
||||
|
|
Loading…
Add table
Reference in a new issue