diff --git a/lib/src/models/config/others/animations.dart b/lib/src/models/config/others/animations.dart index 829442c5..ce6bcb0c 100644 --- a/lib/src/models/config/others/animations.dart +++ b/lib/src/models/config/others/animations.dart @@ -1,10 +1,8 @@ import 'package:equatable/equatable.dart'; -import 'package:flutter/foundation.dart' show immutable; - -import '../../../utils/experimental.dart'; +import 'package:meta/meta.dart' show experimental, immutable; @immutable -@Experimental('This class might removed') +@experimental class QuillAnimationConfigurations extends Equatable { const QuillAnimationConfigurations({ required this.checkBoxPointItem, diff --git a/lib/src/models/documents/nodes/block.dart b/lib/src/models/documents/nodes/block.dart index ed5a4c75..886ad392 100644 --- a/lib/src/models/documents/nodes/block.dart +++ b/lib/src/models/documents/nodes/block.dart @@ -13,7 +13,7 @@ import 'node.dart'; /// - Text Alignment /// - Text Direction /// - Code Block -class Block extends Container { +base class Block extends Container { /// Creates new unmounted [Block]. @override Node newInstance() => Block(); diff --git a/lib/src/models/documents/nodes/container.dart b/lib/src/models/documents/nodes/container.dart index f061a4ca..47bc37e4 100644 --- a/lib/src/models/documents/nodes/container.dart +++ b/lib/src/models/documents/nodes/container.dart @@ -14,7 +14,7 @@ import 'node.dart'; /// /// Most of the operation handling logic is implemented by [Line] /// and [QuillText]. -abstract class Container extends Node { +abstract base class Container extends Node { final LinkedList _children = LinkedList(); /// List of children. diff --git a/lib/src/models/documents/nodes/leaf.dart b/lib/src/models/documents/nodes/leaf.dart index 8bf78462..8ae3be36 100644 --- a/lib/src/models/documents/nodes/leaf.dart +++ b/lib/src/models/documents/nodes/leaf.dart @@ -8,7 +8,7 @@ import 'line.dart'; import 'node.dart'; /// A leaf in Quill document tree. -abstract class Leaf extends Node { +abstract base class Leaf extends Node { /// Creates a new [Leaf] with specified [data]. factory Leaf(Object data) { if (data is Embeddable) { @@ -216,7 +216,7 @@ abstract class Leaf extends Node { /// The reason we are renamed quill Text to [QuillText] so it doesn't /// conflict with the one from the widgets, material or cupertino library /// -class QuillText extends Leaf { +base class QuillText extends Leaf { QuillText([String text = '']) : assert(!text.contains('\n')), super.val(text); @@ -249,7 +249,7 @@ class QuillText extends Leaf { /// necessarily mean the embed will look according to that style. For instance, /// applying "bold" style to an image gives no effect, while adding a "link" to /// an image actually makes the image react to user's action. -class Embed extends Leaf { +base class Embed extends Leaf { Embed(Embeddable data) : super.val(data); // Refer to https://www.fileformat.info/info/unicode/char/fffc/index.htm diff --git a/lib/src/models/documents/nodes/line.dart b/lib/src/models/documents/nodes/line.dart index b34f00fa..3133665e 100644 --- a/lib/src/models/documents/nodes/line.dart +++ b/lib/src/models/documents/nodes/line.dart @@ -19,7 +19,7 @@ import 'node.dart'; /// /// When a line contains an embed, it fully occupies the line, no other embeds /// or text nodes are allowed. -class Line extends Container { +base class Line extends Container { @override Leaf get defaultChild => QuillText(); diff --git a/lib/src/models/documents/nodes/node.dart b/lib/src/models/documents/nodes/node.dart index 098f1241..bb6a1c59 100644 --- a/lib/src/models/documents/nodes/node.dart +++ b/lib/src/models/documents/nodes/node.dart @@ -17,7 +17,7 @@ import 'line.dart'; /// /// The current parent node is exposed by the [parent] property. A node is /// considered [mounted] when the [parent] property is not `null`. -abstract class Node extends LinkedListEntry { +abstract base class Node extends LinkedListEntry { /// Current parent of this node. May be null if this node is not mounted. Container? parent; @@ -127,7 +127,7 @@ abstract class Node extends LinkedListEntry { } /// Root node of document tree. -class Root extends Container> { +base class Root extends Container> { @override Node newInstance() => Root(); diff --git a/lib/src/test/widget_tester_extension.dart b/lib/src/test/widget_tester_extension.dart index 85cc4500..ab811fdc 100644 --- a/lib/src/test/widget_tester_extension.dart +++ b/lib/src/test/widget_tester_extension.dart @@ -11,10 +11,10 @@ extension QuillEnterText on WidgetTester { return TestAsyncUtils.guard(() async { final editor = state( find.descendant( - of: finder, - matching: - find.byType(QuillEditor, skipOffstage: finder.skipOffstage), - matchRoot: true), + of: finder, + matching: find.byType(QuillEditor, skipOffstage: finder.skipOffstage), + matchRoot: true, + ), ); editor.widget.focusNode.requestFocus(); await pump(); diff --git a/lib/src/utils/delta.dart b/lib/src/utils/delta.dart index c737e1ac..7ef44a2d 100644 --- a/lib/src/utils/delta.dart +++ b/lib/src/utils/delta.dart @@ -1,13 +1,20 @@ import 'dart:math' as math; import 'dart:ui'; +import 'package:meta/meta.dart' show immutable; + import '../models/documents/attribute.dart'; import '../models/documents/nodes/node.dart'; import '../models/quill_delta.dart'; // Diff between two texts - old text and new text +@immutable class Diff { - Diff(this.start, this.deleted, this.inserted); + const Diff({ + required this.start, + required this.deleted, + required this.inserted, + }); // Start index in old text at which changes begin. final int start; @@ -37,7 +44,11 @@ Diff getDiff(String oldText, String newText, int cursorPosition) { start++) {} final deleted = (start >= end) ? '' : oldText.substring(start, end); final inserted = newText.substring(start, end + delta); - return Diff(start, deleted, inserted); + return Diff( + start: start, + deleted: deleted, + inserted: inserted, + ); } int getPositionDelta(Delta user, Delta actual) { diff --git a/lib/src/utils/experimental.dart b/lib/src/utils/experimental.dart deleted file mode 100644 index 8f24e87e..00000000 --- a/lib/src/utils/experimental.dart +++ /dev/null @@ -1,7 +0,0 @@ -import 'package:flutter/foundation.dart' show immutable; - -@immutable -class Experimental { - const Experimental([this.reason = 'Experimental feature']); - final String reason; -} diff --git a/lib/src/utils/string.dart b/lib/src/utils/string.dart index f639c716..3de84e65 100644 --- a/lib/src/utils/string.dart +++ b/lib/src/utils/string.dart @@ -19,20 +19,6 @@ Map parseKeyValuePairs(String s, Set targetKeys) { return result; } -@Deprecated('Use replaceStyleStringWithSize instead') -String replaceStyleString( - String s, - double width, - double height, -) { - return replaceStyleStringWithSize( - s, - width: width, - height: height, - isMobile: true, - ); -} - String replaceStyleStringWithSize( String s, { required double width, diff --git a/lib/src/widgets/controller.dart b/lib/src/widgets/controller.dart index 242faa55..fbfc77f0 100644 --- a/lib/src/widgets/controller.dart +++ b/lib/src/widgets/controller.dart @@ -333,18 +333,23 @@ class QuillController extends ChangeNotifier { void moveCursorToStart() { updateSelection( - const TextSelection.collapsed(offset: 0), ChangeSource.LOCAL); + const TextSelection.collapsed(offset: 0), + ChangeSource.LOCAL, + ); } void moveCursorToPosition(int position) { updateSelection( - TextSelection.collapsed(offset: position), ChangeSource.LOCAL); + TextSelection.collapsed(offset: position), + ChangeSource.LOCAL, + ); } void moveCursorToEnd() { updateSelection( - TextSelection.collapsed(offset: plainTextEditingValue.text.length), - ChangeSource.LOCAL); + TextSelection.collapsed(offset: plainTextEditingValue.text.length), + ChangeSource.LOCAL, + ); } void updateSelection(TextSelection textSelection, ChangeSource source) { @@ -358,9 +363,12 @@ class QuillController extends ChangeNotifier { } textSelection = selection.copyWith( - baseOffset: delta.transformPosition(selection.baseOffset, force: false), - extentOffset: - delta.transformPosition(selection.extentOffset, force: false)); + baseOffset: delta.transformPosition(selection.baseOffset, force: false), + extentOffset: delta.transformPosition( + selection.extentOffset, + force: false, + ), + ); if (selection != textSelection) { _updateSelection(textSelection, source); } diff --git a/lib/src/widgets/cursor.dart b/lib/src/widgets/cursor.dart index de2dbb5f..293b2ec6 100644 --- a/lib/src/widgets/cursor.dart +++ b/lib/src/widgets/cursor.dart @@ -257,7 +257,11 @@ class CursorPainter { /// [offset] is global top left (x, y) of text line /// [position] is relative (x) in text line void paint( - Canvas canvas, Offset offset, TextPosition position, bool lineHasEmbed) { + Canvas canvas, + Offset offset, + TextPosition position, + bool lineHasEmbed, + ) { // relative (x, y) to global offset var relativeCaretOffset = editable!.getOffsetForCaret(position, prototype); if (lineHasEmbed && relativeCaretOffset == Offset.zero) { diff --git a/lib/src/widgets/default_styles.dart b/lib/src/widgets/default_styles.dart index d600b71d..dded6d08 100644 --- a/lib/src/widgets/default_styles.dart +++ b/lib/src/widgets/default_styles.dart @@ -240,22 +240,30 @@ class DefaultStyles { const VerticalSpacing(0, 0), null), h3: DefaultTextBlockStyle( - defaultTextStyle.style.copyWith( - fontSize: 20, - color: defaultTextStyle.style.color!.withOpacity(0.70), - height: 1.25, - fontWeight: FontWeight.w500, - decoration: TextDecoration.none, - ), - const VerticalSpacing(8, 0), - const VerticalSpacing(0, 0), - null), + defaultTextStyle.style.copyWith( + fontSize: 20, + color: defaultTextStyle.style.color!.withOpacity(0.70), + height: 1.25, + fontWeight: FontWeight.w500, + decoration: TextDecoration.none, + ), + const VerticalSpacing(8, 0), + const VerticalSpacing(0, 0), + null, + ), paragraph: DefaultTextBlockStyle(baseStyle, const VerticalSpacing(0, 0), const VerticalSpacing(0, 0), null), bold: const TextStyle(fontWeight: FontWeight.bold), - subscript: const TextStyle(fontFeatures: [FontFeature.subscripts()]), - superscript: - const TextStyle(fontFeatures: [FontFeature.superscripts()]), + subscript: const TextStyle( + fontFeatures: [ + FontFeature.subscripts(), + ], + ), + superscript: const TextStyle( + fontFeatures: [ + FontFeature.superscripts(), + ], + ), italic: const TextStyle(fontStyle: FontStyle.italic), small: const TextStyle(fontSize: 12), underline: const TextStyle(decoration: TextDecoration.underline), @@ -288,16 +296,22 @@ class DefaultStyles { const VerticalSpacing(0, 0), null), lists: DefaultListBlockStyle( - baseStyle, baseSpacing, const VerticalSpacing(0, 6), null, null), + baseStyle, + baseSpacing, + const VerticalSpacing(0, 6), + null, + null, + ), quote: DefaultTextBlockStyle( - TextStyle(color: baseStyle.color!.withOpacity(0.6)), - baseSpacing, - const VerticalSpacing(6, 2), - BoxDecoration( - border: Border( - left: BorderSide(width: 4, color: Colors.grey.shade300), - ), - )), + TextStyle(color: baseStyle.color!.withOpacity(0.6)), + baseSpacing, + const VerticalSpacing(6, 2), + BoxDecoration( + border: Border( + left: BorderSide(width: 4, color: Colors.grey.shade300), + ), + ), + ), code: DefaultTextBlockStyle( TextStyle( color: Colors.blue.shade900.withOpacity(0.9), @@ -312,11 +326,23 @@ class DefaultStyles { borderRadius: BorderRadius.circular(2), )), indent: DefaultTextBlockStyle( - baseStyle, baseSpacing, const VerticalSpacing(0, 6), null), - align: DefaultTextBlockStyle(baseStyle, const VerticalSpacing(0, 0), - const VerticalSpacing(0, 0), null), - leading: DefaultTextBlockStyle(baseStyle, const VerticalSpacing(0, 0), - const VerticalSpacing(0, 0), null), + baseStyle, + baseSpacing, + const VerticalSpacing(0, 6), + null, + ), + align: DefaultTextBlockStyle( + baseStyle, + const VerticalSpacing(0, 0), + const VerticalSpacing(0, 0), + null, + ), + leading: DefaultTextBlockStyle( + baseStyle, + const VerticalSpacing(0, 0), + const VerticalSpacing(0, 0), + null, + ), sizeSmall: const TextStyle(fontSize: 10), sizeLarge: const TextStyle(fontSize: 18), sizeHuge: const TextStyle(fontSize: 22)); @@ -324,29 +350,30 @@ class DefaultStyles { DefaultStyles merge(DefaultStyles other) { return DefaultStyles( - h1: other.h1 ?? h1, - h2: other.h2 ?? h2, - h3: other.h3 ?? h3, - paragraph: other.paragraph ?? paragraph, - bold: other.bold ?? bold, - subscript: other.subscript ?? subscript, - superscript: other.superscript ?? superscript, - italic: other.italic ?? italic, - small: other.small ?? small, - underline: other.underline ?? underline, - strikeThrough: other.strikeThrough ?? strikeThrough, - inlineCode: other.inlineCode ?? inlineCode, - link: other.link ?? link, - color: other.color ?? color, - placeHolder: other.placeHolder ?? placeHolder, - lists: other.lists ?? lists, - quote: other.quote ?? quote, - code: other.code ?? code, - indent: other.indent ?? indent, - align: other.align ?? align, - leading: other.leading ?? leading, - sizeSmall: other.sizeSmall ?? sizeSmall, - sizeLarge: other.sizeLarge ?? sizeLarge, - sizeHuge: other.sizeHuge ?? sizeHuge); + h1: other.h1 ?? h1, + h2: other.h2 ?? h2, + h3: other.h3 ?? h3, + paragraph: other.paragraph ?? paragraph, + bold: other.bold ?? bold, + subscript: other.subscript ?? subscript, + superscript: other.superscript ?? superscript, + italic: other.italic ?? italic, + small: other.small ?? small, + underline: other.underline ?? underline, + strikeThrough: other.strikeThrough ?? strikeThrough, + inlineCode: other.inlineCode ?? inlineCode, + link: other.link ?? link, + color: other.color ?? color, + placeHolder: other.placeHolder ?? placeHolder, + lists: other.lists ?? lists, + quote: other.quote ?? quote, + code: other.code ?? code, + indent: other.indent ?? indent, + align: other.align ?? align, + leading: other.leading ?? leading, + sizeSmall: other.sizeSmall ?? sizeSmall, + sizeLarge: other.sizeLarge ?? sizeLarge, + sizeHuge: other.sizeHuge ?? sizeHuge, + ); } } diff --git a/lib/src/widgets/delegate.dart b/lib/src/widgets/delegate.dart index c196a5d3..f595beff 100644 --- a/lib/src/widgets/delegate.dart +++ b/lib/src/widgets/delegate.dart @@ -314,8 +314,10 @@ class EditorTextSelectionGestureDetectorBuilder { void onDragSelectionUpdate( //DragStartDetails startDetails, DragUpdateDetails updateDetails) { - renderEditor!.extendSelection(updateDetails.globalPosition, - cause: SelectionChangedCause.drag); + renderEditor!.extendSelection( + updateDetails.globalPosition, + cause: SelectionChangedCause.drag, + ); } /// Handler for [EditorTextSelectionGestureDetector.onDragSelectionEnd]. @@ -341,29 +343,30 @@ class EditorTextSelectionGestureDetectorBuilder { /// the handlers provided by this builder. /// /// The [child] or its subtree should contain [EditableText]. - Widget build( - {required HitTestBehavior behavior, - required Widget child, - Key? key, - bool detectWordBoundary = true}) { + Widget build({ + required HitTestBehavior behavior, + required Widget child, + Key? key, + bool detectWordBoundary = true, + }) { return EditorTextSelectionGestureDetector( - key: key, - onTapDown: onTapDown, - onForcePressStart: - delegate.forcePressEnabled ? onForcePressStart : null, - onForcePressEnd: delegate.forcePressEnabled ? onForcePressEnd : null, - onSingleTapUp: onSingleTapUp, - onSingleTapCancel: onSingleTapCancel, - onSingleLongTapStart: onSingleLongTapStart, - onSingleLongTapMoveUpdate: onSingleLongTapMoveUpdate, - onSingleLongTapEnd: onSingleLongTapEnd, - onDoubleTapDown: onDoubleTapDown, - onSecondarySingleTapUp: onSecondarySingleTapUp, - onDragSelectionStart: onDragSelectionStart, - onDragSelectionUpdate: onDragSelectionUpdate, - onDragSelectionEnd: onDragSelectionEnd, - behavior: behavior, - detectWordBoundary: detectWordBoundary, - child: child); + key: key, + onTapDown: onTapDown, + onForcePressStart: delegate.forcePressEnabled ? onForcePressStart : null, + onForcePressEnd: delegate.forcePressEnabled ? onForcePressEnd : null, + onSingleTapUp: onSingleTapUp, + onSingleTapCancel: onSingleTapCancel, + onSingleLongTapStart: onSingleLongTapStart, + onSingleLongTapMoveUpdate: onSingleLongTapMoveUpdate, + onSingleLongTapEnd: onSingleLongTapEnd, + onDoubleTapDown: onDoubleTapDown, + onSecondarySingleTapUp: onSecondarySingleTapUp, + onDragSelectionStart: onDragSelectionStart, + onDragSelectionUpdate: onDragSelectionUpdate, + onDragSelectionEnd: onDragSelectionEnd, + behavior: behavior, + detectWordBoundary: detectWordBoundary, + child: child, + ); } } diff --git a/lib/src/widgets/editor/editor.dart b/lib/src/widgets/editor/editor.dart index 766ad8aa..3c25cdb4 100644 --- a/lib/src/widgets/editor/editor.dart +++ b/lib/src/widgets/editor/editor.dart @@ -1,10 +1,5 @@ import 'dart:math' as math; -// ignore: unnecessary_import -// import 'dart:typed_data'; -// The project maanged to compiled successfully without the import -// do we still need this import (dart:typed_data)?? - import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; @@ -1495,7 +1490,7 @@ class RenderEditor extends RenderEditableContainerBox } } -class QuillVerticalCaretMovementRun extends Iterator { +class QuillVerticalCaretMovementRun implements Iterator { QuillVerticalCaretMovementRun._( this._editor, this._currentTextPosition, diff --git a/lib/src/widgets/embeds.dart b/lib/src/widgets/embeds.dart index 11d34b87..87511204 100644 --- a/lib/src/widgets/embeds.dart +++ b/lib/src/widgets/embeds.dart @@ -29,7 +29,8 @@ abstract class EmbedBuilder { } typedef EmbedButtonBuilder = Widget Function( - QuillController controller, - double toolbarIconSize, - QuillIconTheme? iconTheme, - QuillDialogTheme? dialogTheme); + QuillController controller, + double toolbarIconSize, + QuillIconTheme? iconTheme, + QuillDialogTheme? dialogTheme, +); diff --git a/lib/src/widgets/keyboard_listener.dart b/lib/src/widgets/keyboard_listener.dart index 47cb9555..ee1e3d11 100644 --- a/lib/src/widgets/keyboard_listener.dart +++ b/lib/src/widgets/keyboard_listener.dart @@ -44,8 +44,9 @@ class QuillKeyboardListenerState extends State { final QuillPressedKeys _pressedKeys = QuillPressedKeys(); bool _keyEvent(KeyEvent event) { - _pressedKeys - ._updatePressedKeys(HardwareKeyboard.instance.logicalKeysPressed); + _pressedKeys._updatePressedKeys( + HardwareKeyboard.instance.logicalKeysPressed, + ); return false; } diff --git a/lib/src/widgets/proxy.dart b/lib/src/widgets/proxy.dart index 155e620a..2379c883 100644 --- a/lib/src/widgets/proxy.dart +++ b/lib/src/widgets/proxy.dart @@ -6,8 +6,12 @@ import 'package:flutter/widgets.dart'; import 'box.dart'; class BaselineProxy extends SingleChildRenderObjectWidget { - const BaselineProxy({Key? key, Widget? child, this.textStyle, this.padding}) - : super(key: key, child: child); + const BaselineProxy({ + Key? key, + Widget? child, + this.textStyle, + this.padding, + }) : super(key: key, child: child); final TextStyle? textStyle; final EdgeInsets? padding; diff --git a/lib/src/widgets/quill_single_child_scroll_view.dart b/lib/src/widgets/quill_single_child_scroll_view.dart index 40971b06..ba6c0371 100644 --- a/lib/src/widgets/quill_single_child_scroll_view.dart +++ b/lib/src/widgets/quill_single_child_scroll_view.dart @@ -14,10 +14,10 @@ class QuillSingleChildScrollView extends StatelessWidget { const QuillSingleChildScrollView({ required this.controller, required this.viewportBuilder, - Key? key, + super.key, this.physics, this.restorationId, - }) : super(key: key); + }); /// An object that can be used to control the position to which this scroll /// view is scrolled. @@ -48,7 +48,10 @@ class QuillSingleChildScrollView extends StatelessWidget { AxisDirection _getDirection(BuildContext context) { return getAxisDirectionFromAxisReverseAndDirectionality( - context, Axis.vertical, false); + context, + Axis.vertical, + false, + ); } @override diff --git a/lib/src/widgets/raw_editor/raw_editor.dart b/lib/src/widgets/raw_editor/raw_editor.dart index 8e5090f0..28d6c342 100644 --- a/lib/src/widgets/raw_editor/raw_editor.dart +++ b/lib/src/widgets/raw_editor/raw_editor.dart @@ -437,9 +437,6 @@ class RawEditorState extends EditorState // in the web browser, but we do unfocus for all other kinds of events. switch (event.kind) { case ui.PointerDeviceKind.touch: - // if (isWeb()) { - // widget.focusNode.unfocus(); - // } break; case ui.PointerDeviceKind.mouse: case ui.PointerDeviceKind.stylus: @@ -449,7 +446,7 @@ class RawEditorState extends EditorState break; case ui.PointerDeviceKind.trackpad: throw UnimplementedError( - 'Unexpected pointer down event for trackpad', + 'Unexpected pointer down event for trackpad.', ); } break; @@ -461,7 +458,7 @@ class RawEditorState extends EditorState default: throw UnsupportedError( 'The platform ${defaultTargetPlatform.name} is not supported in the' - ' _defaultOnTapOutside', + ' _defaultOnTapOutside()', ); } } @@ -474,8 +471,11 @@ class RawEditorState extends EditorState var _doc = controller.document; if (_doc.isEmpty() && widget.placeholder != null) { final raw = widget.placeholder?.replaceAll(r'"', '\\"'); - _doc = Document.fromJson(jsonDecode( - '[{"attributes":{"placeholder":true},"insert":"$raw\\n"}]')); + _doc = Document.fromJson( + jsonDecode( + '[{"attributes":{"placeholder":true},"insert":"$raw\\n"}]', + ), + ); } Widget child = CompositedTransformTarget( @@ -1435,7 +1435,6 @@ class RawEditorState extends EditorState @override void requestKeyboard() { if (controller.skipRequestKeyboard) { - // TODO: There is a bug, requestKeyboard is being called 2-4 times! // and that just by one simple change controller.skipRequestKeyboard = false; return; diff --git a/lib/src/widgets/style_widgets/bullet_point.dart b/lib/src/widgets/style_widgets/bullet_point.dart index 8b5fce70..f760c992 100644 --- a/lib/src/widgets/style_widgets/bullet_point.dart +++ b/lib/src/widgets/style_widgets/bullet_point.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; -class QuillBulletPoint extends StatelessWidget { - const QuillBulletPoint({ +class QuillEditorBulletPoint extends StatelessWidget { + const QuillEditorBulletPoint({ required this.style, required this.width, this.padding = 0, diff --git a/lib/src/widgets/style_widgets/checkbox_point.dart b/lib/src/widgets/style_widgets/checkbox_point.dart index 1276a152..4d87df16 100644 --- a/lib/src/widgets/style_widgets/checkbox_point.dart +++ b/lib/src/widgets/style_widgets/checkbox_point.dart @@ -3,8 +3,8 @@ import 'package:flutter_animate/flutter_animate.dart'; import '../../utils/extensions/build_context.dart'; -class CheckboxPoint extends StatefulWidget { - const CheckboxPoint({ +class QuillEditorCheckboxPoint extends StatefulWidget { + const QuillEditorCheckboxPoint({ required this.size, required this.value, required this.enabled, @@ -20,10 +20,11 @@ class CheckboxPoint extends StatefulWidget { final QuillCheckboxBuilder? uiBuilder; @override - _CheckboxPointState createState() => _CheckboxPointState(); + _QuillEditorCheckboxPointState createState() => + _QuillEditorCheckboxPointState(); } -class _CheckboxPointState extends State { +class _QuillEditorCheckboxPointState extends State { @override Widget build(BuildContext context) { final uiBuilder = widget.uiBuilder; diff --git a/lib/src/widgets/style_widgets/number_point.dart b/lib/src/widgets/style_widgets/number_point.dart index 54d5ebc9..30b5590e 100644 --- a/lib/src/widgets/style_widgets/number_point.dart +++ b/lib/src/widgets/style_widgets/number_point.dart @@ -3,8 +3,8 @@ import 'package:flutter/material.dart'; import '../../models/documents/attribute.dart'; import '../text_block.dart'; -class QuillNumberPoint extends StatelessWidget { - const QuillNumberPoint({ +class QuillEditorNumberPoint extends StatelessWidget { + const QuillEditorNumberPoint({ required this.index, required this.indentLevelCounts, required this.count, @@ -13,8 +13,8 @@ class QuillNumberPoint extends StatelessWidget { required this.attrs, this.withDot = true, this.padding = 0.0, - Key? key, - }) : super(key: key); + super.key, + }); final int index; final Map indentLevelCounts; diff --git a/lib/src/widgets/text_block.dart b/lib/src/widgets/text_block.dart index d10596fe..f99ccbb0 100644 --- a/lib/src/widgets/text_block.dart +++ b/lib/src/widgets/text_block.dart @@ -146,7 +146,13 @@ class EditableTextBlock extends StatelessWidget { index++; final editableTextLine = EditableTextLine( line, - _buildLeading(context, line, index, indentLevelCounts, count), + _buildLeading( + context: context, + line: line, + index: index, + indentLevelCounts: indentLevelCounts, + count: count, + ), TextLine( line: line, textDirection: textDirection, @@ -194,14 +200,19 @@ class EditableTextBlock extends StatelessWidget { } } - Widget? _buildLeading(BuildContext context, Line line, int index, - Map indentLevelCounts, int count) { + Widget? _buildLeading({ + required BuildContext context, + required Line line, + required int index, + required Map indentLevelCounts, + required int count, + }) { final defaultStyles = QuillStyles.getStyles(context, false)!; final fontSize = defaultStyles.paragraph?.style.fontSize ?? 16; final attrs = line.style.attributes; if (attrs[Attribute.list.key] == Attribute.ol) { - return QuillNumberPoint( + return QuillEditorNumberPoint( index: index, indentLevelCounts: indentLevelCounts, count: count, @@ -213,7 +224,7 @@ class EditableTextBlock extends StatelessWidget { } if (attrs[Attribute.list.key] == Attribute.ul) { - return QuillBulletPoint( + return QuillEditorBulletPoint( style: defaultStyles.leading!.style.copyWith(fontWeight: FontWeight.bold), width: fontSize * 2, @@ -223,7 +234,7 @@ class EditableTextBlock extends StatelessWidget { if (attrs[Attribute.list.key] == Attribute.checked || attrs[Attribute.list.key] == Attribute.unchecked) { - return CheckboxPoint( + return QuillEditorCheckboxPoint( size: fontSize, value: attrs[Attribute.list.key] == Attribute.checked, enabled: !readOnly, @@ -233,7 +244,7 @@ class EditableTextBlock extends StatelessWidget { } if (attrs.containsKey(Attribute.codeBlock.key) && context.requireQuillEditorElementOptions.codeBlock.enableLineNumbers) { - return QuillNumberPoint( + return QuillEditorNumberPoint( index: index, indentLevelCounts: indentLevelCounts, count: count, @@ -278,7 +289,11 @@ class EditableTextBlock extends StatelessWidget { } VerticalSpacing _getSpacingForLine( - Line node, int index, int count, DefaultStyles? defaultStyles) { + Line node, + int index, + int count, + DefaultStyles? defaultStyles, + ) { var top = 0.0, bottom = 0.0; final attrs = block.style.attributes; @@ -301,7 +316,7 @@ class EditableTextBlock extends StatelessWidget { throw 'Invalid level $level'; } } else { - late VerticalSpacing lineSpacing; + final VerticalSpacing lineSpacing; if (attrs.containsKey(Attribute.blockQuote.key)) { lineSpacing = defaultStyles!.quote!.lineSpacing; } else if (attrs.containsKey(Attribute.indent.key)) { @@ -500,12 +515,18 @@ class RenderEditableTextBlock extends RenderEditableContainerBox TextSelectionPoint getBaseEndpointForSelection(TextSelection selection) { if (selection.isCollapsed) { return TextSelectionPoint( - Offset(0, preferredLineHeight(selection.extent)) + - getOffsetForCaret(selection.extent), - null); + Offset(0, preferredLineHeight(selection.extent)) + + getOffsetForCaret(selection.extent), + null, + ); } - final baseNode = container.queryChild(selection.start, false).node; + final baseNode = container + .queryChild( + selection.start, + false, + ) + .node; var baseChild = firstChild; while (baseChild != null) { if (baseChild.container == baseNode) { @@ -516,19 +537,26 @@ class RenderEditableTextBlock extends RenderEditableContainerBox assert(baseChild != null); final basePoint = baseChild!.getBaseEndpointForSelection( - localSelection(baseChild.container, selection, true)); + localSelection( + baseChild.container, + selection, + true, + ), + ); return TextSelectionPoint( - basePoint.point + (baseChild.parentData as BoxParentData).offset, - basePoint.direction); + basePoint.point + (baseChild.parentData as BoxParentData).offset, + basePoint.direction, + ); } @override TextSelectionPoint getExtentEndpointForSelection(TextSelection selection) { if (selection.isCollapsed) { return TextSelectionPoint( - Offset(0, preferredLineHeight(selection.extent)) + - getOffsetForCaret(selection.extent), - null); + Offset(0, preferredLineHeight(selection.extent)) + + getOffsetForCaret(selection.extent), + null, + ); } final extentNode = container.queryChild(selection.end, false).node; @@ -543,10 +571,16 @@ class RenderEditableTextBlock extends RenderEditableContainerBox assert(extentChild != null); final extentPoint = extentChild!.getExtentEndpointForSelection( - localSelection(extentChild.container, selection, true)); + localSelection( + extentChild.container, + selection, + true, + ), + ); return TextSelectionPoint( - extentPoint.point + (extentChild.parentData as BoxParentData).offset, - extentPoint.direction); + extentPoint.point + (extentChild.parentData as BoxParentData).offset, + extentPoint.direction, + ); } @override @@ -576,8 +610,10 @@ class RenderEditableTextBlock extends RenderEditableContainerBox offset.translate(decorationPadding.left, decorationPadding.top); _painter!.paint(context.canvas, decorationOffset, filledConfiguration); if (debugSaveCount != context.canvas.getSaveCount()) { - throw '${_decoration.runtimeType} painter had mismatching save and ' - 'restore calls.'; + throw StateError( + '${_decoration.runtimeType} painter had mismatching save and ' + 'restore calls.', + ); } if (decoration.isComplex) { context.setIsComplexHint(); diff --git a/lib/src/widgets/text_line.dart b/lib/src/widgets/text_line.dart index 6dd4f793..8aa88ccb 100644 --- a/lib/src/widgets/text_line.dart +++ b/lib/src/widgets/text_line.dart @@ -43,8 +43,8 @@ class TextLine extends StatefulWidget { this.customStyleBuilder, this.customRecognizerBuilder, this.customLinkPrefixes = const [], - Key? key, - }) : super(key: key); + super.key, + }); final Line line; final TextDirection? textDirection; @@ -88,8 +88,8 @@ class _TextLineState extends State { // In editing mode it depends on the platform: - // Desktop platforms (macos, linux, windows): - // only allow Meta(Control)+Click combinations + // Desktop platforms (macOS, Linux, Windows): + // only allow Meta (Control) + Click combinations if (isDesktop()) { return _metaOrControlPressed; } @@ -581,21 +581,22 @@ class EditableTextLine extends RenderObjectWidget { } } -enum TextLineSlot { LEADING, BODY } +enum TextLineSlot { leading, body } class RenderEditableTextLine extends RenderEditableBox { /// Creates new editable paragraph render box. RenderEditableTextLine( - this.line, - this.textDirection, - this.textSelection, - this.enableInteractiveSelection, - this.hasFocus, - this.devicePixelRatio, - this.padding, - this.color, - this.cursorCont, - this.inlineCodeStyle); + this.line, + this.textDirection, + this.textSelection, + this.enableInteractiveSelection, + this.hasFocus, + this.devicePixelRatio, + this.padding, + this.color, + this.cursorCont, + this.inlineCodeStyle, + ); RenderBox? _leading; RenderContentProxyBox? _body; @@ -715,11 +716,11 @@ class RenderEditableTextLine extends RenderEditableBox { } void setLeading(RenderBox? l) { - _leading = _updateChild(_leading, l, TextLineSlot.LEADING); + _leading = _updateChild(_leading, l, TextLineSlot.leading); } void setBody(RenderContentProxyBox? b) { - _body = _updateChild(_body, b, TextLineSlot.BODY) as RenderContentProxyBox?; + _body = _updateChild(_body, b, TextLineSlot.body) as RenderContentProxyBox?; } void setInlineCodeStyle(InlineCodeStyle newStyle) { @@ -744,7 +745,10 @@ class RenderEditableTextLine extends RenderEditableBox { } RenderBox? _updateChild( - RenderBox? old, RenderBox? newChild, TextLineSlot slot) { + RenderBox? old, + RenderBox? newChild, + TextLineSlot slot, + ) { if (old != null) { dropChild(old); children.remove(slot); @@ -800,8 +804,9 @@ class RenderEditableTextLine extends RenderEditableBox { assert(boxes.isNotEmpty); final targetBox = first ? boxes.first : boxes.last; return TextSelectionPoint( - Offset(first ? targetBox.start : targetBox.end, targetBox.bottom), - targetBox.direction); + Offset(first ? targetBox.start : targetBox.end, targetBox.bottom), + targetBox.direction, + ); } @override @@ -814,9 +819,12 @@ class RenderEditableTextLine extends RenderEditableBox { .where((element) => element.top < lineDy && element.bottom > lineDy) .toList(growable: false); return TextRange( - start: - getPositionForOffset(Offset(lineBoxes.first.left, lineDy)).offset, - end: getPositionForOffset(Offset(lineBoxes.last.right, lineDy)).offset); + start: getPositionForOffset( + Offset(lineBoxes.first.left, lineDy), + ).offset, + end: getPositionForOffset( + Offset(lineBoxes.last.right, lineDy), + ).offset); } @override @@ -886,7 +894,9 @@ class RenderEditableTextLine extends RenderEditableBox { /// of the cursor for iOS is approximate and obtained through an eyeball /// comparison. void _computeCaretPrototype() { - if (isAppleOS()) { + // If the cursor is taller only on iOS and not AppleOS then we should check + // only for iOS instead of AppleOS (macOS for example) + if (isIOS()) { _caretPrototype = Rect.fromLTWH(0, 0, cursorWidth, cursorHeight + 2); } else { _caretPrototype = Rect.fromLTWH(0, 2, cursorWidth, cursorHeight - 4.0); @@ -1090,8 +1100,13 @@ class RenderEditableTextLine extends RenderEditableBox { } else { final parentData = _leading!.parentData as BoxParentData; final effectiveOffset = offset + parentData.offset; - context.paintChild(_leading!, - Offset(size.width - _leading!.size.width, effectiveOffset.dy)); + context.paintChild( + _leading!, + Offset( + size.width - _leading!.size.width, + effectiveOffset.dy, + ), + ); } } @@ -1106,18 +1121,29 @@ class RenderEditableTextLine extends RenderEditableBox { continue; } final textRange = TextSelection( - baseOffset: item.offset, extentOffset: item.offset + item.length); + baseOffset: item.offset, + extentOffset: item.offset + item.length, + ); final rects = _body!.getBoxesForSelection(textRange); final paint = Paint()..color = inlineCodeStyle.backgroundColor!; for (final box in rects) { final rect = box.toRect().translate(0, 1).shift(effectiveOffset); if (inlineCodeStyle.radius == null) { final paintRect = Rect.fromLTRB( - rect.left - 2, rect.top, rect.right + 2, rect.bottom); + rect.left - 2, + rect.top, + rect.right + 2, + rect.bottom, + ); context.canvas.drawRect(paintRect, paint); } else { - final paintRect = RRect.fromLTRBR(rect.left - 2, rect.top, - rect.right + 2, rect.bottom, inlineCodeStyle.radius!); + final paintRect = RRect.fromLTRBR( + rect.left - 2, + rect.top, + rect.right + 2, + rect.bottom, + inlineCodeStyle.radius!, + ); context.canvas.drawRRect(paintRect, paint); } } @@ -1154,10 +1180,20 @@ class RenderEditableTextLine extends RenderEditableBox { if (line.isEmpty && textSelection.baseOffset <= line.offset && textSelection.extentOffset > line.offset) { - final lineHeight = - preferredLineHeight(TextPosition(offset: line.offset)); - _selectedRects - ?.add(TextBox.fromLTRBD(0, 0, 3, lineHeight, textDirection)); + final lineHeight = preferredLineHeight( + TextPosition( + offset: line.offset, + ), + ); + _selectedRects?.add( + TextBox.fromLTRBD( + 0, + 0, + 3, + lineHeight, + textDirection, + ), + ); } _paintSelection(context, effectiveOffset); @@ -1179,12 +1215,18 @@ class RenderEditableTextLine extends RenderEditableBox { ? TextPosition( offset: cursorCont.floatingCursorTextPosition.value!.offset - line.documentOffset, - affinity: cursorCont.floatingCursorTextPosition.value!.affinity) + affinity: cursorCont.floatingCursorTextPosition.value!.affinity, + ) : TextPosition( offset: textSelection.extentOffset - line.documentOffset, - affinity: textSelection.base.affinity); + affinity: textSelection.base.affinity, + ); _cursorPainter.paint( - context.canvas, effectiveOffset, position, lineHasEmbed); + context.canvas, + effectiveOffset, + position, + lineHasEmbed, + ); } @override @@ -1192,29 +1234,35 @@ class RenderEditableTextLine extends RenderEditableBox { if (_leading != null) { final childParentData = _leading!.parentData as BoxParentData; final isHit = result.addWithPaintOffset( - offset: childParentData.offset, - position: position, - hitTest: (result, transformed) { - assert(transformed == position - childParentData.offset); - return _leading!.hitTest(result, position: transformed); - }); + offset: childParentData.offset, + position: position, + hitTest: (result, transformed) { + assert(transformed == position - childParentData.offset); + return _leading!.hitTest(result, position: transformed); + }, + ); if (isHit) return true; } if (_body == null) return false; final parentData = _body!.parentData as BoxParentData; return result.addWithPaintOffset( - offset: parentData.offset, - position: position, - hitTest: (result, position) { - return _body!.hitTest(result, position: position); - }); + offset: parentData.offset, + position: position, + hitTest: (result, position) { + return _body!.hitTest(result, position: position); + }, + ); } @override Rect getLocalRectForCaret(TextPosition position) { final caretOffset = getOffsetForCaret(position); - var rect = - Rect.fromLTWH(0, 0, cursorWidth, cursorHeight).shift(caretOffset); + var rect = Rect.fromLTWH( + 0, + 0, + cursorWidth, + cursorHeight, + ).shift(caretOffset); final cursorOffset = cursorCont.style.offset; // Add additional cursor offset (generally only if on iOS). if (cursorOffset != null) rect = rect.shift(cursorOffset); @@ -1272,16 +1320,16 @@ class _TextLineElement extends RenderObjectElement { @override void mount(Element? parent, dynamic newSlot) { super.mount(parent, newSlot); - _mountChild(widget.leading, TextLineSlot.LEADING); - _mountChild(widget.body, TextLineSlot.BODY); + _mountChild(widget.leading, TextLineSlot.leading); + _mountChild(widget.body, TextLineSlot.body); } @override void update(EditableTextLine newWidget) { super.update(newWidget); assert(widget == newWidget); - _updateChild(widget.leading, TextLineSlot.LEADING); - _updateChild(widget.body, TextLineSlot.BODY); + _updateChild(widget.leading, TextLineSlot.leading); + _updateChild(widget.body, TextLineSlot.body); } @override @@ -1318,10 +1366,10 @@ class _TextLineElement extends RenderObjectElement { void _updateRenderObject(RenderBox? child, TextLineSlot? slot) { switch (slot) { - case TextLineSlot.LEADING: + case TextLineSlot.leading: renderObject.setLeading(child); break; - case TextLineSlot.BODY: + case TextLineSlot.body: renderObject.setBody(child as RenderContentProxyBox?); break; default: diff --git a/lib/src/widgets/text_selection.dart b/lib/src/widgets/text_selection.dart index c13f9952..07cbdeb8 100644 --- a/lib/src/widgets/text_selection.dart +++ b/lib/src/widgets/text_selection.dart @@ -842,8 +842,10 @@ class _EditorTextSelectionGestureDetectorState void _handleDragUpdate(DragUpdateDetails details) { _lastDragUpdateDetails = details; - _dragUpdateThrottleTimer ??= - Timer(const Duration(milliseconds: 50), _handleDragUpdateThrottled); + _dragUpdateThrottleTimer ??= Timer( + const Duration(milliseconds: 50), + _handleDragUpdateThrottled, + ); } /// Drag updates are being throttled to avoid excessive text layouts in text diff --git a/pubspec.yaml b/pubspec.yaml index 86abf644..9892808b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -17,7 +17,8 @@ platforms: windows: environment: - sdk: ">=2.17.0 <4.0.0" + sdk: '>=3.1.3 <4.0.0' + # sdk: ">=2.17.0 <4.0.0" flutter: ">=3.10.0" dependencies: @@ -40,5 +41,6 @@ dependencies: flutter_test: sdk: flutter + meta: ^1.9.1 flutter: null \ No newline at end of file diff --git a/test/bug_fix_test.dart b/test/bug_fix_test.dart index 6ade28f5..9869d517 100644 --- a/test/bug_fix_test.dart +++ b/test/bug_fix_test.dart @@ -130,7 +130,7 @@ void main() { controller.formatSelection(Attribute.unchecked); editor.focusNode.unfocus(); await tester.pump(); - await tester.tap(find.byType(CheckboxPoint)); + await tester.tap(find.byType(QuillEditorCheckboxPoint)); expect(tester.takeException(), isNull); }); });