Rich text editor for Flutter
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

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,
)
];
}