dartlangeditorflutterflutter-appsflutter-examplesflutter-packageflutter-widgetquillquill-deltaquilljsreactquillrich-textrich-text-editorwysiwygwysiwyg-editor
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
278 lines
11 KiB
278 lines
11 KiB
library flutter_quill_extensions; |
|
|
|
import 'package:flutter/material.dart'; |
|
import 'package:flutter_quill/extensions.dart'; |
|
import 'package:flutter_quill/flutter_quill.dart'; |
|
|
|
import 'embeds/builders.dart'; |
|
import 'embeds/embed_types.dart'; |
|
import 'embeds/toolbar/camera_button.dart'; |
|
import 'embeds/toolbar/formula_button.dart'; |
|
import 'embeds/toolbar/image_button.dart'; |
|
import 'embeds/toolbar/video_button.dart'; |
|
|
|
export 'embeds/embed_types.dart'; |
|
export 'embeds/toolbar/camera_button.dart'; |
|
export 'embeds/toolbar/formula_button.dart'; |
|
export 'embeds/toolbar/image_button.dart'; |
|
export 'embeds/toolbar/image_video_utils.dart'; |
|
export 'embeds/toolbar/media_button.dart'; |
|
export 'embeds/toolbar/video_button.dart'; |
|
export 'embeds/utils.dart'; |
|
|
|
class FlutterQuillEmbeds { |
|
/// Returns a list of embed builders for QuillEditor. |
|
/// |
|
/// This method provides a collection of embed builders to enhance the |
|
/// functionality |
|
/// of a QuillEditor. It offers customization options for |
|
/// handling various types of |
|
/// embedded content, such as images, videos, and formulas. |
|
/// |
|
/// **Note:** This method is not intended for web usage. |
|
/// For web-specific embeds, |
|
/// use [webBuilders]. |
|
/// |
|
/// [onVideoInit] is a callback function that gets triggered when |
|
/// a video is initialized. |
|
/// You can use this to perform actions or setup configurations related |
|
/// to video embedding. |
|
/// |
|
/// [onImageRemovedCallback] is called when an image is |
|
/// removed from the editor. |
|
/// By default, [onImageRemovedCallback] deletes the |
|
/// temporary image file if |
|
/// the platform is mobile and if it still exists. You |
|
/// can customize this behavior |
|
/// by passing your own function that handles the removal process. |
|
/// |
|
/// Example of [onImageRemovedCallback] customization: |
|
/// ```dart |
|
/// afterRemoveImageFromEditor: (imageFile) async { |
|
/// // Your custom logic here |
|
/// // or leave it empty to do nothing |
|
/// } |
|
/// ``` |
|
/// |
|
/// [shouldRemoveImageCallback] is a callback |
|
/// function that is invoked when the |
|
/// user attempts to remove an image from the editor. It allows you to control |
|
/// whether the image should be removed based on your custom logic. |
|
/// |
|
/// Example of [shouldRemoveImageCallback] customization: |
|
/// ```dart |
|
/// shouldRemoveImageFromEditor: (imageFile) async { |
|
/// // Show a confirmation dialog before removing the image |
|
/// final isShouldRemove = await showYesCancelDialog( |
|
/// context: context, |
|
/// options: const YesOrCancelDialogOptions( |
|
/// title: 'Deleting an image', |
|
/// message: 'Are you sure you want' ' to delete this |
|
/// image from the editor?', |
|
/// ), |
|
/// ); |
|
/// |
|
/// // Return `true` to allow image removal if the user confirms, otherwise `false` |
|
/// return isShouldRemove; |
|
/// } |
|
/// ``` |
|
/// |
|
/// [forceUseMobileOptionMenuForImageClick] is a boolean |
|
/// flag that, when set to `true`, |
|
/// enforces the use of the mobile-specific option menu for image clicks in |
|
/// other platforms like desktop, this option doesn't affect mobile. it will |
|
/// not affect web |
|
/// This option |
|
/// can be used to override the default behavior based on the platform. |
|
/// |
|
/// The method returns a list of [EmbedBuilder] objects that can be used with |
|
/// QuillEditor |
|
/// to enable embedded content features like images, videos, and formulas. |
|
/// |
|
/// Example usage: |
|
/// ```dart |
|
/// final embedBuilders = QuillEmbedBuilders.builders( |
|
/// onVideoInit: (videoContainerKey) { |
|
/// // Custom video initialization logic |
|
/// }, |
|
/// // Customize other callback functions as needed |
|
/// ); |
|
/// |
|
/// final quillEditor = QuillEditor( |
|
/// // Other editor configurations |
|
/// embedBuilders: embedBuilders, |
|
/// ); |
|
/// ``` |
|
static List<EmbedBuilder> builders({ |
|
void Function(GlobalKey videoContainerKey)? onVideoInit, |
|
ImageEmbedBuilderOnRemovedCallback? onImageRemovedCallback, |
|
ImageEmbedBuilderWillRemoveCallback? shouldRemoveImageCallback, |
|
bool forceUseMobileOptionMenuForImageClick = false, |
|
}) => |
|
[ |
|
ImageEmbedBuilder( |
|
forceUseMobileOptionMenu: forceUseMobileOptionMenuForImageClick, |
|
onImageRemovedCallback: onImageRemovedCallback ?? |
|
(imageFile) async { |
|
final mobile = isMobile(); |
|
// If the platform is not mobile, return void; |
|
// Since the mobile OS gives us a copy of the image |
|
|
|
// Note: We should remove the image on Flutter web |
|
// since the behavior is similar to how it is on mobile, |
|
// but since this builder is not for web, we will ignore it |
|
if (!mobile) { |
|
return; |
|
} |
|
|
|
// On mobile OS (Android, iOS), the system will not give us |
|
// direct access to the image; instead, |
|
// it will give us the image |
|
// in the temp directory of the application. So, we want to |
|
// remove it when we no longer need it. |
|
|
|
// but on desktop we don't want to touch user files |
|
// especially on macOS, where we can't even delete it without |
|
// permission |
|
|
|
final isFileExists = await imageFile.exists(); |
|
if (isFileExists) { |
|
await imageFile.delete(); |
|
} |
|
}, |
|
shouldRemoveImageCallback: shouldRemoveImageCallback, |
|
), |
|
VideoEmbedBuilder(onVideoInit: onVideoInit), |
|
FormulaEmbedBuilder(), |
|
]; |
|
|
|
/// Returns a list of embed builders specifically designed for web support. |
|
/// |
|
/// [ImageEmbedBuilderWeb] is the embed builder for handling |
|
/// images on the web. |
|
/// |
|
static List<EmbedBuilder> webBuilders() => [ |
|
ImageEmbedBuilderWeb(), |
|
]; |
|
|
|
/// Returns a list of embed button builders to customize the toolbar buttons. |
|
/// |
|
/// [showImageButton] determines whether the image button should be displayed. |
|
/// [showVideoButton] determines whether the video button should be displayed. |
|
/// [showCameraButton] determines whether the camera button should |
|
/// be displayed. |
|
/// [showFormulaButton] determines whether the formula button |
|
/// should be displayed. |
|
/// |
|
/// [imageButtonTooltip] specifies the tooltip text for the image button. |
|
/// [videoButtonTooltip] specifies the tooltip text for the video button. |
|
/// [cameraButtonTooltip] specifies the tooltip text for the camera button. |
|
/// [formulaButtonTooltip] specifies the tooltip text for the formula button. |
|
/// |
|
/// [onImagePickCallback] is a callback function called when an |
|
/// image is picked. |
|
/// [onVideoPickCallback] is a callback function called when a |
|
/// video is picked. |
|
/// |
|
/// [mediaPickSettingSelector] allows customizing media pick settings. |
|
/// [cameraPickSettingSelector] allows customizing camera pick settings. |
|
/// |
|
/// Example of customizing media pick settings for the image button: |
|
/// ```dart |
|
/// mediaPickSettingSelector: (context) async { |
|
/// final mediaPickSetting = await showModalBottomSheet<MediaPickSetting>( |
|
/// showDragHandle: true, |
|
/// context: context, |
|
/// constraints: const BoxConstraints(maxWidth: 640), |
|
/// builder: (context) => const SelectImageSourceDialog(), |
|
/// ); |
|
/// if (mediaPickSetting == null) { |
|
/// return null; |
|
/// } |
|
/// return mediaPickSetting; |
|
/// } |
|
/// ``` |
|
/// |
|
/// [filePickImpl] is an implementation for picking files. |
|
/// [webImagePickImpl] is an implementation for picking web images. |
|
/// [webVideoPickImpl] is an implementation for picking web videos. |
|
/// |
|
/// [imageLinkRegExp] is a regular expression to identify image links. |
|
/// [videoLinkRegExp] is a regular expression to identify video links. |
|
/// |
|
/// The returned list contains embed button builders for the Quill toolbar. |
|
static List<EmbedButtonBuilder> buttons({ |
|
bool showImageButton = true, |
|
bool showVideoButton = true, |
|
bool showCameraButton = true, |
|
bool showFormulaButton = false, |
|
String? imageButtonTooltip, |
|
String? videoButtonTooltip, |
|
String? cameraButtonTooltip, |
|
String? formulaButtonTooltip, |
|
OnImagePickCallback? onImagePickCallback, |
|
OnVideoPickCallback? onVideoPickCallback, |
|
MediaPickSettingSelector? mediaPickSettingSelector, |
|
MediaPickSettingSelector? cameraPickSettingSelector, |
|
FilePickImpl? filePickImpl, |
|
WebImagePickImpl? webImagePickImpl, |
|
WebVideoPickImpl? webVideoPickImpl, |
|
RegExp? imageLinkRegExp, |
|
RegExp? videoLinkRegExp, |
|
}) => |
|
[ |
|
if (showImageButton) |
|
(controller, toolbarIconSize, iconTheme, dialogTheme) => ImageButton( |
|
icon: Icons.image, |
|
iconSize: toolbarIconSize, |
|
tooltip: imageButtonTooltip, |
|
controller: controller, |
|
onImagePickCallback: onImagePickCallback, |
|
filePickImpl: filePickImpl, |
|
webImagePickImpl: webImagePickImpl, |
|
mediaPickSettingSelector: mediaPickSettingSelector, |
|
iconTheme: iconTheme, |
|
dialogTheme: dialogTheme, |
|
linkRegExp: imageLinkRegExp, |
|
), |
|
if (showVideoButton) |
|
(controller, toolbarIconSize, iconTheme, dialogTheme) => VideoButton( |
|
icon: Icons.movie_creation, |
|
iconSize: toolbarIconSize, |
|
tooltip: videoButtonTooltip, |
|
controller: controller, |
|
onVideoPickCallback: onVideoPickCallback, |
|
filePickImpl: filePickImpl, |
|
webVideoPickImpl: webImagePickImpl, |
|
mediaPickSettingSelector: mediaPickSettingSelector, |
|
iconTheme: iconTheme, |
|
dialogTheme: dialogTheme, |
|
linkRegExp: videoLinkRegExp, |
|
), |
|
if ((onImagePickCallback != null || onVideoPickCallback != null) && |
|
showCameraButton) |
|
(controller, toolbarIconSize, iconTheme, dialogTheme) => CameraButton( |
|
icon: Icons.photo_camera, |
|
iconSize: toolbarIconSize, |
|
tooltip: cameraButtonTooltip, |
|
controller: controller, |
|
onImagePickCallback: onImagePickCallback, |
|
onVideoPickCallback: onVideoPickCallback, |
|
filePickImpl: filePickImpl, |
|
webImagePickImpl: webImagePickImpl, |
|
webVideoPickImpl: webVideoPickImpl, |
|
cameraPickSettingSelector: cameraPickSettingSelector, |
|
iconTheme: iconTheme, |
|
), |
|
if (showFormulaButton) |
|
(controller, toolbarIconSize, iconTheme, dialogTheme) => |
|
FormulaButton( |
|
icon: Icons.functions, |
|
iconSize: toolbarIconSize, |
|
tooltip: formulaButtonTooltip, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
dialogTheme: dialogTheme, |
|
) |
|
]; |
|
}
|
|
|