// lib/pages/shell_page.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../services/audio_service.dart'; import '../widgets/global_mini_player.dart'; import 'home_page.dart'; import 'player_page.dart'; import 'playlist_page.dart'; class ShellPage extends StatefulWidget { const ShellPage({super.key}); @override State createState() => _ShellPageState(); } class _ShellPageState extends State { // ✅ 从 PlayerPage 打开 PlaylistPage void _openPlaylistFromPlayer() { Navigator.pushNamed(context, '/playlist'); } // ✅ 关闭 PlayerPage void _closePlayer() { Navigator.pop(context); } // ✅ 关闭 PlaylistPage void _closePlaylist() { Navigator.pop(context); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFF0E1211), body: Stack( children: [ // ---- 页面内容(Navigator) ---- Navigator( initialRoute: '/', onGenerateRoute: (settings) { switch (settings.name) { case '/': return _buildPageRoute( const HomePage(), settings: settings, ); case '/player': return _buildPageRoute( PlayerPage( onClose: _closePlayer, onOpenPlaylist: _openPlaylistFromPlayer, ), settings: settings, fromBottom: true, ); case '/playlist': return _buildPageRoute( PlaylistPage( onClose: _closePlaylist, ), settings: settings, ); default: return null; } }, ), // ---- MiniPlayer(覆盖在最上层) ---- const Positioned( left: 0, right: 0, bottom: 0, child: GlobalMiniPlayer(), ), ], ), ); } PageRouteBuilder _buildPageRoute( Widget page, { required RouteSettings settings, bool fromBottom = false, }) { return PageRouteBuilder( settings: settings, pageBuilder: (context, animation, secondaryAnimation) => page, transitionsBuilder: (context, animation, secondaryAnimation, child) { if (fromBottom) { // 播放页:从底部滑入 final offset = Tween( begin: const Offset(0, 1), end: Offset.zero, ).animate(CurvedAnimation( parent: animation, curve: Curves.easeOutCubic, )); return SlideTransition(position: offset, child: child); } else { // 其他页面:淡入 return FadeTransition( opacity: animation, child: child, ); } }, transitionDuration: const Duration(milliseconds: 300), reverseTransitionDuration: const Duration(milliseconds: 300), ); } }