mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-21 17:46:24 +08:00
refa: pgc intro
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -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'];
|
||||
if (isLogin) {
|
||||
if (seasonId != null) {
|
||||
queryIsFollowed();
|
||||
}
|
||||
if (epId != null) {
|
||||
queryBangumiLikeCoinFav();
|
||||
}
|
||||
}
|
||||
userInfo = GStorage.userInfo.get('userInfoCache');
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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,246 +80,196 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
||||
bottom: StyleString.safeSpace + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: !widget.isLoading || bangumiItem != null
|
||||
? Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
videoDetailCtr.onViewImage();
|
||||
context.imageView(
|
||||
imgList: [
|
||||
SourceModel(
|
||||
url: !widget.isLoading
|
||||
? widget.bangumiDetail!.cover!
|
||||
: bangumiItem!.cover!,
|
||||
)
|
||||
],
|
||||
onDismissed: videoDetailCtr.onDismissed,
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: !widget.isLoading
|
||||
? widget.bangumiDetail!.cover!
|
||||
: bangumiItem!.cover!,
|
||||
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,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
videoDetailCtr.onViewImage();
|
||||
context.imageView(
|
||||
imgList: [
|
||||
SourceModel(
|
||||
url: bangumiItem.cover!,
|
||||
)
|
||||
],
|
||||
onDismissed: videoDetailCtr.onDismissed,
|
||||
);
|
||||
},
|
||||
child: Hero(
|
||||
tag: bangumiItem.cover!,
|
||||
child: NetworkImgLayer(
|
||||
width: isLandscape ? 115 / 0.75 : 115,
|
||||
height: isLandscape ? 115 : 115 / 0.75,
|
||||
src: bangumiItem.cover!,
|
||||
semanticsLabel: '封面',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
// 点赞收藏转发 布局样式2
|
||||
actionGrid(theme, bangumiIntroController),
|
||||
// 番剧分p
|
||||
if ((!widget.isLoading &&
|
||||
widget.bangumiDetail!.episodes!.isNotEmpty) ||
|
||||
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,
|
||||
)
|
||||
),
|
||||
if (bangumiItem.rating != null)
|
||||
PBadge(
|
||||
text: '评分 ${bangumiItem.rating!['score']!}',
|
||||
top: null,
|
||||
right: 6,
|
||||
bottom: 6,
|
||||
left: null,
|
||||
),
|
||||
],
|
||||
],
|
||||
)
|
||||
: 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(
|
||||
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,
|
||||
semanticsLabel: '转发',
|
||||
text: !widget.isLoading
|
||||
? Utils.numFormat(widget.bangumiDetail!.stat!['share']!)
|
||||
: Utils.numFormat(bangumiItem!.stat!['share']!)),
|
||||
icon: const Icon(FontAwesomeIcons.shareFromSquare),
|
||||
onTap: () => bangumiIntroController.actionShareVideo(context),
|
||||
selectStatus: false,
|
||||
isLoading: false,
|
||||
semanticsLabel: '转发',
|
||||
text: Utils.numFormat(bangumiItem.stat!['share']!),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -535,95 +361,72 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
||||
}
|
||||
|
||||
Widget actionRow(
|
||||
BuildContext context,
|
||||
BangumiInfoModel bangumiItem,
|
||||
BangumiIntroController bangumiIntroController,
|
||||
VideoDetailController videoDetailCtr,
|
||||
) {
|
||||
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()
|
||||
: '-',
|
||||
return Row(
|
||||
children: [
|
||||
Obx(
|
||||
() => ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.thumbsUp),
|
||||
onTap: () => handleState(bangumiIntroController.actionLikeVideo),
|
||||
selectStatus: bangumiIntroController.hasLike.value,
|
||||
isLoading: false,
|
||||
text: bangumiItem.stat!['likes']!.toString(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Obx(
|
||||
() => ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.b),
|
||||
onTap: () => handleState(bangumiIntroController.actionCoinVideo),
|
||||
selectStatus: bangumiIntroController.hasCoin,
|
||||
loadingStatus: widget.isLoading,
|
||||
text: !widget.isLoading
|
||||
? widget.bangumiDetail!.stat!['coins']!.toString()
|
||||
: '-',
|
||||
const SizedBox(width: 8),
|
||||
Obx(
|
||||
() => ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.b),
|
||||
onTap: () => handleState(bangumiIntroController.actionCoinVideo),
|
||||
selectStatus: bangumiIntroController.hasCoin,
|
||||
isLoading: false,
|
||||
text: bangumiItem.stat!['coins']!.toString(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Obx(
|
||||
() => ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.heart),
|
||||
onTap: () => bangumiIntroController.showFavBottomSheet(context),
|
||||
onLongPress: () => bangumiIntroController.showFavBottomSheet(context,
|
||||
type: 'longPress'),
|
||||
selectStatus: bangumiIntroController.hasFav.value,
|
||||
loadingStatus: widget.isLoading,
|
||||
text: !widget.isLoading
|
||||
? widget.bangumiDetail!.stat!['favorite']!.toString()
|
||||
: '-',
|
||||
const SizedBox(width: 8),
|
||||
Obx(
|
||||
() => ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.heart),
|
||||
onTap: () => bangumiIntroController.showFavBottomSheet(context),
|
||||
onLongPress: () => bangumiIntroController
|
||||
.showFavBottomSheet(context, type: 'longPress'),
|
||||
selectStatus: bangumiIntroController.hasFav.value,
|
||||
isLoading: false,
|
||||
text: bangumiItem.stat!['favorite']!.toString(),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.comment),
|
||||
onTap: () {
|
||||
videoDetailCtr.tabCtr.animateTo(1);
|
||||
},
|
||||
selectStatus: false,
|
||||
loadingStatus: widget.isLoading,
|
||||
text: !widget.isLoading
|
||||
? widget.bangumiDetail!.stat!['reply']!.toString()
|
||||
: '-',
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
ActionRowItem(
|
||||
const SizedBox(width: 8),
|
||||
ActionRowItem(
|
||||
icon: const Icon(FontAwesomeIcons.comment),
|
||||
onTap: () {
|
||||
videoDetailCtr.tabCtr.animateTo(1);
|
||||
},
|
||||
selectStatus: false,
|
||||
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,
|
||||
color: theme.colorScheme.outline,
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user