feat: add more gesture interceptors (#757)

This commit is contained in:
Mathias Mogensen 2024-04-04 13:51:05 +02:00 • committed by GitHub
commit c97842ae91
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 59 additions and 14 deletions

View file

@ -1,11 +1,13 @@
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/editor/editor_component/service/selection/mobile_selection_service.dart'; import 'package:appflowy_editor/src/editor/editor_component/service/selection/mobile_selection_service.dart';
import 'package:appflowy_editor/src/editor/editor_component/service/selection/shared.dart'; import 'package:appflowy_editor/src/editor/editor_component/service/selection/shared.dart';
import 'package:appflowy_editor/src/flutter/overlay.dart'; import 'package:appflowy_editor/src/flutter/overlay.dart';
import 'package:appflowy_editor/src/service/selection/selection_gesture.dart'; import 'package:appflowy_editor/src/service/selection/selection_gesture.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';
class DesktopSelectionServiceWidget extends StatefulWidget { class DesktopSelectionServiceWidget extends StatefulWidget {
const DesktopSelectionServiceWidget({ const DesktopSelectionServiceWidget({
@ -235,6 +237,14 @@ class _DesktopSelectionServiceWidgetState
} }
void _onDoubleTapDown(TapDownDetails details) { void _onDoubleTapDown(TapDownDetails details) {
final canDoubleTap = _interceptors.every(
(interceptor) => interceptor.canDoubleTap?.call(details) ?? true,
);
if (!canDoubleTap) {
return updateSelection(null);
}
final offset = details.globalPosition; final offset = details.globalPosition;
final node = getNodeInOffset(offset); final node = getNodeInOffset(offset);
final selection = node?.selectable?.getWordBoundaryInOffset(offset); final selection = node?.selectable?.getWordBoundaryInOffset(offset);
@ -277,6 +287,13 @@ class _DesktopSelectionServiceWidgetState
void _onPanStart(DragStartDetails details) { void _onPanStart(DragStartDetails details) {
clearSelection(); clearSelection();
final canPanStart = _interceptors
.every((interceptor) => interceptor.canPanStart?.call(details) ?? true);
if (!canPanStart) {
return;
}
_panStartOffset = details.globalPosition.translate(-3.0, 0); _panStartOffset = details.globalPosition.translate(-3.0, 0);
_panStartScrollDy = editorState.service.scrollService?.dy; _panStartScrollDy = editorState.service.scrollService?.dy;
@ -286,6 +303,14 @@ class _DesktopSelectionServiceWidgetState
} }
void _onPanUpdate(DragUpdateDetails details) { void _onPanUpdate(DragUpdateDetails details) {
final canPanUpdate = _interceptors.every(
(interceptor) => interceptor.canPanUpdate?.call(details) ?? true,
);
if (!canPanUpdate) {
return;
}
if (_panStartOffset == null || if (_panStartOffset == null ||
_panStartScrollDy == null || _panStartScrollDy == null ||
_panStartPosition == null) { _panStartPosition == null) {
@ -316,6 +341,13 @@ class _DesktopSelectionServiceWidgetState
} }
void _onPanEnd(DragEndDetails details) { void _onPanEnd(DragEndDetails details) {
final canPanEnd = _interceptors
.every((interceptor) => interceptor.canPanEnd?.call(details) ?? true);
if (!canPanEnd) {
return;
}
_panStartPosition = null; _panStartPosition = null;
editorState.service.scrollService?.stopAutoScroll(); editorState.service.scrollService?.stopAutoScroll();

View file

@ -1,8 +1,9 @@
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
import 'package:appflowy_editor/src/core/document/node.dart'; import 'package:appflowy_editor/src/core/document/node.dart';
import 'package:appflowy_editor/src/core/location/position.dart'; import 'package:appflowy_editor/src/core/location/position.dart';
import 'package:appflowy_editor/src/core/location/selection.dart'; import 'package:appflowy_editor/src/core/location/selection.dart';
import 'package:appflowy_editor/src/editor/editor_component/service/selection/mobile_selection_service.dart'; import 'package:appflowy_editor/src/editor/editor_component/service/selection/mobile_selection_service.dart';
import 'package:flutter/material.dart' hide Overlay, OverlayEntry;
/// [AppFlowySelectionService] is responsible for processing /// [AppFlowySelectionService] is responsible for processing
/// the [Selection] changes and updates. /// the [Selection] changes and updates.
@ -87,9 +88,17 @@ class SelectionGestureInterceptor {
SelectionGestureInterceptor({ SelectionGestureInterceptor({
required this.key, required this.key,
this.canTap, this.canTap,
this.canDoubleTap,
this.canPanStart,
this.canPanUpdate,
this.canPanEnd,
}); });
final String key; final String key;
bool Function(TapDownDetails details)? canTap; bool Function(TapDownDetails details)? canTap;
bool Function(TapDownDetails details)? canDoubleTap;
bool Function(DragStartDetails details)? canPanStart;
bool Function(DragUpdateDetails details)? canPanUpdate;
bool Function(DragEndDetails details)? canPanEnd;
} }

View file

@ -1,9 +1,11 @@
import 'dart:io'; import 'dart:io';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import '../../../../infra/clipboard_test.dart'; import '../../../../infra/clipboard_test.dart';
import '../../../infra/testable_editor.dart'; import '../../../infra/testable_editor.dart';
@ -40,12 +42,12 @@ void main() async {
(tester) async { (tester) async {
await _testHandleCopy(tester, Document.fromJson(data)); await _testHandleCopy(tester, Document.fromJson(data));
}); });
testWidgets( // TODO: fix this test
'Presses Command + A in nested document and copy text nestednode', // testWidgets(
(tester) async { // 'Presses Command + A in nested document and copy text nestednode',
// TODO: fix this test // (tester) async {
// await _testNestedNodeCopyPaste(tester, Document.fromJson(exampledoc)); // await _testNestedNodeCopyPaste(tester, Document.fromJson(exampledoc));
}); // });
testWidgets('update selection and execute cut command', (tester) async { testWidgets('update selection and execute cut command', (tester) async {
await _testCutHandle(tester, Document.fromJson(cutData)); await _testCutHandle(tester, Document.fromJson(cutData));

View file

@ -1,7 +1,9 @@
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import '../../../infra/testable_editor.dart'; import '../../../infra/testable_editor.dart';
const _padding = 24.0; const _padding = 24.0;
@ -103,8 +105,8 @@ void main() async {
}); });
// TODO(.): The purpose of this test is to catch addPostFrameCallback from // TODO(.): The purpose of this test is to catch addPostFrameCallback from
// calculateTextDirection but it doesn't catch it. Commenting the callback // calculateTextDirection but it doesn't catch it. Commenting the callback
// out doesn't make this test fail. // out doesn't make this test fail.
testWidgets( testWidgets(
"indent AUTO line under AUTO line changing the second line calculated direction", "indent AUTO line under AUTO line changing the second line calculated direction",
(tester) async { (tester) async {