Files
LihonT/docs/settings-model.md
cheb0chik ce1d870d54 LihonT 2 Luna beta: source release
Mod for TikTok 47.1.3 (arm64) in Material 3 style: bottom bar, profile menu, TikTok settings and
comments; downloads without the watermark; switches for ads, live streams and the Shop tab; badges of
other mods next to names and the niche mod badge (members service); app icons; mod settings screen.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-22 20:32:13 +03:00

127 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Модель настроек LihonT 2
Первая схема настроек, 15 октября 2026. Код написан в `src/lihont/two/settings/`
без зависимости от классов или хранилищ других модов.
## Значения
| Поле | Тип и допустимые значения | По умолчанию | Применение после подключения |
|---|---|---|---|
| `region` | Строка, один из 249 ISO 3166-1 alpha-2 кодов, верхний регистр | `JP` | Следующий запуск процесса |
| `profileBanners` | Boolean | `true` | Следующий запуск процесса |
| `commentReposts` | Boolean | `true` | Следующий запуск процесса |
| `theme` | `system`, `light`, `dark` | `system` | Следующее создание экрана настроек |
Перечень стран фиксирован в модели и не зависит от локали Android. Это список
стран и территорий ISO; названия для списка в интерфейсе будут локализованы
отдельно. `regionIso()` возвращает код в нижнем регистре для будущих хуков.
Ни телефонный префикс, ни MCC/MNC не вычисляются из позиции в этом списке.
Для выбранного региона кроме `JP` метод `needsBannerWarning()` возвращает
`true`: интерфейс должен предупредить, что баннеры могут быть недоступны. Для
Японии предупреждения нет. Показ диалога будет реализован на этапе интерфейса.
`ModSettings` неизменяемый: методы `with…` создают новый набор. По умолчанию
баннеры и репосты запрошены локально, но модель не сообщает, что сервер их выдал.
Тема относится к собственным экранам мода; сохранение темы пока не меняет TikTok.
## Хранилище и жизненный цикл
`SettingsRepository` получает `Storage`. На первом открытии создаёт файл со
значениями по умолчанию. На следующих открытиях полностью проверяет сохранённый
документ. Повреждённый файл, неизвестная версия или ошибка чтения приводят к
ошибке открытия и сохраняют исходные данные. Тихой замены на defaults нет.
Нужен **один экземпляр репозитория на процесс приложения**. Это обязательство
будущего хоста; сейчас хост и инициализация из TikTok отсутствуют. Запись из
нескольких процессов не поддерживается.
- `current()` — последний успешно сохранённый набор, для интерфейса.
- `active()` — набор, загруженный при создании репозитория, для будущих хуков.
- `restartRequired()` — различаются ли регион, баннеры или репосты между этими
наборами. Возврат к активным значениям снимает признак перезапуска. Тема в это
сравнение не входит.
- `save()` сначала записывает полный документ, затем публикует новое состояние.
Ошибка записи не меняет опубликованный набор.
- `reset()` сохраняет defaults. Если активные значения отличались от defaults,
необходимость перезапуска остаётся.
`AndroidSettingsStorage` использует приватный `Context.getFilesDir()` и файл
`lihont-settings.json`. Разрешения на файлы и доступ к сети не требуются. Запись
идёт во временный файл в той же директории, выполняет `fsync`, затем атомарный
`android.system.Os.rename`. Старый файл не удаляется до замены. При ошибке до
замены старые данные сохраняются. Ошибки чтения не трактуются как первый запуск.
Доступен на minSDK 23; шифрование настроек не требуется, секретов в схеме нет.
## Формат импорта и экспорта
```json
{
"format": "lihont.settings",
"schemaVersion": 1,
"values": {
"region": "JP",
"profileBanners": true,
"commentReposts": true,
"theme": "system"
}
}
```
`exportJson()` возвращает сохранённые значения. `importJson()` **заменяет весь
набор**, предварительно проверив структуру, формат, версию, точные типы и
допустимые значения. Частичного импорта и приведения строк к boolean нет.
Лишние, отсутствующие и повторяющиеся ключи, неизвестные страны и темы,
повреждённый JSON, `null`, массивы, дробная версия, данные после документа и
документ длиннее 16 384 символов отклоняются. Файл Android читается как строгий
UTF-8 и ограничен 16 384 байтами; стандартный экспорт содержит только ASCII.
Ошибка проверки не вызывает запись. Ошибка записи не обновляет `current()`.
Это **первая** схема: предыдущих форматов настроек у LihonT 2 нет. Поэтому версии
0 и выше 1 отклоняются с сохранением файла. При появлении схемы 2 потребуется
явная миграция 1 → 2 и её тесты до изменения номера. Настройки старой серии и
других модов автоматически не импортируются.
Формат и API готовы для будущего интерфейса резервных копий. Кнопки экспорта и
импорта в APK на этом этапе не добавляются.
## Граница текущего этапа
Сейчас это модель, кодек и адаптер хранения. Они ещё не подключены к экрану
TikTok Settings, региональным вызовам, флагам баннеров или репостам. Существующий
`LihonTRegion` в прежнем тестовом APK по-прежнему возвращает фиксированный `by`.
Новые значения `JP` не выдаются за изменение аккаунта или серверного региона.
Следующий этап — собственный хост настроек с инициализацией репозитория и
обработкой ошибок хранения. Затем подключаются функции по roadmap и проверяются
на устройстве.
## Проверка
Из корня проекта:
```powershell
py -m unittest discover -s tests -v
py -c "from lihont.toolchain import Toolchain; print(Toolchain('tools').compile_dex('src/lihont/two', 'work/settings-model/runtime', 23))"
```
JVM-тесты компилируют и исполняют реальные `ModSettings`, `SettingsCodec` и
`SettingsRepository`. Android-адаптер компилируется против `android.jar`, затем
весь runtime проходит D8 с minAPI 23. JVM-тесты не подменяют проверку Android
файловой системы на устройстве; её включаем в интеграционный этап.
## Подключение флагов TikTok
`lihont.two.settings.SettingsHost` держит единственный `SettingsRepository` процесса.
Им пользуются экран настроек и `lihont.two.LihonTFlags`, поэтому `active()` — это то,
что видели хуки с первого чтения, а `restartRequired()` сравнивает экран именно с ним.
- Переключатель включён: чтение флага возвращает значение LihonT (см. `profile_features.py`).
- Переключатель выключен: возвращается значение, которое прочитал сам TikTok. LihonT
ничего не подставляет и не утверждает, что функция доступна.
- Приложение ещё не создано или файл временно не читается: для этого вызова действуют
значения по умолчанию, результат не запоминается.
- Файл повреждён или записан более новой схемой: процесс до перезапуска работает со
значениями по умолчанию; экран настроек при этом показывает ошибку и файл не трогает.