import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/data_models.dart'; import '../providers/app_provider.dart'; import '../widgets/fade_in_local_image.dart'; import '../widgets/animated_star_rating.dart'; import '../utils/toast_util.dart'; import '../widgets/app_overlay.dart'; /// 书籍列表项组件 - 网格布局设计 class BookListItem extends StatelessWidget { final Book book; final bool selected; final VoidCallback? onTap; const BookListItem({super.key, required this.book, this.selected = false, this.onTap}); @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; return GestureDetector( onTap: onTap ?? () => Navigator.pushNamed(context, '/book-detail', arguments: book), onLongPress: () => _showDeleteDialog(context), child: Container( decoration: selected ? BoxDecoration( borderRadius: BorderRadius.circular(10), border: Border.all(color: colors.primary, width: 2), ) : null, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: _buildCover(colors), ), const SizedBox(height: 8), Text( book.title, style: TextStyle( fontSize: 13, fontWeight: FontWeight.w500, color: colors.onSurface, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), if (book.rating != null) AnimatedStarRating(rating: book.rating!, starSize: 12, showNumber: true) else const SizedBox(height: 16), ], ), ), ); } Widget _buildCover(ColorScheme colors) { return Container( width: double.infinity, decoration: BoxDecoration( borderRadius: BorderRadius.circular(4), ), clipBehavior: Clip.antiAlias, child: FadeInLocalImage( path: book.coverPath, fit: BoxFit.cover, placeholder: Center(child: Icon(Icons.menu_book_outlined, size: 32, color: colors.onSurface.withValues(alpha: 0.25))), errorWidget: Center(child: Icon(Icons.menu_book_outlined, size: 32, color: colors.onSurface.withValues(alpha: 0.25))), ), ); } void _showDeleteDialog(BuildContext context) { final colors = Theme.of(context).colorScheme; appDialog( context: context, builder: (context) => AlertDialog( backgroundColor: colors.surface, elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), title: Text( '确认删除', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: colors.onSurface, ), ), content: Text( '确定要删除《${book.title}》吗?删除后可在回收站恢复。', style: TextStyle( fontSize: 14, color: colors.onSurface.withValues(alpha: 0.6), height: 1.5, ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), style: TextButton.styleFrom( foregroundColor: colors.onSurface.withValues(alpha: 0.6), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), child: const Text('取消'), ), ElevatedButton( onPressed: () async { await context.read().removeBook(book.id); Navigator.pop(context); ToastUtil.show(context, '已删除'); }, style: ElevatedButton.styleFrom( backgroundColor: colors.error, foregroundColor: colors.onError, elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), child: const Text('删除'), ), ], actionsPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ); } }