mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Added TTL badge to dialogs list.
This commit is contained in:
parent
cbbbcd877c
commit
92756f418b
7 changed files with 157 additions and 38 deletions
|
@ -99,6 +99,11 @@ dialogsOnlineBadgeDuration: 150;
|
||||||
dialogsCallBadgeSize: 16px;
|
dialogsCallBadgeSize: 16px;
|
||||||
dialogsCallBadgeSkip: point(-3px, -3px);
|
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;
|
dialogsSpeakingStrokeNumerator: 16px;
|
||||||
dialogsSpeakingDenominator: 8.;
|
dialogsSpeakingDenominator: 8.;
|
||||||
|
|
||||||
|
|
|
@ -3530,11 +3530,24 @@ void InnerWidget::setupOnlineStatusCheck() {
|
||||||
session().changes().peerUpdates(
|
session().changes().peerUpdates(
|
||||||
Data::PeerUpdate::Flag::OnlineStatus
|
Data::PeerUpdate::Flag::OnlineStatus
|
||||||
| Data::PeerUpdate::Flag::GroupCall
|
| Data::PeerUpdate::Flag::GroupCall
|
||||||
|
| Data::PeerUpdate::Flag::MessagesTTL
|
||||||
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
) | rpl::start_with_next([=](const Data::PeerUpdate &update) {
|
||||||
if (const auto user = update.peer->asUser()) {
|
const auto &peer = update.peer;
|
||||||
userOnlineUpdated(user);
|
if (const auto user = peer->asUser()) {
|
||||||
} else {
|
if (user->isSelf()) {
|
||||||
groupHasCallUpdated(update.peer);
|
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());
|
}, lifetime());
|
||||||
}
|
}
|
||||||
|
@ -3559,37 +3572,22 @@ void InnerWidget::repaintDialogRowCornerStatus(not_null<History*> history) {
|
||||||
st::defaultDialogRow.padding.left(),
|
st::defaultDialogRow.padding.left(),
|
||||||
st::defaultDialogRow.padding.top()
|
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(
|
updateDialogRow(
|
||||||
RowDescriptor(
|
RowDescriptor(
|
||||||
history,
|
history,
|
||||||
FullMsgId()),
|
FullMsgId()),
|
||||||
updateRect,
|
updateRect.united(ttlUpdateRect),
|
||||||
UpdateRowSection::Default | UpdateRowSection::Filtered);
|
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) {
|
void InnerWidget::updateRowCornerStatusShown(not_null<History*> history) {
|
||||||
const auto repaint = [=] {
|
const auto repaint = [=] {
|
||||||
repaintDialogRowCornerStatus(history);
|
repaintDialogRowCornerStatus(history);
|
||||||
|
|
|
@ -276,8 +276,6 @@ private:
|
||||||
|
|
||||||
int defaultRowTop(not_null<Row*> row) const;
|
int defaultRowTop(not_null<Row*> row) const;
|
||||||
void setupOnlineStatusCheck();
|
void setupOnlineStatusCheck();
|
||||||
void userOnlineUpdated(not_null<UserData*> user);
|
|
||||||
void groupHasCallUpdated(not_null<PeerData*> peer);
|
|
||||||
|
|
||||||
void updateRowCornerStatusShown(not_null<History*> history);
|
void updateRowCornerStatusShown(not_null<History*> history);
|
||||||
void repaintDialogRowCornerStatus(not_null<History*> history);
|
void repaintDialogRowCornerStatus(not_null<History*> history);
|
||||||
|
|
|
@ -7,7 +7,11 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "dialogs/dialogs_row.h"
|
#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/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_options.h"
|
||||||
#include "ui/text/text_utilities.h"
|
#include "ui/text/text_utilities.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
@ -22,14 +26,112 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "history/history_item.h"
|
#include "history/history_item.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "base/unixtime.h"
|
#include "base/unixtime.h"
|
||||||
#include "mainwidget.h"
|
|
||||||
#include "styles/style_dialogs.h"
|
#include "styles/style_dialogs.h"
|
||||||
|
|
||||||
namespace Dialogs {
|
namespace Dialogs {
|
||||||
|
namespace {
|
||||||
|
|
||||||
constexpr auto kTopLayer = 1;
|
constexpr auto kTopLayer = 2;
|
||||||
|
constexpr auto kBottomLayer = 1;
|
||||||
constexpr auto kNoneLayer = 0;
|
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;
|
Row::CornerLayersManager::CornerLayersManager() = default;
|
||||||
|
|
||||||
bool Row::CornerLayersManager::isSameLayer(Layer layer) const {
|
bool Row::CornerLayersManager::isSameLayer(Layer layer) const {
|
||||||
|
@ -214,6 +316,8 @@ void Row::updateCornerBadgeShown(
|
||||||
} else if (peer->isChannel()
|
} else if (peer->isChannel()
|
||||||
&& Data::ChannelHasActiveCall(peer->asChannel())) {
|
&& Data::ChannelHasActiveCall(peer->asChannel())) {
|
||||||
return kTopLayer;
|
return kTopLayer;
|
||||||
|
} else if (peer->messagesTTL()) {
|
||||||
|
return kBottomLayer;
|
||||||
}
|
}
|
||||||
return kNoneLayer;
|
return kNoneLayer;
|
||||||
}();
|
}();
|
||||||
|
@ -250,10 +354,18 @@ void Row::PaintCornerBadgeFrame(
|
||||||
context.st->photoSize,
|
context.st->photoSize,
|
||||||
context.paused);
|
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);
|
PainterHighQualityEnabler hq(q);
|
||||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||||
|
|
||||||
const auto progress = data->layersManager.progressForLayer(kTopLayer);
|
|
||||||
const auto size = peer->isUser()
|
const auto size = peer->isUser()
|
||||||
? st::dialogsOnlineBadgeSize
|
? st::dialogsOnlineBadgeSize
|
||||||
: st::dialogsCallBadgeSize;
|
: st::dialogsCallBadgeSize;
|
||||||
|
@ -261,10 +373,10 @@ void Row::PaintCornerBadgeFrame(
|
||||||
const auto skip = peer->isUser()
|
const auto skip = peer->isUser()
|
||||||
? st::dialogsOnlineBadgeSkip
|
? st::dialogsOnlineBadgeSkip
|
||||||
: st::dialogsCallBadgeSkip;
|
: st::dialogsCallBadgeSkip;
|
||||||
const auto shrink = (size / 2) * (1. - progress);
|
const auto shrink = (size / 2) * (1. - topLayerProgress);
|
||||||
|
|
||||||
auto pen = QPen(Qt::transparent);
|
auto pen = QPen(Qt::transparent);
|
||||||
pen.setWidthF(stroke * progress);
|
pen.setWidthF(stroke * topLayerProgress);
|
||||||
q.setPen(pen);
|
q.setPen(pen);
|
||||||
q.setBrush(data->active
|
q.setBrush(data->active
|
||||||
? st::dialogsOnlineBadgeFgActive
|
? st::dialogsOnlineBadgeFgActive
|
||||||
|
@ -315,7 +427,8 @@ void Row::paintUserpic(
|
||||||
QImage::Format_ARGB32_Premultiplied);
|
QImage::Format_ARGB32_Premultiplied);
|
||||||
_cornerBadgeUserpic->frame.setDevicePixelRatio(ratio);
|
_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;
|
const auto frameIndex = videoUserpic ? videoUserpic->frameIndex() : -1;
|
||||||
if (!_cornerBadgeUserpic->layersManager.isFinished()
|
if (!_cornerBadgeUserpic->layersManager.isFinished()
|
||||||
|| _cornerBadgeUserpic->key != key
|
|| _cornerBadgeUserpic->key != key
|
||||||
|
|
|
@ -40,6 +40,8 @@ namespace Dialogs {
|
||||||
|
|
||||||
enum class SortMode;
|
enum class SortMode;
|
||||||
|
|
||||||
|
[[nodiscard]] QRect CornerBadgeTTLRect(int photoSize);
|
||||||
|
|
||||||
class BasicRow {
|
class BasicRow {
|
||||||
public:
|
public:
|
||||||
BasicRow();
|
BasicRow();
|
||||||
|
|
|
@ -2764,6 +2764,9 @@ void History::applyDialog(
|
||||||
MsgId(0), // topicRootId
|
MsgId(0), // topicRootId
|
||||||
draft->c_draftMessage());
|
draft->c_draftMessage());
|
||||||
}
|
}
|
||||||
|
if (const auto ttl = data.vttl_period()) {
|
||||||
|
peer->setMessagesTTL(ttl->v);
|
||||||
|
}
|
||||||
owner().histories().dialogEntryApplied(this);
|
owner().histories().dialogEntryApplied(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -119,10 +119,10 @@ bool TTLValidator::can() const {
|
||||||
&& !_peer->isNotificationsUser()
|
&& !_peer->isNotificationsUser()
|
||||||
&& !_peer->asUser()->isInaccessible())
|
&& !_peer->asUser()->isInaccessible())
|
||||||
|| (_peer->isChat()
|
|| (_peer->isChat()
|
||||||
&& _peer->asChat()->canDeleteMessages()
|
&& _peer->asChat()->canEditInformation()
|
||||||
&& _peer->asChat()->amIn())
|
&& _peer->asChat()->amIn())
|
||||||
|| (_peer->isChannel()
|
|| (_peer->isChannel()
|
||||||
&& _peer->asChannel()->canDeleteMessages()
|
&& _peer->asChannel()->canEditInformation()
|
||||||
&& _peer->asChannel()->amIn());
|
&& _peer->asChannel()->amIn());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue