generated from exteraGramPlugins/pluginBase
Message Logger: show logged edits and deletions from telegram-panel [no bump]
Publish plugin / publish (push) Successful in 4s
Publish plugin / publish (push) Successful in 4s
Keeps deleted messages (75% opacity, red icon-pack trash icon), restores logged messages deleted while away, reports deletions, and shows edit history as a mock chat (Edit history in the message menu, Open topic). Message links and history open as any signed-in account with access. Per-master API tokens; chat state synced per checked range with an hour's validity, cached in SQLite with a configurable lifetime. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
80f1d5e55c
commit
9b2f26a845
26 files changed
+2928
-112
No files matched your search
@@ -0,0 +1,129 @@
|
||||
""""Edit history" 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 jutil import field, hook_methods, java_class
|
||||
|
||||
CHAT = "org.telegram.ui.ChatActivity"
|
||||
_LABEL = "Edit history"
|
||||
|
||||
|
||||
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):
|
||||
self.plugin = plugin
|
||||
self.open_history = open_history
|
||||
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 not _worth_it(message):
|
||||
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
|
||||
|
||||
content = popup.getContentView()
|
||||
# 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.
|
||||
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")
|
||||
return
|
||||
forward = anchor
|
||||
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()
|
||||
item.setColors(color, color)
|
||||
item.setMinimumWidth(forward.getMinimumWidth())
|
||||
|
||||
def chosen(_view):
|
||||
self._close_menu(chat)
|
||||
self.open_history(message)
|
||||
|
||||
item.setOnClickListener(OnClickListener(chosen))
|
||||
parent.addView(item, parent.indexOfChild(forward), forward.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)
|
||||
Reference in new issue
Block a user