You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MTMusic/lib/view/music_view_test.dart

508 lines
19 KiB

// 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<Song> 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<MusicView> createState() => _MusicViewState();
}
class _MusicViewState extends State<MusicView>
with SingleTickerProviderStateMixin {
// late AnimationController _rotationController;
final AudioPlayerController playerController =
Get.put(AudioPlayerController());
final downloadManager = Get.find<DownloadManager>();
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>(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,
),
),
],
),
],
),
),
),
),
);
}
}