From c961dc6cf596c84a2c02ac4f9b6d4102c2540845 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 4 Aug 2023 17:04:55 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E7=95=AA=E5=89=A7=E6=92=AD?= =?UTF-8?q?=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Podfile.lock | 6 - lib/models/bangumi/info.dart | 4 +- lib/models/search/result.dart | 10 +- lib/models/video_detail_res.dart | 16 +- .../bangumi/introduction/controller.dart | 401 ++++++++++++++++ lib/pages/bangumi/introduction/index.dart | 4 + lib/pages/bangumi/introduction/view.dart | 446 ++++++++++++++++++ lib/pages/bangumi/widgets/bangumi_panel.dart | 233 +++++++++ lib/pages/searchPanel/view.dart | 4 +- .../widgets/media_bangumi_panel.dart | 13 +- lib/pages/video/detail/controller.dart | 5 + .../video/detail/introduction/controller.dart | 9 + lib/pages/video/detail/view.dart | 29 +- lib/plugin/pl_player/utils/fullscreen.dart | 12 +- lib/plugin/pl_player/view.dart | 2 +- pubspec.lock | 8 - pubspec.yaml | 2 +- 17 files changed, 1155 insertions(+), 49 deletions(-) create mode 100644 lib/pages/bangumi/introduction/controller.dart create mode 100644 lib/pages/bangumi/introduction/index.dart create mode 100644 lib/pages/bangumi/introduction/view.dart create mode 100644 lib/pages/bangumi/widgets/bangumi_panel.dart diff --git a/ios/Podfile.lock b/ios/Podfile.lock index ed152c62..65ff98a1 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,6 +1,4 @@ PODS: - - auto_orientation (0.0.1): - - Flutter - connectivity_plus (0.0.1): - Flutter - ReachabilitySwift @@ -43,7 +41,6 @@ PODS: - Flutter DEPENDENCIES: - - auto_orientation (from `.symlinks/plugins/auto_orientation/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - Flutter (from `Flutter`) @@ -68,8 +65,6 @@ SPEC REPOS: - ReachabilitySwift EXTERNAL SOURCES: - auto_orientation: - :path: ".symlinks/plugins/auto_orientation/ios" connectivity_plus: :path: ".symlinks/plugins/connectivity_plus/ios" device_info_plus: @@ -106,7 +101,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/webview_flutter_wkwebview/ios" SPEC CHECKSUMS: - auto_orientation: 102ed811a5938d52c86520ddd7ecd3a126b5d39d connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 diff --git a/lib/models/bangumi/info.dart b/lib/models/bangumi/info.dart index 3bc2af25..c66f66ab 100644 --- a/lib/models/bangumi/info.dart +++ b/lib/models/bangumi/info.dart @@ -95,7 +95,7 @@ class BangumiInfoModel { jpTitle = json['jp_title']; link = json['link']; mediaId = json['media_id']; - newEp = json['newEp']; + newEp = json['new_ep']; playStrategy = json['play_strategy']; positive = json['positive']; publish = json['publish']; @@ -184,7 +184,7 @@ class EpisodeItem { EpisodeItem.fromJson(Map json) { aid = json['aid']; - badge = json['badge']; + badge = json['badge'] != '' ? json['badge'] : null; badgeInfo = json['badge_info']; badgeType = json['badge_type']; bvid = json['bvid']; diff --git a/lib/models/search/result.dart b/lib/models/search/result.dart index 9579f2e4..af5e2cfb 100644 --- a/lib/models/search/result.dart +++ b/lib/models/search/result.dart @@ -277,10 +277,12 @@ class SearchMBangumiModel { SearchMBangumiModel({this.list}); List? list; SearchMBangumiModel.fromJson(Map json) { - list = json['result'] - .map( - (e) => SearchMBangumiItemModel.fromJson(e)) - .toList(); + list = json['result'] != null + ? json['result'] + .map( + (e) => SearchMBangumiItemModel.fromJson(e)) + .toList() + : []; } } diff --git a/lib/models/video_detail_res.dart b/lib/models/video_detail_res.dart index 5b16d70c..5de83ce2 100644 --- a/lib/models/video_detail_res.dart +++ b/lib/models/video_detail_res.dart @@ -57,7 +57,7 @@ class VideoDetailData { bool? isChargeableSeason; bool? isStory; bool? noCache; - List? pages; + List? pages; Subtitle? subtitle; // Label? label; UgcSeason? ugcSeason; @@ -136,7 +136,7 @@ class VideoDetailData { noCache = json["no_cache"]; pages = json["pages"] == null ? [] - : List.from(json["pages"]!.map((e) => Page.fromJson(e))); + : List.from(json["pages"]!.map((e) => Part.fromJson(e))); subtitle = json["subtitle"] == null ? null : Subtitle.fromJson(json["subtitle"]); ugcSeason = json["ugc_season"] != null @@ -352,7 +352,7 @@ class Owner { } } -class Page { +class Part { int? cid; int? page; String? from; @@ -363,7 +363,7 @@ class Page { Dimension? dimension; String? firstFrame; - Page({ + Part({ this.cid, this.page, this.from, @@ -375,11 +375,11 @@ class Page { this.firstFrame, }); - fromRawJson(String str) => Page.fromJson(json.decode(str)); + fromRawJson(String str) => Part.fromJson(json.decode(str)); String toRawJson() => json.encode(toJson()); - Page.fromJson(Map json) { + Part.fromJson(Map json) { cid = json["cid"]; page = json["page"]; from = json["from"]; @@ -620,7 +620,7 @@ class EpisodeItem { int? cid; String? title; int? attribute; - Page? page; + Part? page; String? bvid; EpisodeItem.fromJson(Map json) { @@ -631,7 +631,7 @@ class EpisodeItem { cid = json['cid']; title = json['title']; attribute = json['attribute']; - page = Page.fromJson(json['page']); + page = Part.fromJson(json['page']); bvid = json['bvid']; } } diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart new file mode 100644 index 00000000..d3cbabda --- /dev/null +++ b/lib/pages/bangumi/introduction/controller.dart @@ -0,0 +1,401 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +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'; +import 'package:pilipala/models/video_detail_res.dart'; +import 'package:pilipala/pages/video/detail/index.dart'; +import 'package:pilipala/utils/feed_back.dart'; +import 'package:pilipala/utils/id_utils.dart'; +import 'package:pilipala/utils/storage.dart'; +import 'package:share_plus/share_plus.dart'; + +class BangumiIntroController extends GetxController { + // 视频bvid + String bvid = Get.parameters['bvid']!; + int seasonId = int.parse(Get.parameters['seasonId']!); + + // 是否预渲染 骨架屏 + bool preRender = false; + + // 视频详情 上个页面传入 + Map? videoItem = {}; + BangumiInfoModel? bangumiItem; + + // 请求状态 + RxBool isLoading = false.obs; + + // 视频详情 请求返回 + Rx videoDetail = VideoDetailData().obs; + Rx bangumiDetail = BangumiInfoModel().obs; + + // 请求返回的信息 + String responseMsg = '请求异常'; + + // up主粉丝数 + Map userStat = {'follower': '-'}; + + // 是否点赞 + RxBool hasLike = false.obs; + // 是否投币 + RxBool hasCoin = false.obs; + // 是否收藏 + RxBool hasFav = false.obs; + Box user = GStrorage.user; + bool userLogin = false; + Rx favFolderData = FavFolderData().obs; + List addMediaIdsNew = []; + List delMediaIdsNew = []; + // 关注状态 默认未关注 + RxMap followStatus = {}.obs; + int _tempThemeValue = -1; + + @override + void onInit() { + super.onInit(); + if (Get.arguments.isNotEmpty) { + if (Get.arguments.containsKey('bangumiItem')) { + preRender = true; + bangumiItem = Get.arguments['bangumiItem']; + // bangumiItem!['pic'] = args.pic; + // if (args.title is String) { + // videoItem!['title'] = args.title; + // } else { + // String str = ''; + // for (Map map in args.title) { + // str += map['text']; + // } + // videoItem!['title'] = str; + // } + // if (args.stat != null) { + // videoItem!['stat'] = args.stat; + // } + // videoItem!['pubdate'] = args.pubdate; + // videoItem!['owner'] = args.owner; + } + } + userLogin = user.get(UserBoxKey.userLogin) != null; + } + + // 获取番剧简介&选集 + Future queryBangumiIntro() async { + print('🐶🐶: $seasonId'); + var result = await SearchHttp.bangumiInfo(seasonId: seasonId); + print("🐶🐶:${result['data']}"); + if (result['status']) { + bangumiDetail.value = result['data']; + } + if (userLogin) { + // 获取点赞状态 + // queryHasLikeVideo(); + // 获取投币状态 + // 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); + // data num 被点赞标志 0:未点赞 1:已点赞 + hasLike.value = result["data"] == 1 ? true : false; + } + + // 获取投币状态 + Future queryHasCoinVideo() async { + var result = await VideoHttp.hasCoinVideo(bvid: bvid); + hasCoin.value = result["data"]['multiply'] == 0 ? false : true; + } + + // 获取收藏状态 + Future queryHasFavVideo() async { + var result = await VideoHttp.hasFavVideo(aid: IdUtils.bv2av(bvid)); + if (result['status']) { + hasFav.value = result["data"]['favoured']; + } else { + hasFav.value = false; + } + } + + // 一键三连 + 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; + videoDetail.value.stat!.like = videoDetail.value.stat!.like! + 1; + } else if (hasLike.value) { + SmartDialog.showToast('取消赞'); + hasLike.value = false; + videoDetail.value.stat!.like = videoDetail.value.stat!.like! - 1; + } + hasLike.refresh(); + } else { + SmartDialog.showToast(result['msg']); + } + } + + // 投币 + Future actionCoinVideo() async { + if (user.get(UserBoxKey.userMid) == null) { + SmartDialog.showToast('账号未登录'); + return; + } + showDialog( + context: Get.context!, + builder: (context) { + return AlertDialog( + title: const Text('选择投币个数'), + contentPadding: const EdgeInsets.fromLTRB(0, 12, 0, 12), + content: StatefulBuilder(builder: (context, StateSetter setState) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + RadioListTile( + value: 1, + title: const Text('1枚'), + groupValue: _tempThemeValue, + onChanged: (value) { + _tempThemeValue = value!; + Get.appUpdate(); + }, + ), + RadioListTile( + value: 2, + title: const Text('2枚'), + groupValue: _tempThemeValue, + onChanged: (value) { + _tempThemeValue = value!; + Get.appUpdate(); + }, + ), + ], + ); + }), + actions: [ + TextButton(onPressed: () => Get.back(), child: const Text('取消')), + TextButton( + onPressed: () async { + var res = await VideoHttp.coinVideo( + bvid: bvid, multiply: _tempThemeValue); + if (res['status']) { + SmartDialog.showToast('投币成功 👏'); + hasCoin.value = true; + videoDetail.value.stat!.coin = + videoDetail.value.stat!.coin! + _tempThemeValue; + } else { + SmartDialog.showToast(res['msg']); + } + Get.back(); + }, + child: const Text('确定')) + ], + ); + }); + } + + // (取消)收藏 + Future actionFavVideo() async { + try { + for (var i in favFolderData.value.list!.toList()) { + if (i.favState == 1) { + addMediaIdsNew.add(i.id); + } else { + delMediaIdsNew.add(i.id); + } + } + } catch (e) { + // ignore: avoid_print + print(e); + } + var result = await VideoHttp.favVideo( + aid: IdUtils.bv2av(bvid), + addIds: addMediaIdsNew.join(','), + delIds: delMediaIdsNew.join(',')); + if (result['status']) { + if (result['data']['prompt']) { + addMediaIdsNew = []; + delMediaIdsNew = []; + Get.back(); + // 重新获取收藏状态 + queryHasFavVideo(); + SmartDialog.showToast('✅ 操作成功'); + } + } + } + + // 分享视频 + Future actionShareVideo() async { + var result = await Share.share('${HttpString.baseUrl}/video/$bvid') + .whenComplete(() {}); + 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(); + List datalist = favFolderData.value.list!; + for (var i = 0; i < datalist.length; i++) { + if (i == index) { + datalist[i].favState = checkValue == true ? 1 : 0; + datalist[i].mediaCount = checkValue == true + ? datalist[i].mediaCount! + 1 + : datalist[i].mediaCount! - 1; + } + } + favFolderData.value.list = datalist; + favFolderData.refresh(); + } + + // 查询关注状态 + Future queryFollowStatus() async { + var result = await VideoHttp.hasFollow(mid: videoDetail.value.owner!.mid!); + if (result['status']) { + followStatus.value = result['data']; + } + return result; + } + + // 关注/取关up + Future actionRelationMod() async { + feedBack(); + if (user.get(UserBoxKey.userMid) == null) { + SmartDialog.showToast('账号未登录'); + return; + } + int currentStatus = followStatus['attribute']; + int actionStatus = 0; + switch (currentStatus) { + case 0: + actionStatus = 1; + break; + case 2: + actionStatus = 2; + break; + default: + actionStatus = 0; + break; + } + SmartDialog.show( + useSystem: true, + animationType: SmartAnimationType.centerFade_otherSlide, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('提示'), + content: Text(currentStatus == 0 ? '关注UP主?' : '取消关注UP主?'), + actions: [ + TextButton( + onPressed: () => SmartDialog.dismiss(), + child: const Text('点错了')), + TextButton( + onPressed: () async { + var result = await VideoHttp.relationMod( + mid: videoDetail.value.owner!.mid!, + act: actionStatus, + reSrc: 14, + ); + if (result['status']) { + switch (currentStatus) { + case 0: + actionStatus = 2; + break; + case 2: + actionStatus = 0; + break; + default: + actionStatus = 0; + break; + } + followStatus['attribute'] = actionStatus; + followStatus.refresh(); + } + SmartDialog.dismiss(); + }, + child: const Text('确认'), + ) + ], + ); + }, + ); + } + + // 修改分P或番剧分集 + Future changeSeasonOrbangu(bvid, cid) async { + VideoDetailController videoDetailCtr = + Get.find(tag: Get.arguments['heroTag']); + videoDetailCtr.bvid = bvid; + videoDetailCtr.cid = cid; + videoDetailCtr.queryVideoUrl(); + } +} diff --git a/lib/pages/bangumi/introduction/index.dart b/lib/pages/bangumi/introduction/index.dart new file mode 100644 index 00000000..40eab5b4 --- /dev/null +++ b/lib/pages/bangumi/introduction/index.dart @@ -0,0 +1,4 @@ +library bangumi_intro; + +export './controller.dart'; +export './view.dart'; diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart new file mode 100644 index 00000000..dc1d5252 --- /dev/null +++ b/lib/pages/bangumi/introduction/view.dart @@ -0,0 +1,446 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +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/http_error.dart'; +import 'package:pilipala/common/widgets/network_img_layer.dart'; +import 'package:pilipala/common/widgets/stat/danmu.dart'; +import 'package:pilipala/common/widgets/stat/view.dart'; +import 'package:pilipala/models/bangumi/info.dart'; +import 'package:pilipala/pages/bangumi/widgets/bangumi_panel.dart'; +import 'package:pilipala/pages/video/detail/index.dart'; +import 'package:pilipala/pages/video/detail/introduction/widgets/action_item.dart'; +import 'package:pilipala/pages/video/detail/introduction/widgets/action_row_item.dart'; +import 'package:pilipala/utils/feed_back.dart'; +import 'package:pilipala/utils/storage.dart'; + +import 'controller.dart'; + +class BangumiIntroPanel extends StatefulWidget { + const BangumiIntroPanel({super.key}); + + @override + State createState() => _BangumiIntroPanelState(); +} + +class _BangumiIntroPanelState extends State + with AutomaticKeepAliveClientMixin { + final BangumiIntroController bangumiIntroController = + Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']); + BangumiInfoModel? bangumiDetail; + +// 添加页面缓存 + @override + bool get wantKeepAlive => true; + + @override + void initState() { + super.initState(); + bangumiIntroController.bangumiDetail.listen((value) { + bangumiDetail = value; + }); + } + + @override + Widget build(BuildContext context) { + super.build(context); + return FutureBuilder( + future: bangumiIntroController.queryBangumiIntro(), + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.done) { + if (snapshot.data['status']) { + // 请求成功 + return BangumiInfo( + loadingStatus: false, + bangumiDetail: bangumiDetail, + ); + } else { + // 请求错误 + return HttpError( + errMsg: snapshot.data['msg'], + fn: () => Get.back(), + ); + } + } else { + return BangumiInfo(loadingStatus: true, bangumiDetail: bangumiDetail); + } + }, + ); + } +} + +class BangumiInfo extends StatefulWidget { + final bool loadingStatus; + final BangumiInfoModel? bangumiDetail; + + const BangumiInfo({ + Key? key, + this.loadingStatus = false, + this.bangumiDetail, + }) : super(key: key); + + @override + State createState() => _BangumiInfoState(); +} + +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; + late double sheetHeight; + + @override + void initState() { + super.initState(); + bangumiItem = bangumiIntroController.bangumiItem!; + videoDetailCtr = + Get.find(tag: Get.arguments['heroTag']); + sheetHeight = localCache.get('sheetHeight'); + } + + // 收藏 + showFavBottomSheet() { + if (bangumiIntroController.user.get(UserBoxKey.userMid) == null) { + SmartDialog.showToast('账号未登录'); + return; + } + // showModalBottomSheet( + // context: context, + // useRootNavigator: true, + // isScrollControlled: true, + // builder: (context) { + // return FavPanel(ctr: videoIntroController); + // }, + // ); + } + + // 视频介绍 + showIntroDetail() { + feedBack(); + // showBottomSheet( + // context: context, + // enableDrag: true, + // builder: (BuildContext context) { + // return IntroDetail(videoDetail: widget.videoDetail!); + // }, + // ); + } + + @override + Widget build(BuildContext context) { + ThemeData t = Theme.of(context); + return SliverPadding( + padding: const EdgeInsets.only( + left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13), + sliver: SliverToBoxAdapter( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + NetworkImgLayer( + width: 105, + height: 160, + src: !widget.loadingStatus + ? 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(height: 6), + // 点赞收藏转发 布局样式1 + // SingleChildScrollView( + // padding: const EdgeInsets.only(top: 7, bottom: 7), + // scrollDirection: Axis.horizontal, + // child: actionRow( + // context, + // bangumiIntroController, + // videoDetailCtr, + // ), + // ), + // 点赞收藏转发 布局样式2 + actionGrid(context, bangumiIntroController), + // 番剧分p + if (!widget.loadingStatus && + widget.bangumiDetail!.episodes!.isNotEmpty) ...[ + BangumiPanel( + pages: widget.bangumiDetail!.episodes!, + cid: widget.bangumiDetail!.episodes!.first.cid, + sheetHeight: sheetHeight, + changeFuc: (bvid, cid) => + bangumiIntroController.changeSeasonOrbangu(bvid, cid), + ) + ], + ], + ), + ), + ); + } + + Widget actionGrid(BuildContext context, bangumiIntroController) { + return LayoutBuilder(builder: (context, constraints) { + return Material( + child: Padding( + padding: const EdgeInsets.only(top: 16, bottom: 8), + child: SizedBox( + height: constraints.maxWidth / 5 * 0.8, + child: GridView.count( + primary: false, + padding: const EdgeInsets.all(0), + crossAxisCount: 5, + childAspectRatio: 1.25, + children: [ + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.thumbsUp), + selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp), + onTap: () => bangumiIntroController.actionLikeVideo(), + selectStatus: bangumiIntroController.hasLike.value, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['likes']!.toString() + : '-'), + ), + ActionItem( + icon: const Icon(FontAwesomeIcons.clock), + onTap: () => () {}, + selectStatus: false, + loadingStatus: widget.loadingStatus, + text: '稍后再看'), + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.b), + selectIcon: const Icon(FontAwesomeIcons.b), + onTap: () => bangumiIntroController.actionCoinVideo(), + selectStatus: bangumiIntroController.hasCoin.value, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['coins']!.toString() + : '-'), + ), + Obx( + () => ActionItem( + icon: const Icon(FontAwesomeIcons.star), + selectIcon: const Icon(FontAwesomeIcons.solidStar), + // onTap: () => videoIntroController.actionFavVideo(), + onTap: () => showFavBottomSheet(), + selectStatus: bangumiIntroController.hasFav.value, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['favorite']!.toString() + : '-'), + ), + ActionItem( + icon: const Icon(FontAwesomeIcons.shareFromSquare), + onTap: () => bangumiIntroController.actionShareVideo(), + selectStatus: false, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['share']!.toString() + : '-'), + ], + ), + ), + ), + ); + }); + } + + Widget actionRow(BuildContext context, videoIntroController, videoDetailCtr) { + return Row(children: [ + Obx( + () => ActionRowItem( + icon: const Icon(FontAwesomeIcons.thumbsUp), + onTap: () => videoIntroController.actionLikeVideo(), + selectStatus: videoIntroController.hasLike.value, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['likes']!.toString() + : '-', + ), + ), + const SizedBox(width: 8), + Obx( + () => ActionRowItem( + icon: const Icon(FontAwesomeIcons.b), + onTap: () => videoIntroController.actionCoinVideo(), + selectStatus: videoIntroController.hasCoin.value, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['coins']!.toString() + : '-', + ), + ), + const SizedBox(width: 8), + Obx( + () => ActionRowItem( + icon: const Icon(FontAwesomeIcons.heart), + onTap: () => showFavBottomSheet(), + selectStatus: videoIntroController.hasFav.value, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['favorite']!.toString() + : '-', + ), + ), + const SizedBox(width: 8), + ActionRowItem( + icon: const Icon(FontAwesomeIcons.comment), + onTap: () { + videoDetailCtr.tabCtr.animateTo(1); + }, + selectStatus: false, + loadingStatus: widget.loadingStatus, + text: !widget.loadingStatus + ? widget.bangumiDetail!.stat!['reply']!.toString() + : '-', + ), + const SizedBox(width: 8), + ActionRowItem( + icon: const Icon(FontAwesomeIcons.share), + onTap: () => videoIntroController.actionShareVideo(), + selectStatus: false, + loadingStatus: widget.loadingStatus, + // text: !widget.loadingStatus + // ? widget.videoDetail!.stat!.share!.toString() + // : '-', + text: '转发'), + ]); + } +} diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart new file mode 100644 index 00000000..6ee22024 --- /dev/null +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -0,0 +1,233 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:pilipala/models/bangumi/info.dart'; + +class BangumiPanel extends StatefulWidget { + final List pages; + final int? cid; + final double? sheetHeight; + final Function? changeFuc; + + const BangumiPanel({ + super.key, + required this.pages, + this.cid, + this.sheetHeight, + this.changeFuc, + }); + + @override + State createState() => _BangumiPanelState(); +} + +class _BangumiPanelState extends State { + late int currentIndex; + + @override + void initState() { + super.initState(); + currentIndex = widget.pages.indexWhere((e) => e.cid == widget.cid!); + } + + void showBangumiPanel() { + showBottomSheet( + context: context, + builder: (_) => Container( + height: widget.sheetHeight, + color: Theme.of(context).colorScheme.background, + child: Column( + children: [ + Container( + height: 45, + padding: const EdgeInsets.only(left: 14, right: 14), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + '合集(${widget.pages.length})', + style: Theme.of(context).textTheme.titleMedium, + ), + IconButton( + icon: const Icon(Icons.close), + onPressed: () => Navigator.pop(context), + ), + ], + ), + ), + Divider( + height: 1, + color: Theme.of(context).dividerColor.withOpacity(0.1), + ), + Expanded( + child: Material( + child: ListView.builder( + itemCount: widget.pages.length, + itemBuilder: (context, index) { + return ListTile( + onTap: () async { + if (widget.pages[index].badge != null) { + SmartDialog.showToast('需要大会员'); + return; + } + await widget.changeFuc!( + widget.pages[index].bvid, + widget.pages[index].cid, + ); + currentIndex = index; + setState(() {}); + }, + dense: false, + title: Text( + widget.pages[index].longTitle!, + style: TextStyle( + fontSize: 14, + color: index == currentIndex + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + ), + ), + trailing: widget.pages[index].badge != null + ? Image.asset( + 'assets/images/big-vip.png', + height: 20, + ) + : const SizedBox(), + ); + }, + ), + ), + ), + ], + ), + ), + ); + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 10), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text('合集 '), + Expanded( + child: Text( + ' 正在播放:${widget.pages[currentIndex].longTitle}', + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 12, + color: Theme.of(context).colorScheme.outline, + ), + ), + ), + const SizedBox(width: 10), + SizedBox( + height: 34, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all(EdgeInsets.zero), + ), + onPressed: () => showBangumiPanel(), + child: Text( + '全${widget.pages.length}话', + style: const TextStyle(fontSize: 13), + ), + ), + ), + ], + ), + ), + SingleChildScrollView( + padding: const EdgeInsets.only(top: 7, bottom: 7), + scrollDirection: Axis.horizontal, + 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: () async { + if (widget.pages[i].badge != null) { + SmartDialog.showToast('需要大会员'); + return; + } + await widget.changeFuc!( + widget.pages[i].bvid, + widget.pages[i].cid, + ); + currentIndex = i; + setState(() {}); + }, + 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/view.dart b/lib/pages/searchPanel/view.dart index 4d49f11c..2683e7e9 100644 --- a/lib/pages/searchPanel/view.dart +++ b/lib/pages/searchPanel/view.dart @@ -27,6 +27,7 @@ class _SearchPanelState extends State late SearchPanelController? _searchPanelController; bool _isLoadingMore = false; + late Future _futureBuilderFuture; @override bool get wantKeepAlive => true; @@ -53,6 +54,7 @@ class _SearchPanelState extends State } } }); + _futureBuilderFuture = _searchPanelController!.onSearch(); } @override @@ -63,7 +65,7 @@ class _SearchPanelState extends State await _searchPanelController!.onRefresh(); }, child: FutureBuilder( - future: _searchPanelController!.onSearch(), + future: _futureBuilderFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done) { Map data = snapshot.data; diff --git a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart index 4a0cb8c4..82558105 100644 --- a/lib/pages/searchPanel/widgets/media_bangumi_panel.dart +++ b/lib/pages/searchPanel/widgets/media_bangumi_panel.dart @@ -5,6 +5,7 @@ import 'package:pilipala/common/widgets/badge.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/http/search.dart'; import 'package:pilipala/models/bangumi/info.dart'; +import 'package:pilipala/models/common/search_type.dart'; import 'package:pilipala/utils/utils.dart'; Widget searchMbangumiPanel(BuildContext context, ctr, list) { @@ -19,8 +20,12 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) { var i = list![index]; return InkWell( onTap: () { - Get.toNamed('/video?bvid=${i.bvid}&cid=${i.cid}', - arguments: {'videoItem': i, 'heroTag': Utils.makeHeroTag(i.id)}); + /// TODO 番剧详情页面 + // Get.toNamed('/video?bvid=${i.bvid}&cid=${i.cid}', arguments: { + // 'videoItem': i, + // 'heroTag': Utils.makeHeroTag(i.id), + // 'videoType': SearchType.media_bangumi + // }); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), @@ -107,10 +112,12 @@ Widget searchMbangumiPanel(BuildContext context, ctr, list) { String pic = episode.cover!; String heroTag = Utils.makeHeroTag(cid); Get.toNamed( - '/video?bvid=$bvid&cid=$cid', + '/video?bvid=$bvid&cid=$cid&seasonId=${i.seasonId}', arguments: { 'pic': pic, 'heroTag': heroTag, + 'videoType': SearchType.media_bangumi, + 'bangumiItem': res['data'], }, ); } diff --git a/lib/pages/video/detail/controller.dart b/lib/pages/video/detail/controller.dart index 597030ed..0f07101c 100644 --- a/lib/pages/video/detail/controller.dart +++ b/lib/pages/video/detail/controller.dart @@ -5,6 +5,7 @@ import 'package:hive/hive.dart'; import 'package:pilipala/http/constants.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/common/reply_type.dart'; +import 'package:pilipala/models/common/search_type.dart'; import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/models/video/play/url.dart'; import 'package:pilipala/models/video/reply/item.dart'; @@ -22,6 +23,9 @@ class VideoDetailController extends GetxController // 视频aid String bvid = Get.parameters['bvid']!; int cid = int.parse(Get.parameters['cid']!); + // 视频类型 默认投稿视频 + SearchType videoType = SearchType.video; + late PlayUrlModel data; // 当前画质 late VideoQuality currentVideoQa; @@ -74,6 +78,7 @@ class VideoDetailController extends GetxController bgCover.value = Get.arguments['pic']; } heroTag = Get.arguments['heroTag']; + videoType = Get.arguments['videoType'] ?? SearchType.video; } tabCtr = TabController(length: 2, vsync: this); // queryVideoUrl(); diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index c6cb792b..494f163f 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -389,4 +389,13 @@ class VideoIntroController extends GetxController { }, ); } + + // 修改分P或番剧分集 + Future changeSeasonOrbangu(bvid, cid) async { + var _videoDetailCtr = + Get.find(tag: Get.arguments['heroTag']); + _videoDetailCtr.bvid = bvid; + _videoDetailCtr.cid = cid; + _videoDetailCtr.queryVideoUrl(); + } } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 7325cfd0..cf74d5aa 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:hive/hive.dart'; import 'package:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/common/widgets/sliver_header.dart'; +import 'package:pilipala/models/common/search_type.dart'; +import 'package:pilipala/pages/bangumi/introduction/index.dart'; import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart'; import 'package:pilipala/pages/video/detail/reply/index.dart'; import 'package:pilipala/pages/video/detail/controller.dart'; @@ -324,16 +326,25 @@ class _VideoDetailPageState extends State return CustomScrollView( key: const PageStorageKey('简介'), slivers: [ - const VideoIntroPanel(), - SliverPersistentHeader( - floating: true, - pinned: true, - delegate: SliverHeaderDelegate( - height: 50, - child: - const MenuRow(loadingStatus: false), + if (videoDetailController.videoType == + SearchType.video) ...[ + const VideoIntroPanel(), + ] else if (videoDetailController.videoType == + SearchType.media_bangumi) ...[ + const BangumiIntroPanel() + ], + if (videoDetailController.videoType == + SearchType.video) ...[ + SliverPersistentHeader( + floating: true, + pinned: true, + delegate: SliverHeaderDelegate( + height: 50, + child: + const MenuRow(loadingStatus: false), + ), ), - ), + ], const RelatedVideoPanel(), ], ); diff --git a/lib/plugin/pl_player/utils/fullscreen.dart b/lib/plugin/pl_player/utils/fullscreen.dart index 4f5ca948..6139416d 100644 --- a/lib/plugin/pl_player/utils/fullscreen.dart +++ b/lib/plugin/pl_player/utils/fullscreen.dart @@ -1,16 +1,16 @@ import 'dart:io'; import 'package:device_info_plus/device_info_plus.dart'; -import 'package:auto_orientation/auto_orientation.dart'; +// import 'package:auto_orientation/auto_orientation.dart'; import 'package:flutter/services.dart'; //横屏 /// 低版本xcode不支持auto_orientation -Future landScape() async { - if (Platform.isAndroid || Platform.isIOS) { - await AutoOrientation.landscapeAutoMode(forceSensor: true); - } -} +// Future landScape() async { +// if (Platform.isAndroid || Platform.isIOS) { +// await AutoOrientation.landscapeAutoMode(forceSensor: true); +// } +// } //竖屏 Future verticalScreen() async { diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 07745901..4b69a5b9 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -153,7 +153,7 @@ class _PLVideoPlayerState extends State /// 进入全屏 await enterFullScreen(); // 横屏 - await landScape(); + // await landScape(); } else { // 竖屏 await verticalScreen(); diff --git a/pubspec.lock b/pubspec.lock index db99cf2a..494f2fe1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -49,14 +49,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" - auto_orientation: - dependency: "direct main" - description: - name: auto_orientation - sha256: cd56bb59b36fa54cc28ee254bc600524f022a4862f31d5ab20abd7bb1c54e678 - url: "https://pub.dev" - source: hosted - version: "2.3.1" boolean_selector: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index acc018c7..5d97d0e4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -107,7 +107,7 @@ dependencies: universal_platform: ^1.0.0+1 # 进度条 audio_video_progress_bar: ^1.0.1 - auto_orientation: ^2.3.1 + # auto_orientation: ^2.3.1 dev_dependencies: flutter_test: From 01829ad965e649bdf695aa637f62f191dc0866de Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 4 Aug 2023 18:29:38 +0800 Subject: [PATCH 2/4] =?UTF-8?q?mod:=20=E5=8E=86=E5=8F=B2=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E8=B7=B3=E8=BD=AC=E7=95=AA=E5=89=A7=E6=92=AD=E6=94=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/models/video_detail_res.dart | 11 + .../bangumi/introduction/controller.dart | 11 +- lib/pages/bangumi/introduction/view.dart | 351 +++++++++--------- lib/pages/bangumi/widgets/bangumi_panel.dart | 157 ++++---- lib/pages/history/widgets/item.dart | 50 ++- 5 files changed, 330 insertions(+), 250 deletions(-) diff --git a/lib/models/video_detail_res.dart b/lib/models/video_detail_res.dart index 5de83ce2..5ac9dcf0 100644 --- a/lib/models/video_detail_res.dart +++ b/lib/models/video_detail_res.dart @@ -66,6 +66,7 @@ class VideoDetailData { HonorReply? honorReply; String? likeIcon; bool? needJumpBv; + String? epId; VideoDetailData({ this.bvid, @@ -101,6 +102,7 @@ class VideoDetailData { this.honorReply, this.likeIcon, this.needJumpBv, + this.epId, }); VideoDetailData.fromJson(Map json) { @@ -150,6 +152,15 @@ class VideoDetailData { : HonorReply.fromJson(json["honor_reply"]); likeIcon = json["like_icon"]; needJumpBv = json["need_jump_bv"]; + if (json['redirect_url'] != null) { + RegExp regex = RegExp(r'\d+'); + Iterable matches = regex.allMatches(json['redirect_url']); + List numbers = []; + for (Match match in matches) { + numbers.add(match.group(0)!); + } + epId = numbers[0]; + } } Map toJson() => { diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index d3cbabda..91e3d527 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -18,7 +18,12 @@ import 'package:share_plus/share_plus.dart'; class BangumiIntroController extends GetxController { // 视频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; @@ -84,9 +89,7 @@ class BangumiIntroController extends GetxController { // 获取番剧简介&选集 Future queryBangumiIntro() async { - print('🐶🐶: $seasonId'); - var result = await SearchHttp.bangumiInfo(seasonId: seasonId); - print("🐶🐶:${result['data']}"); + var result = await SearchHttp.bangumiInfo(seasonId: seasonId, epId: epId); if (result['status']) { bangumiDetail.value = result['data']; } diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index dc1d5252..081ecc4e 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -86,7 +86,7 @@ class BangumiInfo extends StatefulWidget { } class _BangumiInfoState extends State { - late BangumiInfoModel bangumiItem; + late BangumiInfoModel? bangumiItem; final BangumiIntroController bangumiIntroController = Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']); bool isExpand = false; @@ -98,7 +98,7 @@ class _BangumiInfoState extends State { @override void initState() { super.initState(); - bangumiItem = bangumiIntroController.bangumiItem!; + bangumiItem = bangumiIntroController.bangumiItem; videoDetailCtr = Get.find(tag: Get.arguments['heroTag']); sheetHeight = localCache.get('sheetHeight'); @@ -139,176 +139,189 @@ class _BangumiInfoState extends State { padding: const EdgeInsets.only( left: StyleString.safeSpace, right: StyleString.safeSpace, top: 13), sliver: SliverToBoxAdapter( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NetworkImgLayer( - width: 105, - height: 160, - src: !widget.loadingStatus - ? 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, - ), - ), - ], + child: !widget.loadingStatus || bangumiItem != null + ? Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + NetworkImgLayer( + width: 105, + height: 160, + src: !widget.loadingStatus + ? 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(), + 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( - // padding: const EdgeInsets.only(top: 7, bottom: 7), - // scrollDirection: Axis.horizontal, - // child: actionRow( - // context, - // bangumiIntroController, - // videoDetailCtr, - // ), - // ), - // 点赞收藏转发 布局样式2 - actionGrid(context, bangumiIntroController), - // 番剧分p - if (!widget.loadingStatus && - widget.bangumiDetail!.episodes!.isNotEmpty) ...[ - BangumiPanel( - pages: widget.bangumiDetail!.episodes!, - cid: widget.bangumiDetail!.episodes!.first.cid, - sheetHeight: sheetHeight, - changeFuc: (bvid, cid) => - bangumiIntroController.changeSeasonOrbangu(bvid, cid), + const SizedBox(height: 6), + // 点赞收藏转发 布局样式1 + // SingleChildScrollView( + // padding: const EdgeInsets.only(top: 7, bottom: 7), + // scrollDirection: Axis.horizontal, + // child: actionRow( + // context, + // bangumiIntroController, + // videoDetailCtr, + // ), + // ), + // 点赞收藏转发 布局样式2 + actionGrid(context, bangumiIntroController), + // 番剧分p + if (!widget.loadingStatus && + widget.bangumiDetail!.episodes!.isNotEmpty) ...[ + BangumiPanel( + pages: widget.bangumiDetail!.episodes!, + cid: widget.bangumiDetail!.episodes!.first.cid, + sheetHeight: sheetHeight, + changeFuc: (bvid, cid) => + bangumiIntroController.changeSeasonOrbangu(bvid, cid), + ) + ], + ], ) - ], - ], - ), + : const SizedBox( + height: 100, + child: Center( + child: CircularProgressIndicator(), + ), + ), ), ); } diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index 6ee22024..5d39b7cd 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -143,88 +143,93 @@ class _BangumiPanelState extends State { SingleChildScrollView( padding: const EdgeInsets.only(top: 7, bottom: 7), scrollDirection: Axis.horizontal, - 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: () async { - if (widget.pages[i].badge != null) { - SmartDialog.showToast('需要大会员'); - return; - } - await widget.changeFuc!( - widget.pages[i].bvid, - widget.pages[i].cid, - ); - currentIndex = i; - setState(() {}); - }, - 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, + 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: () async { + if (widget.pages[i].badge != null) { + SmartDialog.showToast('需要大会员'); + return; + } + await widget.changeFuc!( + widget.pages[i].bvid, + widget.pages[i].cid, + ); + currentIndex = i; + setState(() {}); + }, + 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: 6) + const SizedBox(width: 2), + if (widget.pages[i].badge != null) ...[ + Image.asset( + 'assets/images/big-vip.png', + height: 16, + ), + ], ], - 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, - ) - ], + ), + 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/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index b5dc3ee3..c4a7b791 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -1,10 +1,14 @@ import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/common/constants.dart'; import 'package:pilipala/common/widgets/badge.dart'; import 'package:pilipala/common/widgets/network_img_layer.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/search_type.dart'; import 'package:pilipala/models/live/item.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/utils.dart'; @@ -47,6 +51,50 @@ class HistoryItem extends StatelessWidget { '/liveRoom?roomid=${videoItem.history.oid}', 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 { int cid = videoItem.history.cid ?? // videoItem.history.oid ?? @@ -150,7 +198,7 @@ class VideoContent extends StatelessWidget { maxLines: videoItem.videos > 1 ? 1 : 2, overflow: TextOverflow.ellipsis, ), - if (videoItem.videos > 1) + if (videoItem.showTitle != null) Text( videoItem.showTitle, textAlign: TextAlign.start, From 1454190f431e1217c27d0dcc9acabf5cb5fc2385 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 4 Aug 2023 19:15:53 +0800 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=E7=95=AA=E5=89=A7=E9=80=89?= =?UTF-8?q?=E9=9B=86=E8=AF=84=E8=AE=BA=E5=8A=A0=E8=BD=BD=E3=80=81=E5=88=86?= =?UTF-8?q?=E9=9B=86=E6=B8=B2=E6=9F=93=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bangumi/introduction/controller.dart | 72 +++---------------- lib/pages/bangumi/introduction/view.dart | 18 +++-- lib/pages/bangumi/widgets/bangumi_panel.dart | 40 +++++------ lib/pages/history/widgets/item.dart | 25 ++++--- lib/pages/video/detail/reply/controller.dart | 3 + lib/pages/video/detail/reply/view.dart | 3 +- 6 files changed, 58 insertions(+), 103 deletions(-) diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index 91e3d527..c4bb1bb8 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -10,6 +10,7 @@ import 'package:pilipala/models/bangumi/info.dart'; import 'package:pilipala/models/user/fav_folder.dart'; import 'package:pilipala/models/video_detail_res.dart'; import 'package:pilipala/pages/video/detail/index.dart'; +import 'package:pilipala/pages/video/detail/reply/index.dart'; import 'package:pilipala/utils/feed_back.dart'; import 'package:pilipala/utils/id_utils.dart'; import 'package:pilipala/utils/storage.dart'; @@ -330,75 +331,18 @@ class BangumiIntroController extends GetxController { return result; } - // 关注/取关up - Future actionRelationMod() async { - feedBack(); - if (user.get(UserBoxKey.userMid) == null) { - SmartDialog.showToast('账号未登录'); - return; - } - int currentStatus = followStatus['attribute']; - int actionStatus = 0; - switch (currentStatus) { - case 0: - actionStatus = 1; - break; - case 2: - actionStatus = 2; - break; - default: - actionStatus = 0; - break; - } - SmartDialog.show( - useSystem: true, - animationType: SmartAnimationType.centerFade_otherSlide, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('提示'), - content: Text(currentStatus == 0 ? '关注UP主?' : '取消关注UP主?'), - actions: [ - TextButton( - onPressed: () => SmartDialog.dismiss(), - child: const Text('点错了')), - TextButton( - onPressed: () async { - var result = await VideoHttp.relationMod( - mid: videoDetail.value.owner!.mid!, - act: actionStatus, - reSrc: 14, - ); - if (result['status']) { - switch (currentStatus) { - case 0: - actionStatus = 2; - break; - case 2: - actionStatus = 0; - break; - default: - actionStatus = 0; - break; - } - followStatus['attribute'] = actionStatus; - followStatus.refresh(); - } - SmartDialog.dismiss(); - }, - child: const Text('确认'), - ) - ], - ); - }, - ); - } - // 修改分P或番剧分集 - Future changeSeasonOrbangu(bvid, cid) async { + Future changeSeasonOrbangu(bvid, cid, aid) async { + // 重新获取视频资源 VideoDetailController videoDetailCtr = Get.find(tag: Get.arguments['heroTag']); videoDetailCtr.bvid = bvid; videoDetailCtr.cid = cid; videoDetailCtr.queryVideoUrl(); + // 重新请求评论 + VideoReplyController videoReplyCtr = + Get.find(tag: Get.arguments['heroTag']); + videoReplyCtr.aid = aid; + videoReplyCtr.queryReplyList(type: 'init'); } } diff --git a/lib/pages/bangumi/introduction/view.dart b/lib/pages/bangumi/introduction/view.dart index 081ecc4e..41d7dc51 100644 --- a/lib/pages/bangumi/introduction/view.dart +++ b/lib/pages/bangumi/introduction/view.dart @@ -304,14 +304,20 @@ class _BangumiInfoState extends State { // 点赞收藏转发 布局样式2 actionGrid(context, bangumiIntroController), // 番剧分p - if (!widget.loadingStatus && - widget.bangumiDetail!.episodes!.isNotEmpty) ...[ + if ((!widget.loadingStatus && + widget.bangumiDetail!.episodes!.isNotEmpty) || + bangumiItem != null && + bangumiItem!.episodes!.isNotEmpty) ...[ BangumiPanel( - pages: widget.bangumiDetail!.episodes!, - cid: widget.bangumiDetail!.episodes!.first.cid, + pages: bangumiItem != null + ? bangumiItem!.episodes! + : widget.bangumiDetail!.episodes!, + cid: bangumiItem != null + ? bangumiItem!.episodes!.first.cid + : widget.bangumiDetail!.episodes!.first.cid, sheetHeight: sheetHeight, - changeFuc: (bvid, cid) => - bangumiIntroController.changeSeasonOrbangu(bvid, cid), + changeFuc: (bvid, cid, aid) => bangumiIntroController + .changeSeasonOrbangu(bvid, cid, aid), ) ], ], diff --git a/lib/pages/bangumi/widgets/bangumi_panel.dart b/lib/pages/bangumi/widgets/bangumi_panel.dart index 5d39b7cd..692112fd 100644 --- a/lib/pages/bangumi/widgets/bangumi_panel.dart +++ b/lib/pages/bangumi/widgets/bangumi_panel.dart @@ -64,18 +64,7 @@ class _BangumiPanelState extends State { itemCount: widget.pages.length, itemBuilder: (context, index) { return ListTile( - onTap: () async { - if (widget.pages[index].badge != null) { - SmartDialog.showToast('需要大会员'); - return; - } - await widget.changeFuc!( - widget.pages[index].bvid, - widget.pages[index].cid, - ); - currentIndex = index; - setState(() {}); - }, + onTap: () => changeFucCall(widget.pages[index], index), dense: false, title: Text( widget.pages[index].longTitle!, @@ -103,6 +92,20 @@ class _BangumiPanelState extends State { ); } + void changeFucCall(item, i) async { + if (item.badge != null) { + SmartDialog.showToast('需要大会员'); + return; + } + await widget.changeFuc!( + item.bvid, + item.cid, + item.aid, + ); + currentIndex = i; + setState(() {}); + } + @override Widget build(BuildContext context) { return Column( @@ -158,18 +161,7 @@ class _BangumiPanelState extends State { borderRadius: BorderRadius.circular(6), clipBehavior: Clip.hardEdge, child: InkWell( - onTap: () async { - if (widget.pages[i].badge != null) { - SmartDialog.showToast('需要大会员'); - return; - } - await widget.changeFuc!( - widget.pages[i].bvid, - widget.pages[i].cid, - ); - currentIndex = i; - setState(() {}); - }, + onTap: () => changeFucCall(widget.pages[i], i), child: Padding( padding: const EdgeInsets.symmetric( vertical: 8, horizontal: 10), diff --git a/lib/pages/history/widgets/item.dart b/lib/pages/history/widgets/item.dart index c4a7b791..11183d0e 100644 --- a/lib/pages/history/widgets/item.dart +++ b/lib/pages/history/widgets/item.dart @@ -62,14 +62,23 @@ class HistoryItem extends StatelessWidget { 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, - }, - ); + var epid = result['data'].epId; + if (epid != null) { + Get.toNamed( + '/video?bvid=$bvid&cid=$cid&epId=${result['data'].epId}', + arguments: { + 'pic': pic, + 'heroTag': heroTag, + 'videoType': SearchType.media_bangumi, + }, + ); + } else { + int cid = videoItem.history.cid ?? + // videoItem.history.oid ?? + await SearchHttp.ab2c(aid: aid, bvid: bvid); + Get.toNamed('/video?bvid=$bvid&cid=$cid', + arguments: {'heroTag': heroTag, 'pic': videoItem.cover}); + } } } else { if (videoItem.history.epid != '') { diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index c920c38f..5bde42ba 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -34,6 +34,9 @@ class VideoReplyController extends GetxController { Future queryReplyList({type = 'init'}) async { isLoadingMore = true; + if (type == 'init') { + currentPage = 0; + } var res = await ReplyHttp.replyList( oid: aid!, pageNum: currentPage + 1, diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index dc12f07f..83744c47 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -281,7 +281,8 @@ class _VideoReplyPanelState extends State isScrollControlled: true, builder: (BuildContext context) { return VideoReplyNewDialog( - oid: IdUtils.bv2av(Get.parameters['bvid']!), + oid: _videoReplyController.aid ?? + IdUtils.bv2av(Get.parameters['bvid']!), root: 0, parent: 0, replyType: ReplyType.video, From 8a59b0577727b089b0d0d9e656133a22fc7c4961 Mon Sep 17 00:00:00 2001 From: guozhigq Date: Fri, 4 Aug 2023 22:33:38 +0800 Subject: [PATCH 4/4] =?UTF-8?q?feat:=20=E6=89=8B=E6=8C=87=E6=BB=91?= =?UTF-8?q?=E5=8A=A8=E5=BF=AB=E8=BF=9B=E3=80=81=E5=BF=AB=E9=80=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video/detail/widgets/header_control.dart | 4 +-- lib/plugin/pl_player/controller.dart | 5 ++-- lib/plugin/pl_player/view.dart | 28 +++++++++++++++++-- .../pl_player/widgets/bottom_control.dart | 2 ++ 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/lib/pages/video/detail/widgets/header_control.dart b/lib/pages/video/detail/widgets/header_control.dart index 54eecc4b..bedcd008 100644 --- a/lib/pages/video/detail/widgets/header_control.dart +++ b/lib/pages/video/detail/widgets/header_control.dart @@ -4,7 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:pilipala/models/video/play/quality.dart'; import 'package:pilipala/models/video/play/url.dart'; -import 'package:pilipala/pages/home/index.dart'; +import 'package:pilipala/pages/main/index.dart'; import 'package:pilipala/pages/video/detail/index.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; @@ -403,7 +403,7 @@ class _HeaderControlState extends State { size: 15, color: Colors.white, ), - fuc: () => Get.offAll(const HomePage()), + fuc: () => Get.offAll(const MainApp()), ), const Spacer(), // ComBtn( diff --git a/lib/plugin/pl_player/controller.dart b/lib/plugin/pl_player/controller.dart index a7c8676a..50be2477 100644 --- a/lib/plugin/pl_player/controller.dart +++ b/lib/plugin/pl_player/controller.dart @@ -505,15 +505,16 @@ class PlPlayerController { } void onChangedSliderStart() { - feedBack(); _isSliderMoving.value = true; } - void onUodatedSliderProgress(value) { + void onUodatedSliderProgress(Duration value) { _sliderTempPosition.value = value; + _sliderPosition.value = value; } void onChangedSliderEnd() { + feedBack(); _isSliderMoving.value = false; _hideTaskControls(); } diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index 4b69a5b9..f359b5c5 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -57,6 +57,8 @@ class _PLVideoPlayerState extends State Timer? _volumeTimer; double _distance = 0.0; + // 初始手指落下位置 + double _initTapPositoin = 0.0; bool _volumeInterceptEventStream = false; @@ -464,8 +466,28 @@ class _PLVideoPlayerState extends State _.setPlaybackSpeed(currentSpeed / 2); }, // 水平位置 快进 - onHorizontalDragUpdate: (DragUpdateDetails details) {}, - onHorizontalDragEnd: (DragEndDetails details) {}, + onHorizontalDragUpdate: (DragUpdateDetails details) { + final tapPosition = details.localPosition.dx; + int curSliderPosition = _.sliderPosition.value.inSeconds; + late int result; + if (tapPosition - _initTapPositoin > 0) { + // 快进 + /// TODO 优化屏幕越小效果越明显 + result = (curSliderPosition + 1) + .clamp(0, _.duration.value.inSeconds); + } else { + // 快退 + result = (curSliderPosition - 1) + .clamp(0, _.duration.value.inSeconds); + } + _.onUodatedSliderProgress(Duration(seconds: result)); + _.onChangedSliderStart(); + _initTapPositoin = tapPosition; + }, + onHorizontalDragEnd: (DragEndDetails details) { + _.onChangedSliderEnd(); + _.seekTo(_.sliderPosition.value); + }, // 垂直方向 音量/亮度调节 onVerticalDragUpdate: (DragUpdateDetails details) async { final totalWidth = MediaQuery.of(context).size.width; @@ -546,7 +568,7 @@ class _PLVideoPlayerState extends State return Container(); } return Positioned( - bottom: -3, + bottom: -3.5, left: 0, right: 0, child: SlideTransition( diff --git a/lib/plugin/pl_player/widgets/bottom_control.dart b/lib/plugin/pl_player/widgets/bottom_control.dart index 32b98a19..0fd6c95d 100644 --- a/lib/plugin/pl_player/widgets/bottom_control.dart +++ b/lib/plugin/pl_player/widgets/bottom_control.dart @@ -4,6 +4,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:pilipala/plugin/pl_player/index.dart'; import 'package:pilipala/plugin/pl_player/widgets/play_pause_btn.dart'; +import 'package:pilipala/utils/feed_back.dart'; class BottomControl extends StatelessWidget implements PreferredSizeWidget { final PlPlayerController? controller; @@ -55,6 +56,7 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget { barHeight: 3.0, thumbRadius: 5.5, onDragStart: (duration) { + feedBack(); _.onChangedSliderStart(); }, onDragUpdate: (duration) {