From 38921f848fd78f085eca4d6797649cd4715b3304 Mon Sep 17 00:00:00 2001 From: Spark <2666652@gmail.com> Date: Sat, 16 Nov 2024 21:55:27 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E6=92=AD=E6=94=BE?= =?UTF-8?q?=E5=99=A8=E6=A0=B7=E5=BC=8F,=20=E5=90=AF=E7=94=A8=E9=A1=B5?= =?UTF-8?q?=E9=9D=A2=E4=BF=9D=E6=8C=81,=20=E6=B7=BB=E5=8A=A0=E4=B8=8B?= =?UTF-8?q?=E6=8B=89=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/view/home_view.dart | 618 +++++++++++++++++++---------------- lib/view/music_view.dart | 54 ++- lib/view/rank_view.dart | 339 ++++++++++--------- lib/view/release_view.dart | 6 +- lib/view/user/user_view.dart | 43 ++- 5 files changed, 584 insertions(+), 476 deletions(-) diff --git a/lib/view/home_view.dart b/lib/view/home_view.dart index 8fd1806..3b21abf 100644 --- a/lib/view/home_view.dart +++ b/lib/view/home_view.dart @@ -20,67 +20,77 @@ class HomeView extends StatefulWidget { State createState() => _HomeViewState(); } -class _HomeViewState extends State { - // 使用 GetX 框架的依赖注入,将 HomeViewModel 实例注册为 homeVM。 - // Get.put() 方法会创建 HomeViewModel 的实例,并将其保存在 GetX 的依赖管理器中,方便后续使用。 +class _HomeViewState extends State + with AutomaticKeepAliveClientMixin { final homeVM = Get.put(HomeViewModel()); - - // 创建一个 TextEditingController,用于控制和监听搜索输入框的文本变化。 - // 这个控制器可以用于获取输入框的内容、清空输入框等操作。 final TextEditingController _controller = TextEditingController(); - - // 定义一个布尔变量 _isSearching,用于表示当前是否处于搜索状态。 - // 当用户在搜索框中输入内容时,_isSearching 会变为 true;当输入框为空时,_isSearching 会变为 false。 bool _isSearching = false; final downloadManager = Get.put(DownloadManager()); + List selectedSongs = []; + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); _fetchSonglistData(); } - List selectedSongs = []; - Future _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!), - ]; - }); + Future _onRefresh() async { + try { + // 重新获取数据 + await _fetchSonglistData(); + } catch (e) { + print('Refresh error: $e'); + // 可以在这里添加错误提示 + } } + Future _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 imgList = [ @@ -107,32 +117,40 @@ class _HomeViewState extends State { // 循环处理每个搜索结果,通过 id 请求详细信息 for (var data in bean.data!) { - if (data.id != null) { // 确保 id 不为 null + 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 - }) - ); + 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}"); } @@ -142,12 +160,15 @@ class _HomeViewState extends State { List songDetailsList = await Future.wait(songDetailsFutures); // 过滤掉 null 值 - List validSongDetails = songDetailsList.where((song) => song != null).cast().toList(); + List validSongDetails = songDetailsList + .where((song) => song != null) + .cast() + .toList(); // 最后更新 UI,一次性更新 _filteredData setState(() { - _filteredData = validSongDetails; // 更新搜索结果 - _isSearching = true; // 设置正在搜索中 + _filteredData = validSongDetails; // 更新搜索结果 + _isSearching = true; // 设置正在搜索中 }); // 打印最终结果 @@ -175,6 +196,8 @@ class _HomeViewState extends State { @override Widget build(BuildContext context) { + super.build(context); + ///轮播图 var MySwiperWidget = Swiper( itemBuilder: (BuildContext context, int index) { @@ -205,222 +228,258 @@ class _HomeViewState extends State { 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, + 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, + ) + ], ), - Text( - '你的云端音乐库', - style: - TextStyle(fontSize: 20, fontWeight: FontWeight.w500), + 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, + ), + ), ), - ], - ), - ), - const SizedBox(height: 10,), - ///搜索 - Container( - padding: const EdgeInsets.only(left: 20, right: 20, top: 10), - child: Column( - children: [ + ), + if (_isSearching) Container( - height: 38, + height: 150, + width: 345, decoration: BoxDecoration( - color: const Color(0xffF9F2AF), - borderRadius: BorderRadius.circular(19), - boxShadow: const [ - BoxShadow( - color: Colors.black26, - offset: Offset(0, 1), - blurRadius: 0.1, - ) - ], + color: const Color(0xffF9F2AF).withOpacity(0.7), ), - child: TextField( - controller: _controller, - onChanged: (query) { - setState(() async { - _filterData(query); - }); + 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, // 传递当前歌曲在歌曲列表中的索引,用于在新页面中显示或操作 + ), + ), + ); + }, + ); }, - 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) + ], + ), + ), + + 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( - height: 150, - width: 345, - decoration: BoxDecoration( - color: const Color(0xffF9F2AF).withOpacity(0.7), + padding: + const EdgeInsets.only(left: 20, right: 20, top: 10), + child: const Text( + '每日推荐', + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w500), ), - child: ListView.builder( - padding: EdgeInsets.zero, - itemCount: _filteredData.length, - itemBuilder: (context, index) { - return ListTile( - title: Text(_filteredData[index].title), + ), + 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: 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: () { - // 用户点击列表项时,执行以下操作: - Navigator.push( - // 使用 Navigator 进行页面跳转 - context, - MaterialPageRoute( - // 创建一个新的页面(MusicView),并将当前歌曲和索引作为参数传递给它 - builder: (context) => MusicView( - songList: _filteredData, // 传递当前列表项对应的歌曲对象,包含歌曲的详细信息 - initialSongIndex: index, // 传递当前歌曲在歌曲列表中的索引,用于在新页面中显示或操作 - ), - ), - ); + _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: 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), + 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); - }); - }, - ), + ///精选歌单 + Container( + padding: + const EdgeInsets.only(left: 20, right: 20, top: 5), + child: const Text( + '精选歌单', + style: TextStyle( + fontSize: 20, fontWeight: FontWeight.w500), ), - ); - }, - ); - }, - ), - - 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: () {}, + ); + }), + ), + ], + ), ), ), - 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: () {}, - ); - }), - ), - ], - ), + ), + ], ), ), ); @@ -433,7 +492,8 @@ class _HomeViewState extends State { shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(30)), ), - builder: (context) => StatefulBuilder( // 使用StatefulBuilder以便动态修改状态 + builder: (context) => StatefulBuilder( + // 使用StatefulBuilder以便动态修改状态 builder: (context, setState) { bool likesnot = false; // 初始状态,假设未点赞 @@ -479,11 +539,11 @@ class _HomeViewState extends State { Column( children: [ IconButton( - onPressed: (){}, + onPressed: () {}, icon: Image.asset("assets/img/list_good.png"), iconSize: 60, ), - Text("点赞") + const Text("点赞") ], ), Column( @@ -492,8 +552,8 @@ class _HomeViewState extends State { onPressed: () { Navigator.pop(context); Get.to(() => CommentView( - initialSongIndex: index, - )); + initialSongIndex: index, + )); }, icon: Image.asset("assets/img/list_comment.png"), iconSize: 60, diff --git a/lib/view/music_view.dart b/lib/view/music_view.dart index e3a1bd5..ae82590 100644 --- a/lib/view/music_view.dart +++ b/lib/view/music_view.dart @@ -33,6 +33,7 @@ class _MusicViewState extends State with SingleTickerProviderStateMix AppData appData = AppData(); late int currentSongIndex; late AudioPlayer _audioPlayer; + StreamSubscription? _playerStateSubscription; final downloadManager = Get.put(DownloadManager()); @@ -69,24 +70,24 @@ class _MusicViewState extends State with SingleTickerProviderStateMix vsync: this, ); - // 2. 监听播放器状态来控制动画 - _audioPlayer.playerStateStream.listen((state) { - if (state.playing) { - // 当开始播放时,从当前角度继续旋转 - _rotationController.repeat(); - } else { - // 当暂停时,保持当前角度停止 - _rotationController.stop(canceled: false); + _playerStateSubscription = _audioPlayer.playerStateStream.listen((state) { + if (!_isDisposed) { + if (state.playing) { + _rotationController.repeat(); + } else { + _rotationController.stop(); + } } }); - } @override void dispose() { _isDisposed = true; - _audioPlayer.dispose(); + _playerStateSubscription?.cancel(); + _rotationController.stop(); _rotationController.dispose(); + _audioPlayer.dispose(); super.dispose(); } @@ -104,6 +105,7 @@ class _MusicViewState extends State with SingleTickerProviderStateMix } Future _updateCurrentSong() async { + if (_isDisposed) return; // 立即更新UI和歌曲信息 setState(() { _isLoading = true; @@ -216,14 +218,22 @@ class _MusicViewState extends State with SingleTickerProviderStateMix } void playOrPause() async { + if (_isDisposed) return; // 添加状态检查 + if (_audioPlayer.playing) { await _audioPlayer.pause(); - _rotationController.stop(canceled: false); + if (!_isDisposed) { // 再次检查状态 + _rotationController.stop(); + } } else { await _audioPlayer.play(); - _rotationController.repeat(); + if (!_isDisposed) { // 再次检查状态 + _rotationController.repeat(); + } + } + if (!_isDisposed) { + setState(() {}); } - setState(() {}); } void playNextSong() { @@ -605,6 +615,9 @@ class _MusicViewState extends State with SingleTickerProviderStateMix ), ), ), + const SizedBox( + height: 10, + ), Expanded( child: ListView.builder( itemCount: music.length, @@ -641,21 +654,6 @@ class _MusicViewState extends State with SingleTickerProviderStateMix }, ), ), - ElevatedButton( - onPressed: () => Navigator.pop(context), - style: ElevatedButton.styleFrom( - backgroundColor: const Color(0xff429482), - padding: const EdgeInsets.symmetric(vertical: 14), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.zero, - ), - ), - child: const Text( - "关闭", - style: TextStyle(color: Colors.black, fontSize: 20), - ), - ), ], ), ); diff --git a/lib/view/rank_view.dart b/lib/view/rank_view.dart index b94bbf8..5fa73dc 100644 --- a/lib/view/rank_view.dart +++ b/lib/view/rank_view.dart @@ -15,7 +15,7 @@ class RankView extends StatefulWidget { State createState() => _RankViewState(); } -class _RankViewState extends State { +class _RankViewState extends State with AutomaticKeepAliveClientMixin { final rankVM = Get.put(RankViewModel()); List rankNames = []; List rankSingerName = []; @@ -25,42 +25,55 @@ class _RankViewState extends State { final downloadManager = Get.put(DownloadManager()); + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); _fetchSonglistData(); } + Future _onRefresh() async { + await _fetchSonglistData(); + } + Future _fetchSonglistData() async { - RankBean bean2 = await GetRank().getRank(Authorization: AppData().currentToken); - setState(() { - rankNames = bean2.data!.map((data) => data.name!).toList(); - rankSingerName = bean2.data!.map((data) => data.singerName!).toList(); - rankCoverPath = bean2.data!.map((data) => data.coverPath!).toList(); - rankMusicPath = bean2.data!.map((data) => data.musicPath!).toList(); + try { + RankBean bean2 = await GetRank().getRank(Authorization: AppData().currentToken); + setState(() { + rankNames = bean2.data!.map((data) => data.name!).toList(); + rankSingerName = bean2.data!.map((data) => data.singerName!).toList(); + rankCoverPath = bean2.data!.map((data) => data.coverPath!).toList(); + rankMusicPath = bean2.data!.map((data) => data.musicPath!).toList(); - if (rankNames.isNotEmpty && - rankNames.length == rankSingerName.length && - rankNames.length == rankCoverPath.length && - rankNames.length == rankMusicPath.length) { - for (int i = 0; i < rankNames.length; i++) { - songs.add(Song( - artistPic: rankCoverPath[i], - title: rankNames[i], - artist: rankSingerName[i], - musicurl: rankMusicPath[i], - pic: rankCoverPath[i], - id: i, - likes: false, - collection: false, - )); + if (rankNames.isNotEmpty && + rankNames.length == rankSingerName.length && + rankNames.length == rankCoverPath.length && + rankNames.length == rankMusicPath.length) { + for (int i = 0; i < rankNames.length; i++) { + songs.add(Song( + artistPic: rankCoverPath[i], + title: rankNames[i], + artist: rankSingerName[i], + musicurl: rankMusicPath[i], + pic: rankCoverPath[i], + id: i, + likes: false, + collection: false, + )); + } } - } - }); + }); + } catch (e) { + // 可以添加错误处理逻辑 + print('Error fetching data: $e'); + } } @override Widget build(BuildContext context) { + super.build(context); return Container( decoration: const BoxDecoration( image: DecorationImage( @@ -74,20 +87,19 @@ class _RankViewState extends State { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - const SizedBox( - height: 40, - ), + const SizedBox(height: 40), //头部 const Center( child: Column( children: [ + SizedBox( + height: 10, + ), Text( '喵听排行榜', style: TextStyle(fontSize: 22, fontWeight: FontWeight.w400), ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), Text( 'Top50', style: TextStyle( @@ -95,19 +107,15 @@ class _RankViewState extends State { fontSize: 40, fontWeight: FontWeight.w500), ), - SizedBox( - height: 10, - ), - Text( - '2023/12/12更新 1期', - style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), - ), + // SizedBox(height: 10), + // Text( + // '2023/12/12更新 1期', + // style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500), + // ), ], ), ), - const SizedBox( - height: 10, - ), + const SizedBox(height: 10), Container( decoration: const BoxDecoration( color: Colors.white, @@ -119,7 +127,25 @@ class _RankViewState extends State { child: Row( children: [ IconButton( - onPressed: () {}, + onPressed: () { + // 播放全部 + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MusicView( + songList: songs, + initialSongIndex: 0, + onSongStatusChanged: (index, isCollected, isLiked) { + setState(() { + songs[index].collection = isCollected; + songs[index].likes = isLiked; + downloadManager.updateSongInfo(songs[index].id, isCollected, isLiked); + }); + }, + ), + ), + ); + }, icon: Image.asset( "assets/img/button_play.png", width: 20, @@ -130,9 +156,7 @@ class _RankViewState extends State { '播放全部', style: TextStyle(fontSize: 16), ), - const SizedBox( - width: 5, - ), + const SizedBox(width: 5), const Text( '50', style: TextStyle(fontSize: 16), @@ -141,13 +165,16 @@ class _RankViewState extends State { ), ), Expanded( - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Container( - color: Colors.white, - child: Column( - children: [ - ListView.builder( + child: RefreshIndicator( + onRefresh: _onRefresh, + color: const Color(0xff429482), + child: SingleChildScrollView( + physics: const AlwaysScrollableScrollPhysics(), // 修改为始终可滚动 + child: Container( + color: Colors.white, + child: Column( + children: [ + ListView.builder( physics: const NeverScrollableScrollPhysics(), shrinkWrap: true, padding: const EdgeInsets.symmetric( @@ -156,119 +183,107 @@ class _RankViewState extends State { itemBuilder: (context, index) { int rankNum = index + 1; return ListTile( - onTap: () { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => MusicView( - songList: songs, - initialSongIndex: index, - onSongStatusChanged: (index, isCollected, isLiked) { - setState(() { - // 更新父组件中的数据 - songs[index].collection = isCollected; - songs[index].likes = isLiked; - downloadManager.updateSongInfo(songs[index].id, isCollected, isLiked); - }); - }, - ), + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MusicView( + songList: songs, + initialSongIndex: index, + onSongStatusChanged: (index, isCollected, isLiked) { + setState(() { + songs[index].collection = isCollected; + songs[index].likes = isLiked; + downloadManager.updateSongInfo(songs[index].id, isCollected, isLiked); + }); + }, ), - ); - }, - title: Column( - children: [ - Row( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - SizedBox( - width: 25, - child: RichText( - text: TextSpan( - text: rankNum.toString(), - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.w700, - color: Color(0xffCE0000), + ), + ); + }, + title: Column( + children: [ + Row( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + width: 25, + child: RichText( + text: TextSpan( + text: rankNum.toString(), + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.w700, + color: Color(0xffCE0000), + ), ), ), ), - ), - const SizedBox( - width: 10, - ), - ClipRRect( - borderRadius: - BorderRadius.circular(10), - child: Image.network( - rankCoverPath[index], - width: 60, - height: 60, - fit: BoxFit.cover, - + const SizedBox(width: 10), + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.network( + rankCoverPath[index], + width: 60, + height: 60, + fit: BoxFit.cover, + ), ), - ), - const SizedBox( - width: 20, - ), - SizedBox( - width: 170, - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - rankNames[index], - maxLines: 1, - style: const TextStyle( - color: Colors.black, - fontSize: 16, - fontWeight: - FontWeight.w400), - ), - Text( - rankSingerName[index], - maxLines: 1, - style: const TextStyle( - color: Colors.black, - fontSize: 14), - ) - ], + const SizedBox(width: 20), + SizedBox( + width: 170, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + rankNames[index], + maxLines: 1, + style: const TextStyle( + color: Colors.black, + fontSize: 16, + fontWeight: FontWeight.w400 + ), + ), + Text( + rankSingerName[index], + maxLines: 1, + style: const TextStyle( + color: Colors.black, + fontSize: 14 + ), + ) + ], + ), ), - ), - const SizedBox( - width: 18, - ), - ], - ), - IconButton( - onPressed: () { - _bottomSheet(context, index); // 传递当前的 index - }, - icon: Image.asset( - 'assets/img/More.png', - width: 25, - height: 25, - errorBuilder: (context, error, stackTrace) { - print('Error loading image: $error'); - return const Icon(Icons.error, size: 25); // 使用 const + const SizedBox(width: 18), + ], + ), + IconButton( + onPressed: () { + _bottomSheet(context, index); }, + icon: Image.asset( + 'assets/img/More.png', + width: 25, + height: 25, + errorBuilder: (context, error, stackTrace) { + print('Error loading image: $error'); + return const Icon(Icons.error, size: 25); + }, + ), ), - ), - const SizedBox( - height: 20, - ) - ], - ), - const SizedBox( - height: 10, - ) - ], - )); - }), - ], + ], + ), + const SizedBox(height: 10) + ], + ), + ); + }, + ), + ], + ), ), ), ), @@ -278,12 +293,15 @@ class _RankViewState extends State { ), ); } - Future _bottomSheet(BuildContext context, int index){ + + 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) =>Container( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(30)) + ), + builder: (context) => Container( height: 150, padding: const EdgeInsets.only(top: 20), child: Column( @@ -349,7 +367,6 @@ class _RankViewState extends State { ], ), ) - ); } -} +} \ No newline at end of file diff --git a/lib/view/release_view.dart b/lib/view/release_view.dart index e4ee656..d408d18 100644 --- a/lib/view/release_view.dart +++ b/lib/view/release_view.dart @@ -23,17 +23,19 @@ class SongInfo { SongInfo({required this.songName, required this.artistName}); } -class _ReleaseViewState extends State { +class _ReleaseViewState extends State with AutomaticKeepAliveClientMixin { List coverImages = []; List songInfoList = []; late File selectedMp3File; - + @override + bool get wantKeepAlive => true; @override Widget build(BuildContext context) { + super.build(context); return Scaffold( resizeToAvoidBottomInset: false, backgroundColor: Colors.transparent, diff --git a/lib/view/user/user_view.dart b/lib/view/user/user_view.dart index 08ad44b..9f44c1e 100644 --- a/lib/view/user/user_view.dart +++ b/lib/view/user/user_view.dart @@ -24,7 +24,7 @@ class UserView extends StatefulWidget { State createState() => _UserViewState(); } -class _UserViewState extends State { +class _UserViewState extends State with AutomaticKeepAliveClientMixin { final homeVM = Get.put(HomeViewModel()); final TextEditingController _controller = TextEditingController(); int playlistCount = 0; @@ -36,6 +36,9 @@ class _UserViewState extends State { final downloadManager = Get.put(DownloadManager()); + @override + bool get wantKeepAlive => true; + @override void initState() { super.initState(); @@ -61,6 +64,7 @@ class _UserViewState extends State { @override Widget build(BuildContext context) { + super.build(context); return Container( decoration: const BoxDecoration( image: DecorationImage( @@ -123,7 +127,12 @@ class _UserViewState extends State { children: [ InkWell( onTap: () { - Get.to(const MyMusicView()); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const MyMusicView(), + ), + ); }, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -159,7 +168,12 @@ class _UserViewState extends State { //我的收藏和本地下载分界 InkWell( onTap: () async { - final result = await Get.to(const MyDownloadView()); + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MyDownloadView(), + ), + ); if (result == true) { setState(() { @@ -252,7 +266,14 @@ class _UserViewState extends State { InkWell( onTap: () { print('点击成功'); - Get.to(MyMusicView(songlistIdd: playlistid[index])); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MyMusicView( + songlistIdd: playlistid[index] + ), + ), + ); }, child: Row( children: [ @@ -304,7 +325,12 @@ class _UserViewState extends State { children: [ InkWell( onTap: () { - Get.to(const MyWorkView()); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const MyWorkView(), + ), + ); }, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -365,7 +391,12 @@ class _UserViewState extends State { IconButton( onPressed: () async { Navigator.pop(context); - bool result = await Get.to(const UserInfo()); + bool result = await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const UserInfo(), + ), + ); if (result) { setState(() { avatar = AppData().currentAvatar;