feat: semi-transparent deleted messages

This commit is contained in:
AlexeyZavar
2026-02-06 21:50:50 +03:00
parent 9952048550
commit 48c7a4046c
11 changed files with 150 additions and 11 deletions
@@ -389,6 +389,12 @@ void AyuSettings::setHideFromBlocked(bool val) {
save();
}
void AyuSettings::setSemiTransparentDeletedMessages(bool val) {
if (_semiTransparentDeletedMessages.current() == val) return;
_semiTransparentDeletedMessages = val;
save();
}
void AyuSettings::setDisableAds(bool val) {
if (_disableAds.current() == val) return;
_disableAds = val;
@@ -808,6 +814,7 @@ void to_json(nlohmann::json &j, const AyuSettings &s) {
{"filtersEnabled", s._filtersEnabled.current()},
{"filtersEnabledInChats", s._filtersEnabledInChats.current()},
{"hideFromBlocked", s._hideFromBlocked.current()},
{"semiTransparentDeletedMessages", s._semiTransparentDeletedMessages.current()},
{"disableAds", s._disableAds.current()},
{"disableStories", s._disableStories.current()},
{"disableCustomBackgrounds", s._disableCustomBackgrounds.current()},
@@ -898,6 +905,7 @@ void from_json(const nlohmann::json &j, AyuSettings &s) {
s._filtersEnabled = j.value("filtersEnabled", defaults._filtersEnabled.current());
s._filtersEnabledInChats = j.value("filtersEnabledInChats", defaults._filtersEnabledInChats.current());
s._hideFromBlocked = j.value("hideFromBlocked", defaults._hideFromBlocked.current());
s._semiTransparentDeletedMessages = j.value("semiTransparentDeletedMessages", defaults._semiTransparentDeletedMessages.current());
s._disableAds = j.value("disableAds", defaults._disableAds.current());
s._disableStories = j.value("disableStories", defaults._disableStories.current());
s._disableCustomBackgrounds = j.value("disableCustomBackgrounds", defaults._disableCustomBackgrounds.current());
+4
View File
@@ -167,6 +167,7 @@ public:
[[nodiscard]] bool filtersEnabled() const { return _filtersEnabled.current(); }
[[nodiscard]] bool filtersEnabledInChats() const { return _filtersEnabledInChats.current(); }
[[nodiscard]] bool hideFromBlocked() const { return _hideFromBlocked.current(); }
[[nodiscard]] bool semiTransparentDeletedMessages() const { return _semiTransparentDeletedMessages.current(); }
[[nodiscard]] bool disableAds() const { return _disableAds.current(); }
[[nodiscard]] bool disableStories() const { return _disableStories.current(); }
[[nodiscard]] bool disableCustomBackgrounds() const { return _disableCustomBackgrounds.current(); }
@@ -241,6 +242,7 @@ public:
void setFiltersEnabled(bool val);
void setFiltersEnabledInChats(bool val);
void setHideFromBlocked(bool val);
void setSemiTransparentDeletedMessages(bool val);
void setDisableAds(bool val);
void setDisableStories(bool val);
void setDisableCustomBackgrounds(bool val);
@@ -316,6 +318,7 @@ public:
[[nodiscard]] rpl::producer<bool> filtersEnabledChanges() const { return _filtersEnabled.value(); }
[[nodiscard]] rpl::producer<bool> filtersEnabledInChatsChanges() const { return _filtersEnabledInChats.value(); }
[[nodiscard]] rpl::producer<bool> hideFromBlockedChanges() const { return _hideFromBlocked.value(); }
[[nodiscard]] rpl::producer<bool> semiTransparentDeletedMessagesChanges() const { return _semiTransparentDeletedMessages.value(); }
[[nodiscard]] rpl::producer<bool> disableAdsChanges() const { return _disableAds.value(); }
[[nodiscard]] rpl::producer<bool> disableStoriesChanges() const { return _disableStories.value(); }
[[nodiscard]] rpl::producer<bool> disableCustomBackgroundsChanges() const { return _disableCustomBackgrounds.value(); }
@@ -399,6 +402,7 @@ private:
rpl::variable<bool> _filtersEnabled = false;
rpl::variable<bool> _filtersEnabledInChats = false;
rpl::variable<bool> _hideFromBlocked = false;
rpl::variable<bool> _semiTransparentDeletedMessages = false;
rpl::variable<bool> _disableAds = true;
rpl::variable<bool> _disableStories = false;
rpl::variable<bool> _disableCustomBackgrounds = true;
@@ -490,6 +490,7 @@ void SetupOther(not_null<Ui::VerticalLayout*> container) {
AddSettingToggle(container, tr::ayu_LocalPremium(), &AyuSettings::localPremium, &AyuSettings::setLocalPremium);
AddSettingToggle(container, tr::ayu_DisableAds(), &AyuSettings::disableAds, &AyuSettings::setDisableAds);
AddSettingToggle(container, tr::ayu_SemiTransparentDeletedMessages(), &AyuSettings::semiTransparentDeletedMessages, &AyuSettings::setSemiTransparentDeletedMessages);
}
rpl::producer<QString> AyuGhost::title() {
@@ -40,8 +40,6 @@ AyuChats::AyuChats(
}
void SetupStickersAndEmojiSettings(not_null<Ui::VerticalLayout*> container) {
auto *settings = &AyuSettings::getInstance();
AddSubsectionTitle(container, tr::lng_settings_stickers_emoji()/*rpl::single(QString("Stickers and Emoji"))*/);
AddSettingToggle(container, tr::ayu_ShowOnlyAddedEmojisAndStickers(), &AyuSettings::showOnlyAddedEmojisAndStickers, &AyuSettings::setShowOnlyAddedEmojisAndStickers);
@@ -3500,6 +3500,7 @@ void HistoryItem::setPostAuthor(const QString &postAuthor) {
void HistoryItem::setDeleted() {
_deleted = true;
_deletedAnimated = true;
if (isService()) {
const auto &settings = AyuSettings::getInstance();
@@ -3514,6 +3515,14 @@ bool HistoryItem::isDeleted() const {
return _deleted;
}
bool HistoryItem::wasDeletedAnimated() const {
return _deletedAnimated;
}
void HistoryItem::markDeletedAnimated() {
_deletedAnimated = false;
}
void HistoryItem::setAyuHint(const QString &hint) {
try {
auto msgsigned = Get<HistoryMessageSigned>();
@@ -437,6 +437,8 @@ public:
void setPostAuthor(const QString &author);
void setDeleted();
bool isDeleted() const;
[[nodiscard]] bool wasDeletedAnimated() const;
void markDeletedAnimated();
void applyTTL(TimeId destroyAt);
void setAyuHint(const QString &hint);
void setRealId(MsgId newId);
@@ -739,6 +741,7 @@ private:
crl::time _reactionsLastRefreshed = 0;
bool _deleted = false;
bool _deletedAnimated = false;
int _unsupportedTTL = 0;
TimeId _date = 0;
@@ -48,6 +48,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/round_rect.h"
#include "data/components/sponsored_messages.h"
#include "data/data_channel.h"
#include "data/data_groups.h"
#include "data/data_saved_sublist.h"
#include "data/data_session.h"
#include "data/data_todo_list.h"
@@ -1152,6 +1153,15 @@ Element::Element(
AddComponents(FakeBotAboutTop::Bit());
}
}
if (replacing && replacing->_deletedOpacityAnimation.animating()) {
_deletedOpacityAnimation = replacing->takeDeletedAnimation();
} else if (data->isDeleted() && data->wasDeletedAnimated()) {
// grouped messages handle it per-item
if (!history()->owner().groups().find(data)) {
startDeletedAnimation();
data->markDeletedAnimated();
}
}
}
bool Element::embedReactionsInBubble() const {
@@ -1284,6 +1294,40 @@ void Element::repaint(QRect r) const {
history()->owner().requestViewRepaint(this, r);
}
float64 Element::deletedOpacity() const {
const auto &settings = AyuSettings::getInstance();
if (!settings.semiTransparentDeletedMessages()) {
return 1.;
}
if (_context == Context::AdminLog) { // render normally in "View Deleted"
return 1.;
}
if (_data->isDeleted()) {
if (const auto group = history()->owner().groups().find(_data)) {
// animation works weirdly on grouped messages, so only a fixed opacity here
const auto allDeleted = ranges::all_of(
group->items,
&HistoryItem::isDeleted);
return allDeleted ? 0.7 : 1.;
}
return _deletedOpacityAnimation.value(0.7);
}
return 1.;
}
void Element::startDeletedAnimation() {
_deletedOpacityAnimation.start(
[=] { repaint(); },
1.,
0.7,
500,
anim::easeOutCubic);
}
Ui::Animations::Simple Element::takeDeletedAnimation() {
return std::move(_deletedOpacityAnimation);
}
void Element::paintHighlight(
Painter &p,
const PaintContext &context,
@@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "base/runtime_composer.h"
#include "base/flags.h"
#include "base/weak_ptr.h"
#include "ui/effects/animations.h"
#include "ui/userpic_view.h"
class History;
@@ -458,6 +459,10 @@ public:
[[nodiscard]] bool isHiddenByGroup() const;
[[nodiscard]] virtual bool isHidden() const;
[[nodiscard]] float64 deletedOpacity() const;
void startDeletedAnimation();
[[nodiscard]] Ui::Animations::Simple takeDeletedAnimation();
[[nodiscard]] bool isIsolatedEmoji() const {
return (_flags & Flag::SpecialOnlyEmoji)
&& _text.isIsolatedEmoji();
@@ -765,6 +770,8 @@ private:
mutable Flags _flags = Flag(0);
Context _context = Context();
mutable Ui::Animations::Simple _deletedOpacityAnimation;
};
[[nodiscard]] int FindViewY(
@@ -991,6 +991,12 @@ void Message::draw(Painter &p, const PaintContext &context) const {
}
}
const auto deletedFade = deletedOpacity();
const auto savedOpacityForDeleted = p.opacity();
if (deletedFade < 1.) {
p.setOpacity(savedOpacityForDeleted * deletedFade);
}
const auto roll = media ? media->bubbleRoll() : Media::BubbleRoll();
if (roll) {
p.save();
@@ -1321,6 +1327,10 @@ void Message::draw(Painter &p, const PaintContext &context) const {
p.restoreTextPalette();
if (deletedFade < 1.) {
p.setOpacity(savedOpacityForDeleted);
}
if (context.highlightPathCache
&& !context.highlightPathCache->isEmpty()) {
const auto alpha = int(0.25
@@ -27,6 +27,10 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "layout/layout_selection.h"
#include "styles/style_chat.h"
// AyuGram includes
#include "ayu/ayu_settings.h"
namespace HistoryView {
namespace {
@@ -404,6 +408,26 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
const auto tagged = lookupSpoilerTagMedia();
auto fullRect = QRect();
const auto subpartHighlight = IsSubGroupSelection(highlight);
auto allDeleted = true;
auto anyDeleted = false;
const auto &ayuSettings = AyuSettings::getInstance();
const auto perItemOpacityEnabled = ayuSettings.semiTransparentDeletedMessages();
if (perItemOpacityEnabled) {
for (const auto &part : _parts) {
if (part.item->isDeleted()) {
anyDeleted = true;
} else {
allDeleted = false;
}
}
}
const auto perItemDeletedOpacity = perItemOpacityEnabled
&& anyDeleted;
const auto elementDeletedOpacity = perItemDeletedOpacity
? _parent->deletedOpacity()
: 1.;
for (auto i = 0, count = int(_parts.size()); i != count; ++i) {
const auto &part = _parts[i];
auto partContext = context.withSelection(fullSelection
@@ -430,15 +454,44 @@ void GroupedMedia::draw(Painter &p, const PaintContext &context) const {
if (!part.cache.isNull()) {
wasCache = true;
}
part.content->drawGrouped(
p,
partContext,
part.geometry.translated(0, groupPadding.top()),
part.sides,
applyRoundingSides(rounding, part.sides),
highlightOpacity,
&part.cacheKey,
&part.cache);
if (perItemDeletedOpacity && part.item->isDeleted()) {
if (part.item->wasDeletedAnimated()
&& !part.deletedAnimation.animating()) {
part.deletedAnimation.start(
[parent = _parent] { parent->repaint(); },
1.,
0.7,
500,
anim::easeOutCubic);
part.item->markDeletedAnimated();
}
const auto itemOpacity = part.deletedAnimation.value(0.7);
const auto adjustedOpacity = (elementDeletedOpacity > 0.)
? (itemOpacity / elementDeletedOpacity)
: 0.;
const auto savedOp = p.opacity();
p.setOpacity(savedOp * adjustedOpacity);
part.content->drawGrouped(
p,
partContext,
part.geometry.translated(0, groupPadding.top()),
part.sides,
applyRoundingSides(rounding, part.sides),
highlightOpacity,
&part.cacheKey,
&part.cache);
p.setOpacity(savedOp);
} else {
part.content->drawGrouped(
p,
partContext,
part.geometry.translated(0, groupPadding.top()),
part.sides,
applyRoundingSides(rounding, part.sides),
highlightOpacity,
&part.cacheKey,
&part.cache);
}
if (!part.cache.isNull()) {
nowCache = true;
}
@@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "history/view/media/history_view_media.h"
#include "data/data_document.h"
#include "data/data_photo.h"
#include "ui/effects/animations.h"
namespace Data {
class Media;
@@ -124,6 +125,7 @@ private:
QRect geometry;
mutable uint64 cacheKey = 0;
mutable QPixmap cache;
mutable Ui::Animations::Simple deletedAnimation;
};