From aab75fb9a986b7c4dc7f1a24bdf4861d7ad9a6be Mon Sep 17 00:00:00 2001 From: Princess Donut Date: Sat, 15 Aug 2026 11:22:34 +0100 Subject: [PATCH] Bound message snapshot raster size Co-authored-by: Princess Donut Signed-off-by: Princess Donut --- .../channels/message_long_press_region.dart | 24 ++++++++++-- .../channels/message_actions_test.dart | 38 +++++++++++++++++++ 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/mobile/lib/features/channels/message_long_press_region.dart b/mobile/lib/features/channels/message_long_press_region.dart index fa68d7c85..f5e4048e7 100644 --- a/mobile/lib/features/channels/message_long_press_region.dart +++ b/mobile/lib/features/channels/message_long_press_region.dart @@ -8,6 +8,13 @@ import 'package:flutter/rendering.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; const _iosMessageLongPressDuration = Duration(milliseconds: 200); +const _maxMessageSnapshotDimension = 2048.0; + +double _messageSnapshotPixelRatio(Size size, double devicePixelRatio) { + final longestSide = size.longestSide; + if (!longestSide.isFinite || longestSide <= 0) return devicePixelRatio; + return math.min(devicePixelRatio, _maxMessageSnapshotDimension / longestSide); +} /// Geometry and snapshot controls for a completed message long press. class MessageLongPressDetails { @@ -99,7 +106,7 @@ class _MessageLongPressRegion extends HookWidget { onLongPress?.call(anchorRect); return; } - final snapshotPixelRatio = math.min( + final maxSnapshotPixelRatio = math.min( MediaQuery.devicePixelRatioOf(context), 2.0, ); @@ -113,6 +120,10 @@ class _MessageLongPressRegion extends HookWidget { if (boundary == null) { throw StateError('Message snapshot is unavailable'); } + final snapshotPixelRatio = _messageSnapshotPixelRatio( + boundary.size, + maxSnapshotPixelRatio, + ); try { return await boundary.toImage(pixelRatio: snapshotPixelRatio); } catch (_) { @@ -123,10 +134,17 @@ class _MessageLongPressRegion extends HookWidget { rethrow; } try { - return await retryBoundary.toImage(pixelRatio: snapshotPixelRatio); + return await retryBoundary.toImage( + pixelRatio: _messageSnapshotPixelRatio( + retryBoundary.size, + maxSnapshotPixelRatio, + ), + ); } catch (_) { if (snapshotPixelRatio <= 1) rethrow; - return retryBoundary.toImage(pixelRatio: 1); + return retryBoundary.toImage( + pixelRatio: _messageSnapshotPixelRatio(retryBoundary.size, 1), + ); } } } diff --git a/mobile/test/features/channels/message_actions_test.dart b/mobile/test/features/channels/message_actions_test.dart index a4cd51228..9d98603e3 100644 --- a/mobile/test/features/channels/message_actions_test.dart +++ b/mobile/test/features/channels/message_actions_test.dart @@ -441,6 +441,44 @@ void main() { }, ); + testWidgets('message snapshot bounds very tall raster dimensions', ( + tester, + ) async { + tester.view.devicePixelRatio = 1; + tester.view.physicalSize = const Size(800, 5000); + addTearDown(tester.view.resetDevicePixelRatio); + addTearDown(tester.view.resetPhysicalSize); + MessageLongPressDetails? longPressDetails; + ui.Image? snapshot; + addTearDown(() => snapshot?.dispose()); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Material( + child: MessageLongPressInkWell( + key: const ValueKey('tall-snapshot-gesture-target'), + onLongPressDetails: (details) => longPressDetails = details, + child: const SizedBox(width: 240, height: 4096), + ), + ), + ), + ), + ); + + await tester.longPress( + find.byKey(const ValueKey('tall-snapshot-gesture-target')), + ); + expect(longPressDetails, isNotNull); + + final capture = longPressDetails!.captureSnapshot(); + await tester.pump(); + snapshot = await capture; + + expect(snapshot.width, 120); + expect(snapshot.height, 2048); + }); + testWidgets('message snapshot can exclude attached reaction content', ( tester, ) async {