Merge branch 'feature-bangumi'

This commit is contained in:
guozhigq
2023-08-06 13:52:01 +08:00
8 changed files with 386 additions and 209 deletions

View File

@ -243,4 +243,10 @@ class Api {
// 移除已观看 // 移除已观看
static const String toViewDel = '/x/v2/history/toview/del'; static const String toViewDel = '/x/v2/history/toview/del';
// 追番
static const String bangumiAdd = '/pgc/web/follow/add';
// 取消追番
static const String bangumiDel = '/pgc/web/follow/del';
} }

View File

@ -351,4 +351,30 @@ class VideoHttp {
'csrf': await Request.getCsrf(), 'csrf': await Request.getCsrf(),
}); });
} }
// 添加追番
static Future bangumiAdd({int? seasonId}) async {
var res = await Request().post(Api.bangumiAdd, queryParameters: {
'season_id': seasonId,
'csrf': await Request.getCsrf(),
});
if (res.data['code'] == 0) {
return {'status': true, 'msg': res.data['result']['toast']};
} else {
return {'status': false, 'msg': res.data['result']['toast']};
}
}
// 取消追番
static Future bangumiDel({int? seasonId}) async {
var res = await Request().post(Api.bangumiDel, queryParameters: {
'season_id': seasonId,
'csrf': await Request.getCsrf(),
});
if (res.data['code'] == 0) {
return {'status': true, 'msg': res.data['result']['toast']};
} else {
return {'status': false, 'msg': res.data['result']['toast']};
}
}
} }

View File

@ -38,6 +38,7 @@ class BangumiInfoModel {
this.total, this.total,
this.type, this.type,
this.userStatus, this.userStatus,
this.staff,
}); });
Map? activity; Map? activity;
@ -78,6 +79,7 @@ class BangumiInfoModel {
int? total; int? total;
int? type; int? type;
Map? userStatus; Map? userStatus;
String? staff;
BangumiInfoModel.fromJson(Map<String, dynamic> json) { BangumiInfoModel.fromJson(Map<String, dynamic> json) {
activity = json['activity']; activity = json['activity'];
@ -120,6 +122,7 @@ class BangumiInfoModel {
total = json['total']; total = json['total'];
type = json['type']; type = json['type'];
userStatus = json['user_status']; userStatus = json['user_status'];
staff = json['staff'];
} }
} }

View File

@ -4,7 +4,6 @@ import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.dart';
import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/constants.dart';
import 'package:pilipala/http/search.dart'; import 'package:pilipala/http/search.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/http/video.dart'; import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/bangumi/info.dart'; import 'package:pilipala/models/bangumi/info.dart';
import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/user/fav_folder.dart';
@ -93,6 +92,7 @@ class BangumiIntroController extends GetxController {
var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId); var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId);
if (result['status']) { if (result['status']) {
bangumiDetail.value = result['data']; bangumiDetail.value = result['data'];
epId = bangumiDetail.value.episodes!.first.id;
} }
if (userLogin) { if (userLogin) {
// 获取点赞状态 // 获取点赞状态
@ -101,20 +101,10 @@ class BangumiIntroController extends GetxController {
queryHasCoinVideo(); queryHasCoinVideo();
// 获取收藏状态 // 获取收藏状态
queryHasFavVideo(); queryHasFavVideo();
//
queryFollowStatus();
} }
return result; return result;
} }
// 获取up主粉丝数
Future queryUserStat() async {
var result = await UserHttp.userStat(mid: videoDetail.value.owner!.mid!);
if (result['status']) {
userStat = result['data'];
}
}
// 获取点赞状态 // 获取点赞状态
Future queryHasLikeVideo() async { Future queryHasLikeVideo() async {
var result = await VideoHttp.hasLikeVideo(bvid: bvid); var result = await VideoHttp.hasLikeVideo(bvid: bvid);
@ -138,54 +128,10 @@ class BangumiIntroController extends GetxController {
} }
} }
// 一键三连
Future actionOneThree() async {
if (user.get(UserBoxKey.userMid) == null) {
SmartDialog.showToast('账号未登录');
return;
}
if (hasLike.value && hasCoin.value && hasFav.value) {
// 已点赞、投币、收藏
SmartDialog.showToast('🙏 UP已经收到了');
return false;
}
SmartDialog.show(
useSystem: true,
animationType: SmartAnimationType.centerFade_otherSlide,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('提示'),
content: const Text('一键三连 给UP送温暖'),
actions: [
TextButton(
onPressed: () => SmartDialog.dismiss(),
child: const Text('点错了')),
TextButton(
onPressed: () async {
var result = await VideoHttp.oneThree(bvid: bvid);
if (result['status']) {
hasLike.value = result["data"]["like"];
hasCoin.value = result["data"]["coin"];
hasFav.value = result["data"]["fav"];
SmartDialog.showToast('三连成功 🎉');
} else {
SmartDialog.showToast(result['msg']);
}
SmartDialog.dismiss();
},
child: const Text('确认'),
)
],
);
},
);
}
// (取消)点赞 // (取消)点赞
Future actionLikeVideo() async { Future actionLikeVideo() async {
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']) {
// hasLike.value = result["data"] == 1 ? true : false;
if (!hasLike.value) { if (!hasLike.value) {
SmartDialog.showToast('点赞成功 👍'); SmartDialog.showToast('点赞成功 👍');
hasLike.value = true; hasLike.value = true;
@ -270,10 +216,7 @@ class BangumiIntroController extends GetxController {
delMediaIdsNew.add(i.id); delMediaIdsNew.add(i.id);
} }
} }
} catch (e) { } catch (_) {}
// ignore: avoid_print
print(e);
}
var result = await VideoHttp.favVideo( var result = await VideoHttp.favVideo(
aid: IdUtils.bv2av(bvid), aid: IdUtils.bv2av(bvid),
addIds: addMediaIdsNew.join(','), addIds: addMediaIdsNew.join(','),
@ -297,15 +240,6 @@ class BangumiIntroController extends GetxController {
return result; return result;
} }
Future queryVideoInFolder() async {
var result = await VideoHttp.videoInFolder(
mid: user.get(UserBoxKey.userMid), rid: IdUtils.bv2av(bvid));
if (result['status']) {
favFolderData.value = result['data'];
}
return result;
}
// 选择文件夹 // 选择文件夹
onChoose(bool checkValue, int index) { onChoose(bool checkValue, int index) {
feedBack(); feedBack();
@ -322,15 +256,6 @@ class BangumiIntroController extends GetxController {
favFolderData.refresh(); favFolderData.refresh();
} }
// 查询关注状态
Future queryFollowStatus() async {
var result = await VideoHttp.hasFollow(mid: videoDetail.value.owner!.mid!);
if (result['status']) {
followStatus.value = result['data'];
}
return result;
}
// 修改分P或番剧分集 // 修改分P或番剧分集
Future changeSeasonOrbangu(bvid, cid, aid) async { Future changeSeasonOrbangu(bvid, cid, aid) async {
// 重新获取视频资源 // 重新获取视频资源
@ -348,4 +273,18 @@ class BangumiIntroController extends GetxController {
videoReplyCtr.queryReplyList(type: 'init'); videoReplyCtr.queryReplyList(type: 'init');
} catch (_) {} } catch (_) {}
} }
// 追番
Future bangumiAdd() async {
var result =
await VideoHttp.bangumiAdd(seasonId: bangumiDetail.value.seasonId);
SmartDialog.showToast(result['msg']);
}
// 取消追番
Future bangumiDel() async {
var result =
await VideoHttp.bangumiDel(seasonId: bangumiDetail.value.seasonId);
SmartDialog.showToast(result['msg']);
}
} }

View File

@ -4,6 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:hive/hive.dart'; import 'package:hive/hive.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/http_error.dart'; import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/common/widgets/stat/danmu.dart'; import 'package:pilipala/common/widgets/stat/danmu.dart';
@ -18,6 +19,7 @@ import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/storage.dart'; import 'package:pilipala/utils/storage.dart';
import 'controller.dart'; import 'controller.dart';
import 'widgets/intro_detail.dart';
class BangumiIntroPanel extends StatefulWidget { class BangumiIntroPanel extends StatefulWidget {
const BangumiIntroPanel({super.key}); const BangumiIntroPanel({super.key});
@ -90,7 +92,6 @@ 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;
late VideoDetailController? videoDetailCtr; late VideoDetailController? videoDetailCtr;
Box localCache = GStrorage.localCache; Box localCache = GStrorage.localCache;
@ -124,13 +125,13 @@ class _BangumiInfoState extends State<BangumiInfo> {
// 视频介绍 // 视频介绍
showIntroDetail() { showIntroDetail() {
feedBack(); feedBack();
// showBottomSheet( showBottomSheet(
// context: context, context: context,
// enableDrag: true, enableDrag: true,
// builder: (BuildContext context) { builder: (BuildContext context) {
// return IntroDetail(videoDetail: widget.videoDetail!); return IntroDetail(bangumiDetail: widget.bangumiDetail!);
// }, },
// ); );
} }
@override @override
@ -138,7 +139,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
ThemeData t = Theme.of(context); ThemeData t = Theme.of(context);
return SliverPadding( return SliverPadding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13), left: StyleString.safeSpace, right: StyleString.safeSpace, top: 20),
sliver: SliverToBoxAdapter( sliver: SliverToBoxAdapter(
child: !widget.loadingStatus || bangumiItem != null child: !widget.loadingStatus || bangumiItem != null
? Column( ? Column(
@ -147,6 +148,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
Row( Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
children: [ children: [
NetworkImgLayer( NetworkImgLayer(
width: 105, width: 105,
@ -155,6 +158,17 @@ class _BangumiInfoState extends State<BangumiInfo> {
? widget.bangumiDetail!.cover! ? widget.bangumiDetail!.cover!
: bangumiItem!.cover!, : bangumiItem!.cover!,
), ),
if (bangumiItem != null &&
bangumiItem!.rating != null)
pBadge(
'评分 ${!widget.loadingStatus ? widget.bangumiDetail!.rating!['score']! : bangumiItem!.rating!['score']!}',
context,
null,
6,
6,
null),
],
),
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: InkWell( child: InkWell(
@ -196,7 +210,8 @@ class _BangumiInfoState extends State<BangumiInfo> {
.withOpacity(0.7); .withOpacity(0.7);
}), }),
), ),
onPressed: () {}, onPressed: () =>
bangumiIntroController.bangumiAdd(),
icon: Icon( icon: Icon(
Icons.favorite_border_rounded, Icons.favorite_border_rounded,
color: t.colorScheme.primary, color: t.colorScheme.primary,
@ -208,7 +223,6 @@ class _BangumiInfoState extends State<BangumiInfo> {
), ),
Row( Row(
children: [ children: [
// const SizedBox(width: 6),
StatView( StatView(
theme: 'gray', theme: 'gray',
view: !widget.loadingStatus view: !widget.loadingStatus
@ -227,7 +241,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
), ),
], ],
), ),
const SizedBox(height: 2), const SizedBox(height: 6),
Row( Row(
children: [ children: [
Text( Text(
@ -252,7 +266,9 @@ class _BangumiInfoState extends State<BangumiInfo> {
color: t.colorScheme.outline, color: t.colorScheme.outline,
), ),
), ),
const SizedBox(width: 6), ],
),
// const SizedBox(height: 4),
Text( Text(
!widget.loadingStatus !widget.loadingStatus
? widget.bangumiDetail!.newEp!['desc'] ? widget.bangumiDetail!.newEp!['desc']
@ -262,26 +278,15 @@ class _BangumiInfoState extends State<BangumiInfo> {
color: t.colorScheme.outline, color: t.colorScheme.outline,
), ),
), ),
], // const SizedBox(height: 10),
), const Spacer(),
const SizedBox(height: 10),
Text( Text(
'简介:${!widget.loadingStatus ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}', '简介:${!widget.loadingStatus ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}',
maxLines: 3, maxLines: 3,
overflow: TextOverflow.ellipsis, 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( style: TextStyle(
fontSize: 13, fontSize: 13,
color: t.colorScheme.primary, color: t.colorScheme.outline,
), ),
), ),
], ],

View File

@ -0,0 +1,123 @@
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/common/widgets/stat/danmu.dart';
import 'package:pilipala/common/widgets/stat/view.dart';
import 'package:pilipala/utils/storage.dart';
Box localCache = GStrorage.localCache;
late double sheetHeight;
class IntroDetail extends StatelessWidget {
final dynamic bangumiDetail;
const IntroDetail({
Key? key,
this.bangumiDetail,
}) : super(key: key);
@override
Widget build(BuildContext context) {
sheetHeight = localCache.get('sheetHeight');
TextStyle smallTitle = TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.onBackground,
);
return Container(
color: Theme.of(context).colorScheme.background,
padding: const EdgeInsets.only(left: 14, right: 14),
height: sheetHeight,
child: Column(
children: [
Container(
height: 35,
padding: const EdgeInsets.only(bottom: 2),
child: Center(
child: Container(
width: 32,
height: 3,
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.onSecondaryContainer
.withOpacity(0.5),
borderRadius: const BorderRadius.all(Radius.circular(3))),
),
),
),
Expanded(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
bangumiDetail!.title,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 4),
Row(
children: [
StatView(
theme: 'gray',
view: bangumiDetail!.stat!['views'],
size: 'medium',
),
const SizedBox(width: 6),
StatDanMu(
theme: 'gray',
danmu: bangumiDetail!.stat!['danmakus'],
size: 'medium',
),
],
),
const SizedBox(height: 4),
Row(
children: [
Text(
bangumiDetail!.areas!.first['name'],
style: smallTitle,
),
const SizedBox(width: 6),
Text(
bangumiDetail!.publish!['pub_time_show'],
style: smallTitle,
),
const SizedBox(width: 6),
Text(
bangumiDetail!.newEp!['desc'],
style: smallTitle,
),
],
),
const SizedBox(height: 20),
Text(
'简介:',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 4),
Text(
'${bangumiDetail!.evaluate!}',
style: smallTitle.copyWith(fontSize: 13),
),
const SizedBox(height: 20),
Text(
'声优:',
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 4),
Text(
bangumiDetail.actors,
style: smallTitle.copyWith(fontSize: 13),
),
SizedBox(height: MediaQuery.of(context).padding.bottom + 20)
],
),
),
)
],
),
);
}
}

View File

@ -111,7 +111,7 @@ class _BangumiPanelState extends State<BangumiPanel> {
return Column( return Column(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.only(top: 10), padding: const EdgeInsets.only(top: 10, bottom: 6),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -143,17 +143,13 @@ class _BangumiPanelState extends State<BangumiPanel> {
], ],
), ),
), ),
SingleChildScrollView( SizedBox(
padding: const EdgeInsets.only(top: 7, bottom: 7), height: 60,
child: ListView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: ConstrainedBox( itemCount: widget.pages.length,
constraints: BoxConstraints( itemBuilder: ((context, i) {
minWidth: MediaQuery.of(context).size.width, return Container(
),
child: Row(
children: [
for (int i = 0; i < widget.pages.length; i++) ...[
Container(
width: 150, width: 150,
margin: const EdgeInsets.only(right: 10), margin: const EdgeInsets.only(right: 10),
child: Material( child: Material(
@ -218,12 +214,90 @@ class _BangumiPanelState extends State<BangumiPanel> {
), ),
), ),
), ),
), );
] })),
],
),
),
) )
// SingleChildScrollView(
// padding: const EdgeInsets.only(top: 7, bottom: 7),
// scrollDirection: Axis.horizontal,
// child: ConstrainedBox(
// constraints: BoxConstraints(
// minWidth: MediaQuery.of(context).size.width,
// ),
// child: Row(
// children: [
// for (int i = 0; i < widget.pages.length; i++) ...[
// Container(
// width: 150,
// margin: const EdgeInsets.only(right: 10),
// child: Material(
// color: Theme.of(context).colorScheme.onInverseSurface,
// borderRadius: BorderRadius.circular(6),
// clipBehavior: Clip.hardEdge,
// child: InkWell(
// onTap: () => changeFucCall(widget.pages[i], i),
// child: Padding(
// padding: const EdgeInsets.symmetric(
// vertical: 8, horizontal: 10),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Row(
// children: [
// if (i == currentIndex) ...[
// 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: 2),
// 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

@ -104,7 +104,7 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
SmartDialog.showLoading(msg: '获取中...'); SmartDialog.showLoading(msg: '获取中...');
var res = await SearchHttp.bangumiInfo( var res = await SearchHttp.bangumiInfo(
seasonId: i.seasonId); seasonId: i.seasonId);
SmartDialog.dismiss(); SmartDialog.dismiss().then((value) {
if (res['status']) { if (res['status']) {
EpisodeItem episode = res['data'].episodes.first; EpisodeItem episode = res['data'].episodes.first;
String bvid = episode.bvid!; String bvid = episode.bvid!;
@ -121,6 +121,7 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) {
}, },
); );
} }
});
}, },
child: const Text('观看'), child: const Text('观看'),
), ),