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/constants.dart';
import 'package:PiliPlus/http/init.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/user.dart';
import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/http/video.dart';
import 'package:PiliPlus/models/bangumi/info.dart'; import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/models/user/fav_folder.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/dynamics_repost/view.dart';
import 'package:PiliPlus/pages/video/controller.dart'; import 'package:PiliPlus/pages/video/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/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/dom.dart' as dom;
import 'package:html/parser.dart' as html_parser; import 'package:html/parser.dart' as html_parser;
class BangumiIntroController class BangumiIntroController extends GetxController {
extends CommonDataController<BangumiInfoModel, BangumiInfoModel> {
// 视频bvid // 视频bvid
String bvid = Get.parameters['bvid'] ?? ''; String bvid = Get.parameters['bvid'] ?? '';
var seasonId = Get.parameters['seasonId'] != null var seasonId = Get.parameters['seasonId'] != null
@@ -44,15 +40,7 @@ class BangumiIntroController
? '追番' ? '追番'
: '追剧'; : '追剧';
// 是否预渲染 骨架屏 BangumiInfoModel bangumiItem = Get.arguments['bangumiItem'];
bool preRender = false;
// 视频详情 上个页面传入
Map? videoItem = {};
BangumiInfoModel? bangumiItem;
// up主粉丝数
Map userStat = {'follower': '-'};
// 是否点赞 // 是否点赞
RxBool hasLike = false.obs; RxBool hasLike = false.obs;
@@ -62,11 +50,14 @@ class BangumiIntroController
bool get hasCoin => _coinNum.value != 0; bool get hasCoin => _coinNum.value != 0;
// 是否收藏 // 是否收藏
RxBool hasFav = false.obs; RxBool hasFav = false.obs;
dynamic videoTags; dynamic videoTags;
bool isLogin = false;
Rx<FavFolderData> favFolderData = FavFolderData().obs;
List? favIds; List? favIds;
dynamic userInfo; Rx<FavFolderData> favFolderData = FavFolderData().obs;
bool isLogin = Accounts.main.isLogin;
int mid = Accounts.main.mid;
late final enableQuickFav = late final enableQuickFav =
GStorage.setting.get(SettingBoxKey.enableQuickFav, defaultValue: false); GStorage.setting.get(SettingBoxKey.enableQuickFav, defaultValue: false);
@@ -74,30 +65,15 @@ class BangumiIntroController
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
if (Get.arguments.isNotEmpty as bool) { if (isLogin) {
if (Get.arguments.containsKey('bangumiItem') as bool) { if (seasonId != null) {
preRender = true; queryIsFollowed();
bangumiItem = Get.arguments['bangumiItem']; }
if (epId != null) {
queryBangumiLikeCoinFav();
} }
} }
userInfo = GStorage.userInfo.get('userInfoCache'); queryVideoTags();
isLogin = userInfo != null;
if (isLogin && epId != null) {
queryBangumiLikeCoinFav();
}
queryData();
if (isLogin && seasonId != null) {
queryIsFollowed();
}
}
@override
Future<void> queryData([bool isRefresh = true]) async {
await queryVideoTags();
return super.queryData(isRefresh);
} }
Future<void> queryVideoTags() async { 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 { Future<void> queryBangumiLikeCoinFav() async {
var result = await VideoHttp.bangumiLikeCoinFav(epId: epId); var result = await VideoHttp.bangumiLikeCoinFav(epId: epId);
@@ -136,9 +100,8 @@ class BangumiIntroController
var result = await VideoHttp.likeVideo(bvid: bvid, type: !hasLike.value); var result = await VideoHttp.likeVideo(bvid: bvid, type: !hasLike.value);
if (result['status']) { if (result['status']) {
SmartDialog.showToast(!hasLike.value ? result['data']['toast'] : '取消赞'); SmartDialog.showToast(!hasLike.value ? result['data']['toast'] : '取消赞');
BangumiInfoModel bangumiDetail = (loadingState.value as Success).response; bangumiItem.stat!['likes'] =
bangumiDetail.stat!['likes'] = bangumiItem.stat!['likes'] + (!hasLike.value ? 1 : -1);
bangumiDetail.stat!['likes'] + (!hasLike.value ? 1 : -1);
hasLike.value = !hasLike.value; hasLike.value = !hasLike.value;
} else { } else {
SmartDialog.showToast(result['msg']); SmartDialog.showToast(result['msg']);
@@ -153,11 +116,10 @@ class BangumiIntroController
); );
if (res['status']) { if (res['status']) {
SmartDialog.showToast('投币成功'); SmartDialog.showToast('投币成功');
BangumiInfoModel bangumiDetail = (loadingState.value as Success).response; bangumiItem.stat!['coins'] = bangumiItem.stat!['coins'] + coin;
bangumiDetail.stat!['coins'] = bangumiDetail.stat!['coins'] + coin;
if (selectLike && hasLike.value.not) { if (selectLike && hasLike.value.not) {
hasLike.value = true; hasLike.value = true;
bangumiDetail.stat!['likes'] = bangumiDetail.stat!['likes'] + 1; bangumiItem.stat!['likes'] = bangumiItem.stat!['likes'] + 1;
} }
_coinNum.value += coin; _coinNum.value += coin;
GlobalData().afterCoin(coin); GlobalData().afterCoin(coin);
@@ -168,7 +130,7 @@ class BangumiIntroController
// 投币 // 投币
Future<void> actionCoinVideo() async { Future<void> actionCoinVideo() async {
if (userInfo == null) { if (!isLogin) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
return; return;
} }
@@ -306,7 +268,7 @@ class BangumiIntroController
), ),
onTap: () { onTap: () {
Get.back(); Get.back();
EpisodeItem? item = bangumiItem?.episodes EpisodeItem? item = bangumiItem.episodes
?.firstWhereOrNull((item) => item.epId == epId); ?.firstWhereOrNull((item) => item.epId == epId);
showModalBottomSheet( showModalBottomSheet(
context: context, context: context,
@@ -331,9 +293,9 @@ class BangumiIntroController
'5' || '7' => 4099, '5' || '7' => 4099,
_ => -1, _ => -1,
}, },
pic: bangumiItem?.cover, pic: bangumiItem.cover,
title: title:
'${bangumiItem?.title}${item != null ? '\n${item.showTitle}' : ''}', '${bangumiItem.title}${item != null ? '\n${item.showTitle}' : ''}',
uname: '', uname: '',
), ),
); );
@@ -348,9 +310,9 @@ class BangumiIntroController
onTap: () { onTap: () {
Get.back(); Get.back();
try { try {
EpisodeItem item = bangumiItem!.episodes! EpisodeItem item = bangumiItem.episodes!
.firstWhere((item) => item.epId == epId); .firstWhere((item) => item.epId == epId);
final title = '${bangumiItem!.title!} ${item.showTitle}'; final title = '${bangumiItem.title!} ${item.showTitle}';
PageUtils.pmShare( PageUtils.pmShare(
context, context,
content: { content: {
@@ -360,7 +322,7 @@ class BangumiIntroController
"headline": title, "headline": title,
"source": 16, "source": 16,
"thumb": item.cover, "thumb": item.cover,
"source_desc": switch (bangumiItem!.type) { "source_desc": switch (bangumiItem.type) {
1 => '番剧', 1 => '番剧',
2 => '电影', 2 => '电影',
3 => '纪录片', 3 => '纪录片',
@@ -439,8 +401,7 @@ class BangumiIntroController
// 追番 // 追番
Future<void> bangumiAdd() async { Future<void> bangumiAdd() async {
var result = await VideoHttp.bangumiAdd( var result = await VideoHttp.bangumiAdd(seasonId: bangumiItem.seasonId);
seasonId: (loadingState.value as Success).response.seasonId);
if (result['status']) { if (result['status']) {
isFollowed.value = true; isFollowed.value = true;
followStatus.value = 2; followStatus.value = 2;
@@ -450,8 +411,7 @@ class BangumiIntroController
// 取消追番 // 取消追番
Future<void> bangumiDel() async { Future<void> bangumiDel() async {
var result = await VideoHttp.bangumiDel( var result = await VideoHttp.bangumiDel(seasonId: bangumiItem.seasonId);
seasonId: (loadingState.value as Success).response.seasonId);
if (result['status']) { if (result['status']) {
isFollowed.value = false; isFollowed.value = false;
} }
@@ -460,7 +420,7 @@ class BangumiIntroController
Future<void> bangumiUpdate(status) async { Future<void> bangumiUpdate(status) async {
var result = await VideoHttp.bangumiUpdate( var result = await VideoHttp.bangumiUpdate(
seasonId: [(loadingState.value as Success).response.seasonId], seasonId: [bangumiItem.seasonId],
status: status, status: status,
); );
if (result['status']) { if (result['status']) {
@@ -472,7 +432,7 @@ class BangumiIntroController
Future queryVideoInFolder() async { Future queryVideoInFolder() async {
favIds = null; favIds = null;
var result = await VideoHttp.videoInFolder( var result = await VideoHttp.videoInFolder(
mid: userInfo.mid, mid: mid,
rid: epId, // bangumi rid: epId, // bangumi
type: 24, // bangumi type: 24, // bangumi
); );
@@ -487,10 +447,7 @@ class BangumiIntroController
} }
bool prevPlay() { bool prevPlay() {
late List episodes; List episodes = bangumiItem.episodes!;
if ((loadingState.value as Success).response.episodes != null) {
episodes = (loadingState.value as Success).response.episodes!;
}
VideoDetailController videoDetailCtr = VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']); Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
int currentIndex = int currentIndex =
@@ -516,21 +473,11 @@ class BangumiIntroController
/// 列表循环或者顺序播放时,自动播放下一个;自动连播时,播放相关视频 /// 列表循环或者顺序播放时,自动播放下一个;自动连播时,播放相关视频
bool nextPlay() { bool nextPlay() {
try { try {
late List episodes; List episodes = bangumiItem.episodes!;
VideoDetailController videoDetailCtr = VideoDetailController videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']); Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
PlayRepeat playRepeat = videoDetailCtr.plPlayerController.playRepeat; 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 = int currentIndex =
episodes.indexWhere((e) => e.cid == videoDetailCtr.cid.value); episodes.indexWhere((e) => e.cid == videoDetailCtr.cid.value);
int nextIndex = currentIndex + 1; int nextIndex = currentIndex + 1;
@@ -539,7 +486,7 @@ class BangumiIntroController
if (playRepeat == PlayRepeat.listCycle) { if (playRepeat == PlayRepeat.listCycle) {
nextIndex = 0; nextIndex = 0;
} else if (playRepeat == PlayRepeat.autoPlayRelated) { } else if (playRepeat == PlayRepeat.autoPlayRelated) {
return playRelated(); return false;
} else { } else {
return false; return false;
} }
@@ -556,15 +503,10 @@ class BangumiIntroController
} }
} }
bool playRelated() {
SmartDialog.showToast('番剧暂无相关视频');
return false;
}
// 一键三连 // 一键三连
Future<void> actionOneThree() async { Future<void> actionOneThree() async {
feedBack(); feedBack();
if (userInfo == null) { if (!isLogin) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
return; return;
} }
@@ -610,7 +552,7 @@ class BangumiIntroController
// 收藏 // 收藏
void showFavBottomSheet(BuildContext context, {type = 'tap'}) { void showFavBottomSheet(BuildContext context, {type = 'tap'}) {
if (userInfo == null) { if (!isLogin) {
SmartDialog.showToast('账号未登录'); SmartDialog.showToast('账号未登录');
return; 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/badge.dart';
import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
import 'package:PiliPlus/common/widgets/image/network_img_layer.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/common/widgets/stat/stat.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/bangumi/info.dart'; import 'package:PiliPlus/models/bangumi/info.dart';
import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart';
import 'package:PiliPlus/pages/video/controller.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_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_row_item.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_row_item.dart';
import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
@@ -44,95 +41,10 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
with AutomaticKeepAliveClientMixin { with AutomaticKeepAliveClientMixin {
late BangumiIntroController bangumiIntroController; late BangumiIntroController bangumiIntroController;
late VideoDetailController videoDetailCtr; late VideoDetailController videoDetailCtr;
late int cid;
StreamSubscription? _listener;
// 添加页面缓存 late final _coinKey = GlobalKey<ActionItemState>();
@override late final _favKey = GlobalKey<ActionItemState>();
bool get wantKeepAlive => true;
@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; bool isProcessing = false;
Future<void> handleState(Future Function() action) async { Future<void> handleState(Future Function() action) async {
if (isProcessing.not) { if (isProcessing.not) {
@@ -142,10 +54,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
} }
} }
late final _coinKey = GlobalKey<ActionItemState>(); @override
late final _favKey = GlobalKey<ActionItemState>(); bool get wantKeepAlive => true;
StreamSubscription? _listener;
@override @override
void initState() { void initState() {
@@ -153,32 +63,14 @@ class _BangumiInfoState extends State<BangumiInfo> {
bangumiIntroController = bangumiIntroController =
Get.put(BangumiIntroController(), tag: widget.heroTag); Get.put(BangumiIntroController(), tag: widget.heroTag);
videoDetailCtr = Get.find<VideoDetailController>(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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
super.build(context);
final ThemeData theme = Theme.of(context); final ThemeData theme = Theme.of(context);
bool isLandscape = final bangumiItem = bangumiIntroController.bangumiItem;
final isLandscape =
MediaQuery.of(context).orientation == Orientation.landscape; MediaQuery.of(context).orientation == Orientation.landscape;
return SliverPadding( return SliverPadding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
@@ -188,246 +80,196 @@ class _BangumiInfoState extends State<BangumiInfo> {
bottom: StyleString.safeSpace + MediaQuery.paddingOf(context).bottom, bottom: StyleString.safeSpace + MediaQuery.paddingOf(context).bottom,
), ),
sliver: SliverToBoxAdapter( sliver: SliverToBoxAdapter(
child: !widget.isLoading || bangumiItem != null child: Column(
? Column( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Row(
Row( crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, children: [
children: [ Stack(
Stack( clipBehavior: Clip.none,
clipBehavior: Clip.none, children: [
children: [ GestureDetector(
GestureDetector( onTap: () {
onTap: () { videoDetailCtr.onViewImage();
videoDetailCtr.onViewImage(); context.imageView(
context.imageView( imgList: [
imgList: [ SourceModel(
SourceModel( url: bangumiItem.cover!,
url: !widget.isLoading )
? widget.bangumiDetail!.cover! ],
: bangumiItem!.cover!, onDismissed: videoDetailCtr.onDismissed,
) );
], },
onDismissed: videoDetailCtr.onDismissed, child: Hero(
); tag: bangumiItem.cover!,
}, child: NetworkImgLayer(
child: Hero( width: isLandscape ? 115 / 0.75 : 115,
tag: !widget.isLoading height: isLandscape ? 115 : 115 / 0.75,
? widget.bangumiDetail!.cover! src: bangumiItem.cover!,
: bangumiItem!.cover!, semanticsLabel: '封面',
child: NetworkImgLayer(
width: isLandscape ? 115 / 0.75 : 115,
height: isLandscape ? 115 : 115 / 0.75,
src: !widget.isLoading
? widget.bangumiDetail!.cover!
: bangumiItem!.cover!,
semanticsLabel: '封面',
),
),
),
if (bangumiItem != null &&
bangumiItem!.rating != null)
PBadge(
text:
'评分 ${!widget.isLoading ? widget.bangumiDetail!.rating!['score']! : bangumiItem!.rating!['score']!}',
top: null,
right: 6,
bottom: 6,
left: null,
),
],
),
const SizedBox(width: 10),
Expanded(
child: GestureDetector(
onTap: showIntroDetail,
behavior: HitTestBehavior.opaque,
child: SizedBox(
height: isLandscape ? 115 : 115 / 0.75,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
!widget.isLoading
? widget.bangumiDetail!.title!
: bangumiItem!.title!,
style: const TextStyle(
fontSize: 16,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 20),
Obx(
() => FilledButton.tonal(
style: FilledButton.styleFrom(
tapTargetSize:
MaterialTapTargetSize.shrinkWrap,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
visualDensity: VisualDensity.compact,
foregroundColor:
bangumiIntroController
.isFollowed.value
? theme.colorScheme.outline
: null,
backgroundColor:
bangumiIntroController
.isFollowed.value
? theme.colorScheme
.onInverseSurface
: null,
),
onPressed: bangumiIntroController
.followStatus.value ==
-1
? null
: () {
if (bangumiIntroController
.isFollowed.value) {
showPgcFollowDialog(
context: context,
type: bangumiIntroController
.type,
followStatus:
bangumiIntroController
.followStatus.value,
onUpdateStatus:
(followStatus) {
if (followStatus == -1) {
bangumiIntroController
.bangumiDel();
} else {
bangumiIntroController
.bangumiUpdate(
followStatus);
}
},
);
} else {
bangumiIntroController
.bangumiAdd();
}
},
child: Text(
bangumiIntroController
.isFollowed.value
? '${bangumiIntroController.type}'
: '${bangumiIntroController.type}',
),
),
),
],
),
Row(
children: [
StatView(
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.isLoading
? widget.bangumiDetail!.stat!['views']
: bangumiItem!.stat!['views']),
),
const SizedBox(width: 6),
StatDanMu(
context: context,
theme: 'gray',
value: Utils.numFormat(!widget.isLoading
? widget
.bangumiDetail!.stat!['danmakus']
: bangumiItem!.stat!['danmakus']),
),
if (isLandscape) ...[
const SizedBox(width: 6),
AreasAndPubTime(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
const SizedBox(width: 6),
NewEpDesc(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
]
],
),
SizedBox(height: isLandscape ? 2 : 6),
if (!isLandscape)
AreasAndPubTime(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
if (!isLandscape)
NewEpDesc(
widget: widget,
bangumiItem: bangumiItem,
theme: theme,
),
const Spacer(),
Text(
'简介:${!widget.isLoading ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}',
maxLines: isLandscape ? 2 : 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.outline,
),
),
],
),
),
), ),
), ),
], ),
), if (bangumiItem.rating != null)
const SizedBox(height: 6), PBadge(
// 点赞收藏转发 布局样式2 text: '评分 ${bangumiItem.rating!['score']!}',
actionGrid(theme, bangumiIntroController), top: null,
// 番剧分p right: 6,
if ((!widget.isLoading && bottom: 6,
widget.bangumiDetail!.episodes!.isNotEmpty) || left: null,
bangumiItem != null && ),
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),
changeFuc: bangumiIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
newEp: bangumiItem?.newEp,
)
], ],
],
)
: const SizedBox(
height: 100,
child: Center(
child: CircularProgressIndicator(),
), ),
), const SizedBox(width: 10),
Expanded(
child: GestureDetector(
onTap: () => widget.showIntroDetail(
bangumiItem, bangumiIntroController.videoTags),
behavior: HitTestBehavior.opaque,
child: SizedBox(
height: isLandscape ? 115 : 115 / 0.75,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
bangumiItem.title!,
style: const TextStyle(
fontSize: 16,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 20),
Obx(
() => FilledButton.tonal(
style: FilledButton.styleFrom(
tapTargetSize:
MaterialTapTargetSize.shrinkWrap,
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 10,
),
visualDensity: VisualDensity.compact,
foregroundColor:
bangumiIntroController.isFollowed.value
? theme.colorScheme.outline
: null,
backgroundColor:
bangumiIntroController.isFollowed.value
? theme.colorScheme.onInverseSurface
: null,
),
onPressed: bangumiIntroController
.followStatus.value ==
-1
? null
: () {
if (bangumiIntroController
.isFollowed.value) {
showPgcFollowDialog(
context: context,
type: bangumiIntroController.type,
followStatus:
bangumiIntroController
.followStatus.value,
onUpdateStatus: (followStatus) {
if (followStatus == -1) {
bangumiIntroController
.bangumiDel();
} else {
bangumiIntroController
.bangumiUpdate(
followStatus);
}
},
);
} else {
bangumiIntroController.bangumiAdd();
}
},
child: Text(
bangumiIntroController.isFollowed.value
? '${bangumiIntroController.type}'
: '${bangumiIntroController.type}',
),
),
),
],
),
Row(
children: [
StatView(
context: context,
theme: 'gray',
value:
Utils.numFormat(bangumiItem.stat!['views']),
),
const SizedBox(width: 6),
StatDanMu(
context: context,
theme: 'gray',
value: Utils.numFormat(
bangumiItem.stat!['danmakus']),
),
if (isLandscape) ...[
const SizedBox(width: 6),
areasAndPubTime(theme, bangumiItem),
const SizedBox(width: 6),
newEpDesc(theme, bangumiItem),
]
],
),
SizedBox(height: isLandscape ? 2 : 6),
if (!isLandscape) ...[
areasAndPubTime(theme, bangumiItem),
newEpDesc(theme, bangumiItem),
],
const Spacer(),
Text(
'简介:${bangumiItem.evaluate!}',
maxLines: isLandscape ? 2 : 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: theme.colorScheme.outline,
),
),
],
),
),
),
),
],
),
const SizedBox(height: 6),
// 点赞收藏转发 布局样式2
actionGrid(theme, bangumiItem, bangumiIntroController),
// 番剧分p
if (bangumiItem.episodes!.isNotEmpty) ...[
BangumiPanel(
heroTag: widget.heroTag,
pages: bangumiItem.episodes!,
cid: videoDetailCtr.cid.value,
changeFuc: bangumiIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
newEp: bangumiItem.newEp,
)
],
],
),
), ),
); );
} }
Widget actionGrid( Widget actionGrid(ThemeData theme, BangumiInfoModel bangumiItem,
ThemeData theme, BangumiIntroController bangumiIntroController) { BangumiIntroController bangumiIntroController) {
return Material( return Material(
color: theme.colorScheme.surface, color: theme.colorScheme.surface,
child: Padding( child: Padding(
@@ -445,13 +287,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
handleState(bangumiIntroController.actionLikeVideo), handleState(bangumiIntroController.actionLikeVideo),
onLongPress: bangumiIntroController.actionOneThree, onLongPress: bangumiIntroController.actionOneThree,
selectStatus: bangumiIntroController.hasLike.value, selectStatus: bangumiIntroController.hasLike.value,
loadingStatus: false, isLoading: false,
semanticsLabel: '点赞', semanticsLabel: '点赞',
text: !widget.isLoading text: Utils.numFormat(bangumiItem.stat!['likes']!),
? Utils.numFormat(widget.bangumiDetail!.stat!['likes']!)
: Utils.numFormat(
bangumiItem!.stat!['likes']!,
),
needAnim: true, needAnim: true,
hasTriple: bangumiIntroController.hasLike.value && hasTriple: bangumiIntroController.hasLike.value &&
bangumiIntroController.hasCoin && bangumiIntroController.hasCoin &&
@@ -476,13 +314,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
onTap: () => onTap: () =>
handleState(bangumiIntroController.actionCoinVideo), handleState(bangumiIntroController.actionCoinVideo),
selectStatus: bangumiIntroController.hasCoin, selectStatus: bangumiIntroController.hasCoin,
loadingStatus: false, isLoading: false,
semanticsLabel: '投币', semanticsLabel: '投币',
text: !widget.isLoading text: Utils.numFormat(bangumiItem.stat!['coins']!),
? Utils.numFormat(widget.bangumiDetail!.stat!['coins']!)
: Utils.numFormat(
bangumiItem!.stat!['coins']!,
),
needAnim: true, needAnim: true,
), ),
), ),
@@ -496,14 +330,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
onLongPress: () => bangumiIntroController onLongPress: () => bangumiIntroController
.showFavBottomSheet(context, type: 'longPress'), .showFavBottomSheet(context, type: 'longPress'),
selectStatus: bangumiIntroController.hasFav.value, selectStatus: bangumiIntroController.hasFav.value,
loadingStatus: false, isLoading: false,
semanticsLabel: '收藏', semanticsLabel: '收藏',
text: !widget.isLoading text: Utils.numFormat(bangumiItem.stat!['favorite']!),
? Utils.numFormat(
widget.bangumiDetail!.stat!['favorite']!)
: Utils.numFormat(
bangumiItem!.stat!['favorite']!,
),
needAnim: true, needAnim: true,
), ),
), ),
@@ -512,21 +341,18 @@ class _BangumiInfoState extends State<BangumiInfo> {
selectIcon: const Icon(FontAwesomeIcons.reply), selectIcon: const Icon(FontAwesomeIcons.reply),
onTap: () => videoDetailCtr.tabCtr.animateTo(1), onTap: () => videoDetailCtr.tabCtr.animateTo(1),
selectStatus: false, selectStatus: false,
loadingStatus: false, isLoading: false,
semanticsLabel: '评论', semanticsLabel: '评论',
text: !widget.isLoading text: Utils.numFormat(bangumiItem.stat!['reply']!),
? Utils.numFormat(widget.bangumiDetail!.stat!['reply']!)
: Utils.numFormat(bangumiItem!.stat!['reply']!),
), ),
ActionItem( ActionItem(
icon: const Icon(FontAwesomeIcons.shareFromSquare), icon: const Icon(FontAwesomeIcons.shareFromSquare),
onTap: () => bangumiIntroController.actionShareVideo(context), onTap: () => bangumiIntroController.actionShareVideo(context),
selectStatus: false, selectStatus: false,
loadingStatus: false, isLoading: false,
semanticsLabel: '转发', semanticsLabel: '转发',
text: !widget.isLoading text: Utils.numFormat(bangumiItem.stat!['share']!),
? Utils.numFormat(widget.bangumiDetail!.stat!['share']!) ),
: Utils.numFormat(bangumiItem!.stat!['share']!)),
], ],
), ),
), ),
@@ -535,95 +361,72 @@ class _BangumiInfoState extends State<BangumiInfo> {
} }
Widget actionRow( Widget actionRow(
BuildContext context, BangumiInfoModel bangumiItem,
BangumiIntroController bangumiIntroController, BangumiIntroController bangumiIntroController,
VideoDetailController videoDetailCtr, VideoDetailController videoDetailCtr,
) { ) {
return Row(children: [ return Row(
Obx( children: [
() => ActionRowItem( Obx(
icon: const Icon(FontAwesomeIcons.thumbsUp), () => ActionRowItem(
onTap: () => handleState(bangumiIntroController.actionLikeVideo), icon: const Icon(FontAwesomeIcons.thumbsUp),
selectStatus: bangumiIntroController.hasLike.value, onTap: () => handleState(bangumiIntroController.actionLikeVideo),
loadingStatus: widget.isLoading, selectStatus: bangumiIntroController.hasLike.value,
text: !widget.isLoading isLoading: false,
? widget.bangumiDetail!.stat!['likes']!.toString() text: bangumiItem.stat!['likes']!.toString(),
: '-', ),
), ),
), const SizedBox(width: 8),
const SizedBox(width: 8), Obx(
Obx( () => ActionRowItem(
() => ActionRowItem( icon: const Icon(FontAwesomeIcons.b),
icon: const Icon(FontAwesomeIcons.b), onTap: () => handleState(bangumiIntroController.actionCoinVideo),
onTap: () => handleState(bangumiIntroController.actionCoinVideo), selectStatus: bangumiIntroController.hasCoin,
selectStatus: bangumiIntroController.hasCoin, isLoading: false,
loadingStatus: widget.isLoading, text: bangumiItem.stat!['coins']!.toString(),
text: !widget.isLoading ),
? widget.bangumiDetail!.stat!['coins']!.toString()
: '-',
), ),
), const SizedBox(width: 8),
const SizedBox(width: 8), Obx(
Obx( () => ActionRowItem(
() => ActionRowItem( icon: const Icon(FontAwesomeIcons.heart),
icon: const Icon(FontAwesomeIcons.heart), onTap: () => bangumiIntroController.showFavBottomSheet(context),
onTap: () => bangumiIntroController.showFavBottomSheet(context), onLongPress: () => bangumiIntroController
onLongPress: () => bangumiIntroController.showFavBottomSheet(context, .showFavBottomSheet(context, type: 'longPress'),
type: 'longPress'), selectStatus: bangumiIntroController.hasFav.value,
selectStatus: bangumiIntroController.hasFav.value, isLoading: false,
loadingStatus: widget.isLoading, text: bangumiItem.stat!['favorite']!.toString(),
text: !widget.isLoading ),
? widget.bangumiDetail!.stat!['favorite']!.toString()
: '-',
), ),
), const SizedBox(width: 8),
const SizedBox(width: 8), ActionRowItem(
ActionRowItem( icon: const Icon(FontAwesomeIcons.comment),
icon: const Icon(FontAwesomeIcons.comment), onTap: () {
onTap: () { videoDetailCtr.tabCtr.animateTo(1);
videoDetailCtr.tabCtr.animateTo(1); },
}, selectStatus: false,
selectStatus: false, isLoading: false,
loadingStatus: widget.isLoading, text: bangumiItem.stat!['reply']!.toString(),
text: !widget.isLoading ),
? widget.bangumiDetail!.stat!['reply']!.toString() const SizedBox(width: 8),
: '-', ActionRowItem(
),
const SizedBox(width: 8),
ActionRowItem(
icon: const Icon(FontAwesomeIcons.share), icon: const Icon(FontAwesomeIcons.share),
onTap: () => bangumiIntroController.actionShareVideo(context), onTap: () => bangumiIntroController.actionShareVideo(context),
selectStatus: false, selectStatus: false,
loadingStatus: widget.isLoading, isLoading: false,
text: '转发'), text: '转发',
]); ),
],
);
} }
}
class AreasAndPubTime extends StatelessWidget { Widget areasAndPubTime(ThemeData theme, BangumiInfoModel bangumiItem) {
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) {
return Row( return Row(
children: [ children: [
Text( Text(
!widget.isLoading (bangumiItem.areas!.isNotEmpty
? (widget.bangumiDetail!.areas!.isNotEmpty ? bangumiItem.areas!.first['name']
? widget.bangumiDetail!.areas!.first['name'] : ''),
: '')
: (bangumiItem!.areas!.isNotEmpty
? bangumiItem!.areas!.first['name']
: ''),
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: theme.colorScheme.outline, color: theme.colorScheme.outline,
@@ -631,9 +434,7 @@ class AreasAndPubTime extends StatelessWidget {
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
!widget.isLoading bangumiItem.publish!['pub_time_show'],
? widget.bangumiDetail!.publish!['pub_time_show']
: bangumiItem!.publish!['pub_time_show'],
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: theme.colorScheme.outline, color: theme.colorScheme.outline,
@@ -642,26 +443,10 @@ class AreasAndPubTime extends StatelessWidget {
], ],
); );
} }
}
class NewEpDesc extends StatelessWidget { Widget newEpDesc(ThemeData theme, BangumiInfoModel bangumiItem) {
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) {
return Text( return Text(
!widget.isLoading bangumiItem.newEp!['desc'],
? widget.bangumiDetail!.newEp!['desc']
: bangumiItem!.newEp!['desc'],
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
color: theme.colorScheme.outline, color: theme.colorScheme.outline,

View File

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

View File

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

View File

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

View File

@@ -4,9 +4,9 @@ import 'package:flutter/material.dart';
class MenuRow extends StatelessWidget { class MenuRow extends StatelessWidget {
const MenuRow({ const MenuRow({
super.key, super.key,
this.loadingStatus, this.isLoading,
}); });
final bool? loadingStatus; final bool? isLoading;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -20,28 +20,28 @@ class MenuRow extends StatelessWidget {
child: Row(children: [ child: Row(children: [
ActionRowLineItem( ActionRowLineItem(
onTap: () => {}, onTap: () => {},
loadingStatus: loadingStatus, isLoading: isLoading,
text: '推荐', text: '推荐',
selectStatus: false, selectStatus: false,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionRowLineItem( ActionRowLineItem(
onTap: () => {}, onTap: () => {},
loadingStatus: loadingStatus, isLoading: isLoading,
text: '弹幕', text: '弹幕',
selectStatus: false, selectStatus: false,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionRowLineItem( ActionRowLineItem(
onTap: () => {}, onTap: () => {},
loadingStatus: loadingStatus, isLoading: isLoading,
text: '评论列表', text: '评论列表',
selectStatus: false, selectStatus: false,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
ActionRowLineItem( ActionRowLineItem(
onTap: () => {}, onTap: () => {},
loadingStatus: loadingStatus, isLoading: isLoading,
text: '播放列表', text: '播放列表',
selectStatus: false, selectStatus: false,
), ),
@@ -51,7 +51,7 @@ class MenuRow extends StatelessWidget {
} }
Widget actionRowLineItem( Widget actionRowLineItem(
ThemeData theme, Function? onTap, bool? loadingStatus, String? text, ThemeData theme, Function? onTap, bool? isLoading, String? text,
{bool selectStatus = false}) { {bool selectStatus = false}) {
return Material( return Material(
color: selectStatus color: selectStatus
@@ -78,7 +78,7 @@ class MenuRow extends StatelessWidget {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
AnimatedOpacity( AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1, opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
child: Text( child: Text(
text!, text!,
@@ -103,13 +103,13 @@ class ActionRowLineItem extends StatelessWidget {
required this.selectStatus, required this.selectStatus,
this.onTap, this.onTap,
this.text, this.text,
this.loadingStatus = false, this.isLoading = false,
this.iconData, this.iconData,
this.icon, this.icon,
}); });
final bool selectStatus; final bool selectStatus;
final Function? onTap; final Function? onTap;
final bool? loadingStatus; final bool? isLoading;
final String? text; final String? text;
final IconData? iconData; final IconData? iconData;
final Widget? icon; final Widget? icon;
@@ -152,7 +152,7 @@ class ActionRowLineItem extends StatelessWidget {
else if (icon != null) else if (icon != null)
icon!, icon!,
AnimatedOpacity( AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1, opacity: isLoading! ? 0 : 1,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
child: Text( child: Text(
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/http/loading_state.dart';
import 'package:PiliPlus/main.dart'; import 'package:PiliPlus/main.dart';
import 'package:PiliPlus/models/bangumi/info.dart' as bangumi; 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/episode_panel_type.dart';
import 'package:PiliPlus/models/common/reply/reply_type.dart'; import 'package:PiliPlus/models/common/reply/reply_type.dart';
import 'package:PiliPlus/models/common/search_type.dart'; import 'package:PiliPlus/models/common/search_type.dart';
@@ -103,8 +102,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.plPlayerController.horizontalPreview; videoDetailController.plPlayerController.horizontalPreview;
StreamSubscription? _listenerDetail; StreamSubscription? _listenerDetail;
StreamSubscription? _listenerLoadingState;
StreamSubscription? _listenerCid;
StreamSubscription? _listenerFS; StreamSubscription? _listenerFS;
Box get setting => GStorage.setting; Box get setting => GStorage.setting;
@@ -137,23 +134,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
}); });
if (videoDetailController.videoType == SearchType.media_bangumi) { if (videoDetailController.videoType == SearchType.media_bangumi) {
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag); 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 = autoExitFullscreen =
setting.get(SettingBoxKey.enableAutoExit, defaultValue: true); setting.get(SettingBoxKey.enableAutoExit, defaultValue: true);
@@ -337,8 +317,6 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
@override @override
void dispose() { void dispose() {
_listenerDetail?.cancel(); _listenerDetail?.cancel();
_listenerLoadingState?.cancel();
_listenerCid?.cancel();
_listenerFS?.cancel(); _listenerFS?.cancel();
videoDetailController.skipTimer?.cancel(); videoDetailController.skipTimer?.cancel();

View File

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