Organize editor configurations

pull/2078/head
AtlasAutocode 9 months ago
parent 6978512b89
commit e6f600f633
  1. 4
      example/lib/screens/simple/simple_screen.dart
  2. 10
      lib/src/controller/quill_controller.dart
  3. 5
      lib/src/controller/quill_controller_configurations.dart
  4. 9
      lib/src/editor/config/editor_configurations.dart
  5. 68
      lib/src/editor/editor.dart
  6. 19
      lib/src/editor/provider.dart
  7. 4
      test/bug_fix_test.dart
  8. 11
      test/editor/editor_test.dart

@ -23,9 +23,9 @@ class _SimpleScreenState extends State<SimpleScreen> {
), ),
Expanded( Expanded(
child: QuillEditor.basic( child: QuillEditor.basic(
configurations: QuillEditorConfigurations(
controller: _controller, controller: _controller,
padding: const EdgeInsets.all(16), configurations: const QuillEditorConfigurations(
padding: EdgeInsets.all(16),
), ),
), ),
), ),

@ -52,10 +52,14 @@ class QuillController extends ChangeNotifier {
final QuillControllerConfigurations configurations; final QuillControllerConfigurations configurations;
/// Local copy of editor configurations enables fail-safe setting from editor _initState method /// Editor configurations
///
/// Global default can be set in QuillControllerConfigurations.
/// Can be overridden by setting in QuillEditor ctor.
/// Fail safe: returns a default editor configuration.
QuillEditorConfigurations? _editorConfigurations; QuillEditorConfigurations? _editorConfigurations;
QuillEditorConfigurations? get editorConfigurations => QuillEditorConfigurations get editorConfigurations =>
configurations.editorConfigurations ?? _editorConfigurations; _editorConfigurations ?? configurations.editorConfigurations ?? const QuillEditorConfigurations();
set editorConfigurations(QuillEditorConfigurations? value) => set editorConfigurations(QuillEditorConfigurations? value) =>
_editorConfigurations = value; _editorConfigurations = value;

@ -1,8 +1,10 @@
import '../editor/config/editor_configurations.dart'; import '../editor/config/editor_configurations.dart' show QuillEditorConfigurations;
import '../toolbar/config/toolbar_configurations.dart';
class QuillControllerConfigurations { class QuillControllerConfigurations {
const QuillControllerConfigurations( const QuillControllerConfigurations(
{this.editorConfigurations, {this.editorConfigurations,
this.toolbarConfigurations,
this.onClipboardPaste, this.onClipboardPaste,
this.requireScriptFontFeatures = false}); this.requireScriptFontFeatures = false});
@ -10,6 +12,7 @@ class QuillControllerConfigurations {
/// ///
/// Future: will be changed to 'required final' /// Future: will be changed to 'required final'
final QuillEditorConfigurations? editorConfigurations; final QuillEditorConfigurations? editorConfigurations;
final QuillToolbarConfigurations? toolbarConfigurations;
/// Callback when the user pastes and data has not already been processed /// Callback when the user pastes and data has not already been processed
/// ///

@ -24,7 +24,8 @@ 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, @Deprecated('controller should be passed directly to the editor - this parameter will be removed in future versions.')
this.controller,
this.sharedConfigurations = const QuillSharedConfigurations(), this.sharedConfigurations = const QuillSharedConfigurations(),
this.scrollable = true, this.scrollable = true,
this.padding = EdgeInsets.zero, this.padding = EdgeInsets.zero,
@ -86,7 +87,7 @@ class QuillEditorConfigurations extends Equatable {
final QuillSharedConfigurations sharedConfigurations; final QuillSharedConfigurations sharedConfigurations;
final QuillController controller; final QuillController? controller;
/// The text placeholder in the quill editor /// The text placeholder in the quill editor
final String? placeholder; final String? placeholder;
@ -97,7 +98,7 @@ class QuillEditorConfigurations 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`.
bool get readOnly => controller.readOnly; bool get readOnly => controller?.readOnly != false;
/// Override [readOnly] for checkbox. /// Override [readOnly] for checkbox.
/// ///
@ -381,7 +382,7 @@ class QuillEditorConfigurations extends Equatable {
@override @override
List<Object?> get props => [ List<Object?> get props => [
placeholder, placeholder,
controller.readOnly, controller?.readOnly,
]; ];
// We might use code generator like freezed but sometimes it can be limited // We might use code generator like freezed but sometimes it can be limited

@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import '../common/utils/platform.dart'; import '../common/utils/platform.dart';
import '../controller/quill_controller.dart';
import '../document/attribute.dart'; import '../document/attribute.dart';
import '../document/document.dart'; import '../document/document.dart';
import '../document/nodes/container.dart' as container_node; import '../document/nodes/container.dart' as container_node;
@ -120,36 +121,56 @@ abstract class RenderAbstractEditor implements TextLayoutMetrics {
} }
class QuillEditor extends StatefulWidget { class QuillEditor extends StatefulWidget {
const QuillEditor({
required this.configurations, //TODO - sample code
factory QuillEditor ({
required FocusNode focusNode,
required ScrollController scrollController,
/// Controller and configurations are required
///
/// Prefer: use controller and pass QuillEditorConfigurations in constructor for controller (using QuillControllerConfigurations).
/// Backward compatibility: use configurations and pass QuillController in constructor for configurations. (Will be removed in future versions.)
QuillController? controller,
QuillEditorConfigurations? configurations,
}) {
controller ??= configurations?.controller;
assert (controller != null, 'controller required. Provide controller directly (preferred) or indirectly through configurations (not recommended - will be removed in future versions).');
controller ??= QuillController(document: Document(), selection: const TextSelection.collapsed(offset: 0));
//
controller
..editorConfigurations = configurations
..editorFocusNode = focusNode;
//
return QuillEditor._(focusNode: focusNode, scrollController: scrollController, controller: controller);
}
const QuillEditor._({
required this.focusNode, required this.focusNode,
required this.scrollController, required this.scrollController,
super.key, required this.controller
}); });
factory QuillEditor.basic({ factory QuillEditor.basic({
/// The controller for the quill editor widget of flutter quill
QuillController? controller,
/// The configurations for the quill editor widget of flutter quill /// The configurations for the quill editor widget of flutter quill
required QuillEditorConfigurations configurations, QuillEditorConfigurations? configurations,
FocusNode? focusNode, FocusNode? focusNode,
ScrollController? scrollController, ScrollController? scrollController,
}) { }) {
return QuillEditor( return QuillEditor(
scrollController: scrollController ?? ScrollController(), scrollController: scrollController ?? ScrollController(),
focusNode: focusNode ?? FocusNode(), focusNode: focusNode ?? FocusNode(),
configurations: configurations.copyWith( controller: controller,
textSelectionThemeData: configurations.textSelectionThemeData, configurations: configurations?.copyWith(),
autoFocus: configurations.autoFocus,
expands: configurations.expands,
padding: configurations.padding,
keyboardAppearance: configurations.keyboardAppearance,
embedBuilders: configurations.embedBuilders,
editorKey: configurations.editorKey,
),
); );
} }
/// The controller for the quill editor widget of flutter quill
final QuillController controller;
/// The configurations for the quill editor widget of flutter quill /// The configurations for the quill editor widget of flutter quill
final QuillEditorConfigurations configurations; QuillEditorConfigurations get configurations => controller.editorConfigurations;
/// Controls whether this editor has keyboard focus. /// Controls whether this editor has keyboard focus.
final FocusNode focusNode; final FocusNode focusNode;
@ -167,9 +188,9 @@ class QuillEditorState extends State<QuillEditor>
late EditorTextSelectionGestureDetectorBuilder late EditorTextSelectionGestureDetectorBuilder
_selectionGestureDetectorBuilder; _selectionGestureDetectorBuilder;
QuillEditorConfigurations get configurations { QuillController get controller => widget.controller;
return widget.configurations;
} QuillEditorConfigurations get configurations => widget.configurations;
@override @override
void initState() { void initState() {
@ -181,11 +202,7 @@ class QuillEditorState extends State<QuillEditor>
configurations.detectWordBoundary, configurations.detectWordBoundary,
); );
widget.configurations.controller.editorConfigurations ??= final focusNode = widget.focusNode;
widget.configurations;
final focusNode =
widget.configurations.controller.editorFocusNode ??= widget.focusNode;
if (configurations.autoFocus) { if (configurations.autoFocus) {
focusNode.requestFocus(); focusNode.requestFocus();
@ -241,13 +258,14 @@ class QuillEditorState extends State<QuillEditor>
final child = FlutterQuillLocalizationsWidget( final child = FlutterQuillLocalizationsWidget(
child: QuillEditorProvider( child: QuillEditorProvider(
controller: controller,
editorConfigurations: configurations, editorConfigurations: configurations,
child: QuillEditorBuilderWidget( child: QuillEditorBuilderWidget(
builder: configurations.builder, builder: configurations.builder,
child: QuillRawEditor( child: QuillRawEditor(
key: _editorKey, key: _editorKey,
configurations: QuillRawEditorConfigurations( configurations: QuillRawEditorConfigurations(
controller: configurations.controller, controller: controller,
focusNode: widget.focusNode, focusNode: widget.focusNode,
scrollController: widget.scrollController, scrollController: widget.scrollController,
scrollable: configurations.scrollable, scrollable: configurations.scrollable,
@ -255,7 +273,7 @@ class QuillEditorState extends State<QuillEditor>
configurations.enableMarkdownStyleConversion, configurations.enableMarkdownStyleConversion,
scrollBottomInset: configurations.scrollBottomInset, scrollBottomInset: configurations.scrollBottomInset,
padding: configurations.padding, padding: configurations.padding,
readOnly: configurations.readOnly, readOnly: controller.readOnly,
checkBoxReadOnly: configurations.checkBoxReadOnly, checkBoxReadOnly: configurations.checkBoxReadOnly,
disableClipboard: configurations.disableClipboard, disableClipboard: configurations.disableClipboard,
placeholder: configurations.placeholder, placeholder: configurations.placeholder,
@ -445,7 +463,7 @@ class _QuillEditorSelectionGestureDetectorBuilder
} }
bool _isPositionSelected(TapUpDetails details) { bool _isPositionSelected(TapUpDetails details) {
if (_state.configurations.controller.document.isEmpty()) { if (_state.controller.document.isEmpty()) {
return false; return false;
} }
final pos = renderEditor!.getPositionForOffset(details.globalPosition); final pos = renderEditor!.getPositionForOffset(details.globalPosition);

@ -2,15 +2,25 @@ import 'package:flutter/foundation.dart' show debugPrint, kDebugMode;
import 'package:flutter/widgets.dart' import 'package:flutter/widgets.dart'
show BuildContext, InheritedWidget, Widget; show BuildContext, InheritedWidget, Widget;
import '../controller/quill_controller.dart';
import 'config/editor_configurations.dart'; import 'config/editor_configurations.dart';
class QuillEditorProvider extends InheritedWidget { class QuillEditorProvider extends InheritedWidget {
const QuillEditorProvider({ QuillEditorProvider({
required super.child, required super.child,
required this.editorConfigurations, /// Controller and configurations are required but should only be provided from one.
///
/// Passing the controller as part of configurations is being deprecated and will be removed in the future.
/// Prefer: use controller and set QuillEditorConfigurations in the controller.
/// Current: use configurations and pass QuillController in constructor for configurations.
QuillController? controller,
@Deprecated('editorConfigurations are no longer needed and will be removed in future versions. Set configurations in the controller')
QuillEditorConfigurations? editorConfigurations,
super.key, super.key,
}); }) : editorConfigurations = editorConfigurations ?? controller?.editorConfigurations ?? QuillEditorConfigurations(controller: controller!),
controller = controller ?? editorConfigurations?.controller ?? QuillController.basic();
final QuillController controller;
final QuillEditorConfigurations editorConfigurations; final QuillEditorConfigurations editorConfigurations;
@override @override
@ -52,8 +62,9 @@ class QuillEditorProvider extends InheritedWidget {
required QuillEditorProvider value, required QuillEditorProvider value,
required Widget child, required Widget child,
}) { }) {
value.controller.editorConfigurations = value.editorConfigurations;
return QuillEditorProvider( return QuillEditorProvider(
editorConfigurations: value.editorConfigurations, controller: value.controller,
child: child, child: child,
); );
} }

@ -56,9 +56,7 @@ void main() {
setUp(() { setUp(() {
controller = QuillController.basic(); controller = QuillController.basic();
editor = QuillEditor.basic( editor = QuillEditor.basic(
configurations: QuillEditorConfigurations(
controller: controller, controller: controller,
),
); );
}); });
@ -142,8 +140,8 @@ void main() {
home: QuillEditor( home: QuillEditor(
focusNode: FocusNode(), focusNode: FocusNode(),
scrollController: ScrollController(), scrollController: ScrollController(),
configurations: QuillEditorConfigurations(
controller: controller, controller: controller,
configurations: const QuillEditorConfigurations(
autoFocus: true, autoFocus: true,
expands: true, expands: true,
), ),

@ -24,10 +24,10 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: QuillEditor.basic( home: QuillEditor.basic(
// ignore: avoid_redundant_argument_values
configurations: QuillEditorConfigurations(
controller: controller, controller: controller,
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
configurations: const QuillEditorConfigurations(
// ignore: avoid_redundant_argument_values
), ),
), ),
), ),
@ -44,8 +44,8 @@ void main() {
home: QuillEditor( home: QuillEditor(
focusNode: FocusNode(), focusNode: FocusNode(),
scrollController: ScrollController(), scrollController: ScrollController(),
configurations: QuillEditorConfigurations(
controller: controller, controller: controller,
configurations: QuillEditorConfigurations(
// ignore: avoid_redundant_argument_values // ignore: avoid_redundant_argument_values
autoFocus: true, autoFocus: true,
expands: true, expands: true,
@ -116,9 +116,9 @@ void main() {
home: QuillEditor( home: QuillEditor(
focusNode: FocusNode(), focusNode: FocusNode(),
scrollController: ScrollController(), scrollController: ScrollController(),
controller: controller,
// 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
autoFocus: true, autoFocus: true,
expands: true, expands: true,
@ -146,7 +146,8 @@ void main() {
await tester.pumpWidget( await tester.pumpWidget(
MaterialApp( MaterialApp(
home: QuillEditor.basic( home: QuillEditor.basic(
configurations: QuillEditorConfigurations(controller: controller), controller: controller,
configurations: const QuillEditorConfigurations(),
focusNode: editorFocusNode, focusNode: editorFocusNode,
), ),
), ),

Loading…
Cancel
Save