diff --git a/packages/flutter/lib/src/widgets/selectable_region.dart b/packages/flutter/lib/src/widgets/selectable_region.dart index 0a33ee8e2dc..9a8b670a7c3 100644 --- a/packages/flutter/lib/src/widgets/selectable_region.dart +++ b/packages/flutter/lib/src/widgets/selectable_region.dart @@ -303,18 +303,21 @@ class SelectableRegion extends StatefulWidget { }) { final bool canCopy = selectionGeometry.status == SelectionStatus.uncollapsed; final bool canSelectAll = selectionGeometry.hasContent; - final bool platformCanShare = switch (defaultTargetPlatform) { - TargetPlatform.android => selectionGeometry.status == SelectionStatus.uncollapsed, - TargetPlatform.macOS || - TargetPlatform.fuchsia || - TargetPlatform.linux || - TargetPlatform.windows => false, - // TODO(bleroux): the share button should be shown on iOS but the share - // functionality requires some changes on the engine side because, on iPad, - // it needs an anchor for the popup. - // See: https://github.com/flutter/flutter/issues/141775. - TargetPlatform.iOS => false, - }; + // The share button is not supported on the web. + final bool platformCanShare = + !kIsWeb && + switch (defaultTargetPlatform) { + TargetPlatform.android => selectionGeometry.status == SelectionStatus.uncollapsed, + TargetPlatform.macOS || + TargetPlatform.fuchsia || + TargetPlatform.linux || + TargetPlatform.windows => false, + // TODO(bleroux): the share button should be shown on iOS but the share + // functionality requires some changes on the engine side because, on iPad, + // it needs an anchor for the popup. + // See: https://github.com/flutter/flutter/issues/141775. + TargetPlatform.iOS => false, + }; final bool canShare = onShare != null && platformCanShare; // On Android, the share button is before the select all button. @@ -410,7 +413,14 @@ class SelectableRegionState extends State SelectedContent? _lastSelectedContent; /// Whether the native browser context menu is enabled. - bool get _webContextMenuEnabled => kIsWeb && BrowserContextMenu.enabled; + // TODO(Renzo-Olivares): Re-enable web context menu for Android + // and iOS when https://github.com/flutter/flutter/issues/177123 + // is resolved. + bool get _webContextMenuEnabled => + kIsWeb && + BrowserContextMenu.enabled && + defaultTargetPlatform != TargetPlatform.android && + defaultTargetPlatform != TargetPlatform.iOS; /// The [SelectionOverlay] that is currently visible on the screen. /// diff --git a/packages/flutter/test/material/selection_area_test.dart b/packages/flutter/test/material/selection_area_test.dart index 5e38d566af8..7e865bbe25b 100644 --- a/packages/flutter/test/material/selection_area_test.dart +++ b/packages/flutter/test/material/selection_area_test.dart @@ -130,6 +130,50 @@ void main() { variant: const TargetPlatformVariant({TargetPlatform.iOS}), ); + testWidgets( + 'builds the default context menu by default on Android and iOS web', + (WidgetTester tester) async { + final FocusNode focusNode = FocusNode(); + addTearDown(focusNode.dispose); + + await tester.pumpWidget( + MaterialApp( + home: SelectionArea(focusNode: focusNode, child: const Text('How are you?')), + ), + ); + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); + + // Show the toolbar by longpressing. + final RenderParagraph paragraph1 = tester.renderObject( + find.descendant(of: find.text('How are you?'), matching: find.byType(RichText)), + ); + final TestGesture gesture = await tester.startGesture( + textOffsetToPosition(paragraph1, 6), + ); // at the 'r' + addTearDown(gesture.removePointer); + await tester.pump(const Duration(milliseconds: 500)); + // `are` is selected. + expect(paragraph1.selections[0], const TextSelection(baseOffset: 4, extentOffset: 7)); + + await gesture.up(); + await tester.pumpAndSettle(); + + expect(find.byType(AdaptiveTextSelectionToolbar), findsOneWidget); + }, + // TODO(Renzo-Olivares): Remove this test when the web context menu + // for Android and iOS is re-enabled. + // See: https://github.com/flutter/flutter/issues/177123. + // [intended] Android and iOS use the flutter rendered menu on the web. + skip: + !kIsWeb || + !{ + TargetPlatform.android, + TargetPlatform.iOS, + }.contains(defaultTargetPlatform), + ); + testWidgets( 'builds the default context menu by default', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/selectable_region_context_menu_test.dart b/packages/flutter/test/widgets/selectable_region_context_menu_test.dart index 6ab42eaa78e..c7c1a70b416 100644 --- a/packages/flutter/test/widgets/selectable_region_context_menu_test.dart +++ b/packages/flutter/test/widgets/selectable_region_context_menu_test.dart @@ -24,6 +24,14 @@ extension on web.CSSRuleList { Iterable.generate(length, (int index) => item(index)); } +bool _browserContextMenuEnabled() { + // TODO(Renzo-Olivares): Remove this when the web context menu + // for Android and iOS is re-enabled. + // See: https://github.com/flutter/flutter/issues/177123. + return kIsWeb && + !{TargetPlatform.android, TargetPlatform.iOS}.contains(defaultTargetPlatform); +} + void main() { late FakePlatformViewRegistry fakePlatformViewRegistry; @@ -39,128 +47,144 @@ void main() { PlatformSelectableRegionContextMenu.debugResetRegistry(); }); - testWidgets('DOM element is set up correctly', (WidgetTester tester) async { - final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + testWidgets( + 'DOM element is set up correctly', + (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); - await tester.pumpWidget( - MaterialApp( - home: SelectableRegion( - selectionControls: EmptyTextSelectionControls(), - child: const Placeholder(), + await tester.pumpWidget( + MaterialApp( + home: SelectableRegion( + selectionControls: EmptyTextSelectionControls(), + child: const Placeholder(), + ), ), - ), - ); + ); - final web.HTMLElement element = - fakePlatformViewRegistry.getViewById(currentViewId + 1) as web.HTMLElement; + final web.HTMLElement element = + fakePlatformViewRegistry.getViewById(currentViewId + 1) as web.HTMLElement; - expect(element, isNotNull); - expect(element.style.width, '100%'); - expect(element.style.height, '100%'); - expect(element.classList.length, 1); + expect(element, isNotNull); + expect(element.style.width, '100%'); + expect(element.style.height, '100%'); + expect(element.classList.length, 1); - final int numberOfStyleElements = getNumberOfStyleElements(); - expect(numberOfStyleElements, 1); - }); + final int numberOfStyleElements = getNumberOfStyleElements(); + expect(numberOfStyleElements, 1); + }, + skip: !_browserContextMenuEnabled(), // [intended] + ); - testWidgets('only one