Skip to content

Commit

Permalink
[SuperTextField][Mobile] Don't show the mobile toolbar upon first tap (
Browse files Browse the repository at this point in the history
…Resolves #2005)
  • Loading branch information
angelosilvestre committed May 19, 2024
1 parent d2aeb94 commit 18d57a0
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class IOSTextFieldTouchInteractorState extends State<IOSTextFieldTouchInteractor
final didCaretStayInSamePlace = _selectionBeforeTap != null &&
_selectionBeforeTap?.hasSameBoundsAs(widget.textController.selection) == true &&
_selectionBeforeTap!.isCollapsed;
if (didCaretStayInSamePlace || didTapOnExistingSelection) {
if ((didCaretStayInSamePlace || didTapOnExistingSelection) && widget.focusNode.hasFocus) {
// The user either tapped directly on the caret, or on an expanded selection,
// or the user tapped in empty space but didn't move the caret, for example
// the user tapped in empty space after the text and the caret was already
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,68 @@ a scrollbar
// Ensure we are connected again.
expect(controller.isAttachedToIme, true);
});

testWidgetsOnMobile("tap up does not shows the toolbar if the field does not have focus", (tester) async {
await _pumpTestApp(
tester,
controller: AttributedTextEditingController(text: AttributedText('')),
);

// Tap down and up so the field is focused.
await tester.tapAt(tester.getTopLeft(find.byType(SuperTextField)));
await tester.pumpAndSettle();

// Ensure the toolbar isn't visible.
expect(SuperTextFieldInspector.wantsMobileToolbarToBeVisible(), isFalse);
});

testWidgetsOnIos("tap up shows the toolbar if the field already has focus", (tester) async {
await _pumpTestApp(
tester,
controller: AttributedTextEditingController(text: AttributedText('')),
);

// Tap down and up so the field is focused.
await tester.tapAt(tester.getTopLeft(find.byType(SuperTextField)));
await tester.pumpAndSettle();

// Ensure the toolbar isn't visible.
expect(SuperTextFieldInspector.wantsMobileToolbarToBeVisible(), isFalse);

// Avoid a double tap.
await tester.pump(kDoubleTapTimeout + const Duration(milliseconds: 1));

// Tap down and up again.
await tester.tapAt(tester.getTopLeft(find.byType(SuperTextField)));
await tester.pumpAndSettle();

// Ensure the toolbar is visible.
expect(SuperTextFieldInspector.wantsMobileToolbarToBeVisible(), isTrue);
});

testWidgetsOnAndroid("tap up does not shows the toolbar if the field already has focus", (tester) async {
await _pumpTestApp(
tester,
controller: AttributedTextEditingController(text: AttributedText('')),
);

// Tap down and up so the field is focused.
await tester.tapAt(tester.getTopLeft(find.byType(SuperTextField)));
await tester.pumpAndSettle();

// Ensure the toolbar isn't visible.
expect(SuperTextFieldInspector.wantsMobileToolbarToBeVisible(), isFalse);

// Avoid a double tap.
await tester.pump(kDoubleTapTimeout + const Duration(milliseconds: 1));

// Tap down and up again.
await tester.tapAt(tester.getTopLeft(find.byType(SuperTextField)));
await tester.pumpAndSettle();

// Ensure the toolbar is visible.
expect(SuperTextFieldInspector.wantsMobileToolbarToBeVisible(), isFalse);
});
});

testWidgetsOnAllPlatforms("loses focus when user taps outside in a TapRegion", (tester) async {
Expand Down
40 changes: 40 additions & 0 deletions super_editor/test/super_textfield/super_textfield_inspector.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:super_editor/src/super_textfield/android/_editing_controls.dart';
import 'package:super_editor/super_editor.dart';
import 'package:super_text_layout/super_text_layout.dart';

Expand Down Expand Up @@ -293,6 +294,45 @@ class SuperTextFieldInspector {
"Couldn't find the caret rectangle because we couldn't find a SuperTextField. Finder: $superTextFieldFinder");
}

/// Returns `true` if the mobile text field is configured to display a toolbar.
///
/// {@macro supertextfield_finder}
///
/// Throws if a mobile text field isn't found.
static bool wantsMobileToolbarToBeVisible([Finder? superTextFieldFinder]) {
final finder = superTextFieldFinder ?? find.byType(SuperTextField);

final fieldFinder = findInnerPlatformTextField(finder);
final match = fieldFinder.evaluate().single.widget;

switch (match.runtimeType) {
case SuperAndroidTextField:
final touchInteractor = (find
.descendant(
of: fieldFinder,
matching: find.byType(AndroidEditingOverlayControls),
)
.evaluate()
.single as StatefulElement)
.widget as AndroidEditingOverlayControls;

return touchInteractor.editingController.isToolbarVisible;
case SuperIOSTextField:
final touchInteractor = (find
.descendant(
of: fieldFinder,
matching: find.byType(IOSTextFieldTouchInteractor),
)
.evaluate()
.single as StatefulElement)
.widget as IOSTextFieldTouchInteractor;

return touchInteractor.editingOverlayController.isToolbarVisible;
default:
throw Exception("Didn't find a mobile SuperTextField");
}
}

static Rect? _findCaretRectInViewportOnDesktop(Finder desktopTextField) {
final viewport = find
.descendant(of: desktopTextField, matching: find.byType(SuperTextFieldScrollview))
Expand Down

0 comments on commit 18d57a0

Please sign in to comment.