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.

514 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import 'package:flutter/material.dart';
import 'package:flutter_swiper_view/flutter_swiper_view.dart';
import 'package:get/get.dart';
import 'package:music_player_miao/api/api_music_return.dart';
import 'package:music_player_miao/common_widget/app_data.dart';
import 'package:music_player_miao/models/search_bean.dart';
import 'package:music_player_miao/view/commend_view.dart';
import '../../view_model/home_view_model.dart';
import '../api/api_music_list.dart';
import '../common/download_manager.dart';
import '../common_widget/Song_widegt.dart';
import '../common_widget/list_cell.dart';
import '../models/getMusicList_bean.dart';
import 'music_view.dart';
class HomeView extends StatefulWidget {
const HomeView({super.key});
@override
State<HomeView> createState() => _HomeViewState();
}
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> selectedSongs = [];
Future<void> _fetchSonglistData() async {
MusicListBean bean1 =
await GetMusic().getMusic1(Authorization: AppData().currentToken);
MusicListBean bean2 =
await GetMusic().getMusic2(Authorization: AppData().currentToken);
MusicListBean bean3 =
await GetMusic().getMusic3(Authorization: AppData().currentToken);
setState(() {
selectedSongs = [
Song(
artistPic: bean1.coverPath!,
title: bean1.name!,
artist: bean1.singerName!,
musicurl: bean1.musicPath!,
pic: bean1.coverPath!,
id: bean1.id!,
likes: bean1.likeOrNot!,
collection: bean1.collectOrNot!),
Song(
artistPic: bean2.coverPath!,
title: bean2.name!,
artist: bean2.singerName!,
musicurl: bean2.musicPath!,
pic: bean2.coverPath!,
id: bean2.id!,
likes: bean2.likeOrNot!,
collection: bean2.collectOrNot!),
Song(
artistPic: bean3.coverPath!,
title: bean3.name!,
artist: bean3.singerName!,
musicurl: bean3.musicPath!,
pic: bean3.coverPath!,
id: bean3.id!,
likes: bean3.likeOrNot!,
collection: bean3.collectOrNot!),
];
});
}
///轮播图
List<Map> imgList = [
{"image": "assets/img/banner.png"},
{"image": "assets/img/banner.png"},
{"image": "assets/img/banner.png"},
];
List<Song> _filteredData = [];
Future<void> _filterData(String query) async {
if (query.isNotEmpty) {
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 = [];
_isSearching = false;
});
}
} catch (error) {
print("Error occurred during search: $error");
setState(() {
_filteredData = [];
_isSearching = false;
});
}
} else {
setState(() {
_filteredData = [];
_isSearching = false;
});
}
}
@override
Widget build(BuildContext context) {
///轮播图
var MySwiperWidget = Swiper(
itemBuilder: (BuildContext context, int index) {
//每次循环遍历时将i赋值给index
return new Image.asset(
imgList[index]['image'],
fit: BoxFit.fill,
);
},
itemCount: imgList.length,
//指示器
pagination: SwiperPagination(
builder: DotSwiperPaginationBuilder(
color: Colors.white.withOpacity(0.85), // Color of inactive dots
activeColor: const Color(0xff429482), // Color of active dot
),
),
// autoplay: true,
autoplayDelay: 3000,
);
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: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
///头部
Container(
padding: const EdgeInsets.only(left: 20, top: 50),
child: const Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(
'喵听',
style:
TextStyle(fontSize: 35, fontWeight: FontWeight.bold),
),
SizedBox(
width: 10,
),
Text(
'你的云端音乐库',
style:
TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
],
),
),
const SizedBox(height: 10,),
///搜索
Container(
padding: const EdgeInsets.only(left: 20, right: 20, top: 10),
child: Column(
children: [
Container(
height: 38,
decoration: BoxDecoration(
color: const Color(0xffF9F2AF),
borderRadius: BorderRadius.circular(19),
boxShadow: const [
BoxShadow(
color: Colors.black26,
offset: Offset(0, 1),
blurRadius: 0.1,
)
],
),
child: TextField(
controller: _controller,
onChanged: (query) {
setState(() async {
_filterData(query);
});
},
decoration: InputDecoration(
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
contentPadding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 20,
),
prefixIcon: Container(
margin: const EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
width: 30,
child: Image.asset(
"assets/img/home_search.png",
width: 20,
height: 20,
fit: BoxFit.contain,
),
),
hintText: "大家都在搜《背对背拥抱》",
hintStyle: const TextStyle(
color: Color(0xffA5A5A5),
fontSize: 13,
),
),
),
),
if (_isSearching)
Container(
height: 150,
width: 345,
decoration: BoxDecoration(
color: const Color(0xffF9F2AF).withOpacity(0.7),
),
child: ListView.builder(
padding: EdgeInsets.zero,
itemCount: _filteredData.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(_filteredData[index].title),
onTap: () {
// 用户点击列表项时,执行以下操作:
Navigator.push(
// 使用 Navigator 进行页面跳转
context,
MaterialPageRoute(
// 创建一个新的页面MusicView并将当前歌曲和索引作为参数传递给它
builder: (context) => MusicView(
songList: _filteredData, // 传递当前列表项对应的歌曲对象,包含歌曲的详细信息
initialSongIndex: index, // 传递当前歌曲在歌曲列表中的索引,用于在新页面中显示或操作
),
),
);
},
);
},
),
),
],
),
),
const SizedBox(height: 10,),
///推荐+轮播图
Container(
padding: const EdgeInsets.only(left: 20, right: 20, top: 10),
child: const Text(
'每日推荐',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
),
const SizedBox(height: 5,),
Container(
padding: const EdgeInsets.only(left: 20, right: 20, top: 5),
height: 186,
width: double.infinity,
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: 20, fontWeight: FontWeight.w500),
),
),
const SizedBox(height: 5,),
ListView.builder(
padding: EdgeInsets.zero,
itemCount: selectedSongs.length,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
leading: Image.network(selectedSongs[index].pic),
title: Text(
selectedSongs[index].title,
style: const TextStyle(fontSize: 18, color: Colors.black),
),
subtitle: Text(
selectedSongs[index].artist,
style: const TextStyle(fontSize: 16, color: Colors.black),
),
trailing: InkWell(
onTap: () {
_bottomSheet(context, index);
},
child: Image.asset('assets/img/More.png'),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MusicView(
songList: selectedSongs,
initialSongIndex: index,
onSongStatusChanged: (index, isCollected, isLiked) {
setState(() {
// 更新父组件中的数据
selectedSongs[index].collection = isCollected;
selectedSongs[index].likes = isLiked;
downloadManager.updateSongInfo(selectedSongs[index].id, isCollected, isLiked);
});
},
),
),
);
},
);
},
),
const SizedBox(height: 10,),
///精选歌单
Container(
padding: const EdgeInsets.only(left: 20, right: 20, top: 5),
child: const Text(
'精选歌单',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),
),
),
const SizedBox(height: 5,),
SizedBox(
height: 180,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 20),
itemCount: homeVM.listArr.length,
itemBuilder: (context, index) {
var sObj = homeVM.listArr[index];
return ListRow(
sObj: sObj,
onPressed: () {},
onPressedPlay: () {},
);
}),
),
],
),
),
),
);
}
Future _bottomSheet(BuildContext context, int index) {
return showModalBottomSheet(
context: context,
backgroundColor: Colors.white,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(30)),
),
builder: (context) => StatefulBuilder( // 使用StatefulBuilder以便动态修改状态
builder: (context, setState) {
bool likesnot = false; // 初始状态,假设未点赞
return Container(
height: 150,
padding: const EdgeInsets.only(top: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
IconButton(
onPressed: () {},
icon: Image.asset("assets/img/list_add.png"),
iconSize: 60,
),
const Text("加入歌单"),
],
),
Column(
children: [
IconButton(
onPressed: () {},
icon: Image.asset("assets/img/list_download.png"),
iconSize: 60,
),
const Text("下载"),
],
),
Column(
children: [
IconButton(
onPressed: () {},
icon: Image.asset("assets/img/list_collection.png"),
iconSize: 60,
),
const Text("收藏"),
],
),
Column(
children: [
IconButton(
onPressed: (){},
icon: Image.asset("assets/img/list_good.png"),
iconSize: 60,
),
Text("点赞")
],
),
Column(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
Get.to(() => CommentView(
initialSongIndex: index,
));
},
icon: Image.asset("assets/img/list_comment.png"),
iconSize: 60,
),
const Text("评论"),
],
),
],
),
],
),
);
},
),
);
}
}