From f4523b2dbaf2ae72e3f78cc4c87f0d9edb83be57 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Tue, 19 Nov 2024 12:15:05 +0300 Subject: [PATCH] Added initial implementation of filter tags to dialog rows. --- .../dialogs/dialogs_inner_widget.cpp | 113 ++++++++++++++++++ .../dialogs/dialogs_inner_widget.h | 3 + .../SourceFiles/dialogs/ui/dialogs_layout.cpp | 11 +- .../SourceFiles/dialogs/ui/dialogs_layout.h | 1 + 4 files changed, 127 insertions(+), 1 deletion(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 585f72aa8..6012f9d73 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -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(); + 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; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index a284cca11..dc316c2c1 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -448,6 +448,8 @@ private: void saveChatsFilterScrollState(FilterId filterId); void restoreChatsFilterScrollState(FilterId filterId); + [[nodiscard]] QImage *cacheChatsFilterTag(FilterId filterId, ushort more); + const not_null _controller; not_null _shownList; @@ -554,6 +556,7 @@ private: base::flat_map _chatsFilterScrollStates; + std::unordered_map _chatsFilterTags; Fn _loadMoreCallback; Fn _loadMoreFilteredCallback; rpl::event_stream<> _listBottomReached; diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 74ef86948..1a7b5a1ac 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -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 diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h index cc67307d5..5e51c8e73 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.h @@ -53,6 +53,7 @@ struct TopicJumpCache { }; struct PaintContext { + std::vector *chatsFilterTags = nullptr; not_null st; TopicJumpCache *topicJumpCache = nullptr; Data::Folder *folder = nullptr;