Message Logger: hidden messages on the server, removed chats, old chat photos
Publish plugin / publish (push) Successful in 6s

- Hidden deleted messages are marked on the server (local marks migrated);
  "Reveal hidden messages" in the chat menu, Unhide in the message menu and
  the selection bar.
- Chats an account lost are reported, listed among its chats again and
  opened read-only with their logged messages, all deleted.
- Logged chat photos: a removed chat's avatar, and in a chat's photos the
  ones it no longer has, translucent with a trash icon in the viewer's
  previews.
- Fix: the deleted-post comments thread is answered locally again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
lyuksovannyyandClaude Opus 5.5 committed 2026-10-10 23:12:33 +02:00
1 parent 0176f7099d
commit 362b358d8d
15 files changed
+1821 -125

No files matched your search

+32 -18
View File
@@ -1,4 +1,5 @@
""""Edit history" in the message menu itself, right above Forward.
""""Edit history" (and "Unhide" for a revealed hidden message, see
hooks/hidden.py) in the message menu itself, right above Forward.
Plugin menu items (MenuItemData) only go into the menu's Plugins folder, and
exteraGram drops option ids it doesn't know from fillMessageMenu's lists, so
@@ -12,10 +13,12 @@ from base_plugin import MethodHook
import diag
import store
from hooks.hidden import is_revealed_hidden
from jutil import field, hook_methods, java_class
CHAT = "org.telegram.ui.ChatActivity"
_LABEL = "Edit history"
_HISTORY = "Edit history"
_UNHIDE = "Unhide"
def _worth_it(message):
@@ -58,9 +61,10 @@ def _find_item(view, text):
class Menu:
def __init__(self, plugin, open_history):
def __init__(self, plugin, open_history, unhide):
self.plugin = plugin
self.open_history = open_history
self.unhide = unhide # hooks/hidden.Hidden.unhide
self.handles = []
self._close = None
@@ -87,39 +91,49 @@ class Menu:
def add_item(self, chat):
message = field(chat, "selectedObject")
popup = field(chat, "scrimPopupWindow")
if popup is None or not _worth_it(message):
if popup is None or message is None:
return
# The createMenu overloads call one another: add the row once.
if _find_item(popup.getContentView(), _LABEL) is not None:
return
from org.telegram.messenger import LocaleController, R
from org.telegram.messenger import R
rows = []
if _worth_it(message):
rows.append((_HISTORY, R.drawable.msg_edit, lambda: self.open_history(message)))
if is_revealed_hidden(message):
rows.append((_UNHIDE, R.drawable.msg_views, lambda: self.unhide([message])))
# The createMenu overloads call one another: add the rows once.
content = popup.getContentView()
if not rows or _find_item(content, rows[0][0]) is not None:
return
from org.telegram.messenger import LocaleController
# Forward is a row in some chats and an icon in the bottom action bar
# in others (groups): then the row goes first in the list.
# in others (groups): then the rows go first in the list.
anchor = _find_item(
content, str(LocaleController.getString(R.string.Forward))
) or _first_item(content)
if anchor is None:
diag.log("menu: no row to place Edit history by")
diag.log("menu: no row to place the rows by")
return
forward = anchor
for label, icon, action in rows:
self._add_row(chat, anchor, label, icon, action)
def _add_row(self, chat, anchor, label, icon, action):
from android_utils import OnClickListener
from org.telegram.ui.ActionBar import ActionBarMenuSubItem
parent = forward.getParent()
item = ActionBarMenuSubItem(forward.getContext(), False, False)
item.setTextAndIcon(_LABEL, R.drawable.msg_edit)
color = forward.getTextView().getCurrentTextColor()
parent = anchor.getParent()
item = ActionBarMenuSubItem(anchor.getContext(), False, False)
item.setTextAndIcon(label, icon)
color = anchor.getTextView().getCurrentTextColor()
item.setColors(color, color)
item.setMinimumWidth(forward.getMinimumWidth())
item.setMinimumWidth(anchor.getMinimumWidth())
def chosen(_view):
self._close_menu(chat)
self.open_history(message)
action()
item.setOnClickListener(OnClickListener(chosen))
parent.addView(item, parent.indexOfChild(forward), forward.getLayoutParams())
parent.addView(item, parent.indexOfChild(anchor), anchor.getLayoutParams())
def _close_menu(self, chat):
if self._close is None: