|
|
|
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 '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/image_video_utils.dart';
|
|
|
|
import 'toolbar/indent_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 'toolbar/clear_format_button.dart';
|
|
|
|
export 'toolbar/color_button.dart';
|
|
|
|
export 'toolbar/history_button.dart';
|
|
|
|
export 'toolbar/image_button.dart';
|
|
|
|
export 'toolbar/image_video_utils.dart';
|
|
|
|
export 'toolbar/indent_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.toolbarIconAlignment = WrapAlignment.center,
|
|
|
|
this.toolbarSectionSpacing = 4,
|
|
|
|
this.multiRowsDisplay = true,
|
|
|
|
this.color,
|
|
|
|
this.filePickImpl,
|
|
|
|
this.locale,
|
|
|
|
Key? key,
|
|
|
|
}) : super(key: key);
|
|
|
|
|
|
|
|
factory QuillToolbar.basic({
|
|
|
|
required QuillController controller,
|
|
|
|
double toolbarIconSize = kDefaultIconSize,
|
|
|
|
double toolbarSectionSpacing = 4,
|
|
|
|
WrapAlignment toolbarIconAlignment = WrapAlignment.center,
|
|
|
|
bool showDividers = true,
|
|
|
|
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 showUndo = true,
|
|
|
|
bool showRedo = true,
|
|
|
|
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')
|
|
|
|
/// and more https://github.com/singerdmx/flutter-quill#translation-of-toolbar
|
|
|
|
Locale? locale,
|
|
|
|
Key? key,
|
|
|
|
}) {
|
|
|
|
final isButtonGroupShown = [
|
|
|
|
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
|
|
|
|
];
|
|
|
|
|
|
|
|
return QuillToolbar(
|
|
|
|
key: key,
|
|
|
|
toolbarHeight: toolbarIconSize * 2,
|
|
|
|
toolbarSectionSpacing: toolbarSectionSpacing,
|
|
|
|
toolbarIconAlignment: toolbarIconAlignment,
|
|
|
|
multiRowsDisplay: multiRowsDisplay,
|
|
|
|
locale: locale,
|
|
|
|
children: [
|
|
|
|
if (showUndo)
|
|
|
|
HistoryButton(
|
|
|
|
icon: Icons.undo_outlined,
|
|
|
|
iconSize: toolbarIconSize,
|
|
|
|
controller: controller,
|
|
|
|
undo: true,
|
|
|
|
iconTheme: iconTheme,
|
|
|
|
),
|
|
|
|
if (showRedo)
|
|
|
|
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 (showDividers &&
|
|
|
|
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 (showDividers &&
|
|
|
|
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 (showDividers &&
|
|
|
|
showHeaderStyle &&
|
|
|
|
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 (showDividers &&
|
|
|
|
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 (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5])
|
|
|
|
VerticalDivider(
|
|
|
|
indent: 12,
|
|
|
|
endIndent: 12,
|
|
|
|
color: Colors.grey.shade400,
|
|
|
|
),
|
|
|
|
if (showLink)
|
|
|
|
LinkStyleButton(
|
|
|
|
controller: controller,
|
|
|
|
iconSize: toolbarIconSize,
|
|
|
|
iconTheme: iconTheme,
|
|
|
|
dialogTheme: dialogTheme,
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
final List<Widget> children;
|
|
|
|
final double toolbarHeight;
|
|
|
|
final double toolbarSectionSpacing;
|
|
|
|
final WrapAlignment 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
|
|
|
|
/// and more https://github.com/singerdmx/flutter-quill#translation-of-toolbar
|
|
|
|
final Locale? locale;
|
|
|
|
|
|
|
|
@override
|
|
|
|
Size get preferredSize => Size.fromHeight(toolbarHeight);
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return I18n(
|
|
|
|
initialLocale: locale,
|
|
|
|
child: multiRowsDisplay
|
|
|
|
? Wrap(
|
|
|
|
alignment: toolbarIconAlignment,
|
|
|
|
runSpacing: 4,
|
|
|
|
spacing: toolbarSectionSpacing,
|
|
|
|
children: children,
|
|
|
|
)
|
|
|
|
: Container(
|
|
|
|
constraints:
|
|
|
|
BoxConstraints.tightFor(height: preferredSize.height),
|
|
|
|
color: color ?? Theme.of(context).canvasColor,
|
|
|
|
child: ArrowIndicatedButtonList(buttons: children),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|