generated from exteraGramPlugins/pluginBase
Adds a share action to the Instant View photo viewer that downloads the media and re-sends it from the user's own account with a text_url caption linking back to the source article. - src/main.py: hooks PhotoViewer.onPhotoShow, injects the toolbar item - src/ivmedia.py: resolves the viewer's page block to a TL media object - src/picker.py: share sheet + comment field (restores focus after the keyboard animation, which PhotoViewer.showShareAlert does itself) - src/sender.py: FileLoader download, cache reuse, re-send with caption - src/icons.py: IconManager-aware drawable lookup so icon packs apply - tools/verify_bundle.py: offline checks for URL acceptance, caption entity shape and bundled-module isolation Drops the sample greeting/textutil modules.
This commit is contained in:
1 parent
bfd0f80c6f
commit
05c5212a8a
10 files changed
+757
-95
No files matched your search
@@ -0,0 +1,92 @@
|
||||
"""Opens the client's own "Share / Forward to" sheet and reports the chosen chats.
|
||||
|
||||
`ShareAlert` is the sheet the app itself uses for forwarding, so reusing it keeps
|
||||
the picker pixel-identical to the stock one. It is constructed with no payload
|
||||
(`sendingMessageObjects`, `sendingText` and `sendingFile` all null), which makes
|
||||
its send path a no-op: it selects chats, fires `ShareAlertDelegate.didShare()`
|
||||
and dismisses. The selection is read back off the (protected) `selectedDialogs`
|
||||
field and the comment off `commentTextView`.
|
||||
"""
|
||||
|
||||
from android_utils import log, run_on_ui_thread
|
||||
from hook_utils import get_private_field
|
||||
|
||||
_delegate_class = None
|
||||
|
||||
# ShareAlert's own constant for "keep the keyboard out of the way".
|
||||
_SOFT_INPUT_ADJUST_NOTHING = 48
|
||||
|
||||
# PhotoViewer hands focus over after AdjustPanLayoutHelper.keyboardDuration,
|
||||
# which is 250ms in the app's animation constants.
|
||||
_FOCUS_DELAY_MS = 250
|
||||
|
||||
|
||||
def _make_delegate_class():
|
||||
"""Builds the ShareAlertDelegate proxy lazily: the Java interface can only
|
||||
be resolved once the app classes are loadable."""
|
||||
from java import dynamic_proxy
|
||||
from org.telegram.ui.Components import ShareAlert
|
||||
|
||||
class Delegate(dynamic_proxy(ShareAlert.ShareAlertDelegate)):
|
||||
def __init__(self, alert, on_picked):
|
||||
super().__init__()
|
||||
self.alert = alert
|
||||
self.on_picked = on_picked
|
||||
|
||||
def didCopy(self):
|
||||
return False
|
||||
|
||||
def didShare(self):
|
||||
self.on_picked(_selected_peers(self.alert), _comment(self.alert))
|
||||
|
||||
return Delegate
|
||||
|
||||
|
||||
def _selected_peers(alert):
|
||||
dialogs = get_private_field(alert, "selectedDialogs")
|
||||
if dialogs is None:
|
||||
return []
|
||||
return [dialogs.keyAt(i) for i in range(dialogs.size())]
|
||||
|
||||
|
||||
def _comment(alert):
|
||||
field = get_private_field(alert, "commentTextView")
|
||||
if field is None:
|
||||
return ""
|
||||
text = field.getText()
|
||||
return str(text).strip() if text is not None else ""
|
||||
|
||||
|
||||
def pick_chats(context, on_picked, resources_provider=None):
|
||||
"""Shows the stock share sheet. `on_picked(dialog_ids, comment)` runs on the
|
||||
UI thread once the user confirms."""
|
||||
global _delegate_class
|
||||
from org.telegram.ui.Components import ShareAlert
|
||||
|
||||
alert = ShareAlert(context, None, None, False, None, False, resources_provider)
|
||||
|
||||
if _delegate_class is None:
|
||||
_delegate_class = _make_delegate_class()
|
||||
# Keep a reference on the module so the proxy is not collected early.
|
||||
delegate = _delegate_class(alert, on_picked)
|
||||
alert.setDelegate(delegate)
|
||||
pick_chats._alive = delegate
|
||||
|
||||
# ShareAlert opens over PhotoViewer's window. Taking focus immediately
|
||||
# fights the viewer's own window animation, so the stock code in
|
||||
# PhotoViewer.showShareAlert() starts unfocused and hands focus over once
|
||||
# the keyboard-transition window has passed; without that second step the
|
||||
# comment field can be tapped but never receives key events.
|
||||
alert.setFocusable(False)
|
||||
alert.getWindow().setSoftInputMode(_SOFT_INPUT_ADJUST_NOTHING)
|
||||
run_on_ui_thread(lambda: _enable_focus(alert), _FOCUS_DELAY_MS)
|
||||
alert.show()
|
||||
return alert
|
||||
|
||||
|
||||
def _enable_focus(alert):
|
||||
try:
|
||||
if alert.getWindow() is not None:
|
||||
alert.setFocusable(True)
|
||||
except Exception as exc:
|
||||
log("[telegraph_media_forward] focus handoff failed: %s" % exc)
|
||||
Reference in new issue
Block a user