From 92756f418bd5db55825ca2df37846b1cf73f546a Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Thu, 1 Dec 2022 13:46:04 +0300 Subject: [PATCH] Added TTL badge to dialogs list. --- Telegram/SourceFiles/dialogs/dialogs.style | 5 + .../dialogs/dialogs_inner_widget.cpp | 54 ++++---- .../dialogs/dialogs_inner_widget.h | 2 - Telegram/SourceFiles/dialogs/dialogs_row.cpp | 125 +++++++++++++++++- Telegram/SourceFiles/dialogs/dialogs_row.h | 2 + Telegram/SourceFiles/history/history.cpp | 3 + .../SourceFiles/menu/menu_ttl_validator.cpp | 4 +- 7 files changed, 157 insertions(+), 38 deletions(-) diff --git a/Telegram/SourceFiles/dialogs/dialogs.style b/Telegram/SourceFiles/dialogs/dialogs.style index fbe385e220..451cefcf36 100644 --- a/Telegram/SourceFiles/dialogs/dialogs.style +++ b/Telegram/SourceFiles/dialogs/dialogs.style @@ -99,6 +99,11 @@ dialogsOnlineBadgeDuration: 150; dialogsCallBadgeSize: 16px; dialogsCallBadgeSkip: point(-3px, -3px); +dialogsTTLBadgeSize: 20px; +dialogsTTLBadgeInnerMargins: margins(2px, 2px, 2px, 2px); +// Relative to a photo place, not a whole userpic place. +dialogsTTLBadgeSkip: point(1px, 1px); + dialogsSpeakingStrokeNumerator: 16px; dialogsSpeakingDenominator: 8.; diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp index 9209a44cab..92d48847ad 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.cpp @@ -3530,11 +3530,24 @@ void InnerWidget::setupOnlineStatusCheck() { session().changes().peerUpdates( Data::PeerUpdate::Flag::OnlineStatus | Data::PeerUpdate::Flag::GroupCall + | Data::PeerUpdate::Flag::MessagesTTL ) | rpl::start_with_next([=](const Data::PeerUpdate &update) { - if (const auto user = update.peer->asUser()) { - userOnlineUpdated(user); - } else { - groupHasCallUpdated(update.peer); + const auto &peer = update.peer; + if (const auto user = peer->asUser()) { + if (user->isSelf()) { + return; + } + if (const auto history = session().data().historyLoaded(user)) { + updateRowCornerStatusShown(history); + } + } else if (const auto group = peer->asMegagroup()) { + if (const auto history = session().data().historyLoaded(group)) { + updateRowCornerStatusShown(history); + } + } else if (peer->messagesTTL()) { + if (const auto history = session().data().historyLoaded(peer)) { + updateRowCornerStatusShown(history); + } } }, lifetime()); } @@ -3559,37 +3572,22 @@ void InnerWidget::repaintDialogRowCornerStatus(not_null history) { st::defaultDialogRow.padding.left(), st::defaultDialogRow.padding.top() ); + const auto ttlUpdateRect = !history->peer->messagesTTL() + ? QRect() + : Dialogs::CornerBadgeTTLRect( + _st->photoSize + ).translated( + st::defaultDialogRow.padding.left(), + st::defaultDialogRow.padding.top() + ); updateDialogRow( RowDescriptor( history, FullMsgId()), - updateRect, + updateRect.united(ttlUpdateRect), UpdateRowSection::Default | UpdateRowSection::Filtered); } -void InnerWidget::userOnlineUpdated(not_null user) { - if (user->isSelf()) { - return; - } - const auto history = session().data().historyLoaded(user); - if (!history) { - return; - } - updateRowCornerStatusShown(history); -} - -void InnerWidget::groupHasCallUpdated(not_null peer) { - const auto group = peer->asMegagroup(); - if (!group) { - return; - } - const auto history = session().data().historyLoaded(group); - if (!history) { - return; - } - updateRowCornerStatusShown(history); -} - void InnerWidget::updateRowCornerStatusShown(not_null history) { const auto repaint = [=] { repaintDialogRowCornerStatus(history); diff --git a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h index 50445011a3..dc153f5d5b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h +++ b/Telegram/SourceFiles/dialogs/dialogs_inner_widget.h @@ -276,8 +276,6 @@ private: int defaultRowTop(not_null row) const; void setupOnlineStatusCheck(); - void userOnlineUpdated(not_null user); - void groupHasCallUpdated(not_null peer); void updateRowCornerStatusShown(not_null history); void repaintDialogRowCornerStatus(not_null history); diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.cpp b/Telegram/SourceFiles/dialogs/dialogs_row.cpp index 9bc44f0b41..85c47d986b 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_row.cpp @@ -7,7 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL */ #include "dialogs/dialogs_row.h" +#include "ui/chat/chat_theme.h" // CountAverageColor. +#include "ui/color_contrast.h" #include "ui/effects/ripple_animation.h" +#include "ui/image/image_prepare.h" +#include "ui/text/format_values.h" #include "ui/text/text_options.h" #include "ui/text/text_utilities.h" #include "ui/painter.h" @@ -22,14 +26,112 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "history/history_item.h" #include "lang/lang_keys.h" #include "base/unixtime.h" -#include "mainwidget.h" #include "styles/style_dialogs.h" namespace Dialogs { +namespace { -constexpr auto kTopLayer = 1; +constexpr auto kTopLayer = 2; +constexpr auto kBottomLayer = 1; constexpr auto kNoneLayer = 0; +void PaintCornerBadgeTTLFrame( + QPainter &q, + not_null peer, + std::shared_ptr &view, + float64 progress, + int photoSize) { + const auto ttl = peer->messagesTTL(); + if (!ttl || !view) { + return; + } + using Radius = ImageRoundRadius; + constexpr auto kBlurRadius = 24; + PainterHighQualityEnabler hq(q); + + q.setOpacity(progress); + + const auto ratio = style::DevicePixelRatio(); + const auto fullSize = photoSize; + const auto blurredFull = Images::BlurLargeImage( + peer->generateUserpicImage(view, fullSize * ratio, Radius::None), + kBlurRadius); + const auto partRect = CornerBadgeTTLRect(fullSize); + const auto &partSize = partRect.width(); + if (progress <= 1.) { + q.save(); + q.translate(partRect.center()); + q.scale(progress, progress); + q.translate(-partRect.center()); + q.restore(); + } + { + auto blurredPart = blurredFull.copy( + blurredFull.width() - partSize * ratio, + blurredFull.height() - partSize * ratio, + partSize * ratio, + partSize * ratio); + blurredPart.setDevicePixelRatio(ratio); + + constexpr auto kMinAcceptableContrast = 4.5; + const auto averageColor = Ui::CountAverageColor(blurredPart); + const auto contrast = Ui::CountContrast( + averageColor, + st::premiumButtonFg->c); + if (contrast < kMinAcceptableContrast) { + constexpr auto kDarkerBy = 0.2; + auto painterPart = QPainter(&blurredPart); + painterPart.setOpacity(kDarkerBy); + painterPart.fillRect( + QRect(QPoint(), partRect.size()), + Qt::black); + } + q.drawImage( + partRect.topLeft(), + Images::Circle(std::move(blurredPart))); + } + const auto innerRect = partRect - st::dialogsTTLBadgeInnerMargins; + const auto ttlText = Ui::FormatTTLTiny(ttl); + + q.setFont(st::dialogsScamFont); + q.setPen(st::premiumButtonFg); + q.drawText( + innerRect, + (ttlText.size() > 2) ? ttlText.mid(0, 2) : ttlText, + style::al_center); + + constexpr auto kPenWidth = 1.5; + constexpr auto kAngleStart = 90 * 16; + constexpr auto kAngleSpan = 180 * 16; + + auto pen = QPen(st::premiumButtonFg); + pen.setJoinStyle(Qt::RoundJoin); + pen.setCapStyle(Qt::RoundCap); + pen.setWidthF(kPenWidth); + + q.setPen(pen); + q.setBrush(Qt::NoBrush); + q.drawArc(innerRect, kAngleStart, kAngleSpan); + + q.setClipRect(partRect - QMargins(partRect.width() / 2, 0, 0, 0)); + pen.setStyle(Qt::DotLine); + q.setPen(pen); + q.drawEllipse(innerRect); + + q.setOpacity(1.); +} + +} // namespace + +QRect CornerBadgeTTLRect(int photoSize) { + const auto &partSize = st::dialogsTTLBadgeSize; + return QRect( + photoSize - partSize + st::dialogsTTLBadgeSkip.x(), + photoSize - partSize + st::dialogsTTLBadgeSkip.y(), + partSize, + partSize); +} + Row::CornerLayersManager::CornerLayersManager() = default; bool Row::CornerLayersManager::isSameLayer(Layer layer) const { @@ -214,6 +316,8 @@ void Row::updateCornerBadgeShown( } else if (peer->isChannel() && Data::ChannelHasActiveCall(peer->asChannel())) { return kTopLayer; + } else if (peer->messagesTTL()) { + return kBottomLayer; } return kNoneLayer; }(); @@ -250,10 +354,18 @@ void Row::PaintCornerBadgeFrame( context.st->photoSize, context.paused); + const auto &manager = data->layersManager; + if (const auto p = manager.progressForLayer(kBottomLayer); p) { + PaintCornerBadgeTTLFrame(q, peer, view, p, context.st->photoSize); + } + const auto topLayerProgress = manager.progressForLayer(kTopLayer); + if (!topLayerProgress) { + return; + } + PainterHighQualityEnabler hq(q); q.setCompositionMode(QPainter::CompositionMode_Source); - const auto progress = data->layersManager.progressForLayer(kTopLayer); const auto size = peer->isUser() ? st::dialogsOnlineBadgeSize : st::dialogsCallBadgeSize; @@ -261,10 +373,10 @@ void Row::PaintCornerBadgeFrame( const auto skip = peer->isUser() ? st::dialogsOnlineBadgeSkip : st::dialogsCallBadgeSkip; - const auto shrink = (size / 2) * (1. - progress); + const auto shrink = (size / 2) * (1. - topLayerProgress); auto pen = QPen(Qt::transparent); - pen.setWidthF(stroke * progress); + pen.setWidthF(stroke * topLayerProgress); q.setPen(pen); q.setBrush(data->active ? st::dialogsOnlineBadgeFgActive @@ -315,7 +427,8 @@ void Row::paintUserpic( QImage::Format_ARGB32_Premultiplied); _cornerBadgeUserpic->frame.setDevicePixelRatio(ratio); } - const auto key = peer->userpicUniqueKey(userpicView()); + auto key = peer->userpicUniqueKey(userpicView()); + key.first += peer->messagesTTL(); const auto frameIndex = videoUserpic ? videoUserpic->frameIndex() : -1; if (!_cornerBadgeUserpic->layersManager.isFinished() || _cornerBadgeUserpic->key != key diff --git a/Telegram/SourceFiles/dialogs/dialogs_row.h b/Telegram/SourceFiles/dialogs/dialogs_row.h index 6e8f3c4847..a8689bf2af 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_row.h +++ b/Telegram/SourceFiles/dialogs/dialogs_row.h @@ -40,6 +40,8 @@ namespace Dialogs { enum class SortMode; +[[nodiscard]] QRect CornerBadgeTTLRect(int photoSize); + class BasicRow { public: BasicRow(); diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index 82f34b5fc3..63547c143a 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -2764,6 +2764,9 @@ void History::applyDialog( MsgId(0), // topicRootId draft->c_draftMessage()); } + if (const auto ttl = data.vttl_period()) { + peer->setMessagesTTL(ttl->v); + } owner().histories().dialogEntryApplied(this); } diff --git a/Telegram/SourceFiles/menu/menu_ttl_validator.cpp b/Telegram/SourceFiles/menu/menu_ttl_validator.cpp index a81108a1ba..9a5283bfc5 100644 --- a/Telegram/SourceFiles/menu/menu_ttl_validator.cpp +++ b/Telegram/SourceFiles/menu/menu_ttl_validator.cpp @@ -119,10 +119,10 @@ bool TTLValidator::can() const { && !_peer->isNotificationsUser() && !_peer->asUser()->isInaccessible()) || (_peer->isChat() - && _peer->asChat()->canDeleteMessages() + && _peer->asChat()->canEditInformation() && _peer->asChat()->amIn()) || (_peer->isChannel() - && _peer->asChannel()->canDeleteMessages() + && _peer->asChannel()->canEditInformation() && _peer->asChannel()->amIn()); }