Android app for the VienDesu!
  • Dart 99.4%
  • Nix 0.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Aleksandr 664ee8fc42 fix the editor rendering as a black box, polish lists and motion
AppFlowyEditor's overlay asserts on unbounded height, and every host put
it inside a scroll view, so the subtree fell back to an error widget — a
black rectangle in release builds — wherever an editor appeared: writing
and editing articles, game and author descriptions, author creation and
the profile bio. MdEditor now bounds its text area and scrolls the
document inside it, or fills a parent that bounds it; the article form
spends the whole page on the editor. A test covers both shapes.

Search results dropped the fixed row height that clipped a card whose
chips wrapped to a second line, cutting the excerpt mid-line. Rows size
to their content, cards side by side stretch to the taller one, and the
marks are capped at four with a "+N" remainder.

Polish:
- skeletons stand in for spinners while a page loads
- the poster flies from a tile into the game page it opens
- game search filters fold away behind a toggle that counts them
- browsing pages keep search in the app bar
- content is capped at 920px on tablets and in landscape
- the app bar tints when content scrolls under it
- tiles and the rating meter answer with haptics
- the game page pulls to refresh, a failed home page offers a retry
- entrance animations respect the system's reduce-motion setting

Co-Authored-By: Eva
2026-08-24 23:21:51 +03:00
android build: compile plugins against the app's android platform 2026-08-24 21:59:32 +03:00
assets/img Initial Android client: feature parity with the web frontend 2026-07-12 20:56:03 +03:00
lib fix the editor rendering as a black box, polish lists and motion 2026-08-24 23:21:51 +03:00
test fix the editor rendering as a black box, polish lists and motion 2026-08-24 23:21:51 +03:00
.envrc Initial Android client: feature parity with the web frontend 2026-07-12 20:56:03 +03:00
.gitignore Initial Android client: feature parity with the web frontend 2026-07-12 20:56:03 +03:00
analysis_options.yaml Initial Android client: feature parity with the web frontend 2026-07-12 20:56:03 +03:00
flake.lock Initial Android client: feature parity with the web frontend 2026-07-12 20:56:03 +03:00
flake.nix Initial Android client: feature parity with the web frontend 2026-07-12 20:56:03 +03:00
pubspec.lock web parity: latest games, ratings, article authoring, WYSIWYG editor 2026-08-24 21:40:01 +03:00
pubspec.yaml web parity: latest games, ratings, article authoring, WYSIWYG editor 2026-08-24 21:40:01 +03:00
README.md api moved to api.desu.church 2026-07-13 14:18:05 +03:00

VienDesu! — Android

Android-клиент агрегатора визуальных новелл, feature-parity с веб-фронтендом (../frontend), кроме создания игр и авторов — только просмотр, поиск и редактирование.

Стек

  • Flutter (Material 3, тёмная тема, indigo — как на вебе)
  • flutter_bloc — кубиты на бизнес-логику (SessionCubit, PagedSearchCubit, по кубиту на экран данных), зависимости через RepositoryProvider; эфемерное состояние форм — локально в виджетах
  • go_router — маршруты зеркалят веб-URL (/@author/@game, /profiles/@nick), так что ссылки с сайта диплинкуются 1-в-1
  • Слои: core/ (Result/Patch), domain/ (sealed-модели), data/ (API-клиент, репозитории, сессия), features/ (экраны + кубиты), shared/ (виджеты)

Сборка

nix develop            # flutter + android sdk + jdk
flutter pub get
flutter analyze && flutter test
flutter build apk --release

Эндпоинты переопределяются на этапе сборки:

flutter build apk --dart-define=API_URL=https://api.viende.su/ \
                  --dart-define=CDN_URL=https://cdn.viende.su/

По умолчанию — staging (api.desu.church).

Контракт с бэкендом

  • Ответы — конверт {"ok": ...} | {"error": ..., "description": ...} (core/result.dart).
  • PATCH-семантика: {"change": v} ставит поле, пропущенное поле не трогает (core/patch.dart, сравнение глубокое, шлём только изменённые поля).
  • Загрузка файлов двухшаговая: POST /uploadsPOST /uploads/{id} (multipart, поле file).
  • Сессия — Bearer-токен, хранится в EncryptedSharedPreferences.