переход с Navigator.push на OverlayEntry: route модал глотал pointer events после cancel

This commit is contained in:
klockky
2026-05-23 07:22:53 +00:00
parent aca19cfd20
commit d98a660d36
2 changed files with 74 additions and 53 deletions
+15 -17
View File
@@ -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
@@ -60,36 +60,33 @@ class MessageActionsController extends ChangeNotifier {
}
}
class MessageActionsRoute extends PageRouteBuilder<void> {
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<double> 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<double> _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<void> _close() async {
if (!mounted || _closing) return;
_closing = true;
try {
await _animController.reverse();
} catch (_) {}
if (!mounted) return;
Navigator.of(context).maybePop();
widget.onDismiss();
}
Future<void> _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;