Update widget

pull/1575/head
Aleksei 1 year ago
parent 09cc3860de
commit 7f605048d1
  1. 303
      lib/src/widgets/toolbar/buttons/dropdown_header_style.dart

@ -1,8 +1,118 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import '../../../../flutter_quill.dart';
import '../../../../translations.dart';
import '../../../utils/widgets.dart';
class QuillToolbarSelectHeaderStyleDropdownButtonExtraOptions
extends QuillToolbarBaseButtonExtraOptions {
const QuillToolbarSelectHeaderStyleDropdownButtonExtraOptions({
required this.currentValue,
required super.controller,
required super.context,
required super.onPressed,
});
final Attribute currentValue;
}
class QuillToolbarSelectHeaderStyleDropdownButtonOptions
extends QuillToolbarBaseButtonOptions<
QuillToolbarSelectHeaderStyleDropdownButtonOptions,
QuillToolbarSelectHeaderStyleDropdownButtonExtraOptions> {
const QuillToolbarSelectHeaderStyleDropdownButtonOptions({
super.controller,
super.iconData,
super.afterButtonPressed,
super.tooltip,
super.iconTheme,
super.childBuilder,
this.iconSize,
this.iconButtonFactor,
this.fillColor,
this.hoverElevation = 1,
this.highlightElevation = 1,
this.rawItemsMap,
this.onSelected,
this.attributes,
this.padding,
this.style,
this.width,
this.initialValue,
this.labelOverflow = TextOverflow.visible,
this.itemHeight,
this.itemPadding,
this.defaultItemColor,
});
final double? iconSize;
final double? iconButtonFactor;
final Color? fillColor;
final double hoverElevation;
final double highlightElevation;
final Map<String, String>? rawItemsMap;
final ValueChanged<String>? onSelected;
final List<Attribute>? attributes;
final EdgeInsetsGeometry? padding;
final TextStyle? style;
final double? width;
final String? initialValue;
final TextOverflow labelOverflow;
final double? itemHeight;
final EdgeInsets? itemPadding;
final Color? defaultItemColor;
QuillToolbarSelectHeaderStyleDropdownButtonOptions copyWith({
Color? fillColor,
double? hoverElevation,
double? highlightElevation,
List<PopupMenuEntry<String>>? items,
Map<String, String>? rawItemsMap,
ValueChanged<String>? onSelected,
List<Attribute>? attributes,
EdgeInsetsGeometry? padding,
TextStyle? style,
double? width,
String? initialValue,
TextOverflow? labelOverflow,
bool? renderFontFamilies,
bool? overrideTooltipByFontFamily,
double? itemHeight,
EdgeInsets? itemPadding,
Color? defaultItemColor,
double? iconSize,
double? iconButtonFactor,
// Add properties to override inherited properties
QuillController? controller,
IconData? iconData,
VoidCallback? afterButtonPressed,
String? tooltip,
QuillIconTheme? iconTheme,
}) {
return QuillToolbarSelectHeaderStyleDropdownButtonOptions(
attributes: attributes ?? this.attributes,
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,
itemHeight: itemHeight ?? this.itemHeight,
itemPadding: itemPadding ?? this.itemPadding,
defaultItemColor: defaultItemColor ?? this.defaultItemColor,
iconSize: iconSize ?? this.iconSize,
iconButtonFactor: iconButtonFactor ?? this.iconButtonFactor,
fillColor: fillColor ?? this.fillColor,
hoverElevation: hoverElevation ?? this.hoverElevation,
highlightElevation: highlightElevation ?? this.highlightElevation,
);
}
}
class QuillToolbarSelectHeaderStyleDropdownButton extends StatefulWidget {
const QuillToolbarSelectHeaderStyleDropdownButton({
@ -11,8 +121,10 @@ class QuillToolbarSelectHeaderStyleDropdownButton extends StatefulWidget {
super.key,
});
/// 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;
final QuillToolbarSelectHeaderStyleButtonsOptions options;
final QuillToolbarSelectHeaderStyleDropdownButtonOptions options;
@override
State<QuillToolbarSelectHeaderStyleDropdownButton> createState() =>
@ -26,13 +138,13 @@ class _QuillToolbarSelectHeaderStyleDropdownButtonState
Style get _selectionStyle => controller.getSelectionStyle();
final _valueToText = <Attribute, String>{
Attribute.header: 'N',
Attribute.header: 'Normal',
Attribute.h1: 'H1',
Attribute.h2: 'H2',
Attribute.h3: 'H3',
};
QuillToolbarSelectHeaderStyleButtonsOptions get options {
QuillToolbarSelectHeaderStyleDropdownButtonOptions get options {
return widget.options;
}
@ -71,14 +183,6 @@ class _QuillToolbarSelectHeaderStyleDropdownButtonState
context.loc.headerStyle;
}
Axis get axis {
return options.axis ??
context.quillToolbarConfigurations?.axis ??
context.quillBaseToolbarConfigurations?.axis ??
(throw ArgumentError(
'There is no default value for the Axis of the toolbar'));
}
List<Attribute> get _attrbuites {
return options.attributes ??
const [
@ -109,9 +213,7 @@ class _QuillToolbarSelectHeaderStyleDropdownButtonState
@override
void initState() {
super.initState();
setState(() {
_selectedAttribute = _getHeaderValue();
});
_selectedAttribute = _getHeaderValue();
controller.addListener(_didChangeEditingValue);
}
@ -124,76 +226,45 @@ class _QuillToolbarSelectHeaderStyleDropdownButtonState
'All attributes must be one of them: header, h1, h2 or h3',
);
final style = TextStyle(
fontWeight: FontWeight.w600,
fontSize: iconSize * 0.7,
);
final baseButtonConfigurations =
context.requireQuillToolbarBaseButtonOptions;
final childBuilder =
options.childBuilder ?? baseButtonExtraOptions.childBuilder;
for (final attribute in _attrbuites) {
if (childBuilder != null) {
return childBuilder(
QuillToolbarSelectHeaderStyleButtonsOptions(
afterButtonPressed: afterButtonPressed,
attributes: _attrbuites,
axis: axis,
iconSize: iconSize,
iconButtonFactor: iconButtonFactor,
iconTheme: iconTheme,
tooltip: tooltip,
),
QuillToolbarSelectHeaderStyleButtonExtraOptions(
controller: controller,
context: context,
onPressed: () => _sharedOnPressed(attribute),
),
);
}
options.childBuilder ?? baseButtonConfigurations.childBuilder;
if (childBuilder != null) {
return childBuilder(
options.copyWith(
iconSize: iconSize,
iconTheme: iconTheme,
tooltip: tooltip,
afterButtonPressed: afterButtonPressed,
),
QuillToolbarSelectHeaderStyleDropdownButtonExtraOptions(
currentValue: _selectedAttribute!,
controller: controller,
context: context,
onPressed: _onPressed,
),
);
}
final theme = Theme.of(context);
return ConstrainedBox(
constraints: BoxConstraints.tightFor(
width: iconSize * iconButtonFactor,
height: iconSize * iconButtonFactor,
height: iconSize * 1.81,
width: options.width,
),
child: Tooltip(
child: UtilityWidgets.maybeTooltip(
message: tooltip,
child: DropdownButtonHideUnderline(
child: DropdownButton<Attribute>(
value: _selectedAttribute,
items: _valueToText.entries
.map((header) => DropdownMenuItem(
value: header.key,
child: Text(
header.value,
style: style,
),
))
.toList(),
selectedItemBuilder: (context) =>
_valueToText.entries.map((header) {
final isSelected = _selectedAttribute == header.key;
return Text(
header.value,
style: style.copyWith(
color: isSelected
? (iconTheme?.iconSelectedColor ??
theme.primaryIconTheme.color)
: (iconTheme?.iconUnselectedColor ??
theme.iconTheme.color),
),
);
}).toList(),
elevation: 0,
child: RawMaterialButton(
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(iconTheme?.borderRadius ?? 2),
padding:
const EdgeInsets.symmetric(horizontal: !kIsWeb ? 1.0 : 5.0),
onChanged: (attribute) => _sharedOnPressed(attribute!),
),
fillColor: options.fillColor,
elevation: 0,
hoverElevation: options.hoverElevation,
highlightElevation: options.hoverElevation,
onPressed: _onPressed,
child: _buildContent(context),
),
),
);
@ -215,9 +286,85 @@ class _QuillToolbarSelectHeaderStyleDropdownButtonState
return _selectionStyle.attributes[Attribute.header.key] ?? Attribute.header;
}
void _sharedOnPressed(Attribute attribute) {
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(
_selectedAttribute!.key,
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,
)
],
),
);
}
void _onPressed() {
_showMenu();
options.afterButtonPressed?.call();
}
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<Attribute>(
context: context,
elevation: 4,
items: [
for (final header in _valueToText.entries)
PopupMenuItem<Attribute>(
key: ValueKey(header.value),
value: header.key,
height: options.itemHeight ?? kMinInteractiveDimension,
padding: options.itemPadding,
child: Text(
header.value,
style: TextStyle(
color: header.value == 'N' ? options.defaultItemColor : null,
),
),
),
],
position: position,
shape: popupMenuTheme.shape,
color: popupMenuTheme.color,
);
if (newValue == null) {
return;
}
final attribute0 =
_selectedAttribute == attribute ? Attribute.header : attribute;
_selectedAttribute == newValue ? Attribute.header : newValue;
controller.formatSelection(attribute0);
afterButtonPressed?.call();
}

Loading…
Cancel
Save