mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +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
|
[[nodiscard]] auto selectedValue() const
|
||||||
-> rpl::producer<base::flat_set<not_null<PeerData*>>>;
|
-> 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:
|
private:
|
||||||
void setupAboveWidget();
|
void setupAboveWidget();
|
||||||
void setupBelowWidget();
|
void setupBelowWidget();
|
||||||
|
void initDesiredHeightValue();
|
||||||
|
|
||||||
const not_null<Window::SessionController*> _window;
|
const not_null<Window::SessionController*> _window;
|
||||||
Ui::RpWidget *_addedTopWidget = nullptr;
|
Ui::RpWidget *_addedTopWidget = nullptr;
|
||||||
|
Ui::RpWidget *_addedBottomWidget = nullptr;
|
||||||
|
|
||||||
ToggleAction _action = ToggleAction::Adding;
|
ToggleAction _action = ToggleAction::Adding;
|
||||||
QString _filterTitle;
|
QString _filterTitle;
|
||||||
|
@ -70,6 +74,12 @@ private:
|
||||||
std::vector<not_null<PeerData*>> _additional;
|
std::vector<not_null<PeerData*>> _additional;
|
||||||
rpl::variable<base::flat_set<not_null<PeerData*>>> _selected;
|
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;
|
base::unique_qptr<Ui::PopupMenu> _menu;
|
||||||
|
|
||||||
rpl::lifetime _lifetime;
|
rpl::lifetime _lifetime;
|
||||||
|
@ -126,7 +136,7 @@ private:
|
||||||
|
|
||||||
void InitFilterLinkHeader(
|
void InitFilterLinkHeader(
|
||||||
not_null<PeerListBox*> box,
|
not_null<PeerListBox*> box,
|
||||||
Fn<void(int)> setAddedTopHeight,
|
Fn<void(int minHeight, int maxHeight, int addedTopHeight)> adjust,
|
||||||
Ui::FilterLinkHeaderType type,
|
Ui::FilterLinkHeaderType type,
|
||||||
const QString &title,
|
const QString &title,
|
||||||
const QString &iconEmoji,
|
const QString &iconEmoji,
|
||||||
|
@ -159,6 +169,12 @@ void InitFilterLinkHeader(
|
||||||
box->sendScrollViewportEvent(e);
|
box->sendScrollViewportEvent(e);
|
||||||
}, widget->lifetime());
|
}, widget->lifetime());
|
||||||
|
|
||||||
|
std::move(
|
||||||
|
header.closeRequests
|
||||||
|
) | rpl::start_with_next([=] {
|
||||||
|
box->closeBox();
|
||||||
|
}, widget->lifetime());
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
bool processing = false;
|
bool processing = false;
|
||||||
int addedTopHeight = 0;
|
int addedTopHeight = 0;
|
||||||
|
@ -178,17 +194,18 @@ void InitFilterLinkHeader(
|
||||||
const auto addedTopHeight = max - headerHeight;
|
const auto addedTopHeight = max - headerHeight;
|
||||||
widget->resize(widget->width(), headerHeight);
|
widget->resize(widget->width(), headerHeight);
|
||||||
if (state->addedTopHeight < addedTopHeight) {
|
if (state->addedTopHeight < addedTopHeight) {
|
||||||
setAddedTopHeight(addedTopHeight);
|
adjust(min, max, addedTopHeight);
|
||||||
box->setAddedTopScrollSkip(headerHeight);
|
box->setAddedTopScrollSkip(headerHeight);
|
||||||
} else {
|
} else {
|
||||||
box->setAddedTopScrollSkip(headerHeight);
|
box->setAddedTopScrollSkip(headerHeight);
|
||||||
setAddedTopHeight(addedTopHeight);
|
adjust(min, max, addedTopHeight);
|
||||||
}
|
}
|
||||||
state->addedTopHeight = addedTopHeight;
|
state->addedTopHeight = addedTopHeight;
|
||||||
box->peerListRefreshRows();
|
box->peerListRefreshRows();
|
||||||
}, widget->lifetime());
|
}, widget->lifetime());
|
||||||
|
|
||||||
box->setNoContentMargin(true);
|
box->setNoContentMargin(true);
|
||||||
|
adjust(min, max, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImportInvite(
|
void ImportInvite(
|
||||||
|
@ -260,6 +277,7 @@ void ToggleChatsController::prepare() {
|
||||||
}
|
}
|
||||||
if (!additional) {
|
if (!additional) {
|
||||||
delegate()->peerListSetRowChecked(raw, true);
|
delegate()->peerListSetRowChecked(raw, true);
|
||||||
|
raw->finishCheckedAnimation();
|
||||||
selected.emplace(peer);
|
selected.emplace(peer);
|
||||||
} else if (_action == ToggleAction::Adding) {
|
} else if (_action == ToggleAction::Adding) {
|
||||||
raw->setDisabledState(PeerListRow::State::DisabledChecked);
|
raw->setDisabledState(PeerListRow::State::DisabledChecked);
|
||||||
|
@ -274,6 +292,7 @@ void ToggleChatsController::prepare() {
|
||||||
for (const auto &peer : _additional) {
|
for (const auto &peer : _additional) {
|
||||||
add(peer, true);
|
add(peer, true);
|
||||||
}
|
}
|
||||||
|
initDesiredHeightValue();
|
||||||
delegate()->peerListRefreshRows();
|
delegate()->peerListRefreshRows();
|
||||||
_selected = std::move(selected);
|
_selected = std::move(selected);
|
||||||
}
|
}
|
||||||
|
@ -298,7 +317,9 @@ void ToggleChatsController::setupAboveWidget() {
|
||||||
const auto container = wrap.data();
|
const auto container = wrap.data();
|
||||||
|
|
||||||
_addedTopWidget = container->add(object_ptr<Ui::RpWidget>(container));
|
_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 = [&] {
|
const auto totalCount = [&] {
|
||||||
if (_chats.empty()) {
|
if (_chats.empty()) {
|
||||||
return _additional.size();
|
return _additional.size();
|
||||||
|
@ -319,7 +340,7 @@ void ToggleChatsController::setupAboveWidget() {
|
||||||
? _additional.size()
|
? _additional.size()
|
||||||
: _chats.size();
|
: _chats.size();
|
||||||
AddSubsectionTitle(
|
AddSubsectionTitle(
|
||||||
container,
|
realAbove,
|
||||||
(_action == ToggleAction::Removing
|
(_action == ToggleAction::Removing
|
||||||
? tr::lng_filters_by_link_quit
|
? tr::lng_filters_by_link_quit
|
||||||
: _chats.empty()
|
: _chats.empty()
|
||||||
|
@ -329,23 +350,34 @@ void ToggleChatsController::setupAboveWidget() {
|
||||||
rpl::single(float64(count))),
|
rpl::single(float64(count))),
|
||||||
st::filterLinkSubsectionTitlePadding);
|
st::filterLinkSubsectionTitlePadding);
|
||||||
|
|
||||||
|
_aboveHeight = realAbove->heightValue();
|
||||||
delegate()->peerListSetAboveWidget(std::move(wrap));
|
delegate()->peerListSetAboveWidget(std::move(wrap));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleChatsController::setupBelowWidget() {
|
void ToggleChatsController::setupBelowWidget() {
|
||||||
if (_chats.empty()) {
|
if (_chats.empty()) {
|
||||||
|
auto widget = object_ptr<Ui::RpWidget>((QWidget*)nullptr);
|
||||||
|
_addedBottomWidget = widget.data();
|
||||||
|
delegate()->peerListSetBelowWidget(std::move(widget));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delegate()->peerListSetBelowWidget(
|
auto layout = object_ptr<Ui::VerticalLayout>((QWidget*)nullptr);
|
||||||
object_ptr<Ui::DividerLabel>(
|
const auto raw = layout.data();
|
||||||
(QWidget*)nullptr,
|
auto widget = object_ptr<Ui::DividerLabel>(
|
||||||
object_ptr<Ui::FlatLabel>(
|
(QWidget*)nullptr,
|
||||||
(QWidget*)nullptr,
|
std::move(layout),
|
||||||
(_action == ToggleAction::Removing
|
st::settingsDividerLabelPadding);
|
||||||
? tr::lng_filters_by_link_about_quit
|
raw->add(object_ptr<Ui::FlatLabel>(
|
||||||
: tr::lng_filters_by_link_about)(tr::now),
|
raw,
|
||||||
st::boxDividerLabel),
|
(_action == ToggleAction::Removing
|
||||||
st::settingsDividerLabelPadding));
|
? 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 {
|
Main::Session &ToggleChatsController::session() const {
|
||||||
|
@ -357,10 +389,56 @@ auto ToggleChatsController::selectedValue() const
|
||||||
return _selected.value();
|
return _selected.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToggleChatsController::setAddedTopHeight(int addedTopHeight) {
|
void ToggleChatsController::adjust(
|
||||||
|
int minHeight,
|
||||||
|
int maxHeight,
|
||||||
|
int addedTopHeight) {
|
||||||
Expects(addedTopHeight >= 0);
|
Expects(addedTopHeight >= 0);
|
||||||
|
|
||||||
_addedTopWidget->resize(_addedTopWidget->width(), addedTopHeight);
|
_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(
|
void ShowImportError(
|
||||||
|
@ -454,10 +532,12 @@ void ProcessFilterInvite(
|
||||||
) | rpl::map([=](const base::flat_set<not_null<PeerData*>> &peers) {
|
) | rpl::map([=](const base::flat_set<not_null<PeerData*>> &peers) {
|
||||||
return int(peers.size());
|
return int(peers.size());
|
||||||
});
|
});
|
||||||
InitFilterLinkHeader(box, [=](int addedTopHeight) {
|
InitFilterLinkHeader(box, [=](int min, int max, int addedTop) {
|
||||||
raw->setAddedTopHeight(addedTopHeight);
|
raw->adjust(min, max, addedTop);
|
||||||
}, type, title, iconEmoji, rpl::duplicate(badge));
|
}, type, title, iconEmoji, rpl::duplicate(badge));
|
||||||
|
|
||||||
|
raw->setRealContentHeight(box->heightValue());
|
||||||
|
|
||||||
auto owned = Ui::FilterLinkProcessButton(
|
auto owned = Ui::FilterLinkProcessButton(
|
||||||
box,
|
box,
|
||||||
type,
|
type,
|
||||||
|
@ -677,8 +757,8 @@ void ProcessFilterRemove(
|
||||||
) | rpl::map([=](const base::flat_set<not_null<PeerData*>> &peers) {
|
) | rpl::map([=](const base::flat_set<not_null<PeerData*>> &peers) {
|
||||||
return int(peers.size());
|
return int(peers.size());
|
||||||
});
|
});
|
||||||
InitFilterLinkHeader(box, [=](int addedTopHeight) {
|
InitFilterLinkHeader(box, [=](int min, int max, int addedTop) {
|
||||||
raw->setAddedTopHeight(addedTopHeight);
|
raw->adjust(min, max, addedTop);
|
||||||
}, type, title, iconEmoji, rpl::single(0));
|
}, type, title, iconEmoji, rpl::single(0));
|
||||||
|
|
||||||
auto owned = Ui::FilterLinkProcessButton(
|
auto owned = Ui::FilterLinkProcessButton(
|
||||||
|
|
|
@ -217,16 +217,18 @@ Ui::FlatLabel *EditPrivacyBox::addLabel(
|
||||||
if (!text) {
|
if (!text) {
|
||||||
return nullptr;
|
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>(
|
object_ptr<Ui::DividerLabel>(
|
||||||
container,
|
container,
|
||||||
object_ptr<Ui::FlatLabel>(
|
std::move(label),
|
||||||
container,
|
|
||||||
rpl::duplicate(text),
|
|
||||||
st::boxDividerLabel),
|
|
||||||
st::settingsDividerLabelPadding),
|
st::settingsDividerLabelPadding),
|
||||||
{ 0, topSkip, 0, 0 }
|
{ 0, topSkip, 0, 0 });
|
||||||
)->entity();
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ui::FlatLabel *EditPrivacyBox::addLabelOrDivider(
|
Ui::FlatLabel *EditPrivacyBox::addLabelOrDivider(
|
||||||
|
|
|
@ -695,6 +695,7 @@ void LinkController::prepare() {
|
||||||
const auto raw = row.get();
|
const auto raw = row.get();
|
||||||
delegate()->peerListAppendRow(std::move(row));
|
delegate()->peerListAppendRow(std::move(row));
|
||||||
delegate()->peerListSetRowChecked(raw, true);
|
delegate()->peerListSetRowChecked(raw, true);
|
||||||
|
raw->finishCheckedAnimation();
|
||||||
_initial.emplace(peer);
|
_initial.emplace(peer);
|
||||||
}
|
}
|
||||||
for (const auto &history : _filterChats) {
|
for (const auto &history : _filterChats) {
|
||||||
|
|
|
@ -31,9 +31,9 @@ public:
|
||||||
FilterLinkHeaderDescriptor &&descriptor);
|
FilterLinkHeaderDescriptor &&descriptor);
|
||||||
|
|
||||||
void setTitlePosition(int x, int y);
|
void setTitlePosition(int x, int y);
|
||||||
void updateDimensions(int newWidth);
|
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<not_null<QWheelEvent*>> wheelEvents() const;
|
[[nodiscard]] rpl::producer<not_null<QWheelEvent*>> wheelEvents() const;
|
||||||
|
[[nodiscard]] rpl::producer<> closeRequests() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void resizeEvent(QResizeEvent *e) override;
|
void resizeEvent(QResizeEvent *e) override;
|
||||||
|
@ -46,6 +46,7 @@ private:
|
||||||
void refreshTitleText();
|
void refreshTitleText();
|
||||||
|
|
||||||
const not_null<FlatLabel*> _about;
|
const not_null<FlatLabel*> _about;
|
||||||
|
const not_null<IconButton*> _close;
|
||||||
QMargins _aboutPadding;
|
QMargins _aboutPadding;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
@ -176,10 +177,11 @@ Widget::Widget(
|
||||||
not_null<QWidget*> parent,
|
not_null<QWidget*> parent,
|
||||||
FilterLinkHeaderDescriptor &&descriptor)
|
FilterLinkHeaderDescriptor &&descriptor)
|
||||||
: RpWidget(parent)
|
: RpWidget(parent)
|
||||||
, _about(CreateChild<Ui::FlatLabel>(
|
, _about(CreateChild<FlatLabel>(
|
||||||
this,
|
this,
|
||||||
rpl::single(descriptor.about.value()),
|
rpl::single(descriptor.about.value()),
|
||||||
st::filterLinkAbout))
|
st::filterLinkAbout))
|
||||||
|
, _close(CreateChild<IconButton>(this, st::boxTitleClose))
|
||||||
, _aboutPadding(st::boxRowPadding)
|
, _aboutPadding(st::boxRowPadding)
|
||||||
, _badge(std::move(descriptor.badge))
|
, _badge(std::move(descriptor.badge))
|
||||||
, _titleText(descriptor.title)
|
, _titleText(descriptor.title)
|
||||||
|
@ -216,6 +218,10 @@ rpl::producer<not_null<QWheelEvent*>> Widget::wheelEvents() const {
|
||||||
return _wheelEvents.events();
|
return _wheelEvents.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rpl::producer<> Widget::closeRequests() const {
|
||||||
|
return _close->clicks() | rpl::to_empty;
|
||||||
|
}
|
||||||
|
|
||||||
void Widget::resizeEvent(QResizeEvent *e) {
|
void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
const auto &padding = _aboutPadding;
|
const auto &padding = _aboutPadding;
|
||||||
const auto availableWidth = width() - padding.left() - padding.right();
|
const auto availableWidth = width() - padding.left() - padding.right();
|
||||||
|
@ -258,13 +264,15 @@ void Widget::resizeEvent(QResizeEvent *e) {
|
||||||
_about->moveToLeft(_aboutPadding.left(), aboutTop);
|
_about->moveToLeft(_aboutPadding.left(), aboutTop);
|
||||||
_about->setOpacity(_progress.body);
|
_about->setOpacity(_progress.body);
|
||||||
|
|
||||||
|
_close->moveToRight(0, 0);
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRectF Widget::previewRect(
|
QRectF Widget::previewRect(
|
||||||
float64 topProgress,
|
float64 topProgress,
|
||||||
float64 sizeProgress) const {
|
float64 sizeProgress) const {
|
||||||
const auto size = st::filterLinkPreview;
|
const auto size = st::filterLinkPreview * sizeProgress;
|
||||||
return QRectF(
|
return QRectF(
|
||||||
(width() - size) / 2.,
|
(width() - size) / 2.,
|
||||||
st::filterLinkPreviewTop * topProgress,
|
st::filterLinkPreviewTop * topProgress,
|
||||||
|
@ -276,9 +284,6 @@ void Widget::paintEvent(QPaintEvent *e) {
|
||||||
auto p = QPainter(this);
|
auto p = QPainter(this);
|
||||||
|
|
||||||
p.setOpacity(_progress.body);
|
p.setOpacity(_progress.body);
|
||||||
p.translate(_previewRect.center());
|
|
||||||
p.scale(_progress.body, _progress.body);
|
|
||||||
p.translate(-_previewRect.center());
|
|
||||||
if (_progress.top) {
|
if (_progress.top) {
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
if (_preview.isNull()) {
|
if (_preview.isNull()) {
|
||||||
|
@ -327,7 +332,11 @@ void Widget::wheelEvent(QWheelEvent *e) {
|
||||||
const auto result = CreateChild<Widget>(
|
const auto result = CreateChild<Widget>(
|
||||||
parent.get(),
|
parent.get(),
|
||||||
std::move(descriptor));
|
std::move(descriptor));
|
||||||
return { .widget = result, .wheelEvents = result->wheelEvents() };
|
return {
|
||||||
|
.widget = result,
|
||||||
|
.wheelEvents = result->wheelEvents(),
|
||||||
|
.closeRequests = result->closeRequests(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
object_ptr<RoundButton> FilterLinkProcessButton(
|
object_ptr<RoundButton> FilterLinkProcessButton(
|
||||||
|
|
|
@ -34,6 +34,7 @@ struct FilterLinkHeaderDescriptor {
|
||||||
struct FilterLinkHeader {
|
struct FilterLinkHeader {
|
||||||
not_null<RpWidget*> widget;
|
not_null<RpWidget*> widget;
|
||||||
rpl::producer<not_null<QWheelEvent*>> wheelEvents;
|
rpl::producer<not_null<QWheelEvent*>> wheelEvents;
|
||||||
|
rpl::producer<> closeRequests;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] FilterLinkHeader MakeFilterLinkHeader(
|
[[nodiscard]] FilterLinkHeader MakeFilterLinkHeader(
|
||||||
|
|
Loading…
Add table
Reference in a new issue