5.3 KiB
2026-09-20 — Мобильное приложение Please Pay Me собрано на iOS-ките
Запрос
«Собери теперь приложение please-pay-me, используя эти компоненты» — то есть поверх Cupertino-кита из прошлой сессии сделать рабочее приложение против существующего API.
Что сделано
Слой данных (lib/data/)
models/—Budget,BudgetStatus(+ вычисляемыеspentProgress/dailyProgress),Expense,ExpensesPage,Job,UpcomingPay,WeekendPolicy,AuthUser,AuthSession. Зеркалятweb/src/types.ts, парсятся черезmodels/json.dart— толерантные коэрсеры (int/double/string), потому что API отдаёт числа из C#-рекордов.api/api_client.dart— транспорт наhttp: Bearer-токен черезtokenProvider, маппингdetail/titleвApiException, отдельная обработка 401 с колбэкомonUnauthorized(разлогинивает сессию).repositories/— интерфейсыBudgetRepository/ExpenseRepository/JobRepository/UserRepository+ REST-реализации на все ручкиMeController.demo/demo_backend.dart— in-memory бэкенд, повторяющий математику конверта (dailyLimit = remaining / daysLeft). Используется в демо-режиме, превью и тестах;DemoBackend.empty()— для пустых состояний.
Ядро (lib/core/)
config/app_config.dart—PPM_API_BASE_URL,PPM_WEB_URL,PPM_DEMOчерез--dart-define; пустой адрес API автоматически включает демо-режим.storage/session_storage.dart— интерфейс +SharedPreferencesи in-memory реализации.state/async_value.dart— sealedAsyncLoading/AsyncData/AsyncErrorсmap(...), чтобы экраны матчились по состоянию, а не жонглировали тремя nullable-полями.format/formatters.dart— деньги (1 234,50 ₽), русские плюрали, «Сегодня/Вчера».
Состояние (lib/features/*/)
SessionController— владеет авторизацией и выдаёт репозитории (REST или demo), так что остальное приложение не знает про токены.sessionKeyпересобирает фичевые контроллеры при входе/выходе.BudgetsController— источник правды по конвертам (список, выбранный, мутации с авто-перезагрузкой, возврат текста ошибки вместо исключения).JournalController— пагинация + группировка по дням + скоуп «текущий/все».JobsController— работы и ближайшая выплата.
Экраны (lib/features/, lib/app/)
Пять вкладок: Обзор, Журнал, Бюджеты, Работа, Профиль (+ экран входа и сплэш).
Формы — модальные шиты: новая/редактирование траты, бюджета, работы; все они
принимают onSubmit, возвращающий текст ошибки, и не знают про репозитории.
_SessionGate разводит restoring / signedOut / signedIn.
Кит
Удалены демо-экраны lib/ui/screens/*; добавлены AppEmptyState, AppErrorView,
AppLoadingView, showAppDatePicker, showAppFormSheet.
Widgetbook
Папка Screens теперь показывает настоящие экраны приложения на DemoScope
(demo-бэкенд + провайдеры), включая пустые состояния, формы и полный таб-бар.
Авторизация — известное ограничение
Telegram Login Widget работает только в вебе. Мобильный клиент принимает JWT из
localStorage.ppm_session_jwt веб-кабинета и валидирует его через GET /api/me.
Нативный вход (WebView с Telegram-виджетом либо one-time code через бота)
не делался — это отдельное продуктовое решение.
Тесты
mobile: 32 теста — парсинг моделей, форматтеры, все контроллеры на demo-бэкенде, виджет-сценарии (вход, табы, пустые состояния, запись траты end-to-end).mobile/widgetbook: 100 — каждый use-case рендерится в light и dark.flutter analyzeпо обоим пакетам — 0 issues.flutter build windows --debugпроходит (проверка плагинов shared_preferences/url_launcher).
Запуск
cd mobile
.\run.ps1 # демо-данные
.\run.ps1 -ApiBaseUrl https://ppm.example.com