From 4d56bf0cd69e7eb2abfe6ff956a10987c33b4ba8 Mon Sep 17 00:00:00 2001 From: n7484443 Date: Sun, 7 Jul 2024 01:49:20 +0900 Subject: [PATCH] refactor: context menu function, add test code (#1979) --- lib/src/widgets/others/delegate.dart | 27 ++++++++----- test/bug_fix_test.dart | 58 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 9 deletions(-) diff --git a/lib/src/widgets/others/delegate.dart b/lib/src/widgets/others/delegate.dart index 4b3441ba..64ccd21b 100644 --- a/lib/src/widgets/others/delegate.dart +++ b/lib/src/widgets/others/delegate.dart @@ -85,7 +85,18 @@ class EditorTextSelectionGestureDetectorBuilder { /// will return true if current [onTapDown] event is triggered by a touch or /// a stylus. bool shouldShowSelectionToolbar = true; - bool requiresAdditionalActionForToolbar = false; + PointerDeviceKind? kind; + + /// Check if the selection toolbar should show. + /// + /// If mouse is used, the toolbar should only show when right click. + /// Else, it should show when the selection is enabled. + bool checkSelectionToolbarShouldShow({required bool isAdditionalAction}) { + if (kind != PointerDeviceKind.mouse) { + return shouldShowSelectionToolbar; + } + return shouldShowSelectionToolbar && isAdditionalAction; + } bool detectWordBoundary = true; @@ -116,14 +127,13 @@ class EditorTextSelectionGestureDetectorBuilder { // through a touch screen (via either a finger or a stylus). // A mouse shouldn't trigger the selection overlay. // For backwards-compatibility, we treat a null kind the same as touch. - final kind = details.kind; + kind = details.kind; shouldShowSelectionToolbar = kind == null || kind == PointerDeviceKind .mouse || // Enable word selection by mouse double tap kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; - requiresAdditionalActionForToolbar = kind == PointerDeviceKind.mouse; } /// Handler for [EditorTextSelectionGestureDetector.onForcePressStart]. @@ -169,7 +179,7 @@ class EditorTextSelectionGestureDetectorBuilder { null, SelectionChangedCause.forcePress, ); - if (shouldShowSelectionToolbar && !requiresAdditionalActionForToolbar) { + if (checkSelectionToolbarShouldShow(isAdditionalAction: false)) { editor!.showToolbar(); } } @@ -193,7 +203,7 @@ class EditorTextSelectionGestureDetectorBuilder { @protected void onSecondarySingleTapUp(TapUpDetails details) { // added to show toolbar by right click - if (shouldShowSelectionToolbar) { + if (checkSelectionToolbarShouldShow(isAdditionalAction: true)) { editor!.showToolbar(); } } @@ -259,7 +269,7 @@ class EditorTextSelectionGestureDetectorBuilder { /// which triggers this callback. @protected void onSingleLongTapEnd(LongPressEndDetails details) { - if (shouldShowSelectionToolbar && !requiresAdditionalActionForToolbar) { + if (checkSelectionToolbarShouldShow(isAdditionalAction: false)) { editor!.showToolbar(); } } @@ -284,7 +294,7 @@ class EditorTextSelectionGestureDetectorBuilder { // have focus, selection hasn't been set when the toolbars // get added SchedulerBinding.instance.addPostFrameCallback((_) { - if (shouldShowSelectionToolbar && !requiresAdditionalActionForToolbar) { + if (checkSelectionToolbarShouldShow(isAdditionalAction: false)) { editor!.showToolbar(); } }); @@ -336,8 +346,7 @@ class EditorTextSelectionGestureDetectorBuilder { renderEditor!.handleDragEnd(details); if (isDesktop(supportWeb: true) && delegate.selectionEnabled && - shouldShowSelectionToolbar && - !requiresAdditionalActionForToolbar) { + checkSelectionToolbarShouldShow(isAdditionalAction: false)) { // added to show selection copy/paste toolbar after drag to select editor!.showToolbar(); } diff --git a/test/bug_fix_test.dart b/test/bug_fix_test.dart index 7c4f565b..0be8a1e0 100644 --- a/test/bug_fix_test.dart +++ b/test/bug_fix_test.dart @@ -1,3 +1,4 @@ +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill_test/flutter_quill_test.dart'; @@ -128,4 +129,61 @@ void main() { }); }); }); + + group('1742 - Disable context menu after selection for desktop platform', () { + late QuillController controller; + + setUp(() { + controller = QuillController.basic(); + }); + + tearDown(() { + controller.dispose(); + }); + + for (final device in [PointerDeviceKind.mouse, PointerDeviceKind.touch]) { + testWidgets( + '1742 - Disable context menu after selection for desktop platform $device', + (tester) async { + await tester.pumpWidget( + MaterialApp( + home: QuillEditor( + focusNode: FocusNode(), + scrollController: ScrollController(), + // ignore: avoid_redundant_argument_values + configurations: QuillEditorConfigurations( + controller: controller, + // ignore: avoid_redundant_argument_values + autoFocus: true, + expands: true, + ), + ), + ), + ); + if (device == PointerDeviceKind.mouse) { + expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); + // Long press to show menu + await tester.longPress(find.byType(QuillEditor), kind: device); + await tester.pumpAndSettle(); + + // Verify custom widget not shows + expect(find.byType(AdaptiveTextSelectionToolbar), findsNothing); + + await tester.tap(find.byType(QuillEditor), + buttons: kSecondaryButton, kind: device); + await tester.pumpAndSettle(); + + // Verify custom widget shows + expect(find.byType(AdaptiveTextSelectionToolbar), findsAny); + } else { + // Long press to show menu + await tester.longPress(find.byType(QuillEditor), kind: device); + await tester.pumpAndSettle(); + + // Verify custom widget shows + expect(find.byType(AdaptiveTextSelectionToolbar), findsAny); + } + }); + } + }); }