Added support of locked sections to chats filters tabs slider.

This commit is contained in:
23rd 2024-11-03 12:50:21 +03:00
parent dc49c788a8
commit 4d9112283d
3 changed files with 102 additions and 1 deletions

View file

@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/widgets/chat_filters_tabs_slider.h"
#include "ui/effects/ripple_animation.h"
#include "ui/widgets/side_bar_button.h"
#include "styles/style_widgets.h"
#include <QScrollBar>
@ -57,6 +58,7 @@ int ChatsFiltersTabs::centerOfSection(int section) const {
void ChatsFiltersTabs::fitWidthToSections() {
const auto widths = countSectionsWidths(0);
resizeToWidth(ranges::accumulate(widths, .0));
_lockedFromX = calculateLockedFromX();
}
void ChatsFiltersTabs::setUnreadCount(int index, int unreadCount) {
@ -90,6 +92,37 @@ void ChatsFiltersTabs::setUnreadCount(int index, int unreadCount) {
}
}
int ChatsFiltersTabs::calculateLockedFromX() const {
if (!_lockedFrom) {
return std::numeric_limits<int>::max();
}
auto left = 0;
auto index = 0;
enumerateSections([&](const Section &section) {
const auto currentRight = section.left + section.width;
if (index == _lockedFrom) {
return false;
}
left = currentRight;
index++;
return true;
});
return left ? left : std::numeric_limits<int>::max();
}
void ChatsFiltersTabs::setLockedFrom(int index) {
_lockedFrom = index;
_lockedFromX = calculateLockedFromX();
if (!index) {
_paletteLifetime.destroy();
return;
}
_paletteLifetime = style::PaletteChanged(
) | rpl::start_with_next([this] {
_lockCache.emplace(Ui::SideBarLockIcon(_st.labelFg));
});
}
QImage ChatsFiltersTabs::cacheUnreadCount(int count) const {
const auto widthIndex = (count < 10) ? 0 : (count < 100) ? 1 : 2;
auto image = QImage(
@ -144,6 +177,11 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
section.contentWidth,
_st.labelStyle.font->height);
if (rect.intersects(clip)) {
const auto locked = (_lockedFrom && (index >= _lockedFrom));
if (locked) {
constexpr auto kPremiumLockedOpacity = 0.6;
p.setOpacity(kPremiumLockedOpacity);
}
p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
section.label.draw(p, {
.position = QPoint(labelLeft, _st.labelTop),
@ -161,6 +199,18 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
it->second.cache);
}
}
if (locked) {
if (!_lockCache) {
_lockCache.emplace(Ui::SideBarLockIcon(_st.labelFg));
}
const auto size = _lockCache->size()
/ style::DevicePixelRatio();
p.drawImage(
labelLeft + (section.label.maxWidth() - size.width()) / 2,
height() - size.height() - st::lineWidth,
*_lockCache);
p.setOpacity(1.0);
}
}
index++;
return true;
@ -188,14 +238,36 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
void ChatsFiltersTabs::mousePressEvent(QMouseEvent *e) {
const auto mouseButton = e->button();
if (mouseButton == Qt::MouseButton::LeftButton) {
Ui::SettingsSlider::mousePressEvent(e);
_lockedPressed = (e->pos().x() >= _lockedFromX);
if (_lockedPressed) {
Ui::RpWidget::mousePressEvent(e);
} else {
Ui::SettingsSlider::mousePressEvent(e);
}
} else {
Ui::RpWidget::mousePressEvent(e);
}
}
void ChatsFiltersTabs::mouseReleaseEvent(QMouseEvent *e) {
const auto mouseButton = e->button();
if (mouseButton == Qt::MouseButton::LeftButton) {
if (base::take(_lockedPressed)) {
_lockedPressed = false;
_lockedClicked.fire({});
} else {
Ui::SettingsSlider::mouseReleaseEvent(e);
}
} else {
Ui::RpWidget::mouseReleaseEvent(e);
}
}
void ChatsFiltersTabs::contextMenuEvent(QContextMenuEvent *e) {
const auto pos = e->pos();
if (pos.x() >= _lockedFromX) {
return;
}
auto left = 0;
auto index = 0;
enumerateSections([&](const Section &section) {
@ -214,4 +286,8 @@ rpl::producer<int> ChatsFiltersTabs::contextMenuRequested() const {
return _contextMenuRequested.events();
}
rpl::producer<> ChatsFiltersTabs::lockedClicked() const {
return _lockedClicked.events();
}
} // namespace Ui

View file

@ -28,16 +28,20 @@ public:
[[nodiscard]] int centerOfSection(int section) const;
void fitWidthToSections();
void setUnreadCount(int index, int unreadCount);
void setLockedFrom(int index);
[[nodiscard]] rpl::producer<int> contextMenuRequested() const;
[[nodiscard]] rpl::producer<> lockedClicked() const;
protected:
void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override;
private:
[[nodiscard]] QImage cacheUnreadCount(int count) const;
[[nodiscard]] int calculateLockedFromX() const;
using Index = int;
struct Unread final {
@ -51,10 +55,16 @@ private:
const int _unreadSkip;
std::vector<int> _cachedBadgeWidths;
int _cachedBadgeHeight = 0;
int _lockedFrom = 0;
int _lockedFromX = 0;
bool _lockedPressed = false;
std::optional<Ui::RoundRect> _bar;
std::optional<Ui::RoundRect> _barActive;
std::optional<QImage> _lockCache;
rpl::lifetime _paletteLifetime;
rpl::event_stream<int> _contextMenuRequested;
rpl::event_stream<> _lockedClicked;
};

View file

@ -9,10 +9,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "api/api_chat_filters_remove_manager.h"
#include "boxes/filters/edit_filter_box.h"
#include "boxes/premium_limits_box.h"
#include "core/application.h"
#include "data/data_chat_filters.h"
#include "data/data_premium_limits.h"
#include "data/data_session.h"
#include "data/data_unread_value.h"
#include "data/data_user.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "settings/settings_folders.h"
@ -205,6 +208,18 @@ not_null<Ui::RpWidget*> AddChatFiltersTabsStrip(
}) | ranges::to_vector;
slider->setSections(std::move(sections));
slider->fitWidthToSections();
{
const auto reorderAll = session->user()->isPremium();
const auto maxLimit = (reorderAll ? 1 : 0)
+ Data::PremiumLimits(session).dialogFiltersCurrent();
const auto premiumFrom = (reorderAll ? 0 : 1) + maxLimit;
slider->setLockedFrom((premiumFrom >= list.size())
? 0
: premiumFrom);
slider->lockedClicked() | rpl::start_with_next([=] {
controller->show(Box(FiltersLimitBox, session, std::nullopt));
}, slider->lifetime());
}
{
auto includeMuted = Data::IncludeMutedCounterFoldersValue();
state->unreadLifetime.destroy();