import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:cached_network_image/cached_network_image.dart'; import '../../bloc/app_bloc.dart'; import '../../bloc/app_event.dart'; import '../../bloc/app_state.dart'; import '../../../models/models.dart'; class LibraryScreen extends StatefulWidget { const LibraryScreen({super.key}); @override State createState() => _LibraryScreenState(); } class _LibraryScreenState extends State { @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF112116), body: Column( children: [ _buildHeader(context), Expanded(child: _buildBookGrid(context)), ], ), floatingActionButton: Padding( padding: const EdgeInsets.only(bottom: 80), child: FloatingActionButton( onPressed: () { context.read().add(const AddBookClicked()); }, backgroundColor: const Color(0xFF17CF54), elevation: 8, child: const Icon(Icons.add, size: 28), ), ), floatingActionButtonLocation: FloatingActionButtonLocation.endFloat, ); } Widget _buildHeader(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), decoration: BoxDecoration( color: const Color(0xFF112116).withValues(alpha: 0.95), border: Border( bottom: BorderSide(color: Colors.white.withValues(alpha: 0.05), width: 1), ), ), child: Column( children: [ Row( children: [ const SizedBox(width: 40), Expanded( child: Text( 'Книжная полка', textAlign: TextAlign.center, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.white, ), ), ), const SizedBox( width: 40, child: Icon( Icons.notifications_outlined, color: Colors.white, size: 24, ), ), ], ), const SizedBox(height: 8), BlocBuilder( buildWhen: (previous, current) => previous.searchQuery != current.searchQuery, builder: (context, state) { return Container( height: 48, decoration: BoxDecoration( color: const Color(0xFF244730), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withValues(alpha: 0.05)), ), child: TextField( onChanged: (value) { context.read().add(SearchChanged(value)); }, style: const TextStyle(color: Colors.white, fontSize: 16), decoration: InputDecoration( hintText: 'Поиск по названию или автору...', hintStyle: const TextStyle( color: Color(0xFF93C8A5), ), prefixIcon: const Icon( Icons.search, color: Color(0xFF93C8A5), size: 20, ), border: InputBorder.none, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ), ); }, ), ], ), ); } Widget _buildBookGrid(BuildContext context) { return BlocBuilder( builder: (context, state) { final filteredBooks = state.books.where((book) { final query = state.searchQuery.toLowerCase(); return book.title.toLowerCase().contains(query) || book.author.toLowerCase().contains(query); }).toList(); if (filteredBooks.isEmpty) { return Center( child: Text( 'Книги не найдены', style: TextStyle( color: const Color(0xFF93C8A5), fontSize: 16, ), ), ); } return GridView.builder( padding: const EdgeInsets.all(16), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, crossAxisSpacing: 16, mainAxisSpacing: 16, childAspectRatio: 0.67, ), itemCount: filteredBooks.length, itemBuilder: (context, index) { final book = filteredBooks[index]; return _buildBookCard(context, book); }, ); }, ); } Widget _buildBookCard(BuildContext context, Book book) { return GestureDetector( onTap: () { context.read().add(BookClicked(book)); }, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Stack( children: [ Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), color: const Color(0xFF1A3222), boxShadow: [ BoxShadow( color: Colors.black.withValues(alpha: 0.3), blurRadius: 8, offset: const Offset(0, 4), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(12), child: CachedNetworkImage( imageUrl: book.coverUrl ?? 'https://picsum.photos/seed/placeholder/400/600', fit: BoxFit.cover, width: double.infinity, placeholder: (context, url) => const Center( child: CircularProgressIndicator( color: Color(0xFF17CF54), ), ), errorWidget: (context, url, error) => Container( color: const Color(0xFF1A3222), child: const Icon( Icons.book_outlined, size: 48, color: Color(0xFF93C8A5), ), ), ), ), ), if (book.status == BookStatus.reading && book.progress != null) Positioned( left: 0, right: 0, bottom: 0, child: Container( height: 4, decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.5), ), child: FractionallySizedBox( widthFactor: book.progress! / 100, alignment: Alignment.centerLeft, child: Container( color: const Color(0xFF17CF54), ), ), ), ), if (book.status == BookStatus.done) Positioned( top: 8, left: 8, child: Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: const Color(0xFF17CF54), borderRadius: BorderRadius.circular(12), ), child: const Text( 'DONE', style: TextStyle( color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold, ), ), ), ), if (book.isFavorite) Positioned( top: 8, right: 8, child: Container( padding: const EdgeInsets.all(4), decoration: BoxDecoration( color: Colors.black.withValues(alpha: 0.6), shape: BoxShape.circle, ), child: const Icon( Icons.favorite, size: 14, color: Colors.white, ), ), ), ], ), ), const SizedBox(height: 8), Text( book.title, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, ), ), Text( book.author, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( color: Color(0xFF93C8A5), fontSize: 14, ), ), ], ), ); } }