mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-06-21 09:50:13 +08:00
opt intro controller
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
import 'dart:async' show Timer;
|
||||
|
||||
import 'package:PiliPlus/http/fav.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/user.dart';
|
||||
import 'package:PiliPlus/http/video.dart';
|
||||
import 'package:PiliPlus/models_new/fav/fav_folder/data.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/data.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/stat_detail.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_tag/data.dart';
|
||||
import 'package:PiliPlus/services/account_service.dart';
|
||||
import 'package:PiliPlus/utils/global_data.dart';
|
||||
import 'package:PiliPlus/utils/id_utils.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/storage_key.dart';
|
||||
@@ -17,6 +21,8 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
abstract class CommonIntroController extends GetxController {
|
||||
String heroTag = Get.arguments['heroTag'];
|
||||
|
||||
String bvid = Get.parameters['bvid']!;
|
||||
|
||||
// 是否点赞
|
||||
@@ -27,6 +33,8 @@ abstract class CommonIntroController extends GetxController {
|
||||
bool get hasCoin => coinNum.value != 0;
|
||||
// 是否收藏
|
||||
final RxBool hasFav = false.obs;
|
||||
// 是否稍后再看
|
||||
final RxBool hasLater = false.obs;
|
||||
|
||||
final Rx<List<VideoTagItem>?> videoTags = Rx<List<VideoTagItem>?>(null);
|
||||
|
||||
@@ -39,6 +47,62 @@ abstract class CommonIntroController extends GetxController {
|
||||
|
||||
StatDetail? getStat();
|
||||
|
||||
final Rx<VideoDetailData> videoDetail = VideoDetailData().obs;
|
||||
|
||||
Future<void> queryVideoIntro();
|
||||
|
||||
bool prevPlay();
|
||||
bool nextPlay();
|
||||
|
||||
// 同时观看
|
||||
final bool isShowOnlineTotal = Pref.enableOnlineTotal;
|
||||
late final RxString total = '1'.obs;
|
||||
Timer? timer;
|
||||
|
||||
final RxInt cid = int.parse(Get.parameters['cid']!).obs;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
queryVideoIntro();
|
||||
startTimer();
|
||||
}
|
||||
|
||||
void startTimer() {
|
||||
if (isShowOnlineTotal) {
|
||||
queryOnlineTotal();
|
||||
timer ??= Timer.periodic(const Duration(seconds: 10), (Timer timer) {
|
||||
queryOnlineTotal();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void canelTimer() {
|
||||
timer?.cancel();
|
||||
timer = null;
|
||||
}
|
||||
|
||||
// 查看同时在看人数
|
||||
Future<void> queryOnlineTotal() async {
|
||||
if (!isShowOnlineTotal) {
|
||||
return;
|
||||
}
|
||||
var result = await VideoHttp.onlineTotal(
|
||||
aid: IdUtils.bv2av(bvid),
|
||||
bvid: bvid,
|
||||
cid: cid.value,
|
||||
);
|
||||
if (result['status']) {
|
||||
total.value = result['data'];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
canelTimer();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
Future<LoadingState<FavFolderData>> queryVideoInFolder() async {
|
||||
favIds = null;
|
||||
final (rid, type) = getFavRidType();
|
||||
@@ -197,4 +261,12 @@ abstract class CommonIntroController extends GetxController {
|
||||
videoTags.value = null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> viewLater() async {
|
||||
var res = await (hasLater.value
|
||||
? UserHttp.toViewDel(aids: [IdUtils.bv2av(bvid)])
|
||||
: await UserHttp.toViewLater(bvid: bvid));
|
||||
if (res['status']) hasLater.value = !hasLater.value;
|
||||
SmartDialog.showToast(res['msg']);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class EpisodePanel extends CommonSlidePage {
|
||||
const EpisodePanel({
|
||||
super.key,
|
||||
super.enableSlide,
|
||||
required this.videoIntroController,
|
||||
required this.ugcIntroController,
|
||||
required this.heroTag,
|
||||
required this.type,
|
||||
// required this.count,
|
||||
@@ -57,11 +57,11 @@ class EpisodePanel extends CommonSlidePage {
|
||||
this.isSupportReverse,
|
||||
this.isReversed,
|
||||
this.onReverse,
|
||||
required this.changeFucCall,
|
||||
required this.onChangeEpisode,
|
||||
this.onClose,
|
||||
});
|
||||
}) : assert(type == EpisodeType.pgc || ugcIntroController != null);
|
||||
|
||||
final VideoIntroController videoIntroController;
|
||||
final UgcIntroController? ugcIntroController;
|
||||
final String heroTag;
|
||||
final EpisodeType type;
|
||||
// final int count;
|
||||
@@ -76,7 +76,7 @@ class EpisodePanel extends CommonSlidePage {
|
||||
final int initialTabIndex;
|
||||
final bool? isSupportReverse;
|
||||
final bool? isReversed;
|
||||
final Function changeFucCall;
|
||||
final Function onChangeEpisode;
|
||||
final VoidCallback? onReverse;
|
||||
final VoidCallback? onClose;
|
||||
|
||||
@@ -315,7 +315,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
|
||||
: episode.pages,
|
||||
cover: episode.arc?.pic,
|
||||
heroTag: widget.heroTag,
|
||||
videoIntroController: widget.videoIntroController,
|
||||
ugcIntroController: widget.ugcIntroController!,
|
||||
bvid: IdUtils.av2bv(episode.aid),
|
||||
),
|
||||
),
|
||||
@@ -401,7 +401,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
|
||||
_currentItemIndex = index;
|
||||
}
|
||||
final isEpisode = episode is ugc.BaseEpisodeItem;
|
||||
widget.changeFucCall(
|
||||
widget.onChangeEpisode(
|
||||
episode is pgc.EpisodeItem ? episode.epId : null,
|
||||
isEpisode ? episode.bvid : widget.bvid,
|
||||
episode.cid,
|
||||
@@ -411,7 +411,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
|
||||
if (widget.type == EpisodeType.season) {
|
||||
try {
|
||||
Get.find<VideoDetailController>(
|
||||
tag: widget.videoIntroController.heroTag,
|
||||
tag: widget.ugcIntroController!.heroTag,
|
||||
).seasonCid = episode.cid;
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ class _SavePanelState extends State<SavePanel> {
|
||||
if (currentRoute.startsWith('/video')) {
|
||||
try {
|
||||
final heroTag = Get.arguments?['heroTag'];
|
||||
late final ctr = Get.find<VideoIntroController>(tag: heroTag);
|
||||
late final ctr = Get.find<UgcIntroController>(tag: heroTag);
|
||||
final videoDetail = ctr.videoDetail.value;
|
||||
cover = videoDetail.pic;
|
||||
title = videoDetail.title;
|
||||
|
||||
@@ -19,6 +19,14 @@ class AiConclusionPanel extends CommonCollapseSlidePage {
|
||||
}
|
||||
|
||||
class _AiDetailState extends CommonCollapseSlidePageState<AiConclusionPanel> {
|
||||
final _controller = ScrollController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Material(
|
||||
@@ -53,7 +61,7 @@ class _AiDetailState extends CommonCollapseSlidePageState<AiConclusionPanel> {
|
||||
@override
|
||||
Widget buildList(ThemeData theme) {
|
||||
return CustomScrollView(
|
||||
controller: ScrollController(),
|
||||
controller: _controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
if (widget.item.summary?.isNotEmpty == true) ...[
|
||||
|
||||
@@ -68,11 +68,11 @@ class VideoDetailController extends GetxController
|
||||
/// 路由传参
|
||||
String bvid = Get.parameters['bvid']!;
|
||||
final RxInt cid = int.parse(Get.parameters['cid']!).obs;
|
||||
final RxInt danmakuCid = 0.obs;
|
||||
final heroTag = Get.arguments['heroTag'];
|
||||
final RxString cover = ''.obs;
|
||||
// 视频类型 默认投稿视频
|
||||
final SearchType videoType = Get.arguments['videoType'] ?? SearchType.video;
|
||||
final isUgc =
|
||||
(Get.arguments['videoType'] ?? SearchType.video) == SearchType.video;
|
||||
|
||||
/// tabs相关配置
|
||||
late TabController tabCtr;
|
||||
@@ -114,7 +114,7 @@ class VideoDetailController extends GetxController
|
||||
late String cacheDecode;
|
||||
late String cacheSecondDecode;
|
||||
|
||||
bool get showReply => videoType == SearchType.video
|
||||
bool get showReply => isUgc
|
||||
? plPlayerController.showVideoReply
|
||||
: plPlayerController.showBangumiReply;
|
||||
|
||||
@@ -283,7 +283,6 @@ class VideoDetailController extends GetxController
|
||||
);
|
||||
autoPlay.value = Pref.autoPlayEnable;
|
||||
if (autoPlay.value) isShowCover.value = false;
|
||||
danmakuCid.value = cid.value;
|
||||
|
||||
// 预设的解码格式
|
||||
cacheDecode = Pref.defaultDecode;
|
||||
@@ -336,9 +335,9 @@ class VideoDetailController extends GetxController
|
||||
try {
|
||||
for (var item in mediaList) {
|
||||
if (item.cid != null) {
|
||||
Get.find<VideoIntroController>(
|
||||
Get.find<UgcIntroController>(
|
||||
tag: heroTag,
|
||||
).changeSeasonOrbangu(
|
||||
).onChangeEpisode(
|
||||
null,
|
||||
item.bvid,
|
||||
item.cid,
|
||||
@@ -367,9 +366,9 @@ class VideoDetailController extends GetxController
|
||||
mediaList: mediaList,
|
||||
changeMediaList: (bvid, cid, aid, cover) {
|
||||
try {
|
||||
Get.find<VideoIntroController>(
|
||||
Get.find<UgcIntroController>(
|
||||
tag: heroTag,
|
||||
).changeSeasonOrbangu(null, bvid, cid, aid, cover);
|
||||
).onChangeEpisode(null, bvid, cid, aid, cover);
|
||||
} catch (_) {}
|
||||
},
|
||||
panelTitle: watchLaterTitle,
|
||||
@@ -901,11 +900,11 @@ class VideoDetailController extends GetxController
|
||||
onTap: (_) {
|
||||
if (item is int) {
|
||||
try {
|
||||
VideoIntroController videoIntroController =
|
||||
Get.find<VideoIntroController>(tag: heroTag);
|
||||
UgcIntroController ugcIntroController =
|
||||
Get.find<UgcIntroController>(tag: heroTag);
|
||||
Part part =
|
||||
videoIntroController.videoDetail.value.pages![item];
|
||||
videoIntroController.changeSeasonOrbangu(
|
||||
ugcIntroController.videoDetail.value.pages![item];
|
||||
ugcIntroController.onChangeEpisode(
|
||||
null,
|
||||
bvid,
|
||||
part.cid,
|
||||
@@ -1137,9 +1136,9 @@ class VideoDetailController extends GetxController
|
||||
bvid: bvid,
|
||||
cid: cid.value,
|
||||
autoplay: autoplay ?? autoPlay.value,
|
||||
epid: videoType == SearchType.media_bangumi ? epId : null,
|
||||
seasonId: videoType == SearchType.media_bangumi ? seasonId : null,
|
||||
subType: videoType == SearchType.media_bangumi ? subType : null,
|
||||
epid: isUgc ? null : epId,
|
||||
seasonId: isUgc ? null : seasonId,
|
||||
subType: isUgc ? null : subType,
|
||||
callback: () {
|
||||
if (videoState.value is! Success) {
|
||||
videoState.value = const Success(null);
|
||||
@@ -1496,9 +1495,9 @@ class VideoDetailController extends GetxController
|
||||
if (res['status']) {
|
||||
PlayInfoData playInfo = res['data'];
|
||||
// interactive video
|
||||
if (graphVersion == null) {
|
||||
if (isUgc && graphVersion == null) {
|
||||
try {
|
||||
final introCtr = Get.find<VideoIntroController>(tag: heroTag);
|
||||
final introCtr = Get.find<UgcIntroController>(tag: heroTag);
|
||||
if (introCtr.videoDetail.value.rights?.isSteinGate == 1) {
|
||||
graphVersion = playInfo.interaction?.graphVersion;
|
||||
getSteinEdgeInfo();
|
||||
@@ -1508,16 +1507,17 @@ class VideoDetailController extends GetxController
|
||||
}
|
||||
}
|
||||
|
||||
if (continuePlayingPart) {
|
||||
if (isUgc && continuePlayingPart) {
|
||||
continuePlayingPart = false;
|
||||
try {
|
||||
VideoIntroController videoIntroController =
|
||||
Get.find<VideoIntroController>(tag: heroTag);
|
||||
if ((videoIntroController.videoDetail.value.pages?.length ?? 0) > 1 &&
|
||||
UgcIntroController ugcIntroController = Get.find<UgcIntroController>(
|
||||
tag: heroTag,
|
||||
);
|
||||
if ((ugcIntroController.videoDetail.value.pages?.length ?? 0) > 1 &&
|
||||
playInfo.lastPlayCid != null &&
|
||||
playInfo.lastPlayCid != 0) {
|
||||
if (playInfo.lastPlayCid != cid.value) {
|
||||
int index = videoIntroController.videoDetail.value.pages!
|
||||
int index = ugcIntroController.videoDetail.value.pages!
|
||||
.indexWhere((item) => item.cid == playInfo.lastPlayCid);
|
||||
if (index != -1) {
|
||||
onAddItem(index);
|
||||
@@ -1598,9 +1598,9 @@ class VideoDetailController extends GetxController
|
||||
isManual: true,
|
||||
bvid: bvid,
|
||||
cid: cid.value,
|
||||
epid: videoType == SearchType.media_bangumi ? epId : null,
|
||||
seasonId: videoType == SearchType.media_bangumi ? seasonId : null,
|
||||
subType: videoType == SearchType.media_bangumi ? subType : null,
|
||||
epid: isUgc ? null : epId,
|
||||
seasonId: isUgc ? null : seasonId,
|
||||
subType: isUgc ? null : subType,
|
||||
);
|
||||
} catch (_) {}
|
||||
}
|
||||
@@ -1683,7 +1683,7 @@ class VideoDetailController extends GetxController
|
||||
void showNoteList(BuildContext context) {
|
||||
String? title;
|
||||
try {
|
||||
title = Get.find<VideoIntroController>(
|
||||
title = Get.find<UgcIntroController>(
|
||||
tag: heroTag,
|
||||
).videoDetail.value.title;
|
||||
} catch (_) {}
|
||||
|
||||
@@ -10,14 +10,15 @@ import 'package:PiliPlus/models/pgc_lcf.dart';
|
||||
import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart';
|
||||
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart';
|
||||
import 'package:PiliPlus/models_new/triple/pgc_triple.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/data.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/stat_detail.dart';
|
||||
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
||||
import 'package:PiliPlus/pages/dynamics_repost/view.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/pay_coins/view.dart';
|
||||
import 'package:PiliPlus/pages/video/reply/controller.dart';
|
||||
import 'package:PiliPlus/plugin/pl_player/models/play_repeat.dart';
|
||||
import 'package:PiliPlus/services/service_locator.dart';
|
||||
import 'package:PiliPlus/utils/feed_back.dart';
|
||||
import 'package:PiliPlus/utils/global_data.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
@@ -257,7 +258,7 @@ class PgcIntroController extends CommonIntroController {
|
||||
}
|
||||
|
||||
// 修改分P或番剧分集
|
||||
void changeSeasonOrbangu(dynamic epId, bvid, cid, aid, cover) {
|
||||
void onChangeEpisode(dynamic epId, bvid, cid, aid, cover) {
|
||||
// 重新获取视频资源
|
||||
this.epId = epId;
|
||||
this.bvid = bvid;
|
||||
@@ -270,7 +271,6 @@ class PgcIntroController extends CommonIntroController {
|
||||
..epId = epId
|
||||
..bvid = bvid
|
||||
..cid.value = cid
|
||||
..danmakuCid.value = cid
|
||||
..queryVideoUrl();
|
||||
if (cover is String && cover.isNotEmpty) {
|
||||
videoDetailCtr.cover.value = cover;
|
||||
@@ -289,13 +289,9 @@ class PgcIntroController extends CommonIntroController {
|
||||
queryPgcLikeCoinFav();
|
||||
}
|
||||
|
||||
try {
|
||||
Get.find<VideoIntroController>(tag: Get.arguments['heroTag'])
|
||||
..bvid = bvid
|
||||
..lastPlayCid.value = cid
|
||||
..queryVideoIntro()
|
||||
..queryOnlineTotal();
|
||||
} catch (_) {}
|
||||
this.cid.value = cid;
|
||||
queryVideoIntro();
|
||||
queryOnlineTotal();
|
||||
}
|
||||
|
||||
// 追番
|
||||
@@ -328,6 +324,7 @@ class PgcIntroController extends CommonIntroController {
|
||||
SmartDialog.showToast(result['msg']);
|
||||
}
|
||||
|
||||
@override
|
||||
bool prevPlay() {
|
||||
final episodes = pgcItem.episodes!;
|
||||
VideoDetailController videoDetailCtr = Get.find<VideoDetailController>(
|
||||
@@ -346,7 +343,7 @@ class PgcIntroController extends CommonIntroController {
|
||||
}
|
||||
}
|
||||
final episode = episodes[prevIndex];
|
||||
changeSeasonOrbangu(
|
||||
onChangeEpisode(
|
||||
episode.epId,
|
||||
episode.bvid,
|
||||
episode.cid,
|
||||
@@ -357,6 +354,7 @@ class PgcIntroController extends CommonIntroController {
|
||||
}
|
||||
|
||||
/// 列表循环或者顺序播放时,自动播放下一个;自动连播时,播放相关视频
|
||||
@override
|
||||
bool nextPlay() {
|
||||
try {
|
||||
final episodes = pgcItem.episodes!;
|
||||
@@ -380,7 +378,7 @@ class PgcIntroController extends CommonIntroController {
|
||||
}
|
||||
}
|
||||
final episode = episodes[nextIndex];
|
||||
changeSeasonOrbangu(
|
||||
onChangeEpisode(
|
||||
episode.epId,
|
||||
episode.bvid,
|
||||
episode.cid,
|
||||
@@ -456,4 +454,14 @@ class PgcIntroController extends CommonIntroController {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> queryVideoIntro() async {
|
||||
var res = await VideoHttp.videoIntro(bvid: bvid);
|
||||
if (res.isSuccess) {
|
||||
VideoDetailData data = res.data;
|
||||
videoPlayerServiceHandler.onVideoDetailChange(data, data.cid!, heroTag);
|
||||
videoDetail.value = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ class _PgcIntroPageState extends State<PgcIntroPage>
|
||||
heroTag: widget.heroTag,
|
||||
pages: item.episodes!,
|
||||
cid: videoDetailCtr.cid.value,
|
||||
changeFuc: pgcIntroController.changeSeasonOrbangu,
|
||||
onChangeEpisode: pgcIntroController.onChangeEpisode,
|
||||
showEpisodes: widget.showEpisodes,
|
||||
newEp: item.newEp,
|
||||
),
|
||||
@@ -326,13 +326,15 @@ class _PgcIntroPageState extends State<PgcIntroPage>
|
||||
needAnim: true,
|
||||
),
|
||||
),
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.comment),
|
||||
selectIcon: const Icon(FontAwesomeIcons.reply),
|
||||
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
|
||||
selectStatus: false,
|
||||
semanticsLabel: '评论',
|
||||
text: NumUtil.numFormat(item.stat!.reply),
|
||||
Obx(
|
||||
() => ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.clock),
|
||||
selectIcon: const Icon(FontAwesomeIcons.solidClock),
|
||||
onTap: () => handleState(pgcIntroController.viewLater),
|
||||
selectStatus: pgcIntroController.hasLater.value,
|
||||
semanticsLabel: '再看',
|
||||
text: '再看',
|
||||
),
|
||||
),
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.shareFromSquare),
|
||||
|
||||
@@ -94,94 +94,99 @@ class _IntroDetailState extends CommonCollapseSlidePageState<PgcIntroPanel> {
|
||||
fontSize: 12,
|
||||
color: theme.colorScheme.onSurface,
|
||||
);
|
||||
return ListView(
|
||||
controller: _controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
left: 14,
|
||||
right: 14,
|
||||
top: 14,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
children: [
|
||||
SelectableText(
|
||||
widget.item.title!,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
final TextStyle textStyle = TextStyle(
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
);
|
||||
return SelectionArea(
|
||||
child: ListView(
|
||||
controller: _controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
left: 14,
|
||||
right: 14,
|
||||
top: 14,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
StatWidget(
|
||||
type: StatType.play,
|
||||
value: widget.item.stat!.view,
|
||||
),
|
||||
StatWidget(
|
||||
type: StatType.danmaku,
|
||||
value: widget.item.stat!.danmaku,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.item.areas!.first.name!,
|
||||
style: smallTitle,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
widget.item.publish!.pubTimeShow!,
|
||||
style: smallTitle,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
widget.item.newEp!.desc!,
|
||||
style: smallTitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'简介:',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
SelectableText(
|
||||
widget.item.evaluate!,
|
||||
style: smallTitle.copyWith(fontSize: 14),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'声优:',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
SelectableText(
|
||||
widget.item.actors!,
|
||||
style: smallTitle.copyWith(fontSize: 14),
|
||||
),
|
||||
if (widget.videoTags?.isNotEmpty == true) ...[
|
||||
const SizedBox(height: 10),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: widget.videoTags!
|
||||
.map(
|
||||
(item) => SearchText(
|
||||
fontSize: 13,
|
||||
text: item.tagName!,
|
||||
onTap: (tagName) => Get.toNamed(
|
||||
'/searchResult',
|
||||
parameters: {'keyword': tagName},
|
||||
),
|
||||
onLongPress: Utils.copyText,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
children: [
|
||||
Text(
|
||||
widget.item.title!,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
spacing: 6,
|
||||
children: [
|
||||
StatWidget(
|
||||
type: StatType.play,
|
||||
value: widget.item.stat!.view,
|
||||
),
|
||||
StatWidget(
|
||||
type: StatType.danmaku,
|
||||
value: widget.item.stat!.danmaku,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
widget.item.areas!.first.name!,
|
||||
style: smallTitle,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
widget.item.publish!.pubTimeShow!,
|
||||
style: smallTitle,
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
widget.item.newEp!.desc!,
|
||||
style: smallTitle,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'简介:',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
widget.item.evaluate!,
|
||||
style: textStyle,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text(
|
||||
'演职人员:',
|
||||
style: theme.textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
widget.item.actors!,
|
||||
style: textStyle,
|
||||
),
|
||||
if (widget.videoTags?.isNotEmpty == true) ...[
|
||||
const SizedBox(height: 10),
|
||||
Wrap(
|
||||
spacing: 8,
|
||||
runSpacing: 8,
|
||||
children: widget.videoTags!
|
||||
.map(
|
||||
(item) => SearchText(
|
||||
fontSize: 13,
|
||||
text: item.tagName!,
|
||||
onTap: (tagName) => Get.toNamed(
|
||||
'/searchResult',
|
||||
parameters: {'keyword': tagName},
|
||||
),
|
||||
onLongPress: Utils.copyText,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
],
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class PgcPanel extends StatefulWidget {
|
||||
super.key,
|
||||
required this.pages,
|
||||
this.cid,
|
||||
required this.changeFuc,
|
||||
required this.onChangeEpisode,
|
||||
required this.showEpisodes,
|
||||
required this.heroTag,
|
||||
this.newEp,
|
||||
@@ -23,7 +23,7 @@ class PgcPanel extends StatefulWidget {
|
||||
|
||||
final List<EpisodeItem> pages;
|
||||
final int? cid;
|
||||
final Function changeFuc;
|
||||
final Function onChangeEpisode;
|
||||
final Function showEpisodes;
|
||||
final String heroTag;
|
||||
final NewEp? newEp;
|
||||
@@ -154,7 +154,7 @@ class _PgcPanelState extends State<PgcPanel> {
|
||||
vipStatus != 1) {
|
||||
SmartDialog.showToast('需要大会员');
|
||||
}
|
||||
widget.changeFuc(
|
||||
widget.onChangeEpisode(
|
||||
item.epId,
|
||||
item.bvid,
|
||||
item.cid,
|
||||
|
||||
@@ -43,13 +43,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
String heroTag = '';
|
||||
|
||||
class UgcIntroController extends CommonIntroController with ReloadMixin {
|
||||
late ExpandableController expandableCtr;
|
||||
|
||||
final RxBool status = true.obs;
|
||||
final Rx<VideoDetailData> videoDetail = VideoDetailData().obs;
|
||||
|
||||
// up主粉丝数
|
||||
final Rx<MemberCardInfoData> userStat = MemberCardInfoData().obs;
|
||||
@@ -60,16 +57,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
// 是否点踩
|
||||
final RxBool hasDislike = false.obs;
|
||||
|
||||
// 是否稍后再看
|
||||
final RxBool hasLater = false.obs;
|
||||
|
||||
final RxInt lastPlayCid = 0.obs;
|
||||
|
||||
// 同时观看
|
||||
final bool isShowOnlineTotal = Pref.enableOnlineTotal;
|
||||
late final RxString total = '1'.obs;
|
||||
Timer? timer;
|
||||
|
||||
late final showArgueMsg = Pref.showArgueMsg;
|
||||
late final enableAi = Pref.enableAi;
|
||||
late final horizontalMemberPage = Pref.horizontalMemberPage;
|
||||
@@ -92,11 +79,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
if (heroTag.isEmpty) {
|
||||
heroTag = Get.arguments['heroTag'];
|
||||
}
|
||||
} catch (_) {}
|
||||
try {
|
||||
var videoItem = Get.arguments['videoItem'];
|
||||
if (videoItem != null) {
|
||||
@@ -110,12 +92,10 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
}
|
||||
}
|
||||
} catch (_) {}
|
||||
lastPlayCid.value = int.parse(Get.parameters['cid']!);
|
||||
startTimer();
|
||||
queryVideoIntro();
|
||||
}
|
||||
|
||||
// 获取视频简介&分p
|
||||
@override
|
||||
Future<void> queryVideoIntro() async {
|
||||
queryVideoTags();
|
||||
var res = await VideoHttp.videoIntro(bvid: bvid);
|
||||
@@ -152,8 +132,8 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
}
|
||||
} catch (_) {}
|
||||
final pages = videoDetail.value.pages;
|
||||
if (pages != null && pages.isNotEmpty && lastPlayCid.value == 0) {
|
||||
lastPlayCid.value = pages.first.cid!;
|
||||
if (pages != null && pages.isNotEmpty && cid.value == 0) {
|
||||
cid.value = pages.first.cid!;
|
||||
}
|
||||
queryUserStat(data.staff);
|
||||
} else {
|
||||
@@ -298,14 +278,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> viewLater() async {
|
||||
var res = await (hasLater.value
|
||||
? UserHttp.toViewDel(aids: [IdUtils.bv2av(bvid)])
|
||||
: await UserHttp.toViewLater(bvid: bvid));
|
||||
if (res['status']) hasLater.value = !hasLater.value;
|
||||
SmartDialog.showToast(res['msg']);
|
||||
}
|
||||
|
||||
// 投币
|
||||
Future<void> actionCoinVideo() async {
|
||||
if (!accountService.isLogin.value) {
|
||||
@@ -493,7 +465,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
}
|
||||
|
||||
// 修改分P或番剧分集
|
||||
bool changeSeasonOrbangu(dynamic epid, bvid, cid, aid, cover, [isStein]) {
|
||||
bool onChangeEpisode(dynamic epid, bvid, cid, aid, cover, [isStein]) {
|
||||
// 重新获取视频资源
|
||||
final videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
|
||||
|
||||
@@ -519,7 +491,6 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
..bvid = bvid
|
||||
..oid.value = aid ?? IdUtils.bv2av(bvid)
|
||||
..cid.value = cid
|
||||
..danmakuCid.value = cid
|
||||
..queryVideoUrl();
|
||||
|
||||
if (this.bvid != bvid) {
|
||||
@@ -553,48 +524,19 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
queryVideoIntro();
|
||||
}
|
||||
|
||||
lastPlayCid.value = cid;
|
||||
this.cid.value = cid;
|
||||
queryOnlineTotal();
|
||||
return true;
|
||||
}
|
||||
|
||||
void startTimer() {
|
||||
if (isShowOnlineTotal) {
|
||||
queryOnlineTotal();
|
||||
timer ??= Timer.periodic(const Duration(seconds: 10), (Timer timer) {
|
||||
queryOnlineTotal();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void canelTimer() {
|
||||
timer?.cancel();
|
||||
timer = null;
|
||||
}
|
||||
|
||||
// 查看同时在看人数
|
||||
Future<void> queryOnlineTotal() async {
|
||||
if (!isShowOnlineTotal) {
|
||||
return;
|
||||
}
|
||||
var result = await VideoHttp.onlineTotal(
|
||||
aid: IdUtils.bv2av(bvid),
|
||||
bvid: bvid,
|
||||
cid: lastPlayCid.value,
|
||||
);
|
||||
if (result['status']) {
|
||||
total.value = result['data'];
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
canelTimer();
|
||||
expandableCtr.dispose();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
/// 播放上一个
|
||||
@override
|
||||
bool prevPlay([bool skipPages = false]) {
|
||||
final List episodes = [];
|
||||
bool isPages = false;
|
||||
@@ -624,7 +566,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
? videoDetail.isPageReversed == true
|
||||
? videoDetail.pages!.last.cid
|
||||
: videoDetail.pages!.first.cid
|
||||
: lastPlayCid.value),
|
||||
: this.cid.value),
|
||||
);
|
||||
int prevIndex = currentIndex - 1;
|
||||
final PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat;
|
||||
@@ -644,11 +586,12 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
final int cid = episodes[prevIndex].cid!;
|
||||
final String rBvid = isPages ? bvid : episodes[prevIndex].bvid;
|
||||
final int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[prevIndex].aid!;
|
||||
changeSeasonOrbangu(null, rBvid, cid, rAid, null);
|
||||
onChangeEpisode(null, rBvid, cid, rAid, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// 列表循环或者顺序播放时,自动播放下一个
|
||||
@override
|
||||
bool nextPlay([bool skipPages = false]) {
|
||||
try {
|
||||
final List episodes = [];
|
||||
@@ -731,7 +674,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
|
||||
final String rBvid = isPages ? bvid : episodes[nextIndex].bvid;
|
||||
final int rAid = isPages ? IdUtils.bv2av(bvid) : episodes[nextIndex].aid!;
|
||||
changeSeasonOrbangu(null, rBvid, cid, rAid, null);
|
||||
onChangeEpisode(null, rBvid, cid, rAid, null);
|
||||
return true;
|
||||
} catch (_) {
|
||||
return false;
|
||||
@@ -762,7 +705,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
final firstItem = relatedCtr.loadingState.value.data!.first;
|
||||
try {
|
||||
if (firstItem.cid != null) {
|
||||
changeSeasonOrbangu(
|
||||
onChangeEpisode(
|
||||
null,
|
||||
firstItem.bvid,
|
||||
firstItem.cid,
|
||||
@@ -771,7 +714,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
);
|
||||
} else {
|
||||
SearchHttp.ab2c(aid: firstItem.aid, bvid: firstItem.bvid).then(
|
||||
(cid) => changeSeasonOrbangu(
|
||||
(cid) => onChangeEpisode(
|
||||
null,
|
||||
firstItem.bvid,
|
||||
cid,
|
||||
@@ -791,7 +734,7 @@ class VideoIntroController extends CommonIntroController with ReloadMixin {
|
||||
SmartDialog.showLoading(msg: '正在获取AI总结');
|
||||
final res = await VideoHttp.aiConclusion(
|
||||
bvid: bvid,
|
||||
cid: lastPlayCid.value,
|
||||
cid: cid.value,
|
||||
upMid: videoDetail.value.owner?.mid,
|
||||
);
|
||||
SmartDialog.dismiss();
|
||||
|
||||
@@ -35,8 +35,8 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
|
||||
class VideoIntroPanel extends StatefulWidget {
|
||||
const VideoIntroPanel({
|
||||
class UgcIntroPanel extends StatefulWidget {
|
||||
const UgcIntroPanel({
|
||||
super.key,
|
||||
required this.heroTag,
|
||||
required this.showAiBottomSheet,
|
||||
@@ -49,12 +49,12 @@ class VideoIntroPanel extends StatefulWidget {
|
||||
final ValueChanged<int?> onShowMemberPage;
|
||||
|
||||
@override
|
||||
State<VideoIntroPanel> createState() => _VideoIntroPanelState();
|
||||
State<UgcIntroPanel> createState() => _UgcIntroPanelState();
|
||||
}
|
||||
|
||||
class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
class _UgcIntroPanelState extends State<UgcIntroPanel>
|
||||
with AutomaticKeepAliveClientMixin {
|
||||
late VideoIntroController introController;
|
||||
late UgcIntroController ugcIntroController;
|
||||
late final VideoDetailController videoDetailCtr =
|
||||
Get.find<VideoDetailController>(tag: widget.heroTag);
|
||||
|
||||
@@ -66,7 +66,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
introController = Get.put(VideoIntroController(), tag: widget.heroTag)
|
||||
ugcIntroController = Get.put(UgcIntroController(), tag: widget.heroTag)
|
||||
..heroTag = widget.heroTag;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
),
|
||||
sliver: Obx(
|
||||
() {
|
||||
VideoDetailData videoDetail = introController.videoDetail.value;
|
||||
VideoDetailData videoDetail =
|
||||
ugcIntroController.videoDetail.value;
|
||||
bool isLoading = videoDetail.bvid == null;
|
||||
int? mid = videoDetail.owner?.mid;
|
||||
return SliverToBoxAdapter(
|
||||
@@ -107,7 +108,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
return;
|
||||
}
|
||||
feedBack();
|
||||
introController.expandableCtr.toggle();
|
||||
ugcIntroController.expandableCtr.toggle();
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -127,7 +128,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
if (mid != null) {
|
||||
feedBack();
|
||||
if (!isPortrait &&
|
||||
introController
|
||||
ugcIntroController
|
||||
.horizontalMemberPage) {
|
||||
widget.onShowMemberPage(mid);
|
||||
} else {
|
||||
@@ -146,7 +147,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: ReloadScrollPhysics(
|
||||
controller: introController,
|
||||
controller: ugcIntroController,
|
||||
),
|
||||
child: Row(
|
||||
spacing: 25,
|
||||
@@ -170,7 +171,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
context,
|
||||
isLoading,
|
||||
videoDetail,
|
||||
introController,
|
||||
ugcIntroController,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -182,7 +183,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
_buildVideoTitle(theme, videoDetail)
|
||||
else
|
||||
ExpandablePanel(
|
||||
controller: introController.expandableCtr,
|
||||
controller: ugcIntroController.expandableCtr,
|
||||
collapsed: GestureDetector(
|
||||
onLongPress: () {
|
||||
Feedback.forLongPress(context);
|
||||
@@ -208,11 +209,11 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
_buildInfo(theme, videoDetail),
|
||||
if (introController.enableAi) _aiBtn,
|
||||
if (ugcIntroController.enableAi) _aiBtn,
|
||||
],
|
||||
),
|
||||
if (videoDetail.argueInfo?.argueMsg?.isNotEmpty == true &&
|
||||
introController.showArgueMsg) ...[
|
||||
ugcIntroController.showArgueMsg) ...[
|
||||
const SizedBox(height: 2),
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
@@ -238,7 +239,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
),
|
||||
],
|
||||
ExpandablePanel(
|
||||
controller: introController.expandableCtr,
|
||||
controller: ugcIntroController.expandableCtr,
|
||||
collapsed: const SizedBox.shrink(),
|
||||
expanded: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -270,7 +271,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
),
|
||||
],
|
||||
Obx(() {
|
||||
final videoTags = introController.videoTags.value;
|
||||
final videoTags =
|
||||
ugcIntroController.videoTags.value;
|
||||
if (videoTags.isNullOrEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
@@ -281,14 +283,15 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
theme: expandTheme,
|
||||
),
|
||||
Obx(
|
||||
() => introController.status.value
|
||||
() => ugcIntroController.status.value
|
||||
? const SizedBox.shrink()
|
||||
: Center(
|
||||
child: TextButton.icon(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: () {
|
||||
introController.status.value = true;
|
||||
introController.queryVideoIntro();
|
||||
ugcIntroController
|
||||
..status.value = true
|
||||
..queryVideoIntro();
|
||||
if (videoDetailCtr.videoUrl.isNullOrEmpty &&
|
||||
!videoDetailCtr.isQuerying) {
|
||||
videoDetailCtr.queryVideoUrl();
|
||||
@@ -305,7 +308,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
context,
|
||||
isLoading,
|
||||
videoDetail,
|
||||
introController,
|
||||
ugcIntroController,
|
||||
),
|
||||
],
|
||||
// 合集
|
||||
@@ -317,9 +320,9 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
.horizontalSeasonPanel))
|
||||
SeasonPanel(
|
||||
heroTag: widget.heroTag,
|
||||
changeFuc: introController.changeSeasonOrbangu,
|
||||
onChangeEpisode: ugcIntroController.onChangeEpisode,
|
||||
showEpisodes: widget.showEpisodes,
|
||||
videoIntroController: introController,
|
||||
ugcIntroController: ugcIntroController,
|
||||
),
|
||||
if (!isLoading &&
|
||||
videoDetail.pages != null &&
|
||||
@@ -330,8 +333,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
.horizontalSeasonPanel)) ...[
|
||||
PagesPanel(
|
||||
heroTag: widget.heroTag,
|
||||
videoIntroController: introController,
|
||||
bvid: introController.bvid,
|
||||
ugcIntroController: ugcIntroController,
|
||||
bvid: ugcIntroController.bvid,
|
||||
showEpisodes: widget.showEpisodes,
|
||||
),
|
||||
],
|
||||
@@ -484,9 +487,9 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
Widget followButton(BuildContext context, ThemeData t) {
|
||||
return Obx(
|
||||
() {
|
||||
int attr = introController.followStatus['attribute'] ?? 0;
|
||||
int attr = ugcIntroController.followStatus['attribute'] ?? 0;
|
||||
return TextButton(
|
||||
onPressed: () => introController.actionRelationMod(context),
|
||||
onPressed: () => ugcIntroController.actionRelationMod(context),
|
||||
style: TextButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
visualDensity: const VisualDensity(vertical: -2.8),
|
||||
@@ -517,7 +520,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
BuildContext context,
|
||||
bool isLoading,
|
||||
VideoDetailData videoDetail,
|
||||
VideoIntroController videoIntroController,
|
||||
UgcIntroController ugcIntroController,
|
||||
) {
|
||||
return SizedBox(
|
||||
height: 48,
|
||||
@@ -527,19 +530,18 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
() => ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
||||
selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
|
||||
onTap: () => handleState(videoIntroController.actionLikeVideo),
|
||||
onLongPress: () =>
|
||||
handleState(videoIntroController.actionOneThree),
|
||||
selectStatus: videoIntroController.hasLike.value,
|
||||
onTap: () => handleState(ugcIntroController.actionLikeVideo),
|
||||
onLongPress: () => handleState(ugcIntroController.actionOneThree),
|
||||
selectStatus: ugcIntroController.hasLike.value,
|
||||
semanticsLabel: '点赞',
|
||||
text: !isLoading
|
||||
? NumUtil.numFormat(videoDetail.stat!.like)
|
||||
: null,
|
||||
needAnim: true,
|
||||
hasTriple:
|
||||
videoIntroController.hasLike.value &&
|
||||
videoIntroController.hasCoin &&
|
||||
videoIntroController.hasFav.value,
|
||||
ugcIntroController.hasLike.value &&
|
||||
ugcIntroController.hasCoin &&
|
||||
ugcIntroController.hasFav.value,
|
||||
callBack: (start) {
|
||||
if (start) {
|
||||
HapticFeedback.lightImpact();
|
||||
@@ -556,8 +558,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
() => ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.thumbsDown),
|
||||
selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown),
|
||||
onTap: () => handleState(videoIntroController.actionDislikeVideo),
|
||||
selectStatus: videoIntroController.hasDislike.value,
|
||||
onTap: () => handleState(ugcIntroController.actionDislikeVideo),
|
||||
selectStatus: ugcIntroController.hasDislike.value,
|
||||
semanticsLabel: '点踩',
|
||||
text: "点踩",
|
||||
),
|
||||
@@ -567,8 +569,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
key: _coinKey,
|
||||
icon: const Icon(FontAwesomeIcons.b),
|
||||
selectIcon: const Icon(FontAwesomeIcons.b),
|
||||
onTap: () => handleState(videoIntroController.actionCoinVideo),
|
||||
selectStatus: videoIntroController.hasCoin,
|
||||
onTap: () => handleState(ugcIntroController.actionCoinVideo),
|
||||
selectStatus: ugcIntroController.hasCoin,
|
||||
semanticsLabel: '投币',
|
||||
text: !isLoading
|
||||
? NumUtil.numFormat(videoDetail.stat!.coin)
|
||||
@@ -581,12 +583,12 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
key: _favKey,
|
||||
icon: const Icon(FontAwesomeIcons.star),
|
||||
selectIcon: const Icon(FontAwesomeIcons.solidStar),
|
||||
onTap: () => videoIntroController.showFavBottomSheet(context),
|
||||
onLongPress: () => videoIntroController.showFavBottomSheet(
|
||||
onTap: () => ugcIntroController.showFavBottomSheet(context),
|
||||
onLongPress: () => ugcIntroController.showFavBottomSheet(
|
||||
context,
|
||||
isLongPress: true,
|
||||
),
|
||||
selectStatus: videoIntroController.hasFav.value,
|
||||
selectStatus: ugcIntroController.hasFav.value,
|
||||
semanticsLabel: '收藏',
|
||||
text: !isLoading
|
||||
? NumUtil.numFormat(videoDetail.stat!.favorite)
|
||||
@@ -598,15 +600,15 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
() => ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.clock),
|
||||
selectIcon: const Icon(FontAwesomeIcons.solidClock),
|
||||
onTap: () => handleState(videoIntroController.viewLater),
|
||||
selectStatus: videoIntroController.hasLater.value,
|
||||
onTap: () => handleState(ugcIntroController.viewLater),
|
||||
selectStatus: ugcIntroController.hasLater.value,
|
||||
semanticsLabel: '再看',
|
||||
text: '再看',
|
||||
),
|
||||
),
|
||||
ActionItem(
|
||||
icon: const Icon(FontAwesomeIcons.shareFromSquare),
|
||||
onTap: () => videoIntroController.actionShareVideo(context),
|
||||
onTap: () => ugcIntroController.actionShareVideo(context),
|
||||
selectStatus: false,
|
||||
semanticsLabel: '分享',
|
||||
text: !isLoading
|
||||
@@ -717,7 +719,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
onTap: () {
|
||||
if (item.mid == ownerMid &&
|
||||
!isPortrait &&
|
||||
introController.horizontalMemberPage) {
|
||||
ugcIntroController.horizontalMemberPage) {
|
||||
widget.onShowMemberPage(ownerMid);
|
||||
} else {
|
||||
Get.toNamed(
|
||||
@@ -761,8 +763,9 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
right: -6,
|
||||
child: Obx(
|
||||
() =>
|
||||
introController.staffRelations['status'] == true &&
|
||||
introController.staffRelations['${item.mid}'] == null
|
||||
ugcIntroController.staffRelations['status'] == true &&
|
||||
ugcIntroController.staffRelations['${item.mid}'] ==
|
||||
null
|
||||
? Material(
|
||||
type: MaterialType.transparency,
|
||||
shape: const CircleBorder(),
|
||||
@@ -773,7 +776,8 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
mid: item.mid,
|
||||
isFollow: false,
|
||||
callback: (val) {
|
||||
introController.staffRelations['${item.mid}'] =
|
||||
ugcIntroController
|
||||
.staffRelations['${item.mid}'] =
|
||||
true;
|
||||
},
|
||||
),
|
||||
@@ -834,7 +838,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
behavior: HitTestBehavior.opaque,
|
||||
child: Obx(
|
||||
() {
|
||||
final userStat = introController.userStat.value;
|
||||
final userStat = ugcIntroController.userStat.value;
|
||||
final isVip = (userStat.card?.vip?.status ?? 0) > 0;
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -904,10 +908,10 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
color: theme.colorScheme.outline,
|
||||
semanticLabel: '无痕',
|
||||
),
|
||||
if (introController.isShowOnlineTotal)
|
||||
if (ugcIntroController.isShowOnlineTotal)
|
||||
Obx(
|
||||
() => Text(
|
||||
'${introController.total.value}人在看',
|
||||
'${ugcIntroController.total.value}人在看',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: theme.colorScheme.outline,
|
||||
@@ -926,15 +930,15 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
|
||||
label: 'AI总结',
|
||||
child: GestureDetector(
|
||||
onTap: () async {
|
||||
if (introController.aiConclusionResult == null) {
|
||||
await introController.aiConclusion();
|
||||
if (ugcIntroController.aiConclusionResult == null) {
|
||||
await ugcIntroController.aiConclusion();
|
||||
}
|
||||
if (introController.aiConclusionResult == null) {
|
||||
if (ugcIntroController.aiConclusionResult == null) {
|
||||
return;
|
||||
}
|
||||
if (introController.aiConclusionResult!.summary?.isNotEmpty ==
|
||||
if (ugcIntroController.aiConclusionResult!.summary?.isNotEmpty ==
|
||||
true ||
|
||||
introController.aiConclusionResult!.outline?.isNotEmpty ==
|
||||
ugcIntroController.aiConclusionResult!.outline?.isNotEmpty ==
|
||||
true) {
|
||||
widget.showAiBottomSheet();
|
||||
} else {
|
||||
|
||||
@@ -16,7 +16,7 @@ class PagesPanel extends StatefulWidget {
|
||||
required this.bvid,
|
||||
required this.heroTag,
|
||||
this.showEpisodes,
|
||||
required this.videoIntroController,
|
||||
required this.ugcIntroController,
|
||||
});
|
||||
|
||||
final List<Part>? list;
|
||||
@@ -25,7 +25,7 @@ class PagesPanel extends StatefulWidget {
|
||||
final String bvid;
|
||||
final String heroTag;
|
||||
final Function? showEpisodes;
|
||||
final VideoIntroController videoIntroController;
|
||||
final UgcIntroController ugcIntroController;
|
||||
|
||||
@override
|
||||
State<PagesPanel> createState() => _PagesPanelState();
|
||||
@@ -39,7 +39,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
StreamSubscription? _listener;
|
||||
|
||||
List<Part> get pages =>
|
||||
widget.list ?? widget.videoIntroController.videoDetail.value.pages!;
|
||||
widget.list ?? widget.ugcIntroController.videoDetail.value.pages!;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -48,7 +48,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
tag: widget.heroTag,
|
||||
);
|
||||
if (widget.list == null) {
|
||||
cid = widget.videoIntroController.lastPlayCid.value;
|
||||
cid = widget.ugcIntroController.cid.value;
|
||||
pageIndex = pages.indexWhere((Part e) => e.cid == cid);
|
||||
_listener = _videoDetailController.cid.listen((int cid) {
|
||||
this.cid = cid;
|
||||
@@ -156,7 +156,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
if (widget.showEpisodes == null) {
|
||||
Get.back();
|
||||
}
|
||||
widget.videoIntroController.changeSeasonOrbangu(
|
||||
widget.ugcIntroController.onChangeEpisode(
|
||||
null,
|
||||
widget.bvid,
|
||||
item.cid,
|
||||
@@ -165,7 +165,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
);
|
||||
if (widget.list != null &&
|
||||
widget
|
||||
.videoIntroController
|
||||
.ugcIntroController
|
||||
.videoDetail
|
||||
.value
|
||||
.ugcSeason !=
|
||||
|
||||
@@ -11,17 +11,17 @@ import 'package:get/get.dart';
|
||||
class SeasonPanel extends StatefulWidget {
|
||||
const SeasonPanel({
|
||||
super.key,
|
||||
required this.changeFuc,
|
||||
required this.onChangeEpisode,
|
||||
required this.heroTag,
|
||||
required this.showEpisodes,
|
||||
this.onTap,
|
||||
required this.videoIntroController,
|
||||
required this.ugcIntroController,
|
||||
});
|
||||
final Function changeFuc;
|
||||
final Function onChangeEpisode;
|
||||
final String heroTag;
|
||||
final Function showEpisodes;
|
||||
final bool? onTap;
|
||||
final VideoIntroController videoIntroController;
|
||||
final UgcIntroController ugcIntroController;
|
||||
|
||||
@override
|
||||
State<SeasonPanel> createState() => _SeasonPanelState();
|
||||
@@ -33,9 +33,9 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
||||
StreamSubscription? _listener;
|
||||
List<EpisodeItem> episodes = <EpisodeItem>[];
|
||||
|
||||
VideoIntroController get videoIntroController => widget.videoIntroController;
|
||||
UgcIntroController get ugcIntroController => widget.ugcIntroController;
|
||||
VideoDetailData get videoDetail =>
|
||||
widget.videoIntroController.videoDetail.value;
|
||||
widget.ugcIntroController.videoDetail.value;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -44,13 +44,12 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
||||
tag: widget.heroTag,
|
||||
);
|
||||
|
||||
_videoDetailController.seasonCid =
|
||||
videoIntroController.lastPlayCid.value != 0
|
||||
_videoDetailController.seasonCid = ugcIntroController.cid.value != 0
|
||||
? (videoDetail.pages?.isNotEmpty == true
|
||||
? videoDetail.isPageReversed
|
||||
? videoDetail.pages!.last.cid
|
||||
: videoDetail.pages!.first.cid
|
||||
: videoIntroController.lastPlayCid.value)
|
||||
: ugcIntroController.cid.value)
|
||||
: videoDetail.isPageReversed
|
||||
? videoDetail.pages!.last.cid
|
||||
: videoDetail.pages!.first.cid;
|
||||
|
||||
@@ -30,12 +30,12 @@ class HorizontalMemberPage extends StatefulWidget {
|
||||
super.key,
|
||||
required this.mid,
|
||||
required this.videoDetailController,
|
||||
required this.videoIntroController,
|
||||
required this.ugcIntroController,
|
||||
});
|
||||
|
||||
final dynamic mid;
|
||||
final VideoDetailController videoDetailController;
|
||||
final VideoIntroController videoIntroController;
|
||||
final UgcIntroController ugcIntroController;
|
||||
|
||||
@override
|
||||
State<HorizontalMemberPage> createState() => _HorizontalMemberPageState();
|
||||
@@ -200,8 +200,8 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
videoItem: videoItem,
|
||||
bvid: _bvid,
|
||||
onTap: () {
|
||||
final status = widget.videoIntroController
|
||||
.changeSeasonOrbangu(
|
||||
final status = widget.ugcIntroController
|
||||
.onChangeEpisode(
|
||||
null,
|
||||
videoItem.bvid,
|
||||
videoItem.cid,
|
||||
|
||||
@@ -51,6 +51,14 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
||||
double get currentPos =>
|
||||
plPlayerController.position.value.inMilliseconds / 1000;
|
||||
|
||||
final _controller = ScrollController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Scaffold(
|
||||
@@ -104,7 +112,7 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
controller: ScrollController(),
|
||||
controller: _controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(bottom: 88 + bottom),
|
||||
child: Column(
|
||||
|
||||
@@ -11,12 +11,12 @@ import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/main.dart';
|
||||
import 'package:PiliPlus/models/common/episode_panel_type.dart';
|
||||
import 'package:PiliPlus/models/common/search_type.dart';
|
||||
import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart' as pgc;
|
||||
import 'package:PiliPlus/models_new/pgc/pgc_info_model/result.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/episode.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/page.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_tag/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
||||
import 'package:PiliPlus/pages/danmaku/view.dart';
|
||||
import 'package:PiliPlus/pages/episode_panel/view.dart';
|
||||
import 'package:PiliPlus/pages/video/ai_conclusion/view.dart';
|
||||
@@ -77,12 +77,18 @@ class VideoDetailPageV extends StatefulWidget {
|
||||
|
||||
class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
with TickerProviderStateMixin, RouteAware, WidgetsBindingObserver {
|
||||
late VideoDetailController videoDetailController;
|
||||
late VideoReplyController _videoReplyController;
|
||||
late final VideoDetailController videoDetailController;
|
||||
late final VideoReplyController _videoReplyController;
|
||||
PlPlayerController? plPlayerController;
|
||||
late VideoIntroController videoIntroController;
|
||||
late PgcIntroController pgcIntroController;
|
||||
late final _introController = ScrollController();
|
||||
late final CommonIntroController introController = videoDetailController.isUgc
|
||||
? ugcIntroController
|
||||
: pgcIntroController;
|
||||
late final UgcIntroController ugcIntroController;
|
||||
late final PgcIntroController pgcIntroController;
|
||||
ScrollController? _introScrollController;
|
||||
ScrollController get introScrollController =>
|
||||
_introScrollController ??= ScrollController();
|
||||
|
||||
late String heroTag;
|
||||
|
||||
bool get autoExitFullscreen =>
|
||||
@@ -100,7 +106,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
bool get isFullScreen => plPlayerController?.isFullScreen.value ?? false;
|
||||
|
||||
bool get _shouldShowSeasonPanel {
|
||||
late final videoDetail = videoIntroController.videoDetail.value;
|
||||
if (!videoDetailController.isUgc) {
|
||||
return false;
|
||||
}
|
||||
late final videoDetail = ugcIntroController.videoDetail.value;
|
||||
return videoDetailController.plPlayerController.horizontalSeasonPanel &&
|
||||
(videoDetail.ugcSeason != null ||
|
||||
((videoDetail.pages?.length ?? 0) > 1)) &&
|
||||
@@ -135,8 +144,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
tag: heroTag,
|
||||
);
|
||||
}
|
||||
videoIntroController = Get.put(VideoIntroController(), tag: heroTag);
|
||||
if (videoDetailController.videoType == SearchType.media_bangumi) {
|
||||
if (videoDetailController.isUgc) {
|
||||
ugcIntroController = Get.put(UgcIntroController(), tag: heroTag);
|
||||
} else {
|
||||
pgcIntroController = Get.put(PgcIntroController(), tag: heroTag);
|
||||
}
|
||||
|
||||
@@ -180,7 +190,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.resumed) {
|
||||
videoIntroController.startTimer();
|
||||
introController.startTimer();
|
||||
videoDetailController.plPlayerController.showDanmaku = true;
|
||||
|
||||
// 修复从后台恢复时全屏状态下屏幕方向错误的问题
|
||||
@@ -200,7 +210,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
});
|
||||
}
|
||||
} else if (state == AppLifecycleState.paused) {
|
||||
videoIntroController.canelTimer();
|
||||
introController.canelTimer();
|
||||
videoDetailController.plPlayerController.showDanmaku = false;
|
||||
}
|
||||
}
|
||||
@@ -256,11 +266,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
/// 顺序播放 列表循环
|
||||
if (plPlayerController!.playRepeat != PlayRepeat.pause &&
|
||||
plPlayerController!.playRepeat != PlayRepeat.singleCycle) {
|
||||
if (videoDetailController.isPlayAll ||
|
||||
videoDetailController.videoType == SearchType.video) {
|
||||
notExitFlag = videoIntroController.nextPlay();
|
||||
} else if (videoDetailController.videoType ==
|
||||
SearchType.media_bangumi) {
|
||||
if (videoDetailController.isUgc) {
|
||||
notExitFlag = ugcIntroController.nextPlay();
|
||||
} else {
|
||||
notExitFlag = pgcIntroController.nextPlay();
|
||||
}
|
||||
}
|
||||
@@ -346,10 +354,16 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
ScreenBrightness.instance.resetApplicationScreenBrightness();
|
||||
PlPlayerController.setPlayCallBack(null);
|
||||
}
|
||||
videoDetailController.positionSubscription?.cancel();
|
||||
videoIntroController.canelTimer();
|
||||
videoIntroController.videoDetail.close();
|
||||
videoDetailController.cid.close();
|
||||
videoDetailController
|
||||
..positionSubscription?.cancel()
|
||||
..cid.close();
|
||||
if (videoDetailController.isUgc) {
|
||||
ugcIntroController
|
||||
..canelTimer()
|
||||
..videoDetail.close();
|
||||
} else {
|
||||
pgcIntroController.canelTimer();
|
||||
}
|
||||
if (!videoDetailController.horizontalScreen) {
|
||||
AutoOrientation.portraitUpMode();
|
||||
}
|
||||
@@ -359,14 +373,16 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
}
|
||||
if (plPlayerController != null) {
|
||||
videoDetailController.makeHeartBeat();
|
||||
plPlayerController!.removeStatusLister(playerListener);
|
||||
plPlayerController!.removePositionListener(positionListener);
|
||||
plPlayerController!.dispose();
|
||||
plPlayerController!
|
||||
..removeStatusLister(playerListener)
|
||||
..removePositionListener(positionListener)
|
||||
..dispose();
|
||||
} else {
|
||||
PlPlayerController.updatePlayCount();
|
||||
}
|
||||
VideoDetailPageV.routeObserver.unsubscribe(this);
|
||||
showStatusBar();
|
||||
_introScrollController?.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@@ -382,7 +398,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
ScreenBrightness.instance.resetApplicationScreenBrightness();
|
||||
|
||||
videoDetailController.positionSubscription?.cancel();
|
||||
videoIntroController.canelTimer();
|
||||
|
||||
introController.canelTimer();
|
||||
|
||||
videoDetailController
|
||||
..playerStatus = plPlayerController?.playerStatus.status.value
|
||||
@@ -416,7 +433,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
|
||||
isShowing = true;
|
||||
PlPlayerController.setPlayCallBack(playCallBack);
|
||||
videoIntroController.startTimer();
|
||||
|
||||
introController.startTimer();
|
||||
|
||||
if (mounted) {
|
||||
if (videoDetailController.brightness != null) {
|
||||
plPlayerController?.setCurrBrightness(
|
||||
@@ -769,11 +788,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
.colorScheme
|
||||
.onSurface,
|
||||
),
|
||||
onSelected: (String type) async {
|
||||
onSelected: (String type) {
|
||||
switch (type) {
|
||||
case 'later':
|
||||
await videoIntroController
|
||||
.viewLater();
|
||||
introController.viewLater();
|
||||
break;
|
||||
case 'report':
|
||||
if (!Accounts.main.isLogin) {
|
||||
@@ -1127,7 +1145,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
buildTabbar(
|
||||
introText: '相关视频',
|
||||
showIntro:
|
||||
videoDetailController.videoType == SearchType.video &&
|
||||
videoDetailController.isUgc &&
|
||||
videoDetailController
|
||||
.plPlayerController
|
||||
.showRelatedVideo,
|
||||
@@ -1137,13 +1155,12 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
child: videoTabBarView(
|
||||
controller: videoDetailController.tabCtr,
|
||||
children: [
|
||||
if (videoDetailController.videoType ==
|
||||
SearchType.video &&
|
||||
if (videoDetailController.isUgc &&
|
||||
videoDetailController
|
||||
.plPlayerController
|
||||
.showRelatedVideo)
|
||||
CustomScrollView(
|
||||
controller: _introController,
|
||||
controller: introScrollController,
|
||||
slivers: [
|
||||
RelatedVideoPanel(
|
||||
key: relatedVideoPanelKey,
|
||||
@@ -1215,14 +1232,12 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
key: Key(heroTag),
|
||||
plPlayerController: plPlayerController!,
|
||||
videoDetailController: videoDetailController,
|
||||
videoIntroController:
|
||||
videoDetailController.videoType == SearchType.video
|
||||
? videoIntroController
|
||||
: null,
|
||||
pgcIntroController:
|
||||
videoDetailController.videoType == SearchType.media_bangumi
|
||||
? pgcIntroController
|
||||
ugcIntroController: videoDetailController.isUgc
|
||||
? ugcIntroController
|
||||
: null,
|
||||
pgcIntroController: videoDetailController.isUgc
|
||||
? null
|
||||
: pgcIntroController,
|
||||
headerControl: HeaderControl(
|
||||
controller: plPlayerController!,
|
||||
videoDetailCtr: videoDetailController,
|
||||
@@ -1232,11 +1247,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
? null
|
||||
: Obx(
|
||||
() => PlDanmaku(
|
||||
key: Key(
|
||||
videoDetailController.danmakuCid.value.toString(),
|
||||
),
|
||||
key: Key(videoDetailController.cid.value.toString()),
|
||||
isPipMode: true,
|
||||
cid: videoDetailController.danmakuCid.value,
|
||||
cid: videoDetailController.cid.value,
|
||||
playerController: plPlayerController!,
|
||||
),
|
||||
),
|
||||
@@ -1321,10 +1334,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
),
|
||||
],
|
||||
),
|
||||
onSelected: (String type) async {
|
||||
onSelected: (String type) {
|
||||
switch (type) {
|
||||
case 'later':
|
||||
await videoIntroController.viewLater();
|
||||
introController.viewLater();
|
||||
break;
|
||||
case 'report':
|
||||
if (!Accounts.main.isLogin) {
|
||||
@@ -1400,14 +1413,12 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
key: Key(heroTag),
|
||||
plPlayerController: plPlayerController!,
|
||||
videoDetailController: videoDetailController,
|
||||
videoIntroController:
|
||||
videoDetailController.videoType == SearchType.video
|
||||
? videoIntroController
|
||||
: null,
|
||||
pgcIntroController:
|
||||
videoDetailController.videoType == SearchType.media_bangumi
|
||||
? pgcIntroController
|
||||
ugcIntroController: videoDetailController.isUgc
|
||||
? ugcIntroController
|
||||
: null,
|
||||
pgcIntroController: videoDetailController.isUgc
|
||||
? null
|
||||
: pgcIntroController,
|
||||
headerControl: HeaderControl(
|
||||
key: videoDetailController.headerCtrKey,
|
||||
controller: videoDetailController.plPlayerController,
|
||||
@@ -1416,8 +1427,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
),
|
||||
danmuWidget: Obx(
|
||||
() => PlDanmaku(
|
||||
key: Key(videoDetailController.danmakuCid.value.toString()),
|
||||
cid: videoDetailController.danmakuCid.value,
|
||||
key: Key(videoDetailController.cid.value.toString()),
|
||||
cid: videoDetailController.cid.value,
|
||||
playerController: plPlayerController!,
|
||||
),
|
||||
),
|
||||
@@ -1507,7 +1518,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
}
|
||||
String text = tabs[value];
|
||||
if (text == '简介' || text == '相关视频') {
|
||||
_introController.animToTop();
|
||||
_introScrollController?.animToTop();
|
||||
} else if (text.startsWith('评论')) {
|
||||
_videoReplyController.animateToTop();
|
||||
}
|
||||
@@ -1759,7 +1770,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: () {
|
||||
videoIntroController.changeSeasonOrbangu(
|
||||
ugcIntroController.onChangeEpisode(
|
||||
null,
|
||||
videoDetailController.bvid,
|
||||
item.cid,
|
||||
@@ -1795,13 +1806,13 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
final bottom = MediaQuery.paddingOf(context).bottom;
|
||||
Widget introPanel() => CustomScrollView(
|
||||
key: const PageStorageKey<String>('简介'),
|
||||
controller: needCtr ? _introController : null,
|
||||
controller: needCtr ? introScrollController : null,
|
||||
physics: !needCtr
|
||||
? const AlwaysScrollableScrollPhysics(parent: ClampingScrollPhysics())
|
||||
: null,
|
||||
slivers: [
|
||||
if (videoDetailController.videoType == SearchType.video) ...[
|
||||
VideoIntroPanel(
|
||||
if (videoDetailController.isUgc) ...[
|
||||
UgcIntroPanel(
|
||||
key: ugcPanelKey,
|
||||
heroTag: heroTag,
|
||||
showAiBottomSheet: showAiBottomSheet,
|
||||
@@ -1828,7 +1839,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
height: bottom + StyleString.safeSpace,
|
||||
),
|
||||
),
|
||||
] else if (videoDetailController.videoType == SearchType.media_bangumi)
|
||||
] else
|
||||
Obx(
|
||||
() => PgcIntroPage(
|
||||
key: pgcPanelKey,
|
||||
@@ -1901,7 +1912,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
}
|
||||
|
||||
Widget get seasonPanel {
|
||||
final videoDetail = videoIntroController.videoDetail.value;
|
||||
final videoDetail = ugcIntroController.videoDetail.value;
|
||||
return Column(
|
||||
children: [
|
||||
if ((videoDetail.pages?.length ?? 0) > 1)
|
||||
@@ -1910,8 +1921,8 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: PagesPanel(
|
||||
heroTag: heroTag,
|
||||
videoIntroController: videoIntroController,
|
||||
bvid: videoIntroController.bvid,
|
||||
ugcIntroController: ugcIntroController,
|
||||
bvid: ugcIntroController.bvid,
|
||||
showEpisodes: showEpisodes,
|
||||
),
|
||||
)
|
||||
@@ -1921,7 +1932,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
() => EpisodePanel(
|
||||
heroTag: heroTag,
|
||||
enableSlide: false,
|
||||
videoIntroController: videoIntroController,
|
||||
ugcIntroController: videoDetailController.isUgc
|
||||
? ugcIntroController
|
||||
: null,
|
||||
type: EpisodeType.part,
|
||||
list: [videoDetail.pages!],
|
||||
cover: videoDetailController.cover.value,
|
||||
@@ -1929,15 +1942,11 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
aid: IdUtils.bv2av(videoDetailController.bvid),
|
||||
cid: videoDetailController.cid.value,
|
||||
isReversed: videoDetail.isPageReversed,
|
||||
changeFucCall:
|
||||
videoDetailController.videoType ==
|
||||
SearchType.media_bangumi
|
||||
? pgcIntroController.changeSeasonOrbangu
|
||||
: videoIntroController.changeSeasonOrbangu,
|
||||
onChangeEpisode: videoDetailController.isUgc
|
||||
? ugcIntroController.onChangeEpisode
|
||||
: pgcIntroController.onChangeEpisode,
|
||||
showTitle: false,
|
||||
isSupportReverse:
|
||||
videoDetailController.videoType !=
|
||||
SearchType.media_bangumi,
|
||||
isSupportReverse: videoDetailController.isUgc,
|
||||
onReverse: () => onReversePlay(
|
||||
bvid: videoDetailController.bvid,
|
||||
aid: IdUtils.bv2av(videoDetailController.bvid),
|
||||
@@ -1959,9 +1968,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
child: SeasonPanel(
|
||||
heroTag: heroTag,
|
||||
onTap: false,
|
||||
changeFuc: videoIntroController.changeSeasonOrbangu,
|
||||
onChangeEpisode: ugcIntroController.onChangeEpisode,
|
||||
showEpisodes: showEpisodes,
|
||||
videoIntroController: videoIntroController,
|
||||
ugcIntroController: ugcIntroController,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
@@ -1969,7 +1978,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
() => EpisodePanel(
|
||||
heroTag: heroTag,
|
||||
enableSlide: false,
|
||||
videoIntroController: videoIntroController,
|
||||
ugcIntroController: videoDetailController.isUgc
|
||||
? ugcIntroController
|
||||
: null,
|
||||
type: EpisodeType.season,
|
||||
initialTabIndex: videoDetailController.seasonIndex.value,
|
||||
cover: videoDetailController.cover.value,
|
||||
@@ -1978,19 +1989,17 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
bvid: videoDetailController.bvid,
|
||||
aid: IdUtils.bv2av(videoDetailController.bvid),
|
||||
cid: videoDetailController.seasonCid ?? 0,
|
||||
isReversed: videoIntroController
|
||||
isReversed: ugcIntroController
|
||||
.videoDetail
|
||||
.value
|
||||
.ugcSeason!
|
||||
.sections![videoDetailController.seasonIndex.value]
|
||||
.isReversed,
|
||||
changeFucCall:
|
||||
videoDetailController.videoType == SearchType.media_bangumi
|
||||
? pgcIntroController.changeSeasonOrbangu
|
||||
: videoIntroController.changeSeasonOrbangu,
|
||||
onChangeEpisode: videoDetailController.isUgc
|
||||
? ugcIntroController.onChangeEpisode
|
||||
: pgcIntroController.onChangeEpisode,
|
||||
showTitle: false,
|
||||
isSupportReverse:
|
||||
videoDetailController.videoType != SearchType.media_bangumi,
|
||||
isSupportReverse: videoDetailController.isUgc,
|
||||
onReverse: () => onReversePlay(
|
||||
bvid: videoDetailController.bvid,
|
||||
aid: IdUtils.bv2av(videoDetailController.bvid),
|
||||
@@ -2051,7 +2060,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||
backgroundColor: Colors.transparent,
|
||||
(context) =>
|
||||
AiConclusionPanel(item: videoIntroController.aiConclusionResult!),
|
||||
AiConclusionPanel(item: ugcIntroController.aiConclusionResult!),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2075,7 +2084,9 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
}
|
||||
Widget listSheetContent([bool? enableSlide]) => EpisodePanel(
|
||||
heroTag: heroTag,
|
||||
videoIntroController: videoIntroController,
|
||||
ugcIntroController: videoDetailController.isUgc
|
||||
? ugcIntroController
|
||||
: null,
|
||||
type: season != null
|
||||
? EpisodeType.season
|
||||
: episodes is List<Part>
|
||||
@@ -2089,21 +2100,20 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
cid: cid,
|
||||
seasonId: season?.id,
|
||||
list: season != null ? season.sections : [episodes],
|
||||
isReversed: videoDetailController.videoType == SearchType.media_bangumi
|
||||
isReversed: !videoDetailController.isUgc
|
||||
? null
|
||||
: season != null
|
||||
? videoIntroController
|
||||
? ugcIntroController
|
||||
.videoDetail
|
||||
.value
|
||||
.ugcSeason!
|
||||
.sections![videoDetailController.seasonIndex.value]
|
||||
.isReversed
|
||||
: videoIntroController.videoDetail.value.isPageReversed,
|
||||
isSupportReverse:
|
||||
videoDetailController.videoType != SearchType.media_bangumi,
|
||||
changeFucCall: videoDetailController.videoType == SearchType.media_bangumi
|
||||
? pgcIntroController.changeSeasonOrbangu
|
||||
: videoIntroController.changeSeasonOrbangu,
|
||||
: ugcIntroController.videoDetail.value.isPageReversed,
|
||||
isSupportReverse: videoDetailController.isUgc,
|
||||
onChangeEpisode: videoDetailController.isUgc
|
||||
? ugcIntroController.onChangeEpisode
|
||||
: pgcIntroController.onChangeEpisode,
|
||||
onClose: Get.back,
|
||||
onReverse: () {
|
||||
Get.back();
|
||||
@@ -2143,10 +2153,10 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
return;
|
||||
}
|
||||
|
||||
void changeEpisode(episode) {
|
||||
void onChangeEpisode(episode) {
|
||||
final isEpisode = episode is BaseEpisodeItem;
|
||||
final isPgc = episode is pgc.EpisodeItem;
|
||||
videoIntroController.changeSeasonOrbangu(
|
||||
ugcIntroController.onChangeEpisode(
|
||||
isPgc ? episode.epId : null,
|
||||
isEpisode ? episode.bvid : bvid,
|
||||
episode.cid,
|
||||
@@ -2159,7 +2169,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
);
|
||||
}
|
||||
|
||||
final videoDetail = videoIntroController.videoDetail.value;
|
||||
final videoDetail = ugcIntroController.videoDetail.value;
|
||||
if (isSeason) {
|
||||
// reverse season
|
||||
final item = videoDetail
|
||||
@@ -2176,7 +2186,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
..cid.refresh();
|
||||
} else {
|
||||
// switch to first episode
|
||||
var episode = videoIntroController
|
||||
var episode = ugcIntroController
|
||||
.videoDetail
|
||||
.value
|
||||
.ugcSeason!
|
||||
@@ -2184,7 +2194,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
.episodes!
|
||||
.first;
|
||||
if (episode.cid != videoDetailController.cid.value) {
|
||||
changeEpisode(episode);
|
||||
onChangeEpisode(episode);
|
||||
videoDetailController.seasonCid = episode.cid;
|
||||
} else {
|
||||
videoDetailController
|
||||
@@ -2204,7 +2214,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
// switch to first episode
|
||||
var episode = videoDetail.pages!.first;
|
||||
if (episode.cid != videoDetailController.cid.value) {
|
||||
changeEpisode(episode);
|
||||
onChangeEpisode(episode);
|
||||
} else {
|
||||
videoDetailController.cid.refresh();
|
||||
}
|
||||
@@ -2264,7 +2274,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
||||
return HorizontalMemberPage(
|
||||
mid: mid,
|
||||
videoDetailController: videoDetailController,
|
||||
videoIntroController: videoIntroController,
|
||||
ugcIntroController: ugcIntroController,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -32,6 +32,14 @@ class _ViewPointsPageState
|
||||
|
||||
int currentIndex = -1;
|
||||
|
||||
final _controller = ScrollController();
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Scaffold(
|
||||
@@ -92,7 +100,7 @@ class _ViewPointsPageState
|
||||
color: theme.dividerColor.withValues(alpha: 0.1),
|
||||
);
|
||||
return ListView.separated(
|
||||
controller: ScrollController(),
|
||||
controller: _controller,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
|
||||
@@ -4,13 +4,13 @@ import 'dart:math';
|
||||
|
||||
import 'package:PiliPlus/common/widgets/button/icon_button.dart';
|
||||
import 'package:PiliPlus/common/widgets/custom_icon.dart';
|
||||
import 'package:PiliPlus/models/common/search_type.dart';
|
||||
import 'package:PiliPlus/models/common/super_resolution_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/audio_quality.dart';
|
||||
import 'package:PiliPlus/models/common/video/cdn_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_decode_type.dart';
|
||||
import 'package:PiliPlus/models/common/video/video_quality.dart';
|
||||
import 'package:PiliPlus/models/video/play/url.dart';
|
||||
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/select_dialog.dart';
|
||||
import 'package:PiliPlus/pages/setting/widgets/switch_item.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
@@ -64,12 +64,17 @@ class HeaderControl extends StatefulWidget {
|
||||
}
|
||||
|
||||
class HeaderControlState extends State<HeaderControl> {
|
||||
PlayUrlModel get videoInfo => videoDetailCtr.data;
|
||||
late final PlPlayerController plPlayerController = widget.controller;
|
||||
late final VideoDetailController videoDetailCtr = widget.videoDetailCtr;
|
||||
late final PlayUrlModel videoInfo = videoDetailCtr.data;
|
||||
static const TextStyle subTitleStyle = TextStyle(fontSize: 12);
|
||||
static const TextStyle titleStyle = TextStyle(fontSize: 14);
|
||||
String get heroTag => widget.heroTag;
|
||||
late VideoIntroController videoIntroController;
|
||||
late PgcIntroController pgcIntroController;
|
||||
late final UgcIntroController ugcIntroController;
|
||||
late final PgcIntroController pgcIntroController;
|
||||
late final CommonIntroController introController = videoDetailCtr.isUgc
|
||||
? ugcIntroController
|
||||
: pgcIntroController;
|
||||
bool get horizontalScreen => videoDetailCtr.horizontalScreen;
|
||||
RxString now = ''.obs;
|
||||
Timer? clock;
|
||||
@@ -78,14 +83,12 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
late final _coinKey = GlobalKey<ActionItemState>();
|
||||
late final _favKey = GlobalKey<ActionItemState>();
|
||||
|
||||
PlPlayerController get plPlayerController => widget.controller;
|
||||
VideoDetailController get videoDetailCtr => widget.videoDetailCtr;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
videoIntroController = Get.find<VideoIntroController>(tag: heroTag);
|
||||
if (videoDetailCtr.videoType != SearchType.video) {
|
||||
if (videoDetailCtr.isUgc) {
|
||||
ugcIntroController = Get.find<UgcIntroController>(tag: heroTag);
|
||||
} else {
|
||||
pgcIntroController = Get.find<PgcIntroController>(tag: heroTag);
|
||||
}
|
||||
}
|
||||
@@ -130,7 +133,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Get.back();
|
||||
videoIntroController.viewLater();
|
||||
introController.viewLater();
|
||||
},
|
||||
leading: const Icon(Icons.watch_later_outlined, size: 20),
|
||||
title: const Text('添加至「稍后再看」', style: titleStyle),
|
||||
@@ -874,7 +877,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
);
|
||||
if (res.statusCode == 200) {
|
||||
final name =
|
||||
'${videoIntroController.videoDetail.value.title}-${videoDetailCtr.bvid}-${videoDetailCtr.cid.value}-${item.lanDoc}.json';
|
||||
'${introController.videoDetail.value.title}-${videoDetailCtr.bvid}-${videoDetailCtr.cid.value}-${item.lanDoc}.json';
|
||||
try {
|
||||
DocumentFileSavePlusPlatform.instance
|
||||
.saveMultipleFiles(
|
||||
@@ -1897,7 +1900,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
},
|
||||
),
|
||||
),
|
||||
if ((videoIntroController.videoDetail.value.title != null) &&
|
||||
if ((introController.videoDetail.value.title != null) &&
|
||||
(isFullScreen ||
|
||||
(!isFullScreen &&
|
||||
!horizontalScreen &&
|
||||
@@ -1914,7 +1917,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
() {
|
||||
String title;
|
||||
final videoDetail =
|
||||
videoIntroController.videoDetail.value;
|
||||
introController.videoDetail.value;
|
||||
if (videoDetail.videos == 1) {
|
||||
title = videoDetail.title!;
|
||||
} else {
|
||||
@@ -1984,10 +1987,10 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
);
|
||||
},
|
||||
),
|
||||
if (videoIntroController.isShowOnlineTotal)
|
||||
if (introController.isShowOnlineTotal)
|
||||
Obx(
|
||||
() => Text(
|
||||
'${videoIntroController.total.value}人正在看',
|
||||
'${introController.total.value}人正在看',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 11,
|
||||
@@ -2226,7 +2229,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
? Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (videoDetailCtr.videoType == SearchType.video) ...[
|
||||
if (videoDetailCtr.isUgc) ...[
|
||||
SizedBox(
|
||||
width: 42,
|
||||
height: 34,
|
||||
@@ -2240,20 +2243,20 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
selectIcon: const Icon(
|
||||
FontAwesomeIcons.solidThumbsUp,
|
||||
),
|
||||
onTap: videoIntroController.actionLikeVideo,
|
||||
onTap: ugcIntroController.actionLikeVideo,
|
||||
onLongPress: () {
|
||||
videoIntroController.actionOneThree();
|
||||
ugcIntroController.actionOneThree();
|
||||
plPlayerController
|
||||
..isTriple = null
|
||||
..hideTaskControls();
|
||||
},
|
||||
selectStatus: videoIntroController.hasLike.value,
|
||||
selectStatus: ugcIntroController.hasLike.value,
|
||||
semanticsLabel: '点赞',
|
||||
needAnim: true,
|
||||
hasTriple:
|
||||
videoIntroController.hasLike.value &&
|
||||
videoIntroController.hasCoin &&
|
||||
videoIntroController.hasFav.value,
|
||||
ugcIntroController.hasLike.value &&
|
||||
ugcIntroController.hasCoin &&
|
||||
ugcIntroController.hasFav.value,
|
||||
callBack: (start) {
|
||||
if (start) {
|
||||
HapticFeedback.lightImpact();
|
||||
@@ -2284,8 +2287,8 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
selectIcon: const Icon(
|
||||
FontAwesomeIcons.solidThumbsDown,
|
||||
),
|
||||
onTap: videoIntroController.actionDislikeVideo,
|
||||
selectStatus: videoIntroController.hasDislike.value,
|
||||
onTap: ugcIntroController.actionDislikeVideo,
|
||||
selectStatus: ugcIntroController.hasDislike.value,
|
||||
semanticsLabel: '点踩',
|
||||
),
|
||||
),
|
||||
@@ -2302,8 +2305,8 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
color: Colors.white,
|
||||
),
|
||||
selectIcon: const Icon(FontAwesomeIcons.b),
|
||||
onTap: videoIntroController.actionCoinVideo,
|
||||
selectStatus: videoIntroController.hasCoin,
|
||||
onTap: ugcIntroController.actionCoinVideo,
|
||||
selectStatus: ugcIntroController.hasCoin,
|
||||
semanticsLabel: '投币',
|
||||
needAnim: true,
|
||||
),
|
||||
@@ -2321,11 +2324,11 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
color: Colors.white,
|
||||
),
|
||||
selectIcon: const Icon(FontAwesomeIcons.solidStar),
|
||||
onTap: () => videoIntroController
|
||||
.showFavBottomSheet(context),
|
||||
onLongPress: () => videoIntroController
|
||||
onTap: () =>
|
||||
ugcIntroController.showFavBottomSheet(context),
|
||||
onLongPress: () => ugcIntroController
|
||||
.showFavBottomSheet(context, isLongPress: true),
|
||||
selectStatus: videoIntroController.hasFav.value,
|
||||
selectStatus: ugcIntroController.hasFav.value,
|
||||
semanticsLabel: '收藏',
|
||||
needAnim: true,
|
||||
),
|
||||
@@ -2341,7 +2344,7 @@ class HeaderControlState extends State<HeaderControl> {
|
||||
color: Colors.white,
|
||||
),
|
||||
onTap: () =>
|
||||
videoIntroController.actionShareVideo(context),
|
||||
ugcIntroController.actionShareVideo(context),
|
||||
semanticsLabel: '分享',
|
||||
),
|
||||
),
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:PiliPlus/models_new/video/video_detail/episode.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/page.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_detail/section.dart';
|
||||
import 'package:PiliPlus/models_new/video/video_shot/data.dart';
|
||||
import 'package:PiliPlus/pages/common/common_intro_controller.dart';
|
||||
import 'package:PiliPlus/pages/video/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/pgc/controller.dart';
|
||||
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
|
||||
@@ -48,7 +49,7 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
const PLVideoPlayer({
|
||||
required this.plPlayerController,
|
||||
this.videoDetailController,
|
||||
this.videoIntroController,
|
||||
this.ugcIntroController,
|
||||
this.pgcIntroController,
|
||||
required this.headerControl,
|
||||
this.bottomControl,
|
||||
@@ -64,7 +65,7 @@ class PLVideoPlayer extends StatefulWidget {
|
||||
|
||||
final PlPlayerController plPlayerController;
|
||||
final VideoDetailController? videoDetailController;
|
||||
final VideoIntroController? videoIntroController;
|
||||
final UgcIntroController? ugcIntroController;
|
||||
final PgcIntroController? pgcIntroController;
|
||||
final Widget headerControl;
|
||||
final Widget? bottomControl;
|
||||
@@ -86,8 +87,12 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController animationController;
|
||||
late VideoController videoController;
|
||||
VideoIntroController? videoIntroController;
|
||||
UgcIntroController? ugcIntroController;
|
||||
PgcIntroController? pgcIntroController;
|
||||
late final CommonIntroController introController =
|
||||
widget.videoDetailController!.isUgc
|
||||
? ugcIntroController!
|
||||
: pgcIntroController!;
|
||||
|
||||
final GlobalKey _playerKey = GlobalKey();
|
||||
final GlobalKey<VideoState> key = GlobalKey<VideoState>();
|
||||
@@ -170,7 +175,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
duration: const Duration(milliseconds: 100),
|
||||
);
|
||||
videoController = plPlayerController.videoController!;
|
||||
videoIntroController = widget.videoIntroController;
|
||||
ugcIntroController = widget.ugcIntroController;
|
||||
pgcIntroController = widget.pgcIntroController;
|
||||
Future.microtask(() async {
|
||||
try {
|
||||
@@ -250,9 +255,9 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
// 动态构建底部控制条
|
||||
Widget buildBottomControl() {
|
||||
final videoDetail = videoIntroController?.videoDetail.value;
|
||||
bool isSeason = videoDetail?.ugcSeason != null;
|
||||
bool isPage = videoDetail?.pages != null && videoDetail!.pages!.length > 1;
|
||||
final videoDetail = introController.videoDetail.value;
|
||||
bool isSeason = videoDetail.ugcSeason != null;
|
||||
bool isPage = videoDetail.pages != null && videoDetail.pages!.length > 1;
|
||||
bool isPgc = pgcIntroController != null;
|
||||
bool anySeason = isSeason || isPage || isPgc;
|
||||
double widgetWidth = isFullScreen && context.isLandscape ? 42 : 35;
|
||||
@@ -270,14 +275,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
color: Colors.white,
|
||||
),
|
||||
onTap: () {
|
||||
bool? res;
|
||||
if (videoIntroController != null) {
|
||||
res = videoIntroController!.prevPlay();
|
||||
}
|
||||
if (pgcIntroController != null) {
|
||||
res = pgcIntroController!.prevPlay();
|
||||
}
|
||||
if (res == false) {
|
||||
if (!introController.prevPlay()) {
|
||||
SmartDialog.showToast('已经是第一集了');
|
||||
}
|
||||
},
|
||||
@@ -302,14 +300,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
color: Colors.white,
|
||||
),
|
||||
onTap: () {
|
||||
bool? res;
|
||||
if (videoIntroController != null) {
|
||||
res = videoIntroController!.nextPlay();
|
||||
}
|
||||
if (pgcIntroController != null) {
|
||||
res = pgcIntroController!.nextPlay();
|
||||
}
|
||||
if (res == false) {
|
||||
if (!introController.nextPlay()) {
|
||||
SmartDialog.showToast('已经是最后一集了');
|
||||
}
|
||||
},
|
||||
@@ -477,7 +468,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
int currentCid = plPlayerController.cid;
|
||||
String bvid = plPlayerController.bvid;
|
||||
List episodes = [];
|
||||
final videoDetail = videoIntroController!.videoDetail.value;
|
||||
final videoDetail = introController.videoDetail.value;
|
||||
if (isSeason) {
|
||||
final List<SectionItem> sections =
|
||||
videoDetail.ugcSeason!.sections!;
|
||||
|
||||
Reference in New Issue
Block a user