Added initial implementation of filter tags to dialog rows.

This commit is contained in:
23rd 2024-11-19 12:15:05 +03:00
parent 0d58b32914
commit f4523b2dba
4 changed files with 127 additions and 1 deletions

View file

@ -73,6 +73,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "styles/style_dialogs.h"
#include "styles/style_chat.h" // popupMenuExpandedSeparator
#include "styles/style_chat_helpers.h"
#include "styles/style_color_indices.h"
#include "styles/style_window.h"
#include "styles/style_menu_icons.h"
@ -702,6 +703,62 @@ void InnerWidget::paintEvent(QPaintEvent *e) {
&& (key.history()->peer->id == childListShown.peerId);
context.st = (forum ? &st::forumDialogRow : _st.get());
auto chatsFilterTags = std::vector<QImage*>();
if (context.narrow) {
context.chatsFilterTags = nullptr;
} else if (row->entry()->hasChatsFilterTags(context.filter)) {
context.st = forum
? &st::taggedForumDialogRow
: &st::taggedDialogRow;
auto availableWidth = context.width
- context.st->padding.right()
- st::dialogsUnreadPadding
- context.st->nameLeft;
auto more = ushort(0);
const auto &list = session().data().chatsFilters().list();
for (const auto &filter : list) {
if (!row->entry()->inChatList(filter.id())
|| (filter.id() == context.filter)) {
continue;
}
if (const auto tag = cacheChatsFilterTag(filter.id(), 0)) {
if (more) {
more++;
continue;
}
const auto tagWidth = tag->width()
/ style::DevicePixelRatio();
if (availableWidth < tagWidth) {
more++;
} else {
chatsFilterTags.push_back(tag);
availableWidth -= tagWidth
+ st::dialogRowFilterTagSkip;
}
}
}
if (more) {
if (const auto tag = cacheChatsFilterTag(0, more)) {
const auto tagWidth = tag->width()
/ style::DevicePixelRatio();
if (availableWidth < tagWidth) {
more++;
if (const auto tag = cacheChatsFilterTag(0, more)) {
if (!chatsFilterTags.empty()) {
chatsFilterTags.back() = tag;
}
}
} else {
chatsFilterTags.push_back(tag);
}
}
}
context.chatsFilterTags = &chatsFilterTags;
} else {
context.chatsFilterTags = nullptr;
}
context.topicsExpanded = (expanding && !active)
? childListShown.shown
: 0.;
@ -3943,6 +4000,62 @@ void InnerWidget::restoreChatsFilterScrollState(FilterId filterId) {
}
}
QImage *InnerWidget::cacheChatsFilterTag(FilterId filterId, ushort more) {
if (!filterId && !more) {
return nullptr;
}
const auto key = filterId ? filterId : -more;
{
const auto it = _chatsFilterTags.find(key);
if (it != end(_chatsFilterTags)) {
return &it->second;
}
}
auto roundedText = QString();
auto colorIndex = -1;
if (filterId) {
const auto &list = session().data().chatsFilters().list();
const auto it = ranges::find(list, filterId, &Data::ChatFilter::id);
if (it != end(list)) {
roundedText = it->title().toUpper();
if (it->colorIndex()) {
colorIndex = *it->colorIndex();
}
}
} else if (more > 0) {
roundedText = QChar('+') + QString::number(more);
colorIndex = st::colorIndexBlue;
}
if (roundedText.isEmpty() || colorIndex < 0) {
return nullptr;
}
const auto &roundedFont = st::dialogRowFilterTagFont;
const auto roundedWidth = roundedFont->width(roundedText)
+ roundedFont->spacew * 3;
const auto rect = QRect(0, 0, roundedWidth, roundedFont->height);
auto cache = QImage(
rect.size() * style::DevicePixelRatio(),
QImage::Format_ARGB32_Premultiplied);
cache.setDevicePixelRatio(style::DevicePixelRatio());
cache.fill(Qt::transparent);
{
auto p = QPainter(&cache);
const auto pen = QPen(
Ui::EmptyUserpic::UserpicColor(colorIndex).color2);
p.setPen(Qt::NoPen);
p.setBrush(anim::with_alpha(pen.color(), .15));
{
auto hq = PainterHighQualityEnabler(p);
const auto radius = roundedFont->height / 3.;
p.drawRoundedRect(rect, radius, radius);
}
p.setPen(pen);
p.setFont(roundedFont);
p.drawText(rect, roundedText, style::al_center);
}
return &_chatsFilterTags.emplace(key, std::move(cache)).first->second;
}
bool InnerWidget::chooseHashtag() {
if (_state != WidgetState::Filtered) {
return false;

View file

@ -448,6 +448,8 @@ private:
void saveChatsFilterScrollState(FilterId filterId);
void restoreChatsFilterScrollState(FilterId filterId);
[[nodiscard]] QImage *cacheChatsFilterTag(FilterId filterId, ushort more);
const not_null<Window::SessionController*> _controller;
not_null<IndexedList*> _shownList;
@ -554,6 +556,7 @@ private:
base::flat_map<FilterId, int> _chatsFilterScrollStates;
std::unordered_map<FilterId, QImage> _chatsFilterTags;
Fn<void()> _loadMoreCallback;
Fn<void()> _loadMoreFilteredCallback;
rpl::event_stream<> _listBottomReached;

View file

@ -344,7 +344,7 @@ void PaintRow(
row->paintUserpic(p, entry, from, videoUserpic, context);
}
auto nameleft = context.st->nameLeft;
const auto nameleft = context.st->nameLeft;
if (context.topicsExpanded > 0.) {
PaintExpandedTopicsBar(p, context.topicsExpanded);
}
@ -712,6 +712,15 @@ void PaintRow(
.elisionLines = 1,
});
}
if (const auto tags = context.chatsFilterTags) {
auto left = nameleft;
for (const auto &tag : *tags) {
p.drawImage(left, context.st->tagTop, *tag);
left += st::dialogRowFilterTagSkip
+ (tag->width() / style::DevicePixelRatio());
}
}
}
} // namespace

View file

@ -53,6 +53,7 @@ struct TopicJumpCache {
};
struct PaintContext {
std::vector<QImage*> *chatsFilterTags = nullptr;
not_null<const style::DialogRow*> st;
TopicJumpCache *topicJumpCache = nullptr;
Data::Folder *folder = nullptr;