generated from exteraGramPlugins/pluginBase
[no bump] Ghost Mode: AyuGram's ghost mode with per-account and per-chat settings
Publish plugin / publish (push) Successful in 5s
Publish plugin / publish (push) Successful in 5s
Read receipts, story views, typing and online status are held back per the options; read on interact, scheduled and silent sending as in AyuGram. Every option resolves chat -> account -> global; forum topics follow their group. Settings live in the plugin page, a chat/profile menu popup, and a drawer row for the current account. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
dfd1f659fe
commit
00553970b7
20 files changed
+3223
-178
No files matched your search
@@ -0,0 +1,186 @@
|
||||
"""The plugin's settings screen.
|
||||
|
||||
main page global ghost mode switch, the option switches, the accounts
|
||||
account page that account's choice per option (Global / On / Off) and
|
||||
its chat exceptions
|
||||
"""
|
||||
|
||||
from ui.settings import Divider, Header, Selector, Switch, Text
|
||||
|
||||
import features
|
||||
import peers
|
||||
from prefs import INHERIT, OFF, ON, account_key, chats_key, global_key
|
||||
|
||||
GHOST_KEY = "g_ghost"
|
||||
GHOST_ICON = "ghost"
|
||||
|
||||
|
||||
def _state(value):
|
||||
return "On" if value else "Off"
|
||||
|
||||
|
||||
class SettingsPage:
|
||||
def __init__(self, plugin, prefs, menus):
|
||||
self.plugin = plugin
|
||||
self.prefs = prefs
|
||||
self.menus = menus
|
||||
|
||||
# main page
|
||||
|
||||
def build(self):
|
||||
prefs = self.prefs
|
||||
# The master switch shows whether every essential is on (AyuGram's
|
||||
# isGhostModeActive), whichever way they got there.
|
||||
self.plugin.set_setting(GHOST_KEY, prefs.ghost_active(0))
|
||||
rows = [
|
||||
Header(text="Ghost mode"),
|
||||
Switch(
|
||||
key=GHOST_KEY,
|
||||
text="Ghost mode",
|
||||
default=False,
|
||||
subtext="Turns all ghost essentials on or off",
|
||||
icon=GHOST_ICON,
|
||||
on_change=self._on_ghost_change,
|
||||
),
|
||||
Header(text="Ghost essentials"),
|
||||
]
|
||||
rows += [self._switch(f) for f in features.ESSENTIALS]
|
||||
rows.append(Header(text="Options"))
|
||||
rows += [self._switch(f) for f in features.EXTRAS]
|
||||
rows.append(Divider(text="These are the defaults. Each account can override them, and each chat can override its account: open the chat's ⋮ menu → Ghost mode."))
|
||||
rows.append(Header(text="Accounts"))
|
||||
accounts = self._accounts()
|
||||
for slot, uid in accounts:
|
||||
rows.append(
|
||||
Text(
|
||||
text=peers.account_name(slot),
|
||||
subtext=self._account_summary(uid),
|
||||
icon="msg_contacts",
|
||||
create_sub_fragment=lambda slot=slot, uid=uid: self.build_account(slot, uid),
|
||||
)
|
||||
)
|
||||
if not accounts:
|
||||
rows.append(Text(text="No signed-in accounts", icon="msg_info"))
|
||||
rows.append(Divider(text="The side menu's Ghost mode item opens these options for the account in use."))
|
||||
return rows
|
||||
|
||||
def _switch(self, feature):
|
||||
return Switch(
|
||||
key=global_key(feature),
|
||||
text=feature.title,
|
||||
default=feature.default,
|
||||
subtext=feature.subtext,
|
||||
icon=feature.icon,
|
||||
on_change=self._on_essential_change if feature.essential else None,
|
||||
)
|
||||
|
||||
def _on_ghost_change(self, enabled):
|
||||
for feature in features.ESSENTIALS:
|
||||
self.prefs.set_global(feature, enabled)
|
||||
self.plugin.set_setting(GHOST_KEY, bool(enabled), True)
|
||||
|
||||
def _on_essential_change(self, _value):
|
||||
active = self.prefs.ghost_active(0)
|
||||
if bool(self.plugin.get_setting(GHOST_KEY, False)) != active:
|
||||
self.plugin.set_setting(GHOST_KEY, active, True)
|
||||
|
||||
def _accounts(self):
|
||||
try:
|
||||
return peers.signed_in()
|
||||
except Exception as exc:
|
||||
self.plugin.log(f"accounts: {exc}")
|
||||
return []
|
||||
|
||||
def _account_summary(self, uid):
|
||||
overridden = len(self.prefs.account_overrides(uid))
|
||||
chats = len(self.prefs.chat_overrides(uid))
|
||||
parts = [f"Ghost mode {_state(self.prefs.ghost_active(uid)).lower()}"]
|
||||
parts.append(f"{overridden} own option{'s' if overridden != 1 else ''}" if overridden else "global options")
|
||||
if chats:
|
||||
parts.append(f"{chats} chat exception{'s' if chats != 1 else ''}")
|
||||
return " · ".join(parts)
|
||||
|
||||
# account page
|
||||
|
||||
def build_account(self, slot, uid):
|
||||
prefs = self.prefs
|
||||
ghost_key = f"a_{uid}_ghost"
|
||||
self.plugin.set_setting(ghost_key, self._ghost_choice(uid))
|
||||
rows = [
|
||||
Header(text=peers.account_name(slot)),
|
||||
Selector(
|
||||
key=ghost_key,
|
||||
text="Ghost mode",
|
||||
default=INHERIT,
|
||||
items=["Global", "On", "Off"],
|
||||
icon=GHOST_ICON,
|
||||
on_change=lambda choice: self._on_account_ghost_change(uid, choice),
|
||||
),
|
||||
Header(text="Options"),
|
||||
]
|
||||
for feature in features.ALL:
|
||||
global_value = prefs.global_value(feature)
|
||||
rows.append(
|
||||
Selector(
|
||||
key=account_key(uid, feature),
|
||||
text=feature.title,
|
||||
default=INHERIT,
|
||||
items=[f"Global ({_state(global_value)})", "On", "Off"],
|
||||
icon=feature.icon,
|
||||
on_change=lambda _choice: self._refresh_account_ghost(uid),
|
||||
)
|
||||
)
|
||||
rows.append(Divider(text="Global follows the plugin's main switches."))
|
||||
rows.append(Header(text="Chat exceptions"))
|
||||
chats = prefs.chat_overrides(uid)
|
||||
for dialog, values in sorted(chats.items(), key=lambda item: peers.dialog_title(slot, item[0]).lower()):
|
||||
rows.append(
|
||||
Text(
|
||||
text=peers.dialog_title(slot, dialog),
|
||||
subtext=" · ".join(
|
||||
f"{features.BY_KEY[k].title}: {_state(v)}" for k, v in values.items()
|
||||
),
|
||||
icon="msg_discussion",
|
||||
on_click=lambda _view, dialog=dialog: self._edit_chat(slot, uid, dialog),
|
||||
)
|
||||
)
|
||||
if chats:
|
||||
rows.append(
|
||||
Text(
|
||||
text="Remove all chat exceptions",
|
||||
icon="msg_delete",
|
||||
red=True,
|
||||
on_click=lambda _view: prefs.clear_chats(uid, True),
|
||||
)
|
||||
)
|
||||
else:
|
||||
rows.append(Text(text="No chat exceptions", icon="msg_info"))
|
||||
rows.append(Divider(text="Add one from a chat's ⋮ menu → Ghost mode. Tap an exception to change it."))
|
||||
return rows
|
||||
|
||||
def _ghost_choice(self, uid):
|
||||
"""What the account's Ghost mode selector shows."""
|
||||
choices = {self.prefs.account_choice(uid, f) for f in features.ESSENTIALS}
|
||||
if choices == {INHERIT}:
|
||||
return INHERIT
|
||||
return ON if self.prefs.ghost_active(uid) else OFF
|
||||
|
||||
def _on_account_ghost_change(self, uid, choice):
|
||||
for feature in features.ESSENTIALS:
|
||||
self.prefs.set_account_choice(uid, feature, choice)
|
||||
self.plugin.set_setting(f"a_{uid}_ghost", int(choice), True)
|
||||
|
||||
def _refresh_account_ghost(self, uid):
|
||||
key = f"a_{uid}_ghost"
|
||||
choice = self._ghost_choice(uid)
|
||||
if self.plugin.get_setting(key, INHERIT) != choice:
|
||||
self.plugin.set_setting(key, choice, True)
|
||||
|
||||
def _edit_chat(self, slot, uid, dialog):
|
||||
# Reload the page once the dialog closes, so the list shows the result.
|
||||
raw_key = chats_key(uid)
|
||||
|
||||
def closed():
|
||||
self.plugin.set_setting(raw_key, self.plugin.get_setting(raw_key, ""), True)
|
||||
|
||||
self.menus.open_chat_dialog(slot, dialog, closed)
|
||||
Reference in new issue
Block a user