Code cleanup and mirgrate to dart 3 as minimum

pull/1486/head
Ellet 2 years ago
parent 7638535a33
commit 2610dab118
No known key found for this signature in database
GPG Key ID: C488CC70BBCEF0D1
  1. 6
      lib/src/models/config/others/animations.dart
  2. 2
      lib/src/models/documents/nodes/block.dart
  3. 2
      lib/src/models/documents/nodes/container.dart
  4. 6
      lib/src/models/documents/nodes/leaf.dart
  5. 2
      lib/src/models/documents/nodes/line.dart
  6. 4
      lib/src/models/documents/nodes/node.dart
  7. 6
      lib/src/test/widget_tester_extension.dart
  8. 15
      lib/src/utils/delta.dart
  9. 7
      lib/src/utils/experimental.dart
  10. 14
      lib/src/utils/string.dart
  11. 18
      lib/src/widgets/controller.dart
  12. 6
      lib/src/widgets/cursor.dart
  13. 51
      lib/src/widgets/default_styles.dart
  14. 19
      lib/src/widgets/delegate.dart
  15. 7
      lib/src/widgets/editor/editor.dart
  16. 3
      lib/src/widgets/embeds.dart
  17. 5
      lib/src/widgets/keyboard_listener.dart
  18. 8
      lib/src/widgets/proxy.dart
  19. 9
      lib/src/widgets/quill_single_child_scroll_view.dart
  20. 15
      lib/src/widgets/raw_editor/raw_editor.dart
  21. 4
      lib/src/widgets/style_widgets/bullet_point.dart
  22. 9
      lib/src/widgets/style_widgets/checkbox_point.dart
  23. 8
      lib/src/widgets/style_widgets/number_point.dart
  24. 72
      lib/src/widgets/text_block.dart
  25. 120
      lib/src/widgets/text_line.dart
  26. 6
      lib/src/widgets/text_selection.dart
  27. 4
      pubspec.yaml
  28. 2
      test/bug_fix_test.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,

@ -13,7 +13,7 @@ import 'node.dart';
/// - Text Alignment
/// - Text Direction
/// - Code Block
class Block extends Container<Line?> {
base class Block extends Container<Line?> {
/// Creates new unmounted [Block].
@override
Node newInstance() => Block();

@ -14,7 +14,7 @@ import 'node.dart';
///
/// Most of the operation handling logic is implemented by [Line]
/// and [QuillText].
abstract class Container<T extends Node?> extends Node {
abstract base class Container<T extends Node?> extends Node {
final LinkedList<Node> _children = LinkedList<Node>();
/// List of children.

@ -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

@ -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<Leaf?> {
base class Line extends Container<Leaf?> {
@override
Leaf get defaultChild => QuillText();

@ -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<Node> {
abstract base class Node extends LinkedListEntry<Node> {
/// 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<Node> {
}
/// Root node of document tree.
class Root extends Container<Container<Node?>> {
base class Root extends Container<Container<Node?>> {
@override
Node newInstance() => Root();

@ -12,9 +12,9 @@ extension QuillEnterText on WidgetTester {
final editor = state<QuillEditorState>(
find.descendant(
of: finder,
matching:
find.byType(QuillEditor, skipOffstage: finder.skipOffstage),
matchRoot: true),
matching: find.byType(QuillEditor, skipOffstage: finder.skipOffstage),
matchRoot: true,
),
);
editor.widget.focusNode.requestFocus();
await pump();

@ -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) {

@ -1,7 +0,0 @@
import 'package:flutter/foundation.dart' show immutable;
@immutable
class Experimental {
const Experimental([this.reason = 'Experimental feature']);
final String reason;
}

@ -19,20 +19,6 @@ Map<String, String> parseKeyValuePairs(String s, Set<String> 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,

@ -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);
ChangeSource.LOCAL,
);
}
void updateSelection(TextSelection textSelection, ChangeSource source) {
@ -359,8 +364,11 @@ class QuillController extends ChangeNotifier {
textSelection = selection.copyWith(
baseOffset: delta.transformPosition(selection.baseOffset, force: false),
extentOffset:
delta.transformPosition(selection.extentOffset, force: false));
extentOffset: delta.transformPosition(
selection.extentOffset,
force: false,
),
);
if (selection != textSelection) {
_updateSelection(textSelection, source);
}

@ -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) {

@ -249,13 +249,21 @@ class DefaultStyles {
),
const VerticalSpacing(8, 0),
const VerticalSpacing(0, 0),
null),
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,7 +296,12 @@ 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,
@ -297,7 +310,8 @@ class DefaultStyles {
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));
@ -347,6 +373,7 @@ class DefaultStyles {
leading: other.leading ?? leading,
sizeSmall: other.sizeSmall ?? sizeSmall,
sizeLarge: other.sizeLarge ?? sizeLarge,
sizeHuge: other.sizeHuge ?? sizeHuge);
sizeHuge: other.sizeHuge ?? sizeHuge,
);
}
}

@ -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,16 +343,16 @@ class EditorTextSelectionGestureDetectorBuilder {
/// the handlers provided by this builder.
///
/// The [child] or its subtree should contain [EditableText].
Widget build(
{required HitTestBehavior behavior,
Widget build({
required HitTestBehavior behavior,
required Widget child,
Key? key,
bool detectWordBoundary = true}) {
bool detectWordBoundary = true,
}) {
return EditorTextSelectionGestureDetector(
key: key,
onTapDown: onTapDown,
onForcePressStart:
delegate.forcePressEnabled ? onForcePressStart : null,
onForcePressStart: delegate.forcePressEnabled ? onForcePressStart : null,
onForcePressEnd: delegate.forcePressEnabled ? onForcePressEnd : null,
onSingleTapUp: onSingleTapUp,
onSingleTapCancel: onSingleTapCancel,
@ -364,6 +366,7 @@ class EditorTextSelectionGestureDetectorBuilder {
onDragSelectionEnd: onDragSelectionEnd,
behavior: behavior,
detectWordBoundary: detectWordBoundary,
child: child);
child: child,
);
}
}

@ -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<TextPosition> {
class QuillVerticalCaretMovementRun implements Iterator<TextPosition> {
QuillVerticalCaretMovementRun._(
this._editor,
this._currentTextPosition,

@ -32,4 +32,5 @@ typedef EmbedButtonBuilder = Widget Function(
QuillController controller,
double toolbarIconSize,
QuillIconTheme? iconTheme,
QuillDialogTheme? dialogTheme);
QuillDialogTheme? dialogTheme,
);

@ -44,8 +44,9 @@ class QuillKeyboardListenerState extends State<QuillKeyboardListener> {
final QuillPressedKeys _pressedKeys = QuillPressedKeys();
bool _keyEvent(KeyEvent event) {
_pressedKeys
._updatePressedKeys(HardwareKeyboard.instance.logicalKeysPressed);
_pressedKeys._updatePressedKeys(
HardwareKeyboard.instance.logicalKeysPressed,
);
return false;
}

@ -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;

@ -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

@ -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;

@ -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,

@ -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<CheckboxPoint> {
class _QuillEditorCheckboxPointState extends State<QuillEditorCheckboxPoint> {
@override
Widget build(BuildContext context) {
final uiBuilder = widget.uiBuilder;

@ -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<int?, int> indentLevelCounts;

@ -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<int, int> indentLevelCounts, int count) {
Widget? _buildLeading({
required BuildContext context,
required Line line,
required int index,
required Map<int, int> 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)) {
@ -502,10 +517,16 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
return TextSelectionPoint(
Offset(0, preferredLineHeight(selection.extent)) +
getOffsetForCaret(selection.extent),
null);
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,10 +537,16 @@ 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.direction,
);
}
@override
@ -528,7 +555,8 @@ class RenderEditableTextBlock extends RenderEditableContainerBox
return TextSelectionPoint(
Offset(0, preferredLineHeight(selection.extent)) +
getOffsetForCaret(selection.extent),
null);
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.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();

@ -43,8 +43,8 @@ class TextLine extends StatefulWidget {
this.customStyleBuilder,
this.customRecognizerBuilder,
this.customLinkPrefixes = const <String>[],
Key? key,
}) : super(key: key);
super.key,
});
final Line line;
final TextDirection? textDirection;
@ -88,7 +88,7 @@ class _TextLineState extends State<TextLine> {
// In editing mode it depends on the platform:
// Desktop platforms (macos, linux, windows):
// Desktop platforms (macOS, Linux, Windows):
// only allow Meta (Control) + Click combinations
if (isDesktop()) {
return _metaOrControlPressed;
@ -581,7 +581,7 @@ class EditableTextLine extends RenderObjectWidget {
}
}
enum TextLineSlot { LEADING, BODY }
enum TextLineSlot { leading, body }
class RenderEditableTextLine extends RenderEditableBox {
/// Creates new editable paragraph render box.
@ -595,7 +595,8 @@ class RenderEditableTextLine extends RenderEditableBox {
this.padding,
this.color,
this.cursorCont,
this.inlineCodeStyle);
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);
@ -801,7 +805,8 @@ class RenderEditableTextLine extends RenderEditableBox {
final targetBox = first ? boxes.first : boxes.last;
return TextSelectionPoint(
Offset(first ? targetBox.start : targetBox.end, targetBox.bottom),
targetBox.direction);
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
@ -1197,7 +1239,8 @@ class RenderEditableTextLine extends RenderEditableBox {
hitTest: (result, transformed) {
assert(transformed == position - childParentData.offset);
return _leading!.hitTest(result, position: transformed);
});
},
);
if (isHit) return true;
}
if (_body == null) return false;
@ -1207,14 +1250,19 @@ class RenderEditableTextLine extends RenderEditableBox {
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:

@ -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

@ -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

@ -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);
});
});

Loading…
Cancel
Save