generated from exteraGramPlugins/pluginBase
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>
144 lines
5.2 KiB
Python
144 lines
5.2 KiB
Python
""""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
|
|
the row is added to the built popup instead: after ChatActivity.createMenu,
|
|
an ActionBarMenuSubItem styled like the Forward row (found by its localized
|
|
text) is inserted above it, or first in the list when Forward is an icon of
|
|
the bottom action bar (groups). ChatActivity.selectedObject is the message.
|
|
"""
|
|
|
|
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"
|
|
_HISTORY = "Edit history"
|
|
_UNHIDE = "Unhide"
|
|
|
|
|
|
def _worth_it(message):
|
|
"""Messages that may have a logged history: edited ones (the app's own
|
|
flag or the server's state), which logger posts are once their header
|
|
was refreshed."""
|
|
if message is None or int(message.getId()) <= 0:
|
|
return False
|
|
if int(getattr(message.messageOwner, "edit_date", 0) or 0):
|
|
return True
|
|
return store.is_edited(
|
|
int(message.currentAccount), int(message.getDialogId()), int(message.getId())
|
|
)
|
|
|
|
|
|
def _first_item(view):
|
|
"""The first ActionBarMenuSubItem under `view` (the main page comes
|
|
before the swipe-back pages), else None."""
|
|
if view.getClass().getSimpleName() == "ActionBarMenuSubItem":
|
|
return view
|
|
if hasattr(view, "getChildCount"):
|
|
for index in range(view.getChildCount()):
|
|
found = _first_item(view.getChildAt(index))
|
|
if found is not None:
|
|
return found
|
|
return None
|
|
|
|
|
|
def _find_item(view, text):
|
|
"""The ActionBarMenuSubItem showing `text` under `view`, else None."""
|
|
if view.getClass().getSimpleName() == "ActionBarMenuSubItem":
|
|
label = view.getTextView()
|
|
return view if label is not None and str(label.getText()) == text else None
|
|
if hasattr(view, "getChildCount"):
|
|
for index in range(view.getChildCount()):
|
|
found = _find_item(view.getChildAt(index), text)
|
|
if found is not None:
|
|
return found
|
|
return None
|
|
|
|
|
|
class Menu:
|
|
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
|
|
|
|
def install(self):
|
|
menu = self
|
|
|
|
class AfterCreate(MethodHook):
|
|
def after_hooked_method(self, param):
|
|
try:
|
|
menu.add_item(param.thisObject)
|
|
except Exception as exc:
|
|
diag.error("menu.add", exc)
|
|
|
|
self.handles += hook_methods(self.plugin, CHAT, "createMenu", AfterCreate())
|
|
|
|
def uninstall(self):
|
|
for handle in self.handles:
|
|
try:
|
|
self.plugin.unhook_method(handle)
|
|
except Exception:
|
|
pass
|
|
self.handles = []
|
|
|
|
def add_item(self, chat):
|
|
message = field(chat, "selectedObject")
|
|
popup = field(chat, "scrimPopupWindow")
|
|
if popup is None or message is None:
|
|
return
|
|
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 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 the rows by")
|
|
return
|
|
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 = anchor.getParent()
|
|
item = ActionBarMenuSubItem(anchor.getContext(), False, False)
|
|
item.setTextAndIcon(label, icon)
|
|
color = anchor.getTextView().getCurrentTextColor()
|
|
item.setColors(color, color)
|
|
item.setMinimumWidth(anchor.getMinimumWidth())
|
|
|
|
def chosen(_view):
|
|
self._close_menu(chat)
|
|
action()
|
|
|
|
item.setOnClickListener(OnClickListener(chosen))
|
|
parent.addView(item, parent.indexOfChild(anchor), anchor.getLayoutParams())
|
|
|
|
def _close_menu(self, chat):
|
|
if self._close is None:
|
|
method = java_class(CHAT).getDeclaredMethod("closeMenu")
|
|
method.setAccessible(True)
|
|
self._close = method
|
|
self._close.invoke(chat)
|