From 11dde3a88706d706b10079b15a884e9c77a6a365 Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Wed, 25 Dec 2024 18:10:57 +0800 Subject: [PATCH] opt: play all Signed-off-by: bggRGjQaUbCoE --- lib/common/widgets/watch_later_list.dart | 50 ++++++----------- lib/models/video/later.dart | 1 - lib/pages/video/detail/controller.dart | 56 +++++++++++-------- .../video/detail/introduction/controller.dart | 5 ++ 4 files changed, 55 insertions(+), 57 deletions(-) diff --git a/lib/common/widgets/watch_later_list.dart b/lib/common/widgets/watch_later_list.dart index e343fef7..8fefae4e 100644 --- a/lib/common/widgets/watch_later_list.dart +++ b/lib/common/widgets/watch_later_list.dart @@ -1,68 +1,50 @@ import 'package:PiliPalaX/common/widgets/stat/danmu.dart'; import 'package:PiliPalaX/common/widgets/stat/view.dart'; -import 'package:PiliPalaX/utils/extension.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:PiliPalaX/common/constants.dart'; import 'package:PiliPalaX/common/widgets/badge.dart'; import 'package:PiliPalaX/common/widgets/network_img_layer.dart'; import 'package:PiliPalaX/http/search.dart'; -import 'package:PiliPalaX/http/user.dart'; import 'package:PiliPalaX/models/video/later.dart'; import 'package:PiliPalaX/utils/utils.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; class MediaListPanel extends StatefulWidget { const MediaListPanel({ - this.sheetHeight, required this.mediaList, this.changeMediaList, this.panelTitle, this.bvid, - this.mediaId, this.hasMore = false, + required this.loadMoreMedia, super.key, }); - final double? sheetHeight; final List mediaList; final Function? changeMediaList; final String? panelTitle; final String? bvid; - final int? mediaId; final bool hasMore; + final VoidCallback loadMoreMedia; @override State createState() => _MediaListPanelState(); } class _MediaListPanelState extends State { - RxList mediaList = [].obs; - bool _isEnd = false; + final _scrollController = ItemScrollController(); @override void initState() { super.initState(); - mediaList.value = widget.mediaList; - _isEnd = widget.hasMore.not; - } - - void loadMore() async { - var res = await UserHttp.getMediaList( - type: 3, - bizId: widget.mediaId ?? -1, - ps: 20, - oid: mediaList.last.id, - ); - if (res['status']) { - if (res['data'].isNotEmpty) { - mediaList.addAll(res['data']); - } else { - _isEnd = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + int index = + widget.mediaList.indexWhere((item) => item.bvid == widget.bvid); + if (index != -1 && index != 0) { + _scrollController.jumpTo(index: index); } - } else { - SmartDialog.showToast(res['msg']); - } + }); } @override @@ -90,12 +72,14 @@ class _MediaListPanelState extends State { child: Material( color: Theme.of(context).colorScheme.surface, child: Obx( - () => ListView.builder( - itemCount: mediaList.length, + () => ScrollablePositionedList.builder( + itemScrollController: _scrollController, + itemCount: widget.mediaList.length, itemBuilder: ((context, index) { - var item = mediaList[index]; - if (index == widget.mediaList.length - 1 && _isEnd.not) { - loadMore(); + var item = widget.mediaList[index]; + if (index == widget.mediaList.length - 1 && + widget.hasMore) { + widget.loadMoreMedia(); } return InkWell( onTap: () async { diff --git a/lib/models/video/later.dart b/lib/models/video/later.dart index 83ccd54e..dd4f3154 100644 --- a/lib/models/video/later.dart +++ b/lib/models/video/later.dart @@ -55,7 +55,6 @@ class MediaVideoItemModel { int? type; Upper? upper; String? link; - String? bvId; String? shortLink; Rights? rights; dynamic elecInfo; diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index a4e8bcf9..7bb0b39e 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -24,7 +24,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; -import 'package:hive/hive.dart'; import 'package:PiliPalaX/http/constants.dart'; import 'package:PiliPalaX/http/video.dart'; import 'package:PiliPalaX/models/common/search_type.dart'; @@ -183,11 +182,6 @@ class VideoDetailController extends GetxController RxBool enableHA = true.obs; RxString hwdec = 'auto-safe'.obs; - /// 本地存储 - Box userInfoCache = GStorage.userInfo; - Box localCache = GStorage.localCache; - Box setting = GStorage.setting; - RxInt oid = 0.obs; final scaffoldKey = GlobalKey(); @@ -247,36 +241,35 @@ class VideoDetailController extends GetxController // 页面来源 稍后再看 收藏夹 RxString sourceType = 'normal'.obs; - List mediaList = []; - RxString watchLaterTitle = ''.obs; + late RxList mediaList = [].obs; + late RxString watchLaterTitle = ''.obs; bool get isPlayAll => sourceType.value == 'watchLater' || sourceType.value == 'fav'; @override void onInit() { super.onInit(); - final Map argMap = Get.arguments; - userInfo = userInfoCache.get('userInfoCache'); - var keys = argMap.keys.toList(); + userInfo = GStorage.userInfo.get('userInfoCache'); + var keys = Get.arguments.keys.toList(); if (keys.isNotEmpty) { if (keys.contains('videoItem')) { - var args = argMap['videoItem']; + var args = Get.arguments['videoItem']; if (args.pic != null && args.pic != '') { videoItem['pic'] = args.pic; } } if (keys.contains('pic')) { - videoItem['pic'] = argMap['pic']; + videoItem['pic'] = Get.arguments['pic']; } } - sourceType.value = argMap['sourceType'] ?? 'normal'; + sourceType.value = Get.arguments['sourceType'] ?? 'normal'; if (sourceType.value == 'watchLater') { watchLaterTitle.value = '稍后再看'; fetchMediaList(); } else if (sourceType.value == 'fav') { - watchLaterTitle.value = argMap['favTitle']; + watchLaterTitle.value = Get.arguments['favTitle']; queryFavVideoList(); } @@ -332,8 +325,7 @@ class VideoDetailController extends GetxController // 获取稍后再看列表 Future fetchMediaList() async { - final Map argMap = Get.arguments; - var count = argMap['count']; + var count = Get.arguments['count']; var res = await UserHttp.getMediaList( type: 2, bizId: userInfo.mid, @@ -346,6 +338,25 @@ class VideoDetailController extends GetxController } } + void loadMoreMedia() async { + if (mediaList.length >= Get.arguments['count']) { + return; + } + var res = await UserHttp.getMediaList( + type: 3, + bizId: Get.arguments['mediaId'] ?? -1, + ps: 20, + oid: mediaList.last.id, + ); + if (res['status']) { + if (res['data'].isNotEmpty) { + mediaList.addAll(res['data']); + } + } else { + SmartDialog.showToast(res['msg']); + } + } + // 稍后再看面板展开 showMediaListPanel() { if (mediaList.isNotEmpty) { @@ -355,8 +366,8 @@ class VideoDetailController extends GetxController changeMediaList: changeMediaList, panelTitle: watchLaterTitle.value, bvid: bvid, - mediaId: Get.arguments['mediaId'], - hasMore: mediaList.length != Get.arguments['count'], + hasMore: mediaList.length < Get.arguments['count'], + loadMoreMedia: loadMoreMedia, ), ); } @@ -393,16 +404,15 @@ class VideoDetailController extends GetxController // 获取收藏夹视频列表 Future queryFavVideoList() async { - final Map argMap = Get.arguments; - var mediaId = argMap['mediaId']; - var oid = argMap['oid']; + var mediaId = Get.arguments['mediaId']; + var oid = Get.arguments['oid']; var res = await UserHttp.parseFavVideo( mediaId: mediaId, oid: oid, bvid: bvid, ); if (res['status']) { - mediaList = res['data']; + mediaList.value = res['data']; } } diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 86b60946..21ca203c 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -691,6 +691,11 @@ class VideoIntroController extends GetxController episodes.indexWhere((e) => e.cid == lastPlayCid.value); int nextIndex = currentIndex + 1; + if (videoDetailController.isPlayAll && + currentIndex == episodes.length - 2) { + videoDetailCtr.loadMoreMedia(); + } + // 列表循环 if (nextIndex >= episodes.length) { if (platRepeat == PlayRepeat.listCycle) {