Major update step 3 (#1452)

pull/1454/head
Ahmed Hnewa 1 year ago committed by GitHub
parent 55f5101ccc
commit 9039b8cd7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      CHANGELOG.md
  2. 56
      lib/src/models/config/toolbar/buttons/base.dart
  3. 69
      lib/src/models/config/toolbar/buttons/font_family.dart
  4. 94
      lib/src/models/config/toolbar/buttons/font_size.dart
  5. 16
      lib/src/models/config/toolbar/buttons/history.dart
  6. 27
      lib/src/models/config/toolbar/buttons/toggle_style.dart
  7. 48
      lib/src/models/config/toolbar/configurations.dart
  8. 16
      lib/src/models/documents/attribute.dart
  9. 2
      lib/src/utils/extensions/quill_controller.dart
  10. 18
      lib/src/utils/widgets.dart
  11. 11
      lib/src/widgets/toolbar/buttons/arrow_indicated_list.dart
  12. 12
      lib/src/widgets/toolbar/buttons/clear_format.dart
  13. 13
      lib/src/widgets/toolbar/buttons/color.dart
  14. 2
      lib/src/widgets/toolbar/buttons/custom_button.dart
  15. 82
      lib/src/widgets/toolbar/buttons/font_family.dart
  16. 282
      lib/src/widgets/toolbar/buttons/font_size.dart
  17. 6
      lib/src/widgets/toolbar/buttons/history.dart
  18. 11
      lib/src/widgets/toolbar/buttons/indent.dart
  19. 14
      lib/src/widgets/toolbar/buttons/link_style.dart
  20. 17
      lib/src/widgets/toolbar/buttons/link_style2.dart
  21. 225
      lib/src/widgets/toolbar/buttons/quill_font_size.dart
  22. 4
      lib/src/widgets/toolbar/buttons/quill_icon.dart
  23. 6
      lib/src/widgets/toolbar/buttons/search.dart
  24. 12
      lib/src/widgets/toolbar/buttons/select_alignment.dart
  25. 14
      lib/src/widgets/toolbar/buttons/select_header_style.dart
  26. 12
      lib/src/widgets/toolbar/buttons/toggle_check_list.dart
  27. 230
      lib/src/widgets/toolbar/buttons/toggle_style.dart
  28. 306
      lib/src/widgets/toolbar/toolbar.dart
  29. 2
      pubspec.yaml
  30. 8
      test/bug_fix_test.dart

@ -1,3 +1,8 @@
## [7.7.0]
- **Breaking change**: We have mirgrated more buttons in the toolbar configurations, you can do change them in the `QuillProvider`
- Important bug fixes
## [7.6.1] ## [7.6.1]
- Bug fixes - Bug fixes

@ -1,11 +1,35 @@
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
import 'package:flutter/foundation.dart' show VoidCallback, immutable; import 'package:flutter/foundation.dart' show VoidCallback, immutable;
import 'package:flutter/widgets.dart' show IconData, Widget; import 'package:flutter/widgets.dart' show BuildContext, IconData, Widget;
import '../../../../../flutter_quill.dart' show QuillController, QuillProvider; import '../../../../../flutter_quill.dart' show QuillController, QuillProvider;
import '../../../themes/quill_icon_theme.dart' show QuillIconTheme; import '../../../themes/quill_icon_theme.dart' show QuillIconTheme;
import '../../quill_configurations.dart' show kDefaultIconSize; import '../../quill_configurations.dart' show kDefaultIconSize;
@immutable
class QuillToolbarBaseButtonExtraOptions extends Equatable {
const QuillToolbarBaseButtonExtraOptions({
required this.controller,
required this.context,
required this.onPressed,
});
/// if you need the not null controller for some usage in the [childBuilder]
/// then please use this instead of the one in the [options]
final QuillController controller;
/// if the child builder you must use this when the widget tapped or pressed
/// in order to do what it expected to do
final VoidCallback? onPressed;
final BuildContext context;
@override
List<Object?> get props => [
controller,
];
}
/// The [T] is the options for the button, usually should refresnce itself /// The [T] is the options for the button, usually should refresnce itself
/// it's used in [childBuilder] so the developer can custmize this when using it /// it's used in [childBuilder] so the developer can custmize this when using it
/// The [I] is extra options for the button, usually for it's state /// The [I] is extra options for the button, usually for it's state
@ -41,10 +65,13 @@ class QuillToolbarBaseButtonOptions<T, I> extends Equatable {
final QuillIconTheme? iconTheme; final QuillIconTheme? iconTheme;
/// If you want to dispaly a differnet widget based using a builder /// If you want to dispaly a differnet widget based using a builder
final Widget Function(T options, I extraOptions)? childBuilder; final QuillToolbarButtonOptionsChildBuilder<T, I> childBuilder;
/// By default it will be from the one in [QuillProvider] /// By default it will be from the one in [QuillProvider]
/// To override it you must pass not null controller /// To override it you must pass not null controller
/// if you wish to use the controller in the [childBuilder], please use the
/// one from the extraOptions since it will be not null and will be the one
/// which will be used from the quill toolbar
final QuillController? controller; final QuillController? controller;
@override @override
@ -57,4 +84,29 @@ class QuillToolbarBaseButtonOptions<T, I> extends Equatable {
childBuilder, childBuilder,
controller, controller,
]; ];
// QuillToolbarBaseButtonOptions<T, I> copyWith({
// IconData? iconData,
// double? globalIconSize,
// VoidCallback? afterButtonPressed,
// String? tooltip,
// QuillIconTheme? iconTheme,
// Widget Function(T options, I extraOptions)? childBuilder,
// QuillController? controller,
// }) {
// return QuillToolbarBaseButtonOptions<T, I>(
// iconData: iconData ?? this.iconData,
// globalIconSize: globalIconSize ?? this.globalIconSize,
// afterButtonPressed: afterButtonPressed ?? this.afterButtonPressed,
// tooltip: tooltip ?? this.tooltip,
// iconTheme: iconTheme ?? this.iconTheme,
// childBuilder: childBuilder ?? this.childBuilder,
// controller: controller ?? this.controller,
// );
// }
} }
typedef QuillToolbarButtonOptionsChildBuilder<T, I> = Widget Function(
T options,
I extraOptions,
)?;

@ -3,19 +3,25 @@ import 'package:flutter/material.dart' show Colors, PopupMenuEntry;
import 'package:flutter/widgets.dart' import 'package:flutter/widgets.dart'
show show
Color, Color,
ValueChanged, EdgeInsets,
EdgeInsetsGeometry, EdgeInsetsGeometry,
IconData,
TextOverflow,
TextStyle, TextStyle,
EdgeInsets, ValueChanged,
TextOverflow; VoidCallback;
import '../../../../../flutter_quill.dart'; import '../../../../../flutter_quill.dart';
@immutable @immutable
class QuillToolbarFontFamilyButtonExtraOptions { class QuillToolbarFontFamilyButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarFontFamilyButtonExtraOptions({ const QuillToolbarFontFamilyButtonExtraOptions({
required this.defaultDisplayText, required this.defaultDisplayText,
required this.currentValue, required this.currentValue,
required super.controller,
required super.context,
required super.onPressed,
}); });
final String defaultDisplayText; final String defaultDisplayText;
final String currentValue; final String currentValue;
@ -76,4 +82,59 @@ class QuillToolbarFontFamilyButtonOptions extends QuillToolbarBaseButtonOptions<
/// By default will use [globalIconSize] /// By default will use [globalIconSize]
final double? iconSize; final double? iconSize;
QuillToolbarFontFamilyButtonOptions copyWith({
Color? fillColor,
double? hoverElevation,
double? highlightElevation,
List<PopupMenuEntry<String>>? items,
Map<String, String>? rawItemsMap,
ValueChanged<String>? onSelected,
Attribute? attribute,
EdgeInsetsGeometry? padding,
TextStyle? style,
double? width,
String? initialValue,
TextOverflow? labelOverflow,
bool? renderFontFamilies,
bool? overrideTooltipByFontFamily,
double? itemHeight,
EdgeInsets? itemPadding,
Color? defaultItemColor,
double? iconSize,
// Add properties to override inherited properties
QuillController? controller,
IconData? iconData,
VoidCallback? afterButtonPressed,
String? tooltip,
QuillIconTheme? iconTheme,
}) {
return QuillToolbarFontFamilyButtonOptions(
attribute: attribute ?? this.attribute,
rawItemsMap: rawItemsMap ?? this.rawItemsMap,
controller: controller ?? this.controller,
iconData: iconData ?? this.iconData,
afterButtonPressed: afterButtonPressed ?? this.afterButtonPressed,
tooltip: tooltip ?? this.tooltip,
iconTheme: iconTheme ?? this.iconTheme,
onSelected: onSelected ?? this.onSelected,
padding: padding ?? this.padding,
style: style ?? this.style,
width: width ?? this.width,
initialValue: initialValue ?? this.initialValue,
labelOverflow: labelOverflow ?? this.labelOverflow,
renderFontFamilies: renderFontFamilies ?? this.renderFontFamilies,
overrideTooltipByFontFamily:
overrideTooltipByFontFamily ?? this.overrideTooltipByFontFamily,
itemHeight: itemHeight ?? this.itemHeight,
itemPadding: itemPadding ?? this.itemPadding,
defaultItemColor: defaultItemColor ?? this.defaultItemColor,
iconSize: iconSize ?? this.iconSize,
fillColor: fillColor ?? this.fillColor,
hoverElevation: hoverElevation ?? this.hoverElevation,
highlightElevation: highlightElevation ?? this.highlightElevation,
// ignore: deprecated_member_use_from_same_package
items: items ?? this.items,
);
}
} }

@ -1,22 +1,33 @@
import 'dart:ui';
import 'package:flutter/foundation.dart' show immutable; import 'package:flutter/foundation.dart' show immutable;
import 'package:flutter/material.dart' import 'package:flutter/material.dart'
show Colors, PopupMenuEntry, ValueChanged; show Colors, PopupMenuEntry, ValueChanged;
import 'package:flutter/widgets.dart' import 'package:flutter/widgets.dart'
show show Color, EdgeInsets, EdgeInsetsGeometry, TextOverflow, TextStyle;
Color,
EdgeInsetsGeometry,
TextStyle,
VoidCallback,
TextOverflow,
EdgeInsets;
import '../../../../widgets/controller.dart'; import '../../../../widgets/controller.dart';
import '../../../documents/attribute.dart'; import '../../../documents/attribute.dart';
import '../../../themes/quill_icon_theme.dart'; import '../../../themes/quill_icon_theme.dart';
import '../../quill_configurations.dart'; import '../../quill_configurations.dart';
class QuillToolbarFontSizeButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarFontSizeButtonExtraOptions({
required super.controller,
required this.currentValue,
required this.defaultDisplayText,
required super.context,
required super.onPressed,
});
final String currentValue;
final String defaultDisplayText;
}
@immutable @immutable
class QuillToolbarFontSizeButtonOptions extends QuillToolbarBaseButtonOptions { class QuillToolbarFontSizeButtonOptions extends QuillToolbarBaseButtonOptions<
QuillToolbarFontSizeButtonOptions, QuillToolbarFontSizeButtonExtraOptions> {
const QuillToolbarFontSizeButtonOptions({ const QuillToolbarFontSizeButtonOptions({
this.iconSize, this.iconSize,
this.fillColor, this.fillColor,
@ -25,11 +36,11 @@ class QuillToolbarFontSizeButtonOptions extends QuillToolbarBaseButtonOptions {
this.items, this.items,
this.rawItemsMap, this.rawItemsMap,
this.onSelected, this.onSelected,
this.iconTheme, super.iconTheme,
this.attribute = Attribute.size, this.attribute = Attribute.size,
this.controller, super.controller,
this.afterButtonPressed, super.afterButtonPressed,
this.tooltip, super.tooltip,
this.padding, this.padding,
this.style, this.style,
this.width, this.width,
@ -38,6 +49,7 @@ class QuillToolbarFontSizeButtonOptions extends QuillToolbarBaseButtonOptions {
this.itemHeight, this.itemHeight,
this.itemPadding, this.itemPadding,
this.defaultItemColor = Colors.red, this.defaultItemColor = Colors.red,
super.childBuilder,
}); });
final double? iconSize; final double? iconSize;
@ -46,17 +58,12 @@ class QuillToolbarFontSizeButtonOptions extends QuillToolbarBaseButtonOptions {
final double highlightElevation; final double highlightElevation;
@Deprecated('It is not required because of `rawItemsMap`') @Deprecated('It is not required because of `rawItemsMap`')
final List<PopupMenuEntry<String>>? items; final List<PopupMenuEntry<String>>? items;
/// By default it will be [fontSizesValues] from [QuillToolbarConfigurations]
/// You can override this if you want
final Map<String, String>? rawItemsMap; final Map<String, String>? rawItemsMap;
final ValueChanged<String>? onSelected; final ValueChanged<String>? onSelected;
@override
final QuillIconTheme? iconTheme;
final Attribute attribute; final Attribute attribute;
@override
final QuillController? controller;
@override
final VoidCallback? afterButtonPressed;
@override
final String? tooltip;
final EdgeInsetsGeometry? padding; final EdgeInsetsGeometry? padding;
final TextStyle? style; final TextStyle? style;
final double? width; final double? width;
@ -65,4 +72,51 @@ class QuillToolbarFontSizeButtonOptions extends QuillToolbarBaseButtonOptions {
final double? itemHeight; final double? itemHeight;
final EdgeInsets? itemPadding; final EdgeInsets? itemPadding;
final Color? defaultItemColor; final Color? defaultItemColor;
QuillToolbarFontSizeButtonOptions copyWith({
double? iconSize,
Color? fillColor,
double? hoverElevation,
double? highlightElevation,
List<PopupMenuEntry<String>>? items,
Map<String, String>? rawItemsMap,
ValueChanged<String>? onSelected,
Attribute? attribute,
EdgeInsetsGeometry? padding,
TextStyle? style,
double? width,
String? initialValue,
TextOverflow? labelOverflow,
double? itemHeight,
EdgeInsets? itemPadding,
Color? defaultItemColor,
VoidCallback? afterButtonPressed,
String? tooltip,
QuillIconTheme? iconTheme,
QuillController? controller,
}) {
return QuillToolbarFontSizeButtonOptions(
iconSize: iconSize ?? this.iconSize,
fillColor: fillColor ?? this.fillColor,
hoverElevation: hoverElevation ?? this.hoverElevation,
highlightElevation: highlightElevation ?? this.highlightElevation,
// ignore: deprecated_member_use_from_same_package
items: items ?? this.items,
rawItemsMap: rawItemsMap ?? this.rawItemsMap,
onSelected: onSelected ?? this.onSelected,
attribute: attribute ?? this.attribute,
padding: padding ?? this.padding,
style: style ?? this.style,
width: width ?? this.width,
initialValue: initialValue ?? this.initialValue,
labelOverflow: labelOverflow ?? this.labelOverflow,
itemHeight: itemHeight ?? this.itemHeight,
itemPadding: itemPadding ?? this.itemPadding,
defaultItemColor: defaultItemColor ?? this.defaultItemColor,
tooltip: tooltip ?? super.tooltip,
iconTheme: iconTheme ?? super.iconTheme,
afterButtonPressed: afterButtonPressed ?? super.afterButtonPressed,
controller: controller ?? super.controller,
);
}
} }

@ -1,24 +1,24 @@
import 'package:flutter/foundation.dart' show VoidCallback, immutable; import 'package:flutter/foundation.dart' show immutable;
import '../../../../../flutter_quill.dart'; import '../../../../../flutter_quill.dart';
@immutable @immutable
class HistoryButtonExtraOptions { class QuillToolbarHistoryButtonExtraOptions
const HistoryButtonExtraOptions({ extends QuillToolbarBaseButtonExtraOptions {
required this.onPressed, const QuillToolbarHistoryButtonExtraOptions({
required this.canPressed, required this.canPressed,
required super.controller,
required super.context,
required super.onPressed,
}); });
/// When the button pressed
final VoidCallback onPressed;
/// If it can redo or undo /// If it can redo or undo
final bool canPressed; final bool canPressed;
} }
@immutable @immutable
class QuillToolbarHistoryButtonOptions extends QuillToolbarBaseButtonOptions< class QuillToolbarHistoryButtonOptions extends QuillToolbarBaseButtonOptions<
QuillToolbarHistoryButtonOptions, HistoryButtonExtraOptions> { QuillToolbarHistoryButtonOptions, QuillToolbarHistoryButtonExtraOptions> {
const QuillToolbarHistoryButtonOptions({ const QuillToolbarHistoryButtonOptions({
required this.isUndo, required this.isUndo,
super.iconData, super.iconData,

@ -1,15 +1,32 @@
import 'package:flutter/foundation.dart' show immutable; import 'package:flutter/foundation.dart' show immutable;
import 'package:flutter/widgets.dart' show IconData; import 'package:flutter/widgets.dart' show Color;
import 'base.dart'; import 'base.dart';
class QuillToolbarToggleStyleButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarToggleStyleButtonExtraOptions({
required super.controller,
required super.context,
required super.onPressed,
});
}
@immutable @immutable
class QuillToolbarToggleStyleButtonOptions class QuillToolbarToggleStyleButtonOptions
extends QuillToolbarBaseButtonOptions { extends QuillToolbarBaseButtonOptions<QuillToolbarToggleStyleButtonOptions,
QuillToolbarToggleStyleButtonExtraOptions> {
const QuillToolbarToggleStyleButtonOptions({ const QuillToolbarToggleStyleButtonOptions({
required this.iconData, super.iconData,
this.iconSize,
this.fillColor,
super.tooltip,
super.afterButtonPressed,
super.iconTheme,
super.childBuilder,
super.controller,
}); });
@override final double? iconSize;
final IconData iconData; final Color? fillColor;
} }

@ -3,8 +3,9 @@ import 'package:flutter/foundation.dart' show immutable;
import 'buttons/base.dart'; import 'buttons/base.dart';
import 'buttons/font_family.dart'; import 'buttons/font_family.dart';
// import 'buttons/font_size.dart'; import 'buttons/font_size.dart';
import 'buttons/history.dart'; import 'buttons/history.dart';
import 'buttons/toggle_style.dart';
export './buttons/base.dart'; export './buttons/base.dart';
export './buttons/font_family.dart'; export './buttons/font_family.dart';
@ -31,6 +32,7 @@ class QuillToolbarConfigurations extends Equatable {
this.buttonOptions = const QuillToolbarButtonOptions(), this.buttonOptions = const QuillToolbarButtonOptions(),
this.multiRowsDisplay = true, this.multiRowsDisplay = true,
this.fontFamilyValues, this.fontFamilyValues,
this.fontSizesValues,
/// By default it will calculated based on the [baseOptions] iconSize /// By default it will calculated based on the [baseOptions] iconSize
/// You can change it but the the change only apply if /// You can change it but the the change only apply if
@ -55,7 +57,7 @@ class QuillToolbarConfigurations extends Equatable {
final QuillToolbarButtonOptions buttonOptions; final QuillToolbarButtonOptions buttonOptions;
final bool multiRowsDisplay; final bool multiRowsDisplay;
/// By default will be final /// By default it will be
/// ``` /// ```
/// { /// {
/// 'Sans Serif': 'sans-serif', /// 'Sans Serif': 'sans-serif',
@ -71,11 +73,23 @@ class QuillToolbarConfigurations extends Equatable {
/// ``` /// ```
final Map<String, String>? fontFamilyValues; final Map<String, String>? fontFamilyValues;
/// By default it will be
/// ```
/// {
/// 'Small'.i18n: 'small',
/// 'Large'.i18n: 'large',
/// 'Huge'.i18n: 'huge',
/// 'Clear'.i18n: '0'
/// }
/// ```
final Map<String, String>? fontSizesValues;
@override @override
List<Object?> get props => [ List<Object?> get props => [
buttonOptions, buttonOptions,
multiRowsDisplay, multiRowsDisplay,
fontFamilyValues, fontFamilyValues,
fontSizesValues,
toolbarSize, toolbarSize,
]; ];
} }
@ -92,7 +106,20 @@ class QuillToolbarButtonOptions extends Equatable {
isUndo: false, isUndo: false,
), ),
this.fontFamily = const QuillToolbarFontFamilyButtonOptions(), this.fontFamily = const QuillToolbarFontFamilyButtonOptions(),
// this.fontSize = const QuillToolbarFontSizeButtonOptions(), this.fontSize = const QuillToolbarFontSizeButtonOptions(),
this.bold = const QuillToolbarToggleStyleButtonOptions(),
this.subscript = const QuillToolbarToggleStyleButtonOptions(),
this.superscript = const QuillToolbarToggleStyleButtonOptions(),
this.italic = const QuillToolbarToggleStyleButtonOptions(),
this.small = const QuillToolbarToggleStyleButtonOptions(),
this.underLine = const QuillToolbarToggleStyleButtonOptions(),
this.strikeThrough = const QuillToolbarToggleStyleButtonOptions(),
this.inlineCode = const QuillToolbarToggleStyleButtonOptions(),
this.direction = const QuillToolbarToggleStyleButtonOptions(),
this.listNumbers = const QuillToolbarToggleStyleButtonOptions(),
this.listBullets = const QuillToolbarToggleStyleButtonOptions(),
this.codeBlock = const QuillToolbarToggleStyleButtonOptions(),
this.quote = const QuillToolbarToggleStyleButtonOptions(),
}); });
/// The base configurations for all the buttons which will apply to all /// The base configurations for all the buttons which will apply to all
@ -102,7 +129,20 @@ class QuillToolbarButtonOptions extends Equatable {
final QuillToolbarHistoryButtonOptions undoHistory; final QuillToolbarHistoryButtonOptions undoHistory;
final QuillToolbarHistoryButtonOptions redoHistory; final QuillToolbarHistoryButtonOptions redoHistory;
final QuillToolbarFontFamilyButtonOptions fontFamily; final QuillToolbarFontFamilyButtonOptions fontFamily;
// final QuillToolbarFontSizeButtonOptions fontSize; final QuillToolbarFontSizeButtonOptions fontSize;
final QuillToolbarToggleStyleButtonOptions bold;
final QuillToolbarToggleStyleButtonOptions subscript;
final QuillToolbarToggleStyleButtonOptions superscript;
final QuillToolbarToggleStyleButtonOptions italic;
final QuillToolbarToggleStyleButtonOptions small;
final QuillToolbarToggleStyleButtonOptions underLine;
final QuillToolbarToggleStyleButtonOptions strikeThrough;
final QuillToolbarToggleStyleButtonOptions inlineCode;
final QuillToolbarToggleStyleButtonOptions direction;
final QuillToolbarToggleStyleButtonOptions listNumbers;
final QuillToolbarToggleStyleButtonOptions listBullets;
final QuillToolbarToggleStyleButtonOptions codeBlock;
final QuillToolbarToggleStyleButtonOptions quote;
@override @override
List<Object?> get props => [ List<Object?> get props => [

@ -1,5 +1,6 @@
import 'dart:collection'; import 'dart:collection';
import 'package:equatable/equatable.dart';
import 'package:quiver/core.dart'; import 'package:quiver/core.dart';
enum AttributeScope { enum AttributeScope {
@ -9,8 +10,12 @@ enum AttributeScope {
IGNORE, // attributes that can be ignored IGNORE, // attributes that can be ignored
} }
class Attribute<T> { class Attribute<T> extends Equatable {
const Attribute(this.key, this.scope, this.value); const Attribute(
this.key,
this.scope,
this.value,
);
/// Unique key of this attribute. /// Unique key of this attribute.
final String key; final String key;
@ -102,7 +107,7 @@ class Attribute<T> {
static final ScriptAttribute script = ScriptAttribute(null); static final ScriptAttribute script = ScriptAttribute(null);
// TODO: You might want to mark those as key (mobileWidthKey) // TODO: You might want to mark those as key (like mobileWidthKey)
// because it was not very clear to a developer that is new to this project // because it was not very clear to a developer that is new to this project
static const String mobileWidth = 'mobileWidth'; static const String mobileWidth = 'mobileWidth';
@ -253,6 +258,7 @@ class Attribute<T> {
return Attribute(origin.key, origin.scope, value); return Attribute(origin.key, origin.scope, value);
} }
// This might not needed anymore because of equatable
@override @override
bool operator ==(Object other) { bool operator ==(Object other) {
if (identical(this, other)) return true; if (identical(this, other)) return true;
@ -263,6 +269,7 @@ class Attribute<T> {
value == typedOther.value; value == typedOther.value;
} }
// This might not needed anymore because of equatable
@override @override
int get hashCode => hash3(key, scope, value); int get hashCode => hash3(key, scope, value);
@ -270,6 +277,9 @@ class Attribute<T> {
String toString() { String toString() {
return 'Attribute{key: $key, scope: $scope, value: $value}'; return 'Attribute{key: $key, scope: $scope, value: $value}';
} }
@override
List<Object?> get props => [key, scope, value];
} }
class BoldAttribute extends Attribute<bool> { class BoldAttribute extends Attribute<bool> {

@ -3,7 +3,7 @@ import 'package:flutter/widgets.dart' show BuildContext;
import '../../../flutter_quill.dart' show QuillController, QuillProvider; import '../../../flutter_quill.dart' show QuillController, QuillProvider;
import 'build_context.dart'; import 'build_context.dart';
extension QuillControllerExt on QuillController? { extension QuillControllerNullableExt on QuillController? {
/// Simple logic to use the current passed controller if not null /// Simple logic to use the current passed controller if not null
/// if null then we will have to use the default one from [QuillProvider] /// if null then we will have to use the default one from [QuillProvider]
/// using the [context] /// using the [context]

@ -6,16 +6,20 @@ typedef WidgetWrapper = Widget Function(Widget child);
abstract class UtilityWidgets { abstract class UtilityWidgets {
/// Conditionally wraps the [child] with [Tooltip] widget if [message] /// Conditionally wraps the [child] with [Tooltip] widget if [message]
/// is not null and not empty. /// is not null and not empty.
static Widget maybeTooltip({required Widget child, String? message}) => static Widget maybeTooltip({
(message ?? '').isNotEmpty required Widget child,
? Tooltip(message: message!, child: child) String? message,
}) =>
(message?.isNotEmpty ?? false)
? Tooltip(message: message, child: child)
: child; : child;
/// Conditionally wraps the [child] with [wrapper] widget if [enabled] /// Conditionally wraps the [child] with [wrapper] widget if [enabled]
/// is true. /// is true.
static Widget maybeWidget( static Widget maybeWidget({
{required WidgetWrapper wrapper, required WidgetWrapper wrapper,
required Widget child, required Widget child,
bool enabled = false}) => bool enabled = false,
}) =>
enabled ? wrapper(child) : child; enabled ? wrapper(child) : child;
} }

@ -6,8 +6,8 @@ import 'package:flutter/material.dart';
/// ///
/// The arrow indicators are automatically hidden if the list is not /// The arrow indicators are automatically hidden if the list is not
/// scrollable in the direction of the respective arrow. /// scrollable in the direction of the respective arrow.
class ArrowIndicatedButtonList extends StatefulWidget { class QuillToolbarArrowIndicatedButtonList extends StatefulWidget {
const ArrowIndicatedButtonList({ const QuillToolbarArrowIndicatedButtonList({
required this.axis, required this.axis,
required this.buttons, required this.buttons,
Key? key, Key? key,
@ -17,11 +17,12 @@ class ArrowIndicatedButtonList extends StatefulWidget {
final List<Widget> buttons; final List<Widget> buttons;
@override @override
_ArrowIndicatedButtonListState createState() => _QuillToolbarArrowIndicatedButtonListState createState() =>
_ArrowIndicatedButtonListState(); _QuillToolbarArrowIndicatedButtonListState();
} }
class _ArrowIndicatedButtonListState extends State<ArrowIndicatedButtonList> class _QuillToolbarArrowIndicatedButtonListState
extends State<QuillToolbarArrowIndicatedButtonList>
with WidgetsBindingObserver { with WidgetsBindingObserver {
final ScrollController _controller = ScrollController(); final ScrollController _controller = ScrollController();
bool _showBackwardArrow = false; bool _showBackwardArrow = false;

@ -5,8 +5,8 @@ import '../../../models/themes/quill_icon_theme.dart';
import '../../controller.dart'; import '../../controller.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class ClearFormatButton extends StatefulWidget { class QuillToolbarClearFormatButton extends StatefulWidget {
const ClearFormatButton({ const QuillToolbarClearFormatButton({
required this.icon, required this.icon,
required this.controller, required this.controller,
this.iconSize = kDefaultIconSize, this.iconSize = kDefaultIconSize,
@ -26,10 +26,12 @@ class ClearFormatButton extends StatefulWidget {
final String? tooltip; final String? tooltip;
@override @override
_ClearFormatButtonState createState() => _ClearFormatButtonState(); _QuillToolbarClearFormatButtonState createState() =>
_QuillToolbarClearFormatButtonState();
} }
class _ClearFormatButtonState extends State<ClearFormatButton> { class _QuillToolbarClearFormatButtonState
extends State<QuillToolbarClearFormatButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
@ -37,7 +39,7 @@ class _ClearFormatButtonState extends State<ClearFormatButton> {
widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color; widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
final fillColor = final fillColor =
widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor; widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor;
return QuillIconButton( return QuillToolbarIconButton(
tooltip: widget.tooltip, tooltip: widget.tooltip,
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,

@ -13,8 +13,8 @@ import '../toolbar.dart';
/// ///
/// When pressed, this button displays overlay toolbar with /// When pressed, this button displays overlay toolbar with
/// buttons for each color. /// buttons for each color.
class ColorButton extends StatefulWidget { class QuillToolbarColorButton extends StatefulWidget {
const ColorButton({ const QuillToolbarColorButton({
required this.icon, required this.icon,
required this.controller, required this.controller,
required this.background, required this.background,
@ -36,10 +36,11 @@ class ColorButton extends StatefulWidget {
final Color dialogBarrierColor; final Color dialogBarrierColor;
@override @override
_ColorButtonState createState() => _ColorButtonState(); _QuillToolbarColorButtonState createState() =>
_QuillToolbarColorButtonState();
} }
class _ColorButtonState extends State<ColorButton> { class _QuillToolbarColorButtonState extends State<QuillToolbarColorButton> {
late bool _isToggledColor; late bool _isToggledColor;
late bool _isToggledBackground; late bool _isToggledBackground;
late bool _isWhite; late bool _isWhite;
@ -81,7 +82,7 @@ class _ColorButtonState extends State<ColorButton> {
} }
@override @override
void didUpdateWidget(covariant ColorButton oldWidget) { void didUpdateWidget(covariant QuillToolbarColorButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue); oldWidget.controller.removeListener(_didChangeEditingValue);
@ -122,7 +123,7 @@ class _ColorButtonState extends State<ColorButton> {
? stringToColor('#ffffff') ? stringToColor('#ffffff')
: (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor); : (widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor);
return QuillIconButton( return QuillToolbarIconButton(
tooltip: widget.tooltip, tooltip: widget.tooltip,
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,

@ -28,7 +28,7 @@ class CustomButton extends StatelessWidget {
final theme = Theme.of(context); final theme = Theme.of(context);
final iconColor = iconTheme?.iconUnselectedColor ?? theme.iconTheme.color; final iconColor = iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
return QuillIconButton( return QuillToolbarIconButton(
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,
size: iconSize * kIconButtonFactor, size: iconSize * kIconButtonFactor,

@ -4,14 +4,15 @@ import '../../../../extensions.dart';
import '../../../models/config/toolbar/buttons/font_family.dart'; import '../../../models/config/toolbar/buttons/font_family.dart';
import '../../../models/documents/attribute.dart'; import '../../../models/documents/attribute.dart';
import '../../../models/documents/style.dart'; import '../../../models/documents/style.dart';
import '../../../models/themes/quill_icon_theme.dart';
import '../../../translations/toolbar.i18n.dart'; import '../../../translations/toolbar.i18n.dart';
import '../../../utils/extensions/build_context.dart'; import '../../../utils/extensions/build_context.dart';
import '../../../utils/extensions/quill_controller.dart';
import '../../controller.dart'; import '../../controller.dart';
class QuillToolbarFontFamilyButton extends StatefulWidget { class QuillToolbarFontFamilyButton extends StatefulWidget {
QuillToolbarFontFamilyButton({ QuillToolbarFontFamilyButton({
required this.options, required this.options,
required this.controller,
super.key, super.key,
}) : assert(options.rawItemsMap?.isNotEmpty ?? (true)), }) : assert(options.rawItemsMap?.isNotEmpty ?? (true)),
assert( assert(
@ -20,6 +21,10 @@ class QuillToolbarFontFamilyButton extends StatefulWidget {
final QuillToolbarFontFamilyButtonOptions options; final QuillToolbarFontFamilyButtonOptions options;
/// Since we can't get the state from the instace of the widget for comparing
/// in [didUpdateWidget] then we will have to store reference here
final QuillController controller;
@override @override
_QuillToolbarFontFamilyButtonState createState() => _QuillToolbarFontFamilyButtonState createState() =>
_QuillToolbarFontFamilyButtonState(); _QuillToolbarFontFamilyButtonState();
@ -33,16 +38,12 @@ class _QuillToolbarFontFamilyButtonState
return widget.options; return widget.options;
} }
/// Since t's not safe to call anything related to the context in dispose /// Since it's not safe to call anything related to the context in dispose
/// then we will save a reference to the [controller] /// then we will save a reference to the [controller]
/// and update it in [didChangeDependencies] /// and update it in [didChangeDependencies]
/// and use it in dispose method /// and use it in dispose method
late QuillController _controller; late QuillController _controller;
QuillController get controller {
return options.controller.notNull(context);
}
Style get _selectionStyle => controller.getSelectionStyle(); Style get _selectionStyle => controller.getSelectionStyle();
@override @override
@ -82,7 +83,7 @@ class _QuillToolbarFontFamilyButtonState
@override @override
void didUpdateWidget(covariant QuillToolbarFontFamilyButton oldWidget) { void didUpdateWidget(covariant QuillToolbarFontFamilyButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (controller == controller) { if (oldWidget.controller == controller) {
return; return;
} }
controller controller
@ -102,6 +103,7 @@ class _QuillToolbarFontFamilyButtonState
Map<String, String> get rawItemsMap { Map<String, String> get rawItemsMap {
final rawItemsMap = options.rawItemsMap ?? final rawItemsMap = options.rawItemsMap ??
context.requireQuillToolbarConfigurations.fontFamilyValues ??
{ {
'Sans Serif': 'sans-serif', 'Sans Serif': 'sans-serif',
'Serif': 'serif', 'Serif': 'serif',
@ -125,15 +127,36 @@ class _QuillToolbarFontFamilyButtonState
return null; return null;
} }
QuillController get controller {
return options.controller ?? widget.controller;
}
double get iconSize { double get iconSize {
final baseFontSize =
context.requireQuillToolbarBaseButtonOptions.globalIconSize;
final iconSize = options.iconSize; final iconSize = options.iconSize;
return iconSize ?? 40; return iconSize ?? baseFontSize;
// final baseFontSize = }
// context.requireQuillToolbarBaseButtonOptions.globalIconSize;
// if (baseFontSize != iconSize) { VoidCallback? get afterButtonPressed {
// return 40; return options.afterButtonPressed ??
// } context.requireQuillToolbarBaseButtonOptions.afterButtonPressed;
// return iconSize ?? baseFontSize; }
QuillIconTheme? get iconTheme {
return options.iconTheme ??
context.requireQuillToolbarBaseButtonOptions.iconTheme;
}
String get tooltip {
return options.tooltip ??
context.requireQuillToolbarBaseButtonOptions.tooltip ??
'Font family'.i18n;
}
void _onPressed() {
_showMenu();
options.afterButtonPressed?.call();
} }
@override @override
@ -144,10 +167,19 @@ class _QuillToolbarFontFamilyButtonState
options.childBuilder ?? baseButtonConfigurations.childBuilder; options.childBuilder ?? baseButtonConfigurations.childBuilder;
if (childBuilder != null) { if (childBuilder != null) {
return childBuilder( return childBuilder(
options, options.copyWith(
iconSize: iconSize,
rawItemsMap: rawItemsMap,
iconTheme: iconTheme,
tooltip: tooltip,
afterButtonPressed: afterButtonPressed,
),
QuillToolbarFontFamilyButtonExtraOptions( QuillToolbarFontFamilyButtonExtraOptions(
currentValue: _currentValue, currentValue: _currentValue,
defaultDisplayText: _defaultDisplayText, defaultDisplayText: _defaultDisplayText,
controller: controller,
context: context,
onPressed: _onPressed,
), ),
); );
} }
@ -157,10 +189,9 @@ class _QuillToolbarFontFamilyButtonState
width: options.width, width: options.width,
), ),
child: UtilityWidgets.maybeWidget( child: UtilityWidgets.maybeWidget(
enabled: (options.tooltip ?? '').isNotEmpty || enabled: tooltip.isNotEmpty || options.overrideTooltipByFontFamily,
options.overrideTooltipByFontFamily,
wrapper: (child) { wrapper: (child) {
var effectiveTooltip = options.tooltip ?? ''; var effectiveTooltip = tooltip;
if (options.overrideTooltipByFontFamily) { if (options.overrideTooltipByFontFamily) {
effectiveTooltip = effectiveTooltip.isNotEmpty effectiveTooltip = effectiveTooltip.isNotEmpty
? '$effectiveTooltip: $_currentValue' ? '$effectiveTooltip: $_currentValue'
@ -171,17 +202,13 @@ class _QuillToolbarFontFamilyButtonState
child: RawMaterialButton( child: RawMaterialButton(
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius: BorderRadius.circular(iconTheme?.borderRadius ?? 2),
BorderRadius.circular(options.iconTheme?.borderRadius ?? 2),
), ),
fillColor: options.fillColor, fillColor: options.fillColor,
elevation: 0, elevation: 0,
hoverElevation: options.hoverElevation, hoverElevation: options.hoverElevation,
highlightElevation: options.hoverElevation, highlightElevation: options.hoverElevation,
onPressed: () { onPressed: _onPressed,
_showMenu();
options.afterButtonPressed?.call();
},
child: _buildContent(context), child: _buildContent(context),
), ),
), ),
@ -266,8 +293,8 @@ class _QuillToolbarFontFamilyButtonState
style: options.style ?? style: options.style ??
TextStyle( TextStyle(
fontSize: iconSize / 1.15, fontSize: iconSize / 1.15,
color: options.iconTheme?.iconUnselectedColor ?? color:
theme.iconTheme.color, iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
), ),
), ),
), ),
@ -275,8 +302,7 @@ class _QuillToolbarFontFamilyButtonState
Icon( Icon(
Icons.arrow_drop_down, Icons.arrow_drop_down,
size: iconSize / 1.15, size: iconSize / 1.15,
color: color: iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
options.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
) )
], ],
), ),

@ -0,0 +1,282 @@
import 'package:flutter/material.dart';
import '../../../../extensions.dart';
import '../../../../flutter_quill.dart';
import '../../../translations/toolbar.i18n.dart';
import '../../../utils/extensions/build_context.dart';
import '../../../utils/font.dart';
class QuillToolbarFontSizeButton extends StatefulWidget {
QuillToolbarFontSizeButton({
required this.options,
required this.controller,
super.key,
}) : assert(options.rawItemsMap?.isNotEmpty ?? true),
assert(options.initialValue == null ||
(options.initialValue?.isNotEmpty ?? true));
final QuillToolbarFontSizeButtonOptions options;
/// Since we can't get the state from the instace of the widget for comparing
/// in [didUpdateWidget] then we will have to store reference here
final QuillController controller;
@override
_QuillToolbarFontSizeButtonState createState() =>
_QuillToolbarFontSizeButtonState();
}
class _QuillToolbarFontSizeButtonState
extends State<QuillToolbarFontSizeButton> {
String _currentValue = '';
QuillToolbarFontSizeButtonOptions get options {
return widget.options;
}
/// Since it's not safe to call anything related to the context in dispose
/// then we will save a reference to the [controller]
/// and update it in [didChangeDependencies]
/// and use it in dispose method
late QuillController _controller;
Map<String, String> get rawItemsMap {
final fontSizes = options.rawItemsMap ??
context.requireQuillToolbarConfigurations.fontSizesValues ??
{
'Small'.i18n: 'small',
'Large'.i18n: 'large',
'Huge'.i18n: 'huge',
'Clear'.i18n: '0'
};
return fontSizes;
}
String get _defaultDisplayText {
return options.initialValue ?? 'Size'.i18n;
}
Style get _selectionStyle => controller.getSelectionStyle();
@override
void initState() {
super.initState();
_initState();
}
Future<void> _initState() async {
if (isFlutterTest()) {
return;
}
await Future.delayed(Duration.zero);
setState(() {
_currentValue = _defaultDisplayText;
});
controller.addListener(_didChangeEditingValue);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_controller = controller;
}
@override
void dispose() {
_controller.removeListener(_didChangeEditingValue);
super.dispose();
}
@override
void didUpdateWidget(covariant QuillToolbarFontSizeButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.controller == controller) {
return;
}
controller
..removeListener(_didChangeEditingValue)
..addListener(_didChangeEditingValue);
}
void _didChangeEditingValue() {
final attribute = _selectionStyle.attributes[options.attribute.key];
if (attribute == null) {
setState(() => _currentValue = _defaultDisplayText);
return;
}
final keyName = _getKeyName(attribute.value);
setState(() => _currentValue = keyName ?? _defaultDisplayText);
}
String? _getKeyName(dynamic value) {
for (final entry in rawItemsMap.entries) {
if (getFontSize(entry.value) == getFontSize(value)) {
return entry.key;
}
}
return null;
}
QuillController get controller {
return options.controller ?? widget.controller;
}
double get iconSize {
final baseFontSize =
context.requireQuillToolbarBaseButtonOptions.globalIconSize;
final iconSize = options.iconSize;
return iconSize ?? baseFontSize;
}
VoidCallback? get afterButtonPressed {
return options.afterButtonPressed ??
context.requireQuillToolbarBaseButtonOptions.afterButtonPressed;
}
QuillIconTheme? get iconTheme {
return options.iconTheme ??
context.requireQuillToolbarBaseButtonOptions.iconTheme;
}
String get tooltip {
return options.tooltip ??
context.requireQuillToolbarBaseButtonOptions.tooltip ??
'Font size'.i18n;
}
void _onPressed() {
_showMenu();
afterButtonPressed?.call();
}
@override
Widget build(BuildContext context) {
final baseButtonConfigurations =
context.requireQuillToolbarBaseButtonOptions;
final childBuilder =
options.childBuilder ?? baseButtonConfigurations.childBuilder;
if (childBuilder != null) {
return childBuilder(
options.copyWith(
tooltip: tooltip,
iconSize: iconSize,
iconTheme: iconTheme,
afterButtonPressed: afterButtonPressed,
controller: controller,
),
QuillToolbarFontSizeButtonExtraOptions(
controller: controller,
currentValue: _currentValue,
defaultDisplayText: _defaultDisplayText,
context: context,
onPressed: _onPressed,
),
);
}
return ConstrainedBox(
constraints: BoxConstraints.tightFor(
height: iconSize * 1.81,
width: options.width,
),
child: UtilityWidgets.maybeTooltip(
message: tooltip,
child: RawMaterialButton(
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(iconTheme?.borderRadius ?? 2),
),
fillColor: options.fillColor,
elevation: 0,
hoverElevation: options.hoverElevation,
highlightElevation: options.hoverElevation,
onPressed: _onPressed,
child: _buildContent(context),
),
),
);
}
Future<void> _showMenu() async {
final popupMenuTheme = PopupMenuTheme.of(context);
final button = context.findRenderObject() as RenderBox;
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
final position = RelativeRect.fromRect(
Rect.fromPoints(
button.localToGlobal(Offset.zero, ancestor: overlay),
button.localToGlobal(button.size.bottomLeft(Offset.zero),
ancestor: overlay),
),
Offset.zero & overlay.size,
);
final newValue = await showMenu<String>(
context: context,
elevation: 4,
items: [
for (final MapEntry<String, String> fontSize in rawItemsMap.entries)
PopupMenuItem<String>(
key: ValueKey(fontSize.key),
value: fontSize.value,
height: options.itemHeight ?? kMinInteractiveDimension,
padding: options.itemPadding,
child: Text(
fontSize.key.toString(),
style: TextStyle(
color: fontSize.value == '0' ? options.defaultItemColor : null,
),
),
),
],
position: position,
shape: popupMenuTheme.shape,
color: popupMenuTheme.color,
);
if (!mounted) return;
if (newValue == null) {
return;
}
final keyName = _getKeyName(newValue);
setState(() {
_currentValue = keyName ?? _defaultDisplayText;
if (keyName != null) {
controller.formatSelection(Attribute.fromKeyValue(
'size', newValue == '0' ? null : getFontSize(newValue)));
options.onSelected?.call(newValue);
}
});
}
Widget _buildContent(BuildContext context) {
final theme = Theme.of(context);
final hasFinalWidth = options.width != null;
return Padding(
padding: options.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Row(
mainAxisSize: !hasFinalWidth ? MainAxisSize.min : MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
UtilityWidgets.maybeWidget(
enabled: hasFinalWidth,
wrapper: (child) => Expanded(child: child),
child: Text(
_currentValue,
overflow: options.labelOverflow,
style: options.style ??
TextStyle(
fontSize: iconSize / 1.15,
color:
iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
),
),
),
const SizedBox(width: 3),
Icon(
Icons.arrow_drop_down,
size: iconSize / 1.15,
color: iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
)
],
),
);
}
}

@ -86,16 +86,18 @@ class _QuillToolbarHistoryButtonState extends State<QuillToolbarHistoryButton> {
iconTheme: iconTheme, iconTheme: iconTheme,
tooltip: tooltip, tooltip: tooltip,
), ),
HistoryButtonExtraOptions( QuillToolbarHistoryButtonExtraOptions(
onPressed: () { onPressed: () {
_updateHistory(); _updateHistory();
afterButtonPressed?.call(); afterButtonPressed?.call();
}, },
canPressed: _canPressed, canPressed: _canPressed,
controller: controller,
context: context,
), ),
); );
} }
return QuillIconButton( return QuillToolbarIconButton(
tooltip: tooltip, tooltip: tooltip,
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,

@ -4,8 +4,8 @@ import '../../../models/themes/quill_icon_theme.dart';
import '../../controller.dart'; import '../../controller.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class IndentButton extends StatefulWidget { class QuillToolbarIndentButton extends StatefulWidget {
const IndentButton({ const QuillToolbarIndentButton({
required this.icon, required this.icon,
required this.controller, required this.controller,
required this.isIncrease, required this.isIncrease,
@ -26,10 +26,11 @@ class IndentButton extends StatefulWidget {
final String? tooltip; final String? tooltip;
@override @override
_IndentButtonState createState() => _IndentButtonState(); _QuillToolbarIndentButtonState createState() =>
_QuillToolbarIndentButtonState();
} }
class _IndentButtonState extends State<IndentButton> { class _QuillToolbarIndentButtonState extends State<QuillToolbarIndentButton> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
@ -38,7 +39,7 @@ class _IndentButtonState extends State<IndentButton> {
widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color; widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color;
final iconFillColor = final iconFillColor =
widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor; widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor;
return QuillIconButton( return QuillToolbarIconButton(
tooltip: widget.tooltip, tooltip: widget.tooltip,
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,

@ -10,8 +10,8 @@ import '../../controller.dart';
import '../../link.dart'; import '../../link.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class LinkStyleButton extends StatefulWidget { class QuillToolbarLinkStyleButton extends StatefulWidget {
const LinkStyleButton({ const QuillToolbarLinkStyleButton({
required this.controller, required this.controller,
this.iconSize = kDefaultIconSize, this.iconSize = kDefaultIconSize,
this.icon, this.icon,
@ -37,10 +37,12 @@ class LinkStyleButton extends StatefulWidget {
final Color dialogBarrierColor; final Color dialogBarrierColor;
@override @override
_LinkStyleButtonState createState() => _LinkStyleButtonState(); _QuillToolbarLinkStyleButtonState createState() =>
_QuillToolbarLinkStyleButtonState();
} }
class _LinkStyleButtonState extends State<LinkStyleButton> { class _QuillToolbarLinkStyleButtonState
extends State<QuillToolbarLinkStyleButton> {
void _didChangeSelection() { void _didChangeSelection() {
setState(() {}); setState(() {});
} }
@ -52,7 +54,7 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
} }
@override @override
void didUpdateWidget(covariant LinkStyleButton oldWidget) { void didUpdateWidget(covariant QuillToolbarLinkStyleButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeSelection); oldWidget.controller.removeListener(_didChangeSelection);
@ -71,7 +73,7 @@ class _LinkStyleButtonState extends State<LinkStyleButton> {
final theme = Theme.of(context); final theme = Theme.of(context);
final isToggled = _getLinkAttributeValue() != null; final isToggled = _getLinkAttributeValue() != null;
final pressedHandler = () => _openLinkDialog(context); final pressedHandler = () => _openLinkDialog(context);
return QuillIconButton( return QuillToolbarIconButton(
tooltip: widget.tooltip, tooltip: widget.tooltip,
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,

@ -12,10 +12,11 @@ import '../../controller.dart';
import '../../link.dart'; import '../../link.dart';
import '../toolbar.dart'; import '../toolbar.dart';
/// Alternative version of [LinkStyleButton]. This widget has more customization /// Alternative version of [QuillToolbarLinkStyleButton]. This widget has more
/// customization
/// and uses dialog similar to one which is used on [http://quilljs.com]. /// and uses dialog similar to one which is used on [http://quilljs.com].
class LinkStyleButton2 extends StatefulWidget { class QuillToolbarLinkStyleButton2 extends StatefulWidget {
const LinkStyleButton2({ const QuillToolbarLinkStyleButton2({
required this.controller, required this.controller,
this.icon, this.icon,
this.iconSize = kDefaultIconSize, this.iconSize = kDefaultIconSize,
@ -71,10 +72,12 @@ class LinkStyleButton2 extends StatefulWidget {
final Color dialogBarrierColor; final Color dialogBarrierColor;
@override @override
State<LinkStyleButton2> createState() => _LinkStyleButton2State(); State<QuillToolbarLinkStyleButton2> createState() =>
_QuillToolbarLinkStyleButton2State();
} }
class _LinkStyleButton2State extends State<LinkStyleButton2> { class _QuillToolbarLinkStyleButton2State
extends State<QuillToolbarLinkStyleButton2> {
@override @override
void dispose() { void dispose() {
super.dispose(); super.dispose();
@ -88,7 +91,7 @@ class _LinkStyleButton2State extends State<LinkStyleButton2> {
} }
@override @override
void didUpdateWidget(covariant LinkStyleButton2 oldWidget) { void didUpdateWidget(covariant QuillToolbarLinkStyleButton2 oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeSelection); oldWidget.controller.removeListener(_didChangeSelection);
@ -100,7 +103,7 @@ class _LinkStyleButton2State extends State<LinkStyleButton2> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final isToggled = _getLinkAttributeValue() != null; final isToggled = _getLinkAttributeValue() != null;
return QuillIconButton( return QuillToolbarIconButton(
tooltip: widget.tooltip, tooltip: widget.tooltip,
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,

@ -1,225 +0,0 @@
import 'package:flutter/material.dart';
import '../../../models/documents/attribute.dart';
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 QuillToolbarFontSizeButton extends StatefulWidget {
const QuillToolbarFontSizeButton({
required this.rawItemsMap,
required this.attribute,
required this.controller,
this.onSelected,
@Deprecated('It is not required because of `rawItemsMap`') this.items,
this.iconSize = 40,
this.fillColor,
this.hoverElevation = 1,
this.highlightElevation = 1,
this.iconTheme,
this.afterButtonPressed,
this.tooltip,
this.padding,
this.style,
this.width,
this.initialValue,
this.labelOverflow = TextOverflow.visible,
this.itemHeight,
this.itemPadding,
this.defaultItemColor = Colors.red,
Key? key,
}) : assert(rawItemsMap.length > 0),
assert(initialValue == null || initialValue.length > 0),
super(key: key);
final double iconSize;
final Color? fillColor;
final double hoverElevation;
final double highlightElevation;
@Deprecated('It is not required because of `rawItemsMap`')
final List<PopupMenuEntry<String>>? items;
final Map<String, String> rawItemsMap;
final ValueChanged<String>? onSelected;
final QuillIconTheme? iconTheme;
final Attribute attribute;
final QuillController controller;
final VoidCallback? afterButtonPressed;
final String? tooltip;
final EdgeInsetsGeometry? padding;
final TextStyle? style;
final double? width;
final String? initialValue;
final TextOverflow labelOverflow;
final double? itemHeight;
final EdgeInsets? itemPadding;
final Color? defaultItemColor;
@override
_QuillToolbarFontSizeButtonState createState() =>
_QuillToolbarFontSizeButtonState();
}
class _QuillToolbarFontSizeButtonState
extends State<QuillToolbarFontSizeButton> {
late String _defaultDisplayText;
late String _currentValue;
Style get _selectionStyle => widget.controller.getSelectionStyle();
@override
void initState() {
super.initState();
_currentValue = _defaultDisplayText = widget.initialValue ?? 'Size'.i18n;
widget.controller.addListener(_didChangeEditingValue);
}
@override
void dispose() {
widget.controller.removeListener(_didChangeEditingValue);
super.dispose();
}
@override
void didUpdateWidget(covariant QuillToolbarFontSizeButton oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue);
widget.controller.addListener(_didChangeEditingValue);
}
}
void _didChangeEditingValue() {
final attribute = _selectionStyle.attributes[widget.attribute.key];
if (attribute == null) {
setState(() => _currentValue = _defaultDisplayText);
return;
}
final keyName = _getKeyName(attribute.value);
setState(() => _currentValue = keyName ?? _defaultDisplayText);
}
String? _getKeyName(dynamic value) {
for (final entry in widget.rawItemsMap.entries) {
if (getFontSize(entry.value) == getFontSize(value)) {
return entry.key;
}
}
return null;
}
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints.tightFor(
height: widget.iconSize * 1.81,
width: widget.width,
),
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),
),
),
);
}
Future<void> _showMenu() async {
final popupMenuTheme = PopupMenuTheme.of(context);
final button = context.findRenderObject() as RenderBox;
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
final position = RelativeRect.fromRect(
Rect.fromPoints(
button.localToGlobal(Offset.zero, ancestor: overlay),
button.localToGlobal(button.size.bottomLeft(Offset.zero),
ancestor: overlay),
),
Offset.zero & overlay.size,
);
final newValue = await showMenu<String>(
context: context,
elevation: 4,
items: [
for (final MapEntry<String, String> fontSize
in widget.rawItemsMap.entries)
PopupMenuItem<String>(
key: ValueKey(fontSize.key),
value: fontSize.value,
height: widget.itemHeight ?? kMinInteractiveDimension,
padding: widget.itemPadding,
child: Text(
fontSize.key.toString(),
style: TextStyle(
color: fontSize.value == '0' ? widget.defaultItemColor : null,
),
),
),
],
position: position,
shape: popupMenuTheme.shape,
color: popupMenuTheme.color,
);
if (!mounted) return;
if (newValue == null) {
return;
}
final keyName = _getKeyName(newValue);
setState(() {
_currentValue = keyName ?? _defaultDisplayText;
if (keyName != null) {
widget.controller.formatSelection(Attribute.fromKeyValue(
'size', newValue == '0' ? null : getFontSize(newValue)));
widget.onSelected?.call(newValue);
}
});
}
Widget _buildContent(BuildContext context) {
final theme = Theme.of(context);
final hasFinalWidth = widget.width != null;
return Padding(
padding: widget.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Row(
mainAxisSize: !hasFinalWidth ? MainAxisSize.min : MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
UtilityWidgets.maybeWidget(
enabled: hasFinalWidth,
wrapper: (child) => Expanded(child: child),
child: Text(
_currentValue,
overflow: widget.labelOverflow,
style: widget.style ??
TextStyle(
fontSize: widget.iconSize / 1.15,
color: widget.iconTheme?.iconUnselectedColor ??
theme.iconTheme.color,
),
),
),
const SizedBox(width: 3),
Icon(
Icons.arrow_drop_down,
size: widget.iconSize / 1.15,
color:
widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
)
],
),
);
}
}

@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import '../../../utils/widgets.dart'; import '../../../utils/widgets.dart';
class QuillIconButton extends StatelessWidget { class QuillToolbarIconButton extends StatelessWidget {
const QuillIconButton({ const QuillToolbarIconButton({
required this.onPressed, required this.onPressed,
this.afterPressed, this.afterPressed,
this.icon, this.icon,

@ -6,8 +6,8 @@ import '../../controller.dart';
import '../search_dialog.dart'; import '../search_dialog.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class SearchButton extends StatelessWidget { class QuillToolbarSearchButton extends StatelessWidget {
const SearchButton({ const QuillToolbarSearchButton({
required this.icon, required this.icon,
required this.controller, required this.controller,
this.iconSize = kDefaultIconSize, this.iconSize = kDefaultIconSize,
@ -40,7 +40,7 @@ class SearchButton extends StatelessWidget {
final iconFillColor = final iconFillColor =
iconTheme?.iconUnselectedFillColor ?? (fillColor ?? theme.canvasColor); iconTheme?.iconUnselectedFillColor ?? (fillColor ?? theme.canvasColor);
return QuillIconButton( return QuillToolbarIconButton(
tooltip: tooltip, tooltip: tooltip,
icon: Icon(icon, size: iconSize, color: iconColor), icon: Icon(icon, size: iconSize, color: iconColor),
highlightElevation: 0, highlightElevation: 0,

@ -9,8 +9,8 @@ import '../../controller.dart';
import '../enum.dart'; import '../enum.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class SelectAlignmentButton extends StatefulWidget { class QuillToolbarSelectAlignmentButton extends StatefulWidget {
const SelectAlignmentButton({ const QuillToolbarSelectAlignmentButton({
required this.controller, required this.controller,
this.iconSize = kDefaultIconSize, this.iconSize = kDefaultIconSize,
this.iconTheme, this.iconTheme,
@ -37,10 +37,12 @@ class SelectAlignmentButton extends StatefulWidget {
final EdgeInsetsGeometry? padding; final EdgeInsetsGeometry? padding;
@override @override
_SelectAlignmentButtonState createState() => _SelectAlignmentButtonState(); _QuillToolbarSelectAlignmentButtonState createState() =>
_QuillToolbarSelectAlignmentButtonState();
} }
class _SelectAlignmentButtonState extends State<SelectAlignmentButton> { class _QuillToolbarSelectAlignmentButtonState
extends State<QuillToolbarSelectAlignmentButton> {
Attribute? _value; Attribute? _value;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -164,7 +166,7 @@ class _SelectAlignmentButtonState extends State<SelectAlignmentButton> {
} }
@override @override
void didUpdateWidget(covariant SelectAlignmentButton oldWidget) { void didUpdateWidget(covariant QuillToolbarSelectAlignmentButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue); oldWidget.controller.removeListener(_didChangeEditingValue);

@ -8,8 +8,8 @@ import '../../../utils/widgets.dart';
import '../../controller.dart'; import '../../controller.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class SelectHeaderStyleButton extends StatefulWidget { class QuillToolbarSelectHeaderStyleButton extends StatefulWidget {
const SelectHeaderStyleButton({ const QuillToolbarSelectHeaderStyleButton({
required this.controller, required this.controller,
this.axis = Axis.horizontal, this.axis = Axis.horizontal,
this.iconSize = kDefaultIconSize, this.iconSize = kDefaultIconSize,
@ -34,11 +34,12 @@ class SelectHeaderStyleButton extends StatefulWidget {
final String? tooltip; final String? tooltip;
@override @override
_SelectHeaderStyleButtonState createState() => _QuillToolbarSelectHeaderStyleButtonState createState() =>
_SelectHeaderStyleButtonState(); _QuillToolbarSelectHeaderStyleButtonState();
} }
class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> { class _QuillToolbarSelectHeaderStyleButtonState
extends State<QuillToolbarSelectHeaderStyleButton> {
Attribute? _selectedAttribute; Attribute? _selectedAttribute;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -148,7 +149,8 @@ class _SelectHeaderStyleButtonState extends State<SelectHeaderStyleButton> {
} }
@override @override
void didUpdateWidget(covariant SelectHeaderStyleButton oldWidget) { void didUpdateWidget(
covariant QuillToolbarSelectHeaderStyleButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue); oldWidget.controller.removeListener(_didChangeEditingValue);

@ -7,8 +7,8 @@ import '../../../utils/widgets.dart';
import '../../controller.dart'; import '../../controller.dart';
import '../toolbar.dart'; import '../toolbar.dart';
class ToggleCheckListButton extends StatefulWidget { class QuillToolbarToggleCheckListButton extends StatefulWidget {
const ToggleCheckListButton({ const QuillToolbarToggleCheckListButton({
required this.icon, required this.icon,
required this.controller, required this.controller,
required this.attribute, required this.attribute,
@ -37,10 +37,12 @@ class ToggleCheckListButton extends StatefulWidget {
final String? tooltip; final String? tooltip;
@override @override
_ToggleCheckListButtonState createState() => _ToggleCheckListButtonState(); _QuillToolbarToggleCheckListButtonState createState() =>
_QuillToolbarToggleCheckListButtonState();
} }
class _ToggleCheckListButtonState extends State<ToggleCheckListButton> { class _QuillToolbarToggleCheckListButtonState
extends State<QuillToolbarToggleCheckListButton> {
bool? _isToggled; bool? _isToggled;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => widget.controller.getSelectionStyle();
@ -77,7 +79,7 @@ class _ToggleCheckListButtonState extends State<ToggleCheckListButton> {
} }
@override @override
void didUpdateWidget(covariant ToggleCheckListButton oldWidget) { void didUpdateWidget(covariant QuillToolbarToggleCheckListButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != widget.controller) {
oldWidget.controller.removeListener(_didChangeEditingValue); oldWidget.controller.removeListener(_didChangeEditingValue);

@ -1,8 +1,10 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../../translations.dart';
import '../../../models/documents/attribute.dart'; import '../../../models/documents/attribute.dart';
import '../../../models/documents/style.dart'; import '../../../models/documents/style.dart';
import '../../../models/themes/quill_icon_theme.dart'; import '../../../models/themes/quill_icon_theme.dart';
import '../../../utils/extensions/build_context.dart';
import '../../../utils/widgets.dart'; import '../../../utils/widgets.dart';
import '../../controller.dart'; import '../../controller.dart';
import '../toolbar.dart'; import '../toolbar.dart';
@ -19,84 +21,234 @@ typedef ToggleStyleButtonBuilder = Widget Function(
QuillIconTheme? iconTheme, QuillIconTheme? iconTheme,
]); ]);
class ToggleStyleButton extends StatefulWidget { class QuillToolbarToggleStyleButton extends StatefulWidget {
const ToggleStyleButton({ const QuillToolbarToggleStyleButton({
required this.attribute, required this.options,
required this.icon,
required this.controller, required this.controller,
this.iconSize = kDefaultIconSize, required this.attribute,
this.fillColor, // required this.icon,
this.childBuilder = defaultToggleStyleButtonBuilder, // required this.controller,
this.iconTheme, // this.iconSize = kDefaultIconSize,
this.afterButtonPressed, // this.fillColor,
this.tooltip, // this.childBuilder = defaultToggleStyleButtonBuilder,
Key? key, // this.iconTheme,
}) : super(key: key); // this.afterButtonPressed,
// this.tooltip,
super.key,
});
final Attribute attribute; final Attribute attribute;
final IconData icon; // final IconData icon;
final double iconSize; // final double iconSize;
final Color? fillColor; // final Color? fillColor;
final QuillController controller; // final QuillController controller;
final ToggleStyleButtonBuilder childBuilder; // final ToggleStyleButtonBuilder childBuilder;
///Specify an icon theme for the icons in the toolbar // ///Specify an icon theme for the icons in the toolbar
final QuillIconTheme? iconTheme; // final QuillIconTheme? iconTheme;
final VoidCallback? afterButtonPressed; // final VoidCallback? afterButtonPressed;
final String? tooltip; // final String? tooltip;
final QuillToolbarToggleStyleButtonOptions options;
/// Since we can't get the state from the instace of the widget for comparing
/// in [didUpdateWidget] then we will have to store reference here
final QuillController controller;
@override @override
_ToggleStyleButtonState createState() => _ToggleStyleButtonState(); _QuillToolbarToggleStyleButtonState createState() =>
_QuillToolbarToggleStyleButtonState();
} }
class _ToggleStyleButtonState extends State<ToggleStyleButton> { class _QuillToolbarToggleStyleButtonState
extends State<QuillToolbarToggleStyleButton> {
/// Since it's not safe to call anything related to the context in dispose
/// then we will save a reference to the [controller]
/// and update it in [didChangeDependencies]
/// and use it in dispose method
late QuillController _controller;
bool? _isToggled; bool? _isToggled;
Style get _selectionStyle => widget.controller.getSelectionStyle(); Style get _selectionStyle => controller.getSelectionStyle();
QuillToolbarToggleStyleButtonOptions get options {
return widget.options;
}
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_isToggled = _getIsToggled(_selectionStyle.attributes); _isToggled = _getIsToggled(_selectionStyle.attributes);
widget.controller.addListener(_didChangeEditingValue); controller.addListener(_didChangeEditingValue);
}
QuillController get controller {
return options.controller ?? widget.controller;
}
double get iconSize {
final baseFontSize =
context.requireQuillToolbarBaseButtonOptions.globalIconSize;
final iconSize = options.iconSize;
return iconSize ?? baseFontSize;
}
VoidCallback? get afterButtonPressed {
return options.afterButtonPressed ??
context.requireQuillToolbarBaseButtonOptions.afterButtonPressed;
}
QuillIconTheme? get iconTheme {
return options.iconTheme ??
context.requireQuillToolbarBaseButtonOptions.iconTheme;
}
String? get _defaultTooltip {
switch (widget.attribute.key) {
case 'bold':
return 'Bold'.i18n;
case 'script':
if (widget.attribute.value == ScriptAttributes.sub.value) {
return 'Subscript'.i18n;
}
return 'Superscript'.i18n;
case 'italic':
return 'Italic'.i18n;
case 'small':
return 'Small'.i18n;
case 'underline':
return 'Underline'.i18n;
case 'strike':
return 'Strike through'.i18n;
case 'code':
return 'Inline code'.i18n;
case 'rtl':
return 'Text direction'.i18n;
case 'list':
if (widget.attribute.value == 'bullet') {
return 'Bullet list'.i18n;
}
return 'Numbered list'.i18n;
case 'code-block':
return 'Code block'.i18n;
case 'blockquote':
return 'Quote'.i18n;
default:
throw ArgumentError(
'Could not find the default tooltip for '
'${widget.attribute.toString()}',
);
}
}
String? get tooltip {
return options.tooltip ??
context.requireQuillToolbarBaseButtonOptions.tooltip ??
_defaultTooltip;
}
IconData get _defaultIconData {
switch (widget.attribute.key) {
case 'bold':
return Icons.format_bold;
case 'script':
if (widget.attribute.value == ScriptAttributes.sub.value) {
return Icons.subscript;
}
return Icons.superscript;
case 'italic':
return Icons.format_italic;
case 'small':
return Icons.format_size;
case 'underline':
return Icons.format_underline;
case 'strike':
return Icons.format_strikethrough;
case 'code':
return Icons.code;
case 'rtl':
return Icons.format_textdirection_r_to_l;
case 'list':
if (widget.attribute.value == 'bullet') {
return Icons.format_list_bulleted;
}
return Icons.format_list_numbered;
case 'code-block':
return Icons.code;
case 'blockquote':
return Icons.format_quote;
default:
throw ArgumentError(
'Could not find the icon for ${widget.attribute.toString()}',
);
}
}
IconData get iconData {
return options.iconData ??
context.requireQuillToolbarBaseButtonOptions.iconData ??
_defaultIconData;
}
void _onPressed() {
_toggleAttribute();
options.afterButtonPressed?.call();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final childBuilder = options.childBuilder ??
context.requireQuillToolbarBaseButtonOptions.childBuilder;
if (childBuilder != null) {
return childBuilder(
options,
QuillToolbarToggleStyleButtonExtraOptions(
context: context,
controller: controller,
onPressed: _onPressed,
),
);
}
return UtilityWidgets.maybeTooltip( return UtilityWidgets.maybeTooltip(
message: widget.tooltip, message: tooltip,
child: widget.childBuilder( child: defaultToggleStyleButtonBuilder(
context, context,
widget.attribute, widget.attribute,
widget.icon, iconData,
widget.fillColor, options.fillColor,
_isToggled, _isToggled,
_toggleAttribute, _toggleAttribute,
widget.afterButtonPressed, options.afterButtonPressed,
widget.iconSize, iconSize,
widget.iconTheme, iconTheme,
), ),
); );
} }
@override @override
void didUpdateWidget(covariant ToggleStyleButton oldWidget) { void didUpdateWidget(covariant QuillToolbarToggleStyleButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (oldWidget.controller != controller) {
oldWidget.controller.removeListener(_didChangeEditingValue); oldWidget.controller.removeListener(_didChangeEditingValue);
widget.controller.addListener(_didChangeEditingValue); widget.controller.addListener(_didChangeEditingValue);
_isToggled = _getIsToggled(_selectionStyle.attributes); _isToggled = _getIsToggled(_selectionStyle.attributes);
} }
} }
@override
void didChangeDependencies() {
super.didChangeDependencies();
_controller = controller;
}
@override @override
void dispose() { void dispose() {
widget.controller.removeListener(_didChangeEditingValue); _controller.removeListener(_didChangeEditingValue);
super.dispose(); super.dispose();
} }
@ -117,9 +269,9 @@ class _ToggleStyleButtonState extends State<ToggleStyleButton> {
} }
void _toggleAttribute() { void _toggleAttribute() {
widget.controller.formatSelection(_isToggled! controller.formatSelection(
? Attribute.clone(widget.attribute, null) _isToggled! ? Attribute.clone(widget.attribute, null) : widget.attribute,
: widget.attribute); );
} }
} }
@ -151,7 +303,7 @@ Widget defaultToggleStyleButtonBuilder(
theme.canvasColor) //Unselected icon fill color : theme.canvasColor) //Unselected icon fill color :
: (iconTheme?.disabledIconFillColor ?? : (iconTheme?.disabledIconFillColor ??
(fillColor ?? theme.canvasColor)); //Disabled icon fill color (fillColor ?? theme.canvasColor)); //Disabled icon fill color
return QuillIconButton( return QuillToolbarIconButton(
highlightElevation: 0, highlightElevation: 0,
hoverElevation: 0, hoverElevation: 0,
size: iconSize * kIconButtonFactor, size: iconSize * kIconButtonFactor,

@ -12,11 +12,11 @@ export 'buttons/clear_format.dart';
export 'buttons/color.dart'; export 'buttons/color.dart';
export 'buttons/custom_button.dart'; export 'buttons/custom_button.dart';
export 'buttons/font_family.dart'; export 'buttons/font_family.dart';
export 'buttons/font_size.dart';
export 'buttons/history.dart'; export 'buttons/history.dart';
export 'buttons/indent.dart'; export 'buttons/indent.dart';
export 'buttons/link_style.dart'; export 'buttons/link_style.dart';
export 'buttons/link_style2.dart'; export 'buttons/link_style2.dart';
export 'buttons/quill_font_size.dart';
export 'buttons/quill_icon.dart'; export 'buttons/quill_icon.dart';
export 'buttons/search.dart'; export 'buttons/search.dart';
export 'buttons/select_alignment.dart'; export 'buttons/select_alignment.dart';
@ -48,7 +48,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
factory QuillToolbar.basic({ factory QuillToolbar.basic({
Axis axis = Axis.horizontal, Axis axis = Axis.horizontal,
// double toolbarIconSize = kDefaultIconSize,
double toolbarSectionSpacing = kToolbarSectionSpacing, double toolbarSectionSpacing = kToolbarSectionSpacing,
WrapAlignment toolbarIconAlignment = WrapAlignment.center, WrapAlignment toolbarIconAlignment = WrapAlignment.center,
WrapCrossAlignment toolbarIconCrossAlignment = WrapCrossAlignment.center, WrapCrossAlignment toolbarIconCrossAlignment = WrapCrossAlignment.center,
@ -88,9 +87,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
/// The decoration to use for the toolbar. /// The decoration to use for the toolbar.
Decoration? decoration, Decoration? decoration,
///Map of font sizes in string
Map<String, String>? fontSizeValues,
/// Toolbar items to display for controls of embed blocks /// Toolbar items to display for controls of embed blocks
List<EmbedButtonBuilder>? embedButtons, List<EmbedButtonBuilder>? embedButtons,
@ -161,20 +157,9 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
showLink || showSearchButton showLink || showSearchButton
]; ];
//default font size values
final fontSizes = fontSizeValues ??
{
'Small'.i18n: 'small',
'Large'.i18n: 'large',
'Huge'.i18n: 'huge',
'Clear'.i18n: '0'
};
//default button tooltips //default button tooltips
final buttonTooltips = tooltips ?? final buttonTooltips = tooltips ??
<ToolbarButtons, String>{ <ToolbarButtons, String>{
// ToolbarButtons.undo: 'Undo'.i18n,
// ToolbarButtons.redo: 'Redo'.i18n,
ToolbarButtons.fontFamily: 'Font family'.i18n, ToolbarButtons.fontFamily: 'Font family'.i18n,
ToolbarButtons.fontSize: 'Font size'.i18n, ToolbarButtons.fontSize: 'Font size'.i18n,
ToolbarButtons.bold: 'Bold'.i18n, ToolbarButtons.bold: 'Bold'.i18n,
@ -235,99 +220,130 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
if (showFontFamily) if (showFontFamily)
QuillToolbarFontFamilyButton( QuillToolbarFontFamilyButton(
options: toolbarConfigurations.buttonOptions.fontFamily, options: toolbarConfigurations.buttonOptions.fontFamily,
controller:
toolbarConfigurations.buttonOptions.fontFamily.controller ??
context.requireQuillController,
), ),
if (showFontSize) if (showFontSize)
QuillToolbarFontSizeButton( QuillToolbarFontSizeButton(
iconTheme: iconTheme, options: toolbarConfigurations.buttonOptions.fontSize,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.fontSize], toolbarConfigurations.buttonOptions.fontFamily.controller ??
attribute: Attribute.size, context.requireQuillController,
controller: controller,
rawItemsMap: fontSizes,
afterButtonPressed: afterButtonPressed,
), ),
if (showBoldButton) if (showBoldButton)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.bold, attribute: Attribute.bold,
icon: Icons.format_bold, options: toolbarConfigurations.buttonOptions.bold,
iconSize: toolbarIconSize, controller: toolbarConfigurations.buttonOptions.bold.controller ??
tooltip: buttonTooltips[ToolbarButtons.bold], context.requireQuillController,
controller: controller, // icon: Icons.format_bold,
iconTheme: iconTheme, // iconSize: toolbarIconSize,
afterButtonPressed: afterButtonPressed, // tooltip: buttonTooltips[ToolbarButtons.bold],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showSubscript) if (showSubscript)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.subscript, attribute: Attribute.subscript,
icon: Icons.subscript, options: toolbarConfigurations.buttonOptions.subscript,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.subscript], toolbarConfigurations.buttonOptions.subscript.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.subscript,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.subscript],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showSuperscript) if (showSuperscript)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.superscript, attribute: Attribute.superscript,
icon: Icons.superscript, options: toolbarConfigurations.buttonOptions.superscript,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.superscript], toolbarConfigurations.buttonOptions.superscript.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.superscript,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.superscript],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showItalicButton) if (showItalicButton)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.italic, attribute: Attribute.italic,
icon: Icons.format_italic, options: toolbarConfigurations.buttonOptions.italic,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.italic], toolbarConfigurations.buttonOptions.italic.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.format_italic,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.italic],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showSmallButton) if (showSmallButton)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.small, attribute: Attribute.small,
icon: Icons.format_size, options: toolbarConfigurations.buttonOptions.small,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.small], toolbarConfigurations.buttonOptions.small.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.format_size,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.small],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showUnderLineButton) if (showUnderLineButton)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.underline, attribute: Attribute.underline,
icon: Icons.format_underline, options: toolbarConfigurations.buttonOptions.underLine,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.underline], toolbarConfigurations.buttonOptions.underLine.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.format_underline,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.underline],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showStrikeThrough) if (showStrikeThrough)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.strikeThrough, attribute: Attribute.strikeThrough,
icon: Icons.format_strikethrough, options: toolbarConfigurations.buttonOptions.strikeThrough,
iconSize: toolbarIconSize, controller: toolbarConfigurations
tooltip: buttonTooltips[ToolbarButtons.strikeThrough], .buttonOptions.strikeThrough.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.format_strikethrough,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.strikeThrough],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showInlineCode) if (showInlineCode)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.inlineCode, attribute: Attribute.inlineCode,
icon: Icons.code, options: toolbarConfigurations.buttonOptions.inlineCode,
iconSize: toolbarIconSize, controller:
tooltip: buttonTooltips[ToolbarButtons.inlineCode], toolbarConfigurations.buttonOptions.inlineCode.controller ??
controller: controller, context.requireQuillController,
iconTheme: iconTheme, // icon: Icons.code,
afterButtonPressed: afterButtonPressed, // iconSize: toolbarIconSize,
// tooltip: buttonTooltips[ToolbarButtons.inlineCode],
// controller: controller,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showColorButton) if (showColorButton)
ColorButton( QuillToolbarColorButton(
icon: Icons.color_lens, icon: Icons.color_lens,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
tooltip: buttonTooltips[ToolbarButtons.color], tooltip: buttonTooltips[ToolbarButtons.color],
@ -339,7 +355,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
context.requireQuillSharedConfigurations.dialogBarrierColor, context.requireQuillSharedConfigurations.dialogBarrierColor,
), ),
if (showBackgroundColorButton) if (showBackgroundColorButton)
ColorButton( QuillToolbarColorButton(
icon: Icons.format_color_fill, icon: Icons.format_color_fill,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
tooltip: buttonTooltips[ToolbarButtons.backgroundColor], tooltip: buttonTooltips[ToolbarButtons.backgroundColor],
@ -351,7 +367,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
context.requireQuillSharedConfigurations.dialogBarrierColor, context.requireQuillSharedConfigurations.dialogBarrierColor,
), ),
if (showClearFormat) if (showClearFormat)
ClearFormatButton( QuillToolbarClearFormatButton(
icon: Icons.format_clear, icon: Icons.format_clear,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
tooltip: buttonTooltips[ToolbarButtons.clearFormat], tooltip: buttonTooltips[ToolbarButtons.clearFormat],
@ -369,13 +385,13 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
isButtonGroupShown[3] || isButtonGroupShown[3] ||
isButtonGroupShown[4] || isButtonGroupShown[4] ||
isButtonGroupShown[5])) isButtonGroupShown[5]))
QuillDivider( QuillToolbarDivider(
axis, axis,
color: sectionDividerColor, color: sectionDividerColor,
space: sectionDividerSpace, space: sectionDividerSpace,
), ),
if (showAlignmentButtons) if (showAlignmentButtons)
SelectAlignmentButton( QuillToolbarSelectAlignmentButton(
controller: controller, controller: controller,
tooltips: Map.of(buttonTooltips) tooltips: Map.of(buttonTooltips)
..removeWhere((key, value) => ![ ..removeWhere((key, value) => ![
@ -393,14 +409,18 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
afterButtonPressed: afterButtonPressed, afterButtonPressed: afterButtonPressed,
), ),
if (showDirection) if (showDirection)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.rtl, attribute: Attribute.rtl,
tooltip: buttonTooltips[ToolbarButtons.direction], options: toolbarConfigurations.buttonOptions.direction,
controller: controller, controller:
icon: Icons.format_textdirection_r_to_l, toolbarConfigurations.buttonOptions.direction.controller ??
iconSize: toolbarIconSize, context.requireQuillController,
iconTheme: iconTheme, // tooltip: buttonTooltips[ToolbarButtons.direction],
afterButtonPressed: afterButtonPressed, // controller: controller,
// icon: Icons.format_textdirection_r_to_l,
// iconSize: toolbarIconSize,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showDividers && if (showDividers &&
isButtonGroupShown[1] && isButtonGroupShown[1] &&
@ -408,13 +428,13 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
isButtonGroupShown[3] || isButtonGroupShown[3] ||
isButtonGroupShown[4] || isButtonGroupShown[4] ||
isButtonGroupShown[5])) isButtonGroupShown[5]))
QuillDivider( QuillToolbarDivider(
axis, axis,
color: sectionDividerColor, color: sectionDividerColor,
space: sectionDividerSpace, space: sectionDividerSpace,
), ),
if (showHeaderStyle) if (showHeaderStyle)
SelectHeaderStyleButton( QuillToolbarSelectHeaderStyleButton(
tooltip: buttonTooltips[ToolbarButtons.headerStyle], tooltip: buttonTooltips[ToolbarButtons.headerStyle],
controller: controller, controller: controller,
axis: axis, axis: axis,
@ -428,33 +448,41 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
(isButtonGroupShown[3] || (isButtonGroupShown[3] ||
isButtonGroupShown[4] || isButtonGroupShown[4] ||
isButtonGroupShown[5])) isButtonGroupShown[5]))
QuillDivider( QuillToolbarDivider(
axis, axis,
color: sectionDividerColor, color: sectionDividerColor,
space: sectionDividerSpace, space: sectionDividerSpace,
), ),
if (showListNumbers) if (showListNumbers)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.ol, attribute: Attribute.ol,
tooltip: buttonTooltips[ToolbarButtons.listNumbers], options: toolbarConfigurations.buttonOptions.listNumbers,
controller: controller, controller:
icon: Icons.format_list_numbered, toolbarConfigurations.buttonOptions.listNumbers.controller ??
iconSize: toolbarIconSize, context.requireQuillController,
iconTheme: iconTheme, // tooltip: buttonTooltips[ToolbarButtons.listNumbers],
afterButtonPressed: afterButtonPressed, // controller: controller,
// icon: Icons.format_list_numbered,
// iconSize: toolbarIconSize,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showListBullets) if (showListBullets)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.ul, attribute: Attribute.ul,
tooltip: buttonTooltips[ToolbarButtons.listBullets], options: toolbarConfigurations.buttonOptions.listBullets,
controller: controller, controller:
icon: Icons.format_list_bulleted, toolbarConfigurations.buttonOptions.listBullets.controller ??
iconSize: toolbarIconSize, context.requireQuillController,
iconTheme: iconTheme, // tooltip: buttonTooltips[ToolbarButtons.listBullets],
afterButtonPressed: afterButtonPressed, // controller: controller,
// icon: Icons.format_list_bulleted,
// iconSize: toolbarIconSize,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showListCheck) if (showListCheck)
ToggleCheckListButton( QuillToolbarToggleCheckListButton(
attribute: Attribute.unchecked, attribute: Attribute.unchecked,
tooltip: buttonTooltips[ToolbarButtons.listChecks], tooltip: buttonTooltips[ToolbarButtons.listChecks],
controller: controller, controller: controller,
@ -464,32 +492,40 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
afterButtonPressed: afterButtonPressed, afterButtonPressed: afterButtonPressed,
), ),
if (showCodeBlock) if (showCodeBlock)
ToggleStyleButton( QuillToolbarToggleStyleButton(
attribute: Attribute.codeBlock, attribute: Attribute.codeBlock,
tooltip: buttonTooltips[ToolbarButtons.codeBlock], options: toolbarConfigurations.buttonOptions.codeBlock,
controller: controller, controller:
icon: Icons.code, toolbarConfigurations.buttonOptions.codeBlock.controller ??
iconSize: toolbarIconSize, context.requireQuillController,
iconTheme: iconTheme, // tooltip: buttonTooltips[ToolbarButtons.codeBlock],
afterButtonPressed: afterButtonPressed, // controller: controller,
// icon: Icons.code,
// iconSize: toolbarIconSize,
// iconTheme: iconTheme,
// afterButtonPressed: afterButtonPressed,
), ),
if (showDividers && if (showDividers &&
isButtonGroupShown[3] && isButtonGroupShown[3] &&
(isButtonGroupShown[4] || isButtonGroupShown[5])) (isButtonGroupShown[4] || isButtonGroupShown[5]))
QuillDivider(axis, QuillToolbarDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace), color: sectionDividerColor, space: sectionDividerSpace),
if (showQuote) if (showQuote)
ToggleStyleButton( QuillToolbarToggleStyleButton(
options: toolbarConfigurations.buttonOptions.quote,
controller:
toolbarConfigurations.buttonOptions.quote.controller ??
context.requireQuillController,
attribute: Attribute.blockQuote, attribute: Attribute.blockQuote,
tooltip: buttonTooltips[ToolbarButtons.quote], // tooltip: buttonTooltips[ToolbarButtons.quote],
controller: controller, // controller: controller,
icon: Icons.format_quote, // icon: Icons.format_quote,
iconSize: toolbarIconSize, // iconSize: toolbarIconSize,
iconTheme: iconTheme, // iconTheme: iconTheme,
afterButtonPressed: afterButtonPressed, // afterButtonPressed: afterButtonPressed,
), ),
if (showIndent) if (showIndent)
IndentButton( QuillToolbarIndentButton(
icon: Icons.format_indent_increase, icon: Icons.format_indent_increase,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
tooltip: buttonTooltips[ToolbarButtons.indentIncrease], tooltip: buttonTooltips[ToolbarButtons.indentIncrease],
@ -499,7 +535,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
afterButtonPressed: afterButtonPressed, afterButtonPressed: afterButtonPressed,
), ),
if (showIndent) if (showIndent)
IndentButton( QuillToolbarIndentButton(
icon: Icons.format_indent_decrease, icon: Icons.format_indent_decrease,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
tooltip: buttonTooltips[ToolbarButtons.indentDecrease], tooltip: buttonTooltips[ToolbarButtons.indentDecrease],
@ -509,10 +545,10 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
afterButtonPressed: afterButtonPressed, afterButtonPressed: afterButtonPressed,
), ),
if (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5]) if (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5])
QuillDivider(axis, QuillToolbarDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace), color: sectionDividerColor, space: sectionDividerSpace),
if (showLink) if (showLink)
LinkStyleButton( QuillToolbarLinkStyleButton(
tooltip: buttonTooltips[ToolbarButtons.link], tooltip: buttonTooltips[ToolbarButtons.link],
controller: controller, controller: controller,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
@ -525,7 +561,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
context.requireQuillSharedConfigurations.dialogBarrierColor, context.requireQuillSharedConfigurations.dialogBarrierColor,
), ),
if (showSearchButton) if (showSearchButton)
SearchButton( QuillToolbarSearchButton(
icon: Icons.search, icon: Icons.search,
iconSize: toolbarIconSize, iconSize: toolbarIconSize,
dialogBarrierColor: dialogBarrierColor:
@ -538,7 +574,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
), ),
if (customButtons.isNotEmpty) if (customButtons.isNotEmpty)
if (showDividers) if (showDividers)
QuillDivider( QuillToolbarDivider(
axis, axis,
color: sectionDividerColor, color: sectionDividerColor,
space: sectionDividerSpace, space: sectionDividerSpace,
@ -628,7 +664,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
height: axis == Axis.horizontal ? toolbarSize : null, height: axis == Axis.horizontal ? toolbarSize : null,
width: axis == Axis.vertical ? toolbarSize : null, width: axis == Axis.vertical ? toolbarSize : null,
), ),
child: ArrowIndicatedButtonList( child: QuillToolbarArrowIndicatedButtonList(
axis: axis, axis: axis,
buttons: childrenBuilder(context), buttons: childrenBuilder(context),
), ),
@ -641,8 +677,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
/// ///
/// It can be used outside of this package, for example when user does not use /// It can be used outside of this package, for example when user does not use
/// [QuillToolbar.basic] and compose toolbar's children on its own. /// [QuillToolbar.basic] and compose toolbar's children on its own.
class QuillDivider extends StatelessWidget { class QuillToolbarDivider extends StatelessWidget {
const QuillDivider( const QuillToolbarDivider(
this.axis, { this.axis, {
Key? key, Key? key,
this.color, this.color,
@ -650,11 +686,11 @@ class QuillDivider extends StatelessWidget {
}) : super(key: key); }) : super(key: key);
/// Provides a horizontal divider for vertical toolbar. /// Provides a horizontal divider for vertical toolbar.
const QuillDivider.horizontal({Color? color, double? space}) const QuillToolbarDivider.horizontal({Color? color, double? space})
: this(Axis.horizontal, color: color, space: space); : this(Axis.horizontal, color: color, space: space);
/// Provides a horizontal divider for horizontal toolbar. /// Provides a horizontal divider for horizontal toolbar.
const QuillDivider.vertical({Color? color, double? space}) const QuillToolbarDivider.vertical({Color? color, double? space})
: this(Axis.vertical, color: color, space: space); : this(Axis.vertical, color: color, space: space);
/// The axis along which the toolbar is. /// The axis along which the toolbar is.

@ -1,6 +1,6 @@
name: flutter_quill name: flutter_quill
description: A rich text editor built for the modern Android, iOS, web and desktop platforms. It is the WYSIWYG editor and a Quill component for Flutter. description: A rich text editor built for the modern Android, iOS, web and desktop platforms. It is the WYSIWYG editor and a Quill component for Flutter.
version: 7.6.1 version: 7.7.0
homepage: https://1o24bbs.com/c/bulletjournal/108 homepage: https://1o24bbs.com/c/bulletjournal/108
repository: https://github.com/singerdmx/flutter-quill repository: https://github.com/singerdmx/flutter-quill
platforms: platforms:

@ -30,21 +30,21 @@ void main() {
final builtinFinder = find.descendant( final builtinFinder = find.descendant(
of: find.byType(QuillToolbarHistoryButton), of: find.byType(QuillToolbarHistoryButton),
matching: find.byType(QuillIconButton), matching: find.byType(QuillToolbarIconButton),
matchRoot: true, matchRoot: true,
); );
expect(builtinFinder, findsOneWidget); expect(builtinFinder, findsOneWidget);
final builtinButton = final builtinButton =
builtinFinder.evaluate().first.widget as QuillIconButton; builtinFinder.evaluate().first.widget as QuillToolbarIconButton;
final customFinder = find.descendant( final customFinder = find.descendant(
of: find.byType(QuillToolbar), of: find.byType(QuillToolbar),
matching: find.byWidgetPredicate((widget) => matching: find.byWidgetPredicate((widget) =>
widget is QuillIconButton && widget.tooltip == tooltip), widget is QuillToolbarIconButton && widget.tooltip == tooltip),
matchRoot: true); matchRoot: true);
expect(customFinder, findsOneWidget); expect(customFinder, findsOneWidget);
final customButton = final customButton =
customFinder.evaluate().first.widget as QuillIconButton; customFinder.evaluate().first.widget as QuillToolbarIconButton;
expect(customButton.fillColor, equals(builtinButton.fillColor)); expect(customButton.fillColor, equals(builtinButton.fillColor));
}); });

Loading…
Cancel
Save