import 'package:flutter/material.dart'; import '../models/word_model.dart'; import '../services/words_repository.dart'; import '../widgets/gradient_star_badge.dart'; import '../widgets/word_card_widget.dart'; class CatalogScreen extends StatefulWidget { const CatalogScreen({super.key}); @override State createState() => _CatalogScreenState(); } class _CatalogScreenState extends State { final _repo = WordsRepository(); final _searchController = TextEditingController(); String _selectedCategory = 'Все'; String _sortBy = 'id'; // 'id', 'alpha' List _filteredWords = []; @override void initState() { super.initState(); _applyFilter(); _searchController.addListener(_applyFilter); } @override void dispose() { _searchController.removeListener(_applyFilter); _searchController.dispose(); super.dispose(); } void _applyFilter() { final query = _searchController.text.trim(); List list; if (query.isEmpty) { list = _repo.allWords; } else { list = _repo.search(query); } if (_selectedCategory != 'Все') { list = list .where((w) => w.partOfSpeech == _selectedCategory || w.category == _selectedCategory) .toList(); } if (_sortBy == 'alpha') { list = List.of(list)..sort((a, b) => a.word.compareTo(b.word)); } else { // By session number list = List.of(list)..sort((a, b) => a.sessionNumber.compareTo(b.sessionNumber)); } setState(() { _filteredWords = list; }); } void _showWordDetails(WordItem word) { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => StatefulBuilder( builder: (context, setSheetState) { return Container( padding: const EdgeInsets.only(top: 12), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: const BorderRadius.vertical(top: Radius.circular(28)), ), child: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( width: 40, height: 4, decoration: BoxDecoration( color: Theme.of(context).colorScheme.outlineVariant, borderRadius: BorderRadius.circular(2), ), ), const SizedBox(height: 12), WordCardWidget( word: word, onNext: () { final next = _repo.getNextWord(word.sessionNumber); Navigator.pop(context); _showWordDetails(next); }, onPrevious: () { final prev = _repo.getPreviousWord(word.sessionNumber); Navigator.pop(context); _showWordDetails(prev); }, onRandom: () { final rnd = _repo.getRandomWord(); Navigator.pop(context); _showWordDetails(rnd); }, ), ], ), ), ), ); }, ), ); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isDark = theme.brightness == Brightness.dark; final categories = _repo.getPartsOfSpeech(); return Scaffold( appBar: AppBar( title: const Row( children: [ GradientStar(size: 22), SizedBox(width: 8), Text( 'Каталог 999 символов', style: TextStyle(fontWeight: FontWeight.w900), ), ], ), actions: [ PopupMenuButton( tooltip: 'Сортировка', icon: const Icon(Icons.sort_rounded), initialValue: _sortBy, onSelected: (val) { setState(() { _sortBy = val; _applyFilter(); }); }, itemBuilder: (context) => [ const PopupMenuItem( value: 'id', child: Row( children: [ Icon(Icons.format_list_numbered, size: 20), SizedBox(width: 8), Text('По номеру сессии (#000..#999)'), ], ), ), const PopupMenuItem( value: 'alpha', child: Row( children: [ Icon(Icons.sort_by_alpha, size: 20), SizedBox(width: 8), Text('По алфавиту (А..Я)'), ], ), ), ], ), ], ), body: Column( children: [ // Search input Padding( padding: const EdgeInsets.fromLTRB(16, 8, 16, 8), child: TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Поиск по слову, номеру или смыслу...', prefixIcon: const Padding( padding: EdgeInsets.symmetric(horizontal: 10), child: GradientStar(size: 16), ), suffixIcon: _searchController.text.isNotEmpty ? IconButton( icon: const Icon(Icons.clear), onPressed: () => _searchController.clear(), ) : null, filled: true, fillColor: isDark ? const Color(0xFF1B1D30) : theme.colorScheme.surfaceContainerHighest.withValues(alpha: 0.4), border: OutlineInputBorder( borderRadius: BorderRadius.circular(16), borderSide: BorderSide( color: const Color(0xFFFFD54F).withValues(alpha: 0.3), ), ), contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ), ), // Categories Filter Chips SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), child: Row( children: categories.map((cat) { final isSelected = _selectedCategory == cat; return Padding( padding: const EdgeInsets.only(right: 6), child: FilterChip( label: Text(cat), selected: isSelected, onSelected: (selected) { setState(() { _selectedCategory = cat; _applyFilter(); }); }, selectedColor: const Color(0xFF2A2D4A), checkmarkColor: const Color(0xFFFFD54F), labelStyle: TextStyle( color: isSelected ? const Color(0xFFFFF9C4) : null, fontWeight: isSelected ? FontWeight.bold : FontWeight.normal, ), ), ); }).toList(), ), ), // Stats Bar Padding( padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 6), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( 'Найдено: ${_filteredWords.length}', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: theme.colorScheme.outline, ), ), Text( 'Всего знаков: ${_repo.totalWords}', style: TextStyle( fontSize: 12, color: theme.colorScheme.outline, ), ), ], ), ), const Divider(height: 1), // Words List Expanded( child: _filteredWords.isEmpty ? const Center( child: Text('Ничего не найдено'), ) : ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), itemCount: _filteredWords.length, separatorBuilder: (_, _) => const Divider(height: 1, indent: 64), itemBuilder: (context, index) { final item = _filteredWords[index]; return ListTile( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), ), leading: GradientStarBadge( text: '#${item.formattedSessionNumber}', size: 14, ), title: Text( item.word.toUpperCase(), style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 16, letterSpacing: 0.5, ), ), subtitle: Text( item.description, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 12, color: theme.colorScheme.onSurfaceVariant, ), ), trailing: const Icon(Icons.chevron_right_rounded, size: 20), onTap: () => _showWordDetails(item), ); }, ), ), ], ), ); } }