feat: part: reverse play #70

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-12-31 12:25:45 +08:00
parent 1215d126cc
commit de3edcfa13
7 changed files with 144 additions and 99 deletions

View File

@@ -27,6 +27,7 @@ class ListSheetContent extends StatefulWidget {
this.onClose, this.onClose,
this.onReverse, this.onReverse,
this.showTitle, this.showTitle,
this.isSupportReverse,
}); });
final dynamic index; final dynamic index;
@@ -39,6 +40,7 @@ class ListSheetContent extends StatefulWidget {
final VoidCallback? onClose; final VoidCallback? onClose;
final VoidCallback? onReverse; final VoidCallback? onReverse;
final bool? showTitle; final bool? showTitle;
final bool? isSupportReverse;
@override @override
State<ListSheetContent> createState() => _ListSheetContentState(); State<ListSheetContent> createState() => _ListSheetContentState();
@@ -361,7 +363,7 @@ class _ListSheetContentState extends State<ListSheetContent>
} catch (_) {} } catch (_) {}
}, },
), ),
if (widget.season != null) if (widget.isSupportReverse == true)
if (!_isList) if (!_isList)
_reverseButton _reverseButton
else else

View File

@@ -402,7 +402,7 @@ class _ExtraSettingState extends State<ExtraSetting> {
defaultVal: true, defaultVal: true,
), ),
SetSwitchItem( SetSwitchItem(
title: '倒序播放从首集开始播放', title: '分P/合集:倒序播放从首集开始播放',
subTitle: '开启则自动切换为倒序首集,否则保持当前集', subTitle: '开启则自动切换为倒序首集,否则保持当前集',
leading: const Icon(Icons.u_turn_right), leading: const Icon(Icons.u_turn_right),
setKey: SettingBoxKey.reverseFromFirst, setKey: SettingBoxKey.reverseFromFirst,

View File

@@ -131,8 +131,13 @@ class VideoIntroController extends GetxController
var result = await VideoHttp.videoIntro(bvid: bvid); var result = await VideoHttp.videoIntro(bvid: bvid);
if (result['status']) { if (result['status']) {
if (videoDetail.value.ugcSeason?.id == result['data']?.ugcSeason?.id) { if (videoDetail.value.ugcSeason?.id == result['data']?.ugcSeason?.id) {
// keep reversed season
result['data']?.ugcSeason = videoDetail.value.ugcSeason; result['data']?.ugcSeason = videoDetail.value.ugcSeason;
} }
if (videoDetail.value.cid == result['data']?.cid) {
// keep reversed pages
result['data']?.pages = videoDetail.value.pages;
}
videoDetail.value = result['data']; videoDetail.value = result['data'];
videoItem!['staff'] = result['data'].staff; videoItem!['staff'] = result['data'].staff;
try { try {

View File

@@ -71,7 +71,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
() => videoIntroController.videoDetail.value.title == null () => videoIntroController.videoDetail.value.title == null
? VideoInfo( ? VideoInfo(
loadingStatus: true, loadingStatus: true,
videoDetail: videoIntroController.videoDetail.value, videoIntroController: videoIntroController,
heroTag: widget.heroTag, heroTag: widget.heroTag,
showAiBottomSheet: widget.showAiBottomSheet, showAiBottomSheet: widget.showAiBottomSheet,
showIntroDetail: () => widget.showIntroDetail( showIntroDetail: () => widget.showIntroDetail(
@@ -83,7 +83,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
) )
: VideoInfo( : VideoInfo(
loadingStatus: false, loadingStatus: false,
videoDetail: videoIntroController.videoDetail.value, videoIntroController: videoIntroController,
heroTag: widget.heroTag, heroTag: widget.heroTag,
showAiBottomSheet: widget.showAiBottomSheet, showAiBottomSheet: widget.showAiBottomSheet,
showIntroDetail: () => widget.showIntroDetail( showIntroDetail: () => widget.showIntroDetail(
@@ -99,17 +99,17 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
class VideoInfo extends StatefulWidget { class VideoInfo extends StatefulWidget {
final bool loadingStatus; final bool loadingStatus;
final VideoDetailData? videoDetail;
final String heroTag; final String heroTag;
final Function showAiBottomSheet; final Function showAiBottomSheet;
final Function showIntroDetail; final Function showIntroDetail;
final Function showEpisodes; final Function showEpisodes;
final ValueChanged onShowMemberPage; final ValueChanged onShowMemberPage;
final VideoIntroController videoIntroController;
const VideoInfo({ const VideoInfo({
super.key, super.key,
this.loadingStatus = false, this.loadingStatus = false,
this.videoDetail, required this.videoIntroController,
required this.heroTag, required this.heroTag,
required this.showAiBottomSheet, required this.showAiBottomSheet,
required this.showIntroDetail, required this.showIntroDetail,
@@ -122,10 +122,13 @@ class VideoInfo extends StatefulWidget {
} }
class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin { class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
late final VideoIntroController videoIntroController;
late final VideoDetailController videoDetailCtr; late final VideoDetailController videoDetailCtr;
late final Map<dynamic, dynamic> videoItem; late final Map<dynamic, dynamic> videoItem;
VideoIntroController get videoIntroController => widget.videoIntroController;
VideoDetailData get videoDetail =>
widget.videoIntroController.videoDetail.value;
late final _coinKey = GlobalKey<ActionItemState>(); late final _coinKey = GlobalKey<ActionItemState>();
late final _favKey = GlobalKey<ActionItemState>(); late final _favKey = GlobalKey<ActionItemState>();
@@ -145,7 +148,6 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
videoIntroController = Get.put(VideoIntroController(), tag: widget.heroTag);
videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag); videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag);
videoItem = videoIntroController.videoItem!; videoItem = videoIntroController.videoItem!;
@@ -232,7 +234,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
onPushMember() { onPushMember() {
feedBack(); feedBack();
int? mid = !widget.loadingStatus int? mid = !widget.loadingStatus
? widget.videoDetail?.owner?.mid ? videoDetail.owner?.mid
: videoItem['owner']?.mid; : videoItem['owner']?.mid;
if (mid != null) { if (mid != null) {
if (context.orientation == Orientation.landscape && if (context.orientation == Orientation.landscape &&
@@ -241,7 +243,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
} else { } else {
// memberHeroTag = Utils.makeHeroTag(mid); // memberHeroTag = Utils.makeHeroTag(mid);
// String face = !loadingStatus // String face = !loadingStatus
// ? widget.videoDetail!.owner!.face // ? videoDetail.owner!.face
// : videoItem['owner'].face; // : videoItem['owner'].face;
Get.toNamed( Get.toNamed(
'/member?mid=$mid', '/member?mid=$mid',
@@ -287,7 +289,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
type: 'avatar', type: 'avatar',
src: widget.loadingStatus src: widget.loadingStatus
? videoItem['owner']?.face ?? "" ? videoItem['owner']?.face ?? ""
: widget.videoDetail!.owner!.face, : videoDetail.owner!.face,
width: 30, width: 30,
height: 30, height: 30,
fadeInDuration: Duration.zero, fadeInDuration: Duration.zero,
@@ -302,7 +304,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
Text( Text(
widget.loadingStatus widget.loadingStatus
? videoItem['owner']?.name ?? "" ? videoItem['owner']?.name ?? ""
: widget.videoDetail!.owner!.name, : videoDetail.owner!.name,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
@@ -335,7 +337,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
childBuilder: (index) => GestureDetector( childBuilder: (index) => GestureDetector(
onTap: () { onTap: () {
int? ownerMid = !widget.loadingStatus int? ownerMid = !widget.loadingStatus
? widget.videoDetail?.owner?.mid ? videoDetail.owner?.mid
: videoItem['owner']?.mid; : videoItem['owner']?.mid;
if (videoItem['staff'][index].mid == ownerMid && if (videoItem['staff'][index].mid == ownerMid &&
context.orientation == context.orientation ==
@@ -454,10 +456,10 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
Utils.copyText( Utils.copyText(
'${widget.videoDetail?.title ?? videoItem['title'] ?? ''}'); '${videoDetail.title ?? videoItem['title'] ?? ''}');
}, },
child: Text( child: Text(
'${widget.videoDetail?.title ?? videoItem['title'] ?? ''}', '${videoDetail.title ?? videoItem['title'] ?? ''}',
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 16), style: const TextStyle(fontSize: 16),
@@ -467,10 +469,10 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
onLongPress: () { onLongPress: () {
feedBack(); feedBack();
Utils.copyText( Utils.copyText(
'${widget.videoDetail?.title ?? videoItem['title'] ?? ''}'); '${videoDetail.title ?? videoItem['title'] ?? ''}');
}, },
child: Text( child: Text(
widget.videoDetail?.title ?? videoItem['title'] ?? '', videoDetail.title ?? videoItem['title'] ?? '',
style: const TextStyle(fontSize: 16), style: const TextStyle(fontSize: 16),
), ),
), ),
@@ -495,7 +497,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
context: context, context: context,
theme: 'gray', theme: 'gray',
view: !widget.loadingStatus view: !widget.loadingStatus
? widget.videoDetail?.stat?.view ?? '-' ? videoDetail.stat?.view ?? '-'
: videoItem['stat']?.view ?? '-', : videoItem['stat']?.view ?? '-',
size: 'medium', size: 'medium',
), ),
@@ -504,7 +506,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
context: context, context: context,
theme: 'gray', theme: 'gray',
danmu: !widget.loadingStatus danmu: !widget.loadingStatus
? widget.videoDetail?.stat?.danmu ?? '-' ? videoDetail.stat?.danmu ?? '-'
: videoItem['stat']?.danmu ?? '-', : videoItem['stat']?.danmu ?? '-',
size: 'medium', size: 'medium',
), ),
@@ -512,7 +514,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
Text( Text(
Utils.dateFormat( Utils.dateFormat(
!widget.loadingStatus !widget.loadingStatus
? widget.videoDetail?.pubdate ? videoDetail.pubdate
: videoItem['pubdate'], : videoItem['pubdate'],
formatType: 'detail'), formatType: 'detail'),
style: TextStyle( style: TextStyle(
@@ -670,34 +672,34 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
if (!isHorizontal) actionGrid(context, videoIntroController), if (!isHorizontal) actionGrid(context, videoIntroController),
// 合集 // 合集
if (!widget.loadingStatus && if (!widget.loadingStatus &&
widget.videoDetail?.ugcSeason != null && videoDetail.ugcSeason != null &&
(context.orientation != Orientation.landscape || (context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape && (context.orientation == Orientation.landscape &&
videoDetailCtr.horizontalSeasonPanel.not))) videoDetailCtr.horizontalSeasonPanel.not)))
Obx( Obx(
() => SeasonPanel( () => SeasonPanel(
heroTag: widget.heroTag, heroTag: widget.heroTag,
ugcSeason: widget.videoDetail!.ugcSeason!, ugcSeason: videoDetail.ugcSeason!,
cid: videoIntroController.lastPlayCid.value != 0 cid: videoIntroController.lastPlayCid.value != 0
? (widget.videoDetail!.pages?.isNotEmpty == true ? (videoDetail.pages?.isNotEmpty == true
? widget.videoDetail!.pages!.first.cid ? videoDetail.pages!.first.cid
: videoIntroController.lastPlayCid.value) : videoIntroController.lastPlayCid.value)
: widget.videoDetail!.pages!.first.cid, : videoDetail.pages!.first.cid,
changeFuc: videoIntroController.changeSeasonOrbangu, changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes, showEpisodes: widget.showEpisodes,
pages: widget.videoDetail!.pages, pages: videoDetail.pages,
), ),
), ),
if (!widget.loadingStatus && if (!widget.loadingStatus &&
widget.videoDetail?.pages != null && videoDetail.pages != null &&
widget.videoDetail!.pages!.length > 1 && videoDetail.pages!.length > 1 &&
(context.orientation != Orientation.landscape || (context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape && (context.orientation == Orientation.landscape &&
videoDetailCtr.horizontalSeasonPanel.not))) ...[ videoDetailCtr.horizontalSeasonPanel.not))) ...[
Obx( Obx(
() => PagesPanel( () => PagesPanel(
heroTag: widget.heroTag, heroTag: widget.heroTag,
pages: widget.videoDetail!.pages!, videoDetailData: videoIntroController.videoDetail.value,
cid: videoIntroController.lastPlayCid.value, cid: videoIntroController.lastPlayCid.value,
bvid: videoIntroController.bvid, bvid: videoIntroController.bvid,
changeFuc: videoIntroController.changeSeasonOrbangu, changeFuc: videoIntroController.changeSeasonOrbangu,
@@ -760,7 +762,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
semanticsLabel: '点赞', semanticsLabel: '点赞',
text: !widget.loadingStatus text: !widget.loadingStatus
? Utils.numFormat(widget.videoDetail!.stat!.like!) ? Utils.numFormat(videoDetail.stat!.like!)
: '-', : '-',
needAnim: true, needAnim: true,
hasOneThree: videoIntroController.hasLike.value && hasOneThree: videoIntroController.hasLike.value &&
@@ -804,7 +806,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
semanticsLabel: '投币', semanticsLabel: '投币',
text: !widget.loadingStatus text: !widget.loadingStatus
? Utils.numFormat(widget.videoDetail!.stat!.coin!) ? Utils.numFormat(videoDetail.stat!.coin!)
: '-', : '-',
needAnim: true, needAnim: true,
), ),
@@ -820,7 +822,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
semanticsLabel: '收藏', semanticsLabel: '收藏',
text: !widget.loadingStatus text: !widget.loadingStatus
? Utils.numFormat(widget.videoDetail!.stat!.favorite!) ? Utils.numFormat(videoDetail.stat!.favorite!)
: '-', : '-',
needAnim: true, needAnim: true,
), ),
@@ -833,7 +835,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
semanticsLabel: '评论', semanticsLabel: '评论',
text: !widget.loadingStatus text: !widget.loadingStatus
? Utils.numFormat(widget.videoDetail!.stat!.reply!) ? Utils.numFormat(videoDetail.stat!.reply!)
: '评论'), : '评论'),
ActionItem( ActionItem(
icon: const Icon(FontAwesomeIcons.shareFromSquare), icon: const Icon(FontAwesomeIcons.shareFromSquare),
@@ -842,7 +844,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
semanticsLabel: '分享', semanticsLabel: '分享',
text: !widget.loadingStatus text: !widget.loadingStatus
? Utils.numFormat(widget.videoDetail!.stat!.share!) ? Utils.numFormat(videoDetail.stat!.share!)
: '分享'), : '分享'),
], ],
), ),
@@ -858,9 +860,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
onTap: () => handleState(videoIntroController.actionLikeVideo), onTap: () => handleState(videoIntroController.actionLikeVideo),
selectStatus: videoIntroController.hasLike.value, selectStatus: videoIntroController.hasLike.value,
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
text: !widget.loadingStatus text:
? widget.videoDetail!.stat!.like!.toString() !widget.loadingStatus ? videoDetail.stat!.like!.toString() : '-',
: '-',
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -870,9 +871,8 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
onTap: () => handleState(videoIntroController.actionCoinVideo), onTap: () => handleState(videoIntroController.actionCoinVideo),
selectStatus: videoIntroController.hasCoin.value, selectStatus: videoIntroController.hasCoin.value,
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
text: !widget.loadingStatus text:
? widget.videoDetail!.stat!.coin!.toString() !widget.loadingStatus ? videoDetail.stat!.coin!.toString() : '-',
: '-',
), ),
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -884,7 +884,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
selectStatus: videoIntroController.hasFav.value, selectStatus: videoIntroController.hasFav.value,
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
text: !widget.loadingStatus text: !widget.loadingStatus
? widget.videoDetail!.stat!.favorite!.toString() ? videoDetail.stat!.favorite!.toString()
: '-', : '-',
), ),
), ),
@@ -896,9 +896,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
}, },
selectStatus: false, selectStatus: false,
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
text: !widget.loadingStatus text: !widget.loadingStatus ? videoDetail.stat!.reply!.toString() : '-',
? widget.videoDetail!.stat!.reply!.toString()
: '-',
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionRowItem( ActionRowItem(
@@ -907,7 +905,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
selectStatus: false, selectStatus: false,
loadingStatus: widget.loadingStatus, loadingStatus: widget.loadingStatus,
// text: !loadingStatus // text: !loadingStatus
// ? widget.videoDetail!.stat!.share!.toString() // ? videoDetail.stat!.share!.toString()
// : '-', // : '-',
text: '转发'), text: '转发'),
]); ]);

View File

@@ -11,19 +11,19 @@ import '../../../../../utils/id_utils.dart';
class PagesPanel extends StatefulWidget { class PagesPanel extends StatefulWidget {
const PagesPanel({ const PagesPanel({
super.key, super.key,
required this.pages,
required this.cid, required this.cid,
required this.bvid, required this.bvid,
required this.changeFuc, required this.changeFuc,
required this.heroTag, required this.heroTag,
required this.showEpisodes, required this.showEpisodes,
required this.videoDetailData,
}); });
final List<Part> pages;
final int cid; final int cid;
final String bvid; final String bvid;
final Function changeFuc; final Function changeFuc;
final String heroTag; final String heroTag;
final Function showEpisodes; final Function showEpisodes;
final VideoDetailData videoDetailData;
@override @override
State<PagesPanel> createState() => _PagesPanelState(); State<PagesPanel> createState() => _PagesPanelState();
@@ -32,8 +32,6 @@ class PagesPanel extends StatefulWidget {
class _PagesPanelState extends State<PagesPanel> { class _PagesPanelState extends State<PagesPanel> {
late int cid; late int cid;
late int pageIndex; late int pageIndex;
// final String heroTag = Get.arguments['heroTag'];
late final String heroTag;
late VideoDetailController _videoDetailController; late VideoDetailController _videoDetailController;
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
StreamSubscription? _listener; StreamSubscription? _listener;
@@ -42,12 +40,14 @@ class _PagesPanelState extends State<PagesPanel> {
void initState() { void initState() {
super.initState(); super.initState();
cid = widget.cid; cid = widget.cid;
heroTag = widget.heroTag; _videoDetailController =
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag); Get.find<VideoDetailController>(tag: widget.heroTag);
pageIndex = widget.pages.indexWhere((Part e) => e.cid == cid); pageIndex =
_listener = _videoDetailController.cid.listen((int p0) { widget.videoDetailData.pages!.indexWhere((Part e) => e.cid == cid);
cid = p0; _listener = _videoDetailController.cid.listen((int cid) {
pageIndex = max(0, widget.pages.indexWhere((Part e) => e.cid == cid)); this.cid = cid;
pageIndex = max(0,
widget.videoDetailData.pages!.indexWhere((Part e) => e.cid == cid));
if (!mounted) return; if (!mounted) return;
const double itemWidth = 150; // 每个列表项的宽度 const double itemWidth = 150; // 每个列表项的宽度
final double targetOffset = min((pageIndex * itemWidth) - (itemWidth / 2), final double targetOffset = min((pageIndex * itemWidth) - (itemWidth / 2),
@@ -80,7 +80,7 @@ class _PagesPanelState extends State<PagesPanel> {
const Text('视频选集 '), const Text('视频选集 '),
Expanded( Expanded(
child: Text( child: Text(
' 正在播放:${widget.pages[pageIndex].pagePart}', ' 正在播放:${widget.videoDetailData.pages![pageIndex].pagePart}',
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
@@ -98,13 +98,13 @@ class _PagesPanelState extends State<PagesPanel> {
onPressed: () => widget.showEpisodes( onPressed: () => widget.showEpisodes(
null, null,
null, null,
widget.pages, widget.videoDetailData.pages!,
widget.bvid, widget.bvid,
IdUtils.bv2av(widget.bvid), IdUtils.bv2av(widget.bvid),
cid, cid,
), ),
child: Text( child: Text(
'${widget.pages.length}', '${widget.videoDetailData.pages!.length}',
style: const TextStyle(fontSize: 13), style: const TextStyle(fontSize: 13),
), ),
), ),
@@ -118,14 +118,14 @@ class _PagesPanelState extends State<PagesPanel> {
child: ListView.builder( child: ListView.builder(
controller: _scrollController, controller: _scrollController,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: widget.pages.length, itemCount: widget.videoDetailData.pages!.length,
itemExtent: 150, itemExtent: 150,
itemBuilder: (BuildContext context, int i) { itemBuilder: (BuildContext context, int i) {
bool isCurrentIndex = pageIndex == i; bool isCurrentIndex = pageIndex == i;
return Container( return Container(
width: 150, width: 150,
margin: EdgeInsets.only( margin: EdgeInsets.only(
right: i != widget.pages.length - 1 ? 10 : 0, right: i != widget.videoDetailData.pages!.length - 1 ? 10 : 0,
), ),
child: Material( child: Material(
color: Theme.of(context).colorScheme.onInverseSurface, color: Theme.of(context).colorScheme.onInverseSurface,
@@ -136,7 +136,7 @@ class _PagesPanelState extends State<PagesPanel> {
widget.changeFuc( widget.changeFuc(
null, null,
widget.bvid, widget.bvid,
widget.pages[i].cid, widget.videoDetailData.pages![i].cid,
IdUtils.bv2av(widget.bvid), IdUtils.bv2av(widget.bvid),
null, null,
) )
@@ -157,7 +157,7 @@ class _PagesPanelState extends State<PagesPanel> {
], ],
Expanded( Expanded(
child: Text( child: Text(
widget.pages[i].pagePart!, widget.videoDetailData.pages![i].pagePart!,
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,

View File

@@ -55,10 +55,15 @@ class _SeasonPanelState extends State<SeasonPanel> {
currentIndex.value = episodes.indexWhere( currentIndex.value = episodes.indexWhere(
(EpisodeItem e) => e.cid == _videoDetailController.seasonCid); (EpisodeItem e) => e.cid == _videoDetailController.seasonCid);
_listener = _videoDetailController.cid.listen((int cid) { _listener = _videoDetailController.cid.listen((int cid) {
if (widget.pages != null && widget.pages!.length != 1) { if (_videoDetailController.seasonCid == cid) {
bool isPart = widget.pages?.indexWhere((item) => item.cid == cid) != -1; //refresh
if (isPart) return; _findEpisode();
currentIndex.value = episodes.indexWhere(
(EpisodeItem e) => e.cid == _videoDetailController.seasonCid);
return;
} }
bool isPart = widget.pages?.indexWhere((item) => item.cid == cid) != -1;
if (isPart) return;
_videoDetailController.seasonCid = cid; _videoDetailController.seasonCid = cid;
_findEpisode(); _findEpisode();
currentIndex.value = episodes.indexWhere( currentIndex.value = episodes.indexWhere(

View File

@@ -1470,7 +1470,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
padding: const EdgeInsets.symmetric(horizontal: 14), padding: const EdgeInsets.symmetric(horizontal: 14),
child: PagesPanel( child: PagesPanel(
heroTag: heroTag, heroTag: heroTag,
pages: videoIntroController.videoDetail.value.pages!, videoDetailData: videoIntroController.videoDetail.value,
cid: videoIntroController.lastPlayCid.value, cid: videoIntroController.lastPlayCid.value,
bvid: videoIntroController.bvid, bvid: videoIntroController.bvid,
changeFuc: videoIntroController.changeSeasonOrbangu, changeFuc: videoIntroController.changeSeasonOrbangu,
@@ -1516,10 +1516,13 @@ class _VideoDetailPageState extends State<VideoDetailPage>
? bangumiIntroController.changeSeasonOrbangu ? bangumiIntroController.changeSeasonOrbangu
: videoIntroController.changeSeasonOrbangu, : videoIntroController.changeSeasonOrbangu,
showTitle: false, showTitle: false,
isSupportReverse: videoDetailController.videoType !=
SearchType.media_bangumi,
onReverse: () { onReverse: () {
onReversePlay( onReversePlay(
videoDetailController.bvid, bvid: videoDetailController.bvid,
IdUtils.bv2av(videoDetailController.bvid), aid: IdUtils.bv2av(videoDetailController.bvid),
isSeason: true,
); );
}, },
), ),
@@ -1592,6 +1595,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
aid: aid, aid: aid,
currentCid: cid, currentCid: cid,
episodes: episodes, episodes: episodes,
isSupportReverse:
videoDetailController.videoType != SearchType.media_bangumi,
changeFucCall: changeFucCall:
videoDetailController.videoType == SearchType.media_bangumi videoDetailController.videoType == SearchType.media_bangumi
? bangumiIntroController.changeSeasonOrbangu ? bangumiIntroController.changeSeasonOrbangu
@@ -1606,7 +1611,11 @@ class _VideoDetailPageState extends State<VideoDetailPage>
}, },
onReverse: () { onReverse: () {
Get.back(); Get.back();
onReversePlay(bvid, aid); onReversePlay(
bvid: bvid,
aid: aid,
isSeason: season != null,
);
}, },
); );
if (isFullScreen) { if (isFullScreen) {
@@ -1621,38 +1630,64 @@ class _VideoDetailPageState extends State<VideoDetailPage>
} }
} }
void onReversePlay(bvid, aid) { void onReversePlay({
videoIntroController.videoDetail.value.ugcSeason! required dynamic bvid,
.sections![videoDetailController.seasonIndex.value].episodes = required dynamic aid,
videoIntroController required bool isSeason,
.videoDetail }) {
.value void changeEpisode(episode) {
.ugcSeason! videoIntroController.changeSeasonOrbangu(
.sections![videoDetailController.seasonIndex.value] episode is bangumi.EpisodeItem ? episode.epId : null,
.episodes! episode.runtimeType.toString() == "EpisodeItem" ? episode.bvid : bvid,
.reversed episode.cid,
.toList(); episode.runtimeType.toString() == "EpisodeItem" ? episode.aid : aid,
episode is video.EpisodeItem
? episode.arc?.pic
: episode is bangumi.EpisodeItem
? episode.cover
: null,
);
}
if (videoDetailController.reverseFromFirst.not) { if (isSeason) {
// keep current episode // reverse season
videoDetailController.seasonIndex.refresh(); videoIntroController.videoDetail.value.ugcSeason!
videoDetailController.cid.refresh(); .sections![videoDetailController.seasonIndex.value].episodes =
videoIntroController
.videoDetail
.value
.ugcSeason!
.sections![videoDetailController.seasonIndex.value]
.episodes!
.reversed
.toList();
if (videoDetailController.reverseFromFirst.not) {
// keep current episode
videoDetailController.seasonIndex.refresh();
videoDetailController.cid.refresh();
} else {
// switch to first episode
dynamic episode = videoIntroController.videoDetail.value.ugcSeason!
.sections![videoDetailController.seasonIndex.value].episodes!.first;
if (episode.cid != videoDetailController.cid.value) {
changeEpisode(episode);
}
}
} else { } else {
// switch to first episode // reverse part
dynamic episode = videoIntroController.videoDetail.value.ugcSeason! videoIntroController.videoDetail.value.pages =
.sections![videoDetailController.seasonIndex.value].episodes!.first; videoIntroController.videoDetail.value.pages!.reversed.toList();
if (episode.cid != videoDetailController.cid.value) { videoIntroController.lastPlayCid.refresh();
videoIntroController.changeSeasonOrbangu( if (videoDetailController.reverseFromFirst.not) {
episode is bangumi.EpisodeItem ? episode.epId : null, // keep current episode
episode.runtimeType.toString() == "EpisodeItem" ? episode.bvid : bvid, videoDetailController.cid.refresh();
episode.cid, } else {
episode.runtimeType.toString() == "EpisodeItem" ? episode.aid : aid, // switch to first episode
episode is video.EpisodeItem dynamic episode = videoIntroController.videoDetail.value.pages!.first;
? episode.arc?.pic if (episode.cid != videoDetailController.cid.value) {
: episode is bangumi.EpisodeItem changeEpisode(episode);
? episode.cover }
: null,
);
} }
} }
} }