// music_view_test.dart import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../common/audio_player_controller.dart'; import '../common/download_manager.dart'; import '../common_widget/Song_widegt.dart'; import '../common_widget/app_data.dart'; import 'comment_view.dart'; class MusicView extends StatefulWidget { final List songList; final int initialSongIndex; final Function(int index, bool isCollected, bool isLiked)? onSongStatusChanged; const MusicView({ super.key, required this.songList, required this.initialSongIndex, this.onSongStatusChanged, }); @override State createState() => _MusicViewState(); } class _MusicViewState extends State with SingleTickerProviderStateMixin { // late AnimationController _rotationController; final AudioPlayerController playerController = Get.put(AudioPlayerController()); final downloadManager = Get.find(); final AppData appData = AppData(); @override void initState() { super.initState(); playerController.initWithSongs(widget.songList, widget.initialSongIndex); } @override void dispose() { super.dispose(); } String formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, "0"); String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60)); String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60)); return "$twoDigitMinutes:$twoDigitSeconds"; } Widget _buildProgressSlider() { return Obx(() { final max = playerController.duration.value.inSeconds.toDouble() == 0 ? 0.1 : playerController.duration.value.inSeconds.toDouble(); final current = playerController.position.value.inSeconds.toDouble().clamp(0, max); return SliderTheme( data: const SliderThemeData( trackHeight: 3.0, thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7.0), overlayShape: RoundSliderOverlayShape(overlayRadius: 12.0), ), child: Slider( min: 0, max: max, value: current.toDouble(), onChanged: (value) { playerController.seekTo(Duration(seconds: value.toInt())); }, activeColor: const Color(0xff429482), inactiveColor: const Color(0xffE3F0ED), ), ); }); } Widget _buildPlayButton() { return Obx(() { return SizedBox( width: 52, height: 52, child: Center( child: playerController.isLoading.value ? const CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Color(0xff429482)), strokeWidth: 3.0, ) : IconButton( padding: EdgeInsets.zero, constraints: const BoxConstraints( minWidth: 52, minHeight: 52, maxWidth: 52, maxHeight: 52, ), onPressed: playerController.playOrPause, icon: !playerController.isPlaying.value ? Image.asset( "assets/img/music_play.png", width: 52, height: 52, ) : Image.asset( "assets/img/music_pause.png", width: 52, height: 52, ), ), ), ); }); } // Widget _buildRotatingAlbumCover() { // return Obx(() { // final currentSong = // widget.songList[playerController.currentSongIndex.value]; // return RotationTransition( // turns: _rotationController, // child: Stack( // alignment: Alignment.center, // children: [ // Positioned( // child: ClipRRect( // child: Image.network( // currentSong.artistPic, // width: 225, // height: 225, // fit: BoxFit.cover, // ), // ), // ), // ClipRRect( // child: Image.asset( // "assets/img/music_Ellipse.png", // width: 350, // height: 350, // fit: BoxFit.cover, // ), // ), // ], // ), // ); // }); // } Widget _buildRotatingAlbumCover() { return Obx(() { final currentSong = widget.songList[playerController.currentSongIndex.value]; // 移除 RotationTransition,直接返回静态封面 return Stack( alignment: Alignment.center, children: [ Positioned( child: ClipRRect( child: Image.network( currentSong.artistPic, width: 225, height: 225, fit: BoxFit.cover, ), ), ), ClipRRect( child: Image.asset( "assets/img/music_Ellipse.png", width: 350, height: 350, fit: BoxFit.cover, ), ), ], ); }); } void _showPlaylist() { showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(30)), ), builder: (BuildContext context) { return Container( padding: const EdgeInsets.only(top: 15), constraints: BoxConstraints( maxHeight: MediaQuery.of(context).size.height * 0.45, ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const Center( child: Text( "播放列表", style: TextStyle(fontSize: 20), ), ), const SizedBox(height: 10), Expanded( child: Obx(() => ListView.builder( itemCount: playerController.musicNames.length, itemBuilder: (BuildContext context, int index) { final isCurrentlyPlaying = playerController.currentSongIndex.value == index; return ListTile( tileColor: isCurrentlyPlaying ? const Color(0xffE3F0ED) : null, title: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Padding( padding: const EdgeInsets.only(left: 20), child: Text( playerController.musicNames[index], style: const TextStyle(fontSize: 18), ), ), Padding( padding: const EdgeInsets.only(right: 20), child: Image.asset( "assets/img/songs_run.png", width: 25, ), ), ], ), onTap: () { playerController.changeSong(index); Navigator.pop(context); }, ); }, )), ), ], ), ); }, ); } @override Widget build(BuildContext context) { return Container( decoration: const BoxDecoration( image: DecorationImage( image: AssetImage("assets/img/app_bg.png"), fit: BoxFit.cover, ), ), child: Scaffold( resizeToAvoidBottomInset: false, backgroundColor: Colors.transparent, body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.only(top: 45, left: 10, right: 10), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( onPressed: () { Get.back(); }, icon: Image.asset( "assets/img/back.png", width: 25, height: 25, fit: BoxFit.contain, ), ), Row( children: [ IconButton( onPressed: () {}, icon: Image.asset( "assets/img/music_add.png", width: 30, height: 30, ), ), Obx(() => IconButton( onPressed: downloadManager.isDownloading( playerController.ids[playerController .currentSongIndex.value]) || downloadManager.isCompleted( playerController.ids[playerController .currentSongIndex.value]) ? null : () async { await downloadManager.startDownload( song: widget.songList[playerController .currentSongIndex.value], context: context, ); }, icon: Obx(() { if (downloadManager.isDownloading( playerController.ids[playerController .currentSongIndex.value])) { return Stack( alignment: Alignment.center, children: [ SizedBox( width: 32, height: 32, child: CircularProgressIndicator( value: downloadManager.getProgress( playerController.ids[ playerController .currentSongIndex.value]), backgroundColor: Colors.grey[200], valueColor: const AlwaysStoppedAnimation< Color>(Color(0xff429482)), strokeWidth: 3.0, ), ), Text( '${(downloadManager.getProgress(playerController.ids[playerController.currentSongIndex.value]) * 100).toInt()}', style: const TextStyle(fontSize: 12), ), ], ); } return Image.asset( downloadManager.isCompleted( playerController.ids[playerController .currentSongIndex.value]) ? "assets/img/music_download_completed.png" : "assets/img/music_download.png", width: 30, height: 30, ); }), )), ], ), ], ), const SizedBox(height: 80), Center(child: _buildRotatingAlbumCover()), const SizedBox(height: 60), Obx(() => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.end, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( playerController.musicName.value, style: const TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), Text( playerController.artistName.value, style: const TextStyle(fontSize: 20), ), ], ), Row( children: [ IconButton( onPressed: () async { playerController.toggleLike(); final currentIndex = playerController.currentSongIndex.value; widget.onSongStatusChanged?.call( currentIndex, playerController.collections[currentIndex], playerController.likes[currentIndex], ); }, icon: Image.asset( playerController.likesStatus.value ? "assets/img/music_good.png" : "assets/img/music_good_un.png", width: 29, height: 29, ), ), IconButton( onPressed: () async { playerController.toggleCollection(); final currentIndex = playerController.currentSongIndex.value; widget.onSongStatusChanged?.call( currentIndex, playerController.collections[currentIndex], playerController.likes[currentIndex], ); }, icon: Image.asset( playerController.collectionsStatus.value ? "assets/img/music_star.png" : "assets/img/music_star_un.png", width: 29, height: 29, ), ), IconButton( onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => CommentView( id: playerController.ids[playerController .currentSongIndex.value], song: playerController.musicName.value, singer: playerController.artistName.value, cover: widget .songList[playerController .currentSongIndex.value] .artistPic, ), ), ); }, icon: Image.asset( "assets/img/music_commend_un.png", width: 29, height: 29, ), ), ], ), ], )), const SizedBox(height: 80), Obx(() => Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( formatDuration(playerController.position.value), style: const TextStyle(color: Colors.black), ), Expanded(child: _buildProgressSlider()), Text( formatDuration(playerController.duration.value), style: const TextStyle(color: Colors.black), ), ], )), const SizedBox(height: 30), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ IconButton( onPressed: () {}, icon: Image.asset( "assets/img/music_random.png", width: 35, height: 35, ), ), Row( children: [ IconButton( onPressed: playerController.playPrevious, icon: Image.asset( "assets/img/music_back.png", width: 42, height: 42, ), ), const SizedBox(width: 10), _buildPlayButton(), const SizedBox(width: 10), IconButton( onPressed: playerController.playNext, icon: Image.asset( "assets/img/music_next.png", width: 42, height: 42, ), ), ], ), IconButton( onPressed: _showPlaylist, icon: Image.asset( "assets/img/music_more.png", width: 35, height: 35, ), ), ], ), ], ), ), ), ), ); } }