From 0d8f755c801eac1b3309a004d23923d6541ee6e5 Mon Sep 17 00:00:00 2001 From: Steve Date: Tue, 30 Jan 2024 02:59:26 +0100 Subject: [PATCH] feat: add contentInsertionConfiguration to editor and text input service (#691) * Add contentInsertionConfiguration to editor and text input service * add unit tests * feat(editor): add contentInsertionConfiguration --- .../editor_component/service/editor.dart | 5 ++++ .../service/ime/non_delta_input_service.dart | 10 ++++++- .../service/ime/text_input_service.dart | 3 ++ .../service/keyboard_service_widget.dart | 5 ++++ .../ime/non_delta_input_service_test.dart | 28 +++++++++++++++++++ 5 files changed, 50 insertions(+), 1 deletion(-) diff --git a/lib/src/editor/editor_component/service/editor.dart b/lib/src/editor/editor_component/service/editor.dart index 1735052f5..d66cbbf6c 100644 --- a/lib/src/editor/editor_component/service/editor.dart +++ b/lib/src/editor/editor_component/service/editor.dart @@ -23,6 +23,7 @@ class AppFlowyEditor extends StatefulWidget { List? characterShortcutEvents, List? commandShortcutEvents, List>? contextMenuItems, + this.contentInsertionConfiguration, this.editable = true, this.autoFocus = false, this.focusedSelection, @@ -157,6 +158,9 @@ class AppFlowyEditor extends StatefulWidget { /// only works on iOS or Android. final bool showMagnifier; + /// {@macro flutter.widgets.editableText.contentInsertionConfiguration} + final ContentInsertionConfiguration? contentInsertionConfiguration; + @override State createState() => _AppFlowyEditorState(); } @@ -260,6 +264,7 @@ class _AppFlowyEditorState extends State { characterShortcutEvents: widget.characterShortcutEvents, commandShortcutEvents: widget.commandShortcutEvents, focusNode: widget.focusNode, + contentInsertionConfiguration: widget.contentInsertionConfiguration, child: child, ), ); diff --git a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart index 19731189a..55888b473 100644 --- a/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/non_delta_input_service.dart @@ -13,6 +13,7 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { required super.onReplace, required super.onNonTextUpdate, required super.onPerformAction, + super.contentInsertionConfiguration, super.onFloatingCursor, }); @@ -171,7 +172,14 @@ class NonDeltaTextInputService extends TextInputService with TextInputClient { } @override - void insertContent(KeyboardInsertedContent content) {} + void insertContent(KeyboardInsertedContent content) { + assert( + contentInsertionConfiguration?.allowedMimeTypes + .contains(content.mimeType) ?? + false, + ); + contentInsertionConfiguration?.onContentInserted.call(content); + } void _updateComposing(TextEditingDelta delta) { if (delta is! TextEditingDeltaNonTextUpdate) { diff --git a/lib/src/editor/editor_component/service/ime/text_input_service.dart b/lib/src/editor/editor_component/service/ime/text_input_service.dart index 279eaa3bf..6ef0877be 100644 --- a/lib/src/editor/editor_component/service/ime/text_input_service.dart +++ b/lib/src/editor/editor_component/service/ime/text_input_service.dart @@ -9,6 +9,7 @@ abstract class TextInputService { required this.onNonTextUpdate, required this.onPerformAction, this.onFloatingCursor, + this.contentInsertionConfiguration, }); Future Function(TextEditingDeltaInsertion insertion) onInsert; @@ -19,6 +20,8 @@ abstract class TextInputService { Future Function(TextInputAction action) onPerformAction; Future Function(RawFloatingCursorPoint point)? onFloatingCursor; + final ContentInsertionConfiguration? contentInsertionConfiguration; + TextRange? get composingTextRange; bool get attached; diff --git a/lib/src/editor/editor_component/service/keyboard_service_widget.dart b/lib/src/editor/editor_component/service/keyboard_service_widget.dart index b62afb684..61ddf2882 100644 --- a/lib/src/editor/editor_component/service/keyboard_service_widget.dart +++ b/lib/src/editor/editor_component/service/keyboard_service_widget.dart @@ -14,9 +14,11 @@ class KeyboardServiceWidget extends StatefulWidget { this.commandShortcutEvents = const [], this.characterShortcutEvents = const [], this.focusNode, + this.contentInsertionConfiguration, required this.child, }); + final ContentInsertionConfiguration? contentInsertionConfiguration; final FocusNode? focusNode; final List commandShortcutEvents; final List characterShortcutEvents; @@ -86,6 +88,7 @@ class KeyboardServiceWidgetState extends State point, editorState, ), + contentInsertionConfiguration: widget.contentInsertionConfiguration, ); focusNode = widget.focusNode ?? FocusNode(debugLabel: 'keyboard service'); @@ -236,6 +239,8 @@ class KeyboardServiceWidgetState extends State textCapitalization: TextCapitalization.sentences, inputAction: TextInputAction.newline, keyboardAppearance: Theme.of(context).brightness, + allowedMimeTypes: + widget.contentInsertionConfiguration?.allowedMimeTypes ?? [], ), ); // disable shortcuts when the IME active diff --git a/test/editor/editor_component/ime/non_delta_input_service_test.dart b/test/editor/editor_component/ime/non_delta_input_service_test.dart index edadbd896..5f08273c4 100644 --- a/test/editor/editor_component/ime/non_delta_input_service_test.dart +++ b/test/editor/editor_component/ime/non_delta_input_service_test.dart @@ -1,4 +1,7 @@ +import 'dart:async'; + import 'package:appflowy_editor/src/editor/editor_component/service/ime/non_delta_input_service.dart'; +import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -75,5 +78,30 @@ void main() { inputService.performAction(TextInputAction.newline); expect(onPerformAction, true); }); + + test('content insertion configuration is handled', () { + final completer = Completer(); + final config = ContentInsertionConfiguration( + allowedMimeTypes: ['mimeType'], + onContentInserted: (value) => completer.complete(true), + ); + final inputService = NonDeltaTextInputService( + onInsert: (_) async {}, + onDelete: (_) async {}, + onReplace: (_) async {}, + onNonTextUpdate: (_) async {}, + onPerformAction: (_) async {}, + contentInsertionConfiguration: config, + ); + + inputService.insertContent( + const KeyboardInsertedContent( + mimeType: 'mimeType', + uri: 'uri', + ), + ); + + expect(completer.future, completion(true)); + }); }); }