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.

584 lines
21 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/comment_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>
with AutomaticKeepAliveClientMixin {
final homeVM = Get.put(HomeViewModel());
final TextEditingController _controller = TextEditingController();
bool _isSearching = false;
final downloadManager = Get.put(DownloadManager());
List<Song> selectedSongs = [];
@override
bool get wantKeepAlive => true;
@override
void initState() {
super.initState();
_fetchSonglistData();
}
Future<void> _onRefresh() async {
try {
// 重新获取数据
await _fetchSonglistData();
} catch (e) {
print('Refresh error: $e');
// 可以在这里添加错误提示
}
}
Future<void> _fetchSonglistData() async {
try {
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!),
];
});
} catch (e) {
print('Error occurred while fetching song list: $e');
}
}
///轮播图
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) {
super.build(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: Column(
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.symmetric(horizontal: 20, vertical: 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,
),
///推荐+轮播图
Expanded(
child: RefreshIndicator(
onRefresh: _onRefresh,
color: const Color(0xff429482),
backgroundColor: Colors.white,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
///推荐+轮播图
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.symmetric(
horizontal: 20, vertical: 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: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
selectedSongs[index].pic,
width: 60,
height: 60,
fit: BoxFit.cover,
),
),
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,
),
const Text("点赞")
],
),
Column(
children: [
IconButton(
onPressed: () {
Navigator.pop(context);
// Get.to(() =>
// CommentView(
// id:,
// song:,
// singer:,
// ));
},
icon: Image.asset("assets/img/list_comment.png"),
iconSize: 60,
),
const Text("评论"),
],
),
],
),
],
),
);
},
),
);
}
}