From 7cba9a85234e38731db86cbdd10543970623e5b7 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 18:01:14 +0200 Subject: [PATCH 01/19] Fix height of empty line bug (#141) --- lib/widgets/text_line.dart | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 0b6788cf..57455d5b 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -44,12 +44,11 @@ class TextLine extends StatelessWidget { return EmbedProxy(embedBuilder(context, embed)); } - TextSpan textSpan = _buildTextSpan(context); - StrutStyle strutStyle = - StrutStyle.fromTextStyle(textSpan.style!, forceStrutHeight: true); + final textSpan = _buildTextSpan(context); + final strutStyle = StrutStyle.fromTextStyle(textSpan.style!); final textAlign = _getTextAlign(); RichText child = RichText( - text: TextSpan(children: [textSpan]), + text: textSpan, textAlign: textAlign, textDirection: textDirection, strutStyle: strutStyle, From 31ec14c114214eb16862ae1cb36c842885205593 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 18:07:22 +0200 Subject: [PATCH 02/19] Prefer relative imports This streamlines our imports. --- analysis_options.yaml | 2 ++ lib/models/documents/document.dart | 10 +++++----- lib/models/documents/history.dart | 2 +- lib/models/documents/nodes/block.dart | 3 +-- lib/models/documents/nodes/leaf.dart | 3 +-- lib/models/documents/nodes/line.dart | 7 +++---- lib/models/documents/nodes/node.dart | 5 ++--- lib/models/documents/style.dart | 3 ++- lib/models/rules/delete.dart | 6 +++--- lib/models/rules/format.dart | 6 +++--- lib/models/rules/insert.dart | 9 +++++---- lib/models/rules/rule.dart | 7 +++---- lib/utils/diff_delta.dart | 2 +- lib/widgets/box.dart | 3 ++- lib/widgets/controller.dart | 13 +++++++------ lib/widgets/delegate.dart | 4 ++-- lib/widgets/editor.dart | 21 ++++++++++----------- lib/widgets/raw_editor.dart | 22 +++++++++++----------- lib/widgets/text_block.dart | 16 ++++++++-------- lib/widgets/text_line.dart | 23 +++++++++++------------ lib/widgets/text_selection.dart | 2 +- lib/widgets/toolbar.dart | 8 ++++---- 22 files changed, 88 insertions(+), 89 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 306d335b..fb75bccd 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -10,6 +10,8 @@ linter: - always_put_required_named_parameters_first - avoid_print - avoid_redundant_argument_values + - directives_ordering - prefer_const_constructors - prefer_const_constructors_in_immutables + - prefer_relative_imports - unnecessary_parenthesis diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index 8a620446..a8810079 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -1,17 +1,17 @@ import 'dart:async'; -import 'package:flutter_quill/models/documents/nodes/block.dart'; -import 'package:flutter_quill/models/documents/nodes/container.dart'; -import 'package:flutter_quill/models/documents/nodes/line.dart'; -import 'package:flutter_quill/models/documents/style.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; import 'package:tuple/tuple.dart'; +import '../quill_delta.dart'; import '../rules/rule.dart'; import 'attribute.dart'; import 'history.dart'; +import 'nodes/block.dart'; +import 'nodes/container.dart'; import 'nodes/embed.dart'; +import 'nodes/line.dart'; import 'nodes/node.dart'; +import 'style.dart'; /// The rich text document class Document { diff --git a/lib/models/documents/history.dart b/lib/models/documents/history.dart index 6d89b389..d3e36e32 100644 --- a/lib/models/documents/history.dart +++ b/lib/models/documents/history.dart @@ -1,6 +1,6 @@ -import 'package:flutter_quill/models/quill_delta.dart'; import 'package:tuple/tuple.dart'; +import '../quill_delta.dart'; import 'document.dart'; class History { diff --git a/lib/models/documents/nodes/block.dart b/lib/models/documents/nodes/block.dart index 4d569cc7..acae321b 100644 --- a/lib/models/documents/nodes/block.dart +++ b/lib/models/documents/nodes/block.dart @@ -1,5 +1,4 @@ -import 'package:flutter_quill/models/quill_delta.dart'; - +import '../../quill_delta.dart'; import 'container.dart'; import 'line.dart'; import 'node.dart'; diff --git a/lib/models/documents/nodes/leaf.dart b/lib/models/documents/nodes/leaf.dart index 6cb9af24..fab88b53 100644 --- a/lib/models/documents/nodes/leaf.dart +++ b/lib/models/documents/nodes/leaf.dart @@ -1,7 +1,6 @@ import 'dart:math' as math; -import 'package:flutter_quill/models/quill_delta.dart'; - +import '../../quill_delta.dart'; import '../style.dart'; import 'embed.dart'; import 'line.dart'; diff --git a/lib/models/documents/nodes/line.dart b/lib/models/documents/nodes/line.dart index 574549ea..ceb95801 100644 --- a/lib/models/documents/nodes/line.dart +++ b/lib/models/documents/nodes/line.dart @@ -1,14 +1,13 @@ import 'dart:math' as math; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/nodes/node.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; - +import '../../quill_delta.dart'; +import '../attribute.dart'; import '../style.dart'; import 'block.dart'; import 'container.dart'; import 'embed.dart'; import 'leaf.dart'; +import 'node.dart'; class Line extends Container { @override diff --git a/lib/models/documents/nodes/node.dart b/lib/models/documents/nodes/node.dart index abc093c3..2d694222 100644 --- a/lib/models/documents/nodes/node.dart +++ b/lib/models/documents/nodes/node.dart @@ -1,9 +1,8 @@ import 'dart:collection'; -import 'package:flutter_quill/models/documents/style.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; - +import '../../quill_delta.dart'; import '../attribute.dart'; +import '../style.dart'; import 'container.dart'; import 'line.dart'; diff --git a/lib/models/documents/style.dart b/lib/models/documents/style.dart index 7b9b050b..90c03df0 100644 --- a/lib/models/documents/style.dart +++ b/lib/models/documents/style.dart @@ -1,7 +1,8 @@ import 'package:collection/collection.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; import 'package:quiver/core.dart'; +import 'attribute.dart'; + /* Collection of style attributes */ class Style { final Map _attributes; diff --git a/lib/models/rules/delete.dart b/lib/models/rules/delete.dart index 15aa3862..535504d5 100644 --- a/lib/models/rules/delete.dart +++ b/lib/models/rules/delete.dart @@ -1,6 +1,6 @@ -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; -import 'package:flutter_quill/models/rules/rule.dart'; +import '../documents/attribute.dart'; +import '../quill_delta.dart'; +import 'rule.dart'; abstract class DeleteRule extends Rule { const DeleteRule(); diff --git a/lib/models/rules/format.dart b/lib/models/rules/format.dart index 755f4137..0d574c94 100644 --- a/lib/models/rules/format.dart +++ b/lib/models/rules/format.dart @@ -1,6 +1,6 @@ -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; -import 'package:flutter_quill/models/rules/rule.dart'; +import '../documents/attribute.dart'; +import '../quill_delta.dart'; +import 'rule.dart'; abstract class FormatRule extends Rule { const FormatRule(); diff --git a/lib/models/rules/insert.dart b/lib/models/rules/insert.dart index 5ea7f215..f0f7d001 100644 --- a/lib/models/rules/insert.dart +++ b/lib/models/rules/insert.dart @@ -1,9 +1,10 @@ -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/style.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; -import 'package:flutter_quill/models/rules/rule.dart'; import 'package:tuple/tuple.dart'; +import '../documents/attribute.dart'; +import '../documents/style.dart'; +import '../quill_delta.dart'; +import 'rule.dart'; + abstract class InsertRule extends Rule { const InsertRule(); diff --git a/lib/models/rules/rule.dart b/lib/models/rules/rule.dart index 70a5aa74..23eb3b9d 100644 --- a/lib/models/rules/rule.dart +++ b/lib/models/rules/rule.dart @@ -1,7 +1,6 @@ -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/document.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; - +import '../documents/attribute.dart'; +import '../documents/document.dart'; +import '../quill_delta.dart'; import 'delete.dart'; import 'format.dart'; import 'insert.dart'; diff --git a/lib/utils/diff_delta.dart b/lib/utils/diff_delta.dart index 127c2d8b..d3b97116 100644 --- a/lib/utils/diff_delta.dart +++ b/lib/utils/diff_delta.dart @@ -1,6 +1,6 @@ import 'dart:math' as math; -import 'package:flutter_quill/models/quill_delta.dart'; +import '../models/quill_delta.dart'; const Set WHITE_SPACE = { 0x9, diff --git a/lib/widgets/box.dart b/lib/widgets/box.dart index 5e43b841..75547923 100644 --- a/lib/widgets/box.dart +++ b/lib/widgets/box.dart @@ -1,5 +1,6 @@ import 'package:flutter/rendering.dart'; -import 'package:flutter_quill/models/documents/nodes/container.dart'; + +import '../models/documents/nodes/container.dart'; abstract class RenderContentProxyBox implements RenderBox { double getPreferredLineHeight(); diff --git a/lib/widgets/controller.dart b/lib/widgets/controller.dart index da876bf1..510db24c 100644 --- a/lib/widgets/controller.dart +++ b/lib/widgets/controller.dart @@ -1,14 +1,15 @@ import 'dart:math' as math; import 'package:flutter/cupertino.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/document.dart'; -import 'package:flutter_quill/models/documents/nodes/embed.dart'; -import 'package:flutter_quill/models/documents/style.dart'; -import 'package:flutter_quill/models/quill_delta.dart'; -import 'package:flutter_quill/utils/diff_delta.dart'; import 'package:tuple/tuple.dart'; +import '../models/documents/attribute.dart'; +import '../models/documents/document.dart'; +import '../models/documents/nodes/embed.dart'; +import '../models/documents/style.dart'; +import '../models/quill_delta.dart'; +import '../utils/diff_delta.dart'; + class QuillController extends ChangeNotifier { final Document document; TextSelection selection; diff --git a/lib/widgets/delegate.dart b/lib/widgets/delegate.dart index 3cfb9cd6..f134a77e 100644 --- a/lib/widgets/delegate.dart +++ b/lib/widgets/delegate.dart @@ -2,10 +2,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter_quill/models/documents/nodes/leaf.dart'; -import 'package:flutter_quill/widgets/text_selection.dart'; +import '../models/documents/nodes/leaf.dart'; import 'editor.dart'; +import 'text_selection.dart'; typedef EmbedBuilder = Widget Function(BuildContext context, Embed node); diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index f9bab1c1..654daf1e 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -8,25 +8,24 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/document.dart'; -import 'package:flutter_quill/models/documents/nodes/container.dart' - as container_node; -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/widgets/image.dart'; -import 'package:flutter_quill/widgets/raw_editor.dart'; -import 'package:flutter_quill/widgets/text_selection.dart'; import 'package:string_validator/string_validator.dart'; import 'package:url_launcher/url_launcher.dart'; +import '../models/documents/attribute.dart'; +import '../models/documents/document.dart'; +import '../models/documents/nodes/container.dart' as container_node; +import '../models/documents/nodes/embed.dart'; +import '../models/documents/nodes/leaf.dart' as leaf; +import '../models/documents/nodes/line.dart'; +import '../models/documents/nodes/node.dart'; import 'box.dart'; import 'controller.dart'; import 'cursor.dart'; import 'default_styles.dart'; import 'delegate.dart'; +import 'image.dart'; +import 'raw_editor.dart'; +import 'text_selection.dart'; const linkPrefixes = [ 'mailto:', // email diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 6a24f39c..155a90ff 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -9,25 +9,25 @@ import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; import 'package:flutter/services.dart'; import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/document.dart'; -import 'package:flutter_quill/models/documents/nodes/block.dart'; -import 'package:flutter_quill/models/documents/nodes/line.dart'; -import 'package:flutter_quill/models/documents/nodes/node.dart'; -import 'package:flutter_quill/utils/diff_delta.dart'; -import 'package:flutter_quill/widgets/default_styles.dart'; -import 'package:flutter_quill/widgets/proxy.dart'; -import 'package:flutter_quill/widgets/text_block.dart'; -import 'package:flutter_quill/widgets/text_line.dart'; -import 'package:flutter_quill/widgets/text_selection.dart'; import 'package:tuple/tuple.dart'; +import '../models/documents/attribute.dart'; +import '../models/documents/document.dart'; +import '../models/documents/nodes/block.dart'; +import '../models/documents/nodes/line.dart'; +import '../models/documents/nodes/node.dart'; +import '../utils/diff_delta.dart'; import 'box.dart'; import 'controller.dart'; import 'cursor.dart'; +import 'default_styles.dart'; import 'delegate.dart'; import 'editor.dart'; import 'keyboard_listener.dart'; +import 'proxy.dart'; +import 'text_block.dart'; +import 'text_line.dart'; +import 'text_selection.dart'; class RawEditor extends StatefulWidget { final QuillController controller; diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index 85912431..031ecbd5 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -1,19 +1,19 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/nodes/block.dart'; -import 'package:flutter_quill/models/documents/nodes/line.dart'; -import 'package:flutter_quill/models/documents/nodes/node.dart'; -import 'package:flutter_quill/widgets/cursor.dart'; -import 'package:flutter_quill/widgets/default_styles.dart'; -import 'package:flutter_quill/widgets/text_line.dart'; -import 'package:flutter_quill/widgets/text_selection.dart'; import 'package:tuple/tuple.dart'; +import '../models/documents/attribute.dart'; +import '../models/documents/nodes/block.dart'; +import '../models/documents/nodes/line.dart'; +import '../models/documents/nodes/node.dart'; import 'box.dart'; +import 'cursor.dart'; +import 'default_styles.dart'; import 'delegate.dart'; import 'editor.dart'; +import 'text_line.dart'; +import 'text_selection.dart'; const List arabianRomanNumbers = [ 1000, diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 57455d5b..c10c6c8e 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -3,23 +3,22 @@ import 'dart:math' as math; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/nodes/container.dart' - as container; -import 'package:flutter_quill/models/documents/nodes/leaf.dart' as leaf; -import 'package:flutter_quill/models/documents/nodes/leaf.dart'; -import 'package:flutter_quill/models/documents/nodes/line.dart'; -import 'package:flutter_quill/models/documents/nodes/node.dart'; -import 'package:flutter_quill/models/documents/style.dart'; -import 'package:flutter_quill/utils/color.dart'; -import 'package:flutter_quill/widgets/cursor.dart'; -import 'package:flutter_quill/widgets/proxy.dart'; -import 'package:flutter_quill/widgets/text_selection.dart'; import 'package:tuple/tuple.dart'; +import '../models/documents/attribute.dart'; +import '../models/documents/nodes/container.dart' as container; +import '../models/documents/nodes/leaf.dart' as leaf; +import '../models/documents/nodes/leaf.dart'; +import '../models/documents/nodes/line.dart'; +import '../models/documents/nodes/node.dart'; +import '../models/documents/style.dart'; +import '../utils/color.dart'; import 'box.dart'; +import 'cursor.dart'; import 'default_styles.dart'; import 'delegate.dart'; +import 'proxy.dart'; +import 'text_selection.dart'; class TextLine extends StatelessWidget { final Line line; diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index 8aa29d25..7873c99d 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -7,8 +7,8 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/scheduler.dart'; -import 'package:flutter_quill/models/documents/nodes/node.dart'; +import '../models/documents/nodes/node.dart'; import 'editor.dart'; TextSelection localSelection(Node node, TextSelection selection, fromParent) { diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 6b4b4147..07bdd421 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -5,13 +5,13 @@ import 'package:filesystem_picker/filesystem_picker.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_colorpicker/flutter_colorpicker.dart'; -import 'package:flutter_quill/models/documents/attribute.dart'; -import 'package:flutter_quill/models/documents/nodes/embed.dart'; -import 'package:flutter_quill/models/documents/style.dart'; -import 'package:flutter_quill/utils/color.dart'; import 'package:image_picker/image_picker.dart'; import 'package:path_provider/path_provider.dart'; +import '../models/documents/attribute.dart'; +import '../models/documents/nodes/embed.dart'; +import '../models/documents/style.dart'; +import '../utils/color.dart'; import 'controller.dart'; double iconSize = 18.0; From e4a3c11702ca9982b9928b955901fecf4e72fb20 Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Thu, 8 Apr 2021 09:35:59 -0700 Subject: [PATCH 03/19] Update example code --- example/lib/pages/home_page.dart | 2 +- example/lib/pages/read_only_page.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 65c2f165..5d02d71e 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:app/universal_ui/universal_ui.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -16,6 +15,7 @@ import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; import 'package:tuple/tuple.dart'; +import '../universal_ui/universal_ui.dart'; import 'read_only_page.dart'; class HomePage extends StatefulWidget { diff --git a/example/lib/pages/read_only_page.dart b/example/lib/pages/read_only_page.dart index e87e4f8f..395c20f5 100644 --- a/example/lib/pages/read_only_page.dart +++ b/example/lib/pages/read_only_page.dart @@ -1,9 +1,9 @@ -import 'package:app/universal_ui/universal_ui.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/widgets/controller.dart'; import 'package:flutter_quill/widgets/editor.dart'; +import '../universal_ui/universal_ui.dart'; import '../widgets/demo_scaffold.dart'; class ReadOnlyPage extends StatefulWidget { From bc494bc50f6c3bacb31d76abfe2b41c5e3ae04ea Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:08:26 +0200 Subject: [PATCH 04/19] Prefer final Declaring variables as final when possible is a good practice because it helps avoid accidental reassignments and allows the compiler to do optimizations. --- analysis_options.yaml | 5 +- example/lib/pages/home_page.dart | 6 +- example/lib/universal_ui/universal_ui.dart | 4 +- lib/models/documents/attribute.dart | 6 +- lib/models/documents/document.dart | 48 +++---- lib/models/documents/history.dart | 12 +- lib/models/documents/nodes/block.dart | 10 +- lib/models/documents/nodes/container.dart | 16 +-- lib/models/documents/nodes/embed.dart | 4 +- lib/models/documents/nodes/leaf.dart | 37 ++--- lib/models/documents/nodes/line.dart | 74 +++++----- lib/models/documents/nodes/node.dart | 6 +- lib/models/documents/style.dart | 18 +-- lib/models/quill_delta.dart | 15 +- lib/models/rules/delete.dart | 28 ++-- lib/models/rules/format.dart | 36 ++--- lib/models/rules/insert.dart | 96 +++++++------ lib/models/rules/rule.dart | 2 +- lib/utils/color.dart | 4 +- lib/utils/diff_delta.dart | 24 ++-- lib/widgets/controller.dart | 18 +-- lib/widgets/cursor.dart | 16 +-- lib/widgets/default_styles.dart | 10 +- lib/widgets/delegate.dart | 2 +- lib/widgets/editor.dart | 152 ++++++++++----------- lib/widgets/keyboard_listener.dart | 6 +- lib/widgets/proxy.dart | 4 +- lib/widgets/raw_editor.dart | 135 +++++++++--------- lib/widgets/text_block.dart | 102 +++++++------- lib/widgets/text_line.dart | 85 ++++++------ lib/widgets/text_selection.dart | 49 ++++--- lib/widgets/toolbar.dart | 34 ++--- 32 files changed, 524 insertions(+), 540 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index fb75bccd..50b1b8fc 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -3,7 +3,6 @@ include: package:pedantic/analysis_options.yaml analyzer: errors: undefined_prefixed_name: ignore - omit_local_variable_types: ignore unsafe_html: ignore linter: rules: @@ -11,7 +10,11 @@ linter: - avoid_print - avoid_redundant_argument_values - directives_ordering + - omit_local_variable_types - prefer_const_constructors - prefer_const_constructors_in_immutables + - prefer_final_fields + - prefer_final_in_for_each + - prefer_final_locals - prefer_relative_imports - unnecessary_parenthesis diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 5d02d71e..a613c085 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -178,14 +178,14 @@ class _HomePageState extends State { // 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 { // Copies the picked file from temporary cache to applications directory - Directory appDocDir = await getApplicationDocumentsDirectory(); - File copiedFile = + final appDocDir = await getApplicationDocumentsDirectory(); + final copiedFile = await file.copy('${appDocDir.path}/${basename(file.path)}'); return copiedFile.path.toString(); } Widget _buildMenuBar(BuildContext context) { - Size size = MediaQuery.of(context).size; + final size = MediaQuery.of(context).size; final itemStyle = const TextStyle( color: Colors.white, fontSize: 18, diff --git a/example/lib/universal_ui/universal_ui.dart b/example/lib/universal_ui/universal_ui.dart index 15eeb9f8..9c833aa2 100644 --- a/example/lib/universal_ui/universal_ui.dart +++ b/example/lib/universal_ui/universal_ui.dart @@ -28,8 +28,8 @@ var ui = UniversalUI(); Widget defaultEmbedBuilderWeb(BuildContext context, leaf.Embed node) { switch (node.value.type) { case 'image': - String imageUrl = node.value.data; - Size size = MediaQuery.of(context).size; + final String imageUrl = node.value.data; + final size = MediaQuery.of(context).size; UniversalUI().platformViewRegistry.registerViewFactory( imageUrl, (int viewId) => html.ImageElement()..src = imageUrl); return Padding( diff --git a/lib/models/documents/attribute.dart b/lib/models/documents/attribute.dart index 8d43e805..7683b9ed 100644 --- a/lib/models/documents/attribute.dart +++ b/lib/models/documents/attribute.dart @@ -164,8 +164,8 @@ class Attribute { if (!_registry.containsKey(key)) { throw ArgumentError.value(key, 'key "$key" not found.'); } - Attribute origin = _registry[key]!; - Attribute attribute = clone(origin, value); + final origin = _registry[key]!; + final attribute = clone(origin, value); return attribute; } @@ -177,7 +177,7 @@ class Attribute { bool operator ==(Object other) { if (identical(this, other)) return true; if (other is! Attribute) return false; - Attribute typedOther = other; + final typedOther = other; return key == typedOther.key && scope == typedOther.scope && value == typedOther.value; diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index a8810079..232642fb 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -56,14 +56,14 @@ class Document { return Delta(); } - Delta delta = _rules.apply(RuleType.INSERT, this, index, data: data); + final delta = _rules.apply(RuleType.INSERT, this, index, data: data); compose(delta, ChangeSource.LOCAL); return delta; } Delta delete(int index, int len) { assert(index >= 0 && len > 0); - Delta delta = _rules.apply(RuleType.DELETE, this, index, len: len); + final delta = _rules.apply(RuleType.DELETE, this, index, len: len); if (delta.isNotEmpty) { compose(delta, ChangeSource.LOCAL); } @@ -74,18 +74,18 @@ class Document { assert(index >= 0); assert(data is String || data is Embeddable); - bool dataIsNotEmpty = (data is String) ? data.isNotEmpty : true; + final dataIsNotEmpty = (data is String) ? data.isNotEmpty : true; assert(dataIsNotEmpty || len > 0); - Delta delta = Delta(); + var delta = Delta(); if (dataIsNotEmpty) { delta = insert(index + len, data); } if (len > 0) { - Delta deleteDelta = delete(index, len); + final deleteDelta = delete(index, len); delta = delta.compose(deleteDelta); } @@ -95,9 +95,9 @@ class Document { Delta format(int index, int len, Attribute? attribute) { assert(index >= 0 && len >= 0 && attribute != null); - Delta delta = Delta(); + var delta = Delta(); - Delta formatDelta = _rules.apply(RuleType.FORMAT, this, index, + final formatDelta = _rules.apply(RuleType.FORMAT, this, index, len: len, attribute: attribute); if (formatDelta.isNotEmpty) { compose(formatDelta, ChangeSource.LOCAL); @@ -108,16 +108,16 @@ class Document { } Style collectStyle(int index, int len) { - ChildQuery res = queryChild(index); + final res = queryChild(index); return (res.node as Line).collectStyle(res.offset, len); } ChildQuery queryChild(int offset) { - ChildQuery res = _root.queryChild(offset, true); + final res = _root.queryChild(offset, true); if (res.node is Line) { return res; } - Block block = res.node as Block; + final block = res.node as Block; return block.queryChild(res.offset, true); } @@ -126,11 +126,11 @@ class Document { delta.trim(); assert(delta.isNotEmpty); - int offset = 0; + var offset = 0; delta = _transform(delta); - Delta originalDelta = toDelta(); - for (Operation op in delta.toList()) { - Style? style = + final originalDelta = toDelta(); + for (final op in delta.toList()) { + final style = op.attributes != null ? Style.fromJson(op.attributes) : null; if (op.isInsert) { @@ -172,10 +172,10 @@ class Document { bool get hasRedo => _history.hasRedo; static Delta _transform(Delta delta) { - Delta res = Delta(); - List ops = delta.toList(); - for (int i = 0; i < ops.length; i++) { - Operation op = ops[i]; + final res = Delta(); + final ops = delta.toList(); + for (var i = 0; i < ops.length; i++) { + final op = ops[i]; res.push(op); _handleImageInsert(i, ops, op, res); } @@ -184,14 +184,14 @@ class Document { static void _handleImageInsert( int i, List ops, Operation op, Delta res) { - bool nextOpIsImage = + final nextOpIsImage = i + 1 < ops.length && ops[i + 1].isInsert && ops[i + 1].data is! String; if (nextOpIsImage && !(op.data as String).endsWith('\n')) { res.push(Operation.insert('\n')); } // Currently embed is equivalent to image and hence `is! String` - bool opInsertImage = op.isInsert && op.data is! String; - bool nextOpIsLineBreak = i + 1 < ops.length && + final opInsertImage = op.isInsert && op.data is! String; + final nextOpIsLineBreak = i + 1 < ops.length && ops[i + 1].isInsert && ops[i + 1].data is String && (ops[i + 1].data as String).startsWith('\n'); @@ -221,7 +221,7 @@ class Document { void _loadDocument(Delta doc) { assert((doc.last.data as String).endsWith('\n')); - int offset = 0; + var offset = 0; for (final op in doc.toList()) { if (!op.isInsert) { throw ArgumentError.value(doc, @@ -247,12 +247,12 @@ class Document { return false; } - final Node node = root.children.first; + final node = root.children.first; if (!node.isLast) { return false; } - Delta delta = node.toDelta(); + final delta = node.toDelta(); return delta.length == 1 && delta.first.data == '\n' && delta.first.key == 'insert'; diff --git a/lib/models/documents/history.dart b/lib/models/documents/history.dart index d3e36e32..9398ad1c 100644 --- a/lib/models/documents/history.dart +++ b/lib/models/documents/history.dart @@ -47,7 +47,7 @@ class History { void record(Delta change, Delta before) { if (change.isEmpty) return; stack.redo.clear(); - Delta undoDelta = change.invert(before); + var undoDelta = change.invert(before); final timeStamp = DateTime.now().millisecondsSinceEpoch; if (lastRecorded + interval > timeStamp && stack.undo.isNotEmpty) { @@ -74,7 +74,7 @@ class History { } void transformStack(List stack, Delta delta) { - for (int i = stack.length - 1; i >= 0; i -= 1) { + for (var i = stack.length - 1; i >= 0; i -= 1) { final oldDelta = stack[i]; stack[i] = delta.transform(oldDelta, true); delta = oldDelta.transform(delta, false); @@ -88,10 +88,10 @@ class History { if (source.isEmpty) { return const Tuple2(false, 0); } - Delta delta = source.removeLast(); + final delta = source.removeLast(); // look for insert or delete int? len = 0; - List ops = delta.toList(); + final ops = delta.toList(); for (var i = 0; i < ops.length; i++) { if (ops[i].key == Operation.insertKey) { len = ops[i].length; @@ -99,8 +99,8 @@ class History { len = ops[i].length! * -1; } } - Delta base = Delta.from(doc.toDelta()); - Delta inverseDelta = delta.invert(base); + final base = Delta.from(doc.toDelta()); + final inverseDelta = delta.invert(base); dest.add(inverseDelta); lastRecorded = 0; ignoreChange = true; diff --git a/lib/models/documents/nodes/block.dart b/lib/models/documents/nodes/block.dart index acae321b..0919806f 100644 --- a/lib/models/documents/nodes/block.dart +++ b/lib/models/documents/nodes/block.dart @@ -17,7 +17,7 @@ class Block extends Container { @override void adjust() { if (isEmpty) { - Node? sibling = previous; + final sibling = previous; unlink(); if (sibling != null) { sibling.adjust(); @@ -25,8 +25,8 @@ class Block extends Container { return; } - Block block = this; - Node? prev = block.previous; + var block = this; + final prev = block.previous; // merging it with previous block if style is the same if (!block.isFirst && block.previous is Block && @@ -35,7 +35,7 @@ class Block extends Container { block.unlink(); block = prev as Block; } - Node? next = block.next; + final next = block.next; // merging it with next block if style is the same if (!block.isLast && block.next is Block && next!.style == block.style) { (next as Block).moveChildToNewParent(block); @@ -47,7 +47,7 @@ class Block extends Container { String toString() { final block = style.attributes.toString(); final buffer = StringBuffer('§ {$block}\n'); - for (var child in children) { + for (final child in children) { final tree = child.isLast ? '└' : '├'; buffer.write(' $tree $child'); if (!child.isLast) buffer.writeln(); diff --git a/lib/models/documents/nodes/container.dart b/lib/models/documents/nodes/container.dart index c7c10390..8b3fd0c3 100644 --- a/lib/models/documents/nodes/container.dart +++ b/lib/models/documents/nodes/container.dart @@ -48,9 +48,9 @@ abstract class Container extends Node { return; } - T? last = newParent!.isEmpty ? null : newParent.last as T?; + final last = newParent!.isEmpty ? null : newParent.last as T?; while (isNotEmpty) { - T child = first as T; + final child = first as T; child?.unlink(); newParent.add(child); } @@ -63,8 +63,8 @@ abstract class Container extends Node { return ChildQuery(null, 0); } - for (Node node in children) { - int len = node.length; + for (final node in children) { + final len = node.length; if (offset < len || (inclusive && offset == len && (node.isLast))) { return ChildQuery(node, offset); } @@ -84,14 +84,14 @@ abstract class Container extends Node { assert(index == 0 || (index > 0 && index < length)); if (isNotEmpty) { - ChildQuery child = queryChild(index, false); + final child = queryChild(index, false); child.node!.insert(child.offset, data, style); return; } // empty assert(index == 0); - T node = defaultChild; + final node = defaultChild; add(node); node?.insert(index, data, style); } @@ -99,14 +99,14 @@ abstract class Container extends Node { @override void retain(int index, int? length, Style? attributes) { assert(isNotEmpty); - ChildQuery child = queryChild(index, false); + final child = queryChild(index, false); child.node!.retain(child.offset, length, attributes); } @override void delete(int index, int? length) { assert(isNotEmpty); - ChildQuery child = queryChild(index, false); + final child = queryChild(index, false); child.node!.delete(child.offset, length); } diff --git a/lib/models/documents/nodes/embed.dart b/lib/models/documents/nodes/embed.dart index 3268e257..cc0ecaea 100644 --- a/lib/models/documents/nodes/embed.dart +++ b/lib/models/documents/nodes/embed.dart @@ -5,12 +5,12 @@ class Embeddable { Embeddable(this.type, this.data); Map toJson() { - Map m = {type: data}; + final m = {type: data}; return m; } static Embeddable fromJson(Map json) { - Map m = Map.from(json); + final m = Map.from(json); assert(m.length == 1, 'Embeddable map has one key'); return BlockEmbed(m.keys.first, m.values.first); diff --git a/lib/models/documents/nodes/leaf.dart b/lib/models/documents/nodes/leaf.dart index fab88b53..88aeca6c 100644 --- a/lib/models/documents/nodes/leaf.dart +++ b/lib/models/documents/nodes/leaf.dart @@ -18,7 +18,7 @@ abstract class Leaf extends Node { if (data is Embeddable) { return Embed(data); } - String text = data as String; + final text = data as String; assert(text.isNotEmpty); return Text(text); } @@ -44,14 +44,15 @@ abstract class Leaf extends Node { @override Delta toDelta() { - var data = _value is Embeddable ? (_value as Embeddable).toJson() : _value; + final data = + _value is Embeddable ? (_value as Embeddable).toJson() : _value; return Delta()..insert(data, style.toJson()); } @override void insert(int index, Object data, Style? style) { assert(index >= 0 && index <= length); - Leaf node = Leaf(data); + final node = Leaf(data); if (index < length) { splitAt(index)!.insertBefore(node); } else { @@ -66,9 +67,9 @@ abstract class Leaf extends Node { return; } - int local = math.min(length - index, len!); - int remain = len - local; - Leaf node = _isolate(index, local); + final local = math.min(length - index, len!); + final remain = len - local; + final node = _isolate(index, local); if (remain > 0) { assert(node.next != null); @@ -81,13 +82,13 @@ abstract class Leaf extends Node { void delete(int index, int? len) { assert(index < length); - int local = math.min(length - index, len!); - Leaf target = _isolate(index, local); - Leaf? prev = target.previous as Leaf?; - Leaf? next = target.next as Leaf?; + final local = math.min(length - index, len!); + final target = _isolate(index, local); + final prev = target.previous as Leaf?; + final next = target.next as Leaf?; target.unlink(); - int remain = len - local; + final remain = len - local; if (remain > 0) { assert(next != null); next!.delete(0, remain); @@ -104,9 +105,9 @@ abstract class Leaf extends Node { return; } - Text node = this as Text; + var node = this as Text; // merging it with previous node if style is the same - Node? prev = node.previous; + final prev = node.previous; if (!node.isFirst && prev is Text && prev.style == node.style) { prev._value = prev.value + node.value; node.unlink(); @@ -114,7 +115,7 @@ abstract class Leaf extends Node { } // merging it with next node if style is the same - Node? next = node.next; + final next = node.next; if (!node.isLast && next is Text && next.style == node.style) { node._value = node.value + next.value; next.unlink(); @@ -123,7 +124,7 @@ abstract class Leaf extends Node { Leaf? cutAt(int index) { assert(index >= 0 && index <= length); - Leaf? cut = splitAt(index); + final cut = splitAt(index); cut?.unlink(); return cut; } @@ -138,9 +139,9 @@ abstract class Leaf extends Node { } assert(this is Text); - String text = _value as String; + final text = _value as String; _value = text.substring(0, index); - Leaf split = Leaf(text.substring(index)); + final split = Leaf(text.substring(index)); split.applyStyle(style); insertAfter(split); return split; @@ -157,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)!; + final 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 ceb95801..7dba241f 100644 --- a/lib/models/documents/nodes/line.dart +++ b/lib/models/documents/nodes/line.dart @@ -47,7 +47,7 @@ class Line extends Container { .fold(Delta(), (dynamic a, b) => a.concat(b)); var attributes = style; if (parent is Block) { - Block block = parent as Block; + final block = parent as Block; attributes = attributes.mergeAll(block.style); } delta.insert('\n', attributes.toJson()); @@ -71,20 +71,20 @@ class Line extends Container { return; } - String text = data as String; - int lineBreak = text.indexOf('\n'); + final text = data as String; + final lineBreak = text.indexOf('\n'); if (lineBreak < 0) { _insert(index, text, style); return; } - String prefix = text.substring(0, lineBreak); + final prefix = text.substring(0, lineBreak); _insert(index, prefix, style); if (prefix.isNotEmpty) { index += prefix.length; } - Line nextLine = _getNextLine(index); + final nextLine = _getNextLine(index); clearStyle(); @@ -95,7 +95,7 @@ class Line extends Container { _format(style); // Continue with the remaining - String remain = text.substring(lineBreak + 1); + final remain = text.substring(lineBreak + 1); nextLine.insert(0, remain, style); } @@ -104,9 +104,9 @@ class Line extends Container { if (style == null) { return; } - int thisLen = length; + final thisLen = length; - int local = math.min(thisLen - index, len!); + final local = math.min(thisLen - index, len!); if (index + local == thisLen && local == 1) { assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK)); @@ -117,7 +117,7 @@ class Line extends Container { super.retain(index, local, style); } - int remain = len - local; + final remain = len - local; if (remain > 0) { assert(nextLine != null); nextLine!.retain(0, remain, style); @@ -126,8 +126,8 @@ class Line extends Container { @override void delete(int index, int? len) { - int local = math.min(length - index, len!); - bool deleted = index + local == length; + final local = math.min(length - index, len!); + final deleted = index + local == length; if (deleted) { clearStyle(); if (local > 1) { @@ -137,7 +137,7 @@ class Line extends Container { super.delete(index, local); } - int remain = len - local; + final remain = len - local; if (remain > 0) { assert(nextLine != null); nextLine!.delete(0, remain); @@ -150,7 +150,7 @@ class Line extends Container { } if (deleted) { - Node p = parent!; + final Node p = parent!; unlink(); p.adjust(); } @@ -162,24 +162,24 @@ class Line extends Container { } applyStyle(newStyle); - Attribute? blockStyle = newStyle.getBlockExceptHeader(); + final blockStyle = newStyle.getBlockExceptHeader(); if (blockStyle == null) { return; } if (parent is Block) { - Attribute? parentStyle = (parent as Block).style.getBlockExceptHeader(); + final parentStyle = (parent as Block).style.getBlockExceptHeader(); if (blockStyle.value == null) { _unwrap(); } else if (blockStyle != parentStyle) { _unwrap(); - Block block = Block(); + final block = Block(); block.applyAttribute(blockStyle); _wrap(block); block.adjust(); } } else if (blockStyle.value != null) { - Block block = Block(); + final block = Block(); block.applyAttribute(blockStyle); _wrap(block); block.adjust(); @@ -197,7 +197,7 @@ class Line extends Container { if (parent is! Block) { throw ArgumentError('Invalid parent'); } - Block block = parent as Block; + final block = parent as Block; assert(block.children.contains(this)); @@ -208,10 +208,10 @@ class Line extends Container { unlink(); block.insertAfter(this); } else { - Block before = block.clone() as Block; + final before = block.clone() as Block; block.insertBefore(before); - Line child = block.first as Line; + var child = block.first as Line; while (child != this) { child.unlink(); before.add(child); @@ -226,20 +226,20 @@ class Line extends Container { Line _getNextLine(int index) { assert(index == 0 || (index > 0 && index < length)); - Line line = clone() as Line; + final line = clone() as Line; insertAfter(line); if (index == length - 1) { return line; } - ChildQuery query = queryChild(index, false); + final query = queryChild(index, false); while (!query.node!.isLast) { - Leaf next = last as Leaf; + final next = last as Leaf; next.unlink(); line.addFirst(next); } - Leaf child = query.node as Leaf; - Leaf? cut = child.splitAt(query.offset); + final child = query.node as Leaf; + final cut = child.splitAt(query.offset); cut?.unlink(); line.addFirst(cut); return line; @@ -256,12 +256,12 @@ class Line extends Container { } if (isNotEmpty) { - ChildQuery result = queryChild(index, true); + final result = queryChild(index, true); result.node!.insert(result.offset, data, style); return; } - Leaf child = Leaf(data); + final child = Leaf(data); add(child); child.format(style); } @@ -272,30 +272,30 @@ class Line extends Container { } Style collectStyle(int offset, int len) { - int local = math.min(length - offset, len); - Style res = Style(); - var excluded = {}; + final local = math.min(length - offset, len); + var res = Style(); + final excluded = {}; void _handle(Style style) { if (res.isEmpty) { excluded.addAll(style.values); } else { - for (Attribute attr in res.values) { + for (final attr in res.values) { if (!style.containsKey(attr.key)) { excluded.add(attr); } } } - Style remain = style.removeAll(excluded); + final remain = style.removeAll(excluded); res = res.removeAll(excluded); res = res.mergeAll(remain); } - ChildQuery data = queryChild(offset, true); - Leaf? node = data.node as Leaf?; + final data = queryChild(offset, true); + var node = data.node as Leaf?; if (node != null) { res = res.mergeAll(node.style); - int pos = node.length - data.offset; + var pos = node.length - data.offset; while (!node!.isLast && pos < local) { node = node.next as Leaf?; _handle(node!.style); @@ -305,11 +305,11 @@ class Line extends Container { res = res.mergeAll(style); if (parent is Block) { - Block block = parent as Block; + final block = parent as Block; res = res.mergeAll(block.style); } - int remain = len - local; + final remain = len - local; if (remain > 0) { _handle(nextLine!.collectStyle(0, remain)); } diff --git a/lib/models/documents/nodes/node.dart b/lib/models/documents/nodes/node.dart index 2d694222..d46b4647 100644 --- a/lib/models/documents/nodes/node.dart +++ b/lib/models/documents/nodes/node.dart @@ -32,19 +32,19 @@ abstract class Node extends LinkedListEntry { int get length; Node clone() { - Node node = newInstance(); + final node = newInstance(); node.applyStyle(style); return node; } int getOffset() { - int offset = 0; + var offset = 0; if (list == null || isFirst) { return offset; } - Node cur = this; + var cur = this; do { cur = cur.previous!; offset += cur.length; diff --git a/lib/models/documents/style.dart b/lib/models/documents/style.dart index 90c03df0..4becc57e 100644 --- a/lib/models/documents/style.dart +++ b/lib/models/documents/style.dart @@ -16,8 +16,8 @@ class Style { return Style(); } - Map result = attributes.map((String key, dynamic value) { - Attribute attr = Attribute.fromKeyValue(key, value); + final result = attributes.map((String key, dynamic value) { + final attr = Attribute.fromKeyValue(key, value); return MapEntry(key, attr); }); return Style.attr(result); @@ -48,7 +48,7 @@ class Style { bool containsKey(String key) => _attributes.containsKey(key); Attribute? getBlockExceptHeader() { - for (Attribute val in values) { + for (final val in values) { if (val.isBlockExceptHeader) { return val; } @@ -57,7 +57,7 @@ class Style { } Style merge(Attribute attribute) { - Map merged = Map.from(_attributes); + final merged = Map.from(_attributes); if (attribute.value == null) { merged.remove(attribute.key); } else { @@ -67,21 +67,21 @@ class Style { } Style mergeAll(Style other) { - Style result = Style.attr(_attributes); - for (Attribute attribute in other.values) { + var result = Style.attr(_attributes); + for (final attribute in other.values) { result = result.merge(attribute); } return result; } Style removeAll(Set attributes) { - Map merged = Map.from(_attributes); + final merged = Map.from(_attributes); attributes.map((item) => item.key).forEach(merged.remove); return Style.attr(merged); } Style put(Attribute attribute) { - Map m = Map.from(attributes); + final m = Map.from(attributes); m[attribute.key] = attribute; return Style.attr(m); } @@ -94,7 +94,7 @@ class Style { if (other is! Style) { return false; } - Style typedOther = other; + final typedOther = other; final eq = const MapEquality(); return eq.equals(_attributes, typedOther._attributes); } diff --git a/lib/models/quill_delta.dart b/lib/models/quill_delta.dart index ddccb710..c8707ee0 100644 --- a/lib/models/quill_delta.dart +++ b/lib/models/quill_delta.dart @@ -135,7 +135,7 @@ class Operation { bool operator ==(other) { if (identical(this, other)) return true; if (other is! Operation) return false; - Operation typedOther = other; + final typedOther = other; return key == typedOther.key && length == typedOther.length && _valueEquality.equals(data, typedOther.data) && @@ -221,14 +221,14 @@ class Delta { attr ??= const {}; base ??= const {}; - var baseInverted = base.keys.fold({}, (dynamic memo, key) { + final baseInverted = base.keys.fold({}, (dynamic memo, key) { if (base![key] != attr![key] && attr.containsKey(key)) { memo[key] = base[key]; } return memo; }); - var inverted = + final inverted = Map.from(attr.keys.fold(baseInverted, (memo, key) { if (base![key] != attr![key] && !base.containsKey(key)) { memo[key] = null; @@ -292,7 +292,7 @@ class Delta { bool operator ==(dynamic other) { if (identical(this, other)) return true; if (other is! Delta) return false; - Delta typedOther = other; + final typedOther = other; final comparator = const ListEquality(DefaultEquality()); return comparator.equals(_operations, typedOther._operations); @@ -529,7 +529,8 @@ class Delta { if (op.isDelete) { inverted.push(baseOp); } else if (op.isRetain && op.isNotPlain) { - var invertAttr = invertAttributes(op.attributes, baseOp.attributes); + final invertAttr = + invertAttributes(op.attributes, baseOp.attributes); inverted.retain( baseOp.length!, invertAttr.isEmpty ? null : invertAttr); } @@ -548,7 +549,7 @@ class Delta { Delta slice(int start, [int? end]) { final delta = Delta(); var index = 0; - var opIterator = DeltaIterator(this); + final opIterator = DeltaIterator(this); final actualEnd = end ?? double.infinity; @@ -661,7 +662,7 @@ class DeltaIterator { 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 as int; + final opActualLength = opIsNotEmpty ? opLength : actualLength as int; return Operation._(opKey, opActualLength, opData, opAttributes); } return Operation.retain(length); diff --git a/lib/models/rules/delete.dart b/lib/models/rules/delete.dart index 535504d5..60cee64d 100644 --- a/lib/models/rules/delete.dart +++ b/lib/models/rules/delete.dart @@ -34,31 +34,31 @@ class PreserveLineStyleOnMergeRule extends DeleteRule { @override Delta? applyRule(Delta document, int index, {int? len, Object? data, Attribute? attribute}) { - DeltaIterator itr = DeltaIterator(document); + final itr = DeltaIterator(document); itr.skip(index); - Operation op = itr.next(1); + var op = itr.next(1); if (op.data != '\n') { return null; } - bool isNotPlain = op.isNotPlain; - Map? attrs = op.attributes; + final isNotPlain = op.isNotPlain; + final attrs = op.attributes; itr.skip(len! - 1); - Delta delta = Delta() + final delta = Delta() ..retain(index) ..delete(len); while (itr.hasNext) { op = itr.next(); - String text = op.data is String ? (op.data as String?)! : ''; - int lineBreak = text.indexOf('\n'); + final text = op.data is String ? (op.data as String?)! : ''; + final lineBreak = text.indexOf('\n'); if (lineBreak == -1) { delta.retain(op.length!); continue; } - Map? attributes = op.attributes == null + var attributes = op.attributes == null ? null : op.attributes!.map((String key, dynamic value) => MapEntry(key, null)); @@ -80,15 +80,15 @@ class EnsureEmbedLineRule extends DeleteRule { @override Delta? applyRule(Delta document, int index, {int? len, Object? data, Attribute? attribute}) { - DeltaIterator itr = DeltaIterator(document); + final itr = DeltaIterator(document); - Operation? op = itr.skip(index); + var op = itr.skip(index); int? indexDelta = 0, lengthDelta = 0, remain = len; - bool embedFound = op != null && op.data is! String; - bool hasLineBreakBefore = + var embedFound = op != null && op.data is! String; + final hasLineBreakBefore = !embedFound && (op == null || (op.data as String).endsWith('\n')); if (embedFound) { - Operation candidate = itr.next(1); + var candidate = itr.next(1); if (remain != null) { remain--; if (candidate.data == '\n') { @@ -107,7 +107,7 @@ class EnsureEmbedLineRule extends DeleteRule { op = itr.skip(remain!); if (op != null && (op.data is String ? op.data as String? : '')!.endsWith('\n')) { - Operation candidate = itr.next(1); + final candidate = itr.next(1); if (candidate.data is! String && !hasLineBreakBefore) { embedFound = true; lengthDelta--; diff --git a/lib/models/rules/format.dart b/lib/models/rules/format.dart index 0d574c94..470ca200 100644 --- a/lib/models/rules/format.dart +++ b/lib/models/rules/format.dart @@ -26,21 +26,21 @@ class ResolveLineFormatRule extends FormatRule { return null; } - Delta delta = Delta()..retain(index); - DeltaIterator itr = DeltaIterator(document); + var delta = Delta()..retain(index); + final itr = DeltaIterator(document); itr.skip(index); Operation op; - for (int cur = 0; cur < len! && itr.hasNext; cur += op.length!) { + for (var 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!); continue; } - String text = op.data as String; - Delta tmp = Delta(); - int offset = 0; + final text = op.data as String; + final tmp = Delta(); + var offset = 0; - for (int lineBreak = text.indexOf('\n'); + for (var lineBreak = text.indexOf('\n'); lineBreak >= 0; lineBreak = text.indexOf('\n', offset)) { tmp..retain(lineBreak - offset)..retain(1, attribute.toJson()); @@ -52,8 +52,8 @@ class ResolveLineFormatRule extends FormatRule { while (itr.hasNext) { op = itr.next(); - String text = op.data is String ? (op.data as String?)! : ''; - int lineBreak = text.indexOf('\n'); + final text = op.data is String ? (op.data as String?)! : ''; + final lineBreak = text.indexOf('\n'); if (lineBreak < 0) { delta.retain(op.length!); continue; @@ -75,9 +75,9 @@ class FormatLinkAtCaretPositionRule extends FormatRule { return null; } - Delta delta = Delta(); - DeltaIterator itr = DeltaIterator(document); - Operation? before = itr.skip(index), after = itr.next(); + final delta = Delta(); + final itr = DeltaIterator(document); + final before = itr.skip(index), after = itr.next(); int? beg = index, retain = 0; if (before != null && before.hasAttribute(attribute.key)) { beg -= before.length!; @@ -105,20 +105,20 @@ class ResolveInlineFormatRule extends FormatRule { return null; } - Delta delta = Delta()..retain(index); - DeltaIterator itr = DeltaIterator(document); + final delta = Delta()..retain(index); + final itr = DeltaIterator(document); itr.skip(index); Operation op; - for (int cur = 0; cur < len! && itr.hasNext; cur += op.length!) { + for (var cur = 0; cur < len! && itr.hasNext; cur += op.length!) { op = itr.next(len - cur); - String text = op.data is String ? (op.data as String?)! : ''; - int lineBreak = text.indexOf('\n'); + final text = op.data is String ? (op.data as String?)! : ''; + var lineBreak = text.indexOf('\n'); if (lineBreak < 0) { delta.retain(op.length!, attribute.toJson()); continue; } - int pos = 0; + var pos = 0; while (lineBreak >= 0) { delta..retain(lineBreak - pos, attribute.toJson())..retain(1); pos = lineBreak + 1; diff --git a/lib/models/rules/insert.dart b/lib/models/rules/insert.dart index f0f7d001..97f386d5 100644 --- a/lib/models/rules/insert.dart +++ b/lib/models/rules/insert.dart @@ -29,28 +29,28 @@ class PreserveLineStyleOnSplitRule extends InsertRule { return null; } - DeltaIterator itr = DeltaIterator(document); - Operation? before = itr.skip(index); + final itr = DeltaIterator(document); + final before = itr.skip(index); if (before == null || before.data is! String || (before.data as String).endsWith('\n')) { return null; } - Operation after = itr.next(); + final after = itr.next(); if (after.data is! String || (after.data as String).startsWith('\n')) { return null; } final text = after.data as String; - Delta delta = Delta()..retain(index); + final delta = Delta()..retain(index); if (text.contains('\n')) { assert(after.isPlain); delta.insert('\n'); return delta; } - Tuple2 nextNewLine = _getNextNewLine(itr); - Map? attributes = nextNewLine.item1?.attributes; + final nextNewLine = _getNextNewLine(itr); + final attributes = nextNewLine.item1?.attributes; return delta..insert('\n', attributes); } @@ -66,19 +66,19 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { return null; } - DeltaIterator itr = DeltaIterator(document); + final itr = DeltaIterator(document); itr.skip(index); - Tuple2 nextNewLine = _getNextNewLine(itr); - Style lineStyle = + final nextNewLine = _getNextNewLine(itr); + final lineStyle = Style.fromJson(nextNewLine.item1?.attributes ?? {}); - Attribute? attribute = lineStyle.getBlockExceptHeader(); + final attribute = lineStyle.getBlockExceptHeader(); if (attribute == null) { return null; } - var blockStyle = {attribute.key: attribute.value}; + final blockStyle = {attribute.key: attribute.value}; Map? resetStyle; @@ -86,10 +86,10 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { resetStyle = Attribute.header.toJson(); } - List lines = data.split('\n'); - Delta delta = Delta()..retain(index); - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; + final lines = data.split('\n'); + final delta = Delta()..retain(index); + for (var i = 0; i < lines.length; i++) { + final line = lines[i]; if (line.isNotEmpty) { delta.insert(line); } @@ -131,10 +131,9 @@ class AutoExitBlockRule extends InsertRule { return null; } - DeltaIterator itr = DeltaIterator(document); - Operation? prev = itr.skip(index), cur = itr.next(); - Attribute? blockStyle = - Style.fromJson(cur.attributes).getBlockExceptHeader(); + final itr = DeltaIterator(document); + final prev = itr.skip(index), cur = itr.next(); + final blockStyle = Style.fromJson(cur.attributes).getBlockExceptHeader(); if (cur.isPlain || blockStyle == null) { return null; } @@ -146,7 +145,7 @@ class AutoExitBlockRule extends InsertRule { return null; } - Tuple2 nextNewLine = _getNextNewLine(itr); + final nextNewLine = _getNextNewLine(itr); if (nextNewLine.item1 != null && nextNewLine.item1!.attributes != null && Style.fromJson(nextNewLine.item1!.attributes).getBlockExceptHeader() == @@ -155,7 +154,7 @@ class AutoExitBlockRule extends InsertRule { } final attributes = cur.attributes ?? {}; - String k = attributes.keys + final k = attributes.keys .firstWhere((k) => Attribute.blockKeysExceptHeader.contains(k)); attributes[k] = null; // retain(1) should be '\n', set it with no attribute @@ -173,9 +172,9 @@ class ResetLineFormatOnNewLineRule extends InsertRule { return null; } - DeltaIterator itr = DeltaIterator(document); + final itr = DeltaIterator(document); itr.skip(index); - Operation cur = itr.next(); + final cur = itr.next(); if (cur.data is! String || !(cur.data as String).startsWith('\n')) { return null; } @@ -203,12 +202,12 @@ class InsertEmbedsRule extends InsertRule { return null; } - Delta delta = Delta()..retain(index); - DeltaIterator itr = DeltaIterator(document); - Operation? prev = itr.skip(index), cur = itr.next(); + final delta = Delta()..retain(index); + final itr = DeltaIterator(document); + final 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?)! : ''; + final textBefore = prev?.data is String ? prev!.data as String? : ''; + final textAfter = cur.data is String ? (cur.data as String?)! : ''; final isNewlineBefore = prev == null || textBefore!.endsWith('\n'); final isNewlineAfter = textAfter.startsWith('\n'); @@ -222,7 +221,7 @@ class InsertEmbedsRule extends InsertRule { lineStyle = cur.attributes; } else { while (itr.hasNext) { - Operation op = itr.next(); + final op = itr.next(); if ((op.data is String ? op.data as String? : '')!.contains('\n')) { lineStyle = op.attributes; break; @@ -251,17 +250,17 @@ class ForceNewlineForInsertsAroundEmbedRule extends InsertRule { return null; } - String text = data; - DeltaIterator itr = DeltaIterator(document); + final text = data; + final itr = DeltaIterator(document); final prev = itr.skip(index); final cur = itr.next(); - bool cursorBeforeEmbed = cur.data is! String; - bool cursorAfterEmbed = prev != null && prev.data is! String; + final cursorBeforeEmbed = cur.data is! String; + final cursorAfterEmbed = prev != null && prev.data is! String; if (!cursorBeforeEmbed && !cursorAfterEmbed) { return null; } - Delta delta = Delta()..retain(index); + final delta = Delta()..retain(index); if (cursorBeforeEmbed && !text.endsWith('\n')) { return delta..insert(text)..insert('\n'); } @@ -282,19 +281,19 @@ class AutoFormatLinksRule extends InsertRule { return null; } - DeltaIterator itr = DeltaIterator(document); - Operation? prev = itr.skip(index); + final itr = DeltaIterator(document); + final prev = itr.skip(index); if (prev == null || prev.data is! String) { return null; } try { - String cand = (prev.data as String).split('\n').last.split(' ').last; - Uri link = Uri.parse(cand); + final cand = (prev.data as String).split('\n').last.split(' ').last; + final link = Uri.parse(cand); if (!['https', 'http'].contains(link.scheme)) { return null; } - Map attributes = prev.attributes ?? {}; + final attributes = prev.attributes ?? {}; if (attributes.containsKey(Attribute.link.key)) { return null; @@ -321,16 +320,16 @@ class PreserveInlineStylesRule extends InsertRule { return null; } - DeltaIterator itr = DeltaIterator(document); - Operation? prev = itr.skip(index); + final itr = DeltaIterator(document); + final 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; + final attributes = prev.attributes; + final text = data; if (attributes == null || !attributes.containsKey(Attribute.link.key)) { return Delta() ..retain(index) @@ -338,13 +337,12 @@ class PreserveInlineStylesRule extends InsertRule { } attributes.remove(Attribute.link.key); - Delta delta = Delta() + final delta = Delta() ..retain(index) ..insert(text, attributes.isEmpty ? null : attributes); - Operation next = itr.next(); + final next = itr.next(); - Map nextAttributes = - next.attributes ?? const {}; + final nextAttributes = next.attributes ?? const {}; if (!nextAttributes.containsKey(Attribute.link.key)) { return delta; } @@ -371,9 +369,9 @@ class CatchAllInsertRule extends InsertRule { Tuple2 _getNextNewLine(DeltaIterator iterator) { Operation op; - for (int skipped = 0; iterator.hasNext; skipped += op.length!) { + for (var skipped = 0; iterator.hasNext; skipped += op.length!) { op = iterator.next(); - int lineBreak = + final 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 23eb3b9d..19bc9177 100644 --- a/lib/models/rules/rule.dart +++ b/lib/models/rules/rule.dart @@ -52,7 +52,7 @@ class Rules { Delta apply(RuleType ruleType, Document document, int index, {int? len, Object? data, Attribute? attribute}) { final delta = document.toDelta(); - for (var rule in _rules) { + for (final rule in _rules) { if (rule.type != ruleType) { continue; } diff --git a/lib/utils/color.dart b/lib/utils/color.dart index 4e206644..f4c26040 100644 --- a/lib/utils/color.dart +++ b/lib/utils/color.dart @@ -118,8 +118,8 @@ Color stringToColor(String? s) { throw 'Color code not supported'; } - String hex = s.replaceFirst('#', ''); + var hex = s.replaceFirst('#', ''); hex = hex.length == 6 ? 'ff' + hex : hex; - int val = int.parse(hex, radix: 16); + final val = int.parse(hex, radix: 16); return Color(val); } diff --git a/lib/utils/diff_delta.dart b/lib/utils/diff_delta.dart index d3b97116..a3653eb0 100644 --- a/lib/utils/diff_delta.dart +++ b/lib/utils/diff_delta.dart @@ -52,17 +52,17 @@ class Diff { /* Get diff operation between old text and new text */ Diff getDiff(String oldText, String newText, int cursorPosition) { - int end = oldText.length; - int delta = newText.length - end; - for (int limit = math.max(0, cursorPosition - delta); + var end = oldText.length; + final delta = newText.length - end; + for (final limit = math.max(0, cursorPosition - delta); end > limit && oldText[end - 1] == newText[end + delta - 1]; end--) {} - int start = 0; - for (int startLimit = cursorPosition - math.max(0, delta); + var start = 0; + for (final startLimit = cursorPosition - math.max(0, delta); start < startLimit && oldText[start] == newText[start]; start++) {} - String deleted = (start >= end) ? '' : oldText.substring(start, end); - String inserted = newText.substring(start, end + delta); + final deleted = (start >= end) ? '' : oldText.substring(start, end); + final inserted = newText.substring(start, end + delta); return Diff(start, deleted, inserted); } @@ -71,13 +71,13 @@ int getPositionDelta(Delta user, Delta actual) { return 0; } - DeltaIterator userItr = DeltaIterator(user); - DeltaIterator actualItr = DeltaIterator(actual); - int diff = 0; + final userItr = DeltaIterator(user); + final actualItr = DeltaIterator(actual); + var diff = 0; while (userItr.hasNext || actualItr.hasNext) { final length = math.min(userItr.peekLength(), actualItr.peekLength()); - Operation userOperation = userItr.next(length as int); - Operation actualOperation = actualItr.next(length); + final userOperation = userItr.next(length as int); + final actualOperation = actualItr.next(length); if (userOperation.length != actualOperation.length) { throw 'userOp ' + userOperation.length.toString() + diff --git a/lib/widgets/controller.dart b/lib/widgets/controller.dart index 510db24c..faabf4c2 100644 --- a/lib/widgets/controller.dart +++ b/lib/widgets/controller.dart @@ -43,7 +43,7 @@ class QuillController extends ChangeNotifier { } void undo() { - Tuple2 tup = document.undo(); + final tup = document.undo(); if (tup.item1) { _handleHistoryChange(tup.item2); } @@ -65,7 +65,7 @@ class QuillController extends ChangeNotifier { } void redo() { - Tuple2 tup = document.redo(); + final tup = document.redo(); if (tup.item1) { _handleHistoryChange(tup.item2); } @@ -82,7 +82,7 @@ class QuillController extends ChangeNotifier { Delta? delta; if (len > 0 || data is! String || data.isNotEmpty) { delta = document.replace(index, len, data); - bool shouldRetainDelta = toggledStyle.isNotEmpty && + var shouldRetainDelta = toggledStyle.isNotEmpty && delta.isNotEmpty && delta.length <= 2 && delta.last.isInsert; @@ -98,7 +98,7 @@ class QuillController extends ChangeNotifier { } } if (shouldRetainDelta) { - Delta retainDelta = Delta() + final retainDelta = Delta() ..retain(index) ..retain(data is String ? data.length : 1, toggledStyle.toJson()); document.compose(retainDelta, ChangeSource.LOCAL); @@ -110,11 +110,11 @@ class QuillController extends ChangeNotifier { if (delta == null || delta.isEmpty) { _updateSelection(textSelection, ChangeSource.LOCAL); } else { - Delta user = Delta() + final user = Delta() ..retain(index) ..insert(data) ..delete(len); - int positionDelta = getPositionDelta(user, delta); + final positionDelta = getPositionDelta(user, delta); _updateSelection( textSelection.copyWith( baseOffset: textSelection.baseOffset + positionDelta, @@ -134,8 +134,8 @@ class QuillController extends ChangeNotifier { toggledStyle = toggledStyle.put(attribute); } - Delta change = document.format(index, len, attribute); - TextSelection adjustedSelection = selection.copyWith( + final change = document.format(index, len, attribute); + final adjustedSelection = selection.copyWith( baseOffset: change.transformPosition(selection.baseOffset), extentOffset: change.transformPosition(selection.extentOffset)); if (selection != adjustedSelection) { @@ -177,7 +177,7 @@ class QuillController extends ChangeNotifier { void _updateSelection(TextSelection textSelection, ChangeSource source) { selection = textSelection; - int end = document.length - 1; + final end = document.length - 1; selection = selection.copyWith( baseOffset: math.min(selection.baseOffset, end), extentOffset: math.min(selection.extentOffset, end)); diff --git a/lib/widgets/cursor.dart b/lib/widgets/cursor.dart index 4195d947..8a22c7c2 100644 --- a/lib/widgets/cursor.dart +++ b/lib/widgets/cursor.dart @@ -99,7 +99,7 @@ class CursorCont extends ChangeNotifier { void _cursorTick(Timer timer) { _targetCursorVisibility = !_targetCursorVisibility; - double targetOpacity = _targetCursorVisibility ? 1.0 : 0.0; + final targetOpacity = _targetCursorVisibility ? 1.0 : 0.0; if (style.opacityAnimates) { _blinkOpacityCont.animateTo(targetOpacity, curve: Curves.easeOut); } else { @@ -168,9 +168,9 @@ class CursorPainter { void paint(Canvas canvas, Offset offset, TextPosition position) { assert(prototype != null); - Offset caretOffset = + final caretOffset = editable!.getOffsetForCaret(position, prototype) + offset; - Rect caretRect = prototype!.shift(caretOffset); + var caretRect = prototype!.shift(caretOffset); if (style.offset != null) { caretRect = caretRect.shift(style.offset!); } @@ -179,7 +179,7 @@ class CursorPainter { caretRect = caretRect.shift(Offset(-caretRect.left, 0.0)); } - double? caretHeight = editable!.getFullHeightForCaret(position); + final caretHeight = editable!.getFullHeightForCaret(position); if (caretHeight != null) { switch (defaultTargetPlatform) { case TargetPlatform.android: @@ -207,8 +207,8 @@ class CursorPainter { } } - Offset caretPosition = editable!.localToGlobal(caretRect.topLeft); - double pixelMultiple = 1.0 / devicePixelRatio; + final caretPosition = editable!.localToGlobal(caretRect.topLeft); + final pixelMultiple = 1.0 / devicePixelRatio; caretRect = caretRect.shift(Offset( caretPosition.dx.isFinite ? (caretPosition.dx / pixelMultiple).round() * pixelMultiple - @@ -219,13 +219,13 @@ class CursorPainter { caretPosition.dy : caretPosition.dy)); - Paint paint = Paint()..color = color; + final paint = Paint()..color = color; if (style.radius == null) { canvas.drawRect(caretRect, paint); return; } - RRect caretRRect = RRect.fromRectAndRadius(caretRect, style.radius!); + final 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 9490bebd..7f908114 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -17,7 +17,7 @@ class QuillStyles extends InheritedWidget { } static DefaultStyles? getStyles(BuildContext context, bool nullOk) { - var widget = context.dependOnInheritedWidgetOfExactType(); + final widget = context.dependOnInheritedWidgetOfExactType(); if (widget == null && nullOk) { return null; } @@ -84,13 +84,13 @@ class DefaultStyles { this.sizeHuge}); static DefaultStyles getInstance(BuildContext context) { - ThemeData themeData = Theme.of(context); - DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context); - TextStyle baseStyle = defaultTextStyle.style.copyWith( + final themeData = Theme.of(context); + final defaultTextStyle = DefaultTextStyle.of(context); + final baseStyle = defaultTextStyle.style.copyWith( fontSize: 16.0, height: 1.3, ); - Tuple2 baseSpacing = const Tuple2(6.0, 0); + final baseSpacing = const Tuple2(6.0, 0); String fontFamily; switch (themeData.platform) { case TargetPlatform.iOS: diff --git a/lib/widgets/delegate.dart b/lib/widgets/delegate.dart index f134a77e..8adf8ce7 100644 --- a/lib/widgets/delegate.dart +++ b/lib/widgets/delegate.dart @@ -34,7 +34,7 @@ class EditorTextSelectionGestureDetectorBuilder { void onTapDown(TapDownDetails details) { getRenderEditor()!.handleTapDown(details); - PointerDeviceKind? kind = details.kind; + final kind = details.kind; shouldShowSelectionToolbar = kind == null || kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus; diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 654daf1e..c3f24d98 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -17,7 +17,6 @@ import '../models/documents/nodes/container.dart' as container_node; import '../models/documents/nodes/embed.dart'; import '../models/documents/nodes/leaf.dart' as leaf; import '../models/documents/nodes/line.dart'; -import '../models/documents/nodes/node.dart'; import 'box.dart'; import 'controller.dart'; import 'cursor.dart'; @@ -100,7 +99,7 @@ Widget _defaultEmbedBuilder(BuildContext context, leaf.Embed node) { assert(!kIsWeb, 'Please provide EmbedBuilder for Web'); switch (node.value.type) { case 'image': - String imageUrl = _standardizeImageUrl(node.value.data); + final imageUrl = _standardizeImageUrl(node.value.data); return imageUrl.startsWith('http') ? Image.network(imageUrl) : isBase64(imageUrl) @@ -188,8 +187,8 @@ class _QuillEditorState extends State @override Widget build(BuildContext context) { - ThemeData theme = Theme.of(context); - TextSelectionThemeData selectionTheme = TextSelectionTheme.of(context); + final theme = Theme.of(context); + final selectionTheme = TextSelectionTheme.of(context); TextSelectionControls textSelectionControls; bool paintCursorAboveText; @@ -213,7 +212,7 @@ class _QuillEditorState extends State break; case TargetPlatform.iOS: case TargetPlatform.macOS: - CupertinoThemeData cupertinoTheme = CupertinoTheme.of(context); + final cupertinoTheme = CupertinoTheme.of(context); textSelectionControls = cupertinoTextSelectionControls; paintCursorAboveText = true; cursorOpacityAnimates = true; @@ -344,16 +343,14 @@ class _QuillEditorSelectionGestureDetectorBuilder if (_state.widget.controller.document.isEmpty()) { return false; } - TextPosition pos = - getRenderEditor()!.getPositionForOffset(details.globalPosition); - container_node.ChildQuery result = + final pos = getRenderEditor()!.getPositionForOffset(details.globalPosition); + final result = getEditor()!.widget.controller.document.queryChild(pos.offset); if (result.node == null) { return false; } - Line line = result.node as Line; - container_node.ChildQuery segmentResult = - line.queryChild(result.offset, false); + final line = result.node as Line; + final segmentResult = line.queryChild(result.offset, false); if (segmentResult.node == null) { if (line.length == 1) { // tapping when no text yet on this line @@ -364,7 +361,7 @@ class _QuillEditorSelectionGestureDetectorBuilder } return false; } - leaf.Leaf segment = segmentResult.node as leaf.Leaf; + final segment = segmentResult.node as leaf.Leaf; if (segment.style.containsKey(Attribute.link.key)) { var launchUrl = getEditor()!.widget.onLaunchUrl; launchUrl ??= _launchUrl; @@ -380,9 +377,9 @@ class _QuillEditorSelectionGestureDetectorBuilder return false; } if (getEditor()!.widget.readOnly && segment.value is BlockEmbed) { - BlockEmbed blockEmbed = segment.value as BlockEmbed; + final blockEmbed = segment.value as BlockEmbed; if (blockEmbed.type == 'image') { - final String imageUrl = _standardizeImageUrl(blockEmbed.data); + final imageUrl = _standardizeImageUrl(blockEmbed.data); Navigator.push( getEditor()!.context, MaterialPageRoute( @@ -413,7 +410,7 @@ class _QuillEditorSelectionGestureDetectorBuilder return false; } // segmentResult.offset == 0 means tap at the beginning of the TextLine - String? listVal = line.style.attributes[Attribute.list.key]!.value; + final String? listVal = line.style.attributes[Attribute.list.key]!.value; if (listVal == Attribute.unchecked.value) { getEditor()! .widget @@ -438,7 +435,7 @@ class _QuillEditorSelectionGestureDetectorBuilder void onSingleTapUp(TapUpDetails details) { getEditor()!.hideToolbar(); - bool positionSelected = _onTapping(details); + final positionSelected = _onTapping(details); if (delegate.getSelectionEnabled() && !positionSelected) { switch (Theme.of(_state.context).platform) { @@ -575,12 +572,12 @@ class RenderEditor extends RenderEditableContainerBox List getEndpointsForSelection( TextSelection textSelection) { if (textSelection.isCollapsed) { - RenderEditableBox child = childAtPosition(textSelection.extent); - TextPosition localPosition = TextPosition( + final child = childAtPosition(textSelection.extent); + final localPosition = TextPosition( offset: textSelection.extentOffset - child.getContainer().getOffset()); - Offset localOffset = child.getOffsetForCaret(localPosition); - BoxParentData parentData = child.parentData as BoxParentData; + final localOffset = child.getOffsetForCaret(localPosition); + final parentData = child.parentData as BoxParentData; return [ TextSelectionPoint( Offset(0.0, child.preferredLineHeight(localPosition)) + @@ -590,7 +587,7 @@ class RenderEditor extends RenderEditableContainerBox ]; } - Node? baseNode = _container.queryChild(textSelection.start, false).node; + final baseNode = _container.queryChild(textSelection.start, false).node; var baseChild = firstChild; while (baseChild != null) { @@ -601,15 +598,14 @@ class RenderEditor extends RenderEditableContainerBox } assert(baseChild != null); - BoxParentData baseParentData = baseChild!.parentData as BoxParentData; - TextSelection baseSelection = + final baseParentData = baseChild!.parentData as BoxParentData; + final baseSelection = localSelection(baseChild.getContainer(), textSelection, true); - TextSelectionPoint basePoint = - baseChild.getBaseEndpointForSelection(baseSelection); + var basePoint = baseChild.getBaseEndpointForSelection(baseSelection); basePoint = TextSelectionPoint( basePoint.point + baseParentData.offset, basePoint.direction); - Node? extentNode = _container.queryChild(textSelection.end, false).node; + final extentNode = _container.queryChild(textSelection.end, false).node; RenderEditableBox? extentChild = baseChild; while (extentChild != null) { if (extentChild.getContainer() == extentNode) { @@ -619,10 +615,10 @@ class RenderEditor extends RenderEditableContainerBox } assert(extentChild != null); - BoxParentData extentParentData = extentChild!.parentData as BoxParentData; - TextSelection extentSelection = + final extentParentData = extentChild!.parentData as BoxParentData; + final extentSelection = localSelection(extentChild.getContainer(), textSelection, true); - TextSelectionPoint extentPoint = + var extentPoint = extentChild.getExtentEndpointForSelection(extentSelection); extentPoint = TextSelectionPoint( extentPoint.point + extentParentData.offset, extentPoint.direction); @@ -643,9 +639,9 @@ class RenderEditor extends RenderEditableContainerBox Offset? to, SelectionChangedCause cause, ) { - TextPosition firstPosition = getPositionForOffset(from); - TextSelection firstWord = selectWordAtPosition(firstPosition); - TextSelection lastWord = + final firstPosition = getPositionForOffset(from); + final firstWord = selectWordAtPosition(firstPosition); + final lastWord = to == null ? firstWord : selectWordAtPosition(getPositionForOffset(to)); _handleSelectionChange( @@ -662,7 +658,7 @@ class RenderEditor extends RenderEditableContainerBox TextSelection nextSelection, SelectionChangedCause cause, ) { - bool focusingEmpty = nextSelection.baseOffset == 0 && + final focusingEmpty = nextSelection.baseOffset == 0 && nextSelection.extentOffset == 0 && !_hasFocus; if (nextSelection == selection && @@ -676,15 +672,15 @@ class RenderEditor extends RenderEditableContainerBox @override void selectWordEdge(SelectionChangedCause cause) { assert(_lastTapDownPosition != null); - TextPosition position = getPositionForOffset(_lastTapDownPosition!); - RenderEditableBox child = childAtPosition(position); - int nodeOffset = child.getContainer().getOffset(); - TextPosition localPosition = TextPosition( + final position = getPositionForOffset(_lastTapDownPosition!); + final child = childAtPosition(position); + final nodeOffset = child.getContainer().getOffset(); + final localPosition = TextPosition( offset: position.offset - nodeOffset, affinity: position.affinity, ); - TextRange localWord = child.getWordBoundary(localPosition); - TextRange word = TextRange( + final localWord = child.getWordBoundary(localPosition); + final word = TextRange( start: localWord.start + nodeOffset, end: localWord.end + nodeOffset, ); @@ -708,17 +704,17 @@ class RenderEditor extends RenderEditableContainerBox Offset? to, SelectionChangedCause cause, ) { - TextPosition fromPosition = getPositionForOffset(from); - TextPosition? toPosition = to == null ? null : getPositionForOffset(to); + final fromPosition = getPositionForOffset(from); + final toPosition = to == null ? null : getPositionForOffset(to); - int baseOffset = fromPosition.offset; - int extentOffset = fromPosition.offset; + var baseOffset = fromPosition.offset; + var extentOffset = fromPosition.offset; if (toPosition != null) { baseOffset = math.min(fromPosition.offset, toPosition.offset); extentOffset = math.max(fromPosition.offset, toPosition.offset); } - TextSelection newSelection = TextSelection( + final newSelection = TextSelection( baseOffset: baseOffset, extentOffset: extentOffset, affinity: fromPosition.affinity, @@ -738,12 +734,12 @@ class RenderEditor extends RenderEditableContainerBox @override TextSelection selectWordAtPosition(TextPosition position) { - RenderEditableBox child = childAtPosition(position); - int nodeOffset = child.getContainer().getOffset(); - TextPosition localPosition = TextPosition( + final child = childAtPosition(position); + final nodeOffset = child.getContainer().getOffset(); + final localPosition = TextPosition( offset: position.offset - nodeOffset, affinity: position.affinity); - TextRange localWord = child.getWordBoundary(localPosition); - TextRange word = TextRange( + final localWord = child.getWordBoundary(localPosition); + final word = TextRange( start: localWord.start + nodeOffset, end: localWord.end + nodeOffset, ); @@ -755,12 +751,12 @@ class RenderEditor extends RenderEditableContainerBox @override TextSelection selectLineAtPosition(TextPosition position) { - RenderEditableBox child = childAtPosition(position); - int nodeOffset = child.getContainer().getOffset(); - TextPosition localPosition = TextPosition( + final child = childAtPosition(position); + final nodeOffset = child.getContainer().getOffset(); + final localPosition = TextPosition( offset: position.offset - nodeOffset, affinity: position.affinity); - TextRange localLineRange = child.getLineBoundary(localPosition); - TextRange line = TextRange( + final localLineRange = child.getLineBoundary(localPosition); + final line = TextRange( start: localLineRange.start + nodeOffset, end: localLineRange.end + nodeOffset, ); @@ -810,19 +806,19 @@ class RenderEditor extends RenderEditableContainerBox @override double preferredLineHeight(TextPosition position) { - RenderEditableBox child = childAtPosition(position); + final child = childAtPosition(position); return child.preferredLineHeight(TextPosition( offset: position.offset - child.getContainer().getOffset())); } @override TextPosition getPositionForOffset(Offset offset) { - Offset local = globalToLocal(offset); - RenderEditableBox child = childAtOffset(local)!; + final local = globalToLocal(offset); + final child = childAtOffset(local)!; - BoxParentData parentData = child.parentData as BoxParentData; - Offset localOffset = local - parentData.offset; - TextPosition localPosition = child.getPositionForOffset(localOffset); + final parentData = child.parentData as BoxParentData; + final localOffset = local - parentData.offset; + final localPosition = child.getPositionForOffset(localOffset); return TextPosition( offset: localPosition.offset + child.getContainer().getOffset(), affinity: localPosition.affinity, @@ -836,12 +832,12 @@ class RenderEditor extends RenderEditableContainerBox /// Returns null if [selection] is already visible. double? getOffsetToRevealCursor( double viewportHeight, double scrollOffset, double offsetInViewport) { - List endpoints = getEndpointsForSelection(selection); - TextSelectionPoint endpoint = endpoints.first; - RenderEditableBox child = childAtPosition(selection.extent); + final endpoints = getEndpointsForSelection(selection); + final endpoint = endpoints.first; + final child = childAtPosition(selection.extent); const kMargin = 8.0; - double caretTop = endpoint.point.dy - + final caretTop = endpoint.point.dy - child.preferredLineHeight(TextPosition( offset: selection.extentOffset - child.getContainer().getOffset())) - @@ -919,7 +915,7 @@ class RenderEditableContainerBox extends RenderBox RenderEditableBox childAtPosition(TextPosition position) { assert(firstChild != null); - Node? targetNode = _container.queryChild(position.offset, false).node; + final targetNode = _container.queryChild(position.offset, false).node; var targetChild = firstChild; while (targetChild != null) { @@ -951,7 +947,8 @@ class RenderEditableContainerBox extends RenderBox } var child = firstChild; - double dx = -offset.dx, dy = _resolvedPadding!.top; + final dx = -offset.dx; + var dy = _resolvedPadding!.top; while (child != null) { if (child.size.contains(offset.translate(dx, -dy))) { return child; @@ -978,15 +975,14 @@ class RenderEditableContainerBox extends RenderBox _resolvePadding(); assert(_resolvedPadding != null); - double mainAxisExtent = _resolvedPadding!.top; + var mainAxisExtent = _resolvedPadding!.top; var child = firstChild; - BoxConstraints innerConstraints = + final innerConstraints = BoxConstraints.tightFor(width: constraints.maxWidth) .deflate(_resolvedPadding!); while (child != null) { child.layout(innerConstraints, parentUsesSize: true); - final EditableContainerParentData childParentData = - child.parentData as EditableContainerParentData; + final childParentData = child.parentData as EditableContainerParentData; childParentData.offset = Offset(_resolvedPadding!.left, mainAxisExtent); mainAxisExtent += child.size.height; assert(child.parentData == childParentData); @@ -999,24 +995,22 @@ class RenderEditableContainerBox extends RenderBox } double _getIntrinsicCrossAxis(double Function(RenderBox child) childSize) { - double extent = 0.0; + var extent = 0.0; var child = firstChild; while (child != null) { extent = math.max(extent, childSize(child)); - EditableContainerParentData childParentData = - child.parentData as EditableContainerParentData; + final childParentData = child.parentData as EditableContainerParentData; child = childParentData.nextSibling; } return extent; } double _getIntrinsicMainAxis(double Function(RenderBox child) childSize) { - double extent = 0.0; + var extent = 0.0; var child = firstChild; while (child != null) { extent += childSize(child); - EditableContainerParentData childParentData = - child.parentData as EditableContainerParentData; + final childParentData = child.parentData as EditableContainerParentData; child = childParentData.nextSibling; } return extent; @@ -1026,7 +1020,7 @@ class RenderEditableContainerBox extends RenderBox double computeMinIntrinsicWidth(double height) { _resolvePadding(); return _getIntrinsicCrossAxis((RenderBox child) { - double childHeight = math.max( + final childHeight = math.max( 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMinIntrinsicWidth(childHeight) + _resolvedPadding!.left + @@ -1038,7 +1032,7 @@ class RenderEditableContainerBox extends RenderBox double computeMaxIntrinsicWidth(double height) { _resolvePadding(); return _getIntrinsicCrossAxis((RenderBox child) { - double childHeight = math.max( + final childHeight = math.max( 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMaxIntrinsicWidth(childHeight) + _resolvedPadding!.left + @@ -1050,7 +1044,7 @@ class RenderEditableContainerBox extends RenderBox double computeMinIntrinsicHeight(double width) { _resolvePadding(); return _getIntrinsicMainAxis((RenderBox child) { - double childWidth = math.max( + final childWidth = math.max( 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMinIntrinsicHeight(childWidth) + _resolvedPadding!.top + diff --git a/lib/widgets/keyboard_listener.dart b/lib/widgets/keyboard_listener.dart index 7311b345..f952c3dd 100644 --- a/lib/widgets/keyboard_listener.dart +++ b/lib/widgets/keyboard_listener.dart @@ -71,10 +71,10 @@ class KeyboardListener { return false; } - Set keysPressed = + final keysPressed = LogicalKeyboardKey.collapseSynonyms(RawKeyboard.instance.keysPressed); - LogicalKeyboardKey key = event.logicalKey; - bool isMacOS = event.data is RawKeyEventDataMacOs; + final key = event.logicalKey; + final isMacOS = event.data is RawKeyEventDataMacOs; if (!_nonModifierKeys.contains(key) || keysPressed .difference(isMacOS ? _macOsModifierKeys : _modifierKeys) diff --git a/lib/widgets/proxy.dart b/lib/widgets/proxy.dart index 8717d12a..71fc219d 100644 --- a/lib/widgets/proxy.dart +++ b/lib/widgets/proxy.dart @@ -91,8 +91,8 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { ]; } - double left = selection.extentOffset == 0 ? 0.0 : size.width; - double right = selection.extentOffset == 0 ? 0.0 : size.width; + final left = selection.extentOffset == 0 ? 0.0 : size.width; + final right = selection.extentOffset == 0 ? 0.0 : size.width; return [ TextBox.fromLTRBD(left, 0.0, right, size.height, TextDirection.ltr) ]; diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 155a90ff..8fc9babd 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -15,9 +15,7 @@ import '../models/documents/attribute.dart'; import '../models/documents/document.dart'; import '../models/documents/nodes/block.dart'; import '../models/documents/nodes/line.dart'; -import '../models/documents/nodes/node.dart'; import '../utils/diff_delta.dart'; -import 'box.dart'; import 'controller.dart'; import 'cursor.dart'; import 'default_styles.dart'; @@ -140,7 +138,7 @@ class RawEditorState extends EditorState bool get _hasFocus => widget.focusNode.hasFocus; TextDirection get _textDirection { - TextDirection result = Directionality.of(context); + final result = Directionality.of(context); return result; } @@ -153,13 +151,13 @@ class RawEditorState extends EditorState if (wordModifier && lineModifier) { return; } - TextSelection selection = widget.controller.selection; + final selection = widget.controller.selection; - TextSelection newSelection = widget.controller.selection; + var newSelection = widget.controller.selection; - String plainText = textEditingValue.text; + final plainText = textEditingValue.text; - bool rightKey = key == LogicalKeyboardKey.arrowRight, + final rightKey = key == LogicalKeyboardKey.arrowRight, leftKey = key == LogicalKeyboardKey.arrowLeft, upKey = key == LogicalKeyboardKey.arrowUp, downKey = key == LogicalKeyboardKey.arrowDown; @@ -184,7 +182,7 @@ class RawEditorState extends EditorState TextSelection _placeCollapsedSelection(TextSelection selection, TextSelection newSelection, bool leftKey, bool rightKey) { - int newOffset = newSelection.extentOffset; + var newOffset = newSelection.extentOffset; if (!selection.isCollapsed) { if (leftKey) { newOffset = newSelection.baseOffset < newSelection.extentOffset @@ -206,34 +204,32 @@ class RawEditorState extends EditorState TextSelection selection, TextSelection newSelection, String plainText) { - TextPosition originPosition = TextPosition( + final originPosition = TextPosition( offset: upKey ? selection.baseOffset : selection.extentOffset); - RenderEditableBox child = - getRenderEditor()!.childAtPosition(originPosition); - TextPosition localPosition = TextPosition( + final child = getRenderEditor()!.childAtPosition(originPosition); + final localPosition = TextPosition( offset: originPosition.offset - child.getContainer().getDocumentOffset()); - TextPosition? position = upKey + var position = upKey ? child.getPositionAbove(localPosition) : child.getPositionBelow(localPosition); if (position == null) { - var sibling = upKey + final sibling = upKey ? getRenderEditor()!.childBefore(child) : getRenderEditor()!.childAfter(child); if (sibling == null) { position = TextPosition(offset: upKey ? 0 : plainText.length - 1); } else { - Offset finalOffset = Offset( + final finalOffset = Offset( child.getOffsetForCaret(localPosition).dx, sibling .getOffsetForCaret(TextPosition( offset: upKey ? sibling.getContainer().length - 1 : 0)) .dy); - TextPosition siblingPosition = - sibling.getPositionForOffset(finalOffset); + final siblingPosition = sibling.getPositionForOffset(finalOffset); position = TextPosition( offset: sibling.getContainer().getDocumentOffset() + siblingPosition.offset); @@ -273,28 +269,28 @@ class RawEditorState extends EditorState bool shift) { if (wordModifier) { if (leftKey) { - TextSelection textSelection = getRenderEditor()!.selectWordAtPosition( + final textSelection = getRenderEditor()!.selectWordAtPosition( TextPosition( offset: _previousCharacter( newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.baseOffset); } - TextSelection textSelection = getRenderEditor()!.selectWordAtPosition( + final 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( + final textSelection = getRenderEditor()!.selectLineAtPosition( TextPosition( offset: _previousCharacter( newSelection.extentOffset, plainText, false))); return newSelection.copyWith(extentOffset: textSelection.baseOffset); } - int startPoint = newSelection.extentOffset; + final startPoint = newSelection.extentOffset; if (startPoint < plainText.length) { - TextSelection textSelection = getRenderEditor()! + final textSelection = getRenderEditor()! .selectLineAtPosition(TextPosition(offset: startPoint)); return newSelection.copyWith(extentOffset: textSelection.extentOffset); } @@ -302,9 +298,9 @@ class RawEditorState extends EditorState } if (rightKey && newSelection.extentOffset < plainText.length) { - int nextExtent = + final nextExtent = _nextCharacter(newSelection.extentOffset, plainText, true); - int distance = nextExtent - newSelection.extentOffset; + final distance = nextExtent - newSelection.extentOffset; newSelection = newSelection.copyWith(extentOffset: nextExtent); if (shift) { _cursorResetLocation += distance; @@ -313,9 +309,9 @@ class RawEditorState extends EditorState } if (leftKey && newSelection.extentOffset > 0) { - int previousExtent = + final previousExtent = _previousCharacter(newSelection.extentOffset, plainText, true); - int distance = newSelection.extentOffset - previousExtent; + final distance = newSelection.extentOffset - previousExtent; newSelection = newSelection.copyWith(extentOffset: previousExtent); if (shift) { _cursorResetLocation -= distance; @@ -331,8 +327,8 @@ class RawEditorState extends EditorState return string.length; } - int count = 0; - Characters remain = string.characters.skipWhile((String currentString) { + var count = 0; + final remain = string.characters.skipWhile((String currentString) { if (count <= index) { count += currentString.length; return true; @@ -351,9 +347,9 @@ class RawEditorState extends EditorState return 0; } - int count = 0; + var count = 0; int? lastNonWhitespace; - for (String currentString in string.characters) { + for (final currentString in string.characters) { if (!includeWhitespace && !WHITE_SPACE.contains( currentString.characters.first.toString().codeUnitAt(0))) { @@ -411,7 +407,7 @@ class RawEditorState extends EditorState return; } - TextEditingValue actualValue = textEditingValue.copyWith( + final actualValue = textEditingValue.copyWith( composing: _lastKnownRemoteTextEditingValue!.composing, ); @@ -419,7 +415,7 @@ class RawEditorState extends EditorState return; } - bool shouldRemember = + final shouldRemember = textEditingValue.text != _lastKnownRemoteTextEditingValue!.text; _lastKnownRemoteTextEditingValue = actualValue; _textInputConnection!.setEditingState(actualValue); @@ -456,13 +452,12 @@ class RawEditorState extends EditorState return; } - TextEditingValue effectiveLastKnownValue = - _lastKnownRemoteTextEditingValue!; + final effectiveLastKnownValue = _lastKnownRemoteTextEditingValue!; _lastKnownRemoteTextEditingValue = value; - String oldText = effectiveLastKnownValue.text; - String text = value.text; - int cursorPosition = value.selection.extentOffset; - Diff diff = getDiff(oldText, text, cursorPosition); + final oldText = effectiveLastKnownValue.text; + final text = value.text; + final cursorPosition = value.selection.extentOffset; + final diff = getDiff(oldText, text, cursorPosition); widget.controller.replaceText( diff.start, diff.deleted.length, diff.inserted, value.selection); } @@ -513,7 +508,7 @@ class RawEditorState extends EditorState _focusAttachment!.reparent(); super.build(context); - Document _doc = widget.controller.document; + var _doc = widget.controller.document; if (_doc.isEmpty() && !widget.focusNode.hasFocus && widget.placeholder != null) { @@ -540,7 +535,7 @@ class RawEditorState extends EditorState ); if (widget.scrollable) { - EdgeInsets baselinePadding = + final baselinePadding = EdgeInsets.only(top: _styles!.paragraph!.verticalSpacing.item1); child = BaselineProxy( textStyle: _styles!.paragraph!.style, @@ -553,7 +548,7 @@ class RawEditorState extends EditorState ); } - BoxConstraints constraints = widget.expands + final constraints = widget.expands ? const BoxConstraints.expand() : BoxConstraints( minHeight: widget.minHeight ?? 0.0, @@ -584,15 +579,14 @@ class RawEditorState extends EditorState List _buildChildren(Document doc, BuildContext context) { final result = []; - Map indentLevelCounts = {}; - for (Node node in doc.root.children) { + final indentLevelCounts = {}; + for (final node in doc.root.children) { if (node is Line) { - EditableTextLine editableTextLine = - _getEditableTextLineFromNode(node, context); + final editableTextLine = _getEditableTextLineFromNode(node, context); result.add(editableTextLine); } else if (node is Block) { - Map attrs = node.style.attributes; - EditableTextBlock editableTextBlock = EditableTextBlock( + final attrs = node.style.attributes; + final editableTextBlock = EditableTextBlock( node, _textDirection, _getVerticalSpacingForBlock(node, _styles), @@ -617,13 +611,13 @@ class RawEditorState extends EditorState EditableTextLine _getEditableTextLineFromNode( Line node, BuildContext context) { - TextLine textLine = TextLine( + final textLine = TextLine( line: node, textDirection: _textDirection, embedBuilder: widget.embedBuilder, styles: _styles!, ); - EditableTextLine editableTextLine = EditableTextLine( + final editableTextLine = EditableTextLine( node, null, textLine, @@ -641,9 +635,9 @@ class RawEditorState extends EditorState Tuple2 _getVerticalSpacingForLine( Line line, DefaultStyles? defaultStyles) { - Map attrs = line.style.attributes; + final attrs = line.style.attributes; if (attrs.containsKey(Attribute.header.key)) { - int? level = attrs[Attribute.header.key]!.value; + final int? level = attrs[Attribute.header.key]!.value; switch (level) { case 1: return defaultStyles!.h1!.verticalSpacing; @@ -661,7 +655,7 @@ class RawEditorState extends EditorState Tuple2 _getVerticalSpacingForBlock( Block node, DefaultStyles? defaultStyles) { - Map attrs = node.style.attributes; + final attrs = node.style.attributes; if (attrs.containsKey(Attribute.blockQuote.key)) { return defaultStyles!.quote!.verticalSpacing; } else if (attrs.containsKey(Attribute.codeBlock.key)) { @@ -720,8 +714,8 @@ class RawEditorState extends EditorState @override void didChangeDependencies() { super.didChangeDependencies(); - DefaultStyles? parentStyles = QuillStyles.getStyles(context, true); - DefaultStyles defaultStyles = DefaultStyles.getInstance(context); + final parentStyles = QuillStyles.getStyles(context, true); + final defaultStyles = DefaultStyles.getInstance(context); _styles = (parentStyles != null) ? defaultStyles.merge(parentStyles) : defaultStyles; @@ -784,27 +778,26 @@ class RawEditorState extends EditorState } void handleDelete(bool forward) { - TextSelection selection = widget.controller.selection; - String plainText = textEditingValue.text; - int cursorPosition = selection.start; - String textBefore = selection.textBefore(plainText); - String textAfter = selection.textAfter(plainText); + final selection = widget.controller.selection; + final plainText = textEditingValue.text; + var cursorPosition = selection.start; + var textBefore = selection.textBefore(plainText); + var textAfter = selection.textAfter(plainText); if (selection.isCollapsed) { if (!forward && textBefore.isNotEmpty) { - final int characterBoundary = + final characterBoundary = _previousCharacter(textBefore.length, textBefore, true); textBefore = textBefore.substring(0, characterBoundary); cursorPosition = characterBoundary; } if (forward && textAfter.isNotEmpty && textAfter != '\n') { - final int deleteCount = _nextCharacter(0, textAfter, true); + final deleteCount = _nextCharacter(0, textAfter, true); textAfter = textAfter.substring(deleteCount); } } - TextSelection newSelection = - TextSelection.collapsed(offset: cursorPosition); - String newText = textBefore + textAfter; - int size = plainText.length - newText.length; + final newSelection = TextSelection.collapsed(offset: cursorPosition); + final newText = textBefore + textAfter; + final size = plainText.length - newText.length; widget.controller.replaceText( cursorPosition, size, @@ -814,8 +807,8 @@ class RawEditorState extends EditorState } void handleShortcut(InputShortcut? shortcut) async { - TextSelection selection = widget.controller.selection; - String plainText = textEditingValue.text; + final selection = widget.controller.selection; + final plainText = textEditingValue.text; if (shortcut == InputShortcut.COPY) { if (!selection.isCollapsed) { await Clipboard.setData( @@ -844,7 +837,7 @@ class RawEditorState extends EditorState return; } if (shortcut == InputShortcut.PASTE && !widget.readOnly) { - ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); + final data = await Clipboard.getData(Clipboard.kTextPlain); if (data != null) { widget.controller.replaceText( selection.start, @@ -1074,8 +1067,8 @@ class RawEditorState extends EditorState value.selection, ); } else { - final TextEditingValue value = textEditingValue; - final ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); + final value = textEditingValue; + final data = await Clipboard.getData(Clipboard.kTextPlain); if (data != null) { final length = textEditingValue.selection.end - textEditingValue.selection.start; @@ -1095,7 +1088,7 @@ class RawEditorState extends EditorState } Future __isItCut(TextEditingValue value) async { - ClipboardData? data = await Clipboard.getData(Clipboard.kTextPlain); + final data = await Clipboard.getData(Clipboard.kTextPlain); if (data == null) { return false; } diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index 031ecbd5..b9808fad 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -6,7 +6,6 @@ import 'package:tuple/tuple.dart'; import '../models/documents/attribute.dart'; import '../models/documents/nodes/block.dart'; import '../models/documents/nodes/line.dart'; -import '../models/documents/nodes/node.dart'; import 'box.dart'; import 'cursor.dart'; import 'default_styles.dart'; @@ -79,7 +78,7 @@ class EditableTextBlock extends StatelessWidget { Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); - DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); + final defaultStyles = QuillStyles.getStyles(context, false); return _EditableBlock( block, textDirection, @@ -91,7 +90,7 @@ class EditableTextBlock extends StatelessWidget { BoxDecoration? _getDecorationForBlock( Block node, DefaultStyles? defaultStyles) { - Map attrs = block.style.attributes; + final attrs = block.style.attributes; if (attrs.containsKey(Attribute.blockQuote.key)) { return defaultStyles!.quote!.decoration; } @@ -103,13 +102,13 @@ class EditableTextBlock extends StatelessWidget { List _buildChildren( BuildContext context, Map indentLevelCounts) { - DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); - int count = block.children.length; - var children = []; - int index = 0; - for (Line line in Iterable.castFrom(block.children)) { + final defaultStyles = QuillStyles.getStyles(context, false); + final count = block.children.length; + final children = []; + var index = 0; + for (final line in Iterable.castFrom(block.children)) { index++; - EditableTextLine editableTextLine = EditableTextLine( + final editableTextLine = EditableTextLine( line, _buildLeading(context, line, index, indentLevelCounts, count), TextLine( @@ -134,8 +133,8 @@ class EditableTextBlock extends StatelessWidget { Widget? _buildLeading(BuildContext context, Line line, int index, Map indentLevelCounts, int count) { - DefaultStyles? defaultStyles = QuillStyles.getStyles(context, false); - Map attrs = line.style.attributes; + final defaultStyles = QuillStyles.getStyles(context, false); + final attrs = line.style.attributes; if (attrs[Attribute.list.key] == Attribute.ol) { return _NumberPoint( index: index, @@ -183,10 +182,10 @@ class EditableTextBlock extends StatelessWidget { } double _getIndentWidth() { - Map attrs = block.style.attributes; + final attrs = block.style.attributes; - Attribute? indent = attrs[Attribute.indent.key]; - double extraIndent = 0.0; + final indent = attrs[Attribute.indent.key]; + var extraIndent = 0.0; if (indent != null && indent.value != null) { extraIndent = 16.0 * indent.value; } @@ -200,11 +199,11 @@ class EditableTextBlock extends StatelessWidget { Tuple2 _getSpacingForLine( Line node, int index, int count, DefaultStyles? defaultStyles) { - double top = 0.0, bottom = 0.0; + var top = 0.0, bottom = 0.0; - Map attrs = block.style.attributes; + final attrs = block.style.attributes; if (attrs.containsKey(Attribute.header.key)) { - int? level = attrs[Attribute.header.key]!.value; + final level = attrs[Attribute.header.key]!.value; switch (level) { case 1: top = defaultStyles!.h1!.verticalSpacing.item1; @@ -310,8 +309,8 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override TextRange getLineBoundary(TextPosition position) { - RenderEditableBox child = childAtPosition(position); - TextRange rangeInChild = child.getLineBoundary(TextPosition( + final child = childAtPosition(position); + final rangeInChild = child.getLineBoundary(TextPosition( offset: position.offset - child.getContainer().getOffset(), affinity: position.affinity, )); @@ -323,7 +322,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override Offset getOffsetForCaret(TextPosition position) { - RenderEditableBox child = childAtPosition(position); + final child = childAtPosition(position); return child.getOffsetForCaret(TextPosition( offset: position.offset - child.getContainer().getOffset(), affinity: position.affinity, @@ -333,9 +332,9 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override TextPosition getPositionForOffset(Offset offset) { - RenderEditableBox child = childAtOffset(offset)!; - BoxParentData parentData = child.parentData as BoxParentData; - TextPosition localPosition = + final child = childAtOffset(offset)!; + final parentData = child.parentData as BoxParentData; + final localPosition = child.getPositionForOffset(offset - parentData.offset); return TextPosition( offset: localPosition.offset + child.getContainer().getOffset(), @@ -345,9 +344,9 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override TextRange getWordBoundary(TextPosition position) { - RenderEditableBox child = childAtPosition(position); - int nodeOffset = child.getContainer().getOffset(); - TextRange childWord = child + final child = childAtPosition(position); + final nodeOffset = child.getContainer().getOffset(); + final childWord = child .getWordBoundary(TextPosition(offset: position.offset - nodeOffset)); return TextRange( start: childWord.start + nodeOffset, @@ -359,25 +358,25 @@ class RenderEditableTextBlock extends RenderEditableContainerBox TextPosition? getPositionAbove(TextPosition position) { assert(position.offset < getContainer().length); - RenderEditableBox child = childAtPosition(position); - TextPosition childLocalPosition = TextPosition( + final child = childAtPosition(position); + final childLocalPosition = TextPosition( offset: position.offset - child.getContainer().getOffset()); - TextPosition? result = child.getPositionAbove(childLocalPosition); + final result = child.getPositionAbove(childLocalPosition); if (result != null) { return TextPosition( offset: result.offset + child.getContainer().getOffset()); } - RenderEditableBox? sibling = childBefore(child); + final sibling = childBefore(child); if (sibling == null) { return null; } - Offset caretOffset = child.getOffsetForCaret(childLocalPosition); - TextPosition testPosition = + final caretOffset = child.getOffsetForCaret(childLocalPosition); + final testPosition = TextPosition(offset: sibling.getContainer().length - 1); - Offset testOffset = sibling.getOffsetForCaret(testPosition); - Offset finalOffset = Offset(caretOffset.dx, testOffset.dy); + final testOffset = sibling.getOffsetForCaret(testPosition); + final finalOffset = Offset(caretOffset.dx, testOffset.dy); return TextPosition( offset: sibling.getContainer().getOffset() + sibling.getPositionForOffset(finalOffset).offset); @@ -387,24 +386,23 @@ class RenderEditableTextBlock extends RenderEditableContainerBox TextPosition? getPositionBelow(TextPosition position) { assert(position.offset < getContainer().length); - RenderEditableBox child = childAtPosition(position); - TextPosition childLocalPosition = TextPosition( + final child = childAtPosition(position); + final childLocalPosition = TextPosition( offset: position.offset - child.getContainer().getOffset()); - TextPosition? result = child.getPositionBelow(childLocalPosition); + final result = child.getPositionBelow(childLocalPosition); if (result != null) { return TextPosition( offset: result.offset + child.getContainer().getOffset()); } - RenderEditableBox? sibling = childAfter(child); + final sibling = childAfter(child); if (sibling == null) { return null; } - Offset caretOffset = child.getOffsetForCaret(childLocalPosition); - Offset testOffset = - sibling.getOffsetForCaret(const TextPosition(offset: 0)); - Offset finalOffset = Offset(caretOffset.dx, testOffset.dy); + final caretOffset = child.getOffsetForCaret(childLocalPosition); + final testOffset = sibling.getOffsetForCaret(const TextPosition(offset: 0)); + final finalOffset = Offset(caretOffset.dx, testOffset.dy); return TextPosition( offset: sibling.getContainer().getOffset() + sibling.getPositionForOffset(finalOffset).offset); @@ -412,7 +410,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override double preferredLineHeight(TextPosition position) { - RenderEditableBox child = childAtPosition(position); + final child = childAtPosition(position); return child.preferredLineHeight(TextPosition( offset: position.offset - child.getContainer().getOffset())); } @@ -426,7 +424,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox null); } - Node? baseNode = getContainer().queryChild(selection.start, false).node; + final baseNode = getContainer().queryChild(selection.start, false).node; var baseChild = firstChild; while (baseChild != null) { if (baseChild.getContainer() == baseNode) { @@ -436,7 +434,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } assert(baseChild != null); - TextSelectionPoint basePoint = baseChild!.getBaseEndpointForSelection( + final basePoint = baseChild!.getBaseEndpointForSelection( localSelection(baseChild.getContainer(), selection, true)); return TextSelectionPoint( basePoint.point + (baseChild.parentData as BoxParentData).offset, @@ -452,7 +450,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox null); } - Node? extentNode = getContainer().queryChild(selection.end, false).node; + final extentNode = getContainer().queryChild(selection.end, false).node; var extentChild = firstChild; while (extentChild != null) { @@ -463,7 +461,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } assert(extentChild != null); - TextSelectionPoint extentPoint = extentChild!.getExtentEndpointForSelection( + final extentPoint = extentChild!.getExtentEndpointForSelection( localSelection(extentChild.getContainer(), selection, true)); return TextSelectionPoint( extentPoint.point + (extentChild.parentData as BoxParentData).offset, @@ -487,11 +485,11 @@ class RenderEditableTextBlock extends RenderEditableContainerBox void _paintDecoration(PaintingContext context, Offset offset) { _painter ??= _decoration.createBoxPainter(markNeedsPaint); - EdgeInsets decorationPadding = resolvedPadding! - _contentPadding; + final decorationPadding = resolvedPadding! - _contentPadding; - ImageConfiguration filledConfiguration = + final filledConfiguration = configuration.copyWith(size: decorationPadding.deflateSize(size)); - int debugSaveCount = context.canvas.getSaveCount(); + final debugSaveCount = context.canvas.getSaveCount(); final decorationOffset = offset.translate(decorationPadding.left, decorationPadding.top); @@ -572,7 +570,7 @@ class _NumberPoint extends StatelessWidget { @override Widget build(BuildContext context) { - String s = index.toString(); + var s = index.toString(); int? level = 0; if (!attrs.containsKey(Attribute.indent.key) && !indentLevelCounts.containsKey(1)) { @@ -595,7 +593,7 @@ class _NumberPoint extends StatelessWidget { // last visited level is done, going up indentLevelCounts.remove(level + 1); } - int count = (indentLevelCounts[level] ?? 0) + 1; + final count = (indentLevelCounts[level] ?? 0) + 1; indentLevelCounts[level] = count; s = count.toString(); diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index c10c6c8e..99075411 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -11,7 +11,6 @@ import '../models/documents/nodes/leaf.dart' as leaf; import '../models/documents/nodes/leaf.dart'; import '../models/documents/nodes/line.dart'; import '../models/documents/nodes/node.dart'; -import '../models/documents/style.dart'; import '../utils/color.dart'; import 'box.dart'; import 'cursor.dart'; @@ -39,14 +38,14 @@ class TextLine extends StatelessWidget { assert(debugCheckHasMediaQuery(context)); if (line.hasEmbed) { - Embed embed = line.children.single as Embed; + final embed = line.children.single as Embed; return EmbedProxy(embedBuilder(context, embed)); } final textSpan = _buildTextSpan(context); final strutStyle = StrutStyle.fromTextStyle(textSpan.style!); final textAlign = _getTextAlign(); - RichText child = RichText( + final child = RichText( text: textSpan, textAlign: textAlign, textDirection: textDirection, @@ -80,20 +79,20 @@ class TextLine extends StatelessWidget { } TextSpan _buildTextSpan(BuildContext context) { - DefaultStyles defaultStyles = styles; - List children = line.children + final defaultStyles = styles; + final children = line.children .map((node) => _getTextSpanFromNode(defaultStyles, node)) .toList(growable: false); - TextStyle textStyle = const TextStyle(); + var textStyle = const TextStyle(); if (line.style.containsKey(Attribute.placeholder.key)) { textStyle = defaultStyles.placeHolder!.style; return TextSpan(children: children, style: textStyle); } - Attribute? header = line.style.attributes[Attribute.header.key]; - Map m = { + final header = line.style.attributes[Attribute.header.key]; + final m = { Attribute.h1: defaultStyles.h1!.style, Attribute.h2: defaultStyles.h2!.style, Attribute.h3: defaultStyles.h3!.style, @@ -101,7 +100,7 @@ class TextLine extends StatelessWidget { textStyle = textStyle.merge(m[header] ?? defaultStyles.paragraph!.style); - Attribute? block = line.style.getBlockExceptHeader(); + final block = line.style.getBlockExceptHeader(); TextStyle? toMerge; if (block == Attribute.blockQuote) { toMerge = defaultStyles.quote!.style; @@ -117,11 +116,11 @@ class TextLine extends StatelessWidget { } TextSpan _getTextSpanFromNode(DefaultStyles defaultStyles, Node node) { - leaf.Text textNode = node as leaf.Text; - Style style = textNode.style; - TextStyle res = const TextStyle(); + final textNode = node as leaf.Text; + final style = textNode.style; + var res = const TextStyle(); - Map m = { + final m = { Attribute.bold.key: defaultStyles.bold, Attribute.italic.key: defaultStyles.italic, Attribute.link.key: defaultStyles.link, @@ -134,12 +133,12 @@ class TextLine extends StatelessWidget { } }); - Attribute? font = textNode.style.attributes[Attribute.font.key]; + final 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]; + final size = textNode.style.attributes[Attribute.size.key]; if (size != null && size.value != null) { switch (size.value) { case 'small': @@ -152,7 +151,7 @@ class TextLine extends StatelessWidget { res = res.merge(defaultStyles.sizeHuge); break; default: - double? fontSize = double.tryParse(size.value); + final fontSize = double.tryParse(size.value); if (fontSize != null) { res = res.merge(TextStyle(fontSize: fontSize)); } else { @@ -161,7 +160,7 @@ class TextLine extends StatelessWidget { } } - Attribute? color = textNode.style.attributes[Attribute.color.key]; + final color = textNode.style.attributes[Attribute.color.key]; if (color != null && color.value != null) { var textColor = defaultStyles.color; if (color.value is String) { @@ -172,7 +171,7 @@ class TextLine extends StatelessWidget { } } - Attribute? background = textNode.style.attributes[Attribute.background.key]; + final background = textNode.style.attributes[Attribute.background.key]; if (background != null && background.value != null) { final backgroundColor = stringToColor(background.value); res = res.merge(TextStyle(backgroundColor: backgroundColor)); @@ -345,7 +344,7 @@ class RenderEditableTextLine extends RenderEditableBox { return; } - bool containsSelection = containsTextSelection(); + final containsSelection = containsTextSelection(); if (attached && containsCursor()) { cursorCont.removeListener(markNeedsLayout); cursorCont.color.removeListener(markNeedsPaint); @@ -424,7 +423,7 @@ class RenderEditableTextLine extends RenderEditableBox { } List _getBoxes(TextSelection textSelection) { - BoxParentData? parentData = _body!.parentData as BoxParentData?; + final parentData = _body!.parentData as BoxParentData?; return _body!.getBoxesForSelection(textSelection).map((box) { return TextBox.fromLTRBD( box.left + parentData!.offset.dx, @@ -463,9 +462,9 @@ class RenderEditableTextLine extends RenderEditableBox { getOffsetForCaret(textSelection.extent), null); } - List boxes = _getBoxes(textSelection); + final boxes = _getBoxes(textSelection); assert(boxes.isNotEmpty); - TextBox targetBox = first ? boxes.first : boxes.last; + final targetBox = first ? boxes.first : boxes.last; return TextSelectionPoint( Offset(first ? targetBox.start : targetBox.end, targetBox.bottom), targetBox.direction); @@ -473,10 +472,10 @@ class RenderEditableTextLine extends RenderEditableBox { @override TextRange getLineBoundary(TextPosition position) { - double lineDy = getOffsetForCaret(position) + final lineDy = getOffsetForCaret(position) .translate(0.0, 0.5 * preferredLineHeight(position)) .dy; - List lineBoxes = + final lineBoxes = _getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1)) .where((element) => element.top < lineDy && element.bottom > lineDy) .toList(growable: false); @@ -504,7 +503,7 @@ class RenderEditableTextLine extends RenderEditableBox { TextPosition? _getPosition(TextPosition textPosition, double dyScale) { assert(textPosition.offset < line.length); - Offset offset = getOffsetForCaret(textPosition) + final offset = getOffsetForCaret(textPosition) .translate(0, dyScale * preferredLineHeight(textPosition)); if (_body!.size .contains(offset - (_body!.parentData as BoxParentData).offset)) { @@ -574,7 +573,7 @@ class RenderEditableTextLine extends RenderEditableBox { @override void detach() { super.detach(); - for (RenderBox child in _children) { + for (final child in _children) { child.detach(); } if (containsCursor()) { @@ -595,7 +594,7 @@ class RenderEditableTextLine extends RenderEditableBox { @override List debugDescribeChildren() { - var value = []; + final value = []; void add(RenderBox? child, String name) { if (child != null) { value.add(child.toDiagnosticsNode(name: name)); @@ -613,12 +612,12 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeMinIntrinsicWidth(double height) { _resolvePadding(); - double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; - double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; - int leadingWidth = _leading == null + final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; + final leadingWidth = _leading == null ? 0 : _leading!.getMinIntrinsicWidth(height - verticalPadding) as int; - int bodyWidth = _body == null + final bodyWidth = _body == null ? 0 : _body!.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding)) as int; @@ -628,12 +627,12 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeMaxIntrinsicWidth(double height) { _resolvePadding(); - double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; - double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; - int leadingWidth = _leading == null + final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; + final leadingWidth = _leading == null ? 0 : _leading!.getMaxIntrinsicWidth(height - verticalPadding) as int; - int bodyWidth = _body == null + final bodyWidth = _body == null ? 0 : _body!.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding)) as int; @@ -643,8 +642,8 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeMinIntrinsicHeight(double width) { _resolvePadding(); - double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; - double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; + final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; if (_body != null) { return _body! .getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + @@ -656,8 +655,8 @@ class RenderEditableTextLine extends RenderEditableBox { @override double computeMaxIntrinsicHeight(double width) { _resolvePadding(); - double horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; - double verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; + final horizontalPadding = _resolvedPadding!.left + _resolvedPadding!.right; + final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; if (_body != null) { return _body! .getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + @@ -849,8 +848,8 @@ class _TextLineElement extends RenderObjectElement { } void _mountChild(Widget? widget, TextLineSlot slot) { - Element? oldChild = _slotToChildren[slot]; - Element? newChild = updateChild(oldChild, widget, slot); + final oldChild = _slotToChildren[slot]; + final newChild = updateChild(oldChild, widget, slot); if (oldChild != null) { _slotToChildren.remove(slot); } @@ -873,8 +872,8 @@ class _TextLineElement extends RenderObjectElement { } void _updateChild(Widget? widget, TextLineSlot slot) { - Element? oldChild = _slotToChildren[slot]; - Element? newChild = updateChild(oldChild, widget, slot); + final oldChild = _slotToChildren[slot]; + final 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 7873c99d..cf963d9a 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -12,10 +12,10 @@ import '../models/documents/nodes/node.dart'; import 'editor.dart'; TextSelection localSelection(Node node, TextSelection selection, fromParent) { - int base = fromParent ? node.getOffset() : node.getDocumentOffset(); + final base = fromParent ? node.getOffset() : node.getDocumentOffset(); assert(base <= selection.end && selection.start <= base + node.length - 1); - int offset = fromParent ? node.getOffset() : node.getDocumentOffset(); + final offset = fromParent ? node.getOffset() : node.getDocumentOffset(); return selection.copyWith( baseOffset: math.max(selection.start - offset, 0), extentOffset: math.min(selection.end - offset, node.length - 1)); @@ -55,7 +55,7 @@ class EditorTextSelectionOverlay { this.dragStartBehavior, this.onSelectionHandleTapped, this.clipboardStatus) { - OverlayState overlay = Overlay.of(context, rootOverlay: true)!; + final overlay = Overlay.of(context, rootOverlay: true)!; _toolbarController = AnimationController( duration: const Duration(milliseconds: 150), vsync: overlay); @@ -161,26 +161,25 @@ class EditorTextSelectionOverlay { } Widget _buildToolbar(BuildContext context) { - List endpoints = - renderObject!.getEndpointsForSelection(_selection); + final endpoints = renderObject!.getEndpointsForSelection(_selection); - Rect editingRegion = Rect.fromPoints( + final editingRegion = Rect.fromPoints( renderObject!.localToGlobal(Offset.zero), renderObject!.localToGlobal(renderObject!.size.bottomRight(Offset.zero)), ); - double baseLineHeight = renderObject!.preferredLineHeight(_selection.base); - double extentLineHeight = + final baseLineHeight = renderObject!.preferredLineHeight(_selection.base); + final extentLineHeight = renderObject!.preferredLineHeight(_selection.extent); - double smallestLineHeight = math.min(baseLineHeight, extentLineHeight); - bool isMultiline = endpoints.last.point.dy - endpoints.first.point.dy > + final smallestLineHeight = math.min(baseLineHeight, extentLineHeight); + final isMultiline = endpoints.last.point.dy - endpoints.first.point.dy > smallestLineHeight / 2; - double midX = isMultiline + final midX = isMultiline ? editingRegion.width / 2 : (endpoints.first.point.dx + endpoints.last.point.dx) / 2; - Offset midpoint = Offset( + final midpoint = Offset( midX, endpoints[0].point.dy - baseLineHeight, ); @@ -326,14 +325,14 @@ class _TextSelectionHandleOverlayState void _handleDragStart(DragStartDetails details) {} void _handleDragUpdate(DragUpdateDetails details) { - TextPosition position = + final position = widget.renderObject!.getPositionForOffset(details.globalPosition); if (widget.selection.isCollapsed) { widget.onSelectionHandleChanged(TextSelection.fromPosition(position)); return; } - bool isNormalized = + final isNormalized = widget.selection.extentOffset >= widget.selection.baseOffset; TextSelection? newSelection; switch (widget.position) { @@ -389,27 +388,26 @@ class _TextSelectionHandleOverlayState break; } - TextPosition textPosition = - widget.position == _TextSelectionHandlePosition.START - ? widget.selection.base - : widget.selection.extent; - double lineHeight = widget.renderObject!.preferredLineHeight(textPosition); - Offset handleAnchor = + final textPosition = widget.position == _TextSelectionHandlePosition.START + ? widget.selection.base + : widget.selection.extent; + final lineHeight = widget.renderObject!.preferredLineHeight(textPosition); + final handleAnchor = widget.selectionControls.getHandleAnchor(type!, lineHeight); - Size handleSize = widget.selectionControls.getHandleSize(lineHeight); + final handleSize = widget.selectionControls.getHandleSize(lineHeight); - Rect handleRect = Rect.fromLTWH( + final handleRect = Rect.fromLTWH( -handleAnchor.dx, -handleAnchor.dy, handleSize.width, handleSize.height, ); - Rect interactiveRect = handleRect.expandToInclude( + final interactiveRect = handleRect.expandToInclude( Rect.fromCircle( center: handleRect.center, radius: kMinInteractiveDimension / 2), ); - RelativeRect padding = RelativeRect.fromLTRB( + final padding = RelativeRect.fromLTRB( math.max((interactiveRect.width - handleRect.width) / 2, 0), math.max((interactiveRect.height - handleRect.height) / 2, 0), math.max((interactiveRect.width - handleRect.width) / 2, 0), @@ -656,8 +654,7 @@ class _EditorTextSelectionGestureDetectorState @override Widget build(BuildContext context) { - final Map gestures = - {}; + final gestures = {}; gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers( diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 07bdd421..0941760f 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -215,7 +215,7 @@ class _ToggleStyleButtonState extends State { bool _getIsToggled(Map attrs) { if (widget.attribute.key == Attribute.list.key) { - Attribute? attribute = attrs[widget.attribute.key]; + final attribute = attrs[widget.attribute.key]; if (attribute == null) { return false; } @@ -299,7 +299,7 @@ class _ToggleCheckListButtonState extends State { bool _getIsToggled(Map attrs) { if (widget.attribute.key == Attribute.list.key) { - Attribute? attribute = attrs[widget.attribute.key]; + final attribute = attrs[widget.attribute.key]; if (attribute == null) { return false; } @@ -430,20 +430,20 @@ class _SelectHeaderStyleButtonState extends State { Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value, ValueChanged onSelected) { - final Map _valueToText = { + final _valueToText = { Attribute.header: 'N', Attribute.h1: 'H1', Attribute.h2: 'H2', Attribute.h3: 'H3', }; - List _valueAttribute = [ + final _valueAttribute = [ Attribute.header, Attribute.h1, Attribute.h2, Attribute.h3 ]; - List _valueString = ['N', 'H1', 'H2', 'H3']; + final _valueString = ['N', 'H1', 'H2', 'H3']; final theme = Theme.of(context); final style = TextStyle( @@ -520,10 +520,10 @@ class _ImageButtonState extends State { final FileType _pickingType = FileType.any; Future _pickImage(ImageSource source) async { - final PickedFile? pickedFile = await _picker.getImage(source: source); + final pickedFile = await _picker.getImage(source: source); if (pickedFile == null) return null; - final File file = File(pickedFile.path); + final file = File(pickedFile.path); return widget.onImagePickCallback!(file); } @@ -536,11 +536,11 @@ class _ImageButtonState extends State { : null, )) ?.files; - var _fileName = + final _fileName = _paths != null ? _paths!.map((e) => e.name).toString() : '...'; if (_paths != null) { - File file = File(_fileName); + final file = File(_fileName); // We simply return the absolute path to selected file. return widget.onImagePickCallback!(file); } else { @@ -550,7 +550,7 @@ class _ImageButtonState extends State { } Future _pickImageDesktop() async { - var filePath = await FilesystemPicker.open( + final filePath = await FilesystemPicker.open( context: context, rootDirectory: await getApplicationDocumentsDirectory(), fsType: FilesystemType.file, @@ -558,7 +558,7 @@ class _ImageButtonState extends State { ); if (filePath != null && filePath.isEmpty) return ''; - final File file = File(filePath!); + final file = File(filePath!); return widget.onImagePickCallback!(file); } @@ -683,19 +683,19 @@ class _ColorButtonState extends State { @override Widget build(BuildContext context) { final theme = Theme.of(context); - Color? iconColor = _isToggledColor && !widget.background && !_isWhite + final iconColor = _isToggledColor && !widget.background && !_isWhite ? stringToColor(_selectionStyle.attributes['color']!.value) : theme.iconTheme.color; - var iconColorBackground = + final iconColorBackground = _isToggledBackground && widget.background && !_isWhitebackground ? stringToColor(_selectionStyle.attributes['background']!.value) : theme.iconTheme.color; - Color fillColor = _isToggledColor && !widget.background && _isWhite + final fillColor = _isToggledColor && !widget.background && _isWhite ? stringToColor('#ffffff') : theme.canvasColor; - Color fillColorBackground = + final fillColorBackground = _isToggledBackground && widget.background && _isWhitebackground ? stringToColor('#ffffff') : theme.canvasColor; @@ -713,7 +713,7 @@ class _ColorButtonState extends State { } void _changeColor(Color color) { - String hex = color.value.toRadixString(16); + var hex = color.value.toRadixString(16); if (hex.startsWith('ff')) { hex = hex.substring(2); } @@ -894,7 +894,7 @@ class _ClearFormatButtonState extends State { icon: Icon(widget.icon, size: iconSize, color: iconColor), fillColor: fillColor, onPressed: () { - for (Attribute k + for (final k in widget.controller.getSelectionStyle().attributes.values) { widget.controller.formatSelection(Attribute.clone(k, null)); } From 15a2f1d76f7c81b62adca20ff5b9bfd13f0100be Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:20:09 +0200 Subject: [PATCH 05/19] Prefer const declarations Const declarations are more hot-reload friendly and allow to use const constructors if an instantiation references this declaration. --- analysis_options.yaml | 1 + lib/models/documents/style.dart | 2 +- lib/models/quill_delta.dart | 3 +-- lib/widgets/default_styles.dart | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 50b1b8fc..ac173063 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -13,6 +13,7 @@ linter: - omit_local_variable_types - prefer_const_constructors - prefer_const_constructors_in_immutables + - prefer_const_declarations - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals diff --git a/lib/models/documents/style.dart b/lib/models/documents/style.dart index 4becc57e..37f6a0b9 100644 --- a/lib/models/documents/style.dart +++ b/lib/models/documents/style.dart @@ -95,7 +95,7 @@ class Style { return false; } final typedOther = other; - final eq = const MapEquality(); + const eq = MapEquality(); return eq.equals(_attributes, typedOther._attributes); } diff --git a/lib/models/quill_delta.dart b/lib/models/quill_delta.dart index c8707ee0..0135bd6a 100644 --- a/lib/models/quill_delta.dart +++ b/lib/models/quill_delta.dart @@ -293,8 +293,7 @@ class Delta { if (identical(this, other)) return true; if (other is! Delta) return false; final typedOther = other; - final comparator = - const ListEquality(DefaultEquality()); + const comparator = ListEquality(DefaultEquality()); return comparator.equals(_operations, typedOther._operations); } diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index 7f908114..2f2ea02c 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -90,7 +90,7 @@ class DefaultStyles { fontSize: 16.0, height: 1.3, ); - final baseSpacing = const Tuple2(6.0, 0); + const baseSpacing = Tuple2(6.0, 0); String fontFamily; switch (themeData.platform) { case TargetPlatform.iOS: From b47d22856b82cb66c9b19610d023a347b403bd35 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:24:07 +0200 Subject: [PATCH 06/19] Add already complied rules --- analysis_options.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/analysis_options.yaml b/analysis_options.yaml index ac173063..eac60d7e 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -6,7 +6,11 @@ analyzer: unsafe_html: ignore linter: rules: + - always_declare_return_types - always_put_required_named_parameters_first + - annotate_overrides + - avoid_empty_else + - avoid_escaping_inner_quotes - avoid_print - avoid_redundant_argument_values - directives_ordering @@ -18,4 +22,5 @@ linter: - prefer_final_in_for_each - prefer_final_locals - prefer_relative_imports + - prefer_single_quotes - unnecessary_parenthesis From 6c31fb1bc3df3318273385bd05cd3a422e09402c Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:27:07 +0200 Subject: [PATCH 07/19] Avoid types on closure parameters Annotating types for function expression parameters is usually unnecessary because the parameter types can almost always be inferred from the context, thus making the practice redundant. --- analysis_options.yaml | 1 + lib/models/documents/style.dart | 4 ++-- lib/models/rules/delete.dart | 4 ++-- lib/widgets/editor.dart | 8 ++++---- lib/widgets/raw_editor.dart | 8 ++++---- lib/widgets/text_selection.dart | 14 +++++++------- lib/widgets/toolbar.dart | 2 +- 7 files changed, 21 insertions(+), 20 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index eac60d7e..a7b7b075 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -24,3 +24,4 @@ linter: - prefer_relative_imports - prefer_single_quotes - unnecessary_parenthesis + - avoid_types_on_closure_parameters diff --git a/lib/models/documents/style.dart b/lib/models/documents/style.dart index 37f6a0b9..f8a8ee74 100644 --- a/lib/models/documents/style.dart +++ b/lib/models/documents/style.dart @@ -16,7 +16,7 @@ class Style { return Style(); } - final result = attributes.map((String key, dynamic value) { + final result = attributes.map((key, dynamic value) { final attr = Attribute.fromKeyValue(key, value); return MapEntry(key, attr); }); @@ -25,7 +25,7 @@ class Style { Map? toJson() => _attributes.isEmpty ? null - : _attributes.map((String _, Attribute attribute) => + : _attributes.map((_, attribute) => MapEntry(attribute.key, attribute.value)); Iterable get keys => _attributes.keys; diff --git a/lib/models/rules/delete.dart b/lib/models/rules/delete.dart index 60cee64d..def2e8c7 100644 --- a/lib/models/rules/delete.dart +++ b/lib/models/rules/delete.dart @@ -60,8 +60,8 @@ class PreserveLineStyleOnMergeRule extends DeleteRule { var attributes = op.attributes == null ? null - : op.attributes!.map((String key, dynamic value) => - MapEntry(key, null)); + : op.attributes!.map( + (key, dynamic value) => MapEntry(key, null)); if (isNotPlain) { attributes ??= {}; diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index c3f24d98..f1faaec6 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -1019,7 +1019,7 @@ class RenderEditableContainerBox extends RenderBox @override double computeMinIntrinsicWidth(double height) { _resolvePadding(); - return _getIntrinsicCrossAxis((RenderBox child) { + return _getIntrinsicCrossAxis((child) { final childHeight = math.max( 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMinIntrinsicWidth(childHeight) + @@ -1031,7 +1031,7 @@ class RenderEditableContainerBox extends RenderBox @override double computeMaxIntrinsicWidth(double height) { _resolvePadding(); - return _getIntrinsicCrossAxis((RenderBox child) { + return _getIntrinsicCrossAxis((child) { final childHeight = math.max( 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMaxIntrinsicWidth(childHeight) + @@ -1043,7 +1043,7 @@ class RenderEditableContainerBox extends RenderBox @override double computeMinIntrinsicHeight(double width) { _resolvePadding(); - return _getIntrinsicMainAxis((RenderBox child) { + return _getIntrinsicMainAxis((child) { final childWidth = math.max( 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMinIntrinsicHeight(childWidth) + @@ -1055,7 +1055,7 @@ class RenderEditableContainerBox extends RenderBox @override double computeMaxIntrinsicHeight(double width) { _resolvePadding(); - return _getIntrinsicMainAxis((RenderBox child) { + return _getIntrinsicMainAxis((child) { final childWidth = math.max( 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMaxIntrinsicHeight(childWidth) + diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 8fc9babd..9747901f 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -328,7 +328,7 @@ class RawEditorState extends EditorState } var count = 0; - final remain = string.characters.skipWhile((String currentString) { + final remain = string.characters.skipWhile((currentString) { if (count <= index) { count += currentString.length; return true; @@ -698,7 +698,7 @@ class RawEditorState extends EditorState _keyboardVisibilityController = KeyboardVisibilityController(); _keyboardVisible = _keyboardVisibilityController!.isVisible; _keyboardVisibilitySubscription = - _keyboardVisibilityController?.onChange.listen((bool visible) { + _keyboardVisibilityController?.onChange.listen((visible) { _keyboardVisible = visible; if (visible) { _onChangeTextEditingValue(); @@ -911,7 +911,7 @@ class RawEditorState extends EditorState } SchedulerBinding.instance!.addPostFrameCallback( - (Duration _) => _updateOrDisposeSelectionOverlayIfNeeded()); + (_) => _updateOrDisposeSelectionOverlayIfNeeded()); if (mounted) { setState(() { // Use widget.controller.value in build() @@ -982,7 +982,7 @@ class RawEditorState extends EditorState } _showCaretOnScreenScheduled = true; - SchedulerBinding.instance!.addPostFrameCallback((Duration _) { + SchedulerBinding.instance!.addPostFrameCallback((_) { _showCaretOnScreenScheduled = false; final viewport = RenderAbstractViewport.of(getRenderEditor())!; diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index cf963d9a..c113faeb 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -111,7 +111,7 @@ class EditorTextSelectionOverlay { return Visibility( visible: handlesVisible, child: _TextSelectionHandleOverlay( - onSelectionHandleChanged: (TextSelection? newSelection) { + onSelectionHandleChanged: (newSelection) { _handleSelectionHandleChanged(newSelection, position); }, onSelectionHandleTapped: onSelectionHandleTapped, @@ -231,10 +231,10 @@ class EditorTextSelectionOverlay { assert(_handles == null); _handles = [ OverlayEntry( - builder: (BuildContext context) => + builder: (context) => _buildHandle(context, _TextSelectionHandlePosition.START)), OverlayEntry( - builder: (BuildContext context) => + builder: (context) => _buildHandle(context, _TextSelectionHandlePosition.END)), ]; @@ -659,7 +659,7 @@ class _EditorTextSelectionGestureDetectorState gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => TapGestureRecognizer(debugOwner: this), - (TapGestureRecognizer instance) { + (instance) { instance ..onTapDown = _handleTapDown ..onTapUp = _handleTapUp @@ -674,7 +674,7 @@ class _EditorTextSelectionGestureDetectorState GestureRecognizerFactoryWithHandlers( () => LongPressGestureRecognizer( debugOwner: this, kind: PointerDeviceKind.touch), - (LongPressGestureRecognizer instance) { + (instance) { instance ..onLongPressStart = _handleLongPressStart ..onLongPressMoveUpdate = _handleLongPressMoveUpdate @@ -690,7 +690,7 @@ class _EditorTextSelectionGestureDetectorState GestureRecognizerFactoryWithHandlers( () => HorizontalDragGestureRecognizer( debugOwner: this, kind: PointerDeviceKind.mouse), - (HorizontalDragGestureRecognizer instance) { + (instance) { instance ..dragStartBehavior = DragStartBehavior.down ..onStart = _handleDragStart @@ -704,7 +704,7 @@ class _EditorTextSelectionGestureDetectorState gestures[ForcePressGestureRecognizer] = GestureRecognizerFactoryWithHandlers( () => ForcePressGestureRecognizer(debugOwner: this), - (ForcePressGestureRecognizer instance) { + (instance) { instance ..onStart = widget.onForcePressStart != null ? _forcePressStarted : null diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 0941760f..9348c3af 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -1251,7 +1251,7 @@ class _QuillDropdownButtonState extends State> { // widget.shape ?? popupMenuTheme.shape, color: popupMenuTheme.color, // widget.color ?? popupMenuTheme.color, // captureInheritedThemes: widget.captureInheritedThemes, - ).then((T? newValue) { + ).then((newValue) { if (!mounted) return null; if (newValue == null) { // if (widget.onCanceled != null) widget.onCanceled(); From 0a136edb8667255ec8c392b2a007d2d718b570ba Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:29:01 +0200 Subject: [PATCH 08/19] Avoid void async When declaring an async method or function which does not return a value, declare that it returns Future and not just void. --- analysis_options.yaml | 3 ++- lib/widgets/editor.dart | 2 +- lib/widgets/raw_editor.dart | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index a7b7b075..b00ad5ad 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -13,6 +13,8 @@ linter: - avoid_escaping_inner_quotes - avoid_print - avoid_redundant_argument_values + - avoid_types_on_closure_parameters + - avoid_void_async - directives_ordering - omit_local_variable_types - prefer_const_constructors @@ -24,4 +26,3 @@ linter: - prefer_relative_imports - prefer_single_quotes - unnecessary_parenthesis - - avoid_types_on_closure_parameters diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index f1faaec6..1b92dece 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -427,7 +427,7 @@ class _QuillEditorSelectionGestureDetectorBuilder return true; } - void _launchUrl(String url) async { + Future _launchUrl(String url) async { await launch(url); } diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 9747901f..fc07a110 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -806,7 +806,7 @@ class RawEditorState extends EditorState ); } - void handleShortcut(InputShortcut? shortcut) async { + Future handleShortcut(InputShortcut? shortcut) async { final selection = widget.controller.selection; final plainText = textEditingValue.text; if (shortcut == InputShortcut.COPY) { @@ -1058,7 +1058,7 @@ class RawEditorState extends EditorState } } - void __setEditingValue(TextEditingValue value) async { + Future __setEditingValue(TextEditingValue value) async { if (await __isItCut(value)) { widget.controller.replaceText( textEditingValue.selection.start, From 78594aa266eb3eb895f93e2dab6073fafb845c58 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:36:59 +0200 Subject: [PATCH 09/19] Cascade invocations Use the cascading style when succesively invoking methods on the same reference. --- analysis_options.yaml | 1 + lib/models/documents/nodes/block.dart | 5 +++-- lib/models/documents/nodes/leaf.dart | 6 ++---- lib/models/documents/nodes/line.dart | 9 +++----- lib/models/documents/nodes/node.dart | 4 +--- lib/models/rules/delete.dart | 3 +-- lib/models/rules/format.dart | 6 ++---- lib/models/rules/insert.dart | 8 +++---- lib/widgets/cursor.dart | 5 +++-- lib/widgets/editor.dart | 4 ++-- lib/widgets/proxy.dart | 17 ++++++++------- lib/widgets/raw_editor.dart | 24 +++++++++++---------- lib/widgets/text_block.dart | 11 +++++----- lib/widgets/text_line.dart | 31 +++++++++++++-------------- lib/widgets/text_selection.dart | 7 +++--- 15 files changed, 68 insertions(+), 73 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index b00ad5ad..5e1da9dc 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -15,6 +15,7 @@ linter: - avoid_redundant_argument_values - avoid_types_on_closure_parameters - avoid_void_async + - cascade_invocations - directives_ordering - omit_local_variable_types - prefer_const_constructors diff --git a/lib/models/documents/nodes/block.dart b/lib/models/documents/nodes/block.dart index 0919806f..5128f598 100644 --- a/lib/models/documents/nodes/block.dart +++ b/lib/models/documents/nodes/block.dart @@ -31,8 +31,9 @@ class Block extends Container { if (!block.isFirst && block.previous is Block && prev!.style == block.style) { - block.moveChildToNewParent(prev as Container?); - block.unlink(); + block + ..moveChildToNewParent(prev as Container?) + ..unlink(); block = prev as Block; } final next = block.next; diff --git a/lib/models/documents/nodes/leaf.dart b/lib/models/documents/nodes/leaf.dart index 88aeca6c..3d98060e 100644 --- a/lib/models/documents/nodes/leaf.dart +++ b/lib/models/documents/nodes/leaf.dart @@ -141,8 +141,7 @@ abstract class Leaf extends Node { assert(this is Text); final text = _value as String; _value = text.substring(0, index); - final split = Leaf(text.substring(index)); - split.applyStyle(style); + final split = Leaf(text.substring(index))..applyStyle(style); insertAfter(split); return split; } @@ -158,8 +157,7 @@ abstract class Leaf extends Node { Leaf _isolate(int index, int length) { assert( index >= 0 && index < this.length && (index + length <= this.length)); - final target = splitAt(index)!; - target.splitAt(length); + final target = splitAt(index)!..splitAt(length); return target; } } diff --git a/lib/models/documents/nodes/line.dart b/lib/models/documents/nodes/line.dart index 7dba241f..08ec39ee 100644 --- a/lib/models/documents/nodes/line.dart +++ b/lib/models/documents/nodes/line.dart @@ -173,14 +173,12 @@ class Line extends Container { _unwrap(); } else if (blockStyle != parentStyle) { _unwrap(); - final block = Block(); - block.applyAttribute(blockStyle); + final block = Block()..applyAttribute(blockStyle); _wrap(block); block.adjust(); } } else if (blockStyle.value != null) { - final block = Block(); - block.applyAttribute(blockStyle); + final block = Block()..applyAttribute(blockStyle); _wrap(block); block.adjust(); } @@ -234,8 +232,7 @@ class Line extends Container { final query = queryChild(index, false); while (!query.node!.isLast) { - final next = last as Leaf; - next.unlink(); + final next = (last as Leaf)..unlink(); line.addFirst(next); } final child = query.node as Leaf; diff --git a/lib/models/documents/nodes/node.dart b/lib/models/documents/nodes/node.dart index d46b4647..ddd1078c 100644 --- a/lib/models/documents/nodes/node.dart +++ b/lib/models/documents/nodes/node.dart @@ -32,9 +32,7 @@ abstract class Node extends LinkedListEntry { int get length; Node clone() { - final node = newInstance(); - node.applyStyle(style); - return node; + return newInstance()..applyStyle(style); } int getOffset() { diff --git a/lib/models/rules/delete.dart b/lib/models/rules/delete.dart index def2e8c7..e6682f94 100644 --- a/lib/models/rules/delete.dart +++ b/lib/models/rules/delete.dart @@ -34,8 +34,7 @@ class PreserveLineStyleOnMergeRule extends DeleteRule { @override Delta? applyRule(Delta document, int index, {int? len, Object? data, Attribute? attribute}) { - final itr = DeltaIterator(document); - itr.skip(index); + final itr = DeltaIterator(document)..skip(index); var op = itr.next(1); if (op.data != '\n') { return null; diff --git a/lib/models/rules/format.dart b/lib/models/rules/format.dart index 470ca200..be201925 100644 --- a/lib/models/rules/format.dart +++ b/lib/models/rules/format.dart @@ -27,8 +27,7 @@ class ResolveLineFormatRule extends FormatRule { } var delta = Delta()..retain(index); - final itr = DeltaIterator(document); - itr.skip(index); + final itr = DeltaIterator(document)..skip(index); Operation op; for (var cur = 0; cur < len! && itr.hasNext; cur += op.length!) { op = itr.next(len - cur); @@ -106,8 +105,7 @@ class ResolveInlineFormatRule extends FormatRule { } final delta = Delta()..retain(index); - final itr = DeltaIterator(document); - itr.skip(index); + final itr = DeltaIterator(document)..skip(index); Operation op; for (var cur = 0; cur < len! && itr.hasNext; cur += op.length!) { diff --git a/lib/models/rules/insert.dart b/lib/models/rules/insert.dart index 97f386d5..f7d029a4 100644 --- a/lib/models/rules/insert.dart +++ b/lib/models/rules/insert.dart @@ -66,8 +66,7 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { return null; } - final itr = DeltaIterator(document); - itr.skip(index); + final itr = DeltaIterator(document)..skip(index); final nextNewLine = _getNextNewLine(itr); final lineStyle = @@ -101,8 +100,8 @@ class PreserveBlockStyleOnInsertRule extends InsertRule { } if (resetStyle != null) { - delta.retain(nextNewLine.item2!); delta + ..retain(nextNewLine.item2!) ..retain((nextNewLine.item1!.data as String).indexOf('\n')) ..retain(1, resetStyle); } @@ -172,8 +171,7 @@ class ResetLineFormatOnNewLineRule extends InsertRule { return null; } - final itr = DeltaIterator(document); - itr.skip(index); + final itr = DeltaIterator(document)..skip(index); final cur = itr.next(); if (cur.data is! String || !(cur.data as String).startsWith('\n')) { return null; diff --git a/lib/widgets/cursor.dart b/lib/widgets/cursor.dart index 8a22c7c2..6c9ce734 100644 --- a/lib/widgets/cursor.dart +++ b/lib/widgets/cursor.dart @@ -133,8 +133,9 @@ class CursorCont extends ChangeNotifier { _blinkOpacityCont.value = 0.0; if (style.opacityAnimates) { - _blinkOpacityCont.stop(); - _blinkOpacityCont.value = 0.0; + _blinkOpacityCont + ..stop() + ..value = 0.0; } } diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 1b92dece..b77b4673 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -982,8 +982,8 @@ class RenderEditableContainerBox extends RenderBox .deflate(_resolvedPadding!); while (child != null) { child.layout(innerConstraints, parentUsesSize: true); - final childParentData = child.parentData as EditableContainerParentData; - childParentData.offset = Offset(_resolvedPadding!.left, mainAxisExtent); + final childParentData = (child.parentData as EditableContainerParentData) + ..offset = Offset(_resolvedPadding!.left, mainAxisExtent); mainAxisExtent += child.size.height; assert(child.parentData == childParentData); child = childParentData.nextSibling; diff --git a/lib/widgets/proxy.dart b/lib/widgets/proxy.dart index 71fc219d..ef763b9b 100644 --- a/lib/widgets/proxy.dart +++ b/lib/widgets/proxy.dart @@ -160,14 +160,15 @@ class RichTextProxy extends SingleChildRenderObjectWidget { @override void updateRenderObject( BuildContext context, covariant RenderParagraphProxy renderObject) { - renderObject.textStyle = textStyle; - renderObject.textAlign = textAlign; - renderObject.textDirection = textDirection; - renderObject.textScaleFactor = textScaleFactor; - renderObject.locale = locale; - renderObject.strutStyle = strutStyle; - renderObject.textWidthBasis = textWidthBasis; - renderObject.textHeightBehavior = textHeightBehavior; + renderObject + ..textStyle = textStyle + ..textAlign = textAlign + ..textDirection = textDirection + ..textScaleFactor = textScaleFactor + ..locale = locale + ..strutStyle = strutStyle + ..textWidthBasis = textWidthBasis + ..textHeightBehavior = textHeightBehavior; } } diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index fc07a110..2f076a20 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -906,8 +906,9 @@ class RawEditorState extends EditorState _cursorCont.startOrStopCursorTimerIfNeeded( _hasFocus, widget.controller.selection); if (hasConnection) { - _cursorCont.stopCursorTimer(resetCharTicks: false); - _cursorCont.startCursorTimer(); + _cursorCont + ..stopCursorTimer(resetCharTicks: false) + ..startCursorTimer(); } SchedulerBinding.instance!.addPostFrameCallback( @@ -1168,14 +1169,15 @@ class _Editor extends MultiChildRenderObjectWidget { @override void updateRenderObject( BuildContext context, covariant RenderEditor renderObject) { - renderObject.document = document; - renderObject.setContainer(document.root); - renderObject.textDirection = textDirection; - renderObject.setHasFocus(hasFocus); - renderObject.setSelection(selection); - renderObject.setStartHandleLayerLink(startHandleLayerLink); - renderObject.setEndHandleLayerLink(endHandleLayerLink); - renderObject.onSelectionChanged = onSelectionChanged; - renderObject.setPadding(padding); + renderObject + ..document = document + ..setContainer(document.root) + ..textDirection = textDirection + ..setHasFocus(hasFocus) + ..setSelection(selection) + ..setStartHandleLayerLink(startHandleLayerLink) + ..setEndHandleLayerLink(endHandleLayerLink) + ..onSelectionChanged = onSelectionChanged + ..setPadding(padding); } } diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index b9808fad..9cb40275 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -538,11 +538,12 @@ class _EditableBlock extends MultiChildRenderObjectWidget { @override void updateRenderObject( BuildContext context, covariant RenderEditableTextBlock renderObject) { - renderObject.setContainer(block); - renderObject.textDirection = textDirection; - renderObject.setPadding(_padding); - renderObject.decoration = decoration; - renderObject.contentPadding = _contentPadding; + renderObject + ..setContainer(block) + ..textDirection = textDirection + ..setPadding(_padding) + ..decoration = decoration + ..contentPadding = _contentPadding; } } diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 99075411..8eff21c3 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -120,14 +120,13 @@ class TextLine extends StatelessWidget { final style = textNode.style; var res = const TextStyle(); - final m = { + { Attribute.bold.key: defaultStyles.bold, Attribute.italic.key: defaultStyles.italic, Attribute.link.key: defaultStyles.link, Attribute.underline.key: defaultStyles.underline, Attribute.strikeThrough.key: defaultStyles.strikeThrough, - }; - m.forEach((k, s) { + }.forEach((k, s) { if (style.values.any((v) => v.key == k)) { res = _merge(res, s!); } @@ -244,15 +243,16 @@ class EditableTextLine extends RenderObjectWidget { @override void updateRenderObject( BuildContext context, covariant RenderEditableTextLine renderObject) { - renderObject.setLine(line); - renderObject.setPadding(_getPadding()); - renderObject.setTextDirection(textDirection); - renderObject.setTextSelection(textSelection); - renderObject.setColor(color); - renderObject.setEnableInteractiveSelection(enableInteractiveSelection); - renderObject.hasFocus = hasFocus; - renderObject.setDevicePixelRatio(devicePixelRatio); - renderObject.setCursorCont(cursorCont); + renderObject + ..setLine(line) + ..setPadding(_getPadding()) + ..setTextDirection(textDirection) + ..setTextSelection(textSelection) + ..setColor(color) + ..setEnableInteractiveSelection(enableInteractiveSelection) + ..hasFocus = hasFocus + ..setDevicePixelRatio(devicePixelRatio) + ..setCursorCont(cursorCont); } EdgeInsetsGeometry _getPadding() { @@ -694,8 +694,7 @@ class RenderEditableTextLine extends RenderEditableBox { : _resolvedPadding!.right; _body!.layout(innerConstraints, parentUsesSize: true); - final bodyParentData = _body!.parentData as BoxParentData; - bodyParentData.offset = + (_body!.parentData as BoxParentData).offset = Offset(_resolvedPadding!.left, _resolvedPadding!.top); if (_leading != null) { @@ -704,8 +703,8 @@ class RenderEditableTextLine extends RenderEditableBox { maxWidth: indentWidth, maxHeight: _body!.size.height); _leading!.layout(leadingConstraints, parentUsesSize: true); - final parentData = _leading!.parentData as BoxParentData; - parentData.offset = Offset(0.0, _resolvedPadding!.top); + (_leading!.parentData as BoxParentData).offset = + Offset(0.0, _resolvedPadding!.top); } size = constraints.constrain(Size( diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index c113faeb..ff008742 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -155,9 +155,10 @@ class EditorTextSelectionOverlay { default: throw 'Invalid position'; } - selectionDelegate.textEditingValue = - value.copyWith(selection: newSelection, composing: TextRange.empty); - selectionDelegate.bringIntoView(textPosition); + selectionDelegate + ..textEditingValue = + value.copyWith(selection: newSelection, composing: TextRange.empty) + ..bringIntoView(textPosition); } Widget _buildToolbar(BuildContext context) { From 32b6c9169a1fd749a48d66567dd82397f23b43e4 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:38:34 +0200 Subject: [PATCH 10/19] Prefer initializing formals --- analysis_options.yaml | 1 + lib/widgets/cursor.dart | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 5e1da9dc..9b96f35d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -24,6 +24,7 @@ linter: - prefer_final_fields - prefer_final_in_for_each - prefer_final_locals + - prefer_initializing_formals - prefer_relative_imports - prefer_single_quotes - unnecessary_parenthesis diff --git a/lib/widgets/cursor.dart b/lib/widgets/cursor.dart index 6c9ce734..a2d7488b 100644 --- a/lib/widgets/cursor.dart +++ b/lib/widgets/cursor.dart @@ -64,11 +64,10 @@ class CursorCont extends ChangeNotifier { CursorStyle _style; CursorCont({ - required ValueNotifier show, + required this.show, required CursorStyle style, required TickerProvider tickerProvider, - }) : show = show, - _style = style, + }) : _style = style, _blink = ValueNotifier(false), color = ValueNotifier(style.color) { _blinkOpacityCont = From 5c18ca1dc3977b0d2c69fc9e48e7670a4ec937c5 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:45:49 +0200 Subject: [PATCH 11/19] Prefer int literals --- analysis_options.yaml | 1 + lib/widgets/cursor.dart | 2 +- lib/widgets/default_styles.dart | 50 ++++++++++++++++----------------- lib/widgets/editor.dart | 24 ++++++++-------- lib/widgets/proxy.dart | 6 ++-- lib/widgets/raw_editor.dart | 4 +-- lib/widgets/text_block.dart | 16 +++++------ lib/widgets/text_line.dart | 22 +++++++-------- lib/widgets/text_selection.dart | 2 +- lib/widgets/toolbar.dart | 6 ++-- 10 files changed, 66 insertions(+), 67 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 9b96f35d..22b167da 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -25,6 +25,7 @@ linter: - prefer_final_in_for_each - prefer_final_locals - prefer_initializing_formals + - prefer_int_literals - prefer_relative_imports - prefer_single_quotes - unnecessary_parenthesis diff --git a/lib/widgets/cursor.dart b/lib/widgets/cursor.dart index a2d7488b..307e70a5 100644 --- a/lib/widgets/cursor.dart +++ b/lib/widgets/cursor.dart @@ -176,7 +176,7 @@ class CursorPainter { } if (caretRect.left < 0.0) { - caretRect = caretRect.shift(Offset(-caretRect.left, 0.0)); + caretRect = caretRect.shift(Offset(-caretRect.left, 0)); } final caretHeight = editable!.getFullHeightForCaret(position); diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index 2f2ea02c..8612d92b 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -87,10 +87,10 @@ class DefaultStyles { final themeData = Theme.of(context); final defaultTextStyle = DefaultTextStyle.of(context); final baseStyle = defaultTextStyle.style.copyWith( - fontSize: 16.0, + fontSize: 16, height: 1.3, ); - const baseSpacing = Tuple2(6.0, 0); + const baseSpacing = Tuple2(6, 0); String fontFamily; switch (themeData.platform) { case TargetPlatform.iOS: @@ -110,36 +110,36 @@ class DefaultStyles { return DefaultStyles( h1: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( - fontSize: 34.0, + fontSize: 34, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.15, fontWeight: FontWeight.w300, ), - const Tuple2(16.0, 0.0), - const Tuple2(0.0, 0.0), + const Tuple2(16, 0), + const Tuple2(0, 0), null), h2: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( - fontSize: 24.0, + fontSize: 24, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.15, fontWeight: FontWeight.normal, ), - const Tuple2(8.0, 0.0), - const Tuple2(0.0, 0.0), + const Tuple2(8, 0), + const Tuple2(0, 0), null), h3: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( - fontSize: 20.0, + fontSize: 20, color: defaultTextStyle.style.color!.withOpacity(0.70), height: 1.25, fontWeight: FontWeight.w500, ), - const Tuple2(8.0, 0.0), - const Tuple2(0.0, 0.0), + const Tuple2(8, 0), + const Tuple2(0, 0), null), paragraph: DefaultTextBlockStyle( - baseStyle, const Tuple2(0.0, 0.0), const Tuple2(0.0, 0.0), null), + baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null), bold: const TextStyle(fontWeight: FontWeight.bold), italic: const TextStyle(fontStyle: FontStyle.italic), underline: const TextStyle(decoration: TextDecoration.underline), @@ -150,19 +150,19 @@ class DefaultStyles { ), placeHolder: DefaultTextBlockStyle( defaultTextStyle.style.copyWith( - fontSize: 20.0, + fontSize: 20, height: 1.5, color: Colors.grey.withOpacity(0.6), ), - const Tuple2(0.0, 0.0), - const Tuple2(0.0, 0.0), + const Tuple2(0, 0), + const Tuple2(0, 0), null), lists: DefaultTextBlockStyle( - baseStyle, baseSpacing, const Tuple2(0.0, 6.0), null), + baseStyle, baseSpacing, const Tuple2(0, 6), null), quote: DefaultTextBlockStyle( TextStyle(color: baseStyle.color!.withOpacity(0.6)), baseSpacing, - const Tuple2(6.0, 2.0), + const Tuple2(6, 2), BoxDecoration( border: Border( left: BorderSide(width: 4, color: Colors.grey.shade300), @@ -172,24 +172,24 @@ class DefaultStyles { TextStyle( color: Colors.blue.shade900.withOpacity(0.9), fontFamily: fontFamily, - fontSize: 13.0, + fontSize: 13, height: 1.15, ), baseSpacing, - const Tuple2(0.0, 0.0), + const Tuple2(0, 0), BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(2), )), indent: DefaultTextBlockStyle( - baseStyle, baseSpacing, const Tuple2(0.0, 6.0), null), + baseStyle, baseSpacing, const Tuple2(0, 6), null), align: DefaultTextBlockStyle( - baseStyle, const Tuple2(0.0, 0.0), const Tuple2(0.0, 0.0), null), + baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null), leading: DefaultTextBlockStyle( - baseStyle, const Tuple2(0.0, 0.0), const Tuple2(0.0, 0.0), null), - sizeSmall: const TextStyle(fontSize: 10.0), - sizeLarge: const TextStyle(fontSize: 18.0), - sizeHuge: const TextStyle(fontSize: 22.0)); + baseStyle, const Tuple2(0, 0), const Tuple2(0, 0), null), + sizeSmall: const TextStyle(fontSize: 10), + sizeLarge: const TextStyle(fontSize: 18), + sizeHuge: const TextStyle(fontSize: 22)); } DefaultStyles merge(DefaultStyles other) { diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index b77b4673..c3d5d2cb 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -220,7 +220,7 @@ class _QuillEditorState extends State selectionTheme.cursorColor ?? cupertinoTheme.primaryColor; selectionColor = selectionTheme.selectionColor ?? cupertinoTheme.primaryColor.withOpacity(0.40); - cursorRadius ??= const Radius.circular(2.0); + cursorRadius ??= const Radius.circular(2); cursorOffset = Offset( iOSHorizontalOffset / MediaQuery.of(context).devicePixelRatio, 0); break; @@ -252,7 +252,7 @@ class _QuillEditorState extends State CursorStyle( color: cursorColor, backgroundColor: Colors.grey, - width: 2.0, + width: 2, radius: cursorRadius, offset: cursorOffset, paintAboveText: paintCursorAboveText, @@ -580,7 +580,7 @@ class RenderEditor extends RenderEditableContainerBox final parentData = child.parentData as BoxParentData; return [ TextSelectionPoint( - Offset(0.0, child.preferredLineHeight(localPosition)) + + Offset(0, child.preferredLineHeight(localPosition)) + localOffset + parentData.offset, null) @@ -853,7 +853,7 @@ class RenderEditor extends RenderEditableContainerBox if (dy == null) { return null; } - return math.max(dy, 0.0); + return math.max(dy, 0); } } @@ -1020,8 +1020,8 @@ class RenderEditableContainerBox extends RenderBox double computeMinIntrinsicWidth(double height) { _resolvePadding(); return _getIntrinsicCrossAxis((child) { - final childHeight = math.max( - 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); + final childHeight = math.max( + 0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMinIntrinsicWidth(childHeight) + _resolvedPadding!.left + _resolvedPadding!.right; @@ -1032,8 +1032,8 @@ class RenderEditableContainerBox extends RenderBox double computeMaxIntrinsicWidth(double height) { _resolvePadding(); return _getIntrinsicCrossAxis((child) { - final childHeight = math.max( - 0.0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); + final childHeight = math.max( + 0, height - _resolvedPadding!.top + _resolvedPadding!.bottom); return child.getMaxIntrinsicWidth(childHeight) + _resolvedPadding!.left + _resolvedPadding!.right; @@ -1044,8 +1044,8 @@ class RenderEditableContainerBox extends RenderBox double computeMinIntrinsicHeight(double width) { _resolvePadding(); return _getIntrinsicMainAxis((child) { - final childWidth = math.max( - 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); + final childWidth = math.max( + 0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMinIntrinsicHeight(childWidth) + _resolvedPadding!.top + _resolvedPadding!.bottom; @@ -1056,8 +1056,8 @@ class RenderEditableContainerBox extends RenderBox double computeMaxIntrinsicHeight(double width) { _resolvePadding(); return _getIntrinsicMainAxis((child) { - final childWidth = math.max( - 0.0, width - _resolvedPadding!.left + _resolvedPadding!.right); + final childWidth = math.max( + 0, width - _resolvedPadding!.left + _resolvedPadding!.right); return child.getMaxIntrinsicHeight(childWidth) + _resolvedPadding!.top + _resolvedPadding!.bottom; diff --git a/lib/widgets/proxy.dart b/lib/widgets/proxy.dart index ef763b9b..bae59f1b 100644 --- a/lib/widgets/proxy.dart +++ b/lib/widgets/proxy.dart @@ -87,14 +87,14 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { List getBoxesForSelection(TextSelection selection) { if (!selection.isCollapsed) { return [ - TextBox.fromLTRBD(0.0, 0.0, size.width, size.height, TextDirection.ltr) + TextBox.fromLTRBD(0, 0, size.width, size.height, TextDirection.ltr) ]; } final left = selection.extentOffset == 0 ? 0.0 : size.width; final right = selection.extentOffset == 0 ? 0.0 : size.width; return [ - TextBox.fromLTRBD(left, 0.0, right, size.height, TextDirection.ltr) + TextBox.fromLTRBD(left, 0, right, size.height, TextDirection.ltr) ]; } @@ -104,7 +104,7 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { @override Offset getOffsetForCaret(TextPosition position, Rect? caretPrototype) { assert(position.offset <= 1 && position.offset >= 0); - return position.offset == 0 ? Offset.zero : Offset(size.width, 0.0); + return position.offset == 0 ? Offset.zero : Offset(size.width, 0); } @override diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 2f076a20..cf293aba 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -596,7 +596,7 @@ class RawEditorState extends EditorState widget.enableInteractiveSelection, _hasFocus, attrs.containsKey(Attribute.codeBlock.key) - ? const EdgeInsets.all(16.0) + ? const EdgeInsets.all(16) : null, widget.embedBuilder, _cursorCont, @@ -988,7 +988,7 @@ class RawEditorState extends EditorState final viewport = RenderAbstractViewport.of(getRenderEditor())!; final editorOffset = getRenderEditor()! - .localToGlobal(const Offset(0.0, 0.0), ancestor: viewport); + .localToGlobal(const Offset(0, 0), ancestor: viewport); final offsetInViewport = _scrollController!.offset + editorOffset.dy; final offset = getRenderEditor()!.getOffsetToRevealCursor( diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index 9cb40275..757a2c9c 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -142,8 +142,8 @@ class EditableTextBlock extends StatelessWidget { count: count, style: defaultStyles!.leading!.style, attrs: attrs, - width: 32.0, - padding: 8.0, + width: 32, + padding: 8, ); } @@ -172,9 +172,9 @@ class EditableTextBlock extends StatelessWidget { count: count, style: defaultStyles!.code!.style .copyWith(color: defaultStyles.code!.style.color!.withOpacity(0.4)), - width: 32.0, + width: 32, attrs: attrs, - padding: 16.0, + padding: 16, withDot: false, ); } @@ -419,7 +419,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox TextSelectionPoint getBaseEndpointForSelection(TextSelection selection) { if (selection.isCollapsed) { return TextSelectionPoint( - Offset(0.0, preferredLineHeight(selection.extent)) + + Offset(0, preferredLineHeight(selection.extent)) + getOffsetForCaret(selection.extent), null); } @@ -445,7 +445,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox TextSelectionPoint getExtentEndpointForSelection(TextSelection selection) { if (selection.isCollapsed) { return TextSelectionPoint( - Offset(0.0, preferredLineHeight(selection.extent)) + + Offset(0, preferredLineHeight(selection.extent)) + getOffsetForCaret(selection.extent), null); } @@ -666,7 +666,7 @@ class _BulletPoint extends StatelessWidget { return Container( alignment: AlignmentDirectional.topEnd, width: width, - padding: const EdgeInsetsDirectional.only(end: 13.0), + padding: const EdgeInsetsDirectional.only(end: 13), child: Text('•', style: style), ); } @@ -707,7 +707,7 @@ class __CheckboxState extends State<_Checkbox> { return Container( alignment: AlignmentDirectional.topEnd, width: widget.width, - padding: const EdgeInsetsDirectional.only(end: 13.0), + padding: const EdgeInsetsDirectional.only(end: 13), child: Checkbox( value: widget.isChecked, onChanged: _onCheckboxClicked, diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 8eff21c3..304742ac 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -57,7 +57,7 @@ class TextLine extends StatelessWidget { textSpan.style!, textAlign, textDirection!, - 1.0, + 1, Localizations.localeOf(context), strutStyle, TextWidthBasis.parent, @@ -458,7 +458,7 @@ class RenderEditableTextLine extends RenderEditableBox { TextSelection textSelection, bool first) { if (textSelection.isCollapsed) { return TextSelectionPoint( - Offset(0.0, preferredLineHeight(textSelection.extent)) + + Offset(0, preferredLineHeight(textSelection.extent)) + getOffsetForCaret(textSelection.extent), null); } @@ -473,7 +473,7 @@ class RenderEditableTextLine extends RenderEditableBox { @override TextRange getLineBoundary(TextPosition position) { final lineDy = getOffsetForCaret(position) - .translate(0.0, 0.5 * preferredLineHeight(position)) + .translate(0, 0.5 * preferredLineHeight(position)) .dy; final lineBoxes = _getBoxes(TextSelection(baseOffset: 0, extentOffset: line.length - 1)) @@ -543,15 +543,13 @@ class RenderEditableTextLine extends RenderEditableBox { switch (defaultTargetPlatform) { case TargetPlatform.iOS: case TargetPlatform.macOS: - _caretPrototype = - Rect.fromLTWH(0.0, 0.0, cursorWidth, cursorHeight + 2); + _caretPrototype = Rect.fromLTWH(0, 0, cursorWidth, cursorHeight + 2); break; case TargetPlatform.android: case TargetPlatform.fuchsia: case TargetPlatform.linux: case TargetPlatform.windows: - _caretPrototype = - Rect.fromLTWH(0.0, 2.0, cursorWidth, cursorHeight - 4.0); + _caretPrototype = Rect.fromLTWH(0, 2, cursorWidth, cursorHeight - 4.0); break; default: throw 'Invalid platform'; @@ -619,7 +617,7 @@ class RenderEditableTextLine extends RenderEditableBox { : _leading!.getMinIntrinsicWidth(height - verticalPadding) as int; final bodyWidth = _body == null ? 0 - : _body!.getMinIntrinsicWidth(math.max(0.0, height - verticalPadding)) + : _body!.getMinIntrinsicWidth(math.max(0, height - verticalPadding)) as int; return horizontalPadding + leadingWidth + bodyWidth; } @@ -634,7 +632,7 @@ class RenderEditableTextLine extends RenderEditableBox { : _leading!.getMaxIntrinsicWidth(height - verticalPadding) as int; final bodyWidth = _body == null ? 0 - : _body!.getMaxIntrinsicWidth(math.max(0.0, height - verticalPadding)) + : _body!.getMaxIntrinsicWidth(math.max(0, height - verticalPadding)) as int; return horizontalPadding + leadingWidth + bodyWidth; } @@ -646,7 +644,7 @@ class RenderEditableTextLine extends RenderEditableBox { final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; if (_body != null) { return _body! - .getMinIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + + .getMinIntrinsicHeight(math.max(0, width - horizontalPadding)) + verticalPadding; } return verticalPadding; @@ -659,7 +657,7 @@ class RenderEditableTextLine extends RenderEditableBox { final verticalPadding = _resolvedPadding!.top + _resolvedPadding!.bottom; if (_body != null) { return _body! - .getMaxIntrinsicHeight(math.max(0.0, width - horizontalPadding)) + + .getMaxIntrinsicHeight(math.max(0, width - horizontalPadding)) + verticalPadding; } return verticalPadding; @@ -704,7 +702,7 @@ class RenderEditableTextLine extends RenderEditableBox { maxHeight: _body!.size.height); _leading!.layout(leadingConstraints, parentUsesSize: true); (_leading!.parentData as BoxParentData).offset = - Offset(0.0, _resolvedPadding!.top); + Offset(0, _resolvedPadding!.top); } size = constraints.constrain(Size( diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index ff008742..d6d24467 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -99,7 +99,7 @@ class EditorTextSelectionOverlay { toolbar = OverlayEntry(builder: _buildToolbar); Overlay.of(context, rootOverlay: true, debugRequiredFor: debugRequiredFor)! .insert(toolbar!); - _toolbarController.forward(from: 0.0); + _toolbarController.forward(from: 0); } Widget _buildHandle( diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 9348c3af..73e0c9a7 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -14,7 +14,7 @@ import '../models/documents/style.dart'; import '../utils/color.dart'; import 'controller.dart'; -double iconSize = 18.0; +double iconSize = 18; double kToolbarHeight = iconSize * 2; typedef OnImagePickCallback = Future Function(File file); @@ -464,7 +464,7 @@ Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value, child: RawMaterialButton( hoverElevation: 0, highlightElevation: 0, - elevation: 0.0, + elevation: 0, visualDensity: VisualDensity.compact, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(2)), @@ -1265,7 +1265,7 @@ class _QuillDropdownButtonState extends State> { return ConstrainedBox( constraints: const BoxConstraints.tightFor(width: 110), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), + padding: const EdgeInsets.symmetric(horizontal: 8), child: Row( children: [ widget.child, From 5bab9188608b60d0237021365268e05128d2b720 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:47:14 +0200 Subject: [PATCH 12/19] Prefer interpolation to compose strings Using interpolation when composing strings and values is usually easier to write and read than concatenation. --- analysis_options.yaml | 1 + lib/models/documents/nodes/line.dart | 2 +- lib/utils/color.dart | 2 +- lib/utils/diff_delta.dart | 6 +----- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 22b167da..df405fed 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -26,6 +26,7 @@ linter: - prefer_final_locals - prefer_initializing_formals - prefer_int_literals + - prefer_interpolation_to_compose_strings - prefer_relative_imports - prefer_single_quotes - unnecessary_parenthesis diff --git a/lib/models/documents/nodes/line.dart b/lib/models/documents/nodes/line.dart index 08ec39ee..f3473ac9 100644 --- a/lib/models/documents/nodes/line.dart +++ b/lib/models/documents/nodes/line.dart @@ -55,7 +55,7 @@ class Line extends Container { } @override - String toPlainText() => super.toPlainText() + '\n'; + String toPlainText() => '${super.toPlainText()}\n'; @override String toString() { diff --git a/lib/utils/color.dart b/lib/utils/color.dart index f4c26040..93b6e12b 100644 --- a/lib/utils/color.dart +++ b/lib/utils/color.dart @@ -119,7 +119,7 @@ Color stringToColor(String? s) { } var hex = s.replaceFirst('#', ''); - hex = hex.length == 6 ? 'ff' + hex : hex; + hex = hex.length == 6 ? 'ff$hex' : hex; final val = int.parse(hex, radix: 16); return Color(val); } diff --git a/lib/utils/diff_delta.dart b/lib/utils/diff_delta.dart index a3653eb0..1e6d913e 100644 --- a/lib/utils/diff_delta.dart +++ b/lib/utils/diff_delta.dart @@ -79,11 +79,7 @@ int getPositionDelta(Delta user, Delta actual) { final userOperation = userItr.next(length as int); final actualOperation = actualItr.next(length); if (userOperation.length != actualOperation.length) { - throw 'userOp ' + - userOperation.length.toString() + - ' does not match ' + - ' actualOp ' + - actualOperation.length.toString(); + throw 'userOp ${userOperation.length} does not match actualOp ${actualOperation.length}'; } if (userOperation.key == actualOperation.key) { continue; From 483dba0e4a113d62e7252f881dfe28fd5a4dc709 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 20:49:27 +0200 Subject: [PATCH 13/19] Remove unnecessary string interpolations --- analysis_options.yaml | 1 + lib/widgets/text_block.dart | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index df405fed..e62a6e5c 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -30,3 +30,4 @@ linter: - prefer_relative_imports - prefer_single_quotes - unnecessary_parenthesis + - unnecessary_string_interpolations diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index 757a2c9c..61448d5a 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -580,7 +580,7 @@ class _NumberPoint extends StatelessWidget { alignment: AlignmentDirectional.topEnd, width: width, padding: EdgeInsetsDirectional.only(end: padding), - child: Text(withDot ? '$s.' : '$s', style: style), + child: Text(withDot ? '$s.' : s, style: style), ); } if (attrs.containsKey(Attribute.indent.key)) { @@ -611,7 +611,7 @@ class _NumberPoint extends StatelessWidget { alignment: AlignmentDirectional.topEnd, width: width, padding: EdgeInsetsDirectional.only(end: padding), - child: Text(withDot ? '$s.' : '$s', style: style), + child: Text(withDot ? '$s.' : s, style: style), ); } From e1793ead612a6a896ca07790e0edcab66a446f88 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 21:03:54 +0200 Subject: [PATCH 14/19] Fix linter warnings in example --- example/lib/pages/home_page.dart | 10 +++++----- example/lib/pages/read_only_page.dart | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index a613c085..34441303 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -74,7 +74,7 @@ class _HomePageState extends State { ), body: RawKeyboardListener( focusNode: FocusNode(), - onKey: (RawKeyEvent event) { + onKey: (event) { if (event.data.isControlPressed && event.character == 'b') { if (_controller! .getSelectionStyle() @@ -107,15 +107,15 @@ class _HomePageState extends State { customStyles: DefaultStyles( h1: DefaultTextBlockStyle( const TextStyle( - fontSize: 32.0, + fontSize: 32, color: Colors.black, height: 1.15, fontWeight: FontWeight.w300, ), - const Tuple2(16.0, 0.0), - const Tuple2(0.0, 0.0), + const Tuple2(16, 0), + const Tuple2(0, 0), null), - sizeSmall: const TextStyle(fontSize: 9.0), + sizeSmall: const TextStyle(fontSize: 9), )); if (kIsWeb) { quillEditor = QuillEditor( diff --git a/example/lib/pages/read_only_page.dart b/example/lib/pages/read_only_page.dart index 395c20f5..42957b52 100644 --- a/example/lib/pages/read_only_page.dart +++ b/example/lib/pages/read_only_page.dart @@ -53,7 +53,7 @@ class _ReadOnlyPageState extends State { embedBuilder: defaultEmbedBuilderWeb); } return Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(8), child: Container( decoration: BoxDecoration( color: Colors.white, From ff61b1a95111be7bea17d55f0fdd8e4fb8ea1105 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 21:15:58 +0200 Subject: [PATCH 15/19] Fix more warnings (forgot to save the files) --- example/lib/pages/home_page.dart | 16 ++++++++-------- example/lib/universal_ui/universal_ui.dart | 2 +- example/test/widget_test.dart | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/example/lib/pages/home_page.dart b/example/lib/pages/home_page.dart index 34441303..075f3f9b 100644 --- a/example/lib/pages/home_page.dart +++ b/example/lib/pages/home_page.dart @@ -131,15 +131,15 @@ class _HomePageState extends State { customStyles: DefaultStyles( h1: DefaultTextBlockStyle( const TextStyle( - fontSize: 32.0, + fontSize: 32, color: Colors.black, height: 1.15, fontWeight: FontWeight.w300, ), - const Tuple2(16.0, 0.0), - const Tuple2(0.0, 0.0), + const Tuple2(16, 0), + const Tuple2(0, 0), null), - sizeSmall: const TextStyle(fontSize: 9.0), + sizeSmall: const TextStyle(fontSize: 9), ), embedBuilder: defaultEmbedBuilderWeb); } @@ -151,7 +151,7 @@ class _HomePageState extends State { flex: 15, child: Container( color: Colors.white, - padding: const EdgeInsets.only(left: 16.0, right: 16.0), + padding: const EdgeInsets.only(left: 16, right: 16), child: quillEditor, ), ), @@ -186,7 +186,7 @@ class _HomePageState extends State { Widget _buildMenuBar(BuildContext context) { final size = MediaQuery.of(context).size; - final itemStyle = const TextStyle( + const itemStyle = TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, @@ -201,7 +201,7 @@ class _HomePageState extends State { endIndent: size.width * 0.1, ), ListTile( - title: Center(child: Text('Read only demo', style: itemStyle)), + title: const Center(child: Text('Read only demo', style: itemStyle)), dense: true, visualDensity: VisualDensity.compact, onTap: _readOnly, @@ -220,7 +220,7 @@ class _HomePageState extends State { Navigator.push( super.context, MaterialPageRoute( - builder: (BuildContext context) => ReadOnlyPage(), + builder: (context) => ReadOnlyPage(), ), ); } diff --git a/example/lib/universal_ui/universal_ui.dart b/example/lib/universal_ui/universal_ui.dart index 9c833aa2..b242af34 100644 --- a/example/lib/universal_ui/universal_ui.dart +++ b/example/lib/universal_ui/universal_ui.dart @@ -31,7 +31,7 @@ Widget defaultEmbedBuilderWeb(BuildContext context, leaf.Embed node) { final String imageUrl = node.value.data; final size = MediaQuery.of(context).size; UniversalUI().platformViewRegistry.registerViewFactory( - imageUrl, (int viewId) => html.ImageElement()..src = imageUrl); + imageUrl, (viewId) => html.ImageElement()..src = imageUrl); return Padding( padding: EdgeInsets.only( right: ResponsiveWidget.isMediumScreen(context) diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart index 5029542e..bf233450 100644 --- a/example/test/widget_test.dart +++ b/example/test/widget_test.dart @@ -10,7 +10,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:app/main.dart'; void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { + testWidgets('Counter increments smoke test', (tester) async { // Build our app and trigger a frame. await tester.pumpWidget(MyApp()); From 9a29446c97d58ba525bb227d4e7ede7fd62db105 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 21:21:23 +0200 Subject: [PATCH 16/19] Make the issue template a little more friendly --- .github/ISSUE_TEMPLATE/issue-template.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/issue-template.md b/.github/ISSUE_TEMPLATE/issue-template.md index a908ed53..ff759a4b 100644 --- a/.github/ISSUE_TEMPLATE/issue-template.md +++ b/.github/ISSUE_TEMPLATE/issue-template.md @@ -11,6 +11,6 @@ My issue is about [Web] My issue is about [Mobile] My issue is about [Desktop] -I have tried running `example` directory successfully before creating an issue here AND it is NOT a stupid question. +I have tried running `example` directory successfully before creating an issue here. Please note that we are using stable channel. If you are using beta or master channel, those are not supported. From 873bfbcee112d18143cfc3b589524f0ba4f6e49b Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 21:46:10 +0200 Subject: [PATCH 17/19] Sort constructors first --- analysis_options.yaml | 2 + example/lib/widgets/demo_scaffold.dart | 14 +-- lib/models/documents/attribute.dart | 4 +- lib/models/documents/document.dart | 24 ++-- lib/models/documents/history.dart | 21 ++-- lib/models/documents/nodes/container.dart | 4 +- lib/models/documents/nodes/embed.dart | 4 +- lib/models/documents/nodes/leaf.dart | 12 +- lib/models/documents/style.dart | 4 +- lib/models/quill_delta.dart | 68 +++++------ lib/models/rules/rule.dart | 4 +- lib/utils/diff_delta.dart | 4 +- lib/widgets/controller.dart | 8 +- lib/widgets/cursor.dart | 40 +++---- lib/widgets/default_styles.dart | 59 +++++----- lib/widgets/delegate.dart | 4 +- lib/widgets/editor.dart | 126 ++++++++++---------- lib/widgets/keyboard_listener.dart | 5 +- lib/widgets/proxy.dart | 30 ++--- lib/widgets/raw_editor.dart | 66 +++++------ lib/widgets/responsive_widget.dart | 8 +- lib/widgets/text_block.dart | 71 ++++++------ lib/widgets/text_line.dart | 62 +++++----- lib/widgets/text_selection.dart | 41 +++---- lib/widgets/toolbar.dart | 134 +++++++++++----------- 25 files changed, 422 insertions(+), 397 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index e62a6e5c..2fc4fec6 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -29,5 +29,7 @@ linter: - prefer_interpolation_to_compose_strings - prefer_relative_imports - prefer_single_quotes + - sort_constructors_first + - sort_unnamed_constructors_first - unnecessary_parenthesis - unnecessary_string_interpolations diff --git a/example/lib/widgets/demo_scaffold.dart b/example/lib/widgets/demo_scaffold.dart index 52d44e4f..4098a5f6 100644 --- a/example/lib/widgets/demo_scaffold.dart +++ b/example/lib/widgets/demo_scaffold.dart @@ -11,13 +11,6 @@ typedef DemoContentBuilder = Widget Function( // 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 bool showToolbar; - const DemoScaffold({ required this.documentFilename, required this.builder, @@ -27,6 +20,13 @@ class DemoScaffold extends StatefulWidget { Key? key, }) : super(key: key); + /// Filename of the document to load into the editor. + final String documentFilename; + final DemoContentBuilder builder; + final List? actions; + final Widget? floatingActionButton; + final bool showToolbar; + @override _DemoScaffoldState createState() => _DemoScaffoldState(); } diff --git a/lib/models/documents/attribute.dart b/lib/models/documents/attribute.dart index 7683b9ed..18822e01 100644 --- a/lib/models/documents/attribute.dart +++ b/lib/models/documents/attribute.dart @@ -8,12 +8,12 @@ enum AttributeScope { } class Attribute { + Attribute(this.key, this.scope, this.value); + final String key; final AttributeScope scope; final T value; - Attribute(this.key, this.scope, this.value); - static final Map _registry = { Attribute.bold.key: Attribute.bold, Attribute.italic.key: Attribute.italic, diff --git a/lib/models/documents/document.dart b/lib/models/documents/document.dart index 232642fb..0362665e 100644 --- a/lib/models/documents/document.dart +++ b/lib/models/documents/document.dart @@ -15,6 +15,18 @@ import 'style.dart'; /// The rich text document class Document { + Document() : _delta = Delta()..insert('\n') { + _loadDocument(_delta); + } + + Document.fromJson(List data) : _delta = _transform(Delta.fromJson(data)) { + _loadDocument(_delta); + } + + Document.fromDelta(Delta delta) : _delta = delta { + _loadDocument(delta); + } + /// The root node of the document tree final Root _root = Root(); @@ -35,18 +47,6 @@ class Document { Stream> get changes => _observer.stream; - Document() : _delta = Delta()..insert('\n') { - _loadDocument(_delta); - } - - Document.fromJson(List data) : _delta = _transform(Delta.fromJson(data)) { - _loadDocument(_delta); - } - - Document.fromDelta(Delta delta) : _delta = delta { - _loadDocument(delta); - } - Delta insert(int index, Object? data) { assert(index >= 0); assert(data is String || data is Embeddable); diff --git a/lib/models/documents/history.dart b/lib/models/documents/history.dart index 9398ad1c..d406505e 100644 --- a/lib/models/documents/history.dart +++ b/lib/models/documents/history.dart @@ -4,6 +4,14 @@ import '../quill_delta.dart'; import 'document.dart'; class History { + History({ + this.ignoreChange = false, + this.interval = 400, + this.maxStack = 100, + this.userOnly = false, + this.lastRecorded = 0, + }); + final HistoryStack stack = HistoryStack.empty(); bool get hasUndo => stack.undo.isNotEmpty; @@ -24,13 +32,6 @@ class History { ///record delay final int interval; - History( - {this.ignoreChange = false, - this.interval = 400, - this.maxStack = 100, - this.userOnly = false, - this.lastRecorded = 0}); - void handleDocChange(Tuple3 change) { if (ignoreChange) return; if (!userOnly || change.item3 == ChangeSource.LOCAL) { @@ -119,13 +120,13 @@ class History { } class HistoryStack { - final List undo; - final List redo; - HistoryStack.empty() : undo = [], redo = []; + final List undo; + final List redo; + void clear() { undo.clear(); redo.clear(); diff --git a/lib/models/documents/nodes/container.dart b/lib/models/documents/nodes/container.dart index 8b3fd0c3..28fc2475 100644 --- a/lib/models/documents/nodes/container.dart +++ b/lib/models/documents/nodes/container.dart @@ -116,9 +116,9 @@ abstract class Container extends Node { /// Query of a child in a Container class ChildQuery { + ChildQuery(this.node, this.offset); + final Node? node; // null if not found final int offset; - - ChildQuery(this.node, this.offset); } diff --git a/lib/models/documents/nodes/embed.dart b/lib/models/documents/nodes/embed.dart index cc0ecaea..81ca6005 100644 --- a/lib/models/documents/nodes/embed.dart +++ b/lib/models/documents/nodes/embed.dart @@ -1,9 +1,9 @@ class Embeddable { + Embeddable(this.type, this.data); + final String type; final dynamic data; - Embeddable(this.type, this.data); - Map toJson() { final m = {type: data}; return m; diff --git a/lib/models/documents/nodes/leaf.dart b/lib/models/documents/nodes/leaf.dart index 3d98060e..24431fc9 100644 --- a/lib/models/documents/nodes/leaf.dart +++ b/lib/models/documents/nodes/leaf.dart @@ -8,12 +8,6 @@ import 'node.dart'; /* A leaf node in document tree */ abstract class Leaf extends Node { - Object _value; - - Object get value => _value; - - Leaf.val(Object val) : _value = val; - factory Leaf(Object data) { if (data is Embeddable) { return Embed(data); @@ -23,6 +17,12 @@ abstract class Leaf extends Node { return Text(text); } + Leaf.val(Object val) : _value = val; + + Object _value; + + Object get value => _value; + @override void applyStyle(Style value) { assert(value.isInline || value.isIgnored || value.isEmpty, diff --git a/lib/models/documents/style.dart b/lib/models/documents/style.dart index f8a8ee74..c805280d 100644 --- a/lib/models/documents/style.dart +++ b/lib/models/documents/style.dart @@ -5,11 +5,11 @@ import 'attribute.dart'; /* Collection of style attributes */ class Style { - final Map _attributes; + Style() : _attributes = {}; Style.attr(this._attributes); - Style() : _attributes = {}; + final Map _attributes; static Style fromJson(Map? attributes) { if (attributes == null) { diff --git a/lib/models/quill_delta.dart b/lib/models/quill_delta.dart index 0135bd6a..895b27fe 100644 --- a/lib/models/quill_delta.dart +++ b/lib/models/quill_delta.dart @@ -22,6 +22,29 @@ Object? _passThroughDataDecoder(Object? data) => data; /// Operation performed on a rich-text document. class Operation { + 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; + }(), 'Length of insert operation must be equal to the data length.'), + _attributes = + attributes != null ? Map.from(attributes) : null; + + /// Creates operation which deletes [length] of characters. + factory Operation.delete(int length) => + Operation._(Operation.deleteKey, length, '', null); + + /// Creates operation which inserts [text] with optional [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]) => + Operation._(Operation.retainKey, length, '', attributes); + /// Key of insert operations. static const String insertKey = 'insert'; @@ -50,15 +73,6 @@ class Operation { _attributes == null ? null : Map.from(_attributes!); final Map? _attributes; - 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; - }(), 'Length of insert operation must be equal to the data length.'), - _attributes = - attributes != null ? Map.from(attributes) : null; - /// Creates new [Operation] from JSON payload. /// /// If `dataDecoder` parameter is not null then it is used to additionally @@ -89,20 +103,6 @@ class Operation { return json; } - /// Creates operation which deletes [length] of characters. - factory Operation.delete(int length) => - Operation._(Operation.deleteKey, length, '', null); - - /// Creates operation which inserts [text] with optional [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]) => - Operation._(Operation.retainKey, length, '', attributes); - /// Returns value of this operation. /// /// For insert operations this returns text, for delete and retain - length. @@ -180,6 +180,15 @@ class Operation { /// "document delta". When delta includes also "retain" or "delete" operations /// it is a "change delta". class Delta { + /// Creates new empty [Delta]. + factory Delta() => Delta._([]); + + Delta._(List operations) : _operations = operations; + + /// Creates new [Delta] from [other]. + factory Delta.from(Delta other) => + Delta._(List.from(other._operations)); + /// Transforms two attribute sets. static Map? transformAttributes( Map? a, Map? b, bool priority) { @@ -242,15 +251,6 @@ class Delta { int _modificationCount = 0; - Delta._(List operations) : _operations = operations; - - /// Creates new empty [Delta]. - factory Delta() => Delta._([]); - - /// Creates new [Delta] from [other]. - factory Delta.from(Delta other) => - Delta._(List.from(other._operations)); - /// Creates [Delta] from de-serialized JSON representation. /// /// If `dataDecoder` parameter is not null then it is used to additionally @@ -599,13 +599,13 @@ class Delta { /// Specialized iterator for [Delta]s. class DeltaIterator { + DeltaIterator(this.delta) : _modificationCount = delta._modificationCount; + final Delta delta; final int _modificationCount; int _index = 0; num _offset = 0; - DeltaIterator(this.delta) : _modificationCount = delta._modificationCount; - bool get isNextInsert => nextOperationKey == Operation.insertKey; bool get isNextDelete => nextOperationKey == Operation.deleteKey; diff --git a/lib/models/rules/rule.dart b/lib/models/rules/rule.dart index 19bc9177..4ee6c278 100644 --- a/lib/models/rules/rule.dart +++ b/lib/models/rules/rule.dart @@ -26,6 +26,8 @@ abstract class Rule { } class Rules { + Rules(this._rules); + final List _rules; static final Rules _instance = Rules([ const FormatLinkAtCaretPositionRule(), @@ -45,8 +47,6 @@ class Rules { const CatchAllDeleteRule(), ]); - Rules(this._rules); - static Rules getInstance() => _instance; Delta apply(RuleType ruleType, Document document, int index, diff --git a/lib/utils/diff_delta.dart b/lib/utils/diff_delta.dart index 1e6d913e..003bae47 100644 --- a/lib/utils/diff_delta.dart +++ b/lib/utils/diff_delta.dart @@ -33,6 +33,8 @@ const Set WHITE_SPACE = { // Diff between two texts - old text and new text class Diff { + Diff(this.start, this.deleted, this.inserted); + // Start index in old text at which changes begin. final int start; @@ -42,8 +44,6 @@ class Diff { // The inserted text final String inserted; - Diff(this.start, this.deleted, this.inserted); - @override String toString() { return 'Diff[$start, "$deleted", "$inserted"]'; diff --git a/lib/widgets/controller.dart b/lib/widgets/controller.dart index faabf4c2..3bd66b6f 100644 --- a/lib/widgets/controller.dart +++ b/lib/widgets/controller.dart @@ -11,10 +11,6 @@ import '../models/quill_delta.dart'; import '../utils/diff_delta.dart'; class QuillController extends ChangeNotifier { - final Document document; - TextSelection selection; - Style toggledStyle = Style(); - QuillController({required this.document, required this.selection}); factory QuillController.basic() { @@ -24,6 +20,10 @@ class QuillController extends ChangeNotifier { ); } + final Document document; + TextSelection selection; + Style toggledStyle = Style(); + // item1: Document state before [change]. // // item2: Change delta applied to the document. diff --git a/lib/widgets/cursor.dart b/lib/widgets/cursor.dart index 307e70a5..383906d0 100644 --- a/lib/widgets/cursor.dart +++ b/lib/widgets/cursor.dart @@ -8,15 +8,6 @@ import 'box.dart'; const Duration _FADE_DURATION = Duration(milliseconds: 250); class CursorStyle { - final Color color; - final Color backgroundColor; - final double width; - final double? height; - final Radius? radius; - final Offset? offset; - final bool opacityAnimates; - final bool paintAboveText; - const CursorStyle({ required this.color, required this.backgroundColor, @@ -28,6 +19,15 @@ class CursorStyle { this.paintAboveText = false, }); + final Color color; + final Color backgroundColor; + final double width; + final double? height; + final Radius? radius; + final Offset? offset; + final bool opacityAnimates; + final bool paintAboveText; + @override bool operator ==(Object other) => identical(this, other) || @@ -55,14 +55,6 @@ class CursorStyle { } class CursorCont extends ChangeNotifier { - final ValueNotifier show; - final ValueNotifier _blink; - final ValueNotifier color; - late AnimationController _blinkOpacityCont; - Timer? _cursorTimer; - bool _targetCursorVisibility = false; - CursorStyle _style; - CursorCont({ required this.show, required CursorStyle style, @@ -75,6 +67,14 @@ class CursorCont extends ChangeNotifier { _blinkOpacityCont.addListener(_onColorTick); } + final ValueNotifier show; + final ValueNotifier _blink; + final ValueNotifier color; + late AnimationController _blinkOpacityCont; + Timer? _cursorTimer; + bool _targetCursorVisibility = false; + CursorStyle _style; + ValueNotifier get cursorBlink => _blink; ValueNotifier get cursorColor => color; @@ -156,15 +156,15 @@ class CursorCont extends ChangeNotifier { } class CursorPainter { + CursorPainter(this.editable, this.style, this.prototype, this.color, + this.devicePixelRatio); + final RenderContentProxyBox? editable; final CursorStyle style; final Rect? prototype; final Color color; final double devicePixelRatio; - CursorPainter(this.editable, this.style, this.prototype, this.color, - this.devicePixelRatio); - void paint(Canvas canvas, Offset offset, TextPosition position) { assert(prototype != null); diff --git a/lib/widgets/default_styles.dart b/lib/widgets/default_styles.dart index 8612d92b..1cebe135 100644 --- a/lib/widgets/default_styles.dart +++ b/lib/widgets/default_styles.dart @@ -3,14 +3,14 @@ import 'package:flutter/widgets.dart'; import 'package:tuple/tuple.dart'; class QuillStyles extends InheritedWidget { - final DefaultStyles data; - const QuillStyles({ required this.data, required Widget child, Key? key, }) : super(key: key, child: child); + final DefaultStyles data; + @override bool updateShouldNotify(QuillStyles oldWidget) { return data != oldWidget.data; @@ -27,6 +27,13 @@ class QuillStyles extends InheritedWidget { } class DefaultTextBlockStyle { + DefaultTextBlockStyle( + this.style, + this.verticalSpacing, + this.lineSpacing, + this.decoration, + ); + final TextStyle style; final Tuple2 verticalSpacing; @@ -34,12 +41,32 @@ class DefaultTextBlockStyle { final Tuple2 lineSpacing; final BoxDecoration? decoration; - - DefaultTextBlockStyle( - this.style, this.verticalSpacing, this.lineSpacing, this.decoration); } class DefaultStyles { + DefaultStyles({ + this.h1, + this.h2, + this.h3, + this.paragraph, + this.bold, + this.italic, + this.underline, + this.strikeThrough, + this.link, + this.color, + this.placeHolder, + this.lists, + this.quote, + this.code, + this.indent, + this.align, + this.leading, + this.sizeSmall, + this.sizeLarge, + this.sizeHuge, + }); + final DefaultTextBlockStyle? h1; final DefaultTextBlockStyle? h2; final DefaultTextBlockStyle? h3; @@ -61,28 +88,6 @@ class DefaultStyles { final DefaultTextBlockStyle? align; final DefaultTextBlockStyle? leading; - DefaultStyles( - {this.h1, - this.h2, - this.h3, - this.paragraph, - this.bold, - this.italic, - this.underline, - this.strikeThrough, - this.link, - this.color, - this.placeHolder, - this.lists, - this.quote, - this.code, - this.indent, - this.align, - this.leading, - this.sizeSmall, - this.sizeLarge, - this.sizeHuge}); - static DefaultStyles getInstance(BuildContext context) { final themeData = Theme.of(context); final defaultTextStyle = DefaultTextStyle.of(context); diff --git a/lib/widgets/delegate.dart b/lib/widgets/delegate.dart index 8adf8ce7..4b4bdea7 100644 --- a/lib/widgets/delegate.dart +++ b/lib/widgets/delegate.dart @@ -18,11 +18,11 @@ abstract class EditorTextSelectionGestureDetectorBuilderDelegate { } class EditorTextSelectionGestureDetectorBuilder { + EditorTextSelectionGestureDetectorBuilder(this.delegate); + final EditorTextSelectionGestureDetectorBuilderDelegate delegate; bool shouldShowSelectionToolbar = true; - EditorTextSelectionGestureDetectorBuilder(this.delegate); - EditorState? getEditor() { return delegate.getEditableTextKey().currentState; } diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index c3d5d2cb..3b33211c 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -114,6 +114,43 @@ Widget _defaultEmbedBuilder(BuildContext context, leaf.Embed node) { } class QuillEditor extends StatefulWidget { + const QuillEditor({ + required this.controller, + required this.focusNode, + required this.scrollController, + required this.scrollable, + required this.padding, + required this.autoFocus, + required this.readOnly, + required this.expands, + this.showCursor, + this.placeholder, + this.enableInteractiveSelection = true, + this.minHeight, + this.maxHeight, + this.customStyles, + this.textCapitalization = TextCapitalization.sentences, + this.keyboardAppearance = Brightness.light, + this.scrollPhysics, + this.onLaunchUrl, + this.embedBuilder = _defaultEmbedBuilder, + }); + + factory QuillEditor.basic({ + required QuillController controller, + required bool readOnly, + }) { + return QuillEditor( + controller: controller, + scrollController: ScrollController(), + scrollable: true, + focusNode: FocusNode(), + autoFocus: true, + readOnly: readOnly, + expands: false, + padding: EdgeInsets.zero); + } + final QuillController controller; final FocusNode focusNode; final ScrollController scrollController; @@ -134,40 +171,6 @@ class QuillEditor extends StatefulWidget { final ValueChanged? onLaunchUrl; final EmbedBuilder embedBuilder; - const QuillEditor( - {required this.controller, - required this.focusNode, - required this.scrollController, - required this.scrollable, - required this.padding, - required this.autoFocus, - required this.readOnly, - required this.expands, - this.showCursor, - this.placeholder, - this.enableInteractiveSelection = true, - this.minHeight, - this.maxHeight, - this.customStyles, - this.textCapitalization = TextCapitalization.sentences, - this.keyboardAppearance = Brightness.light, - this.scrollPhysics, - this.onLaunchUrl, - this.embedBuilder = _defaultEmbedBuilder}); - - factory QuillEditor.basic( - {required QuillController controller, required bool readOnly}) { - return QuillEditor( - controller: controller, - scrollController: ScrollController(), - scrollable: true, - focusNode: FocusNode(), - autoFocus: true, - readOnly: readOnly, - expands: false, - padding: EdgeInsets.zero); - } - @override _QuillEditorState createState() => _QuillEditorState(); } @@ -295,10 +298,10 @@ class _QuillEditorState extends State class _QuillEditorSelectionGestureDetectorBuilder extends EditorTextSelectionGestureDetectorBuilder { - final _QuillEditorState _state; - _QuillEditorSelectionGestureDetectorBuilder(this._state) : super(_state); + final _QuillEditorState _state; + @override void onForcePressStart(ForcePressDetails details) { super.onForcePressStart(details); @@ -495,6 +498,24 @@ typedef TextSelectionChangedHandler = void Function( class RenderEditor extends RenderEditableContainerBox implements RenderAbstractEditor { + RenderEditor( + List? children, + TextDirection textDirection, + EdgeInsetsGeometry padding, + this.document, + this.selection, + this._hasFocus, + this.onSelectionChanged, + this._startHandleLayerLink, + this._endHandleLayerLink, + EdgeInsets floatingCursorAddedMargin, + ) : super( + children, + document.root, + textDirection, + padding, + ); + Document document; TextSelection selection; bool _hasFocus = false; @@ -510,24 +531,6 @@ class RenderEditor extends RenderEditableContainerBox ValueListenable get selectionEndInViewport => _selectionEndInViewport; final ValueNotifier _selectionEndInViewport = ValueNotifier(true); - RenderEditor( - List? children, - TextDirection textDirection, - EdgeInsetsGeometry padding, - this.document, - this.selection, - this._hasFocus, - this.onSelectionChanged, - this._startHandleLayerLink, - this._endHandleLayerLink, - EdgeInsets floatingCursorAddedMargin) - : super( - children, - document.root, - textDirection, - padding, - ); - void setDocument(Document doc) { if (document == doc) { return; @@ -866,17 +869,20 @@ class RenderEditableContainerBox extends RenderBox EditableContainerParentData>, RenderBoxContainerDefaultsMixin { + RenderEditableContainerBox( + List? children, + this._container, + this.textDirection, + this._padding, + ) : assert(_padding.isNonNegative) { + addAll(children); + } + container_node.Container _container; TextDirection textDirection; EdgeInsetsGeometry _padding; EdgeInsets? _resolvedPadding; - RenderEditableContainerBox(List? children, this._container, - this.textDirection, this._padding) - : assert(_padding.isNonNegative) { - addAll(children); - } - container_node.Container getContainer() { return _container; } diff --git a/lib/widgets/keyboard_listener.dart b/lib/widgets/keyboard_listener.dart index f952c3dd..17c47aad 100644 --- a/lib/widgets/keyboard_listener.dart +++ b/lib/widgets/keyboard_listener.dart @@ -9,9 +9,12 @@ typedef InputShortcutCallback = void Function(InputShortcut? shortcut); typedef OnDeleteCallback = void Function(bool forward); class KeyboardListener { + KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete); + final CursorMoveCallback onCursorMove; final InputShortcutCallback onShortcut; final OnDeleteCallback onDelete; + static final Set _moveKeys = { LogicalKeyboardKey.arrowRight, LogicalKeyboardKey.arrowLeft, @@ -59,8 +62,6 @@ class KeyboardListener { LogicalKeyboardKey.keyA: InputShortcut.SELECT_ALL, }; - KeyboardListener(this.onCursorMove, this.onShortcut, this.onDelete); - bool handleRawKeyEvent(RawKeyEvent event) { if (kIsWeb) { // On web platform, we should ignore the key because it's processed already. diff --git a/lib/widgets/proxy.dart b/lib/widgets/proxy.dart index bae59f1b..8a04c4e1 100644 --- a/lib/widgets/proxy.dart +++ b/lib/widgets/proxy.dart @@ -4,12 +4,12 @@ import 'package:flutter/widgets.dart'; import 'box.dart'; class BaselineProxy extends SingleChildRenderObjectWidget { - final TextStyle? textStyle; - final EdgeInsets? padding; - const BaselineProxy({Key? key, Widget? child, this.textStyle, this.padding}) : super(key: key, child: child); + final TextStyle? textStyle; + final EdgeInsets? padding; + @override RenderBaselineProxy createRenderObject(BuildContext context) { return RenderBaselineProxy( @@ -122,6 +122,18 @@ class RenderEmbedProxy extends RenderProxyBox implements RenderContentProxyBox { } class RichTextProxy extends SingleChildRenderObjectWidget { + const RichTextProxy( + RichText child, + this.textStyle, + this.textAlign, + this.textDirection, + this.textScaleFactor, + this.locale, + this.strutStyle, + this.textWidthBasis, + this.textHeightBehavior, + ) : super(child: child); + final TextStyle textStyle; final TextAlign textAlign; final TextDirection textDirection; @@ -145,18 +157,6 @@ class RichTextProxy extends SingleChildRenderObjectWidget { textHeightBehavior); } - const RichTextProxy( - RichText child, - this.textStyle, - this.textAlign, - this.textDirection, - this.textScaleFactor, - this.locale, - this.strutStyle, - this.textWidthBasis, - this.textHeightBehavior) - : super(child: child); - @override void updateRenderObject( BuildContext context, covariant RenderParagraphProxy renderObject) { diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index cf293aba..72422991 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -28,6 +28,39 @@ import 'text_line.dart'; import 'text_selection.dart'; class RawEditor extends StatefulWidget { + const RawEditor( + Key key, + this.controller, + this.focusNode, + this.scrollController, + this.scrollable, + this.padding, + this.readOnly, + this.placeholder, + this.onLaunchUrl, + this.toolbarOptions, + this.showSelectionHandles, + bool? showCursor, + this.cursorStyle, + this.textCapitalization, + this.maxHeight, + this.minHeight, + this.customStyles, + this.expands, + this.autoFocus, + this.selectionColor, + this.selectionCtrls, + this.keyboardAppearance, + this.enableInteractiveSelection, + this.scrollPhysics, + this.embedBuilder, + ) : 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'), + showCursor = showCursor ?? true, + super(key: key); + final QuillController controller; final FocusNode focusNode; final ScrollController scrollController; @@ -53,39 +86,6 @@ class RawEditor extends StatefulWidget { final ScrollPhysics? scrollPhysics; final EmbedBuilder embedBuilder; - const RawEditor( - Key key, - this.controller, - this.focusNode, - this.scrollController, - this.scrollable, - this.padding, - this.readOnly, - this.placeholder, - this.onLaunchUrl, - this.toolbarOptions, - this.showSelectionHandles, - bool? showCursor, - this.cursorStyle, - this.textCapitalization, - this.maxHeight, - this.minHeight, - this.customStyles, - this.expands, - this.autoFocus, - this.selectionColor, - this.selectionCtrls, - this.keyboardAppearance, - this.enableInteractiveSelection, - this.scrollPhysics, - this.embedBuilder) - : 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'), - showCursor = showCursor ?? true, - super(key: key); - @override State createState() { return RawEditorState(); diff --git a/lib/widgets/responsive_widget.dart b/lib/widgets/responsive_widget.dart index dbfec8d5..3829565c 100644 --- a/lib/widgets/responsive_widget.dart +++ b/lib/widgets/responsive_widget.dart @@ -1,10 +1,6 @@ import 'package:flutter/material.dart'; class ResponsiveWidget extends StatelessWidget { - final Widget largeScreen; - final Widget? mediumScreen; - final Widget? smallScreen; - const ResponsiveWidget({ required this.largeScreen, this.mediumScreen, @@ -12,6 +8,10 @@ class ResponsiveWidget extends StatelessWidget { Key? key, }) : super(key: key); + final Widget largeScreen; + final Widget? mediumScreen; + final Widget? smallScreen; + static bool isSmallScreen(BuildContext context) { return MediaQuery.of(context).size.width < 800; } diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index 61448d5a..25ea8d9c 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -47,6 +47,21 @@ const List romanNumbers = [ ]; class EditableTextBlock extends StatelessWidget { + const EditableTextBlock( + this.block, + this.textDirection, + this.verticalSpacing, + this.textSelection, + this.color, + this.styles, + this.enableInteractiveSelection, + this.hasFocus, + this.contentPadding, + this.embedBuilder, + this.cursorCont, + this.indentLevelCounts, + ); + final Block block; final TextDirection textDirection; final Tuple2 verticalSpacing; @@ -60,20 +75,6 @@ class EditableTextBlock extends StatelessWidget { final CursorCont cursorCont; final Map indentLevelCounts; - const EditableTextBlock( - this.block, - this.textDirection, - this.verticalSpacing, - this.textSelection, - this.color, - this.styles, - this.enableInteractiveSelection, - this.hasFocus, - this.contentPadding, - this.embedBuilder, - this.cursorCont, - this.indentLevelCounts); - @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); @@ -509,16 +510,21 @@ class RenderEditableTextBlock extends RenderEditableContainerBox } class _EditableBlock extends MultiChildRenderObjectWidget { + _EditableBlock( + this.block, + this.textDirection, + this.padding, + this.decoration, + this.contentPadding, + List children, + ) : super(children: children); + final Block block; final TextDirection textDirection; final Tuple2 padding; final Decoration decoration; final EdgeInsets? contentPadding; - _EditableBlock(this.block, this.textDirection, this.padding, this.decoration, - this.contentPadding, List children) - : super(children: children); - EdgeInsets get _padding => EdgeInsets.only(top: padding.item1, bottom: padding.item2); @@ -548,15 +554,6 @@ class _EditableBlock extends MultiChildRenderObjectWidget { } class _NumberPoint extends StatelessWidget { - final int index; - final Map indentLevelCounts; - final int count; - final TextStyle style; - final double width; - final Map attrs; - final bool withDot; - final double padding; - const _NumberPoint({ required this.index, required this.indentLevelCounts, @@ -569,6 +566,15 @@ class _NumberPoint extends StatelessWidget { Key? key, }) : super(key: key); + final int index; + final Map indentLevelCounts; + final int count; + final TextStyle style; + final double width; + final Map attrs; + final bool withDot; + final double padding; + @override Widget build(BuildContext context) { var s = index.toString(); @@ -652,15 +658,15 @@ class _NumberPoint extends StatelessWidget { } class _BulletPoint extends StatelessWidget { - final TextStyle style; - final double width; - const _BulletPoint({ required this.style, required this.width, Key? key, }) : super(key: key); + final TextStyle style; + final double width; + @override Widget build(BuildContext context) { return Container( @@ -673,12 +679,13 @@ class _BulletPoint extends StatelessWidget { } class _Checkbox extends StatefulWidget { + const _Checkbox({Key? key, this.style, this.width, this.isChecked}) + : super(key: key); + final TextStyle? style; final double? width; final bool? isChecked; - const _Checkbox({Key? key, this.style, this.width, this.isChecked}) - : super(key: key); @override __CheckboxState createState() => __CheckboxState(); } diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 304742ac..43cc6969 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -20,11 +20,6 @@ import 'proxy.dart'; import 'text_selection.dart'; class TextLine extends StatelessWidget { - final Line line; - final TextDirection? textDirection; - final EmbedBuilder embedBuilder; - final DefaultStyles styles; - const TextLine({ required this.line, required this.embedBuilder, @@ -33,6 +28,11 @@ class TextLine extends StatelessWidget { Key? key, }) : super(key: key); + final Line line; + final TextDirection? textDirection; + final EmbedBuilder embedBuilder; + final DefaultStyles styles; + @override Widget build(BuildContext context) { assert(debugCheckHasMediaQuery(context)); @@ -194,6 +194,21 @@ class TextLine extends StatelessWidget { } class EditableTextLine extends RenderObjectWidget { + const EditableTextLine( + this.line, + this.leading, + this.body, + this.indentWidth, + this.verticalSpacing, + this.textDirection, + this.textSelection, + this.color, + this.enableInteractiveSelection, + this.hasFocus, + this.devicePixelRatio, + this.cursorCont, + ); + final Line line; final Widget? leading; final Widget body; @@ -207,20 +222,6 @@ class EditableTextLine extends RenderObjectWidget { final double devicePixelRatio; final CursorCont cursorCont; - const EditableTextLine( - this.line, - this.leading, - this.body, - this.indentWidth, - this.verticalSpacing, - this.textDirection, - this.textSelection, - this.color, - this.enableInteractiveSelection, - this.hasFocus, - this.devicePixelRatio, - this.cursorCont); - @override RenderObjectElement createElement() { return _TextLineElement(this); @@ -266,6 +267,18 @@ class EditableTextLine extends RenderObjectWidget { enum TextLineSlot { LEADING, BODY } class RenderEditableTextLine extends RenderEditableBox { + RenderEditableTextLine( + this.line, + this.textDirection, + this.textSelection, + this.enableInteractiveSelection, + this.hasFocus, + this.devicePixelRatio, + this.padding, + this.color, + this.cursorCont, + ); + RenderBox? _leading; RenderContentProxyBox? _body; Line line; @@ -283,17 +296,6 @@ class RenderEditableTextLine extends RenderEditableBox { Rect? _caretPrototype; final Map children = {}; - RenderEditableTextLine( - this.line, - this.textDirection, - this.textSelection, - this.enableInteractiveSelection, - this.hasFocus, - this.devicePixelRatio, - this.padding, - this.color, - this.cursorCont); - Iterable get _children sync* { if (_leading != null) { yield _leading!; diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index d6d24467..fe28741b 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -24,6 +24,27 @@ TextSelection localSelection(Node node, TextSelection selection, fromParent) { enum _TextSelectionHandlePosition { START, END } class EditorTextSelectionOverlay { + EditorTextSelectionOverlay( + this.value, + this.handlesVisible, + this.context, + this.debugRequiredFor, + this.toolbarLayerLink, + this.startHandleLayerLink, + this.endHandleLayerLink, + this.renderObject, + this.selectionCtrls, + this.selectionDelegate, + this.dragStartBehavior, + this.onSelectionHandleTapped, + this.clipboardStatus, + ) { + final overlay = Overlay.of(context, rootOverlay: true)!; + + _toolbarController = AnimationController( + duration: const Duration(milliseconds: 150), vsync: overlay); + } + TextEditingValue value; bool handlesVisible = false; final BuildContext context; @@ -41,26 +62,6 @@ class EditorTextSelectionOverlay { List? _handles; OverlayEntry? toolbar; - EditorTextSelectionOverlay( - this.value, - this.handlesVisible, - this.context, - this.debugRequiredFor, - this.toolbarLayerLink, - this.startHandleLayerLink, - this.endHandleLayerLink, - this.renderObject, - this.selectionCtrls, - this.selectionDelegate, - this.dragStartBehavior, - this.onSelectionHandleTapped, - this.clipboardStatus) { - final overlay = Overlay.of(context, rootOverlay: true)!; - - _toolbarController = AnimationController( - duration: const Duration(milliseconds: 150), vsync: overlay); - } - TextSelection get _selection => value.selection; Animation get _toolbarOpacity => _toolbarController.view; diff --git a/lib/widgets/toolbar.dart b/lib/widgets/toolbar.dart index 73e0c9a7..71ddec1d 100644 --- a/lib/widgets/toolbar.dart +++ b/lib/widgets/toolbar.dart @@ -21,15 +21,15 @@ typedef OnImagePickCallback = Future Function(File file); typedef ImagePickImpl = Future Function(ImageSource source); class InsertEmbedButton extends StatelessWidget { - final QuillController controller; - final IconData icon; - const InsertEmbedButton({ required this.controller, required this.icon, Key? key, }) : super(key: key); + final QuillController controller; + final IconData icon; + @override Widget build(BuildContext context) { return QuillIconButton( @@ -52,15 +52,15 @@ class InsertEmbedButton extends StatelessWidget { } class LinkStyleButton extends StatefulWidget { - final QuillController controller; - final IconData? icon; - const LinkStyleButton({ required this.controller, this.icon, Key? key, }) : super(key: key); + final QuillController controller; + final IconData? icon; + @override _LinkStyleButtonState createState() => _LinkStyleButtonState(); } @@ -174,14 +174,6 @@ typedef ToggleStyleButtonBuilder = Widget Function( ); class ToggleStyleButton extends StatefulWidget { - final Attribute attribute; - - final IconData icon; - - final QuillController controller; - - final ToggleStyleButtonBuilder childBuilder; - const ToggleStyleButton({ required this.attribute, required this.icon, @@ -190,6 +182,14 @@ class ToggleStyleButton extends StatefulWidget { Key? key, }) : super(key: key); + final Attribute attribute; + + final IconData icon; + + final QuillController controller; + + final ToggleStyleButtonBuilder childBuilder; + @override _ToggleStyleButtonState createState() => _ToggleStyleButtonState(); } @@ -258,14 +258,6 @@ class _ToggleStyleButtonState extends State { } class ToggleCheckListButton extends StatefulWidget { - final IconData icon; - - final QuillController controller; - - final ToggleStyleButtonBuilder childBuilder; - - final Attribute attribute; - const ToggleCheckListButton({ required this.icon, required this.controller, @@ -274,6 +266,14 @@ class ToggleCheckListButton extends StatefulWidget { Key? key, }) : super(key: key); + final IconData icon; + + final QuillController controller; + + final ToggleStyleButtonBuilder childBuilder; + + final Attribute attribute; + @override _ToggleCheckListButtonState createState() => _ToggleCheckListButtonState(); } @@ -369,11 +369,11 @@ Widget defaultToggleStyleButtonBuilder( } class SelectHeaderStyleButton extends StatefulWidget { - final QuillController controller; - const SelectHeaderStyleButton({required this.controller, Key? key}) : super(key: key); + final QuillController controller; + @override _SelectHeaderStyleButtonState createState() => _SelectHeaderStyleButtonState(); @@ -490,6 +490,15 @@ Widget _selectHeadingStyleButtonBuilder(BuildContext context, Attribute? value, } class ImageButton extends StatefulWidget { + const ImageButton({ + required this.icon, + required this.controller, + required this.imageSource, + this.onImagePickCallback, + this.imagePickImpl, + Key? key, + }) : super(key: key); + final IconData icon; final QuillController controller; @@ -500,15 +509,6 @@ class ImageButton extends StatefulWidget { final ImageSource imageSource; - const ImageButton({ - required this.icon, - required this.controller, - required this.imageSource, - this.onImagePickCallback, - this.imagePickImpl, - Key? key, - }) : super(key: key); - @override _ImageButtonState createState() => _ImageButtonState(); } @@ -602,10 +602,6 @@ class _ImageButtonState extends State { /// When pressed, this button displays overlay toolbar with /// buttons for each color. class ColorButton extends StatefulWidget { - final IconData icon; - final bool background; - final QuillController controller; - const ColorButton({ required this.icon, required this.controller, @@ -613,6 +609,10 @@ class ColorButton extends StatefulWidget { Key? key, }) : super(key: key); + final IconData icon; + final bool background; + final QuillController controller; + @override _ColorButtonState createState() => _ColorButtonState(); } @@ -740,10 +740,6 @@ class _ColorButtonState extends State { } class HistoryButton extends StatefulWidget { - final IconData icon; - final bool undo; - final QuillController controller; - const HistoryButton({ required this.icon, required this.controller, @@ -751,6 +747,10 @@ class HistoryButton extends StatefulWidget { Key? key, }) : super(key: key); + final IconData icon; + final bool undo; + final QuillController controller; + @override _HistoryButtonState createState() => _HistoryButtonState(); } @@ -812,10 +812,6 @@ class _HistoryButtonState extends State { } class IndentButton extends StatefulWidget { - final IconData icon; - final QuillController controller; - final bool isIncrease; - const IndentButton({ required this.icon, required this.controller, @@ -823,6 +819,10 @@ class IndentButton extends StatefulWidget { Key? key, }) : super(key: key); + final IconData icon; + final QuillController controller; + final bool isIncrease; + @override _IndentButtonState createState() => _IndentButtonState(); } @@ -867,16 +867,16 @@ class _IndentButtonState extends State { } class ClearFormatButton extends StatefulWidget { - final IconData icon; - - final QuillController controller; - const ClearFormatButton({ required this.icon, required this.controller, Key? key, }) : super(key: key); + final IconData icon; + + final QuillController controller; + @override _ClearFormatButtonState createState() => _ClearFormatButtonState(); } @@ -903,8 +903,6 @@ class _ClearFormatButtonState extends State { } class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { - final List children; - const QuillToolbar({required this.children, Key? key}) : super(key: key); factory QuillToolbar.basic({ @@ -1117,6 +1115,8 @@ class QuillToolbar extends StatefulWidget implements PreferredSizeWidget { ]); } + final List children; + @override _QuillToolbarState createState() => _QuillToolbarState(); @@ -1148,13 +1148,6 @@ class _QuillToolbarState extends State { } class QuillIconButton extends StatelessWidget { - final VoidCallback? onPressed; - final Widget? icon; - final double size; - final Color? fillColor; - final double hoverElevation; - final double highlightElevation; - const QuillIconButton({ required this.onPressed, this.icon, @@ -1165,6 +1158,13 @@ class QuillIconButton extends StatelessWidget { Key? key, }) : super(key: key); + final VoidCallback? onPressed; + final Widget? icon; + final double size; + final Color? fillColor; + final double hoverElevation; + final double highlightElevation; + @override Widget build(BuildContext context) { return ConstrainedBox( @@ -1184,15 +1184,6 @@ class QuillIconButton extends StatelessWidget { } class QuillDropdownButton extends StatefulWidget { - final double height; - final Color? fillColor; - final double hoverElevation; - final double highlightElevation; - final Widget child; - final T initialValue; - final List> items; - final ValueChanged onSelected; - const QuillDropdownButton({ required this.child, required this.initialValue, @@ -1205,6 +1196,15 @@ class QuillDropdownButton extends StatefulWidget { Key? key, }) : super(key: key); + final double height; + final Color? fillColor; + final double hoverElevation; + final double highlightElevation; + final Widget child; + final T initialValue; + final List> items; + final ValueChanged onSelected; + @override _QuillDropdownButtonState createState() => _QuillDropdownButtonState(); } From 8c663ad9f5d9258137dc05ec055109e02db245e4 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Thu, 8 Apr 2021 23:30:54 +0200 Subject: [PATCH 18/19] Add comments from Zefyr to nodes folder Since quite a lot of code was taken from Zefyr, the license should be changed to BSD to meet the requirements of Zefyr. --- lib/models/documents/nodes/block.dart | 19 ++- lib/models/documents/nodes/container.dart | 50 ++++++-- lib/models/documents/nodes/embed.dart | 16 ++- lib/models/documents/nodes/leaf.dart | 108 ++++++++++++----- lib/models/documents/nodes/line.dart | 139 +++++++++++++++------- lib/models/documents/nodes/node.dart | 75 +++++++----- lib/widgets/editor.dart | 18 ++- lib/widgets/raw_editor.dart | 9 +- lib/widgets/text_block.dart | 34 +++--- lib/widgets/text_line.dart | 10 +- lib/widgets/text_selection.dart | 4 +- 11 files changed, 323 insertions(+), 159 deletions(-) diff --git a/lib/models/documents/nodes/block.dart b/lib/models/documents/nodes/block.dart index 5128f598..095f1183 100644 --- a/lib/models/documents/nodes/block.dart +++ b/lib/models/documents/nodes/block.dart @@ -3,7 +3,21 @@ import 'container.dart'; import 'line.dart'; import 'node.dart'; +/// Represents a group of adjacent [Line]s with the same block style. +/// +/// Block elements are: +/// - Blockquote +/// - Header +/// - Indent +/// - List +/// - Text Alignment +/// - Text Direction +/// - Code Block class Block extends Container { + /// Creates new unmounted [Block]. + @override + Node newInstance() => Block(); + @override Line get defaultChild => Line(); @@ -55,9 +69,4 @@ class Block extends Container { } return buffer.toString(); } - - @override - Node newInstance() { - return Block(); - } } diff --git a/lib/models/documents/nodes/container.dart b/lib/models/documents/nodes/container.dart index 28fc2475..dbdd12d1 100644 --- a/lib/models/documents/nodes/container.dart +++ b/lib/models/documents/nodes/container.dart @@ -1,48 +1,67 @@ import 'dart:collection'; import '../style.dart'; +import 'leaf.dart'; +import 'line.dart'; import 'node.dart'; -/* Container of multiple nodes */ +/// Container can accommodate other nodes. +/// +/// Delegates insert, retain and delete operations to children nodes. For each +/// operation container looks for a child at specified index position and +/// forwards operation to that child. +/// +/// Most of the operation handling logic is implemented by [Line] and [Text]. abstract class Container extends Node { final LinkedList _children = LinkedList(); + /// List of children. LinkedList get children => _children; + /// Returns total number of child nodes in this container. + /// + /// To get text length of this container see [length]. int get childCount => _children.length; + /// Returns the first child [Node]. Node get first => _children.first; + /// Returns the last child [Node]. Node get last => _children.last; + /// Returns `true` if this container has no child nodes. bool get isEmpty => _children.isEmpty; + /// Returns `true` if this container has at least 1 child. bool get isNotEmpty => _children.isNotEmpty; - /// abstract methods begin - + /// Returns an instance of default child for this container node. + /// + /// Always returns fresh instance. T get defaultChild; - /// abstract methods end - + /// Adds [node] to the end of this container children list. void add(T node) { assert(node?.parent == null); node?.parent = this; _children.add(node as Node); } + /// Adds [node] to the beginning of this container children list. void addFirst(T node) { assert(node?.parent == null); node?.parent = this; _children.addFirst(node as Node); } + /// Removes [node] from this container. void remove(T node) { assert(node?.parent == this); node?.parent = null; _children.remove(node as Node); } + /// Moves children of this node to [newParent]. void moveChildToNewParent(Container? newParent) { if (isEmpty) { return; @@ -55,9 +74,19 @@ abstract class Container extends Node { newParent.add(child); } + /// In case [newParent] already had children we need to make sure + /// combined list is optimized. if (last != null) last.adjust(); } + /// Queries the child [Node] at specified character [offset] in this container. + /// + /// The result may contain the found node or `null` if no node is found + /// at specified offset. + /// + /// [ChildQuery.offset] is set to relative offset within returned child node + /// which points at the same character position in the document as the + /// original [offset]. ChildQuery queryChild(int offset, bool inclusive) { if (offset < 0 || offset > length) { return ChildQuery(null, 0); @@ -76,6 +105,9 @@ abstract class Container extends Node { @override String toPlainText() => children.map((child) => child.toPlainText()).join(); + /// Content length of this node's children. + /// + /// To get number of children in this node use [childCount]. @override int get length => _children.fold(0, (cur, node) => cur + node.length); @@ -114,11 +146,15 @@ abstract class Container extends Node { String toString() => _children.join('\n'); } -/// Query of a child in a Container +/// Result of a child query in a [Container]. class ChildQuery { ChildQuery(this.node, this.offset); - final Node? node; // null if not found + /// The child node if found, otherwise `null`. + final Node? node; + /// Starting offset within the child [node] which points at the same + /// character in the document as the original offset passed to + /// [Container.queryChild] method. final int offset; } diff --git a/lib/models/documents/nodes/embed.dart b/lib/models/documents/nodes/embed.dart index 81ca6005..d6fe628a 100644 --- a/lib/models/documents/nodes/embed.dart +++ b/lib/models/documents/nodes/embed.dart @@ -1,7 +1,15 @@ +/// An object which can be embedded into a Quill document. +/// +/// See also: +/// +/// * [BlockEmbed] which represents a block embed. class Embeddable { Embeddable(this.type, this.data); + /// The type of this object. final String type; + + /// The data payload of this object. final dynamic data; Map toJson() { @@ -17,10 +25,16 @@ class Embeddable { } } +/// An object which occupies an entire line in a document and cannot co-exist +/// inline with regular text. +/// +/// There are two built-in embed types supported by Quill documents, however +/// the document model itself does not make any assumptions about the types +/// of embedded objects and allows users to define their own types. class BlockEmbed extends Embeddable { BlockEmbed(String type, String data) : super(type, data); - static final BlockEmbed horizontalRule = BlockEmbed('divider', 'hr'); + static BlockEmbed horizontalRule = BlockEmbed('divider', 'hr'); static BlockEmbed image(String imageUrl) => BlockEmbed('image', imageUrl); } diff --git a/lib/models/documents/nodes/leaf.dart b/lib/models/documents/nodes/leaf.dart index 24431fc9..bd9292f5 100644 --- a/lib/models/documents/nodes/leaf.dart +++ b/lib/models/documents/nodes/leaf.dart @@ -6,8 +6,9 @@ import 'embed.dart'; import 'line.dart'; import 'node.dart'; -/* A leaf node in document tree */ +/// A leaf in Quill document tree. abstract class Leaf extends Node { + /// Creates a new [Leaf] with specified [data]. factory Leaf(Object data) { if (data is Embeddable) { return Embed(data); @@ -19,9 +20,10 @@ abstract class Leaf extends Node { Leaf.val(Object val) : _value = val; - Object _value; - + /// Contents of this node, either a String if this is a [Text] or an + /// [Embed] if this is an [BlockEmbed]. Object get value => _value; + Object _value; @override void applyStyle(Style value) { @@ -99,14 +101,21 @@ abstract class Leaf extends Node { } } + /// Adjust this text node by merging it with adjacent nodes if they share + /// the same style. @override void adjust() { if (this is Embed) { + // Embed nodes cannot be merged with text nor other embeds (in fact, + // there could be no two adjacent embeds on the same line since an + // embed occupies an entire line). return; } + // This is a text node and it can only be merged with other text nodes. var node = this as Text; - // merging it with previous node if style is the same + + // Merging it with previous node if style is the same. final prev = node.previous; if (!node.isFirst && prev is Text && prev.style == node.style) { prev._value = prev.value + node.value; @@ -114,7 +123,7 @@ abstract class Leaf extends Node { node = prev; } - // merging it with next node if style is the same + // Merging it with next node if style is the same. final next = node.next; if (!node.isLast && next is Text && next.style == node.style) { node._value = node.value + next.value; @@ -122,13 +131,17 @@ abstract class Leaf extends Node { } } - Leaf? cutAt(int index) { - assert(index >= 0 && index <= length); - final cut = splitAt(index); - cut?.unlink(); - return cut; - } - + /// Splits this leaf node at [index] and returns new node. + /// + /// If this is the last node in its list and [index] equals this node's + /// length then this method returns `null` as there is nothing left to split. + /// If there is another leaf node after this one and [index] equals this + /// node's length then the next leaf node is returned. + /// + /// If [index] equals to `0` then this node itself is returned unchanged. + /// + /// In case a new node is actually split from this one, it inherits this + /// node's style. Leaf? splitAt(int index) { assert(index >= 0 && index <= length); if (index == 0) { @@ -146,14 +159,33 @@ abstract class Leaf extends Node { return split; } + /// Cuts a leaf from [index] to the end of this node and returns new node + /// in detached state (e.g. [mounted] returns `false`). + /// + /// Splitting logic is identical to one described in [splitAt], meaning this + /// method may return `null`. + Leaf? cutAt(int index) { + assert(index >= 0 && index <= length); + final cut = splitAt(index); + cut?.unlink(); + return cut; + } + + /// Formats this node and optimizes it with adjacent leaf nodes if needed. void format(Style? style) { if (style != null && style.isNotEmpty) { applyStyle(style); } - adjust(); } + /// Isolates a new leaf starting at [index] with specified [length]. + /// + /// Splitting logic is identical to one described in [splitAt], with one + /// exception that it is required for [index] to always be less than this + /// node's length. As a result this method always returns a [LeafNode] + /// instance. Returned node may still be the same as this node + /// if provided [index] is `0`. Leaf _isolate(int index, int length) { assert( index >= 0 && index < this.length && (index + length <= this.length)); @@ -162,39 +194,59 @@ abstract class Leaf extends Node { } } +/// A span of formatted text within a line in a Quill document. +/// +/// Text is a leaf node of a document tree. +/// +/// Parent of a text node is always a [Line], and as a consequence text +/// node's [value] cannot contain any line-break characters. +/// +/// See also: +/// +/// * [Embed], a leaf node representing an embeddable object. +/// * [Line], a node representing a line of text. class Text extends Leaf { Text([String text = '']) : assert(!text.contains('\n')), super.val(text); @override - String get value => _value as String; + Node newInstance() => Text(); @override - String toPlainText() { - return value; - } + String get value => _value as String; @override - Node newInstance() { - return Text(); - } + String toPlainText() => value; } -/// An embedded node such as image or video +/// An embed node inside of a line in a Quill document. +/// +/// Embed node is a leaf node similar to [Text]. It represents an arbitrary +/// piece of non-textual content embedded into a document, such as, image, +/// horizontal rule, video, or any other object with defined structure, +/// like a tweet, for instance. +/// +/// Embed node's length is always `1` character and it is represented with +/// unicode object replacement character in the document text. +/// +/// Any inline style can be applied to an embed, however this does not +/// necessarily mean the embed will look according to that style. For instance, +/// applying "bold" style to an image gives no effect, while adding a "link" to +/// an image actually makes the image react to user's action. class Embed extends Leaf { Embed(Embeddable data) : super.val(data); + static const kObjectReplacementCharacter = '\uFFFC'; + @override - Embeddable get value => super.value as Embeddable; + Node newInstance() => throw UnimplementedError(); @override - String toPlainText() { - return '\uFFFC'; - } + Embeddable get value => super.value as Embeddable; + /// // Embed nodes are represented as unicode object replacement character in + // plain text. @override - Node newInstance() { - throw UnimplementedError(); - } + String toPlainText() => kObjectReplacementCharacter; } diff --git a/lib/models/documents/nodes/line.dart b/lib/models/documents/nodes/line.dart index f3473ac9..ec933b52 100644 --- a/lib/models/documents/nodes/line.dart +++ b/lib/models/documents/nodes/line.dart @@ -9,6 +9,12 @@ import 'embed.dart'; import 'leaf.dart'; import 'node.dart'; +/// A line of rich text in a Quill document. +/// +/// Line serves as a container for [Leaf]s, like [Text] and [Embed]. +/// +/// When a line contains an embed, it fully occupies the line, no other embeds +/// or text nodes are allowed. class Line extends Container { @override Leaf get defaultChild => Text(); @@ -16,6 +22,7 @@ class Line extends Container { @override int get length => super.length + 1; + /// Returns `true` if this line contains an embedded object. bool get hasEmbed { if (childCount != 1) { return false; @@ -24,6 +31,7 @@ class Line extends Container { return children.single is Embed; } + /// Returns next [Line] or `null` if this is the last line in the document. Line? get nextLine { if (!isLast) { return next is Block ? (next as Block).first as Line? : next as Line?; @@ -40,6 +48,9 @@ class Line extends Container { : parent!.next as Line?; } + @override + Node newInstance() => Line(); + @override Delta toDelta() { final delta = children @@ -67,34 +78,42 @@ class Line extends Container { @override void insert(int index, Object data, Style? style) { if (data is Embeddable) { - _insert(index, data, style); + // We do not check whether this line already has any children here as + // inserting an embed into a line with other text is acceptable from the + // Delta format perspective. + // We rely on heuristic rules to ensure that embeds occupy an entire line. + _insertSafe(index, data, style); return; } final text = data as String; final lineBreak = text.indexOf('\n'); if (lineBreak < 0) { - _insert(index, text, style); + _insertSafe(index, text, style); + // No need to update line or block format since those attributes can only + // be attached to `\n` character and we already know it's not present. return; } final prefix = text.substring(0, lineBreak); - _insert(index, prefix, style); + _insertSafe(index, prefix, style); if (prefix.isNotEmpty) { index += prefix.length; } + // Next line inherits our format. final nextLine = _getNextLine(index); + // Reset our format and unwrap from a block if needed. clearStyle(); - if (parent is Block) { _unwrap(); } + // Now we can apply new format and re-layout. _format(style); - // Continue with the remaining + // Continue with remaining part. final remain = text.substring(lineBreak + 1); nextLine.insert(0, remain, style); } @@ -104,16 +123,20 @@ class Line extends Container { if (style == null) { return; } - final thisLen = length; + final thisLength = length; - final local = math.min(thisLen - index, len!); + final local = math.min(thisLength - index, len!); + // If index is at newline character then this is a line/block style update. + final isLineFormat = (index + local == thisLength) && local == 1; - if (index + local == thisLen && local == 1) { - assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK)); + if (isLineFormat) { + assert(style.values.every((attr) => attr.scope == AttributeScope.BLOCK), + 'It is not allowed to apply inline attributes to line itself.'); _format(style); } else { + // Otherwise forward to children as it's an inline format update. assert(style.values.every((attr) => attr.scope == AttributeScope.INLINE)); - assert(index + local != thisLen); + assert(index + local != thisLength); super.retain(index, local, style); } @@ -127,35 +150,47 @@ class Line extends Container { @override void delete(int index, int? len) { final local = math.min(length - index, len!); - final deleted = index + local == length; - if (deleted) { + final isLFDeleted = index + local == length; // Line feed + if (isLFDeleted) { + // Our newline character deleted with all style information. clearStyle(); if (local > 1) { + // Exclude newline character from delete range for children. super.delete(index, local - 1); } } else { super.delete(index, local); } - final remain = len - local; - if (remain > 0) { + final remaining = len - local; + if (remaining > 0) { assert(nextLine != null); - nextLine!.delete(0, remain); + nextLine!.delete(0, remaining); } - if (deleted && isNotEmpty) { + if (isLFDeleted && isNotEmpty) { + // Since we lost our line-break and still have child text nodes those must + // migrate to the next line. + + // nextLine might have been unmounted since last assert so we need to + // check again we still have a line after us. assert(nextLine != null); + + // Move remaining children in this line to the next line so that all + // attributes of nextLine are preserved. nextLine!.moveChildToNewParent(this); moveChildToNewParent(nextLine); } - if (deleted) { - final Node p = parent!; + if (isLFDeleted) { + // Now we can remove this line. + final block = parent!; // remember reference before un-linking. unlink(); - p.adjust(); + block.adjust(); } } + /// Formats this line. void _format(Style? newStyle) { if (newStyle == null || newStyle.isEmpty) { return; @@ -165,7 +200,7 @@ class Line extends Container { final blockStyle = newStyle.getBlockExceptHeader(); if (blockStyle == null) { return; - } + } // No block-level changes if (parent is Block) { final parentStyle = (parent as Block).style.getBlockExceptHeader(); @@ -176,14 +211,18 @@ class Line extends Container { final block = Block()..applyAttribute(blockStyle); _wrap(block); block.adjust(); - } + } // else the same style, no-op. } else if (blockStyle.value != null) { + // Only wrap with a new block if this is not an unset final block = Block()..applyAttribute(blockStyle); _wrap(block); block.adjust(); } } + /// Wraps this line with new parent [block]. + /// + /// This line can not be in a [Block] when this method is called. void _wrap(Block block) { assert(parent != null && parent is! Block); insertAfter(block); @@ -191,6 +230,9 @@ class Line extends Container { block.add(this); } + /// Unwraps this line from it's parent [Block]. + /// + /// This method asserts if current [parent] of this line is not a [Block]. void _unwrap() { if (parent is! Block) { throw ArgumentError('Invalid parent'); @@ -242,7 +284,7 @@ class Line extends Container { return line; } - void _insert(int index, Object data, Style? style) { + void _insertSafe(int index, Object data, Style? style) { assert(index == 0 || (index > 0 && index < length)); if (data is String) { @@ -252,46 +294,50 @@ class Line extends Container { } } - if (isNotEmpty) { + if (isEmpty) { + final child = Leaf(data); + add(child); + child.format(style); + } else { final result = queryChild(index, true); result.node!.insert(result.offset, data, style); - return; } - - final child = Leaf(data); - add(child); - child.format(style); - } - - @override - Node newInstance() { - return Line(); } + /// Returns style for specified text range. + /// + /// Only attributes applied to all characters within this range are + /// included in the result. Inline and line level attributes are + /// handled separately, e.g.: + /// + /// - line attribute X is included in the result only if it exists for + /// every line within this range (partially included lines are counted). + /// - inline attribute X is included in the result only if it exists + /// for every character within this range (line-break characters excluded). Style collectStyle(int offset, int len) { final local = math.min(length - offset, len); - var res = Style(); + var result = Style(); final excluded = {}; void _handle(Style style) { - if (res.isEmpty) { + if (result.isEmpty) { excluded.addAll(style.values); } else { - for (final attr in res.values) { + for (final attr in result.values) { if (!style.containsKey(attr.key)) { excluded.add(attr); } } } - final remain = style.removeAll(excluded); - res = res.removeAll(excluded); - res = res.mergeAll(remain); + final remaining = style.removeAll(excluded); + result = result.removeAll(excluded); + result = result.mergeAll(remaining); } final data = queryChild(offset, true); var node = data.node as Leaf?; if (node != null) { - res = res.mergeAll(node.style); + result = result.mergeAll(node.style); var pos = node.length - data.offset; while (!node!.isLast && pos < local) { node = node.next as Leaf?; @@ -300,17 +346,18 @@ class Line extends Container { } } - res = res.mergeAll(style); + result = result.mergeAll(style); if (parent is Block) { final block = parent as Block; - res = res.mergeAll(block.style); + result = result.mergeAll(block.style); } - final remain = len - local; - if (remain > 0) { - _handle(nextLine!.collectStyle(0, remain)); + final remaining = len - local; + if (remaining > 0) { + final rest = nextLine!.collectStyle(0, remaining); + _handle(rest); } - return res; + return result; } } diff --git a/lib/models/documents/nodes/node.dart b/lib/models/documents/nodes/node.dart index ddd1078c..6bb0fb97 100644 --- a/lib/models/documents/nodes/node.dart +++ b/lib/models/documents/nodes/node.dart @@ -6,36 +6,37 @@ import '../style.dart'; import 'container.dart'; import 'line.dart'; -/* node in a document tree */ +/// An abstract node in a document tree. +/// +/// Represents a segment of a Quill document with specified [offset] +/// and [length]. +/// +/// The [offset] property is relative to [parent]. See also [documentOffset] +/// which provides absolute offset of this node within the document. +/// +/// The current parent node is exposed by the [parent] property. abstract class Node extends LinkedListEntry { + /// Current parent of this node. May be null if this node is not mounted. Container? parent; - Style _style = Style(); Style get style => _style; + Style _style = Style(); - void applyAttribute(Attribute attribute) { - _style = _style.merge(attribute); - } - - void applyStyle(Style value) { - _style = _style.mergeAll(value); - } - - void clearStyle() { - _style = Style(); - } - + /// Returns `true` if this node is the first node in the [parent] list. bool get isFirst => list!.first == this; + /// Returns `true` if this node is the last node in the [parent] list. bool get isLast => list!.last == this; + /// Length of this node in characters. int get length; - Node clone() { - return newInstance()..applyStyle(style); - } + Node clone() => newInstance()..applyStyle(style); - int getOffset() { + /// Offset in characters of this node relative to [parent] node. + /// + /// To get offset of this node in the document see [documentOffset]. + int get offset { var offset = 0; if (list == null || isFirst) { @@ -50,16 +51,31 @@ abstract class Node extends LinkedListEntry { return offset; } - int getDocumentOffset() { - final parentOffset = (parent is! Root) ? parent!.getDocumentOffset() : 0; - return parentOffset + getOffset(); + /// Offset in characters of this node in the document. + int get documentOffset { + final parentOffset = (parent is! Root) ? parent!.documentOffset : 0; + return parentOffset + offset; } + /// Returns `true` if this node contains character at specified [offset] in + /// the document. bool containsOffset(int offset) { - final o = getDocumentOffset(); + final o = documentOffset; return o <= offset && offset < o + length; } + void applyAttribute(Attribute attribute) { + _style = _style.merge(attribute); + } + + void applyStyle(Style value) { + _style = _style.mergeAll(value); + } + + void clearStyle() { + _style = Style(); + } + @override void insertBefore(Node entry) { assert(entry.parent == null && parent != null); @@ -81,9 +97,7 @@ abstract class Node extends LinkedListEntry { super.unlink(); } - void adjust() { - // do nothing - } + void adjust() {/* no-op */} /// abstract methods begin @@ -100,11 +114,13 @@ abstract class Node extends LinkedListEntry { void delete(int index, int? len); /// abstract methods end - } -/* Root node of document tree */ +/// Root node of document tree. class Root extends Container> { + @override + Node newInstance() => Root(); + @override Container get defaultChild => Line(); @@ -112,9 +128,4 @@ class Root extends Container> { Delta toDelta() => children .map((child) => child.toDelta()) .fold(Delta(), (a, b) => a.concat(b)); - - @override - Node newInstance() { - return Root(); - } } diff --git a/lib/widgets/editor.dart b/lib/widgets/editor.dart index 3b33211c..4d2ce846 100644 --- a/lib/widgets/editor.dart +++ b/lib/widgets/editor.dart @@ -577,8 +577,7 @@ class RenderEditor extends RenderEditableContainerBox if (textSelection.isCollapsed) { final child = childAtPosition(textSelection.extent); final localPosition = TextPosition( - offset: - textSelection.extentOffset - child.getContainer().getOffset()); + offset: textSelection.extentOffset - child.getContainer().offset); final localOffset = child.getOffsetForCaret(localPosition); final parentData = child.parentData as BoxParentData; return [ @@ -677,7 +676,7 @@ class RenderEditor extends RenderEditableContainerBox assert(_lastTapDownPosition != null); final position = getPositionForOffset(_lastTapDownPosition!); final child = childAtPosition(position); - final nodeOffset = child.getContainer().getOffset(); + final nodeOffset = child.getContainer().offset; final localPosition = TextPosition( offset: position.offset - nodeOffset, affinity: position.affinity, @@ -738,7 +737,7 @@ class RenderEditor extends RenderEditableContainerBox @override TextSelection selectWordAtPosition(TextPosition position) { final child = childAtPosition(position); - final nodeOffset = child.getContainer().getOffset(); + final nodeOffset = child.getContainer().offset; final localPosition = TextPosition( offset: position.offset - nodeOffset, affinity: position.affinity); final localWord = child.getWordBoundary(localPosition); @@ -755,7 +754,7 @@ class RenderEditor extends RenderEditableContainerBox @override TextSelection selectLineAtPosition(TextPosition position) { final child = childAtPosition(position); - final nodeOffset = child.getContainer().getOffset(); + final nodeOffset = child.getContainer().offset; final localPosition = TextPosition( offset: position.offset - nodeOffset, affinity: position.affinity); final localLineRange = child.getLineBoundary(localPosition); @@ -810,8 +809,8 @@ class RenderEditor extends RenderEditableContainerBox @override double preferredLineHeight(TextPosition position) { final child = childAtPosition(position); - return child.preferredLineHeight(TextPosition( - offset: position.offset - child.getContainer().getOffset())); + return child.preferredLineHeight( + TextPosition(offset: position.offset - child.getContainer().offset)); } @override @@ -823,7 +822,7 @@ class RenderEditor extends RenderEditableContainerBox final localOffset = local - parentData.offset; final localPosition = child.getPositionForOffset(localOffset); return TextPosition( - offset: localPosition.offset + child.getContainer().getOffset(), + offset: localPosition.offset + child.getContainer().offset, affinity: localPosition.affinity, ); } @@ -842,8 +841,7 @@ class RenderEditor extends RenderEditableContainerBox final caretTop = endpoint.point.dy - child.preferredLineHeight(TextPosition( - offset: - selection.extentOffset - child.getContainer().getOffset())) - + offset: selection.extentOffset - child.getContainer().offset)) - kMargin + offsetInViewport; final caretBottom = endpoint.point.dy + kMargin + offsetInViewport; diff --git a/lib/widgets/raw_editor.dart b/lib/widgets/raw_editor.dart index 72422991..0ae9e82d 100644 --- a/lib/widgets/raw_editor.dart +++ b/lib/widgets/raw_editor.dart @@ -209,8 +209,7 @@ class RawEditorState extends EditorState final child = getRenderEditor()!.childAtPosition(originPosition); final localPosition = TextPosition( - offset: - originPosition.offset - child.getContainer().getDocumentOffset()); + offset: originPosition.offset - child.getContainer().documentOffset); var position = upKey ? child.getPositionAbove(localPosition) @@ -231,12 +230,12 @@ class RawEditorState extends EditorState .dy); final siblingPosition = sibling.getPositionForOffset(finalOffset); position = TextPosition( - offset: sibling.getContainer().getDocumentOffset() + - siblingPosition.offset); + offset: + sibling.getContainer().documentOffset + siblingPosition.offset); } } else { position = TextPosition( - offset: child.getContainer().getDocumentOffset() + position.offset); + offset: child.getContainer().documentOffset + position.offset); } if (position.offset == newSelection.extentOffset) { diff --git a/lib/widgets/text_block.dart b/lib/widgets/text_block.dart index 25ea8d9c..1c81f1ac 100644 --- a/lib/widgets/text_block.dart +++ b/lib/widgets/text_block.dart @@ -312,12 +312,12 @@ class RenderEditableTextBlock extends RenderEditableContainerBox TextRange getLineBoundary(TextPosition position) { final child = childAtPosition(position); final rangeInChild = child.getLineBoundary(TextPosition( - offset: position.offset - child.getContainer().getOffset(), + offset: position.offset - child.getContainer().offset, affinity: position.affinity, )); return TextRange( - start: rangeInChild.start + child.getContainer().getOffset(), - end: rangeInChild.end + child.getContainer().getOffset(), + start: rangeInChild.start + child.getContainer().offset, + end: rangeInChild.end + child.getContainer().offset, ); } @@ -325,7 +325,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox Offset getOffsetForCaret(TextPosition position) { final child = childAtPosition(position); return child.getOffsetForCaret(TextPosition( - offset: position.offset - child.getContainer().getOffset(), + offset: position.offset - child.getContainer().offset, affinity: position.affinity, )) + (child.parentData as BoxParentData).offset; @@ -338,7 +338,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox final localPosition = child.getPositionForOffset(offset - parentData.offset); return TextPosition( - offset: localPosition.offset + child.getContainer().getOffset(), + offset: localPosition.offset + child.getContainer().offset, affinity: localPosition.affinity, ); } @@ -346,7 +346,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox @override TextRange getWordBoundary(TextPosition position) { final child = childAtPosition(position); - final nodeOffset = child.getContainer().getOffset(); + final nodeOffset = child.getContainer().offset; final childWord = child .getWordBoundary(TextPosition(offset: position.offset - nodeOffset)); return TextRange( @@ -360,12 +360,11 @@ class RenderEditableTextBlock extends RenderEditableContainerBox assert(position.offset < getContainer().length); final child = childAtPosition(position); - final childLocalPosition = TextPosition( - offset: position.offset - child.getContainer().getOffset()); + final childLocalPosition = + TextPosition(offset: position.offset - child.getContainer().offset); final result = child.getPositionAbove(childLocalPosition); if (result != null) { - return TextPosition( - offset: result.offset + child.getContainer().getOffset()); + return TextPosition(offset: result.offset + child.getContainer().offset); } final sibling = childBefore(child); @@ -379,7 +378,7 @@ class RenderEditableTextBlock extends RenderEditableContainerBox final testOffset = sibling.getOffsetForCaret(testPosition); final finalOffset = Offset(caretOffset.dx, testOffset.dy); return TextPosition( - offset: sibling.getContainer().getOffset() + + offset: sibling.getContainer().offset + sibling.getPositionForOffset(finalOffset).offset); } @@ -388,12 +387,11 @@ class RenderEditableTextBlock extends RenderEditableContainerBox assert(position.offset < getContainer().length); final child = childAtPosition(position); - final childLocalPosition = TextPosition( - offset: position.offset - child.getContainer().getOffset()); + final childLocalPosition = + TextPosition(offset: position.offset - child.getContainer().offset); final result = child.getPositionBelow(childLocalPosition); if (result != null) { - return TextPosition( - offset: result.offset + child.getContainer().getOffset()); + return TextPosition(offset: result.offset + child.getContainer().offset); } final sibling = childAfter(child); @@ -405,15 +403,15 @@ class RenderEditableTextBlock extends RenderEditableContainerBox final testOffset = sibling.getOffsetForCaret(const TextPosition(offset: 0)); final finalOffset = Offset(caretOffset.dx, testOffset.dy); return TextPosition( - offset: sibling.getContainer().getOffset() + + offset: sibling.getContainer().offset + sibling.getPositionForOffset(finalOffset).offset); } @override double preferredLineHeight(TextPosition position) { final child = childAtPosition(position); - return child.preferredLineHeight(TextPosition( - offset: position.offset - child.getContainer().getOffset())); + return child.preferredLineHeight( + TextPosition(offset: position.offset - child.getContainer().offset)); } @override diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index 43cc6969..3106a08d 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -402,8 +402,8 @@ class RenderEditableTextLine extends RenderEditableBox { } bool containsTextSelection() { - return line.getDocumentOffset() <= textSelection.end && - textSelection.start <= line.getDocumentOffset() + line.length - 1; + return line.documentOffset <= textSelection.end && + textSelection.start <= line.documentOffset + line.length - 1; } bool containsCursor() { @@ -735,8 +735,8 @@ class RenderEditableTextLine extends RenderEditableBox { final parentData = _body!.parentData as BoxParentData; final effectiveOffset = offset + parentData.offset; if (enableInteractiveSelection && - line.getDocumentOffset() <= textSelection.end && - textSelection.start <= line.getDocumentOffset() + line.length - 1) { + line.documentOffset <= textSelection.end && + textSelection.start <= line.documentOffset + line.length - 1) { final local = localSelection(line, textSelection, false); _selectedRects ??= _body!.getBoxesForSelection( local, @@ -772,7 +772,7 @@ class RenderEditableTextLine extends RenderEditableBox { void _paintCursor(PaintingContext context, Offset effectiveOffset) { final position = TextPosition( - offset: textSelection.extentOffset - line.getDocumentOffset(), + offset: textSelection.extentOffset - line.documentOffset, affinity: textSelection.base.affinity, ); _cursorPainter.paint(context.canvas, effectiveOffset, position); diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index fe28741b..dbf9d856 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -12,10 +12,10 @@ import '../models/documents/nodes/node.dart'; import 'editor.dart'; TextSelection localSelection(Node node, TextSelection selection, fromParent) { - final base = fromParent ? node.getOffset() : node.getDocumentOffset(); + final base = fromParent ? node.offset : node.documentOffset; assert(base <= selection.end && selection.start <= base + node.length - 1); - final offset = fromParent ? node.getOffset() : node.getDocumentOffset(); + final offset = fromParent ? node.offset : node.documentOffset; return selection.copyWith( baseOffset: math.max(selection.start - offset, 0), extentOffset: math.min(selection.end - offset, node.length - 1)); From ce60ed3b4bcfef07eb60611a0770e6dc2aa4b667 Mon Sep 17 00:00:00 2001 From: Xin Yao Date: Thu, 8 Apr 2021 16:54:46 -0700 Subject: [PATCH 19/19] Bump version to 1.1.8 --- CHANGELOG.md | 3 +++ pubspec.yaml | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3550e11a..01145d24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## [1.1.8] +* Fix height of empty line bug. + ## [1.1.7] * Fix text selection in read-only mode. diff --git a/pubspec.yaml b/pubspec.yaml index 504f96d1..15c4de29 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: flutter_quill description: A rich text editor supporting mobile and web (Demo App @ bulletjournal.us) -version: 1.1.7 +version: 1.1.8 #author: bulletjournal homepage: https://bulletjournal.us/home/index.html repository: https://github.com/singerdmx/flutter-quill