From d98a660d362705933aa46a16486d5757d730130e Mon Sep 17 00:00:00 2001 From: klockky Date: Sat, 23 May 2026 07:22:53 +0000 Subject: [PATCH] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4=20?= =?UTF-8?q?=D1=81=20Navigator.push=20=D0=BD=D0=B0=20OverlayEntry:=20route?= =?UTF-8?q?=20=D0=BC=D0=BE=D0=B4=D0=B0=D0=BB=20=D0=B3=D0=BB=D0=BE=D1=82?= =?UTF-8?q?=D0=B0=D0=BB=20pointer=20events=20=D0=BF=D0=BE=D1=81=D0=BB?= =?UTF-8?q?=D0=B5=20cancel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/frontend/screens/chats/chat_screen.dart | 32 +++---- .../widgets/message_actions_overlay.dart | 95 ++++++++++++------- 2 files changed, 74 insertions(+), 53 deletions(-) diff --git a/lib/frontend/screens/chats/chat_screen.dart b/lib/frontend/screens/chats/chat_screen.dart index dd44b50..3fb8bdb 100644 --- a/lib/frontend/screens/chats/chat_screen.dart +++ b/lib/frontend/screens/chats/chat_screen.dart @@ -1737,23 +1737,21 @@ class _LongPressBubbleState extends State<_LongPressBubble> { controller.attach(details.globalPosition); _controller = controller; - Navigator.of(ctx) - .push( - MessageActionsRoute( - snapshot: snapshot, - originRect: rect, - tapPoint: details.globalPosition, - isMe: widget.isMe, - messageText: widget.message.text, - controller: controller, - ), - ) - .whenComplete(() { - if (identical(_controller, controller)) { - _controller = null; - } - controller.dispose(); - }); + showMessageActions( + context: ctx, + snapshot: snapshot, + originRect: rect, + tapPoint: details.globalPosition, + isMe: widget.isMe, + messageText: widget.message.text, + controller: controller, + onDispose: () { + if (identical(_controller, controller)) { + _controller = null; + } + controller.dispose(); + }, + ); } @override diff --git a/lib/frontend/widgets/message_actions_overlay.dart b/lib/frontend/widgets/message_actions_overlay.dart index 80e6ae2..dc6b3b6 100644 --- a/lib/frontend/widgets/message_actions_overlay.dart +++ b/lib/frontend/widgets/message_actions_overlay.dart @@ -60,36 +60,33 @@ class MessageActionsController extends ChangeNotifier { } } -class MessageActionsRoute extends PageRouteBuilder { - MessageActionsRoute({ - required ui.Image snapshot, - required Rect originRect, - required Offset tapPoint, - required bool isMe, - required String? messageText, - required MessageActionsController controller, - }) : super( - opaque: false, - barrierColor: Colors.transparent, - transitionDuration: const Duration(milliseconds: 320), - reverseTransitionDuration: const Duration(milliseconds: 220), - pageBuilder: (ctx, anim, secondaryAnim) { - return _MessageActionsLayer( - snapshot: snapshot, - originRect: originRect, - tapPoint: tapPoint, - isMe: isMe, - messageText: messageText, - controller: controller, - animation: CurvedAnimation( - parent: anim, - curve: Curves.easeOutCubic, - reverseCurve: Curves.easeInCubic, - ), - ); - }, - transitionsBuilder: (_, __, ___, child) => child, - ); +void showMessageActions({ + required BuildContext context, + required ui.Image snapshot, + required Rect originRect, + required Offset tapPoint, + required bool isMe, + required String? messageText, + required MessageActionsController controller, + required VoidCallback onDispose, +}) { + final overlay = Overlay.of(context, rootOverlay: true); + late OverlayEntry entry; + entry = OverlayEntry( + builder: (ctx) => _MessageActionsLayer( + snapshot: snapshot, + originRect: originRect, + tapPoint: tapPoint, + isMe: isMe, + messageText: messageText, + controller: controller, + onDismiss: () { + if (entry.mounted) entry.remove(); + onDispose(); + }, + ), + ); + overlay.insert(entry); } class _MessageActionsLayer extends StatefulWidget { @@ -99,7 +96,7 @@ class _MessageActionsLayer extends StatefulWidget { final bool isMe; final String? messageText; final MessageActionsController controller; - final Animation animation; + final VoidCallback onDismiss; const _MessageActionsLayer({ required this.snapshot, @@ -108,14 +105,18 @@ class _MessageActionsLayer extends StatefulWidget { required this.isMe, required this.messageText, required this.controller, - required this.animation, + required this.onDismiss, }); @override State<_MessageActionsLayer> createState() => _MessageActionsLayerState(); } -class _MessageActionsLayerState extends State<_MessageActionsLayer> { +class _MessageActionsLayerState extends State<_MessageActionsLayer> + with SingleTickerProviderStateMixin { + late final AnimationController _animController; + late final Animation _animation; + bool _closing = false; static const double _radius = 92.0; static const double _arcSpan = math.pi * 0.62; static const double _btnSize = 52.0; @@ -131,6 +132,22 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> { int _hoveredIndex = -1; bool _committedFired = false; + @override + void initState() { + super.initState(); + _animController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: 320), + reverseDuration: const Duration(milliseconds: 220), + ); + _animation = CurvedAnimation( + parent: _animController, + curve: Curves.easeOutCubic, + reverseCurve: Curves.easeInCubic, + ); + _animController.forward(); + } + @override void didChangeDependencies() { super.didChangeDependencies(); @@ -151,6 +168,7 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> { @override void dispose() { + _animController.dispose(); widget.controller.removeListener(_onControllerUpdate); widget.snapshot.dispose(); super.dispose(); @@ -223,8 +241,13 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> { } Future _close() async { + if (!mounted || _closing) return; + _closing = true; + try { + await _animController.reverse(); + } catch (_) {} if (!mounted) return; - Navigator.of(context).maybePop(); + widget.onDismiss(); } Future _copy() async { @@ -247,9 +270,9 @@ class _MessageActionsLayerState extends State<_MessageActionsLayer> { Widget build(BuildContext context) { final size = MediaQuery.sizeOf(context); return AnimatedBuilder( - animation: widget.animation, + animation: _animation, builder: (ctx, _) { - final t = widget.animation.value.clamp(0.0, 1.0); + final t = _animation.value.clamp(0.0, 1.0); final blurSigma = 14.0 * t; final bubbleScale = 1.0 + 0.05 * t;