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/home_view.dart

588 lines
23 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/common_widget/app_data.dart';
import 'package:music_player_miao/view/comment_view.dart';
import 'package:music_player_miao/view/search_view.dart';
import '../../view_model/home_view_model.dart';
import '../api/api_music_likes.dart';
import '../api/api_music_list.dart';
import '../common/download_manager.dart';
import '../common_widget/Song_widegt.dart';
import '../models/MusicsListBean.dart';
import '../models/universal_bean.dart';
import 'music_view.dart';
import '../api/api_collection.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 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 {
MusicsListBean bean = await GetMusic()
.getMusicList(Authorization: AppData().currentToken, num: 10);
setState(() {
selectedSongs = [];
for (var data in bean.data!) {
selectedSongs.add(Song(
artistPic: data.coverPath!,
title: data.name!,
artist: data.singerName!,
musicurl: data.musicPath,
pic: data.coverPath!,
id: data.id!,
likes: data.likeOrNot!,
collection: data.collectOrNot!,
mid: data.mid,
));
print(data.coverPath!);
}
});
} catch (e) {
print('Error occurred while fetching song list: $e');
}
}
///轮播图
List<Map> imgList = [
{"image": "assets/img/banner.png"},
{"image": "assets/img/banner1.png"},
{"image": "assets/img/banner2.png"},
];
@override
Widget build(BuildContext context) {
super.build(context);
///轮播图
var MySwiperWidget = Swiper(
itemBuilder: (BuildContext context, int index) {
return ClipRRect(
borderRadius: BorderRadius.circular(8), // 添加圆角
child: Image.asset(
imgList[index]['image'],
fit: BoxFit.fill,
),
);
},
itemCount: imgList.length,
pagination: SwiperPagination(
builder: DotSwiperPaginationBuilder(
color: Colors.white.withOpacity(0.85),
activeColor: const Color(0xff429482),
),
),
autoplay: true,
// 开启自动播放
loop: true,
// 开启循环
autoplayDelay: 5000,
control: const SwiperControl(color: Colors.transparent),
// 隐藏默认的左右箭头按钮
viewportFraction: 1.0, // 设置视图比例为1.0,确保图片填充整个容器
);
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: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const SearchView(),
),
);
},
child: 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: Row(
children: [
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,
),
),
const SizedBox(width: 10),
const Text(
"搜索你想找的音乐",
style: TextStyle(
color: Color(0xffA5A5A5),
fontSize: 13,
),
),
],
),
),
),
],
),
),
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: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
boxShadow: [
BoxShadow(
color: Colors.black.withOpacity(0.1),
blurRadius: 5,
offset: const Offset(0, 2),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
selectedSongs[index].pic,
width: 60,
height: 60,
fit: BoxFit.cover,
errorBuilder: (context, error, stackTrace) =>
Container(
width: 60,
height: 60,
color: Colors.grey[100],
child: const Icon(Icons.music_note, size: 30),
),
// loadingBuilder: (context, child, loadingProgress) {
// if (loadingProgress == null) return child;
// return Container(
// width: 60,
// height: 60,
// color: Colors.grey[100],
// child: Center(
// child: CircularProgressIndicator(
// strokeWidth: 2,
// valueColor: const AlwaysStoppedAnimation<Color>(
// Color(0xff429482)),
// value: loadingProgress.expectedTotalBytes != null
// ? loadingProgress.cumulativeBytesLoaded /
// loadingProgress.expectedTotalBytes!
// : null,
// ),
// ),
// );
// },
),
),
),
title: Text(
selectedSongs[index].title,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w500,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
subtitle: Text(
selectedSongs[index].artist,
style: TextStyle(
fontSize: 16,
color: Colors.grey[600],
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
trailing: Padding(
padding: const EdgeInsets.only(right: 16),
child: InkWell(
onTap: () async {
setState(() {
selectedSongs[index].likes = !selectedSongs[index].likes!;
});
UniversalBean response = await LikesApiMusic()
.likesMusic(
musicId: selectedSongs[index].id,
Authorization: AppData().currentToken);
if (response.code != 200) {
setState(() {
selectedSongs[index].likes = !selectedSongs[index].likes!;
});
}
},
child: selectedSongs[index].likes!
? Image.asset(
'assets/img/like.png',
width: 24,
height: 24,
)
: ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.grey[700]!,
BlendMode.srcIn,
),
child: Image.asset(
'assets/img/unlike.png',
width: 24,
height: 24,
),
),
),
),
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: 20,
),
],
),
),
),
),
const SizedBox(
height: 130,
),
],
),
),
);
}
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(
builder: (context, setState) {
// 获取当前歌曲的点赞和收藏状态
bool likesnot = selectedSongs[index].likes ?? false;
bool collectionsnot = selectedSongs[index].collection ?? false;
return Container(
height: 150,
padding: const EdgeInsets.only(top: 20),
child: Column(
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: () async {
// 1. 立即更新UI状态提供即时反馈
setState(() {
collectionsnot = !collectionsnot;
selectedSongs[index].collection = collectionsnot;
});
// 2. 调用收藏API
UniversalBean response =
await CollectionApiMusic().addCollection(
musicId: selectedSongs[index].id,
Authorization: AppData().currentToken,
);
// 3. 处理API响应
if (response.code != 200) {
// 3.1 如果API调用失败回滚状态变化
setState(() {
collectionsnot = !collectionsnot;
selectedSongs[index].collection =
collectionsnot;
});
} else {
// 3.2 API调用成功更新全局状态管理器
downloadManager.updateSongInfo(
selectedSongs[index].id, // 当前歌曲ID
collectionsnot, // 新的收藏状态
selectedSongs[index].likes ??
false // 保持原有的点赞状态
);
}
},
icon: SizedBox(
width: 60,
height: 60,
child: Image.asset(
// 根据收藏状态显示对应图标
collectionsnot
? "assets/img/list_collection.png" // 已收藏状态图标
: "assets/img/list_collection_un.png" // 未收藏状态图标
),
),
),
const Text("收藏"),
],
),
// 点赞按钮及功能
Column(
children: [
IconButton(
onPressed: () async {
// 1. 立即更新UI状态提供即时反馈
setState(() {
likesnot = !likesnot;
selectedSongs[index].likes = likesnot;
});
// 2. 调用点赞API
UniversalBean response =
await LikesApiMusic().likesMusic(
musicId: selectedSongs[index].id,
Authorization: AppData().currentToken,
);
// 3. 处理API响应
if (response.code != 200) {
// 3.1 如果API调用失败回滚状态变化
setState(() {
likesnot = !likesnot;
selectedSongs[index].likes = likesnot;
});
} else {
// 3.2 API调用成功更新全局状态管理器
downloadManager.updateSongInfo(
selectedSongs[index].id, // 当前歌曲ID
selectedSongs[index].collection ?? false,
// 保持原有的收藏状态
likesnot // 新的点赞状态
);
}
},
icon: SizedBox(
width: 60,
height: 60,
child: Image.asset(
// 根据点赞状态显示对应图标
likesnot
? "assets/img/list_good.png" // 已点赞状态图标
: "assets/img/list_good_un.png" // 未点赞状态图标
),
),
),
const Text("点赞"),
],
),
// 评论按钮
Column(
children: [
IconButton(
onPressed: () {
// 关闭底部弹出栏
Navigator.pop(context);
// 导航到评论页面
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CommentView(
id: selectedSongs[index].id,
song: selectedSongs[index].title,
singer: selectedSongs[index].artist,
cover: selectedSongs[index].artistPic,
),
),
);
},
icon: Image.asset("assets/img/list_comment.png"),
iconSize: 60,
),
const Text("评论"),
],
),
],
),
],
),
);
},
),
);
}
}