From c593026fd90003c30bae1b0b3d9e8b858b1a490a Mon Sep 17 00:00:00 2001 From: Miller Adulu Date: Fri, 19 Mar 2021 21:03:19 +0300 Subject: [PATCH] Sound null safety migration (#87) * Upgrade upgradable packages * Apply default null-safety migrations * Remove hashnode as a dependency and localize its functionality to the package. Maintenance was done long time ago hence no need to wait for the update * Localize ui package to reduce maintenance burdens * Replace universal html with dart:html * Remove unnecessary checks * Fix formatting * Migrate app to null safety * Enable methods to be nullable * Fix non-nullable issue with node methods * Cast as Node * Use universal html * Use universal html package to bring in the ImageElement class * Remove unused imports * Fix imports on the editor file * Add key to quill editor * Remove final from the GlobalKey * Remove final on GlobalKey * Remove custom util implementation in favor of quiver * Fix issue with null on token attrivute * Remove final hashcode that is replaced by quiver functionality * Fix merge request * Fix hit test position in text_line.dart * Fix null safety errors on text_selection.dart * Fix sound null safe errors in toolbar.dart * Import null safe file picker --- analysis_options.yaml | 3 + app/lib/pages/home_page.dart | 15 +- app/lib/pages/read_only_page.dart | 4 +- app/lib/widgets/demo_scaffold.dart | 16 +- app/lib/widgets/field.dart | 50 ++-- app/pubspec.lock | 75 +----- app/pubspec.yaml | 2 +- lib/models/documents/attribute.dart | 82 +++--- lib/models/documents/document.dart | 20 +- lib/models/documents/history.dart | 4 +- lib/models/documents/nodes/block.dart | 16 +- lib/models/documents/nodes/container.dart | 44 ++-- lib/models/documents/nodes/embed.dart | 4 +- lib/models/documents/nodes/leaf.dart | 51 ++-- lib/models/documents/nodes/line.dart | 70 +++--- lib/models/documents/nodes/node.dart | 23 +- lib/models/documents/style.dart | 6 +- lib/models/quill_delta.dart | 126 +++++----- lib/models/rules/delete.dart | 56 +++-- lib/models/rules/format.dart | 52 ++-- lib/models/rules/insert.dart | 123 +++++---- lib/models/rules/rule.dart | 14 +- lib/utils/color.dart | 4 +- lib/utils/diff_delta.dart | 14 +- lib/utils/universal_ui/fake_ui.dart | 3 + lib/utils/universal_ui/real_ui.dart | 9 + lib/utils/universal_ui/universal_ui.dart | 22 ++ lib/widgets/box.dart | 8 +- lib/widgets/controller.dart | 44 ++-- lib/widgets/cursor.dart | 47 ++-- lib/widgets/default_styles.dart | 60 +++-- lib/widgets/delegate.dart | 47 ++-- lib/widgets/editor.dart | 266 +++++++++----------- lib/widgets/image.dart | 2 +- lib/widgets/keyboard_listener.dart | 7 +- lib/widgets/proxy.dart | 75 +++--- lib/widgets/raw_editor.dart | 294 ++++++++++------------ lib/widgets/responsive_widget.dart | 8 +- lib/widgets/text_block.dart | 180 ++++++------- lib/widgets/text_line.dart | 246 +++++++++--------- lib/widgets/text_selection.dart | 238 +++++++++--------- lib/widgets/toolbar.dart | 262 +++++++++---------- pubspec.lock | 43 ++-- pubspec.yaml | 88 +++---- 44 files changed, 1315 insertions(+), 1508 deletions(-) create mode 100644 analysis_options.yaml create mode 100644 lib/utils/universal_ui/fake_ui.dart create mode 100644 lib/utils/universal_ui/real_ui.dart create mode 100644 lib/utils/universal_ui/universal_ui.dart diff --git a/analysis_options.yaml b/analysis_options.yaml new file mode 100644 index 00000000..cb1ea33c --- /dev/null +++ b/analysis_options.yaml @@ -0,0 +1,3 @@ +analyzer: + errors: + undefined_prefixed_name: ignore \ No newline at end of file diff --git a/app/lib/pages/home_page.dart b/app/lib/pages/home_page.dart index 60a42a64..f7299805 100644 --- a/app/lib/pages/home_page.dart +++ b/app/lib/pages/home_page.dart @@ -23,7 +23,7 @@ class HomePage extends StatefulWidget { } class _HomePageState extends State { - QuillController _controller; + QuillController? _controller; final FocusNode _focusNode = FocusNode(); @override @@ -75,15 +75,15 @@ class _HomePageState extends State { focusNode: FocusNode(), onKey: (RawKeyEvent event) { if (event.data.isControlPressed && event.character == 'b') { - if (_controller + if (_controller! .getSelectionStyle() .attributes .keys .contains("bold")) { - _controller + _controller! .formatSelection(Attribute.clone(Attribute.bold, null)); } else { - _controller.formatSelection(Attribute.bold); + _controller!.formatSelection(Attribute.bold); print("not bold"); } } @@ -104,7 +104,7 @@ class _HomePageState extends State { color: Colors.white, padding: const EdgeInsets.only(left: 16.0, right: 16.0), child: QuillEditor( - controller: _controller, + controller: _controller!, scrollController: ScrollController(), scrollable: true, focusNode: _focusNode, @@ -135,12 +135,12 @@ class _HomePageState extends State { child: Container( padding: EdgeInsets.symmetric(vertical: 16, horizontal: 8), child: QuillToolbar.basic( - controller: _controller, + controller: _controller!, onImagePickCallback: _onImagePickCallback), )) : Container( child: QuillToolbar.basic( - controller: _controller, + controller: _controller!, onImagePickCallback: _onImagePickCallback), ), ], @@ -151,7 +151,6 @@ class _HomePageState extends State { // Renders the image picked by imagePicker from local file storage // You can also upload the picked image to any server (eg : AWS s3 or Firebase) and then return the uploaded image URL Future _onImagePickCallback(File file) async { - if (file == null) return null; // Copies the picked file from temporary cache to applications directory Directory appDocDir = await getApplicationDocumentsDirectory(); File copiedFile = diff --git a/app/lib/pages/read_only_page.dart b/app/lib/pages/read_only_page.dart index c72313ad..8f03d45c 100644 --- a/app/lib/pages/read_only_page.dart +++ b/app/lib/pages/read_only_page.dart @@ -27,7 +27,7 @@ class _ReadOnlyPageState extends State { ); } - Widget _buildContent(BuildContext context, QuillController controller) { + Widget _buildContent(BuildContext context, QuillController? controller) { return Padding( padding: const EdgeInsets.all(8.0), child: Container( @@ -36,7 +36,7 @@ class _ReadOnlyPageState extends State { border: Border.all(color: Colors.grey.shade200), ), child: QuillEditor( - controller: controller, + controller: controller!, scrollController: ScrollController(), scrollable: true, focusNode: _focusNode, diff --git a/app/lib/widgets/demo_scaffold.dart b/app/lib/widgets/demo_scaffold.dart index 3caa00d5..1533da28 100644 --- a/app/lib/widgets/demo_scaffold.dart +++ b/app/lib/widgets/demo_scaffold.dart @@ -7,21 +7,21 @@ import 'package:flutter_quill/widgets/controller.dart'; import 'package:flutter_quill/widgets/toolbar.dart'; typedef DemoContentBuilder = Widget Function( - BuildContext context, QuillController controller); + BuildContext context, QuillController? controller); // Common scaffold for all examples. class DemoScaffold extends StatefulWidget { /// Filename of the document to load into the editor. final String documentFilename; final DemoContentBuilder builder; - final List actions; - final Widget floatingActionButton; + final List? actions; + final Widget? floatingActionButton; final bool showToolbar; const DemoScaffold({ - Key key, - @required this.documentFilename, - @required this.builder, + Key? key, + required this.documentFilename, + required this.builder, this.actions, this.showToolbar = true, this.floatingActionButton, @@ -33,7 +33,7 @@ class DemoScaffold extends StatefulWidget { class _DemoScaffoldState extends State { final _scaffoldKey = GlobalKey(); - QuillController _controller; + QuillController? _controller; bool _loading = false; @@ -92,7 +92,7 @@ class _DemoScaffoldState extends State { ), title: _loading || widget.showToolbar == false ? null - : QuillToolbar.basic(controller: _controller), + : QuillToolbar.basic(controller: _controller!), actions: actions, ), floatingActionButton: widget.floatingActionButton, diff --git a/app/lib/widgets/field.dart b/app/lib/widgets/field.dart index dd8b4bf4..35e710f2 100644 --- a/app/lib/widgets/field.dart +++ b/app/lib/widgets/field.dart @@ -6,28 +6,28 @@ import 'package:flutter_quill/widgets/editor.dart'; class QuillField extends StatefulWidget { final QuillController controller; - final FocusNode focusNode; - final ScrollController scrollController; + final FocusNode? focusNode; + final ScrollController? scrollController; final bool scrollable; final EdgeInsetsGeometry padding; final bool autofocus; final bool showCursor; final bool readOnly; final bool enableInteractiveSelection; - final double minHeight; - final double maxHeight; + final double? minHeight; + final double? maxHeight; final bool expands; final TextCapitalization textCapitalization; final Brightness keyboardAppearance; - final ScrollPhysics scrollPhysics; - final ValueChanged onLaunchUrl; - final InputDecoration decoration; - final Widget toolbar; - final EmbedBuilder embedBuilder; + final ScrollPhysics? scrollPhysics; + final ValueChanged? onLaunchUrl; + final InputDecoration? decoration; + final Widget? toolbar; + final EmbedBuilder? embedBuilder; QuillField({ - Key key, - @required this.controller, + Key? key, + required this.controller, this.focusNode, this.scrollController, this.scrollable = true, @@ -53,28 +53,28 @@ class QuillField extends StatefulWidget { } class _QuillFieldState extends State { - bool _focused; + late bool _focused; void _editorFocusChanged() { setState(() { - _focused = widget.focusNode.hasFocus; + _focused = widget.focusNode!.hasFocus; }); } @override void initState() { super.initState(); - _focused = widget.focusNode.hasFocus; - widget.focusNode.addListener(_editorFocusChanged); + _focused = widget.focusNode!.hasFocus; + widget.focusNode!.addListener(_editorFocusChanged); } @override void didUpdateWidget(covariant QuillField oldWidget) { super.didUpdateWidget(oldWidget); if (widget.focusNode != oldWidget.focusNode) { - oldWidget.focusNode.removeListener(_editorFocusChanged); - widget.focusNode.addListener(_editorFocusChanged); - _focused = widget.focusNode.hasFocus; + oldWidget.focusNode!.removeListener(_editorFocusChanged); + widget.focusNode!.addListener(_editorFocusChanged); + _focused = widget.focusNode!.hasFocus; } } @@ -82,8 +82,8 @@ class _QuillFieldState extends State { Widget build(BuildContext context) { Widget child = QuillEditor( controller: widget.controller, - focusNode: widget.focusNode, - scrollController: widget.scrollController, + focusNode: widget.focusNode!, + scrollController: widget.scrollController!, scrollable: widget.scrollable, padding: widget.padding, autoFocus: widget.autofocus, @@ -97,7 +97,7 @@ class _QuillFieldState extends State { keyboardAppearance: widget.keyboardAppearance, scrollPhysics: widget.scrollPhysics, onLaunchUrl: widget.onLaunchUrl, - embedBuilder: widget.embedBuilder, + embedBuilder: widget.embedBuilder!, ); if (widget.toolbar != null) { @@ -105,7 +105,7 @@ class _QuillFieldState extends State { children: [ child, Visibility( - child: widget.toolbar, + child: widget.toolbar!, visible: _focused, maintainSize: true, maintainAnimation: true, @@ -117,11 +117,11 @@ class _QuillFieldState extends State { return AnimatedBuilder( animation: - Listenable.merge([widget.focusNode, widget.controller]), - builder: (BuildContext context, Widget child) { + Listenable.merge([widget.focusNode, widget.controller]), + builder: (BuildContext context, Widget? child) { return InputDecorator( decoration: _getEffectiveDecoration(), - isFocused: widget.focusNode.hasFocus, + isFocused: widget.focusNode!.hasFocus, // TODO: Document should be considered empty of it has single empty line with no styles applied isEmpty: widget.controller.document.length == 1, child: child, diff --git a/app/pubspec.lock b/app/pubspec.lock index 73de09ad..e7326d61 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -43,27 +43,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.15.0" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.1" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.5" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.dartlang.org" - source: hosted - version: "0.16.2" cupertino_icons: dependency: "direct main" description: @@ -117,7 +96,7 @@ packages: name: flutter_colorpicker url: "https://pub.dartlang.org" source: hosted - version: "0.3.5" + version: "0.4.0-nullsafety.0" flutter_keyboard_visibility: dependency: transitive description: @@ -163,13 +142,6 @@ packages: description: flutter source: sdk version: "0.0.0" - html: - dependency: transitive - description: - name: html - url: "https://pub.dartlang.org" - source: hosted - version: "0.14.0+4" http: dependency: transitive description: @@ -190,7 +162,7 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.7.2" + version: "0.7.2+1" image_picker_platform_interface: dependency: transitive description: @@ -302,14 +274,7 @@ packages: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" - quiver_hashcode: - dependency: transitive - description: - name: quiver_hashcode - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" + version: "3.0.0" sky_engine: dependency: transitive description: flutter @@ -349,7 +314,7 @@ packages: name: string_validator url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.2.0-nullsafety.0" term_glyph: dependency: transitive description: @@ -370,7 +335,7 @@ packages: name: tuple url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" typed_data: dependency: transitive description: @@ -378,27 +343,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.0" - universal_html: - dependency: transitive - description: - name: universal_html - url: "https://pub.dartlang.org" - source: hosted - version: "1.2.4" - universal_io: - dependency: transitive - description: - name: universal_io - url: "https://pub.dartlang.org" - source: hosted - version: "1.0.2" - universal_ui: - dependency: transitive - description: - name: universal_ui - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.8" url_launcher: dependency: transitive description: @@ -462,13 +406,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.0" - zone_local: - dependency: transitive - description: - name: zone_local - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2" sdks: dart: ">=2.12.0 <3.0.0" - flutter: ">=1.22.0" + flutter: ">=1.24.0-10.2.pre" diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 8858a8dc..3a31d347 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -18,7 +18,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev version: 1.0.0+1 environment: - sdk: ">=2.7.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: flutter: diff --git a/lib/models/documents/attribute.dart b/lib/models/documents/attribute.dart index 2821661a..8d43e805 100644 --- a/lib/models/documents/attribute.dart +++ b/lib/models/documents/attribute.dart @@ -75,7 +75,7 @@ class Attribute { static final StyleAttribute style = StyleAttribute(null); - static final TokenAttribute token = TokenAttribute(null); + static final TokenAttribute token = TokenAttribute(''); static final Set inlineKeys = { Attribute.bold.key, @@ -105,46 +105,46 @@ class Attribute { Attribute.blockQuote.key, }; - static Attribute get h1 => HeaderAttribute(level: 1); + static Attribute get h1 => HeaderAttribute(level: 1); - static Attribute get h2 => HeaderAttribute(level: 2); + static Attribute get h2 => HeaderAttribute(level: 2); - static Attribute get h3 => HeaderAttribute(level: 3); + static Attribute get h3 => HeaderAttribute(level: 3); // "attributes":{"align":"left"} - static Attribute get leftAlignment => AlignAttribute('left'); + static Attribute get leftAlignment => AlignAttribute('left'); // "attributes":{"align":"center"} - static Attribute get centerAlignment => AlignAttribute('center'); + static Attribute get centerAlignment => AlignAttribute('center'); // "attributes":{"align":"right"} - static Attribute get rightAlignment => AlignAttribute('right'); + static Attribute get rightAlignment => AlignAttribute('right'); // "attributes":{"align":"justify"} - static Attribute get justifyAlignment => AlignAttribute('justify'); + static Attribute get justifyAlignment => AlignAttribute('justify'); // "attributes":{"list":"bullet"} - static Attribute get ul => ListAttribute('bullet'); + static Attribute get ul => ListAttribute('bullet'); // "attributes":{"list":"ordered"} - static Attribute get ol => ListAttribute('ordered'); + static Attribute get ol => ListAttribute('ordered'); // "attributes":{"list":"checked"} - static Attribute get checked => ListAttribute('checked'); + static Attribute get checked => ListAttribute('checked'); // "attributes":{"list":"unchecked"} - static Attribute get unchecked => ListAttribute('unchecked'); + static Attribute get unchecked => ListAttribute('unchecked'); // "attributes":{"indent":1"} - static Attribute get indentL1 => IndentAttribute(level: 1); + static Attribute get indentL1 => IndentAttribute(level: 1); // "attributes":{"indent":2"} - static Attribute get indentL2 => IndentAttribute(level: 2); + static Attribute get indentL2 => IndentAttribute(level: 2); // "attributes":{"indent":3"} - static Attribute get indentL3 => IndentAttribute(level: 3); + static Attribute get indentL3 => IndentAttribute(level: 3); - static Attribute getIndentLevel(int level) { + static Attribute getIndentLevel(int? level) { if (level == 1) { return indentL1; } @@ -164,7 +164,7 @@ class Attribute { if (!_registry.containsKey(key)) { throw ArgumentError.value(key, 'key "$key" not found.'); } - Attribute origin = _registry[key]; + Attribute origin = _registry[key]!; Attribute attribute = clone(origin, value); return attribute; } @@ -208,24 +208,24 @@ class StrikeThroughAttribute extends Attribute { StrikeThroughAttribute() : super('strike', AttributeScope.INLINE, true); } -class FontAttribute extends Attribute { - FontAttribute(String val) : super('font', AttributeScope.INLINE, val); +class FontAttribute extends Attribute { + FontAttribute(String? val) : super('font', AttributeScope.INLINE, val); } -class SizeAttribute extends Attribute { - SizeAttribute(String val) : super('size', AttributeScope.INLINE, val); +class SizeAttribute extends Attribute { + SizeAttribute(String? val) : super('size', AttributeScope.INLINE, val); } -class LinkAttribute extends Attribute { - LinkAttribute(String val) : super('link', AttributeScope.INLINE, val); +class LinkAttribute extends Attribute { + LinkAttribute(String? val) : super('link', AttributeScope.INLINE, val); } -class ColorAttribute extends Attribute { - ColorAttribute(String val) : super('color', AttributeScope.INLINE, val); +class ColorAttribute extends Attribute { + ColorAttribute(String? val) : super('color', AttributeScope.INLINE, val); } -class BackgroundAttribute extends Attribute { - BackgroundAttribute(String val) +class BackgroundAttribute extends Attribute { + BackgroundAttribute(String? val) : super('background', AttributeScope.INLINE, val); } @@ -234,20 +234,20 @@ class PlaceholderAttribute extends Attribute { PlaceholderAttribute() : super('placeholder', AttributeScope.INLINE, true); } -class HeaderAttribute extends Attribute { - HeaderAttribute({int level}) : super('header', AttributeScope.BLOCK, level); +class HeaderAttribute extends Attribute { + HeaderAttribute({int? level}) : super('header', AttributeScope.BLOCK, level); } -class IndentAttribute extends Attribute { - IndentAttribute({int level}) : super('indent', AttributeScope.BLOCK, level); +class IndentAttribute extends Attribute { + IndentAttribute({int? level}) : super('indent', AttributeScope.BLOCK, level); } -class AlignAttribute extends Attribute { - AlignAttribute(String val) : super('align', AttributeScope.BLOCK, val); +class AlignAttribute extends Attribute { + AlignAttribute(String? val) : super('align', AttributeScope.BLOCK, val); } -class ListAttribute extends Attribute { - ListAttribute(String val) : super('list', AttributeScope.BLOCK, val); +class ListAttribute extends Attribute { + ListAttribute(String? val) : super('list', AttributeScope.BLOCK, val); } class CodeBlockAttribute extends Attribute { @@ -258,16 +258,16 @@ class BlockQuoteAttribute extends Attribute { BlockQuoteAttribute() : super('blockquote', AttributeScope.BLOCK, true); } -class WidthAttribute extends Attribute { - WidthAttribute(String val) : super('width', AttributeScope.IGNORE, val); +class WidthAttribute extends Attribute { + WidthAttribute(String? val) : super('width', AttributeScope.IGNORE, val); } -class HeightAttribute extends Attribute { - HeightAttribute(String val) : super('height', AttributeScope.IGNORE, val); +class HeightAttribute extends Attribute { + HeightAttribute(String? val) : super('height', AttributeScope.IGNORE, val); } -class StyleAttribute extends Attribute { - StyleAttribute(String val) : super('style', AttributeScope.IGNORE, val); +class StyleAttribute extends Attribute { + StyleAttribute(String? val) : super('style', AttributeScope.IGNORE, val); } class TokenAttribute extends Attribute { diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index 73391d7b..38813510 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -43,11 +43,11 @@ class Document { _loadDocument(_delta); } - Delta insert(int index, Object data) { + Delta insert(int index, Object? data) { assert(index >= 0); assert(data is String || data is Embeddable); if (data is Embeddable) { - data = (data as Embeddable).toJson(); + data = data.toJson(); } else if ((data as String).isEmpty) { return Delta(); } @@ -66,7 +66,7 @@ class Document { return delta; } - Delta replace(int index, int len, Object data) { + Delta replace(int index, int len, Object? data) { assert(index >= 0); assert(data is String || data is Embeddable); @@ -88,7 +88,7 @@ class Document { return delta; } - Delta format(int index, int len, Attribute attribute) { + Delta format(int index, int len, Attribute? attribute) { assert(index >= 0 && len >= 0 && attribute != null); Delta delta = Delta(); @@ -113,7 +113,7 @@ class Document { if (res.node is Line) { return res; } - Block block = res.node; + Block block = res.node as Block; return block.queryChild(res.offset, true); } @@ -126,7 +126,7 @@ class Document { delta = _transform(delta); Delta originalDelta = toDelta(); for (Operation op in delta.toList()) { - Style style = + Style? style = op.attributes != null ? Style.fromJson(op.attributes) : null; if (op.isInsert) { @@ -138,7 +138,7 @@ class Document { } if (!op.isDelete) { - offset += op.length; + offset += op.length!; } } try { @@ -197,7 +197,7 @@ class Document { } } - Object _normalize(Object data) { + Object _normalize(Object? data) { if (data is String) { return data; } @@ -205,7 +205,7 @@ class Document { if (data is Embeddable) { return data; } - return Embeddable.fromJson(data); + return Embeddable.fromJson(data as Map); } close() { @@ -227,7 +227,7 @@ class Document { op.attributes != null ? Style.fromJson(op.attributes) : null; final data = _normalize(op.data); _root.insert(offset, data, style); - offset += op.length; + offset += op.length!; } final node = _root.last; if (node is Line && diff --git a/lib/models/documents/history.dart b/lib/models/documents/history.dart index ea71afe9..1bb92105 100644 --- a/lib/models/documents/history.dart +++ b/lib/models/documents/history.dart @@ -90,13 +90,13 @@ class History { } Delta delta = source.removeLast(); // look for insert or delete - int len = 0; + int? len = 0; List ops = delta.toList(); for (var i = 0; i < ops.length; i++) { if (ops[i].key == Operation.insertKey) { len = ops[i].length; } else if (ops[i].key == Operation.deleteKey) { - len = ops[i].length * -1; + len = ops[i].length! * -1; } } Delta base = Delta.from(doc.toDelta()); diff --git a/lib/models/documents/nodes/block.dart b/lib/models/documents/nodes/block.dart index d48dc38d..6ab8d331 100644 --- a/lib/models/documents/nodes/block.dart +++ b/lib/models/documents/nodes/block.dart @@ -4,7 +4,7 @@ import 'container.dart'; import 'line.dart'; import 'node.dart'; -class Block extends Container { +class Block extends Container { @override Line get defaultChild => Line(); @@ -18,7 +18,7 @@ class Block extends Container { @override adjust() { if (isEmpty) { - Node sibling = previous; + Node? sibling = previous; unlink(); if (sibling != null) { sibling.adjust(); @@ -27,18 +27,18 @@ class Block extends Container { } Block block = this; - Node prev = block.previous; + Node? prev = block.previous; // merging it with previous block if style is the same if (!block.isFirst && block.previous is Block && - prev.style == block.style) { - block.moveChildToNewParent(prev); + prev!.style == block.style) { + block.moveChildToNewParent(prev as Container?); block.unlink(); - block = prev; + block = prev as Block; } - Node next = block.next; + Node? next = block.next; // merging it with next block if style is the same - if (!block.isLast && block.next is Block && next.style == block.style) { + if (!block.isLast && block.next is Block && next!.style == block.style) { (next as Block).moveChildToNewParent(block); next.unlink(); } diff --git a/lib/models/documents/nodes/container.dart b/lib/models/documents/nodes/container.dart index b4a4aa58..2e1c29fa 100644 --- a/lib/models/documents/nodes/container.dart +++ b/lib/models/documents/nodes/container.dart @@ -4,7 +4,7 @@ import '../style.dart'; import 'node.dart'; /* Container of multiple nodes */ -abstract class Container extends Node { +abstract class Container extends Node { final LinkedList _children = LinkedList(); LinkedList get children => _children; @@ -26,32 +26,32 @@ abstract class Container extends Node { /// abstract methods end add(T node) { - assert(node.parent == null); - node.parent = this; - _children.add(node); + assert(node?.parent == null); + node?.parent = this; + _children.add(node as Node); } addFirst(T node) { - assert(node.parent == null); - node.parent = this; - _children.addFirst(node); + assert(node?.parent == null); + node?.parent = this; + _children.addFirst(node as Node); } void remove(T node) { - assert(node.parent == this); - node.parent = null; - _children.remove(node); + assert(node?.parent == this); + node?.parent = null; + _children.remove(node as Node); } - void moveChildToNewParent(Container newParent) { + void moveChildToNewParent(Container? newParent) { if (isEmpty) { return; } - T last = newParent.isEmpty ? null : newParent.last; + T? last = newParent!.isEmpty ? null : newParent.last as T?; while (isNotEmpty) { - T child = first; - child.unlink(); + T child = first as T; + child?.unlink(); newParent.add(child); } @@ -80,12 +80,12 @@ abstract class Container extends Node { int get length => _children.fold(0, (cur, node) => cur + node.length); @override - insert(int index, Object data, Style style) { + insert(int index, Object data, Style? style) { assert(index == 0 || (index > 0 && index < length)); if (isNotEmpty) { ChildQuery child = queryChild(index, false); - child.node.insert(child.offset, data, style); + child.node!.insert(child.offset, data, style); return; } @@ -93,21 +93,21 @@ abstract class Container extends Node { assert(index == 0); T node = defaultChild; add(node); - node.insert(index, data, style); + node?.insert(index, data, style); } @override - retain(int index, int length, Style attributes) { + retain(int index, int? length, Style? attributes) { assert(isNotEmpty); ChildQuery child = queryChild(index, false); - child.node.retain(child.offset, length, attributes); + child.node!.retain(child.offset, length, attributes); } @override - delete(int index, int length) { + delete(int index, int? length) { assert(isNotEmpty); ChildQuery child = queryChild(index, false); - child.node.delete(child.offset, length); + child.node!.delete(child.offset, length); } @override @@ -116,7 +116,7 @@ abstract class Container extends Node { /// Query of a child in a Container class ChildQuery { - final Node node; // null if not found + final Node? node; // null if not found final int offset; diff --git a/lib/models/documents/nodes/embed.dart b/lib/models/documents/nodes/embed.dart index a8dff833..3268e257 100644 --- a/lib/models/documents/nodes/embed.dart +++ b/lib/models/documents/nodes/embed.dart @@ -2,9 +2,7 @@ class Embeddable { final String type; final dynamic data; - Embeddable(this.type, this.data) - : assert(type != null), - assert(data != null); + Embeddable(this.type, this.data); Map toJson() { Map m = {type: data}; diff --git a/lib/models/documents/nodes/leaf.dart b/lib/models/documents/nodes/leaf.dart index 13c7b6f0..804c9a10 100644 --- a/lib/models/documents/nodes/leaf.dart +++ b/lib/models/documents/nodes/leaf.dart @@ -13,13 +13,9 @@ abstract class Leaf extends Node { Object get value => _value; - Leaf.val(Object val) - : assert(val != null), - _value = val; - - factory Leaf([Object data]) { - assert(data != null); + Leaf.val(Object val) : _value = val; + factory Leaf(Object data) { if (data is Embeddable) { return Embed(data); } @@ -30,14 +26,13 @@ abstract class Leaf extends Node { @override void applyStyle(Style value) { - assert( - value != null && (value.isInline || value.isIgnored || value.isEmpty), + assert((value.isInline || value.isIgnored || value.isEmpty), 'Unable to apply Style to leaf: $value'); super.applyStyle(value); } @override - Line get parent => super.parent as Line; + Line? get parent => super.parent as Line?; @override int get length { @@ -55,11 +50,11 @@ abstract class Leaf extends Node { } @override - insert(int index, Object data, Style style) { - assert(data != null && index >= 0 && index <= length); + insert(int index, Object data, Style? style) { + assert(index >= 0 && index <= length); Leaf node = Leaf(data); if (index < length) { - splitAt(index).insertBefore(node); + splitAt(index)!.insertBefore(node); } else { insertAfter(node); } @@ -67,36 +62,36 @@ abstract class Leaf extends Node { } @override - retain(int index, int len, Style style) { + retain(int index, int? len, Style? style) { if (style == null) { return; } - int local = math.min(this.length - index, len); + int local = math.min(this.length - index, len!); int remain = len - local; Leaf node = _isolate(index, local); if (remain > 0) { assert(node.next != null); - node.next.retain(0, remain, style); + node.next!.retain(0, remain, style); } node.format(style); } @override - delete(int index, int len) { + delete(int index, int? len) { assert(index < this.length); - int local = math.min(this.length - index, len); + int local = math.min(this.length - index, len!); Leaf target = _isolate(index, local); - Leaf prev = target.previous; - Leaf next = target.next; + Leaf? prev = target.previous as Leaf?; + Leaf? next = target.next as Leaf?; target.unlink(); int remain = len - local; if (remain > 0) { assert(next != null); - next.delete(0, remain); + next!.delete(0, remain); } if (prev != null) { @@ -112,7 +107,7 @@ abstract class Leaf extends Node { Text node = this as Text; // merging it with previous node if style is the same - Node prev = node.previous; + Node? prev = node.previous; if (!node.isFirst && prev is Text && prev.style == node.style) { prev._value = prev.value + node.value; node.unlink(); @@ -120,27 +115,27 @@ abstract class Leaf extends Node { } // merging it with next node if style is the same - Node next = node.next; + Node? next = node.next; if (!node.isLast && next is Text && next.style == node.style) { node._value = node.value + next.value; next.unlink(); } } - Leaf cutAt(int index) { + Leaf? cutAt(int index) { assert(index >= 0 && index <= length); - Leaf cut = splitAt(index); + Leaf? cut = splitAt(index); cut?.unlink(); return cut; } - Leaf splitAt(int index) { + Leaf? splitAt(int index) { assert(index >= 0 && index <= length); if (index == 0) { return this; } if (index == length) { - return isLast ? null : next as Leaf; + return isLast ? null : next as Leaf?; } assert(this is Text); @@ -152,7 +147,7 @@ abstract class Leaf extends Node { return split; } - format(Style style) { + format(Style? style) { if (style != null && style.isNotEmpty) { applyStyle(style); } @@ -163,7 +158,7 @@ abstract class Leaf extends Node { Leaf _isolate(int index, int length) { assert( index >= 0 && index < this.length && (index + length <= this.length)); - Leaf target = splitAt(index); + Leaf target = splitAt(index)!; target.splitAt(length); return target; } diff --git a/lib/models/documents/nodes/line.dart b/lib/models/documents/nodes/line.dart index 90b19f03..4e3b1ac0 100644 --- a/lib/models/documents/nodes/line.dart +++ b/lib/models/documents/nodes/line.dart @@ -10,7 +10,7 @@ import 'container.dart'; import 'embed.dart'; import 'leaf.dart'; -class Line extends Container { +class Line extends Container { @override Leaf get defaultChild => Text(); @@ -25,28 +25,30 @@ class Line extends Container { return children.single is Embed; } - Line get nextLine { + Line? get nextLine { if (!isLast) { - return next is Block ? (next as Block).first : next; + return next is Block ? (next as Block).first as Line? : next as Line?; } if (parent is! Block) { return null; } - if (parent.isLast) { + if (parent!.isLast) { return null; } - return parent.next is Block ? (parent.next as Block).first : parent.next; + return parent!.next is Block + ? (parent!.next as Block).first as Line? + : parent!.next as Line?; } @override Delta toDelta() { final delta = children .map((child) => child.toDelta()) - .fold(Delta(), (a, b) => a.concat(b)); + .fold(Delta(), (dynamic a, b) => a.concat(b)); var attributes = style; if (parent is Block) { - Block block = parent; + Block block = parent as Block; attributes = attributes.mergeAll(block.style); } delta.insert('\n', attributes.toJson()); @@ -64,7 +66,7 @@ class Line extends Container { } @override - insert(int index, Object data, Style style) { + insert(int index, Object data, Style? style) { if (data is Embeddable) { _insert(index, data, style); return; @@ -99,13 +101,13 @@ class Line extends Container { } @override - retain(int index, int len, Style style) { + retain(int index, int? len, Style? style) { if (style == null) { return; } int thisLen = this.length; - int local = math.min(thisLen - index, len); + int local = math.min(thisLen - index, len!); if (index + local == thisLen && local == 1) { assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK)); @@ -119,13 +121,13 @@ class Line extends Container { int remain = len - local; if (remain > 0) { assert(nextLine != null); - nextLine.retain(0, remain, style); + nextLine!.retain(0, remain, style); } } @override - delete(int index, int len) { - int local = math.min(this.length - index, len); + delete(int index, int? len) { + int local = math.min(this.length - index, len!); bool deleted = index + local == this.length; if (deleted) { clearStyle(); @@ -139,35 +141,35 @@ class Line extends Container { int remain = len - local; if (remain > 0) { assert(nextLine != null); - nextLine.delete(0, remain); + nextLine!.delete(0, remain); } if (deleted && isNotEmpty) { assert(nextLine != null); - nextLine.moveChildToNewParent(this); + nextLine!.moveChildToNewParent(this); moveChildToNewParent(nextLine); } if (deleted) { - Node p = parent; + Node p = parent!; unlink(); p.adjust(); } } - void _format(Style newStyle) { + void _format(Style? newStyle) { if (newStyle == null || newStyle.isEmpty) { return; } applyStyle(newStyle); - Attribute blockStyle = newStyle.getBlockExceptHeader(); + Attribute? blockStyle = newStyle.getBlockExceptHeader(); if (blockStyle == null) { return; } if (parent is Block) { - Attribute parentStyle = (parent as Block).style.getBlockExceptHeader(); + Attribute? parentStyle = (parent as Block).style.getBlockExceptHeader(); if (blockStyle.value == null) { _unwrap(); } else if (blockStyle != parentStyle) { @@ -196,7 +198,7 @@ class Line extends Container { if (parent is! Block) { throw ArgumentError('Invalid parent'); } - Block block = parent; + Block block = parent as Block; assert(block.children.contains(this)); @@ -207,10 +209,10 @@ class Line extends Container { unlink(); block.insertAfter(this); } else { - Block before = block.clone(); + Block before = block.clone() as Block; block.insertBefore(before); - Line child = block.first; + Line child = block.first as Line; while (child != this) { child.unlink(); before.add(child); @@ -232,19 +234,19 @@ class Line extends Container { } ChildQuery query = queryChild(index, false); - while (!query.node.isLast) { - Leaf next = last; + while (!query.node!.isLast) { + Leaf next = last as Leaf; next.unlink(); line.addFirst(next); } - Leaf child = query.node; - Leaf cut = child.splitAt(query.offset); + Leaf child = query.node as Leaf; + Leaf? cut = child.splitAt(query.offset); cut?.unlink(); line.addFirst(cut); return line; } - _insert(int index, Object data, Style style) { + _insert(int index, Object data, Style? style) { assert(index == 0 || (index > 0 && index < length)); if (data is String) { @@ -256,7 +258,7 @@ class Line extends Container { if (isNotEmpty) { ChildQuery result = queryChild(index, true); - result.node.insert(result.offset, data, style); + result.node!.insert(result.offset, data, style); return; } @@ -291,26 +293,26 @@ class Line extends Container { } ChildQuery data = queryChild(offset, true); - Leaf node = data.node; + Leaf? node = data.node as Leaf?; if (node != null) { res = res.mergeAll(node.style); int pos = node.length - data.offset; - while (!node.isLast && pos < local) { - node = node.next as Leaf; - _handle(node.style); + while (!node!.isLast && pos < local) { + node = node.next as Leaf?; + _handle(node!.style); pos += node.length; } } res = res.mergeAll(style); if (parent is Block) { - Block block = parent; + Block block = parent as Block; res = res.mergeAll(block.style); } int remain = len - local; if (remain > 0) { - _handle(nextLine.collectStyle(0, remain)); + _handle(nextLine!.collectStyle(0, remain)); } return res; diff --git a/lib/models/documents/nodes/node.dart b/lib/models/documents/nodes/node.dart index 9c52f9c7..984ed0a1 100644 --- a/lib/models/documents/nodes/node.dart +++ b/lib/models/documents/nodes/node.dart @@ -9,7 +9,7 @@ import 'line.dart'; /* node in a document tree */ abstract class Node extends LinkedListEntry { - Container parent; + Container? parent; Style _style = Style(); Style get style => _style; @@ -19,9 +19,6 @@ abstract class Node extends LinkedListEntry { } void applyStyle(Style value) { - if (value == null) { - throw ArgumentError('null value'); - } _style = _style.mergeAll(value); } @@ -29,9 +26,9 @@ abstract class Node extends LinkedListEntry { _style = Style(); } - bool get isFirst => list.first == this; + bool get isFirst => list!.first == this; - bool get isLast => list.last == this; + bool get isLast => list!.last == this; int get length; @@ -50,14 +47,14 @@ abstract class Node extends LinkedListEntry { Node cur = this; do { - cur = cur.previous; + cur = cur.previous!; offset += cur.length; } while (!cur.isFirst); return offset; } int getDocumentOffset() { - final parentOffset = (parent is! Root) ? parent.getDocumentOffset() : 0; + final parentOffset = (parent is! Root) ? parent!.getDocumentOffset() : 0; return parentOffset + getOffset(); } @@ -99,20 +96,20 @@ abstract class Node extends LinkedListEntry { Delta toDelta(); - insert(int index, Object data, Style style); + insert(int index, Object data, Style? style); - retain(int index, int len, Style style); + retain(int index, int? len, Style? style); - delete(int index, int len); + delete(int index, int? len); /// abstract methods end } /* Root node of document tree */ -class Root extends Container> { +class Root extends Container> { @override - Container get defaultChild => Line(); + Container get defaultChild => Line(); @override Delta toDelta() => children diff --git a/lib/models/documents/style.dart b/lib/models/documents/style.dart index aa3588d6..7b9b050b 100644 --- a/lib/models/documents/style.dart +++ b/lib/models/documents/style.dart @@ -10,7 +10,7 @@ class Style { Style() : _attributes = {}; - static Style fromJson(Map attributes) { + static Style fromJson(Map? attributes) { if (attributes == null) { return Style(); } @@ -22,7 +22,7 @@ class Style { return Style.attr(result); } - Map toJson() => _attributes.isEmpty + Map? toJson() => _attributes.isEmpty ? null : _attributes.map((String _, Attribute attribute) => MapEntry(attribute.key, attribute.value)); @@ -46,7 +46,7 @@ class Style { bool containsKey(String key) => _attributes.containsKey(key); - Attribute getBlockExceptHeader() { + Attribute? getBlockExceptHeader() { for (Attribute val in values) { if (val.isBlockExceptHeader) { return val; diff --git a/lib/models/quill_delta.dart b/lib/models/quill_delta.dart index cbfee575..bced9b88 100644 --- a/lib/models/quill_delta.dart +++ b/lib/models/quill_delta.dart @@ -15,10 +15,10 @@ const _valueEquality = DeepCollectionEquality(); /// Decoder function to convert raw `data` object into a user-defined data type. /// /// Useful with embedded content. -typedef DataDecoder = Object Function(Object data); +typedef DataDecoder = Object? Function(Object data); /// Default data decoder which simply passes through the original value. -Object _passThroughDataDecoder(Object data) => data; +Object? _passThroughDataDecoder(Object? data) => data; /// Operation performed on a rich-text document. class Operation { @@ -40,19 +40,18 @@ class Operation { final String key; /// Length of this operation. - final int length; + final int? length; /// Payload of "insert" operation, for other types is set to empty string. - final Object data; + final Object? data; /// Rich-text attributes set by this operation, can be `null`. - Map get attributes => - _attributes == null ? null : Map.from(_attributes); - final Map _attributes; + Map? get attributes => + _attributes == null ? null : Map.from(_attributes!); + final Map? _attributes; - Operation._(this.key, this.length, this.data, Map attributes) - : assert(key != null && length != null && data != null), - assert(_validKeys.contains(key), 'Invalid operation key "$key".'), + Operation._(this.key, this.length, this.data, Map? attributes) + : assert(_validKeys.contains(key), 'Invalid operation key "$key".'), assert(() { if (key != Operation.insertKey) return true; return data is String ? data.length == length : length == 1; @@ -64,7 +63,7 @@ class Operation { /// /// If `dataDecoder` parameter is not null then it is used to additionally /// decode the operation's data object. Only applied to insert operations. - static Operation fromJson(Map data, {DataDecoder dataDecoder}) { + static Operation fromJson(Map data, {DataDecoder? dataDecoder}) { dataDecoder ??= _passThroughDataDecoder; final map = Map.from(data); if (map.containsKey(Operation.insertKey)) { @@ -73,10 +72,10 @@ class Operation { return Operation._( Operation.insertKey, dataLength, data, map[Operation.attributesKey]); } else if (map.containsKey(Operation.deleteKey)) { - final int length = map[Operation.deleteKey]; + final int? length = map[Operation.deleteKey]; return Operation._(Operation.deleteKey, length, '', null); } else if (map.containsKey(Operation.retainKey)) { - final int length = map[Operation.retainKey]; + final int? length = map[Operation.retainKey]; return Operation._( Operation.retainKey, length, '', map[Operation.attributesKey]); } @@ -95,13 +94,13 @@ class Operation { Operation._(Operation.deleteKey, length, '', null); /// Creates operation which inserts [text] with optional [attributes]. - factory Operation.insert(dynamic data, [Map attributes]) => + factory Operation.insert(dynamic data, [Map? attributes]) => Operation._(Operation.insertKey, data is String ? data.length : 1, data, attributes); /// Creates operation which retains [length] of characters and optionally /// applies attributes. - factory Operation.retain(int length, [Map attributes]) => + factory Operation.retain(int? length, [Map? attributes]) => Operation._(Operation.retainKey, length, '', attributes); /// Returns value of this operation. @@ -119,7 +118,7 @@ class Operation { bool get isRetain => key == Operation.retainKey; /// Returns `true` if this operation has no attributes, e.g. is plain text. - bool get isPlain => (_attributes == null || _attributes.isEmpty); + bool get isPlain => (_attributes == null || _attributes!.isEmpty); /// Returns `true` if this operation sets at least one attribute. bool get isNotPlain => !isPlain; @@ -130,7 +129,7 @@ class Operation { bool get isEmpty => length == 0; /// Returns `true` is this operation is not empty. - bool get isNotEmpty => length > 0; + bool get isNotEmpty => length! > 0; @override bool operator ==(other) { @@ -144,7 +143,8 @@ class Operation { } /// Returns `true` if this operation has attribute specified by [name]. - bool hasAttribute(String name) => isNotPlain && _attributes.containsKey(name); + bool hasAttribute(String name) => + isNotPlain && _attributes!.containsKey(name); /// Returns `true` if [other] operation has the same attributes as this one. bool hasSameAttributes(Operation other) { @@ -153,9 +153,9 @@ class Operation { @override int get hashCode { - if (_attributes != null && _attributes.isNotEmpty) { + if (_attributes != null && _attributes!.isNotEmpty) { final attrsHash = - hashObjects(_attributes.entries.map((e) => hash2(e.key, e.value))); + hashObjects(_attributes!.entries.map((e) => hash2(e.key, e.value))); return hash3(key, value, attrsHash); } return hash2(key, value); @@ -181,8 +181,8 @@ class Operation { /// it is a "change delta". class Delta { /// Transforms two attribute sets. - static Map transformAttributes( - Map a, Map b, bool priority) { + static Map? transformAttributes( + Map? a, Map? b, bool priority) { if (a == null) return b; if (b == null) return null; @@ -197,8 +197,8 @@ class Delta { } /// Composes two attribute sets. - static Map composeAttributes( - Map a, Map b, + static Map? composeAttributes( + Map? a, Map? b, {bool keepNull = false}) { a ??= const {}; b ??= const {}; @@ -217,12 +217,12 @@ class Delta { ///get anti-attr result base on base static Map invertAttributes( - Map attr, Map base) { + Map? attr, Map? base) { attr ??= const {}; base ??= const {}; - var baseInverted = base.keys.fold({}, (memo, key) { - if (base[key] != attr[key] && attr.containsKey(key)) { + var baseInverted = base.keys.fold({}, (dynamic memo, key) { + if (base![key] != attr![key] && attr.containsKey(key)) { memo[key] = base[key]; } return memo; @@ -230,7 +230,7 @@ class Delta { var inverted = Map.from(attr.keys.fold(baseInverted, (memo, key) { - if (base[key] != attr[key] && !base.containsKey(key)) { + if (base![key] != attr![key] && !base.containsKey(key)) { memo[key] = null; } return memo; @@ -242,9 +242,7 @@ class Delta { int _modificationCount = 0; - Delta._(List operations) - : assert(operations != null), - _operations = operations; + Delta._(List operations) : _operations = operations; /// Creates new empty [Delta]. factory Delta() => Delta._([]); @@ -257,7 +255,7 @@ class Delta { /// /// If `dataDecoder` parameter is not null then it is used to additionally /// decode the operation's data object. Only applied to insert operations. - static Delta fromJson(List data, {DataDecoder dataDecoder}) { + static Delta fromJson(List data, {DataDecoder? dataDecoder}) { return Delta._(data .map((op) => Operation.fromJson(op, dataDecoder: dataDecoder)) .toList()); @@ -304,15 +302,14 @@ class Delta { int get hashCode => hashObjects(_operations); /// Retain [count] of characters from current position. - void retain(int count, [Map attributes]) { + void retain(int count, [Map? attributes]) { assert(count >= 0); if (count == 0) return; // no-op push(Operation.retain(count, attributes)); } /// Insert [data] at current position. - void insert(dynamic data, [Map attributes]) { - assert(data != null); + void insert(dynamic data, [Map? attributes]) { if (data is String && data.isEmpty) return; // no-op push(Operation.insert(data, attributes)); } @@ -326,10 +323,10 @@ class Delta { void _mergeWithTail(Operation operation) { assert(isNotEmpty); - assert(operation != null && last.key == operation.key); + assert(last.key == operation.key); assert(operation.data is String && last.data is String); - final length = operation.length + last.length; + final length = operation.length! + last.length!; final lastText = last.data as String; final opText = operation.data as String; final resultText = lastText + opText; @@ -396,12 +393,13 @@ class Delta { /// Returns new operation or `null` if operations from [thisIter] and /// [otherIter] nullify each other. For instance, for the pair `insert('abc')` /// and `delete(3)` composition result would be empty string. - Operation _composeOperation(DeltaIterator thisIter, DeltaIterator otherIter) { + Operation? _composeOperation( + DeltaIterator thisIter, DeltaIterator otherIter) { if (otherIter.isNextInsert) return otherIter.next(); if (thisIter.isNextDelete) return thisIter.next(); final length = math.min(thisIter.peekLength(), otherIter.peekLength()); - final thisOp = thisIter.next(length); + final thisOp = thisIter.next(length as int); final otherOp = otherIter.next(length); assert(thisOp.length == otherOp.length); @@ -448,7 +446,7 @@ class Delta { /// [thisIter]. /// /// Returns `null` if both operations nullify each other. - Operation _transformOperation( + Operation? _transformOperation( DeltaIterator thisIter, DeltaIterator otherIter, bool priority) { if (thisIter.isNextInsert && (priority || !otherIter.isNextInsert)) { return Operation.retain(thisIter.next().length); @@ -457,7 +455,7 @@ class Delta { } final length = math.min(thisIter.peekLength(), otherIter.peekLength()); - final thisOp = thisIter.next(length); + final thisOp = thisIter.next(length as int); final otherOp = otherIter.next(length); assert(thisOp.length == otherOp.length); @@ -520,12 +518,12 @@ class Delta { var baseIndex = 0; for (final op in _operations) { if (op.isInsert) { - inverted.delete(op.length); + inverted.delete(op.length!); } else if (op.isRetain && op.isPlain) { - inverted.retain(op.length, null); - baseIndex += op.length; + inverted.retain(op.length!, null); + baseIndex += op.length!; } else if (op.isDelete || (op.isRetain && op.isNotPlain)) { - final length = op.length; + final length = op.length!; final sliceDelta = base.slice(baseIndex, baseIndex + length); sliceDelta.toList().forEach((baseOp) { if (op.isDelete) { @@ -533,7 +531,7 @@ class Delta { } else if (op.isRetain && op.isNotPlain) { var invertAttr = invertAttributes(op.attributes, baseOp.attributes); inverted.retain( - baseOp.length, invertAttr.isEmpty ? null : invertAttr); + baseOp.length!, invertAttr.isEmpty ? null : invertAttr); } }); baseIndex += length; @@ -547,7 +545,7 @@ class Delta { /// Returns slice of this delta from [start] index (inclusive) to [end] /// (exclusive). - Delta slice(int start, [int end]) { + Delta slice(int start, [int? end]) { final delta = Delta(); var index = 0; var opIterator = DeltaIterator(this); @@ -559,10 +557,10 @@ class Delta { if (index < start) { op = opIterator.next(start - index); } else { - op = opIterator.next(actualEnd - index); + op = opIterator.next(actualEnd - index as int); delta.push(op); } - index += op.length; + index += op.length!; } return delta; } @@ -585,12 +583,12 @@ class Delta { while (iter.hasNext && offset <= index) { final op = iter.next(); if (op.isDelete) { - index -= math.min(op.length, index - offset); + index -= math.min(op.length!, index - offset); continue; } else if (op.isInsert && (offset < index || force)) { - index += op.length; + index += op.length!; } - offset += op.length; + offset += op.length!; } return index; } @@ -614,7 +612,7 @@ class DeltaIterator { bool get isNextRetain => nextOperationKey == Operation.retainKey; - String get nextOperationKey { + String? get nextOperationKey { if (_index < delta.length) { return delta.elementAt(_index).key; } else { @@ -630,7 +628,7 @@ class DeltaIterator { num peekLength() { if (_index < delta.length) { final operation = delta._operations[_index]; - return operation.length - _offset; + return operation.length! - _offset; } return double.infinity; } @@ -640,8 +638,6 @@ class DeltaIterator { /// Optional [length] specifies maximum length of operation to return. Note /// that actual length of returned operation may be less than specified value. Operation next([int length = 4294967296]) { - assert(length != null); - if (_modificationCount != delta._modificationCount) { throw ConcurrentModificationError(delta); } @@ -651,21 +647,21 @@ class DeltaIterator { final opKey = op.key; final opAttributes = op.attributes; final _currentOffset = _offset; - final actualLength = math.min(op.length - _currentOffset, length); - if (actualLength == op.length - _currentOffset) { + final actualLength = math.min(op.length! - _currentOffset, length); + if (actualLength == op.length! - _currentOffset) { _index++; _offset = 0; } else { _offset += actualLength; } final opData = op.isInsert && op.data is String - ? (op.data as String) - .substring(_currentOffset, _currentOffset + actualLength) + ? (op.data as String).substring( + _currentOffset as int, _currentOffset + (actualLength as int)) : op.data; final opIsNotEmpty = opData is String ? opData.isNotEmpty : true; // embeds are never empty final opLength = opData is String ? opData.length : 1; - final int opActualLength = opIsNotEmpty ? opLength : actualLength; + final int opActualLength = opIsNotEmpty ? opLength : actualLength as int; return Operation._(opKey, opActualLength, opData, opAttributes); } return Operation.retain(length); @@ -674,14 +670,14 @@ class DeltaIterator { /// Skips [length] characters in source delta. /// /// Returns last skipped operation, or `null` if there was nothing to skip. - Operation skip(int length) { + Operation? skip(int length) { var skipped = 0; - Operation op; + Operation? op; while (skipped < length && hasNext) { final opLength = peekLength(); final skip = math.min(length - skipped, opLength); - op = next(skip); - skipped += op.length; + op = next(skip as int); + skipped += op.length!; } return op; } diff --git a/lib/models/rules/delete.dart b/lib/models/rules/delete.dart index 6cbb28ff..8f590231 100644 --- a/lib/models/rules/delete.dart +++ b/lib/models/rules/delete.dart @@ -9,7 +9,7 @@ abstract class DeleteRule extends Rule { RuleType get type => RuleType.DELETE; @override - validateArgs(int len, Object data, Attribute attribute) { + validateArgs(int? len, Object? data, Attribute? attribute) { assert(len != null); assert(data == null); assert(attribute == null); @@ -21,10 +21,10 @@ class CatchAllDeleteRule extends DeleteRule { @override Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { + {int? len, Object? data, Attribute? attribute}) { return Delta() ..retain(index) - ..delete(len); + ..delete(len!); } } @@ -32,8 +32,8 @@ class PreserveLineStyleOnMergeRule extends DeleteRule { const PreserveLineStyleOnMergeRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { DeltaIterator itr = DeltaIterator(document); itr.skip(index); Operation op = itr.next(1); @@ -42,30 +42,30 @@ class PreserveLineStyleOnMergeRule extends DeleteRule { } bool isNotPlain = op.isNotPlain; - Map attrs = op.attributes; + Map? attrs = op.attributes; - itr.skip(len - 1); + itr.skip(len! - 1); Delta delta = Delta() ..retain(index) ..delete(len); while (itr.hasNext) { op = itr.next(); - String text = op.data is String ? op.data as String : ''; + String text = op.data is String ? (op.data as String?)! : ''; int lineBreak = text.indexOf('\n'); if (lineBreak == -1) { - delta..retain(op.length); + delta..retain(op.length!); continue; } - Map attributes = op.attributes == null + Map? attributes = op.attributes == null ? null - : op.attributes.map((String key, dynamic value) => + : op.attributes!.map((String key, dynamic value) => MapEntry(key, null)); if (isNotPlain) { attributes ??= {}; - attributes.addAll(attrs); + attributes.addAll(attrs!); } delta..retain(lineBreak)..retain(1, attributes); break; @@ -78,33 +78,35 @@ class EnsureEmbedLineRule extends DeleteRule { const EnsureEmbedLineRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { DeltaIterator itr = DeltaIterator(document); - Operation op = itr.skip(index); - int indexDelta = 0, lengthDelta = 0, remain = len; + Operation? op = itr.skip(index); + int? indexDelta = 0, lengthDelta = 0, remain = len; bool embedFound = op != null && op.data is! String; bool hasLineBreakBefore = - !embedFound && (op == null || (op?.data as String).endsWith('\n')); + !embedFound && (op == null || (op.data as String).endsWith('\n')); if (embedFound) { Operation candidate = itr.next(1); - remain--; - if (candidate.data == '\n') { - indexDelta++; - lengthDelta--; - - candidate = itr.next(1); + if (remain != null) { remain--; if (candidate.data == '\n') { - lengthDelta++; + indexDelta++; + lengthDelta--; + + candidate = itr.next(1); + remain--; + if (candidate.data == '\n') { + lengthDelta++; + } } } } - op = itr.skip(remain); + op = itr.skip(remain!); if (op != null && - (op?.data is String ? op.data as String : '').endsWith('\n')) { + (op.data is String ? op.data as String? : '')!.endsWith('\n')) { Operation candidate = itr.next(1); if (candidate.data is! String && !hasLineBreakBefore) { embedFound = true; @@ -118,6 +120,6 @@ class EnsureEmbedLineRule extends DeleteRule { return Delta() ..retain(index + indexDelta) - ..delete(len + lengthDelta); + ..delete(len! + lengthDelta); } } diff --git a/lib/models/rules/format.dart b/lib/models/rules/format.dart index 755bc0bb..f5875833 100644 --- a/lib/models/rules/format.dart +++ b/lib/models/rules/format.dart @@ -9,7 +9,7 @@ abstract class FormatRule extends Rule { RuleType get type => RuleType.FORMAT; @override - validateArgs(int len, Object data, Attribute attribute) { + validateArgs(int? len, Object? data, Attribute? attribute) { assert(len != null); assert(data == null); assert(attribute != null); @@ -20,9 +20,9 @@ class ResolveLineFormatRule extends FormatRule { const ResolveLineFormatRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (attribute.scope != AttributeScope.BLOCK) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (attribute!.scope != AttributeScope.BLOCK) { return null; } @@ -30,13 +30,13 @@ class ResolveLineFormatRule extends FormatRule { DeltaIterator itr = DeltaIterator(document); itr.skip(index); Operation op; - for (int cur = 0; cur < len && itr.hasNext; cur += op.length) { + for (int cur = 0; cur < len! && itr.hasNext; cur += op.length!) { op = itr.next(len - cur); if (op.data is! String || !(op.data as String).contains('\n')) { - delta.retain(op.length); + delta.retain(op.length!); continue; } - String text = op.data; + String text = op.data as String; Delta tmp = Delta(); int offset = 0; @@ -52,10 +52,10 @@ class ResolveLineFormatRule extends FormatRule { while (itr.hasNext) { op = itr.next(); - String text = op.data is String ? op.data as String : ''; + String text = op.data is String ? (op.data as String?)! : ''; int lineBreak = text.indexOf('\n'); if (lineBreak < 0) { - delta..retain(op.length); + delta..retain(op.length!); continue; } delta..retain(lineBreak)..retain(1, attribute.toJson()); @@ -69,28 +69,28 @@ class FormatLinkAtCaretPositionRule extends FormatRule { const FormatLinkAtCaretPositionRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (attribute.key != Attribute.link.key || len > 0) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (attribute!.key != Attribute.link.key || len! > 0) { return null; } Delta delta = Delta(); DeltaIterator itr = DeltaIterator(document); - Operation before = itr.skip(index), after = itr.next(); - int beg = index, retain = 0; + Operation? before = itr.skip(index), after = itr.next(); + int? beg = index, retain = 0; if (before != null && before.hasAttribute(attribute.key)) { - beg -= before.length; + beg -= before.length!; retain = before.length; } - if (after != null && after.hasAttribute(attribute.key)) { - retain += after.length; + if (after.hasAttribute(attribute.key)) { + if (retain != null) retain += after.length!; } if (retain == 0) { return null; } - delta..retain(beg)..retain(retain, attribute.toJson()); + delta..retain(beg)..retain(retain!, attribute.toJson()); return delta; } } @@ -99,9 +99,9 @@ class ResolveInlineFormatRule extends FormatRule { const ResolveInlineFormatRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (attribute.scope != AttributeScope.INLINE) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (attribute!.scope != AttributeScope.INLINE) { return null; } @@ -110,12 +110,12 @@ class ResolveInlineFormatRule extends FormatRule { itr.skip(index); Operation op; - for (int cur = 0; cur < len && itr.hasNext; cur += op.length) { + for (int cur = 0; cur < len! && itr.hasNext; cur += op.length!) { op = itr.next(len - cur); - String text = op.data is String ? op.data as String : ''; + String text = op.data is String ? (op.data as String?)! : ''; int lineBreak = text.indexOf('\n'); if (lineBreak < 0) { - delta.retain(op.length, attribute.toJson()); + delta.retain(op.length!, attribute.toJson()); continue; } int pos = 0; @@ -124,8 +124,8 @@ class ResolveInlineFormatRule extends FormatRule { pos = lineBreak + 1; lineBreak = text.indexOf('\n', pos); } - if (pos < op.length) { - delta.retain(op.length - pos, attribute.toJson()); + if (pos < op.length!) { + delta.retain(op.length! - pos, attribute.toJson()); } } diff --git a/lib/models/rules/insert.dart b/lib/models/rules/insert.dart index 1973d981..61829972 100644 --- a/lib/models/rules/insert.dart +++ b/lib/models/rules/insert.dart @@ -11,7 +11,7 @@ abstract class InsertRule extends Rule { RuleType get type => RuleType.INSERT; @override - validateArgs(int len, Object data, Attribute attribute) { + validateArgs(int? len, Object? data, Attribute? attribute) { assert(len == null); assert(data != null); assert(attribute == null); @@ -22,23 +22,21 @@ class PreserveLineStyleOnSplitRule extends InsertRule { const PreserveLineStyleOnSplitRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (data is! String || (data as String) != '\n') { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (data is! String || data != '\n') { return null; } DeltaIterator itr = DeltaIterator(document); - Operation before = itr.skip(index); + Operation? before = itr.skip(index); if (before == null || before.data is! String || (before.data as String).endsWith('\n')) { return null; } Operation after = itr.next(); - if (after == null || - after.data is! String || - (after.data as String).startsWith('\n')) { + if (after.data is! String || (after.data as String).startsWith('\n')) { return null; } @@ -50,8 +48,8 @@ class PreserveLineStyleOnSplitRule extends InsertRule { delta..insert('\n'); return delta; } - Tuple2 nextNewLine = _getNextNewLine(itr); - Map attributes = nextNewLine?.item1?.attributes; + Tuple2 nextNewLine = _getNextNewLine(itr); + Map? attributes = nextNewLine.item1?.attributes; return delta..insert('\n', attributes); } @@ -61,33 +59,33 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { const PreserveBlockStyleOnInsertRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (data is! String || !(data as String).contains('\n')) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (data is! String || !data.contains('\n')) { return null; } DeltaIterator itr = DeltaIterator(document); itr.skip(index); - Tuple2 nextNewLine = _getNextNewLine(itr); + Tuple2 nextNewLine = _getNextNewLine(itr); Style lineStyle = Style.fromJson(nextNewLine.item1?.attributes ?? {}); - Attribute attribute = lineStyle.getBlockExceptHeader(); + Attribute? attribute = lineStyle.getBlockExceptHeader(); if (attribute == null) { return null; } var blockStyle = {attribute.key: attribute.value}; - Map resetStyle; + Map? resetStyle; if (lineStyle.containsKey(Attribute.header.key)) { resetStyle = Attribute.header.toJson(); } - List lines = (data as String).split('\n'); + List lines = data.split('\n'); Delta delta = Delta()..retain(index); for (int i = 0; i < lines.length; i++) { String line = lines[i]; @@ -102,9 +100,9 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { } if (resetStyle != null) { - delta.retain(nextNewLine.item2); + delta.retain(nextNewLine.item2!); delta - ..retain((nextNewLine.item1.data as String).indexOf('\n')) + ..retain((nextNewLine.item1!.data as String).indexOf('\n')) ..retain(1, resetStyle); } @@ -115,26 +113,26 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { class AutoExitBlockRule extends InsertRule { const AutoExitBlockRule(); - bool _isEmptyLine(Operation before, Operation after) { + bool _isEmptyLine(Operation? before, Operation? after) { if (before == null) { return true; } return before.data is String && (before.data as String).endsWith('\n') && - after.data is String && + after!.data is String && (after.data as String).startsWith('\n'); } @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (data is! String || (data as String) != '\n') { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (data is! String || data != '\n') { return null; } DeltaIterator itr = DeltaIterator(document); - Operation prev = itr.skip(index), cur = itr.next(); - Attribute blockStyle = + Operation? prev = itr.skip(index), cur = itr.next(); + Attribute? blockStyle = Style.fromJson(cur.attributes).getBlockExceptHeader(); if (cur.isPlain || blockStyle == null) { return null; @@ -147,10 +145,10 @@ class AutoExitBlockRule extends InsertRule { return null; } - Tuple2 nextNewLine = _getNextNewLine(itr); + Tuple2 nextNewLine = _getNextNewLine(itr); if (nextNewLine.item1 != null && - nextNewLine.item1.attributes != null && - Style.fromJson(nextNewLine.item1.attributes).getBlockExceptHeader() == + nextNewLine.item1!.attributes != null && + Style.fromJson(nextNewLine.item1!.attributes).getBlockExceptHeader() == blockStyle) { return null; } @@ -168,9 +166,9 @@ class ResetLineFormatOnNewLineRule extends InsertRule { const ResetLineFormatOnNewLineRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (data is! String || (data as String) != '\n') { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (data is! String || data != '\n') { return null; } @@ -181,9 +179,9 @@ class ResetLineFormatOnNewLineRule extends InsertRule { return null; } - Map resetStyle; + Map? resetStyle; if (cur.attributes != null && - cur.attributes.containsKey(Attribute.header.key)) { + cur.attributes!.containsKey(Attribute.header.key)) { resetStyle = Attribute.header.toJson(); } return Delta() @@ -198,33 +196,33 @@ class InsertEmbedsRule extends InsertRule { const InsertEmbedsRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { if (data is String) { return null; } Delta delta = Delta()..retain(index); DeltaIterator itr = DeltaIterator(document); - Operation prev = itr.skip(index), cur = itr.next(); + Operation? prev = itr.skip(index), cur = itr.next(); - String textBefore = prev?.data is String ? prev.data as String : ''; - String textAfter = cur.data is String ? cur.data as String : ''; + String? textBefore = prev?.data is String ? prev!.data as String? : ''; + String textAfter = cur.data is String ? (cur.data as String?)! : ''; - final isNewlineBefore = prev == null || textBefore.endsWith('\n'); + final isNewlineBefore = prev == null || textBefore!.endsWith('\n'); final isNewlineAfter = textAfter.startsWith('\n'); if (isNewlineBefore && isNewlineAfter) { return delta..insert(data); } - Map lineStyle; + Map? lineStyle; if (textAfter.contains('\n')) { lineStyle = cur.attributes; } else { while (itr.hasNext) { Operation op = itr.next(); - if ((op.data is String ? op.data as String : '').indexOf('\n') >= 0) { + if ((op.data is String ? op.data as String? : '')!.indexOf('\n') >= 0) { lineStyle = op.attributes; break; } @@ -246,13 +244,13 @@ class ForceNewlineForInsertsAroundEmbedRule extends InsertRule { const ForceNewlineForInsertsAroundEmbedRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { if (data is! String) { return null; } - String text = data as String; + String text = data; DeltaIterator itr = DeltaIterator(document); final prev = itr.skip(index); final cur = itr.next(); @@ -277,14 +275,14 @@ class AutoFormatLinksRule extends InsertRule { const AutoFormatLinksRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (data is! String || (data as String) != ' ') { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (data is! String || data != ' ') { return null; } DeltaIterator itr = DeltaIterator(document); - Operation prev = itr.skip(index); + Operation? prev = itr.skip(index); if (prev == null || prev.data is! String) { return null; } @@ -305,7 +303,7 @@ class AutoFormatLinksRule extends InsertRule { return Delta() ..retain(index - cand.length) ..retain(cand.length, attributes) - ..insert(data as String, prev.attributes); + ..insert(data, prev.attributes); } on FormatException { return null; } @@ -316,22 +314,22 @@ class PreserveInlineStylesRule extends InsertRule { const PreserveInlineStylesRule(); @override - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { - if (data is! String || (data as String).contains('\n')) { + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { + if (data is! String || data.contains('\n')) { return null; } DeltaIterator itr = DeltaIterator(document); - Operation prev = itr.skip(index); + Operation? prev = itr.skip(index); if (prev == null || prev.data is! String || (prev.data as String).contains('\n')) { return null; } - Map attributes = prev.attributes; - String text = data as String; + Map? attributes = prev.attributes; + String text = data; if (attributes == null || !attributes.containsKey(Attribute.link.key)) { return Delta() ..retain(index) @@ -343,9 +341,7 @@ class PreserveInlineStylesRule extends InsertRule { ..retain(index) ..insert(text, attributes.isEmpty ? null : attributes); Operation next = itr.next(); - if (next == null) { - return delta; - } + Map nextAttributes = next.attributes ?? const {}; if (!nextAttributes.containsKey(Attribute.link.key)) { @@ -365,18 +361,19 @@ class CatchAllInsertRule extends InsertRule { @override Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}) { + {int? len, Object? data, Attribute? attribute}) { return Delta() ..retain(index) ..insert(data); } } -Tuple2 _getNextNewLine(DeltaIterator iterator) { +Tuple2 _getNextNewLine(DeltaIterator iterator) { Operation op; - for (int skipped = 0; iterator.hasNext; skipped += op.length) { + for (int skipped = 0; iterator.hasNext; skipped += op.length!) { op = iterator.next(); - int lineBreak = (op.data is String ? op.data as String : '').indexOf('\n'); + int lineBreak = + (op.data is String ? op.data as String? : '')!.indexOf('\n'); if (lineBreak >= 0) { return Tuple2(op, skipped); } diff --git a/lib/models/rules/rule.dart b/lib/models/rules/rule.dart index 13c7d12e..a549c22f 100644 --- a/lib/models/rules/rule.dart +++ b/lib/models/rules/rule.dart @@ -11,19 +11,17 @@ enum RuleType { INSERT, DELETE, FORMAT } abstract class Rule { const Rule(); - Delta apply(Delta document, int index, - {int len, Object data, Attribute attribute}) { - assert(document != null); - assert(index != null); + Delta? apply(Delta document, int index, + {int? len, Object? data, Attribute? attribute}) { validateArgs(len, data, attribute); return applyRule(document, index, len: len, data: data, attribute: attribute); } - validateArgs(int len, Object data, Attribute attribute); + validateArgs(int? len, Object? data, Attribute? attribute); - Delta applyRule(Delta document, int index, - {int len, Object data, Attribute attribute}); + Delta? applyRule(Delta document, int index, + {int? len, Object? data, Attribute? attribute}); RuleType get type; } @@ -53,7 +51,7 @@ class Rules { static Rules getInstance() => _instance; Delta apply(RuleType ruleType, Document document, int index, - {int len, Object data, Attribute attribute}) { + {int? len, Object? data, Attribute? attribute}) { final delta = document.toDelta(); for (var rule in _rules) { if (rule.type != ruleType) { diff --git a/lib/utils/color.dart b/lib/utils/color.dart index f37906ff..c7f467fa 100644 --- a/lib/utils/color.dart +++ b/lib/utils/color.dart @@ -2,7 +2,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; -Color stringToColor(String s) { +Color stringToColor(String? s) { switch (s) { case 'transparent': return Colors.transparent; @@ -106,7 +106,7 @@ Color stringToColor(String s) { return Colors.brown; } - if (s.startsWith('rgba')) { + if (s!.startsWith('rgba')) { s = s.substring(5); // trim left 'rgba(' s = s.substring(0, s.length - 1); // trim right ')' final arr = s.split(',').map((e) => e.trim()).toList(); diff --git a/lib/utils/diff_delta.dart b/lib/utils/diff_delta.dart index 673dacd2..8733c48f 100644 --- a/lib/utils/diff_delta.dart +++ b/lib/utils/diff_delta.dart @@ -76,7 +76,7 @@ int getPositionDelta(Delta user, Delta actual) { int diff = 0; while (userItr.hasNext || actualItr.hasNext) { final length = math.min(userItr.peekLength(), actualItr.peekLength()); - Operation userOperation = userItr.next(length); + Operation userOperation = userItr.next(length as int); Operation actualOperation = actualItr.next(length); if (userOperation.length != actualOperation.length) { throw ('userOp ' + @@ -88,18 +88,18 @@ int getPositionDelta(Delta user, Delta actual) { if (userOperation.key == actualOperation.key) { continue; } else if (userOperation.isInsert && actualOperation.isRetain) { - diff -= userOperation.length; + diff -= userOperation.length!; } else if (userOperation.isDelete && actualOperation.isRetain) { - diff += userOperation.length; + diff += userOperation.length!; } else if (userOperation.isRetain && actualOperation.isInsert) { - String operationTxt = ''; + String? operationTxt = ''; if (actualOperation.data is String) { - operationTxt = actualOperation.data as String; + operationTxt = actualOperation.data as String?; } - if (operationTxt.startsWith('\n')) { + if (operationTxt!.startsWith('\n')) { continue; } - diff += actualOperation.length; + diff += actualOperation.length!; } } return diff; diff --git a/lib/utils/universal_ui/fake_ui.dart b/lib/utils/universal_ui/fake_ui.dart new file mode 100644 index 00000000..da0f9a32 --- /dev/null +++ b/lib/utils/universal_ui/fake_ui.dart @@ -0,0 +1,3 @@ +class platformViewRegistry { + static registerViewFactory(String viewId, dynamic cb) {} +} diff --git a/lib/utils/universal_ui/real_ui.dart b/lib/utils/universal_ui/real_ui.dart new file mode 100644 index 00000000..c2b8ea23 --- /dev/null +++ b/lib/utils/universal_ui/real_ui.dart @@ -0,0 +1,9 @@ +import 'dart:ui' as ui; + +// ignore: camel_case_types +class platformViewRegistry { + static registerViewFactory(String viewId, dynamic cb) { + // ignore:undefined_prefixed_name + ui.platformViewRegistry.registerViewFactory(viewId, cb); + } +} diff --git a/lib/utils/universal_ui/universal_ui.dart b/lib/utils/universal_ui/universal_ui.dart new file mode 100644 index 00000000..d97aff1f --- /dev/null +++ b/lib/utils/universal_ui/universal_ui.dart @@ -0,0 +1,22 @@ +library universal_ui; + +import 'package:flutter/foundation.dart'; +import 'fake_ui.dart' if (dart.library.html) 'real_ui.dart' as ui_instance; + +class PlatformViewRegistryFix { + registerViewFactory(dynamic x, dynamic y) { + if (kIsWeb) { + // ignore: undefined_prefixed_name + ui_instance.platformViewRegistry.registerViewFactory( + x, + y, + ); + } else {} + } +} + +class UniversalUI { + PlatformViewRegistryFix platformViewRegistry = PlatformViewRegistryFix(); +} + +var ui = UniversalUI(); diff --git a/lib/widgets/box.dart b/lib/widgets/box.dart index 9a28d1e1..5e43b841 100644 --- a/lib/widgets/box.dart +++ b/lib/widgets/box.dart @@ -4,11 +4,11 @@ import 'package:flutter_quill/models/documents/nodes/container.dart'; abstract class RenderContentProxyBox implements RenderBox { double getPreferredLineHeight(); - Offset getOffsetForCaret(TextPosition position, Rect caretPrototype); + Offset getOffsetForCaret(TextPosition position, Rect? caretPrototype); TextPosition getPositionForOffset(Offset offset); - double getFullHeightForCaret(TextPosition position); + double? getFullHeightForCaret(TextPosition position); TextRange getWordBoundary(TextPosition position); @@ -24,9 +24,9 @@ abstract class RenderEditableBox extends RenderBox { TextPosition getPositionForOffset(Offset offset); - TextPosition getPositionAbove(TextPosition position); + TextPosition? getPositionAbove(TextPosition position); - TextPosition getPositionBelow(TextPosition position); + TextPosition? getPositionBelow(TextPosition position); TextRange getWordBoundary(TextPosition position); diff --git a/lib/widgets/controller.dart b/lib/widgets/controller.dart index 9c23d327..2ea56e32 100644 --- a/lib/widgets/controller.dart +++ b/lib/widgets/controller.dart @@ -14,9 +14,7 @@ class QuillController extends ChangeNotifier { TextSelection selection; Style toggledStyle = Style(); - QuillController({@required this.document, @required this.selection}) - : assert(document != null), - assert(selection != null); + QuillController({required this.document, required this.selection}); factory QuillController.basic() { return QuillController( @@ -49,14 +47,14 @@ class QuillController extends ChangeNotifier { } } - void _handleHistoryChange(int len) { + void _handleHistoryChange(int? len) { if (len != 0) { // if (this.selection.extentOffset >= document.length) { // // cursor exceeds the length of document, position it in the end // updateSelection( // TextSelection.collapsed(offset: document.length), ChangeSource.LOCAL); updateSelection( - TextSelection.collapsed(offset: this.selection.baseOffset + len), + TextSelection.collapsed(offset: this.selection.baseOffset + len!), ChangeSource.LOCAL); } else { // no need to move cursor @@ -75,19 +73,18 @@ class QuillController extends ChangeNotifier { get hasRedo => document.hasRedo; - replaceText(int index, int len, Object data, TextSelection textSelection) { + replaceText(int index, int len, Object? data, TextSelection? textSelection) { assert(data is String || data is Embeddable); - Delta delta; - if (len > 0 || data is! String || (data as String).isNotEmpty) { + Delta? delta; + if (len > 0 || data is! String || data.isNotEmpty) { try { delta = document.replace(index, len, data); } catch (e) { print('document.replace failed: $e'); throw e; } - bool shouldRetainDelta = delta != null && - toggledStyle.isNotEmpty && + bool shouldRetainDelta = toggledStyle.isNotEmpty && delta.isNotEmpty && delta.length <= 2 && delta.last.isInsert; @@ -137,8 +134,10 @@ class QuillController extends ChangeNotifier { notifyListeners(); } - formatText(int index, int len, Attribute attribute) { - if (len == 0 && attribute.isInline && attribute.key != Attribute.link.key) { + formatText(int index, int len, Attribute? attribute) { + if (len == 0 && + attribute!.isInline && + attribute.key != Attribute.link.key) { toggledStyle = toggledStyle.put(attribute); } @@ -152,7 +151,7 @@ class QuillController extends ChangeNotifier { notifyListeners(); } - formatSelection(Attribute attribute) { + formatSelection(Attribute? attribute) { formatText(selection.start, selection.end - selection.start, attribute); } @@ -165,18 +164,15 @@ class QuillController extends ChangeNotifier { if (delta.isNotEmpty) { document.compose(delta, source); } - if (textSelection != null) { + + textSelection = selection.copyWith( + baseOffset: delta.transformPosition(selection.baseOffset, force: false), + extentOffset: + delta.transformPosition(selection.extentOffset, force: false)); + if (selection != textSelection) { _updateSelection(textSelection, source); - } else { - textSelection = selection.copyWith( - baseOffset: - delta.transformPosition(selection.baseOffset, force: false), - extentOffset: - delta.transformPosition(selection.extentOffset, force: false)); - if (selection != textSelection) { - _updateSelection(textSelection, source); - } } + notifyListeners(); } @@ -187,8 +183,6 @@ class QuillController extends ChangeNotifier { } _updateSelection(TextSelection textSelection, ChangeSource source) { - assert(textSelection != null); - assert(source != null); selection = textSelection; int end = document.length - 1; selection = selection.copyWith( diff --git a/lib/widgets/cursor.dart b/lib/widgets/cursor.dart index 6318dba6..d6305569 100644 --- a/lib/widgets/cursor.dart +++ b/lib/widgets/cursor.dart @@ -11,25 +11,22 @@ class CursorStyle { final Color color; final Color backgroundColor; final double width; - final double height; - final Radius radius; - final Offset offset; + final double? height; + final Radius? radius; + final Offset? offset; final bool opacityAnimates; final bool paintAboveText; const CursorStyle({ - @required this.color, - @required this.backgroundColor, + required this.color, + required this.backgroundColor, this.width = 1.0, this.height, this.radius, this.offset, this.opacityAnimates = false, this.paintAboveText = false, - }) : assert(color != null), - assert(backgroundColor != null), - assert(opacityAnimates != null), - assert(paintAboveText != null); + }); @override bool operator ==(Object other) => @@ -61,19 +58,16 @@ class CursorCont extends ChangeNotifier { final ValueNotifier show; final ValueNotifier _blink; final ValueNotifier color; - AnimationController _blinkOpacityCont; - Timer _cursorTimer; + late AnimationController _blinkOpacityCont; + Timer? _cursorTimer; bool _targetCursorVisibility = false; CursorStyle _style; CursorCont({ - @required ValueNotifier show, - @required CursorStyle style, - @required TickerProvider tickerProvider, - }) : assert(show != null), - assert(style != null), - assert(tickerProvider != null), - show = show ?? ValueNotifier(false), + required ValueNotifier show, + required CursorStyle style, + required TickerProvider tickerProvider, + }) : show = show, _style = style, _blink = ValueNotifier(false), color = ValueNotifier(style.color) { @@ -89,7 +83,6 @@ class CursorCont extends ChangeNotifier { CursorStyle get style => _style; set style(CursorStyle value) { - assert(value != null); if (_style == value) return; _style = value; notifyListeners(); @@ -161,9 +154,9 @@ class CursorCont extends ChangeNotifier { } class CursorPainter { - final RenderContentProxyBox editable; + final RenderContentProxyBox? editable; final CursorStyle style; - final Rect prototype; + final Rect? prototype; final Color color; final double devicePixelRatio; @@ -174,17 +167,17 @@ class CursorPainter { assert(prototype != null); Offset caretOffset = - editable.getOffsetForCaret(position, prototype) + offset; - Rect caretRect = prototype.shift(caretOffset); + editable!.getOffsetForCaret(position, prototype) + offset; + Rect caretRect = prototype!.shift(caretOffset); if (style.offset != null) { - caretRect = caretRect.shift(style.offset); + caretRect = caretRect.shift(style.offset!); } if (caretRect.left < 0.0) { caretRect = caretRect.shift(Offset(-caretRect.left, 0.0)); } - double caretHeight = editable.getFullHeightForCaret(position); + double? caretHeight = editable!.getFullHeightForCaret(position); if (caretHeight != null) { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -212,7 +205,7 @@ class CursorPainter { } } - Offset caretPosition = editable.localToGlobal(caretRect.topLeft); + Offset caretPosition = editable!.localToGlobal(caretRect.topLeft); double pixelMultiple = 1.0 / devicePixelRatio; caretRect = caretRect.shift(Offset( caretPosition.dx.isFinite @@ -230,7 +223,7 @@ class CursorPainter { return; } - RRect caretRRect = RRect.fromRectAndRadius(caretRect, style.radius); + RRect caretRRect = RRect.fromRectAndRadius(caretRect, style.radius!); canvas.drawRRect(caretRRect, paint); } } diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index 4cad7bbb..7beb9f5c 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -6,25 +6,23 @@ class QuillStyles extends InheritedWidget { final DefaultStyles data; QuillStyles({ - Key key, - @required this.data, - @required Widget child, - }) : assert(data != null), - assert(child != null), - super(key: key, child: child); + Key? key, + required this.data, + required Widget child, + }) : super(key: key, child: child); @override bool updateShouldNotify(QuillStyles oldWidget) { return data != oldWidget.data; } - static DefaultStyles getStyles(BuildContext context, bool nullOk) { + static DefaultStyles? getStyles(BuildContext context, bool nullOk) { var widget = context.dependOnInheritedWidgetOfExactType(); if (widget == null && nullOk) { return null; } assert(widget != null); - return widget.data; + return widget!.data; } } @@ -35,31 +33,31 @@ class DefaultTextBlockStyle { final Tuple2 lineSpacing; - final BoxDecoration decoration; + final BoxDecoration? decoration; DefaultTextBlockStyle( this.style, this.verticalSpacing, this.lineSpacing, this.decoration); } class DefaultStyles { - final DefaultTextBlockStyle h1; - final DefaultTextBlockStyle h2; - final DefaultTextBlockStyle h3; - final DefaultTextBlockStyle paragraph; - final TextStyle bold; - final TextStyle italic; - final TextStyle underline; - final TextStyle strikeThrough; - final TextStyle sizeSmall; // 'small' - final TextStyle sizeLarge; // 'large' - final TextStyle sizeHuge; // 'huge' - final TextStyle link; - final DefaultTextBlockStyle placeHolder; - final DefaultTextBlockStyle lists; - final DefaultTextBlockStyle quote; - final DefaultTextBlockStyle code; - final DefaultTextBlockStyle indent; - final DefaultTextBlockStyle align; + final DefaultTextBlockStyle? h1; + final DefaultTextBlockStyle? h2; + final DefaultTextBlockStyle? h3; + final DefaultTextBlockStyle? paragraph; + final TextStyle? bold; + final TextStyle? italic; + final TextStyle? underline; + final TextStyle? strikeThrough; + final TextStyle? sizeSmall; // 'small' + final TextStyle? sizeLarge; // 'large' + final TextStyle? sizeHuge; // 'huge' + final TextStyle? link; + final DefaultTextBlockStyle? placeHolder; + final DefaultTextBlockStyle? lists; + final DefaultTextBlockStyle? quote; + final DefaultTextBlockStyle? code; + final DefaultTextBlockStyle? indent; + final DefaultTextBlockStyle? align; DefaultStyles( {this.h1, @@ -109,7 +107,7 @@ class DefaultStyles { h1: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 34.0, - color: defaultTextStyle.style.color.withOpacity(0.70), + color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.15, fontWeight: FontWeight.w300, ), @@ -119,7 +117,7 @@ class DefaultStyles { h2: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 24.0, - color: defaultTextStyle.style.color.withOpacity(0.70), + color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.15, fontWeight: FontWeight.normal, ), @@ -129,7 +127,7 @@ class DefaultStyles { h3: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( fontSize: 20.0, - color: defaultTextStyle.style.color.withOpacity(0.70), + color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.25, fontWeight: FontWeight.w500, ), @@ -158,7 +156,7 @@ class DefaultStyles { lists: DefaultTextBlockStyle( baseStyle, baseSpacing, Tuple2(0.0, 6.0), null), quote: DefaultTextBlockStyle( - TextStyle(color: baseStyle.color.withOpacity(0.6)), + TextStyle(color: baseStyle.color!.withOpacity(0.6)), baseSpacing, Tuple2(6.0, 2.0), BoxDecoration( diff --git a/lib/widgets/delegate.dart b/lib/widgets/delegate.dart index aee7a058..a8278246 100644 --- a/lib/widgets/delegate.dart +++ b/lib/widgets/delegate.dart @@ -14,28 +14,27 @@ abstract class EditorTextSelectionGestureDetectorBuilderDelegate { bool getForcePressEnabled(); - bool getSelectionEnabled(); + bool? getSelectionEnabled(); } class EditorTextSelectionGestureDetectorBuilder { final EditorTextSelectionGestureDetectorBuilderDelegate delegate; bool shouldShowSelectionToolbar = true; - EditorTextSelectionGestureDetectorBuilder(this.delegate) - : assert(delegate != null); + EditorTextSelectionGestureDetectorBuilder(this.delegate); - EditorState getEditor() { + EditorState? getEditor() { return delegate.getEditableTextKey().currentState; } - RenderEditor getRenderEditor() { - return this.getEditor().getRenderEditor(); + RenderEditor? getRenderEditor() { + return this.getEditor()!.getRenderEditor(); } onTapDown(TapDownDetails details) { - getRenderEditor().handleTapDown(details); + getRenderEditor()!.handleTapDown(details); - PointerDeviceKind kind = details.kind; + PointerDeviceKind? kind = details.kind; shouldShowSelectionToolbar = kind == null || kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; @@ -44,8 +43,8 @@ class EditorTextSelectionGestureDetectorBuilder { onForcePressStart(ForcePressDetails details) { assert(delegate.getForcePressEnabled()); shouldShowSelectionToolbar = true; - if (delegate.getSelectionEnabled()) { - getRenderEditor().selectWordsInRange( + if (delegate.getSelectionEnabled()!) { + getRenderEditor()!.selectWordsInRange( details.globalPosition, null, SelectionChangedCause.forcePress, @@ -55,27 +54,27 @@ class EditorTextSelectionGestureDetectorBuilder { onForcePressEnd(ForcePressDetails details) { assert(delegate.getForcePressEnabled()); - getRenderEditor().selectWordsInRange( + getRenderEditor()!.selectWordsInRange( details.globalPosition, null, SelectionChangedCause.forcePress, ); if (shouldShowSelectionToolbar) { - getEditor().showToolbar(); + getEditor()!.showToolbar(); } } onSingleTapUp(TapUpDetails details) { - if (delegate.getSelectionEnabled()) { - getRenderEditor().selectWordEdge(SelectionChangedCause.tap); + if (delegate.getSelectionEnabled()!) { + getRenderEditor()!.selectWordEdge(SelectionChangedCause.tap); } } onSingleTapCancel() {} onSingleLongTapStart(LongPressStartDetails details) { - if (delegate.getSelectionEnabled()) { - getRenderEditor().selectPositionAt( + if (delegate.getSelectionEnabled()!) { + getRenderEditor()!.selectPositionAt( details.globalPosition, null, SelectionChangedCause.longPress, @@ -84,8 +83,8 @@ class EditorTextSelectionGestureDetectorBuilder { } onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) { - if (delegate.getSelectionEnabled()) { - getRenderEditor().selectPositionAt( + if (delegate.getSelectionEnabled()!) { + getRenderEditor()!.selectPositionAt( details.globalPosition, null, SelectionChangedCause.longPress, @@ -95,21 +94,21 @@ class EditorTextSelectionGestureDetectorBuilder { onSingleLongTapEnd(LongPressEndDetails details) { if (shouldShowSelectionToolbar) { - getEditor().showToolbar(); + getEditor()!.showToolbar(); } } onDoubleTapDown(TapDownDetails details) { - if (delegate.getSelectionEnabled()) { - getRenderEditor().selectWord(SelectionChangedCause.tap); + if (delegate.getSelectionEnabled()!) { + getRenderEditor()!.selectWord(SelectionChangedCause.tap); if (shouldShowSelectionToolbar) { - getEditor().showToolbar(); + getEditor()!.showToolbar(); } } } onDragSelectionStart(DragStartDetails details) { - getRenderEditor().selectPositionAt( + getRenderEditor()!.selectPositionAt( details.globalPosition, null, SelectionChangedCause.drag, @@ -118,7 +117,7 @@ class EditorTextSelectionGestureDetectorBuilder { onDragSelectionUpdate( DragStartDetails startDetails, DragUpdateDetails updateDetails) { - getRenderEditor().selectPositionAt( + getRenderEditor()!.selectPositionAt( startDetails.globalPosition, updateDetails.globalPosition, SelectionChangedCause.drag, diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 6c355b22..12b698bf 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -16,13 +16,13 @@ import 'package:flutter_quill/models/documents/nodes/embed.dart'; import 'package:flutter_quill/models/documents/nodes/leaf.dart' as leaf; import 'package:flutter_quill/models/documents/nodes/line.dart'; import 'package:flutter_quill/models/documents/nodes/node.dart'; +import 'package:flutter_quill/utils/universal_ui/universal_ui.dart'; import 'package:flutter_quill/widgets/image.dart'; import 'package:flutter_quill/widgets/raw_editor.dart'; import 'package:flutter_quill/widgets/responsive_widget.dart'; import 'package:flutter_quill/widgets/text_selection.dart'; import 'package:string_validator/string_validator.dart'; -import 'package:universal_html/prefer_universal/html.dart' as html; -import 'package:universal_ui/universal_ui.dart'; +import 'package:universal_html/html.dart' as html; import 'package:url_launcher/url_launcher.dart'; import 'box.dart'; @@ -53,9 +53,9 @@ abstract class EditorState extends State { void setTextEditingValue(TextEditingValue value); - RenderEditor getRenderEditor(); + RenderEditor? getRenderEditor(); - EditorTextSelectionOverlay getSelectionOverlay(); + EditorTextSelectionOverlay? getSelectionOverlay(); bool showToolbar(); @@ -146,51 +146,45 @@ class QuillEditor extends StatefulWidget { final bool scrollable; final EdgeInsetsGeometry padding; final bool autoFocus; - final bool showCursor; + final bool? showCursor; final bool readOnly; - final String placeholder; - final bool enableInteractiveSelection; - final double minHeight; - final double maxHeight; - final DefaultStyles customStyles; + final String? placeholder; + final bool? enableInteractiveSelection; + final double? minHeight; + final double? maxHeight; + final DefaultStyles? customStyles; final bool expands; final TextCapitalization textCapitalization; final Brightness keyboardAppearance; - final ScrollPhysics scrollPhysics; - final ValueChanged onLaunchUrl; + final ScrollPhysics? scrollPhysics; + final ValueChanged? onLaunchUrl; final EmbedBuilder embedBuilder; QuillEditor( - {@required this.controller, - @required this.focusNode, - @required this.scrollController, - @required this.scrollable, - @required this.padding, - @required this.autoFocus, + {Key? key, + required this.controller, + required this.focusNode, + required this.scrollController, + required this.scrollable, + required this.padding, + required this.autoFocus, this.showCursor, - @required this.readOnly, + required this.readOnly, this.placeholder, this.enableInteractiveSelection, this.minHeight, this.maxHeight, this.customStyles, - @required this.expands, + required this.expands, this.textCapitalization = TextCapitalization.sentences, this.keyboardAppearance = Brightness.light, this.scrollPhysics, this.onLaunchUrl, this.embedBuilder = - kIsWeb ? _defaultEmbedBuilderWeb : _defaultEmbedBuilder}) - : assert(controller != null), - assert(scrollController != null), - assert(scrollable != null), - assert(focusNode != null), - assert(autoFocus != null), - assert(readOnly != null), - assert(embedBuilder != null); + kIsWeb ? _defaultEmbedBuilderWeb : _defaultEmbedBuilder}); factory QuillEditor.basic( - {@required QuillController controller, bool readOnly}) { + {Key? key, required QuillController controller, required bool readOnly}) { return QuillEditor( controller: controller, scrollController: ScrollController(), @@ -209,8 +203,9 @@ class QuillEditor extends StatefulWidget { class _QuillEditorState extends State implements EditorTextSelectionGestureDetectorBuilderDelegate { - final GlobalKey _editorKey = GlobalKey(); - EditorTextSelectionGestureDetectorBuilder _selectionGestureDetectorBuilder; + GlobalKey _editorKey = GlobalKey(); + late EditorTextSelectionGestureDetectorBuilder + _selectionGestureDetectorBuilder; @override void initState() { @@ -227,10 +222,10 @@ class _QuillEditorState extends State TextSelectionControls textSelectionControls; bool paintCursorAboveText; bool cursorOpacityAnimates; - Offset cursorOffset; - Color cursorColor; + Offset? cursorOffset; + Color? cursorColor; Color selectionColor; - Radius cursorRadius; + Radius? cursorRadius; switch (theme.platform) { case TargetPlatform.android: @@ -301,7 +296,7 @@ class _QuillEditorState extends State selectionColor, textSelectionControls, widget.keyboardAppearance, - widget.enableInteractiveSelection, + widget.enableInteractiveSelection!, widget.scrollPhysics, widget.embedBuilder), ); @@ -318,12 +313,12 @@ class _QuillEditorState extends State } @override - bool getSelectionEnabled() { + bool? getSelectionEnabled() { return widget.enableInteractiveSelection; } _requestKeyboard() { - _editorKey.currentState.requestKeyboard(); + _editorKey.currentState!.requestKeyboard(); } } @@ -336,8 +331,8 @@ class _QuillEditorSelectionGestureDetectorBuilder @override onForcePressStart(ForcePressDetails details) { super.onForcePressStart(details); - if (delegate.getSelectionEnabled() && shouldShowSelectionToolbar) { - getEditor().showToolbar(); + if (delegate.getSelectionEnabled()! && shouldShowSelectionToolbar) { + getEditor()!.showToolbar(); } } @@ -346,13 +341,13 @@ class _QuillEditorSelectionGestureDetectorBuilder @override void onSingleLongTapMoveUpdate(LongPressMoveUpdateDetails details) { - if (!delegate.getSelectionEnabled()) { + if (!delegate.getSelectionEnabled()!) { return; } switch (Theme.of(_state.context).platform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - getRenderEditor().selectPositionAt( + getRenderEditor()!.selectPositionAt( details.globalPosition, null, SelectionChangedCause.longPress, @@ -362,7 +357,7 @@ class _QuillEditorSelectionGestureDetectorBuilder case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - getRenderEditor().selectWordsInRange( + getRenderEditor()!.selectWordsInRange( details.globalPosition - details.offsetFromOrigin, details.globalPosition, SelectionChangedCause.longPress, @@ -378,9 +373,9 @@ class _QuillEditorSelectionGestureDetectorBuilder return false; } TextPosition pos = - getRenderEditor().getPositionForOffset(details.globalPosition); + getRenderEditor()!.getPositionForOffset(details.globalPosition); containerNode.ChildQuery result = - getEditor().widget.controller.document.queryChild(pos.offset); + getEditor()!.widget.controller.document.queryChild(pos.offset); if (result.node == null) { return false; } @@ -391,7 +386,7 @@ class _QuillEditorSelectionGestureDetectorBuilder if (line.length == 1) { // tapping when no text yet on this line _flipListCheckbox(pos, line, segmentResult); - getEditor().widget.controller.updateSelection( + getEditor()!.widget.controller.updateSelection( TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL); return true; } @@ -399,33 +394,34 @@ class _QuillEditorSelectionGestureDetectorBuilder } leaf.Leaf segment = segmentResult.node as leaf.Leaf; if (segment.style.containsKey(Attribute.link.key)) { - var launchUrl = getEditor().widget.onLaunchUrl; + var launchUrl = getEditor()!.widget.onLaunchUrl; if (launchUrl == null) { launchUrl = _launchUrl; } - String link = segment.style.attributes[Attribute.link.key].value; - if (getEditor().widget.readOnly && link != null) { + String? link = segment.style.attributes[Attribute.link.key]!.value; + if (getEditor()!.widget.readOnly && link != null) { link = link.trim(); if (!linkPrefixes - .any((linkPrefix) => link.toLowerCase().startsWith(linkPrefix))) { + .any((linkPrefix) => link!.toLowerCase().startsWith(linkPrefix))) { link = 'https://$link'; } launchUrl(link); } return false; } - if (getEditor().widget.readOnly && segment.value is BlockEmbed) { + if (getEditor()!.widget.readOnly && segment.value is BlockEmbed) { BlockEmbed blockEmbed = segment.value as BlockEmbed; if (blockEmbed.type == 'image') { final String imageUrl = blockEmbed.data; Navigator.push( - getEditor().context, + getEditor()!.context, MaterialPageRoute( builder: (context) => ImageTapWrapper( imageProvider: imageUrl.startsWith('http') ? NetworkImage(imageUrl) : isBase64(imageUrl) ? Image.memory(base64.decode(imageUrl)) + as ImageProvider? : FileImage(io.File(imageUrl)), ), ), @@ -441,25 +437,25 @@ class _QuillEditorSelectionGestureDetectorBuilder bool _flipListCheckbox( TextPosition pos, Line line, containerNode.ChildQuery segmentResult) { - if (getEditor().widget.readOnly || + if (getEditor()!.widget.readOnly || !line.style.containsKey(Attribute.list.key) || segmentResult.offset != 0) { return false; } // segmentResult.offset == 0 means tap at the beginning of the TextLine - String listVal = line.style.attributes[Attribute.list.key].value; + String? listVal = line.style.attributes[Attribute.list.key]!.value; if (listVal == Attribute.unchecked.value) { - getEditor() + getEditor()! .widget .controller .formatText(pos.offset, 0, Attribute.checked); } else if (listVal == Attribute.checked.value) { - getEditor() + getEditor()! .widget .controller .formatText(pos.offset, 0, Attribute.unchecked); } - getEditor().widget.controller.updateSelection( + getEditor()!.widget.controller.updateSelection( TextSelection.collapsed(offset: pos.offset), ChangeSource.LOCAL); return true; } @@ -470,11 +466,11 @@ class _QuillEditorSelectionGestureDetectorBuilder @override onSingleTapUp(TapUpDetails details) { - getEditor().hideToolbar(); + getEditor()!.hideToolbar(); bool positionSelected = _onTapping(details); - if (delegate.getSelectionEnabled() && !positionSelected) { + if (delegate.getSelectionEnabled()! && !positionSelected) { switch (Theme.of(_state.context).platform) { case TargetPlatform.iOS: case TargetPlatform.macOS: @@ -482,11 +478,11 @@ class _QuillEditorSelectionGestureDetectorBuilder case PointerDeviceKind.mouse: case PointerDeviceKind.stylus: case PointerDeviceKind.invertedStylus: - getRenderEditor().selectPosition(SelectionChangedCause.tap); + getRenderEditor()!.selectPosition(SelectionChangedCause.tap); break; case PointerDeviceKind.touch: case PointerDeviceKind.unknown: - getRenderEditor().selectWordEdge(SelectionChangedCause.tap); + getRenderEditor()!.selectWordEdge(SelectionChangedCause.tap); break; } break; @@ -494,7 +490,7 @@ class _QuillEditorSelectionGestureDetectorBuilder case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - getRenderEditor().selectPosition(SelectionChangedCause.tap); + getRenderEditor()!.selectPosition(SelectionChangedCause.tap); break; } } @@ -503,11 +499,11 @@ class _QuillEditorSelectionGestureDetectorBuilder @override void onSingleLongTapStart(LongPressStartDetails details) { - if (delegate.getSelectionEnabled()) { + if (delegate.getSelectionEnabled()!) { switch (Theme.of(_state.context).platform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - getRenderEditor().selectPositionAt( + getRenderEditor()!.selectPositionAt( details.globalPosition, null, SelectionChangedCause.longPress, @@ -517,7 +513,7 @@ class _QuillEditorSelectionGestureDetectorBuilder case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - getRenderEditor().selectWord(SelectionChangedCause.longPress); + getRenderEditor()!.selectWord(SelectionChangedCause.longPress); Feedback.forLongPress(_state.context); break; default: @@ -548,7 +544,7 @@ class RenderEditor extends RenderEditableContainerBox final ValueNotifier _selectionEndInViewport = ValueNotifier(true); RenderEditor( - List children, + List? children, TextDirection textDirection, EdgeInsetsGeometry padding, this.document, @@ -558,11 +554,7 @@ class RenderEditor extends RenderEditableContainerBox this._startHandleLayerLink, this._endHandleLayerLink, EdgeInsets floatingCursorAddedMargin) - : assert(document != null), - assert(textDirection != null), - assert(_hasFocus != null), - assert(floatingCursorAddedMargin != null), - super( + : super( children, document.root, textDirection, @@ -570,7 +562,6 @@ class RenderEditor extends RenderEditableContainerBox ); setDocument(Document doc) { - assert(doc != null); if (document == doc) { return; } @@ -579,7 +570,6 @@ class RenderEditor extends RenderEditableContainerBox } setHasFocus(bool h) { - assert(h != null); if (_hasFocus == h) { return; } @@ -614,15 +604,13 @@ class RenderEditor extends RenderEditableContainerBox @override List getEndpointsForSelection( TextSelection textSelection) { - assert(constraints != null); - if (textSelection.isCollapsed) { RenderEditableBox child = childAtPosition(textSelection.extent); TextPosition localPosition = TextPosition( offset: textSelection.extentOffset - child.getContainer().getOffset()); Offset localOffset = child.getOffsetForCaret(localPosition); - BoxParentData parentData = child.parentData; + BoxParentData parentData = child.parentData as BoxParentData; return [ TextSelectionPoint( Offset(0.0, child.preferredLineHeight(localPosition)) + @@ -632,7 +620,7 @@ class RenderEditor extends RenderEditableContainerBox ]; } - Node baseNode = _container.queryChild(textSelection.start, false).node; + Node? baseNode = _container.queryChild(textSelection.start, false).node; var baseChild = firstChild; while (baseChild != null) { @@ -643,7 +631,7 @@ class RenderEditor extends RenderEditableContainerBox } assert(baseChild != null); - BoxParentData baseParentData = baseChild.parentData; + BoxParentData baseParentData = baseChild!.parentData as BoxParentData; TextSelection baseSelection = localSelection(baseChild.getContainer(), textSelection, true); TextSelectionPoint basePoint = @@ -651,8 +639,8 @@ class RenderEditor extends RenderEditableContainerBox basePoint = TextSelectionPoint( basePoint.point + baseParentData.offset, basePoint.direction); - Node extentNode = _container.queryChild(textSelection.end, false).node; - var extentChild = baseChild; + Node? extentNode = _container.queryChild(textSelection.end, false).node; + RenderEditableBox? extentChild = baseChild; while (extentChild != null) { if (extentChild.getContainer() == extentNode) { break; @@ -661,7 +649,7 @@ class RenderEditor extends RenderEditableContainerBox } assert(extentChild != null); - BoxParentData extentParentData = extentChild.parentData; + BoxParentData extentParentData = extentChild!.parentData as BoxParentData; TextSelection extentSelection = localSelection(extentChild.getContainer(), textSelection, true); TextSelectionPoint extentPoint = @@ -672,7 +660,7 @@ class RenderEditor extends RenderEditableContainerBox return [basePoint, extentPoint]; } - Offset _lastTapDownPosition; + Offset? _lastTapDownPosition; @override handleTapDown(TapDownDetails details) { @@ -682,14 +670,9 @@ class RenderEditor extends RenderEditableContainerBox @override selectWordsInRange( Offset from, - Offset to, + Offset? to, SelectionChangedCause cause, ) { - assert(cause != null); - assert(from != null); - if (onSelectionChanged == null) { - return; - } TextPosition firstPosition = getPositionForOffset(from); TextSelection firstWord = selectWordAtPosition(firstPosition); TextSelection lastWord = @@ -717,19 +700,13 @@ class RenderEditor extends RenderEditableContainerBox !focusingEmpty) { return; } - if (onSelectionChanged != null) { - onSelectionChanged(nextSelection, cause); - } + onSelectionChanged(nextSelection, cause); } @override selectWordEdge(SelectionChangedCause cause) { - assert(cause != null); assert(_lastTapDownPosition != null); - if (onSelectionChanged == null) { - return; - } - TextPosition position = getPositionForOffset(_lastTapDownPosition); + TextPosition position = getPositionForOffset(_lastTapDownPosition!); RenderEditableBox child = childAtPosition(position); int nodeOffset = child.getContainer().getOffset(); TextPosition localPosition = TextPosition( @@ -759,16 +736,11 @@ class RenderEditor extends RenderEditableContainerBox @override selectPositionAt( Offset from, - Offset to, + Offset? to, SelectionChangedCause cause, ) { - assert(cause != null); - assert(from != null); - if (onSelectionChanged == null) { - return; - } TextPosition fromPosition = getPositionForOffset(from); - TextPosition toPosition = to == null ? null : getPositionForOffset(to); + TextPosition? toPosition = to == null ? null : getPositionForOffset(to); int baseOffset = fromPosition.offset; int extentOffset = fromPosition.offset; @@ -787,12 +759,12 @@ class RenderEditor extends RenderEditableContainerBox @override selectWord(SelectionChangedCause cause) { - selectWordsInRange(_lastTapDownPosition, null, cause); + selectWordsInRange(_lastTapDownPosition!, null, cause); } @override selectPosition(SelectionChangedCause cause) { - selectPositionAt(_lastTapDownPosition, null, cause); + selectPositionAt(_lastTapDownPosition!, null, cause); } @override @@ -837,7 +809,7 @@ class RenderEditor extends RenderEditableContainerBox } @override - bool hitTestChildren(BoxHitTestResult result, {Offset position}) { + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { return defaultHitTestChildren(result, position: position); } @@ -877,9 +849,9 @@ class RenderEditor extends RenderEditableContainerBox @override TextPosition getPositionForOffset(Offset offset) { Offset local = globalToLocal(offset); - RenderEditableBox child = childAtOffset(local); + RenderEditableBox child = childAtOffset(local)!; - BoxParentData parentData = child.parentData; + BoxParentData parentData = child.parentData as BoxParentData; Offset localOffset = local - parentData.offset; TextPosition localPosition = child.getPositionForOffset(localOffset); return TextPosition( @@ -888,7 +860,7 @@ class RenderEditor extends RenderEditableContainerBox ); } - double getOffsetToRevealCursor( + double? getOffsetToRevealCursor( double viewportHeight, double scrollOffset, double offsetInViewport) { List endpoints = getEndpointsForSelection(selection); TextSelectionPoint endpoint = endpoints.first; @@ -902,7 +874,7 @@ class RenderEditor extends RenderEditableContainerBox kMargin + offsetInViewport; final caretBottom = endpoint.point.dy + kMargin + offsetInViewport; - double dy; + double? dy; if (caretTop < scrollOffset) { dy = caretTop; } else if (caretBottom > scrollOffset + viewportHeight) { @@ -927,14 +899,11 @@ class RenderEditableContainerBox extends RenderBox containerNode.Container _container; TextDirection textDirection; EdgeInsetsGeometry _padding; - EdgeInsets _resolvedPadding; + EdgeInsets? _resolvedPadding; - RenderEditableContainerBox(List children, this._container, + RenderEditableContainerBox(List? children, this._container, this.textDirection, this._padding) - : assert(_container != null), - assert(textDirection != null), - assert(_padding != null), - assert(_padding.isNonNegative) { + : assert(_padding.isNonNegative) { addAll(children); } @@ -943,7 +912,6 @@ class RenderEditableContainerBox extends RenderBox } setContainer(containerNode.Container c) { - assert(c != null); if (_container == c) { return; } @@ -954,7 +922,6 @@ class RenderEditableContainerBox extends RenderBox EdgeInsetsGeometry getPadding() => _padding; setPadding(EdgeInsetsGeometry value) { - assert(value != null); assert(value.isNonNegative); if (_padding == value) { return; @@ -963,22 +930,22 @@ class RenderEditableContainerBox extends RenderBox _markNeedsPaddingResolution(); } - EdgeInsets get resolvedPadding => _resolvedPadding; + EdgeInsets? get resolvedPadding => _resolvedPadding; _resolvePadding() { if (_resolvedPadding != null) { return; } _resolvedPadding = _padding.resolve(textDirection); - _resolvedPadding = _resolvedPadding.copyWith(left: _resolvedPadding.left); + _resolvedPadding = _resolvedPadding!.copyWith(left: _resolvedPadding!.left); - assert(_resolvedPadding.isNonNegative); + assert(_resolvedPadding!.isNonNegative); } RenderEditableBox childAtPosition(TextPosition position) { assert(firstChild != null); - Node targetNode = _container.queryChild(position.offset, false).node; + Node? targetNode = _container.queryChild(position.offset, false).node; var targetChild = firstChild; while (targetChild != null) { @@ -998,19 +965,19 @@ class RenderEditableContainerBox extends RenderBox markNeedsLayout(); } - RenderEditableBox childAtOffset(Offset offset) { + RenderEditableBox? childAtOffset(Offset offset) { assert(firstChild != null); _resolvePadding(); - if (offset.dy <= _resolvedPadding.top) { + if (offset.dy <= _resolvedPadding!.top) { return firstChild; } - if (offset.dy >= size.height - _resolvedPadding.bottom) { + if (offset.dy >= size.height - _resolvedPadding!.bottom) { return lastChild; } var child = firstChild; - double dx = -offset.dx, dy = _resolvedPadding.top; + double dx = -offset.dx, dy = _resolvedPadding!.top; while (child != null) { if (child.size.contains(offset.translate(dx, -dy))) { return child; @@ -1037,20 +1004,21 @@ class RenderEditableContainerBox extends RenderBox _resolvePadding(); assert(_resolvedPadding != null); - double mainAxisExtent = _resolvedPadding.top; + double mainAxisExtent = _resolvedPadding!.top; var child = firstChild; BoxConstraints innerConstraints = BoxConstraints.tightFor(width: constraints.maxWidth) - .deflate(_resolvedPadding); + .deflate(_resolvedPadding!); while (child != null) { child.layout(innerConstraints, parentUsesSize: true); - final EditableContainerParentData childParentData = child.parentData; - childParentData.offset = Offset(_resolvedPadding.left, mainAxisExtent); + final EditableContainerParentData childParentData = + child.parentData as EditableContainerParentData; + childParentData.offset = Offset(_resolvedPadding!.left, mainAxisExtent); mainAxisExtent += child.size.height; assert(child.parentData == childParentData); child = childParentData.nextSibling; } - mainAxisExtent += _resolvedPadding.bottom; + mainAxisExtent += _resolvedPadding!.bottom; size = constraints.constrain(Size(constraints.maxWidth, mainAxisExtent)); assert(size.isFinite); @@ -1061,7 +1029,8 @@ class RenderEditableContainerBox extends RenderBox var child = firstChild; while (child != null) { extent = math.max(extent, childSize(child)); - EditableContainerParentData childParentData = child.parentData; + EditableContainerParentData childParentData = + child.parentData as EditableContainerParentData; child = childParentData.nextSibling; } return extent; @@ -1072,7 +1041,8 @@ class RenderEditableContainerBox extends RenderBox var child = firstChild; while (child != null) { extent += childSize(child); - EditableContainerParentData childParentData = child.parentData; + EditableContainerParentData childParentData = + child.parentData as EditableContainerParentData; child = childParentData.nextSibling; } return extent; @@ -1083,10 +1053,10 @@ class RenderEditableContainerBox extends RenderBox _resolvePadding(); return _getIntrinsicCrossAxis((RenderBox child) { double childHeight = math.max( - 0.0, height - _resolvedPadding.top + _resolvedPadding.bottom); + 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMinIntrinsicWidth(childHeight) + - _resolvedPadding.left + - _resolvedPadding.right; + _resolvedPadding!.left + + _resolvedPadding!.right; }); } @@ -1095,10 +1065,10 @@ class RenderEditableContainerBox extends RenderBox _resolvePadding(); return _getIntrinsicCrossAxis((RenderBox child) { double childHeight = math.max( - 0.0, height - _resolvedPadding.top + _resolvedPadding.bottom); + 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMaxIntrinsicWidth(childHeight) + - _resolvedPadding.left + - _resolvedPadding.right; + _resolvedPadding!.left + + _resolvedPadding!.right; }); } @@ -1106,11 +1076,11 @@ class RenderEditableContainerBox extends RenderBox double computeMinIntrinsicHeight(double width) { _resolvePadding(); return _getIntrinsicMainAxis((RenderBox child) { - double childWidth = - math.max(0.0, width - _resolvedPadding.left + _resolvedPadding.right); + double childWidth = math.max( + 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMinIntrinsicHeight(childWidth) + - _resolvedPadding.top + - _resolvedPadding.bottom; + _resolvedPadding!.top + + _resolvedPadding!.bottom; }); } @@ -1118,18 +1088,18 @@ class RenderEditableContainerBox extends RenderBox double computeMaxIntrinsicHeight(double width) { _resolvePadding(); return _getIntrinsicMainAxis((RenderBox child) { - final childWidth = - math.max(0.0, width - _resolvedPadding.left + _resolvedPadding.right); + final childWidth = math.max( + 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMaxIntrinsicHeight(childWidth) + - _resolvedPadding.top + - _resolvedPadding.bottom; + _resolvedPadding!.top + + _resolvedPadding!.bottom; }); } @override double computeDistanceToActualBaseline(TextBaseline baseline) { _resolvePadding(); - return defaultComputeDistanceToFirstActualBaseline(baseline) + - _resolvedPadding.top; + return defaultComputeDistanceToFirstActualBaseline(baseline)! + + _resolvedPadding!.top; } } diff --git a/lib/widgets/image.dart b/lib/widgets/image.dart index 2a6785f0..b9df48ce 100644 --- a/lib/widgets/image.dart +++ b/lib/widgets/image.dart @@ -8,7 +8,7 @@ class ImageTapWrapper extends StatelessWidget { this.imageProvider, }); - final ImageProvider imageProvider; + final ImageProvider? imageProvider; @override Widget build(BuildContext context) { diff --git a/lib/widgets/keyboard_listener.dart b/lib/widgets/keyboard_listener.dart index c0dc0c27..7311b345 100644 --- a/lib/widgets/keyboard_listener.dart +++ b/lib/widgets/keyboard_listener.dart @@ -5,7 +5,7 @@ enum InputShortcut { CUT, COPY, PASTE, SELECT_ALL } typedef CursorMoveCallback = void Function( LogicalKeyboardKey key, bool wordModifier, bool lineModifier, bool shift); -typedef InputShortcutCallback = void Function(InputShortcut shortcut); +typedef InputShortcutCallback = void Function(InputShortcut? shortcut); typedef OnDeleteCallback = void Function(bool forward); class KeyboardListener { @@ -59,10 +59,7 @@ class KeyboardListener { LogicalKeyboardKey.keyA: InputShortcut.SELECT_ALL, }; - KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete) - : assert(onCursorMove != null), - assert(onShortcut != null), - assert(onDelete != null); + KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete); bool handleRawKeyEvent(RawKeyEvent event) { if (kIsWeb) { diff --git a/lib/widgets/proxy.dart b/lib/widgets/proxy.dart index b710e8d3..9f2e0bb3 100644 --- a/lib/widgets/proxy.dart +++ b/lib/widgets/proxy.dart @@ -4,17 +4,17 @@ import 'package:flutter/widgets.dart'; import 'box.dart'; class BaselineProxy extends SingleChildRenderObjectWidget { - final TextStyle textStyle; - final EdgeInsets padding; + final TextStyle? textStyle; + final EdgeInsets? padding; - BaselineProxy({Key key, Widget child, this.textStyle, this.padding}) + BaselineProxy({Key? key, Widget? child, this.textStyle, this.padding}) : super(key: key, child: child); @override RenderBaselineProxy createRenderObject(BuildContext context) { return RenderBaselineProxy( null, - textStyle, + textStyle!, padding, ); } @@ -23,16 +23,16 @@ class BaselineProxy extends SingleChildRenderObjectWidget { void updateRenderObject( BuildContext context, covariant RenderBaselineProxy renderObject) { renderObject - ..textStyle = textStyle - ..padding = padding; + ..textStyle = textStyle! + ..padding = padding!; } } class RenderBaselineProxy extends RenderProxyBox { RenderBaselineProxy( - RenderParagraph child, + RenderParagraph? child, TextStyle textStyle, - EdgeInsets padding, + EdgeInsets? padding, ) : _prototypePainter = TextPainter( text: TextSpan(text: ' ', style: textStyle), textDirection: TextDirection.ltr, @@ -43,18 +43,16 @@ class RenderBaselineProxy extends RenderProxyBox { final TextPainter _prototypePainter; set textStyle(TextStyle value) { - assert(value != null); - if (_prototypePainter.text.style == value) { + if (_prototypePainter.text!.style == value) { return; } _prototypePainter.text = TextSpan(text: ' ', style: value); markNeedsLayout(); } - EdgeInsets _padding; + EdgeInsets? _padding; set padding(EdgeInsets value) { - assert(value != null); if (_padding == value) { return; } @@ -64,9 +62,8 @@ class RenderBaselineProxy extends RenderProxyBox { @override double computeDistanceToActualBaseline(TextBaseline baseline) => - _prototypePainter.computeDistanceToActualBaseline(baseline) + - _padding?.top ?? - 0.0; + _prototypePainter.computeDistanceToActualBaseline(baseline); + // SEE What happens + _padding?.top; @override performLayout() { @@ -84,7 +81,7 @@ class EmbedProxy extends SingleChildRenderObjectWidget { } class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { - RenderEmbedProxy(RenderBox child) : super(child); + RenderEmbedProxy(RenderBox? child) : super(child); @override List getBoxesForSelection(TextSelection selection) { @@ -105,10 +102,8 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { double getFullHeightForCaret(TextPosition position) => size.height; @override - Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) { - assert(position.offset != null && - position.offset <= 1 && - position.offset >= 0); + Offset getOffsetForCaret(TextPosition position, Rect? caretPrototype) { + assert(position.offset <= 1 && position.offset >= 0); return position.offset == 0 ? Offset.zero : Offset(size.width, 0.0); } @@ -134,7 +129,7 @@ class RichTextProxy extends SingleChildRenderObjectWidget { final Locale locale; final StrutStyle strutStyle; final TextWidthBasis textWidthBasis; - final TextHeightBehavior textHeightBehavior; + final TextHeightBehavior? textHeightBehavior; @override RenderParagraphProxy createRenderObject(BuildContext context) { @@ -160,13 +155,7 @@ class RichTextProxy extends SingleChildRenderObjectWidget { this.strutStyle, this.textWidthBasis, this.textHeightBehavior) - : assert(child != null), - assert(textStyle != null), - assert(textAlign != null), - assert(textDirection != null), - assert(locale != null), - assert(strutStyle != null), - super(child: child); + : super(child: child); @override void updateRenderObject( @@ -185,7 +174,7 @@ class RichTextProxy extends SingleChildRenderObjectWidget { class RenderParagraphProxy extends RenderProxyBox implements RenderContentProxyBox { RenderParagraphProxy( - RenderParagraph child, + RenderParagraph? child, TextStyle textStyle, TextAlign textAlign, TextDirection textDirection, @@ -193,7 +182,7 @@ class RenderParagraphProxy extends RenderProxyBox StrutStyle strutStyle, Locale locale, TextWidthBasis textWidthBasis, - TextHeightBehavior textHeightBehavior, + TextHeightBehavior? textHeightBehavior, ) : _prototypePainter = TextPainter( text: TextSpan(text: ' ', style: textStyle), textAlign: textAlign, @@ -208,8 +197,7 @@ class RenderParagraphProxy extends RenderProxyBox final TextPainter _prototypePainter; set textStyle(TextStyle value) { - assert(value != null); - if (_prototypePainter.text.style == value) { + if (_prototypePainter.text!.style == value) { return; } _prototypePainter.text = TextSpan(text: ' ', style: value); @@ -217,7 +205,6 @@ class RenderParagraphProxy extends RenderProxyBox } set textAlign(TextAlign value) { - assert(value != null); if (_prototypePainter.textAlign == value) { return; } @@ -226,7 +213,6 @@ class RenderParagraphProxy extends RenderProxyBox } set textDirection(TextDirection value) { - assert(value != null); if (_prototypePainter.textDirection == value) { return; } @@ -235,7 +221,6 @@ class RenderParagraphProxy extends RenderProxyBox } set textScaleFactor(double value) { - assert(value != null); if (_prototypePainter.textScaleFactor == value) { return; } @@ -244,7 +229,6 @@ class RenderParagraphProxy extends RenderProxyBox } set strutStyle(StrutStyle value) { - assert(value != null); if (_prototypePainter.strutStyle == value) { return; } @@ -261,7 +245,6 @@ class RenderParagraphProxy extends RenderProxyBox } set textWidthBasis(TextWidthBasis value) { - assert(value != null); if (_prototypePainter.textWidthBasis == value) { return; } @@ -269,7 +252,7 @@ class RenderParagraphProxy extends RenderProxyBox markNeedsLayout(); } - set textHeightBehavior(TextHeightBehavior value) { + set textHeightBehavior(TextHeightBehavior? value) { if (_prototypePainter.textHeightBehavior == value) { return; } @@ -278,7 +261,7 @@ class RenderParagraphProxy extends RenderProxyBox } @override - RenderParagraph get child => super.child; + RenderParagraph? get child => super.child as RenderParagraph?; @override double getPreferredLineHeight() { @@ -286,24 +269,24 @@ class RenderParagraphProxy extends RenderProxyBox } @override - Offset getOffsetForCaret(TextPosition position, Rect caretPrototype) => - child.getOffsetForCaret(position, caretPrototype); + Offset getOffsetForCaret(TextPosition position, Rect? caretPrototype) => + child!.getOffsetForCaret(position, caretPrototype!); @override TextPosition getPositionForOffset(Offset offset) => - child.getPositionForOffset(offset); + child!.getPositionForOffset(offset); @override - double getFullHeightForCaret(TextPosition position) => - child.getFullHeightForCaret(position); + double? getFullHeightForCaret(TextPosition position) => + child!.getFullHeightForCaret(position); @override TextRange getWordBoundary(TextPosition position) => - child.getWordBoundary(position); + child!.getWordBoundary(position); @override List getBoxesForSelection(TextSelection selection) => - child.getBoxesForSelection(selection); + child!.getBoxesForSelection(selection); @override performLayout() { diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index e3cb78af..24f9c397 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -36,23 +36,23 @@ class RawEditor extends StatefulWidget { final bool scrollable; final EdgeInsetsGeometry padding; final bool readOnly; - final String placeholder; - final ValueChanged onLaunchUrl; + final String? placeholder; + final ValueChanged? onLaunchUrl; final ToolbarOptions toolbarOptions; final bool showSelectionHandles; final bool showCursor; final CursorStyle cursorStyle; final TextCapitalization textCapitalization; - final double maxHeight; - final double minHeight; - final DefaultStyles customStyles; + final double? maxHeight; + final double? minHeight; + final DefaultStyles? customStyles; final bool expands; final bool autoFocus; final Color selectionColor; final TextSelectionControls selectionCtrls; final Brightness keyboardAppearance; final bool enableInteractiveSelection; - final ScrollPhysics scrollPhysics; + final ScrollPhysics? scrollPhysics; final EmbedBuilder embedBuilder; RawEditor( @@ -67,7 +67,7 @@ class RawEditor extends StatefulWidget { this.onLaunchUrl, this.toolbarOptions, this.showSelectionHandles, - bool showCursor, + bool? showCursor, this.cursorStyle, this.textCapitalization, this.maxHeight, @@ -81,26 +81,11 @@ class RawEditor extends StatefulWidget { this.enableInteractiveSelection, this.scrollPhysics, this.embedBuilder) - : assert(controller != null, 'controller cannot be null'), - assert(focusNode != null, 'focusNode cannot be null'), - assert(scrollable || scrollController != null, - 'scrollController cannot be null'), - assert(selectionColor != null, 'selectionColor cannot be null'), - assert(enableInteractiveSelection != null, - 'enableInteractiveSelection cannot be null'), - assert(showSelectionHandles != null, - 'showSelectionHandles cannot be null'), - assert(readOnly != null, 'readOnly cannot be null'), - assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'), + : assert(maxHeight == null || maxHeight > 0, 'maxHeight cannot be null'), assert(minHeight == null || minHeight >= 0, 'minHeight cannot be null'), assert(maxHeight == null || minHeight == null || maxHeight >= minHeight, 'maxHeight cannot be null'), - assert(autoFocus != null, 'autoFocus cannot be null'), - assert(toolbarOptions != null, 'toolbarOptions cannot be null'), showCursor = showCursor ?? !readOnly, - assert(embedBuilder != null, 'embedBuilder cannot be null'), - assert(expands != null, 'expands cannot be null'), - assert(padding != null), super(key: key); @override @@ -115,23 +100,23 @@ class RawEditorState extends EditorState WidgetsBindingObserver, TickerProviderStateMixin implements TextSelectionDelegate, TextInputClient { - final GlobalKey _editorKey = GlobalKey(); + GlobalKey _editorKey = GlobalKey(); final List _sentRemoteValues = []; - TextInputConnection _textInputConnection; - TextEditingValue _lastKnownRemoteTextEditingValue; + TextInputConnection? _textInputConnection; + TextEditingValue? _lastKnownRemoteTextEditingValue; int _cursorResetLocation = -1; bool _wasSelectingVerticallyWithKeyboard = false; - EditorTextSelectionOverlay _selectionOverlay; - FocusAttachment _focusAttachment; - CursorCont _cursorCont; - ScrollController _scrollController; - KeyboardVisibilityController _keyboardVisibilityController; - StreamSubscription _keyboardVisibilitySubscription; - KeyboardListener _keyboardListener; + EditorTextSelectionOverlay? _selectionOverlay; + FocusAttachment? _focusAttachment; + late CursorCont _cursorCont; + ScrollController? _scrollController; + late KeyboardVisibilityController _keyboardVisibilityController; + late StreamSubscription _keyboardVisibilitySubscription; + late KeyboardListener _keyboardListener; bool _didAutoFocus = false; bool _keyboardVisible = false; - DefaultStyles _styles; - final ClipboardStatusNotifier _clipboardStatus = + DefaultStyles? _styles; + final ClipboardStatusNotifier? _clipboardStatus = kIsWeb ? null : ClipboardStatusNotifier(); final LayerLink _toolbarLayerLink = LayerLink(); final LayerLink _startHandleLayerLink = LayerLink(); @@ -156,7 +141,6 @@ class RawEditorState extends EditorState TextDirection get _textDirection { TextDirection result = Directionality.of(context); - assert(result != null); return result; } @@ -170,7 +154,6 @@ class RawEditorState extends EditorState return; } TextSelection selection = widget.controller.selection; - assert(selection != null); TextSelection newSelection = widget.controller.selection; @@ -226,19 +209,20 @@ class RawEditorState extends EditorState TextPosition originPosition = TextPosition( offset: upKey ? selection.baseOffset : selection.extentOffset); - RenderEditableBox child = getRenderEditor().childAtPosition(originPosition); + RenderEditableBox child = + getRenderEditor()!.childAtPosition(originPosition); TextPosition localPosition = TextPosition( offset: originPosition.offset - child.getContainer().getDocumentOffset()); - TextPosition position = upKey + TextPosition? position = upKey ? child.getPositionAbove(localPosition) : child.getPositionBelow(localPosition); if (position == null) { var sibling = upKey - ? getRenderEditor().childBefore(child) - : getRenderEditor().childAfter(child); + ? getRenderEditor()!.childBefore(child) + : getRenderEditor()!.childAfter(child); if (sibling == null) { position = TextPosition(offset: upKey ? 0 : plainText.length - 1); } else { @@ -289,20 +273,20 @@ class RawEditorState extends EditorState bool shift) { if (wordModifier) { if (leftKey) { - TextSelection textSelection = getRenderEditor().selectWordAtPosition( + TextSelection textSelection = getRenderEditor()!.selectWordAtPosition( TextPosition( offset: _previousCharacter( newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.baseOffset); } - TextSelection textSelection = getRenderEditor().selectWordAtPosition( + TextSelection textSelection = getRenderEditor()!.selectWordAtPosition( TextPosition( offset: _nextCharacter(newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.extentOffset); } else if (lineModifier) { if (leftKey) { - TextSelection textSelection = getRenderEditor().selectLineAtPosition( + TextSelection textSelection = getRenderEditor()!.selectLineAtPosition( TextPosition( offset: _previousCharacter( newSelection.extentOffset, plainText, false))); @@ -310,7 +294,7 @@ class RawEditorState extends EditorState } int startPoint = newSelection.extentOffset; if (startPoint < plainText.length) { - TextSelection textSelection = getRenderEditor() + TextSelection textSelection = getRenderEditor()! .selectLineAtPosition(TextPosition(offset: startPoint)); return newSelection.copyWith(extentOffset: textSelection.extentOffset); } @@ -368,7 +352,7 @@ class RawEditorState extends EditorState } int count = 0; - int lastNonWhitespace; + int? lastNonWhitespace; for (String currentString in string.characters) { if (!includeWhitespace && !WHITE_SPACE.contains( @@ -384,7 +368,7 @@ class RawEditorState extends EditorState } bool get hasConnection => - _textInputConnection != null && _textInputConnection.attached; + _textInputConnection != null && _textInputConnection!.attached; openConnectionIfNeeded() { if (!shouldCreateInputConnection) { @@ -406,17 +390,17 @@ class RawEditorState extends EditorState ), ); - _textInputConnection.setEditingState(_lastKnownRemoteTextEditingValue); + _textInputConnection!.setEditingState(_lastKnownRemoteTextEditingValue!); // _sentRemoteValues.add(_lastKnownRemoteTextEditingValue); } - _textInputConnection.show(); + _textInputConnection!.show(); } closeConnectionIfNeeded() { if (!hasConnection) { return; } - _textInputConnection.close(); + _textInputConnection!.close(); _textInputConnection = null; _lastKnownRemoteTextEditingValue = null; _sentRemoteValues.clear(); @@ -428,7 +412,7 @@ class RawEditorState extends EditorState } TextEditingValue actualValue = textEditingValue.copyWith( - composing: _lastKnownRemoteTextEditingValue.composing, + composing: _lastKnownRemoteTextEditingValue!.composing, ); if (actualValue == _lastKnownRemoteTextEditingValue) { @@ -436,20 +420,20 @@ class RawEditorState extends EditorState } bool shouldRemember = - textEditingValue.text != _lastKnownRemoteTextEditingValue.text; + textEditingValue.text != _lastKnownRemoteTextEditingValue!.text; _lastKnownRemoteTextEditingValue = actualValue; - _textInputConnection.setEditingState(actualValue); + _textInputConnection!.setEditingState(actualValue); if (shouldRemember) { _sentRemoteValues.add(actualValue); } } @override - TextEditingValue get currentTextEditingValue => + TextEditingValue? get currentTextEditingValue => _lastKnownRemoteTextEditingValue; @override - AutofillScope get currentAutofillScope => null; + AutofillScope? get currentAutofillScope => null; @override void updateEditingValue(TextEditingValue value) { @@ -466,13 +450,14 @@ class RawEditorState extends EditorState return; } - if (_lastKnownRemoteTextEditingValue.text == value.text && - _lastKnownRemoteTextEditingValue.selection == value.selection) { + if (_lastKnownRemoteTextEditingValue!.text == value.text && + _lastKnownRemoteTextEditingValue!.selection == value.selection) { _lastKnownRemoteTextEditingValue = value; return; } - TextEditingValue effectiveLastKnownValue = _lastKnownRemoteTextEditingValue; + TextEditingValue effectiveLastKnownValue = + _lastKnownRemoteTextEditingValue!; _lastKnownRemoteTextEditingValue = value; String oldText = effectiveLastKnownValue.text; String text = value.text; @@ -516,7 +501,7 @@ class RawEditorState extends EditorState if (!hasConnection) { return; } - _textInputConnection.connectionClosedReceived(); + _textInputConnection!.connectionClosedReceived(); _textInputConnection = null; _lastKnownRemoteTextEditingValue = null; _sentRemoteValues.clear(); @@ -525,7 +510,7 @@ class RawEditorState extends EditorState @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - _focusAttachment.reparent(); + _focusAttachment!.reparent(); super.build(context); Document _doc = widget.controller.document; @@ -556,9 +541,9 @@ class RawEditorState extends EditorState if (widget.scrollable) { EdgeInsets baselinePadding = - EdgeInsets.only(top: _styles.paragraph.verticalSpacing.item1); + EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1); child = BaselineProxy( - textStyle: _styles.paragraph.style, + textStyle: _styles!.paragraph!.style, padding: baselinePadding, child: SingleChildScrollView( controller: _scrollController, @@ -575,7 +560,7 @@ class RawEditorState extends EditorState maxHeight: widget.maxHeight ?? double.infinity); return QuillStyles( - data: _styles, + data: _styles!, child: MouseRegion( cursor: SystemMouseCursors.text, child: Container( @@ -636,7 +621,7 @@ class RawEditorState extends EditorState line: node, textDirection: _textDirection, embedBuilder: widget.embedBuilder, - styles: _styles, + styles: _styles!, ); EditableTextLine editableTextLine = EditableTextLine( node, @@ -655,36 +640,36 @@ class RawEditorState extends EditorState } Tuple2 _getVerticalSpacingForLine( - Line line, DefaultStyles defaultStyles) { + Line line, DefaultStyles? defaultStyles) { Map attrs = line.style.attributes; if (attrs.containsKey(Attribute.header.key)) { - int level = attrs[Attribute.header.key].value; + int? level = attrs[Attribute.header.key]!.value; switch (level) { case 1: - return defaultStyles.h1.verticalSpacing; + return defaultStyles!.h1!.verticalSpacing; case 2: - return defaultStyles.h2.verticalSpacing; + return defaultStyles!.h2!.verticalSpacing; case 3: - return defaultStyles.h3.verticalSpacing; + return defaultStyles!.h3!.verticalSpacing; default: throw ('Invalid level $level'); } } - return defaultStyles.paragraph.verticalSpacing; + return defaultStyles!.paragraph!.verticalSpacing; } Tuple2 _getVerticalSpacingForBlock( - Block node, DefaultStyles defaultStyles) { + Block node, DefaultStyles? defaultStyles) { Map attrs = node.style.attributes; if (attrs.containsKey(Attribute.blockQuote.key)) { - return defaultStyles.quote.verticalSpacing; + return defaultStyles!.quote!.verticalSpacing; } else if (attrs.containsKey(Attribute.codeBlock.key)) { - return defaultStyles.code.verticalSpacing; + return defaultStyles!.code!.verticalSpacing; } else if (attrs.containsKey(Attribute.indent.key)) { - return defaultStyles.indent.verticalSpacing; + return defaultStyles!.indent!.verticalSpacing; } - return defaultStyles.lists.verticalSpacing; + return defaultStyles!.lists!.verticalSpacing; } @override @@ -695,17 +680,12 @@ class RawEditorState extends EditorState widget.controller.addListener(_didChangeTextEditingValue); - _scrollController = widget.scrollController ?? ScrollController(); - _scrollController.addListener(_updateSelectionOverlayForScroll); + _scrollController = widget.scrollController; + _scrollController!.addListener(_updateSelectionOverlayForScroll); _cursorCont = CursorCont( - show: ValueNotifier(widget.showCursor ?? false), - style: widget.cursorStyle ?? - CursorStyle( - color: Colors.blueAccent, - backgroundColor: Colors.grey, - width: 2.0, - ), + show: ValueNotifier(widget.showCursor), + style: widget.cursorStyle, tickerProvider: this, ); @@ -739,14 +719,14 @@ class RawEditorState extends EditorState @override didChangeDependencies() { super.didChangeDependencies(); - DefaultStyles parentStyles = QuillStyles.getStyles(context, true); + DefaultStyles? parentStyles = QuillStyles.getStyles(context, true); DefaultStyles defaultStyles = DefaultStyles.getInstance(context); _styles = (parentStyles != null) ? defaultStyles.merge(parentStyles) : defaultStyles; if (widget.customStyles != null) { - _styles = _styles.merge(widget.customStyles); + _styles = _styles!.merge(widget.customStyles!); } if (!_didAutoFocus && widget.autoFocus) { @@ -768,11 +748,10 @@ class RawEditorState extends EditorState updateRemoteValueIfNeeded(); } - if (widget.scrollController != null && - widget.scrollController != _scrollController) { - _scrollController.removeListener(_updateSelectionOverlayForScroll); + if (widget.scrollController != _scrollController) { + _scrollController!.removeListener(_updateSelectionOverlayForScroll); _scrollController = widget.scrollController; - _scrollController.addListener(_updateSelectionOverlayForScroll); + _scrollController!.addListener(_updateSelectionOverlayForScroll); } if (widget.focusNode != oldWidget.focusNode) { @@ -806,7 +785,6 @@ class RawEditorState extends EditorState handleDelete(bool forward) { TextSelection selection = widget.controller.selection; String plainText = textEditingValue.text; - assert(selection != null); int cursorPosition = selection.start; String textBefore = selection.textBefore(plainText); String textAfter = selection.textAfter(plainText); @@ -834,9 +812,8 @@ class RawEditorState extends EditorState ); } - Future handleShortcut(InputShortcut shortcut) async { + void handleShortcut(InputShortcut? shortcut) async { TextSelection selection = widget.controller.selection; - assert(selection != null); String plainText = textEditingValue.text; if (shortcut == InputShortcut.COPY) { if (!selection.isCollapsed) { @@ -865,13 +842,13 @@ class RawEditorState extends EditorState return; } if (shortcut == InputShortcut.PASTE && !widget.readOnly) { - ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); + ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); if (data != null) { widget.controller.replaceText( selection.start, selection.end - selection.start, data.text, - TextSelection.collapsed(offset: selection.start + data.text.length), + TextSelection.collapsed(offset: selection.start + data.text!.length), ); } return; @@ -891,13 +868,13 @@ class RawEditorState extends EditorState @override void dispose() { closeConnectionIfNeeded(); - _keyboardVisibilitySubscription?.cancel(); + _keyboardVisibilitySubscription.cancel(); assert(!hasConnection); _selectionOverlay?.dispose(); _selectionOverlay = null; widget.controller.removeListener(_didChangeTextEditingValue); widget.focusNode.removeListener(_handleFocusChanged); - _focusAttachment.detach(); + _focusAttachment!.detach(); _cursorCont.dispose(); _clipboardStatus?.removeListener(_onChangedClipboardStatus); _clipboardStatus?.dispose(); @@ -932,7 +909,7 @@ class RawEditorState extends EditorState _cursorCont.startCursorTimer(); } - SchedulerBinding.instance.addPostFrameCallback( + SchedulerBinding.instance!.addPostFrameCallback( (Duration _) => _updateOrDisposeSelectionOverlayIfNeeded()); if (!mounted) return; setState(() { @@ -944,33 +921,32 @@ class RawEditorState extends EditorState _updateOrDisposeSelectionOverlayIfNeeded() { if (_selectionOverlay != null) { if (_hasFocus) { - _selectionOverlay.update(textEditingValue); + _selectionOverlay!.update(textEditingValue); } else { - _selectionOverlay.dispose(); + _selectionOverlay!.dispose(); _selectionOverlay = null; } } else if (_hasFocus) { _selectionOverlay?.hide(); _selectionOverlay = null; - if (widget.selectionCtrls != null) { - _selectionOverlay = EditorTextSelectionOverlay( - textEditingValue, - false, - context, - widget, - _toolbarLayerLink, - _startHandleLayerLink, - _endHandleLayerLink, - getRenderEditor(), - widget.selectionCtrls, - this, - DragStartBehavior.start, - null, - _clipboardStatus); - _selectionOverlay.handlesVisible = _shouldShowSelectionHandles(); - _selectionOverlay.showHandles(); - } + _selectionOverlay = EditorTextSelectionOverlay( + textEditingValue, + false, + context, + widget, + _toolbarLayerLink, + _startHandleLayerLink, + _endHandleLayerLink, + getRenderEditor(), + widget.selectionCtrls, + this, + DragStartBehavior.start, + null, + _clipboardStatus!, + ); + _selectionOverlay!.handlesVisible = _shouldShowSelectionHandles(); + _selectionOverlay!.showHandles(); } } @@ -980,10 +956,10 @@ class RawEditorState extends EditorState _hasFocus, widget.controller.selection); _updateOrDisposeSelectionOverlayIfNeeded(); if (_hasFocus) { - WidgetsBinding.instance.addObserver(this); + WidgetsBinding.instance!.addObserver(this); _showCaretOnScreen(); } else { - WidgetsBinding.instance.removeObserver(this); + WidgetsBinding.instance!.removeObserver(this); } updateKeepAlive(); } @@ -1004,23 +980,22 @@ class RawEditorState extends EditorState } _showCaretOnScreenScheduled = true; - SchedulerBinding.instance.addPostFrameCallback((Duration _) { + SchedulerBinding.instance!.addPostFrameCallback((Duration _) { _showCaretOnScreenScheduled = false; - final viewport = RenderAbstractViewport.of(getRenderEditor()); - assert(viewport != null); - final editorOffset = - getRenderEditor().localToGlobal(Offset(0.0, 0.0), ancestor: viewport); - final offsetInViewport = _scrollController.offset + editorOffset.dy; + final viewport = RenderAbstractViewport.of(getRenderEditor())!; + final editorOffset = getRenderEditor()! + .localToGlobal(Offset(0.0, 0.0), ancestor: viewport); + final offsetInViewport = _scrollController!.offset + editorOffset.dy; - final offset = getRenderEditor().getOffsetToRevealCursor( - _scrollController.position.viewportDimension, - _scrollController.offset, + final offset = getRenderEditor()!.getOffsetToRevealCursor( + _scrollController!.position.viewportDimension, + _scrollController!.offset, offsetInViewport, ); if (offset != null) { - _scrollController.animateTo( + _scrollController!.animateTo( offset, duration: Duration(milliseconds: 100), curve: Curves.fastOutSlowIn, @@ -1030,12 +1005,12 @@ class RawEditorState extends EditorState } @override - RenderEditor getRenderEditor() { - return _editorKey.currentContext.findRenderObject(); + RenderEditor? getRenderEditor() { + return _editorKey.currentContext!.findRenderObject() as RenderEditor?; } @override - EditorTextSelectionOverlay getSelectionOverlay() { + EditorTextSelectionOverlay? getSelectionOverlay() { return _selectionOverlay; } @@ -1091,7 +1066,7 @@ class RawEditorState extends EditorState ); } else { final TextEditingValue value = textEditingValue; - final ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); + final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); if (data != null) { final length = textEditingValue.selection.end - textEditingValue.selection.start; @@ -1104,32 +1079,37 @@ class RawEditorState extends EditorState // move cursor to the end of pasted text selection widget.controller.updateSelection( TextSelection.collapsed( - offset: value.selection.start + data.text.length), + offset: value.selection.start + data.text!.length), ChangeSource.LOCAL); } } } Future __isItCut(TextEditingValue value) async { - final ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain); - return textEditingValue.text.length - value.text.length == data.text.length; + final ClipboardData data = await (Clipboard.getData(Clipboard.kTextPlain) + as FutureOr); + return textEditingValue.text.length - value.text.length == + data.text!.length; } @override bool showToolbar() { - // Web is using native dom elements to enable clipboard functionality of the - // toolbar: copy, paste, select, cut. It might also provide additional - // functionality depending on the browser (such as translate). Due to this - // we should not show a Flutter toolbar for the editable text elements. - if (kIsWeb) { - return false; - } + if (_selectionOverlay == null || _selectionOverlay!.toolbar != null) { + // Web is using native dom elements to enable clipboard functionality of the + // toolbar: copy, paste, select, cut. It might also provide additional + // functionality depending on the browser (such as translate). Due to this + // we should not show a Flutter toolbar for the editable text elements. + if (kIsWeb) { + return false; + } - if (_selectionOverlay == null || _selectionOverlay.toolbar != null) { - return false; - } + if (_selectionOverlay == null || _selectionOverlay!.toolbar != null) { + return false; + } - _selectionOverlay.showToolbar(); + _selectionOverlay!.showToolbar(); + return true; + } return true; } @@ -1147,15 +1127,15 @@ class RawEditorState extends EditorState class _Editor extends MultiChildRenderObjectWidget { _Editor({ - @required Key key, - @required List children, - @required this.document, - @required this.textDirection, - @required this.hasFocus, - @required this.selection, - @required this.startHandleLayerLink, - @required this.endHandleLayerLink, - @required this.onSelectionChanged, + required Key key, + required List children, + required this.document, + required this.textDirection, + required this.hasFocus, + required this.selection, + required this.startHandleLayerLink, + required this.endHandleLayerLink, + required this.onSelectionChanged, this.padding = EdgeInsets.zero, }) : super(key: key, children: children); diff --git a/lib/widgets/responsive_widget.dart b/lib/widgets/responsive_widget.dart index a047deab..806883ec 100644 --- a/lib/widgets/responsive_widget.dart +++ b/lib/widgets/responsive_widget.dart @@ -2,12 +2,12 @@ import 'package:flutter/material.dart'; class ResponsiveWidget extends StatelessWidget { final Widget largeScreen; - final Widget mediumScreen; - final Widget smallScreen; + final Widget? mediumScreen; + final Widget? smallScreen; const ResponsiveWidget( - {Key key, - @required this.largeScreen, + {Key? key, + required this.largeScreen, this.mediumScreen, this.smallScreen}) : super(key: key); diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index f0bc6487..6a12559f 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -53,10 +53,10 @@ class EditableTextBlock extends StatelessWidget { final Tuple2 verticalSpacing; final TextSelection textSelection; final Color color; - final DefaultStyles styles; + final DefaultStyles? styles; final bool enableInteractiveSelection; final bool hasFocus; - final EdgeInsets contentPadding; + final EdgeInsets? contentPadding; final EmbedBuilder embedBuilder; final CursorCont cursorCont; final Map indentLevelCounts; @@ -73,44 +73,41 @@ class EditableTextBlock extends StatelessWidget { this.contentPadding, this.embedBuilder, this.cursorCont, - this.indentLevelCounts) - : assert(hasFocus != null), - assert(embedBuilder != null), - assert(cursorCont != null); + this.indentLevelCounts); @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - DefaultStyles defaultStyles = QuillStyles.getStyles(context, false); + DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); return _EditableBlock( block, textDirection, - verticalSpacing, + verticalSpacing as Tuple2, _getDecorationForBlock(block, defaultStyles) ?? BoxDecoration(), contentPadding, _buildChildren(context, this.indentLevelCounts)); } - BoxDecoration _getDecorationForBlock( - Block node, DefaultStyles defaultStyles) { + BoxDecoration? _getDecorationForBlock( + Block node, DefaultStyles? defaultStyles) { Map attrs = block.style.attributes; if (attrs.containsKey(Attribute.blockQuote.key)) { - return defaultStyles.quote.decoration; + return defaultStyles!.quote!.decoration; } if (attrs.containsKey(Attribute.codeBlock.key)) { - return defaultStyles.code.decoration; + return defaultStyles!.code!.decoration; } return null; } List _buildChildren( BuildContext context, Map indentLevelCounts) { - DefaultStyles defaultStyles = QuillStyles.getStyles(context, false); + DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); int count = block.children.length; var children = []; int index = 0; - for (Line line in block.children) { + for (Line line in block.children as Iterable) { index++; EditableTextLine editableTextLine = EditableTextLine( line, @@ -119,7 +116,7 @@ class EditableTextBlock extends StatelessWidget { line: line, textDirection: textDirection, embedBuilder: embedBuilder, - styles: styles, + styles: styles!, ), _getIndentWidth(), _getSpacingForLine(line, index, count, defaultStyles), @@ -135,16 +132,16 @@ class EditableTextBlock extends StatelessWidget { return children.toList(growable: false); } - Widget _buildLeading(BuildContext context, Line line, int index, + Widget? _buildLeading(BuildContext context, Line line, int index, Map indentLevelCounts, int count) { - DefaultStyles defaultStyles = QuillStyles.getStyles(context, false); + DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); Map attrs = line.style.attributes; if (attrs[Attribute.list.key] == Attribute.ol) { return _NumberPoint( index: index, indentLevelCounts: indentLevelCounts, count: count, - style: defaultStyles.paragraph.style, + style: defaultStyles!.paragraph!.style, attrs: attrs, width: 32.0, padding: 8.0, @@ -153,20 +150,20 @@ class EditableTextBlock extends StatelessWidget { if (attrs[Attribute.list.key] == Attribute.ul) { return _BulletPoint( - style: - defaultStyles.paragraph.style.copyWith(fontWeight: FontWeight.bold), + style: defaultStyles!.paragraph!.style + .copyWith(fontWeight: FontWeight.bold), width: 32, ); } if (attrs[Attribute.list.key] == Attribute.checked) { return _Checkbox( - style: defaultStyles.paragraph.style, width: 32, isChecked: true); + style: defaultStyles!.paragraph!.style, width: 32, isChecked: true); } if (attrs[Attribute.list.key] == Attribute.unchecked) { return _Checkbox( - style: defaultStyles.paragraph.style, width: 32, isChecked: false); + style: defaultStyles!.paragraph!.style, width: 32, isChecked: false); } if (attrs.containsKey(Attribute.codeBlock.key)) { @@ -174,8 +171,8 @@ class EditableTextBlock extends StatelessWidget { index: index, indentLevelCounts: indentLevelCounts, count: count, - style: defaultStyles.code.style - .copyWith(color: defaultStyles.code.style.color.withOpacity(0.4)), + style: defaultStyles!.code!.style + .copyWith(color: defaultStyles.code!.style.color!.withOpacity(0.4)), width: 32.0, attrs: attrs, padding: 16.0, @@ -188,7 +185,7 @@ class EditableTextBlock extends StatelessWidget { double _getIndentWidth() { Map attrs = block.style.attributes; - Attribute indent = attrs[Attribute.indent.key]; + Attribute? indent = attrs[Attribute.indent.key]; double extraIndent = 0.0; if (indent != null && indent.value != null) { extraIndent = 16.0 * indent.value; @@ -202,40 +199,40 @@ class EditableTextBlock extends StatelessWidget { } Tuple2 _getSpacingForLine( - Line node, int index, int count, DefaultStyles defaultStyles) { + Line node, int index, int count, DefaultStyles? defaultStyles) { double top = 0.0, bottom = 0.0; Map attrs = block.style.attributes; if (attrs.containsKey(Attribute.header.key)) { - int level = attrs[Attribute.header.key].value; + int? level = attrs[Attribute.header.key]!.value; switch (level) { case 1: - top = defaultStyles.h1.verticalSpacing.item1; - bottom = defaultStyles.h1.verticalSpacing.item2; + top = defaultStyles!.h1!.verticalSpacing.item1; + bottom = defaultStyles.h1!.verticalSpacing.item2; break; case 2: - top = defaultStyles.h2.verticalSpacing.item1; - bottom = defaultStyles.h2.verticalSpacing.item2; + top = defaultStyles!.h2!.verticalSpacing.item1; + bottom = defaultStyles.h2!.verticalSpacing.item2; break; case 3: - top = defaultStyles.h3.verticalSpacing.item1; - bottom = defaultStyles.h3.verticalSpacing.item2; + top = defaultStyles!.h3!.verticalSpacing.item1; + bottom = defaultStyles.h3!.verticalSpacing.item2; break; default: throw ('Invalid level $level'); } } else { - Tuple2 lineSpacing; + late Tuple2 lineSpacing; if (attrs.containsKey(Attribute.blockQuote.key)) { - lineSpacing = defaultStyles.quote.lineSpacing; + lineSpacing = defaultStyles!.quote!.lineSpacing; } else if (attrs.containsKey(Attribute.indent.key)) { - lineSpacing = defaultStyles.indent.lineSpacing; + lineSpacing = defaultStyles!.indent!.lineSpacing; } else if (attrs.containsKey(Attribute.list.key)) { - lineSpacing = defaultStyles.lists.lineSpacing; + lineSpacing = defaultStyles!.lists!.lineSpacing; } else if (attrs.containsKey(Attribute.codeBlock.key)) { - lineSpacing = defaultStyles.code.lineSpacing; + lineSpacing = defaultStyles!.code!.lineSpacing; } else if (attrs.containsKey(Attribute.align.key)) { - lineSpacing = defaultStyles.align.lineSpacing; + lineSpacing = defaultStyles!.align!.lineSpacing; } top = lineSpacing.item1; bottom = lineSpacing.item2; @@ -256,19 +253,14 @@ class EditableTextBlock extends StatelessWidget { class RenderEditableTextBlock extends RenderEditableContainerBox implements RenderEditableBox { RenderEditableTextBlock({ - List children, - @required Block block, - @required TextDirection textDirection, - @required EdgeInsetsGeometry padding, - @required Decoration decoration, + List? children, + required Block block, + required TextDirection textDirection, + required EdgeInsetsGeometry padding, + required Decoration decoration, ImageConfiguration configuration = ImageConfiguration.empty, EdgeInsets contentPadding = EdgeInsets.zero, - }) : assert(block != null), - assert(textDirection != null), - assert(decoration != null), - assert(padding != null), - assert(contentPadding != null), - _decoration = decoration, + }) : _decoration = decoration, _configuration = configuration, _savedPadding = padding, _contentPadding = contentPadding, @@ -283,7 +275,6 @@ class RenderEditableTextBlock extends RenderEditableContainerBox EdgeInsets _contentPadding; set contentPadding(EdgeInsets value) { - assert(value != null); if (_contentPadding == value) return; _contentPadding = value; super.setPadding(_savedPadding.add(_contentPadding)); @@ -295,13 +286,12 @@ class RenderEditableTextBlock extends RenderEditableContainerBox _savedPadding = value; } - BoxPainter _painter; + BoxPainter? _painter; Decoration get decoration => _decoration; Decoration _decoration; set decoration(Decoration value) { - assert(value != null); if (value == _decoration) return; _painter?.dispose(); _painter = null; @@ -313,7 +303,6 @@ class RenderEditableTextBlock extends RenderEditableContainerBox ImageConfiguration _configuration; set configuration(ImageConfiguration value) { - assert(value != null); if (value == _configuration) return; _configuration = value; markNeedsPaint(); @@ -344,8 +333,8 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override TextPosition getPositionForOffset(Offset offset) { - RenderEditableBox child = childAtOffset(offset); - BoxParentData parentData = child.parentData; + RenderEditableBox child = childAtOffset(offset)!; + BoxParentData parentData = child.parentData as BoxParentData; TextPosition localPosition = child.getPositionForOffset(offset - parentData.offset); return TextPosition( @@ -367,19 +356,19 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } @override - TextPosition getPositionAbove(TextPosition position) { + TextPosition? getPositionAbove(TextPosition position) { assert(position.offset < getContainer().length); RenderEditableBox child = childAtPosition(position); TextPosition childLocalPosition = TextPosition( offset: position.offset - child.getContainer().getOffset()); - TextPosition result = child.getPositionAbove(childLocalPosition); + TextPosition? result = child.getPositionAbove(childLocalPosition); if (result != null) { return TextPosition( offset: result.offset + child.getContainer().getOffset()); } - RenderEditableBox sibling = childBefore(child); + RenderEditableBox? sibling = childBefore(child); if (sibling == null) { return null; } @@ -395,19 +384,19 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } @override - TextPosition getPositionBelow(TextPosition position) { + TextPosition? getPositionBelow(TextPosition position) { assert(position.offset < getContainer().length); RenderEditableBox child = childAtPosition(position); TextPosition childLocalPosition = TextPosition( offset: position.offset - child.getContainer().getOffset()); - TextPosition result = child.getPositionBelow(childLocalPosition); + TextPosition? result = child.getPositionBelow(childLocalPosition); if (result != null) { return TextPosition( offset: result.offset + child.getContainer().getOffset()); } - RenderEditableBox sibling = childAfter(child); + RenderEditableBox? sibling = childAfter(child); if (sibling == null) { return null; } @@ -436,7 +425,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox null); } - Node baseNode = getContainer().queryChild(selection.start, false).node; + Node? baseNode = getContainer().queryChild(selection.start, false).node; var baseChild = firstChild; while (baseChild != null) { if (baseChild.getContainer() == baseNode) { @@ -446,7 +435,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } assert(baseChild != null); - TextSelectionPoint basePoint = baseChild.getBaseEndpointForSelection( + TextSelectionPoint basePoint = baseChild!.getBaseEndpointForSelection( localSelection(baseChild.getContainer(), selection, true)); return TextSelectionPoint( basePoint.point + (baseChild.parentData as BoxParentData).offset, @@ -462,7 +451,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox null); } - Node extentNode = getContainer().queryChild(selection.end, false).node; + Node? extentNode = getContainer().queryChild(selection.end, false).node; var extentChild = firstChild; while (extentChild != null) { @@ -473,7 +462,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } assert(extentChild != null); - TextSelectionPoint extentPoint = extentChild.getExtentEndpointForSelection( + TextSelectionPoint extentPoint = extentChild!.getExtentEndpointForSelection( localSelection(extentChild.getContainer(), selection, true)); return TextSelectionPoint( extentPoint.point + (extentChild.parentData as BoxParentData).offset, @@ -495,11 +484,9 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } _paintDecoration(PaintingContext context, Offset offset) { - assert(size.width != null); - assert(size.height != null); _painter ??= _decoration.createBoxPainter(markNeedsPaint); - EdgeInsets decorationPadding = resolvedPadding - _contentPadding; + EdgeInsets decorationPadding = resolvedPadding! - _contentPadding; ImageConfiguration filledConfiguration = configuration.copyWith(size: decorationPadding.deflateSize(size)); @@ -507,7 +494,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox final decorationOffset = offset.translate(decorationPadding.left, decorationPadding.top); - _painter.paint(context.canvas, decorationOffset, filledConfiguration); + _painter!.paint(context.canvas, decorationOffset, filledConfiguration); if (debugSaveCount != context.canvas.getSaveCount()) { throw ('${_decoration.runtimeType} painter had mismatching save and restore calls.'); } @@ -517,7 +504,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } @override - bool hitTestChildren(BoxHitTestResult result, {Offset position}) { + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { return defaultHitTestChildren(result, position: position); } } @@ -527,16 +514,11 @@ class _EditableBlock extends MultiChildRenderObjectWidget { final TextDirection textDirection; final Tuple2 padding; final Decoration decoration; - final EdgeInsets contentPadding; + final EdgeInsets? contentPadding; _EditableBlock(this.block, this.textDirection, this.padding, this.decoration, this.contentPadding, List children) - : assert(block != null), - assert(textDirection != null), - assert(padding != null), - assert(decoration != null), - assert(children != null), - super(children: children); + : super(children: children); EdgeInsets get _padding => EdgeInsets.only(top: padding.item1, bottom: padding.item2); @@ -567,7 +549,7 @@ class _EditableBlock extends MultiChildRenderObjectWidget { class _NumberPoint extends StatelessWidget { final int index; - final Map indentLevelCounts; + final Map indentLevelCounts; final int count; final TextStyle style; final double width; @@ -576,13 +558,13 @@ class _NumberPoint extends StatelessWidget { final double padding; const _NumberPoint({ - Key key, - @required this.index, - @required this.indentLevelCounts, - @required this.count, - @required this.style, - @required this.width, - @required this.attrs, + Key? key, + required this.index, + required this.indentLevelCounts, + required this.count, + required this.style, + required this.width, + required this.attrs, this.withDot = true, this.padding = 0.0, }) : super(key: key); @@ -590,7 +572,7 @@ class _NumberPoint extends StatelessWidget { @override Widget build(BuildContext context) { String s = this.index.toString(); - int level = 0; + int? level = 0; if (!this.attrs.containsKey(Attribute.indent.key) && !this.indentLevelCounts.containsKey(1)) { this.indentLevelCounts.clear(); @@ -602,13 +584,13 @@ class _NumberPoint extends StatelessWidget { ); } if (this.attrs.containsKey(Attribute.indent.key)) { - level = this.attrs[Attribute.indent.key].value; + level = this.attrs[Attribute.indent.key]!.value; } else { // first level but is back from previous indent level // supposed to be "2." this.indentLevelCounts[0] = 1; } - if (this.indentLevelCounts.containsKey(level + 1)) { + if (this.indentLevelCounts.containsKey(level! + 1)) { // last visited level is done, going up this.indentLevelCounts.remove(level + 1); } @@ -674,9 +656,9 @@ class _BulletPoint extends StatelessWidget { final double width; const _BulletPoint({ - Key key, - @required this.style, - @required this.width, + Key? key, + required this.style, + required this.width, }) : super(key: key); @override @@ -691,23 +673,23 @@ class _BulletPoint extends StatelessWidget { } class _Checkbox extends StatefulWidget { - final TextStyle style; - final double width; - final bool isChecked; + final TextStyle? style; + final double? width; + final bool? isChecked; - const _Checkbox({Key key, this.style, this.width, this.isChecked}) + const _Checkbox({Key? key, this.style, this.width, this.isChecked}) : super(key: key); @override __CheckboxState createState() => __CheckboxState(); } class __CheckboxState extends State<_Checkbox> { - bool isChecked; + bool? isChecked; - void _onCheckboxClicked(bool newValue) => setState(() { + void _onCheckboxClicked(bool? newValue) => setState(() { isChecked = newValue; - if (isChecked) { + if (isChecked!) { // check list } else { // uncheck list diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index a9260e8f..8eb7207e 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -23,16 +23,17 @@ import 'delegate.dart'; class TextLine extends StatelessWidget { final Line line; - final TextDirection textDirection; + final TextDirection? textDirection; final EmbedBuilder embedBuilder; final DefaultStyles styles; const TextLine( - {Key key, this.line, this.textDirection, this.embedBuilder, this.styles}) - : assert(line != null), - assert(embedBuilder != null), - assert(styles != null), - super(key: key); + {Key? key, + required this.line, + this.textDirection, + required this.embedBuilder, + required this.styles}) + : super(key: key); @override Widget build(BuildContext context) { @@ -45,7 +46,7 @@ class TextLine extends StatelessWidget { TextSpan textSpan = _buildTextSpan(context); StrutStyle strutStyle = - StrutStyle.fromTextStyle(textSpan.style, forceStrutHeight: true); + StrutStyle.fromTextStyle(textSpan.style!, forceStrutHeight: true); final textAlign = _getTextAlign(); RichText child = RichText( text: TextSpan(children: [textSpan]), @@ -56,9 +57,9 @@ class TextLine extends StatelessWidget { ); return RichTextProxy( child, - textSpan.style, + textSpan.style!, textAlign, - textDirection, + textDirection!, 1.0, Localizations.localeOf(context), strutStyle, @@ -89,27 +90,27 @@ class TextLine extends StatelessWidget { TextStyle textStyle = TextStyle(); if (line.style.containsKey(Attribute.placeholder.key)) { - textStyle = defaultStyles.placeHolder.style; + textStyle = defaultStyles.placeHolder!.style; return TextSpan(children: children, style: textStyle); } - Attribute header = line.style.attributes[Attribute.header.key]; + Attribute? header = line.style.attributes[Attribute.header.key]; Map m = { - Attribute.h1: defaultStyles.h1.style, - Attribute.h2: defaultStyles.h2.style, - Attribute.h3: defaultStyles.h3.style, + Attribute.h1: defaultStyles.h1!.style, + Attribute.h2: defaultStyles.h2!.style, + Attribute.h3: defaultStyles.h3!.style, }; - textStyle = textStyle.merge(m[header] ?? defaultStyles.paragraph.style); + textStyle = textStyle.merge(m[header!] ?? defaultStyles.paragraph!.style); - Attribute block = line.style.getBlockExceptHeader(); - TextStyle toMerge; + Attribute? block = line.style.getBlockExceptHeader(); + TextStyle? toMerge; if (block == Attribute.blockQuote) { - toMerge = defaultStyles.quote.style; + toMerge = defaultStyles.quote!.style; } else if (block == Attribute.codeBlock) { - toMerge = defaultStyles.code.style; + toMerge = defaultStyles.code!.style; } else if (block != null) { - toMerge = defaultStyles.lists.style; + toMerge = defaultStyles.lists!.style; } textStyle = textStyle.merge(toMerge); @@ -122,7 +123,7 @@ class TextLine extends StatelessWidget { Style style = textNode.style; TextStyle res = TextStyle(); - Map m = { + Map m = { Attribute.bold.key: defaultStyles.bold, Attribute.italic.key: defaultStyles.italic, Attribute.link.key: defaultStyles.link, @@ -131,16 +132,16 @@ class TextLine extends StatelessWidget { }; m.forEach((k, s) { if (style.values.any((v) => v.key == k)) { - res = _merge(res, s); + res = _merge(res, s!); } }); - Attribute font = textNode.style.attributes[Attribute.font.key]; + Attribute? font = textNode.style.attributes[Attribute.font.key]; if (font != null && font.value != null) { res = res.merge(TextStyle(fontFamily: font.value)); } - Attribute size = textNode.style.attributes[Attribute.size.key]; + Attribute? size = textNode.style.attributes[Attribute.size.key]; if (size != null && size.value != null) { switch (size.value) { case 'small': @@ -153,7 +154,7 @@ class TextLine extends StatelessWidget { res = res.merge(defaultStyles.sizeHuge); break; default: - double fontSize = double.tryParse(size.value); + double? fontSize = double.tryParse(size.value); if (fontSize != null) { res = res.merge(TextStyle(fontSize: fontSize)); } else { @@ -162,13 +163,13 @@ class TextLine extends StatelessWidget { } } - Attribute color = textNode.style.attributes[Attribute.color.key]; + Attribute? color = textNode.style.attributes[Attribute.color.key]; if (color != null && color.value != null) { final textColor = stringToColor(color.value); res = res.merge(new TextStyle(color: textColor)); } - Attribute background = textNode.style.attributes[Attribute.background.key]; + Attribute? background = textNode.style.attributes[Attribute.background.key]; if (background != null && background.value != null) { final backgroundColor = stringToColor(background.value); res = res.merge(new TextStyle(backgroundColor: backgroundColor)); @@ -178,20 +179,22 @@ class TextLine extends StatelessWidget { } TextStyle _merge(TextStyle a, TextStyle b) { - final decorations = []; + final decorations = []; if (a.decoration != null) { decorations.add(a.decoration); } if (b.decoration != null) { decorations.add(b.decoration); } - return a.merge(b).apply(decoration: TextDecoration.combine(decorations)); + return a.merge(b).apply( + decoration: + TextDecoration.combine(decorations as List)); } } class EditableTextLine extends RenderObjectWidget { final Line line; - final Widget leading; + final Widget? leading; final Widget body; final double indentWidth; final Tuple2 verticalSpacing; @@ -215,14 +218,7 @@ class EditableTextLine extends RenderObjectWidget { this.enableInteractiveSelection, this.hasFocus, this.devicePixelRatio, - this.cursorCont) - : assert(line != null), - assert(indentWidth != null), - assert(textSelection != null), - assert(color != null), - assert(enableInteractiveSelection != null), - assert(hasFocus != null), - assert(cursorCont != null); + this.cursorCont); @override RenderObjectElement createElement() { @@ -268,8 +264,8 @@ class EditableTextLine extends RenderObjectWidget { enum TextLineSlot { LEADING, BODY } class RenderEditableTextLine extends RenderEditableBox { - RenderBox _leading; - RenderContentProxyBox _body; + RenderBox? _leading; + RenderContentProxyBox? _body; Line line; TextDirection textDirection; TextSelection textSelection; @@ -279,10 +275,10 @@ class RenderEditableTextLine extends RenderEditableBox { double devicePixelRatio; EdgeInsetsGeometry padding; CursorCont cursorCont; - EdgeInsets _resolvedPadding; - bool _containsCursor; - List _selectedRects; - Rect _caretPrototype; + EdgeInsets? _resolvedPadding; + bool? _containsCursor; + List? _selectedRects; + Rect? _caretPrototype; final Map children = {}; RenderEditableTextLine( @@ -294,26 +290,18 @@ class RenderEditableTextLine extends RenderEditableBox { this.devicePixelRatio, this.padding, this.color, - this.cursorCont) - : assert(line != null), - assert(padding != null), - assert(padding.isNonNegative), - assert(devicePixelRatio != null), - assert(hasFocus != null), - assert(color != null), - assert(cursorCont != null); + this.cursorCont); Iterable get _children sync* { if (_leading != null) { - yield _leading; + yield _leading!; } if (_body != null) { - yield _body; + yield _body!; } } setCursorCont(CursorCont c) { - assert(c != null); if (cursorCont == c) { return; } @@ -383,7 +371,6 @@ class RenderEditableTextLine extends RenderEditableBox { } setLine(Line l) { - assert(l != null); if (line == l) { return; } @@ -393,7 +380,6 @@ class RenderEditableTextLine extends RenderEditableBox { } setPadding(EdgeInsetsGeometry p) { - assert(p != null); assert(p.isNonNegative); if (padding == p) { return; @@ -403,12 +389,12 @@ class RenderEditableTextLine extends RenderEditableBox { markNeedsLayout(); } - setLeading(RenderBox l) { + setLeading(RenderBox? l) { _leading = _updateChild(_leading, l, TextLineSlot.LEADING); } - setBody(RenderContentProxyBox b) { - _body = _updateChild(_body, b, TextLineSlot.BODY); + setBody(RenderContentProxyBox? b) { + _body = _updateChild(_body, b, TextLineSlot.BODY) as RenderContentProxyBox?; } bool containsTextSelection() { @@ -421,7 +407,8 @@ class RenderEditableTextLine extends RenderEditableBox { line.containsOffset(textSelection.baseOffset); } - RenderBox _updateChild(RenderBox old, RenderBox newChild, TextLineSlot slot) { + RenderBox? _updateChild( + RenderBox? old, RenderBox? newChild, TextLineSlot slot) { if (old != null) { dropChild(old); children.remove(slot); @@ -434,10 +421,10 @@ class RenderEditableTextLine extends RenderEditableBox { } List _getBoxes(TextSelection textSelection) { - BoxParentData parentData = _body.parentData as BoxParentData; - return _body.getBoxesForSelection(textSelection).map((box) { + BoxParentData? parentData = _body!.parentData as BoxParentData?; + return _body!.getBoxesForSelection(textSelection).map((box) { return TextBox.fromLTRBD( - box.left + parentData.offset.dx, + box.left + parentData!.offset.dx, box.top + parentData.offset.dy, box.right + parentData.offset.dx, box.bottom + parentData.offset.dy, @@ -451,7 +438,7 @@ class RenderEditableTextLine extends RenderEditableBox { return; } _resolvedPadding = padding.resolve(textDirection); - assert(_resolvedPadding.isNonNegative); + assert(_resolvedPadding!.isNonNegative); } @override @@ -498,26 +485,26 @@ class RenderEditableTextLine extends RenderEditableBox { @override Offset getOffsetForCaret(TextPosition position) { - return _body.getOffsetForCaret(position, _caretPrototype) + - (_body.parentData as BoxParentData).offset; + return _body!.getOffsetForCaret(position, _caretPrototype) + + (_body!.parentData as BoxParentData).offset; } @override - TextPosition getPositionAbove(TextPosition position) { + TextPosition? getPositionAbove(TextPosition position) { return _getPosition(position, -0.5); } @override - TextPosition getPositionBelow(TextPosition position) { + TextPosition? getPositionBelow(TextPosition position) { return _getPosition(position, 1.5); } - TextPosition _getPosition(TextPosition textPosition, double dyScale) { + TextPosition? _getPosition(TextPosition textPosition, double dyScale) { assert(textPosition.offset < line.length); Offset offset = getOffsetForCaret(textPosition) .translate(0, dyScale * preferredLineHeight(textPosition)); - if (_body.size - .contains(offset - (_body.parentData as BoxParentData).offset)) { + if (_body!.size + .contains(offset - (_body!.parentData as BoxParentData).offset)) { return getPositionForOffset(offset); } return null; @@ -525,18 +512,18 @@ class RenderEditableTextLine extends RenderEditableBox { @override TextPosition getPositionForOffset(Offset offset) { - return _body.getPositionForOffset( - offset - (_body.parentData as BoxParentData).offset); + return _body!.getPositionForOffset( + offset - (_body!.parentData as BoxParentData).offset); } @override TextRange getWordBoundary(TextPosition position) { - return _body.getWordBoundary(position); + return _body!.getWordBoundary(position); } @override double preferredLineHeight(TextPosition position) { - return _body.getPreferredLineHeight(); + return _body!.getPreferredLineHeight(); } @override @@ -550,7 +537,6 @@ class RenderEditableTextLine extends RenderEditableBox { cursorCont.style.height ?? preferredLineHeight(TextPosition(offset: 0)); _computeCaretPrototype() { - assert(defaultTargetPlatform != null); switch (defaultTargetPlatform) { case TargetPlatform.iOS: case TargetPlatform.macOS: @@ -606,7 +592,7 @@ class RenderEditableTextLine extends RenderEditableBox { @override List debugDescribeChildren() { var value = []; - void add(RenderBox child, String name) { + void add(RenderBox? child, String name) { if (child != null) { value.add(child.toDiagnosticsNode(name: name)); } @@ -623,38 +609,40 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeMinIntrinsicWidth(double height) { _resolvePadding(); - double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; - double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; + double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; int leadingWidth = _leading == null ? 0 - : _leading.getMinIntrinsicWidth(height - verticalPadding); + : _leading!.getMinIntrinsicWidth(height - verticalPadding) as int; int bodyWidth = _body == null ? 0 - : _body.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding)); + : _body!.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding)) + as int; return horizontalPadding + leadingWidth + bodyWidth; } @override double computeMaxIntrinsicWidth(double height) { _resolvePadding(); - double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; - double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; + double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; int leadingWidth = _leading == null ? 0 - : _leading.getMaxIntrinsicWidth(height - verticalPadding); + : _leading!.getMaxIntrinsicWidth(height - verticalPadding) as int; int bodyWidth = _body == null ? 0 - : _body.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding)); + : _body!.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding)) + as int; return horizontalPadding + leadingWidth + bodyWidth; } @override double computeMinIntrinsicHeight(double width) { _resolvePadding(); - double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; - double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; + double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; if (_body != null) { - return _body + return _body! .getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + verticalPadding; } @@ -664,10 +652,10 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeMaxIntrinsicHeight(double width) { _resolvePadding(); - double horizontalPadding = _resolvedPadding.left + _resolvedPadding.right; - double verticalPadding = _resolvedPadding.top + _resolvedPadding.bottom; + double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; if (_body != null) { - return _body + return _body! .getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + verticalPadding; } @@ -677,7 +665,8 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeDistanceToActualBaseline(TextBaseline baseline) { _resolvePadding(); - return _body.getDistanceToActualBaseline(baseline) + _resolvedPadding.top; + return _body!.getDistanceToActualBaseline(baseline)! + + _resolvedPadding!.top; } @override @@ -690,34 +679,35 @@ class RenderEditableTextLine extends RenderEditableBox { if (_body == null && _leading == null) { size = constraints.constrain(Size( - _resolvedPadding.left + _resolvedPadding.right, - _resolvedPadding.top + _resolvedPadding.bottom, + _resolvedPadding!.left + _resolvedPadding!.right, + _resolvedPadding!.top + _resolvedPadding!.bottom, )); return; } - final innerConstraints = constraints.deflate(_resolvedPadding); + final innerConstraints = constraints.deflate(_resolvedPadding!); final indentWidth = textDirection == TextDirection.ltr - ? _resolvedPadding.left - : _resolvedPadding.right; + ? _resolvedPadding!.left + : _resolvedPadding!.right; - _body.layout(innerConstraints, parentUsesSize: true); - final bodyParentData = _body.parentData as BoxParentData; - bodyParentData.offset = Offset(_resolvedPadding.left, _resolvedPadding.top); + _body!.layout(innerConstraints, parentUsesSize: true); + final bodyParentData = _body!.parentData as BoxParentData; + bodyParentData.offset = + Offset(_resolvedPadding!.left, _resolvedPadding!.top); if (_leading != null) { final leadingConstraints = innerConstraints.copyWith( minWidth: indentWidth, maxWidth: indentWidth, - maxHeight: _body.size.height); - _leading.layout(leadingConstraints, parentUsesSize: true); - final parentData = _leading.parentData as BoxParentData; - parentData.offset = Offset(0.0, _resolvedPadding.top); + maxHeight: _body!.size.height); + _leading!.layout(leadingConstraints, parentUsesSize: true); + final parentData = _leading!.parentData as BoxParentData; + parentData.offset = Offset(0.0, _resolvedPadding!.top); } size = constraints.constrain(Size( - _resolvedPadding.left + _body.size.width + _resolvedPadding.right, - _resolvedPadding.top + _body.size.height + _resolvedPadding.bottom, + _resolvedPadding!.left + _body!.size.width + _resolvedPadding!.right, + _resolvedPadding!.top + _body!.size.height + _resolvedPadding!.bottom, )); _computeCaretPrototype(); @@ -734,19 +724,19 @@ class RenderEditableTextLine extends RenderEditableBox { @override paint(PaintingContext context, Offset offset) { if (_leading != null) { - final parentData = _leading.parentData as BoxParentData; + final parentData = _leading!.parentData as BoxParentData; final effectiveOffset = offset + parentData.offset; - context.paintChild(_leading, effectiveOffset); + context.paintChild(_leading!, effectiveOffset); } if (_body != null) { - final parentData = _body.parentData as BoxParentData; + final parentData = _body!.parentData as BoxParentData; final effectiveOffset = offset + parentData.offset; - if ((enableInteractiveSelection ?? true) && + if ((enableInteractiveSelection) && line.getDocumentOffset() <= textSelection.end && textSelection.start <= line.getDocumentOffset() + line.length - 1) { final local = localSelection(line, textSelection, false); - _selectedRects ??= _body.getBoxesForSelection( + _selectedRects ??= _body!.getBoxesForSelection( local, ); _paintSelection(context, effectiveOffset); @@ -759,7 +749,7 @@ class RenderEditableTextLine extends RenderEditableBox { _paintCursor(context, effectiveOffset); } - context.paintChild(_body, effectiveOffset); + context.paintChild(_body!, effectiveOffset); if (hasFocus && cursorCont.show.value && @@ -773,7 +763,7 @@ class RenderEditableTextLine extends RenderEditableBox { _paintSelection(PaintingContext context, Offset effectiveOffset) { assert(_selectedRects != null); final paint = Paint()..color = color; - for (final box in _selectedRects) { + for (final box in _selectedRects!) { context.canvas.drawRect(box.toRect().shift(effectiveOffset), paint); } } @@ -787,7 +777,7 @@ class RenderEditableTextLine extends RenderEditableBox { } @override - bool hitTestChildren(BoxHitTestResult result, {Offset position}) { + bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { return this._children.first.hitTest(result, position: position); } } @@ -819,7 +809,7 @@ class _TextLineElement extends RenderObjectElement { } @override - mount(Element parent, dynamic newSlot) { + mount(Element? parent, dynamic newSlot) { super.mount(parent, newSlot); _mountChild(widget.leading, TextLineSlot.LEADING); _mountChild(widget.body, TextLineSlot.BODY); @@ -834,16 +824,16 @@ class _TextLineElement extends RenderObjectElement { } @override - insertRenderObjectChild(RenderObject child, TextLineSlot slot) { + insertRenderObjectChild(RenderObject child, TextLineSlot? slot) { assert(child is RenderBox); _updateRenderObject(child, slot); assert(renderObject.children.keys.contains(slot)); } @override - removeRenderObjectChild(RenderObject child, TextLineSlot slot) { + removeRenderObjectChild(RenderObject child, TextLineSlot? slot) { assert(child is RenderBox); - assert(renderObject.children[slot] == child); + assert(renderObject.children[slot!] == child); _updateRenderObject(null, slot); assert(!renderObject.children.keys.contains(slot)); } @@ -853,9 +843,9 @@ class _TextLineElement extends RenderObjectElement { throw UnimplementedError(); } - _mountChild(Widget widget, TextLineSlot slot) { - Element oldChild = _slotToChildren[slot]; - Element newChild = updateChild(oldChild, widget, slot); + _mountChild(Widget? widget, TextLineSlot slot) { + Element? oldChild = _slotToChildren[slot]; + Element? newChild = updateChild(oldChild, widget, slot); if (oldChild != null) { _slotToChildren.remove(slot); } @@ -864,22 +854,22 @@ class _TextLineElement extends RenderObjectElement { } } - _updateRenderObject(RenderObject child, TextLineSlot slot) { + _updateRenderObject(RenderObject? child, TextLineSlot? slot) { switch (slot) { case TextLineSlot.LEADING: - renderObject.setLeading(child as RenderBox); + renderObject.setLeading(child as RenderBox?); break; case TextLineSlot.BODY: - renderObject.setBody(child as RenderBox); + renderObject.setBody((child as RenderBox?) as RenderContentProxyBox?); break; default: throw UnimplementedError(); } } - _updateChild(Widget widget, TextLineSlot slot) { - Element oldChild = _slotToChildren[slot]; - Element newChild = updateChild(oldChild, widget, slot); + _updateChild(Widget? widget, TextLineSlot slot) { + Element? oldChild = _slotToChildren[slot]; + Element? newChild = updateChild(oldChild, widget, slot); if (oldChild != null) { _slotToChildren.remove(slot); } diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index 0790cbd0..22b687b2 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -31,15 +31,15 @@ class EditorTextSelectionOverlay { final LayerLink toolbarLayerLink; final LayerLink startHandleLayerLink; final LayerLink endHandleLayerLink; - final RenderEditor renderObject; + final RenderEditor? renderObject; final TextSelectionControls selectionCtrls; final TextSelectionDelegate selectionDelegate; final DragStartBehavior dragStartBehavior; - final VoidCallback onSelectionHandleTapped; + final VoidCallback? onSelectionHandleTapped; final ClipboardStatusNotifier clipboardStatus; - AnimationController _toolbarController; - List _handles; - OverlayEntry toolbar; + late AnimationController _toolbarController; + List? _handles; + OverlayEntry? toolbar; EditorTextSelectionOverlay( this.value, @@ -54,14 +54,9 @@ class EditorTextSelectionOverlay { this.selectionDelegate, this.dragStartBehavior, this.onSelectionHandleTapped, - this.clipboardStatus) - : assert(value != null), - assert(context != null), - assert(handlesVisible != null) { - OverlayState overlay = Overlay.of(context, rootOverlay: true); - assert( - overlay != null, - ); + this.clipboardStatus) { + OverlayState overlay = Overlay.of(context, rootOverlay: true)!; + _toolbarController = AnimationController( duration: Duration(milliseconds: 150), vsync: overlay); } @@ -71,14 +66,13 @@ class EditorTextSelectionOverlay { Animation get _toolbarOpacity => _toolbarController.view; setHandlesVisible(bool visible) { - assert(visible != null); if (handlesVisible == visible) { return; } handlesVisible = visible; - if (SchedulerBinding.instance.schedulerPhase == + if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.persistentCallbacks) { - SchedulerBinding.instance.addPostFrameCallback(markNeedsBuild); + SchedulerBinding.instance!.addPostFrameCallback(markNeedsBuild); } else { markNeedsBuild(); } @@ -88,37 +82,36 @@ class EditorTextSelectionOverlay { if (_handles == null) { return; } - _handles[0].remove(); - _handles[1].remove(); + _handles![0].remove(); + _handles![1].remove(); _handles = null; } hideToolbar() { assert(toolbar != null); _toolbarController.stop(); - toolbar.remove(); + toolbar!.remove(); toolbar = null; } showToolbar() { assert(toolbar == null); toolbar = OverlayEntry(builder: _buildToolbar); - Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor) - .insert(toolbar); + Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)! + .insert(toolbar!); _toolbarController.forward(from: 0.0); } Widget _buildHandle( BuildContext context, _TextSelectionHandlePosition position) { if ((_selection.isCollapsed && - position == _TextSelectionHandlePosition.END) || - selectionCtrls == null) { + position == _TextSelectionHandlePosition.END)) { return Container(); } return Visibility( visible: handlesVisible, child: _TextSelectionHandleOverlay( - onSelectionHandleChanged: (TextSelection newSelection) { + onSelectionHandleChanged: (TextSelection? newSelection) { _handleSelectionHandleChanged(newSelection, position); }, onSelectionHandleTapped: onSelectionHandleTapped, @@ -137,23 +130,26 @@ class EditorTextSelectionOverlay { return; } value = newValue; - if (SchedulerBinding.instance.schedulerPhase == + if (SchedulerBinding.instance!.schedulerPhase == SchedulerPhase.persistentCallbacks) { - SchedulerBinding.instance.addPostFrameCallback(markNeedsBuild); + SchedulerBinding.instance!.addPostFrameCallback(markNeedsBuild); } else { markNeedsBuild(); } } _handleSelectionHandleChanged( - TextSelection newSelection, _TextSelectionHandlePosition position) { + TextSelection? newSelection, _TextSelectionHandlePosition position) { TextPosition textPosition; switch (position) { case _TextSelectionHandlePosition.START: - textPosition = newSelection.base; + textPosition = + newSelection != null ? newSelection.base : TextPosition(offset: 0); break; case _TextSelectionHandlePosition.END: - textPosition = newSelection.extent; + textPosition = newSelection != null + ? newSelection.extent + : TextPosition(offset: 0); break; default: throw ('Invalid position'); @@ -164,21 +160,17 @@ class EditorTextSelectionOverlay { } Widget _buildToolbar(BuildContext context) { - if (selectionCtrls == null) { - return Container(); - } - List endpoints = - renderObject.getEndpointsForSelection(_selection); + renderObject!.getEndpointsForSelection(_selection); Rect editingRegion = Rect.fromPoints( - renderObject.localToGlobal(Offset.zero), - renderObject.localToGlobal(renderObject.size.bottomRight(Offset.zero)), + renderObject!.localToGlobal(Offset.zero), + renderObject!.localToGlobal(renderObject!.size.bottomRight(Offset.zero)), ); - double baseLineHeight = renderObject.preferredLineHeight(_selection.base); + double baseLineHeight = renderObject!.preferredLineHeight(_selection.base); double extentLineHeight = - renderObject.preferredLineHeight(_selection.extent); + renderObject!.preferredLineHeight(_selection.extent); double smallestLineHeight = math.min(baseLineHeight, extentLineHeight); bool isMultiline = endpoints.last.point.dy - endpoints.first.point.dy > smallestLineHeight / 2; @@ -211,18 +203,18 @@ class EditorTextSelectionOverlay { ); } - markNeedsBuild([Duration duration]) { + markNeedsBuild([Duration? duration]) { if (_handles != null) { - _handles[0].markNeedsBuild(); - _handles[1].markNeedsBuild(); + _handles![0].markNeedsBuild(); + _handles![1].markNeedsBuild(); } toolbar?.markNeedsBuild(); } hide() { if (_handles != null) { - _handles[0].remove(); - _handles[1].remove(); + _handles![0].remove(); + _handles![1].remove(); _handles = null; } if (toolbar != null) { @@ -246,22 +238,22 @@ class EditorTextSelectionOverlay { _buildHandle(context, _TextSelectionHandlePosition.END)), ]; - Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor) - .insertAll(_handles); + Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)! + .insertAll(_handles!); } } class _TextSelectionHandleOverlay extends StatefulWidget { const _TextSelectionHandleOverlay({ - Key key, - @required this.selection, - @required this.position, - @required this.startHandleLayerLink, - @required this.endHandleLayerLink, - @required this.renderObject, - @required this.onSelectionHandleChanged, - @required this.onSelectionHandleTapped, - @required this.selectionControls, + Key? key, + required this.selection, + required this.position, + required this.startHandleLayerLink, + required this.endHandleLayerLink, + required this.renderObject, + required this.onSelectionHandleChanged, + required this.onSelectionHandleTapped, + required this.selectionControls, this.dragStartBehavior = DragStartBehavior.start, }) : super(key: key); @@ -269,9 +261,9 @@ class _TextSelectionHandleOverlay extends StatefulWidget { final _TextSelectionHandlePosition position; final LayerLink startHandleLayerLink; final LayerLink endHandleLayerLink; - final RenderEditor renderObject; - final ValueChanged onSelectionHandleChanged; - final VoidCallback onSelectionHandleTapped; + final RenderEditor? renderObject; + final ValueChanged onSelectionHandleChanged; + final VoidCallback? onSelectionHandleTapped; final TextSelectionControls selectionControls; final DragStartBehavior dragStartBehavior; @@ -279,21 +271,20 @@ class _TextSelectionHandleOverlay extends StatefulWidget { _TextSelectionHandleOverlayState createState() => _TextSelectionHandleOverlayState(); - ValueListenable get _visibility { + ValueListenable? get _visibility { switch (position) { case _TextSelectionHandlePosition.START: - return renderObject.selectionStartInViewport; + return renderObject!.selectionStartInViewport; case _TextSelectionHandlePosition.END: - return renderObject.selectionEndInViewport; + return renderObject!.selectionEndInViewport; } - return null; } } class _TextSelectionHandleOverlayState extends State<_TextSelectionHandleOverlay> with SingleTickerProviderStateMixin { - AnimationController _controller; + late AnimationController _controller; Animation get _opacity => _controller.view; @@ -305,11 +296,11 @@ class _TextSelectionHandleOverlayState AnimationController(duration: Duration(milliseconds: 150), vsync: this); _handleVisibilityChanged(); - widget._visibility.addListener(_handleVisibilityChanged); + widget._visibility!.addListener(_handleVisibilityChanged); } _handleVisibilityChanged() { - if (widget._visibility.value) { + if (widget._visibility!.value) { _controller.forward(); } else { _controller.reverse(); @@ -319,14 +310,14 @@ class _TextSelectionHandleOverlayState @override didUpdateWidget(_TextSelectionHandleOverlay oldWidget) { super.didUpdateWidget(oldWidget); - oldWidget._visibility.removeListener(_handleVisibilityChanged); + oldWidget._visibility!.removeListener(_handleVisibilityChanged); _handleVisibilityChanged(); - widget._visibility.addListener(_handleVisibilityChanged); + widget._visibility!.addListener(_handleVisibilityChanged); } @override void dispose() { - widget._visibility.removeListener(_handleVisibilityChanged); + widget._visibility!.removeListener(_handleVisibilityChanged); _controller.dispose(); super.dispose(); } @@ -335,7 +326,7 @@ class _TextSelectionHandleOverlayState _handleDragUpdate(DragUpdateDetails details) { TextPosition position = - widget.renderObject.getPositionForOffset(details.globalPosition); + widget.renderObject!.getPositionForOffset(details.globalPosition); if (widget.selection.isCollapsed) { widget.onSelectionHandleChanged(TextSelection.fromPosition(position)); return; @@ -343,7 +334,7 @@ class _TextSelectionHandleOverlayState bool isNormalized = widget.selection.extentOffset >= widget.selection.baseOffset; - TextSelection newSelection; + TextSelection? newSelection; switch (widget.position) { case _TextSelectionHandlePosition.START: newSelection = TextSelection( @@ -368,19 +359,19 @@ class _TextSelectionHandleOverlayState _handleTap() { if (widget.onSelectionHandleTapped != null) - widget.onSelectionHandleTapped(); + widget.onSelectionHandleTapped!(); } @override Widget build(BuildContext context) { - LayerLink layerLink; - TextSelectionHandleType type; + late LayerLink layerLink; + TextSelectionHandleType? type; switch (widget.position) { case _TextSelectionHandlePosition.START: layerLink = widget.startHandleLayerLink; type = _chooseType( - widget.renderObject.textDirection, + widget.renderObject!.textDirection, TextSelectionHandleType.left, TextSelectionHandleType.right, ); @@ -389,7 +380,7 @@ class _TextSelectionHandleOverlayState assert(!widget.selection.isCollapsed); layerLink = widget.endHandleLayerLink; type = _chooseType( - widget.renderObject.textDirection, + widget.renderObject!.textDirection, TextSelectionHandleType.right, TextSelectionHandleType.left, ); @@ -400,9 +391,9 @@ class _TextSelectionHandleOverlayState widget.position == _TextSelectionHandlePosition.START ? widget.selection.base : widget.selection.extent; - double lineHeight = widget.renderObject.preferredLineHeight(textPosition); + double lineHeight = widget.renderObject!.preferredLineHeight(textPosition); Offset handleAnchor = - widget.selectionControls.getHandleAnchor(type, lineHeight); + widget.selectionControls.getHandleAnchor(type!, lineHeight); Size handleSize = widget.selectionControls.getHandleSize(lineHeight); Rect handleRect = Rect.fromLTWH( @@ -458,27 +449,25 @@ class _TextSelectionHandleOverlayState ); } - TextSelectionHandleType _chooseType( + TextSelectionHandleType? _chooseType( TextDirection textDirection, TextSelectionHandleType ltrType, TextSelectionHandleType rtlType, ) { if (widget.selection.isCollapsed) return TextSelectionHandleType.collapsed; - assert(textDirection != null); switch (textDirection) { case TextDirection.ltr: return ltrType; case TextDirection.rtl: return rtlType; } - return null; } } class EditorTextSelectionGestureDetector extends StatefulWidget { const EditorTextSelectionGestureDetector({ - Key key, + Key? key, this.onTapDown, this.onForcePressStart, this.onForcePressEnd, @@ -492,35 +481,34 @@ class EditorTextSelectionGestureDetector extends StatefulWidget { this.onDragSelectionUpdate, this.onDragSelectionEnd, this.behavior, - @required this.child, - }) : assert(child != null), - super(key: key); + required this.child, + }) : super(key: key); - final GestureTapDownCallback onTapDown; + final GestureTapDownCallback? onTapDown; - final GestureForcePressStartCallback onForcePressStart; + final GestureForcePressStartCallback? onForcePressStart; - final GestureForcePressEndCallback onForcePressEnd; + final GestureForcePressEndCallback? onForcePressEnd; - final GestureTapUpCallback onSingleTapUp; + final GestureTapUpCallback? onSingleTapUp; - final GestureTapCancelCallback onSingleTapCancel; + final GestureTapCancelCallback? onSingleTapCancel; - final GestureLongPressStartCallback onSingleLongTapStart; + final GestureLongPressStartCallback? onSingleLongTapStart; - final GestureLongPressMoveUpdateCallback onSingleLongTapMoveUpdate; + final GestureLongPressMoveUpdateCallback? onSingleLongTapMoveUpdate; - final GestureLongPressEndCallback onSingleLongTapEnd; + final GestureLongPressEndCallback? onSingleLongTapEnd; - final GestureTapDownCallback onDoubleTapDown; + final GestureTapDownCallback? onDoubleTapDown; - final GestureDragStartCallback onDragSelectionStart; + final GestureDragStartCallback? onDragSelectionStart; - final DragSelectionUpdateCallback onDragSelectionUpdate; + final DragSelectionUpdateCallback? onDragSelectionUpdate; - final GestureDragEndCallback onDragSelectionEnd; + final GestureDragEndCallback? onDragSelectionEnd; - final HitTestBehavior behavior; + final HitTestBehavior? behavior; final Widget child; @@ -531,8 +519,8 @@ class EditorTextSelectionGestureDetector extends StatefulWidget { class _EditorTextSelectionGestureDetectorState extends State { - Timer _doubleTapTimer; - Offset _lastTapOffset; + Timer? _doubleTapTimer; + Offset? _lastTapOffset; bool _isDoubleTap = false; @override @@ -544,15 +532,15 @@ class _EditorTextSelectionGestureDetectorState _handleTapDown(TapDownDetails details) { if (widget.onTapDown != null) { - widget.onTapDown(details); + widget.onTapDown!(details); } if (_doubleTapTimer != null && _isWithinDoubleTapTolerance(details.globalPosition)) { if (widget.onDoubleTapDown != null) { - widget.onDoubleTapDown(details); + widget.onDoubleTapDown!(details); } - _doubleTapTimer.cancel(); + _doubleTapTimer!.cancel(); _doubleTapTimeout(); _isDoubleTap = true; } @@ -561,7 +549,7 @@ class _EditorTextSelectionGestureDetectorState _handleTapUp(TapUpDetails details) { if (!_isDoubleTap) { if (widget.onSingleTapUp != null) { - widget.onSingleTapUp(details); + widget.onSingleTapUp!(details); } _lastTapOffset = details.globalPosition; _doubleTapTimer = Timer(kDoubleTapTimeout, _doubleTapTimeout); @@ -571,19 +559,19 @@ class _EditorTextSelectionGestureDetectorState _handleTapCancel() { if (widget.onSingleTapCancel != null) { - widget.onSingleTapCancel(); + widget.onSingleTapCancel!(); } } - DragStartDetails _lastDragStartDetails; - DragUpdateDetails _lastDragUpdateDetails; - Timer _dragUpdateThrottleTimer; + DragStartDetails? _lastDragStartDetails; + DragUpdateDetails? _lastDragUpdateDetails; + Timer? _dragUpdateThrottleTimer; _handleDragStart(DragStartDetails details) { assert(_lastDragStartDetails == null); _lastDragStartDetails = details; if (widget.onDragSelectionStart != null) { - widget.onDragSelectionStart(details); + widget.onDragSelectionStart!(details); } } @@ -597,8 +585,8 @@ class _EditorTextSelectionGestureDetectorState assert(_lastDragStartDetails != null); assert(_lastDragUpdateDetails != null); if (widget.onDragSelectionUpdate != null) { - widget.onDragSelectionUpdate( - _lastDragStartDetails, _lastDragUpdateDetails); + widget.onDragSelectionUpdate!( + _lastDragStartDetails!, _lastDragUpdateDetails!); } _dragUpdateThrottleTimer = null; _lastDragUpdateDetails = null; @@ -607,11 +595,11 @@ class _EditorTextSelectionGestureDetectorState _handleDragEnd(DragEndDetails details) { assert(_lastDragStartDetails != null); if (_dragUpdateThrottleTimer != null) { - _dragUpdateThrottleTimer.cancel(); + _dragUpdateThrottleTimer!.cancel(); _handleDragUpdateThrottled(); } if (widget.onDragSelectionEnd != null) { - widget.onDragSelectionEnd(details); + widget.onDragSelectionEnd!(details); } _dragUpdateThrottleTimer = null; _lastDragStartDetails = null; @@ -622,31 +610,31 @@ class _EditorTextSelectionGestureDetectorState _doubleTapTimer?.cancel(); _doubleTapTimer = null; if (widget.onForcePressStart != null) { - widget.onForcePressStart(details); + widget.onForcePressStart!(details); } } _forcePressEnded(ForcePressDetails details) { if (widget.onForcePressEnd != null) { - widget.onForcePressEnd(details); + widget.onForcePressEnd!(details); } } _handleLongPressStart(LongPressStartDetails details) { if (!_isDoubleTap && widget.onSingleLongTapStart != null) { - widget.onSingleLongTapStart(details); + widget.onSingleLongTapStart!(details); } } _handleLongPressMoveUpdate(LongPressMoveUpdateDetails details) { if (!_isDoubleTap && widget.onSingleLongTapMoveUpdate != null) { - widget.onSingleLongTapMoveUpdate(details); + widget.onSingleLongTapMoveUpdate!(details); } } _handleLongPressEnd(LongPressEndDetails details) { if (!_isDoubleTap && widget.onSingleLongTapEnd != null) { - widget.onSingleLongTapEnd(details); + widget.onSingleLongTapEnd!(details); } _isDoubleTap = false; } @@ -657,12 +645,11 @@ class _EditorTextSelectionGestureDetectorState } bool _isWithinDoubleTapTolerance(Offset secondTapOffset) { - assert(secondTapOffset != null); if (_lastTapOffset == null) { return false; } - return (secondTapOffset - _lastTapOffset).distance <= kDoubleTapSlop; + return (secondTapOffset - _lastTapOffset!).distance <= kDoubleTapSlop; } @override @@ -735,3 +722,18 @@ class _EditorTextSelectionGestureDetectorState ); } } + +class _TransparentTapGestureRecognizer extends TapGestureRecognizer { + _TransparentTapGestureRecognizer({ + Object? debugOwner, + }) : super(debugOwner: debugOwner); + + @override + void rejectGesture(int pointer) { + if (state == GestureRecognizerState.ready) { + acceptGesture(pointer); + } else { + super.rejectGesture(pointer); + } + } +} diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 74ee989b..2f6e0115 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -26,9 +26,9 @@ class InsertEmbedButton extends StatelessWidget { final IconData icon; const InsertEmbedButton({ - Key key, - @required this.controller, - @required this.icon, + Key? key, + required this.controller, + required this.icon, }) : super(key: key); @override @@ -54,11 +54,11 @@ class InsertEmbedButton extends StatelessWidget { class LinkStyleButton extends StatefulWidget { final QuillController controller; - final IconData icon; + final IconData? icon; const LinkStyleButton({ - Key key, - @required this.controller, + Key? key, + required this.controller, this.icon, }) : super(key: key); @@ -120,7 +120,7 @@ class _LinkStyleButtonState extends State { ).then(_linkSubmitted); } - void _linkSubmitted(String value) { + void _linkSubmitted(String? value) { if (value == null || value.isEmpty) { return; } @@ -129,7 +129,7 @@ class _LinkStyleButtonState extends State { } class _LinkDialog extends StatefulWidget { - const _LinkDialog({Key key}) : super(key: key); + const _LinkDialog({Key? key}) : super(key: key); @override _LinkDialogState createState() => _LinkDialogState(); @@ -170,8 +170,8 @@ typedef ToggleStyleButtonBuilder = Widget Function( BuildContext context, Attribute attribute, IconData icon, - bool isToggled, - VoidCallback onPressed, + bool? isToggled, + VoidCallback? onPressed, ); class ToggleStyleButton extends StatefulWidget { @@ -184,23 +184,19 @@ class ToggleStyleButton extends StatefulWidget { final ToggleStyleButtonBuilder childBuilder; ToggleStyleButton({ - Key key, - @required this.attribute, - @required this.icon, - @required this.controller, + Key? key, + required this.attribute, + required this.icon, + required this.controller, this.childBuilder = defaultToggleStyleButtonBuilder, - }) : assert(attribute.value != null), - assert(icon != null), - assert(controller != null), - assert(childBuilder != null), - super(key: key); + }) : super(key: key); @override _ToggleStyleButtonState createState() => _ToggleStyleButtonState(); } class _ToggleStyleButtonState extends State { - bool _isToggled; + bool? _isToggled; Style get _selectionStyle => widget.controller.getSelectionStyle(); @@ -220,7 +216,7 @@ class _ToggleStyleButtonState extends State { bool _getIsToggled(Map attrs) { if (widget.attribute.key == Attribute.list.key) { - Attribute attribute = attrs[widget.attribute.key]; + Attribute? attribute = attrs[widget.attribute.key]; if (attribute == null) { return false; } @@ -256,7 +252,7 @@ class _ToggleStyleButtonState extends State { } _toggleAttribute() { - widget.controller.formatSelection(_isToggled + widget.controller.formatSelection(_isToggled! ? Attribute.clone(widget.attribute, null) : widget.attribute); } @@ -272,22 +268,19 @@ class ToggleCheckListButton extends StatefulWidget { final Attribute attribute; ToggleCheckListButton({ - Key key, - @required this.icon, - @required this.controller, + Key? key, + required this.icon, + required this.controller, this.childBuilder = defaultToggleStyleButtonBuilder, - @required this.attribute, - }) : assert(icon != null), - assert(controller != null), - assert(childBuilder != null), - super(key: key); + required this.attribute, + }) : super(key: key); @override _ToggleCheckListButtonState createState() => _ToggleCheckListButtonState(); } class _ToggleCheckListButtonState extends State { - bool _isToggled; + bool? _isToggled; Style get _selectionStyle => widget.controller.getSelectionStyle(); @@ -307,7 +300,7 @@ class _ToggleCheckListButtonState extends State { bool _getIsToggled(Map attrs) { if (widget.attribute.key == Attribute.list.key) { - Attribute attribute = attrs[widget.attribute.key]; + Attribute? attribute = attrs[widget.attribute.key]; if (attribute == null) { return false; } @@ -344,7 +337,7 @@ class _ToggleCheckListButtonState extends State { } _toggleAttribute() { - widget.controller.formatSelection(_isToggled + widget.controller.formatSelection(_isToggled! ? Attribute.clone(Attribute.unchecked, null) : Attribute.unchecked); } @@ -354,17 +347,18 @@ Widget defaultToggleStyleButtonBuilder( BuildContext context, Attribute attribute, IconData icon, - bool isToggled, - VoidCallback onPressed, + bool? isToggled, + VoidCallback? onPressed, ) { final theme = Theme.of(context); final isEnabled = onPressed != null; final iconColor = isEnabled - ? isToggled + ? isToggled != null ? theme.primaryIconTheme.color : theme.iconTheme.color : theme.disabledColor; - final fillColor = isToggled ? theme.toggleableActiveColor : theme.canvasColor; + final fillColor = + isToggled != null ? theme.toggleableActiveColor : theme.canvasColor; return QuillIconButton( highlightElevation: 0, hoverElevation: 0, @@ -378,7 +372,7 @@ Widget defaultToggleStyleButtonBuilder( class SelectHeaderStyleButton extends StatefulWidget { final QuillController controller; - const SelectHeaderStyleButton({Key key, @required this.controller}) + const SelectHeaderStyleButton({Key? key, required this.controller}) : super(key: key); @override @@ -387,7 +381,7 @@ class SelectHeaderStyleButton extends StatefulWidget { } class _SelectHeaderStyleButtonState extends State { - Attribute _value; + Attribute? _value; Style get _selectionStyle => widget.controller.getSelectionStyle(); @@ -435,8 +429,8 @@ class _SelectHeaderStyleButtonState extends State { } } -Widget _selectHeadingStyleButtonBuilder( - BuildContext context, Attribute value, ValueChanged onSelected) { +Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value, + ValueChanged onSelected) { final style = TextStyle(fontSize: 13); final Map _valueToText = { @@ -446,42 +440,42 @@ Widget _selectHeadingStyleButtonBuilder( Attribute.h3: 'Heading 3', }; - return QuillDropdownButton( + return QuillDropdownButton( highlightElevation: 0, hoverElevation: 0, height: iconSize * 1.77, fillColor: Theme.of(context).canvasColor, child: Text( !kIsWeb - ? _valueToText[value] - : _valueToText[value.key == "header" + ? _valueToText[value!]! + : _valueToText[value!.key == "header" ? Attribute.header : (value.key == "h1") ? Attribute.h1 : (value.key == "h2") ? Attribute.h2 - : Attribute.h3], + : Attribute.h3]!, style: TextStyle(fontSize: 13, fontWeight: FontWeight.w600), ), initialValue: value, items: [ PopupMenuItem( - child: Text(_valueToText[Attribute.header], style: style), + child: Text(_valueToText[Attribute.header]!, style: style), value: Attribute.header, height: iconSize * 1.77, ), PopupMenuItem( - child: Text(_valueToText[Attribute.h1], style: style), + child: Text(_valueToText[Attribute.h1]!, style: style), value: Attribute.h1, height: iconSize * 1.77, ), PopupMenuItem( - child: Text(_valueToText[Attribute.h2], style: style), + child: Text(_valueToText[Attribute.h2]!, style: style), value: Attribute.h2, height: iconSize * 1.77, ), PopupMenuItem( - child: Text(_valueToText[Attribute.h3], style: style), + child: Text(_valueToText[Attribute.h3]!, style: style), value: Attribute.h3, height: iconSize * 1.77, ), @@ -495,43 +489,40 @@ class ImageButton extends StatefulWidget { final QuillController controller; - final OnImagePickCallback onImagePickCallback; + final OnImagePickCallback? onImagePickCallback; - final ImagePickImpl imagePickImpl; + final ImagePickImpl? imagePickImpl; final ImageSource imageSource; ImageButton( - {Key key, - @required this.icon, - @required this.controller, - @required this.imageSource, + {Key? key, + required this.icon, + required this.controller, + required this.imageSource, this.onImagePickCallback, this.imagePickImpl}) - : assert(icon != null), - assert(controller != null), - super(key: key); + : super(key: key); @override _ImageButtonState createState() => _ImageButtonState(); } class _ImageButtonState extends State { - List _paths; - String _extension; + List? _paths; + String? _extension; final _picker = ImagePicker(); FileType _pickingType = FileType.any; - Future _pickImage(ImageSource source) async { - final PickedFile pickedFile = await _picker.getImage(source: source); + Future _pickImage(ImageSource source) async { + final PickedFile? pickedFile = await _picker.getImage(source: source); if (pickedFile == null) return null; final File file = File(pickedFile.path); - if (file == null || widget.onImagePickCallback == null) return null; // We simply return the absolute path to selected file. try { - String url = await widget.onImagePickCallback(file); + String url = await widget.onImagePickCallback!(file); print('Image uploaded and its url is $url'); return url; } catch (error) { @@ -540,13 +531,13 @@ class _ImageButtonState extends State { return null; } - Future _pickImageWeb() async { + Future _pickImageWeb() async { try { _paths = (await FilePicker.platform.pickFiles( type: _pickingType, allowMultiple: false, allowedExtensions: (_extension?.isNotEmpty ?? false) - ? _extension?.replaceAll(' ', '')?.split(',') + ? _extension?.replaceAll(' ', '').split(',') : null, )) ?.files; @@ -556,14 +547,13 @@ class _ImageButtonState extends State { print(ex); } var _fileName = - _paths != null ? _paths.map((e) => e.name).toString() : '...'; + _paths != null ? _paths!.map((e) => e.name).toString() : '...'; if (_paths != null) { File file = File(_fileName); - if (file == null || widget.onImagePickCallback == null) return null; // We simply return the absolute path to selected file. try { - String url = await widget.onImagePickCallback(file); + String url = await widget.onImagePickCallback!(file); print('Image uploaded and its url is $url'); return url; } catch (error) { @@ -584,16 +574,16 @@ class _ImageButtonState extends State { fsType: FilesystemType.file, fileTileSelectMode: FileTileSelectMode.wholeTile, ); - if (filePath == null || filePath.isEmpty) return null; + if (filePath != null && filePath.isEmpty) return ''; - final File file = File(filePath); - String url = await widget.onImagePickCallback(file); + final File file = File(filePath!); + String url = await widget.onImagePickCallback!(file); print('Image uploaded and its url is $url'); return url; } catch (error) { print('Upload image error $error'); } - return null; + return ''; } @override @@ -610,9 +600,9 @@ class _ImageButtonState extends State { onPressed: () { final index = widget.controller.selection.baseOffset; final length = widget.controller.selection.extentOffset - index; - Future image; + Future image; if (widget.imagePickImpl != null) { - image = widget.imagePickImpl(widget.imageSource); + image = widget.imagePickImpl!(widget.imageSource); } else { if (kIsWeb) { image = _pickImageWeb(); @@ -623,11 +613,8 @@ class _ImageButtonState extends State { } } image.then((imageUploadUrl) => { - if (imageUploadUrl != null) - { - widget.controller.replaceText( - index, length, BlockEmbed.image(imageUploadUrl), null) - } + widget.controller.replaceText( + index, length, BlockEmbed.image(imageUploadUrl!), null) }); }, ); @@ -644,24 +631,21 @@ class ColorButton extends StatefulWidget { final QuillController controller; ColorButton( - {Key key, - @required this.icon, - @required this.controller, - @required this.background}) - : assert(icon != null), - assert(controller != null), - assert(background != null), - super(key: key); + {Key? key, + required this.icon, + required this.controller, + required this.background}) + : super(key: key); @override _ColorButtonState createState() => _ColorButtonState(); } class _ColorButtonState extends State { - bool _isToggledColor; - bool _isToggledBackground; - bool _isWhite; - bool _isWhitebackground; + late bool _isToggledColor; + late bool _isToggledBackground; + late bool _isWhite; + late bool _isWhitebackground; Style get _selectionStyle => widget.controller.getSelectionStyle(); @@ -672,9 +656,9 @@ class _ColorButtonState extends State { _isToggledBackground = _getIsToggledBackground( widget.controller.getSelectionStyle().attributes); _isWhite = _isToggledColor && - _selectionStyle.attributes["color"].value == '#ffffff'; + _selectionStyle.attributes["color"]!.value == '#ffffff'; _isWhitebackground = _isToggledBackground && - _selectionStyle.attributes["background"].value == '#ffffff'; + _selectionStyle.attributes["background"]!.value == '#ffffff'; }); } @@ -684,9 +668,9 @@ class _ColorButtonState extends State { _isToggledColor = _getIsToggledColor(_selectionStyle.attributes); _isToggledBackground = _getIsToggledBackground(_selectionStyle.attributes); _isWhite = _isToggledColor && - _selectionStyle.attributes["color"].value == '#ffffff'; + _selectionStyle.attributes["color"]!.value == '#ffffff'; _isWhitebackground = _isToggledBackground && - _selectionStyle.attributes["background"].value == '#ffffff'; + _selectionStyle.attributes["background"]!.value == '#ffffff'; widget.controller.addListener(_didChangeEditingValue); } @@ -708,9 +692,9 @@ class _ColorButtonState extends State { _isToggledBackground = _getIsToggledBackground(_selectionStyle.attributes); _isWhite = _isToggledColor && - _selectionStyle.attributes["color"].value == '#ffffff'; + _selectionStyle.attributes["color"]!.value == '#ffffff'; _isWhitebackground = _isToggledBackground && - _selectionStyle.attributes["background"].value == '#ffffff'; + _selectionStyle.attributes["background"]!.value == '#ffffff'; } } @@ -723,13 +707,13 @@ class _ColorButtonState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); - Color iconColor = _isToggledColor && !widget.background && !_isWhite - ? stringToColor(_selectionStyle.attributes["color"].value) + Color? iconColor = _isToggledColor && !widget.background && !_isWhite + ? stringToColor(_selectionStyle.attributes["color"]!.value) : theme.iconTheme.color; - Color iconColorBackground = + Color? iconColorBackground = _isToggledBackground && widget.background && !_isWhitebackground - ? stringToColor(_selectionStyle.attributes["background"].value) + ? stringToColor(_selectionStyle.attributes["background"]!.value) : theme.iconTheme.color; Color fillColor = _isToggledColor && !widget.background && _isWhite @@ -785,22 +769,19 @@ class HistoryButton extends StatefulWidget { final QuillController controller; HistoryButton( - {Key key, - @required this.icon, - @required this.controller, - @required this.undo}) - : assert(icon != null), - assert(controller != null), - assert(undo != null), - super(key: key); + {Key? key, + required this.icon, + required this.controller, + required this.undo}) + : super(key: key); @override _HistoryButtonState createState() => _HistoryButtonState(); } class _HistoryButtonState extends State { - Color _iconColor; - ThemeData theme; + Color? _iconColor; + late ThemeData theme; @override Widget build(BuildContext context) { @@ -860,14 +841,11 @@ class IndentButton extends StatefulWidget { final bool isIncrease; IndentButton( - {Key key, - @required this.icon, - @required this.controller, - @required this.isIncrease}) - : assert(icon != null), - assert(controller != null), - assert(isIncrease != null), - super(key: key); + {Key? key, + required this.icon, + required this.controller, + required this.isIncrease}) + : super(key: key); @override _IndentButtonState createState() => _IndentButtonState(); @@ -917,10 +895,8 @@ class ClearFormatButton extends StatefulWidget { final QuillController controller; - ClearFormatButton({Key key, @required this.icon, @required this.controller}) - : assert(icon != null), - assert(controller != null), - super(key: key); + ClearFormatButton({Key? key, required this.icon, required this.controller}) + : super(key: key); @override _ClearFormatButtonState createState() => _ClearFormatButtonState(); @@ -950,11 +926,11 @@ class _ClearFormatButtonState extends State { class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { final List children; - const QuillToolbar({Key key, @required this.children}) : super(key: key); + const QuillToolbar({Key? key, required this.children}) : super(key: key); factory QuillToolbar.basic( - {Key key, - @required QuillController controller, + {Key? key, + required QuillController controller, double toolbarIconSize = 18.0, bool showBoldButton = true, bool showItalicButton = true, @@ -973,7 +949,7 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { bool showLink = true, bool showHistory = true, bool showHorizontalRule = false, - OnImagePickCallback onImagePickCallback}) { + OnImagePickCallback? onImagePickCallback}) { iconSize = toolbarIconSize; return QuillToolbar(key: key, children: [ Visibility( @@ -1192,16 +1168,16 @@ class _QuillToolbarState extends State { } class QuillIconButton extends StatelessWidget { - final VoidCallback onPressed; - final Widget icon; + final VoidCallback? onPressed; + final Widget? icon; final double size; - final Color fillColor; + final Color? fillColor; final double hoverElevation; final double highlightElevation; const QuillIconButton({ - Key key, - @required this.onPressed, + Key? key, + required this.onPressed, this.icon, this.size = 40, this.fillColor, @@ -1230,7 +1206,7 @@ class QuillIconButton extends StatelessWidget { class QuillDropdownButton extends StatefulWidget { final double height; - final Color fillColor; + final Color? fillColor; final double hoverElevation; final double highlightElevation; final Widget child; @@ -1239,15 +1215,15 @@ class QuillDropdownButton extends StatefulWidget { final ValueChanged onSelected; const QuillDropdownButton({ - Key key, + Key? key, this.height = 40, this.fillColor, this.hoverElevation = 1, this.highlightElevation = 1, - @required this.child, - @required this.initialValue, - @required this.items, - @required this.onSelected, + required this.child, + required this.initialValue, + required this.items, + required this.onSelected, }) : super(key: key); @override @@ -1276,7 +1252,8 @@ class _QuillDropdownButtonState extends State> { void _showMenu() { final popupMenuTheme = PopupMenuTheme.of(context); final button = context.findRenderObject() as RenderBox; - final overlay = Overlay.of(context).context.findRenderObject() as RenderBox; + final overlay = + Overlay.of(context)!.context.findRenderObject() as RenderBox; final position = RelativeRect.fromRect( Rect.fromPoints( button.localToGlobal(Offset.zero, ancestor: overlay), @@ -1296,15 +1273,12 @@ class _QuillDropdownButtonState extends State> { // widget.shape ?? popupMenuTheme.shape, color: popupMenuTheme.color, // widget.color ?? popupMenuTheme.color, // captureInheritedThemes: widget.captureInheritedThemes, - ).then((T newValue) { + ).then((T? newValue) { if (!mounted) return null; if (newValue == null) { // if (widget.onCanceled != null) widget.onCanceled(); return null; } - if (widget.onSelected != null) { - widget.onSelected(newValue); - } }); } diff --git a/pubspec.lock b/pubspec.lock index 080b2b98..aac0d9cd 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -56,7 +56,7 @@ packages: name: csslib url: "https://pub.dartlang.org" source: hosted - version: "0.16.2" + version: "0.17.0" fake_async: dependency: transitive description: @@ -91,7 +91,7 @@ packages: name: filesystem_picker url: "https://pub.dartlang.org" source: hosted - version: "1.0.4" + version: "2.0.0-nullsafety.0" flutter: dependency: "direct main" description: flutter @@ -103,7 +103,7 @@ packages: name: flutter_colorpicker url: "https://pub.dartlang.org" source: hosted - version: "0.3.5" + version: "0.4.0-nullsafety.0" flutter_keyboard_visibility: dependency: "direct main" description: @@ -148,14 +148,14 @@ packages: name: html url: "https://pub.dartlang.org" source: hosted - version: "0.14.0+4" + version: "0.15.0" http: dependency: transitive description: name: http url: "https://pub.dartlang.org" source: hosted - version: "0.13.0" + version: "0.13.1" http_parser: dependency: transitive description: @@ -169,7 +169,14 @@ packages: name: image_picker url: "https://pub.dartlang.org" source: hosted - version: "0.7.2+1" + version: "0.7.3" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" image_picker_platform_interface: dependency: transitive description: @@ -321,7 +328,7 @@ packages: name: string_validator url: "https://pub.dartlang.org" source: hosted - version: "0.1.4" + version: "0.3.0" term_glyph: dependency: transitive description: @@ -356,21 +363,14 @@ packages: name: universal_html url: "https://pub.dartlang.org" source: hosted - version: "1.2.4" + version: "2.0.4" universal_io: dependency: transitive description: name: universal_io url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" - universal_ui: - dependency: "direct main" - description: - name: universal_ui - url: "https://pub.dartlang.org" - source: hosted - version: "0.0.8" + version: "2.0.1" url_launcher: dependency: "direct main" description: @@ -426,7 +426,7 @@ packages: name: win32 url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" xdg_directories: dependency: transitive description: @@ -434,13 +434,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.2.0" - zone_local: - dependency: transitive - description: - name: zone_local - url: "https://pub.dartlang.org" - source: hosted - version: "0.1.2" sdks: dart: ">=2.12.0 <3.0.0" - flutter: ">=1.22.0" + flutter: ">=1.24.0-10.2.pre" diff --git a/pubspec.yaml b/pubspec.yaml index aac2f51e..682eb412 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,28 +6,25 @@ homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill environment: - sdk: ">=2.7.0 <3.0.0" + sdk: ">=2.12.0 <3.0.0" flutter: ">=1.17.0" dependencies: flutter: sdk: flutter - quiver: ^3.0.0 collection: ^1.15.0 - tuple: ^2.0.0 - url_launcher: ^6.0.0 - flutter_colorpicker: ^0.3.5 - image_picker: ^0.7.2 - photo_view: ^0.11.0 - universal_html: ^1.2.4 file_picker: ^3.0.0 - filesystem_picker: ^1.0.4 - path_provider: ^2.0.1 - string_validator: ^0.1.4 + filesystem_picker: ^2.0.0-nullsafety.0 + flutter_colorpicker: ^0.4.0-nullsafety.0 flutter_keyboard_visibility: ^5.0.0 - universal_ui: ^0.0.8 - - + image_picker: ^0.7.3 + path_provider: ^2.0.1 + photo_view: ^0.11.1 + quiver: ^3.0.0 + string_validator: ^0.3.0 + tuple: ^2.0.0 + universal_html: ^2.0.4 + url_launcher: ^6.0.2 dev_dependencies: flutter_test: @@ -35,37 +32,34 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec - # The following section is specific to Flutter. -flutter: - - # To add assets to your package, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - # - # For details regarding assets in packages, see - # https://flutter.dev/assets-and-images/#from-packages - # - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware. - - # To add custom fonts to your package, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts in packages, see - # https://flutter.dev/custom-fonts/#from-packages +flutter: null +# To add assets to your package, add an assets section, like this: +# assets: +# - images/a_dot_burr.jpeg +# - images/a_dot_ham.jpeg +# +# For details regarding assets in packages, see +# https://flutter.dev/assets-and-images/#from-packages +# +# An image asset can refer to one or more resolution-specific "variants", see +# https://flutter.dev/assets-and-images/#resolution-aware. +# To add custom fonts to your package, add a fonts section here, +# in this "flutter" section. Each entry in this list should have a +# "family" key with the font family name, and a "fonts" key with a +# list giving the asset and other descriptors for the font. For +# example: +# fonts: +# - family: Schyler +# fonts: +# - asset: fonts/Schyler-Regular.ttf +# - asset: fonts/Schyler-Italic.ttf +# style: italic +# - family: Trajan Pro +# fonts: +# - asset: fonts/TrajanPro.ttf +# - asset: fonts/TrajanPro_Bold.ttf +# weight: 700 +# +# For details regarding fonts in packages, see +# https://flutter.dev/custom-fonts/#from-packages