diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index 7c02bbb82f..30074e053b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -201,6 +201,7 @@ dialogsTTLBadgeSize: 20px; dialogsTTLBadgeInnerMargins: margins(2px, 2px, 2px, 2px); // Relative to a photo place, not a whole userpic place. dialogsTTLBadgeSkip: point(1px, 1px); +dialogsCommunityHiddenBadgeIcon: icon{{ "community/requests_hidden", premiumButtonFg }}; dialogsSpeakingStrokeNumerator: 16px; dialogsSpeakingDenominator: 8.; @@ -704,13 +705,6 @@ dialogsMuteIcon: ThreeStateIcon { } dialogsMuteIconSkip: 4px; -dialogsCommunityHiddenIcon: ThreeStateIcon { - icon: icon{{ "community/requests_hidden", dialogsTextFg }}; - over: icon{{ "community/requests_hidden", dialogsTextFgOver }}; - active: icon{{ "community/requests_hidden", dialogsTextFgActive }}; -} -dialogsCommunityHiddenIconSkip: 4px; - downloadBarHeight: 46px; downloadArrow: icon{{ "fast_to_original", menuIconFg }}; downloadArrowOver: icon{{ "fast_to_original", menuIconFgOver }}; diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 1b377e9d3f..70a1c7e473 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -41,7 +41,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL namespace Dialogs { namespace { -constexpr auto kTopLayer = 2; +constexpr auto kTopLayer = 3; +constexpr auto kHiddenLayer = 2; constexpr auto kBottomLayer = 1; constexpr auto kNoneLayer = 0; constexpr auto kBlurRadius = 24; @@ -142,6 +143,32 @@ constexpr auto kBlurRadius = 24; return result; } +[[nodiscard]] QImage CornerBadgeHidden( + not_null peer, + Ui::PeerUserpicView &view, + int photoSize) { + const auto ratio = style::DevicePixelRatio(); + const auto fullSize = photoSize; + const auto partRect = CornerBadgeTTLRect(fullSize); + const auto &partSize = partRect.width(); + const auto partSkip = fullSize - partSize; + auto result = Images::Circle(BlurredDarkenedPart( + PeerData::GenerateUserpicImage(peer, view, fullSize * ratio, 0), + QRect( + QPoint(partSkip, partSkip) * ratio, + QSize(partSize, partSize) * ratio))); + result.setDevicePixelRatio(ratio); + + auto q = QPainter(&result); + PainterHighQualityEnabler hq(q); + + const auto innerRect = QRect(QPoint(), partRect.size()) + - st::dialogsTTLBadgeInnerMargins; + st::dialogsCommunityHiddenBadgeIcon.paintInCenter(q, innerRect); + + return result; +} + } // namespace QRect CornerBadgeTTLRect(int photoSize) { @@ -360,7 +387,8 @@ void Row::updateCornerBadgeShown( not_null peer, Fn updateCallback, bool hasUnreadBadgesAbove, - bool insideCommunity) const { + bool insideCommunity, + bool hidden) const { const auto user = peer->asUser(); const auto now = user ? base::unixtime::now() : TimeId(); const auto channel = user ? nullptr : peer->asChannel(); @@ -374,6 +402,8 @@ void Row::updateCornerBadgeShown( || Data::ChannelHasSubscriptionUntilDate(channel) || (!insideCommunity && channel->linkedCommunityId()))) { return kTopLayer; + } else if (hidden) { + return kHiddenLayer; } else if (peer->messagesTTL()) { return kBottomLayer; } @@ -401,7 +431,8 @@ void Row::PaintCornerBadgeFrame( Ui::PeerUserpicView &view, const Ui::PaintContext &context, bool subscribed, - bool communityMember) { + bool communityMember, + bool hidden) { data->frame.fill(Qt::transparent); Painter q(&data->frame); @@ -537,6 +568,27 @@ void Row::PaintCornerBadgeFrame( q.drawImage(point, data->cacheTTL); q.setOpacity(1.); } + if (const auto p = manager.progressForLayer(kHiddenLayer); p > 0.) { + if (data->cacheHidden.isNull() && peer && hidden) { + data->cacheHidden = CornerBadgeHidden(peer, view, photoSize); + } + if (!data->cacheHidden.isNull()) { + const auto rect = CornerBadgeTTLRect(photoSize); + q.setOpacity(p); + q.drawImage(rect.topLeft(), data->cacheHidden); + q.setOpacity(1.); + if (!hq) { + hq.emplace(q); + } + q.setCompositionMode(QPainter::CompositionMode_Source); + auto pen = QPen(Qt::transparent); + pen.setWidthF(st::dialogsOnlineBadgeStroke * p); + q.setPen(pen); + q.setBrush(Qt::NoBrush); + q.drawEllipse(QRectF(rect)); + q.setCompositionMode(QPainter::CompositionMode_SourceOver); + } + } const auto topLayerProgress = manager.progressForLayer(kTopLayer); if (!topLayerProgress) { return; @@ -595,12 +647,16 @@ void Row::paintUserpic( _communityUserpicEffect = nullptr; } const auto insideCommunity = context.insideCommunity; + const auto hidden = peer + && context.community + && context.community->isHidden(peer); if (peer) { updateCornerBadgeShown( peer, nullptr, hasUnreadBadgesAbove, - insideCommunity); + insideCommunity, + hidden); } const auto cornerBadgeShown = !_cornerBadgeUserpic @@ -672,6 +728,7 @@ void Row::paintUserpic( || (_cornerBadgeUserpic->paletteVersion != paletteVersion); if (keyChanged) { _cornerBadgeUserpic->cacheTTL = QImage(); + _cornerBadgeUserpic->cacheHidden = QImage(); } const auto badgeChannel = peer ? peer->asChannel() : nullptr; const auto subscribed = Data::ChannelHasSubscriptionUntilDate( @@ -684,6 +741,7 @@ void Row::paintUserpic( if (keyChanged || !_cornerBadgeUserpic->layersManager.isFinished() || _cornerBadgeUserpic->active != active + || _cornerBadgeUserpic->hidden != (hidden ? 1 : 0) || _cornerBadgeUserpic->frameIndex != frameIndex || _cornerBadgeUserpic->storiesCount != storiesCount || _cornerBadgeUserpic->storiesUnreadCount != storiesUnreadCount @@ -692,6 +750,7 @@ void Row::paintUserpic( _cornerBadgeUserpic->key = key; _cornerBadgeUserpic->paletteVersion = paletteVersion; _cornerBadgeUserpic->active = active; + _cornerBadgeUserpic->hidden = hidden ? 1 : 0; _cornerBadgeUserpic->storiesCount = storiesCount; _cornerBadgeUserpic->storiesUnreadCount = storiesUnreadCount; _cornerBadgeUserpic->storiesHasVideoStream = storiesHasVideoStream; @@ -706,7 +765,8 @@ void Row::paintUserpic( userpicView(), context, subscribed, - communityMember); + communityMember, + hidden); } p.drawImage( context.st->padding.left() - framePadding, @@ -716,7 +776,8 @@ void Row::paintUserpic( if (!history || history->peer->isUser() || subscribed - || communityMember) { + || communityMember + || hidden) { return; } const auto actionPainter = history->sendActionPainter(); diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index 9e0f07329b..ae6a407397 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -106,7 +106,8 @@ public: not_null peer, Fn updateCallback = nullptr, bool hasUnreadBadgesAbove = false, - bool insideCommunity = false) const; + bool insideCommunity = false, + bool hidden = false) const; void paintUserpic( Painter &p, not_null entry, @@ -183,12 +184,14 @@ private: CornerLayersManager layersManager; QImage frame; QImage cacheTTL; + QImage cacheHidden; int frameIndex = -1; uint32 paletteVersion : 16 = 0; - uint32 storiesCount : 7 = 0; - uint32 storiesUnreadCount : 7 = 0; + uint32 storiesCount : 6 = 0; + uint32 storiesUnreadCount : 6 = 0; uint32 storiesHasVideoStream : 1 = 0; uint32 active : 1 = 0; + uint32 hidden : 1 = 0; }; void setCornerBadgeShown( @@ -204,7 +207,8 @@ private: Ui::PeerUserpicView &view, const Ui::PaintContext &context, bool subscribed, - bool communityMember); + bool communityMember, + bool hidden); Key _id; mutable std::unique_ptr _cornerBadgeUserpic; diff --git a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp index 83e0f89545..f5029df3a7 100644 --- a/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/ui/dialogs_layout.cpp @@ -938,21 +938,9 @@ void PaintRow( paintPeerBadge(rowName.maxWidth()); badgeWidth = widthBefore - rectForName.width(); } - const auto hidden = context.community - && context.community->isHidden(from); const auto drawMuteIcon = DialogsMuteIcon.value() && thread && thread->muted(); - if (hidden) { - const auto &icon = ThreeStateIcon( - st::dialogsCommunityHiddenIcon, - context.active, - context.selected); - rectForName.setWidth( - rectForName.width() - - icon.width() - - st::dialogsCommunityHiddenIconSkip); - } if (drawMuteIcon) { const auto &muteIcon = ThreeStateIcon( st::dialogsMuteIcon, @@ -973,41 +961,17 @@ void PaintRow( .availableWidth = rectForName.width(), .elisionLines = 1, }); - if (hidden) { - const auto &icon = ThreeStateIcon( - st::dialogsCommunityHiddenIcon, - context.active, - context.selected); - const auto nameW = std::min( - rowName.maxWidth(), - rectForName.width()); - const auto glyphLeft = rectForName.left() - + nameW - + badgeWidth - + st::dialogsCommunityHiddenIconSkip; - const auto glyphTop = rectForName.top() - + (st::semiboldFont->height - icon.height()) / 2; - icon.paint(p, glyphLeft, glyphTop, context.width); - } if (drawMuteIcon) { const auto &muteIcon = ThreeStateIcon( st::dialogsMuteIcon, context.active, context.selected); - const auto hiddenWidth = hidden - ? (ThreeStateIcon( - st::dialogsCommunityHiddenIcon, - context.active, - context.selected).width() - + st::dialogsCommunityHiddenIconSkip) - : 0; const auto nameW = std::min( rowName.maxWidth(), rectForName.width()); const auto muteLeft = rectForName.left() + nameW + badgeWidth - + hiddenWidth + st::dialogsMuteIconSkip; const auto muteTop = rectForName.top() + (st::semiboldFont->height - muteIcon.height()) / 2;