Metadata-Version: 2.4
Name: enpaf
Version: 1.0.0
Summary: ENPAF — Python + Web framework for building Android APK applications
Author: ENPAF Team
License: MIT
Project-URL: Homepage, https://github.com/enpaf/enpaf
Project-URL: Documentation, https://enpaf.dev
Keywords: android,apk,python,webview,framework,mobile
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Environment :: Console
Classifier: Environment :: Web Environment
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: flask>=3.0.0
Requires-Dist: flask-socketio>=5.3.0
Requires-Dist: simple-websocket>=1.0.0
Requires-Dist: watchdog>=3.0.0
Requires-Dist: jinja2>=3.1.0
Requires-Dist: colorama>=0.4.6
Provides-Extra: dev
Requires-Dist: build>=1.0.0; extra == "dev"
Requires-Dist: twine>=5.0.0; extra == "dev"
Dynamic: license-file

# 🚀 ENPAF — Engine for Native Python App Framework

**Создавайте Android-приложения на Python + HTML/CSS/JS и собирайте их в APK.**

ENPAF — это фреймворк, который позволяет писать мобильные приложения, используя
привычный веб-стек (HTML/CSS/JS) для интерфейса и **Python** для логики. В режиме
разработки приложение работает как обычный сайт (Flask + WebSocket + hot-reload), а
готовый продукт собирается в настоящий **APK** на базе WebView + встроенного Python
(Chaquopy).

```
┌──────────────────────── Android APK ────────────────────────┐
│   ┌────────────┐   Bridge (JSON)   ┌────────────────────┐    │
│   │  WebView   │ ◄───────────────► │   Python (main.py) │    │
│   │ HTML/CSS/JS│                   │   enpaf core       │    │
│   │ + enpaf.js │                   │   ваш код          │    │
│   └────────────┘                   └────────────────────┘    │
└──────────────────────────────────────────────────────────────┘
```

---

## 📑 Содержание

- [Возможности](#-возможности)
- [Установка](#-установка)
- [Требования](#-требования)
- [Быстрый старт](#-быстрый-старт)
- [CLI: команда `paf`](#-cli-команда-paf)
- [Структура проекта](#-структура-проекта)
- [Конфигурация `enpaf.json`](#-конфигурация-enpafjson)
- [Python API](#-python-api)
- [JavaScript SDK (`enpaf.js`)](#-javascript-sdk-enpafjs)
- [Панель настроек ⚙](#-панель-настроек-)
- [Разрешения и фичи устройства](#-разрешения-и-фичи-устройства)
- [Deep links (диплинки)](#-deep-links-диплинки)
- [Уведомления и нативные возможности](#-уведомления-и-нативные-возможности)
- [Сборка APK](#-сборка-apk)
- [Что можно импортировать](#-что-можно-импортировать)
- [Решение проблем](#-решение-проблем)
- [Публикация в PyPI (для мейнтейнеров)](#-публикация-в-pypi-для-мейнтейнеров)
- [Лицензия](#-лицензия)

---

## ✨ Возможности

- 🐍 **Python для логики**, HTML/CSS/JS для интерфейса.
- 🔗 **Двусторонний мост** Python ↔ JavaScript (вызовы и события).
- 💾 **Встроенное хранилище** — key-value и коллекции на SQLite.
- ⚡ **Hot-reload** в режиме разработки.
- ⚙️ **Веб-панель настроек** — иконка, имя, ориентация, цвета, разрешения, фичи и диплинки настраиваются прямо в браузере и пишутся в `enpaf.json`.
- 📱 **Нативные API** — toast, вибрация, уведомления, буфер обмена, шаринг, ориентация.
- 🔐 **Разрешения** и **`uses-feature`** (камера, NFC, датчики, Bluetooth, GPS…).
- 🔗 **Deep links** (кастомные схемы и App Links).
- 📦 **Сборка в APK/AAB** на Windows/macOS/Linux через Gradle + Chaquopy.

---

## 📥 Установка

### Из PyPI

```bash
pip install enpaf
```

После установки доступна команда `paf` и пакет `enpaf` для импорта.

### Из исходников (для разработки фреймворка)

```bash
git clone https://github.com/enpaf/enpaf
cd enpaf
pip install -e .
```

---

## 📋 Требования

| Что | Зачем | Версия |
|-----|-------|--------|
| **Python** | фреймворк и CLI | 3.9+ |
| **Java JDK** | сборка APK | **17–21** (рекомендуется 17) |
| **Android SDK** | сборка APK | Android Studio или command-line tools |

> Для **разработки** (`paf run`) нужен только Python. JDK и Android SDK нужны
> только для **сборки APK** (`paf build`). Проверить окружение: `paf doctor`.

---

## ⚡ Быстрый старт

```bash
paf create myapp          # создать проект
cd myapp
paf run                   # запустить dev-сервер → http://127.0.0.1:8080
# ... разрабатываете, правите app/ и main.py, страница перезагружается сама ...
paf build apk             # собрать APK → dist/myapp-1.0.0.apk
```

Установить APK на телефон:

```bash
adb install dist/myapp-1.0.0.apk
# либо просто перекиньте .apk на телефон и откройте
```

---

## 🛠 CLI: команда `paf`

| Команда | Описание |
|---------|----------|
| `paf create <name>` | Создать новый проект из шаблона |
| `paf run` | Запустить dev-сервер (Flask + hot-reload) |
| `paf build apk` | Собрать **debug** APK |
| `paf build apk --release` | Собрать **release** APK |
| `paf build aab` | Собрать **release** Android App Bundle (`.aab`) |
| `paf doctor` | Проверить окружение (Python, JDK, Android SDK) |
| `paf info` | Показать информацию о текущем проекте |

**Флаги `create`:**
- `--package`, `-p` — Android package id (по умолчанию `com.enpaf.<name>`)
- `--template`, `-t` — шаблон проекта (по умолчанию `default`)

**Флаги `run`:**
- `--host` (по умолчанию `127.0.0.1`)
- `--port` (по умолчанию `8080`)
- `--no-browser` — не открывать браузер автоматически
- `--debug` — режим отладки

**Флаги `build`:**
- `--release` — релизная сборка
- `--keystore <path>` — keystore для подписи
- `--clean` — чистая сборка (удалить кэш сборки)

---

## 🏗 Структура проекта

```
myapp/
├── app/                  # Интерфейс (HTML/CSS/JS) → попадёт в assets APK
│   ├── index.html        # Главная страница
│   ├── css/style.css
│   ├── js/app.js
│   ├── pages/            # Доп. страницы
│   └── img/
├── main.py               # Python-логика (точка входа)
├── enpaf.json            # Конфигурация проекта
├── icon.png              # (опционально) иконка приложения
├── data/                 # Локальная БД (SQLite) — создаётся автоматически
└── dist/                 # Готовые APK после сборки
```

---

## ⚙️ Конфигурация `enpaf.json`

Полный пример со всеми полями:

```json
{
    "name": "My App",
    "package": "com.example.myapp",
    "version": "1.0.0",
    "description": "My ENPAF Application",
    "author": "Developer",
    "orientation": "portrait",
    "icon": "icon.png",
    "permissions": ["INTERNET", "CAMERA", "VIBRATE"],
    "features": [
        { "key": "CAMERA", "required": true },
        { "key": "NFC", "required": false }
    ],
    "deeplinks": [
        { "label": "Open profile", "scheme": "myapp", "host": "open",
          "path": "/profile", "pathType": "prefix", "autoVerify": false }
    ],
    "python_requirements": ["requests"],
    "min_sdk": 24,
    "target_sdk": 34,
    "theme": {
        "primary_color": "#6C5CE7",
        "status_bar_color": "#5A4BD1"
    }
}
```

| Поле | Тип | Описание |
|------|-----|----------|
| `name` | string | Название приложения (ярлык на устройстве) |
| `package` | string | Android application id, напр. `com.example.myapp` |
| `version` | string | Версия (`major.minor.patch`) |
| `description`, `author` | string | Метаданные |
| `orientation` | string | `portrait` / `landscape` / `auto` / `sensor` / `unspecified` |
| `icon` | string | Путь к иконке (PNG/JPG/WebP) относительно проекта |
| `permissions` | string[] | Список ключей разрешений (см. [таблицу](#разрешения)) |
| `features` | object[] | `{ "key": "...", "required": true|false }` (`<uses-feature>`) |
| `deeplinks` | object[] | Диплинки (см. [раздел](#-deep-links-диплинки)) |
| `python_requirements` | string[] | pip-зависимости, встраиваемые в APK через Chaquopy |
| `min_sdk` / `target_sdk` | int | Android API levels (по умолчанию 24 / 34) |
| `theme.primary_color` | string | Основной цвет (HEX) |
| `theme.status_bar_color` | string | Цвет статус-бара (HEX) |
| `log_level` | string | Уровень логирования (`INFO`, `DEBUG`, …) |

> 💡 Эти поля удобнее всего редактировать через [панель настроек ⚙](#-панель-настроек-),
> не открывая JSON вручную.

---

## 🐍 Python API

### `main.py` — точка входа

```python
from enpaf import EnpafApp

app = EnpafApp(__name__)

# ─── Маршруты страниц (Jinja2-шаблоны, режим разработки) ───
@app.route("/")
def index():
    return app.render("index.html", title=app.name)

# ─── Bridge-функции (вызываются из JavaScript) ───
@app.bridge_handler("get_user")
def get_user(params):
    user_id = params.get("id")
    return {"id": user_id, "name": "Alex"}

# ─── События жизненного цикла ───
@app.on("app_start")
def on_start():
    print("Приложение запущено!")

if __name__ == "__main__":
    app.run()
```

### Класс `EnpafApp`

```python
EnpafApp(import_name, app_dir="app", config_file="enpaf.json")
```

**Декораторы / методы:**

| Метод | Назначение |
|-------|------------|
| `@app.route(path, methods=None)` | Зарегистрировать страницу-маршрут |
| `@app.bridge_handler(name)` / `@app.bridge_func(name)` | Зарегистрировать функцию, вызываемую из JS |
| `@app.on(event)` | Подписаться на событие |
| `app.emit(event, data=None)` | Отправить событие (в Python и в JS) |
| `app.render(template, **context)` | Отрендерить Jinja2-шаблон из `app/` |
| `app.run(host, port, debug, open_browser)` | Запустить (dev-сервер или Android runtime) |

**Свойства / компоненты:**

| Свойство | Тип | Описание |
|----------|-----|----------|
| `app.config` | dict | Содержимое `enpaf.json` |
| `app.name` | str | Имя приложения |
| `app.storage` | `Storage` | Локальное хранилище |
| `app.events` | `EventEmitter` | Система событий |
| `app.bridge` | `Bridge` | Мост Python↔JS |
| `app.api` | `DeviceAPI` | Доступ к функциям устройства |
| `app.router` | `Router` | Роутер/шаблонизатор |

### Хранилище — `app.storage`

Key-value:

```python
app.storage.set("theme", "dark")          # значение (str/int/float/bool/dict/list)
theme = app.storage.get("theme", "light") # с дефолтом
app.storage.delete("theme")
app.storage.exists("theme")               # -> bool
app.storage.keys("user_%")                # LIKE-паттерн
app.storage.all()                         # -> dict всех пар
app.storage.clear()
```

Коллекции (мини документ-стор):

```python
notes = app.storage.collection("notes")
note_id = notes.add({"text": "Привет"})   # -> int (id)
notes.all()                                # -> list[dict] (+ _id, _created_at)
notes.find({"text": "Привет"})            # -> list[dict]
notes.find_one({"text": "Привет"})        # -> dict | None
notes.update(note_id, {"text": "Пока"})
notes.delete(note_id)
notes.count()                              # -> int
notes.clear()
```

> На Android БД автоматически пишется в записываемый каталог приложения
> (`getFilesDir()`), а не рядом с исходниками.

### События — `app.events`

```python
@app.on("app_start")
def _(): ...

app.events.once("page_load", handler)   # сработает один раз
app.events.off("app_start", handler)    # отписаться
app.events.emit("my_event", payload)    # вызвать
```

**Встроенные lifecycle-события:** `app_start`, `app_stop`, `app_pause`,
`app_resume`, `app_error`, `page_load`, `page_unload`, `bridge_connect`,
`bridge_disconnect`.

### Функции устройства — `app.api` (`DeviceAPI`)

```python
app.api.toast("Сохранено!", duration="short")  # "short" | "long"
app.api.vibrate(200)                            # мс
app.api.get_device_info()                       # -> dict
app.api.set_status_bar_color("#000000")
app.api.set_orientation("portrait")             # "portrait"|"landscape"|"auto"
app.api.open_url("https://example.com")
app.api.clipboard_set("текст")
app.api.clipboard_get()
app.api.share("Посмотри!", title="Моё приложение")
```

---

## 🌐 JavaScript SDK (`enpaf.js`)

Мост `enpaf.js` подключается автоматически: в режиме разработки его внедряет
сервер, а при сборке APK — билдер вставляет `<script src="js/enpaf.js">` в ваши
HTML-страницы. Глобальный объект — `window.enpaf`.

### Вызовы и события

```javascript
// Вызвать Python-функцию (-> Promise)
const user = await enpaf.call("get_user", { id: 42 });

// События из Python
enpaf.on("data_updated", (payload) => console.log(payload));
enpaf.off("data_updated");

// Отправить событие в Python
enpaf.emit("button_clicked", { id: "save" });

// Готовность моста
enpaf.ready(() => console.log("bridge ready"));

// Навигация между страницами
enpaf.navigate("/pages/about.html");

enpaf.version;    // "1.0.0"
enpaf.isAndroid;  // true в APK, false в браузере
```

### Хранилище из JS

```javascript
await enpaf.storage.set("theme", "dark");
const theme = await enpaf.storage.get("theme");
await enpaf.storage.delete("theme");
```

### Функции устройства — `enpaf.device`

| Метод | Описание |
|-------|----------|
| `enpaf.device.toast(msg, dur)` | Toast-уведомление (`"short"`/`"long"`) |
| `enpaf.device.vibrate(ms)` | Вибрация |
| `enpaf.device.notify(title, text, id)` | Системное уведомление |
| `enpaf.device.share(text, title)` | Системный «Поделиться» |
| `enpaf.device.setOrientation(mode)` | `"portrait"`/`"landscape"`/`"auto"` |
| `enpaf.device.clipboard(text)` | Скопировать в буфер обмена |
| `enpaf.device.openUrl(url)` | Открыть ссылку во внешнем браузере |
| `enpaf.device.getInfo()` | Информация об окружении (Promise) |

В браузере (dev) методы используют веб-аналоги (Web Notifications, `navigator.share`,
`navigator.clipboard` и т.д.), на Android — нативные вызовы.

### Утилиты

```javascript
enpaf.utils.formatDate(Date.now(), "ru-RU");
enpaf.utils.uid();   // случайный id
```

---

## ⚙️ Панель настроек ⚙

Запустите `paf run` и откройте **`http://127.0.0.1:8080/enpaf-settings`** (или нажмите
плавающую кнопку **⚙** в правом нижнем углу страницы). Панель позволяет настроить и
сохранить в `enpaf.json` без ручного редактирования:

- **General** — имя приложения, **иконка** (загрузка с превью), ориентация, основной цвет и цвет статус-бара;
- **Permissions** — разрешения (`<uses-permission>`);
- **Hardware features** — фичи устройства (`<uses-feature>`) с флагом «required»;
- **Deep Links** — диплинки и App Links;
- **Manifest preview** — живой предпросмотр того, что попадёт в `AndroidManifest.xml`.

После «Save» изменения применятся при следующей `paf build`.

---

## 🔐 Разрешения и фичи устройства

### Разрешения

Указываются по коротким ключам в `permissions`. Доступные ключи:

`INTERNET`, `VIBRATE`, `CAMERA`, `READ_STORAGE`, `WRITE_STORAGE`, `FINE_LOCATION`,
`COARSE_LOCATION`, `RECORD_AUDIO`, `READ_CONTACTS`, `CALL_PHONE`, `SEND_SMS`,
`BLUETOOTH`, `BLUETOOTH_ADMIN`, `NFC`, `WAKE_LOCK`, `FOREGROUND_SERVICE`,
`POST_NOTIFICATIONS`.

Можно указать и полное имя, напр. `android.permission.CAMERA`.

### Фичи (`<uses-feature>`)

Формат: `{ "key": "<KEY>", "required": true|false }`. Доступные ключи:

`CAMERA`, `CAMERA_FRONT`, `CAMERA_AUTOFOCUS`, `NFC`, `BLUETOOTH`, `BLUETOOTH_LE`,
`GPS`, `LOCATION`, `MICROPHONE`, `WIFI`, `TELEPHONY`, `TOUCHSCREEN`, `FINGERPRINT`,
`ACCELEROMETER`, `GYROSCOPE`, `COMPASS`, `PROXIMITY`, `LIGHT`, `BAROMETER`,
`STEP_COUNTER`, `HEART_RATE`.

> `required: false` оставляет приложение устанавливаемым на устройствах без
> соответствующего железа.

---

## 🔗 Deep links (диплинки)

Каждый диплинк превращается в `<intent-filter>` на главной активности.

```json
"deeplinks": [
    { "label": "Профиль", "scheme": "myapp", "host": "open",
      "path": "/profile", "pathType": "prefix", "autoVerify": false }
]
```

| Поле | Описание |
|------|----------|
| `scheme` | Обязательно. Напр. `myapp` или `https` |
| `host` | Опционально. Напр. `example.com` |
| `path` | Опционально. Напр. `/profile` |
| `pathType` | `path` (точно) / `prefix` / `pattern` |
| `autoVerify` | `true` для App Links (проверяемые https-ссылки) |
| `label` | Только для UI-панели |

Проверить диплинк на устройстве:

```bash
adb shell am start -a android.intent.action.VIEW -d "myapp://open/profile"
```

---

## 🔔 Уведомления и нативные возможности

Из JavaScript:

```javascript
enpaf.device.notify("Заголовок", "Текст уведомления", 1);
```

На Android уведомления используют канал по умолчанию; на Android 13+ приложение
запрашивает разрешение `POST_NOTIFICATIONS` (добавьте его в `permissions`).

Доступные нативные методы моста (вызываются через `enpaf.device.*`): `toast`,
`vibrate`, `notify`, `share`, `setOrientation`, `clipboard`, `openUrl`.

---

## 📦 Сборка APK

```bash
paf build apk            # debug
paf build apk --release  # release
paf build aab            # release bundle (.aab)
```

Что происходит:

1. Проверяется окружение (Python/JDK/Android SDK).
2. Подбирается совместимая **JDK 17–21** (учитывается `JAVA_HOME`; иначе ищется в стандартных местах, включая JBR из Android Studio).
3. Генерируется Gradle-проект (Chaquopy), скачивается официальный Gradle wrapper.
4. Gradle собирает APK; результат копируется в `dist/<name>-<version>.apk`.

**Первая сборка долгая** — Gradle докачивает Android platform/build-tools и **NDK
(~1 ГБ)** для Chaquopy. Дальнейшие сборки быстрее (всё кэшируется в `~/.gradle` и
Android SDK).

### OneDrive / облачные папки

Если проект лежит в OneDrive (или другой синхронизируемой папке), ENPAF
**автоматически** выносит каталог сборки в `%LOCALAPPDATA%\enpaf\builds\…`, потому что
синхронизация ломает удаление файлов Gradle. Путь можно переопределить переменной
окружения `ENPAF_BUILD_DIR`. Итоговый APK всё равно копируется в `dist/`.

---

## 📥 Что можно импортировать

**Основное (рекомендуется):**

```python
from enpaf import EnpafApp, __version__
```

**Продвинутое** (обычно используется через `app.*`, но доступно напрямую):

```python
from enpaf.core.storage import Storage, Collection
from enpaf.core.events import EventEmitter
from enpaf.core.bridge import Bridge
from enpaf.core.router import Router
from enpaf.core.api import DeviceAPI

# Справочники для манифеста / панели настроек
from enpaf.android.permissions import PERMISSIONS, get_permission_catalog
from enpaf.android.features import FEATURES, get_feature_catalog
from enpaf.android.deeplinks import get_deeplink_xml

# Программная сборка APK
from enpaf.builder.apk_builder import APKBuilder

# Точка входа CLI
from enpaf.cli.main import main
```

Клиентский SDK для подключения вручную (если не используете авто-инъекцию):

```html
<script src="js/enpaf.js"></script>
```

---

## 🩺 Решение проблем

| Симптом | Причина и решение |
|---------|-------------------|
| **Приложение сразу закрывается** | Пересоберите APK — фиксы применяются только в новой сборке. Если повторяется — снимите лог: `adb logcat` (теги `AndroidRuntime`, `python.stderr`, `chaquopy`). |
| **`enpaf is not defined`** | Мост не подключён. Сборка вставляет `js/enpaf.js` автоматически; убедитесь, что собираете свежую версию. |
| **Синий/неожиданный цвет статус-бара** | Это `theme.status_bar_color`. Поменяйте его в панели ⚙ → General или в `enpaf.json`. |
| **`Unable to delete directory … python\sources`** | OneDrive блокирует файлы. ENPAF собирает вне OneDrive автоматически; при желании задайте `ENPAF_BUILD_DIR`. |
| **`Incompatible Java version`** | Нужна JDK 17–21. Установите JDK 17 и задайте `JAVA_HOME`, либо дайте ENPAF найти её автоматически. |
| **`'""' is not recognized` при Gradle** | Старый сломанный wrapper. Удалите каталог сборки и соберите заново (`paf build apk --clean`). |

Полная диагностика окружения: `paf doctor`.

---

## 📤 Публикация в PyPI (для мейнтейнеров)

Пакет уже подготовлен (`pyproject.toml`, `MANIFEST.in`). Подробная пошаговая
инструкция — в [PUBLISHING.md](PUBLISHING.md). Кратко:

```bash
pip install build twine
python -m build                 # создаст dist/*.whl и dist/*.tar.gz
twine check dist/*
twine upload --repository testpypi dist/*   # сначала на TestPyPI
twine upload dist/*                          # затем на PyPI
```

---

## 📄 Лицензия

MIT License — см. [LICENSE](LICENSE).
