diff --git a/flutter_quill_extensions/lib/embeds/toolbar/camera_button.dart b/flutter_quill_extensions/lib/embeds/toolbar/camera_button.dart index bb906f30..202d97b1 100644 --- a/flutter_quill_extensions/lib/embeds/toolbar/camera_button.dart +++ b/flutter_quill_extensions/lib/embeds/toolbar/camera_button.dart @@ -19,6 +19,7 @@ class CameraButton extends StatelessWidget { this.webVideoPickImpl, this.cameraPickSettingSelector, this.iconTheme, + this.tooltip, Key? key, }) : super(key: key); @@ -42,6 +43,7 @@ class CameraButton extends StatelessWidget { final MediaPickSettingSelector? cameraPickSettingSelector; final QuillIconTheme? iconTheme; + final String? tooltip; @override Widget build(BuildContext context) { diff --git a/flutter_quill_extensions/lib/embeds/toolbar/formula_button.dart b/flutter_quill_extensions/lib/embeds/toolbar/formula_button.dart index fb0ab679..70c4987f 100644 --- a/flutter_quill_extensions/lib/embeds/toolbar/formula_button.dart +++ b/flutter_quill_extensions/lib/embeds/toolbar/formula_button.dart @@ -9,6 +9,7 @@ class FormulaButton extends StatelessWidget { this.fillColor, this.iconTheme, this.dialogTheme, + this.tooltip, Key? key, }) : super(key: key); @@ -23,6 +24,7 @@ class FormulaButton extends StatelessWidget { final QuillIconTheme? iconTheme; final QuillDialogTheme? dialogTheme; + final String? tooltip; @override Widget build(BuildContext context) { diff --git a/flutter_quill_extensions/lib/embeds/toolbar/image_button.dart b/flutter_quill_extensions/lib/embeds/toolbar/image_button.dart index 5cc51aff..8cad519c 100644 --- a/flutter_quill_extensions/lib/embeds/toolbar/image_button.dart +++ b/flutter_quill_extensions/lib/embeds/toolbar/image_button.dart @@ -17,6 +17,7 @@ class ImageButton extends StatelessWidget { this.mediaPickSettingSelector, this.iconTheme, this.dialogTheme, + this.tooltip, Key? key, }) : super(key: key); @@ -38,6 +39,7 @@ class ImageButton extends StatelessWidget { final QuillIconTheme? iconTheme; final QuillDialogTheme? dialogTheme; + final String? tooltip; @override Widget build(BuildContext context) { diff --git a/flutter_quill_extensions/lib/embeds/toolbar/video_button.dart b/flutter_quill_extensions/lib/embeds/toolbar/video_button.dart index e6193622..30e0dbf7 100644 --- a/flutter_quill_extensions/lib/embeds/toolbar/video_button.dart +++ b/flutter_quill_extensions/lib/embeds/toolbar/video_button.dart @@ -17,6 +17,7 @@ class VideoButton extends StatelessWidget { this.mediaPickSettingSelector, this.iconTheme, this.dialogTheme, + this.tooltip, Key? key, }) : super(key: key); @@ -38,6 +39,7 @@ class VideoButton extends StatelessWidget { final QuillIconTheme? iconTheme; final QuillDialogTheme? dialogTheme; + final String? tooltip; @override Widget build(BuildContext context) { diff --git a/flutter_quill_extensions/pubspec.yaml b/flutter_quill_extensions/pubspec.yaml index 5ca94b5c..e0e1269d 100644 --- a/flutter_quill_extensions/pubspec.yaml +++ b/flutter_quill_extensions/pubspec.yaml @@ -12,7 +12,7 @@ dependencies: flutter: sdk: flutter - flutter_quill: ^7.0.2 + flutter_quill: ^7.1.4 image_picker: ^0.8.5+3 photo_view: ^0.14.0 @@ -23,10 +23,6 @@ dependencies: string_validator: ^1.0.0 url_launcher: ^6.1.9 -# dependency_overrides: -# flutter_quill: -# path: ../ - dev_dependencies: flutter_test: sdk: flutter diff --git a/lib/src/models/themes/quill_custom_button.dart b/lib/src/models/themes/quill_custom_button.dart index 0dbac618..4ea4e4f5 100644 --- a/lib/src/models/themes/quill_custom_button.dart +++ b/lib/src/models/themes/quill_custom_button.dart @@ -1,11 +1,18 @@ import 'package:flutter/material.dart'; class QuillCustomButton { - const QuillCustomButton({this.icon, this.onTap}); + const QuillCustomButton({ + this.icon, + this.onTap, + this.tooltip, + }); ///The icon widget final IconData? icon; ///The function when the icon is tapped final VoidCallback? onTap; + + /// The button tooltip. + final String? tooltip; } diff --git a/lib/src/translations/toolbar.i18n.dart b/lib/src/translations/toolbar.i18n.dart index 2abcfb21..cb6c7853 100644 --- a/lib/src/translations/toolbar.i18n.dart +++ b/lib/src/translations/toolbar.i18n.dart @@ -35,6 +35,32 @@ extension Localization on String { 'Next': 'Next', 'Camera': 'Camera', 'Video': 'Video', + 'Undo': 'Undo', + 'Redo': 'Redo', + 'Font family': 'Font family', + 'Font size': 'Font size', + 'Bold': 'Bold', + 'Italic': 'Italic', + 'Underline': 'Underline', + 'Strike through': 'Strike through', + 'Inline code': 'Inline code', + 'Font color': 'Font color', + 'Background color': 'Background color', + 'Clear format': 'Clear format', + 'Align left': 'Align left', + 'Align center': 'Align center', + 'Align right': 'Align right', + 'Justify win width': 'Justify win width', + 'Text direction': 'Text direction', + 'Header style': 'Header style', + 'Numbered list': 'Numbered list', + 'Bullet list': 'Bullet list', + 'Checked list': 'Checked list', + 'Code block': 'Code block', + 'Quote': 'Quote', + 'Increase indent': 'Increase indent', + 'Decrease indent': 'Decrease indent', + 'Insert URL': 'Insert URL', }, 'en_us': { 'Paste a link': 'Paste a link', @@ -68,6 +94,32 @@ extension Localization on String { 'Next': 'Next', 'Camera': 'Camera', 'Video': 'Video', + 'Undo': 'Undo', + 'Redo': 'Redo', + 'Font family': 'Font family', + 'Font size': 'Font size', + 'Bold': 'Bold', + 'Italic': 'Italic', + 'Underline': 'Underline', + 'Strike through': 'Strike through', + 'Inline code': 'Inline code', + 'Font color': 'Font color', + 'Background color': 'Background color', + 'Clear format': 'Clear format', + 'Align left': 'Align left', + 'Align center': 'Align center', + 'Align right': 'Align right', + 'Justify win width': 'Justify win width', + 'Text direction': 'Text direction', + 'Header style': 'Header style', + 'Numbered list': 'Numbered list', + 'Bullet list': 'Bullet list', + 'Checked list': 'Checked list', + 'Code block': 'Code block', + 'Quote': 'Quote', + 'Increase indent': 'Increase indent', + 'Decrease indent': 'Decrease indent', + 'Insert URL': 'Insert URL', }, 'ar': { 'Paste a link': 'نسخ الرابط', diff --git a/lib/src/utils/widgets.dart b/lib/src/utils/widgets.dart new file mode 100644 index 00000000..1b560e84 --- /dev/null +++ b/lib/src/utils/widgets.dart @@ -0,0 +1,11 @@ +import 'package:flutter/material.dart'; + +/// Provides utiulity widgets. +abstract class UtilityWidgets { + /// Conditionally wraps the [child] with [Tooltip] widget if [message] + /// is not null and not empty. + static Widget maybeTooltip({required Widget child, String? message}) => + (message ?? '').isNotEmpty + ? Tooltip(message: message!, child: child) + : child; +} diff --git a/lib/src/widgets/toolbar.dart b/lib/src/widgets/toolbar.dart index 58171ad1..08c7c6fe 100644 --- a/lib/src/widgets/toolbar.dart +++ b/lib/src/widgets/toolbar.dart @@ -12,6 +12,7 @@ import 'embeds.dart'; import 'toolbar/arrow_indicated_button_list.dart'; import 'toolbar/clear_format_button.dart'; import 'toolbar/color_button.dart'; +import 'toolbar/enum.dart'; import 'toolbar/history_button.dart'; import 'toolbar/indent_button.dart'; import 'toolbar/link_style_button.dart'; @@ -117,6 +118,20 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { /// Is called after whatever logic the button performs has run. VoidCallback? afterButtonPressed, + ///Map of tooltips for toolbar buttons + /// + ///The example is: + ///```dart + /// tooltips = { + /// ToolbarButtons.undo: 'Undo', + /// ToolbarButtons.redo: 'Redo', + /// } + /// + ///``` + /// + /// To disable tooltips just pass empty map as well. + Map? tooltips, + /// The locale to use for the editor toolbar, defaults to system locale /// More at https://github.com/singerdmx/flutter-quill#translation Locale? locale, @@ -172,6 +187,39 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { 'Clear'.i18n: 'Clear' }; + //default button tooltips + final buttonTooltips = tooltips ?? + { + ToolbarButtons.undo: 'Undo'.i18n, + ToolbarButtons.redo: 'Redo'.i18n, + ToolbarButtons.fontFamily: 'Font family'.i18n, + ToolbarButtons.fontSize: 'Font size'.i18n, + ToolbarButtons.bold: 'Bold'.i18n, + ToolbarButtons.italic: 'Italic'.i18n, + ToolbarButtons.small: 'Small'.i18n, + ToolbarButtons.underline: 'Underline'.i18n, + ToolbarButtons.strikeThrough: 'Strike through'.i18n, + ToolbarButtons.inlineCode: 'Inline code'.i18n, + ToolbarButtons.color: 'Font color'.i18n, + ToolbarButtons.backgroundColor: 'Background color'.i18n, + ToolbarButtons.clearFormat: 'Clear format'.i18n, + ToolbarButtons.leftAlignment: 'Align left'.i18n, + ToolbarButtons.centerAlignment: 'Align center'.i18n, + ToolbarButtons.rightAlignment: 'Align right'.i18n, + ToolbarButtons.justifyAlignment: 'Justify win width'.i18n, + ToolbarButtons.direction: 'Text direction'.i18n, + ToolbarButtons.headerStyle: 'Header style'.i18n, + ToolbarButtons.listNumbers: 'Numbered list'.i18n, + ToolbarButtons.listBullets: 'Bullet list'.i18n, + ToolbarButtons.listChecks: 'Checked list'.i18n, + ToolbarButtons.codeBlock: 'Code block'.i18n, + ToolbarButtons.quote: 'Quote'.i18n, + ToolbarButtons.indentIncrease: 'Increase indent'.i18n, + ToolbarButtons.indentDecrease: 'Decrease indent'.i18n, + ToolbarButtons.link: 'Insert URL'.i18n, + ToolbarButtons.search: 'Search'.i18n, + }; + return QuillToolbar( key: key, axis: axis, @@ -189,6 +237,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { HistoryButton( icon: Icons.undo_outlined, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.undo], controller: controller, undo: true, iconTheme: iconTheme, @@ -198,6 +247,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { HistoryButton( icon: Icons.redo_outlined, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.redo], controller: controller, undo: false, iconTheme: iconTheme, @@ -207,6 +257,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { QuillFontFamilyButton( iconTheme: iconTheme, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.fontFamily], attribute: Attribute.font, controller: controller, items: [ @@ -231,6 +282,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { QuillFontSizeButton( iconTheme: iconTheme, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.fontSize], attribute: Attribute.size, controller: controller, items: [ @@ -255,6 +307,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { attribute: Attribute.bold, icon: Icons.format_bold, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.bold], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -264,6 +317,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { attribute: Attribute.italic, icon: Icons.format_italic, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.italic], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -273,6 +327,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { attribute: Attribute.small, icon: Icons.format_size, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.small], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -282,6 +337,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { attribute: Attribute.underline, icon: Icons.format_underline, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.underline], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -291,6 +347,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { attribute: Attribute.strikeThrough, icon: Icons.format_strikethrough, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.strikeThrough], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -300,6 +357,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { attribute: Attribute.inlineCode, icon: Icons.code, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.inlineCode], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -308,6 +366,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { ColorButton( icon: Icons.color_lens, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.color], controller: controller, background: false, iconTheme: iconTheme, @@ -317,6 +376,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { ColorButton( icon: Icons.format_color_fill, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.backgroundColor], controller: controller, background: true, iconTheme: iconTheme, @@ -326,6 +386,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { ClearFormatButton( icon: Icons.format_clear, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.clearFormat], controller: controller, iconTheme: iconTheme, afterButtonPressed: afterButtonPressed, @@ -344,6 +405,13 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showAlignmentButtons) SelectAlignmentButton( controller: controller, + tooltips: Map.of(buttonTooltips) + ..removeWhere((key, value) => ![ + ToolbarButtons.leftAlignment, + ToolbarButtons.centerAlignment, + ToolbarButtons.rightAlignment, + ToolbarButtons.justifyAlignment, + ].contains(key)), iconSize: toolbarIconSize, iconTheme: iconTheme, showLeftAlignment: showLeftAlignment, @@ -355,6 +423,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showDirection) ToggleStyleButton( attribute: Attribute.rtl, + tooltip: buttonTooltips[ToolbarButtons.direction], controller: controller, icon: Icons.format_textdirection_r_to_l, iconSize: toolbarIconSize, @@ -370,6 +439,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { _dividerOnAxis(axis), if (showHeaderStyle) SelectHeaderStyleButton( + tooltip: buttonTooltips[ToolbarButtons.headerStyle], controller: controller, axis: axis, iconSize: toolbarIconSize, @@ -386,6 +456,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showListNumbers) ToggleStyleButton( attribute: Attribute.ol, + tooltip: buttonTooltips[ToolbarButtons.listNumbers], controller: controller, icon: Icons.format_list_numbered, iconSize: toolbarIconSize, @@ -395,6 +466,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showListBullets) ToggleStyleButton( attribute: Attribute.ul, + tooltip: buttonTooltips[ToolbarButtons.listBullets], controller: controller, icon: Icons.format_list_bulleted, iconSize: toolbarIconSize, @@ -404,6 +476,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showListCheck) ToggleCheckListButton( attribute: Attribute.unchecked, + tooltip: buttonTooltips[ToolbarButtons.listChecks], controller: controller, icon: Icons.check_box, iconSize: toolbarIconSize, @@ -413,6 +486,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showCodeBlock) ToggleStyleButton( attribute: Attribute.codeBlock, + tooltip: buttonTooltips[ToolbarButtons.codeBlock], controller: controller, icon: Icons.code, iconSize: toolbarIconSize, @@ -426,6 +500,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { if (showQuote) ToggleStyleButton( attribute: Attribute.blockQuote, + tooltip: buttonTooltips[ToolbarButtons.quote], controller: controller, icon: Icons.format_quote, iconSize: toolbarIconSize, @@ -436,6 +511,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { IndentButton( icon: Icons.format_indent_increase, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.indentIncrease], controller: controller, isIncrease: true, iconTheme: iconTheme, @@ -445,6 +521,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { IndentButton( icon: Icons.format_indent_decrease, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.indentDecrease], controller: controller, isIncrease: false, iconTheme: iconTheme, @@ -454,6 +531,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { _dividerOnAxis(axis), if (showLink) LinkStyleButton( + tooltip: buttonTooltips[ToolbarButtons.link], controller: controller, iconSize: toolbarIconSize, iconTheme: iconTheme, @@ -464,6 +542,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { SearchButton( icon: Icons.search, iconSize: toolbarIconSize, + tooltip: buttonTooltips[ToolbarButtons.search], controller: controller, iconTheme: iconTheme, dialogTheme: dialogTheme, @@ -477,6 +556,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { hoverElevation: 0, size: toolbarIconSize * kIconButtonFactor, icon: Icon(customButton.icon, size: toolbarIconSize), + tooltip: customButton.tooltip, borderRadius: iconTheme?.borderRadius ?? 2, onPressed: customButton.onTap, afterPressed: afterButtonPressed, diff --git a/lib/src/widgets/toolbar/clear_format_button.dart b/lib/src/widgets/toolbar/clear_format_button.dart index f601bd28..14610232 100644 --- a/lib/src/widgets/toolbar/clear_format_button.dart +++ b/lib/src/widgets/toolbar/clear_format_button.dart @@ -12,6 +12,7 @@ class ClearFormatButton extends StatefulWidget { this.iconSize = kDefaultIconSize, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -22,6 +23,7 @@ class ClearFormatButton extends StatefulWidget { final QuillIconTheme? iconTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _ClearFormatButtonState createState() => _ClearFormatButtonState(); @@ -36,6 +38,7 @@ class _ClearFormatButtonState extends State { final fillColor = widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor; return QuillIconButton( + tooltip: widget.tooltip, highlightElevation: 0, hoverElevation: 0, size: widget.iconSize * kIconButtonFactor, diff --git a/lib/src/widgets/toolbar/color_button.dart b/lib/src/widgets/toolbar/color_button.dart index 087ae94f..60f0a591 100644 --- a/lib/src/widgets/toolbar/color_button.dart +++ b/lib/src/widgets/toolbar/color_button.dart @@ -21,6 +21,7 @@ class ColorButton extends StatefulWidget { this.iconSize = kDefaultIconSize, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -30,6 +31,7 @@ class ColorButton extends StatefulWidget { final QuillController controller; final QuillIconTheme? iconTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _ColorButtonState createState() => _ColorButtonState(); @@ -119,6 +121,7 @@ class _ColorButtonState extends State { : (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor); return QuillIconButton( + tooltip: widget.tooltip, highlightElevation: 0, hoverElevation: 0, size: widget.iconSize * kIconButtonFactor, diff --git a/lib/src/widgets/toolbar/enum.dart b/lib/src/widgets/toolbar/enum.dart new file mode 100644 index 00000000..197bea56 --- /dev/null +++ b/lib/src/widgets/toolbar/enum.dart @@ -0,0 +1,30 @@ +enum ToolbarButtons { + undo, + redo, + fontFamily, + fontSize, + bold, + italic, + small, + underline, + strikeThrough, + inlineCode, + color, + backgroundColor, + clearFormat, + centerAlignment, + leftAlignment, + rightAlignment, + justifyAlignment, + direction, + headerStyle, + listNumbers, + listBullets, + listChecks, + codeBlock, + quote, + indentIncrease, + indentDecrease, + link, + search, +} diff --git a/lib/src/widgets/toolbar/history_button.dart b/lib/src/widgets/toolbar/history_button.dart index a3abc7f2..6d3c29ad 100644 --- a/lib/src/widgets/toolbar/history_button.dart +++ b/lib/src/widgets/toolbar/history_button.dart @@ -12,6 +12,7 @@ class HistoryButton extends StatefulWidget { this.iconSize = kDefaultIconSize, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -21,6 +22,7 @@ class HistoryButton extends StatefulWidget { final QuillController controller; final QuillIconTheme? iconTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _HistoryButtonState createState() => _HistoryButtonState(); @@ -41,6 +43,7 @@ class _HistoryButtonState extends State { _setIconColor(); }); return QuillIconButton( + tooltip: widget.tooltip, highlightElevation: 0, hoverElevation: 0, size: widget.iconSize * 1.77, diff --git a/lib/src/widgets/toolbar/indent_button.dart b/lib/src/widgets/toolbar/indent_button.dart index 129ef8b1..1ce83e99 100644 --- a/lib/src/widgets/toolbar/indent_button.dart +++ b/lib/src/widgets/toolbar/indent_button.dart @@ -12,6 +12,7 @@ class IndentButton extends StatefulWidget { this.iconSize = kDefaultIconSize, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -22,6 +23,7 @@ class IndentButton extends StatefulWidget { final VoidCallback? afterButtonPressed; final QuillIconTheme? iconTheme; + final String? tooltip; @override _IndentButtonState createState() => _IndentButtonState(); @@ -37,6 +39,7 @@ class _IndentButtonState extends State { final iconFillColor = widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor; return QuillIconButton( + tooltip: widget.tooltip, highlightElevation: 0, hoverElevation: 0, size: widget.iconSize * 1.77, diff --git a/lib/src/widgets/toolbar/link_style_button.dart b/lib/src/widgets/toolbar/link_style_button.dart index f48a15e4..a0865941 100644 --- a/lib/src/widgets/toolbar/link_style_button.dart +++ b/lib/src/widgets/toolbar/link_style_button.dart @@ -17,6 +17,7 @@ class LinkStyleButton extends StatefulWidget { this.iconTheme, this.dialogTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -26,6 +27,7 @@ class LinkStyleButton extends StatefulWidget { final QuillIconTheme? iconTheme; final QuillDialogTheme? dialogTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _LinkStyleButtonState createState() => _LinkStyleButtonState(); @@ -63,6 +65,7 @@ class _LinkStyleButtonState extends State { final isToggled = _getLinkAttributeValue() != null; final pressedHandler = () => _openLinkDialog(context); return QuillIconButton( + tooltip: widget.tooltip, highlightElevation: 0, hoverElevation: 0, size: widget.iconSize * kIconButtonFactor, diff --git a/lib/src/widgets/toolbar/quill_font_family_button.dart b/lib/src/widgets/toolbar/quill_font_family_button.dart index 88b3dda4..bdddc832 100644 --- a/lib/src/widgets/toolbar/quill_font_family_button.dart +++ b/lib/src/widgets/toolbar/quill_font_family_button.dart @@ -4,6 +4,7 @@ import '../../models/documents/attribute.dart'; import '../../models/documents/style.dart'; import '../../models/themes/quill_icon_theme.dart'; import '../../translations/toolbar.i18n.dart'; +import '../../utils/widgets.dart'; import '../controller.dart'; class QuillFontFamilyButton extends StatefulWidget { @@ -19,6 +20,7 @@ class QuillFontFamilyButton extends StatefulWidget { this.highlightElevation = 1, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -33,6 +35,7 @@ class QuillFontFamilyButton extends StatefulWidget { final Attribute attribute; final QuillController controller; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _QuillFontFamilyButtonState createState() => _QuillFontFamilyButtonState(); @@ -88,20 +91,23 @@ class _QuillFontFamilyButtonState extends State { Widget build(BuildContext context) { return ConstrainedBox( constraints: BoxConstraints.tightFor(height: widget.iconSize * 1.81), - child: RawMaterialButton( - visualDensity: VisualDensity.compact, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2)), - fillColor: widget.fillColor, - elevation: 0, - hoverElevation: widget.hoverElevation, - highlightElevation: widget.hoverElevation, - onPressed: () { - _showMenu(); - widget.afterButtonPressed?.call(); - }, - child: _buildContent(context), + child: UtilityWidgets.maybeTooltip( + message: widget.tooltip, + child: RawMaterialButton( + visualDensity: VisualDensity.compact, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2)), + fillColor: widget.fillColor, + elevation: 0, + hoverElevation: widget.hoverElevation, + highlightElevation: widget.hoverElevation, + onPressed: () { + _showMenu(); + widget.afterButtonPressed?.call(); + }, + child: _buildContent(context), + ), ), ); } diff --git a/lib/src/widgets/toolbar/quill_font_size_button.dart b/lib/src/widgets/toolbar/quill_font_size_button.dart index da6fa187..f82175c2 100644 --- a/lib/src/widgets/toolbar/quill_font_size_button.dart +++ b/lib/src/widgets/toolbar/quill_font_size_button.dart @@ -5,6 +5,7 @@ import '../../models/documents/style.dart'; import '../../models/themes/quill_icon_theme.dart'; import '../../translations/toolbar.i18n.dart'; import '../../utils/font.dart'; +import '../../utils/widgets.dart'; import '../controller.dart'; class QuillFontSizeButton extends StatefulWidget { @@ -20,6 +21,7 @@ class QuillFontSizeButton extends StatefulWidget { this.highlightElevation = 1, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -34,6 +36,7 @@ class QuillFontSizeButton extends StatefulWidget { final Attribute attribute; final QuillController controller; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _QuillFontSizeButtonState createState() => _QuillFontSizeButtonState(); @@ -89,20 +92,23 @@ class _QuillFontSizeButtonState extends State { Widget build(BuildContext context) { return ConstrainedBox( constraints: BoxConstraints.tightFor(height: widget.iconSize * 1.81), - child: RawMaterialButton( - visualDensity: VisualDensity.compact, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2)), - fillColor: widget.fillColor, - elevation: 0, - hoverElevation: widget.hoverElevation, - highlightElevation: widget.hoverElevation, - onPressed: () { - _showMenu(); - widget.afterButtonPressed?.call(); - }, - child: _buildContent(context), + child: UtilityWidgets.maybeTooltip( + message: widget.tooltip, + child: RawMaterialButton( + visualDensity: VisualDensity.compact, + shape: RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2)), + fillColor: widget.fillColor, + elevation: 0, + hoverElevation: widget.hoverElevation, + highlightElevation: widget.hoverElevation, + onPressed: () { + _showMenu(); + widget.afterButtonPressed?.call(); + }, + child: _buildContent(context), + ), ), ); } diff --git a/lib/src/widgets/toolbar/quill_icon_button.dart b/lib/src/widgets/toolbar/quill_icon_button.dart index 7714187c..86c5b30b 100644 --- a/lib/src/widgets/toolbar/quill_icon_button.dart +++ b/lib/src/widgets/toolbar/quill_icon_button.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import '../../utils/widgets.dart'; + class QuillIconButton extends StatelessWidget { const QuillIconButton({ required this.onPressed, @@ -10,6 +12,7 @@ class QuillIconButton extends StatelessWidget { this.hoverElevation = 1, this.highlightElevation = 1, this.borderRadius = 2, + this.tooltip, Key? key, }) : super(key: key); @@ -21,24 +24,28 @@ class QuillIconButton extends StatelessWidget { final double hoverElevation; final double highlightElevation; final double borderRadius; + final String? tooltip; @override Widget build(BuildContext context) { return ConstrainedBox( constraints: BoxConstraints.tightFor(width: size, height: size), - child: RawMaterialButton( - visualDensity: VisualDensity.compact, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(borderRadius)), - fillColor: fillColor, - elevation: 0, - hoverElevation: hoverElevation, - highlightElevation: hoverElevation, - onPressed: () { - onPressed?.call(); - afterPressed?.call(); - }, - child: icon, + child: UtilityWidgets.maybeTooltip( + message: tooltip, + child: RawMaterialButton( + visualDensity: VisualDensity.compact, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(borderRadius)), + fillColor: fillColor, + elevation: 0, + hoverElevation: hoverElevation, + highlightElevation: hoverElevation, + onPressed: () { + onPressed?.call(); + afterPressed?.call(); + }, + child: icon, + ), ), ); } diff --git a/lib/src/widgets/toolbar/search_button.dart b/lib/src/widgets/toolbar/search_button.dart index b9436bf1..9233cf45 100644 --- a/lib/src/widgets/toolbar/search_button.dart +++ b/lib/src/widgets/toolbar/search_button.dart @@ -15,6 +15,7 @@ class SearchButton extends StatelessWidget { this.iconTheme, this.dialogTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -27,6 +28,7 @@ class SearchButton extends StatelessWidget { final QuillDialogTheme? dialogTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override Widget build(BuildContext context) { @@ -37,6 +39,7 @@ class SearchButton extends StatelessWidget { iconTheme?.iconUnselectedFillColor ?? (fillColor ?? theme.canvasColor); return QuillIconButton( + tooltip: tooltip, icon: Icon(icon, size: iconSize, color: iconColor), highlightElevation: 0, hoverElevation: 0, diff --git a/lib/src/widgets/toolbar/select_alignment_button.dart b/lib/src/widgets/toolbar/select_alignment_button.dart index 596b095d..4d22b2cf 100644 --- a/lib/src/widgets/toolbar/select_alignment_button.dart +++ b/lib/src/widgets/toolbar/select_alignment_button.dart @@ -4,8 +4,10 @@ import 'package:flutter/material.dart'; import '../../models/documents/attribute.dart'; import '../../models/documents/style.dart'; import '../../models/themes/quill_icon_theme.dart'; +import '../../utils/widgets.dart'; import '../controller.dart'; import '../toolbar.dart'; +import 'enum.dart'; class SelectAlignmentButton extends StatefulWidget { const SelectAlignmentButton({ @@ -17,6 +19,7 @@ class SelectAlignmentButton extends StatefulWidget { this.showRightAlignment, this.showJustifyAlignment, this.afterButtonPressed, + this.tooltips = const {}, Key? key, }) : super(key: key); @@ -29,6 +32,7 @@ class SelectAlignmentButton extends StatefulWidget { final bool? showRightAlignment; final bool? showJustifyAlignment; final VoidCallback? afterButtonPressed; + final Map tooltips; @override _SelectAlignmentButtonState createState() => _SelectAlignmentButtonState(); @@ -74,6 +78,16 @@ class _SelectAlignmentButtonState extends State { if (widget.showRightAlignment!) Attribute.rightAlignment.value!, if (widget.showJustifyAlignment!) Attribute.justifyAlignment.value!, ]; + final _valueToButtons = { + if (widget.showLeftAlignment!) + Attribute.leftAlignment: ToolbarButtons.leftAlignment, + if (widget.showCenterAlignment!) + Attribute.centerAlignment: ToolbarButtons.centerAlignment, + if (widget.showRightAlignment!) + Attribute.rightAlignment: ToolbarButtons.rightAlignment, + if (widget.showJustifyAlignment!) + Attribute.justifyAlignment: ToolbarButtons.justifyAlignment, + }; final theme = Theme.of(context); @@ -93,40 +107,45 @@ class _SelectAlignmentButtonState extends State { width: widget.iconSize * kIconButtonFactor, height: widget.iconSize * kIconButtonFactor, ), - child: RawMaterialButton( - hoverElevation: 0, - highlightElevation: 0, - elevation: 0, - visualDensity: VisualDensity.compact, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular( - widget.iconTheme?.borderRadius ?? 2)), - fillColor: _valueToText[_value] == _valueString[index] - ? (widget.iconTheme?.iconSelectedFillColor ?? - Theme.of(context).primaryColor) - : (widget.iconTheme?.iconUnselectedFillColor ?? - theme.canvasColor), - onPressed: () { - _valueAttribute[index] == Attribute.leftAlignment - ? widget.controller - .formatSelection(Attribute.clone(Attribute.align, null)) - : widget.controller.formatSelection(_valueAttribute[index]); - widget.afterButtonPressed?.call(); - }, - child: Icon( - _valueString[index] == Attribute.leftAlignment.value - ? Icons.format_align_left - : _valueString[index] == Attribute.centerAlignment.value - ? Icons.format_align_center - : _valueString[index] == Attribute.rightAlignment.value - ? Icons.format_align_right - : Icons.format_align_justify, - size: widget.iconSize, - color: _valueToText[_value] == _valueString[index] - ? (widget.iconTheme?.iconSelectedColor ?? - theme.primaryIconTheme.color) - : (widget.iconTheme?.iconUnselectedColor ?? - theme.iconTheme.color), + child: UtilityWidgets.maybeTooltip( + message: widget.tooltips[_valueToButtons[_valueAttribute[index]]], + child: RawMaterialButton( + hoverElevation: 0, + highlightElevation: 0, + elevation: 0, + visualDensity: VisualDensity.compact, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + widget.iconTheme?.borderRadius ?? 2)), + fillColor: _valueToText[_value] == _valueString[index] + ? (widget.iconTheme?.iconSelectedFillColor ?? + Theme.of(context).primaryColor) + : (widget.iconTheme?.iconUnselectedFillColor ?? + theme.canvasColor), + onPressed: () { + _valueAttribute[index] == Attribute.leftAlignment + ? widget.controller.formatSelection( + Attribute.clone(Attribute.align, null)) + : widget.controller + .formatSelection(_valueAttribute[index]); + widget.afterButtonPressed?.call(); + }, + child: Icon( + _valueString[index] == Attribute.leftAlignment.value + ? Icons.format_align_left + : _valueString[index] == Attribute.centerAlignment.value + ? Icons.format_align_center + : _valueString[index] == + Attribute.rightAlignment.value + ? Icons.format_align_right + : Icons.format_align_justify, + size: widget.iconSize, + color: _valueToText[_value] == _valueString[index] + ? (widget.iconTheme?.iconSelectedColor ?? + theme.primaryIconTheme.color) + : (widget.iconTheme?.iconUnselectedColor ?? + theme.iconTheme.color), + ), ), ), ), diff --git a/lib/src/widgets/toolbar/select_header_style_button.dart b/lib/src/widgets/toolbar/select_header_style_button.dart index f27998b8..986abc22 100644 --- a/lib/src/widgets/toolbar/select_header_style_button.dart +++ b/lib/src/widgets/toolbar/select_header_style_button.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import '../../models/documents/attribute.dart'; import '../../models/documents/style.dart'; import '../../models/themes/quill_icon_theme.dart'; +import '../../utils/widgets.dart'; import '../controller.dart'; import '../toolbar.dart'; @@ -20,6 +21,7 @@ class SelectHeaderStyleButton extends StatefulWidget { Attribute.h3, ], this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -29,6 +31,7 @@ class SelectHeaderStyleButton extends StatefulWidget { final QuillIconTheme? iconTheme; final List attributes; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _SelectHeaderStyleButtonState createState() => @@ -79,34 +82,37 @@ class _SelectHeaderStyleButtonState extends State { width: widget.iconSize * kIconButtonFactor, height: widget.iconSize * kIconButtonFactor, ), - child: RawMaterialButton( - hoverElevation: 0, - highlightElevation: 0, - elevation: 0, - visualDensity: VisualDensity.compact, - shape: RoundedRectangleBorder( - borderRadius: - BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2)), - fillColor: isSelected - ? (widget.iconTheme?.iconSelectedFillColor ?? - Theme.of(context).primaryColor) - : (widget.iconTheme?.iconUnselectedFillColor ?? - theme.canvasColor), - onPressed: () { - final _attribute = _selectedAttribute == attribute - ? Attribute.header - : attribute; - widget.controller.formatSelection(_attribute); - widget.afterButtonPressed?.call(); - }, - child: Text( - _valueToText[attribute] ?? '', - style: style.copyWith( - color: isSelected - ? (widget.iconTheme?.iconSelectedColor ?? - theme.primaryIconTheme.color) - : (widget.iconTheme?.iconUnselectedColor ?? - theme.iconTheme.color), + child: UtilityWidgets.maybeTooltip( + message: widget.tooltip, + child: RawMaterialButton( + hoverElevation: 0, + highlightElevation: 0, + elevation: 0, + visualDensity: VisualDensity.compact, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular( + widget.iconTheme?.borderRadius ?? 2)), + fillColor: isSelected + ? (widget.iconTheme?.iconSelectedFillColor ?? + Theme.of(context).primaryColor) + : (widget.iconTheme?.iconUnselectedFillColor ?? + theme.canvasColor), + onPressed: () { + final _attribute = _selectedAttribute == attribute + ? Attribute.header + : attribute; + widget.controller.formatSelection(_attribute); + widget.afterButtonPressed?.call(); + }, + child: Text( + _valueToText[attribute] ?? '', + style: style.copyWith( + color: isSelected + ? (widget.iconTheme?.iconSelectedColor ?? + theme.primaryIconTheme.color) + : (widget.iconTheme?.iconUnselectedColor ?? + theme.iconTheme.color), + ), ), ), ), diff --git a/lib/src/widgets/toolbar/toggle_check_list_button.dart b/lib/src/widgets/toolbar/toggle_check_list_button.dart index 037c47cd..6912916b 100644 --- a/lib/src/widgets/toolbar/toggle_check_list_button.dart +++ b/lib/src/widgets/toolbar/toggle_check_list_button.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import '../../models/documents/attribute.dart'; import '../../models/documents/style.dart'; import '../../models/themes/quill_icon_theme.dart'; +import '../../utils/widgets.dart'; import '../controller.dart'; import '../toolbar.dart'; @@ -16,6 +17,7 @@ class ToggleCheckListButton extends StatefulWidget { this.childBuilder = defaultToggleStyleButtonBuilder, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -32,6 +34,7 @@ class ToggleCheckListButton extends StatefulWidget { final QuillIconTheme? iconTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _ToggleCheckListButtonState createState() => _ToggleCheckListButtonState(); @@ -91,16 +94,19 @@ class _ToggleCheckListButtonState extends State { @override Widget build(BuildContext context) { - return widget.childBuilder( - context, - Attribute.unchecked, - widget.icon, - widget.fillColor, - _isToggled, - _toggleAttribute, - widget.afterButtonPressed, - widget.iconSize, - widget.iconTheme, + return UtilityWidgets.maybeTooltip( + message: widget.tooltip, + child: widget.childBuilder( + context, + Attribute.unchecked, + widget.icon, + widget.fillColor, + _isToggled, + _toggleAttribute, + widget.afterButtonPressed, + widget.iconSize, + widget.iconTheme, + ), ); } diff --git a/lib/src/widgets/toolbar/toggle_style_button.dart b/lib/src/widgets/toolbar/toggle_style_button.dart index 176b96b0..1eb0eb57 100644 --- a/lib/src/widgets/toolbar/toggle_style_button.dart +++ b/lib/src/widgets/toolbar/toggle_style_button.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import '../../models/documents/attribute.dart'; import '../../models/documents/style.dart'; import '../../models/themes/quill_icon_theme.dart'; +import '../../utils/widgets.dart'; import '../controller.dart'; import '../toolbar.dart'; @@ -28,6 +29,7 @@ class ToggleStyleButton extends StatefulWidget { this.childBuilder = defaultToggleStyleButtonBuilder, this.iconTheme, this.afterButtonPressed, + this.tooltip, Key? key, }) : super(key: key); @@ -46,6 +48,7 @@ class ToggleStyleButton extends StatefulWidget { final QuillIconTheme? iconTheme; final VoidCallback? afterButtonPressed; + final String? tooltip; @override _ToggleStyleButtonState createState() => _ToggleStyleButtonState(); @@ -65,16 +68,19 @@ class _ToggleStyleButtonState extends State { @override Widget build(BuildContext context) { - return widget.childBuilder( - context, - widget.attribute, - widget.icon, - widget.fillColor, - _isToggled, - _toggleAttribute, - widget.afterButtonPressed, - widget.iconSize, - widget.iconTheme, + return UtilityWidgets.maybeTooltip( + message: widget.tooltip, + child: widget.childBuilder( + context, + widget.attribute, + widget.icon, + widget.fillColor, + _isToggled, + _toggleAttribute, + widget.afterButtonPressed, + widget.iconSize, + widget.iconTheme, + ), ); }