pull/1566/head
Ellet 1 year ago
parent 039e3193d9
commit 35a9502d7e
No known key found for this signature in database
GPG Key ID: C488CC70BBCEF0D1
  1. 3
      CHANGELOG.md
  2. 8
      example/lib/presentation/quill/quill_screen.dart
  3. 3
      example/lib/presentation/quill/quill_toolbar.dart
  4. 5
      flutter_quill_extensions/lib/embeds/image/editor/image_embed.dart
  5. 13
      flutter_quill_extensions/lib/embeds/image/editor/image_menu.dart
  6. 5
      flutter_quill_extensions/lib/embeds/image/toolbar/image_button.dart
  7. 6
      flutter_quill_extensions/lib/embeds/image/toolbar/select_image_source.dart
  8. 5
      flutter_quill_extensions/lib/embeds/video/toolbar/video_button.dart
  9. 2
      flutter_quill_extensions/lib/models/config/shared_configurations.dart
  10. 30
      lib/src/extensions/quill_provider.dart
  11. 2
      lib/src/l10n/widgets/localizations.dart
  12. 6
      lib/src/models/config/editor/configurations.dart
  13. 46
      lib/src/models/config/others/animations.dart
  14. 15
      lib/src/models/config/quill_configurations.dart
  15. 7
      lib/src/models/config/quill_shared_configurations.dart
  16. 6
      lib/src/models/config/raw_editor/configurations.dart
  17. 4
      lib/src/models/config/toolbar/toolbar_configurations.dart
  18. 9
      lib/src/widgets/editor/editor.dart
  19. 2
      lib/src/widgets/raw_editor/raw_editor_actions.dart
  20. 14
      lib/src/widgets/raw_editor/raw_editor_state.dart
  21. 4
      lib/src/widgets/raw_editor/raw_editor_state_selection_delegate_mixin.dart
  22. 6
      lib/src/widgets/raw_editor/raw_editor_state_text_input_client_mixin.dart
  23. 17
      lib/src/widgets/style_widgets/checkbox_point.dart
  24. 9
      lib/src/widgets/toolbar/buttons/color/color.dart
  25. 8
      lib/src/widgets/toolbar/buttons/link_style.dart
  26. 8
      lib/src/widgets/toolbar/buttons/link_style2.dart
  27. 10
      lib/src/widgets/toolbar/buttons/search/search.dart
  28. 6
      lib/src/widgets/toolbar/toolbar.dart
  29. 3
      pubspec.yaml
  30. 28
      test/bug_fix_test.dart
  31. 24
      test/widgets/editor_test.dart

@ -2,6 +2,9 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## 9.0.0-dev
* **Major Breaking change**: The `QuillProvider` is now optional, the `controller` parameter has been moved to the `QuillEditor` and `QuillToolbar` once again.
## 8.6.4 ## 8.6.4
* The default value of `keyboardAppearance` for the iOS will be the one from the App/System theme mode instead of always using the `Brightness.light` * The default value of `keyboardAppearance` for the iOS will be the one from the App/System theme mode instead of always using the `Brightness.light`
* Fix typos in `README.md` * Fix typos in `README.md`

@ -101,11 +101,9 @@ class _QuillScreenState extends State<QuillScreen> {
], ],
), ),
body: QuillProvider( body: QuillProvider(
configurations: QuillConfigurations( configurations: const QuillConfigurations(
controller: _controller,
sharedConfigurations: QuillSharedConfigurations( sharedConfigurations: QuillSharedConfigurations(
animationConfigurations: QuillAnimationConfigurations.disableAll(), extraConfigurations: {
extraConfigurations: const {
QuillSharedExtensionsConfigurations.key: QuillSharedExtensionsConfigurations.key:
QuillSharedExtensionsConfigurations( QuillSharedExtensionsConfigurations(
assetsPrefix: 'assets', assetsPrefix: 'assets',
@ -117,6 +115,7 @@ class _QuillScreenState extends State<QuillScreen> {
children: [ children: [
if (!_isReadOnly) if (!_isReadOnly)
MyQuillToolbar( MyQuillToolbar(
controller: _controller,
focusNode: _editorFocusNode, focusNode: _editorFocusNode,
), ),
Builder( Builder(
@ -124,6 +123,7 @@ class _QuillScreenState extends State<QuillScreen> {
return Expanded( return Expanded(
child: MyQuillEditor( child: MyQuillEditor(
configurations: QuillEditorConfigurations( configurations: QuillEditorConfigurations(
controller: _controller,
readOnly: _isReadOnly, readOnly: _isReadOnly,
), ),
scrollController: _editorScrollController, scrollController: _editorScrollController,

@ -16,10 +16,12 @@ import 'embeds/timestamp_embed.dart';
class MyQuillToolbar extends StatelessWidget { class MyQuillToolbar extends StatelessWidget {
const MyQuillToolbar({ const MyQuillToolbar({
required this.controller,
required this.focusNode, required this.focusNode,
super.key, super.key,
}); });
final QuillController controller;
final FocusNode focusNode; final FocusNode focusNode;
Future<void> onImageInsertWithCropping( Future<void> onImageInsertWithCropping(
@ -224,6 +226,7 @@ class MyQuillToolbar extends StatelessWidget {
} }
return QuillToolbar( return QuillToolbar(
configurations: QuillToolbarConfigurations( configurations: QuillToolbarConfigurations(
controller: controller,
showAlignmentButtons: true, showAlignmentButtons: true,
buttonOptions: QuillToolbarButtonOptions( buttonOptions: QuillToolbarButtonOptions(
base: QuillToolbarBaseButtonOptions( base: QuillToolbarBaseButtonOptions(

@ -56,9 +56,7 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
onTap: configurations.onImageClicked ?? onTap: configurations.onImageClicked ??
() => showDialog( () => showDialog(
context: context, context: context,
builder: (_) => QuillProvider.value( builder: (_) => FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: ImageOptionsMenu( child: ImageOptionsMenu(
controller: controller, controller: controller,
configurations: configurations, configurations: configurations,
@ -69,7 +67,6 @@ class QuillEditorImageEmbedBuilder extends EmbedBuilder {
), ),
), ),
), ),
),
child: Builder( child: Builder(
builder: (context) { builder: (context) {
if (margin != null) { if (margin != null) {

@ -1,13 +1,7 @@
import 'package:flutter/cupertino.dart' show showCupertinoModalPopup; import 'package:flutter/cupertino.dart' show showCupertinoModalPopup;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' import 'package:flutter_quill/flutter_quill.dart'
show show ImageUrl, QuillController, StyleAttribute, getEmbedNode;
ImageUrl,
QuillController,
QuillProvider,
QuillProviderExt,
StyleAttribute,
getEmbedNode;
import 'package:flutter_quill/translations.dart'; import 'package:flutter_quill/translations.dart';
import '../../../models/config/editor/image/image.dart'; import '../../../models/config/editor/image/image.dart';
@ -55,9 +49,7 @@ class ImageOptionsMenu extends StatelessWidget {
context: context, context: context,
builder: (modalContext) { builder: (modalContext) {
final screenSize = MediaQuery.sizeOf(modalContext); final screenSize = MediaQuery.sizeOf(modalContext);
return QuillProvider.value( return FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: ImageResizer( child: ImageResizer(
onImageResize: (width, height) { onImageResize: (width, height) {
final res = getEmbedNode( final res = getEmbedNode(
@ -83,7 +75,6 @@ class ImageOptionsMenu extends StatelessWidget {
maxWidth: screenSize.width, maxWidth: screenSize.width,
maxHeight: screenSize.height, maxHeight: screenSize.height,
), ),
),
); );
}, },
); );

@ -172,16 +172,13 @@ class QuillToolbarImageButton extends StatelessWidget {
Future<String?> _typeLink(BuildContext context) async { Future<String?> _typeLink(BuildContext context) async {
final value = await showDialog<String>( final value = await showDialog<String>(
context: context, context: context,
builder: (_) => QuillProvider.value( builder: (_) => FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: TypeLinkDialog( child: TypeLinkDialog(
dialogTheme: options.dialogTheme, dialogTheme: options.dialogTheme,
linkRegExp: options.linkRegExp, linkRegExp: options.linkRegExp,
linkType: LinkType.image, linkType: LinkType.image,
), ),
), ),
),
); );
return value; return value;
} }

@ -1,6 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart' show isDesktop; import 'package:flutter_quill/extensions.dart' show isDesktop;
import 'package:flutter_quill/flutter_quill.dart';
import 'package:flutter_quill/translations.dart'; import 'package:flutter_quill/translations.dart';
import '../editor/image_embed_types.dart'; import '../editor/image_embed_types.dart';
@ -55,12 +54,9 @@ Future<InsertImageSource?> showSelectImageSourceDialog({
showDragHandle: true, showDragHandle: true,
context: context, context: context,
constraints: const BoxConstraints(maxWidth: 640), constraints: const BoxConstraints(maxWidth: 640),
builder: (_) => QuillProvider.value( builder: (_) => const FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: const FlutterQuillLocalizationsWidget(
child: SelectImageSourceDialog(), child: SelectImageSourceDialog(),
), ),
),
); );
return imageSource; return imageSource;
} }

@ -165,15 +165,12 @@ class QuillToolbarVideoButton extends StatelessWidget {
Future<String?> _typeLink(BuildContext context) async { Future<String?> _typeLink(BuildContext context) async {
final value = await showDialog<String>( final value = await showDialog<String>(
context: context, context: context,
builder: (_) => QuillProvider.value( builder: (_) => FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: TypeLinkDialog( child: TypeLinkDialog(
dialogTheme: options.dialogTheme, dialogTheme: options.dialogTheme,
linkType: LinkType.video, linkType: LinkType.video,
), ),
), ),
),
); );
return value; return value;
} }

@ -48,7 +48,7 @@ class QuillSharedExtensionsConfigurations {
required BuildContext context, required BuildContext context,
}) { }) {
final quillSharedExtensionsConfigurations = final quillSharedExtensionsConfigurations =
context.requireQuillSharedConfigurations.extraConfigurations[key]; context.quillSharedConfigurations?.extraConfigurations[key];
if (quillSharedExtensionsConfigurations != null) { if (quillSharedExtensionsConfigurations != null) {
if (quillSharedExtensionsConfigurations if (quillSharedExtensionsConfigurations
is! QuillSharedExtensionsConfigurations) { is! QuillSharedExtensionsConfigurations) {

@ -6,12 +6,6 @@ import '../../flutter_quill.dart';
/// Public shared extension /// Public shared extension
extension QuillProviderExt on BuildContext { extension QuillProviderExt on BuildContext {
/// return [QuillProvider] as not null
/// throw exception if it's not in the widget tree
QuillProvider get requireQuillProvider {
return QuillProvider.ofNotNull(this);
}
/// return nullable [QuillProvider] /// return nullable [QuillProvider]
/// don't throw exception if it's not in the widget tree /// don't throw exception if it's not in the widget tree
/// instead it will be null /// instead it will be null
@ -25,7 +19,8 @@ extension QuillProviderExt on BuildContext {
/// don't throw exception if [QuillProvider] is not in the widget tree /// don't throw exception if [QuillProvider] is not in the widget tree
/// instead it will be null /// instead it will be null
QuillController? get quilController { QuillController? get quilController {
return quillProvider?.configurations.controller; return quillToolbarConfigurations?.controller ??
quillEditorConfigurations?.controller;
} }
/// return [QuillController] as not null /// return [QuillController] as not null
@ -33,15 +28,10 @@ extension QuillProviderExt on BuildContext {
/// the provider widget first and then we will return the controller /// the provider widget first and then we will return the controller
/// throw exception if [QuillProvider] is not in the widget tree /// throw exception if [QuillProvider] is not in the widget tree
QuillController get requireQuillController { QuillController get requireQuillController {
return requireQuillProvider.configurations.controller; return quillToolbarConfigurations?.controller ??
} quillEditorConfigurations?.controller ??
(throw ArgumentError(
/// return [QuillConfigurations] as not null 'The quill provider is required, you must only call requireQuillController inside the QuillToolbar and QuillEditor'));
/// since the quill configurations is in the [QuillProvider] then we need to
/// get the provider widget first and then we will return quill configurations
/// throw exception if [QuillProvider] is not in the widget tree
QuillConfigurations get requireQuillConfigurations {
return requireQuillProvider.configurations;
} }
/// return nullable [QuillConfigurations] /// return nullable [QuillConfigurations]
@ -52,14 +42,6 @@ extension QuillProviderExt on BuildContext {
return quillProvider?.configurations; return quillProvider?.configurations;
} }
/// return [QuillSharedConfigurations] as not null. Since the quill
/// shared configurations is in the [QuillProvider] then we need to get the
/// provider widget first and then we will return shared configurations
/// throw exception if [QuillProvider] is not in the widget tree
QuillSharedConfigurations get requireQuillSharedConfigurations {
return requireQuillConfigurations.sharedConfigurations;
}
/// return nullable [QuillSharedConfigurations] . Since the quill /// return nullable [QuillSharedConfigurations] . Since the quill
/// shared configurations is in the [QuillProvider] then we need to get the /// shared configurations is in the [QuillProvider] then we need to get the
/// provider widget first and then we will return shared configurations /// provider widget first and then we will return shared configurations

@ -19,7 +19,7 @@ class FlutterQuillLocalizationsWidget extends StatelessWidget {
return child; return child;
} }
return Localizations( return Localizations(
locale: context.requireQuillSharedConfigurations.locale ?? locale: context.quillSharedConfigurations?.locale ??
Localizations.localeOf(context), Localizations.localeOf(context),
delegates: FlutterQuillLocalizations.localizationsDelegates, delegates: FlutterQuillLocalizations.localizationsDelegates,
child: child, child: child,

@ -6,6 +6,7 @@ import 'package:flutter/material.dart'
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:meta/meta.dart' show experimental; import 'package:meta/meta.dart' show experimental;
import '../../../widgets/controller.dart';
import '../../../widgets/default_styles.dart'; import '../../../widgets/default_styles.dart';
import '../../../widgets/delegate.dart'; import '../../../widgets/delegate.dart';
import '../../../widgets/editor/editor.dart'; import '../../../widgets/editor/editor.dart';
@ -24,6 +25,7 @@ class QuillEditorConfigurations extends Equatable {
/// Important note for the maintainers /// Important note for the maintainers
/// When editing this class please update the [copyWith] function too. /// When editing this class please update the [copyWith] function too.
const QuillEditorConfigurations({ const QuillEditorConfigurations({
required this.controller,
this.scrollable = true, this.scrollable = true,
this.padding = EdgeInsets.zero, this.padding = EdgeInsets.zero,
this.autoFocus = false, this.autoFocus = false,
@ -74,6 +76,8 @@ class QuillEditorConfigurations extends Equatable {
this.textInputAction = TextInputAction.newline, this.textInputAction = TextInputAction.newline,
}); });
final QuillController controller;
/// The text placeholder in the quill editor /// The text placeholder in the quill editor
final String? placeholder; final String? placeholder;
@ -331,6 +335,7 @@ class QuillEditorConfigurations extends Equatable {
// regenerate this function using extension in vs code or plugin in intellij // regenerate this function using extension in vs code or plugin in intellij
QuillEditorConfigurations copyWith({ QuillEditorConfigurations copyWith({
QuillController? controller,
String? placeholder, String? placeholder,
bool? readOnly, bool? readOnly,
bool? scrollable, bool? scrollable,
@ -376,6 +381,7 @@ class QuillEditorConfigurations extends Equatable {
TextInputAction? textInputAction, TextInputAction? textInputAction,
}) { }) {
return QuillEditorConfigurations( return QuillEditorConfigurations(
controller: controller ?? this.controller,
placeholder: placeholder ?? this.placeholder, placeholder: placeholder ?? this.placeholder,
readOnly: readOnly ?? this.readOnly, readOnly: readOnly ?? this.readOnly,
scrollable: scrollable ?? this.scrollable, scrollable: scrollable ?? this.scrollable,

@ -1,28 +1,28 @@
import 'package:equatable/equatable.dart'; // import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart' show experimental, immutable; // import 'package:meta/meta.dart' show experimental, immutable;
@immutable // @immutable
@experimental // @experimental
class QuillAnimationConfigurations extends Equatable { // class QuillAnimationConfigurations extends Equatable {
const QuillAnimationConfigurations({ // const QuillAnimationConfigurations({
required this.checkBoxPointItem, // required this.checkBoxPointItem,
}); // });
factory QuillAnimationConfigurations.disableAll() => // factory QuillAnimationConfigurations.disableAll() =>
const QuillAnimationConfigurations( // const QuillAnimationConfigurations(
checkBoxPointItem: false, // checkBoxPointItem: false,
); // );
factory QuillAnimationConfigurations.enableAll() => // factory QuillAnimationConfigurations.enableAll() =>
const QuillAnimationConfigurations( // const QuillAnimationConfigurations(
checkBoxPointItem: true, // checkBoxPointItem: true,
); // );
/// This currently has issue which the whole checkbox list will rebuilt // /// This currently has issue which the whole checkbox list will rebuilt
/// and the animation will replay when some value changes // /// and the animation will replay when some value changes
/// which is why disabled by default // /// which is why disabled by default
final bool checkBoxPointItem; // final bool checkBoxPointItem;
@override // @override
List<Object?> get props => []; // List<Object?> get props => [];
} // }

@ -10,17 +10,16 @@ export 'toolbar/toolbar_configurations.dart';
@immutable @immutable
class QuillConfigurations extends Equatable { class QuillConfigurations extends Equatable {
const QuillConfigurations({ const QuillConfigurations({
required this.controller,
this.sharedConfigurations = const QuillSharedConfigurations(), this.sharedConfigurations = const QuillSharedConfigurations(),
}); });
/// Controller object which establishes a link between a rich text document // /// Controller object which establishes a link between a rich text document
/// and this editor. // /// and this editor.
/// // ///
/// The controller is shared between [QuillEditorConfigurations] and // /// The controller is shared between [QuillEditorConfigurations] and
/// [QuillToolbarConfigurations] but to simplify things we will defined it // /// [QuillToolbarConfigurations] but to simplify things we will defined it
/// here, it should not be null // /// here, it should not be null
final QuillController controller; // final QuillController controller;
/// The shared configurations between [QuillEditorConfigurations] and /// The shared configurations between [QuillEditorConfigurations] and
/// [QuillToolbarConfigurations] so we don't duplicate things /// [QuillToolbarConfigurations] so we don't duplicate things

@ -15,9 +15,6 @@ class QuillSharedConfigurations extends Equatable {
this.dialogBarrierColor = Colors.black54, this.dialogBarrierColor = Colors.black54,
this.dialogTheme, this.dialogTheme,
this.locale, this.locale,
this.animationConfigurations = const QuillAnimationConfigurations(
checkBoxPointItem: false,
),
this.extraConfigurations = const {}, this.extraConfigurations = const {},
}); });
@ -37,9 +34,6 @@ class QuillSharedConfigurations extends Equatable {
/// `MaterialApp` or `WidgetsApp` /// `MaterialApp` or `WidgetsApp`
final Locale? locale; final Locale? locale;
/// To configure which animations you want to be enabled
final QuillAnimationConfigurations animationConfigurations;
/// Store custom configurations in here and use it in the widget tree /// Store custom configurations in here and use it in the widget tree
final Map<String, Object?> extraConfigurations; final Map<String, Object?> extraConfigurations;
@ -48,6 +42,5 @@ class QuillSharedConfigurations extends Equatable {
dialogBarrierColor, dialogBarrierColor,
dialogTheme, dialogTheme,
locale, locale,
animationConfigurations,
]; ];
} }

@ -49,7 +49,7 @@ class QuillRawEditorConfigurations extends Equatable {
this.showCursor = true, this.showCursor = true,
this.scrollable = true, this.scrollable = true,
this.padding = EdgeInsets.zero, this.padding = EdgeInsets.zero,
this.isReadOnly = false, this.readOnly = false,
this.placeholder, this.placeholder,
this.onLaunchUrl, this.onLaunchUrl,
this.contextMenuBuilder = defaultContextMenuBuilder, this.contextMenuBuilder = defaultContextMenuBuilder,
@ -97,7 +97,7 @@ class QuillRawEditorConfigurations extends Equatable {
/// by any shortcut or keyboard operation. The text is still selectable. /// by any shortcut or keyboard operation. The text is still selectable.
/// ///
/// Defaults to false. Must not be null. /// Defaults to false. Must not be null.
final bool isReadOnly; final bool readOnly;
final String? placeholder; final String? placeholder;
@ -296,7 +296,7 @@ class QuillRawEditorConfigurations extends Equatable {
@override @override
List<Object?> get props => [ List<Object?> get props => [
isReadOnly, readOnly,
placeholder, placeholder,
]; ];
} }

@ -3,6 +3,7 @@ import 'package:flutter/foundation.dart' show immutable;
import 'package:flutter/widgets.dart' import 'package:flutter/widgets.dart'
show Axis, Widget, WrapAlignment, WrapCrossAlignment; show Axis, Widget, WrapAlignment, WrapCrossAlignment;
import '../../../widgets/controller.dart';
import '../../../widgets/embeds.dart'; import '../../../widgets/embeds.dart';
import '../../themes/quill_dialog_theme.dart'; import '../../themes/quill_dialog_theme.dart';
import '../../themes/quill_icon_theme.dart'; import '../../themes/quill_icon_theme.dart';
@ -67,6 +68,7 @@ enum LinkStyleType {
@immutable @immutable
class QuillToolbarConfigurations extends QuillSharedToolbarProperties { class QuillToolbarConfigurations extends QuillSharedToolbarProperties {
const QuillToolbarConfigurations({ const QuillToolbarConfigurations({
required this.controller,
super.toolbarSectionSpacing = kToolbarSectionSpacing, super.toolbarSectionSpacing = kToolbarSectionSpacing,
super.toolbarIconAlignment = WrapAlignment.center, super.toolbarIconAlignment = WrapAlignment.center,
super.toolbarIconCrossAlignment = WrapCrossAlignment.center, super.toolbarIconCrossAlignment = WrapCrossAlignment.center,
@ -143,6 +145,8 @@ class QuillToolbarConfigurations extends QuillSharedToolbarProperties {
return buttonOptions.base.globalIconSize * 2; return buttonOptions.base.globalIconSize * 2;
} }
final QuillController controller;
/// A widget that will placed between each button in the toolbar /// A widget that will placed between each button in the toolbar
/// can be used as a spacer /// can be used as a spacer
/// it will not used before the first button /// it will not used before the first button

@ -155,8 +155,7 @@ class QuillEditor extends StatefulWidget {
factory QuillEditor.basic({ factory QuillEditor.basic({
/// The configurations for the quill editor widget of flutter quill /// The configurations for the quill editor widget of flutter quill
QuillEditorConfigurations configurations = required QuillEditorConfigurations configurations,
const QuillEditorConfigurations(),
FocusNode? focusNode, FocusNode? focusNode,
ScrollController? scrollController, ScrollController? scrollController,
}) { }) {
@ -257,13 +256,13 @@ class QuillEditorState extends State<QuillEditor>
child: QuillRawEditor( child: QuillRawEditor(
key: _editorKey, key: _editorKey,
configurations: QuillRawEditorConfigurations( configurations: QuillRawEditorConfigurations(
controller: context.requireQuillController, controller: configurations.controller,
focusNode: widget.focusNode, focusNode: widget.focusNode,
scrollController: widget.scrollController, scrollController: widget.scrollController,
scrollable: configurations.scrollable, scrollable: configurations.scrollable,
scrollBottomInset: configurations.scrollBottomInset, scrollBottomInset: configurations.scrollBottomInset,
padding: configurations.padding, padding: configurations.padding,
isReadOnly: configurations.readOnly, readOnly: configurations.readOnly,
placeholder: configurations.placeholder, placeholder: configurations.placeholder,
onLaunchUrl: configurations.onLaunchUrl, onLaunchUrl: configurations.onLaunchUrl,
contextMenuBuilder: showSelectionToolbar contextMenuBuilder: showSelectionToolbar
@ -442,7 +441,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
} }
bool _isPositionSelected(TapUpDetails details) { bool _isPositionSelected(TapUpDetails details) {
if (_state.context.requireQuillController.document.isEmpty()) { if (_state.configurations.controller.document.isEmpty()) {
return false; return false;
} }
final pos = renderEditor!.getPositionForOffset(details.globalPosition); final pos = renderEditor!.getPositionForOffset(details.globalPosition);

@ -76,7 +76,7 @@ class QuillEditorDeleteTextAction<T extends DirectionalTextEditingIntent>
@override @override
bool get isActionEnabled => bool get isActionEnabled =>
!state.widget.configurations.isReadOnly && !state.widget.configurations.readOnly &&
state.textEditingValue.selection.isValid; state.textEditingValue.selection.isValid;
} }

@ -552,7 +552,7 @@ class QuillRawEditorState extends EditorState
controller.document.queryChild(controller.selection.baseOffset); controller.document.queryChild(controller.selection.baseOffset);
KeyEventResult insertTabCharacter() { KeyEventResult insertTabCharacter() {
if (widget.configurations.isReadOnly) { if (widget.configurations.readOnly) {
return KeyEventResult.ignored; return KeyEventResult.ignored;
} }
controller.replaceText(controller.selection.baseOffset, 0, '\t', null); controller.replaceText(controller.selection.baseOffset, 0, '\t', null);
@ -662,7 +662,7 @@ class QuillRawEditorState extends EditorState
void _handleCheckboxTap(int offset, bool value) { void _handleCheckboxTap(int offset, bool value) {
final requestKeyboardFocusOnCheckListChanged = final requestKeyboardFocusOnCheckListChanged =
widget.configurations.requestKeyboardFocusOnCheckListChanged; widget.configurations.requestKeyboardFocusOnCheckListChanged;
if (!widget.configurations.isReadOnly) { if (!widget.configurations.readOnly) {
_disableScrollControllerAnimateOnce = true; _disableScrollControllerAnimateOnce = true;
final currentSelection = controller.selection.copyWith(); final currentSelection = controller.selection.copyWith();
final attribute = value ? Attribute.checked : Attribute.unchecked; final attribute = value ? Attribute.checked : Attribute.unchecked;
@ -737,7 +737,7 @@ class QuillRawEditorState extends EditorState
indentLevelCounts: indentLevelCounts, indentLevelCounts: indentLevelCounts,
clearIndents: clearIndents, clearIndents: clearIndents,
onCheckboxTap: _handleCheckboxTap, onCheckboxTap: _handleCheckboxTap,
readOnly: widget.configurations.isReadOnly, readOnly: widget.configurations.readOnly,
customStyleBuilder: widget.configurations.customStyleBuilder, customStyleBuilder: widget.configurations.customStyleBuilder,
customLinkPrefixes: widget.configurations.customLinkPrefixes, customLinkPrefixes: widget.configurations.customLinkPrefixes,
); );
@ -767,7 +767,7 @@ class QuillRawEditorState extends EditorState
customStyleBuilder: widget.configurations.customStyleBuilder, customStyleBuilder: widget.configurations.customStyleBuilder,
customRecognizerBuilder: widget.configurations.customRecognizerBuilder, customRecognizerBuilder: widget.configurations.customRecognizerBuilder,
styles: _styles!, styles: _styles!,
readOnly: widget.configurations.isReadOnly, readOnly: widget.configurations.readOnly,
controller: controller, controller: controller,
linkActionPicker: _linkActionPicker, linkActionPicker: _linkActionPicker,
onLaunchUrl: widget.configurations.onLaunchUrl, onLaunchUrl: widget.configurations.onLaunchUrl,
@ -968,7 +968,7 @@ class QuillRawEditorState extends EditorState
if (!shouldCreateInputConnection) { if (!shouldCreateInputConnection) {
closeConnectionIfNeeded(); closeConnectionIfNeeded();
} else { } else {
if (oldWidget.configurations.isReadOnly && _hasFocus) { if (oldWidget.configurations.readOnly && _hasFocus) {
openConnectionIfNeeded(); openConnectionIfNeeded();
} }
} }
@ -1298,7 +1298,7 @@ class QuillRawEditorState extends EditorState
_pastePlainText = controller.getPlainText(); _pastePlainText = controller.getPlainText();
_pasteStyleAndEmbed = controller.getAllIndividualSelectionStylesAndEmbed(); _pasteStyleAndEmbed = controller.getAllIndividualSelectionStylesAndEmbed();
if (widget.configurations.isReadOnly) { if (widget.configurations.readOnly) {
return; return;
} }
final selection = textEditingValue.selection; final selection = textEditingValue.selection;
@ -1318,7 +1318,7 @@ class QuillRawEditorState extends EditorState
/// Paste text from [Clipboard]. /// Paste text from [Clipboard].
@override @override
Future<void> pasteText(SelectionChangedCause cause) async { Future<void> pasteText(SelectionChangedCause cause) async {
if (widget.configurations.isReadOnly) { if (widget.configurations.readOnly) {
return; return;
} }

@ -171,7 +171,7 @@ mixin RawEditorStateSelectionDelegateMixin on EditorState
@override @override
bool get cutEnabled => bool get cutEnabled =>
widget.configurations.contextMenuBuilder != null && widget.configurations.contextMenuBuilder != null &&
!widget.configurations.isReadOnly; !widget.configurations.readOnly;
@override @override
bool get copyEnabled => widget.configurations.contextMenuBuilder != null; bool get copyEnabled => widget.configurations.contextMenuBuilder != null;
@ -179,7 +179,7 @@ mixin RawEditorStateSelectionDelegateMixin on EditorState
@override @override
bool get pasteEnabled => bool get pasteEnabled =>
widget.configurations.contextMenuBuilder != null && widget.configurations.contextMenuBuilder != null &&
!widget.configurations.isReadOnly; !widget.configurations.readOnly;
@override @override
bool get selectAllEnabled => widget.configurations.contextMenuBuilder != null; bool get selectAllEnabled => widget.configurations.contextMenuBuilder != null;

@ -30,7 +30,7 @@ mixin RawEditorStateTextInputClientMixin on EditorState
/// - cmd/ctrl+a to select all. /// - cmd/ctrl+a to select all.
/// - Changing the selection using a physical keyboard. /// - Changing the selection using a physical keyboard.
bool get shouldCreateInputConnection => bool get shouldCreateInputConnection =>
kIsWeb || !widget.configurations.isReadOnly; kIsWeb || !widget.configurations.readOnly;
/// Returns `true` if there is open input connection. /// Returns `true` if there is open input connection.
bool get hasConnection => bool get hasConnection =>
@ -58,9 +58,9 @@ mixin RawEditorStateTextInputClientMixin on EditorState
this, this,
TextInputConfiguration( TextInputConfiguration(
inputType: TextInputType.multiline, inputType: TextInputType.multiline,
readOnly: widget.configurations.isReadOnly, readOnly: widget.configurations.readOnly,
inputAction: widget.configurations.textInputAction, inputAction: widget.configurations.textInputAction,
enableSuggestions: !widget.configurations.isReadOnly, enableSuggestions: !widget.configurations.readOnly,
keyboardAppearance: widget.configurations.keyboardAppearance ?? keyboardAppearance: widget.configurations.keyboardAppearance ??
CupertinoTheme.maybeBrightnessOf(context) ?? CupertinoTheme.maybeBrightnessOf(context) ??
Theme.of(context).brightness, Theme.of(context).brightness,

@ -1,7 +1,4 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart';
import '../../extensions/quill_provider.dart';
class QuillEditorCheckboxPoint extends StatefulWidget { class QuillEditorCheckboxPoint extends StatefulWidget {
const QuillEditorCheckboxPoint({ const QuillEditorCheckboxPoint({
@ -76,20 +73,6 @@ class QuillEditorCheckboxPointState extends State<QuillEditorCheckboxPoint> {
), ),
), ),
); );
if (context.requireQuillSharedConfigurations.animationConfigurations
.checkBoxPointItem) {
return Animate(
effects: const [
SlideEffect(
duration: Duration(milliseconds: 70),
),
ScaleEffect(
duration: Duration(milliseconds: 70),
)
],
child: child,
);
}
return child; return child;
} }
} }

@ -8,7 +8,6 @@ import '../../../../models/documents/style.dart';
import '../../../../models/themes/quill_icon_theme.dart'; import '../../../../models/themes/quill_icon_theme.dart';
import '../../../../utils/color.dart'; import '../../../../utils/color.dart';
import '../../../controller.dart'; import '../../../controller.dart';
import '../../../utils/provider.dart';
import '../../base_toolbar.dart'; import '../../base_toolbar.dart';
import 'dialog.dart'; import 'dialog.dart';
@ -226,10 +225,9 @@ class QuillToolbarColorButtonState extends State<QuillToolbarColorButton> {
showDialog<String>( showDialog<String>(
context: context, context: context,
barrierColor: options.dialogBarrierColor ?? barrierColor: options.dialogBarrierColor ??
context.requireQuillSharedConfigurations.dialogBarrierColor, context.quillSharedConfigurations?.dialogBarrierColor ??
builder: (_) => QuillProvider.value( Colors.black54,
value: context.requireQuillProvider, builder: (_) => FlutterQuillLocalizationsWidget(
child: FlutterQuillLocalizationsWidget(
child: ColorPickerDialog( child: ColorPickerDialog(
isBackground: widget.isBackground, isBackground: widget.isBackground,
onRequestChangeColor: _changeColor, onRequestChangeColor: _changeColor,
@ -237,7 +235,6 @@ class QuillToolbarColorButtonState extends State<QuillToolbarColorButton> {
selectionStyle: _selectionStyle, selectionStyle: _selectionStyle,
), ),
), ),
),
); );
} }
} }

@ -100,7 +100,8 @@ class QuillToolbarLinkStyleButtonState
Color get dialogBarrierColor { Color get dialogBarrierColor {
return options.dialogBarrierColor ?? return options.dialogBarrierColor ??
context.requireQuillSharedConfigurations.dialogBarrierColor; context.quillSharedConfigurations?.dialogBarrierColor ??
Colors.black54;
} }
RegExp? get linkRegExp { RegExp? get linkRegExp {
@ -181,9 +182,7 @@ class QuillToolbarLinkStyleButtonState
final len = controller.selection.end - index; final len = controller.selection.end - index;
text ??= len == 0 ? '' : controller.document.getPlainText(index, len); text ??= len == 0 ? '' : controller.document.getPlainText(index, len);
return QuillProvider.value( return FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: _LinkDialog( child: _LinkDialog(
dialogTheme: options.dialogTheme, dialogTheme: options.dialogTheme,
link: link, link: link,
@ -191,7 +190,6 @@ class QuillToolbarLinkStyleButtonState
linkRegExp: linkRegExp, linkRegExp: linkRegExp,
action: options.linkDialogAction, action: options.linkDialogAction,
), ),
),
); );
}, },
); );

@ -107,7 +107,8 @@ class _QuillToolbarLinkStyleButton2State
Color get dialogBarrierColor { Color get dialogBarrierColor {
return options.dialogBarrierColor ?? return options.dialogBarrierColor ??
context.requireQuillSharedConfigurations.dialogBarrierColor; context.quillSharedConfigurations?.dialogBarrierColor ??
Colors.black54;
} }
@override @override
@ -173,9 +174,7 @@ class _QuillToolbarLinkStyleButton2State
final textLink = await showDialog<QuillTextLink>( final textLink = await showDialog<QuillTextLink>(
context: context, context: context,
barrierColor: dialogBarrierColor, barrierColor: dialogBarrierColor,
builder: (_) => QuillProvider.value( builder: (_) => FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: LinkStyleDialog( child: LinkStyleDialog(
dialogTheme: options.dialogTheme, dialogTheme: options.dialogTheme,
text: initialTextLink.text, text: initialTextLink.text,
@ -190,7 +189,6 @@ class _QuillToolbarLinkStyleButton2State
buttonSize: options.buttonSize, buttonSize: options.buttonSize,
), ),
), ),
),
); );
if (textLink != null) { if (textLink != null) {

@ -63,12 +63,13 @@ class QuillToolbarSearchButton extends StatelessWidget {
Color _dialogBarrierColor(BuildContext context) { Color _dialogBarrierColor(BuildContext context) {
return options.dialogBarrierColor ?? return options.dialogBarrierColor ??
context.requireQuillSharedConfigurations.dialogBarrierColor; context.quillSharedConfigurations?.dialogBarrierColor ??
Colors.black54;
} }
QuillDialogTheme? _dialogTheme(BuildContext context) { QuillDialogTheme? _dialogTheme(BuildContext context) {
return options.dialogTheme ?? return options.dialogTheme ??
context.requireQuillSharedConfigurations.dialogTheme; context.quillSharedConfigurations?.dialogTheme;
} }
@override @override
@ -142,16 +143,13 @@ class QuillToolbarSearchButton extends StatelessWidget {
await showDialog<String>( await showDialog<String>(
barrierColor: _dialogBarrierColor(context), barrierColor: _dialogBarrierColor(context),
context: context, context: context,
builder: (_) => QuillProvider.value( builder: (_) => FlutterQuillLocalizationsWidget(
value: context.requireQuillProvider,
child: FlutterQuillLocalizationsWidget(
child: QuillToolbarSearchDialog( child: QuillToolbarSearchDialog(
controller: controller, controller: controller,
dialogTheme: _dialogTheme(context), dialogTheme: _dialogTheme(context),
text: '', text: '',
), ),
), ),
),
); );
} }
} }

@ -9,8 +9,8 @@ import 'base_toolbar.dart';
class QuillToolbar extends StatelessWidget implements PreferredSizeWidget { class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
const QuillToolbar({ const QuillToolbar({
required this.configurations,
super.key, super.key,
this.configurations = const QuillToolbarConfigurations(),
}); });
/// The configurations for the toolbar widget of flutter quill /// The configurations for the toolbar widget of flutter quill
@ -71,7 +71,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
toolbarConfigurations.buttonOptions.base.globalIconSize; toolbarConfigurations.buttonOptions.base.globalIconSize;
final axis = toolbarConfigurations.axis; final axis = toolbarConfigurations.axis;
final globalController = context.requireQuillController; final globalController = configurations.controller;
final spacerWidget = final spacerWidget =
configurations.spacerWidget ?? const SizedBox.shrink(); configurations.spacerWidget ?? const SizedBox.shrink();
@ -270,7 +270,7 @@ class QuillToolbar extends StatelessWidget implements PreferredSizeWidget {
options: toolbarConfigurations.buttonOptions.direction, options: toolbarConfigurations.buttonOptions.direction,
controller: toolbarConfigurations controller: toolbarConfigurations
.buttonOptions.direction.controller ?? .buttonOptions.direction.controller ??
context.requireQuillController, globalController,
), ),
spacerWidget, spacerWidget,
], ],

@ -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: 8.6.4 version: 9.0.0-dev
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/
issue_tracker: https://github.com/singerdmx/flutter-quill/issues/ issue_tracker: https://github.com/singerdmx/flutter-quill/issues/
@ -50,7 +50,6 @@ dependencies:
characters: ^1.3.0 characters: ^1.3.0
diff_match_patch: ^0.4.1 diff_match_patch: ^0.4.1
equatable: ^2.0.5 equatable: ^2.0.5
flutter_animate: ^4.2.0+1
meta: ^1.9.1 meta: ^1.9.1
# Plugins # Plugins

@ -16,14 +16,11 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: QuillProvider( home: QuillToolbar(
configurations: QuillConfigurations(
controller: controller,
),
child: const QuillToolbar(
configurations: QuillToolbarConfigurations( configurations: QuillToolbarConfigurations(
controller: controller,
showRedo: false, showRedo: false,
customButtons: [ customButtons: const [
QuillToolbarCustomButtonOptions( QuillToolbarCustomButtonOptions(
tooltip: tooltip, tooltip: tooltip,
) )
@ -31,7 +28,6 @@ void main() {
), ),
), ),
), ),
),
); );
final builtinFinder = find.descendant( final builtinFinder = find.descendant(
@ -64,7 +60,8 @@ void main() {
controller = QuillController.basic(); controller = QuillController.basic();
editor = QuillEditor.basic( editor = QuillEditor.basic(
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
configurations: const QuillEditorConfigurations( configurations: QuillEditorConfigurations(
controller: controller,
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
readOnly: false, readOnly: false,
), ),
@ -78,14 +75,11 @@ void main() {
testWidgets('Refocus editor after controller clears document', testWidgets('Refocus editor after controller clears document',
(tester) async { (tester) async {
await tester.pumpWidget( await tester.pumpWidget(
QuillProvider( MaterialApp(
configurations: QuillConfigurations(controller: controller),
child: MaterialApp(
home: Column( home: Column(
children: [editor], children: [editor],
), ),
), ),
),
); );
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
@ -99,13 +93,10 @@ void main() {
testWidgets('Refocus editor after removing block attribute', testWidgets('Refocus editor after removing block attribute',
(tester) async { (tester) async {
await tester.pumpWidget(QuillProvider( await tester.pumpWidget(MaterialApp(
configurations: QuillConfigurations(controller: controller),
child: MaterialApp(
home: Column( home: Column(
children: [editor], children: [editor],
), ),
),
)); ));
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
@ -120,14 +111,11 @@ void main() {
testWidgets('Tap checkbox in unfocused editor', (tester) async { testWidgets('Tap checkbox in unfocused editor', (tester) async {
await tester.pumpWidget( await tester.pumpWidget(
QuillProvider( MaterialApp(
configurations: QuillConfigurations(controller: controller),
child: MaterialApp(
home: Column( home: Column(
children: [editor], children: [editor],
), ),
), ),
),
); );
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); await tester.quillEnterText(find.byType(QuillEditor), 'test\n');

@ -21,18 +21,16 @@ void main() {
group('QuillEditor', () { group('QuillEditor', () {
testWidgets('Keyboard entered text is stored in document', (tester) async { testWidgets('Keyboard entered text is stored in document', (tester) async {
await tester.pumpWidget( await tester.pumpWidget(
QuillProvider( MaterialApp(
configurations: QuillConfigurations(controller: controller),
child: MaterialApp(
home: QuillEditor.basic( home: QuillEditor.basic(
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
configurations: const QuillEditorConfigurations( configurations: QuillEditorConfigurations(
controller: controller,
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
readOnly: false, readOnly: false,
), ),
), ),
), ),
),
); );
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
@ -43,14 +41,11 @@ void main() {
String? latestUri; String? latestUri;
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: QuillProvider( home: QuillEditor(
configurations: QuillConfigurations(
controller: controller,
),
child: QuillEditor(
focusNode: FocusNode(), focusNode: FocusNode(),
scrollController: ScrollController(), scrollController: ScrollController(),
configurations: QuillEditorConfigurations( configurations: QuillEditorConfigurations(
controller: controller,
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
readOnly: false, readOnly: false,
autoFocus: true, autoFocus: true,
@ -64,7 +59,6 @@ void main() {
), ),
), ),
), ),
),
); );
await tester.tap(find.byType(QuillEditor)); await tester.tap(find.byType(QuillEditor));
await tester.quillEnterText(find.byType(QuillEditor), 'test\n'); await tester.quillEnterText(find.byType(QuillEditor), 'test\n');
@ -120,15 +114,12 @@ void main() {
testWidgets('custom context menu builder', (tester) async { testWidgets('custom context menu builder', (tester) async {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: QuillProvider( home: QuillEditor(
configurations: QuillConfigurations(
controller: controller,
),
child: QuillEditor(
focusNode: FocusNode(), focusNode: FocusNode(),
scrollController: ScrollController(), scrollController: ScrollController(),
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
configurations: QuillEditorConfigurations( configurations: QuillEditorConfigurations(
controller: controller,
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
readOnly: false, readOnly: false,
autoFocus: true, autoFocus: true,
@ -137,7 +128,6 @@ void main() {
), ),
), ),
), ),
),
); );
// Long press to show menu // Long press to show menu

Loading…
Cancel
Save