// lib/pages/player_page.dart import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../services/audio_service.dart'; import '../main.dart'; // ✅ 导入 navigatorKey import 'playlist_page.dart'; // ✅ 导入 PlaylistPage class PlayerPage extends StatefulWidget { final VoidCallback onClose; const PlayerPage({ super.key, required this.onClose, }); @override State createState() => _PlayerPageState(); } class _PlayerPageState extends State { double? _dragProgress; String _formatDuration(Duration d) { if (d.inMilliseconds < 0) return '00:00'; final minutes = d.inMinutes; final seconds = d.inSeconds % 60; return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}'; } @override Widget build(BuildContext context) { final service = context.watch(); final song = service.currentSong; if (song == null) { return Scaffold( backgroundColor: const Color(0xFF0E1211), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text( '没有正在播放的歌曲', style: TextStyle(color: Colors.grey), ), const SizedBox(height: 16), ElevatedButton( onPressed: widget.onClose, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFB8D4D0), foregroundColor: Colors.black87, ), child: const Text('返回'), ), ], ), ), ); } final isPlaying = service.isPlaying; final position = service.position; final duration = service.duration; final bufferedPosition = service.bufferedPosition; final progress = duration.inMilliseconds > 0 ? position.inMilliseconds / duration.inMilliseconds : 0.0; final bufferProgress = duration.inMilliseconds > 0 ? (bufferedPosition.inMilliseconds / duration.inMilliseconds) .clamp(0.0, 1.0) : 0.0; final displayProgress = _dragProgress ?? progress; return Scaffold( backgroundColor: const Color(0xFF0E1211), appBar: AppBar( backgroundColor: Colors.transparent, elevation: 0, leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white), onPressed: widget.onClose, // ✅ 使用回调关闭 ), title: const Text( '正在播放', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w400, ), ), centerTitle: true, actions: [ IconButton( icon: const Icon(Icons.playlist_play_outlined, color: Colors.white54), onPressed: () { navigatorKey.currentState?.push( MaterialPageRoute( builder: (_) => const PlaylistPage(), ), ); }, ), IconButton( icon: const Icon(Icons.more_vert, color: Colors.white54), onPressed: () {}, ), ], ), body: Padding( padding: const EdgeInsets.symmetric(horizontal: 24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 240, height: 240, decoration: BoxDecoration( shape: BoxShape.circle, color: const Color(0xFF2A3332), boxShadow: [ BoxShadow( color: const Color(0xFF7C9A9E).withOpacity(0.15), blurRadius: 60, spreadRadius: 10, ), ], ), child: const Icon( Icons.music_note, size: 64, color: Colors.white24, ), ), const SizedBox(height: 48), Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( song.title, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.w600, color: Colors.white, ), textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 8), Text( song.artist, style: TextStyle( fontSize: 15, color: Colors.grey[400], ), textAlign: TextAlign.center, maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), const SizedBox(height: 40), Column( children: [ SizedBox( height: 20, child: LayoutBuilder( builder: (context, constraints) { final width = constraints.maxWidth; final bufferWidth = width * bufferProgress.clamp(0.0, 1.0); final progressWidth = width * displayProgress.clamp(0.0, 1.0); return Stack( alignment: Alignment.centerLeft, children: [ Container( width: width, height: 4, decoration: BoxDecoration( color: Colors.grey[800], borderRadius: BorderRadius.circular(2), ), ), Container( width: bufferWidth, height: 4, decoration: BoxDecoration( color: const Color(0xFF4A7A7A), borderRadius: BorderRadius.circular(2), ), ), Container( width: progressWidth, height: 4, decoration: BoxDecoration( color: const Color(0xFFB8D4D0), borderRadius: BorderRadius.circular(2), ), ), Positioned.fill( child: SliderTheme( data: SliderTheme.of(context).copyWith( trackHeight: 0, activeTrackColor: Colors.transparent, inactiveTrackColor: Colors.transparent, thumbColor: Colors.transparent, overlayColor: Colors.transparent, thumbShape: const RoundSliderThumbShape( enabledThumbRadius: 0, ), ), child: Slider( value: displayProgress.clamp(0.0, 1.0), min: 0.0, max: 1.0, onChanged: (value) { setState(() { _dragProgress = value; }); }, onChangeEnd: (value) { final newPosition = Duration( milliseconds: (value * duration.inMilliseconds) .round(), ); service.seekTo(newPosition); setState(() { _dragProgress = null; }); }, ), ), ), ], ); }, ), ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( _formatDuration(position), style: TextStyle( fontSize: 12, color: Colors.grey[500], ), ), Text( _formatDuration(duration), style: TextStyle( fontSize: 12, color: Colors.grey[500], ), ), ], ), ], ), const SizedBox(height: 32), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( onPressed: service.togglePlayMode, icon: Icon( service.playModeIcon, color: const Color(0xFFB8D4D0), size: 22, ), padding: const EdgeInsets.all(12), ), const SizedBox(width: 4), IconButton( onPressed: service.hasQueue ? service.previous : null, icon: const Icon(Icons.skip_previous, size: 28), color: service.hasQueue ? Colors.white60 : Colors.grey[600], padding: const EdgeInsets.all(12), ), const SizedBox(width: 20), Container( width: 56, height: 56, decoration: BoxDecoration( color: const Color(0xFFB8D4D0), shape: BoxShape.circle, ), child: IconButton( icon: Icon( isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.black87, size: 28, ), padding: EdgeInsets.zero, onPressed: service.togglePlay, ), ), const SizedBox(width: 20), IconButton( onPressed: service.hasQueue ? service.next : null, icon: const Icon(Icons.skip_next, size: 28), color: service.hasQueue ? Colors.white60 : Colors.grey[600], padding: const EdgeInsets.all(12), ), const SizedBox(width: 4), ], ), const SizedBox(height: 16), ], ), ), ); } }