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 Function(File file); typedef OnVideoPickCallback = Future Function(File file); typedef FilePickImpl = Future Function(BuildContext context); typedef WebImagePickImpl = Future Function( OnImagePickCallback onImagePickCallback); typedef WebVideoPickImpl = Future Function( OnVideoPickCallback onImagePickCallback); typedef MediaPickSettingSelector = Future Function( BuildContext context); enum ToolbarAlignment { start, center, end } // 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.toolBarSectionSpacing, this.toolBarIconAlignment, this.color, this.filePickImpl, this.multiRowsDisplay, this.locale, Key? key, }) : super(key: key); factory QuillToolbar.basic({ required QuillController controller, double toolbarIconSize = kDefaultIconSize, double toolBarSectionSpacing = 4, ToolbarAlignment toolBarIconAlignment = ToolbarAlignment.center, 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, toolBarSectionSpacing: toolBarSectionSpacing, toolBarIconAlignment: toolBarIconAlignment, 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 children; final double toolBarHeight; final double? toolBarSectionSpacing; final ToolbarAlignment? toolBarIconAlignment; 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: (toolBarIconAlignment == ToolbarAlignment.start) ? WrapAlignment.start : (toolBarIconAlignment == ToolbarAlignment.center) ? WrapAlignment.center : (toolBarIconAlignment == ToolbarAlignment.end) ? WrapAlignment.end : WrapAlignment.center, runSpacing: 4, spacing: toolBarSectionSpacing ?? 4, children: children, ) : Container( constraints: BoxConstraints.tightFor(height: preferredSize.height), color: color ?? Theme.of(context).canvasColor, child: ArrowIndicatedButtonList(buttons: children), ), ); } }