From 8bd64c62c2a266f426c4ea3ca184011eecddb4d7 Mon Sep 17 00:00:00 2001 From: AlexeyZavar Date: Mon, 2 Mar 2026 20:24:36 +0300 Subject: [PATCH] fix: telegram avatar rounding & ttl badge position & calls speak animation --- Telegram/SourceFiles/ayu/ayu_settings.cpp | 2 +- Telegram/SourceFiles/ayu/ui/ayu_userpic.cpp | 27 ++++++++++--------- Telegram/SourceFiles/ayu/ui/ayu_userpic.h | 4 +-- .../ayu/ui/settings/settings_appearance.cpp | 6 ++--- Telegram/SourceFiles/ayu/utils/rc_manager.cpp | 2 +- Telegram/SourceFiles/calls/calls_userpic.cpp | 23 +++++++++++----- .../calls/group/calls_group_members_row.cpp | 27 ++++++++++++++++++- Telegram/SourceFiles/data/data_peer.cpp | 2 +- Telegram/SourceFiles/dialogs/dialogs_row.cpp | 10 +++---- .../dialogs/ui/top_peers_strip.cpp | 2 +- .../peer_gifts/info_peer_gifts_common.cpp | 2 +- Telegram/lib_ui | 2 +- 12 files changed, 73 insertions(+), 36 deletions(-) diff --git a/Telegram/SourceFiles/ayu/ayu_settings.cpp b/Telegram/SourceFiles/ayu/ayu_settings.cpp index 4f438a9e5f..63efa2b33e 100644 --- a/Telegram/SourceFiles/ayu/ayu_settings.cpp +++ b/Telegram/SourceFiles/ayu/ayu_settings.cpp @@ -467,7 +467,7 @@ void AyuSettings::validate() { validateRange(_wideMultiplier, 0.5, 4.0, defaults._wideMultiplier); validateRange(_recentStickersCount, 1, 200, defaults._recentStickersCount); - validateRange(_avatarCorners, 0, AyuUserpic::kMaxAvatarCorners, defaults._avatarCorners); + validateRange(_avatarCorners, 0, AyuUiSettings::kMaxAvatarCorners, defaults._avatarCorners); const auto embeddedType = _messageShotSettings._embeddedThemeType.current(); auto embeddedTypeValid = (embeddedType == -1) || (embeddedType >= 0 && embeddedType <= 3); // from Window::Theme::EmbeddedType::DayBlue to Window::Theme::EmbeddedType::NightGreen diff --git a/Telegram/SourceFiles/ayu/ui/ayu_userpic.cpp b/Telegram/SourceFiles/ayu/ui/ayu_userpic.cpp index f5e385d07e..a504deda97 100644 --- a/Telegram/SourceFiles/ayu/ui/ayu_userpic.cpp +++ b/Telegram/SourceFiles/ayu/ui/ayu_userpic.cpp @@ -31,20 +31,20 @@ bool ShouldOverrideShape(Ui::PeerUserpicShape shape) { int ComputeRadius(int pixelSize) { const auto corners = AyuUiSettings::getAvatarCorners(); - if (corners >= kMaxAvatarCorners) return pixelSize / 2; + if (corners >= AyuUiSettings::kMaxAvatarCorners) return pixelSize / 2; if (corners <= 0) return 0; - return int(double(corners) / kMaxAvatarCorners * pixelSize / 2.0); + return int(double(corners) / AyuUiSettings::kMaxAvatarCorners * pixelSize / 2.0); } double ComputeRadiusF(double size) { const auto corners = AyuUiSettings::getAvatarCorners(); - if (corners >= kMaxAvatarCorners) return size / 2.0; + if (corners >= AyuUiSettings::kMaxAvatarCorners) return size / 2.0; if (corners <= 0) return 0.0; - return double(corners) / kMaxAvatarCorners * size / 2.0; + return double(corners) / AyuUiSettings::kMaxAvatarCorners * size / 2.0; } bool IsCircle() { - return AyuUiSettings::getAvatarCorners() >= kMaxAvatarCorners; + return AyuUiSettings::getAvatarCorners() >= AyuUiSettings::kMaxAvatarCorners; } uint8 PackedState() { @@ -54,34 +54,37 @@ uint8 PackedState() { void PaintShape(QPainter &p, int x, int y, int size) { const auto corners = AyuUiSettings::getAvatarCorners(); - if (corners >= kMaxAvatarCorners) { + if (corners >= AyuUiSettings::kMaxAvatarCorners) { p.drawEllipse(x, y, size, size); } else if (corners <= 0) { p.drawRect(x, y, size, size); } else { - const auto r = double(corners) / kMaxAvatarCorners * size / 2.0; + const auto r = double(corners) / AyuUiSettings::kMaxAvatarCorners * size / 2.0; p.drawRoundedRect(x, y, size, size, r, r); } } void PaintShape(QPainter &p, const QRectF &rect) { const auto corners = AyuUiSettings::getAvatarCorners(); - if (corners >= kMaxAvatarCorners) { + if (corners >= AyuUiSettings::kMaxAvatarCorners) { p.drawEllipse(rect); } else if (corners <= 0) { p.drawRect(rect); } else { - const auto r = double(corners) / kMaxAvatarCorners + const auto r = double(corners) / AyuUiSettings::kMaxAvatarCorners * std::min(rect.width(), rect.height()) / 2.0; p.drawRoundedRect(rect, r, r); } } -QPointF OnlineBadgePosition(int photoSize, double badgeSize) { +QPointF OnlineBadgePosition(int photoSize, double badgeSize, double stroke) { const auto corners = AyuUiSettings::getAvatarCorners(); - const auto r = double(corners) / kMaxAvatarCorners * photoSize / 2.0; + const auto r = double(corners) / AyuUiSettings::kMaxAvatarCorners * photoSize / 2.0; const auto edge = photoSize - r * (1.0 - std::cos(M_PI / 4.0)); - const auto pos = std::min(edge - badgeSize / 2.0, photoSize - badgeSize); + const auto maxPos = (stroke > 0) + ? photoSize - badgeSize / 2.0 - (badgeSize / 2.0 + stroke / 2.0) / std::sqrt(2.0) + : double(photoSize) - badgeSize; + const auto pos = std::min(edge - badgeSize / 2.0, maxPos); return QPointF(pos, pos); } diff --git a/Telegram/SourceFiles/ayu/ui/ayu_userpic.h b/Telegram/SourceFiles/ayu/ui/ayu_userpic.h index 2db137e74c..7006e2937b 100644 --- a/Telegram/SourceFiles/ayu/ui/ayu_userpic.h +++ b/Telegram/SourceFiles/ayu/ui/ayu_userpic.h @@ -12,8 +12,6 @@ namespace Media::Streaming { struct FrameRequest; } namespace AyuUserpic { -inline constexpr int kMaxAvatarCorners = 23; - [[nodiscard]] bool ShouldOverrideShape(Ui::PeerUserpicShape shape); [[nodiscard]] int ComputeRadius(int pixelSize); [[nodiscard]] double ComputeRadiusF(double size); @@ -24,7 +22,7 @@ inline constexpr int kMaxAvatarCorners = 23; void PaintShape(QPainter &p, int x, int y, int size); void PaintShape(QPainter &p, const QRectF &rect); -[[nodiscard]] QPointF OnlineBadgePosition(int photoSize, double badgeSize); +[[nodiscard]] QPointF OnlineBadgePosition(int photoSize, double badgeSize, double stroke = 0); void ApplyFrameRounding( ::Media::Streaming::FrameRequest &request, diff --git a/Telegram/SourceFiles/ayu/ui/settings/settings_appearance.cpp b/Telegram/SourceFiles/ayu/ui/settings/settings_appearance.cpp index 4ce914ca13..4dddbd68dc 100644 --- a/Telegram/SourceFiles/ayu/ui/settings/settings_appearance.cpp +++ b/Telegram/SourceFiles/ayu/ui/settings/settings_appearance.cpp @@ -9,7 +9,7 @@ #include "apiwrap.h" #include "lang_auto.h" #include "ayu/ayu_settings.h" -#include "ayu/ui/ayu_userpic.h" +#include "ayu/ayu_ui_settings.h" #include "ayu/ui/boxes/font_selector.h" #include "ayu/ui/components/icon_picker.h" #include "ayu/ui/settings/ayu_builder.h" @@ -233,7 +233,7 @@ void BuildAvatarCorners(SectionBuilder &builder, AyuSectionBuilder &ayu) { { if (val == 0) { return tr::ayu_AvatarCornersSquare(tr::now).toUpper(); - } else if (val == AyuUserpic::kMaxAvatarCorners) { + } else if (val == AyuUiSettings::kMaxAvatarCorners) { return tr::ayu_AvatarCornersCircle(tr::now).toUpper(); } return QString::number(val); @@ -304,7 +304,7 @@ void BuildAvatarCorners(SectionBuilder &builder, AyuSectionBuilder &ayu) { .id = u"ayu/avatarCornersSlider"_q, .title = rpl::single(QString()), .showTitle = false, - .steps = AyuUserpic::kMaxAvatarCorners + 1, + .steps = AyuUiSettings::kMaxAvatarCorners + 1, .current = settings->avatarCorners(), .onChanged = [=](int val) { AyuSettings::getInstance().setAvatarCorners(val); diff --git a/Telegram/SourceFiles/ayu/utils/rc_manager.cpp b/Telegram/SourceFiles/ayu/utils/rc_manager.cpp index bbfa57ca1a..7379f039ce 100644 --- a/Telegram/SourceFiles/ayu/utils/rc_manager.cpp +++ b/Telegram/SourceFiles/ayu/utils/rc_manager.cpp @@ -51,7 +51,7 @@ void RCManager::sendRequest() { } const auto url = QString::fromLatin1(_useExteraFallback ? kExteraUrl : kPrimaryUrl); - LOG(("RCManager: requesting map").arg(url)); + LOG(("RCManager: requesting map")); clearSentRequest(); diff --git a/Telegram/SourceFiles/calls/calls_userpic.cpp b/Telegram/SourceFiles/calls/calls_userpic.cpp index e1f55025df..beb188ce67 100644 --- a/Telegram/SourceFiles/calls/calls_userpic.cpp +++ b/Telegram/SourceFiles/calls/calls_userpic.cpp @@ -20,6 +20,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "apiwrap.h" // requestFullPeer. #include "styles/style_calls.h" +// AyuGram includes +#include "ayu/ui/ayu_userpic.h" +#include "ui/image/image_prepare.h" + + namespace Calls { namespace { @@ -100,12 +105,15 @@ void Userpic::paint() { pen.setWidth(_muteStroke); p.setPen(pen); p.setBrush(st::callHangupBg); + const auto pos = AyuUserpic::OnlineBadgePosition( + size(), + _muteSize); const auto rect = QRect( - _mutePosition.x() - _muteSize / 2, - _mutePosition.y() - _muteSize / 2, + int(std::round(pos.x())), + int(std::round(pos.y())), _muteSize, _muteSize); - p.drawEllipse(rect); + AyuUserpic::PaintShape(p, QRectF(rect)); st::callMutedPeerIcon.paintInCenter(p, rect); } } @@ -186,12 +194,15 @@ void Userpic::createCache(Image *image) { height = qMax((height * real) / width, 1); width = real; } - _userPhoto = image->pixNoCache( + auto result = image->pixNoCache( { width, height }, { - .options = Images::Option::RoundCircle, .outer = { size, size }, - }); + }).toImage(); + result = Images::Round( + std::move(result), + ImageRoundRadius::AyuUserpic); + _userPhoto = Images::PixmapFast(std::move(result)); _userPhoto.setDevicePixelRatio(style::DevicePixelRatio()); } else { auto filled = QImage( diff --git a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp index 977d547ee1..544b61028f 100644 --- a/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp +++ b/Telegram/SourceFiles/calls/group/calls_group_members_row.cpp @@ -20,6 +20,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "webrtc/webrtc_video_track.h" #include "styles/style_calls.h" +// AyuGram includes +#include "ayu/ui/ayu_userpic.h" + + namespace Calls::Group { namespace { @@ -407,7 +411,28 @@ void MembersRow::paintBlobs( st::groupCallMemberInactiveStatus, st::groupCallMemberActiveStatus, _speakingAnimation.value(_speaking ? 1. : 0.)); - _blobsAnimation->blobs.paint(p, brush); + if (AyuUserpic::IsCircle()) { + _blobsAnimation->blobs.paint(p, brush); + } else { + const auto level = _blobsAnimation->blobs.currentLevel(); + const auto blobs = RowBlobs(); + for (const auto &blob : blobs) { + const auto scale = blob.minScale + (1. - blob.minScale) * level; + const auto radius = blob.maxRadius; + const auto rectSize = 2. * radius; + const auto cornerRadius = AyuUserpic::ComputeRadiusF(rectSize); + p.save(); + p.scale(scale, scale); + p.setOpacity(p.opacity() * blob.alpha); + p.setPen(Qt::NoPen); + p.setBrush(brush); + p.drawRoundedRect( + QRectF(-radius, -radius, rectSize, rectSize), + cornerRadius, + cornerRadius); + p.restore(); + } + } p.translate(-shift); p.setOpacity(1.); } diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 3ae82cef5e..5882e8915c 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -416,7 +416,7 @@ QImage *PeerData::userpicCloudImage(Ui::PeerUserpicView &view) const { } else if (isNotificationsUser()) { static auto result = Window::LogoTelegramDefault().scaledToWidth( kUserpicSize, - Qt::SmoothTransformation); + Qt::SmoothTransformation).convertToFormat(QImage::Format_RGB32); return &result; } return nullptr; diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 342bec2941..4a9d3c7be3 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -124,11 +124,10 @@ constexpr auto kBlurRadius = 24; 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, + partRect.topLeft() * ratio, QSize(partSize, partSize) * ratio))); result.setDevicePixelRatio(ratio); @@ -171,9 +170,10 @@ constexpr auto kBlurRadius = 24; QRect CornerBadgeTTLRect(int photoSize) { const auto &partSize = st::dialogsTTLBadgeSize; + const auto pos = AyuUserpic::OnlineBadgePosition(photoSize, partSize); return QRect( - photoSize - partSize + st::dialogsTTLBadgeSkip.x(), - photoSize - partSize + st::dialogsTTLBadgeSkip.y(), + int(pos.x()), + int(pos.y()), partSize, partSize); } @@ -553,7 +553,7 @@ void Row::PaintCornerBadgeFrame( q.setBrush(data->active ? st::dialogsOnlineBadgeFgActive : st::dialogsOnlineBadgeFg); - const auto badge = AyuUserpic::OnlineBadgePosition(photoSize, size); + const auto badge = AyuUserpic::OnlineBadgePosition(photoSize, size, stroke); q.drawEllipse(QRectF( badge.x(), badge.y(), diff --git a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp index a648072a40..7879a28401 100644 --- a/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp +++ b/Telegram/SourceFiles/dialogs/ui/top_peers_strip.cpp @@ -841,7 +841,7 @@ void TopPeersStrip::paintUserpic( pen.setWidthF(stroke * online); q.setPen(pen); q.setBrush(st::dialogsOnlineBadgeFg); - const auto badge = AyuUserpic::OnlineBadgePosition(size, onlineSize); + const auto badge = AyuUserpic::OnlineBadgePosition(size, onlineSize, stroke); q.drawEllipse(QRectF( badge.x(), badge.y(), diff --git a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp index 65869cc1dd..38506e41cf 100644 --- a/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp +++ b/Telegram/SourceFiles/info/peer_gifts/info_peer_gifts_common.cpp @@ -823,7 +823,7 @@ void GiftButton::paint(QPainter &p, float64 craftProgress) { } const auto image = _userpic->image(st::giftBoxUserpicSize); const auto corners = AyuUiSettings::getAvatarCorners(); - const auto extraSkip = int(double(AyuUserpic::kMaxAvatarCorners - corners) / AyuUserpic::kMaxAvatarCorners * 6.0); + const auto extraSkip = int(double(AyuUiSettings::kMaxAvatarCorners - corners) / AyuUiSettings::kMaxAvatarCorners * 6.0); const auto skip = st::giftBoxUserpicSkip + extraSkip; p.drawImage(extend.left() + skip, extend.top() + skip, image); } else if (_check) { diff --git a/Telegram/lib_ui b/Telegram/lib_ui index f9f592a3a0..9c6b07ed82 160000 --- a/Telegram/lib_ui +++ b/Telegram/lib_ui @@ -1 +1 @@ -Subproject commit f9f592a3a02d9f0d42dc5968a0e8a7f92258544c +Subproject commit 9c6b07ed82b56e6f04538f1abc155825a318d714