|
|
|
@ -21,17 +21,25 @@ class HomeView extends StatefulWidget {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class _HomeViewState extends State<HomeView> {
|
|
|
|
|
// 使用 GetX 框架的依赖注入,将 HomeViewModel 实例注册为 homeVM。
|
|
|
|
|
// Get.put() 方法会创建 HomeViewModel 的实例,并将其保存在 GetX 的依赖管理器中,方便后续使用。
|
|
|
|
|
final homeVM = Get.put(HomeViewModel());
|
|
|
|
|
|
|
|
|
|
// 创建一个 TextEditingController,用于控制和监听搜索输入框的文本变化。
|
|
|
|
|
// 这个控制器可以用于获取输入框的内容、清空输入框等操作。
|
|
|
|
|
final TextEditingController _controller = TextEditingController();
|
|
|
|
|
|
|
|
|
|
// 定义一个布尔变量 _isSearching,用于表示当前是否处于搜索状态。
|
|
|
|
|
// 当用户在搜索框中输入内容时,_isSearching 会变为 true;当输入框为空时,_isSearching 会变为 false。
|
|
|
|
|
bool _isSearching = false;
|
|
|
|
|
final downloadManager = Get.put(DownloadManager());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void initState() {
|
|
|
|
|
super.initState();
|
|
|
|
|
_fetchSonglistData();
|
|
|
|
|
}
|
|
|
|
|
List<Song> songs = [];
|
|
|
|
|
|
|
|
|
|
List<Song> selectedSongs = [];
|
|
|
|
|
Future<void> _fetchSonglistData() async {
|
|
|
|
|
MusicListBean bean1 =
|
|
|
|
|
await GetMusic().getMusic1(Authorization: AppData().currentToken);
|
|
|
|
@ -41,7 +49,7 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
await GetMusic().getMusic3(Authorization: AppData().currentToken);
|
|
|
|
|
|
|
|
|
|
setState(() {
|
|
|
|
|
songs = [
|
|
|
|
|
selectedSongs = [
|
|
|
|
|
Song(
|
|
|
|
|
artistPic: bean1.coverPath!,
|
|
|
|
|
title: bean1.name!,
|
|
|
|
@ -81,23 +89,85 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
{"image": "assets/img/banner.png"},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
List<String> _filteredData = [];
|
|
|
|
|
List<Song> _filteredData = [];
|
|
|
|
|
|
|
|
|
|
Future<void> _filterData(String query) async {
|
|
|
|
|
if (query.isNotEmpty) {
|
|
|
|
|
SearchBean bean = await SearchMusic().search(keyword: query);
|
|
|
|
|
if (bean.code == 200) {
|
|
|
|
|
try {
|
|
|
|
|
// 发起搜索请求
|
|
|
|
|
SearchBean bean = await SearchMusic().search(
|
|
|
|
|
keyword: query,
|
|
|
|
|
Authorization: AppData().currentToken,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// 如果请求成功且返回的数据不为空
|
|
|
|
|
if (bean.code == 200 && bean.data != null) {
|
|
|
|
|
// 创建一个临时列表来存储所有异步请求
|
|
|
|
|
List<Future<Song?>> songDetailsFutures = [];
|
|
|
|
|
|
|
|
|
|
// 循环处理每个搜索结果,通过 id 请求详细信息
|
|
|
|
|
for (var data in bean.data!) {
|
|
|
|
|
if (data.id != null) { // 确保 id 不为 null
|
|
|
|
|
// 使用每个歌曲的 id 获取详细信息,并返回一个 Future
|
|
|
|
|
songDetailsFutures.add(
|
|
|
|
|
GetMusicDetail().getMusicDetail(
|
|
|
|
|
songId: data.id!,
|
|
|
|
|
Authorization: AppData().currentToken,
|
|
|
|
|
).then((details) {
|
|
|
|
|
if (details != null) {
|
|
|
|
|
// 将详细歌曲信息封装成 Song 对象
|
|
|
|
|
return Song(
|
|
|
|
|
artistPic: details.artistPic ?? '', // 歌手封面图
|
|
|
|
|
title: data.name ?? '', // 歌曲名称
|
|
|
|
|
artist: details.artist ?? '', // 歌手名称
|
|
|
|
|
musicurl: details.musicurl ?? '', // 歌曲路径
|
|
|
|
|
pic: details.pic ?? '', // 封面图片路径
|
|
|
|
|
id: details.id, // 歌曲 ID
|
|
|
|
|
likes: details.likes, // 是否喜欢
|
|
|
|
|
collection: details.collection, // 是否收藏
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
return null; // 如果没有详情返回 null
|
|
|
|
|
}).catchError((error) {
|
|
|
|
|
print("Error occurred while fetching song details: $error");
|
|
|
|
|
return null; // 异常处理,返回 null
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
} else {
|
|
|
|
|
print("Song ID is null for song: ${data.name}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 使用 Future.wait 等待所有异步请求完成
|
|
|
|
|
List<Song?> songDetailsList = await Future.wait(songDetailsFutures);
|
|
|
|
|
|
|
|
|
|
// 过滤掉 null 值
|
|
|
|
|
List<Song> validSongDetails = songDetailsList.where((song) => song != null).cast<Song>().toList();
|
|
|
|
|
|
|
|
|
|
// 最后更新 UI,一次性更新 _filteredData
|
|
|
|
|
setState(() {
|
|
|
|
|
_filteredData = validSongDetails; // 更新搜索结果
|
|
|
|
|
_isSearching = true; // 设置正在搜索中
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 打印最终结果
|
|
|
|
|
print("Filtered Data: $_filteredData");
|
|
|
|
|
} else {
|
|
|
|
|
setState(() {
|
|
|
|
|
_filteredData = bean.data
|
|
|
|
|
?.map((data) =>
|
|
|
|
|
"${data.name} ") // Adjust this based on your data structure
|
|
|
|
|
.toList() ??
|
|
|
|
|
[];
|
|
|
|
|
_isSearching = true;
|
|
|
|
|
_filteredData = [];
|
|
|
|
|
_isSearching = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
print("Error occurred during search: $error");
|
|
|
|
|
setState(() {
|
|
|
|
|
_filteredData = [];
|
|
|
|
|
_isSearching = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
setState(() {
|
|
|
|
|
_filteredData = [];
|
|
|
|
|
_isSearching = false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -161,7 +231,7 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
],
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
const SizedBox(height: 10,),
|
|
|
|
|
///搜索
|
|
|
|
|
Container(
|
|
|
|
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 10),
|
|
|
|
@ -226,7 +296,21 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
itemCount: _filteredData.length,
|
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
|
return ListTile(
|
|
|
|
|
title: Text(_filteredData[index]),
|
|
|
|
|
title: Text(_filteredData[index].title),
|
|
|
|
|
onTap: () {
|
|
|
|
|
// 用户点击列表项时,执行以下操作:
|
|
|
|
|
Navigator.push(
|
|
|
|
|
// 使用 Navigator 进行页面跳转
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
// 创建一个新的页面(MusicView),并将当前歌曲和索引作为参数传递给它
|
|
|
|
|
builder: (context) => MusicView(
|
|
|
|
|
songList: _filteredData, // 传递当前列表项对应的歌曲对象,包含歌曲的详细信息
|
|
|
|
|
initialSongIndex: index, // 传递当前歌曲在歌曲列表中的索引,用于在新页面中显示或操作
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
@ -235,14 +319,16 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
const SizedBox(height: 10,),
|
|
|
|
|
///推荐+轮播图
|
|
|
|
|
Container(
|
|
|
|
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 10),
|
|
|
|
|
child: const Text(
|
|
|
|
|
'每日推荐',
|
|
|
|
|
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
|
|
|
|
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 5,),
|
|
|
|
|
Container(
|
|
|
|
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 5),
|
|
|
|
|
height: 186,
|
|
|
|
@ -250,29 +336,32 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
child: MySwiperWidget,
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
const SizedBox(height: 10),
|
|
|
|
|
|
|
|
|
|
///精选歌曲
|
|
|
|
|
Container(
|
|
|
|
|
alignment: Alignment.topLeft,
|
|
|
|
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 5),
|
|
|
|
|
child: const Text(
|
|
|
|
|
'精选歌曲',
|
|
|
|
|
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
|
|
|
|
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 5,),
|
|
|
|
|
ListView.builder(
|
|
|
|
|
padding: EdgeInsets.zero,
|
|
|
|
|
itemCount: songs.length,
|
|
|
|
|
itemCount: selectedSongs.length,
|
|
|
|
|
physics: const NeverScrollableScrollPhysics(),
|
|
|
|
|
shrinkWrap: true,
|
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
|
return ListTile(
|
|
|
|
|
leading: Image.network(songs[index].pic),
|
|
|
|
|
leading: Image.network(selectedSongs[index].pic),
|
|
|
|
|
title: Text(
|
|
|
|
|
songs[index].title,
|
|
|
|
|
selectedSongs[index].title,
|
|
|
|
|
style: const TextStyle(fontSize: 18, color: Colors.black),
|
|
|
|
|
),
|
|
|
|
|
subtitle: Text(
|
|
|
|
|
songs[index].artist,
|
|
|
|
|
selectedSongs[index].artist,
|
|
|
|
|
style: const TextStyle(fontSize: 16, color: Colors.black),
|
|
|
|
|
),
|
|
|
|
|
trailing: InkWell(
|
|
|
|
@ -286,14 +375,14 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
context,
|
|
|
|
|
MaterialPageRoute(
|
|
|
|
|
builder: (context) => MusicView(
|
|
|
|
|
songList: songs,
|
|
|
|
|
songList: selectedSongs,
|
|
|
|
|
initialSongIndex: index,
|
|
|
|
|
onSongStatusChanged: (index, isCollected, isLiked) {
|
|
|
|
|
setState(() {
|
|
|
|
|
// 更新父组件中的数据
|
|
|
|
|
songs[index].collection = isCollected;
|
|
|
|
|
songs[index].likes = isLiked;
|
|
|
|
|
downloadManager.updateSongInfo(songs[index].id, isCollected, isLiked);
|
|
|
|
|
selectedSongs[index].collection = isCollected;
|
|
|
|
|
selectedSongs[index].likes = isLiked;
|
|
|
|
|
downloadManager.updateSongInfo(selectedSongs[index].id, isCollected, isLiked);
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
@ -304,14 +393,16 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
},
|
|
|
|
|
),
|
|
|
|
|
|
|
|
|
|
const SizedBox(height: 10,),
|
|
|
|
|
///精选歌单
|
|
|
|
|
Container(
|
|
|
|
|
padding: const EdgeInsets.only(left: 20, right: 20, top: 5),
|
|
|
|
|
child: const Text(
|
|
|
|
|
'精选歌单',
|
|
|
|
|
style: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
|
|
|
|
|
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
const SizedBox(height: 5,),
|
|
|
|
|
SizedBox(
|
|
|
|
|
height: 180,
|
|
|
|
|
child: ListView.builder(
|
|
|
|
@ -399,6 +490,7 @@ class _HomeViewState extends State<HomeView> {
|
|
|
|
|
children: [
|
|
|
|
|
IconButton(
|
|
|
|
|
onPressed: () {
|
|
|
|
|
Navigator.pop(context);
|
|
|
|
|
Get.to(() => CommentView(
|
|
|
|
|
initialSongIndex: index,
|
|
|
|
|
));
|
|
|
|
|