import 'package:flutter/material.dart'; import 'package:moonwell_launcher/app/design_system/mw_launcher_components.dart'; import 'package:moonwell_launcher/core/moonwell_theme_variant.dart'; import 'package:widgetbook/widgetbook.dart'; import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; @widgetbook.UseCase(name: 'interactive', type: MwGameTile, path: '[Launcher]') Widget buildMwGameTileInteractiveUseCase(BuildContext context) { return SizedBox( width: context.knobs.double.slider( label: 'width', initialValue: 240, min: 72, max: 360, divisions: 36, ), child: MwGameTile( title: context.knobs.string(label: 'title', initialValue: 'MoonWell'), subtitle: context.knobs.stringOrNull( label: 'subtitle', initialValue: 'Wrath of the Lich King', ), icon: Icons.nights_stay_outlined, selected: context.knobs.boolean(label: 'selected', initialValue: true), enabled: context.knobs.boolean(label: 'enabled', initialValue: true), compact: context.knobs.boolean(label: 'compact', initialValue: false), onPressed: () => debugPrint('Game tile selected'), ), ); } @widgetbook.UseCase(name: 'full', type: MwGameRail, path: '[Launcher]') Widget buildMwGameRailFullUseCase(BuildContext context) { return const SizedBox(width: 240, height: 560, child: MwGameRail()); } @widgetbook.UseCase(name: 'compact', type: MwGameRail, path: '[Launcher]') Widget buildMwGameRailCompactUseCase(BuildContext context) { return const SizedBox( width: 72, height: 560, child: MwGameRail(compact: true), ); } @widgetbook.UseCase(name: 'text_only', type: MwNewsItem, path: '[Launcher]') Widget buildMwNewsItemTextOnlyUseCase(BuildContext context) { return SizedBox( width: 620, child: MwNewsItem( item: MwNewsItemData( title: context.knobs.string( label: 'title', initialValue: 'Добро пожаловать в MoonWell', ), body: context.knobs.string( label: 'body', initialValue: 'Приключение в Нордсколе начинается здесь.', ), createdAt: DateTime(2026, 6, 22), ), ), ); } @widgetbook.UseCase(name: 'image_failure', type: MwNewsItem, path: '[Launcher]') Widget buildMwNewsItemImageFailureUseCase(BuildContext context) { return const SizedBox( width: 620, child: MwNewsItem( item: MwNewsItemData( title: 'Обновление игрового мира', body: 'Изображение недоступно, но публикация остаётся читаемой.', imageUrl: 'https://invalid.moonwell.local/news.jpg', ), ), ); } @widgetbook.UseCase(name: 'loading', type: MwNewsList, path: '[Launcher]') Widget buildMwNewsListLoadingUseCase(BuildContext context) { return const MwNewsList(state: MwNewsListState.loading); } @widgetbook.UseCase(name: 'empty', type: MwNewsList, path: '[Launcher]') Widget buildMwNewsListEmptyUseCase(BuildContext context) { return const MwNewsList(state: MwNewsListState.empty); } @widgetbook.UseCase(name: 'failure', type: MwNewsList, path: '[Launcher]') Widget buildMwNewsListFailureUseCase(BuildContext context) { return MwNewsList( state: MwNewsListState.failure, error: context.knobs.string( label: 'error', initialValue: 'Сервер новостей временно недоступен.', ), onRetry: () => debugPrint('News reload requested'), ); } @widgetbook.UseCase(name: 'populated', type: MwNewsList, path: '[Launcher]') Widget buildMwNewsListPopulatedUseCase(BuildContext context) { final count = context.knobs.int.slider( label: 'itemCount', initialValue: 8, min: 1, max: 50, divisions: 49, ); return MwNewsList( state: MwNewsListState.populated, items: List.generate( count, (index) => MwNewsItemData( title: 'Новость ${index + 1}', body: 'Реалистичный текст публикации о событиях и обновлениях MoonWell.', createdAt: DateTime(2026, 6, 22).subtract(Duration(days: index)), ), ), ); } @widgetbook.UseCase( name: 'interactive', type: MwSyncActionArea, path: '[Launcher]', ) Widget buildMwSyncActionAreaInteractiveUseCase(BuildContext context) { final state = context.knobs.object.dropdown( label: 'state', initialOption: MwSyncPresentation.downloading, options: MwSyncPresentation.values, labelBuilder: (value) => value.name, ); return SizedBox( width: 420, child: MwSyncActionArea( state: state, status: context.knobs.string( label: 'status', initialValue: 'Загружаем обновление клиента…', ), progress: context.knobs.double.slider( label: 'progress', initialValue: .46, min: 0, max: 1, divisions: 100, ), currentPath: context.knobs.stringOrNull( label: 'currentPath', initialValue: r'Data\ruRU\patch-ruRU.MPQ', ), error: state == MwSyncPresentation.failure ? context.knobs.string( label: 'error', initialValue: 'Проверка SHA-256 не пройдена.', ) : null, onPrimary: () => debugPrint('Primary sync action requested: $state'), onPause: state == MwSyncPresentation.downloading ? () => debugPrint('Sync pause requested') : null, ), ); } @widgetbook.UseCase( name: 'metadata', type: MwLauncherStatusBar, path: '[Launcher]', ) Widget buildMwLauncherStatusBarMetadataUseCase(BuildContext context) { return MwLauncherStatusBar( status: context.knobs.string( label: 'status', initialValue: 'Загрузка игровых файлов', ), fileCount: 'Файлы 124/480', speed: '12.4 MB/s', eta: 'ETA 00:01:42', buildHash: 'a93fd1c2', ); } @widgetbook.UseCase( name: 'default', type: MwAccountAffordance, path: '[Launcher]', ) Widget buildMwAccountAffordanceUseCase(BuildContext context) { return MwAccountAffordance( onSettings: () => debugPrint('Settings requested'), onLogout: () => debugPrint('Logout requested'), ); } @widgetbook.UseCase( name: 'interactive', type: MwSettingsPanel, path: '[Launcher]', ) Widget buildMwSettingsPanelInteractiveUseCase(BuildContext context) { final variant = context.knobs.object.dropdown( label: 'themeVariant', initialOption: MoonWellThemeVariant.forest, options: MoonWellThemeVariant.values, labelBuilder: (value) => value.name, ); return SizedBox( width: 420, child: MwSettingsPanel( installationPath: context.knobs.stringOrNull( label: 'installationPath', initialValue: r'C:\Games\MoonWell', ), themeVariant: variant, syncActive: context.knobs.boolean( label: 'syncActive', initialValue: false, ), onChooseDirectory: () => debugPrint('Directory selection requested'), onThemeChanged: (value) => debugPrint('Theme changed: ${value.name}'), onVerify: () => debugPrint('Manual verification requested'), onLogout: () => debugPrint('Logout requested'), ), ); }