import 'package:flutter/material.dart'; import '../models/prank_category.dart'; import '../models/prank_sound.dart'; import '../managers/data_manager.dart'; import '../managers/sound_manager.dart'; import '../widgets/big_player_panel.dart'; class CategoryDetailPage extends StatefulWidget { final PrankCategory category; const CategoryDetailPage({super.key, required this.category}); @override State createState() => _CategoryDetailPageState(); } class _CategoryDetailPageState extends State { @override void dispose() { SoundManager().stop(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: Stack( alignment: Alignment.bottomCenter, children: [ CustomScrollView( physics: const BouncingScrollPhysics(), slivers: [ SliverAppBar( expandedHeight: 200, pinned: true, backgroundColor: widget.category.themeColor, leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), onPressed: () => Navigator.pop(context), ), flexibleSpace: FlexibleSpaceBar( title: Text(widget.category.categoryName), background: Container( decoration: BoxDecoration( gradient: LinearGradient( colors: [ widget.category.themeColor, widget.category.themeColor.withOpacity(0.7), ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), ), child: Stack( children: [ Positioned( right: -30, bottom: -30, child: Icon(Icons.music_note, size: 200, color: Colors.white.withOpacity(0.15)), ), Center( child: Icon(Icons.play_circle_fill, size: 60, color: Colors.white.withOpacity(0.3)), ) ], ), ), ), ), SliverPadding( padding: const EdgeInsets.fromLTRB(0, 20, 0, 250), sliver: SliverList( delegate: SliverChildBuilderDelegate( (context, index) { final sound = widget.category.list[index]; return _buildSoundTile(context, sound); }, childCount: widget.category.list.length, ), ), ), ], ), // 详情页覆盖整个屏幕,不需要避让 BottomBar,所以使用默认的 30 偏移 BigPlayerPanel( themeColor: widget.category.themeColor, bottomOffset: 30, ), ], ), ); } Widget _buildSoundTile(BuildContext context, PrankSound sound) { final manager = SoundManager(); return ValueListenableBuilder>( valueListenable: DataManager().favoritesNotifier, builder: (context, favorites, _) { final isFav = sound.isFavorite; return ValueListenableBuilder( valueListenable: manager.currentSoundNotifier, builder: (context, currentSound, _) { final bool isActive = currentSound == sound; return Container( margin: const EdgeInsets.symmetric(horizontal: 20, vertical: 8), decoration: BoxDecoration( color: isActive ? widget.category.themeColor.withOpacity(0.05) : Colors.white, border: isActive ? Border.all(color: widget.category.themeColor, width: 2) : null, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.02), blurRadius: 10, offset: const Offset(0, 4), ), ], ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(20), onTap: () => manager.play(sound), child: Padding( padding: const EdgeInsets.all(12), child: Row( children: [ Container( width: 50, height: 50, decoration: BoxDecoration( color: widget.category.themeColor.withOpacity(0.1), borderRadius: BorderRadius.circular(15), ), child: isActive ? Icon(Icons.equalizer, color: widget.category.themeColor) : Icon(Icons.music_note, color: widget.category.themeColor), ), const SizedBox(width: 16), Expanded( child: Text( sound.title, style: TextStyle( fontWeight: isActive ? FontWeight.bold : FontWeight.normal, fontSize: 16, color: isActive ? widget.category.themeColor : const Color(0xFF1D1D35), ), ), ), IconButton( icon: Icon( isFav ? Icons.favorite_rounded : Icons.favorite_border_rounded, color: isFav ? const Color(0xFFFF6584) : Colors.grey[300], ), onPressed: () { DataManager().toggleFavorite(sound); }, ), ], ), ), ), ), ); }, ); } ); } }