From 4aae6c22aa734df508eee5f46a8e72a11ff89dd3 Mon Sep 17 00:00:00 2001 From: Matt Wilcox Date: Thu, 5 Nov 2026 17:34:10 -0600 Subject: [PATCH] fix(mobile): delay iOS message actions until a deliberate hold (#9049) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Increase the iOS message and reaction hold delay from 200 ms to 500 ms, giving users more time to start scrolling without opening a menu. Movement detection and other platforms remain unchanged. Apple documents a [0.5-second default for UILongPressGestureRecognizer](https://developer.apple.com/documentation/uikit/uilongpressgesturerecognizer/minimumpressduration). ### Related issue Fixes #8500. ### Testing - Regression checks fail with the old timeout and pass with the change: no recognition at 499 ms, recognition by 501 ms, and scrolling after a 300 ms pause cancels the hold. - Device testing pending; the local iOS simulator SDK is unavailable. Before review, verify deliberate holds, slow scroll starts, and reaction holds on an iPhone. 🤖 Generated with Goose Signed-off-by: Matt Wilcox Co-authored-by: Gen <8a28d770b293a0b223e7c671e5985a35fd9bc1a3c7e3fa92ff715bd2fe61b253@squarewebplatform.communities.buzz.xyz> --- .../features/channels/message_long_press_region.dart | 2 +- .../test/features/channels/message_actions_test.dart | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/mobile/lib/features/channels/message_long_press_region.dart b/mobile/lib/features/channels/message_long_press_region.dart index 526271c8c4..94c4be8750 100644 --- a/mobile/lib/features/channels/message_long_press_region.dart +++ b/mobile/lib/features/channels/message_long_press_region.dart @@ -8,7 +8,7 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; /// Shared hold deadline so nested reaction pills win before the message menu. -const iosMessageLongPressDuration = Duration(milliseconds: 200); +const iosMessageLongPressDuration = Duration(milliseconds: 500); const _maxMessageSnapshotDimension = 2048.0; double _messageSnapshotPixelRatio(Size size, double devicePixelRatio) { diff --git a/mobile/test/features/channels/message_actions_test.dart b/mobile/test/features/channels/message_actions_test.dart index 410d4cc843..e07013a26b 100644 --- a/mobile/test/features/channels/message_actions_test.dart +++ b/mobile/test/features/channels/message_actions_test.dart @@ -476,7 +476,7 @@ void main() { }); testWidgets( - 'message long press keeps taps and scrolling while repeated holds win', + 'message long press keeps taps and delayed scrolling while repeated holds win', (tester) async { var parentTaps = 0; var nestedTaps = 0; @@ -536,6 +536,8 @@ void main() { final drag = await tester.startGesture( tester.getCenter(find.byKey(const ValueKey('parent-gesture-target'))), ); + await tester.pump(const Duration(milliseconds: 300)); + expect(longPresses, 5); await drag.moveBy(const Offset(0, -30)); await tester.pump(); await drag.moveBy(const Offset(0, -70)); @@ -547,9 +549,13 @@ void main() { expect(longPresses, 5); expect(scrollController.offset, greaterThan(0)); }, + variant: TargetPlatformVariant({ + TargetPlatform.iOS, + TargetPlatform.android, + }), ); - testWidgets('iOS message long press recognizes at 200 ms', (tester) async { + testWidgets('iOS message long press recognizes at 500 ms', (tester) async { debugDefaultTargetPlatformOverride = TargetPlatform.iOS; try { var longPresses = 0; @@ -571,7 +577,7 @@ void main() { final gesture = await tester.startGesture( tester.getCenter(find.byKey(const ValueKey('ios-long-press-target'))), ); - await tester.pump(const Duration(milliseconds: 199)); + await tester.pump(const Duration(milliseconds: 499)); expect(longPresses, 0); await tester.pump(const Duration(milliseconds: 2)); expect(longPresses, 1);