mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: part: reverse play #70
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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: '转发'),
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user