import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:lucide_icons/lucide_icons.dart'; import 'package:go_router/go_router.dart'; import '../../data/mock_data.dart'; import '../../models/scenario.dart'; import '../../widgets/tab_content_layout.dart'; class LibraryScreen extends StatefulWidget { const LibraryScreen({super.key}); @override State createState() => _LibraryScreenState(); } class _LibraryScreenState extends State { String _activeCategory = '全部'; final List _categories = ['全部', '职场', '邻家', '科幻', 'ASMR']; List get _filteredScenarios { if (_activeCategory == '全部') return mockScenarios; return mockScenarios.where((s) => s.category == _activeCategory || s.tags.contains(_activeCategory) ).toList(); } Color _getIntensityColor(String intensity) { switch (intensity) { case 'Low': return const Color(0xFF34D399); // Emerald case 'Medium': return const Color(0xFF60A5FA); // Blue case 'High': return const Color(0xFFFBBF24); // Amber case 'Extreme': return const Color(0xFFF472B6); // Pink default: return Colors.white.withOpacity(0.5); } } @override Widget build(BuildContext context) { const double bottomNavHeight = 90; return TabContentLayout( child: Column( children: [ // Filter Bar SizedBox( height: 50, child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, itemCount: _categories.length, separatorBuilder: (_, __) => const SizedBox(width: 12), itemBuilder: (context, index) { final category = _categories[index]; final isActive = _activeCategory == category; return Center( child: GestureDetector( onTap: () => setState(() => _activeCategory = category), child: AnimatedContainer( duration: const Duration(milliseconds: 300), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), decoration: BoxDecoration( gradient: isActive ? const LinearGradient( colors: [Color(0xFFC084FC), Color(0xFFF472B6)], ) : null, color: isActive ? null : Colors.white.withOpacity(0.05), borderRadius: BorderRadius.circular(20), border: Border.all( color: isActive ? Colors.transparent : Colors.white.withOpacity(0.1), ), boxShadow: isActive ? [ BoxShadow( color: const Color(0xFFC084FC).withOpacity(0.4), blurRadius: 15, ), ] : null, ), child: Text( category, style: TextStyle( fontSize: 14, fontWeight: isActive ? FontWeight.bold : FontWeight.normal, color: isActive ? Colors.white : Colors.white.withOpacity(0.7), ), ), ), ), ); }, ), ), const SizedBox(height: 8), // Scenario List Expanded( child: _filteredScenarios.isEmpty ? Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(LucideIcons.activity, size: 32, color: Colors.white.withOpacity(0.5)), const SizedBox(height: 8), Text( '暂无相关剧本', style: TextStyle(fontSize: 12, color: Colors.white.withOpacity(0.5)), ), ], ), ) : ListView.builder( padding: EdgeInsets.fromLTRB(16, 8, 16, bottomNavHeight + 20), itemCount: _filteredScenarios.length, itemBuilder: (context, index) { final scenario = _filteredScenarios[index]; return _ScenarioCard( scenario: scenario, intensityColor: _getIntensityColor(scenario.intensity), onTap: () { if (!scenario.isLocked) { context.push('/player/${scenario.id}'); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('需要积分解锁此高级内容'), backgroundColor: Color(0xFF4C1D95), ), ); } }, ) .animate() .fadeIn(duration: 400.ms, delay: (index * 80).ms) .slideX(begin: 0.05, end: 0); }, ), ), ], ), ); } } class _ScenarioCard extends StatelessWidget { final Scenario scenario; final Color intensityColor; final VoidCallback onTap; const _ScenarioCard({ required this.scenario, required this.intensityColor, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFF4C1D95).withOpacity(0.2), borderRadius: BorderRadius.circular(16), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Row( children: [ // Left: Thumbnail Container( width: 80, height: 80, decoration: BoxDecoration( borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withOpacity(0.1)), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 8, offset: const Offset(0, 2), ), ], ), clipBehavior: Clip.antiAlias, child: Stack( fit: StackFit.expand, children: [ Image.network( scenario.cover, fit: BoxFit.cover, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Container( color: Colors.black26, child: const Center( child: CircularProgressIndicator(strokeWidth: 2), ), ); }, ), if (scenario.isLocked) Container( color: const Color(0xFF2E1065).withOpacity(0.6), child: const Center( child: Icon(LucideIcons.lock, size: 16, color: Colors.white70), ), ), ], ), ), const SizedBox(width: 16), // Center: Info Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [ // Category & Intensity Row( children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), borderRadius: BorderRadius.circular(4), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Text( scenario.category, style: TextStyle( fontSize: 10, fontFamily: 'monospace', letterSpacing: 1, color: Colors.white.withOpacity(0.9), ), ), ), const SizedBox(width: 8), Icon(LucideIcons.zap, size: 10, color: intensityColor), const SizedBox(width: 2), Text( scenario.intensity, style: TextStyle( fontSize: 9, fontWeight: FontWeight.bold, color: intensityColor, ), ), ], ), const SizedBox(height: 6), // Title Text( scenario.title, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 6), // Tags Wrap( spacing: 6, children: scenario.tags.take(3).map((tag) { return Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.white.withOpacity(0.05), borderRadius: BorderRadius.circular(4), border: Border.all(color: Colors.white.withOpacity(0.05)), ), child: Text( '#$tag', style: TextStyle( fontSize: 10, color: Colors.white.withOpacity(0.7), ), ), ); }).toList(), ), ], ), ), // Right: Play Button Container( width: 40, height: 40, decoration: BoxDecoration( shape: BoxShape.circle, color: scenario.isLocked ? Colors.white.withOpacity(0.05) : const Color(0xFFC084FC).withOpacity(0.2), ), child: Center( child: Icon( scenario.isLocked ? LucideIcons.lock : LucideIcons.play, size: scenario.isLocked ? 16 : 18, color: scenario.isLocked ? Colors.white.withOpacity(0.3) : const Color(0xFFC084FC), ), ), ), ], ), ), ); } }