fix(patches): streamer mode dialog list anonymization

- drop streamer-mode-online: keep real last-seen text per user pref
- add streamer-mode-forum-topic: anonymize ForumTopic::chatListName
  (per-topic seed = channel id ^ rootId so distinct pseudonyms)
- extend streamer-mode-name: public PeerData::noteNameUpdated bumps
  _nameVersion so Entry::_chatListNameText cache rebuilds on toggle
- ag_refresh: walk histories + topics, invalidate chat-list-entry
  message-view cache (HistoryItem::invalidateChatListEntry resets
  MessageView _textCachedFor so sender prefix re-renders)
- streamer-mode-avatar/style: hunk-header line drift only from
  noteNameUpdated insertion above
This commit is contained in:
devilreef 2026-05-01 17:07:27 +06:00
parent a3c58ae970
commit 37d80588b7
Signed by: devilreef
SSH key fingerprint: SHA256:UZisRr4iuXx+IhkbZnR655L2RWAT6o2rgbGv5F/6m3Y
9 changed files with 144 additions and 68 deletions

View file

@ -27,7 +27,7 @@ diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/d
index 0000000..0000000 100644
--- a/Telegram/SourceFiles/data/data_peer.h
+++ b/Telegram/SourceFiles/data/data_peer.h
@@ -458,6 +458,7 @@ public:
@@ -459,6 +459,7 @@ public:
}
[[nodiscard]] QImage *userpicCloudImage(Ui::PeerUserpicView &view) const;
@ -35,7 +35,7 @@ index 0000000..0000000 100644
[[nodiscard]] bool canPinMessages() const;
[[nodiscard]] bool canEditMessagesIndefinitely() const;
@@ -596,7 +597,6 @@ protected:
@@ -597,7 +598,6 @@ protected:
const QString &newUsername);
void updateUserpic(PhotoId photoId, MTP::DcId dcId, bool hasVideo);
void clearUserpic();

View file

@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: devilreef <devilreef@femboy.page>
Date: Fri, 1 May 2026 16:53:21 +0600
Subject: [PATCH] streamer mode: anonymize forum topic title
---
Telegram/SourceFiles/data/data_forum_topic.cpp | 7 +++++++
Telegram/SourceFiles/data/data_forum_topic.h | 2 +-
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/Telegram/SourceFiles/data/data_forum_topic.cpp b/Telegram/SourceFiles/data/data_forum_topic.cpp
index 0000000..0000000 100644
--- a/Telegram/SourceFiles/data/data_forum_topic.cpp
+++ b/Telegram/SourceFiles/data/data_forum_topic.cpp
@@ -7,6 +7,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "data/data_forum_topic.h"
+#include "arcanegram/features/streamer/ag_streamer.h"
#include "data/data_channel.h"
#include "data/data_changes.h"
#include "data/data_forum.h"
@@ -958,6 +959,12 @@ bool ForumTopic::chatListMessageKnown() const {
}
const QString &ForumTopic::chatListName() const {
+ if (channel() && Arcanegram::Streamer::ShouldAnonymize(channel())) {
+ static thread_local QString cached;
+ const auto seed = channel()->id.value ^ quint64(rootId().bare);
+ cached = Arcanegram::Streamer::GeneratedShortName(PeerId(seed));
+ return cached;
+ }
return _title;
}
diff --git a/Telegram/SourceFiles/data/data_forum_topic.h b/Telegram/SourceFiles/data/data_forum_topic.h
index 0000000..0000000 100644
--- a/Telegram/SourceFiles/data/data_forum_topic.h
+++ b/Telegram/SourceFiles/data/data_forum_topic.h
@@ -153,6 +153,7 @@ public:
[[nodiscard]] TextWithEntities titleWithIcon() const;
[[nodiscard]] TextWithEntities titleWithIconOrLogo() const;
[[nodiscard]] int titleVersion() const;
+ void invalidateTitleWithIcon();
void applyTitle(const QString &title);
[[nodiscard]] DocumentId iconId() const;
void applyIconId(DocumentId iconId);
@@ -206,7 +207,6 @@ private:
void validateGeneralIcon(const Dialogs::Ui::PaintContext &context) const;
void applyTopicTopMessage(MsgId topMessageId);
void growLastKnownServerMessageId(MsgId id);
- void invalidateTitleWithIcon();
void setLastMessage(HistoryItem *item);
void setLastServerMessage(HistoryItem *item);
--
2.52.0.windows.1

View file

@ -4,8 +4,9 @@ Date: Fri, 1 May 2026 15:49:36 +0600
Subject: [PATCH] streamer mode: pseudonym in PeerData::name accessors
---
Telegram/SourceFiles/data/data_peer.cpp | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
Telegram/SourceFiles/data/data_peer.cpp | 20 ++++++++++++++++++++
Telegram/SourceFiles/data/data_peer.h | 1 +
2 files changed, 21 insertions(+)
diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp
index 0000000..0000000 100644
@ -31,9 +32,14 @@ index 0000000..0000000 100644
if (const auto to = migrateTo()) {
return to->topBarNameText();
} else if (const auto user = asUser()) {
@@ -1328,6 +1334,11 @@ int PeerData::nameVersion() const {
@@ -1327,7 +1333,16 @@ int PeerData::nameVersion() const {
return _nameVersion;
}
+void PeerData::noteNameUpdated() {
+ ++_nameVersion;
+}
+
const QString &PeerData::name() const {
+ if (Arcanegram::Streamer::ShouldAnonymize(this)) {
+ static thread_local QString cached;
@ -43,7 +49,7 @@ index 0000000..0000000 100644
if (const auto to = migrateTo()) {
return to->name();
} else if (const auto broadcast = monoforumBroadcast()) {
@@ -1337,6 +1348,11 @@ const QString &PeerData::name() const {
@@ -1337,6 +1352,11 @@ const QString &PeerData::name() const {
}
const QString &PeerData::shortName() const {
@ -55,6 +61,18 @@ index 0000000..0000000 100644
if (const auto user = asUser()) {
return user->firstName.isEmpty() ? user->lastName : user->firstName;
} else if (const auto to = migrateTo()) {
diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h
index 0000000..0000000 100644
--- a/Telegram/SourceFiles/data/data_peer.h
+++ b/Telegram/SourceFiles/data/data_peer.h
@@ -365,6 +365,7 @@ public:
}
[[nodiscard]] int nameVersion() const;
+ void noteNameUpdated();
[[nodiscard]] const QString &name() const;
[[nodiscard]] const QString &shortName() const;
[[nodiscard]] const QString &topBarNameText() const;
--
2.52.0.windows.1

View file

@ -1,55 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: devilreef <devilreef@femboy.page>
Date: Fri, 1 May 2026 16:11:38 +0600
Subject: [PATCH] streamer mode: generic last-seen text
---
Telegram/SourceFiles/data/data_peer_values.cpp | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/Telegram/SourceFiles/data/data_peer_values.cpp b/Telegram/SourceFiles/data/data_peer_values.cpp
index 0000000..0000000 100644
--- a/Telegram/SourceFiles/data/data_peer_values.cpp
+++ b/Telegram/SourceFiles/data/data_peer_values.cpp
@@ -20,6 +20,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
#include "ui/image/image_prepare.h"
#include "base/unixtime.h"
+#include "arcanegram/features/streamer/ag_streamer.h"
+
namespace Data {
namespace {
@@ -472,6 +474,9 @@ QString OnlineText(Data::LastseenStatus status, TimeId now) {
}
QString OnlineText(not_null<UserData*> user, TimeId now) {
+ if (Arcanegram::Streamer::ShouldAnonymize(user)) {
+ return tr::lng_status_recently(tr::now);
+ }
if (const auto special = OnlineTextSpecial(user)) {
return *special;
}
@@ -479,6 +484,9 @@ QString OnlineText(not_null<UserData*> user, TimeId now) {
}
QString OnlineTextFull(not_null<UserData*> user, TimeId now) {
+ if (Arcanegram::Streamer::ShouldAnonymize(user)) {
+ return tr::lng_status_recently(tr::now);
+ }
if (const auto special = OnlineTextSpecial(user)) {
return *special;
} else if (const auto common = OnlineTextCommon(user->lastseen(), now)) {
@@ -501,6 +509,9 @@ QString OnlineTextFull(not_null<UserData*> user, TimeId now) {
}
bool OnlineTextActive(not_null<UserData*> user, TimeId now) {
+ if (Arcanegram::Streamer::ShouldAnonymize(user)) {
+ return false;
+ }
return !user->isServiceUser()
&& !user->isBot()
&& user->lastseen().isOnline(now);
--
2.52.0.windows.1

View file

@ -12,7 +12,7 @@ diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data
index 0000000..0000000 100644
--- a/Telegram/SourceFiles/data/data_peer.cpp
+++ b/Telegram/SourceFiles/data/data_peer.cpp
@@ -1440,7 +1440,17 @@ bool PeerData::clearColorIndex() {
@@ -1444,7 +1444,17 @@ bool PeerData::clearColorIndex() {
return true;
}
@ -30,7 +30,7 @@ index 0000000..0000000 100644
return _backgroundEmojiId;
}
@@ -1501,6 +1511,9 @@ bool PeerData::clearColorProfileIndex() {
@@ -1505,6 +1515,9 @@ bool PeerData::clearColorProfileIndex() {
}
DocumentId PeerData::profileBackgroundEmojiId() const {
@ -40,7 +40,7 @@ index 0000000..0000000 100644
return _profileBackgroundEmojiId;
}
@@ -1526,6 +1539,9 @@ void PeerData::setEmojiStatus(EmojiStatusId emojiStatusId, TimeId until) {
@@ -1530,6 +1543,9 @@ void PeerData::setEmojiStatus(EmojiStatusId emojiStatusId, TimeId until) {
}
EmojiStatusId PeerData::emojiStatusId() const {

2
series
View file

@ -33,7 +33,7 @@ feature/streamer-mode-style.patch
feature/streamer-mode-badge.patch
feature/streamer-mode-profile-identity.patch
feature/streamer-mode-profile-actions.patch
feature/streamer-mode-online.patch
feature/streamer-mode-autocomplete.patch
feature/streamer-mode-search.patch
feature/streamer-mode-forum-topic.patch
misc/branding.patch

View file

@ -3,6 +3,8 @@
#include "core/application.h"
#include "data/data_channel.h"
#include "data/data_chat.h"
#include "data/data_forum.h"
#include "data/data_forum_topic.h"
#include "data/data_peer.h"
#include "data/data_session.h"
#include "data/data_user.h"
@ -14,7 +16,6 @@
#include "main/main_session.h"
namespace Arcanegram {
namespace {
void ForEachLoadedHistory(Fn<void(not_null<History*>)> action) {
for (const auto &entry : Core::App().domain().accounts()) {
@ -40,7 +41,32 @@ void ForEachLoadedHistory(Fn<void(not_null<History*>)> action) {
}
}
} // namespace
void ForEachLoadedTopic(Fn<void(not_null<Data::ForumTopic*>)> action) {
for (const auto &entry : Core::App().domain().accounts()) {
const auto session = entry.account->maybeSession();
if (!session) {
continue;
}
auto &owner = session->data();
owner.enumerateBroadcasts([&](not_null<ChannelData*> p) {
if (const auto forum = p->forum()) {
forum->enumerateTopics([&](not_null<Data::ForumTopic*> t) {
action(t);
});
}
});
owner.enumerateGroups([&](not_null<PeerData*> p) {
if (const auto channel = p->asChannel()) {
if (const auto forum = channel->forum()) {
forum->enumerateTopics(
[&](not_null<Data::ForumTopic*> t) {
action(t);
});
}
}
});
}
}
void ForEachLoadedItem(Fn<void(not_null<HistoryItem*>)> action) {
ForEachLoadedHistory([&](not_null<History*> h) {

View file

@ -6,6 +6,10 @@ class History;
class HistoryItem;
class PeerData;
namespace Data {
class ForumTopic;
} // namespace Data
namespace Arcanegram {
void ForEachLoadedItem(Fn<void(not_null<HistoryItem*>)> action);
@ -14,6 +18,10 @@ void ForEachLoadedHistoryFor(PeerId id, Fn<void(not_null<History*>)> action);
void ForEachLoadedPeer(Fn<void(not_null<PeerData*>)> action);
void ForEachLoadedTopic(Fn<void(not_null<Data::ForumTopic*>)> action);
void ForEachLoadedHistory(Fn<void(not_null<History*>)> action);
void RefreshAllItems();
} // namespace Arcanegram

View file

@ -6,8 +6,11 @@
#include "arcanegram/ui/ag_settings_main.h"
#include "arcanegram/ui/ag_settings_widgets.h"
#include "data/data_changes.h"
#include "data/data_forum_topic.h"
#include "data/data_peer.h"
#include "data/data_user.h"
#include "history/history.h"
#include "history/history_item.h"
#include "lang/lang_keys.h"
#include "main/main_session.h"
#include "settings/settings_builder.h"
@ -57,10 +60,28 @@ void RefreshAll() {
| Flag::Color
| Flag::EmojiStatus;
ForEachLoadedPeer([&](not_null<PeerData*> peer) {
// drop empty-userpic cache pinned to first-seen name initials.
peer->invalidateEmptyUserpic();
// bump _nameVersion so dialog row name cache rebuilds.
peer->noteNameUpdated();
peer->session().changes().peerUpdated(peer, flags);
});
ForEachLoadedTopic([&](not_null<Data::ForumTopic*> topic) {
topic->invalidateTitleWithIcon();
topic->session().changes().topicUpdated(
topic,
Data::TopicUpdate::Flag::Title);
if (const auto last = topic->chatListMessage()) {
last->invalidateChatListEntry();
}
topic->updateChatListEntry();
});
ForEachLoadedHistory([&](not_null<History*> h) {
// drop sender prefix cache in dialog list message preview.
if (const auto last = h->chatListMessage()) {
last->invalidateChatListEntry();
}
h->updateChatListEntry();
});
RefreshAllItems();
}