import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../bloc/book/book_bloc.dart'; import '../bloc/book/book_event.dart'; import '../bloc/add_book/add_book_bloc.dart'; import '../bloc/add_book/add_book_event.dart'; import '../bloc/add_book/add_book_state.dart'; import '../config/api_config.dart'; import '../models/models.dart'; import '../theme/app_spacing.dart'; import 'scanner_screen.dart'; class AddBookScreen extends StatelessWidget { final Book? editBook; final Book? prefilledData; const AddBookScreen({super.key, this.editBook, this.prefilledData}); @override Widget build(BuildContext context) { return BlocProvider( create: (context) => AddBookBloc( onAddBook: (book) => context.read().add(AddBook(book)), onUpdateBook: (book) => context.read().add(UpdateBook(book)), )..add(InitializeForm(editBook: editBook, prefilledData: prefilledData)), child: const _AddBookScreenContent(), ); } } class _AddBookScreenContent extends StatefulWidget { const _AddBookScreenContent(); @override State<_AddBookScreenContent> createState() => _AddBookScreenContentState(); } class _AddBookScreenContentState extends State<_AddBookScreenContent> { final _titleController = TextEditingController(); final _authorController = TextEditingController(); final _annotationController = TextEditingController(); @override void dispose() { _titleController.dispose(); _authorController.dispose(); _annotationController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; final textTheme = Theme.of(context).textTheme; return BlocListener( listener: (context, state) { // Update controllers when state changes (e.g., from scanned book) if (_titleController.text != state.title) { _titleController.text = state.title; } if (_authorController.text != state.author) { _authorController.text = state.author; } if (_annotationController.text != state.annotation) { _annotationController.text = state.annotation; } // Navigate back when saved if (state.isSaved) { Navigator.pop(context); } }, child: BlocBuilder( builder: (context, state) { final title = state.isEditing ? 'Редактировать' : 'Добавить книгу'; return Material( child: SafeArea( child: Column( children: [ // Header Padding( padding: const EdgeInsets.fromLTRB( AppSpacing.sm, AppSpacing.sm, AppSpacing.sm, 0, ), child: Row( children: [ IconButton( icon: const Icon(Icons.arrow_back), onPressed: () => Navigator.pop(context), ), Text(title, style: textTheme.headlineMedium), ], ), ), Expanded( child: ListView( padding: const EdgeInsets.all(AppSpacing.lg), children: [ // Cover placeholder / scanner trigger GestureDetector( onTap: () => _openScanner(context), child: Container( height: 160, decoration: BoxDecoration( border: Border.all(color: colorScheme.outline), borderRadius: BorderRadius.circular( AppSpacing.radiusMedium, ), color: colorScheme.surfaceContainerHighest, ), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.camera_alt, size: 40, color: colorScheme.primary, ), const SizedBox(height: AppSpacing.sm), Text( 'Загрузить или отсканировать', style: textTheme.bodyMedium?.copyWith( color: colorScheme.onSurface.withValues( alpha: 0.6, ), ), ), ], ), ), ), ), const SizedBox(height: AppSpacing.lg), _field( context, 'Название', _titleController, textTheme, (value) => context.read().add(UpdateTitle(value)), ), const SizedBox(height: AppSpacing.md), _field( context, 'Автор', _authorController, textTheme, (value) => context.read().add( UpdateAuthor(value), ), ), const SizedBox(height: AppSpacing.md), // Genre dropdown Text('Жанр', style: textTheme.labelMedium), const SizedBox(height: AppSpacing.xs), DropdownButtonFormField( value: state.genre, dropdownColor: colorScheme.surface, decoration: const InputDecoration(), items: const [ DropdownMenuItem( value: 'fiction', child: Text('Фантастика'), ), DropdownMenuItem( value: 'fantasy', child: Text('Фэнтези'), ), DropdownMenuItem( value: 'science', child: Text('Научпоп'), ), DropdownMenuItem( value: 'biography', child: Text('Биография'), ), DropdownMenuItem( value: 'detective', child: Text('Детектив'), ), DropdownMenuItem( value: 'other', child: Text('Другое'), ), ], onChanged: (v) { if (v != null) { context.read().add(UpdateGenre(v)); } }, ), const SizedBox(height: AppSpacing.md), Text('Аннотация', style: textTheme.labelMedium), const SizedBox(height: AppSpacing.xs), TextField( controller: _annotationController, maxLines: 4, onChanged: (value) => context.read().add( UpdateAnnotation(value), ), ), const SizedBox(height: 100), ], ), ), // Bottom actions Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.screenPadding, vertical: AppSpacing.md, ), decoration: BoxDecoration( color: colorScheme.surface, border: Border( top: BorderSide(color: colorScheme.outlineVariant), ), boxShadow: [ BoxShadow( color: colorScheme.shadow, blurRadius: 8, offset: const Offset(0, -2), ), ], ), child: Row( children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(context), child: const Text('Отмена'), ), ), const SizedBox(width: AppSpacing.md), Expanded( flex: 2, child: ElevatedButton( onPressed: () => context.read().add(SaveBook()), child: const Text('Сохранить'), ), ), ], ), ), ], ), ), ); }, ), ); } Widget _field( BuildContext context, String label, TextEditingController controller, TextTheme textTheme, void Function(String) onChanged, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: textTheme.labelMedium), const SizedBox(height: AppSpacing.xs), TextField(controller: controller, onChanged: onChanged), ], ); } Future _openScanner(BuildContext context) async { if (!context.mounted) return; final scannedBook = await Navigator.of(context, rootNavigator: true) .push( MaterialPageRoute( builder: (_) => ScannerScreen( geminiApiKey: ApiConfig.geminiApiKey, openaiApiKey: ApiConfig.openaiApiKey, openaiBaseUrl: ApiConfig.openaiBaseUrl, ), ), ); if (scannedBook != null && context.mounted) { context.read().add(ApplyScannedBook(scannedBook)); } } }