opt: save unsent replies

This commit is contained in:
bggRGjQaUbCoE
2024-09-02 14:50:21 +08:00
parent b7c7f3743d
commit 915688e4d1
3 changed files with 115 additions and 36 deletions

View File

@@ -37,6 +37,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
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<VideoReplyPanel>
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<VideoReplyPanel>
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,

View File

@@ -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(

View File

@@ -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<ReplyPage>
with SingleTickerProviderStateMixin {
late final _focusNode = FocusNode();
late final _controller = ChatBottomPanelContainerController<PanelType>();
final TextEditingController _replyContentController = TextEditingController();
late final TextEditingController _replyContentController =
TextEditingController(text: widget.savedReply);
PanelType _currentPanelType = PanelType.none;
bool _readOnly = false;
final _readOnlyStream = StreamController<bool>();
@@ -54,6 +59,11 @@ class _ReplyPageState extends State<ReplyPage>
@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<ReplyPage>
_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<ReplyPage>
),
const Spacer(),
StreamBuilder(
initialData: false,
initialData: _enablePublish,
stream: _publishStream.stream,
builder: (_, snapshot) => FilledButton.tonal(
onPressed: snapshot.data == true ? submitReplyAdd : null,