From bafda1f0bdc09ee7ed1dc67542dd7f2c98138de7 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 23 Jul 2023 23:43:51 +0800 Subject: [PATCH 1/4] =?UTF-8?q?mod:=20=E6=88=91=E7=9A=84=E6=94=B6=E8=97=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/pages/fav/view.dart | 35 +++-------- lib/pages/fav/widgets/item.dart | 96 +++++++++++++++++++++++++++++ lib/pages/favDetail/controller.dart | 28 +++++++-- lib/pages/favDetail/view.dart | 22 ++++--- lib/pages/media/view.dart | 20 +++--- 5 files changed, 153 insertions(+), 48 deletions(-) create mode 100644 lib/pages/fav/widgets/item.dart diff --git a/lib/pages/fav/view.dart b/lib/pages/fav/view.dart index 7a6b147c..f190bc85 100644 --- a/lib/pages/fav/view.dart +++ b/lib/pages/fav/view.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/pages/fav/index.dart'; +import 'package:pilipala/pages/fav/widgets/item.dart'; class FavPage extends StatefulWidget { const FavPage({super.key}); @@ -18,7 +19,11 @@ class _FavPageState extends State { return Scaffold( appBar: AppBar( centerTitle: false, - title: const Text('我的收藏'), + titleSpacing: 0, + title: Text( + '我的收藏', + style: Theme.of(context).textTheme.titleMedium, + ), ), body: FutureBuilder( future: _favController.queryFavFolder(), @@ -30,31 +35,9 @@ class _FavPageState extends State { () => ListView.builder( itemCount: _favController.favFolderData.value.list!.length, itemBuilder: (context, index) { - return ListTile( - onTap: () => Get.toNamed( - '/favDetail', - arguments: - _favController.favFolderData.value.list![index], - parameters: { - 'mediaId': _favController - .favFolderData.value.list![index].id - .toString(), - }, - ), - leading: const Icon(Icons.folder_special_outlined), - minLeadingWidth: 0, - title: Text(_favController - .favFolderData.value.list![index].title!), - subtitle: Text( - '${_favController.favFolderData.value.list![index].mediaCount}个内容', - style: TextStyle( - color: Theme.of(context).colorScheme.outline, - fontSize: Theme.of(context) - .textTheme - .labelSmall! - .fontSize), - ), - ); + return FavItem( + favFolderItem: + _favController.favFolderData.value.list![index]); }, ), ); diff --git a/lib/pages/fav/widgets/item.dart b/lib/pages/fav/widgets/item.dart new file mode 100644 index 00000000..2a92eede --- /dev/null +++ b/lib/pages/fav/widgets/item.dart @@ -0,0 +1,96 @@ +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:pilipala/common/constants.dart'; +import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/utils/utils.dart'; + +class FavItem extends StatelessWidget { + var favFolderItem; + FavItem({super.key, required this.favFolderItem}); + + @override + Widget build(BuildContext context) { + String heroTag = Utils.makeHeroTag(favFolderItem.fid); + return InkWell( + onTap: () => Get.toNamed( + '/favDetail', + arguments: favFolderItem, + parameters: { + 'heroTag': heroTag, + 'mediaId': favFolderItem.id.toString(), + }, + ), + child: Padding( + padding: const EdgeInsets.fromLTRB(12, 7, 12, 7), + child: LayoutBuilder( + builder: (context, boxConstraints) { + double width = + (boxConstraints.maxWidth - StyleString.cardSpace * 6) / 2; + return SizedBox( + height: width / StyleString.aspectRatio, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + AspectRatio( + aspectRatio: StyleString.aspectRatio, + child: LayoutBuilder( + builder: (context, boxConstraints) { + double maxWidth = boxConstraints.maxWidth; + double maxHeight = boxConstraints.maxHeight; + double PR = MediaQuery.of(context).devicePixelRatio; + return Hero( + tag: heroTag, + child: NetworkImgLayer( + src: favFolderItem.cover + '@.webp', + width: maxWidth, + height: maxHeight, + ), + ); + }, + ), + ), + VideoContent(favFolderItem: favFolderItem) + ], + ), + ); + }, + ), + ), + ); + } +} + +class VideoContent extends StatelessWidget { + final favFolderItem; + const VideoContent({super.key, required this.favFolderItem}); + + @override + Widget build(BuildContext context) { + return Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB(10, 2, 6, 0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + favFolderItem.title, + textAlign: TextAlign.start, + style: TextStyle( + fontSize: Theme.of(context).textTheme.titleSmall!.fontSize, + fontWeight: FontWeight.w500), + ), + Text( + '${favFolderItem.mediaCount}个内容', + textAlign: TextAlign.start, + style: TextStyle( + fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, + color: Theme.of(context).colorScheme.outline, + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/favDetail/controller.dart b/lib/pages/favDetail/controller.dart index 52ddebc8..24ecf3e3 100644 --- a/lib/pages/favDetail/controller.dart +++ b/lib/pages/favDetail/controller.dart @@ -4,30 +4,42 @@ import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/user/fav_detail.dart'; import 'package:pilipala/models/user/fav_folder.dart'; -import 'package:pilipala/utils/id_utils.dart'; class FavDetailController extends GetxController { FavFolderItemData? item; Rx favDetailData = FavDetailData().obs; + int? mediaId; + late String heroTag; + int currentPage = 1; + bool isLoadingMore = false; + RxMap favInfo = {}.obs; + RxList favList = [FavDetailItemData()].obs; @override void onInit() { item = Get.arguments; if (Get.parameters.keys.isNotEmpty) { mediaId = int.parse(Get.parameters['mediaId']!); + heroTag = Get.parameters['heroTag']!; } super.onInit(); } - Future queryUserFavFolderDetail() async { - print('🐯🐯虎'); + Future queryUserFavFolderDetail({type = 'init'}) async { var res = await await UserHttp.userFavFolderDetail( - pn: 1, - ps: 15, + pn: currentPage, + ps: 20, mediaId: mediaId!, ); - favDetailData.value = res['data']; + if (res['status']) { + favInfo.value = res['data'].info; + if (currentPage == 1 && type == 'init') { + favList.value = res['data'].medias; + } else if (type == 'onload') { + favList.addAll(res['data'].medias); + } + } return res; } @@ -49,4 +61,8 @@ class FavDetailController extends GetxController { } } } + + onLoad() { + queryUserFavFolderDetail(type: 'onload'); + } } diff --git a/lib/pages/favDetail/view.dart b/lib/pages/favDetail/view.dart index ad7cdb99..88c2cb5f 100644 --- a/lib/pages/favDetail/view.dart +++ b/lib/pages/favDetail/view.dart @@ -34,6 +34,14 @@ class _FavDetailPageState extends State { } else if (_controller.offset <= 160) { titleStreamC.add(false); } + + if (_controller.position.pixels >= + _controller.position.maxScrollExtent - 200) { + if (!_favDetailController.isLoadingMore) { + _favDetailController.isLoadingMore = true; + _favDetailController.onLoad(); + } + } }, ); } @@ -109,9 +117,8 @@ class _FavDetailPageState extends State { // mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, children: [ - SizedBox( - width: 180, - height: 110, + Hero( + tag: _favDetailController.heroTag, child: NetworkImgLayer( width: 180, height: 110, @@ -156,7 +163,7 @@ class _FavDetailPageState extends State { padding: const EdgeInsets.only(top: 15, bottom: 8, left: 14), child: Obx( () => Text( - '共${_favDetailController.favDetailData.value.medias != null ? _favDetailController.favDetailData.value.medias!.length : '-'}条视频', + '共${_favDetailController.favInfo['media_count'] ?? '-'}条视频', style: TextStyle( fontSize: Theme.of(context).textTheme.labelMedium!.fontSize, @@ -184,12 +191,9 @@ class _FavDetailPageState extends State { () => SliverList( delegate: SliverChildBuilderDelegate((context, index) { return FavVideoCardH( - videoItem: _favDetailController - .favDetailData.value.medias![index], + videoItem: _favDetailController.favList[index], ); - }, - childCount: _favDetailController - .favDetailData.value.medias!.length), + }, childCount: _favDetailController.favList.length), ), ); } diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 0860ddb9..43fa8ab0 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -3,6 +3,7 @@ import 'package:get/get.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/pages/media/index.dart'; +import 'package:pilipala/utils/utils.dart'; class MediaPage extends StatelessWidget { const MediaPage({super.key}); @@ -169,12 +170,14 @@ class FavFolderItem extends StatelessWidget { int? index; @override Widget build(BuildContext context) { + String heroTag = Utils.makeHeroTag(item!.fid); + return Container( margin: EdgeInsets.only(left: index == 0 ? 20 : 0, right: 14), child: GestureDetector( - onTap: () => Get.toNamed('/favDetail', arguments: item, parameters: { - 'mediaId': item!.id.toString(), - }), + onTap: () => Get.toNamed('/favDetail', + arguments: item, + parameters: {'mediaId': item!.id.toString(), 'heroTag': heroTag}), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, @@ -199,10 +202,13 @@ class FavFolderItem extends StatelessWidget { ), child: LayoutBuilder( builder: (context, BoxConstraints box) { - return NetworkImgLayer( - src: item!.cover, - width: box.maxWidth, - height: box.maxHeight, + return Hero( + tag: heroTag, + child: NetworkImgLayer( + src: item!.cover, + width: box.maxWidth, + height: box.maxHeight, + ), ); }, ), From ee973167a556de0d0b61e9a8f7c2a46c16b3219e Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 24 Jul 2023 00:32:54 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=E6=9A=82=E5=81=9C/=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E3=80=81=E6=B8=85?= =?UTF-8?q?=E7=A9=BA=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 9 ++++ lib/http/user.dart | 32 +++++++++++++ lib/pages/history/controller.dart | 75 +++++++++++++++++++++++++++++++ lib/pages/history/view.dart | 61 +++++++++++++++++++++---- 4 files changed, 169 insertions(+), 8 deletions(-) diff --git a/lib/http/api.dart b/lib/http/api.dart index e4356840..06c9fd9b 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -148,6 +148,15 @@ class Api { // 获取历史记录 static const String historyList = '/x/web-interface/history/cursor'; + // 暂停历史记录 + static const String pauseHistory = '/x/v2/history/shadow/set'; + + // 查询历史记录暂停状态 + static const String historyStatus = '/x/v2/history/shadow?jsonp=jsonp'; + + // 清空历史记录 + static const String clearHistory = '/x/v2/history/clear'; + // 热搜 static const String hotSearchList = 'https://s.search.bilibili.com/main/hotword'; diff --git a/lib/http/user.dart b/lib/http/user.dart index b38050e0..d4b126e5 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -112,4 +112,36 @@ class UserHttp { return {'status': false, 'data': [], 'msg': res.data['message']}; } } + + // 暂停观看历史 + static Future pauseHistory(bool switchStatus) async { + // 暂停switchStatus传true 否则false + var res = await Request().post( + Api.pauseHistory, + queryParameters: { + 'switch': switchStatus, + 'jsonp': 'jsonp', + 'csrf': await Request.getCsrf(), + }, + ); + return res; + } + + // 观看历史暂停状态 + static Future historyStatus() async { + var res = await Request().get(Api.historyStatus); + return res; + } + + // 清空历史记录 + static Future clearHistory() async { + var res = await Request().post( + Api.clearHistory, + queryParameters: { + 'jsonp': 'jsonp', + 'csrf': await Request.getCsrf(), + }, + ); + return res; + } } diff --git a/lib/pages/history/controller.dart b/lib/pages/history/controller.dart index d3d340d2..0b248a08 100644 --- a/lib/pages/history/controller.dart +++ b/lib/pages/history/controller.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/user.dart'; import 'package:pilipala/models/user/history.dart'; @@ -7,10 +8,12 @@ class HistoryController extends GetxController { final ScrollController scrollController = ScrollController(); RxList historyList = [HisListItem()].obs; bool isLoadingMore = false; + RxBool pauseStatus = false.obs; @override void onInit() { super.onInit(); + historyStatus(); } Future queryHistoryList({type = 'init'}) async { @@ -40,4 +43,76 @@ class HistoryController extends GetxController { Future onRefresh() async { queryHistoryList(type: 'onRefresh'); } + + // 暂停观看历史 + Future onPauseHistory() async { + SmartDialog.show( + useSystem: true, + animationType: SmartAnimationType.centerFade_otherSlide, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('提示'), + content: + Text(!pauseStatus.value ? '啊叻?你要暂停历史记录功能吗?' : '啊叻?要恢复历史记录功能吗?'), + actions: [ + TextButton( + onPressed: () => SmartDialog.dismiss(), + child: const Text('取消')), + TextButton( + onPressed: () async { + SmartDialog.showLoading(msg: '请求中'); + var res = await UserHttp.pauseHistory(!pauseStatus.value); + SmartDialog.dismiss(); + if (res.data['code'] == 0) { + SmartDialog.showToast( + !pauseStatus.value ? '暂停观看历史' : '恢复观看历史'); + pauseStatus.value = !pauseStatus.value; + } + SmartDialog.dismiss(); + }, + child: Text(!pauseStatus.value ? '确认暂停' : '确认恢复'), + ) + ], + ); + }, + ); + } + +// 观看历史暂停状态 + Future historyStatus() async { + var res = await UserHttp.historyStatus(); + pauseStatus.value = res.data['data']; + } + + // 清空观看历史 + Future onClearHistory() async { + SmartDialog.show( + useSystem: true, + animationType: SmartAnimationType.centerFade_otherSlide, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('提示'), + content: const Text('啊叻?你要清空历史记录功能吗?'), + actions: [ + TextButton( + onPressed: () => SmartDialog.dismiss(), + child: const Text('取消')), + TextButton( + onPressed: () async { + SmartDialog.showLoading(msg: '请求中'); + var res = await UserHttp.clearHistory(); + SmartDialog.dismiss(); + if (res.data['code'] == 0) { + SmartDialog.showToast('清空观看历史'); + } + SmartDialog.dismiss(); + historyList.clear(); + }, + child: const Text('确认清空'), + ) + ], + ); + }, + ); + } } diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart index f0142a3e..3de41366 100644 --- a/lib/pages/history/view.dart +++ b/lib/pages/history/view.dart @@ -39,8 +39,43 @@ class _HistoryPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text('观看记录'), + titleSpacing: 0, centerTitle: false, + title: Text( + '观看记录', + style: Theme.of(context).textTheme.titleMedium, + ), + actions: [ + PopupMenuButton( + onSelected: (String type) { + // 处理菜单项选择的逻辑 + switch (type) { + case 'pause': + _historyController.onPauseHistory(); + break; + case 'clear': + _historyController.onClearHistory(); + break; + default: + } + }, + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + value: 'pause', + child: Obx( + () => Text(!_historyController.pauseStatus.value + ? '暂停观看记录' + : '恢复观看记录'), + ), + ), + const PopupMenuItem( + value: 'clear', + child: Text('清空观看记录'), + ), + ], + ), + const SizedBox(width: 6), + ], ), body: RefreshIndicator( onRefresh: () async { @@ -57,13 +92,23 @@ class _HistoryPageState extends State { Map data = snapshot.data; if (data['status']) { return Obx( - () => SliverList( - delegate: SliverChildBuilderDelegate((context, index) { - return HistoryItem( - videoItem: _historyController.historyList[index], - ); - }, childCount: _historyController.historyList.length), - ), + () => _historyController.historyList.isEmpty + ? const SliverToBoxAdapter( + child: Center( + child: Text('没数据'), + ), + ) + : SliverList( + delegate: SliverChildBuilderDelegate( + (context, index) { + return HistoryItem( + videoItem: + _historyController.historyList[index], + ); + }, + childCount: + _historyController.historyList.length), + ), ); } else { return HttpError( From 4e64c74ee01f3da52c0e22f2bfe6626f78570531 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 24 Jul 2023 15:12:00 +0800 Subject: [PATCH 3/4] =?UTF-8?q?mod:=20=E6=9C=AC=E5=9C=B0=E7=BC=93=E5=AD=98?= =?UTF-8?q?=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 2 ++ lib/pages/history/controller.dart | 6 +++++- lib/pages/video/detail/controller.dart | 4 ++++ lib/utils/data.dart | 16 ++++++++++++++++ lib/utils/storage.dart | 5 +++++ 5 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 lib/utils/data.dart diff --git a/lib/main.dart b/lib/main.dart index e6ab6110..9b12d72d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -9,6 +9,7 @@ import 'package:pilipala/pages/search/index.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/router/app_pages.dart'; import 'package:pilipala/pages/main/view.dart'; +import 'package:pilipala/utils/data.dart'; import 'package:pilipala/utils/storage.dart'; void main() async { @@ -16,6 +17,7 @@ void main() async { MediaKit.ensureInitialized(); await GStrorage.init(); await Request.setCookie(); + await Data.init(); runApp(const MyApp()); } diff --git a/lib/pages/history/controller.dart b/lib/pages/history/controller.dart index 0b248a08..2d47726b 100644 --- a/lib/pages/history/controller.dart +++ b/lib/pages/history/controller.dart @@ -1,14 +1,17 @@ import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:hive/hive.dart'; import 'package:pilipala/http/user.dart'; import 'package:pilipala/models/user/history.dart'; +import 'package:pilipala/utils/storage.dart'; class HistoryController extends GetxController { final ScrollController scrollController = ScrollController(); RxList historyList = [HisListItem()].obs; bool isLoadingMore = false; RxBool pauseStatus = false.obs; + Box localCache = GStrorage.localCache; @override void onInit() { @@ -78,10 +81,11 @@ class HistoryController extends GetxController { ); } -// 观看历史暂停状态 + // 观看历史暂停状态 Future historyStatus() async { var res = await UserHttp.historyStatus(); pauseStatus.value = res.data['data']; + localCache.put(LocalCacheKey.historyStatus, res.data['data']); } // 清空观看历史 diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 8158a984..4c4c3085 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -54,6 +54,7 @@ class VideoDetailController extends GetxController RxString bgCover = ''.obs; Box user = GStrorage.user; + Box localCache = GStrorage.localCache; @override void onInit() { @@ -149,6 +150,9 @@ class VideoDetailController extends GetxController if (user.get(UserBoxKey.userMid) == null) { return; } + if (localCache.get(LocalCacheKey.historyStatus) == true) { + return; + } Duration progress = meeduPlayerController.position.value; await VideoHttp.heartBeat( bvid: bvid, diff --git a/lib/utils/data.dart b/lib/utils/data.dart new file mode 100644 index 00000000..e6ab2ae3 --- /dev/null +++ b/lib/utils/data.dart @@ -0,0 +1,16 @@ +import 'package:hive/hive.dart'; +import 'package:pilipala/http/user.dart'; + +import 'storage.dart'; + +class Data { + static Future init() async { + await historyStatus(); + } + + static Future historyStatus() async { + Box localCache = GStrorage.localCache; + var res = await UserHttp.historyStatus(); + localCache.put(LocalCacheKey.historyStatus, res.data['data']); + } +} diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index df3c92b8..899ba485 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -59,3 +59,8 @@ class UserBoxKey { class SettingBoxKey { static const String themeMode = 'themeMode'; } + +class LocalCacheKey { + // 历史记录暂停状态 默认false + static const String historyStatus = 'historyStatus'; +} From 7a3f6cf5ee28c0825487fa2026201c4617064775 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Mon, 24 Jul 2023 16:11:17 +0800 Subject: [PATCH 4/4] =?UTF-8?q?mod:=20=E8=A7=86=E9=A2=91=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E9=A1=B5=E4=BB=A3=E7=A0=81=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/reply.dart | 3 +- lib/pages/video/detail/reply/controller.dart | 54 ++++++------------ lib/pages/video/detail/reply/view.dart | 56 +++++-------------- .../video/detail/replyReply/controller.dart | 5 -- lib/pages/video/detail/replyReply/view.dart | 15 +++-- 5 files changed, 42 insertions(+), 91 deletions(-) diff --git a/lib/http/reply.dart b/lib/http/reply.dart index fa196823..e69e6599 100644 --- a/lib/http/reply.dart +++ b/lib/http/reply.dart @@ -1,5 +1,6 @@ import 'package:pilipala/http/api.dart'; import 'package:pilipala/http/init.dart'; +import 'package:pilipala/models/video/reply/data.dart'; class ReplyHttp { static Future replyList({ @@ -17,7 +18,7 @@ class ReplyHttp { if (res.data['code'] == 0) { return { 'status': true, - 'data': res.data['data'], + 'data': ReplyData.fromJson(res.data['data']), }; } else { Map errMap = { diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index d10408a6..76fb8be6 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -1,26 +1,21 @@ -import 'dart:developer'; - import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/reply.dart'; -import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/common/reply_sort_type.dart'; import 'package:pilipala/models/common/reply_type.dart'; -import 'package:pilipala/models/video/reply/data.dart'; import 'package:pilipala/models/video/reply/item.dart'; class VideoReplyController extends GetxController { VideoReplyController( this.aid, this.rpid, - this.level, + this.replyLevel, ); final ScrollController scrollController = ScrollController(); // 视频aid 请求时使用的oid int? aid; // 层级 2为楼中楼 - String? level; + String? replyLevel; // rpid 请求楼中楼回复 String? rpid; RxList replyList = [ReplyItemModel()].obs; @@ -30,12 +25,6 @@ class VideoReplyController extends GetxController { RxString noMore = ''.obs; // 当前回复的回复 ReplyItemModel? currentReplyItem; - // 回复来源 - String replySource = 'main'; - // 根评论 id 回复楼中楼回复使用 - int? rPid; - // 默认回复主楼 - String replyLevel = '0'; ReplySortType sortType = ReplySortType.time; RxString sortTypeTitle = ReplySortType.time.titles.obs; @@ -43,51 +32,44 @@ class VideoReplyController extends GetxController { Future queryReplyList({type = 'init'}) async { isLoadingMore = true; - var res = level == '1' + var res = replyLevel == '1' ? await ReplyHttp.replyList( oid: aid!, - pageNum: currentPage + 1, + pageNum: ++currentPage, type: ReplyType.video.index, sort: sortType.index, ) : await ReplyHttp.replyReplyList( - oid: aid!, root: rpid!, pageNum: currentPage + 1, type: 1); + oid: aid!, + root: rpid!, + pageNum: ++currentPage, + type: ReplyType.video.index, + ); if (res['status']) { - res['data'] = ReplyData.fromJson(res['data']); - if (res['data'].replies.isNotEmpty) { - currentPage = currentPage + 1; + List replies = res['data'].replies; + if (replies.isNotEmpty) { noMore.value = '加载中'; if (replyList.length == res['data'].page.acount) { noMore.value = '没有更多了'; } } else { - if (currentPage == 0) { - noMore.value = '还没有评论'; - } else { - noMore.value = '没有更多了'; - return; - } + // 未登录状态replies可能返回null + noMore.value = currentPage == 0 ? '还没有评论' : '没有更多了'; } if (type == 'init') { - List replies = res['data'].replies; // 添加置顶回复 if (res['data'].upper.top != null) { - bool flag = false; - for (var i = 0; i < res['data'].topReplies.length; i++) { - if (res['data'].topReplies[i].rpid == res['data'].upper.top.rpid) { - flag = true; - } - } + bool flag = res['data'] + .topReplies + .any((reply) => reply.rpid == res['data'].upper.top.rpid); if (!flag) { replies.insert(0, res['data'].upper.top); } } replies.insertAll(0, res['data'].topReplies); - res['data'].replies = replies; - replyList.value = res['data'].replies!; + replyList.value = replies; } else { - replyList.addAll(res['data'].replies!); - res['data'].replies.addAll(replyList); + replyList.addAll(replies); } } isLoadingMore = false; diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 22846166..b50e6589 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -6,7 +6,6 @@ import 'package:get/get.dart'; import 'package:pilipala/common/skeleton/video_reply.dart'; import 'package:pilipala/common/widgets/http_error.dart'; import 'package:pilipala/models/common/reply_type.dart'; -import 'package:pilipala/models/video/reply/item.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/pages/video/detail/replyNew/index.dart'; import 'package:pilipala/utils/id_utils.dart'; @@ -14,14 +13,14 @@ import 'controller.dart'; import 'widgets/reply_item.dart'; class VideoReplyPanel extends StatefulWidget { - String? bvid; - int rpid; - String? level; - Key? key; - VideoReplyPanel({ + final String? bvid; + final int rpid; + final String? replyLevel; + + const VideoReplyPanel({ this.bvid, this.rpid = 0, - this.level, + this.replyLevel, super.key, }); @@ -46,18 +45,13 @@ class _VideoReplyPanelState extends State void initState() { int oid = widget.bvid != null ? IdUtils.bv2av(widget.bvid!) : 0; super.initState(); - replyLevel = widget.level ?? '1'; - if (widget.level != null && widget.level == '2') { + replyLevel = widget.replyLevel ?? '1'; + if (replyLevel == '2') { _videoReplyController = Get.put( - VideoReplyController(oid, widget.rpid.toString(), '2'), + VideoReplyController(oid, widget.rpid.toString(), replyLevel), tag: widget.rpid.toString()); - _videoReplyController.rPid = widget.rpid; } else { - // fix 评论加载不对称 - // int oid = Get.parameters['bvid'] != null - // ? IdUtils.bv2av(Get.parameters['bvid']!) - // : 0; - _videoReplyController = Get.put(VideoReplyController(oid, '', '1'), + _videoReplyController = Get.put(VideoReplyController(oid, '', replyLevel), tag: Get.arguments['heroTag']); } @@ -101,20 +95,6 @@ class _VideoReplyPanelState extends State } } - void _showReply(source, {ReplyItemModel? replyItem, replyLevel}) async { - // source main 直接回复 floor 楼中楼回复 - if (source == 'floor') { - _videoReplyController.currentReplyItem = replyItem; - _videoReplyController.replySource = source; - _videoReplyController.replyLevel = replyLevel ?? '1'; - } else { - _videoReplyController.replyLevel = '0'; - } - - // await Future.delayed(const Duration(microseconds: 100)); - // _videoReplyController.wakeUpReply(); - } - // 展示二级回复 void replyReply(replyItem) { VideoDetailController videoDetailCtr = @@ -136,7 +116,6 @@ class _VideoReplyPanelState extends State Widget build(BuildContext context) { return RefreshIndicator( onRefresh: () async { - setState(() {}); _videoReplyController.currentPage = 0; return await _videoReplyController.queryReplyList(); }, @@ -204,18 +183,15 @@ class _VideoReplyPanelState extends State : SliverList( delegate: SliverChildBuilderDelegate( (context, index) { + double bottom = + MediaQuery.of(context).padding.bottom; if (index == _videoReplyController .replyList.length) { return Container( - padding: EdgeInsets.only( - bottom: MediaQuery.of(context) - .padding - .bottom), - height: MediaQuery.of(context) - .padding - .bottom + - 100, + padding: + EdgeInsets.only(bottom: bottom), + height: bottom + 100, child: Center( child: Obx(() => Text( _videoReplyController @@ -265,8 +241,6 @@ class _VideoReplyPanelState extends State child: SlideTransition( position: Tween( begin: const Offset(0, 2), - // 评论内容为空/不足一屏 - // begin: const Offset(0, 0), end: const Offset(0, 0), ).animate(CurvedAnimation( parent: fabAnimationCtr, diff --git a/lib/pages/video/detail/replyReply/controller.dart b/lib/pages/video/detail/replyReply/controller.dart index 9f7c7a94..15c95c76 100644 --- a/lib/pages/video/detail/replyReply/controller.dart +++ b/lib/pages/video/detail/replyReply/controller.dart @@ -21,11 +21,6 @@ class VideoReplyReplyController extends GetxController { // 当前回复的回复 ReplyItemModel? currentReplyItem; - // 根评论 id 回复楼中楼回复使用 - int? rPid; - // 默认回复主楼 - String replyLevel = '0'; - @override void onInit() { super.onInit(); diff --git a/lib/pages/video/detail/replyReply/view.dart b/lib/pages/video/detail/replyReply/view.dart index 07dea00d..b0ce293c 100644 --- a/lib/pages/video/detail/replyReply/view.dart +++ b/lib/pages/video/detail/replyReply/view.dart @@ -11,14 +11,14 @@ import 'package:pilipala/utils/storage.dart'; import 'controller.dart'; class VideoReplyReplyPanel extends StatefulWidget { - int? oid; - int? rpid; - Function? closePanel; - ReplyItemModel? firstFloor; - String? source; - ReplyType? replyType; + final int? oid; + final int? rpid; + final Function? closePanel; + final ReplyItemModel? firstFloor; + final String? source; + final ReplyType? replyType; - VideoReplyReplyPanel({ + const VideoReplyReplyPanel({ this.oid, this.rpid, this.closePanel, @@ -91,7 +91,6 @@ class _VideoReplyReplyPanelState extends State { icon: const Icon(Icons.close), onPressed: () { _videoReplyReplyController.currentPage = 0; - _videoReplyReplyController.rPid = 0; widget.closePanel!(); Navigator.pop(context); },