From 915688e4d1ed0a32a407b9a7d0c583eab2fc82f6 Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Mon, 2 Sep 2024 14:50:21 +0800 Subject: [PATCH] opt: save unsent replies --- lib/pages/video/detail/reply/view.dart | 128 +++++++++++++----- .../detail/reply/widgets/reply_item.dart | 6 + .../video/detail/reply_new/reply_page.dart | 17 ++- 3 files changed, 115 insertions(+), 36 deletions(-) diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 71f01607..09a64371 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -37,6 +37,8 @@ class _VideoReplyPanelState extends State late VideoReplyController _videoReplyController; late AnimationController fabAnimationCtr; + late final _savedReplies = {}; + bool _isFabVisible = true; String replyLevel = '1'; late String heroTag; @@ -218,6 +220,59 @@ class _VideoReplyPanelState extends State replyReply: (replyItem) => replyReply(replyItem), replyType: ReplyType.video, + onReply: () { + dynamic oid = _videoReplyController + .replyList[index].oid; + dynamic root = _videoReplyController + .replyList[index].rpid; + dynamic parent = _videoReplyController + .replyList[index].rpid; + dynamic key = oid + root + parent; + Navigator.of(context) + .push( + GetDialogRoute( + pageBuilder: (buildContext, animation, + secondaryAnimation) { + return ReplyPage( + oid: oid, + root: root, + parent: parent, + replyType: ReplyType.video, + replyItem: _videoReplyController + .replyList[index], + savedReply: _savedReplies[key], + onSaveReply: (reply) { + _savedReplies[key] = reply; + }, + ); + }, + transitionDuration: + const Duration(milliseconds: 500), + transitionBuilder: (context, animation, + secondaryAnimation, child) { + const begin = Offset(0.0, 1.0); + const end = Offset.zero; + const curve = Curves.linear; + + var tween = Tween( + begin: begin, end: end) + .chain(CurveTween(curve: curve)); + + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + ), + ) + .then((value) { + // 完成评论,数据添加 + if (value != null && + value['data'] != null) { + _savedReplies[key] = null; + } + }); + }, ); } }, @@ -243,46 +298,51 @@ class _VideoReplyPanelState extends State heroTag: null, onPressed: () { feedBack(); + dynamic oid = _videoReplyController.aid ?? + IdUtils.bv2av(Get.parameters['bvid']!); Navigator.of(context) .push( - GetDialogRoute( - pageBuilder: - (buildContext, animation, secondaryAnimation) { - return ReplyPage( - oid: _videoReplyController.aid ?? - IdUtils.bv2av(Get.parameters['bvid']!), - root: 0, - parent: 0, - replyType: ReplyType.video, - ); + GetDialogRoute( + pageBuilder: + (buildContext, animation, secondaryAnimation) { + return ReplyPage( + oid: oid, + root: 0, + parent: 0, + replyType: ReplyType.video, + savedReply: _savedReplies[oid], + onSaveReply: (reply) { + _savedReplies[oid] = reply; }, - transitionDuration: const Duration(milliseconds: 500), - transitionBuilder: - (context, animation, secondaryAnimation, child) { - const begin = Offset(0.0, 1.0); - const end = Offset.zero; - const curve = Curves.linear; + ); + }, + transitionDuration: const Duration(milliseconds: 500), + transitionBuilder: + (context, animation, secondaryAnimation, child) { + const begin = Offset(0.0, 1.0); + const end = Offset.zero; + const curve = Curves.linear; - var tween = Tween(begin: begin, end: end) - .chain(CurveTween(curve: curve)); + var tween = Tween(begin: begin, end: end) + .chain(CurveTween(curve: curve)); - return SlideTransition( - position: animation.drive(tween), - child: child, - ); - }, - ), - ) + return SlideTransition( + position: animation.drive(tween), + child: child, + ); + }, + ), + ) .then( - (value) => { - // 完成评论,数据添加 - if (value != null && value['data'] != null) - { - _videoReplyController.replyList - .insert(0, value['data']) - } - }, - ); + (value) { + // 完成评论,数据添加 + if (value != null && value['data'] != null) { + _savedReplies[oid] = null; + _videoReplyController.replyList + .insert(0, value['data']); + } + }, + ); // showModalBottomSheet( // context: context, // isScrollControlled: true, diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index d7f1eac9..76d87b12 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -31,6 +31,7 @@ class ReplyItem extends StatelessWidget { this.replyReply, this.replyType, this.needDivider = true, + this.onReply, super.key, }); final ReplyItemModel? replyItem; @@ -40,6 +41,7 @@ class ReplyItem extends StatelessWidget { final Function? replyReply; final ReplyType? replyType; final bool needDivider; + final Function()? onReply; @override Widget build(BuildContext context) { @@ -303,6 +305,10 @@ class ReplyItem extends StatelessWidget { child: TextButton( onPressed: () { feedBack(); + if (onReply != null) { + onReply!(); + return; + } Navigator.of(context) .push( GetDialogRoute( diff --git a/lib/pages/video/detail/reply_new/reply_page.dart b/lib/pages/video/detail/reply_new/reply_page.dart index f4ceeadb..cc0fbd9e 100644 --- a/lib/pages/video/detail/reply_new/reply_page.dart +++ b/lib/pages/video/detail/reply_new/reply_page.dart @@ -23,6 +23,8 @@ class ReplyPage extends StatefulWidget { final int? parent; final ReplyType? replyType; final ReplyItemModel? replyItem; + final String? savedReply; + final Function(String reply)? onSaveReply; const ReplyPage({ super.key, @@ -31,6 +33,8 @@ class ReplyPage extends StatefulWidget { this.parent, this.replyType, this.replyItem, + this.savedReply, + this.onSaveReply, }); @override @@ -41,7 +45,8 @@ class _ReplyPageState extends State with SingleTickerProviderStateMixin { late final _focusNode = FocusNode(); late final _controller = ChatBottomPanelContainerController(); - final TextEditingController _replyContentController = TextEditingController(); + late final TextEditingController _replyContentController = + TextEditingController(text: widget.savedReply); PanelType _currentPanelType = PanelType.none; bool _readOnly = false; final _readOnlyStream = StreamController(); @@ -54,6 +59,11 @@ class _ReplyPageState extends State @override void initState() { super.initState(); + + if (widget.savedReply != null && widget.savedReply!.isNotEmpty) { + _enablePublish = true; + } + () async { await Future.delayed(const Duration(milliseconds: 300)); if (mounted) { @@ -194,6 +204,9 @@ class _ReplyPageState extends State _enablePublish = false; _publishStream.add(false); } + if (widget.onSaveReply != null) { + widget.onSaveReply!(value); + } }, focusNode: _focusNode, decoration: const InputDecoration( @@ -255,7 +268,7 @@ class _ReplyPageState extends State ), const Spacer(), StreamBuilder( - initialData: false, + initialData: _enablePublish, stream: _publishStream.stream, builder: (_, snapshot) => FilledButton.tonal( onPressed: snapshot.data == true ? submitReplyAdd : null,