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>
127 lines
9.7 KiB
Markdown
127 lines
9.7 KiB
Markdown
# Модель настроек 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
|
||
ничего не подставляет и не утверждает, что функция доступна.
|
||
- Приложение ещё не создано или файл временно не читается: для этого вызова действуют
|
||
значения по умолчанию, результат не запоминается.
|
||
- Файл повреждён или записан более новой схемой: процесс до перезапуска работает со
|
||
значениями по умолчанию; экран настроек при этом показывает ошибку и файл не трогает.
|