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/character.dart'; import '../../widgets/tab_content_layout.dart'; class DiscoveryScreen extends StatefulWidget { const DiscoveryScreen({super.key}); @override State createState() => _DiscoveryScreenState(); } class _DiscoveryScreenState extends State { String _activeFilter = 'all'; final List> _filters = [ {'id': 'all', 'label': '全部'}, {'id': 'gentle', 'label': '温柔治愈'}, {'id': 'dom', 'label': '主导强势'}, {'id': 'wild', 'label': '反差/猎奇'}, {'id': 'voice', 'label': '语音陪聊'}, {'id': 'scenario', 'label': '场景扮演'}, {'id': 'exclusive', 'label': '会员限定'}, ]; List get _filteredCharacters { if (_activeFilter == 'all') return mockCharacters; return mockCharacters.where((c) { final tags = c.tags.join(''); if (_activeFilter == 'gentle') return tags.contains('治愈') || tags.contains('温顺') || tags.contains('医疗'); if (_activeFilter == 'dom') return tags.contains('强势') || tags.contains('调教') || tags.contains('指令'); if (_activeFilter == 'wild') return tags.contains('病娇') || tags.contains('神秘') || tags.contains('不稳定') || tags.contains('极乐'); if (_activeFilter == 'exclusive') return c.isLocked; return false; }).toList(); } @override Widget build(BuildContext context) { const double bottomNavHeight = 90; return TabContentLayout( child: Column( children: [ // 1. Sticky Filter Bar (simulated) SizedBox( height: 50, child: ListView.separated( padding: const EdgeInsets.symmetric(horizontal: 16), scrollDirection: Axis.horizontal, itemCount: _filters.length, separatorBuilder: (_, __) => const SizedBox(width: 12), itemBuilder: (context, index) { final filter = _filters[index]; final isActive = _activeFilter == filter['id']; return Center( child: GestureDetector( onTap: () => setState(() => _activeFilter = filter['id']!), child: AnimatedContainer( duration: const Duration(milliseconds: 300), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6), decoration: BoxDecoration( color: isActive ? Colors.white : Colors.white.withOpacity(0.05), borderRadius: BorderRadius.circular(20), border: Border.all( color: isActive ? Colors.white : Colors.white.withOpacity(0.1), ), ), child: Text( filter['label']!, style: TextStyle( fontSize: 14, fontWeight: isActive ? FontWeight.bold : FontWeight.normal, color: isActive ? const Color(0xFF2E1065) : Colors.white.withOpacity(0.7), ), ), ), ), ); }, ), ), // 2. Grid Layout Expanded( child: _filteredCharacters.isEmpty ? Center(child: Text('暂无匹配角色', style: TextStyle(color: Colors.white.withOpacity(0.5)))) : GridView.builder( padding: const EdgeInsets.fromLTRB(16, 16, 16, bottomNavHeight + 20), gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 2, childAspectRatio: 3 / 4, crossAxisSpacing: 16, mainAxisSpacing: 16, ), itemCount: _filteredCharacters.length, itemBuilder: (context, index) { final char = _filteredCharacters[index]; return _CharacterCard( character: char, onTap: () { if (!char.isLocked) { context.push('/interaction/${char.id}'); } }, ) .animate() .fadeIn(duration: 400.ms, delay: (index * 100).ms) .scale(begin: const Offset(0.9, 0.9)); }, ), ), ], ), ); } } class _CharacterCard extends StatelessWidget { final Character character; final VoidCallback onTap; const _CharacterCard({ required this.character, required this.onTap, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.3), blurRadius: 15, offset: const Offset(0, 6), ), BoxShadow( color: const Color(0xFFA855F7).withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 0), ), ], ), child: Stack( fit: StackFit.expand, children: [ // Clipped content area - ensures all elements respect border radius ClipRRect( borderRadius: BorderRadius.circular(24), child: Stack( fit: StackFit.expand, children: [ // Background Image Image.network( character.avatar, fit: BoxFit.cover, loadingBuilder: (context, child, loadingProgress) { if (loadingProgress == null) return child; return Container( color: Colors.black26, child: const Center(child: CircularProgressIndicator(strokeWidth: 2)), ); }, ), // Gradient Overlay Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Colors.transparent, Colors.transparent, Color(0xFF2E1065), // Deep purple at bottom ], stops: [0.0, 0.5, 1.0], ), ), ), // Top Left: Popularity/Compatibility Badge if (!character.isLocked) Positioned( top: 12, left: 12, child: Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.black.withOpacity(0.4), borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.white.withOpacity(0.1)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ const Icon(LucideIcons.flame, size: 12, color: Color(0xFFF472B6)), const SizedBox(width: 4), Text( '${character.compatibility}%', style: const TextStyle( fontSize: 12, fontWeight: FontWeight.bold, fontFamily: 'monospace', color: Colors.white, ), ), ], ), ), ), // Top Right: Lock Icon if (character.isLocked) Positioned( top: 12, right: 12, child: Container( width: 32, height: 32, decoration: BoxDecoration( color: Colors.black.withOpacity(0.4), shape: BoxShape.circle, border: Border.all(color: Colors.white.withOpacity(0.2)), ), child: const Icon(LucideIcons.lock, size: 14, color: Colors.white70), ), ), // Bottom Content Positioned( bottom: 0, left: 0, right: 0, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( character.name, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, shadows: [Shadow(color: Colors.black45, blurRadius: 2, offset: Offset(0, 1))], ), ), const SizedBox(height: 4), Wrap( spacing: 4, runSpacing: 4, children: character.tags.take(2).map((tag) { return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), decoration: BoxDecoration( color: Colors.white.withOpacity(0.12), borderRadius: BorderRadius.circular(10), border: Border.all( color: Colors.white.withOpacity(0.25), width: 0.8, ), ), child: Text( tag, style: const TextStyle(fontSize: 10, color: Colors.white), ), ); }).toList(), ), ], ), ), ), ], ), ), // Border Overlay - Outside ClipRRect to ensure full visibility Positioned.fill( child: IgnorePointer( child: Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(24), border: Border.all( color: Colors.white.withOpacity(0.15), width: 1.2, ), ), ), ), ), ], ), ), ); } }