diff --git a/lib/http/api.dart b/lib/http/api.dart index b6975c4b..1735902c 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -511,4 +511,13 @@ class Api { /// 取消订阅 static const String cancelSub = '/x/v3/fav/season/unfav'; + + /// 动态转发 + static const String dynamicForwardUrl = '/x/dynamic/feed/create/submit_check'; + + /// 创建动态 + static const String dynamicCreate = '/x/dynamic/feed/create/dyn'; + + /// 删除收藏夹 + static const String delFavFolder = '/x/v3/fav/folder/del'; } diff --git a/lib/http/dynamics.dart b/lib/http/dynamics.dart index d62de12f..63dea4ff 100644 --- a/lib/http/dynamics.dart +++ b/lib/http/dynamics.dart @@ -1,3 +1,4 @@ +import 'dart:math'; import '../models/dynamics/result.dart'; import '../models/dynamics/up.dart'; import 'index.dart'; @@ -117,4 +118,94 @@ class DynamicsHttp { }; } } + + static Future dynamicForward() async { + var res = await Request().post( + Api.dynamicForwardUrl, + queryParameters: { + 'csrf': await Request.getCsrf(), + 'x-bili-device-req-json': {'platform': 'web', 'device': 'pc'}, + 'x-bili-web-req-json': {'spm_id': '333.999'}, + }, + data: { + 'attach_card': null, + 'scene': 4, + 'content': { + 'conetents': [ + {'raw_text': "2", 'type': 1, 'biz_id': ""} + ] + } + }, + ); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } + + static Future dynamicCreate({ + required int mid, + required int scene, + int? oid, + String? dynIdStr, + String? rawText, + }) async { + DateTime now = DateTime.now(); + int timestamp = now.millisecondsSinceEpoch ~/ 1000; + Random random = Random(); + int randomNumber = random.nextInt(9000) + 1000; + String uploadId = '${mid}_${timestamp}_$randomNumber'; + + Map webRepostSrc = { + 'dyn_id_str': dynIdStr ?? '', + }; + + /// 投稿转发 + if (scene == 5) { + webRepostSrc = { + 'revs_id': {'dyn_type': 8, 'rid': oid} + }; + } + var res = await Request().post(Api.dynamicCreate, queryParameters: { + 'platform': 'web', + 'csrf': await Request.getCsrf(), + 'x-bili-device-req-json': {'platform': 'web', 'device': 'pc'}, + 'x-bili-web-req-json': {'spm_id': '333.999'}, + }, data: { + 'dyn_req': { + 'content': { + 'contents': [ + {'raw_text': rawText ?? '', 'type': 1, 'biz_id': ''} + ] + }, + 'scene': scene, + 'attach_card': null, + 'upload_id': uploadId, + 'meta': { + 'app_meta': {'from': 'create.dynamic.web', 'mobi_app': 'web'} + } + }, + 'web_repost_src': webRepostSrc + }); + if (res.data['code'] == 0) { + return { + 'status': true, + 'data': res.data['data'], + }; + } else { + return { + 'status': false, + 'data': [], + 'msg': res.data['message'], + }; + } + } } diff --git a/lib/http/user.dart b/lib/http/user.dart index fea0a22e..dfdf187e 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -395,4 +395,21 @@ class UserHttp { return {'status': false, 'msg': res.data['message']}; } } + + // 删除文件夹 + static Future delFavFolder({required int mediaIds}) async { + var res = await Request().post( + Api.delFavFolder, + queryParameters: { + 'media_ids': mediaIds, + 'platform': 'web', + 'csrf': await Request.getCsrf(), + }, + ); + if (res.data['code'] == 0) { + return {'status': true}; + } else { + return {'status': false, 'msg': res.data['message']}; + } + } } diff --git a/lib/pages/dynamics/widgets/action_panel.dart b/lib/pages/dynamics/widgets/action_panel.dart index 0ca09b8c..51ef3952 100644 --- a/lib/pages/dynamics/widgets/action_panel.dart +++ b/lib/pages/dynamics/widgets/action_panel.dart @@ -3,38 +3,58 @@ 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:pilipala/common/widgets/network_img_layer.dart'; import 'package:pilipala/http/dynamics.dart'; import 'package:pilipala/models/dynamics/result.dart'; import 'package:pilipala/pages/dynamics/index.dart'; import 'package:pilipala/utils/feed_back.dart'; +import 'package:status_bar_control/status_bar_control.dart'; +import 'rich_node_panel.dart'; class ActionPanel extends StatefulWidget { const ActionPanel({ super.key, - this.item, + required this.item, }); // ignore: prefer_typing_uninitialized_variables - final item; + final DynamicItemModel item; @override State createState() => _ActionPanelState(); } -class _ActionPanelState extends State { +class _ActionPanelState extends State + with TickerProviderStateMixin { final DynamicsController _dynamicsController = Get.put(DynamicsController()); late ModuleStatModel stat; bool isProcessing = false; + double defaultHeight = 260; + RxDouble height = 0.0.obs; + RxBool isExpand = false.obs; + late double statusHeight; + TextEditingController _inputController = TextEditingController(); + FocusNode myFocusNode = FocusNode(); + String _inputText = ''; + void Function()? handleState(Future Function() action) { - return isProcessing ? null : () async { - setState(() => isProcessing = true); - await action(); - setState(() => isProcessing = false); - }; + return isProcessing + ? null + : () async { + isProcessing = true; + await action(); + isProcessing = false; + }; } + @override void initState() { super.initState(); - stat = widget.item!.modules.moduleStat; + stat = widget.item.modules!.moduleStat!; + onInit(); + } + + onInit() async { + statusHeight = await StatusBarControl.getHeight; } // 动态点赞 @@ -43,7 +63,7 @@ class _ActionPanelState extends State { var item = widget.item!; String dynamicId = item.idStr!; // 1 已点赞 2 不喜欢 0 未操作 - Like like = item.modules.moduleStat.like; + Like like = item.modules!.moduleStat!.like!; int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0'); bool status = like.status!; int up = status ? 2 : 1; @@ -51,15 +71,15 @@ class _ActionPanelState extends State { if (res['status']) { SmartDialog.showToast(!status ? '点赞成功' : '取消赞'); if (up == 1) { - item.modules.moduleStat.like.count = (count + 1).toString(); - item.modules.moduleStat.like.status = true; + item.modules!.moduleStat!.like!.count = (count + 1).toString(); + item.modules!.moduleStat!.like!.status = true; } else { if (count == 1) { - item.modules.moduleStat.like.count = '点赞'; + item.modules!.moduleStat!.like!.count = '点赞'; } else { - item.modules.moduleStat.like.count = (count - 1).toString(); + item.modules!.moduleStat!.like!.count = (count - 1).toString(); } - item.modules.moduleStat.like.status = false; + item.modules!.moduleStat!.like!.status = false; } setState(() {}); } else { @@ -67,17 +87,307 @@ class _ActionPanelState extends State { } } + // 转发动态预览 + Widget dynamicPreview() { + ItemModulesModel? modules = widget.item.modules; + final String type = widget.item.type!; + String? cover = modules?.moduleAuthor?.face; + switch (type) { + /// 图文动态 + case 'DYNAMIC_TYPE_DRAW': + cover = modules?.moduleDynamic?.major?.opus?.pics?.first.url; + + /// 投稿 + case 'DYNAMIC_TYPE_AV': + cover = modules?.moduleDynamic?.major?.archive?.cover; + + /// 转发的动态 + case 'DYNAMIC_TYPE_FORWARD': + String forwardType = widget.item.orig!.type!; + switch (forwardType) { + /// 图文动态 + case 'DYNAMIC_TYPE_DRAW': + cover = modules?.moduleDynamic?.major?.opus?.pics?.first.url; + + /// 投稿 + case 'DYNAMIC_TYPE_AV': + cover = modules?.moduleDynamic?.major?.archive?.cover; + + /// 专栏文章 + case 'DYNAMIC_TYPE_ARTICLE': + cover = ''; + + /// 番剧 + case 'DYNAMIC_TYPE_PGC': + cover = ''; + + /// 纯文字动态 + case 'DYNAMIC_TYPE_WORD': + cover = ''; + + /// 直播 + case 'DYNAMIC_TYPE_LIVE_RCMD': + cover = ''; + + /// 合集查看 + case 'DYNAMIC_TYPE_UGC_SEASON': + cover = ''; + + /// 番剧 + case 'DYNAMIC_TYPE_PGC_UNION': + cover = modules?.moduleDynamic?.major?.pgc?.cover; + + default: + cover = ''; + } + + /// 专栏文章 + case 'DYNAMIC_TYPE_ARTICLE': + cover = ''; + + /// 番剧 + case 'DYNAMIC_TYPE_PGC': + cover = ''; + + /// 纯文字动态 + case 'DYNAMIC_TYPE_WORD': + cover = ''; + + /// 直播 + case 'DYNAMIC_TYPE_LIVE_RCMD': + cover = ''; + + /// 合集查看 + case 'DYNAMIC_TYPE_UGC_SEASON': + cover = ''; + + /// 番剧查看 + case 'DYNAMIC_TYPE_PGC_UNION': + cover = ''; + + default: + cover = ''; + } + return Container( + width: double.infinity, + height: 95, + margin: const EdgeInsets.fromLTRB(12, 0, 12, 14), + decoration: BoxDecoration( + color: + Theme.of(context).colorScheme.secondaryContainer.withOpacity(0.4), + borderRadius: BorderRadius.circular(6), + border: Border( + left: BorderSide( + width: 4, + color: Theme.of(context).colorScheme.primary.withOpacity(0.8)), + ), + ), + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 14), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + '@${widget.item.modules!.moduleAuthor!.name}', + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + ), + ), + const SizedBox(height: 8), + Row( + children: [ + NetworkImgLayer( + src: cover ?? '', + width: 34, + height: 34, + type: 'emote', + ), + const SizedBox(width: 10), + Expanded( + child: Text.rich( + style: const TextStyle(height: 0), + richNode(widget.item, context), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + // Text(data) + ], + ) + ], + ), + ), + ); + } + + // 动态转发 + void forwardHandler() async { + showModalBottomSheet( + context: context, + enableDrag: false, + useRootNavigator: true, + isScrollControlled: true, + builder: (context) { + return Obx( + () => AnimatedContainer( + duration: Durations.medium1, + onEnd: () async { + if (isExpand.value) { + await Future.delayed(const Duration(milliseconds: 80)); + myFocusNode.requestFocus(); + } + }, + height: height.value + MediaQuery.of(context).padding.bottom, + child: Column( + children: [ + AnimatedContainer( + duration: Durations.medium1, + height: isExpand.value ? statusHeight : 0, + ), + Padding( + padding: EdgeInsets.fromLTRB( + isExpand.value ? 10 : 16, + 10, + isExpand.value ? 14 : 12, + 0, + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + if (isExpand.value) ...[ + IconButton( + onPressed: () => togglePanelState(false), + icon: const Icon(Icons.close), + ), + Text( + '转发动态', + style: Theme.of(context) + .textTheme + .titleMedium! + .copyWith(fontWeight: FontWeight.bold), + ) + ] else ...[ + const Text( + '转发动态', + style: TextStyle(fontWeight: FontWeight.bold), + ) + ], + isExpand.value + ? FilledButton( + onPressed: () => dynamicForward('forward'), + child: const Text('转发'), + ) + : TextButton( + onPressed: () {}, + child: const Text('立即转发'), + ) + ], + ), + ), + if (!isExpand.value) ...[ + GestureDetector( + onTap: () => togglePanelState(true), + behavior: HitTestBehavior.translucent, + child: Container( + width: double.infinity, + alignment: Alignment.centerLeft, + padding: const EdgeInsets.fromLTRB(16, 0, 10, 14), + child: Text( + '说点什么吧', + textAlign: TextAlign.start, + style: TextStyle( + color: Theme.of(context).colorScheme.outline), + ), + ), + ), + ] else ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 10, 16, 0), + child: TextField( + maxLines: 5, + focusNode: myFocusNode, + controller: _inputController, + onChanged: (value) { + setState(() { + _inputText = value; + }); + }, + decoration: const InputDecoration( + border: InputBorder.none, + hintText: '说点什么吧', + ), + ), + ), + ], + dynamicPreview(), + if (!isExpand.value) ...[ + const Divider(thickness: 0.1, height: 1), + ListTile( + onTap: () => Get.back(), + minLeadingWidth: 0, + dense: true, + title: Text( + '取消', + style: TextStyle( + color: Theme.of(context).colorScheme.outline), + textAlign: TextAlign.center, + ), + ), + ] + ], + ), + ), + ); + }, + ); + } + + togglePanelState(status) { + if (!status) { + Get.back(); + height.value = defaultHeight; + _inputText = ''; + _inputController.clear(); + } else { + height.value = Get.size.height; + } + isExpand.value = !(isExpand.value); + } + + dynamicForward(String type) async { + String dynamicId = widget.item.idStr!; + var res = await DynamicsHttp.dynamicCreate( + dynIdStr: dynamicId, + mid: _dynamicsController.userInfo.mid, + rawText: _inputText, + scene: 4, + ); + if (res['status']) { + SmartDialog.showToast(type == 'forward' ? '转发成功' : '发布成功'); + togglePanelState(false); + } + } + + @override + void dispose() { + myFocusNode.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { var color = Theme.of(context).colorScheme.outline; var primary = Theme.of(context).colorScheme.primary; + height.value = defaultHeight; + print('height.value: ${height.value}'); return Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Expanded( flex: 1, child: TextButton.icon( - onPressed: () {}, + onPressed: forwardHandler, icon: const Icon( FontAwesomeIcons.shareFromSquare, size: 16, diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index c85cad45..d273a1a6 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -1,15 +1,16 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:pilipala/pages/dynamics/index.dart'; +import '../../../models/dynamics/result.dart'; import 'action_panel.dart'; import 'author_panel.dart'; import 'content_panel.dart'; import 'forward_panel.dart'; class DynamicPanel extends StatelessWidget { - final dynamic item; + final DynamicItemModel item; final String? source; - DynamicPanel({this.item, this.source, Key? key}) : super(key: key); + DynamicPanel({required this.item, this.source, Key? key}) : super(key: key); final DynamicsController _dynamicsController = Get.put(DynamicsController()); @override @@ -41,8 +42,8 @@ class DynamicPanel extends StatelessWidget { padding: const EdgeInsets.fromLTRB(12, 12, 12, 8), child: AuthorPanel(item: item), ), - if (item!.modules!.moduleDynamic!.desc != null || - item!.modules!.moduleDynamic!.major != null) + if (item.modules!.moduleDynamic!.desc != null || + item.modules!.moduleDynamic!.major != null) Content(item: item, source: source), forWard(item, context, _dynamicsController, source), const SizedBox(height: 2), diff --git a/lib/pages/fav/controller.dart b/lib/pages/fav/controller.dart index 6ff0afc8..2307d303 100644 --- a/lib/pages/fav/controller.dart +++ b/lib/pages/fav/controller.dart @@ -10,6 +10,7 @@ import 'package:pilipala/utils/storage.dart'; class FavController extends GetxController { final ScrollController scrollController = ScrollController(); Rx favFolderData = FavFolderData().obs; + RxList favFolderList = [].obs; Box userInfoCache = GStrorage.userInfo; UserInfoData? userInfo; int currentPage = 1; @@ -32,9 +33,10 @@ class FavController extends GetxController { if (res['status']) { if (type == 'init') { favFolderData.value = res['data']; + favFolderList.value = res['data'].list; } else { if (res['data'].list.isNotEmpty) { - favFolderData.value.list!.addAll(res['data'].list); + favFolderList.addAll(res['data'].list); favFolderData.update((val) {}); } } @@ -49,4 +51,13 @@ class FavController extends GetxController { Future onLoad() async { queryFavFolder(type: 'onload'); } + + removeFavFolder({required int mediaIds}) async { + for (var i in favFolderList) { + if (i.id == mediaIds) { + favFolderList.remove(i); + break; + } + } + } } diff --git a/lib/pages/fav/view.dart b/lib/pages/fav/view.dart index b980914a..424a885d 100644 --- a/lib/pages/fav/view.dart +++ b/lib/pages/fav/view.dart @@ -62,11 +62,10 @@ class _FavPageState extends State { return Obx( () => ListView.builder( controller: scrollController, - itemCount: _favController.favFolderData.value.list!.length, + itemCount: _favController.favFolderList.length, itemBuilder: (context, index) { return FavItem( - favFolderItem: - _favController.favFolderData.value.list![index]); + favFolderItem: _favController.favFolderList[index]); }, ), ); diff --git a/lib/pages/fav/widgets/item.dart b/lib/pages/fav/widgets/item.dart index 08730d7b..3c44ec9d 100644 --- a/lib/pages/fav/widgets/item.dart +++ b/lib/pages/fav/widgets/item.dart @@ -13,14 +13,16 @@ class FavItem extends StatelessWidget { Widget build(BuildContext context) { String heroTag = Utils.makeHeroTag(favFolderItem.fid); return InkWell( - onTap: () => Get.toNamed( - '/favDetail', - arguments: favFolderItem, - parameters: { - 'heroTag': heroTag, - 'mediaId': favFolderItem.id.toString(), - }, - ), + onTap: () async { + Get.toNamed( + '/favDetail', + arguments: favFolderItem, + parameters: { + 'heroTag': heroTag, + 'mediaId': favFolderItem.id.toString(), + }, + ); + }, child: Padding( padding: const EdgeInsets.fromLTRB(12, 7, 12, 7), child: LayoutBuilder( diff --git a/lib/pages/fav_detail/controller.dart b/lib/pages/fav_detail/controller.dart index 55d5b884..7af398e8 100644 --- a/lib/pages/fav_detail/controller.dart +++ b/lib/pages/fav_detail/controller.dart @@ -1,9 +1,11 @@ +import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:pilipala/http/user.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/user/fav_detail.dart'; import 'package:pilipala/models/user/fav_folder.dart'; +import 'package:pilipala/pages/fav/index.dart'; class FavDetailController extends GetxController { FavFolderItemData? item; @@ -74,4 +76,41 @@ class FavDetailController extends GetxController { onLoad() { queryUserFavFolderDetail(type: 'onLoad'); } + + onDelFavFolder() async { + SmartDialog.show( + useSystem: true, + animationType: SmartAnimationType.centerFade_otherSlide, + builder: (BuildContext context) { + return AlertDialog( + title: const Text('提示'), + content: const Text('确定删除这个收藏夹吗?'), + actions: [ + TextButton( + onPressed: () async { + SmartDialog.dismiss(); + }, + child: Text( + '点错了', + style: TextStyle(color: Theme.of(context).colorScheme.outline), + ), + ), + TextButton( + onPressed: () async { + var res = await UserHttp.delFavFolder(mediaIds: mediaId!); + SmartDialog.dismiss(); + SmartDialog.showToast(res['status'] ? '操作成功' : res['msg']); + if (res['status']) { + FavController favController = Get.find(); + await favController.removeFavFolder(mediaIds: mediaId!); + Get.back(); + } + }, + child: const Text('确认'), + ) + ], + ); + }, + ); + } } diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index 993ff63b..1bf5cb6f 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -101,11 +101,19 @@ class _FavDetailPageState extends State { Get.toNamed('/favSearch?searchType=0&mediaId=$mediaId'), icon: const Icon(Icons.search_outlined), ), - // IconButton( - // onPressed: () {}, - // icon: const Icon(Icons.more_vert), - // ), - const SizedBox(width: 6), + PopupMenuButton( + icon: const Icon(Icons.more_vert_outlined), + position: PopupMenuPosition.under, + onSelected: (String type) {}, + itemBuilder: (BuildContext context) => >[ + PopupMenuItem( + onTap: () => _favDetailController.onDelFavFolder(), + value: 'pause', + child: const Text('删除收藏夹'), + ), + ], + ), + const SizedBox(width: 14), ], flexibleSpace: FlexibleSpaceBar( background: Container( diff --git a/lib/pages/member_dynamics/view.dart b/lib/pages/member_dynamics/view.dart index 68aa72d7..2e093bcc 100644 --- a/lib/pages/member_dynamics/view.dart +++ b/lib/pages/member_dynamics/view.dart @@ -5,6 +5,7 @@ import 'package:pilipala/pages/member_dynamics/index.dart'; import 'package:pilipala/utils/utils.dart'; import '../../common/widgets/http_error.dart'; +import '../../models/dynamics/result.dart'; import '../dynamics/widgets/dynamic_panel.dart'; class MemberDynamicsPage extends StatefulWidget { @@ -66,7 +67,8 @@ class _MemberDynamicsPageState extends State { if (snapshot.connectionState == ConnectionState.done) { if (snapshot.data != null) { Map data = snapshot.data as Map; - List list = _memberDynamicController.dynamicsList; + RxList list = + _memberDynamicController.dynamicsList; if (data['status']) { return Obx( () => list.isNotEmpty diff --git a/lib/pages/video/detail/reply_new/view.dart b/lib/pages/video/detail/reply_new/view.dart index a94b6071..029e015a 100644 --- a/lib/pages/video/detail/reply_new/view.dart +++ b/lib/pages/video/detail/reply_new/view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:pilipala/http/dynamics.dart'; import 'package:pilipala/http/video.dart'; import 'package:pilipala/models/common/reply_type.dart'; import 'package:pilipala/models/video/reply/emote.dart'; @@ -40,6 +41,8 @@ class _VideoReplyNewDialogState extends State double keyboardHeight = 0.0; // 键盘高度 final _debouncer = Debouncer(milliseconds: 200); // 设置延迟时间 String toolbarType = 'input'; + RxBool isForward = false.obs; + RxBool showForward = false.obs; @override void initState() { @@ -52,6 +55,10 @@ class _VideoReplyNewDialogState extends State _autoFocus(); // 监听聚焦状态 _focuslistener(); + final String routePath = Get.currentRoute; + if (routePath.startsWith('/video')) { + showForward.value = true; + } } _autoFocus() async { @@ -88,6 +95,16 @@ class _VideoReplyNewDialogState extends State Get.back(result: { 'data': ReplyItemModel.fromJson(result['data']['reply'], ''), }); + + /// 投稿、番剧页面 + if (isForward.value) { + await DynamicsHttp.dynamicCreate( + mid: 0, + rawText: message, + oid: widget.oid!, + scene: 5, + ); + } } else { SmartDialog.showToast(result['msg']); } @@ -145,7 +162,6 @@ class _VideoReplyNewDialogState extends State double _keyboardHeight = EdgeInsets.fromViewPadding( View.of(context).viewInsets, View.of(context).devicePixelRatio) .bottom; - print('_keyboardHeight: $_keyboardHeight'); return Container( clipBehavior: Clip.hardEdge, decoration: BoxDecoration( @@ -225,9 +241,37 @@ class _VideoReplyNewDialogState extends State toolbarType: toolbarType, selected: toolbarType == 'emote', ), + const SizedBox(width: 6), + Obx( + () => showForward.value + ? TextButton.icon( + onPressed: () { + isForward.value = !isForward.value; + }, + icon: Icon( + isForward.value + ? Icons.check_box + : Icons.check_box_outline_blank, + size: 22), + label: const Text('转发到动态'), + style: ButtonStyle( + foregroundColor: MaterialStateProperty.all( + isForward.value + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, + ), + ), + ) + : const SizedBox(), + ), const Spacer(), - TextButton( - onPressed: () => submitReplyAdd(), child: const Text('发送')) + SizedBox( + height: 36, + child: FilledButton( + onPressed: () => submitReplyAdd(), + child: const Text('发送'), + ), + ), ], ), ),