Toolbar tweaks (#1179)

pull/1181/head
BambinoUA 2 years ago committed by GitHub
parent c3e410c2a2
commit 431efc1eda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      flutter_quill_extensions/lib/embeds/toolbar/camera_button.dart
  2. 1
      flutter_quill_extensions/lib/embeds/toolbar/formula_button.dart
  3. 1
      flutter_quill_extensions/lib/embeds/toolbar/image_button.dart
  4. 1
      flutter_quill_extensions/lib/embeds/toolbar/video_button.dart
  5. 8
      flutter_quill_extensions/lib/flutter_quill_extensions.dart
  6. 2
      flutter_quill_extensions/pubspec.yaml
  7. 1
      lib/flutter_quill.dart
  8. 3
      lib/src/utils/font.dart
  9. 135
      lib/src/widgets/toolbar.dart
  10. 57
      lib/src/widgets/toolbar/quill_font_family_button.dart
  11. 60
      lib/src/widgets/toolbar/quill_font_size_button.dart
  12. 6
      lib/src/widgets/toolbar/select_alignment_button.dart

@ -55,6 +55,7 @@ class CameraButton extends StatelessWidget {
return QuillIconButton(
icon: Icon(icon, size: iconSize, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,

@ -36,6 +36,7 @@ class FormulaButton extends StatelessWidget {
return QuillIconButton(
icon: Icon(icon, size: iconSize, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,

@ -51,6 +51,7 @@ class ImageButton extends StatelessWidget {
return QuillIconButton(
icon: Icon(icon, size: iconSize, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,

@ -51,6 +51,7 @@ class VideoButton extends StatelessWidget {
return QuillIconButton(
icon: Icon(icon, size: iconSize, color: iconColor),
tooltip: tooltip,
highlightElevation: 0,
hoverElevation: 0,
size: iconSize * 1.77,

@ -32,6 +32,10 @@ class FlutterQuillEmbeds {
bool showVideoButton = true,
bool showCameraButton = true,
bool showFormulaButton = false,
String? imageButtonTooltip,
String? videoButtonTooltip,
String? cameraButtonTooltip,
String? formulaButtonTooltip,
OnImagePickCallback? onImagePickCallback,
OnVideoPickCallback? onVideoPickCallback,
MediaPickSettingSelector? mediaPickSettingSelector,
@ -45,6 +49,7 @@ class FlutterQuillEmbeds {
(controller, toolbarIconSize, iconTheme, dialogTheme) => ImageButton(
icon: Icons.image,
iconSize: toolbarIconSize,
tooltip: imageButtonTooltip,
controller: controller,
onImagePickCallback: onImagePickCallback,
filePickImpl: filePickImpl,
@ -57,6 +62,7 @@ class FlutterQuillEmbeds {
(controller, toolbarIconSize, iconTheme, dialogTheme) => VideoButton(
icon: Icons.movie_creation,
iconSize: toolbarIconSize,
tooltip: videoButtonTooltip,
controller: controller,
onVideoPickCallback: onVideoPickCallback,
filePickImpl: filePickImpl,
@ -70,6 +76,7 @@ class FlutterQuillEmbeds {
(controller, toolbarIconSize, iconTheme, dialogTheme) => CameraButton(
icon: Icons.photo_camera,
iconSize: toolbarIconSize,
tooltip: cameraButtonTooltip,
controller: controller,
onImagePickCallback: onImagePickCallback,
onVideoPickCallback: onVideoPickCallback,
@ -83,6 +90,7 @@ class FlutterQuillEmbeds {
(controller, toolbarIconSize, iconTheme, dialogTheme) => FormulaButton(
icon: Icons.functions,
iconSize: toolbarIconSize,
tooltip: formulaButtonTooltip,
controller: controller,
iconTheme: iconTheme,
dialogTheme: dialogTheme,

@ -12,7 +12,7 @@ dependencies:
flutter:
sdk: flutter
flutter_quill: ^7.1.4
flutter_quill: ^7.1.6
image_picker: ^0.8.5+3
photo_view: ^0.14.0

@ -25,3 +25,4 @@ export 'src/widgets/embeds.dart';
export 'src/widgets/link.dart' show LinkActionPickerDelegate, LinkMenuAction;
export 'src/widgets/style_widgets/style_widgets.dart';
export 'src/widgets/toolbar.dart';
export 'src/widgets/toolbar/enum.dart';

@ -1,5 +1,6 @@
dynamic getFontSize(dynamic sizeValue) {
if (sizeValue is String && ['small', 'large', 'huge'].contains(sizeValue)) {
if (sizeValue is String &&
['small', 'normal', 'large', 'huge'].contains(sizeValue)) {
return sizeValue;
}

@ -6,7 +6,6 @@ import '../models/themes/quill_custom_button.dart';
import '../models/themes/quill_dialog_theme.dart';
import '../models/themes/quill_icon_theme.dart';
import '../translations/toolbar.i18n.dart';
import '../utils/font.dart';
import 'controller.dart';
import 'embeds.dart';
import 'toolbar/arrow_indicated_button_list.dart';
@ -30,32 +29,39 @@ export 'toolbar/color_button.dart';
export 'toolbar/history_button.dart';
export 'toolbar/indent_button.dart';
export 'toolbar/link_style_button.dart';
export 'toolbar/quill_font_family_button.dart';
export 'toolbar/quill_font_size_button.dart';
export 'toolbar/quill_icon_button.dart';
export 'toolbar/search_button.dart';
export 'toolbar/select_alignment_button.dart';
export 'toolbar/select_header_style_button.dart';
export 'toolbar/toggle_check_list_button.dart';
export 'toolbar/toggle_style_button.dart';
// The default size of the icon of a button.
/// The default size of the icon of a button.
const double kDefaultIconSize = 18;
// The factor of how much larger the button is in relation to the icon.
/// The factor of how much larger the button is in relation to the icon.
const double kIconButtonFactor = 1.77;
/// The horizontal margin between the contents of each toolbar section.
const double kToolbarSectionSpacing = 4;
class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
const QuillToolbar({
required this.children,
this.axis = Axis.horizontal,
this.toolbarSize = 36,
this.toolbarSize = kDefaultIconSize * 2,
this.toolbarSectionSpacing = kToolbarSectionSpacing,
this.toolbarIconAlignment = WrapAlignment.center,
this.toolbarIconCrossAlignment = WrapCrossAlignment.center,
this.toolbarSectionSpacing = 4,
this.multiRowsDisplay = true,
this.color,
this.customButtons = const [],
this.locale,
VoidCallback? afterButtonPressed,
this.sectionDividerColor,
this.sectionDividerSpace,
Key? key,
}) : super(key: key);
@ -63,9 +69,10 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
required QuillController controller,
Axis axis = Axis.horizontal,
double toolbarIconSize = kDefaultIconSize,
double toolbarSectionSpacing = 4,
double toolbarSectionSpacing = kToolbarSectionSpacing,
WrapAlignment toolbarIconAlignment = WrapAlignment.center,
WrapCrossAlignment toolbarIconCrossAlignment = WrapCrossAlignment.center,
bool multiRowsDisplay = true,
bool showDividers = true,
bool showFontFamily = true,
bool showFontSize = true,
@ -93,7 +100,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
bool showLink = true,
bool showUndo = true,
bool showRedo = true,
bool multiRowsDisplay = true,
bool showDirection = false,
bool showSearchButton = true,
List<QuillCustomButton> customButtons = const [],
@ -138,6 +144,12 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
/// The color of the toolbar
Color? color,
/// The color of the toolbar section divider
Color? sectionDividerColor,
/// The space occupied by toolbar divider
double? sectionDividerSpace,
Key? key,
}) {
final isButtonGroupShown = [
@ -260,21 +272,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
tooltip: buttonTooltips[ToolbarButtons.fontFamily],
attribute: Attribute.font,
controller: controller,
items: [
for (MapEntry<String, String> fontFamily in fontFamilies.entries)
PopupMenuItem<String>(
key: ValueKey(fontFamily.key),
value: fontFamily.value,
child: Text(fontFamily.key.toString(),
style: TextStyle(
color:
fontFamily.value == 'Clear' ? Colors.red : null)),
),
],
onSelected: (newFont) {
controller.formatSelection(Attribute.fromKeyValue(
'font', newFont == 'Clear' ? null : newFont));
},
rawItemsMap: fontFamilies,
afterButtonPressed: afterButtonPressed,
),
@ -285,20 +282,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
tooltip: buttonTooltips[ToolbarButtons.fontSize],
attribute: Attribute.size,
controller: controller,
items: [
for (MapEntry<String, String> fontSize in fontSizes.entries)
PopupMenuItem<String>(
key: ValueKey(fontSize.key),
value: fontSize.value,
child: Text(fontSize.key.toString(),
style: TextStyle(
color: fontSize.value == '0' ? Colors.red : null)),
),
],
onSelected: (newSize) {
controller.formatSelection(Attribute.fromKeyValue(
'size', newSize == '0' ? null : getFontSize(newSize)));
},
rawItemsMap: fontSizes,
afterButtonPressed: afterButtonPressed,
),
@ -401,7 +384,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
isButtonGroupShown[3] ||
isButtonGroupShown[4] ||
isButtonGroupShown[5]))
_dividerOnAxis(axis),
AxisDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace),
if (showAlignmentButtons)
SelectAlignmentButton(
controller: controller,
@ -436,7 +420,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
isButtonGroupShown[3] ||
isButtonGroupShown[4] ||
isButtonGroupShown[5]))
_dividerOnAxis(axis),
AxisDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace),
if (showHeaderStyle)
SelectHeaderStyleButton(
tooltip: buttonTooltips[ToolbarButtons.headerStyle],
@ -452,7 +437,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
(isButtonGroupShown[3] ||
isButtonGroupShown[4] ||
isButtonGroupShown[5]))
_dividerOnAxis(axis),
AxisDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace),
if (showListNumbers)
ToggleStyleButton(
attribute: Attribute.ol,
@ -496,7 +482,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
if (showDividers &&
isButtonGroupShown[3] &&
(isButtonGroupShown[4] || isButtonGroupShown[5]))
_dividerOnAxis(axis),
AxisDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace),
if (showQuote)
ToggleStyleButton(
attribute: Attribute.blockQuote,
@ -528,7 +515,8 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
afterButtonPressed: afterButtonPressed,
),
if (showDividers && isButtonGroupShown[4] && isButtonGroupShown[5])
_dividerOnAxis(axis),
AxisDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace),
if (showLink)
LinkStyleButton(
tooltip: buttonTooltips[ToolbarButtons.link],
@ -549,7 +537,9 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
afterButtonPressed: afterButtonPressed,
),
if (customButtons.isNotEmpty)
if (showDividers) _dividerOnAxis(axis),
if (showDividers)
AxisDivider(axis,
color: sectionDividerColor, space: sectionDividerSpace),
for (var customButton in customButtons)
QuillIconButton(
highlightElevation: 0,
@ -565,22 +555,6 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
);
}
static Widget _dividerOnAxis(Axis axis) {
if (axis == Axis.horizontal) {
return const VerticalDivider(
indent: 12,
endIndent: 12,
color: Colors.grey,
);
} else {
return const Divider(
indent: 12,
endIndent: 12,
color: Colors.grey,
);
}
}
final List<Widget> children;
final Axis axis;
final double toolbarSize;
@ -602,6 +576,15 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
/// List of custom buttons
final List<QuillCustomButton> customButtons;
/// The color to use when painting the toolbar section divider.
///
/// If this is null, then the [DividerThemeData.color] is used. If that is
/// also null, then [ThemeData.dividerColor] is used.
final Color? sectionDividerColor;
/// The space occupied by toolbar section divider.
final double? sectionDividerSpace;
@override
Size get preferredSize => axis == Axis.horizontal
? Size.fromHeight(toolbarSize)
@ -634,3 +617,39 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
);
}
}
class AxisDivider extends StatelessWidget {
const AxisDivider(
this.axis, {
Key? key,
this.color,
this.space,
}) : super(key: key);
const AxisDivider.horizontal({Color? color, double? space})
: this(Axis.horizontal, color: color, space: space);
const AxisDivider.vertical({Color? color, double? space})
: this(Axis.vertical, color: color, space: space);
final Axis axis;
final Color? color;
final double? space;
@override
Widget build(BuildContext context) {
return axis == Axis.horizontal
? Divider(
height: space,
color: color,
indent: 12,
endIndent: 12,
)
: VerticalDivider(
width: space,
color: color,
indent: 12,
endIndent: 12,
);
}
}

@ -9,11 +9,11 @@ import '../controller.dart';
class QuillFontFamilyButton extends StatefulWidget {
const QuillFontFamilyButton({
required this.items,
required this.rawItemsMap,
required this.attribute,
required this.controller,
required this.onSelected,
@Deprecated('It is not required because of `rawItemsMap`') this.items,
this.onSelected,
this.iconSize = 40,
this.fillColor,
this.hoverElevation = 1,
@ -21,6 +21,11 @@ class QuillFontFamilyButton extends StatefulWidget {
this.iconTheme,
this.afterButtonPressed,
this.tooltip,
this.padding,
this.style,
this.width,
this.renderFontFamilies = true,
this.alignment,
Key? key,
}) : super(key: key);
@ -28,14 +33,20 @@ class QuillFontFamilyButton extends StatefulWidget {
final Color? fillColor;
final double hoverElevation;
final double highlightElevation;
final List<PopupMenuEntry<String>> items;
@Deprecated('It is not required because of `rawItemsMap`')
final List<PopupMenuEntry<String>>? items;
final Map<String, String> rawItemsMap;
final ValueChanged<String> onSelected;
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 bool renderFontFamilies;
final AlignmentGeometry? alignment;
@override
_QuillFontFamilyButtonState createState() => _QuillFontFamilyButtonState();
@ -90,7 +101,10 @@ class _QuillFontFamilyButtonState extends State<QuillFontFamilyButton> {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints.tightFor(height: widget.iconSize * 1.81),
constraints: BoxConstraints.tightFor(
height: widget.iconSize * 1.81,
width: widget.width,
),
child: UtilityWidgets.maybeTooltip(
message: widget.tooltip,
child: RawMaterialButton(
@ -127,7 +141,20 @@ class _QuillFontFamilyButtonState extends State<QuillFontFamilyButton> {
showMenu<String>(
context: context,
elevation: 4,
items: widget.items,
items: [
for (MapEntry<String, String> fontFamily in widget.rawItemsMap.entries)
PopupMenuItem<String>(
key: ValueKey(fontFamily.key),
value: fontFamily.value,
child: Text(
fontFamily.key.toString(),
style: TextStyle(
fontFamily:
widget.renderFontFamilies ? fontFamily.value : null,
color: fontFamily.value == 'Clear' ? Colors.red : null),
),
),
],
position: position,
shape: popupMenuTheme.shape,
color: popupMenuTheme.color,
@ -140,7 +167,9 @@ class _QuillFontFamilyButtonState extends State<QuillFontFamilyButton> {
setState(() {
_currentValue = keyName ?? _defaultDisplayText;
if (keyName != null) {
widget.onSelected(newValue);
widget.controller.formatSelection(Attribute.fromKeyValue(
'font', newValue == 'Clear' ? null : newValue));
widget.onSelected?.call(newValue);
}
});
});
@ -148,16 +177,18 @@ class _QuillFontFamilyButtonState extends State<QuillFontFamilyButton> {
Widget _buildContent(BuildContext context) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
return Container(
alignment: widget.alignment ?? Alignment.center,
padding: widget.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(_currentValue,
style: TextStyle(
fontSize: widget.iconSize / 1.15,
color: widget.iconTheme?.iconUnselectedColor ??
theme.iconTheme.color)),
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,

@ -10,11 +10,11 @@ import '../controller.dart';
class QuillFontSizeButton extends StatefulWidget {
const QuillFontSizeButton({
required this.items,
required this.rawItemsMap,
required this.attribute,
required this.controller,
required this.onSelected,
this.onSelected,
@Deprecated('It is not required because of `rawItemsMap`') this.items,
this.iconSize = 40,
this.fillColor,
this.hoverElevation = 1,
@ -22,21 +22,33 @@ class QuillFontSizeButton extends StatefulWidget {
this.iconTheme,
this.afterButtonPressed,
this.tooltip,
this.padding,
this.style,
this.width,
this.initialValue,
this.alignment,
Key? key,
}) : super(key: key);
}) : assert(rawItemsMap.length > 0),
super(key: key);
final double iconSize;
final Color? fillColor;
final double hoverElevation;
final double highlightElevation;
final List<PopupMenuEntry<String>> items;
@Deprecated('It is not required because of `rawItemsMap`')
final List<PopupMenuEntry<String>>? items;
final Map<String, String> rawItemsMap;
final ValueChanged<String> onSelected;
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 AlignmentGeometry? alignment;
@override
_QuillFontSizeButtonState createState() => _QuillFontSizeButtonState();
@ -50,7 +62,7 @@ class _QuillFontSizeButtonState extends State<QuillFontSizeButton> {
@override
void initState() {
super.initState();
_currentValue = _defaultDisplayText = 'Size'.i18n;
_currentValue = _defaultDisplayText = widget.initialValue ?? 'Size'.i18n;
widget.controller.addListener(_didChangeEditingValue);
}
@ -91,7 +103,10 @@ class _QuillFontSizeButtonState extends State<QuillFontSizeButton> {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints.tightFor(height: widget.iconSize * 1.81),
constraints: BoxConstraints.tightFor(
height: widget.iconSize * 1.81,
width: widget.width,
),
child: UtilityWidgets.maybeTooltip(
message: widget.tooltip,
child: RawMaterialButton(
@ -128,7 +143,18 @@ class _QuillFontSizeButtonState extends State<QuillFontSizeButton> {
showMenu<String>(
context: context,
elevation: 4,
items: widget.items,
items: [
for (MapEntry<String, String> fontSize in widget.rawItemsMap.entries)
PopupMenuItem<String>(
key: ValueKey(fontSize.key),
value: fontSize.value,
child: Text(
fontSize.key.toString(),
style:
TextStyle(color: fontSize.value == '0' ? Colors.red : null),
),
),
],
position: position,
shape: popupMenuTheme.shape,
color: popupMenuTheme.color,
@ -141,7 +167,9 @@ class _QuillFontSizeButtonState extends State<QuillFontSizeButton> {
setState(() {
_currentValue = keyName ?? _defaultDisplayText;
if (keyName != null) {
widget.onSelected(newValue);
widget.controller.formatSelection(Attribute.fromKeyValue(
'size', newValue == '0' ? null : getFontSize(newValue)));
widget.onSelected?.call(newValue);
}
});
});
@ -149,16 +177,18 @@ class _QuillFontSizeButtonState extends State<QuillFontSizeButton> {
Widget _buildContent(BuildContext context) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.fromLTRB(10, 0, 0, 0),
return Container(
alignment: widget.alignment ?? Alignment.center,
padding: widget.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(_currentValue,
style: TextStyle(
fontSize: widget.iconSize / 1.15,
color: widget.iconTheme?.iconUnselectedColor ??
theme.iconTheme.color)),
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,

@ -20,6 +20,7 @@ class SelectAlignmentButton extends StatefulWidget {
this.showJustifyAlignment,
this.afterButtonPressed,
this.tooltips = const <ToolbarButtons, String>{},
this.padding,
Key? key,
}) : super(key: key);
@ -33,6 +34,7 @@ class SelectAlignmentButton extends StatefulWidget {
final bool? showJustifyAlignment;
final VoidCallback? afterButtonPressed;
final Map<ToolbarButtons, String> tooltips;
final EdgeInsetsGeometry? padding;
@override
_SelectAlignmentButtonState createState() => _SelectAlignmentButtonState();
@ -100,8 +102,8 @@ class _SelectAlignmentButtonState extends State<SelectAlignmentButton> {
mainAxisSize: MainAxisSize.min,
children: List.generate(buttonCount, (index) {
return Padding(
// ignore: prefer_const_constructors
padding: EdgeInsets.symmetric(horizontal: !kIsWeb ? 1.0 : 5.0),
padding: widget.padding ??
const EdgeInsets.symmetric(horizontal: !kIsWeb ? 1.0 : 5.0),
child: ConstrainedBox(
constraints: BoxConstraints.tightFor(
width: widget.iconSize * kIconButtonFactor,

Loading…
Cancel
Save