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

9.7 KiB
Raw Blame History

Модель настроек 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; шифрование настроек не требуется, секретов в схеме нет.

Формат импорта и экспорта

{
  "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 и проверяются на устройстве.

Проверка

Из корня проекта:

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