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.
452 lines
14 KiB
452 lines
14 KiB
import 'dart:io'; |
|
|
|
import 'package:flutter/material.dart'; |
|
import 'package:i18n_extension/i18n_widget.dart'; |
|
|
|
import '../models/documents/attribute.dart'; |
|
import '../models/themes/quill_dialog_theme.dart'; |
|
import '../models/themes/quill_icon_theme.dart'; |
|
import '../utils/media_pick_setting.dart'; |
|
import 'controller.dart'; |
|
import 'toolbar/arrow_indicated_button_list.dart'; |
|
import 'toolbar/camera_button.dart'; |
|
import 'toolbar/clear_format_button.dart'; |
|
import 'toolbar/color_button.dart'; |
|
import 'toolbar/history_button.dart'; |
|
import 'toolbar/image_button.dart'; |
|
import 'toolbar/indent_button.dart'; |
|
import 'toolbar/insert_embed_button.dart'; |
|
import 'toolbar/link_style_button.dart'; |
|
import 'toolbar/select_alignment_button.dart'; |
|
import 'toolbar/select_header_style_button.dart'; |
|
import 'toolbar/toggle_check_list_button.dart'; |
|
import 'toolbar/toggle_style_button.dart'; |
|
import 'toolbar/video_button.dart'; |
|
|
|
export '../utils/media_pick_setting.dart'; |
|
export 'toolbar/clear_format_button.dart'; |
|
export 'toolbar/color_button.dart'; |
|
export 'toolbar/history_button.dart'; |
|
export 'toolbar/image_button.dart'; |
|
export 'toolbar/indent_button.dart'; |
|
export 'toolbar/insert_embed_button.dart'; |
|
export 'toolbar/link_style_button.dart'; |
|
export 'toolbar/quill_dropdown_button.dart'; |
|
export 'toolbar/quill_icon_button.dart'; |
|
export 'toolbar/select_alignment_button.dart'; |
|
export 'toolbar/select_header_style_button.dart'; |
|
export 'toolbar/toggle_check_list_button.dart'; |
|
export 'toolbar/toggle_style_button.dart'; |
|
export 'toolbar/video_button.dart'; |
|
|
|
typedef OnImagePickCallback = Future<String?> Function(File file); |
|
typedef OnVideoPickCallback = Future<String?> Function(File file); |
|
typedef FilePickImpl = Future<String?> Function(BuildContext context); |
|
typedef WebImagePickImpl = Future<String?> Function( |
|
OnImagePickCallback onImagePickCallback); |
|
typedef WebVideoPickImpl = Future<String?> Function( |
|
OnVideoPickCallback onImagePickCallback); |
|
typedef MediaPickSettingSelector = Future<MediaPickSetting?> Function( |
|
BuildContext context); |
|
|
|
// The default size of the icon of a button. |
|
const double kDefaultIconSize = 18; |
|
|
|
// The factor of how much larger the button is in relation to the icon. |
|
const double kIconButtonFactor = 1.77; |
|
|
|
class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { |
|
const QuillToolbar({ |
|
required this.children, |
|
this.toolBarHeight = 36, |
|
this.color, |
|
this.filePickImpl, |
|
this.multiRowsDisplay, |
|
this.locale, |
|
Key? key, |
|
}) : super(key: key); |
|
|
|
factory QuillToolbar.basic({ |
|
required QuillController controller, |
|
double toolbarIconSize = kDefaultIconSize, |
|
bool showBoldButton = true, |
|
bool showItalicButton = true, |
|
bool showSmallButton = false, |
|
bool showUnderLineButton = true, |
|
bool showStrikeThrough = true, |
|
bool showInlineCode = true, |
|
bool showColorButton = true, |
|
bool showBackgroundColorButton = true, |
|
bool showClearFormat = true, |
|
bool showAlignmentButtons = false, |
|
bool showLeftAlignment = true, |
|
bool showCenterAlignment = true, |
|
bool showRightAlignment = true, |
|
bool showJustifyAlignment = true, |
|
bool showHeaderStyle = true, |
|
bool showListNumbers = true, |
|
bool showListBullets = true, |
|
bool showListCheck = true, |
|
bool showCodeBlock = true, |
|
bool showQuote = true, |
|
bool showIndent = true, |
|
bool showLink = true, |
|
bool showHistory = true, |
|
bool showHorizontalRule = false, |
|
bool multiRowsDisplay = true, |
|
bool showImageButton = true, |
|
bool showVideoButton = true, |
|
bool showCameraButton = true, |
|
OnImagePickCallback? onImagePickCallback, |
|
OnVideoPickCallback? onVideoPickCallback, |
|
MediaPickSettingSelector? mediaPickSettingSelector, |
|
FilePickImpl? filePickImpl, |
|
WebImagePickImpl? webImagePickImpl, |
|
WebVideoPickImpl? webVideoPickImpl, |
|
|
|
///The theme to use for the icons in the toolbar, uses type [QuillIconTheme] |
|
QuillIconTheme? iconTheme, |
|
|
|
///The theme to use for the theming of the [LinkDialog()], |
|
///shown when embedding an image, for example |
|
QuillDialogTheme? dialogTheme, |
|
|
|
///The locale to use for the editor toolbar, defaults to system locale |
|
///Currently the supported locales are: |
|
/// * Locale('en') |
|
/// * Locale('de') |
|
/// * Locale('fr') |
|
/// * Locale('zh') |
|
Locale? locale, |
|
Key? key, |
|
}) { |
|
final isButtonGroupShown = [ |
|
showHistory || |
|
showBoldButton || |
|
showItalicButton || |
|
showSmallButton || |
|
showUnderLineButton || |
|
showStrikeThrough || |
|
showInlineCode || |
|
showColorButton || |
|
showBackgroundColorButton || |
|
showClearFormat || |
|
onImagePickCallback != null || |
|
onVideoPickCallback != null, |
|
showAlignmentButtons, |
|
showLeftAlignment, |
|
showCenterAlignment, |
|
showRightAlignment, |
|
showJustifyAlignment, |
|
showHeaderStyle, |
|
showListNumbers || showListBullets || showListCheck || showCodeBlock, |
|
showQuote || showIndent, |
|
showLink || showHorizontalRule |
|
]; |
|
|
|
return QuillToolbar( |
|
key: key, |
|
toolBarHeight: toolbarIconSize * 2, |
|
multiRowsDisplay: multiRowsDisplay, |
|
locale: locale, |
|
children: [ |
|
if (showHistory) |
|
HistoryButton( |
|
icon: Icons.undo_outlined, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
undo: true, |
|
iconTheme: iconTheme, |
|
), |
|
if (showHistory) |
|
HistoryButton( |
|
icon: Icons.redo_outlined, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
undo: false, |
|
iconTheme: iconTheme, |
|
), |
|
if (showBoldButton) |
|
ToggleStyleButton( |
|
attribute: Attribute.bold, |
|
icon: Icons.format_bold, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showItalicButton) |
|
ToggleStyleButton( |
|
attribute: Attribute.italic, |
|
icon: Icons.format_italic, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showSmallButton) |
|
ToggleStyleButton( |
|
attribute: Attribute.small, |
|
icon: Icons.format_size, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showUnderLineButton) |
|
ToggleStyleButton( |
|
attribute: Attribute.underline, |
|
icon: Icons.format_underline, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showStrikeThrough) |
|
ToggleStyleButton( |
|
attribute: Attribute.strikeThrough, |
|
icon: Icons.format_strikethrough, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showInlineCode) |
|
ToggleStyleButton( |
|
attribute: Attribute.inlineCode, |
|
icon: Icons.code, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showColorButton) |
|
ColorButton( |
|
icon: Icons.color_lens, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
background: false, |
|
iconTheme: iconTheme, |
|
), |
|
if (showBackgroundColorButton) |
|
ColorButton( |
|
icon: Icons.format_color_fill, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
background: true, |
|
iconTheme: iconTheme, |
|
), |
|
if (showClearFormat) |
|
ClearFormatButton( |
|
icon: Icons.format_clear, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
iconTheme: iconTheme, |
|
), |
|
if (showImageButton) |
|
ImageButton( |
|
icon: Icons.image, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
onImagePickCallback: onImagePickCallback, |
|
filePickImpl: filePickImpl, |
|
webImagePickImpl: webImagePickImpl, |
|
mediaPickSettingSelector: mediaPickSettingSelector, |
|
iconTheme: iconTheme, |
|
dialogTheme: dialogTheme, |
|
), |
|
if (showVideoButton) |
|
VideoButton( |
|
icon: Icons.movie_creation, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
onVideoPickCallback: onVideoPickCallback, |
|
filePickImpl: filePickImpl, |
|
webVideoPickImpl: webImagePickImpl, |
|
mediaPickSettingSelector: mediaPickSettingSelector, |
|
iconTheme: iconTheme, |
|
dialogTheme: dialogTheme, |
|
), |
|
if ((onImagePickCallback != null || onVideoPickCallback != null) && |
|
showCameraButton) |
|
CameraButton( |
|
icon: Icons.photo_camera, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
onImagePickCallback: onImagePickCallback, |
|
onVideoPickCallback: onVideoPickCallback, |
|
filePickImpl: filePickImpl, |
|
webImagePickImpl: webImagePickImpl, |
|
webVideoPickImpl: webVideoPickImpl, |
|
iconTheme: iconTheme, |
|
), |
|
if (isButtonGroupShown[0] && |
|
(isButtonGroupShown[1] || |
|
isButtonGroupShown[2] || |
|
isButtonGroupShown[3] || |
|
isButtonGroupShown[4] || |
|
isButtonGroupShown[5])) |
|
VerticalDivider( |
|
indent: 12, |
|
endIndent: 12, |
|
color: Colors.grey.shade400, |
|
), |
|
if (showAlignmentButtons) |
|
SelectAlignmentButton( |
|
controller: controller, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
showLeftAlignment: showLeftAlignment, |
|
showCenterAlignment: showCenterAlignment, |
|
showRightAlignment: showRightAlignment, |
|
showJustifyAlignment: showJustifyAlignment, |
|
), |
|
if (isButtonGroupShown[1] && |
|
(isButtonGroupShown[2] || |
|
isButtonGroupShown[3] || |
|
isButtonGroupShown[4] || |
|
isButtonGroupShown[5])) |
|
VerticalDivider( |
|
indent: 12, |
|
endIndent: 12, |
|
color: Colors.grey.shade400, |
|
), |
|
if (showHeaderStyle) |
|
SelectHeaderStyleButton( |
|
controller: controller, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
if (isButtonGroupShown[2] && |
|
(isButtonGroupShown[3] || |
|
isButtonGroupShown[4] || |
|
isButtonGroupShown[5])) |
|
VerticalDivider( |
|
indent: 12, |
|
endIndent: 12, |
|
color: Colors.grey.shade400, |
|
), |
|
if (showListNumbers) |
|
ToggleStyleButton( |
|
attribute: Attribute.ol, |
|
controller: controller, |
|
icon: Icons.format_list_numbered, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
if (showListBullets) |
|
ToggleStyleButton( |
|
attribute: Attribute.ul, |
|
controller: controller, |
|
icon: Icons.format_list_bulleted, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
if (showListCheck) |
|
ToggleCheckListButton( |
|
attribute: Attribute.unchecked, |
|
controller: controller, |
|
icon: Icons.check_box, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
if (showCodeBlock) |
|
ToggleStyleButton( |
|
attribute: Attribute.codeBlock, |
|
controller: controller, |
|
icon: Icons.code, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
if (isButtonGroupShown[3] && |
|
(isButtonGroupShown[4] || isButtonGroupShown[5])) |
|
VerticalDivider( |
|
indent: 12, |
|
endIndent: 12, |
|
color: Colors.grey.shade400, |
|
), |
|
if (showQuote) |
|
ToggleStyleButton( |
|
attribute: Attribute.blockQuote, |
|
controller: controller, |
|
icon: Icons.format_quote, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
if (showIndent) |
|
IndentButton( |
|
icon: Icons.format_indent_increase, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
isIncrease: true, |
|
iconTheme: iconTheme, |
|
), |
|
if (showIndent) |
|
IndentButton( |
|
icon: Icons.format_indent_decrease, |
|
iconSize: toolbarIconSize, |
|
controller: controller, |
|
isIncrease: false, |
|
iconTheme: iconTheme, |
|
), |
|
if (isButtonGroupShown[4] && isButtonGroupShown[5]) |
|
VerticalDivider( |
|
indent: 12, |
|
endIndent: 12, |
|
color: Colors.grey.shade400, |
|
), |
|
if (showLink) |
|
LinkStyleButton( |
|
controller: controller, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
dialogTheme: dialogTheme, |
|
), |
|
if (showHorizontalRule) |
|
InsertEmbedButton( |
|
controller: controller, |
|
icon: Icons.horizontal_rule, |
|
iconSize: toolbarIconSize, |
|
iconTheme: iconTheme, |
|
), |
|
], |
|
); |
|
} |
|
|
|
final List<Widget> children; |
|
final double toolBarHeight; |
|
final bool? multiRowsDisplay; |
|
|
|
/// The color of the toolbar. |
|
/// |
|
/// Defaults to [ThemeData.canvasColor] of the current [Theme] if no color |
|
/// is given. |
|
final Color? color; |
|
|
|
final FilePickImpl? filePickImpl; |
|
|
|
///The locale to use for the editor toolbar, defaults to system locale |
|
///Currently the supported locales are: |
|
/// * Locale('en') |
|
/// * Locale('de') |
|
/// * Locale('fr') |
|
/// * Locale('zh', 'CN') |
|
final Locale? locale; |
|
|
|
@override |
|
Size get preferredSize => Size.fromHeight(toolBarHeight); |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
return I18n( |
|
initialLocale: locale, |
|
child: multiRowsDisplay ?? true |
|
? Wrap( |
|
alignment: WrapAlignment.center, |
|
runSpacing: 4, |
|
spacing: 4, |
|
children: children, |
|
) |
|
: Container( |
|
constraints: |
|
BoxConstraints.tightFor(height: preferredSize.height), |
|
color: color ?? Theme.of(context).canvasColor, |
|
child: ArrowIndicatedButtonList(buttons: children), |
|
), |
|
); |
|
} |
|
}
|
|
|