From b25de52b9e59f8313438601f9aeabd13eff8f33e Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Tue, 18 Feb 2025 18:25:20 +0800 Subject: [PATCH] feat: repost video Closes #279 Signed-off-by: bggRGjQaUbCoE --- lib/http/msg.dart | 38 ++++++++----- .../bangumi/introduction/controller.dart | 38 +++++++++++++ lib/pages/dynamics/repost_dyn_panel.dart | 54 ++++++++++++++----- .../video/detail/introduction/controller.dart | 22 ++++++++ 4 files changed, 126 insertions(+), 26 deletions(-) diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 1cca0dfc..b9746367 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -144,11 +144,13 @@ class MsgHttp { static Future createDynamic({ dynamic mid, - dynamic dynIdStr, // repost + dynamic dynIdStr, // repost dyn + dynamic rid, // repost video + dynamic dynType, dynamic rawText, List? pics, int? publishTime, - ReplyOption replyOption = ReplyOption.allow, + ReplyOption? replyOption, int? privatePub, }) async { String csrf = await Request.getCsrf(); @@ -171,17 +173,21 @@ class MsgHttp { } ] }, - if (dynIdStr == null) + if (replyOption != null || publishTime != null) "option": { if (publishTime != null) "timer_pub_time": publishTime, - if (replyOption == ReplyOption.close) "close_comment": 1, - if (replyOption == ReplyOption.choose) "up_choose_comment": 1, + if (replyOption == ReplyOption.close) + "close_comment": 1 + else if (replyOption == ReplyOption.choose) + "up_choose_comment": 1, }, - "scene": dynIdStr != null - ? 4 - : pics != null - ? 2 - : 1, + "scene": rid != null + ? 5 + : dynIdStr != null + ? 4 + : pics != null + ? 2 + : 1, if (privatePub != null) 'create_option': { 'private_pub': privatePub, @@ -189,12 +195,20 @@ class MsgHttp { if (pics != null) 'pics': pics, "attach_card": null, "upload_id": - "${mid}_${DateTime.now().millisecondsSinceEpoch ~/ 1000}_${Random().nextInt(9000) + 1000}", + "${rid != null ? 0 : mid}_${DateTime.now().millisecondsSinceEpoch ~/ 1000}_${Random().nextInt(9000) + 1000}", "meta": { "app_meta": {"from": "create.dynamic.web", "mobi_app": "web"} } }, - if (dynIdStr != null) "web_repost_src": {"dyn_id_str": dynIdStr} + if (dynIdStr != null || rid != null) + "web_repost_src": { + if (dynIdStr != null) "dyn_id_str": dynIdStr, + if (rid != null) + "revs_id": { + "dyn_type": dynType, + "rid": rid, + } + } }, ); if (res.data['code'] == 0) { diff --git a/lib/pages/bangumi/introduction/controller.dart b/lib/pages/bangumi/introduction/controller.dart index 710561c8..4d4d776c 100644 --- a/lib/pages/bangumi/introduction/controller.dart +++ b/lib/pages/bangumi/introduction/controller.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/pages/common/common_controller.dart'; +import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/pages/video/detail/introduction/controller.dart'; import 'package:PiliPlus/pages/video/detail/introduction/pay_coins_page.dart'; import 'package:PiliPlus/utils/extension.dart'; @@ -398,6 +399,43 @@ class BangumiIntroController extends CommonController { Share.share(videoUrl); }, ), + ListTile( + title: const Text( + '分享至动态', + style: TextStyle(fontSize: 14), + ), + onTap: () { + Get.back(); + showModalBottomSheet( + context: context, + isScrollControlled: true, + useSafeArea: true, + builder: (context) => RepostPanel( + rid: epId, + /** + * 1:番剧 // 4097 + 2:电影 // 4098 + 3:纪录片 // 4101 + 4:国创 // 4100 + 5:电视剧 // 4099 + 6:漫画 + 7:综艺 // 4099 + */ + dynType: switch (Get.parameters['type']) { + '1' => 4097, + '2' => 4098, + '3' => 4101, + '4' => 4100, + '5' || '7' => 4099, + _ => -1, + }, + pic: bangumiItem?.cover, + title: bangumiItem?.title, + uname: '', + ), + ); + }, + ), ], ), ); diff --git a/lib/pages/dynamics/repost_dyn_panel.dart b/lib/pages/dynamics/repost_dyn_panel.dart index 5a72877c..d88e7ac2 100644 --- a/lib/pages/dynamics/repost_dyn_panel.dart +++ b/lib/pages/dynamics/repost_dyn_panel.dart @@ -14,20 +14,37 @@ import 'package:get/get.dart'; class RepostPanel extends CommonPublishPage { const RepostPanel({ super.key, - required this.item, - required this.callback, + this.item, + this.callback, + // video + this.rid, + this.dynType, + this.pic, + this.title, + this.uname, + this.isMax, }); + // video + final int? rid; + final int? dynType; + final String? pic; + final String? title; + final String? uname; + final bool? isMax; + final dynamic item; - final Function callback; + final VoidCallback? callback; @override State createState() => _RepostPanelState(); } class _RepostPanelState extends CommonPublishPageState { - bool _isMax = false; - late final dynamic _pic = (widget.item as DynamicItemModel?) + late bool _isMax = widget.isMax ?? false; + + late final dynamic _pic = widget.pic ?? + (widget.item as DynamicItemModel?) ?.modules ?.moduleDynamic ?.major @@ -47,7 +64,9 @@ class _RepostPanelState extends CommonPublishPageState { ?.pics ?.firstOrNull ?.url; - late final _text = (widget.item as DynamicItemModel?) + + late final _text = widget.title ?? + (widget.item as DynamicItemModel?) ?.modules ?.moduleDynamic ?.major @@ -69,6 +88,9 @@ class _RepostPanelState extends CommonPublishPageState { ?.title ?? ''; + late final _uname = widget.uname ?? + (widget.item as DynamicItemModel?)?.modules?.moduleAuthor?.name; + @override void dispose() { try { @@ -139,6 +161,7 @@ class _RepostPanelState extends CommonPublishPageState { borderRadius: BorderRadius.circular(12), ), child: Row( + crossAxisAlignment: CrossAxisAlignment.start, children: [ if (_pic != null) ...[ NetworkImgLayer( @@ -154,13 +177,14 @@ class _RepostPanelState extends CommonPublishPageState { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text( - '@${(widget.item as DynamicItemModel?)?.modules?.moduleAuthor?.name}', - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - fontSize: 13, + if (_uname?.isNotEmpty == true) + Text( + '@$_uname', + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontSize: 13, + ), ), - ), Text( _text, maxLines: 2, @@ -353,13 +377,15 @@ class _RepostPanelState extends CommonPublishPageState { Future onCustomPublish({required String message, List? pictures}) async { dynamic result = await MsgHttp.createDynamic( mid: GStorage.userInfo.get('userInfoCache')?.mid, - dynIdStr: widget.item.idStr, + dynIdStr: widget.item?.idStr, + rid: widget.rid, + dynType: widget.dynType, rawText: editController.text, ); if (result['status']) { Get.back(); SmartDialog.showToast('转发成功'); - widget.callback(); + widget.callback?.call(); } else { SmartDialog.showToast(result['msg']); } diff --git a/lib/pages/video/detail/introduction/controller.dart b/lib/pages/video/detail/introduction/controller.dart index 4b5a8ab9..3f9a1771 100644 --- a/lib/pages/video/detail/introduction/controller.dart +++ b/lib/pages/video/detail/introduction/controller.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/member.dart'; +import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/pages/video/detail/introduction/pay_coins_page.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/utils.dart'; @@ -503,6 +504,27 @@ class VideoIntroController extends GetxController ' - $videoUrl'); }, ), + ListTile( + title: const Text( + '分享至动态', + style: TextStyle(fontSize: 14), + ), + onTap: () { + Get.back(); + showModalBottomSheet( + context: context, + isScrollControlled: true, + useSafeArea: true, + builder: (context) => RepostPanel( + rid: videoDetail.value.aid, + dynType: 8, + pic: videoDetail.value.pic, + title: videoDetail.value.title, + uname: videoDetail.value.owner?.name, + ), + ); + }, + ), ], ), );