refa: pgc intro

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-11 14:32:00 +08:00
parent 6748a20ddb
commit 2f3f712256
8 changed files with 346 additions and 648 deletions

View File

@@ -3,13 +3,10 @@ import 'dart:convert';
import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/search.dart';
import 'package:PiliPlus/http/user.dart';
import 'package:PiliPlus/http/video.dart';
import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/models/user/fav_folder.dart';
import 'package:PiliPlus/pages/common/common_data_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';
@@ -28,8 +25,7 @@ import 'package:get/get.dart';
import 'package:html/dom.dart' as dom;
import 'package:html/parser.dart' as html_parser;
class BangumiIntroController
extends CommonDataController<BangumiInfoModel, BangumiInfoModel> {
class BangumiIntroController extends GetxController {
// 视频bvid
String bvid = Get.parameters['bvid'] ?? '';
var seasonId = Get.parameters['seasonId'] != null
@@ -44,15 +40,7 @@ class BangumiIntroController
? '追番'
: '追剧';
// 是否预渲染 骨架屏
bool preRender = false;
// 视频详情 上个页面传入
Map? videoItem = {};
BangumiInfoModel? bangumiItem;
// up主粉丝数
Map userStat = {'follower': '-'};
BangumiInfoModel bangumiItem = Get.arguments['bangumiItem'];
// 是否点赞
RxBool hasLike = false.obs;
@@ -62,11 +50,14 @@ class BangumiIntroController
bool get hasCoin => _coinNum.value != 0;
// 是否收藏
RxBool hasFav = false.obs;
dynamic videoTags;
bool isLogin = false;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
List? favIds;
dynamic userInfo;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
bool isLogin = Accounts.main.isLogin;
int mid = Accounts.main.mid;
late final enableQuickFav =
GStorage.setting.get(SettingBoxKey.enableQuickFav, defaultValue: false);
@@ -74,30 +65,15 @@ class BangumiIntroController
@override
void onInit() {
super.onInit();
if (Get.arguments.isNotEmpty as bool) {
if (Get.arguments.containsKey('bangumiItem') as bool) {
preRender = true;
bangumiItem = Get.arguments['bangumiItem'];
}
}
userInfo = GStorage.userInfo.get('userInfoCache');
isLogin = userInfo != null;
if (isLogin && epId != null) {
queryBangumiLikeCoinFav();
}
queryData();
if (isLogin && seasonId != null) {
if (isLogin) {
if (seasonId != null) {
queryIsFollowed();
}
if (epId != null) {
queryBangumiLikeCoinFav();
}
@override
Future<void> queryData([bool isRefresh = true]) async {
await queryVideoTags();
return super.queryData(isRefresh);
}
queryVideoTags();
}
Future<void> queryVideoTags() async {
@@ -107,18 +83,6 @@ class BangumiIntroController
}
}
@override
bool customHandleResponse(
bool isRefresh, Success<BangumiInfoModel> response) {
epId ??= response.response.episodes?.firstOrNull?.id;
loadingState.value = response;
return true;
}
@override
Future<LoadingState<BangumiInfoModel>> customGetData() =>
SearchHttp.bangumiInfoNew(seasonId: seasonId, epId: epId);
// 获取点赞/投币/收藏状态
Future<void> queryBangumiLikeCoinFav() async {
var result = await VideoHttp.bangumiLikeCoinFav(epId: epId);
@@ -136,9 +100,8 @@ class BangumiIntroController
var result = await VideoHttp.likeVideo(bvid: bvid, type: !hasLike.value);
if (result['status']) {
SmartDialog.showToast(!hasLike.value ? result['data']['toast'] : '取消赞');
BangumiInfoModel bangumiDetail = (loadingState.value as Success).response;
bangumiDetail.stat!['likes'] =
bangumiDetail.stat!['likes'] + (!hasLike.value ? 1 : -1);
bangumiItem.stat!['likes'] =
bangumiItem.stat!['likes'] + (!hasLike.value ? 1 : -1);
hasLike.value = !hasLike.value;
} else {
SmartDialog.showToast(result['msg']);
@@ -153,11 +116,10 @@ class BangumiIntroController
);
if (res['status']) {
SmartDialog.showToast('投币成功');
BangumiInfoModel bangumiDetail = (loadingState.value as Success).response;
bangumiDetail.stat!['coins'] = bangumiDetail.stat!['coins'] + coin;
bangumiItem.stat!['coins'] = bangumiItem.stat!['coins'] + coin;
if (selectLike && hasLike.value.not) {
hasLike.value = true;
bangumiDetail.stat!['likes'] = bangumiDetail.stat!['likes'] + 1;
bangumiItem.stat!['likes'] = bangumiItem.stat!['likes'] + 1;
}
_coinNum.value += coin;
GlobalData().afterCoin(coin);
@@ -168,7 +130,7 @@ class BangumiIntroController
// 投币
Future<void> actionCoinVideo() async {
if (userInfo == null) {
if (!isLogin) {
SmartDialog.showToast('账号未登录');
return;
}
@@ -306,7 +268,7 @@ class BangumiIntroController
),
onTap: () {
Get.back();
EpisodeItem? item = bangumiItem?.episodes
EpisodeItem? item = bangumiItem.episodes
?.firstWhereOrNull((item) => item.epId == epId);
showModalBottomSheet(
context: context,
@@ -331,9 +293,9 @@ class BangumiIntroController
'5' || '7' => 4099,
_ => -1,
},
pic: bangumiItem?.cover,
pic: bangumiItem.cover,
title:
'${bangumiItem?.title}${item != null ? '\n${item.showTitle}' : ''}',
'${bangumiItem.title}${item != null ? '\n${item.showTitle}' : ''}',
uname: '',
),
);
@@ -348,9 +310,9 @@ class BangumiIntroController
onTap: () {
Get.back();
try {
EpisodeItem item = bangumiItem!.episodes!
EpisodeItem item = bangumiItem.episodes!
.firstWhere((item) => item.epId == epId);
final title = '${bangumiItem!.title!} ${item.showTitle}';
final title = '${bangumiItem.title!} ${item.showTitle}';
PageUtils.pmShare(
context,
content: {
@@ -360,7 +322,7 @@ class BangumiIntroController
"headline": title,
"source": 16,
"thumb": item.cover,
"source_desc": switch (bangumiItem!.type) {
"source_desc": switch (bangumiItem.type) {
1 => '番剧',
2 => '电影',
3 => '纪录片',
@@ -439,8 +401,7 @@ class BangumiIntroController
// 追番
Future<void> bangumiAdd() async {
var result = await VideoHttp.bangumiAdd(
seasonId: (loadingState.value as Success).response.seasonId);
var result = await VideoHttp.bangumiAdd(seasonId: bangumiItem.seasonId);
if (result['status']) {
isFollowed.value = true;
followStatus.value = 2;
@@ -450,8 +411,7 @@ class BangumiIntroController
// 取消追番
Future<void> bangumiDel() async {
var result = await VideoHttp.bangumiDel(
seasonId: (loadingState.value as Success).response.seasonId);
var result = await VideoHttp.bangumiDel(seasonId: bangumiItem.seasonId);
if (result['status']) {
isFollowed.value = false;
}
@@ -460,7 +420,7 @@ class BangumiIntroController
Future<void> bangumiUpdate(status) async {
var result = await VideoHttp.bangumiUpdate(
seasonId: [(loadingState.value as Success).response.seasonId],
seasonId: [bangumiItem.seasonId],
status: status,
);
if (result['status']) {
@@ -472,7 +432,7 @@ class BangumiIntroController
Future queryVideoInFolder() async {
favIds = null;
var result = await VideoHttp.videoInFolder(
mid: userInfo.mid,
mid: mid,
rid: epId, // bangumi
type: 24, // bangumi
);
@@ -487,10 +447,7 @@ class BangumiIntroController
}
bool prevPlay() {
late List episodes;
if ((loadingState.value as Success).response.episodes != null) {
episodes = (loadingState.value as Success).response.episodes!;
}
List episodes = bangumiItem.episodes!;
VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
int currentIndex =
@@ -516,21 +473,11 @@ class BangumiIntroController
/// 列表循环或者顺序播放时,自动播放下一个;自动连播时,播放相关视频
bool nextPlay() {
try {
late List episodes;
List episodes = bangumiItem.episodes!;
VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat;
if ((loadingState.value as Success<BangumiInfoModel>).response.episodes !=
null) {
episodes = (loadingState.value as Success<BangumiInfoModel>)
.response
.episodes!;
} else {
if (playRepeat == PlayRepeat.autoPlayRelated) {
return playRelated();
}
}
int currentIndex =
episodes.indexWhere((e) => e.cid == videoDetailCtr.cid.value);
int nextIndex = currentIndex + 1;
@@ -539,7 +486,7 @@ class BangumiIntroController
if (playRepeat == PlayRepeat.listCycle) {
nextIndex = 0;
} else if (playRepeat == PlayRepeat.autoPlayRelated) {
return playRelated();
return false;
} else {
return false;
}
@@ -556,15 +503,10 @@ class BangumiIntroController
}
}
bool playRelated() {
SmartDialog.showToast('番剧暂无相关视频');
return false;
}
// 一键三连
Future<void> actionOneThree() async {
feedBack();
if (userInfo == null) {
if (!isLogin) {
SmartDialog.showToast('账号未登录');
return;
}
@@ -610,7 +552,7 @@ class BangumiIntroController
// 收藏
void showFavBottomSheet(BuildContext context, {type = 'tap'}) {
if (userInfo == null) {
if (!isLogin) {
SmartDialog.showToast('账号未登录');
return;
}

View File

@@ -4,9 +4,7 @@ import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/badge.dart';
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
import 'package:PiliPlus/common/widgets/stat/stat.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart';
import 'package:PiliPlus/pages/video/controller.dart';
@@ -15,7 +13,6 @@ import 'package:PiliPlus/pages/video/introduction/pgc/widgets/bangumi_panel.dart
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_row_item.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@@ -44,95 +41,10 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
with AutomaticKeepAliveClientMixin {
late BangumiIntroController bangumiIntroController;
late VideoDetailController videoDetailCtr;
late int cid;
StreamSubscription? _listener;
// 添加页面缓存
@override
bool get wantKeepAlive => true;
late final _coinKey = GlobalKey<ActionItemState>();
late final _favKey = GlobalKey<ActionItemState>();
@override
void initState() {
super.initState();
cid = widget.cid!;
bangumiIntroController =
Get.put(BangumiIntroController(), tag: widget.heroTag);
videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag);
_listener = videoDetailCtr.cid.listen((int p0) {
cid = p0;
if (!mounted) return;
setState(() {});
});
}
@override
void dispose() {
_listener?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
super.build(context);
return Obx(() => _buildBody(bangumiIntroController.loadingState.value));
}
Widget _buildBody(LoadingState loadingState) {
return switch (loadingState) {
Loading() => BangumiInfo(
heroTag: widget.heroTag,
isLoading: true,
bangumiDetail: null,
cid: cid,
showEpisodes: widget.showEpisodes,
showIntroDetail: () {},
),
Success(:var response) => BangumiInfo(
heroTag: widget.heroTag,
isLoading: false,
bangumiDetail: response,
cid: cid,
showEpisodes: widget.showEpisodes,
showIntroDetail: () => widget.showIntroDetail(
response,
bangumiIntroController.videoTags,
),
),
Error(:var errMsg) => HttpError(
errMsg: errMsg,
onReload: bangumiIntroController.onReload,
),
};
}
}
class BangumiInfo extends StatefulWidget {
const BangumiInfo({
super.key,
this.isLoading = false,
this.bangumiDetail,
this.cid,
required this.showEpisodes,
required this.showIntroDetail,
required this.heroTag,
});
final bool isLoading;
final BangumiInfoModel? bangumiDetail;
final int? cid;
final Function showEpisodes;
final Function showIntroDetail;
final String heroTag;
@override
State<BangumiInfo> createState() => _BangumiInfoState();
}
class _BangumiInfoState extends State<BangumiInfo> {
late final BangumiIntroController bangumiIntroController;
late final VideoDetailController videoDetailCtr;
late final BangumiInfoModel? bangumiItem;
int? cid;
bool isProcessing = false;
Future<void> handleState(Future Function() action) async {
if (isProcessing.not) {
@@ -142,10 +54,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
}
}
late final _coinKey = GlobalKey<ActionItemState>();
late final _favKey = GlobalKey<ActionItemState>();
StreamSubscription? _listener;
@override
bool get wantKeepAlive => true;
@override
void initState() {
@@ -153,32 +63,14 @@ class _BangumiInfoState extends State<BangumiInfo> {
bangumiIntroController =
Get.put(BangumiIntroController(), tag: widget.heroTag);
videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag);
bangumiItem = bangumiIntroController.bangumiItem;
cid = widget.cid!;
debugPrint('cid: $cid');
_listener = videoDetailCtr.cid.listen((p0) {
cid = p0;
if (!mounted) return;
setState(() {});
});
}
@override
void dispose() {
_listener?.cancel();
super.dispose();
}
// 视频介绍
void showIntroDetail() {
feedBack();
widget.showIntroDetail();
}
@override
Widget build(BuildContext context) {
super.build(context);
final ThemeData theme = Theme.of(context);
bool isLandscape =
final bangumiItem = bangumiIntroController.bangumiItem;
final isLandscape =
MediaQuery.of(context).orientation == Orientation.landscape;
return SliverPadding(
padding: EdgeInsets.only(
@@ -188,8 +80,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
bottom: StyleString.safeSpace + MediaQuery.paddingOf(context).bottom,
),
sliver: SliverToBoxAdapter(
child: !widget.isLoading || bangumiItem != null
? Column(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
@@ -204,33 +95,25 @@ class _BangumiInfoState extends State<BangumiInfo> {
context.imageView(
imgList: [
SourceModel(
url: !widget.isLoading
? widget.bangumiDetail!.cover!
: bangumiItem!.cover!,
url: bangumiItem.cover!,
)
],
onDismissed: videoDetailCtr.onDismissed,
);
},
child: Hero(
tag: !widget.isLoading
? widget.bangumiDetail!.cover!
: bangumiItem!.cover!,
tag: bangumiItem.cover!,
child: NetworkImgLayer(
width: isLandscape ? 115 / 0.75 : 115,
height: isLandscape ? 115 : 115 / 0.75,
src: !widget.isLoading
? widget.bangumiDetail!.cover!
: bangumiItem!.cover!,
src: bangumiItem.cover!,
semanticsLabel: '封面',
),
),
),
if (bangumiItem != null &&
bangumiItem!.rating != null)
if (bangumiItem.rating != null)
PBadge(
text:
'评分 ${!widget.isLoading ? widget.bangumiDetail!.rating!['score']! : bangumiItem!.rating!['score']!}',
text: '评分 ${bangumiItem.rating!['score']!}',
top: null,
right: 6,
bottom: 6,
@@ -241,7 +124,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
const SizedBox(width: 10),
Expanded(
child: GestureDetector(
onTap: showIntroDetail,
onTap: () => widget.showIntroDetail(
bangumiItem, bangumiIntroController.videoTags),
behavior: HitTestBehavior.opaque,
child: SizedBox(
height: isLandscape ? 115 : 115 / 0.75,
@@ -254,9 +138,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
children: [
Expanded(
child: Text(
!widget.isLoading
? widget.bangumiDetail!.title!
: bangumiItem!.title!,
bangumiItem.title!,
style: const TextStyle(
fontSize: 16,
),
@@ -276,15 +158,12 @@ class _BangumiInfoState extends State<BangumiInfo> {
),
visualDensity: VisualDensity.compact,
foregroundColor:
bangumiIntroController
.isFollowed.value
bangumiIntroController.isFollowed.value
? theme.colorScheme.outline
: null,
backgroundColor:
bangumiIntroController
.isFollowed.value
? theme.colorScheme
.onInverseSurface
bangumiIntroController.isFollowed.value
? theme.colorScheme.onInverseSurface
: null,
),
onPressed: bangumiIntroController
@@ -296,13 +175,11 @@ class _BangumiInfoState extends State<BangumiInfo> {
.isFollowed.value) {
showPgcFollowDialog(
context: context,
type: bangumiIntroController
.type,
type: bangumiIntroController.type,
followStatus:
bangumiIntroController
.followStatus.value,
onUpdateStatus:
(followStatus) {
onUpdateStatus: (followStatus) {
if (followStatus == -1) {
bangumiIntroController
.bangumiDel();
@@ -314,13 +191,11 @@ class _BangumiInfoState extends State<BangumiInfo> {
},
);
} else {
bangumiIntroController
.bangumiAdd();
bangumiIntroController.bangumiAdd();
}
},
child: Text(
bangumiIntroController
.isFollowed.value
bangumiIntroController.isFollowed.value
? '${bangumiIntroController.type}'
: '${bangumiIntroController.type}',
),
@@ -333,51 +208,32 @@ class _BangumiInfoState extends State<BangumiInfo> {
StatView(
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.isLoading
? widget.bangumiDetail!.stat!['views']
: bangumiItem!.stat!['views']),
value:
Utils.numFormat(bangumiItem.stat!['views']),
),
const SizedBox(width: 6),
StatDanMu(
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.isLoading
? widget
.bangumiDetail!.stat!['danmakus']
: bangumiItem!.stat!['danmakus']),
value: Utils.numFormat(
bangumiItem.stat!['danmakus']),
),
if (isLandscape) ...[
const SizedBox(width: 6),
AreasAndPubTime(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
areasAndPubTime(theme, bangumiItem),
const SizedBox(width: 6),
NewEpDesc(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
newEpDesc(theme, bangumiItem),
]
],
),
SizedBox(height: isLandscape ? 2 : 6),
if (!isLandscape)
AreasAndPubTime(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
if (!isLandscape)
NewEpDesc(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
if (!isLandscape) ...[
areasAndPubTime(theme, bangumiItem),
newEpDesc(theme, bangumiItem),
],
const Spacer(),
Text(
'简介:${!widget.isLoading ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}',
'简介:${bangumiItem.evaluate!}',
maxLines: isLandscape ? 2 : 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
@@ -394,40 +250,26 @@ class _BangumiInfoState extends State<BangumiInfo> {
),
const SizedBox(height: 6),
// 点赞收藏转发 布局样式2
actionGrid(theme, bangumiIntroController),
actionGrid(theme, bangumiItem, bangumiIntroController),
// 番剧分p
if ((!widget.isLoading &&
widget.bangumiDetail!.episodes!.isNotEmpty) ||
bangumiItem != null &&
bangumiItem!.episodes!.isNotEmpty) ...[
if (bangumiItem.episodes!.isNotEmpty) ...[
BangumiPanel(
heroTag: widget.heroTag,
pages: bangumiItem != null
? bangumiItem!.episodes!
: widget.bangumiDetail!.episodes!,
cid: cid ??
(bangumiItem != null
? bangumiItem!.episodes!.first.cid
: widget.bangumiDetail!.episodes!.first.cid),
pages: bangumiItem.episodes!,
cid: videoDetailCtr.cid.value,
changeFuc: bangumiIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
newEp: bangumiItem?.newEp,
newEp: bangumiItem.newEp,
)
],
],
)
: const SizedBox(
height: 100,
child: Center(
child: CircularProgressIndicator(),
),
),
),
);
}
Widget actionGrid(
ThemeData theme, BangumiIntroController bangumiIntroController) {
Widget actionGrid(ThemeData theme, BangumiInfoModel bangumiItem,
BangumiIntroController bangumiIntroController) {
return Material(
color: theme.colorScheme.surface,
child: Padding(
@@ -445,13 +287,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
handleState(bangumiIntroController.actionLikeVideo),
onLongPress: bangumiIntroController.actionOneThree,
selectStatus: bangumiIntroController.hasLike.value,
loadingStatus: false,
isLoading: false,
semanticsLabel: '点赞',
text: !widget.isLoading
? Utils.numFormat(widget.bangumiDetail!.stat!['likes']!)
: Utils.numFormat(
bangumiItem!.stat!['likes']!,
),
text: Utils.numFormat(bangumiItem.stat!['likes']!),
needAnim: true,
hasTriple: bangumiIntroController.hasLike.value &&
bangumiIntroController.hasCoin &&
@@ -476,13 +314,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
onTap: () =>
handleState(bangumiIntroController.actionCoinVideo),
selectStatus: bangumiIntroController.hasCoin,
loadingStatus: false,
isLoading: false,
semanticsLabel: '投币',
text: !widget.isLoading
? Utils.numFormat(widget.bangumiDetail!.stat!['coins']!)
: Utils.numFormat(
bangumiItem!.stat!['coins']!,
),
text: Utils.numFormat(bangumiItem.stat!['coins']!),
needAnim: true,
),
),
@@ -496,14 +330,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
onLongPress: () => bangumiIntroController
.showFavBottomSheet(context, type: 'longPress'),
selectStatus: bangumiIntroController.hasFav.value,
loadingStatus: false,
isLoading: false,
semanticsLabel: '收藏',
text: !widget.isLoading
? Utils.numFormat(
widget.bangumiDetail!.stat!['favorite']!)
: Utils.numFormat(
bangumiItem!.stat!['favorite']!,
),
text: Utils.numFormat(bangumiItem.stat!['favorite']!),
needAnim: true,
),
),
@@ -512,21 +341,18 @@ class _BangumiInfoState extends State<BangumiInfo> {
selectIcon: const Icon(FontAwesomeIcons.reply),
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
selectStatus: false,
loadingStatus: false,
isLoading: false,
semanticsLabel: '评论',
text: !widget.isLoading
? Utils.numFormat(widget.bangumiDetail!.stat!['reply']!)
: Utils.numFormat(bangumiItem!.stat!['reply']!),
text: Utils.numFormat(bangumiItem.stat!['reply']!),
),
ActionItem(
icon: const Icon(FontAwesomeIcons.shareFromSquare),
onTap: () => bangumiIntroController.actionShareVideo(context),
selectStatus: false,
loadingStatus: false,
isLoading: false,
semanticsLabel: '转发',
text: !widget.isLoading
? Utils.numFormat(widget.bangumiDetail!.stat!['share']!)
: Utils.numFormat(bangumiItem!.stat!['share']!)),
text: Utils.numFormat(bangumiItem.stat!['share']!),
),
],
),
),
@@ -535,20 +361,19 @@ class _BangumiInfoState extends State<BangumiInfo> {
}
Widget actionRow(
BuildContext context,
BangumiInfoModel bangumiItem,
BangumiIntroController bangumiIntroController,
VideoDetailController videoDetailCtr,
) {
return Row(children: [
return Row(
children: [
Obx(
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.thumbsUp),
onTap: () => handleState(bangumiIntroController.actionLikeVideo),
selectStatus: bangumiIntroController.hasLike.value,
loadingStatus: widget.isLoading,
text: !widget.isLoading
? widget.bangumiDetail!.stat!['likes']!.toString()
: '-',
isLoading: false,
text: bangumiItem.stat!['likes']!.toString(),
),
),
const SizedBox(width: 8),
@@ -557,10 +382,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
icon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(bangumiIntroController.actionCoinVideo),
selectStatus: bangumiIntroController.hasCoin,
loadingStatus: widget.isLoading,
text: !widget.isLoading
? widget.bangumiDetail!.stat!['coins']!.toString()
: '-',
isLoading: false,
text: bangumiItem.stat!['coins']!.toString(),
),
),
const SizedBox(width: 8),
@@ -568,13 +391,11 @@ class _BangumiInfoState extends State<BangumiInfo> {
() => ActionRowItem(
icon: const Icon(FontAwesomeIcons.heart),
onTap: () => bangumiIntroController.showFavBottomSheet(context),
onLongPress: () => bangumiIntroController.showFavBottomSheet(context,
type: 'longPress'),
onLongPress: () => bangumiIntroController
.showFavBottomSheet(context, type: 'longPress'),
selectStatus: bangumiIntroController.hasFav.value,
loadingStatus: widget.isLoading,
text: !widget.isLoading
? widget.bangumiDetail!.stat!['favorite']!.toString()
: '-',
isLoading: false,
text: bangumiItem.stat!['favorite']!.toString(),
),
),
const SizedBox(width: 8),
@@ -584,45 +405,27 @@ class _BangumiInfoState extends State<BangumiInfo> {
videoDetailCtr.tabCtr.animateTo(1);
},
selectStatus: false,
loadingStatus: widget.isLoading,
text: !widget.isLoading
? widget.bangumiDetail!.stat!['reply']!.toString()
: '-',
isLoading: false,
text: bangumiItem.stat!['reply']!.toString(),
),
const SizedBox(width: 8),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.share),
onTap: () => bangumiIntroController.actionShareVideo(context),
selectStatus: false,
loadingStatus: widget.isLoading,
text: '转发'),
]);
isLoading: false,
text: '转发',
),
],
);
}
}
class AreasAndPubTime extends StatelessWidget {
const AreasAndPubTime({
super.key,
required this.widget,
required this.bangumiItem,
required this.theme,
});
final BangumiInfo widget;
final BangumiInfoModel? bangumiItem;
final ThemeData theme;
@override
Widget build(BuildContext context) {
Widget areasAndPubTime(ThemeData theme, BangumiInfoModel bangumiItem) {
return Row(
children: [
Text(
!widget.isLoading
? (widget.bangumiDetail!.areas!.isNotEmpty
? widget.bangumiDetail!.areas!.first['name']
: '')
: (bangumiItem!.areas!.isNotEmpty
? bangumiItem!.areas!.first['name']
(bangumiItem.areas!.isNotEmpty
? bangumiItem.areas!.first['name']
: ''),
style: TextStyle(
fontSize: 12,
@@ -631,9 +434,7 @@ class AreasAndPubTime extends StatelessWidget {
),
const SizedBox(width: 6),
Text(
!widget.isLoading
? widget.bangumiDetail!.publish!['pub_time_show']
: bangumiItem!.publish!['pub_time_show'],
bangumiItem.publish!['pub_time_show'],
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
@@ -642,26 +443,10 @@ class AreasAndPubTime extends StatelessWidget {
],
);
}
}
class NewEpDesc extends StatelessWidget {
const NewEpDesc({
super.key,
required this.widget,
required this.bangumiItem,
required this.theme,
});
final BangumiInfo widget;
final BangumiInfoModel? bangumiItem;
final ThemeData theme;
@override
Widget build(BuildContext context) {
Widget newEpDesc(ThemeData theme, BangumiInfoModel bangumiItem) {
return Text(
!widget.isLoading
? widget.bangumiDetail!.newEp!['desc']
: bangumiItem!.newEp!['desc'],
bangumiItem.newEp!['desc'],
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,

View File

@@ -71,7 +71,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
return Obx(
() => videoIntroController.videoDetail.value.title == null
? VideoInfo(
loadingStatus: true,
isLoading: true,
videoIntroController: videoIntroController,
heroTag: widget.heroTag,
showAiBottomSheet: widget.showAiBottomSheet,
@@ -80,7 +80,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
)
: VideoInfo(
key: ValueKey(widget.heroTag),
loadingStatus: false,
isLoading: false,
videoIntroController: videoIntroController,
heroTag: widget.heroTag,
showAiBottomSheet: widget.showAiBottomSheet,
@@ -92,7 +92,7 @@ class _VideoIntroPanelState extends State<VideoIntroPanel>
}
class VideoInfo extends StatefulWidget {
final bool loadingStatus;
final bool isLoading;
final String heroTag;
final Function showAiBottomSheet;
final Function showEpisodes;
@@ -101,7 +101,7 @@ class VideoInfo extends StatefulWidget {
const VideoInfo({
super.key,
this.loadingStatus = false,
this.isLoading = false,
required this.heroTag,
required this.showAiBottomSheet,
required this.showEpisodes,
@@ -236,7 +236,7 @@ class _VideoInfoState extends State<VideoInfo> {
// 视频介绍
void showIntroDetail() {
if (widget.loadingStatus) {
if (widget.isLoading) {
return;
}
feedBack();
@@ -246,9 +246,8 @@ class _VideoInfoState extends State<VideoInfo> {
// 用户主页
void onPushMember() {
feedBack();
int? mid = !widget.loadingStatus
? videoDetail.owner?.mid
: videoItem['owner']?.mid;
int? mid =
!widget.isLoading ? videoDetail.owner?.mid : videoItem['owner']?.mid;
if (mid != null) {
if (context.orientation == Orientation.landscape &&
_horizontalMemberPage) {
@@ -369,7 +368,7 @@ class _VideoInfoState extends State<VideoInfo> {
childBuilder: (index) => GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
int? ownerMid = !widget.loadingStatus
int? ownerMid = !widget.isLoading
? videoDetail.owner?.mid
: videoItem['owner']?.mid;
if (videoItem['staff'][index].mid ==
@@ -557,7 +556,7 @@ class _VideoInfoState extends State<VideoInfo> {
StatView(
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.loadingStatus
value: Utils.numFormat(!widget.isLoading
? videoDetail.stat?.view ?? '-'
: videoItem['stat']?.view ?? '-'),
textColor: theme.colorScheme.outline,
@@ -566,7 +565,7 @@ class _VideoInfoState extends State<VideoInfo> {
StatDanMu(
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.loadingStatus
value: Utils.numFormat(!widget.isLoading
? videoDetail.stat?.danmaku ?? '-'
: videoItem['stat']?.danmu ?? '-'),
textColor: theme.colorScheme.outline,
@@ -574,7 +573,7 @@ class _VideoInfoState extends State<VideoInfo> {
const SizedBox(width: 10),
Text(
Utils.dateFormat(
!widget.loadingStatus
!widget.isLoading
? videoDetail.pubdate
: videoItem['pubdate'],
formatType: 'detail'),
@@ -769,7 +768,7 @@ class _VideoInfoState extends State<VideoInfo> {
actionGrid(context, videoIntroController),
],
// 合集
if (!widget.loadingStatus &&
if (!widget.isLoading &&
videoDetail.ugcSeason != null &&
(context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape &&
@@ -784,7 +783,7 @@ class _VideoInfoState extends State<VideoInfo> {
videoIntroController: videoIntroController,
),
),
if (!widget.loadingStatus &&
if (!widget.isLoading &&
videoDetail.pages != null &&
videoDetail.pages!.length > 1 &&
(context.orientation != Orientation.landscape ||
@@ -857,9 +856,9 @@ class _VideoInfoState extends State<VideoInfo> {
onLongPress: () =>
handleState(videoIntroController.actionOneThree),
selectStatus: videoIntroController.hasLike.value,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
semanticsLabel: '点赞',
text: !widget.loadingStatus
text: !widget.isLoading
? Utils.numFormat(videoDetail.stat!.like!)
: '-',
needAnim: true,
@@ -884,7 +883,7 @@ class _VideoInfoState extends State<VideoInfo> {
selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown),
onTap: () => handleState(videoIntroController.actionDislikeVideo),
selectStatus: videoIntroController.hasDislike.value,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
semanticsLabel: '点踩',
text: "点踩",
),
@@ -896,9 +895,9 @@ class _VideoInfoState extends State<VideoInfo> {
selectIcon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(videoIntroController.actionCoinVideo),
selectStatus: videoIntroController.hasCoin,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
semanticsLabel: '投币',
text: !widget.loadingStatus
text: !widget.isLoading
? Utils.numFormat(videoDetail.stat!.coin!)
: '-',
needAnim: true,
@@ -913,9 +912,9 @@ class _VideoInfoState extends State<VideoInfo> {
onLongPress: () => videoIntroController
.showFavBottomSheet(context, type: 'longPress'),
selectStatus: videoIntroController.hasFav.value,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
semanticsLabel: '收藏',
text: !widget.loadingStatus
text: !widget.isLoading
? Utils.numFormat(videoDetail.stat!.favorite!)
: '-',
needAnim: true,
@@ -927,7 +926,7 @@ class _VideoInfoState extends State<VideoInfo> {
selectIcon: const Icon(FontAwesomeIcons.solidClock),
onTap: () => handleState(videoIntroController.viewLater),
selectStatus: videoIntroController.hasLater.value,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
semanticsLabel: '再看',
text: '再看',
),
@@ -936,9 +935,9 @@ class _VideoInfoState extends State<VideoInfo> {
icon: const Icon(FontAwesomeIcons.shareFromSquare),
onTap: () => videoIntroController.actionShareVideo(context),
selectStatus: false,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
semanticsLabel: '分享',
text: !widget.loadingStatus
text: !widget.isLoading
? Utils.numFormat(videoDetail.stat!.share!)
: '分享',
),
@@ -958,9 +957,8 @@ class _VideoInfoState extends State<VideoInfo> {
icon: const Icon(FontAwesomeIcons.thumbsUp),
onTap: () => handleState(videoIntroController.actionLikeVideo),
selectStatus: videoIntroController.hasLike.value,
loadingStatus: widget.loadingStatus,
text:
!widget.loadingStatus ? videoDetail.stat!.like!.toString() : '-',
isLoading: widget.isLoading,
text: !widget.isLoading ? videoDetail.stat!.like!.toString() : '-',
),
),
const SizedBox(width: 8),
@@ -969,9 +967,8 @@ class _VideoInfoState extends State<VideoInfo> {
icon: const Icon(FontAwesomeIcons.b),
onTap: () => handleState(videoIntroController.actionCoinVideo),
selectStatus: videoIntroController.hasCoin,
loadingStatus: widget.loadingStatus,
text:
!widget.loadingStatus ? videoDetail.stat!.coin!.toString() : '-',
isLoading: widget.isLoading,
text: !widget.isLoading ? videoDetail.stat!.coin!.toString() : '-',
),
),
const SizedBox(width: 8),
@@ -982,10 +979,9 @@ class _VideoInfoState extends State<VideoInfo> {
onLongPress: () => videoIntroController.showFavBottomSheet(context,
type: 'longPress'),
selectStatus: videoIntroController.hasFav.value,
loadingStatus: widget.loadingStatus,
text: !widget.loadingStatus
? videoDetail.stat!.favorite!.toString()
: '-',
isLoading: widget.isLoading,
text:
!widget.isLoading ? videoDetail.stat!.favorite!.toString() : '-',
),
),
const SizedBox(width: 8),
@@ -995,15 +991,15 @@ class _VideoInfoState extends State<VideoInfo> {
videoDetailCtr.tabCtr.animateTo(1);
},
selectStatus: false,
loadingStatus: widget.loadingStatus,
text: !widget.loadingStatus ? videoDetail.stat!.reply!.toString() : '-',
isLoading: widget.isLoading,
text: !widget.isLoading ? videoDetail.stat!.reply!.toString() : '-',
),
const SizedBox(width: 8),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.share),
onTap: () => videoIntroController.actionShareVideo(context),
selectStatus: false,
loadingStatus: widget.loadingStatus,
isLoading: widget.isLoading,
text: '转发',
),
]);

View File

@@ -12,7 +12,7 @@ class ActionItem extends StatefulWidget {
final Icon? selectIcon;
final Function? onTap;
final Function? onLongPress;
final bool? loadingStatus;
final bool? isLoading;
final String? text;
final bool selectStatus;
final String semanticsLabel;
@@ -27,7 +27,7 @@ class ActionItem extends StatefulWidget {
this.selectIcon,
this.onTap,
this.onLongPress,
this.loadingStatus,
this.isLoading,
this.text,
this.selectStatus = false,
this.needAnim = false,
@@ -183,7 +183,7 @@ class ActionItemState extends State<ActionItem>
),
if (widget.text != null)
AnimatedOpacity(
opacity: widget.loadingStatus! ? 0 : 1,
opacity: widget.isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),

View File

@@ -5,7 +5,7 @@ class ActionRowItem extends StatelessWidget {
final Icon? icon;
final Icon? selectIcon;
final Function? onTap;
final bool? loadingStatus;
final bool? isLoading;
final String? text;
final bool selectStatus;
final Function? onLongPress;
@@ -15,7 +15,7 @@ class ActionRowItem extends StatelessWidget {
this.icon,
this.selectIcon,
this.onTap,
this.loadingStatus,
this.isLoading,
this.text,
this.selectStatus = false,
this.onLongPress,
@@ -53,7 +53,7 @@ class ActionRowItem extends StatelessWidget {
const SizedBox(width: 6),
],
AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1,
opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 300),

View File

@@ -4,9 +4,9 @@ import 'package:flutter/material.dart';
class MenuRow extends StatelessWidget {
const MenuRow({
super.key,
this.loadingStatus,
this.isLoading,
});
final bool? loadingStatus;
final bool? isLoading;
@override
Widget build(BuildContext context) {
@@ -20,28 +20,28 @@ class MenuRow extends StatelessWidget {
child: Row(children: [
ActionRowLineItem(
onTap: () => {},
loadingStatus: loadingStatus,
isLoading: isLoading,
text: '推荐',
selectStatus: false,
),
const SizedBox(width: 8),
ActionRowLineItem(
onTap: () => {},
loadingStatus: loadingStatus,
isLoading: isLoading,
text: '弹幕',
selectStatus: false,
),
const SizedBox(width: 8),
ActionRowLineItem(
onTap: () => {},
loadingStatus: loadingStatus,
isLoading: isLoading,
text: '评论列表',
selectStatus: false,
),
const SizedBox(width: 8),
ActionRowLineItem(
onTap: () => {},
loadingStatus: loadingStatus,
isLoading: isLoading,
text: '播放列表',
selectStatus: false,
),
@@ -51,7 +51,7 @@ class MenuRow extends StatelessWidget {
}
Widget actionRowLineItem(
ThemeData theme, Function? onTap, bool? loadingStatus, String? text,
ThemeData theme, Function? onTap, bool? isLoading, String? text,
{bool selectStatus = false}) {
return Material(
color: selectStatus
@@ -78,7 +78,7 @@ class MenuRow extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1,
opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: Text(
text!,
@@ -103,13 +103,13 @@ class ActionRowLineItem extends StatelessWidget {
required this.selectStatus,
this.onTap,
this.text,
this.loadingStatus = false,
this.isLoading = false,
this.iconData,
this.icon,
});
final bool selectStatus;
final Function? onTap;
final bool? loadingStatus;
final bool? isLoading;
final String? text;
final IconData? iconData;
final Widget? icon;
@@ -152,7 +152,7 @@ class ActionRowLineItem extends StatelessWidget {
else if (icon != null)
icon!,
AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1,
opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200),
child: Text(
text!,

View File

@@ -10,7 +10,6 @@ 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/bangumi/info.dart' as bangumi;
import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/models/common/episode_panel_type.dart';
import 'package:PiliPlus/models/common/reply/reply_type.dart';
import 'package:PiliPlus/models/common/search_type.dart';
@@ -103,8 +102,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.plPlayerController.horizontalPreview;
StreamSubscription? _listenerDetail;
StreamSubscription? _listenerLoadingState;
StreamSubscription? _listenerCid;
StreamSubscription? _listenerFS;
Box get setting => GStorage.setting;
@@ -137,23 +134,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
});
if (videoDetailController.videoType == SearchType.media_bangumi) {
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag);
_listenerLoadingState =
bangumiIntroController.loadingState.listen((value) {
if (!context.mounted) return;
if (value is Success<BangumiInfoModel>) {
videoPlayerServiceHandler.onVideoDetailChange(
value.response, videoDetailController.cid.value, heroTag);
}
});
_listenerCid = videoDetailController.cid.listen((p0) {
if (!context.mounted) return;
if (bangumiIntroController.loadingState.value is Success) {
videoPlayerServiceHandler.onVideoDetailChange(
(bangumiIntroController.loadingState.value as Success).response,
p0,
heroTag);
}
});
}
autoExitFullscreen =
setting.get(SettingBoxKey.enableAutoExit, defaultValue: true);
@@ -337,8 +317,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
@override
void dispose() {
_listenerDetail?.cancel();
_listenerLoadingState?.cancel();
_listenerCid?.cancel();
_listenerFS?.cancel();
videoDetailController.skipTimer?.cancel();

View File

@@ -5,7 +5,6 @@ import 'dart:math';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/common/widgets/progress_bar/audio_video_progress_bar.dart';
import 'package:PiliPlus/common/widgets/progress_bar/segment_progress_bar.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/super_resolution_type.dart';
import 'package:PiliPlus/models/video_detail_res.dart';
import 'package:PiliPlus/pages/video/controller.dart';
@@ -266,7 +265,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
bool isSeason = videoIntroController?.videoDetail.value.ugcSeason != null;
bool isPage = videoIntroController?.videoDetail.value.pages != null &&
videoIntroController!.videoDetail.value.pages!.length > 1;
bool isBangumi = bangumiIntroController?.loadingState.value is Success;
bool isBangumi = bangumiIntroController != null;
bool anySeason = isSeason || isPage || isBangumi;
double widgetWidth =
isFullScreen && context.orientation == Orientation.landscape ? 42 : 35;
@@ -508,9 +507,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
videoIntroController!.videoDetail.value.pages!;
episodes = pages;
} else if (isBangumi) {
episodes = (bangumiIntroController!.loadingState.value as Success)
.response
.episodes!;
episodes = bangumiIntroController!.bangumiItem.episodes!;
}
widget.showEpisodes?.call(
index,