Major update 2 (#1446 )
parent
a73fca1f76
commit
3a82930bbe
49 changed files with 1104 additions and 589 deletions
@ -0,0 +1,23 @@ |
||||
#!/bin/bash |
||||
|
||||
# Run Flutter analyze |
||||
echo "Running 'flutter analyze'..." |
||||
flutter analyze |
||||
|
||||
# Run Flutter test |
||||
echo "Running 'flutter test'..." |
||||
flutter test |
||||
|
||||
# Check if package is ready for publishing |
||||
echo "Running 'flutter pub publish --dry-run'..." |
||||
flutter pub publish --dry-run |
||||
|
||||
# Apply Dart fixes |
||||
echo "Running 'dart fix --apply'..." |
||||
dart fix --apply |
||||
|
||||
# Format Dart code |
||||
echo "Running 'dart format .'" |
||||
dart format . |
||||
|
||||
echo "Script completed." |
@ -0,0 +1,21 @@ |
||||
import 'package:flutter/foundation.dart' show immutable; |
||||
|
||||
/// The configurations for the quill editor widget of flutter quill |
||||
@immutable |
||||
class QuillEditorConfigurations { |
||||
const QuillEditorConfigurations({ |
||||
this.placeholder, |
||||
this.readOnly = false, |
||||
}); |
||||
|
||||
/// The text placeholder in the quill editor |
||||
final String? placeholder; |
||||
|
||||
/// Whether the text can be changed. |
||||
/// |
||||
/// When this is set to `true`, the text cannot be modified |
||||
/// by any shortcut or keyboard operation. The text is still selectable. |
||||
/// |
||||
/// Defaults to `false`. Must not be `null`. |
||||
final bool readOnly; |
||||
} |
@ -0,0 +1,21 @@ |
||||
import 'package:flutter/material.dart' show Color, Colors, Locale; |
||||
import './editor/configurations.dart' show QuillEditorConfigurations; |
||||
import './toolbar/configurations.dart' show QuillToolbarConfigurations; |
||||
|
||||
/// The shared configurations between [QuillEditorConfigurations] and |
||||
/// [QuillToolbarConfigurations] so we don't duplicate things |
||||
class QuillSharedConfigurations { |
||||
const QuillSharedConfigurations({ |
||||
this.dialogBarrierColor = Colors.black54, |
||||
this.locale, |
||||
}); |
||||
|
||||
// This is just example or showcase of this major update to make the library |
||||
// more maintanable, flexible, and customizable |
||||
/// The barrier color of the shown dialogs |
||||
final Color dialogBarrierColor; |
||||
|
||||
/// The locale to use for the editor and toolbar, defaults to system locale |
||||
/// More https://github.com/singerdmx/flutter-quill#translation |
||||
final Locale? locale; |
||||
} |
@ -0,0 +1,48 @@ |
||||
import 'package:flutter/foundation.dart' show VoidCallback, immutable; |
||||
import 'package:flutter/widgets.dart' show IconData, Widget; |
||||
|
||||
import '../../../../../flutter_quill.dart' show QuillController, QuillProvider; |
||||
import '../../../themes/quill_icon_theme.dart' show QuillIconTheme; |
||||
import '../../quill_configurations.dart' show kDefaultIconSize; |
||||
|
||||
/// 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 |
||||
/// The [I] is extra options for the button, usually for it's state |
||||
@immutable |
||||
class QuillToolbarBaseButtonOptions<T, I> { |
||||
const QuillToolbarBaseButtonOptions({ |
||||
this.iconData, |
||||
this.globalIconSize = kDefaultIconSize, |
||||
this.afterButtonPressed, |
||||
this.tooltip, |
||||
this.iconTheme, |
||||
this.childBuilder, |
||||
this.controller, |
||||
}); |
||||
|
||||
/// By default it will use a Icon data from Icons which comes from material |
||||
/// library, to change this, please pass a different value |
||||
/// If there is no Icon in this button then pass null in the child class |
||||
final IconData? iconData; |
||||
|
||||
/// To change the the icon size pass a different value, by default will be |
||||
/// [kDefaultIconSize] |
||||
/// this will be used for all the buttons but you can override this |
||||
final double globalIconSize; |
||||
|
||||
/// To do extra logic after pressing the button |
||||
final VoidCallback? afterButtonPressed; |
||||
|
||||
/// By default it will use the default tooltip which already localized |
||||
final String? tooltip; |
||||
|
||||
/// Use custom theme |
||||
final QuillIconTheme? iconTheme; |
||||
|
||||
/// If you want to dispaly a differnet widget based using a builder |
||||
final Widget Function(T options, I extraOptions)? childBuilder; |
||||
|
||||
/// By default it will be from the one in [QuillProvider] |
||||
/// To override it you must pass not null controller |
||||
final QuillController? controller; |
||||
} |
@ -0,0 +1,79 @@ |
||||
import 'package:flutter/foundation.dart' show immutable; |
||||
import 'package:flutter/material.dart' show Colors, PopupMenuEntry; |
||||
import 'package:flutter/widgets.dart' |
||||
show |
||||
Color, |
||||
ValueChanged, |
||||
EdgeInsetsGeometry, |
||||
TextStyle, |
||||
EdgeInsets, |
||||
TextOverflow; |
||||
|
||||
import '../../../../../flutter_quill.dart'; |
||||
|
||||
@immutable |
||||
class QuillToolbarFontFamilyButtonExtraOptions { |
||||
const QuillToolbarFontFamilyButtonExtraOptions({ |
||||
required this.defaultDisplayText, |
||||
required this.currentValue, |
||||
}); |
||||
final String defaultDisplayText; |
||||
final String currentValue; |
||||
} |
||||
|
||||
class QuillToolbarFontFamilyButtonOptions extends QuillToolbarBaseButtonOptions< |
||||
QuillToolbarFontFamilyButtonOptions, |
||||
QuillToolbarFontFamilyButtonExtraOptions> { |
||||
const QuillToolbarFontFamilyButtonOptions({ |
||||
required this.attribute, |
||||
this.rawItemsMap, |
||||
super.controller, |
||||
super.iconData, |
||||
super.afterButtonPressed, |
||||
super.tooltip, |
||||
super.iconTheme, |
||||
super.childBuilder, |
||||
this.onSelected, |
||||
this.padding, |
||||
this.style, |
||||
this.width, |
||||
this.initialValue, |
||||
this.labelOverflow = TextOverflow.visible, |
||||
this.overrideTooltipByFontFamily = false, |
||||
this.itemHeight, |
||||
this.itemPadding, |
||||
this.defaultItemColor = Colors.red, |
||||
this.renderFontFamilies = true, |
||||
@Deprecated('It is not required because of `rawItemsMap`') this.items, |
||||
this.highlightElevation = 1, |
||||
this.hoverElevation = 1, |
||||
this.fillColor, |
||||
this.iconSize, |
||||
}); |
||||
|
||||
final Color? fillColor; |
||||
final double hoverElevation; |
||||
final double highlightElevation; |
||||
@Deprecated('It is not required because of `rawItemsMap`') |
||||
final List<PopupMenuEntry<String>>? items; |
||||
|
||||
/// By default it will be [fontFamilyValues] from [QuillToolbarConfigurations] |
||||
/// You can override this if you want |
||||
final Map<String, String>? rawItemsMap; |
||||
final ValueChanged<String>? onSelected; |
||||
final Attribute attribute; |
||||
|
||||
final EdgeInsetsGeometry? padding; |
||||
final TextStyle? style; |
||||
final double? width; |
||||
final bool renderFontFamilies; |
||||
final String? initialValue; |
||||
final TextOverflow labelOverflow; |
||||
final bool overrideTooltipByFontFamily; |
||||
final double? itemHeight; |
||||
final EdgeInsets? itemPadding; |
||||
final Color? defaultItemColor; |
||||
|
||||
/// By default will use [globalIconSize] |
||||
final double? iconSize; |
||||
} |
@ -0,0 +1,39 @@ |
||||
import 'package:flutter/foundation.dart' show VoidCallback, immutable; |
||||
|
||||
import '../../../../../flutter_quill.dart'; |
||||
|
||||
@immutable |
||||
class HistoryButtonExtraOptions { |
||||
const HistoryButtonExtraOptions({ |
||||
required this.onPressed, |
||||
required this.canPressed, |
||||
}); |
||||
|
||||
/// When the button pressed |
||||
final VoidCallback onPressed; |
||||
|
||||
/// If it can redo or undo |
||||
final bool canPressed; |
||||
} |
||||
|
||||
@immutable |
||||
class QuillToolbarHistoryButtonOptions extends QuillToolbarBaseButtonOptions< |
||||
QuillToolbarHistoryButtonOptions, HistoryButtonExtraOptions> { |
||||
const QuillToolbarHistoryButtonOptions({ |
||||
required this.isUndo, |
||||
super.iconData, |
||||
super.controller, |
||||
super.iconTheme, |
||||
super.afterButtonPressed, |
||||
super.tooltip, |
||||
super.childBuilder, |
||||
this.iconSize, |
||||
}); |
||||
|
||||
/// If this true then it will be the undo button |
||||
/// otherwise it will be redo |
||||
final bool isUndo; |
||||
|
||||
/// By default will use [globalIconSize] |
||||
final double? iconSize; |
||||
} |
@ -0,0 +1,15 @@ |
||||
import 'package:flutter/foundation.dart' show immutable; |
||||
import 'package:flutter/widgets.dart' show IconData; |
||||
|
||||
import 'base.dart'; |
||||
|
||||
@immutable |
||||
class QuillToolbarToggleStyleButtonOptions |
||||
extends QuillToolbarBaseButtonOptions { |
||||
const QuillToolbarToggleStyleButtonOptions({ |
||||
required this.iconData, |
||||
}); |
||||
|
||||
@override |
||||
final IconData iconData; |
||||
} |
@ -0,0 +1,93 @@ |
||||
import 'package:flutter/foundation.dart' show immutable; |
||||
|
||||
import '../../documents/attribute.dart'; |
||||
import 'buttons/base.dart'; |
||||
import 'buttons/font_family.dart'; |
||||
import 'buttons/history.dart'; |
||||
|
||||
export './buttons/base.dart'; |
||||
export './buttons/history.dart'; |
||||
export './buttons/toggle_style.dart'; |
||||
|
||||
/// The default size of the icon of a button. |
||||
const double kDefaultIconSize = 18; |
||||
|
||||
/// The default size for the toolbar (width, height) |
||||
const double defaultToolbarSize = kDefaultIconSize * 2; |
||||
|
||||
/// 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; |
||||
|
||||
/// The configurations for the toolbar widget of flutter quill |
||||
@immutable |
||||
class QuillToolbarConfigurations { |
||||
const QuillToolbarConfigurations({ |
||||
this.buttonOptions = const QuillToolbarButtonOptions(), |
||||
this.multiRowsDisplay = true, |
||||
this.fontFamilyValues, |
||||
|
||||
/// By default it will calculated based on the [baseOptions] iconSize |
||||
/// You can change it but the the change only apply if |
||||
/// the [multiRowsDisplay] is false, if [multiRowsDisplay] then the value |
||||
/// will be [kDefaultIconSize] * 2 |
||||
double? toolbarSize, |
||||
}) : _toolbarSize = toolbarSize; |
||||
|
||||
final double? _toolbarSize; |
||||
|
||||
/// The toolbar size, by default it will be `baseButtonOptions.iconSize * 2` |
||||
double get toolbarSize { |
||||
final alternativeToolbarSize = _toolbarSize; |
||||
if (alternativeToolbarSize != null) { |
||||
return alternativeToolbarSize; |
||||
} |
||||
return buttonOptions.baseButtonOptions.globalIconSize * 2; |
||||
} |
||||
|
||||
/// If you want change spesefic buttons or all of them |
||||
/// then you came to the right place |
||||
final QuillToolbarButtonOptions buttonOptions; |
||||
final bool multiRowsDisplay; |
||||
|
||||
/// By default will be final |
||||
/// ``` |
||||
/// { |
||||
/// 'Sans Serif': 'sans-serif', |
||||
/// 'Serif': 'serif', |
||||
/// 'Monospace': 'monospace', |
||||
/// 'Ibarra Real Nova': 'ibarra-real-nova', |
||||
/// 'SquarePeg': 'square-peg', |
||||
/// 'Nunito': 'nunito', |
||||
/// 'Pacifico': 'pacifico', |
||||
/// 'Roboto Mono': 'roboto-mono', |
||||
/// 'Clear'.i18n: 'Clear' |
||||
/// }; |
||||
/// ``` |
||||
final Map<String, String>? fontFamilyValues; |
||||
} |
||||
|
||||
/// The configurations for the buttons of the toolbar widget of flutter quill |
||||
@immutable |
||||
class QuillToolbarButtonOptions { |
||||
const QuillToolbarButtonOptions({ |
||||
this.baseButtonOptions = const QuillToolbarBaseButtonOptions(), |
||||
this.undoHistoryButtonOptions = const QuillToolbarHistoryButtonOptions( |
||||
isUndo: true, |
||||
), |
||||
this.redoHistoryButtonOptions = const QuillToolbarHistoryButtonOptions( |
||||
isUndo: false, |
||||
), |
||||
this.fontFamilyButtonOptions = const QuillToolbarFontFamilyButtonOptions( |
||||
attribute: Attribute.font, |
||||
), |
||||
}); |
||||
|
||||
/// The base configurations for all the buttons |
||||
final QuillToolbarBaseButtonOptions baseButtonOptions; |
||||
final QuillToolbarHistoryButtonOptions undoHistoryButtonOptions; |
||||
final QuillToolbarHistoryButtonOptions redoHistoryButtonOptions; |
||||
final QuillToolbarFontFamilyButtonOptions fontFamilyButtonOptions; |
||||
} |
@ -0,0 +1,17 @@ |
||||
import 'package:flutter/widgets.dart' show BuildContext; |
||||
|
||||
import '../../../flutter_quill.dart' show QuillController, QuillProvider; |
||||
import 'build_context.dart'; |
||||
|
||||
extension QuillControllerExt on QuillController? { |
||||
/// Simple logic to use the current passed controller if not null |
||||
/// if null then we will have to use the default one from [QuillProvider] |
||||
/// using the [context] |
||||
QuillController notNull(BuildContext context) { |
||||
final controller = this; |
||||
if (controller != null) { |
||||
return controller; |
||||
} |
||||
return context.requireQuillController; |
||||
} |
||||
} |
@ -1,9 +1,9 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class ClearFormatButton extends StatefulWidget { |
||||
const ClearFormatButton({ |
@ -1,13 +1,13 @@ |
||||
import 'package:flutter/material.dart'; |
||||
import 'package:flutter_colorpicker/flutter_colorpicker.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../translations/toolbar.i18n.dart'; |
||||
import '../../utils/color.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../translations/toolbar.i18n.dart'; |
||||
import '../../../utils/color.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
/// Controls color styles. |
||||
/// |
@ -1,7 +1,7 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class CustomButton extends StatelessWidget { |
||||
const CustomButton({ |
@ -0,0 +1,276 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../../../extensions.dart'; |
||||
import '../../../models/config/toolbar/buttons/font_family.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../translations/toolbar.i18n.dart'; |
||||
import '../../../utils/extensions/build_context.dart'; |
||||
import '../../../utils/extensions/quill_controller.dart'; |
||||
import '../../controller.dart'; |
||||
|
||||
class QuillToolbarFontFamilyButton extends StatefulWidget { |
||||
QuillToolbarFontFamilyButton({ |
||||
required this.options, |
||||
super.key, |
||||
}) : assert(options.rawItemsMap?.isNotEmpty ?? (true)), |
||||
assert( |
||||
options.initialValue == null || options.initialValue!.isNotEmpty, |
||||
); |
||||
|
||||
final QuillToolbarFontFamilyButtonOptions options; |
||||
|
||||
@override |
||||
_QuillToolbarFontFamilyButtonState createState() => |
||||
_QuillToolbarFontFamilyButtonState(); |
||||
} |
||||
|
||||
class _QuillToolbarFontFamilyButtonState |
||||
extends State<QuillToolbarFontFamilyButton> { |
||||
late String _defaultDisplayText; |
||||
String _currentValue = ''; |
||||
|
||||
QuillToolbarFontFamilyButtonOptions get options { |
||||
return widget.options; |
||||
} |
||||
|
||||
/// Since t'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; |
||||
|
||||
QuillController get controller { |
||||
return options.controller.notNull(context); |
||||
} |
||||
|
||||
Style get _selectionStyle => controller.getSelectionStyle(); |
||||
|
||||
@override |
||||
void initState() { |
||||
super.initState(); |
||||
_initState(); |
||||
} |
||||
|
||||
Future<void> _initState() async { |
||||
if (isFlutterTest()) { |
||||
// We don't need to listen for changes in the tests |
||||
return; |
||||
} |
||||
await Future.delayed(Duration.zero); |
||||
setState(() { |
||||
_currentValue = _defaultDisplayText = options.initialValue ?? 'Font'.i18n; |
||||
}); |
||||
controller.addListener(_didChangeEditingValue); |
||||
} |
||||
|
||||
@override |
||||
void didChangeDependencies() { |
||||
super.didChangeDependencies(); |
||||
_controller = controller; |
||||
} |
||||
|
||||
@override |
||||
void dispose() { |
||||
_controller.removeListener(_didChangeEditingValue); |
||||
super.dispose(); |
||||
} |
||||
|
||||
@override |
||||
void didUpdateWidget(covariant QuillToolbarFontFamilyButton oldWidget) { |
||||
super.didUpdateWidget(oldWidget); |
||||
if (controller != controller) { |
||||
controller |
||||
..removeListener(_didChangeEditingValue) |
||||
..addListener(_didChangeEditingValue); |
||||
} |
||||
} |
||||
|
||||
void _didChangeEditingValue() { |
||||
final attribute = _selectionStyle.attributes[options.attribute.key]; |
||||
if (attribute == null) { |
||||
setState(() => _currentValue = _defaultDisplayText); |
||||
return; |
||||
} |
||||
final keyName = _getKeyName(attribute.value); |
||||
setState(() => _currentValue = keyName ?? _defaultDisplayText); |
||||
} |
||||
|
||||
Map<String, String> get rawItemsMap { |
||||
final rawItemsMap = options.rawItemsMap ?? |
||||
{ |
||||
'Sans Serif': 'sans-serif', |
||||
'Serif': 'serif', |
||||
'Monospace': 'monospace', |
||||
'Ibarra Real Nova': 'ibarra-real-nova', |
||||
'SquarePeg': 'square-peg', |
||||
'Nunito': 'nunito', |
||||
'Pacifico': 'pacifico', |
||||
'Roboto Mono': 'roboto-mono', |
||||
'Clear'.i18n: 'Clear' |
||||
}; |
||||
return rawItemsMap; |
||||
} |
||||
|
||||
String? _getKeyName(String value) { |
||||
for (final entry in rawItemsMap.entries) { |
||||
if (entry.value == value) { |
||||
return entry.key; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
double get iconSize { |
||||
final iconSize = options.iconSize; |
||||
return iconSize ?? 40; |
||||
// final baseFontSize = |
||||
// context.requireQuillToolbarBaseButtonOptions.globalIconSize; |
||||
// if (baseFontSize != iconSize) { |
||||
// return 40; |
||||
// } |
||||
// return iconSize ?? baseFontSize; |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
final baseButtonConfigurations = |
||||
context.requireQuillToolbarBaseButtonOptions; |
||||
final childBuilder = |
||||
options.childBuilder ?? baseButtonConfigurations.childBuilder; |
||||
if (childBuilder != null) { |
||||
return childBuilder( |
||||
options, |
||||
QuillToolbarFontFamilyButtonExtraOptions( |
||||
currentValue: _currentValue, |
||||
defaultDisplayText: _defaultDisplayText, |
||||
), |
||||
); |
||||
} |
||||
return ConstrainedBox( |
||||
constraints: BoxConstraints.tightFor( |
||||
height: iconSize * 1.81, |
||||
width: options.width, |
||||
), |
||||
child: UtilityWidgets.maybeWidget( |
||||
enabled: (options.tooltip ?? '').isNotEmpty || |
||||
options.overrideTooltipByFontFamily, |
||||
wrapper: (child) { |
||||
var effectiveTooltip = options.tooltip ?? ''; |
||||
if (options.overrideTooltipByFontFamily) { |
||||
effectiveTooltip = effectiveTooltip.isNotEmpty |
||||
? '$effectiveTooltip: $_currentValue' |
||||
: '${'Font'.i18n}: $_currentValue'; |
||||
} |
||||
return Tooltip(message: effectiveTooltip, child: child); |
||||
}, |
||||
child: RawMaterialButton( |
||||
visualDensity: VisualDensity.compact, |
||||
shape: RoundedRectangleBorder( |
||||
borderRadius: |
||||
BorderRadius.circular(options.iconTheme?.borderRadius ?? 2), |
||||
), |
||||
fillColor: options.fillColor, |
||||
elevation: 0, |
||||
hoverElevation: options.hoverElevation, |
||||
highlightElevation: options.hoverElevation, |
||||
onPressed: () { |
||||
_showMenu(); |
||||
options.afterButtonPressed?.call(); |
||||
}, |
||||
child: _buildContent(context), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
|
||||
Future<void> _showMenu() async { |
||||
final popupMenuTheme = PopupMenuTheme.of(context); |
||||
final button = context.findRenderObject() as RenderBox; |
||||
final overlay = Overlay.of(context).context.findRenderObject() as RenderBox; |
||||
final position = RelativeRect.fromRect( |
||||
Rect.fromPoints( |
||||
button.localToGlobal(Offset.zero, ancestor: overlay), |
||||
button.localToGlobal(button.size.bottomLeft(Offset.zero), |
||||
ancestor: overlay), |
||||
), |
||||
Offset.zero & overlay.size, |
||||
); |
||||
final newValue = await showMenu<String>( |
||||
context: context, |
||||
elevation: 4, |
||||
items: [ |
||||
for (final MapEntry<String, String> fontFamily in rawItemsMap.entries) |
||||
PopupMenuItem<String>( |
||||
key: ValueKey(fontFamily.key), |
||||
value: fontFamily.value, |
||||
height: options.itemHeight ?? kMinInteractiveDimension, |
||||
padding: options.itemPadding, |
||||
child: Text( |
||||
fontFamily.key.toString(), |
||||
style: TextStyle( |
||||
fontFamily: |
||||
options.renderFontFamilies ? fontFamily.value : null, |
||||
color: fontFamily.value == 'Clear' |
||||
? options.defaultItemColor |
||||
: null, |
||||
), |
||||
), |
||||
), |
||||
], |
||||
position: position, |
||||
shape: popupMenuTheme.shape, |
||||
color: popupMenuTheme.color, |
||||
); |
||||
if (!mounted) return; |
||||
if (newValue == null) { |
||||
return; |
||||
} |
||||
final keyName = _getKeyName(newValue); |
||||
setState(() { |
||||
_currentValue = keyName ?? _defaultDisplayText; |
||||
if (keyName != null) { |
||||
controller.formatSelection( |
||||
Attribute.fromKeyValue('font', newValue == 'Clear' ? null : newValue), |
||||
); |
||||
options.onSelected?.call(newValue); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
Widget _buildContent(BuildContext context) { |
||||
final theme = Theme.of(context); |
||||
final hasFinalWidth = options.width != null; |
||||
return Padding( |
||||
padding: options.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0), |
||||
child: Row( |
||||
mainAxisSize: !hasFinalWidth ? MainAxisSize.min : MainAxisSize.max, |
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
children: [ |
||||
UtilityWidgets.maybeWidget( |
||||
enabled: hasFinalWidth, |
||||
wrapper: (child) => Expanded(child: child), |
||||
child: Text( |
||||
_currentValue, |
||||
maxLines: 1, |
||||
overflow: options.labelOverflow, |
||||
style: options.style ?? |
||||
TextStyle( |
||||
fontSize: iconSize / 1.15, |
||||
color: options.iconTheme?.iconUnselectedColor ?? |
||||
theme.iconTheme.color, |
||||
), |
||||
), |
||||
), |
||||
const SizedBox(width: 3), |
||||
Icon( |
||||
Icons.arrow_drop_down, |
||||
size: iconSize / 1.15, |
||||
color: |
||||
options.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color, |
||||
) |
||||
], |
||||
), |
||||
); |
||||
} |
||||
} |
@ -0,0 +1,143 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../../../extensions.dart'; |
||||
import '../../../../translations.dart'; |
||||
import '../../../utils/extensions/build_context.dart'; |
||||
import '../../../utils/extensions/quill_controller.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class QuillToolbarHistoryButton extends StatefulWidget { |
||||
const QuillToolbarHistoryButton({ |
||||
required this.options, |
||||
super.key, |
||||
}); |
||||
|
||||
final QuillToolbarHistoryButtonOptions options; |
||||
|
||||
@override |
||||
_QuillToolbarHistoryButtonState createState() => |
||||
_QuillToolbarHistoryButtonState(); |
||||
} |
||||
|
||||
class _QuillToolbarHistoryButtonState extends State<QuillToolbarHistoryButton> { |
||||
late ThemeData theme; |
||||
var _canPressed = false; |
||||
|
||||
QuillToolbarHistoryButtonOptions get options { |
||||
return widget.options; |
||||
} |
||||
|
||||
QuillController get controller { |
||||
return options.controller.notNull(context); |
||||
} |
||||
|
||||
@override |
||||
void initState() { |
||||
super.initState(); |
||||
_listenForChanges(); // Listen for changes and change it |
||||
} |
||||
|
||||
Future<void> _listenForChanges() async { |
||||
if (isFlutterTest()) { |
||||
// We don't need to listen for changes in the tests |
||||
return; |
||||
} |
||||
await Future.delayed(Duration.zero); // Wait for the widget to built |
||||
_updateCanPressed(); // Set the init state |
||||
|
||||
// Listen for changes and change it |
||||
controller.changes.listen((event) async { |
||||
_updateCanPressed(); |
||||
}); |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
theme = Theme.of(context); |
||||
|
||||
final baseButtonConfigurations = |
||||
context.requireQuillToolbarBaseButtonOptions; |
||||
final tooltip = options.tooltip ?? |
||||
baseButtonConfigurations.tooltip ?? |
||||
(options.isUndo ? 'Undo'.i18n : 'Redo'.i18n); |
||||
final iconData = options.iconData ?? |
||||
baseButtonConfigurations.iconData ?? |
||||
(options.isUndo ? Icons.undo_outlined : Icons.redo_outlined); |
||||
final childBuilder = |
||||
options.childBuilder ?? baseButtonConfigurations.childBuilder; |
||||
final iconSize = options.iconSize ?? |
||||
context.requireQuillToolbarBaseButtonOptions.globalIconSize; |
||||
final iconTheme = options.iconTheme ?? baseButtonConfigurations.iconTheme; |
||||
|
||||
final fillColor = iconTheme?.iconUnselectedFillColor ?? theme.canvasColor; |
||||
|
||||
final afterButtonPressed = options.afterButtonPressed ?? |
||||
baseButtonConfigurations.afterButtonPressed; |
||||
|
||||
if (childBuilder != null) { |
||||
return childBuilder( |
||||
QuillToolbarHistoryButtonOptions( |
||||
isUndo: options.isUndo, |
||||
afterButtonPressed: afterButtonPressed, |
||||
controller: controller, |
||||
iconData: iconData, |
||||
iconSize: iconSize, |
||||
iconTheme: iconTheme, |
||||
tooltip: tooltip, |
||||
), |
||||
HistoryButtonExtraOptions( |
||||
onPressed: () { |
||||
_updateHistory(); |
||||
afterButtonPressed?.call(); |
||||
}, |
||||
canPressed: _canPressed, |
||||
), |
||||
); |
||||
} |
||||
return QuillIconButton( |
||||
tooltip: tooltip, |
||||
highlightElevation: 0, |
||||
hoverElevation: 0, |
||||
size: iconSize * kIconButtonFactor, |
||||
icon: Icon( |
||||
iconData, |
||||
size: iconSize, |
||||
color: _canPressed |
||||
? iconTheme?.iconUnselectedColor ?? theme.iconTheme.color |
||||
: iconTheme?.disabledIconColor ?? theme.disabledColor, |
||||
), |
||||
fillColor: fillColor, |
||||
borderRadius: iconTheme?.borderRadius ?? 2, |
||||
onPressed: _updateHistory, |
||||
afterPressed: afterButtonPressed, |
||||
); |
||||
} |
||||
|
||||
void _updateCanPressed() { |
||||
if (!mounted) return; |
||||
|
||||
setState(() { |
||||
if (options.isUndo) { |
||||
_canPressed = controller.hasUndo; |
||||
return; |
||||
} |
||||
_canPressed = controller.hasRedo; |
||||
}); |
||||
} |
||||
|
||||
void _updateHistory() { |
||||
if (options.isUndo) { |
||||
if (controller.hasUndo) { |
||||
controller.undo(); |
||||
} |
||||
// _updateCanPressed(); // We are already listeneting for the changes |
||||
return; |
||||
} |
||||
|
||||
if (controller.hasRedo) { |
||||
controller.redo(); |
||||
// _updateCanPressed(); // We are already listeneting for the changes |
||||
} |
||||
} |
||||
} |
@ -1,8 +1,8 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class IndentButton extends StatefulWidget { |
||||
const IndentButton({ |
@ -1,14 +1,14 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/rules/insert.dart'; |
||||
import '../../models/structs/link_dialog_action.dart'; |
||||
import '../../models/themes/quill_dialog_theme.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../translations/toolbar.i18n.dart'; |
||||
import '../controller.dart'; |
||||
import '../link.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/rules/insert.dart'; |
||||
import '../../../models/structs/link_dialog_action.dart'; |
||||
import '../../../models/themes/quill_dialog_theme.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../translations/toolbar.i18n.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../link.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class LinkStyleButton extends StatefulWidget { |
||||
const LinkStyleButton({ |
@ -1,12 +1,12 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../translations/toolbar.i18n.dart'; |
||||
import '../../utils/font.dart'; |
||||
import '../../utils/widgets.dart'; |
||||
import '../controller.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../translations/toolbar.i18n.dart'; |
||||
import '../../../utils/font.dart'; |
||||
import '../../../utils/widgets.dart'; |
||||
import '../../controller.dart'; |
||||
|
||||
class QuillFontSizeButton extends StatefulWidget { |
||||
const QuillFontSizeButton({ |
@ -1,6 +1,6 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../utils/widgets.dart'; |
||||
import '../../../utils/widgets.dart'; |
||||
|
||||
class QuillIconButton extends StatelessWidget { |
||||
const QuillIconButton({ |
@ -1,10 +1,10 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/themes/quill_dialog_theme.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import 'search_dialog.dart'; |
||||
import '../../../models/themes/quill_dialog_theme.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
import '../search_dialog.dart'; |
||||
|
||||
class SearchButton extends StatelessWidget { |
||||
const SearchButton({ |
@ -1,13 +1,13 @@ |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../utils/widgets.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import 'enum.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../utils/widgets.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
import '../enum.dart'; |
||||
|
||||
class SelectAlignmentButton extends StatefulWidget { |
||||
const SelectAlignmentButton({ |
@ -1,12 +1,12 @@ |
||||
import 'package:flutter/foundation.dart'; |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../utils/widgets.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../utils/widgets.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class SelectHeaderStyleButton extends StatefulWidget { |
||||
const SelectHeaderStyleButton({ |
@ -1,11 +1,11 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../utils/widgets.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../utils/widgets.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
class ToggleCheckListButton extends StatefulWidget { |
||||
const ToggleCheckListButton({ |
@ -1,11 +1,11 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../utils/widgets.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
import '../../../models/documents/attribute.dart'; |
||||
import '../../../models/documents/style.dart'; |
||||
import '../../../models/themes/quill_icon_theme.dart'; |
||||
import '../../../utils/widgets.dart'; |
||||
import '../../controller.dart'; |
||||
import '../../toolbar.dart'; |
||||
|
||||
typedef ToggleStyleButtonBuilder = Widget Function( |
||||
BuildContext context, |
@ -1,89 +0,0 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../controller.dart'; |
||||
import '../toolbar.dart'; |
||||
|
||||
class HistoryButton extends StatefulWidget { |
||||
const HistoryButton({ |
||||
required this.icon, |
||||
required this.controller, |
||||
required this.undo, |
||||
this.iconSize = kDefaultIconSize, |
||||
this.iconTheme, |
||||
this.afterButtonPressed, |
||||
this.tooltip, |
||||
Key? key, |
||||
}) : super(key: key); |
||||
|
||||
final IconData icon; |
||||
final double iconSize; |
||||
final bool undo; |
||||
final QuillController controller; |
||||
final QuillIconTheme? iconTheme; |
||||
final VoidCallback? afterButtonPressed; |
||||
final String? tooltip; |
||||
|
||||
@override |
||||
_HistoryButtonState createState() => _HistoryButtonState(); |
||||
} |
||||
|
||||
class _HistoryButtonState extends State<HistoryButton> { |
||||
Color? _iconColor; |
||||
late ThemeData theme; |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
theme = Theme.of(context); |
||||
_setIconColor(); |
||||
|
||||
final fillColor = |
||||
widget.iconTheme?.iconUnselectedFillColor ?? theme.canvasColor; |
||||
widget.controller.changes.listen((event) async { |
||||
_setIconColor(); |
||||
}); |
||||
return QuillIconButton( |
||||
tooltip: widget.tooltip, |
||||
highlightElevation: 0, |
||||
hoverElevation: 0, |
||||
size: widget.iconSize * kIconButtonFactor, |
||||
icon: Icon(widget.icon, size: widget.iconSize, color: _iconColor), |
||||
fillColor: fillColor, |
||||
borderRadius: widget.iconTheme?.borderRadius ?? 2, |
||||
onPressed: _changeHistory, |
||||
afterPressed: widget.afterButtonPressed, |
||||
); |
||||
} |
||||
|
||||
void _setIconColor() { |
||||
if (!mounted) return; |
||||
|
||||
if (widget.undo) { |
||||
setState(() { |
||||
_iconColor = widget.controller.hasUndo |
||||
? widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color |
||||
: widget.iconTheme?.disabledIconColor ?? theme.disabledColor; |
||||
}); |
||||
} else { |
||||
setState(() { |
||||
_iconColor = widget.controller.hasRedo |
||||
? widget.iconTheme?.iconUnselectedColor ?? theme.iconTheme.color |
||||
: widget.iconTheme?.disabledIconColor ?? theme.disabledColor; |
||||
}); |
||||
} |
||||
} |
||||
|
||||
void _changeHistory() { |
||||
if (widget.undo) { |
||||
if (widget.controller.hasUndo) { |
||||
widget.controller.undo(); |
||||
} |
||||
} else { |
||||
if (widget.controller.hasRedo) { |
||||
widget.controller.redo(); |
||||
} |
||||
} |
||||
|
||||
_setIconColor(); |
||||
} |
||||
} |
@ -1,238 +0,0 @@ |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
import '../../models/documents/attribute.dart'; |
||||
import '../../models/documents/style.dart'; |
||||
import '../../models/themes/quill_icon_theme.dart'; |
||||
import '../../translations/toolbar.i18n.dart'; |
||||
import '../../utils/widgets.dart'; |
||||
import '../controller.dart'; |
||||
|
||||
class QuillFontFamilyButton extends StatefulWidget { |
||||
const QuillFontFamilyButton({ |
||||
required this.rawItemsMap, |
||||
required this.attribute, |
||||
required this.controller, |
||||
@Deprecated('It is not required because of `rawItemsMap`') this.items, |
||||
this.onSelected, |
||||
this.iconSize = 40, |
||||
this.fillColor, |
||||
this.hoverElevation = 1, |
||||
this.highlightElevation = 1, |
||||
this.iconTheme, |
||||
this.afterButtonPressed, |
||||
this.tooltip, |
||||
this.padding, |
||||
this.style, |
||||
this.width, |
||||
this.renderFontFamilies = true, |
||||
this.initialValue, |
||||
this.labelOverflow = TextOverflow.visible, |
||||
this.overrideTooltipByFontFamily = false, |
||||
this.itemHeight, |
||||
this.itemPadding, |
||||
this.defaultItemColor = Colors.red, |
||||
Key? key, |
||||
}) : assert(rawItemsMap.length > 0), |
||||
assert(initialValue == null || initialValue.length > 0), |
||||
super(key: key); |
||||
|
||||
final double iconSize; |
||||
final Color? fillColor; |
||||
final double hoverElevation; |
||||
final double highlightElevation; |
||||
@Deprecated('It is not required because of `rawItemsMap`') |
||||
final List<PopupMenuEntry<String>>? items; |
||||
final Map<String, String> rawItemsMap; |
||||
final ValueChanged<String>? onSelected; |
||||
final QuillIconTheme? iconTheme; |
||||
final Attribute attribute; |
||||
final QuillController controller; |
||||
final VoidCallback? afterButtonPressed; |
||||
final String? tooltip; |
||||
final EdgeInsetsGeometry? padding; |
||||
final TextStyle? style; |
||||
final double? width; |
||||
final bool renderFontFamilies; |
||||
final String? initialValue; |
||||
final TextOverflow labelOverflow; |
||||
final bool overrideTooltipByFontFamily; |
||||
final double? itemHeight; |
||||
final EdgeInsets? itemPadding; |
||||
final Color? defaultItemColor; |
||||
|
||||
@override |
||||
_QuillFontFamilyButtonState createState() => _QuillFontFamilyButtonState(); |
||||
} |
||||
|
||||
class _QuillFontFamilyButtonState extends State<QuillFontFamilyButton> { |
||||
late String _defaultDisplayText; |
||||
late String _currentValue; |
||||
|
||||
Style get _selectionStyle => widget.controller.getSelectionStyle(); |
||||
|
||||
@override |
||||
void initState() { |
||||
super.initState(); |
||||
_currentValue = _defaultDisplayText = widget.initialValue ?? 'Font'.i18n; |
||||
widget.controller.addListener(_didChangeEditingValue); |
||||
} |
||||
|
||||
@override |
||||
void dispose() { |
||||
widget.controller.removeListener(_didChangeEditingValue); |
||||
super.dispose(); |
||||
} |
||||
|
||||
@override |
||||
void didUpdateWidget(covariant QuillFontFamilyButton oldWidget) { |
||||
super.didUpdateWidget(oldWidget); |
||||
if (oldWidget.controller != widget.controller) { |
||||
oldWidget.controller.removeListener(_didChangeEditingValue); |
||||
widget.controller.addListener(_didChangeEditingValue); |
||||
} |
||||
} |
||||
|
||||
void _didChangeEditingValue() { |
||||
final attribute = _selectionStyle.attributes[widget.attribute.key]; |
||||
if (attribute == null) { |
||||
setState(() => _currentValue = _defaultDisplayText); |
||||
return; |
||||
} |
||||
final keyName = _getKeyName(attribute.value); |
||||
setState(() => _currentValue = keyName ?? _defaultDisplayText); |
||||
} |
||||
|
||||
String? _getKeyName(String value) { |
||||
for (final entry in widget.rawItemsMap.entries) { |
||||
if (entry.value == value) { |
||||
return entry.key; |
||||
} |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
@override |
||||
Widget build(BuildContext context) { |
||||
return ConstrainedBox( |
||||
constraints: BoxConstraints.tightFor( |
||||
height: widget.iconSize * 1.81, |
||||
width: widget.width, |
||||
), |
||||
child: UtilityWidgets.maybeWidget( |
||||
enabled: (widget.tooltip ?? '').isNotEmpty || |
||||
widget.overrideTooltipByFontFamily, |
||||
wrapper: (child) { |
||||
var effectiveTooltip = widget.tooltip ?? ''; |
||||
if (widget.overrideTooltipByFontFamily) { |
||||
effectiveTooltip = effectiveTooltip.isNotEmpty |
||||
? '$effectiveTooltip: $_currentValue' |
||||
: '${'Font'.i18n}: $_currentValue'; |
||||
} |
||||
return Tooltip(message: effectiveTooltip, child: child); |
||||
}, |
||||
child: RawMaterialButton( |
||||
visualDensity: VisualDensity.compact, |
||||
shape: RoundedRectangleBorder( |
||||
borderRadius: |
||||
BorderRadius.circular(widget.iconTheme?.borderRadius ?? 2)), |
||||
fillColor: widget.fillColor, |
||||
elevation: 0, |
||||
hoverElevation: widget.hoverElevation, |
||||
highlightElevation: widget.hoverElevation, |
||||
onPressed: () { |
||||
_showMenu(); |
||||
widget.afterButtonPressed?.call(); |
||||
}, |
||||
child: _buildContent(context), |
||||
), |
||||
), |
||||
); |
||||
} |
||||
|
||||
void _showMenu() { |
||||
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, |
||||
); |
||||
showMenu<String>( |
||||
context: context, |
||||
elevation: 4, |
||||
items: [ |
||||
for (final MapEntry<String, String> fontFamily |
||||
in widget.rawItemsMap.entries) |
||||
PopupMenuItem<String>( |
||||
key: ValueKey(fontFamily.key), |
||||
value: fontFamily.value, |
||||
height: widget.itemHeight ?? kMinInteractiveDimension, |
||||
padding: widget.itemPadding, |
||||
child: Text( |
||||
fontFamily.key.toString(), |
||||
style: TextStyle( |
||||
fontFamily: widget.renderFontFamilies ? fontFamily.value : null, |
||||
color: fontFamily.value == 'Clear' |
||||
? widget.defaultItemColor |
||||
: null, |
||||
), |
||||
), |
||||
), |
||||
], |
||||
position: position, |
||||
shape: popupMenuTheme.shape, |
||||
color: popupMenuTheme.color, |
||||
).then((newValue) { |
||||
if (!mounted) return; |
||||
if (newValue == null) { |
||||
return; |
||||
} |
||||
final keyName = _getKeyName(newValue); |
||||
setState(() { |
||||
_currentValue = keyName ?? _defaultDisplayText; |
||||
if (keyName != null) { |
||||
widget.controller.formatSelection(Attribute.fromKeyValue( |
||||
'font', newValue == 'Clear' ? null : newValue)); |
||||
widget.onSelected?.call(newValue); |
||||
} |
||||
}); |
||||
}); |
||||
} |
||||
|
||||
Widget _buildContent(BuildContext context) { |
||||
final theme = Theme.of(context); |
||||
final hasFinalWidth = widget.width != null; |
||||
return Padding( |
||||
padding: widget.padding ?? const EdgeInsets.fromLTRB(10, 0, 0, 0), |
||||
child: Row( |
||||
mainAxisSize: !hasFinalWidth ? MainAxisSize.min : MainAxisSize.max, |
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
children: [ |
||||
UtilityWidgets.maybeWidget( |
||||
enabled: hasFinalWidth, |
||||
wrapper: (child) => Expanded(child: child), |
||||
child: Text( |
||||
_currentValue, |
||||
maxLines: 1, |
||||
overflow: widget.labelOverflow, |
||||
style: widget.style ?? |
||||
TextStyle( |
||||
fontSize: widget.iconSize / 1.15, |
||||
color: widget.iconTheme?.iconUnselectedColor ?? |
||||
theme.iconTheme.color), |
||||
), |
||||
), |
||||
const SizedBox(width: 3), |
||||
Icon(Icons.arrow_drop_down, |
||||
size: widget.iconSize / 1.15, |
||||
color: widget.iconTheme?.iconUnselectedColor ?? |
||||
theme.iconTheme.color) |
||||
], |
||||
), |
||||
); |
||||
} |
||||
} |
Loading…
Reference in new issue