diff --git a/example/lib/screens/quill/my_quill_editor.dart b/example/lib/screens/quill/my_quill_editor.dart index 28ab3100..21791c7c 100644 --- a/example/lib/screens/quill/my_quill_editor.dart +++ b/example/lib/screens/quill/my_quill_editor.dart @@ -80,6 +80,21 @@ class MyQuillEditor extends StatelessWidget { ).writeAsBytes(imageBytes, flush: true); return file.path; }, + onGifPaste: (gifBytes) async { + if (isWeb()) { + return null; + } + // We will save it to system temporary files + final newFileName = '${DateTime.now().toIso8601String()}.gif'; + final newPath = path.join( + io.Directory.systemTemp.path, + newFileName, + ); + final file = await io.File( + newPath, + ).writeAsBytes(gifBytes, flush: true); + return file.path; + }, embedBuilders: [ ...(isWeb() ? FlutterQuillEmbeds.editorWebBuilders() diff --git a/lib/src/models/config/editor/editor_configurations.dart b/lib/src/models/config/editor/editor_configurations.dart index af938f08..cb64336a 100644 --- a/lib/src/models/config/editor/editor_configurations.dart +++ b/lib/src/models/config/editor/editor_configurations.dart @@ -61,6 +61,7 @@ class QuillEditorConfigurations extends Equatable { this.floatingCursorDisabled = false, this.textSelectionControls, this.onImagePaste, + this.onGifPaste, this.customShortcuts, this.customActions, this.detectWordBoundary = true, @@ -282,6 +283,11 @@ class QuillEditorConfigurations extends Equatable { /// Returns the url of the image if the image should be inserted. final Future Function(Uint8List imageBytes)? onImagePaste; + /// Callback when the user pastes the given gif. + /// + /// Returns the url of the gif if the gif should be inserted. + final Future Function(Uint8List imageBytes)? onGifPaste; + /// Contains user-defined shortcuts map. /// /// [https://docs.flutter.dev/development/ui/advanced/actions-and-shortcuts#shortcuts] @@ -391,6 +397,7 @@ class QuillEditorConfigurations extends Equatable { bool? floatingCursorDisabled, TextSelectionControls? textSelectionControls, Future Function(Uint8List imageBytes)? onImagePaste, + Future Function(Uint8List imageBytes)? onGifPaste, Map? customShortcuts, Map>? customActions, bool? detectWordBoundary, @@ -449,6 +456,7 @@ class QuillEditorConfigurations extends Equatable { textSelectionControls: textSelectionControls ?? this.textSelectionControls, onImagePaste: onImagePaste ?? this.onImagePaste, + onGifPaste: onGifPaste ?? this.onGifPaste, customShortcuts: customShortcuts ?? this.customShortcuts, customActions: customActions ?? this.customActions, detectWordBoundary: detectWordBoundary ?? this.detectWordBoundary, diff --git a/lib/src/models/config/raw_editor/raw_editor_configurations.dart b/lib/src/models/config/raw_editor/raw_editor_configurations.dart index 7bb33a6e..726dda0f 100644 --- a/lib/src/models/config/raw_editor/raw_editor_configurations.dart +++ b/lib/src/models/config/raw_editor/raw_editor_configurations.dart @@ -73,6 +73,7 @@ class QuillRawEditorConfigurations extends Equatable { this.customRecognizerBuilder, this.floatingCursorDisabled = false, this.onImagePaste, + this.onGifPaste, this.customLinkPrefixes = const [], this.dialogTheme, this.contentInsertionConfiguration, @@ -261,6 +262,8 @@ class QuillRawEditorConfigurations extends Equatable { final Future Function(Uint8List imageBytes)? onImagePaste; + final Future Function(Uint8List imageBytes)? onGifPaste; + /// Contains user-defined shortcuts map. /// /// [https://docs.flutter.dev/development/ui/advanced/actions-and-shortcuts#shortcuts] diff --git a/lib/src/widgets/editor/editor.dart b/lib/src/widgets/editor/editor.dart index 3957ad9c..4c4ea7cb 100644 --- a/lib/src/widgets/editor/editor.dart +++ b/lib/src/widgets/editor/editor.dart @@ -277,6 +277,7 @@ class QuillEditorState extends State customRecognizerBuilder: configurations.customRecognizerBuilder, floatingCursorDisabled: configurations.floatingCursorDisabled, onImagePaste: configurations.onImagePaste, + onGifPaste: configurations.onGifPaste, customShortcuts: configurations.customShortcuts, customActions: configurations.customActions, customLinkPrefixes: configurations.customLinkPrefixes, diff --git a/lib/src/widgets/raw_editor/raw_editor_state.dart b/lib/src/widgets/raw_editor/raw_editor_state.dart index c9f88df5..670cd8ee 100644 --- a/lib/src/widgets/raw_editor/raw_editor_state.dart +++ b/lib/src/widgets/raw_editor/raw_editor_state.dart @@ -279,26 +279,50 @@ class QuillRawEditorState extends EditorState if (onImagePaste != null) { if (clipboard != null) { final reader = await clipboard.read(); - if (!reader.canProvide(Formats.png)) { - return; + if (reader.canProvide(Formats.png)) { + reader.getFile(Formats.png, (value) async { + final image = value; + + final imageUrl = await onImagePaste(await image.readAll()); + if (imageUrl == null) { + return; + } + + controller.replaceText( + textEditingValue.selection.end, + 0, + BlockEmbed.image(imageUrl), + null, + ); + }); } - reader.getFile(Formats.png, (value) async { - final image = value; + } + } - final imageUrl = await onImagePaste(await image.readAll()); - if (imageUrl == null) { - return; - } + final onGifPaste = widget.configurations.onGifPaste; + if (onGifPaste != null) { + if (clipboard != null) { + final reader = await clipboard.read(); + if (reader.canProvide(Formats.gif)) { + reader.getFile(Formats.gif, (value) async { + final gif = value; - controller.replaceText( - textEditingValue.selection.end, - 0, - BlockEmbed.image(imageUrl), - null, - ); - }); + final gifUrl = await onGifPaste(await gif.readAll()); + if (gifUrl == null) { + return; + } + + controller.replaceText( + textEditingValue.selection.end, + 0, + BlockEmbed.image(gifUrl), + null, + ); + }); + } } } + return; } /// Select the entire text value.