Bug fixes && Refactor more buttons

pull/1452/head
Ahmed Hnewa 2 years ago
parent 55f5101ccc
commit f4266ac326
No known key found for this signature in database
GPG Key ID: C488CC70BBCEF0D1
  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. 82
      lib/src/widgets/toolbar/buttons/font_family.dart
  12. 4
      lib/src/widgets/toolbar/buttons/history.dart
  13. 237
      lib/src/widgets/toolbar/buttons/quill_font_size.dart
  14. 216
      lib/src/widgets/toolbar/buttons/toggle_style.dart
  15. 236
      lib/src/widgets/toolbar/toolbar.dart
  16. 2
      pubspec.yaml

@ -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;
} }

@ -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,
) )
], ],
), ),

@ -86,12 +86,14 @@ 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,
), ),
); );
} }

@ -1,61 +1,25 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../../../models/documents/attribute.dart'; import '../../../../extensions.dart';
import '../../../models/documents/style.dart'; import '../../../../flutter_quill.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/font.dart'; import '../../../utils/font.dart';
import '../../../utils/widgets.dart';
import '../../controller.dart';
class QuillToolbarFontSizeButton extends StatefulWidget { class QuillToolbarFontSizeButton extends StatefulWidget {
const QuillToolbarFontSizeButton({ QuillToolbarFontSizeButton({
required this.rawItemsMap, required this.options,
required this.attribute,
required this.controller, required this.controller,
this.onSelected, super.key,
@Deprecated('It is not required because of `rawItemsMap`') this.items, }) : assert(options.rawItemsMap?.isNotEmpty ?? true),
this.iconSize = 40, assert(options.initialValue == null ||
this.fillColor, (options.initialValue?.isNotEmpty ?? true));
this.hoverElevation = 1,
this.highlightElevation = 1, final QuillToolbarFontSizeButtonOptions options;
this.iconTheme,
this.afterButtonPressed, /// Since we can't get the state from the instace of the widget for comparing
this.tooltip, /// in [didUpdateWidget] then we will have to store reference here
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 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 @override
_QuillToolbarFontSizeButtonState createState() => _QuillToolbarFontSizeButtonState createState() =>
@ -64,34 +28,79 @@ class QuillToolbarFontSizeButton extends StatefulWidget {
class _QuillToolbarFontSizeButtonState class _QuillToolbarFontSizeButtonState
extends State<QuillToolbarFontSizeButton> { extends State<QuillToolbarFontSizeButton> {
late String _defaultDisplayText; String _currentValue = '';
late String _currentValue;
Style get _selectionStyle => widget.controller.getSelectionStyle(); 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 @override
void initState() { void initState() {
super.initState(); super.initState();
_currentValue = _defaultDisplayText = widget.initialValue ?? 'Size'.i18n;
widget.controller.addListener(_didChangeEditingValue); _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 @override
void dispose() { void dispose() {
widget.controller.removeListener(_didChangeEditingValue); _controller.removeListener(_didChangeEditingValue);
super.dispose(); super.dispose();
} }
@override @override
void didUpdateWidget(covariant QuillToolbarFontSizeButton oldWidget) { void didUpdateWidget(covariant QuillToolbarFontSizeButton oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
if (oldWidget.controller != widget.controller) { if (widget.controller == controller) {
oldWidget.controller.removeListener(_didChangeEditingValue); return;
widget.controller.addListener(_didChangeEditingValue);
} }
controller
..removeListener(_didChangeEditingValue)
..addListener(_didChangeEditingValue);
} }
void _didChangeEditingValue() { void _didChangeEditingValue() {
final attribute = _selectionStyle.attributes[widget.attribute.key]; final attribute = _selectionStyle.attributes[options.attribute.key];
if (attribute == null) { if (attribute == null) {
setState(() => _currentValue = _defaultDisplayText); setState(() => _currentValue = _defaultDisplayText);
return; return;
@ -101,7 +110,7 @@ class _QuillToolbarFontSizeButtonState
} }
String? _getKeyName(dynamic value) { String? _getKeyName(dynamic value) {
for (final entry in widget.rawItemsMap.entries) { for (final entry in rawItemsMap.entries) {
if (getFontSize(entry.value) == getFontSize(value)) { if (getFontSize(entry.value) == getFontSize(value)) {
return entry.key; return entry.key;
} }
@ -109,29 +118,79 @@ class _QuillToolbarFontSizeButtonState
return null; 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 @override
Widget build(BuildContext context) { 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( return ConstrainedBox(
constraints: BoxConstraints.tightFor( constraints: BoxConstraints.tightFor(
height: widget.iconSize * 1.81, height: iconSize * 1.81,
width: widget.width, width: options.width,
), ),
child: UtilityWidgets.maybeTooltip( child: UtilityWidgets.maybeTooltip(
message: widget.tooltip, message: tooltip,
child: RawMaterialButton( child: RawMaterialButton(
visualDensity: VisualDensity.compact, visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: borderRadius: BorderRadius.circular(iconTheme?.borderRadius ?? 2),
BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2),
), ),
fillColor: widget.fillColor, fillColor: options.fillColor,
elevation: 0, elevation: 0,
hoverElevation: widget.hoverElevation, hoverElevation: options.hoverElevation,
highlightElevation: widget.hoverElevation, highlightElevation: options.hoverElevation,
onPressed: () { onPressed: _onPressed,
_showMenu();
widget.afterButtonPressed?.call();
},
child: _buildContent(context), child: _buildContent(context),
), ),
), ),
@ -154,17 +213,16 @@ class _QuillToolbarFontSizeButtonState
context: context, context: context,
elevation: 4, elevation: 4,
items: [ items: [
for (final MapEntry<String, String> fontSize for (final MapEntry<String, String> fontSize in rawItemsMap.entries)
in widget.rawItemsMap.entries)
PopupMenuItem<String>( PopupMenuItem<String>(
key: ValueKey(fontSize.key), key: ValueKey(fontSize.key),
value: fontSize.value, value: fontSize.value,
height: widget.itemHeight ?? kMinInteractiveDimension, height: options.itemHeight ?? kMinInteractiveDimension,
padding: widget.itemPadding, padding: options.itemPadding,
child: Text( child: Text(
fontSize.key.toString(), fontSize.key.toString(),
style: TextStyle( style: TextStyle(
color: fontSize.value == '0' ? widget.defaultItemColor : null, color: fontSize.value == '0' ? options.defaultItemColor : null,
), ),
), ),
), ),
@ -181,18 +239,18 @@ class _QuillToolbarFontSizeButtonState
setState(() { setState(() {
_currentValue = keyName ?? _defaultDisplayText; _currentValue = keyName ?? _defaultDisplayText;
if (keyName != null) { if (keyName != null) {
widget.controller.formatSelection(Attribute.fromKeyValue( controller.formatSelection(Attribute.fromKeyValue(
'size', newValue == '0' ? null : getFontSize(newValue))); 'size', newValue == '0' ? null : getFontSize(newValue)));
widget.onSelected?.call(newValue); options.onSelected?.call(newValue);
} }
}); });
} }
Widget _buildContent(BuildContext context) { Widget _buildContent(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final hasFinalWidth = widget.width != null; final hasFinalWidth = options.width != null;
return Padding( return Padding(
padding: widget.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0), padding: options.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Row( child: Row(
mainAxisSize: !hasFinalWidth ? MainAxisSize.min : MainAxisSize.max, mainAxisSize: !hasFinalWidth ? MainAxisSize.min : MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -202,21 +260,20 @@ class _QuillToolbarFontSizeButtonState
wrapper: (child) => Expanded(child: child), wrapper: (child) => Expanded(child: child),
child: Text( child: Text(
_currentValue, _currentValue,
overflow: widget.labelOverflow, overflow: options.labelOverflow,
style: widget.style ?? style: options.style ??
TextStyle( TextStyle(
fontSize: widget.iconSize / 1.15, fontSize: iconSize / 1.15,
color: widget.iconTheme?.iconUnselectedColor ?? color:
theme.iconTheme.color, iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
), ),
), ),
), ),
const SizedBox(width: 3), const SizedBox(width: 3),
Icon( Icon(
Icons.arrow_drop_down, Icons.arrow_drop_down,
size: widget.iconSize / 1.15, size: iconSize / 1.15,
color: color: iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color,
) )
], ],
), ),

@ -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';
@ -21,65 +23,207 @@ typedef ToggleStyleButtonBuilder = Widget Function(
class ToggleStyleButton extends StatefulWidget { class ToggleStyleButton extends StatefulWidget {
const ToggleStyleButton({ const ToggleStyleButton({
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(); _ToggleStyleButtonState createState() => _ToggleStyleButtonState();
} }
class _ToggleStyleButtonState extends State<ToggleStyleButton> { class _ToggleStyleButtonState extends State<ToggleStyleButton> {
/// 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,
), ),
); );
} }
@ -87,16 +231,22 @@ class _ToggleStyleButtonState extends State<ToggleStyleButton> {
@override @override
void didUpdateWidget(covariant ToggleStyleButton oldWidget) { void didUpdateWidget(covariant ToggleStyleButton 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 +267,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); );
} }
} }

@ -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,96 +220,127 @@ 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( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleStyleButton(
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( ColorButton(
@ -395,12 +411,16 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
if (showDirection) if (showDirection)
ToggleStyleButton( ToggleStyleButton(
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] &&
@ -436,22 +456,30 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
if (showListNumbers) if (showListNumbers)
ToggleStyleButton( ToggleStyleButton(
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( ToggleStyleButton(
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( ToggleCheckListButton(
@ -466,12 +494,16 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
if (showCodeBlock) if (showCodeBlock)
ToggleStyleButton( ToggleStyleButton(
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] &&
@ -480,13 +512,17 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
color: sectionDividerColor, space: sectionDividerSpace), color: sectionDividerColor, space: sectionDividerSpace),
if (showQuote) if (showQuote)
ToggleStyleButton( ToggleStyleButton(
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( IndentButton(

@ -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:

Loading…
Cancel
Save