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/widgets/chat_filters_tabs_slider.h"
#include "ui/effects/ripple_animation.h" #include "ui/effects/ripple_animation.h"
#include "ui/widgets/side_bar_button.h"
#include "styles/style_widgets.h" #include "styles/style_widgets.h"
#include <QScrollBar> #include <QScrollBar>
@ -57,6 +58,7 @@ int ChatsFiltersTabs::centerOfSection(int section) const {
void ChatsFiltersTabs::fitWidthToSections() { void ChatsFiltersTabs::fitWidthToSections() {
const auto widths = countSectionsWidths(0); const auto widths = countSectionsWidths(0);
resizeToWidth(ranges::accumulate(widths, .0)); resizeToWidth(ranges::accumulate(widths, .0));
_lockedFromX = calculateLockedFromX();
} }
void ChatsFiltersTabs::setUnreadCount(int index, int unreadCount) { 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 { QImage ChatsFiltersTabs::cacheUnreadCount(int count) const {
const auto widthIndex = (count < 10) ? 0 : (count < 100) ? 1 : 2; const auto widthIndex = (count < 10) ? 0 : (count < 100) ? 1 : 2;
auto image = QImage( auto image = QImage(
@ -144,6 +177,11 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
section.contentWidth, section.contentWidth,
_st.labelStyle.font->height); _st.labelStyle.font->height);
if (rect.intersects(clip)) { 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)); p.setPen(anim::pen(_st.labelFg, _st.labelFgActive, active));
section.label.draw(p, { section.label.draw(p, {
.position = QPoint(labelLeft, _st.labelTop), .position = QPoint(labelLeft, _st.labelTop),
@ -161,6 +199,18 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
it->second.cache); 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++; index++;
return true; return true;
@ -188,14 +238,36 @@ void ChatsFiltersTabs::paintEvent(QPaintEvent *e) {
void ChatsFiltersTabs::mousePressEvent(QMouseEvent *e) { void ChatsFiltersTabs::mousePressEvent(QMouseEvent *e) {
const auto mouseButton = e->button(); const auto mouseButton = e->button();
if (mouseButton == Qt::MouseButton::LeftButton) { 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 { } else {
Ui::RpWidget::mousePressEvent(e); 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) { void ChatsFiltersTabs::contextMenuEvent(QContextMenuEvent *e) {
const auto pos = e->pos(); const auto pos = e->pos();
if (pos.x() >= _lockedFromX) {
return;
}
auto left = 0; auto left = 0;
auto index = 0; auto index = 0;
enumerateSections([&](const Section &section) { enumerateSections([&](const Section &section) {
@ -214,4 +286,8 @@ rpl::producer<int> ChatsFiltersTabs::contextMenuRequested() const {
return _contextMenuRequested.events(); return _contextMenuRequested.events();
} }
rpl::producer<> ChatsFiltersTabs::lockedClicked() const {
return _lockedClicked.events();
}
} // namespace Ui } // namespace Ui

View file

@ -28,16 +28,20 @@ public:
[[nodiscard]] int centerOfSection(int section) const; [[nodiscard]] int centerOfSection(int section) const;
void fitWidthToSections(); void fitWidthToSections();
void setUnreadCount(int index, int unreadCount); void setUnreadCount(int index, int unreadCount);
void setLockedFrom(int index);
[[nodiscard]] rpl::producer<int> contextMenuRequested() const; [[nodiscard]] rpl::producer<int> contextMenuRequested() const;
[[nodiscard]] rpl::producer<> lockedClicked() const;
protected: protected:
void paintEvent(QPaintEvent *e) override; void paintEvent(QPaintEvent *e) override;
void mousePressEvent(QMouseEvent *e) override; void mousePressEvent(QMouseEvent *e) override;
void mouseReleaseEvent(QMouseEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override; void contextMenuEvent(QContextMenuEvent *e) override;
private: private:
[[nodiscard]] QImage cacheUnreadCount(int count) const; [[nodiscard]] QImage cacheUnreadCount(int count) const;
[[nodiscard]] int calculateLockedFromX() const;
using Index = int; using Index = int;
struct Unread final { struct Unread final {
@ -51,10 +55,16 @@ private:
const int _unreadSkip; const int _unreadSkip;
std::vector<int> _cachedBadgeWidths; std::vector<int> _cachedBadgeWidths;
int _cachedBadgeHeight = 0; int _cachedBadgeHeight = 0;
int _lockedFrom = 0;
int _lockedFromX = 0;
bool _lockedPressed = false;
std::optional<Ui::RoundRect> _bar; std::optional<Ui::RoundRect> _bar;
std::optional<Ui::RoundRect> _barActive; std::optional<Ui::RoundRect> _barActive;
std::optional<QImage> _lockCache;
rpl::lifetime _paletteLifetime;
rpl::event_stream<int> _contextMenuRequested; 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 "api/api_chat_filters_remove_manager.h"
#include "boxes/filters/edit_filter_box.h" #include "boxes/filters/edit_filter_box.h"
#include "boxes/premium_limits_box.h"
#include "core/application.h" #include "core/application.h"
#include "data/data_chat_filters.h" #include "data/data_chat_filters.h"
#include "data/data_premium_limits.h"
#include "data/data_session.h" #include "data/data_session.h"
#include "data/data_unread_value.h" #include "data/data_unread_value.h"
#include "data/data_user.h"
#include "lang/lang_keys.h" #include "lang/lang_keys.h"
#include "main/main_session.h" #include "main/main_session.h"
#include "settings/settings_folders.h" #include "settings/settings_folders.h"
@ -205,6 +208,18 @@ not_null<Ui::RpWidget*> AddChatFiltersTabsStrip(
}) | ranges::to_vector; }) | ranges::to_vector;
slider->setSections(std::move(sections)); slider->setSections(std::move(sections));
slider->fitWidthToSections(); 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(); auto includeMuted = Data::IncludeMutedCounterFoldersValue();
state->unreadLifetime.destroy(); state->unreadLifetime.destroy();