Added TTL badge to dialogs list.

This commit is contained in:
23rd 2022-12-01 13:46:04 +03:00
parent cbbbcd877c
commit 92756f418b
7 changed files with 157 additions and 38 deletions

View File

@ -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.;

View File

@ -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*> 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<UserData*> user) {
if (user->isSelf()) {
return;
}
const auto history = session().data().historyLoaded(user);
if (!history) {
return;
}
updateRowCornerStatusShown(history);
}
void InnerWidget::groupHasCallUpdated(not_null<PeerData*> 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*> history) {
const auto repaint = [=] {
repaintDialogRowCornerStatus(history);

View File

@ -276,8 +276,6 @@ private:
int defaultRowTop(not_null<Row*> row) const;
void setupOnlineStatusCheck();
void userOnlineUpdated(not_null<UserData*> user);
void groupHasCallUpdated(not_null<PeerData*> peer);
void updateRowCornerStatusShown(not_null<History*> history);
void repaintDialogRowCornerStatus(not_null<History*> history);

View File

@ -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<PeerData*> peer,
std::shared_ptr<Data::CloudImageView> &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

View File

@ -40,6 +40,8 @@ namespace Dialogs {
enum class SortMode;
[[nodiscard]] QRect CornerBadgeTTLRect(int photoSize);
class BasicRow {
public:
BasicRow();

View File

@ -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);
}

View File

@ -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());
}