mod: 历史记录跳转番剧播放

This commit is contained in:
guozhigq
2023-08-04 18:29:38 +08:00
parent c961dc6cf5
commit 01829ad965
5 changed files with 330 additions and 250 deletions

View File

@ -66,6 +66,7 @@ class VideoDetailData {
HonorReply? honorReply; HonorReply? honorReply;
String? likeIcon; String? likeIcon;
bool? needJumpBv; bool? needJumpBv;
String? epId;
VideoDetailData({ VideoDetailData({
this.bvid, this.bvid,
@ -101,6 +102,7 @@ class VideoDetailData {
this.honorReply, this.honorReply,
this.likeIcon, this.likeIcon,
this.needJumpBv, this.needJumpBv,
this.epId,
}); });
VideoDetailData.fromJson(Map<String, dynamic> json) { VideoDetailData.fromJson(Map<String, dynamic> json) {
@ -150,6 +152,15 @@ class VideoDetailData {
: HonorReply.fromJson(json["honor_reply"]); : HonorReply.fromJson(json["honor_reply"]);
likeIcon = json["like_icon"]; likeIcon = json["like_icon"];
needJumpBv = json["need_jump_bv"]; needJumpBv = json["need_jump_bv"];
if (json['redirect_url'] != null) {
RegExp regex = RegExp(r'\d+');
Iterable<Match> matches = regex.allMatches(json['redirect_url']);
List<String> numbers = [];
for (Match match in matches) {
numbers.add(match.group(0)!);
}
epId = numbers[0];
}
} }
Map<String, dynamic> toJson() => { Map<String, dynamic> toJson() => {

View File

@ -18,7 +18,12 @@ import 'package:share_plus/share_plus.dart';
class BangumiIntroController extends GetxController { class BangumiIntroController extends GetxController {
// 视频bvid // 视频bvid
String bvid = Get.parameters['bvid']!; String bvid = Get.parameters['bvid']!;
int seasonId = int.parse(Get.parameters['seasonId']!); var seasonId = Get.parameters['seasonId'] != null
? int.parse(Get.parameters['seasonId']!)
: null;
var epId = Get.parameters['epId'] != null
? int.parse(Get.parameters['epId']!)
: null;
// 是否预渲染 骨架屏 // 是否预渲染 骨架屏
bool preRender = false; bool preRender = false;
@ -84,9 +89,7 @@ class BangumiIntroController extends GetxController {
// 获取番剧简介&选集 // 获取番剧简介&选集
Future queryBangumiIntro() async { Future queryBangumiIntro() async {
print('🐶🐶: $seasonId'); var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId);
var result = await SearchHttp.bangumiInfo(seasonId: seasonId);
print("🐶🐶:${result['data']}");
if (result['status']) { if (result['status']) {
bangumiDetail.value = result['data']; bangumiDetail.value = result['data'];
} }

View File

@ -86,7 +86,7 @@ class BangumiInfo extends StatefulWidget {
} }
class _BangumiInfoState extends State<BangumiInfo> { class _BangumiInfoState extends State<BangumiInfo> {
late BangumiInfoModel bangumiItem; late BangumiInfoModel? bangumiItem;
final BangumiIntroController bangumiIntroController = final BangumiIntroController bangumiIntroController =
Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']); Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']);
bool isExpand = false; bool isExpand = false;
@ -98,7 +98,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
bangumiItem = bangumiIntroController.bangumiItem!; bangumiItem = bangumiIntroController.bangumiItem;
videoDetailCtr = videoDetailCtr =
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']); Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
sheetHeight = localCache.get('sheetHeight'); sheetHeight = localCache.get('sheetHeight');
@ -139,176 +139,189 @@ class _BangumiInfoState extends State<BangumiInfo> {
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13), left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13),
sliver: SliverToBoxAdapter( sliver: SliverToBoxAdapter(
child: Column( child: !widget.loadingStatus || bangumiItem != null
crossAxisAlignment: CrossAxisAlignment.start, ? Column(
children: [ crossAxisAlignment: CrossAxisAlignment.start,
Row( children: [
mainAxisAlignment: MainAxisAlignment.start, Row(
crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ crossAxisAlignment: CrossAxisAlignment.start,
NetworkImgLayer( children: [
width: 105, NetworkImgLayer(
height: 160, width: 105,
src: !widget.loadingStatus height: 160,
? widget.bangumiDetail!.cover! src: !widget.loadingStatus
: bangumiItem.cover!, ? widget.bangumiDetail!.cover!
), : bangumiItem!.cover!,
const SizedBox(width: 10),
Expanded(
child: InkWell(
onTap: () => showIntroDetail(),
child: SizedBox(
height: 158,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text(
!widget.loadingStatus
? widget.bangumiDetail!.title!
: bangumiItem.title!,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 20),
SizedBox(
width: 34,
height: 34,
child: IconButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.zero),
backgroundColor:
MaterialStateProperty.resolveWith(
(states) {
return t.colorScheme.primaryContainer
.withOpacity(0.7);
}),
),
onPressed: () {},
icon: Icon(
Icons.favorite_border_rounded,
color: t.colorScheme.primary,
size: 22,
),
),
),
],
),
Row(
children: [
// const SizedBox(width: 6),
StatView(
theme: 'gray',
view: !widget.loadingStatus
? widget.bangumiDetail!.stat!['views']
: bangumiItem.stat!['views'],
size: 'medium',
),
const SizedBox(width: 6),
StatDanMu(
theme: 'gray',
danmu: !widget.loadingStatus
? widget.bangumiDetail!.stat!['danmakus']
: bangumiItem.stat!['danmakus'],
size: 'medium',
),
],
),
const SizedBox(height: 2),
Row(
children: [
Text(
!widget.loadingStatus
? widget.bangumiDetail!.areas!.first['name']
: bangumiItem.areas!.first['name'],
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
const SizedBox(width: 6),
Text(
!widget.loadingStatus
? widget.bangumiDetail!
.publish!['pub_time_show']
: bangumiItem.publish!['pub_time_show'],
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
const SizedBox(width: 6),
Text(
!widget.loadingStatus
? widget.bangumiDetail!.newEp!['desc']
: bangumiItem.newEp!['desc'],
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
],
),
const SizedBox(height: 10),
Text(
'简介:${!widget.loadingStatus ? widget.bangumiDetail!.evaluate! : bangumiItem.evaluate!}',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
const Spacer(),
Text(
'评分 ${!widget.loadingStatus ? widget.bangumiDetail!.rating!['score']! : bangumiItem.rating!['score']!}',
style: TextStyle(
fontSize: 13,
color: t.colorScheme.primary,
),
),
],
), ),
), const SizedBox(width: 10),
Expanded(
child: InkWell(
onTap: () => showIntroDetail(),
child: SizedBox(
height: 158,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text(
!widget.loadingStatus
? widget.bangumiDetail!.title!
: bangumiItem!.title!,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 20),
SizedBox(
width: 34,
height: 34,
child: IconButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.zero),
backgroundColor:
MaterialStateProperty.resolveWith(
(states) {
return t
.colorScheme.primaryContainer
.withOpacity(0.7);
}),
),
onPressed: () {},
icon: Icon(
Icons.favorite_border_rounded,
color: t.colorScheme.primary,
size: 22,
),
),
),
],
),
Row(
children: [
// const SizedBox(width: 6),
StatView(
theme: 'gray',
view: !widget.loadingStatus
? widget.bangumiDetail!.stat!['views']
: bangumiItem!.stat!['views'],
size: 'medium',
),
const SizedBox(width: 6),
StatDanMu(
theme: 'gray',
danmu: !widget.loadingStatus
? widget
.bangumiDetail!.stat!['danmakus']
: bangumiItem!.stat!['danmakus'],
size: 'medium',
),
],
),
const SizedBox(height: 2),
Row(
children: [
Text(
!widget.loadingStatus
? widget.bangumiDetail!.areas!
.first['name']
: bangumiItem!.areas!.first['name'],
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
const SizedBox(width: 6),
Text(
!widget.loadingStatus
? widget.bangumiDetail!
.publish!['pub_time_show']
: bangumiItem!
.publish!['pub_time_show'],
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
const SizedBox(width: 6),
Text(
!widget.loadingStatus
? widget.bangumiDetail!.newEp!['desc']
: bangumiItem!.newEp!['desc'],
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
],
),
const SizedBox(height: 10),
Text(
'简介:${!widget.loadingStatus ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
const Spacer(),
if (bangumiItem != null &&
bangumiItem!.rating != null)
Text(
'评分 ${!widget.loadingStatus ? widget.bangumiDetail!.rating!['score']! : bangumiItem!.rating!['score']!}',
style: TextStyle(
fontSize: 13,
color: t.colorScheme.primary,
),
),
],
),
),
),
),
],
), ),
), const SizedBox(height: 6),
], // 点赞收藏转发 布局样式1
), // SingleChildScrollView(
const SizedBox(height: 6), // padding: const EdgeInsets.only(top: 7, bottom: 7),
// 点赞收藏转发 布局样式1 // scrollDirection: Axis.horizontal,
// SingleChildScrollView( // child: actionRow(
// padding: const EdgeInsets.only(top: 7, bottom: 7), // context,
// scrollDirection: Axis.horizontal, // bangumiIntroController,
// child: actionRow( // videoDetailCtr,
// context, // ),
// bangumiIntroController, // ),
// videoDetailCtr, // 点赞收藏转发 布局样式2
// ), actionGrid(context, bangumiIntroController),
// ), // 番剧分p
// 点赞收藏转发 布局样式2 if (!widget.loadingStatus &&
actionGrid(context, bangumiIntroController), widget.bangumiDetail!.episodes!.isNotEmpty) ...[
// 番剧分p BangumiPanel(
if (!widget.loadingStatus && pages: widget.bangumiDetail!.episodes!,
widget.bangumiDetail!.episodes!.isNotEmpty) ...[ cid: widget.bangumiDetail!.episodes!.first.cid,
BangumiPanel( sheetHeight: sheetHeight,
pages: widget.bangumiDetail!.episodes!, changeFuc: (bvid, cid) =>
cid: widget.bangumiDetail!.episodes!.first.cid, bangumiIntroController.changeSeasonOrbangu(bvid, cid),
sheetHeight: sheetHeight, )
changeFuc: (bvid, cid) => ],
bangumiIntroController.changeSeasonOrbangu(bvid, cid), ],
) )
], : const SizedBox(
], height: 100,
), child: Center(
child: CircularProgressIndicator(),
),
),
), ),
); );
} }

View File

@ -143,88 +143,93 @@ class _BangumiPanelState extends State<BangumiPanel> {
SingleChildScrollView( SingleChildScrollView(
padding: const EdgeInsets.only(top: 7, bottom: 7), padding: const EdgeInsets.only(top: 7, bottom: 7),
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Row( child: ConstrainedBox(
children: [ constraints: BoxConstraints(
for (int i = 0; i < widget.pages.length; i++) ...[ minWidth: MediaQuery.of(context).size.width,
Container( ),
width: 150, child: Row(
margin: const EdgeInsets.only(right: 10), children: [
child: Material( for (int i = 0; i < widget.pages.length; i++) ...[
color: Theme.of(context).colorScheme.onInverseSurface, Container(
borderRadius: BorderRadius.circular(6), width: 150,
clipBehavior: Clip.hardEdge, margin: const EdgeInsets.only(right: 10),
child: InkWell( child: Material(
onTap: () async { color: Theme.of(context).colorScheme.onInverseSurface,
if (widget.pages[i].badge != null) { borderRadius: BorderRadius.circular(6),
SmartDialog.showToast('需要大会员'); clipBehavior: Clip.hardEdge,
return; child: InkWell(
} onTap: () async {
await widget.changeFuc!( if (widget.pages[i].badge != null) {
widget.pages[i].bvid, SmartDialog.showToast('需要大会员');
widget.pages[i].cid, return;
); }
currentIndex = i; await widget.changeFuc!(
setState(() {}); widget.pages[i].bvid,
}, widget.pages[i].cid,
child: Padding( );
padding: const EdgeInsets.symmetric( currentIndex = i;
vertical: 8, horizontal: 10), setState(() {});
child: Column( },
crossAxisAlignment: CrossAxisAlignment.start, child: Padding(
children: [ padding: const EdgeInsets.symmetric(
Row( vertical: 8, horizontal: 10),
children: [ child: Column(
if (i == currentIndex) ...[ crossAxisAlignment: CrossAxisAlignment.start,
Image.asset( children: [
'assets/images/live.gif', Row(
color: children: [
Theme.of(context).colorScheme.primary, if (i == currentIndex) ...[
height: 12, Image.asset(
'assets/images/live.gif',
color:
Theme.of(context).colorScheme.primary,
height: 12,
),
const SizedBox(width: 6)
],
Text(
'${i + 1}',
style: TextStyle(
fontSize: 13,
color: i == currentIndex
? Theme.of(context)
.colorScheme
.primary
: Theme.of(context)
.colorScheme
.onSurface),
), ),
const SizedBox(width: 6) const SizedBox(width: 2),
if (widget.pages[i].badge != null) ...[
Image.asset(
'assets/images/big-vip.png',
height: 16,
),
],
], ],
Text( ),
'${i + 1}', const SizedBox(height: 3),
style: TextStyle( Text(
fontSize: 13, widget.pages[i].longTitle!,
color: i == currentIndex maxLines: 1,
? Theme.of(context) style: TextStyle(
.colorScheme fontSize: 13,
.primary color: i == currentIndex
: Theme.of(context) ? Theme.of(context).colorScheme.primary
.colorScheme : Theme.of(context)
.onSurface), .colorScheme
), .onSurface),
const SizedBox(width: 2), overflow: TextOverflow.ellipsis,
if (widget.pages[i].badge != null) ...[ )
Image.asset( ],
'assets/images/big-vip.png', ),
height: 16,
),
],
],
),
const SizedBox(height: 3),
Text(
widget.pages[i].longTitle!,
maxLines: 1,
style: TextStyle(
fontSize: 13,
color: i == currentIndex
? Theme.of(context).colorScheme.primary
: Theme.of(context)
.colorScheme
.onSurface),
overflow: TextOverflow.ellipsis,
)
],
), ),
), ),
), ),
), ),
), ]
] ],
], ),
), ),
) )
], ],

View File

@ -1,10 +1,14 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/constants.dart';
import 'package:pilipala/common/widgets/badge.dart'; import 'package:pilipala/common/widgets/badge.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/http/search.dart'; import 'package:pilipala/http/search.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/bangumi/info.dart';
import 'package:pilipala/models/common/business_type.dart'; import 'package:pilipala/models/common/business_type.dart';
import 'package:pilipala/models/common/search_type.dart';
import 'package:pilipala/models/live/item.dart'; import 'package:pilipala/models/live/item.dart';
import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/id_utils.dart';
import 'package:pilipala/utils/utils.dart'; import 'package:pilipala/utils/utils.dart';
@ -47,6 +51,50 @@ class HistoryItem extends StatelessWidget {
'/liveRoom?roomid=${videoItem.history.oid}', '/liveRoom?roomid=${videoItem.history.oid}',
arguments: {'liveItem': liveItem}, arguments: {'liveItem': liveItem},
); );
} else if (videoItem.badge == '番剧' ||
videoItem.tagName.contains('动画')) {
/// hack
var bvid = videoItem.history.bvid;
if (bvid != null && bvid != '') {
var result = await VideoHttp.videoIntro(bvid: bvid);
if (result['status']) {
String bvid = result['data'].bvid!;
int cid = result['data'].cid!;
String pic = result['data'].pic!;
String heroTag = Utils.makeHeroTag(cid);
Get.toNamed(
'/video?bvid=$bvid&cid=$cid&epId=${result['data'].epId}',
arguments: {
'pic': pic,
'heroTag': heroTag,
'videoType': SearchType.media_bangumi,
},
);
}
} else {
if (videoItem.history.epid != '') {
SmartDialog.showLoading(msg: '获取中...');
var res =
await SearchHttp.bangumiInfo(epId: videoItem.history.epid);
SmartDialog.dismiss();
if (res['status']) {
EpisodeItem episode = res['data'].episodes.first;
String bvid = episode.bvid!;
int cid = episode.cid!;
String pic = episode.cover!;
String heroTag = Utils.makeHeroTag(cid);
Get.toNamed(
'/video?bvid=$bvid&cid=$cid&seasonId=${res['data'].seasonId}',
arguments: {
'pic': pic,
'heroTag': heroTag,
'videoType': SearchType.media_bangumi,
'bangumiItem': res['data'],
},
);
}
}
}
} else { } else {
int cid = videoItem.history.cid ?? int cid = videoItem.history.cid ??
// videoItem.history.oid ?? // videoItem.history.oid ??
@ -150,7 +198,7 @@ class VideoContent extends StatelessWidget {
maxLines: videoItem.videos > 1 ? 1 : 2, maxLines: videoItem.videos > 1 ? 1 : 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
if (videoItem.videos > 1) if (videoItem.showTitle != null)
Text( Text(
videoItem.showTitle, videoItem.showTitle,
textAlign: TextAlign.start, textAlign: TextAlign.start,