exteragram-alib 🚀
Мощная библиотека реактивного декларативного UI и утилит управления потоками для разработки плагинов exteraGram (Android-клиент Telegram).
A powerful reactive declarative UI and threading utility library for writing exteraGram (Android Telegram client) plugins.
Содержание / Table of Contents
- Установка / Installation
- Реактивное состояние / Reactive States (State)
- Декларативный UI / Declarative UI
- Интерактивные виджеты / Interactive Widgets
- Контейнеры разметки / Layout Containers
- Экран настроек / Settings Wrapper (to_setting)
- Всплывающие экраны / Bottom Sheets
- Управление потоками / Threading & Dispatching
- Утилиты рефлексии Java / Java Reflection Helpers
- Локальная база данных JSON / SimpleDB
- Шина событий / EventBus
- Сетевые декораторы / Network Utilities (Caching & Rate-Limiting)
1. Установка / Installation
Укажите библиотеку в списке внешних зависимостей вашего плагина в переменной __requirements__ (exteraGram автоматически скачает её при установке плагина):
Add the library to the __requirements__ metadata list in your exteraGram plugin:
__requirements__ = ["exteragram-alib"]
2. Реактивное состояние / Reactive States (State)
Класс State связывает переменные с UI-компонентами. При обновлении значения через .set(), все подписанные элементы интерфейса автоматически перерисовываются на Android-устройстве.
from alib import State
# Инициализация состояния
my_state = State("Начальный текст")
# Получение значения
current_val = my_state.get()
# Обновление значения (вызывает автоматическую перерисовку привязанных UI-элементов)
my_state.set("Новый реактивный текст")
# Подписка на изменение вручную (если необходимо)
def on_change(val):
print(f"Значение изменилось на: {val}")
my_state.add_listener(on_change)
3. Декларативный UI / Declarative UI
Каждый виджет наследуется от базового класса Widget и поддерживает следующие настройки макета (layout properties):
width—"match"(по всей ширине),"wrap"(по размеру содержимого) или числовое значение в dp.height—"match","wrap"или числовое значение в dp.weight— вес элемента в распределении пространства (float, например1.0).gravity— выравнивание (используется изandroid.view.Gravity).margins— внешние отступы в формате списка[left, top, right, bottom]в dp.padding— внутренние отступы в формате списка[left, top, right, bottom]в dp.
4. Интерактивные виджеты / Interactive Widgets
Label (Текст)
Обычное текстовое поле. Может принимать State в качестве параметра text для реактивного обновления.
from alib import Label
lbl = Label(
text=my_state, # Текст или реактивный State
text_size=15, # Размер шрифта в sp
color=0xFF3390EC, # Цвет текста в формате ARGB/HEX
bold=True # Жирный шрифт (True/False)
)
Button (Кнопка)
Простая кликабельная кнопка.
from alib import Button
btn = Button(
text="Нажми меня",
on_click=lambda view: print("Кнопка нажата!"),
padding=[8, 16, 8, 16]
)
Field (Поле ввода)
Поле текстового ввода. Позволяет реактивно синхронизировать текст с State.
from alib import Field
field = Field(
text=my_text_state, # Привязанный State для двусторонней синхронизации
hint="Введите имя..." # Подсказка
)
Toggle (Переключатель)
Двухпозиционный переключатель (активен/неактивен).
from alib import Toggle
toggle = Toggle(
value=my_boolean_state, # Привязанный boolean State
on_change=lambda val: print(f"Новое состояние: {val}")
)
Radio (Радио-кнопка)
Круглая радио-кнопка для выбора из вариантов.
from alib import Radio
# radio_state принимает checked_value при выборе
radio = Radio(
value=radio_state, # Общий State выбора
checked_value=1, # Значение данного варианта
on_change=lambda val: print(f"Выбран вариант: {val}")
)
Selector (Выпадающий список)
Строка выбора значения. При нажатии открывает системный AlertDialog со списком вариантов.
from alib import Selector
sel = Selector(
text="Выбор языка",
items=["Русский", "English", "Deutsch"],
value=lang_index_state, # Реактивный State (хранит индекс выбранного элемента)
icon="msg_language", # Иконка Telegram
on_change=lambda idx: print(f"Выбран индекс: {idx}")
)
Slider (Слайдер)
Слайдер для выбора числового значения.
from alib import Slider
slider = Slider(
value=num_state, # Привязанный State (int)
min_val=12, # Минимальное значение
max_val=30, # Максимальное значение
to_string=lambda label_type, val: f"Шрифт: {val}sp" # Форматирование отображения
)
AltSeekbar (Альтернативный слайдер)
Слайдер с отображением заголовка и крайних текстовых значений (слева/справа).
from alib import AltSeekbar
alt_slider = AltSeekbar(
value=float_state,
min_val=0,
max_val=28,
title="Скругление углов",
left_text="0%",
right_text="100%",
on_change=lambda val: print(f"Значение изменено: {val}")
)
RowItem (Ячейка списка)
Строка в стиле настроек Telegram. Поддерживает иконку, заголовок, описание и правый виджет.
from alib import RowItem, Toggle
row = RowItem(
title="Оповещения",
subtext="Включить всплывающие уведомления чатов",
icon="msg_notifications",
right_widget=Toggle(value=notif_state)
)
ActionRow (Ячейка действия)
Ячейка со встроенной кнопкой действия справа.
from alib import ActionRow
action = ActionRow(
title="Счетчик кликов",
subtext=click_counter_state, # Реактивный текст
button_text="Кликнуть", # Текст на кнопке
icon="msg_folders", # Иконка слева
on_button_click=lambda view: click_counter_state.set(click_counter_state.get() + 1)
)
5. Контейнеры разметки / Layout Containers
VBox (Вертикальный контейнер)
Размещает дочерние элементы вертикально один под другим.
from alib import VBox
vbox = VBox(
padding=[16, 16, 16, 16], # Внутренние отступы
children=[widget1, widget2]
)
HBox (Горизонтальный контейнер)
Размещает дочерние элементы горизонтально в ряд.
from alib import HBox
hbox = HBox(
children=[widget1, widget2]
)
Card (Карточка/Секция)
Контейнер со скругленными углами и фоном. По умолчанию автоматически отрисовывает разделительные линии (Divider) между дочерними элементами.
from alib import Card, RowItem, Toggle
card = Card(
radius=20, # Радиус скругления углов карточки
show_dividers=True, # Показывать разделители между ячейками
children=[
RowItem(title="Пункт 1", right_widget=Toggle(value=s1)),
RowItem(title="Пункт 2", right_widget=Toggle(value=s2)),
]
)
6. Экран настроек / Settings Wrapper (to_setting)
Для внедрения кастомных декларативных UI-интерфейсов на стандартный экран настроек плагина в exteraGram, оберните виджет функцией to_setting():
from alib import to_setting, RowItem, Toggle
class MyPlugin(BasePlugin):
def create_settings(self) -> List[Any]:
return [
to_setting(
RowItem(title="Включить хуки", right_widget=Toggle(value=self.state))
)
]
[!IMPORTANT] Важно: На стандартном экране настроек плагина (
create_settings) exteraGram автоматически группирует возвращаемые элементы в системные карточки. Не оборачивайте элементы в контейнерCardвнутриcreate_settingsвручную, иначе это приведет к двойному вложению карточек.Класс
Cardпредназначен главным образом для использования внутри всплывающих окон (show_bottom_sheet), где группировка по умолчанию отсутствует и карточки нужно собирать вручную.
7. Всплывающие экраны / Bottom Sheets
Функция show_bottom_sheet() позволяет отобразить кастомный диалог в стиле BottomSheet Telegram поверх любого экрана приложения. Она автоматически обрабатывает жесты смахивания вниз для закрытия с учетом состояния прокрутки.
from alib import show_bottom_sheet, VBox, Header, Card, Button
def open_my_sheet(fragment):
sheet_layout = VBox(
padding=[0, 0, 0, 16],
children=[
Header(text="Кастомное меню"),
Card(children=[...])
]
)
# Возвращает экземпляр BottomSheet диалога
sheet = show_bottom_sheet(
fragment=fragment, # Контекст/фрагмент Telegram
title="Мой Заголовок", # Текст заголовка
content_layout=sheet_layout, # Корневой декларативный виджет
center_header=True, # Центрировать ли заголовок
height_pct=0.8 # Высота экрана (80% от высоты экрана)
)
8. Управление потоками / Threading & Dispatching
Упрощает асинхронное выполнение задач и потокобезопасную работу с интерфейсом.
@main_thread (алиас @run_on_ui)
Декоратор перенаправляет выполнение функции в главный (UI) поток Android для безопасного взаимодействия с интерфейсом.
from alib import main_thread
@main_thread
def update_status(message: str):
# Этот код гарантированно выполнится на UI-потоке Android
status_label.set(message)
@background_thread (алиас @run_on_background)
Декоратор запускает функцию асинхронно в одной из фоновых очередей Telegram с возможностью задержки.
queue— имя очереди:"plugins"(по умолчанию),"global","network","search".delay— задержка запуска в миллисекундах (по умолчанию0).
from alib import background_thread
@background_thread(queue="network", delay=1500)
def load_web_data():
# Запустится через 1.5 секунды в фоне на сетевом потоке
result = make_api_request()
update_status(result) # Отправляем результат обратно на UI-поток
Запуск анонимных функций (run_main и run_bg)
Если не нужно создавать именованную функцию с декоратором, используйте хелперы:
from alib import run_main, run_bg
# Выполнить в фоне
run_bg(lambda: save_cache_to_disk(), queue="plugins", delay=500)
# Вернуть управление на UI
run_main(lambda: show_success_toast())
9. Утилиты рефлексии Java / Java Reflection Helpers
Библиотека предоставляет безопасные функции-хелперы для инспектирования и модификации полей/методов Java-объектов на Android (без написания громоздкого рефлексивного кода).
get_field(obj, field_name)— Возвращает значение приватного/публичного поля. Автоматически ищет в суперклассах.set_field(obj, field_name, value)— Устанавливает значение поля. ВозвращаетTrueпри успехе.call_method(obj, method_name, *args)— Вызывает метод по имени с автоматическим сопоставлением сигнатуры и количества аргументов.
from alib import get_field, set_field, call_method
# Получить приватное значение
username = get_field(telegram_user, "username")
# Перезаписать флаг редактирования сообщения
set_field(message_object, "isEdited", True)
# Вызвать скрытый метод
call_method(chat_activity, "showChatInfo", chat_id)
10. Локальная база данных JSON / SimpleDB
Потокобезопасная Key-Value база данных, хранящая данные в формате JSON в директории плагина на устройстве. Запись на диск выполняется атомарно через создание временного файла, что предотвращает повреждение базы при внезапном выходе из приложения.
db.set(key, value)— Сохраняет значение.db.get(key, default=None)— Читает значение.db.delete(key)— Удаляет ключ.db.clear()— Очищает базу данных.db.increment(key, amount=1)— Потокобезопасно увеличивает числовой счетчик на указанное значение.
from alib import SimpleDB
# База данных "userdata" автоматически создается в надежной папке плагина
db = SimpleDB("userdata")
# Сохранение и чтение любых типов (строки, числа, списки, словари)
db.set("banned_users", [12345, 67890])
users = db.get("banned_users", default=[])
# Быстрый счетчик кликов/просмотров
db.increment("total_clicks")
11. Шина событий / EventBus
Позволяет связывать различные компоненты плагина (например, фоновые сетевые службы и UI-элементы) с помощью легковесной событийной архитектуры (Pub/Sub).
@EventBus.subscribe(event_name)— Декоратор для подписки на событие.EventBus.publish(event_name, *args, **kwargs)— Публикация события (запускает выполнение всех подписанных обработчиков).EventBus.unsubscribe(event_name, callback)— Отмена подписки.
from alib import EventBus
# Подписка на событие (например, в настройках UI)
@EventBus.subscribe("on_message_deleted")
def handle_deleted(msg_id):
print(f"Сообщение {msg_id} удалено")
# Публикация из любой точки программы (например, из фонового потока логов)
EventBus.publish("on_message_deleted", 987654)
12. Сетевые декораторы / Network Utilities (Caching & Rate-Limiting)
Утилиты для предотвращения дублирования запросов и соблюдения лимитов API.
@cached_request(ttl_seconds)— Кэширует результат выполнения функции на указанное время (в секундах) в зависимости от переданных аргументов.@rate_limit(max_calls, period_seconds)— Ограничивает частоту вызовов функции. Если лимит превышен, поток засыпает (time.sleep) до начала следующего окна, гарантируя отправку всех вызовов.
from alib import cached_request, rate_limit
# Результат запроса к API кэшируется на 5 минут для одинаковых URL
@cached_request(ttl_seconds=300)
def fetch_api_data(url):
import requests
return requests.get(url).json()
# Ограничивает частоту запросов к API Telegram: не более 3 запросов в секунду
@rate_limit(max_calls=3, period_seconds=1.0)
def send_analytics(data):
# Отправка статистики на сервер
pass
Release files for exteragram-alib 1.0.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| exteragram_alib-1.0.6.tar.gz | 31.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| exteragram_alib-1.0.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.7 kB
Release files / exteragram_alib-1.0.6.tar.gz
| Download URL | exteragram_alib-1.0.6.tar.gz |
|---|---|
| Size | 31.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d61e9832e61ac562575e07d82bb9617d5b618901da8b52a3edb7f97f6dd5d444
|
|
BLAKE2b-256 checksum How to use checksums |
bfdebccff23ff56f9a00e2d0b4899e2895abc7632065124cdea5f7eb8d8d5d03
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.5
|
Release files / exteragram_alib-1.0.6-py3-none-any.whl
| Download URL | exteragram_alib-1.0.6-py3-none-any.whl |
|---|---|
| Size | 25.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb463981d117c2f5e6b10048c2d3091eb5b3b54f83407aaa26993ed9f976fc57
|
|
BLAKE2b-256 checksum How to use checksums |
bbeb2b0d261ecd551be6bbbfc21bf6703ca3713b1b9e2ff8b12787bb76ea6aea
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.5
|