From b136cd21a933677de93e7e17a8e026f5b82fb0c3 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Sun, 6 Aug 2023 13:51:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BF=BD=E7=95=AA=E3=80=81=E7=95=AA?= =?UTF-8?q?=E5=89=A7=E8=AF=A6=E6=83=85=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/http/api.dart | 6 + lib/http/video.dart | 26 ++ lib/models/bangumi/info.dart | 3 + .../bangumi/introduction/controller.dart | 93 ++------ lib/pages/bangumi/introduction/view.dart | 85 +++---- .../introduction/widgets/intro_detail.dart | 123 ++++++++++ lib/pages/bangumi/widgets/bangumi_panel.dart | 224 ++++++++++++------ .../widgets/media_bangumi_panel.dart | 35 +-- 8 files changed, 386 insertions(+), 209 deletions(-) create mode 100644 lib/pages/bangumi/introduction/widgets/intro_detail.dart diff --git a/lib/http/api.dart b/lib/http/api.dart index f6168bf0..d5727bd5 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -243,4 +243,10 @@ class Api { // 移除已观看 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'; } diff --git a/lib/http/video.dart b/lib/http/video.dart index 1de728cb..afdd9ee2 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -351,4 +351,30 @@ class VideoHttp { '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']}; + } + } } diff --git a/lib/models/bangumi/info.dart b/lib/models/bangumi/info.dart index c66f66ab..b71d327e 100644 --- a/lib/models/bangumi/info.dart +++ b/lib/models/bangumi/info.dart @@ -38,6 +38,7 @@ class BangumiInfoModel { this.total, this.type, this.userStatus, + this.staff, }); Map? activity; @@ -78,6 +79,7 @@ class BangumiInfoModel { int? total; int? type; Map? userStatus; + String? staff; BangumiInfoModel.fromJson(Map json) { activity = json['activity']; @@ -120,6 +122,7 @@ class BangumiInfoModel { total = json['total']; type = json['type']; userStatus = json['user_status']; + staff = json['staff']; } } diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index b2114fc8..1b1599cb 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -4,7 +4,6 @@ import 'package:get/get.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/search.dart'; -import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/bangumi/info.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); if (result['status']) { bangumiDetail.value = result['data']; + epId = bangumiDetail.value.episodes!.first.id; } if (userLogin) { // 获取点赞状态 @@ -101,20 +101,10 @@ class BangumiIntroController extends GetxController { queryHasCoinVideo(); // 获取收藏状态 queryHasFavVideo(); - // - queryFollowStatus(); } 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 { 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 { var result = await VideoHttp.likeVideo(bvid: bvid, type: !hasLike.value); if (result['status']) { - // hasLike.value = result["data"] == 1 ? true : false; if (!hasLike.value) { SmartDialog.showToast('点赞成功 👍'); hasLike.value = true; @@ -270,10 +216,7 @@ class BangumiIntroController extends GetxController { delMediaIdsNew.add(i.id); } } - } catch (e) { - // ignore: avoid_print - print(e); - } + } catch (_) {} var result = await VideoHttp.favVideo( aid: IdUtils.bv2av(bvid), addIds: addMediaIdsNew.join(','), @@ -297,15 +240,6 @@ class BangumiIntroController extends GetxController { 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) { feedBack(); @@ -322,15 +256,6 @@ class BangumiIntroController extends GetxController { 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或番剧分集 Future changeSeasonOrbangu(bvid, cid, aid) async { // 重新获取视频资源 @@ -348,4 +273,18 @@ class BangumiIntroController extends GetxController { videoReplyCtr.queryReplyList(type: 'init'); } 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']); + } } diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index b71ec77c..a8503152 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -4,6 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:hive/hive.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/network_img_layer.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 'controller.dart'; +import 'widgets/intro_detail.dart'; class BangumiIntroPanel extends StatefulWidget { const BangumiIntroPanel({super.key}); @@ -90,7 +92,6 @@ class _BangumiInfoState extends State { late BangumiInfoModel? bangumiItem; final BangumiIntroController bangumiIntroController = Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']); - bool isExpand = false; late VideoDetailController? videoDetailCtr; Box localCache = GStrorage.localCache; @@ -124,13 +125,13 @@ class _BangumiInfoState extends State { // 视频介绍 showIntroDetail() { feedBack(); - // showBottomSheet( - // context: context, - // enableDrag: true, - // builder: (BuildContext context) { - // return IntroDetail(videoDetail: widget.videoDetail!); - // }, - // ); + showBottomSheet( + context: context, + enableDrag: true, + builder: (BuildContext context) { + return IntroDetail(bangumiDetail: widget.bangumiDetail!); + }, + ); } @override @@ -138,7 +139,7 @@ class _BangumiInfoState extends State { ThemeData t = Theme.of(context); return SliverPadding( padding: const EdgeInsets.only( - left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13), + left: StyleString.safeSpace, right: StyleString.safeSpace, top: 20), sliver: SliverToBoxAdapter( child: !widget.loadingStatus || bangumiItem != null ? Column( @@ -148,12 +149,25 @@ class _BangumiInfoState extends State { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - NetworkImgLayer( - width: 105, - height: 160, - src: !widget.loadingStatus - ? widget.bangumiDetail!.cover! - : bangumiItem!.cover!, + Stack( + children: [ + NetworkImgLayer( + width: 105, + height: 160, + src: !widget.loadingStatus + ? widget.bangumiDetail!.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), Expanded( @@ -196,7 +210,8 @@ class _BangumiInfoState extends State { .withOpacity(0.7); }), ), - onPressed: () {}, + onPressed: () => + bangumiIntroController.bangumiAdd(), icon: Icon( Icons.favorite_border_rounded, color: t.colorScheme.primary, @@ -208,7 +223,6 @@ class _BangumiInfoState extends State { ), Row( children: [ - // const SizedBox(width: 6), StatView( theme: 'gray', view: !widget.loadingStatus @@ -227,7 +241,7 @@ class _BangumiInfoState extends State { ), ], ), - const SizedBox(height: 2), + const SizedBox(height: 6), Row( children: [ Text( @@ -252,38 +266,29 @@ class _BangumiInfoState extends State { 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), + // const SizedBox(height: 4), Text( - '简介:${!widget.loadingStatus ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}', - maxLines: 3, - overflow: TextOverflow.ellipsis, + !widget.loadingStatus + ? widget.bangumiDetail!.newEp!['desc'] + : bangumiItem!.newEp!['desc'], style: TextStyle( fontSize: 12, color: t.colorScheme.outline, ), ), + // const SizedBox(height: 10), 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, - ), + Text( + '简介:${!widget.loadingStatus ? widget.bangumiDetail!.evaluate! : bangumiItem!.evaluate!}', + maxLines: 3, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: t.colorScheme.outline, ), + ), ], ), ), diff --git a/lib/pages/bangumi/introduction/widgets/intro_detail.dart b/lib/pages/bangumi/introduction/widgets/intro_detail.dart new file mode 100644 index 00000000..c5bbd566 --- /dev/null +++ b/lib/pages/bangumi/introduction/widgets/intro_detail.dart @@ -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) + ], + ), + ), + ) + ], + ), + ); + } +} diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index 692112fd..85e70d19 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -111,7 +111,7 @@ class _BangumiPanelState extends State { return Column( children: [ Padding( - padding: const EdgeInsets.only(top: 10), + padding: const EdgeInsets.only(top: 10, bottom: 6), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ @@ -143,87 +143,161 @@ class _BangumiPanelState extends State { ], ), ), - 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), + SizedBox( + height: 60, + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: widget.pages.length, + itemBuilder: ((context, i) { + return 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: 2), - if (widget.pages[i].badge != null) ...[ - Image.asset( - 'assets/images/big-vip.png', - height: 16, - ), - ], + const SizedBox(width: 6) ], - ), - 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, - ) - ], - ), + 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, + ) + ], ), ), ), ), - ] - ], - ), - ), + ); + })), ) + // 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, + // ) + // ], + // ), + // ), + // ), + // ), + // ), + // ] + // ], + // ), + // ), + // ) ], ); } diff --git a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart index 82558105..7939a9b3 100644 --- a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart +++ b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart @@ -104,23 +104,24 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) { SmartDialog.showLoading(msg: '获取中...'); var res = await SearchHttp.bangumiInfo( seasonId: i.seasonId); - 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=${i.seasonId}', - arguments: { - 'pic': pic, - 'heroTag': heroTag, - 'videoType': SearchType.media_bangumi, - 'bangumiItem': res['data'], - }, - ); - } + SmartDialog.dismiss().then((value) { + 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=${i.seasonId}', + arguments: { + 'pic': pic, + 'heroTag': heroTag, + 'videoType': SearchType.media_bangumi, + 'bangumiItem': res['data'], + }, + ); + } + }); }, child: const Text('观看'), ),