import 'package:flutter/material.dart'; import '../pages/search_page.dart'; import '../services/epub_parser_service.dart'; import '../services/book_repository.dart'; import 'package:file_picker/file_picker.dart'; /// 应用顶部导航组件 /// /// 可复用的顶部导航栏组件,集成在搜索栏内的导入按钮。 /// 提供统一的搜索和文件导入功能,支持主题自适应。 class AppHeader extends StatefulWidget { /// 标题文本(可选),某些页面可以显示标题而非搜索栏 final String? title; /// 搜索按钮点击回调函数 final VoidCallback? onSearchPressed; /// 导入按钮点击回调函数 final VoidCallback? onImportPressed; /// 是否显示搜索栏(默认值为true) final bool showSearchBar; /// 搜索栏占位符文本 final String searchHint; const AppHeader({ super.key, this.title, this.onSearchPressed, this.onImportPressed, this.showSearchBar = true, this.searchHint = '搜索书名或内容...', }); @override State createState() => _AppHeaderState(); } class _AppHeaderState extends State { final EpubParserService _epubParserService = EpubParserService(); final BookRepository _bookRepository = BookRepository(); /// 构建组件的UI结构 @override Widget build(BuildContext context) { return Container( height: 60, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, border: Border( bottom: BorderSide( color: Theme.of(context).colorScheme.outline.withOpacity(0.2), width: 1, ), ), ), child: Row( children: [ // 标题区域(条件渲染) if (widget.title != null) ...[ Text( widget.title!, style: Theme.of(context).textTheme.headlineSmall?.copyWith( fontWeight: FontWeight.w600, ), ), const SizedBox(width: 16), ], // 搜索栏区域(占据剩余空间) if (widget.showSearchBar) ...[ Expanded( child: _buildSearchBar(context), ), ] ], ), ); } /// 构建搜索栏组件,包含搜索图标、占位符文本和导入按钮 Widget _buildSearchBar(BuildContext context) { return Container( height: 44, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surfaceVariant, borderRadius: BorderRadius.circular(22), border: Border.all( color: Theme.of(context).colorScheme.outline.withOpacity(0.3), ), ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(22), onTap: widget.onSearchPressed ?? () => _navigateToSearchPage(context), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( children: [ Icon( Icons.search, size: 24, color: Theme.of(context).colorScheme.onSurfaceVariant, ), const SizedBox(width: 8), Expanded( child: Text( widget.searchHint, style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context) .colorScheme .onSurfaceVariant .withOpacity(0.6), ), ), ), const SizedBox(width: 8), _buildImportButton(context), ], ), ), ), ), ); } /// 构建导入按钮组件 Widget _buildImportButton(BuildContext context) { return Container( height: 32, decoration: BoxDecoration( color: Theme.of(context).colorScheme.primaryContainer, borderRadius: BorderRadius.circular(16), ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(16), onTap: widget.onImportPressed ?? () => _importEpubFile(), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text( '导入', style: Theme.of(context).textTheme.bodyMedium?.copyWith( color: Theme.of(context).colorScheme.onPrimaryContainer, ), ), ], ), ), ), ), ); } /// 导航到搜索页面 void _navigateToSearchPage(BuildContext context) { Navigator.of(context).push( MaterialPageRoute( builder: (context) => const SearchPage(), ), ); } /// 导入EPUB文件 Future _importEpubFile() async { try { // 1. 使用FilePicker选择EPUB文件 FilePickerResult? result = await FilePicker.platform.pickFiles( type: FileType.custom, allowedExtensions: ['epub'], ); if (result != null && result.files.single.path != null) { final filePath = result.files.single.path!; // 2. 检查文件是否已存在 final existingBooks = await _bookRepository.getAllBooks(); final isDuplicate = existingBooks.any((book) => book.filePath == filePath); if (isDuplicate) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('该文件已经导入过了'), backgroundColor: Colors.orange, ), ); } return; } // 3. 解析EPUB文件 final epubBook = await _epubParserService.parseEpubFile(filePath); // 4. 提取元数据并创建Book对象 final book = await _epubParserService.extractBookMetadata(epubBook, filePath); // 5. 保存到数据库 await _bookRepository.addBook(book); // 6. 显示成功消息 if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('成功导入: ${book.title}'), backgroundColor: Colors.green, duration: const Duration(seconds: 2), ), ); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('导入失败: $e'), backgroundColor: Colors.red, duration: const Duration(seconds: 3), ), ); } } } }