# 2026-09-19 — Мобильный UI-кит переведён на iOS (Cupertino) ## Запрос Widgetbook запустился, но Material-компоненты визуально не устроили. Задача — сделать компоненты «из iOS kit». ## Что сделано ### Токены и тема (`mobile/lib/theme/`) - `tokens.dart` переписан под Apple HIG: семантические цвета (`label`, `secondaryLabel`, `separator`, `opaqueSeparator`, `groupedBackground`, `groupedSurface`, `barBackground`) и системная палитра (`systemRed/Orange/Green/Gray/Gray3/Gray5/Gray6`) объявлены как `CupertinoDynamicColor.withBrightness` — light/dark резолвится самим фреймворком через `AppColors.of(context, color)`. - Бренд-тинт остался зелёным (`accent` = #12885A / #3CD68C в тёмной) и подменяет systemBlue. - Типографика — шкала SF Pro: largeTitle 34 … caption2 11 с нативными letterSpacing. - Размеры контролов: 50 / 44 / 34 pt, hairline 0.5, радиусы 6/10/12/16/capsule. - `app_theme.dart` теперь возвращает `CupertinoThemeData` (`buildLightTheme` / `buildDarkTheme`), шрифт — Inter через google_fonts как кросс-платформенная замена SF Pro (на Windows/web SF недоступен). ### Компоненты (`mobile/lib/ui/`) Material-версии удалены, вместо них Cupertino: - atoms: `AppButton` (filled/tinted/gray/plain/destructive × large/medium/small), `AppTextField` (CupertinoTextField + error/prefix/clear), `AppText` (именованные конструкторы по шкале iOS) + `AppSectionHeader`, `AppIcon` + `AppIconBadge` (Settings-style скруглённый квадрат). - molecules: `AppListSection` (inset-grouped, header/footer, hairline с indent), `AppListTile` (leading/value/chevron, press-highlight, destructive), `AppSwitchRow` (CupertinoSwitch), `AppCard`, `AppChip` (капсула), `AppAvatar`. - navigation: `AppNavBar` (реализует `ObstructingPreferredSizeWidget`, есть subtitle), `AppLargeNavBar` (`CupertinoSliverNavigationBar`), `AppTabBar` (наследник `CupertinoTabBar`, чтобы отдавать в `CupertinoTabScaffold`), `AppSegmentedControl` (`CupertinoSlidingSegmentedControl`), `AppAlert` + `showAppAlert` + `showAppActionSheet`. - feedback: `AppSpinner` (`CupertinoActivityIndicator`), `AppProgressBar` (4pt капсула), `AppSkeleton` / `AppSkeletonRow`, `AppToast` + `showAppToast` (blur-капсула через OverlayEntry — в iOS нет SnackBar). - screens: Feed (large title + сегменты + группы + empty/loading), Detail (hero-сумма, прогресс, группа параметров, кнопки), Profile (Settings-подобный экран со свитчами). - `main.dart` переведён на `CupertinoApp` + `CupertinoTabScaffold`. ### Widgetbook (`mobile/widgetbook/`) - `Widgetbook.cupertino` + `CupertinoThemeAddon` вместо material-варианта. - Новый `lib/support/preview.dart` — `IosPreview` кладёт use-case на grouped-фон, чтобы карточки и разделители читались как в приложении. - Каталог: Atoms (Button/TextField/Typography/Icons), Molecules (Card/ListTile/SwitchRow/ Chip/Avatar), Navigation (NavBar/TabBar/SegmentedControl/Alert), Feedback (Progress/ Skeleton/Toast), Screens (Feed/Detail/Profile) — 42 use-case. - Knobs: добавлены `knobEnum` и `knobTint` (дропдаун по системным тинтам), убран deprecated `knobs.list`. ### Тесты `widgetbook/test/catalog_smoke_test.dart` больше не проверяет только структуру: каждый use-case пампится в light и dark внутри `WidgetbookScope` (knobs читают `WidgetbookState` из контекста, иначе падает «No Widgetbook found in the context»). В тестах отключён `GoogleFonts.config.allowRuntimeFetching` и вызван `TestWidgetsFlutterBinding.ensureInitialized()`. ## Результат - `flutter analyze` (mobile + widgetbook) — 0 issues. - `flutter test` — 84 теста в widgetbook + 1 в приложении, всё зелёное. ## Запуск ```powershell cd mobile\widgetbook .\run.ps1 -Device windows ```